void dma_start(dma_buffer * buffer, unsigned long count, unsigned char mode) { /* Disable interrupts */ int old_ints = disable(); dma_disable(buffer->channel); dma_set_mode(buffer->channel, mode); dma_clear_ff(buffer->channel); dma_set_addr(buffer->channel, buffer->physical); dma_clear_ff(buffer->channel); dma_set_count(buffer->channel, count); dma_enable(buffer->channel); /* Re-enable interrupts */ if (old_ints) enable(); }
static boolean __wss_detect() { /* First find the port number */ if (!wss.port) { static unsigned int wss_ports[] = { 0x32c, 0x530, 0x604, 0xE80, 0xF40 }; int i; for (i = 0; i < 5; i++) { wss.port = wss_ports[i]; if (__wss_ping()) break; } if (i < 0) { wss.port = 0; return FALSE; } } /* Now disable output */ wss_output(FALSE); /* Detect the DMA channel */ if (!wss.dma) { static int __dma[] = { 0, 1, 3 }; int i; /* Enable playback IRQ */ __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE); __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ); /* Start a short DMA transfer and check if DMA count is zero */ for (i = 0; i < 3; i++) { unsigned int timer, status, freq = 44100; wss.dma = __dma[i]; dma_disable(wss.dma); dma_set_mode(wss.dma, DMA_MODE_WRITE); dma_clear_ff(wss.dma); dma_set_count(wss.dma, 10); dma_enable(wss.dma); /* Clear IRQ status */ outportb(WSS_STATUS, 0); __wss_setformat(__wss_getrate(&freq)); __wss_outreg(WSSR_COUNT_LOW, 1); __wss_outreg(WSSR_COUNT_HIGH, 0); /* Tell codec to start transfer */ __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); _farsetsel(_dos_ds); timer = _farnspeekl(0x46c); while (_farnspeekl(0x46c) - timer <= 2) if (dma_get_count(wss.dma) == 0) break; __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); dma_disable(wss.dma); /* Now check if DMA transfer count is zero and an IRQ is pending */ status = inportb(WSS_STATUS); outportb(WSS_STATUS, 0); if ((dma_get_count(wss.dma) == 0) && (status & WSSM_INT)) break; wss.dma = 0; } if (!wss.dma) return FALSE; } /* Now detect the IRQ number */ if (!wss.irq) { unsigned int i, irqmask, freq = 5510; unsigned long timer, delta = 0x7fffffff; /* IRQ can be one of 2,3,5,7,10 */ irq_detect_start(0x04ac, __wss_irq_irqdetect); dma_disable(wss.dma); dma_set_mode(wss.dma, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); dma_clear_ff(wss.dma); dma_set_count(wss.dma, 1); dma_enable(wss.dma); __wss_setformat(__wss_getrate(&freq)); /* Clear IRQ status */ outportb(WSS_STATUS, 0); __wss_outreg(WSSR_COUNT_LOW, 0); __wss_outreg(WSSR_COUNT_HIGH, 0); /* Prepare timeout counter */ _farsetsel(_dos_ds); timer = _farnspeekl(0x46c); while (timer == _farnspeekl(0x46c)); timer = _farnspeekl(0x46c); /* Reset all IRQ counters */ irq_detect_clear(); /* Tell codec to start transfer */ __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); /* Now wait 1/18 seconds */ while (timer == _farnspeekl(0x46c)); __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); dma_disable(wss.dma); /* Given frequency 5510Hz, a buffer size of 1 byte and a time interval of 1/18.2 second, we should have received about 302 interrupts */ for (i = 2; i <= 10; i++) { int count = abs(302 - irq_detect_get(i, &irqmask)); if (count < delta) wss.irq = i, delta = count; } if (delta > 150) wss.irq = 0; irq_detect_end(); if (!wss.irq) return FALSE; } return TRUE; }