Linux 2.6.19-rc1
[linux-2.6/next.git] / sound / oss / emu10k1 / voicemgr.c
blobd88b602c07c2cf73909cd953eda40704e33416ca
1 /*
2 **********************************************************************
3 * voicemgr.c - Voice manager for emu10k1 driver
4 * Copyright 1999, 2000 Creative Labs, Inc.
6 **********************************************************************
8 * Date Author Summary of changes
9 * ---- ------ ------------------
10 * October 20, 1999 Bertrand Lee base code release
12 **********************************************************************
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.
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.
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.
29 **********************************************************************
32 #include "voicemgr.h"
33 #include "8010.h"
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
42 static u32 emu10k1_select_interprom(struct emu10k1_card *card,
43 struct emu_voice *voice)
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;
64 /**
65 * emu10k1_voice_alloc_buffer -
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.
72 int emu10k1_voice_alloc_buffer(struct emu10k1_card *card, struct voice_mem *mem, u32 pages)
74 u32 pageindex, pagecount;
75 u32 busaddx;
76 int i;
78 DPD(2, "requested pages is: %d\n", pages);
80 if ((mem->emupageindex = emu10k1_addxmgr_alloc(pages * PAGE_SIZE, card)) < 0)
82 DPF(1, "couldn't allocate emu10k1 address space\n");
83 return -1;
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;
95 DPD(2, "Virtual Addx: %p\n", mem->addr[pagecount]);
97 for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
98 busaddx = (u32) mem->dma_handle[pagecount] + i * EMUPAGESIZE;
100 DPD(3, "Bus Addx: %#x\n", busaddx);
102 pageindex = mem->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
104 ((u32 *) card->virtualpagetable.addr)[pageindex] = cpu_to_le32((busaddx * 2) | pageindex);
108 mem->pages = pagecount;
110 return 0;
114 * emu10k1_voice_free_buffer -
116 * frees the memory buffer for a voice.
118 void emu10k1_voice_free_buffer(struct emu10k1_card *card, struct voice_mem *mem)
120 u32 pagecount, pageindex;
121 int i;
123 if (mem->emupageindex < 0)
124 return;
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]);
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);
138 emu10k1_addxmgr_free(card, mem->emupageindex);
139 mem->emupageindex = -1;
142 int emu10k1_voice_alloc(struct emu10k1_card *card, struct emu_voice *voice)
144 u8 *voicetable = card->voicetable;
145 int i;
146 unsigned long flags;
148 DPF(2, "emu10k1_voice_alloc()\n");
150 spin_lock_irqsave(&card->lock, flags);
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;
159 } else {
160 for (i = 0; i < NUM_G; i++)
161 if (voicetable[i] == VOICE_USAGE_FREE) {
162 voicetable[i] = voice->usage;
163 break;
167 spin_unlock_irqrestore(&card->lock, flags);
169 if (i >= NUM_G)
170 return -1;
172 voice->card = card;
173 voice->num = i;
175 for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
176 DPD(2, " voice allocated -> %d\n", voice->num + i);
178 sblive_writeptr_tag(card, voice->num + i, IFATN, 0xffff,
179 DCYSUSV, 0,
180 VTFT, 0x0000ffff,
181 PTRX, 0,
182 TAGLIST_END);
185 return 0;
188 void emu10k1_voice_free(struct emu_voice *voice)
190 struct emu10k1_card *card = voice->card;
191 int i;
192 unsigned long flags;
194 DPF(2, "emu10k1_voice_free()\n");
196 if (voice->usage == VOICE_USAGE_FREE)
197 return;
199 for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
200 DPD(2, " voice released -> %d\n", voice->num + i);
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);
209 sblive_writeptr(card, CPF, voice->num + i, 0);
212 voice->usage = VOICE_USAGE_FREE;
214 spin_lock_irqsave(&card->lock, flags);
216 card->voicetable[voice->num] = VOICE_USAGE_FREE;
218 if (voice->flags & VOICE_FLAGS_STEREO)
219 card->voicetable[voice->num + 1] = VOICE_USAGE_FREE;
221 spin_unlock_irqrestore(&card->lock, flags);
224 void emu10k1_voice_playback_setup(struct emu_voice *voice)
226 struct emu10k1_card *card = voice->card;
227 u32 start;
228 int i;
230 DPF(2, "emu10k1_voice_playback_setup()\n");
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);
242 if(!(voice->flags & VOICE_FLAGS_16BIT))
243 start *= 2;
245 voice->start += start;
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);
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));
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);
292 voice->params[i].fc_target = 0xffff;
296 void emu10k1_voices_start(struct emu_voice *first_voice, unsigned int num_voices, int set)
298 struct emu10k1_card *card = first_voice->card;
299 struct emu_voice *voice;
300 unsigned int voicenum;
301 int j;
303 DPF(2, "emu10k1_voices_start()\n");
305 for (voicenum = 0; voicenum < num_voices; voicenum++)
307 voice = first_voice + voicenum;
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;
321 if(voice->flags & VOICE_FLAGS_16BIT) {
322 sample = 0x00000000;
323 } else {
324 sample = 0x80808080;
325 ccis *= 2;
328 for(j = 0; j < cs; j++)
329 sblive_writeptr(card, CD0 + j, voice->num, sample);
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);
336 sblive_writeptr(card, CCR_READADDRESS, voice->num, cra);
338 if (voice->flags & VOICE_FLAGS_STEREO)
339 sblive_writeptr(card, CCR_READADDRESS, voice->num + 1, cra);
341 /* Fill cache */
342 sblive_writeptr(card, CCR_CACHEINVALIDSIZE, voice->num, ccis);
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);
353 emu10k1_clear_stop_on_loop(card, voice->num + j);
358 for (voicenum = 0; voicenum < num_voices; voicenum++)
360 voice = first_voice + voicenum;
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);
365 if (j == 0)
366 sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->pitch_target);
368 sblive_writeptr(card, IP, voice->num + j, voice->initial_pitch);
373 void emu10k1_voices_stop(struct emu_voice *first_voice, int num_voices)
375 struct emu10k1_card *card = first_voice->card;
376 struct emu_voice *voice;
377 unsigned int voice_num;
378 int j;
380 DPF(2, "emu10k1_voice_stop()\n");
382 for (voice_num = 0; voice_num < num_voices; voice_num++)
384 voice = first_voice + voice_num;
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);