X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=libs%2Fmikmod%2Fdrivers%2Fdos%2Fdoswss.c;fp=libs%2Fmikmod%2Fdrivers%2Fdos%2Fdoswss.c;h=0000000000000000000000000000000000000000;hp=41cdf38948339ece22ba0204843191315fd1ef52;hb=b2c24e9d5b637bb78d18a377d9957c07d0759030;hpb=67c749060592270c9cd8b4f7dafe7d7c7a61a614 diff --git a/libs/mikmod/drivers/dos/doswss.c b/libs/mikmod/drivers/dos/doswss.c deleted file mode 100644 index 41cdf38..0000000 --- a/libs/mikmod/drivers/dos/doswss.c +++ /dev/null @@ -1,577 +0,0 @@ -/* MikMod sound library - (c) 1998, 1999 Miodrag Vallat and others - see file AUTHORS for - complete list. - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - 02111-1307, USA. -*/ - -/*============================================================================== - - Windows Sound System I/O routines (CS42XX, ESS18XX, GUS+DaughterBoard etc) - Written by Andrew Zabolotny - -==============================================================================*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#ifdef DRV_WSS - -#include -#include -#include -#include -#include -#include -#include - -#include "doswss.h" - -/********************************************* Private variables/routines *****/ - -__wss_state wss; - -/* WSS frequency rates... lower bit selects one of two frequency generators */ -static unsigned int wss_rates[14][2] = { - {5510, 0x00 | WSSM_XTAL2}, - {6620, 0x0E | WSSM_XTAL2}, - {8000, 0x00 | WSSM_XTAL1}, - {9600, 0x0E | WSSM_XTAL1}, - {11025, 0x02 | WSSM_XTAL2}, - {16000, 0x02 | WSSM_XTAL1}, - {18900, 0x04 | WSSM_XTAL2}, - {22050, 0x06 | WSSM_XTAL2}, - {27420, 0x04 | WSSM_XTAL1}, - {32000, 0x06 | WSSM_XTAL1}, - {33075, 0x0C | WSSM_XTAL2}, - {37800, 0x08 | WSSM_XTAL2}, - {44100, 0x0A | WSSM_XTAL2}, - {48000, 0x0C | WSSM_XTAL1} -}; - -static void wss_irq() -{ - /* Make sure its not a spurious IRQ */ - if (!irq_check(wss.irq_handle)) - return; - - wss.irqcount++; - - /* Clear IRQ status */ - outportb(WSS_STATUS, 0); - - /* Write transfer count again */ - __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff); - __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8); - irq_ack(wss.irq_handle); - - enable(); - if (wss.timer_callback) - wss.timer_callback(); -} - -static void wss_irq_end() -{ -} - -/* WSS accepts some conventional values instead of frequency in Hz... */ -static unsigned char __wss_getrate(unsigned int *freq) -{ - int i, best = -1, delta = 0xffff; - - for (i = 0; i < 14; i++) { - int newdelta = abs(wss_rates[i][0] - *freq); - if (newdelta < delta) - best = i, delta = newdelta; - } - - *freq = wss_rates[best][0]; - return wss_rates[best][1]; -} - -/* Check if we really have a WSS compatible card on given address */ -static boolean __wss_ping() -{ - /* Disable CODEC operations first */ - __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); - /* Now put some harmless values in registers and check them */ - __wss_outreg(WSSR_COUNT_LOW, 0xaa); - __wss_outreg(WSSR_COUNT_HIGH, 0x55); - return (__wss_inreg(WSSR_COUNT_LOW) == 0xaa) - && (__wss_inreg(WSSR_COUNT_HIGH) == 0x55); -} - -static boolean __wss_reset() -{ - int count; - - /* Disable output */ - wss_output(FALSE); - - /* Now select the test/initialization register */ - count = 10000; - while (inportb(WSS_ADDR) != WSSR_TEST_INIT) { - outportb(WSS_ADDR, WSSR_TEST_INIT); - if (!--count) - return FALSE; - } - - count = 10000; - while (inportb(WSS_DATA) & WSSM_CALIB_IN_PROGRESS) { - outportb(WSS_ADDR, WSSR_TEST_INIT); - if (!--count) - return FALSE; - } - - /* Enable playback IRQ */ - __wss_regbit_set(WSSR_PIN_CTRL, WSSM_IRQ_ENABLE); - __wss_outreg(WSSR_IRQ_STATUS, WSSM_PLAYBACK_IRQ); - - /* Clear IRQ status */ - outportb(WSS_STATUS, 0); - - return TRUE; -} - -static boolean __wss_setformat(unsigned char format) -{ - int count; - - outportb(WSS_ADDR, WSSM_MCE | WSSR_PLAY_FORMAT); - outportb(WSS_DATA, format); - inportb(WSS_DATA); /* ERRATA SHEETS ... */ - inportb(WSS_DATA); /* ERRATA SHEETS ... */ - - /* Wait end of syncronization ... */ - if (!__wss_wait()) - return FALSE; - - /* Turn off the ModeChangeEnable bit: do it until it works */ - count = 10000; - while (inportb(WSS_ADDR) != WSSR_PLAY_FORMAT) { - outportb(WSS_ADDR, WSSR_PLAY_FORMAT); - if (!--count) - return FALSE; - } - - return __wss_reset(); -} - -/**************************************************** WSS detection stuff *****/ - -static int __wss_irq_irqdetect(int irqno) -{ - unsigned char status = inportb(WSS_STATUS); - /* Clear IRQ status */ - outportb(WSS_STATUS, 0); - /* Reset transfer counter */ - __wss_outreg(WSSR_COUNT_LOW, 0); - __wss_outreg(WSSR_COUNT_HIGH, 0); - return (status & WSSM_INT); -} - -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; -} - -/*************************************************** High-level interface *****/ - -/* Detect whenever WSS is present and fill "wss" structure */ -boolean wss_detect() -{ - char *env; - - /* Try to find the port and DMA from environment */ - env = getenv("WSS"); - - while (env && *env) { - /* Skip whitespace */ - while ((*env == ' ') || (*env == '\t')) - env++; - if (!*env) - break; - - switch (*env++) { - case 'A': - case 'a': - if (!wss.port) - wss.port = strtol(env, &env, 16); - break; - case 'I': - case 'i': - if (!wss.irq) - wss.irq = strtol(env, &env, 10); - break; - case 'D': - case 'd': - if (!wss.dma) - wss.dma = strtol(env, &env, 10); - break; - default: - /* Skip other values */ - while (*env && (*env != ' ') && (*env != '\t')) - env++; - break; - } - } - - /* Try to fill the gaps in wss hardware parameters */ - __wss_detect(); - - if (!wss.port || !wss.irq || !wss.dma) - return FALSE; - - if (!__wss_ping()) - return FALSE; - - if (!__wss_reset()) - return FALSE; - - wss.ok = 1; - return TRUE; -} - -/* Reset WSS */ -void wss_reset() -{ - wss_stop_dma(); - __wss_reset(); -} - -/* Open WSS for usage */ -boolean wss_open() -{ - __dpmi_meminfo struct_info; - - if (!wss.ok) - if (!wss_detect()) - return FALSE; - - if (wss.open) - return FALSE; - - /* Now lock the wss structure in memory */ - struct_info.address = __djgpp_base_address + (unsigned long)&wss; - struct_info.size = sizeof(wss); - if (__dpmi_lock_linear_region(&struct_info)) - return FALSE; - - /* Hook the WSS IRQ */ - wss.irq_handle = - irq_hook(wss.irq, wss_irq, (long)wss_irq_end - (long)wss_irq); - if (!wss.irq_handle) { - __dpmi_unlock_linear_region(&struct_info); - return FALSE; - } - - /* Enable the interrupt */ - irq_enable(wss.irq_handle); - if (wss.irq > 7) - _irq_enable(2); - - wss.open++; - - return TRUE; -} - -/* Finish working with WSS */ -boolean wss_close() -{ - __dpmi_meminfo struct_info; - if (!wss.open) - return FALSE; - - wss.open--; - - /* Stop/free DMA buffer */ - wss_stop_dma(); - - /* Unhook IRQ */ - irq_unhook(wss.irq_handle); - wss.irq_handle = NULL; - - /* Unlock the wss structure */ - struct_info.address = __djgpp_base_address + (unsigned long)&wss; - struct_info.size = sizeof(wss); - __dpmi_unlock_linear_region(&struct_info); - - return TRUE; -} - -/* Adjust frequency rate to nearest WSS available */ -unsigned int wss_adjust_freq(unsigned int freq) -{ - __wss_getrate(&freq); - return freq; -} - -/* Enable/disable speaker output */ -/* Start playing from DMA buffer in either 8/16 bit mono/stereo */ -boolean wss_start_dma(unsigned char mode, unsigned int freq) -{ - int dmabuffsize; - unsigned char format; - - /* Stop DMA transfer if it is enabled */ - wss_stop_dma(); - - /* Sanity check: we support only 8-bit unsigned and 16-bit signed formats */ - if (((mode & WSSMODE_16BITS) && !(mode & WSSMODE_SIGNED)) - || (!(mode & WSSMODE_16BITS) && (mode & WSSMODE_SIGNED))) - return FALSE; - - /* Find the nearest frequency divisor (rate) */ - format = __wss_getrate(&freq); - wss.mode = mode; - - /* Get a DMA buffer enough for a 1sec interval... 4K <= dmasize <= 32K */ - dmabuffsize = freq; - if (mode & WSSMODE_STEREO) - dmabuffsize *= 2; - if (mode & WSSMODE_16BITS) - dmabuffsize *= 2; - dmabuffsize >>= 2; - if (dmabuffsize < 4096) - dmabuffsize = 4096; - if (dmabuffsize > 32768) - dmabuffsize = 32768; - dmabuffsize = (dmabuffsize + 255) & 0xffffff00; - - wss.dma_buff = dma_allocate(wss.dma, dmabuffsize); - if (!wss.dma_buff) - return FALSE; - - /* Fill DMA buffer with silence */ - dmabuffsize = wss.dma_buff->size; - if (mode & WSSMODE_SIGNED) - memset(wss.dma_buff->linear, 0, dmabuffsize); - else - memset(wss.dma_buff->linear, 0x80, dmabuffsize); - - /* Check data size and build a WSSR_PLAY_FORMAT value accordingly */ - wss.samples = dmabuffsize; - if (mode & WSSMODE_16BITS) { - wss.samples >>= 1; - format |= WSSM_16BITS; - } - - if (mode & WSSMODE_STEREO) { - wss.samples >>= 1; - format |= WSSM_STEREO; - } - - if (!__wss_setformat(format)) { - wss_stop_dma(); - return FALSE; - } - - /* Prime DMA for transfer */ - dma_start(wss.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); - - /* Tell codec how many samples to transfer */ - wss.samples = (wss.samples >> 1) - 1; - __wss_outreg(WSSR_COUNT_LOW, wss.samples & 0xff); - __wss_outreg(WSSR_COUNT_HIGH, wss.samples >> 8); - - /* Tell codec to start transfer */ - __wss_regbit_set(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); - - return TRUE; -} - -/* Stop playing from DMA buffer */ -void wss_stop_dma() -{ - if (!wss.dma_buff) - return; - - __wss_regbit_reset(WSSR_IFACE_CTRL, WSSM_PLAYBACK_ENABLE); - dma_disable(wss.dma); - dma_free(wss.dma_buff); - wss.dma_buff = NULL; -} - -/* Query current position/total size of the DMA buffer */ -void wss_query_dma(unsigned int *dma_size, unsigned int *dma_pos) -{ - unsigned int dma_left; - *dma_size = wss.dma_buff->size; - /* It can happen we try to read DMA count when HI/LO bytes will be - inconsistent */ - for (;;) { - unsigned int dma_left_test; - dma_clear_ff(wss.dma); - dma_left_test = dma_get_count(wss.dma); - dma_left = dma_get_count(wss.dma); - if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10)) - break; - } - *dma_pos = *dma_size - dma_left; -} - -void wss_output(boolean enable) -{ - if (enable) - wss.curlevel = wss.level; - else - wss.curlevel = 0x3f; - - __wss_outreg(WSSR_MASTER_L, wss.curlevel); - __wss_outreg(WSSR_MASTER_R, wss.curlevel); -} - -void wss_level(int level) -{ - if (level < 0) - level = 0; - if (level > 63) - level = 63; - wss.curlevel = wss.level = level ^ 63; - - __wss_outreg(WSSR_MASTER_L, wss.curlevel); - __wss_outreg(WSSR_MASTER_R, wss.curlevel); -} - -#endif /* DRV_WSS */ - -/* ex:set ts=4: */