📄 sb16_dsp.c
字号:
/* This file contains the driver for a DSP (Digital Sound Processor) on
* a SoundBlaster 16 (ASP) soundcard.
*
* The driver supports the following operations (using message format m2):
*
* m_type DEVICE PROC_NR COUNT POSITION ADRRESS
* ----------------------------------------------------------------
* | DEV_OPEN | device | proc nr | | | |
* |------------+---------+---------+---------+---------+---------|
* | DEV_CLOSE | device | proc nr | | | |
* |------------+---------+---------+---------+---------+---------|
* | DEV_READ | device | proc nr | bytes | | buf ptr |
* |------------+---------+---------+---------+---------+---------|
* | DEV_WRITE | device | proc nr | bytes | | buf ptr |
* |------------+---------+---------+---------+---------+---------|
* | DEV_IOCTL | device | proc nr |func code| | buf ptr |
* ----------------------------------------------------------------
*
* The file contains one entry point:
*
* dsp_task: main entry when system is brought up
*
* May 20 1995 Author: Michel R. Prevenier
*/
#include "kernel.h"
#include <minix/com.h>
#include <minix/callnr.h>
#include <sys/ioctl.h>
#if __minix_vmd
#include "proc.h"
#include "config.h"
#endif
#include "sb16.h"
#if ENABLE_SB_AUDIO
/* prototypes */
FORWARD _PROTOTYPE( void init_buffer, (void));
FORWARD _PROTOTYPE( int dsp_init, (void));
FORWARD _PROTOTYPE( int dsp_handler, (int irq));
FORWARD _PROTOTYPE( int dsp_open, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_close, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_ioctl, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_write, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_read, (message *m_ptr));
FORWARD _PROTOTYPE( int dsp_reset, (void));
FORWARD _PROTOTYPE( int dsp_command, (int value));
FORWARD _PROTOTYPE( int dsp_set_speed, (unsigned int speed));
FORWARD _PROTOTYPE( int dsp_set_size, (unsigned int size));
FORWARD _PROTOTYPE( int dsp_set_stereo, (unsigned int stereo));
FORWARD _PROTOTYPE( int dsp_set_bits, (unsigned int bits));
FORWARD _PROTOTYPE( int dsp_set_sign, (unsigned int sign));
FORWARD _PROTOTYPE( void dsp_dma_setup, (phys_bytes address, int count));
FORWARD _PROTOTYPE( void dsp_setup, (void));
/* globals */
#if __minix_vmd
PRIVATE int DspTasknr = ANY;
#endif
PRIVATE int DspVersion[2];
PRIVATE unsigned int DspStereo = DEFAULT_STEREO;
PRIVATE unsigned int DspSpeed = DEFAULT_SPEED;
PRIVATE unsigned int DspBits = DEFAULT_BITS;
PRIVATE unsigned int DspSign = DEFAULT_SIGN;
PRIVATE unsigned int DspFragmentSize = DSP_MAX_FRAGMENT_SIZE;
PRIVATE int DspAvail = 0;
PRIVATE int DspBusy = 0;
PRIVATE int DmaBusy = 0;
PRIVATE int DmaDone = 1;
PRIVATE int DmaMode = 0;
PRIVATE char DmaBuffer[(long)2 * DMA_SIZE];
PRIVATE char *DmaPtr;
PRIVATE phys_bytes DmaPhys;
/*=========================================================================*
* dsp_task *
*=========================================================================*/
PUBLIC void dsp_task()
{
message mess;
int err, caller, proc_nr;
#if __minix_vmd
DspTasknr = proc_number(proc_ptr);
#endif
/* initialize the DMA buffer */
init_buffer();
/* Here is the main loop of the sound task. It waits for a message, carries
* it out, and sends a reply.
*/
while (TRUE)
{
receive(ANY, &mess);
caller = mess.m_source;
proc_nr = mess.PROC_NR;
switch (caller)
{
case HARDWARE:
/* Leftover interrupt. */
continue;
case FS_PROC_NR:
/* The only legitimate caller. */
break;
default:
printf("sb16: got message from %d\n", caller);
continue;
}
/* Now carry out the work. */
switch(mess.m_type)
{
case DEV_OPEN: err = dsp_open(&mess);break;
case DEV_CLOSE: err = dsp_close(&mess);break;
case DEV_IOCTL: err = dsp_ioctl(&mess);break;
case DEV_READ: err = dsp_read(&mess);break;
case DEV_WRITE: err = dsp_write(&mess);break;
default: err = EINVAL;break;
}
/* Finally, prepare and send the reply message. */
mess.m_type = TASK_REPLY;
mess.REP_PROC_NR = proc_nr;
mess.REP_STATUS = err; /* #bytes transfered or error code */
send(caller, &mess); /* send reply to caller */
}
}
/*===========================================================================*
* init_buffer *
*===========================================================================*/
PRIVATE void init_buffer()
{
/* Select a buffer that can safely be used for dma transfers.
* Its absolute address is 'DmaPhys', the normal address is 'DmaPtr'.
*/
DmaPtr = DmaBuffer;
DmaPhys = vir2phys(DmaBuffer);
if (dma_bytes_left(DmaPhys) < DMA_SIZE) {
/* First half of buffer crosses a 64K boundary, can't DMA into that */
DmaPtr += DMA_SIZE;
DmaPhys += DMA_SIZE;
}
}
/*=========================================================================*
* dsp_open *
*=========================================================================*/
PRIVATE int dsp_open(m_ptr)
message *m_ptr;
{
#if SB_DEBUG
printf("sb16_open\n");
#endif
/* try to detect SoundBlaster card */
if (!DspAvail && dsp_init() != OK) return EIO;
/* Only one open at a time with soundcards */
if (DspBusy) return EBUSY;
/* Start with a clean DSP */
if (dsp_reset() != OK) return EIO;
/* Setup default values */
DspStereo = DEFAULT_STEREO;
DspSpeed = DEFAULT_SPEED;
DspBits = DEFAULT_BITS;
DspSign = DEFAULT_SIGN;
DspFragmentSize = DMA_SIZE;
DspBusy = 1;
DmaBusy = 0;
return OK;
}
/*=========================================================================*
* dsp_close *
*=========================================================================*/
PRIVATE int dsp_close(m_ptr)
message *m_ptr;
{
#if SB_DEBUG
printf("dsp_close\n");
#endif
DspBusy = 0; /* soundcard available again */
DmaBusy = 0;
return OK;
}
/*=========================================================================*
* dsp_ioctl *
*=========================================================================*/
PRIVATE int dsp_ioctl(m_ptr)
message *m_ptr;
{
int status;
phys_bytes user_phys;
unsigned int val;
/* Cannot change parameters during play or recording */
if (DmaBusy) return EBUSY;
/* Get user data */
if (m_ptr->REQUEST != DSPIORESET)
{
user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS,
sizeof(unsigned int));
if (user_phys == 0) return(EFAULT);
phys_copy(user_phys, vir2phys(&val), (phys_bytes) sizeof(val));
}
#if SB_DEBUG
printf("dsp_ioctl: got ioctl %d, argument: %d\n", m_ptr->REQUEST, val);
#endif
switch(m_ptr->REQUEST)
{
case DSPIORATE: status = dsp_set_speed(val);break;
case DSPIOSTEREO: status = dsp_set_stereo(val);break;
case DSPIOBITS: status = dsp_set_bits(val);break;
case DSPIOSIZE: status = dsp_set_size(val);break;
case DSPIOSIGN: status = dsp_set_sign(val);break;
case DSPIOMAX: {
val = DMA_SIZE;
phys_copy(vir2phys(&val), user_phys,
(phys_bytes) sizeof(val));
status = OK;
};break;
case DSPIORESET: status = dsp_reset();break;
default: status = ENOTTY;break;
}
return status;
}
/*=========================================================================*
* dsp_init *
*=========================================================================*/
PRIVATE int dsp_init()
{
int i;
if (dsp_reset () != OK)
{
printf("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 (in_byte (DSP_DATA_AVL) & 0x80)
{
if (DspVersion[0] == 0)
DspVersion[0] = in_byte (DSP_READ);
else
{
DspVersion[1] = in_byte (DSP_READ);
break;
}
}
}
if (DspVersion[0] < 4)
{
printf("sb16: No SoundBlaster 16 compatible card detected\n");
return -1;
}
else
printf ("sb16: SoundBlaster DSP version %d.%d detected\n",
DspVersion[0], DspVersion[1]);
/* set 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 */
put_irq_handler(SB_IRQ, dsp_handler);
enable_irq(SB_IRQ);
DspAvail = 1;
return OK;
}
/*=========================================================================*
* dsp_handler *
*=========================================================================*/
PRIVATE int dsp_handler(irq)
int irq;
{
#if SB_DEBUG2
printf("SoundBlaster interrupt %d\n", irq);
#endif
if (DmaDone) /* Dma transfer is done */
{
/* Send DSP command to stop dma */
dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));
DmaBusy = 0; /* Dma available again */
}
/* Send interrupt to audio task and enable again */
#if __minix_vmd
interrupt(DspTasknr);
#else
interrupt(AUDIO);
#endif
/* Acknowledge the interrupt on the DSP */
(void) in_byte((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
return 1;
}
/*=========================================================================*
* dsp_command *
*=========================================================================*/
PRIVATE int dsp_command(value)
int value;
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -