00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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;
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
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
00091 init_buffer();
00092
00093 while(TRUE) {
00094
00095 receive(ANY, &mess);
00096
00097 caller = mess.m_source;
00098 proc_nr = mess.IO_ENDPT;
00099
00100
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;
00107 case DEV_WRITE: dsp_write(&mess); continue;
00108
00109 case DEV_STATUS: dsp_status(&mess); continue;
00110 case HARD_INT: dsp_hardware_msg(); continue;
00111 case SYS_SIG: continue;
00112 default: r = EINVAL;
00113 }
00114
00115
00116 reply(TASK_REPLY, caller, proc_nr, r);
00117 }
00118
00119 }
00120
00121
00122
00123
00124
00125 PRIVATE int dsp_open()
00126 {
00127 dprint("sb16_dsp.c: dsp_open()\n");
00128
00129
00130 if(!DspAvail && dsp_init() != OK) return EIO;
00131
00132
00133 if(DspBusy) return EBUSY;
00134
00135
00136 if(dsp_reset() != OK) return EIO;
00137
00138
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
00153
00154 PRIVATE int dsp_close()
00155 {
00156 dprint("sb16_dsp.c: dsp_close()\n");
00157
00158 DspBusy = 0;
00159
00160 return OK;
00161 }
00162
00163
00164
00165
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
00177 if(DmaBusy >= 0) return EBUSY;
00178
00179
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
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) {
00228
00229 DmaMode = DEV_WRITE;
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;
00234 dprint(" filled dma[0]\n");
00235 DmaFillNext = 1;
00236
00237 } else if(DmaBusy != DmaFillNext) {
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) {
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 {
00251
00252 while(BufReadNext == BufFillNext) {
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
00271
00272 PRIVATE void dsp_hardware_msg()
00273 {
00274 dprint("Interrupt: ");
00275 if(DmaBusy >= 0) {
00276 dprint("Finished playing dma[%d]; ", DmaBusy);
00277 DmaBusy = (DmaBusy + 1) % DMA_NR_OF_BUFFERS;
00278 if(DmaBusy == DmaFillNext) {
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) {
00285
00286
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 {
00301 dprint("Starting dma[%d]\n", DmaBusy);
00302 }
00303 }
00304
00305
00306 sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
00307 }
00308
00309
00310
00311
00312
00313 PRIVATE void dsp_status(m_ptr)
00314 message *m_ptr;
00315 {
00316 if(revivePending) {
00317 m_ptr->m_type = DEV_REVIVE;
00318 m_ptr->REP_ENDPT = reviveProcNr;
00319 m_ptr->REP_STATUS = reviveStatus;
00320
00321 revivePending = 0;
00322 } else {
00323 m_ptr->m_type = DEV_NO_STATUS;
00324 }
00325
00326 send(m_ptr->m_source, m_ptr);
00327 }
00328
00329
00330
00331
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;
00342 m.REP_STATUS = status;
00343 m.REP_ENDPT = process;
00344
00345 send(replyee, &m);
00346 }
00347
00348
00349
00350
00351
00352 PRIVATE void init_buffer()
00353 {
00354
00355
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
00366 DmaPtr += left;
00367 DmaPhys += left;
00368 }
00369 #else
00370 panic("SB16DSP","init_buffer() failed, CHIP != INTEL", 0);
00371 #endif
00372 }
00373
00374
00375
00376
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);
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
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
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
00425
00426 PRIVATE int dsp_reset()
00427 {
00428 int i;
00429
00430 sb16_outb(DSP_RESET, 1);
00431 for(i = 0; i < 1000; i++);
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;
00437
00438 DmaBusy = -1;
00439
00440 return OK;
00441 }
00442
00443
00444
00445
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
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
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
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
00496
00497
00498
00499
00500
00501
00502 dsp_command(DSP_INPUT_RATE);
00503 dsp_command(speed >> 8);
00504 dsp_command(speed);
00505 dsp_command(DSP_OUTPUT_RATE);
00506 dsp_command(speed >> 8);
00507 dsp_command(speed);
00508
00509 DspSpeed = speed;
00510
00511 return OK;
00512 }
00513
00514
00515
00516
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
00533
00534 static int dsp_set_bits(bits)
00535 unsigned int bits;
00536 {
00537
00538 if(bits != 8 && bits != 16) {
00539 return EINVAL;
00540 }
00541
00542 DspBits = bits;
00543
00544 return OK;
00545 }
00546
00547
00548
00549
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
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) {
00575 count--;
00576
00577 pv_set(pvb[0], DMA8_MASK, SB_DMA_8 | 0x04);
00578 pv_set(pvb[1], DMA8_CLEAR, 0x00);
00579
00580
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);
00584 pv_set(pvb[4], DMA8_ADDR, address >> 8);
00585 pv_set(pvb[5], DMA8_PAGE, address >> 16);
00586 pv_set(pvb[6], DMA8_COUNT, count >> 0);
00587 pv_set(pvb[7], DMA8_COUNT, count >> 8);
00588 pv_set(pvb[8], DMA8_MASK, SB_DMA_8);
00589
00590 sys_voutb(pvb, 9);
00591 } else {
00592 count-= 2;
00593
00594 pv_set(pvb[0], DMA16_MASK, (SB_DMA_16 & 3) | 0x04);
00595
00596 pv_set(pvb[1], DMA16_CLEAR, 0x00);
00597
00598
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);
00602 pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF);
00603 pv_set(pvb[5], DMA16_PAGE, (address >> 16) & 0xFE);
00604 pv_set(pvb[6], DMA16_COUNT, count >> 1);
00605 pv_set(pvb[7], DMA16_COUNT, count >> 9);
00606 pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3);
00607
00608 sys_voutb(pvb, 9);
00609 }
00610 }
00611
00612
00613
00614
00615
00616 PRIVATE void dsp_setup()
00617 {
00618
00619 dsp_set_speed(DspSpeed);
00620
00621
00622 if(DmaMode == DEV_WRITE) {
00623 dsp_command (DSP_CMD_SPKON);
00624
00625
00626 dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));
00627 } else {
00628 dsp_command (DSP_CMD_SPKOFF);
00629
00630
00631 dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));
00632 }
00633
00634
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
00642 if (DspBits == 8) {
00643
00644 dsp_command((DspFragmentSize - 1) >> 0);
00645 dsp_command((DspFragmentSize - 1) >> 8);
00646 } else {
00647
00648 dsp_command((DspFragmentSize - 1) >> 1);
00649 dsp_command((DspFragmentSize - 1) >> 9);
00650 }
00651 }
00652
00653