sb16_dsp.c

Go to the documentation of this file.
00001 /* This file contains the driver for a DSP (Digital Sound Processor) on
00002  * a SoundBlaster 16 soundcard.
00003  *
00004  * The driver supports the following operations (using message format m2):
00005  *
00006  *    m_type      DEVICE    IO_ENDPT     COUNT    POSITION  ADRRESS
00007  * ----------------------------------------------------------------
00008  * |  DEV_OPEN  | device  | proc nr |         |         |         |
00009  * |------------+---------+---------+---------+---------+---------|
00010  * |  DEV_CLOSE | device  | proc nr |         |         |         |
00011  * |------------+---------+---------+---------+---------+---------|
00012  * |  DEV_READ  | device  | proc nr |  bytes  |         | buf ptr |
00013  * |------------+---------+---------+---------+---------+---------|
00014  * |  DEV_WRITE | device  | proc nr |  bytes  |         | buf ptr |
00015  * |------------+---------+---------+---------+---------+---------|
00016  * |  DEV_IOCTL | device  | proc nr |func code|         | buf ptr |
00017  * ----------------------------------------------------------------
00018  *
00019  * The file contains one entry point:
00020  *
00021  *   main:      main entry when driver is brought up
00022  *      
00023  *  August 24 2005              Ported driver to user space (only audio playback) (Peter Boonstoppel)
00024  *  May 20 1995                 Author: Michel R. Prevenier 
00025  */
00026 
00027 #include "sb16.h"
00028 
00029 
00030 _PROTOTYPE(void main, (void));
00031 FORWARD _PROTOTYPE( int dsp_open, (void) );
00032 FORWARD _PROTOTYPE( int dsp_close, (void) );
00033 FORWARD _PROTOTYPE( int dsp_ioctl, (message *m_ptr) );
00034 FORWARD _PROTOTYPE( void dsp_write, (message *m_ptr) );
00035 FORWARD _PROTOTYPE( void dsp_hardware_msg, (void) );
00036 FORWARD _PROTOTYPE( void dsp_status, (message *m_ptr) );
00037 
00038 FORWARD _PROTOTYPE( void reply, (int code, int replyee, int process, int status) );
00039 FORWARD _PROTOTYPE( void init_buffer, (void) );
00040 FORWARD _PROTOTYPE( int dsp_init, (void) );
00041 FORWARD _PROTOTYPE( int dsp_reset, (void) );
00042 FORWARD _PROTOTYPE( int dsp_command, (int value) );
00043 FORWARD _PROTOTYPE( int dsp_set_size, (unsigned int size) );
00044 FORWARD _PROTOTYPE( int dsp_set_speed, (unsigned int speed) );
00045 FORWARD _PROTOTYPE( int dsp_set_stereo, (unsigned int stereo) );
00046 FORWARD _PROTOTYPE( int dsp_set_bits, (unsigned int bits) );
00047 FORWARD _PROTOTYPE( int dsp_set_sign, (unsigned int sign) );
00048 FORWARD _PROTOTYPE( void dsp_dma_setup, (phys_bytes address, int count) );
00049 FORWARD _PROTOTYPE( void dsp_setup, (void) );
00050 
00051 PRIVATE int irq_hook_id;        /* id of irq hook at the kernel */
00052 
00053 PRIVATE char DmaBuffer[DMA_SIZE + 64 * 1024];
00054 PRIVATE char* DmaPtr;
00055 PRIVATE phys_bytes DmaPhys;
00056 
00057 PRIVATE char Buffer[DSP_MAX_FRAGMENT_SIZE * DSP_NR_OF_BUFFERS];
00058 
00059 PRIVATE int DspVersion[2]; 
00060 PRIVATE unsigned int DspStereo = DEFAULT_STEREO;
00061 PRIVATE unsigned int DspSpeed = DEFAULT_SPEED; 
00062 PRIVATE unsigned int DspBits = DEFAULT_BITS;
00063 PRIVATE unsigned int DspSign = DEFAULT_SIGN;
00064 PRIVATE unsigned int DspFragmentSize = DSP_MAX_FRAGMENT_SIZE;
00065 PRIVATE int DspAvail = 0;
00066 PRIVATE int DspBusy = 0;
00067 PRIVATE int DmaMode = 0;
00068 PRIVATE int DmaBusy = -1;
00069 PRIVATE int DmaFillNext = 0;
00070 PRIVATE int BufReadNext = -1;
00071 PRIVATE int BufFillNext = 0;
00072 
00073 PRIVATE int revivePending = 0;
00074 PRIVATE int reviveStatus;
00075 PRIVATE int reviveProcNr;
00076 
00077 #define dprint (void)
00078 
00079 
00080 /*===========================================================================*
00081  *                              main
00082  *===========================================================================*/
00083 PUBLIC void main() 
00084 {       
00085         int r, caller, proc_nr, s;
00086         message mess;
00087 
00088         dprint("sb16_dsp.c: main()\n");
00089 
00090         /* Get a DMA buffer. */
00091         init_buffer();
00092 
00093         while(TRUE) {
00094                 /* Wait for an incoming message */
00095                 receive(ANY, &mess);
00096 
00097                 caller = mess.m_source;
00098                 proc_nr = mess.IO_ENDPT;
00099 
00100                 /* Now carry out the work. */
00101                 switch(mess.m_type) {
00102                         case DEV_OPEN:          r = dsp_open(); break;
00103                         case DEV_CLOSE:         r = dsp_close(); break;
00104                         case DEV_IOCTL:         r = dsp_ioctl(&mess); break;
00105 
00106                         case DEV_READ:          r = EINVAL; break; /* Not yet implemented */
00107                         case DEV_WRITE:         dsp_write(&mess); continue; /* don't reply */
00108                         
00109                         case DEV_STATUS:        dsp_status(&mess); continue; /* don't reply */
00110                         case HARD_INT:          dsp_hardware_msg(); continue; /* don't reply */
00111                         case SYS_SIG:           continue; /* don't reply */
00112                         default:                        r = EINVAL;
00113                 }
00114 
00115                 /* Finally, prepare and send the reply message. */
00116                 reply(TASK_REPLY, caller, proc_nr, r);
00117         }
00118 
00119 }
00120 
00121 
00122 /*===========================================================================*
00123  *                              dsp_open
00124  *===========================================================================*/
00125 PRIVATE int dsp_open()
00126 {
00127         dprint("sb16_dsp.c: dsp_open()\n");
00128         
00129         /* try to detect SoundBlaster card */
00130         if(!DspAvail && dsp_init() != OK) return EIO;
00131 
00132         /* Only one open at a time with soundcards */
00133         if(DspBusy) return EBUSY;
00134 
00135         /* Start with a clean DSP */
00136         if(dsp_reset() != OK) return EIO;
00137 
00138         /* Setup default values */
00139         DspStereo = DEFAULT_STEREO;
00140         DspSpeed = DEFAULT_SPEED;
00141         DspBits = DEFAULT_BITS;
00142         DspSign = DEFAULT_SIGN;
00143         DspFragmentSize = DMA_SIZE / 2;
00144 
00145         DspBusy = 1;
00146 
00147         return OK;
00148 }
00149 
00150 
00151 /*===========================================================================*
00152  *                              dsp_close
00153  *===========================================================================*/
00154 PRIVATE int dsp_close()
00155 {
00156         dprint("sb16_dsp.c: dsp_close()\n");
00157 
00158         DspBusy = 0;                  /* soundcard available again */
00159 
00160         return OK;
00161 }
00162 
00163 
00164 /*===========================================================================*
00165  *                              dsp_ioctl
00166  *===========================================================================*/
00167 PRIVATE int dsp_ioctl(m_ptr)
00168 message *m_ptr;
00169 {
00170         int status;
00171         phys_bytes user_phys;
00172         unsigned int val;
00173 
00174         dprint("sb16_dsp.c: dsp_ioctl()\n");
00175 
00176         /* Cannot change parameters during play or recording */
00177         if(DmaBusy >= 0) return EBUSY;
00178 
00179         /* Get user data */
00180         if(m_ptr->REQUEST != DSPIORESET) {
00181                 sys_vircopy(m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS, SELF, D, (vir_bytes)&val, sizeof(val));
00182         }
00183 
00184         dprint("dsp_ioctl: got ioctl %d, argument: %d\n", m_ptr->REQUEST, val);
00185 
00186         switch(m_ptr->REQUEST) {
00187                 case DSPIORATE:         status = dsp_set_speed(val); break;
00188                 case DSPIOSTEREO:       status = dsp_set_stereo(val); break;
00189                 case DSPIOBITS:         status = dsp_set_bits(val); break;
00190                 case DSPIOSIZE:         status = dsp_set_size(val); break;
00191                 case DSPIOSIGN:         status = dsp_set_sign(val); break;
00192                 case DSPIOMAX: 
00193                         val = DSP_MAX_FRAGMENT_SIZE;
00194                         sys_vircopy(SELF, D, (vir_bytes)&val, m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS, sizeof(val));
00195                         status = OK;
00196                         break;
00197                 case DSPIORESET:    status = dsp_reset(); break;
00198                 default:            status = ENOTTY; break;
00199         }
00200 
00201         return status;
00202 }
00203 
00204 
00205 /*===========================================================================*
00206  *                              dsp_write
00207  *===========================================================================*/
00208 PRIVATE void dsp_write(m_ptr)
00209 message *m_ptr;
00210 {
00211         int s;
00212         message mess;
00213         
00214         dprint("sb16_dsp.c: dsp_write()\n");
00215 
00216         if(m_ptr->COUNT != DspFragmentSize) {
00217                 reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
00218                 return;
00219         }
00220         if(m_ptr->m_type != DmaMode && DmaBusy >= 0) {
00221                 reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
00222                 return;
00223         }
00224         
00225         reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);
00226 
00227         if(DmaBusy < 0) { /* Dma tranfer not yet started */
00228 
00229                 DmaMode = DEV_WRITE;           /* Dma mode is writing */
00230                 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)DmaPtr, (phys_bytes)DspFragmentSize);
00231                 dsp_dma_setup(DmaPhys, DspFragmentSize * DMA_NR_OF_BUFFERS);
00232                 dsp_setup();
00233                 DmaBusy = 0;         /* Dma is busy */
00234                 dprint(" filled dma[0]\n");
00235                 DmaFillNext = 1;
00236 
00237         } else if(DmaBusy != DmaFillNext) { /* Dma transfer started, but Dma buffer not yet full */
00238 
00239                 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)DmaPtr + DmaFillNext * DspFragmentSize, (phys_bytes)DspFragmentSize);
00240                 dprint(" filled dma[%d]\n", DmaFillNext);
00241                 DmaFillNext = (DmaFillNext + 1) % DMA_NR_OF_BUFFERS;
00242 
00243         } else if(BufReadNext < 0) { /* Dma buffer full, fill first element of second buffer */ 
00244 
00245                 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)Buffer, (phys_bytes)DspFragmentSize);
00246                 dprint(" filled buf[0]\n");
00247                 BufReadNext = 0;
00248                 BufFillNext = 1;
00249 
00250         } else { /* Dma buffer is full, filling second buffer */ 
00251 
00252                 while(BufReadNext == BufFillNext) { /* Second buffer also full, wait for space to become available */ 
00253                         receive(HARDWARE, &mess);
00254                         dsp_hardware_msg();
00255                 }
00256                 sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)Buffer + BufFillNext * DspFragmentSize, (phys_bytes)DspFragmentSize);
00257                 dprint(" filled buf[%d]\n", BufFillNext);
00258                 BufFillNext = (BufFillNext + 1) % DSP_NR_OF_BUFFERS;
00259 
00260         } 
00261         
00262         revivePending = 1;
00263         reviveStatus = DspFragmentSize;
00264         reviveProcNr = m_ptr->IO_ENDPT;
00265         notify(m_ptr->m_source);
00266 }
00267 
00268 
00269 /*===========================================================================*
00270  *                              dsp_hardware_msg
00271  *===========================================================================*/
00272 PRIVATE void dsp_hardware_msg()
00273 {       
00274         dprint("Interrupt: ");
00275         if(DmaBusy >= 0) { /* Dma transfer was actually busy */
00276                 dprint("Finished playing dma[%d]; ", DmaBusy);
00277                 DmaBusy = (DmaBusy + 1) % DMA_NR_OF_BUFFERS;
00278                 if(DmaBusy == DmaFillNext) { /* Dma buffer empty, stop Dma transfer */
00279 
00280                         dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));
00281                         dprint("No more work...!\n");
00282                         DmaBusy = -1;
00283 
00284                 } else if(BufReadNext >= 0) { /* Data in second buffer, copy one fragment to Dma buffer */
00285                         
00286                         /* Acknowledge the interrupt on the DSP */
00287                         sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
00288 
00289                         memcpy(DmaPtr + DmaFillNext * DspFragmentSize, Buffer + BufReadNext * DspFragmentSize, DspFragmentSize);
00290                         dprint("copy buf[%d] -> dma[%d]; ", BufReadNext, DmaFillNext);
00291                         BufReadNext = (BufReadNext + 1) % DSP_NR_OF_BUFFERS;
00292                         DmaFillNext = (DmaFillNext + 1) % DMA_NR_OF_BUFFERS;
00293                         if(BufReadNext == BufFillNext) {
00294                                 BufReadNext = -1;
00295                         } 
00296                         dprint("Starting dma[%d]\n", DmaBusy);
00297                         
00298                         return;
00299 
00300                 } else { /* Second buffer empty, still data in Dma buffer, continue playback */
00301                         dprint("Starting dma[%d]\n", DmaBusy);
00302                 }
00303         }
00304 
00305         /* Acknowledge the interrupt on the DSP */
00306         sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
00307 }
00308 
00309 
00310 /*===========================================================================*
00311  *                              dsp_status                                   *
00312  *===========================================================================*/
00313 PRIVATE void dsp_status(m_ptr)
00314 message *m_ptr; /* pointer to the newly arrived message */
00315 {
00316         if(revivePending) {
00317                 m_ptr->m_type = DEV_REVIVE;                     /* build message */
00318                 m_ptr->REP_ENDPT = reviveProcNr;
00319                 m_ptr->REP_STATUS = reviveStatus;
00320 
00321                 revivePending = 0;                                      /* unmark event */
00322         } else {
00323                 m_ptr->m_type = DEV_NO_STATUS;
00324         }
00325 
00326         send(m_ptr->m_source, m_ptr);                   /* send the message */
00327 }
00328 
00329 
00330 /*===========================================================================*
00331  *                              reply                                        *
00332  *===========================================================================*/
00333 PRIVATE void reply(code, replyee, process, status)
00334 int code;
00335 int replyee;
00336 int process;
00337 int status;
00338 {
00339         message m;
00340 
00341         m.m_type = code;                /* TASK_REPLY or REVIVE */
00342         m.REP_STATUS = status;  /* result of device operation */
00343         m.REP_ENDPT = process;  /* which user made the request */
00344 
00345         send(replyee, &m);
00346 }
00347 
00348 
00349 /*===========================================================================*
00350  *                              init_buffer
00351  *===========================================================================*/
00352 PRIVATE void init_buffer()
00353 {
00354 /* Select a buffer that can safely be used for dma transfers.  
00355  * Its absolute address is 'DmaPhys', the normal address is 'DmaPtr'.
00356  */
00357 
00358 #if (CHIP == INTEL)
00359         unsigned left;
00360 
00361         DmaPtr = DmaBuffer;
00362         sys_umap(SELF, D, (vir_bytes)DmaBuffer, (phys_bytes)sizeof(DmaBuffer), &DmaPhys);
00363 
00364         if((left = dma_bytes_left(DmaPhys)) < DMA_SIZE) {
00365                 /* First half of buffer crosses a 64K boundary, can't DMA into that */
00366                 DmaPtr += left;
00367                 DmaPhys += left;
00368         }
00369 #else /* CHIP != INTEL */
00370         panic("SB16DSP","init_buffer() failed, CHIP != INTEL", 0);
00371 #endif /* CHIP == INTEL */
00372 }
00373 
00374 
00375 /*===========================================================================*
00376  *                              dsp_init
00377  *===========================================================================*/
00378 PRIVATE int dsp_init()
00379 {
00380         int i, s;
00381 
00382         if(dsp_reset () != OK) { 
00383                 dprint("sb16: No SoundBlaster card detected\n");
00384                 return -1;
00385         }
00386 
00387         DspVersion[0] = DspVersion[1] = 0;
00388         dsp_command(DSP_GET_VERSION);   /* Get DSP version bytes */
00389 
00390         for(i = 1000; i; i--) {
00391                 if(sb16_inb(DSP_DATA_AVL) & 0x80) {             
00392                         if(DspVersion[0] == 0) {
00393                                 DspVersion[0] = sb16_inb(DSP_READ);
00394                         } else {
00395                                 DspVersion[1] = sb16_inb(DSP_READ);
00396                                 break;
00397                         }
00398                 }
00399         }
00400 
00401         if(DspVersion[0] < 4) {
00402                 dprint("sb16: No SoundBlaster 16 compatible card detected\n");
00403                 return -1;
00404         } 
00405         
00406         dprint("sb16: SoundBlaster DSP version %d.%d detected\n", DspVersion[0], DspVersion[1]);
00407 
00408         /* set SB to use our IRQ and DMA channels */
00409         mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));
00410         mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16)); 
00411 
00412         /* register interrupt vector and enable irq */
00413         if ((s=sys_irqsetpolicy(SB_IRQ, IRQ_REENABLE, &irq_hook_id )) != OK)
00414                 panic("SB16DSP", "Couldn't set IRQ policy", s);
00415         if ((s=sys_irqenable(&irq_hook_id)) != OK)
00416                 panic("SB16DSP", "Couldn't enable IRQ", s);
00417 
00418         DspAvail = 1;
00419         return OK;
00420 }
00421 
00422 
00423 /*===========================================================================*
00424  *                              dsp_reset
00425  *===========================================================================*/
00426 PRIVATE int dsp_reset()
00427 {
00428         int i;
00429 
00430         sb16_outb(DSP_RESET, 1);
00431         for(i = 0; i < 1000; i++); /* wait a while */
00432         sb16_outb(DSP_RESET, 0);
00433 
00434         for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++);  
00435         
00436         if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */
00437 
00438         DmaBusy = -1;
00439 
00440         return OK;
00441 }
00442 
00443 
00444 /*===========================================================================*
00445  *                              dsp_command
00446  *===========================================================================*/
00447 PRIVATE int dsp_command(value)
00448 int value;
00449 {
00450         int i, status;
00451 
00452         for (i = 0; i < SB_TIMEOUT; i++) {
00453                 if((sb16_inb(DSP_STATUS) & 0x80) == 0) {
00454                         sb16_outb(DSP_COMMAND, value);
00455                         return OK;
00456                 }
00457         }
00458 
00459         dprint("sb16: SoundBlaster: DSP Command(%x) timeout\n", value);
00460         return -1;
00461 }
00462 
00463 
00464 /*===========================================================================*
00465  *                              dsp_set_size
00466  *===========================================================================*/
00467 static int dsp_set_size(size)
00468 unsigned int size;
00469 {
00470         dprint("dsp_set_size(): set fragment size to %u\n", size);
00471 
00472         /* Sanity checks */
00473         if(size < DSP_MIN_FRAGMENT_SIZE || size > DSP_MAX_FRAGMENT_SIZE || size % 2 != 0) {
00474                 return EINVAL;
00475         }
00476 
00477         DspFragmentSize = size; 
00478 
00479         return OK;
00480 }
00481 
00482 
00483 /*===========================================================================*
00484  *                              dsp_set_speed
00485  *===========================================================================*/
00486 static int dsp_set_speed(speed)
00487 unsigned int speed;
00488 {
00489         dprint("sb16: setting speed to %u, stereo = %d\n", speed, DspStereo);
00490 
00491         if(speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED) {
00492                 return EPERM;
00493         }
00494 
00495         /* Soundblaster 16 can be programmed with real sample rates
00496         * instead of time constants
00497         *
00498         * Since you cannot sample and play at the same time
00499         * we set in- and output rate to the same value 
00500         */
00501 
00502         dsp_command(DSP_INPUT_RATE);            /* set input rate */
00503         dsp_command(speed >> 8);                        /* high byte of speed */
00504         dsp_command(speed);                                     /* low byte of speed */
00505         dsp_command(DSP_OUTPUT_RATE);           /* same for output rate */
00506         dsp_command(speed >> 8);        
00507         dsp_command(speed); 
00508 
00509         DspSpeed = speed;
00510 
00511         return OK;
00512 }
00513 
00514 
00515 /*===========================================================================*
00516  *                              dsp_set_stereo
00517  *===========================================================================*/
00518 static int dsp_set_stereo(stereo)
00519 unsigned int stereo;
00520 {
00521         if(stereo) { 
00522                 DspStereo = 1;
00523         } else { 
00524                 DspStereo = 0;
00525         }
00526 
00527         return OK;
00528 }
00529 
00530 
00531 /*===========================================================================*
00532  *                              dsp_set_bits
00533  *===========================================================================*/
00534 static int dsp_set_bits(bits)
00535 unsigned int bits;
00536 {
00537         /* Sanity checks */
00538         if(bits != 8 && bits != 16) {
00539                 return EINVAL;
00540         }
00541 
00542         DspBits = bits; 
00543 
00544         return OK;
00545 }
00546 
00547 
00548 /*===========================================================================*
00549  *                              dsp_set_sign
00550  *===========================================================================*/
00551 static int dsp_set_sign(sign)
00552 unsigned int sign;
00553 {
00554         dprint("sb16: set sign to %u\n", sign);
00555 
00556         DspSign = (sign > 0 ? 1 : 0); 
00557 
00558         return OK;
00559 }
00560 
00561 
00562 /*===========================================================================*
00563  *                              dsp_dma_setup
00564  *===========================================================================*/
00565 PRIVATE void dsp_dma_setup(address, count)
00566 phys_bytes address;
00567 int count;
00568 {
00569         pvb_pair_t pvb[9];
00570 
00571 
00572         dprint("Setting up %d bit DMA\n", DspBits);
00573 
00574         if(DspBits == 8) {   /* 8 bit sound */
00575                 count--;     
00576 
00577                 pv_set(pvb[0], DMA8_MASK, SB_DMA_8 | 0x04);      /* Disable DMA channel */
00578                 pv_set(pvb[1], DMA8_CLEAR, 0x00);                      /* Clear flip flop */
00579 
00580                 /* set DMA mode */
00581                 pv_set(pvb[2], DMA8_MODE, (DmaMode == DEV_WRITE ? DMA8_AUTO_PLAY : DMA8_AUTO_REC)); 
00582 
00583                 pv_set(pvb[3], DMA8_ADDR, address >>  0);        /* Low_byte of address */
00584                 pv_set(pvb[4], DMA8_ADDR, address >>  8);        /* High byte of address */
00585                 pv_set(pvb[5], DMA8_PAGE, address >> 16);        /* 64K page number */
00586                 pv_set(pvb[6], DMA8_COUNT, count >> 0);          /* Low byte of count */
00587                 pv_set(pvb[7], DMA8_COUNT, count >> 8);          /* High byte of count */
00588                 pv_set(pvb[8], DMA8_MASK, SB_DMA_8);           /* Enable DMA channel */
00589 
00590                 sys_voutb(pvb, 9);
00591         } else {  /* 16 bit sound */
00592                 count-= 2;
00593 
00594                 pv_set(pvb[0], DMA16_MASK, (SB_DMA_16 & 3) | 0x04);     /* Disable DMA channel */
00595                 
00596                 pv_set(pvb[1], DMA16_CLEAR, 0x00);                  /* Clear flip flop */
00597 
00598                 /* Set dma mode */
00599                 pv_set(pvb[2], DMA16_MODE, (DmaMode == DEV_WRITE ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));        
00600 
00601                 pv_set(pvb[3], DMA16_ADDR, (address >> 1) & 0xFF);  /* Low_byte of address */
00602                 pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF);  /* High byte of address */
00603                 pv_set(pvb[5], DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */
00604                 pv_set(pvb[6], DMA16_COUNT, count >> 1);            /* Low byte of count */
00605                 pv_set(pvb[7], DMA16_COUNT, count >> 9);            /* High byte of count */
00606                 pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3);          /* Enable DMA channel */
00607 
00608                 sys_voutb(pvb, 9);
00609         }
00610 }
00611 
00612 
00613 /*===========================================================================*
00614  *                              dsp_setup()
00615  *===========================================================================*/
00616 PRIVATE void dsp_setup()
00617 { 
00618         /* Set current sample speed */
00619         dsp_set_speed(DspSpeed);
00620 
00621         /* Put the speaker on */
00622         if(DmaMode == DEV_WRITE) {
00623                 dsp_command (DSP_CMD_SPKON); /* put speaker on */
00624 
00625                 /* Program DSP with dma mode */
00626                 dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));     
00627         } else {
00628                 dsp_command (DSP_CMD_SPKOFF); /* put speaker off */
00629 
00630                 /* Program DSP with dma mode */
00631                 dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));     
00632         }
00633 
00634         /* Program DSP with transfer mode */
00635         if (!DspSign) {
00636                 dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_US : DSP_MODE_MONO_US));
00637         } else {
00638                 dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_S : DSP_MODE_MONO_S));
00639         }
00640 
00641         /* Give length of fragment to DSP */
00642         if (DspBits == 8) { /* 8 bit transfer */
00643                 /* #bytes - 1 */
00644                 dsp_command((DspFragmentSize - 1) >> 0); 
00645                 dsp_command((DspFragmentSize - 1) >> 8);
00646         } else {             /* 16 bit transfer */
00647                 /* #words - 1 */
00648                 dsp_command((DspFragmentSize - 1) >> 1);
00649                 dsp_command((DspFragmentSize - 1) >> 9);
00650         }
00651 }
00652 
00653   

Generated on Fri Apr 14 22:57:18 2006 for minix by  doxygen 1.4.6