ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / sound / oss / emu10k1 / voicemgr.c
1 /*
2  **********************************************************************
3  *     voicemgr.c - Voice manager for emu10k1 driver
4  *     Copyright 1999, 2000 Creative Labs, Inc.
5  *
6  **********************************************************************
7  *
8  *     Date                 Author          Summary of changes
9  *     ----                 ------          ------------------
10  *     October 20, 1999     Bertrand Lee    base code release
11  *
12  **********************************************************************
13  *
14  *     This program is free software; you can redistribute it and/or
15  *     modify it under the terms of the GNU General Public License as
16  *     published by the Free Software Foundation; either version 2 of
17  *     the License, or (at your option) any later version.
18  *
19  *     This program is distributed in the hope that it will be useful,
20  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *     GNU General Public License for more details.
23  *
24  *     You should have received a copy of the GNU General Public
25  *     License along with this program; if not, write to the Free
26  *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
27  *     USA.
28  *
29  **********************************************************************
30  */
31
32 #include "voicemgr.h"
33 #include "8010.h"
34
35 #define PITCH_48000 0x00004000
36 #define PITCH_96000 0x00008000
37 #define PITCH_85000 0x00007155
38 #define PITCH_80726 0x00006ba2
39 #define PITCH_67882 0x00005a82
40 #define PITCH_57081 0x00004c1c
41
42 u32 emu10k1_select_interprom(struct emu10k1_card *card, struct emu_voice *voice)
43 {
44         if(voice->pitch_target==PITCH_48000)
45                 return CCCA_INTERPROM_0;
46         else if(voice->pitch_target<PITCH_48000)
47                 return CCCA_INTERPROM_1;
48         else  if(voice->pitch_target>=PITCH_96000)
49                 return CCCA_INTERPROM_0;
50         else  if(voice->pitch_target>=PITCH_85000)
51                 return CCCA_INTERPROM_6;
52         else  if(voice->pitch_target>=PITCH_80726)
53                 return CCCA_INTERPROM_5;
54         else  if(voice->pitch_target>=PITCH_67882)
55                 return CCCA_INTERPROM_4;
56         else  if(voice->pitch_target>=PITCH_57081)
57                 return CCCA_INTERPROM_3;
58         else  
59                 return CCCA_INTERPROM_2;
60 }
61
62
63 /**
64  * emu10k1_voice_alloc_buffer -
65  *
66  * allocates the memory buffer for a voice. Two page tables are kept for each buffer.
67  * One (dma_handle) keeps track of the host memory pages used and the other (virtualpagetable)
68  * is passed to the device so that it can do DMA to host memory.
69  *
70  */
71 int emu10k1_voice_alloc_buffer(struct emu10k1_card *card, struct voice_mem *mem, u32 pages)
72 {
73         u32 pageindex, pagecount;
74         u32 busaddx;
75         int i;
76
77         DPD(2, "requested pages is: %d\n", pages);
78
79         if ((mem->emupageindex = emu10k1_addxmgr_alloc(pages * PAGE_SIZE, card)) < 0)
80         {
81                 DPF(1, "couldn't allocate emu10k1 address space\n");
82                 return -1;
83         }
84
85         /* Fill in virtual memory table */
86         for (pagecount = 0; pagecount < pages; pagecount++) {
87                 if ((mem->addr[pagecount] = pci_alloc_consistent(card->pci_dev, PAGE_SIZE, &mem->dma_handle[pagecount]))
88                         == NULL) {
89                         mem->pages = pagecount;
90                         DPF(1, "couldn't allocate dma memory\n");
91                         return -1;
92                 }
93
94                 DPD(2, "Virtual Addx: %p\n", mem->addr[pagecount]);
95
96                 for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
97                         busaddx = (u32) mem->dma_handle[pagecount] + i * EMUPAGESIZE;
98
99                         DPD(3, "Bus Addx: %#x\n", busaddx);
100
101                         pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
102
103                         ((u32 *) card->virtualpagetable.addr)[pageindex] = cpu_to_le32((busaddx * 2) | pageindex);
104                 }
105         }
106
107         mem->pages = pagecount;
108
109         return 0;
110 }
111
112 /**
113  * emu10k1_voice_free_buffer -
114  *
115  * frees the memory buffer for a voice.
116  */
117 void emu10k1_voice_free_buffer(struct emu10k1_card *card, struct voice_mem *mem)
118 {
119         u32 pagecount, pageindex;
120         int i;
121
122         if (mem->emupageindex < 0)
123                 return;
124
125         for (pagecount = 0; pagecount < mem->pages; pagecount++) {
126                 pci_free_consistent(card->pci_dev, PAGE_SIZE,
127                                         mem->addr[pagecount],
128                                         mem->dma_handle[pagecount]);
129
130                 for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
131                         pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
132                         ((u32 *) card->virtualpagetable.addr)[pageindex] =
133                                 cpu_to_le32(((u32) card->silentpage.dma_handle * 2) | pageindex);
134                 }
135         }
136
137         emu10k1_addxmgr_free(card, mem->emupageindex);
138         mem->emupageindex = -1;
139 }
140
141 int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice)
142 {
143         u8 *voicetable = card->voicetable;
144         int i;
145         unsigned long flags;
146
147         DPF(2, "emu10k1_voice_alloc()\n");
148
149         spin_lock_irqsave(&card->lock, flags);
150
151         if (voice->flags & VOICE_FLAGS_STEREO) {
152                 for (i = 0; i < NUM_G; i += 2)
153                         if ((voicetable[i] == VOICE_USAGE_FREE) && (voicetable[i + 1] == VOICE_USAGE_FREE)) {
154                                 voicetable[i] = voice->usage;
155                                 voicetable[i + 1] = voice->usage;
156                                 break;
157                         }
158         } else {
159                 for (i = 0; i < NUM_G; i++)
160                         if (voicetable[i] == VOICE_USAGE_FREE) {
161                                 voicetable[i] = voice->usage;
162                                 break;
163                         }
164         }
165
166         spin_unlock_irqrestore(&card->lock, flags);
167
168         if (i >= NUM_G)
169                 return -1;
170
171         voice->card = card;
172         voice->num = i;
173
174         for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
175                 DPD(2, " voice allocated -> %d\n", voice->num + i);
176
177                 sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff,
178                                                         DCYSUSV, 0,
179                                                         VTFT, 0x0000ffff,
180                                                         PTRX, 0,
181                                                         TAGLIST_END);
182         }
183
184         return 0;
185 }
186
187 void emu10k1_voice_free(struct emu_voice *voice)
188 {
189         struct emu10k1_card *card = voice->card;
190         int i;
191         unsigned long flags;
192
193         DPF(2, "emu10k1_voice_free()\n");
194
195         if (voice->usage == VOICE_USAGE_FREE)
196                 return;
197
198         for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
199                 DPD(2, " voice released -> %d\n", voice->num + i);
200
201                 sblive_writeptr_tag(card, voice->num + i, DCYSUSV, 0, 
202                                                         VTFT, 0x0000ffff,
203                                                         PTRX_PITCHTARGET, 0,
204                                                         CVCF, 0x0000ffff,
205                                                         //CPF, 0,
206                                                         TAGLIST_END);
207                 
208                 sblive_writeptr(card, CPF, voice->num + i, 0);
209         }
210
211         voice->usage = VOICE_USAGE_FREE;
212
213         spin_lock_irqsave(&card->lock, flags);
214
215         card->voicetable[voice->num] = VOICE_USAGE_FREE;
216
217         if (voice->flags & VOICE_FLAGS_STEREO)
218                 card->voicetable[voice->num + 1] = VOICE_USAGE_FREE;
219
220         spin_unlock_irqrestore(&card->lock, flags);
221 }
222
223 void emu10k1_voice_playback_setup(struct emu_voice *voice)
224 {
225         struct emu10k1_card *card = voice->card;
226         u32 start;
227         int i;
228
229         DPF(2, "emu10k1_voice_playback_setup()\n");
230
231         if (voice->flags & VOICE_FLAGS_STEREO) {
232                 /* Set stereo bit */
233                 start = 28;
234                 sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
235                 sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
236         } else {
237                 start = 30;
238                 sblive_writeptr(card, CPF, voice->num, 0);
239         }
240
241         if(!(voice->flags & VOICE_FLAGS_16BIT))
242                 start *= 2;
243
244         voice->start += start;
245
246         for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
247                 if (card->is_audigy) {
248                         sblive_writeptr(card, A_FXRT1, voice->num + i, voice->params[i].send_routing);
249                         sblive_writeptr(card, A_FXRT2, voice->num + i, voice->params[i].send_routing2);
250                         sblive_writeptr(card,  A_SENDAMOUNTS, voice->num + i, voice->params[i].send_hgfe);
251                 } else {
252                         sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
253                 }
254
255                 /* Stop CA */
256                 /* Assumption that PT is already 0 so no harm overwriting */
257                 sblive_writeptr(card, PTRX, voice->num + i, ((voice->params[i].send_dcba & 0xff) << 8)
258                                 | ((voice->params[i].send_dcba & 0xff00) >> 8));
259
260                 sblive_writeptr_tag(card, voice->num + i,
261                                 /* CSL, ST, CA */
262                                     DSL, voice->endloop | (voice->params[i].send_dcba & 0xff000000),
263                                     PSST, voice->startloop | ((voice->params[i].send_dcba & 0x00ff0000) << 8),
264                                     CCCA, (voice->start) |  emu10k1_select_interprom(card,voice) |
265                                         ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
266                                     /* Clear filter delay memory */
267                                     Z1, 0,
268                                     Z2, 0,
269                                     /* Invalidate maps */
270                                     MAPA, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
271                                     MAPB, MAP_PTI_MASK | ((u32) card->silentpage.dma_handle * 2),
272                                 /* modulation envelope */
273                                     CVCF, 0x0000ffff,
274                                     VTFT, 0x0000ffff,
275                                     ATKHLDM, 0,
276                                     DCYSUSM, 0x007f,
277                                     LFOVAL1, 0x8000,
278                                     LFOVAL2, 0x8000,
279                                     FMMOD, 0,
280                                     TREMFRQ, 0,
281                                     FM2FRQ2, 0,
282                                     ENVVAL, 0x8000,
283                                 /* volume envelope */
284                                     ATKHLDV, 0x7f7f,
285                                     ENVVOL, 0x8000,
286                                 /* filter envelope */
287                                     PEFE_FILTERAMOUNT, 0x7f,
288                                 /* pitch envelope */
289                                     PEFE_PITCHAMOUNT, 0, TAGLIST_END);
290
291                 voice->params[i].fc_target = 0xffff;
292         }
293 }
294
295 void emu10k1_voices_start(struct emu_voice *first_voice, unsigned int num_voices, int set)
296 {
297         struct emu10k1_card *card = first_voice->card;
298         struct emu_voice *voice;
299         unsigned int voicenum;
300         int j;
301
302         DPF(2, "emu10k1_voices_start()\n");
303
304         for (voicenum = 0; voicenum < num_voices; voicenum++)
305         {
306                 voice = first_voice + voicenum;
307
308                 if (!set) {
309                         u32 cra, ccis, cs, sample;
310                         if (voice->flags & VOICE_FLAGS_STEREO) {
311                                 cra = 64;
312                                 ccis = 28;
313                                 cs = 4;
314                         } else {
315                                 cra = 64;
316                                 ccis = 30;
317                                 cs = 2;
318                         }
319
320                         if(voice->flags & VOICE_FLAGS_16BIT) {
321                                 sample = 0x00000000;
322                         } else {
323                                 sample = 0x80808080;            
324                                 ccis *= 2;
325                         }
326
327                         for(j = 0; j < cs; j++)
328                                 sblive_writeptr(card, CD0 + j, voice->num, sample);
329
330                         /* Reset cache */
331                         sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, 0);
332                         if (voice->flags & VOICE_FLAGS_STEREO)
333                                 sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num + 1, 0);
334
335                         sblive_writeptr(card, CCR_READADDRESS, voice->num, cra);
336
337                         if (voice->flags & VOICE_FLAGS_STEREO)
338                                 sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra);
339
340                         /* Fill cache */
341                         sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis);
342                 }
343
344                 for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
345                         sblive_writeptr_tag(card, voice->num + j,
346                                     IFATN, (voice->params[j].initial_fc << 8) | voice->params[j].initial_attn,
347                                     VTFT, (voice->params[j].volume_target << 16) | voice->params[j].fc_target,
348                                     CVCF, (voice->params[j].volume_target << 16) | voice->params[j].fc_target,
349                                     DCYSUSV, (voice->params[j].byampl_env_sustain << 8) | voice->params[j].byampl_env_decay,
350                                     TAGLIST_END);
351         
352                         emu10k1_clear_stop_on_loop(card, voice->num + j);
353                 }
354         }
355
356
357         for (voicenum = 0; voicenum < num_voices; voicenum++)
358         {
359                 voice = first_voice + voicenum;
360
361                 for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
362                         sblive_writeptr(card, PTRX_PITCHTARGET, voice->num + j, voice->pitch_target);
363
364                         if (j == 0)
365                                 sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->pitch_target);
366
367                         sblive_writeptr(card, IP, voice->num + j, voice->initial_pitch);
368                 }
369         }
370 }
371
372 void emu10k1_voices_stop(struct emu_voice *first_voice, int num_voices)
373 {
374         struct emu10k1_card *card = first_voice->card;
375         struct emu_voice *voice;
376         unsigned int voice_num;
377         int j;
378
379         DPF(2, "emu10k1_voice_stop()\n");
380
381         for (voice_num = 0; voice_num < num_voices; voice_num++)
382         {
383                 voice = first_voice + voice_num;
384
385                 for (j = 0; j < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); j++) {
386                         sblive_writeptr_tag(card, voice->num + j,
387                                                 PTRX_PITCHTARGET, 0,
388                                                 CPF_CURRENTPITCH, 0,
389                                                 IFATN, 0xffff,
390                                                 VTFT, 0x0000ffff,
391                                                 CVCF, 0x0000ffff,
392                                                 IP, 0,
393                                                 TAGLIST_END);
394                 }
395         }
396 }
397