📄 sb16_dsp.c
字号:
int i;
for (i = 0; i < SB_TIMEOUT; i++)
{
if ((in_byte (DSP_STATUS) & 0x80) == 0)
{
out_byte (DSP_COMMAND, value);
return OK;
}
}
printf ("sb16: SoundBlaster: DSP Command(%x) timeout\n", value);
return -1;
}
/*=========================================================================*
* dsp_reset *
*=========================================================================*/
PRIVATE int dsp_reset(void)
{
int i;
out_byte (DSP_RESET, 1);
for(i =0; i<1000; i++); /* wait a while */
out_byte (DSP_RESET, 0);
for (i = 0; i < 1000 && !(in_byte (DSP_DATA_AVL) & 0x80); i++);
if (in_byte (DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */
DmaBusy = 0;
DmaDone = 1;
return OK;
}
/*=========================================================================*
* dsp_set_speed *
*=========================================================================*/
static int dsp_set_speed(speed)
unsigned int speed;
{
#if SB_DEBUG
printf("sb16: setting speed to %u, stereo = %d\n", speed, DspStereo);
#endif
if (speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED)
return EPERM;
/* Soundblaster 16 can be programmed with real sample rates
* instead of time constants
*
* Since you cannot sample and play at the same time
* we set in- and output rate to the same value
*/
lock(); /* disable interrupts */
dsp_command(DSP_INPUT_RATE); /* set input rate */
dsp_command(speed >> 8); /* high byte of speed */
dsp_command(speed); /* low byte of speed */
dsp_command(DSP_OUTPUT_RATE); /* same for output rate */
dsp_command(speed >> 8);
dsp_command(speed);
unlock(); /* enable interrupts */
DspSpeed = speed;
return OK;
}
/*=========================================================================*
* dsp_set_stereo *
*=========================================================================*/
static int dsp_set_stereo(stereo)
unsigned int stereo;
{
if (stereo)
DspStereo = 1;
else
DspStereo = 0;
return OK;
}
/*=========================================================================*
* dsp_set_bits *
*=========================================================================*/
static int dsp_set_bits(bits)
unsigned int bits;
{
/* Sanity checks */
if (bits != 8 && bits != 16) return EINVAL;
DspBits = bits;
return OK;
}
/*=========================================================================*
* dsp_set_size *
*=========================================================================*/
static int dsp_set_size(size)
unsigned int size;
{
#if SB_DEBUG
printf("sb16: set fragment size to %u\n", size);
#endif
/* Sanity checks */
if (size < DSP_MIN_FRAGMENT_SIZE ||
size > DSP_MAX_FRAGMENT_SIZE ||
size % 2 != 0)
return EINVAL;
DspFragmentSize = size;
return OK;
}
/*=========================================================================*
* dsp_set_sign *
*=========================================================================*/
static int dsp_set_sign(sign)
unsigned int sign;
{
#if SB_DEBUG
printf("sb16: set sign to %u\n", sign);
#endif
DspSign = (sign > 0 ? 1 : 0);
return OK;
}
/*===========================================================================*
* dsp_dma_setup *
*===========================================================================*/
PRIVATE void dsp_dma_setup(address, count)
phys_bytes address;
int count;
{
#if SB_DEBUG
printf("Setting up %d bit DMA\n", DspBits);
#endif
if (DspBits == 8) /* 8 bit sound */
{
count--;
lock();
out_byte(DMA8_MASK, SB_DMA_8 | 0x04); /* Disable DMA channel */
out_byte(DMA8_CLEAR, 0x00); /* Clear flip flop */
/* set DMA mode */
out_byte(DMA8_MODE,
(DmaMode == DEV_WRITE ? DMA8_AUTO_PLAY : DMA8_AUTO_REC));
out_byte(DMA8_ADDR, address >> 0); /* Low_byte of address */
out_byte(DMA8_ADDR, address >> 8); /* High byte of address */
out_byte(DMA8_PAGE, address >> 16); /* 64K page number */
out_byte(DMA8_COUNT, count >> 0); /* Low byte of count */
out_byte(DMA8_COUNT, count >> 8); /* High byte of count */
out_byte(DMA8_MASK, SB_DMA_8); /* Enable DMA channel */
unlock();
}
else /* 16 bit sound */
{
count-= 2;
lock();
out_byte(DMA16_MASK, (SB_DMA_16 & 3) | 0x04); /* Disable DMA channel */
out_byte(DMA16_CLEAR, 0x00); /* Clear flip flop */
/* Set dma mode */
out_byte(DMA16_MODE,
(DmaMode == DEV_WRITE ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));
out_byte(DMA16_ADDR, (address >> 1) & 0xFF); /* Low_byte of address */
out_byte(DMA16_ADDR, (address >> 9) & 0xFF); /* High byte of address */
out_byte(DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */
out_byte(DMA16_COUNT, count >> 1); /* Low byte of count */
out_byte(DMA16_COUNT, count >> 9); /* High byte of count */
out_byte(DMA16_MASK, SB_DMA_16 & 3); /* Enable DMA channel */
unlock();
}
}
/*===========================================================================*
* dsp_setup *
*===========================================================================*/
PRIVATE void dsp_setup()
{
/* Set current sample speed */
dsp_set_speed(DspSpeed);
/* Put the speaker on */
if (DmaMode == DEV_WRITE)
{
dsp_command (DSP_CMD_SPKON); /* put speaker on */
/* Program DSP with dma mode */
dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));
}
else
{
dsp_command (DSP_CMD_SPKOFF); /* put speaker off */
/* Program DSP with dma mode */
dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));
}
/* Program DSP with transfer mode */
if (!DspSign)
dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_US : DSP_MODE_MONO_US));
else
dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_S : DSP_MODE_MONO_S));
/* Give length of fragment to DSP */
if (DspBits == 8) /* 8 bit transfer */
{
/* #bytes - 1 */
dsp_command((DspFragmentSize - 1) >> 0);
dsp_command((DspFragmentSize - 1) >> 8);
}
else /* 16 bit transfer */
{
/* #words - 1 */
dsp_command((DspFragmentSize - 1) >> 1);
dsp_command((DspFragmentSize - 1) >> 9);
}
}
/*===========================================================================*
* dsp_write *
*===========================================================================*/
PRIVATE int dsp_write(m_ptr)
message *m_ptr;
{
phys_bytes user_phys;
message mess;
if (m_ptr->COUNT != DspFragmentSize) return EINVAL;
/* From this user address */
user_phys = numap(m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, DspFragmentSize);
if (user_phys == 0) return EINVAL;
if (DmaBusy) /* Dma already started */
{
if (DmaMode != m_ptr->m_type) return EBUSY;
DmaDone = 0; /* No, we're not done yet */
/* Wait for next block to become free */
receive(HARDWARE, &mess);
/* Copy first block to dma buffer */
phys_copy(user_phys, DmaPhys, (phys_bytes) DspFragmentSize);
}
else /* A new dma transfer has started */
{
DmaMode = DEV_WRITE; /* Dma mode is writing */
/* Copy fragment to dma buffer */
phys_copy(user_phys, DmaPhys, (phys_bytes) DspFragmentSize);
/* Set up the dma chip */
dsp_dma_setup(DmaPhys, DspFragmentSize);
/* Set up the DSP */
dsp_setup();
DmaBusy = 1; /* Dma is busy */
}
DmaDone = 1; /* dma done for now */
return(DspFragmentSize);
}
/*===========================================================================*
* dsp_read *
*===========================================================================*/
PRIVATE int dsp_read(m_ptr)
message *m_ptr;
{
phys_bytes user_phys;
message mess;
if (m_ptr->COUNT != DspFragmentSize) return EINVAL;
/* To this user address */
user_phys = numap(m_ptr->PROC_NR, (vir_bytes)m_ptr->ADDRESS, DspFragmentSize);
if (user_phys == 0) return EINVAL;
if (DmaBusy) /* Dma already started */
{
if (DmaMode != m_ptr->m_type) return EBUSY;
DmaDone = 0; /* No, we're not done yet */
/* Wait for a full dma buffer */
receive(HARDWARE, &mess);
/* Copy the buffer */
phys_copy(DmaPhys, user_phys, (phys_bytes) DspFragmentSize);
}
else /* A new dma transfer has started */
{
DmaMode = DEV_READ; /* Dma mode is reading */
/* Set up the dma chip */
dsp_dma_setup(DmaPhys, DspFragmentSize);
/* Set up the DSP */
dsp_setup();
DmaBusy = 1; /* Dma has started */
DmaDone = 0; /* Dma not done */
/* Wait for dma to finish with first block */
receive(HARDWARE, &mess);
/* Copy dma buffer to user */
phys_copy(DmaPhys, user_phys, (phys_bytes) DspFragmentSize);
}
DmaDone = 1; /* dma done for now */
return(DspFragmentSize);
}
#endif /* ENABLE_AUDIO */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -