Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 
399 
  This page was automatically generated by the LXR engine.