source: cmedia/trunk/Sblive/cardwo.c@ 354

Last change on this file since 354 was 354, checked in by stevenhl, 17 years ago

Import untested baseline cmedia sources, work products and binaries
Binaries and work products should be deleted from repository.
once new builds are verified to work.

File size: 21.6 KB
Line 
1/* $Id: cardwo.c,v 1.3 2000/07/23 16:21:57 sandervl Exp $ */
2
3/*
4 **********************************************************************
5 * cardwo.c - PCM output HAL for emu10k1 driver
6 * Copyright 1999, 2000 Creative Labs, Inc.
7 *
8 **********************************************************************
9 *
10 * Date Author Summary of changes
11 * ---- ------ ------------------
12 * October 20, 1999 Bertrand Lee base code release
13 *
14 **********************************************************************
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License as
18 * published by the Free Software Foundation; either version 2 of
19 * the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public
27 * License along with this program; if not, write to the Free
28 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
29 * USA.
30 *
31 **********************************************************************
32 */
33
34#include "hwaccess.h"
35#include "cardwo.h"
36#include "audio.h"
37
38/* Volume calcs */
39
40static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left)
41{
42 /* only applicable for playback */
43 u32 volL, volR, vol = 0;
44
45 volL = (wave_out->localvol & 0xffff);
46 volR = ((wave_out->localvol >> 16) & 0xffff);
47
48 if (wave_out->globalvolFactor) {
49 volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff;
50 volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff;
51 }
52
53 /* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */
54 /* New volume and pan */
55
56 if (volL == volR) {
57 vol = volL;
58 left->send_c = 0xff;
59 left->send_b = 0xff;
60 } else {
61 if (volL > volR) {
62 vol = volL;
63 left->send_c = 0xff;
64 left->send_b = (char) ((volR * 255) / vol);
65 } else {
66 vol = volR;
67 left->send_b = 0xff;
68 left->send_c = (char) ((volL * 255) / vol);
69 }
70 }
71
72 left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2);
73
74 return vol;
75}
76
77static void query_format(struct wave_format *wave_fmt)
78{
79 if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
80 wave_fmt->channels = 2;
81
82 if (wave_fmt->samplingrate >= 0x2EE00)
83 wave_fmt->samplingrate = 0x2EE00;
84
85 if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16))
86 wave_fmt->bitsperchannel = 16;
87
88 return;
89}
90
91static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer)
92{
93 u32 numpages, reqsize, pageindex, pagecount;
94 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
95 unsigned long busaddx;
96 int i;
97
98 reqsize = *size;
99 numpages = reqsize / PAGE_SIZE;
100
101 /* If size is not a multiple of PAGE_SIZE then we need to round up */
102 if (reqsize % PAGE_SIZE)
103 numpages += 1;
104
105 DPD(2, "requested pages is: %d\n", numpages);
106
107 wavexferbuf->numpages = numpages;
108
109 /* Only for playback, request for emu address space */
110 /* Support non page-aligned buffer, don't need interpolation page */
111
112 if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0)
113 return CTSTATUS_ERROR;
114
115 if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL)
116 return CTSTATUS_ERROR;
117
118 /* Fill in virtual memory table */
119 for (pagecount = 0; pagecount < numpages; pagecount++) {
120 if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) {
121 wavexferbuf->numpages = pagecount;
122 return CTSTATUS_ERROR;
123 }
124
125 DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]);
126
127 for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
128 busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE);
129
130 DPD(3, "Bus Addx: %lx\n", busaddx);
131
132 pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
133
134 ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex;
135 }
136 }
137
138 *buffer = wave_out->pagetable;
139
140 return CTSTATUS_SUCCESS;
141}
142
143static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size)
144{
145 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
146 void **buffer;
147
148 wavexferbuf->xferpos = 0;
149 wavexferbuf->silence_xferpos = 0;
150 wavexferbuf->stopposition = 0;
151 wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
152 wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
153 wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
154
155 if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS)
156 return CTSTATUS_ERROR;
157
158 /* xferbufsize contains actual transfer buffer size */
159 wavexferbuf->xferbufsize = *size;
160 wavexferbuf->xferbuffer = buffer;
161
162 return CTSTATUS_SUCCESS;
163}
164
165static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out)
166{
167 u32 pagecount, pageindex;
168 int i;
169
170 if (wave_out->pagetable != NULL) {
171 for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) {
172 free_page((unsigned long) wave_out->pagetable[pagecount]);
173
174 for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
175 pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
176 ((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex;
177 }
178 }
179 kfree(wave_out->pagetable);
180 }
181
182 emu10k1_addxmgr_free(card, wave_out->emupageindex);
183
184 return;
185}
186
187static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device)
188{
189 struct emu10k1_waveout *card_waveout = card->waveout;
190 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
191 struct voice_allocdesc voice_allocdesc;
192 struct voice_param *left, *right;
193 u32 size;
194
195 /* Allocate voices here, if no voices available, return error.
196 * Init voice_allocdesc first.*/
197
198 voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK;
199
200 voice_allocdesc.flags = 0;
201
202 if (device == 1)
203 voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2;
204
205 if (wave_out->wave_fmt.channels == 1)
206 voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO;
207
208 if (wave_out->wave_fmt.bitsperchannel == 16)
209 voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT;
210
211 if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL)
212 return CTSTATUS_ERROR;
213
214 /* voice initialization */
215
216 left = &wave_out->voice->params;
217
218 /* Calculate pitch */
219 left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8);
220
221 DPD(2, "Initial pitch --> %x\n", left->initial_pitch);
222
223 /* Easy way out.. gotta calculate value */
224 left->pitch_target = 0;
225 left->volume_target = 0;
226 left->FC_target = 0;
227
228 left->byampl_env_sustain = 0x7f;
229 left->byampl_env_decay = 0x7f;
230
231 if (wave_out->globalreverbFactor) {
232 u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff);
233
234 left->send_a = (t > 255) ? 255 : t;
235 } else {
236 left->send_a = 0;
237 }
238
239 if (wave_out->globalchorusFactor) {
240 u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff);
241
242 left->send_d = (t > 255) ? 255 : t;
243 } else {
244 left->send_d = 0;
245 }
246
247 set_volume_instance(card_waveout, wave_out, left);
248
249 left->pan_target = left->send_c;
250 left->aux_target = left->send_b;
251
252 size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample;
253 left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample;
254 left->end = left->start + size;
255 left->startloop = left->start;
256 left->endloop = left->end;
257
258 if (wave_out->voice->linked_voice) {
259 DPF(2, "is stereo\n");
260 right = &wave_out->voice->linked_voice->params;
261
262 right->initial_pitch = left->initial_pitch;
263
264 /* Easy way out.. gotta calculate value */
265 right->pitch_target = 0;
266 right->volume_target = 0;
267 right->FC_target = 0;
268
269 right->byampl_env_sustain = 0x7f;
270 right->byampl_env_decay = 0x7f;
271
272 right->send_d = left->send_d;
273 right->send_a = left->send_a;
274
275 /* Left output of right channel is always zero */
276 right->send_c = 0;
277
278 /* Update right channel aux */
279 right->pan_target = 0;
280 right->send_b = left->send_b;
281 right->aux_target = right->send_b;
282
283 /* Zero out right output of left channel */
284 left->send_b = 0;
285 left->aux_target = 0;
286
287 /* Update right channel attenuation */
288 right->initial_attn = left->initial_attn;
289
290 right->start = left->start;
291 right->end = left->end;
292 right->startloop = left->startloop;
293 right->endloop = left->endloop;
294
295 }
296
297 DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop);
298
299 return CTSTATUS_SUCCESS;
300}
301
302int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
303{
304 struct emu10k1_card *card = wave_dev->card;
305 struct woinst *woinst = wave_dev->woinst;
306 struct wave_out *wave_out;
307 u32 bytespersec, delay;
308 u32 buffsize;
309
310 DPF(2, "emu10k1_waveout_open()\n");
311
312 if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) {
313 ERROR();
314 emu10k1_waveout_close(wave_dev);
315 return CTSTATUS_ERROR;
316 }
317
318 woinst->wave_out = wave_out;
319
320 /* Init channel object */
321 wave_out->state = CARDWAVE_STATE_STOPPED;
322 wave_out->wave_fmt = woinst->wave_fmt;
323 wave_out->voice = NULL;
324 wave_out->emupageindex = -1;
325 wave_out->wavexferbuf = NULL;
326 wave_out->pagetable = NULL;
327 wave_out->timer = NULL;
328
329 /* Assign default local volume */
330 /* FIXME: Should we be maxing the initial values like this? */
331 wave_out->localvol = 0xffffffff;
332 wave_out->localreverb = 0xffffffff;
333 wave_out->localchorus = 0xffffffff;
334 wave_out->globalvolFactor = 0xffff;
335 wave_out->globalreverbFactor = 0xffff;
336 wave_out->globalchorusFactor = 0xffff;
337
338 wave_out->setpos = 0;
339 wave_out->position = 0;
340
341 wave_out->fill_silence = 0;
342
343 if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) {
344 ERROR();
345 emu10k1_waveout_close(wave_dev);
346 return CTSTATUS_ERROR;
347 }
348
349 buffsize = woinst->fragment_size * woinst->numfrags;
350
351 if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) {
352 ERROR();
353 emu10k1_waveout_close(wave_dev);
354 return CTSTATUS_ERROR;
355 }
356
357 woinst->fragment_size = buffsize / woinst->numfrags;
358 wave_out->callbacksize = woinst->fragment_size;
359
360 if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
361 ERROR();
362 emu10k1_waveout_close(wave_dev);
363 return CTSTATUS_ERROR;
364 }
365
366 bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
367 delay = (48000 * wave_out->callbacksize) / bytespersec;
368
369 if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
370 ERROR();
371 emu10k1_waveout_close(wave_dev);
372 return CTSTATUS_ERROR;
373 }
374
375 return CTSTATUS_SUCCESS;
376}
377
378void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev)
379{
380 struct emu10k1_card *card = wave_dev->card;
381 struct wave_out *wave_out = wave_dev->woinst->wave_out;
382
383 DPF(2, "emu10k1_waveout_close()\n");
384
385 if (wave_out->state != CARDWAVE_STATE_STOPPED)
386 emu10k1_waveout_stop(wave_dev);
387
388 if (wave_out->timer != NULL)
389 emu10k1_timer_uninstall(card, wave_out->timer);
390
391 if (wave_out->voice != NULL)
392 emu10k1_voice_free(&card->voicemgr, wave_out->voice);
393
394 if (wave_out->emupageindex >= 0)
395 dealloc_xferbuffer(card, wave_out);
396
397 if (wave_out->wavexferbuf != NULL)
398 kfree(wave_out->wavexferbuf);
399
400 kfree(wave_out);
401 wave_dev->woinst->wave_out = NULL;
402
403 return;
404}
405
406int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
407{
408 struct emu10k1_card *card = wave_dev->card;
409 struct wave_out *wave_out = wave_dev->woinst->wave_out;
410 u32 start, startPosition;
411
412 DPF(2, "emu10k1_waveout_start()\n");
413
414 /* If already started, return success */
415 if (wave_out->state == CARDWAVE_STATE_STARTED)
416 return CTSTATUS_SUCCESS;
417
418 if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos)
419 startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample);
420 else
421 startPosition = wave_out->wavexferbuf->stopposition;
422
423 start = wave_out->voice->params.start;
424 wave_out->voice->params.start += startPosition;
425
426 DPD(2, "CA is %x\n", wave_out->voice->params.start);
427
428 emu10k1_voice_playback_setup(wave_out->voice);
429
430 wave_out->voice->params.start = start;
431
432 /* Actual start */
433 emu10k1_voice_start(wave_out->voice);
434
435 wave_out->state = CARDWAVE_STATE_STARTED;
436 wave_out->setpos = 0;
437
438 emu10k1_timer_enable(card, wave_out->timer);
439
440 return CTSTATUS_SUCCESS;
441}
442
443int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev)
444{
445 struct emu10k1_card *card = wave_dev->card;
446 struct woinst *woinst = wave_dev->woinst;
447 struct wave_out *wave_out = woinst->wave_out;
448 u32 bytespersec, delay;
449
450 DPF(2, "emu10k1_waveout_setformat()\n");
451
452 query_format(&woinst->wave_fmt);
453
454 if (wave_out == NULL)
455 return CTSTATUS_SUCCESS;
456
457 if (wave_out->state == CARDWAVE_STATE_STARTED) {
458 woinst->wave_fmt = wave_out->wave_fmt;
459 return CTSTATUS_SUCCESS;
460 }
461
462 if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate)
463 || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel)
464 || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) {
465 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
466
467 emu10k1_timer_uninstall(card, wave_out->timer);
468
469 emu10k1_voice_free(&card->voicemgr, wave_out->voice);
470
471 wave_out->wave_fmt = woinst->wave_fmt;
472 wave_out->timer = NULL;
473
474 wavexferbuf->xferpos = 0;
475 wavexferbuf->silence_xferpos = 0;
476 wavexferbuf->stopposition = 0;
477 wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
478 wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
479 wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
480
481 if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
482 ERROR();
483 emu10k1_waveout_close(wave_dev);
484 return CTSTATUS_ERROR;
485 }
486
487 bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
488 delay = (48000 * wave_out->callbacksize) / bytespersec;
489
490 if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
491 ERROR();
492 emu10k1_waveout_close(wave_dev);
493 return CTSTATUS_ERROR;
494 }
495 }
496
497 return CTSTATUS_SUCCESS;
498}
499
500void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev)
501{
502 struct emu10k1_card *card = wave_dev->card;
503 struct wave_out *wave_out = wave_dev->woinst->wave_out;
504 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
505 u32 samples = 32;
506 u32 position;
507
508 DPF(2, "emu10k1_waveout_stop()\n");
509
510 if (wave_out->state == CARDWAVE_STATE_STOPPED)
511 return;
512
513 emu10k1_timer_disable(card, wave_out->timer);
514
515 /* Stop actual voice */
516 emu10k1_voice_stop(wave_out->voice);
517
518 /* Save the stop position */
519 emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition);
520 wavexferbuf->stopposition -= wave_out->voice->params.start;
521#ifdef TARGET_OS2
522 wavexferbuf->stopposition &= CCCA_CURRADDR_MASK; //SvL: mask off CCCA_8BITSELECT
523#endif
524
525 /* Refer to voicemgr.c, CA is not started at zero. We need to take this into account. */
526 position = wavexferbuf->stopposition * wavexferbuf->bytespersample;
527
528 if (!wavexferbuf->is_16bit)
529 samples <<= 1;
530
531 if (wavexferbuf->is_stereo)
532 samples <<= 1;
533
534 samples -= 4;
535
536 if (position >= samples * (wavexferbuf->is_16bit + 1))
537 position -= samples * (wavexferbuf->is_16bit + 1);
538 else
539 position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1);
540
541 wavexferbuf->stopposition = position / wavexferbuf->bytespersample;
542
543 DPD(2, "position is %x\n", wavexferbuf->stopposition);
544
545 wave_out->state = CARDWAVE_STATE_STOPPED;
546 wave_out->setpos = 0;
547 wave_out->position = 0;
548
549 return;
550}
551
552void emu10k1_waveout_getxfersize(struct woinst *woinst, u32 * size)
553{
554 struct wave_out *wave_out = woinst->wave_out;
555 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
556 u32 curpos = woinst->curpos;
557 u32 pending;
558
559 if ((curpos > wavexferbuf->silence_xferpos)
560 || ((curpos == wavexferbuf->silence_xferpos)
561 && (wave_out->state == CARDWAVE_STATE_STARTED))
562 || ((curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0)
563 && (wave_out->state == CARDWAVE_STATE_STOPPED))) {
564 *size = curpos - wavexferbuf->silence_xferpos;
565 } else {
566 *size = curpos - wavexferbuf->silence_xferpos + wavexferbuf->xferbufsize;
567 }
568
569 pending = wavexferbuf->xferbufsize - *size;
570
571 wave_out->fill_silence = (pending < wave_out->callbacksize) ? 1 : 0;
572
573 if (pending > woinst->silence_bytes) {
574 *size += woinst->silence_bytes;
575 } else {
576 *size = wavexferbuf->xferbufsize;
577 wavexferbuf->xferpos = curpos;
578 }
579
580 return;
581}
582
583static void copy_block(u32 dst, u8 * src, u32 len, void **pt)
584{
585 int i, j, k;
586
587 i = dst / PAGE_SIZE;
588 j = dst % PAGE_SIZE;
589 k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
590#ifdef TARGET_OS2
591 copy_from_user((u8 *)pt[i] + j, src, k);
592#else
593 copy_from_user(pt[i] + j, src, k);
594#endif
595 len -= k;
596 while (len >= PAGE_SIZE) {
597 copy_from_user(pt[++i], src + k, PAGE_SIZE);
598 k += PAGE_SIZE;
599 len -= PAGE_SIZE;
600 }
601 copy_from_user(pt[++i], src + k, len);
602
603 return;
604}
605
606static void fill_block(u32 dst, u8 val, u32 len, void **pt)
607{
608 int i, j, k;
609
610 i = dst / PAGE_SIZE;
611 j = dst % PAGE_SIZE;
612 k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
613#ifdef TARGET_OS2
614 if(k) {
615 memset((u8 *)pt[i] + j, val, k);
616 }
617#else
618 memset(pt[i] + j, val, k);
619#endif
620 len -= k;
621 while (len >= PAGE_SIZE) {
622 memset(pt[++i], val, PAGE_SIZE);
623 len -= PAGE_SIZE;
624 }
625#ifdef TARGET_OS2
626 if(len)
627#endif
628 memset(pt[++i], val, len);
629
630 return;
631}
632
633void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size)
634{
635 struct wave_out *wave_out = woinst->wave_out;
636 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
637 u32 sizetocopy, sizetocopy_now, start;
638 unsigned long flags;
639
640 sizetocopy = min(wavexferbuf->xferbufsize, *size);
641 *size = sizetocopy;
642
643 if (!sizetocopy)
644 return;
645
646 spin_lock_irqsave(&woinst->lock, flags);
647 woinst->silence_bytes = 0;
648 sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos;
649
650 start = wavexferbuf->xferpos;
651
652 if (sizetocopy > sizetocopy_now) {
653 sizetocopy -= sizetocopy_now;
654 wavexferbuf->xferpos = sizetocopy;
655 wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
656 spin_unlock_irqrestore(&woinst->lock, flags);
657
658 copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer);
659 copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer);
660 } else {
661 if (sizetocopy == sizetocopy_now)
662 wavexferbuf->xferpos = 0;
663 else
664 wavexferbuf->xferpos += sizetocopy;
665
666 wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
667 spin_unlock_irqrestore(&woinst->lock, flags);
668
669 copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer);
670 }
671
672 return;
673}
674
675void emu10k1_waveout_fillsilence(struct woinst *woinst)
676{
677 struct wave_out *wave_out = woinst->wave_out;
678 struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
679 u16 filldata;
680 u32 sizetocopy, sizetocopy_now, start;
681 unsigned long flags;
682
683 sizetocopy = wave_out->callbacksize;
684
685 if (wave_out->wave_fmt.bitsperchannel == 8)
686 filldata = 0x8080;
687 else
688 filldata = 0x0000;
689
690 spin_lock_irqsave(&woinst->lock, flags);
691 woinst->silence_bytes += sizetocopy;
692 sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos;
693 start = wavexferbuf->silence_xferpos;
694
695 if (sizetocopy > sizetocopy_now) {
696 sizetocopy -= sizetocopy_now;
697 wavexferbuf->silence_xferpos = sizetocopy;
698 spin_unlock_irqrestore(&woinst->lock, flags);
699 fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer);
700 fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer);
701 } else {
702 if (sizetocopy == sizetocopy_now)
703 wavexferbuf->silence_xferpos = 0;
704 else
705 wavexferbuf->silence_xferpos += sizetocopy;
706
707 spin_unlock_irqrestore(&woinst->lock, flags);
708
709 fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer);
710 }
711
712 return;
713}
714
715void emu10k1_waveout_update(struct woinst *woinst)
716{
717 struct wave_out *wave_out = woinst->wave_out;
718 u32 curpos;
719
720 /* There is no actual start yet */
721 if (wave_out->state == CARDWAVE_STATE_STOPPED) {
722 if (wave_out->setpos)
723 curpos = wave_out->position;
724 else
725 curpos = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample;
726 } else {
727 u32 samples;
728
729 emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &curpos);
730 curpos -= wave_out->voice->params.start;
731#ifdef TARGET_OS2
732 curpos &= CCCA_CURRADDR_MASK; //SvL: mask off CCCA_8BITSELECT
733#endif
734
735 /* Get number of bytes in play buffer per channel.
736 * If 8 bit mode is enabled, this needs to be changed. */
737 curpos *= wave_out->wavexferbuf->bytespersample;
738
739 /* Refer to voicemgr.c, CA is not started at zero.
740 * We need to take this into account. */
741 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1) - 4 * (wave_out->wavexferbuf->is_16bit + 1);
742
743 if (curpos >= samples)
744 curpos -= samples;
745 else
746 curpos += wave_out->wavexferbuf->xferbufsize - samples;
747 }
748
749 woinst->total_played += curpos - woinst->curpos;
750
751 if (curpos < woinst->curpos)
752 woinst->total_played += woinst->fragment_size * woinst->numfrags;
753
754 woinst->curpos = curpos;
755
756 return;
757}
Note: See TracBrowser for help on using the repository browser.