PUBLIC int drv_reset(void) { int i; Dprint(("drv_reset():\n")); sb16_outb(DSP_RESET, 1); for(i = 0; i < 1000; i++); /* wait a while */ sb16_outb(DSP_RESET, 0); for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++); if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */ return OK; }
/*===========================================================================* * dsp_reset *===========================================================================*/ PRIVATE int dsp_reset() { int i; sb16_outb(DSP_RESET, 1); for(i = 0; i < 1000; i++); /* wait a while */ sb16_outb(DSP_RESET, 0); for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++); if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */ DmaBusy = -1; return OK; }
/*=========================================================================* * mixer_get *=========================================================================*/ PRIVATE int mixer_get(int reg) { int i; sb16_outb(MIXER_REG, reg); for(i = 0; i < 100; i++); return sb16_inb(MIXER_DATA) & 0xff; }
/*===========================================================================* * dsp_init *===========================================================================*/ PRIVATE int dsp_init() { int i, s; if(dsp_reset () != OK) { dprint("sb16: No SoundBlaster card detected\n"); return -1; } DspVersion[0] = DspVersion[1] = 0; dsp_command(DSP_GET_VERSION); /* Get DSP version bytes */ for(i = 1000; i; i--) { if(sb16_inb(DSP_DATA_AVL) & 0x80) { if(DspVersion[0] == 0) { DspVersion[0] = sb16_inb(DSP_READ); } else { DspVersion[1] = sb16_inb(DSP_READ); break; } } } if(DspVersion[0] < 4) { dprint("sb16: No SoundBlaster 16 compatible card detected\n"); return -1; } dprint("sb16: SoundBlaster DSP version %d.%d detected\n", DspVersion[0], DspVersion[1]); /* set SB to use our IRQ and DMA channels */ mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1))); mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16)); /* register interrupt vector and enable irq */ if ((s=sys_irqsetpolicy(SB_IRQ, IRQ_REENABLE, &irq_hook_id )) != OK) panic("Couldn't set IRQ policy: %d", s); if ((s=sys_irqenable(&irq_hook_id)) != OK) panic("Couldn't enable IRQ: %d", s); DspAvail = 1; return OK; }
PUBLIC int drv_init_hw(void) { int i; int DspVersion[2]; Dprint(("drv_init_hw():\n")); if(drv_reset () != OK) { Dprint(("sb16: No SoundBlaster card detected\n")); return -1; } DspVersion[0] = DspVersion[1] = 0; dsp_command(DSP_GET_VERSION); /* Get DSP version bytes */ for(i = 1000; i; i--) { if(sb16_inb(DSP_DATA_AVL) & 0x80) { if(DspVersion[0] == 0) { DspVersion[0] = sb16_inb(DSP_READ); } else { DspVersion[1] = sb16_inb(DSP_READ); break; } } } if(DspVersion[0] < 4) { Dprint(("sb16: No SoundBlaster 16 compatible card detected\n")); return -1; } Dprint(("sb16: SoundBlaster DSP version %d.%d detected!\n", DspVersion[0], DspVersion[1])); /* set SB to use our IRQ and DMA channels */ mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1))); mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16)); DspFragmentSize = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments; return OK; }
/*===========================================================================* * dsp_command *===========================================================================*/ PRIVATE int dsp_command(int value) { int i; for (i = 0; i < SB_TIMEOUT; i++) { if((sb16_inb(DSP_STATUS) & 0x80) == 0) { sb16_outb(DSP_COMMAND, value); return OK; } } dprint("sb16: SoundBlaster: DSP Command(%x) timeout\n", value); return -1; }
/*===========================================================================* * dsp_hardware_msg *===========================================================================*/ PRIVATE void dsp_hardware_msg() { dprint("Interrupt: "); if(DmaBusy >= 0) { /* Dma transfer was actually busy */ dprint("Finished playing dma[%d]; ", DmaBusy); DmaBusy = (DmaBusy + 1) % DMA_NR_OF_BUFFERS; if(DmaBusy == DmaFillNext) { /* Dma buffer empty, stop Dma transfer */ dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT)); dprint("No more work...!\n"); DmaBusy = -1; } else if(BufReadNext >= 0) { /* Data in second buffer, copy one fragment to Dma buffer */ /* Acknowledge the interrupt on the DSP */ sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL)); memcpy(DmaPtr + DmaFillNext * DspFragmentSize, Buffer + BufReadNext * DspFragmentSize, DspFragmentSize); dprint("copy buf[%d] -> dma[%d]; ", BufReadNext, DmaFillNext); BufReadNext = (BufReadNext + 1) % DSP_NR_OF_BUFFERS; DmaFillNext = (DmaFillNext + 1) % DMA_NR_OF_BUFFERS; if(BufReadNext == BufFillNext) { BufReadNext = -1; } dprint("Starting dma[%d]\n", DmaBusy); return; } else { /* Second buffer empty, still data in Dma buffer, continue playback */ dprint("Starting dma[%d]\n", DmaBusy); } } /* Acknowledge the interrupt on the DSP */ sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL)); }