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