dec21140A ethernet driver for virtualpc, contributed by nicolas tittley.
[minix.git] / drivers / sb16 / sb16_dsp.c
blobd4ade9fb072948b095e15f0c8a73e429d38c8d66
1 /* This file contains the driver for a DSP (Digital Sound Processor) on
2 * a SoundBlaster 16 soundcard.
4 * The driver supports the following operations (using message format m2):
6 * m_type DEVICE IO_ENDPT COUNT POSITION ADRRESS
7 * ----------------------------------------------------------------
8 * | DEV_OPEN | device | proc nr | | | |
9 * |------------+---------+---------+---------+---------+---------|
10 * | DEV_CLOSE | device | proc nr | | | |
11 * |------------+---------+---------+---------+---------+---------|
12 * | DEV_READ | device | proc nr | bytes | | buf ptr |
13 * |------------+---------+---------+---------+---------+---------|
14 * | DEV_WRITE | device | proc nr | bytes | | buf ptr |
15 * |------------+---------+---------+---------+---------+---------|
16 * | DEV_IOCTL | device | proc nr |func code| | buf ptr |
17 * ----------------------------------------------------------------
19 * The file contains one entry point:
21 * main: main entry when driver is brought up
23 * August 24 2005 Ported driver to user space (only audio playback) (Peter Boonstoppel)
24 * May 20 1995 Author: Michel R. Prevenier
27 #include <minix/endpoint.h>
28 #include "sb16.h"
31 _PROTOTYPE(void main, (void));
32 FORWARD _PROTOTYPE( int dsp_open, (void) );
33 FORWARD _PROTOTYPE( int dsp_close, (void) );
34 FORWARD _PROTOTYPE( int dsp_ioctl, (message *m_ptr) );
35 FORWARD _PROTOTYPE( void dsp_write, (message *m_ptr) );
36 FORWARD _PROTOTYPE( void dsp_hardware_msg, (void) );
37 FORWARD _PROTOTYPE( void dsp_status, (message *m_ptr) );
39 FORWARD _PROTOTYPE( void reply, (int code, int replyee, int process, int status) );
40 FORWARD _PROTOTYPE( int dsp_init, (void) );
41 FORWARD _PROTOTYPE( int dsp_reset, (void) );
42 FORWARD _PROTOTYPE( int dsp_command, (int value) );
43 FORWARD _PROTOTYPE( int dsp_set_size, (unsigned int size) );
44 FORWARD _PROTOTYPE( int dsp_set_speed, (unsigned int speed) );
45 FORWARD _PROTOTYPE( int dsp_set_stereo, (unsigned int stereo) );
46 FORWARD _PROTOTYPE( int dsp_set_bits, (unsigned int bits) );
47 FORWARD _PROTOTYPE( int dsp_set_sign, (unsigned int sign) );
48 FORWARD _PROTOTYPE( void dsp_dma_setup, (phys_bytes address, int count) );
49 FORWARD _PROTOTYPE( void dsp_setup, (void) );
51 PRIVATE int irq_hook_id; /* id of irq hook at the kernel */
53 PRIVATE char DmaBuffer[DMA_SIZE + 64 * 1024];
54 PRIVATE char* DmaPtr;
55 PRIVATE phys_bytes DmaPhys;
57 PRIVATE char Buffer[DSP_MAX_FRAGMENT_SIZE * DSP_NR_OF_BUFFERS];
59 PRIVATE int DspVersion[2];
60 PRIVATE unsigned int DspStereo = DEFAULT_STEREO;
61 PRIVATE unsigned int DspSpeed = DEFAULT_SPEED;
62 PRIVATE unsigned int DspBits = DEFAULT_BITS;
63 PRIVATE unsigned int DspSign = DEFAULT_SIGN;
64 PRIVATE unsigned int DspFragmentSize = DSP_MAX_FRAGMENT_SIZE;
65 PRIVATE int DspAvail = 0;
66 PRIVATE int DspBusy = 0;
67 PRIVATE int DmaMode = 0;
68 PRIVATE int DmaBusy = -1;
69 PRIVATE int DmaFillNext = 0;
70 PRIVATE int BufReadNext = -1;
71 PRIVATE int BufFillNext = 0;
73 PRIVATE int revivePending = 0;
74 PRIVATE int reviveStatus;
75 PRIVATE int reviveProcNr;
77 #define dprint (void)
79 /* SEF functions and variables. */
80 FORWARD _PROTOTYPE( void sef_local_startup, (void) );
81 FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
82 EXTERN _PROTOTYPE( void sef_cb_lu_prepare, (int state) );
83 EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
84 EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
85 PUBLIC int is_processing = FALSE;
86 PUBLIC int is_status_msg_expected = FALSE;
88 /*===========================================================================*
89 * main
90 *===========================================================================*/
91 PUBLIC void main()
93 int r, caller, proc_nr;
94 message mess;
96 /* SEF local startup. */
97 sef_local_startup();
99 while(TRUE) {
100 /* Wait for an incoming message */
101 sef_receive(ANY, &mess);
103 caller = mess.m_source;
104 proc_nr = mess.IO_ENDPT;
106 if (is_notify(mess.m_type)) {
107 switch (_ENDPOINT_P(mess.m_source)) {
108 case HARDWARE:
109 dsp_hardware_msg();
110 continue; /* don't reply */
111 case SYSTEM:
112 continue; /* don't reply */
113 default:
114 r = EINVAL;
117 /* dont with this message */
118 goto send_reply;
121 /* Now carry out the work. */
122 switch(mess.m_type) {
123 case DEV_OPEN: r = dsp_open(); break;
124 case DEV_CLOSE: r = dsp_close(); break;
125 #ifdef DEV_IOCTL
126 case DEV_IOCTL: r = dsp_ioctl(&mess); break;
127 #endif
128 #ifdef DEV_READ
130 case DEV_READ: r = EINVAL; break; /* Not yet implemented */
131 case DEV_WRITE: dsp_write(&mess); continue; /* don't reply */
132 #endif
134 case DEV_STATUS: dsp_status(&mess); continue; /* don't reply */
135 default: r = EINVAL;
138 send_reply:
139 /* Finally, prepare and send the reply message. */
140 reply(TASK_REPLY, caller, proc_nr, r);
145 /*===========================================================================*
146 * sef_local_startup *
147 *===========================================================================*/
148 PRIVATE void sef_local_startup()
150 /* Register init callbacks. */
151 sef_setcb_init_fresh(sef_cb_init_fresh);
152 sef_setcb_init_lu(sef_cb_init_fresh);
153 sef_setcb_init_restart(sef_cb_init_fresh);
155 /* Register live update callbacks. */
156 sef_setcb_lu_prepare(sef_cb_lu_prepare);
157 sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
158 sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
160 /* Let SEF perform startup. */
161 sef_startup();
164 /*===========================================================================*
165 * sef_cb_init_fresh *
166 *===========================================================================*/
167 PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
169 /* Initialize the rtl8169 driver. */
170 unsigned left;
172 /* Select a buffer that can safely be used for dma transfers.
173 * Its absolute address is 'DmaPhys', the normal address is 'DmaPtr'.
175 #if (CHIP == INTEL)
176 DmaPtr = DmaBuffer;
177 sys_umap(SELF, D, (vir_bytes)DmaBuffer, (phys_bytes)sizeof(DmaBuffer), &DmaPhys);
179 if((left = dma_bytes_left(DmaPhys)) < DMA_SIZE) {
180 /* First half of buffer crosses a 64K boundary, can't DMA into that */
181 DmaPtr += left;
182 DmaPhys += left;
184 #else /* CHIP != INTEL */
185 panic("SB16DSP","initialization failed, CHIP != INTEL", 0);
186 #endif /* CHIP == INTEL */
188 return(OK);
191 /*===========================================================================*
192 * dsp_open
193 *===========================================================================*/
194 PRIVATE int dsp_open()
196 dprint("sb16_dsp.c: dsp_open()\n");
198 /* try to detect SoundBlaster card */
199 if(!DspAvail && dsp_init() != OK) return EIO;
201 /* Only one open at a time with soundcards */
202 if(DspBusy) return EBUSY;
204 /* Start with a clean DSP */
205 if(dsp_reset() != OK) return EIO;
207 /* Setup default values */
208 DspStereo = DEFAULT_STEREO;
209 DspSpeed = DEFAULT_SPEED;
210 DspBits = DEFAULT_BITS;
211 DspSign = DEFAULT_SIGN;
212 DspFragmentSize = DMA_SIZE / 2;
214 DspBusy = 1;
216 return OK;
220 /*===========================================================================*
221 * dsp_close
222 *===========================================================================*/
223 PRIVATE int dsp_close()
225 dprint("sb16_dsp.c: dsp_close()\n");
227 DspBusy = 0; /* soundcard available again */
229 return OK;
233 /*===========================================================================*
234 * dsp_ioctl
235 *===========================================================================*/
236 PRIVATE int dsp_ioctl(m_ptr)
237 message *m_ptr;
239 int status;
240 phys_bytes user_phys;
241 unsigned int val;
243 dprint("sb16_dsp.c: dsp_ioctl()\n");
245 /* Cannot change parameters during play or recording */
246 if(DmaBusy >= 0) return EBUSY;
248 /* Get user data */
249 if(m_ptr->REQUEST != DSPIORESET) {
250 sys_vircopy(m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS, SELF, D, (vir_bytes)&val, sizeof(val));
253 dprint("dsp_ioctl: got ioctl %d, argument: %d\n", m_ptr->REQUEST, val);
255 switch(m_ptr->REQUEST) {
256 case DSPIORATE: status = dsp_set_speed(val); break;
257 case DSPIOSTEREO: status = dsp_set_stereo(val); break;
258 case DSPIOBITS: status = dsp_set_bits(val); break;
259 case DSPIOSIZE: status = dsp_set_size(val); break;
260 case DSPIOSIGN: status = dsp_set_sign(val); break;
261 case DSPIOMAX:
262 val = DSP_MAX_FRAGMENT_SIZE;
263 sys_vircopy(SELF, D, (vir_bytes)&val, m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS, sizeof(val));
264 status = OK;
265 break;
266 case DSPIORESET: status = dsp_reset(); break;
267 default: status = ENOTTY; break;
270 return status;
274 /*===========================================================================*
275 * dsp_write
276 *===========================================================================*/
277 PRIVATE void dsp_write(m_ptr)
278 message *m_ptr;
280 int s;
281 message mess;
283 dprint("sb16_dsp.c: dsp_write()\n");
285 if(m_ptr->COUNT != DspFragmentSize) {
286 reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
287 return;
289 if(m_ptr->m_type != DmaMode && DmaBusy >= 0) {
290 reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
291 return;
294 reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);
295 is_processing = TRUE;
297 if(DmaBusy < 0) { /* Dma tranfer not yet started */
299 DmaMode = DEV_WRITE_S; /* Dma mode is writing */
300 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)DmaPtr, (phys_bytes)DspFragmentSize);
301 dsp_dma_setup(DmaPhys, DspFragmentSize * DMA_NR_OF_BUFFERS);
302 dsp_setup();
303 DmaBusy = 0; /* Dma is busy */
304 dprint(" filled dma[0]\n");
305 DmaFillNext = 1;
307 } else if(DmaBusy != DmaFillNext) { /* Dma transfer started, but Dma buffer not yet full */
309 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)DmaPtr + DmaFillNext * DspFragmentSize, (phys_bytes)DspFragmentSize);
310 dprint(" filled dma[%d]\n", DmaFillNext);
311 DmaFillNext = (DmaFillNext + 1) % DMA_NR_OF_BUFFERS;
313 } else if(BufReadNext < 0) { /* Dma buffer full, fill first element of second buffer */
315 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)Buffer, (phys_bytes)DspFragmentSize);
316 dprint(" filled buf[0]\n");
317 BufReadNext = 0;
318 BufFillNext = 1;
320 } else { /* Dma buffer is full, filling second buffer */
322 while(BufReadNext == BufFillNext) { /* Second buffer also full, wait for space to become available */
323 sef_receive(HARDWARE, &mess);
324 dsp_hardware_msg();
326 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)Buffer + BufFillNext * DspFragmentSize, (phys_bytes)DspFragmentSize);
327 dprint(" filled buf[%d]\n", BufFillNext);
328 BufFillNext = (BufFillNext + 1) % DSP_NR_OF_BUFFERS;
332 is_status_msg_expected = TRUE;
333 revivePending = 1;
334 reviveStatus = DspFragmentSize;
335 reviveProcNr = m_ptr->IO_ENDPT;
336 notify(m_ptr->m_source);
340 /*===========================================================================*
341 * dsp_hardware_msg
342 *===========================================================================*/
343 PRIVATE void dsp_hardware_msg()
345 dprint("Interrupt: ");
346 if(DmaBusy >= 0) { /* Dma transfer was actually busy */
347 dprint("Finished playing dma[%d]; ", DmaBusy);
348 DmaBusy = (DmaBusy + 1) % DMA_NR_OF_BUFFERS;
349 if(DmaBusy == DmaFillNext) { /* Dma buffer empty, stop Dma transfer */
351 dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));
352 dprint("No more work...!\n");
353 DmaBusy = -1;
355 } else if(BufReadNext >= 0) { /* Data in second buffer, copy one fragment to Dma buffer */
357 /* Acknowledge the interrupt on the DSP */
358 sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
360 memcpy(DmaPtr + DmaFillNext * DspFragmentSize, Buffer + BufReadNext * DspFragmentSize, DspFragmentSize);
361 dprint("copy buf[%d] -> dma[%d]; ", BufReadNext, DmaFillNext);
362 BufReadNext = (BufReadNext + 1) % DSP_NR_OF_BUFFERS;
363 DmaFillNext = (DmaFillNext + 1) % DMA_NR_OF_BUFFERS;
364 if(BufReadNext == BufFillNext) {
365 BufReadNext = -1;
367 dprint("Starting dma[%d]\n", DmaBusy);
369 return;
371 } else { /* Second buffer empty, still data in Dma buffer, continue playback */
372 dprint("Starting dma[%d]\n", DmaBusy);
376 /* Acknowledge the interrupt on the DSP */
377 sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
381 /*===========================================================================*
382 * dsp_status *
383 *===========================================================================*/
384 PRIVATE void dsp_status(m_ptr)
385 message *m_ptr; /* pointer to the newly arrived message */
387 if(revivePending) {
388 m_ptr->m_type = DEV_REVIVE; /* build message */
389 m_ptr->REP_ENDPT = reviveProcNr;
390 m_ptr->REP_STATUS = reviveStatus;
392 revivePending = 0; /* unmark event */
393 is_processing = FALSE;
394 } else {
395 m_ptr->m_type = DEV_NO_STATUS;
397 is_status_msg_expected = FALSE;
400 send(m_ptr->m_source, m_ptr); /* send the message */
404 /*===========================================================================*
405 * reply *
406 *===========================================================================*/
407 PRIVATE void reply(code, replyee, process, status)
408 int code;
409 int replyee;
410 int process;
411 int status;
413 message m;
415 m.m_type = code; /* TASK_REPLY or REVIVE */
416 m.REP_STATUS = status; /* result of device operation */
417 m.REP_ENDPT = process; /* which user made the request */
419 send(replyee, &m);
422 /*===========================================================================*
423 * dsp_init
424 *===========================================================================*/
425 PRIVATE int dsp_init()
427 int i, s;
429 if(dsp_reset () != OK) {
430 dprint("sb16: No SoundBlaster card detected\n");
431 return -1;
434 DspVersion[0] = DspVersion[1] = 0;
435 dsp_command(DSP_GET_VERSION); /* Get DSP version bytes */
437 for(i = 1000; i; i--) {
438 if(sb16_inb(DSP_DATA_AVL) & 0x80) {
439 if(DspVersion[0] == 0) {
440 DspVersion[0] = sb16_inb(DSP_READ);
441 } else {
442 DspVersion[1] = sb16_inb(DSP_READ);
443 break;
448 if(DspVersion[0] < 4) {
449 dprint("sb16: No SoundBlaster 16 compatible card detected\n");
450 return -1;
453 dprint("sb16: SoundBlaster DSP version %d.%d detected\n", DspVersion[0], DspVersion[1]);
455 /* set SB to use our IRQ and DMA channels */
456 mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));
457 mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16));
459 /* register interrupt vector and enable irq */
460 if ((s=sys_irqsetpolicy(SB_IRQ, IRQ_REENABLE, &irq_hook_id )) != OK)
461 panic("SB16DSP", "Couldn't set IRQ policy", s);
462 if ((s=sys_irqenable(&irq_hook_id)) != OK)
463 panic("SB16DSP", "Couldn't enable IRQ", s);
465 DspAvail = 1;
466 return OK;
470 /*===========================================================================*
471 * dsp_reset
472 *===========================================================================*/
473 PRIVATE int dsp_reset()
475 int i;
477 sb16_outb(DSP_RESET, 1);
478 for(i = 0; i < 1000; i++); /* wait a while */
479 sb16_outb(DSP_RESET, 0);
481 for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++);
483 if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */
485 DmaBusy = -1;
487 return OK;
491 /*===========================================================================*
492 * dsp_command
493 *===========================================================================*/
494 PRIVATE int dsp_command(value)
495 int value;
497 int i, status;
499 for (i = 0; i < SB_TIMEOUT; i++) {
500 if((sb16_inb(DSP_STATUS) & 0x80) == 0) {
501 sb16_outb(DSP_COMMAND, value);
502 return OK;
506 dprint("sb16: SoundBlaster: DSP Command(%x) timeout\n", value);
507 return -1;
511 /*===========================================================================*
512 * dsp_set_size
513 *===========================================================================*/
514 static int dsp_set_size(size)
515 unsigned int size;
517 dprint("dsp_set_size(): set fragment size to %u\n", size);
519 /* Sanity checks */
520 if(size < DSP_MIN_FRAGMENT_SIZE || size > DSP_MAX_FRAGMENT_SIZE || size % 2 != 0) {
521 return EINVAL;
524 DspFragmentSize = size;
526 return OK;
530 /*===========================================================================*
531 * dsp_set_speed
532 *===========================================================================*/
533 static int dsp_set_speed(speed)
534 unsigned int speed;
536 dprint("sb16: setting speed to %u, stereo = %d\n", speed, DspStereo);
538 if(speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED) {
539 return EPERM;
542 /* Soundblaster 16 can be programmed with real sample rates
543 * instead of time constants
545 * Since you cannot sample and play at the same time
546 * we set in- and output rate to the same value
549 dsp_command(DSP_INPUT_RATE); /* set input rate */
550 dsp_command(speed >> 8); /* high byte of speed */
551 dsp_command(speed); /* low byte of speed */
552 dsp_command(DSP_OUTPUT_RATE); /* same for output rate */
553 dsp_command(speed >> 8);
554 dsp_command(speed);
556 DspSpeed = speed;
558 return OK;
562 /*===========================================================================*
563 * dsp_set_stereo
564 *===========================================================================*/
565 static int dsp_set_stereo(stereo)
566 unsigned int stereo;
568 if(stereo) {
569 DspStereo = 1;
570 } else {
571 DspStereo = 0;
574 return OK;
578 /*===========================================================================*
579 * dsp_set_bits
580 *===========================================================================*/
581 static int dsp_set_bits(bits)
582 unsigned int bits;
584 /* Sanity checks */
585 if(bits != 8 && bits != 16) {
586 return EINVAL;
589 DspBits = bits;
591 return OK;
595 /*===========================================================================*
596 * dsp_set_sign
597 *===========================================================================*/
598 static int dsp_set_sign(sign)
599 unsigned int sign;
601 dprint("sb16: set sign to %u\n", sign);
603 DspSign = (sign > 0 ? 1 : 0);
605 return OK;
609 /*===========================================================================*
610 * dsp_dma_setup
611 *===========================================================================*/
612 PRIVATE void dsp_dma_setup(address, count)
613 phys_bytes address;
614 int count;
616 pvb_pair_t pvb[9];
619 dprint("Setting up %d bit DMA\n", DspBits);
621 if(DspBits == 8) { /* 8 bit sound */
622 count--;
624 pv_set(pvb[0], DMA8_MASK, SB_DMA_8 | 0x04); /* Disable DMA channel */
625 pv_set(pvb[1], DMA8_CLEAR, 0x00); /* Clear flip flop */
627 /* set DMA mode */
628 pv_set(pvb[2], DMA8_MODE, (DmaMode == DEV_WRITE_S ? DMA8_AUTO_PLAY : DMA8_AUTO_REC));
630 pv_set(pvb[3], DMA8_ADDR, (address >> 0) & 0xff); /* Low_byte of address */
631 pv_set(pvb[4], DMA8_ADDR, (address >> 8) & 0xff); /* High byte of address */
632 pv_set(pvb[5], DMA8_PAGE, (address >> 16) & 0xff); /* 64K page number */
633 pv_set(pvb[6], DMA8_COUNT, (count >> 0) & 0xff); /* Low byte of count */
634 pv_set(pvb[7], DMA8_COUNT, (count >> 8) & 0xff); /* High byte of count */
635 pv_set(pvb[8], DMA8_MASK, SB_DMA_8); /* Enable DMA channel */
637 sys_voutb(pvb, 9);
638 } else { /* 16 bit sound */
639 count-= 2;
641 pv_set(pvb[0], DMA16_MASK, (SB_DMA_16 & 3) | 0x04); /* Disable DMA channel */
643 pv_set(pvb[1], DMA16_CLEAR, 0x00); /* Clear flip flop */
645 /* Set dma mode */
646 pv_set(pvb[2], DMA16_MODE, (DmaMode == DEV_WRITE_S ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));
648 pv_set(pvb[3], DMA16_ADDR, (address >> 1) & 0xFF); /* Low_byte of address */
649 pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF); /* High byte of address */
650 pv_set(pvb[5], DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */
651 pv_set(pvb[6], DMA16_COUNT, (count >> 1) & 0xff); /* Low byte of count */
652 pv_set(pvb[7], DMA16_COUNT, (count >> 9) & 0xff); /* High byte of count */
653 pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3); /* Enable DMA channel */
655 sys_voutb(pvb, 9);
660 /*===========================================================================*
661 * dsp_setup()
662 *===========================================================================*/
663 PRIVATE void dsp_setup()
665 /* Set current sample speed */
666 dsp_set_speed(DspSpeed);
668 /* Put the speaker on */
669 if(DmaMode == DEV_WRITE_S) {
670 dsp_command (DSP_CMD_SPKON); /* put speaker on */
672 /* Program DSP with dma mode */
673 dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));
674 } else {
675 dsp_command (DSP_CMD_SPKOFF); /* put speaker off */
677 /* Program DSP with dma mode */
678 dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));
681 /* Program DSP with transfer mode */
682 if (!DspSign) {
683 dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_US : DSP_MODE_MONO_US));
684 } else {
685 dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_S : DSP_MODE_MONO_S));
688 /* Give length of fragment to DSP */
689 if (DspBits == 8) { /* 8 bit transfer */
690 /* #bytes - 1 */
691 dsp_command((DspFragmentSize - 1) >> 0);
692 dsp_command((DspFragmentSize - 1) >> 8);
693 } else { /* 16 bit transfer */
694 /* #words - 1 */
695 dsp_command((DspFragmentSize - 1) >> 1);
696 dsp_command((DspFragmentSize - 1) >> 9);