dossb.c
资源名称:tcpmp.rar [点击查看]
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:12k
源码类别:
Windows CE
开发平台:
C/C++
- /* 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.
- */
- /*==============================================================================
- $Id: dossb.c,v 1.1 2004/02/01 02:01:17 raph Exp $
- Sound Blaster I/O routines, common for SB8, SBPro and SB16
- ==============================================================================*/
- /*
- Written by Andrew Zabolotny <bit@eltech.ru>
- */
- #include <stdlib.h>
- #include <dpmi.h>
- #include <go32.h>
- #include <dos.h>
- #include <sys/nearptr.h>
- #include <sys/farptr.h>
- #include <string.h>
- #include "dossb.h"
- /********************************************* Private variables/routines *****/
- __sb_state sb;
- /* Wait for SoundBlaster for some time */
- volatile void __sb_wait()
- {
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- inportb(SB_DSP_RESET);
- }
- static void sb_irq()
- {
- /* Make sure its not a spurious IRQ */
- if (!irq_check(sb.irq_handle))
- return;
- sb.irqcount++;
- /* Acknowledge DMA transfer is complete */
- if (sb.mode & SBMODE_16BITS)
- __sb_dsp_ack_dma16();
- else
- __sb_dsp_ack_dma8();
- /* SoundBlaster 1.x cannot do autoinit ... */
- if (sb.dspver < SBVER_20)
- __sb_dspreg_outwlh(SBDSP_DMA_PCM8, (sb.dma_buff->size >> 1) - 1);
- /* Send EOI */
- irq_ack(sb.irq_handle);
- enable();
- if (sb.timer_callback)
- sb.timer_callback();
- }
- static void sb_irq_end()
- {
- }
- static boolean __sb_reset()
- {
- /* Disable the output */
- sb_output(FALSE);
- /* Clear pending ints if any */
- __sb_dsp_ack_dma8();
- __sb_dsp_ack_dma16();
- /* Reset the DSP */
- outportb(SB_DSP_RESET, SBM_DSP_RESET);
- __sb_wait();
- __sb_wait();
- outportb(SB_DSP_RESET, 0);
- /* Now wait for AA coming from datain port */
- if (__sb_dsp_in() != 0xaa)
- return FALSE;
- /* Finally, get the DSP version */
- if ((sb.dspver = __sb_dsp_version()) == 0xffff)
- return FALSE;
- /* Check again */
- if (sb.dspver != __sb_dsp_version())
- return FALSE;
- return TRUE;
- }
- /***************************************************** SB detection stuff *****/
- static int __sb_irq_irqdetect(int irqno)
- {
- __sb_dsp_ack_dma8();
- return 1;
- }
- static void __sb_irq_dmadetect()
- {
- /* Make sure its not a spurious IRQ */
- if (!irq_check(sb.irq_handle))
- return;
- sb.irqcount++;
- /* Acknowledge DMA transfer is complete */
- if (sb.mode & SBMODE_16BITS)
- __sb_dsp_ack_dma16();
- else
- __sb_dsp_ack_dma8();
- /* Send EOI */
- irq_ack(sb.irq_handle);
- }
- static boolean __sb_detect()
- {
- /* First find the port number */
- if (!sb.port) {
- int i;
- for (i = 5; i >= 0; i--) {
- sb.port = 0x210 + i * 0x10;
- if (__sb_reset())
- break;
- }
- if (i < 0) {
- sb.port = 0;
- return FALSE;
- }
- }
- /* Now detect the IRQ and DMA numbers */
- if (!sb.irq) {
- unsigned int irqmask, sbirqmask, sbirqcount;
- unsigned long timer;
- /* IRQ can be one of 2,3,5,7,10 */
- irq_detect_start(0x04ac, __sb_irq_irqdetect);
- /* Prepare timeout counter */
- _farsetsel(_dos_ds);
- timer = _farnspeekl(0x46c);
- sbirqmask = 0;
- sbirqcount = 10; /* Emit 10 SB irqs */
- /* Tell SoundBlaster to emit IRQ for 8-bit transfers */
- __sb_dsp_out(SBDSP_GEN_IRQ8);
- __sb_wait();
- for (;;) {
- irq_detect_get(0, &irqmask);
- if (irqmask) {
- sbirqmask |= irqmask;
- if (!--sbirqcount)
- break;
- __sb_dsp_out(SBDSP_GEN_IRQ8);
- }
- if (_farnspeekl(0x46c) - timer >= 9) /* Wait ~1/2 secs */
- break;
- }
- if (sbirqmask)
- for (sb.irq = 15; sb.irq > 0; sb.irq--)
- if (irq_detect_get(sb.irq, &irqmask) == 10)
- break;
- irq_detect_end();
- if (!sb.irq)
- return FALSE;
- }
- /* Detect the 8-bit and 16-bit DMAs */
- if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16)) {
- static int __dma8[] = { 0, 1, 3 };
- static int __dma16[] = { 5, 6, 7 };
- int *dma;
- sb_output(FALSE);
- /* Temporary hook SB IRQ */
- sb.irq_handle = irq_hook(sb.irq, __sb_irq_dmadetect, 200);
- irq_enable(sb.irq_handle);
- if (sb.irq > 7)
- _irq_enable(2);
- /* Start a short DMA transfer and check if IRQ happened */
- for (;;) {
- int i;
- unsigned int timer, oldcount;
- if (!sb.dma8)
- dma = &sb.dma8;
- else if ((sb.dspver >= SBVER_16) && !sb.dma16)
- dma = &sb.dma16;
- else
- break;
- for (i = 0; i < 3; i++) {
- boolean success = 1;
- *dma = (dma == &sb.dma8) ? __dma8[i] : __dma16[i];
- oldcount = sb.irqcount;
- dma_disable(*dma);
- dma_set_mode(*dma, DMA_MODE_WRITE);
- dma_clear_ff(*dma);
- dma_set_count(*dma, 2);
- dma_enable(*dma);
- __sb_dspreg_out(SBDSP_SET_TIMING, 206); /* 20KHz */
- if (dma == &sb.dma8) {
- sb.mode = 0;
- __sb_dspreg_outwlh(SBDSP_DMA_PCM8, 1);
- } else {
- sb.mode = SBMODE_16BITS;
- __sb_dspreg_out(SBDSP_DMA_GENERIC16, 0);
- __sb_dsp_out(0);
- __sb_dsp_out(1);
- }
- _farsetsel(_dos_ds);
- timer = _farnspeekl(0x46c);
- while (oldcount == sb.irqcount)
- if (_farnspeekl(0x46c) - timer >= 2) {
- success = 0;
- break;
- }
- dma_disable(*dma);
- if (success)
- break;
- *dma = 0;
- }
- if (!*dma)
- break;
- }
- irq_unhook(sb.irq_handle);
- if (!sb.dma8 || ((sb.dspver >= SBVER_16) && !sb.dma16))
- return FALSE;
- }
- return TRUE;
- }
- /*************************************************** High-level interface *****/
- /* Detect whenever SoundBlaster is present and fill "sb" structure */
- boolean sb_detect()
- {
- char *env;
- /* Try to find the port and DMA from environment */
- env = getenv("BLASTER");
- while (env && *env) {
- /* Skip whitespace */
- while ((*env == ' ') || (*env == 't'))
- env++;
- if (!*env)
- break;
- switch (*env++) {
- case 'A':
- case 'a':
- if (!sb.port)
- sb.port = strtol(env, &env, 16);
- break;
- case 'E':
- case 'e':
- if (!sb.aweport)
- sb.aweport = strtol(env, &env, 16);
- break;
- case 'I':
- case 'i':
- if (!sb.irq)
- sb.irq = strtol(env, &env, 10);
- break;
- case 'D':
- case 'd':
- if (!sb.dma8)
- sb.dma8 = strtol(env, &env, 10);
- break;
- case 'H':
- case 'h':
- if (!sb.dma16)
- sb.dma16 = strtol(env, &env, 10);
- break;
- default:
- /* Skip other values (H == MIDI, T == model, any other?) */
- while (*env && (*env != ' ') && (*env != 't'))
- env++;
- break;
- }
- }
- /* Try to detect missing sound card parameters */
- __sb_detect();
- if (!sb.port || !sb.irq || !sb.dma8)
- return FALSE;
- if (!__sb_reset())
- return FALSE;
- if ((sb.dspver >= SBVER_16) && !sb.dma16)
- return FALSE;
- if (sb.dspver >= SBVER_PRO)
- sb.caps |= SBMODE_STEREO;
- if (sb.dspver >= SBVER_16 && sb.dma16)
- sb.caps |= SBMODE_16BITS;
- if (sb.dspver < SBVER_20)
- sb.maxfreq_mono = 22222;
- else
- sb.maxfreq_mono = 45454;
- if (sb.dspver <= SBVER_16)
- sb.maxfreq_stereo = 22727;
- else
- sb.maxfreq_stereo = 45454;
- sb.ok = 1;
- return TRUE;
- }
- /* Reset SoundBlaster */
- void sb_reset()
- {
- sb_stop_dma();
- __sb_reset();
- }
- /* Start working with SoundBlaster */
- boolean sb_open()
- {
- __dpmi_meminfo struct_info;
- if (!sb.ok)
- if (!sb_detect())
- return FALSE;
- if (sb.open)
- return FALSE;
- /* Now lock the sb structure in memory */
- struct_info.address = __djgpp_base_address + (unsigned long)&sb;
- struct_info.size = sizeof(sb);
- if (__dpmi_lock_linear_region(&struct_info))
- return FALSE;
- /* Hook the SB IRQ */
- sb.irq_handle = irq_hook(sb.irq, sb_irq, (long)sb_irq_end - (long)sb_irq);
- if (!sb.irq_handle) {
- __dpmi_unlock_linear_region(&struct_info);
- return FALSE;
- }
- /* Enable the interrupt */
- irq_enable(sb.irq_handle);
- if (sb.irq > 7)
- _irq_enable(2);
- sb.open++;
- return TRUE;
- }
- /* Finish working with SoundBlaster */
- boolean sb_close()
- {
- __dpmi_meminfo struct_info;
- if (!sb.open)
- return FALSE;
- sb.open--;
- /* Stop/free DMA buffer */
- sb_stop_dma();
- /* Unhook IRQ */
- irq_unhook(sb.irq_handle);
- sb.irq_handle = NULL;
- /* Unlock the sb structure */
- struct_info.address = __djgpp_base_address + (unsigned long)&sb;
- struct_info.size = sizeof(sb);
- __dpmi_unlock_linear_region(&struct_info);
- return TRUE;
- }
- /* Enable/disable stereo DSP mode */
- /* Enable/disable speaker output */
- void sb_output(boolean enable)
- {
- __sb_dsp_out(enable ? SBDSP_SPEAKER_ENA : SBDSP_SPEAKER_DIS);
- }
- /* Start playing from DMA buffer */
- boolean sb_start_dma(unsigned char mode, unsigned int freq)
- {
- int dmachannel = (mode & SBMODE_16BITS) ? sb.dma16 : sb.dma8;
- int dmabuffsize;
- unsigned int tc = 0; /* timing constant (<=sbpro only) */
- /* Stop DMA transfer if it is enabled */
- sb_stop_dma();
- /* Sanity check */
- if ((mode & SBMODE_MASK & sb.caps) != (mode & SBMODE_MASK))
- return FALSE;
- /* Check this SB can perform at requested frequency */
- if (((mode & SBMODE_STEREO) && (freq > sb.maxfreq_stereo))
- || (!(mode & SBMODE_STEREO) && (freq > sb.maxfreq_mono)))
- return FALSE;
- /* Check the timing constant here to avoid failing later */
- if (sb.dspver < SBVER_16) {
- /* SBpro cannot do signed transfer */
- if (mode & SBMODE_SIGNED)
- return FALSE;
- /* Old SBs have a different way on setting DMA timing constant */
- tc = freq;
- if (mode & SBMODE_STEREO)
- tc *= 2;
- tc = 1000000 / tc;
- if (tc > 255)
- return FALSE;
- }
- sb.mode = mode;
- /* Get a DMA buffer enough for a 1/4sec interval... 4K <= dmasize <= 32K */
- dmabuffsize = freq;
- if (mode & SBMODE_STEREO)
- dmabuffsize *= 2;
- if (mode & SBMODE_16BITS)
- dmabuffsize *= 2;
- dmabuffsize >>= 2;
- if (dmabuffsize < 4096)
- dmabuffsize = 4096;
- if (dmabuffsize > 32768)
- dmabuffsize = 32768;
- dmabuffsize = (dmabuffsize + 255) & 0xffffff00;
- sb.dma_buff = dma_allocate(dmachannel, dmabuffsize);
- if (!sb.dma_buff)
- return FALSE;
- /* Fill DMA buffer with silence */
- dmabuffsize = sb.dma_buff->size;
- if (mode & SBMODE_SIGNED)
- memset(sb.dma_buff->linear, 0, dmabuffsize);
- else
- memset(sb.dma_buff->linear, 0x80, dmabuffsize);
- /* Prime DMA for transfer */
- dma_start(sb.dma_buff, dmabuffsize, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
- /* Tell SoundBlaster to start transfer */
- dmabuffsize = (dmabuffsize >> 1) - 1;
- if (sb.dspver >= SBVER_16) { /* SB16 */
- /* SoundBlaster 16 */
- __sb_dspreg_outwhl(SBDSP_SET_RATE, freq);
- /* Start DMA->DAC transfer */
- __sb_dspreg_out(SBM_GENDAC_AUTOINIT |
- ((mode & SBMODE_16BITS) ? SBDSP_DMA_GENERIC16 :
- SBDSP_DMA_GENERIC8),
- ((mode & SBMODE_SIGNED) ? SBM_GENDAC_SIGNED : 0) |
- ((mode & SBMODE_STEREO) ? SBM_GENDAC_STEREO : 0));
- /* Write the length of transfer */
- __sb_dsp_out(dmabuffsize);
- __sb_dsp_out(dmabuffsize >> 8);
- } else {
- __sb_dspreg_out(SBDSP_SET_TIMING, 256 - tc);
- if (sb.dspver >= SBVER_20) { /* SB 2.0/Pro */
- /* Set stereo mode */
- __sb_stereo((mode & SBMODE_STEREO) ? TRUE : FALSE);
- __sb_dspreg_outwlh(SBDSP_SET_DMA_BLOCK, dmabuffsize);
- if (sb.dspver >= SBVER_PRO)
- __sb_dsp_out(SBDSP_HS_DMA_DAC8_AUTO);
- else
- __sb_dsp_out(SBDSP_DMA_PCM8_AUTO);
- } else { /* Original SB */
- /* Start DMA->DAC transfer */
- __sb_dspreg_outwlh(SBDSP_DMA_PCM8, dmabuffsize);
- }
- }
- return TRUE;
- }
- /* Stop playing from DMA buffer */
- void sb_stop_dma()
- {
- if (!sb.dma_buff)
- return;
- if (sb.mode & SBMODE_16BITS)
- __sb_dsp_out(SBDSP_DMA_HALT16);
- else
- __sb_dsp_out(SBDSP_DMA_HALT8);
- dma_disable(sb.dma_buff->channel);
- dma_free(sb.dma_buff);
- sb.dma_buff = NULL;
- }
- /* Query current position/total size of the DMA buffer */
- void sb_query_dma(unsigned int *dma_size, unsigned int *dma_pos)
- {
- unsigned int dma_left;
- *dma_size = sb.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(sb.dma_buff->channel);
- dma_left_test = dma_get_count(sb.dma_buff->channel);
- dma_left = dma_get_count(sb.dma_buff->channel);
- if ((dma_left >= dma_left_test) && (dma_left - dma_left_test < 10))
- break;
- }
- *dma_pos = *dma_size - dma_left;
- }
- /* ex:set ts=4: */