]> git.ipfire.org Git - thirdparty/linux.git/blob - sound/oss/emu10k1/voicemgr.c
Linux-2.6.12-rc2
[thirdparty/linux.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 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