drivers/sb16: delete altogether; the latest copy is in drivers/audio/sb16
This commit is contained in:
parent
294112db54
commit
7a9e3651fd
@ -66,8 +66,6 @@ drivers/printer/printer
|
||||
drivers/random/random
|
||||
drivers/rtl8139/rtl8139
|
||||
drivers/rtl8169/rtl8169
|
||||
drivers/sb16/sb16_dsp
|
||||
drivers/sb16/sb16_mixer
|
||||
drivers/ti1225/ti1225
|
||||
drivers/tty/tty
|
||||
);
|
||||
|
@ -10,7 +10,7 @@ SUBDIR = acpi
|
||||
|
||||
SUBDIR+= ahci amddev atl2 at_wini audio bios_wini dec21140A dp8390 dpeth \
|
||||
e1000 filter floppy fxp hello lance log orinoco pci printer \
|
||||
random readclock rtl8139 rtl8169 sb16 ti1225 tty \
|
||||
random readclock rtl8139 rtl8169 ti1225 tty \
|
||||
.WAIT ramdisk .WAIT memory
|
||||
|
||||
# memory driver must be last for ramdisk image
|
||||
|
@ -1,13 +0,0 @@
|
||||
# Makefile for the Sound Blaster 16 (SB16) driver
|
||||
|
||||
PROGS=sb16_mixer sb16_dsp
|
||||
|
||||
SRCS.sb16_dsp=sb16.c sb16_dsp.c sb16_dsp_liveupdate.c
|
||||
SRCS.sb16_mixer=sb16.c sb16_mixer.c
|
||||
MAN.sb16_dsp=
|
||||
MAN.sb16_mixer=
|
||||
|
||||
DPADD+= ${LIBDRIVER} ${LIBSYS}
|
||||
LDADD+= -ldriver -lsys
|
||||
|
||||
.include <bsd.prog.mk>
|
@ -1,47 +0,0 @@
|
||||
#include "sb16.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* mixer_set
|
||||
*===========================================================================*/
|
||||
PUBLIC int mixer_set(reg, data)
|
||||
int reg;
|
||||
int data;
|
||||
{
|
||||
int i;
|
||||
|
||||
sb16_outb(MIXER_REG, reg);
|
||||
for(i = 0; i < 100; i++);
|
||||
sb16_outb(MIXER_DATA, data);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* sb16_inb
|
||||
*===========================================================================*/
|
||||
PUBLIC int sb16_inb(port)
|
||||
int port;
|
||||
{
|
||||
int s;
|
||||
unsigned long value;
|
||||
|
||||
if ((s=sys_inb(port, &value)) != OK)
|
||||
panic("sys_inb() failed: %d", s);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* sb16_outb
|
||||
*===========================================================================*/
|
||||
PUBLIC void sb16_outb(port, value)
|
||||
int port;
|
||||
int value;
|
||||
{
|
||||
int s;
|
||||
|
||||
if ((s=sys_outb(port, value)) != OK)
|
||||
panic("sys_outb() failed: %d", s);
|
||||
}
|
@ -1,183 +0,0 @@
|
||||
#ifndef SB16_H
|
||||
#define SB16_H
|
||||
|
||||
#include <minix/drivers.h>
|
||||
#include <minix/driver.h>
|
||||
#include <sys/ioc_sound.h>
|
||||
#include <minix/sound.h>
|
||||
|
||||
#define SB_TIMEOUT 32000 /* timeout count */
|
||||
|
||||
/* IRQ, base address and DMA channels */
|
||||
#define SB_IRQ 7
|
||||
#define SB_BASE_ADDR 0x220 /* 0x210, 0x220, 0x230, 0x240,
|
||||
* 0x250, 0x260, 0x280
|
||||
*/
|
||||
#define SB_DMA_8 1 /* 0, 1, 3 */
|
||||
#define SB_DMA_16 5 /* 5, 6, 7 */
|
||||
#if _WORD_SIZE == 2
|
||||
#define DMA_SIZE 8192 /* Dma buffer MUST BE MULTIPLE OF 2 */
|
||||
#else
|
||||
#define DMA_SIZE (64 * 1024) /* Dma buffer MUST BE MULTIPLE OF 2 */
|
||||
#endif
|
||||
|
||||
/* Some defaults for the DSP */
|
||||
#define DEFAULT_SPEED 22050 /* Sample rate */
|
||||
#define DEFAULT_BITS 8 /* Nr. of bits */
|
||||
#define DEFAULT_SIGN 0 /* 0 = unsigned, 1 = signed */
|
||||
#define DEFAULT_STEREO 0 /* 0 = mono, 1 = stereo */
|
||||
|
||||
/* DMA port addresses */
|
||||
#define DMA8_ADDR (((SB_DMA_8 & 3) << 1) + 0x00)
|
||||
#define DMA8_COUNT (((SB_DMA_8 & 3) << 1) + 0x01)
|
||||
#define DMA8_MASK 0x0A
|
||||
#define DMA8_MODE 0x0B
|
||||
#define DMA8_CLEAR 0x0C
|
||||
|
||||
|
||||
/* If after this preprocessing stuff DMA8_PAGE is not defined
|
||||
* the 8-bit DMA channel specified is not valid
|
||||
*/
|
||||
#if SB_DMA_8 == 0
|
||||
# define DMA8_PAGE 0x87
|
||||
#else
|
||||
# if SB_DMA_8 == 1
|
||||
# define DMA8_PAGE 0x83
|
||||
# else
|
||||
# if SB_DMA_8 == 3
|
||||
# define DMA8_PAGE 0x82
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#define DMA16_ADDR (((SB_DMA_16 & 3) << 2) + 0xC0)
|
||||
#define DMA16_COUNT (((SB_DMA_16 & 3) << 2) + 0xC2)
|
||||
#define DMA16_MASK 0xD4
|
||||
#define DMA16_MODE 0xD6
|
||||
#define DMA16_CLEAR 0xD8
|
||||
|
||||
|
||||
/* If after this preprocessing stuff DMA16_PAGE is not defined
|
||||
* the 16-bit DMA channel specified is not valid
|
||||
*/
|
||||
#if SB_DMA_16 == 5
|
||||
# define DMA16_PAGE 0x8B
|
||||
#else
|
||||
# if SB_DMA_16 == 6
|
||||
# define DMA16_PAGE 0x89
|
||||
# else
|
||||
# if SB_DMA_16 == 7
|
||||
# define DMA16_PAGE 0x8A
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* DMA modes */
|
||||
#define DMA16_AUTO_PLAY (0x58 + (SB_DMA_16 & 3))
|
||||
#define DMA16_AUTO_REC (0x54 + (SB_DMA_16 & 3))
|
||||
#define DMA8_AUTO_PLAY (0x58 + SB_DMA_8)
|
||||
#define DMA8_AUTO_REC (0x54 + SB_DMA_8)
|
||||
|
||||
|
||||
/* IO ports for soundblaster */
|
||||
#define DSP_RESET (0x6 + SB_BASE_ADDR)
|
||||
#define DSP_READ (0xA + SB_BASE_ADDR)
|
||||
#define DSP_WRITE (0xC + SB_BASE_ADDR)
|
||||
#define DSP_COMMAND (0xC + SB_BASE_ADDR)
|
||||
#define DSP_STATUS (0xC + SB_BASE_ADDR)
|
||||
#define DSP_DATA_AVL (0xE + SB_BASE_ADDR)
|
||||
#define DSP_DATA16_AVL (0xF + SB_BASE_ADDR)
|
||||
#define MIXER_REG (0x4 + SB_BASE_ADDR)
|
||||
#define MIXER_DATA (0x5 + SB_BASE_ADDR)
|
||||
#define OPL3_LEFT (0x0 + SB_BASE_ADDR)
|
||||
#define OPL3_RIGHT (0x2 + SB_BASE_ADDR)
|
||||
#define OPL3_BOTH (0x8 + SB_BASE_ADDR)
|
||||
|
||||
|
||||
/* DSP Commands */
|
||||
#define DSP_INPUT_RATE 0x42 /* set input sample rate */
|
||||
#define DSP_OUTPUT_RATE 0x41 /* set output sample rate */
|
||||
#define DSP_CMD_SPKON 0xD1 /* set speaker on */
|
||||
#define DSP_CMD_SPKOFF 0xD3 /* set speaker off */
|
||||
#define DSP_CMD_DMA8HALT 0xD0 /* halt DMA 8-bit operation */
|
||||
#define DSP_CMD_DMA8CONT 0xD4 /* continue DMA 8-bit operation */
|
||||
#define DSP_CMD_DMA16HALT 0xD5 /* halt DMA 16-bit operation */
|
||||
#define DSP_CMD_DMA16CONT 0xD6 /* continue DMA 16-bit operation */
|
||||
#define DSP_GET_VERSION 0xE1 /* get version number of DSP */
|
||||
#define DSP_CMD_8BITAUTO_IN 0xCE /* 8 bit auto-initialized input */
|
||||
#define DSP_CMD_8BITAUTO_OUT 0xC6 /* 8 bit auto-initialized output */
|
||||
#define DSP_CMD_16BITAUTO_IN 0xBE /* 16 bit auto-initialized input */
|
||||
#define DSP_CMD_16BITAUTO_OUT 0xB6 /* 16 bit auto-initialized output */
|
||||
#define DSP_CMD_IRQREQ8 0xF2 /* Interrupt request 8 bit */
|
||||
#define DSP_CMD_IRQREQ16 0xF3 /* Interrupt request 16 bit */
|
||||
|
||||
|
||||
/* DSP Modes */
|
||||
#define DSP_MODE_MONO_US 0x00 /* Mono unsigned */
|
||||
#define DSP_MODE_MONO_S 0x10 /* Mono signed */
|
||||
#define DSP_MODE_STEREO_US 0x20 /* Stereo unsigned */
|
||||
#define DSP_MODE_STEREO_S 0x30 /* Stereo signed */
|
||||
|
||||
|
||||
/* MIXER commands */
|
||||
#define MIXER_RESET 0x00 /* Reset */
|
||||
#define MIXER_DAC_LEVEL 0x04 /* Used for detection only */
|
||||
#define MIXER_MASTER_LEFT 0x30 /* Master volume left */
|
||||
#define MIXER_MASTER_RIGHT 0x31 /* Master volume right */
|
||||
#define MIXER_DAC_LEFT 0x32 /* Dac level left */
|
||||
#define MIXER_DAC_RIGHT 0x33 /* Dac level right */
|
||||
#define MIXER_FM_LEFT 0x34 /* Fm level left */
|
||||
#define MIXER_FM_RIGHT 0x35 /* Fm level right */
|
||||
#define MIXER_CD_LEFT 0x36 /* Cd audio level left */
|
||||
#define MIXER_CD_RIGHT 0x37 /* Cd audio level right */
|
||||
#define MIXER_LINE_LEFT 0x38 /* Line in level left */
|
||||
#define MIXER_LINE_RIGHT 0x39 /* Line in level right */
|
||||
#define MIXER_MIC_LEVEL 0x3A /* Microphone level */
|
||||
#define MIXER_PC_LEVEL 0x3B /* Pc speaker level */
|
||||
#define MIXER_OUTPUT_CTRL 0x3C /* Output control */
|
||||
#define MIXER_IN_LEFT 0x3D /* Input control left */
|
||||
#define MIXER_IN_RIGHT 0x3E /* Input control right */
|
||||
#define MIXER_GAIN_IN_LEFT 0x3F /* Input gain control left */
|
||||
#define MIXER_GAIN_IN_RIGHT 0x40 /* Input gain control right */
|
||||
#define MIXER_GAIN_OUT_LEFT 0x41 /* Output gain control left */
|
||||
#define MIXER_GAIN_OUT_RIGHT 0x42 /* Output gain control rigth */
|
||||
#define MIXER_AGC 0x43 /* Automatic gain control */
|
||||
#define MIXER_TREBLE_LEFT 0x44 /* Treble left */
|
||||
#define MIXER_TREBLE_RIGHT 0x45 /* Treble right */
|
||||
#define MIXER_BASS_LEFT 0x46 /* Bass left */
|
||||
#define MIXER_BASS_RIGHT 0x47 /* Bass right */
|
||||
#define MIXER_SET_IRQ 0x80 /* Set irq number */
|
||||
#define MIXER_SET_DMA 0x81 /* Set DMA channels */
|
||||
#define MIXER_IRQ_STATUS 0x82 /* Irq status */
|
||||
|
||||
/* Mixer constants */
|
||||
#define MIC 0x01 /* Microphone */
|
||||
#define CD_RIGHT 0x02
|
||||
#define CD_LEFT 0x04
|
||||
#define LINE_RIGHT 0x08
|
||||
#define LINE_LEFT 0x10
|
||||
#define FM_RIGHT 0x20
|
||||
#define FM_LEFT 0x40
|
||||
|
||||
/* DSP constants */
|
||||
#define DMA_NR_OF_BUFFERS 2
|
||||
#define DSP_MAX_SPEED 44100 /* Max sample speed in KHz */
|
||||
#define DSP_MIN_SPEED 4000 /* Min sample speed in KHz */
|
||||
#define DSP_MAX_FRAGMENT_SIZE (DMA_SIZE / DMA_NR_OF_BUFFERS) /* Maximum fragment size */
|
||||
#define DSP_MIN_FRAGMENT_SIZE 1024 /* Minimum fragment size */
|
||||
#define DSP_NR_OF_BUFFERS 8
|
||||
|
||||
|
||||
/* Number of bytes you can DMA before hitting a 64K boundary: */
|
||||
#define dma_bytes_left(phys) \
|
||||
((unsigned) (sizeof(int) == 2 ? 0 : 0x10000) - (unsigned) ((phys) & 0xFFFF))
|
||||
|
||||
|
||||
_PROTOTYPE(int mixer_set, (int reg, int data));
|
||||
_PROTOTYPE( int sb16_inb, (int port) );
|
||||
_PROTOTYPE( void sb16_outb, (int port, int value) );
|
||||
|
||||
|
||||
#endif /* SB16_H */
|
@ -1,688 +0,0 @@
|
||||
/* This file contains the driver for a DSP (Digital Sound Processor) on
|
||||
* a SoundBlaster 16 soundcard.
|
||||
*
|
||||
* The driver supports the following operations (using message format m2):
|
||||
*
|
||||
* m_type DEVICE IO_ENDPT 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:
|
||||
*
|
||||
* main: main entry when driver is brought up
|
||||
*
|
||||
* August 24 2005 Ported driver to user space (only audio playback) (Peter Boonstoppel)
|
||||
* May 20 1995 Author: Michel R. Prevenier
|
||||
*/
|
||||
|
||||
#include <minix/endpoint.h>
|
||||
#include "sb16.h"
|
||||
|
||||
|
||||
FORWARD _PROTOTYPE( int dsp_open, (void) );
|
||||
FORWARD _PROTOTYPE( int dsp_close, (void) );
|
||||
FORWARD _PROTOTYPE( int dsp_ioctl, (const message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void dsp_write, (const message *m_ptr) );
|
||||
FORWARD _PROTOTYPE( void dsp_hardware_msg, (void) );
|
||||
FORWARD _PROTOTYPE( void dsp_status, (message *m_ptr) );
|
||||
|
||||
FORWARD _PROTOTYPE( void reply, (int code, int replyee, int process, int status) );
|
||||
FORWARD _PROTOTYPE( int dsp_init, (void) );
|
||||
FORWARD _PROTOTYPE( int dsp_reset, (void) );
|
||||
FORWARD _PROTOTYPE( int dsp_command, (int value) );
|
||||
FORWARD _PROTOTYPE( int dsp_set_size, (unsigned int size) );
|
||||
FORWARD _PROTOTYPE( int dsp_set_speed, (unsigned int speed) );
|
||||
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) );
|
||||
|
||||
PRIVATE int irq_hook_id; /* id of irq hook at the kernel */
|
||||
|
||||
PRIVATE char DmaBuffer[DMA_SIZE + 64 * 1024];
|
||||
PRIVATE char* DmaPtr;
|
||||
PRIVATE phys_bytes DmaPhys;
|
||||
|
||||
PRIVATE char Buffer[DSP_MAX_FRAGMENT_SIZE * DSP_NR_OF_BUFFERS];
|
||||
|
||||
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 DmaMode = 0;
|
||||
PRIVATE int DmaBusy = -1;
|
||||
PRIVATE int DmaFillNext = 0;
|
||||
PRIVATE int BufReadNext = -1;
|
||||
PRIVATE int BufFillNext = 0;
|
||||
|
||||
PRIVATE int revivePending = 0;
|
||||
PRIVATE int reviveStatus;
|
||||
PRIVATE int reviveProcNr;
|
||||
|
||||
#define dprint (void)
|
||||
|
||||
/* SEF functions and variables. */
|
||||
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
|
||||
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
|
||||
EXTERN _PROTOTYPE( int sef_cb_lu_prepare, (int state) );
|
||||
EXTERN _PROTOTYPE( int sef_cb_lu_state_isvalid, (int state) );
|
||||
EXTERN _PROTOTYPE( void sef_cb_lu_state_dump, (int state) );
|
||||
PUBLIC int is_processing = FALSE;
|
||||
PUBLIC int is_status_msg_expected = FALSE;
|
||||
|
||||
/*===========================================================================*
|
||||
* main
|
||||
*===========================================================================*/
|
||||
PUBLIC int main(int argc, char *argv[])
|
||||
{
|
||||
int r;
|
||||
endpoint_t caller;
|
||||
int proc_nr;
|
||||
message mess;
|
||||
int ipc_status;
|
||||
|
||||
/* SEF local startup. */
|
||||
sef_local_startup();
|
||||
|
||||
while(TRUE) {
|
||||
/* Wait for an incoming message */
|
||||
driver_receive(ANY, &mess, &ipc_status);
|
||||
|
||||
caller = mess.m_source;
|
||||
proc_nr = mess.IO_ENDPT;
|
||||
|
||||
if (is_ipc_notify(ipc_status)) {
|
||||
switch (_ENDPOINT_P(mess.m_source)) {
|
||||
case HARDWARE:
|
||||
dsp_hardware_msg();
|
||||
continue; /* don't reply */
|
||||
default:
|
||||
r = EINVAL;
|
||||
}
|
||||
|
||||
/* dont with this message */
|
||||
goto send_reply;
|
||||
}
|
||||
|
||||
/* Now carry out the work. */
|
||||
switch(mess.m_type) {
|
||||
case DEV_OPEN: r = dsp_open(); break;
|
||||
case DEV_CLOSE: r = dsp_close(); break;
|
||||
#ifdef DEV_IOCTL
|
||||
case DEV_IOCTL: r = dsp_ioctl(&mess); break;
|
||||
#endif
|
||||
#ifdef DEV_READ
|
||||
|
||||
case DEV_READ: r = EINVAL; break; /* Not yet implemented */
|
||||
case DEV_WRITE: dsp_write(&mess); continue; /* don't reply */
|
||||
#endif
|
||||
|
||||
case DEV_STATUS: dsp_status(&mess); continue; /* don't reply */
|
||||
default: r = EINVAL;
|
||||
}
|
||||
|
||||
send_reply:
|
||||
/* Finally, prepare and send the reply message. */
|
||||
reply(TASK_REPLY, caller, proc_nr, r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_local_startup *
|
||||
*===========================================================================*/
|
||||
PRIVATE void sef_local_startup(void)
|
||||
{
|
||||
/* Register init callbacks. */
|
||||
sef_setcb_init_fresh(sef_cb_init_fresh);
|
||||
sef_setcb_init_lu(sef_cb_init_fresh);
|
||||
sef_setcb_init_restart(sef_cb_init_fresh);
|
||||
|
||||
/* Register live update callbacks. */
|
||||
sef_setcb_lu_prepare(sef_cb_lu_prepare);
|
||||
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid);
|
||||
sef_setcb_lu_state_dump(sef_cb_lu_state_dump);
|
||||
|
||||
/* Let SEF perform startup. */
|
||||
sef_startup();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_init_fresh *
|
||||
*===========================================================================*/
|
||||
PRIVATE int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
|
||||
{
|
||||
/* Initialize the rtl8169 driver. */
|
||||
unsigned left;
|
||||
|
||||
/* Select a buffer that can safely be used for dma transfers.
|
||||
* Its absolute address is 'DmaPhys', the normal address is 'DmaPtr'.
|
||||
*/
|
||||
#if (CHIP == INTEL)
|
||||
DmaPtr = DmaBuffer;
|
||||
sys_umap(SELF, D, (vir_bytes)DmaBuffer, sizeof(DmaBuffer), &DmaPhys);
|
||||
|
||||
if((left = dma_bytes_left(DmaPhys)) < DMA_SIZE) {
|
||||
/* First half of buffer crosses a 64K boundary, can't DMA into that */
|
||||
DmaPtr += left;
|
||||
DmaPhys += left;
|
||||
}
|
||||
#else /* CHIP != INTEL */
|
||||
panic("initialization failed: CHIP != INTEL: %d", 0);
|
||||
#endif /* CHIP == INTEL */
|
||||
|
||||
/* Announce we are up! */
|
||||
driver_announce();
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_open
|
||||
*===========================================================================*/
|
||||
PRIVATE int dsp_open(void)
|
||||
{
|
||||
dprint("sb16_dsp.c: dsp_open()\n");
|
||||
|
||||
/* 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 / 2;
|
||||
|
||||
DspBusy = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_close
|
||||
*===========================================================================*/
|
||||
PRIVATE int dsp_close(void)
|
||||
{
|
||||
dprint("sb16_dsp.c: dsp_close()\n");
|
||||
|
||||
DspBusy = 0; /* soundcard available again */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_ioctl
|
||||
*===========================================================================*/
|
||||
PRIVATE int dsp_ioctl(const message *m_ptr)
|
||||
{
|
||||
int status;
|
||||
unsigned int val;
|
||||
|
||||
dprint("sb16_dsp.c: dsp_ioctl()\n");
|
||||
|
||||
/* Cannot change parameters during play or recording */
|
||||
if(DmaBusy >= 0) return EBUSY;
|
||||
|
||||
/* Get user data */
|
||||
if(m_ptr->REQUEST != DSPIORESET) {
|
||||
sys_vircopy(m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS, SELF, D, (vir_bytes)&val, sizeof(val));
|
||||
}
|
||||
|
||||
dprint("dsp_ioctl: got ioctl %d, argument: %d\n", m_ptr->REQUEST, val);
|
||||
|
||||
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 = DSP_MAX_FRAGMENT_SIZE;
|
||||
sys_vircopy(SELF, D, (vir_bytes)&val, m_ptr->IO_ENDPT, D, (vir_bytes)m_ptr->ADDRESS, sizeof(val));
|
||||
status = OK;
|
||||
break;
|
||||
case DSPIORESET: status = dsp_reset(); break;
|
||||
default: status = ENOTTY; break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_write
|
||||
*===========================================================================*/
|
||||
PRIVATE void dsp_write(const message *m_ptr)
|
||||
{
|
||||
message mess;
|
||||
int ipc_status;
|
||||
|
||||
dprint("sb16_dsp.c: dsp_write()\n");
|
||||
|
||||
if(m_ptr->COUNT != DspFragmentSize) {
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
|
||||
return;
|
||||
}
|
||||
if(m_ptr->m_type != DmaMode && DmaBusy >= 0) {
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
|
||||
return;
|
||||
}
|
||||
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);
|
||||
is_processing = TRUE;
|
||||
|
||||
if(DmaBusy < 0) { /* Dma tranfer not yet started */
|
||||
|
||||
DmaMode = DEV_WRITE_S; /* Dma mode is writing */
|
||||
sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)DmaPtr, (phys_bytes)DspFragmentSize);
|
||||
dsp_dma_setup(DmaPhys, DspFragmentSize * DMA_NR_OF_BUFFERS);
|
||||
dsp_setup();
|
||||
DmaBusy = 0; /* Dma is busy */
|
||||
dprint(" filled dma[0]\n");
|
||||
DmaFillNext = 1;
|
||||
|
||||
} else if(DmaBusy != DmaFillNext) { /* Dma transfer started, but Dma buffer not yet full */
|
||||
|
||||
sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)DmaPtr + DmaFillNext * DspFragmentSize, (phys_bytes)DspFragmentSize);
|
||||
dprint(" filled dma[%d]\n", DmaFillNext);
|
||||
DmaFillNext = (DmaFillNext + 1) % DMA_NR_OF_BUFFERS;
|
||||
|
||||
} else if(BufReadNext < 0) { /* Dma buffer full, fill first element of second buffer */
|
||||
|
||||
sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)Buffer, (phys_bytes)DspFragmentSize);
|
||||
dprint(" filled buf[0]\n");
|
||||
BufReadNext = 0;
|
||||
BufFillNext = 1;
|
||||
|
||||
} else { /* Dma buffer is full, filling second buffer */
|
||||
|
||||
while(BufReadNext == BufFillNext) { /* Second buffer also full, wait for space to become available */
|
||||
driver_receive(HARDWARE, &mess, &ipc_status);
|
||||
dsp_hardware_msg();
|
||||
}
|
||||
sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)Buffer + BufFillNext * DspFragmentSize, (phys_bytes)DspFragmentSize);
|
||||
dprint(" filled buf[%d]\n", BufFillNext);
|
||||
BufFillNext = (BufFillNext + 1) % DSP_NR_OF_BUFFERS;
|
||||
|
||||
}
|
||||
|
||||
is_status_msg_expected = TRUE;
|
||||
revivePending = 1;
|
||||
reviveStatus = DspFragmentSize;
|
||||
reviveProcNr = m_ptr->IO_ENDPT;
|
||||
notify(m_ptr->m_source);
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_hardware_msg
|
||||
*===========================================================================*/
|
||||
PRIVATE void dsp_hardware_msg()
|
||||
{
|
||||
dprint("Interrupt: ");
|
||||
if(DmaBusy >= 0) { /* Dma transfer was actually busy */
|
||||
dprint("Finished playing dma[%d]; ", DmaBusy);
|
||||
DmaBusy = (DmaBusy + 1) % DMA_NR_OF_BUFFERS;
|
||||
if(DmaBusy == DmaFillNext) { /* Dma buffer empty, stop Dma transfer */
|
||||
|
||||
dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));
|
||||
dprint("No more work...!\n");
|
||||
DmaBusy = -1;
|
||||
|
||||
} else if(BufReadNext >= 0) { /* Data in second buffer, copy one fragment to Dma buffer */
|
||||
|
||||
/* Acknowledge the interrupt on the DSP */
|
||||
sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
|
||||
|
||||
memcpy(DmaPtr + DmaFillNext * DspFragmentSize, Buffer + BufReadNext * DspFragmentSize, DspFragmentSize);
|
||||
dprint("copy buf[%d] -> dma[%d]; ", BufReadNext, DmaFillNext);
|
||||
BufReadNext = (BufReadNext + 1) % DSP_NR_OF_BUFFERS;
|
||||
DmaFillNext = (DmaFillNext + 1) % DMA_NR_OF_BUFFERS;
|
||||
if(BufReadNext == BufFillNext) {
|
||||
BufReadNext = -1;
|
||||
}
|
||||
dprint("Starting dma[%d]\n", DmaBusy);
|
||||
|
||||
return;
|
||||
|
||||
} else { /* Second buffer empty, still data in Dma buffer, continue playback */
|
||||
dprint("Starting dma[%d]\n", DmaBusy);
|
||||
}
|
||||
}
|
||||
|
||||
/* Acknowledge the interrupt on the DSP */
|
||||
sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_status *
|
||||
*===========================================================================*/
|
||||
PRIVATE void dsp_status(message *m_ptr)
|
||||
/* m_ptr pointer to the newly arrived message */
|
||||
{
|
||||
if(revivePending) {
|
||||
m_ptr->m_type = DEV_REVIVE; /* build message */
|
||||
m_ptr->REP_ENDPT = reviveProcNr;
|
||||
m_ptr->REP_STATUS = reviveStatus;
|
||||
|
||||
revivePending = 0; /* unmark event */
|
||||
is_processing = FALSE;
|
||||
} else {
|
||||
m_ptr->m_type = DEV_NO_STATUS;
|
||||
|
||||
is_status_msg_expected = FALSE;
|
||||
}
|
||||
|
||||
send(m_ptr->m_source, m_ptr); /* send the message */
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* reply *
|
||||
*===========================================================================*/
|
||||
PRIVATE void reply(int code, int replyee, int process, int status)
|
||||
{
|
||||
message m;
|
||||
|
||||
m.m_type = code; /* TASK_REPLY or REVIVE */
|
||||
m.REP_STATUS = status; /* result of device operation */
|
||||
m.REP_ENDPT = process; /* which user made the request */
|
||||
|
||||
send(replyee, &m);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_init
|
||||
*===========================================================================*/
|
||||
PRIVATE int dsp_init()
|
||||
{
|
||||
int i, s;
|
||||
|
||||
if(dsp_reset () != OK) {
|
||||
dprint("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(sb16_inb(DSP_DATA_AVL) & 0x80) {
|
||||
if(DspVersion[0] == 0) {
|
||||
DspVersion[0] = sb16_inb(DSP_READ);
|
||||
} else {
|
||||
DspVersion[1] = sb16_inb(DSP_READ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(DspVersion[0] < 4) {
|
||||
dprint("sb16: No SoundBlaster 16 compatible card detected\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dprint("sb16: SoundBlaster DSP version %d.%d detected\n", DspVersion[0], DspVersion[1]);
|
||||
|
||||
/* set SB to use our 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 */
|
||||
if ((s=sys_irqsetpolicy(SB_IRQ, IRQ_REENABLE, &irq_hook_id )) != OK)
|
||||
panic("Couldn't set IRQ policy: %d", s);
|
||||
if ((s=sys_irqenable(&irq_hook_id)) != OK)
|
||||
panic("Couldn't enable IRQ: %d", s);
|
||||
|
||||
DspAvail = 1;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_reset
|
||||
*===========================================================================*/
|
||||
PRIVATE int dsp_reset()
|
||||
{
|
||||
int i;
|
||||
|
||||
sb16_outb(DSP_RESET, 1);
|
||||
for(i = 0; i < 1000; i++); /* wait a while */
|
||||
sb16_outb(DSP_RESET, 0);
|
||||
|
||||
for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++);
|
||||
|
||||
if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */
|
||||
|
||||
DmaBusy = -1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_command
|
||||
*===========================================================================*/
|
||||
PRIVATE int dsp_command(int value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SB_TIMEOUT; i++) {
|
||||
if((sb16_inb(DSP_STATUS) & 0x80) == 0) {
|
||||
sb16_outb(DSP_COMMAND, value);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
dprint("sb16: SoundBlaster: DSP Command(%x) timeout\n", value);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_set_size
|
||||
*===========================================================================*/
|
||||
static int dsp_set_size(unsigned int size)
|
||||
{
|
||||
dprint("dsp_set_size(): set fragment size to %u\n", size);
|
||||
|
||||
/* Sanity checks */
|
||||
if(size < DSP_MIN_FRAGMENT_SIZE || size > DSP_MAX_FRAGMENT_SIZE || size % 2 != 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
DspFragmentSize = size;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_set_speed
|
||||
*===========================================================================*/
|
||||
static int dsp_set_speed(unsigned int speed)
|
||||
{
|
||||
dprint("sb16: setting speed to %u, stereo = %d\n", speed, DspStereo);
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
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);
|
||||
|
||||
DspSpeed = speed;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_set_stereo
|
||||
*===========================================================================*/
|
||||
static int dsp_set_stereo(unsigned int stereo)
|
||||
{
|
||||
if(stereo) {
|
||||
DspStereo = 1;
|
||||
} else {
|
||||
DspStereo = 0;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_set_bits
|
||||
*===========================================================================*/
|
||||
static int dsp_set_bits(unsigned int bits)
|
||||
{
|
||||
/* Sanity checks */
|
||||
if(bits != 8 && bits != 16) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
DspBits = bits;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_set_sign
|
||||
*===========================================================================*/
|
||||
static int dsp_set_sign(unsigned int sign)
|
||||
{
|
||||
dprint("sb16: set sign to %u\n", sign);
|
||||
|
||||
DspSign = (sign > 0 ? 1 : 0);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_dma_setup
|
||||
*===========================================================================*/
|
||||
PRIVATE void dsp_dma_setup(phys_bytes address, int count)
|
||||
{
|
||||
pvb_pair_t pvb[9];
|
||||
|
||||
|
||||
dprint("Setting up %d bit DMA\n", DspBits);
|
||||
|
||||
if(DspBits == 8) { /* 8 bit sound */
|
||||
count--;
|
||||
|
||||
pv_set(pvb[0], DMA8_MASK, SB_DMA_8 | 0x04); /* Disable DMA channel */
|
||||
pv_set(pvb[1], DMA8_CLEAR, 0x00); /* Clear flip flop */
|
||||
|
||||
/* set DMA mode */
|
||||
pv_set(pvb[2], DMA8_MODE, (DmaMode == DEV_WRITE_S ? DMA8_AUTO_PLAY : DMA8_AUTO_REC));
|
||||
|
||||
pv_set(pvb[3], DMA8_ADDR, (address >> 0) & 0xff); /* Low_byte of address */
|
||||
pv_set(pvb[4], DMA8_ADDR, (address >> 8) & 0xff); /* High byte of address */
|
||||
pv_set(pvb[5], DMA8_PAGE, (address >> 16) & 0xff); /* 64K page number */
|
||||
pv_set(pvb[6], DMA8_COUNT, (count >> 0) & 0xff); /* Low byte of count */
|
||||
pv_set(pvb[7], DMA8_COUNT, (count >> 8) & 0xff); /* High byte of count */
|
||||
pv_set(pvb[8], DMA8_MASK, SB_DMA_8); /* Enable DMA channel */
|
||||
|
||||
sys_voutb(pvb, 9);
|
||||
} else { /* 16 bit sound */
|
||||
count-= 2;
|
||||
|
||||
pv_set(pvb[0], DMA16_MASK, (SB_DMA_16 & 3) | 0x04); /* Disable DMA channel */
|
||||
|
||||
pv_set(pvb[1], DMA16_CLEAR, 0x00); /* Clear flip flop */
|
||||
|
||||
/* Set dma mode */
|
||||
pv_set(pvb[2], DMA16_MODE, (DmaMode == DEV_WRITE_S ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));
|
||||
|
||||
pv_set(pvb[3], DMA16_ADDR, (address >> 1) & 0xFF); /* Low_byte of address */
|
||||
pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF); /* High byte of address */
|
||||
pv_set(pvb[5], DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */
|
||||
pv_set(pvb[6], DMA16_COUNT, (count >> 1) & 0xff); /* Low byte of count */
|
||||
pv_set(pvb[7], DMA16_COUNT, (count >> 9) & 0xff); /* High byte of count */
|
||||
pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3); /* Enable DMA channel */
|
||||
|
||||
sys_voutb(pvb, 9);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*===========================================================================*
|
||||
* dsp_setup()
|
||||
*===========================================================================*/
|
||||
PRIVATE void dsp_setup()
|
||||
{
|
||||
/* Set current sample speed */
|
||||
dsp_set_speed(DspSpeed);
|
||||
|
||||
/* Put the speaker on */
|
||||
if(DmaMode == DEV_WRITE_S) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,68 +0,0 @@
|
||||
#include "sb16.h"
|
||||
|
||||
/* State management variables. */
|
||||
EXTERN int is_processing;
|
||||
EXTERN int is_status_msg_expected;
|
||||
|
||||
/* Custom states definition. */
|
||||
#define SB16_STATE_PROCESSING_PROTOCOL_FREE (SEF_LU_STATE_CUSTOM_BASE + 0)
|
||||
#define SB16_STATE_IS_CUSTOM(s) \
|
||||
((s) == SB16_STATE_PROCESSING_PROTOCOL_FREE)
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_lu_prepare *
|
||||
*===========================================================================*/
|
||||
PUBLIC int sef_cb_lu_prepare(int state)
|
||||
{
|
||||
int is_ready;
|
||||
|
||||
/* Check if we are ready for the target state. */
|
||||
is_ready = FALSE;
|
||||
switch(state) {
|
||||
/* Standard states. */
|
||||
case SEF_LU_STATE_REQUEST_FREE:
|
||||
is_ready = TRUE;
|
||||
break;
|
||||
|
||||
case SEF_LU_STATE_PROTOCOL_FREE:
|
||||
is_ready = (!is_processing && !is_status_msg_expected);
|
||||
break;
|
||||
|
||||
/* Custom states. */
|
||||
case SB16_STATE_PROCESSING_PROTOCOL_FREE:
|
||||
is_ready = (!is_processing);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Tell SEF if we are ready. */
|
||||
return is_ready ? OK : ENOTREADY;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_lu_state_isvalid *
|
||||
*===========================================================================*/
|
||||
PUBLIC int sef_cb_lu_state_isvalid(int state)
|
||||
{
|
||||
return SEF_LU_STATE_IS_STANDARD(state) || SB16_STATE_IS_CUSTOM(state);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_lu_state_dump *
|
||||
*===========================================================================*/
|
||||
PUBLIC void sef_cb_lu_state_dump(int state)
|
||||
{
|
||||
sef_lu_dprint("sb16: live update state = %d\n", state);
|
||||
sef_lu_dprint("sb16: is_processing = %d\n", is_processing);
|
||||
sef_lu_dprint("sb16: is_status_msg_expected = %d\n",
|
||||
is_status_msg_expected);
|
||||
|
||||
sef_lu_dprint("sb16: SEF_LU_STATE_WORK_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_WORK_FREE, TRUE);
|
||||
sef_lu_dprint("sb16: SEF_LU_STATE_REQUEST_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_REQUEST_FREE, TRUE);
|
||||
sef_lu_dprint("sb16: SEF_LU_STATE_PROTOCOL_FREE(%d) reached = %d\n",
|
||||
SEF_LU_STATE_PROTOCOL_FREE, (!is_processing && !is_status_msg_expected));
|
||||
sef_lu_dprint("sb16: SB16_STATE_PROCESSING_PROTOCOL_FREE(%d) reached = %d\n",
|
||||
SB16_STATE_PROCESSING_PROTOCOL_FREE, (!is_processing));
|
||||
}
|
||||
|
@ -1,417 +0,0 @@
|
||||
/* This file contains the driver for the mixer on
|
||||
* a SoundBlaster 16 soundcard.
|
||||
*
|
||||
* The driver supports the following operations (using message format m2):
|
||||
*
|
||||
* m_type DEVICE IO_ENDPT COUNT POSITION ADRRESS
|
||||
* ----------------------------------------------------------------
|
||||
* | DEV_OPEN | device | proc nr | | | |
|
||||
* |------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_CLOSE | device | proc nr | | | |
|
||||
* |------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_IOCTL | device | proc nr |func code| | buf_ptr |
|
||||
* ----------------------------------------------------------------
|
||||
*
|
||||
* The file contains one entry point:
|
||||
*
|
||||
* sb16mixer_task: main entry when system is brought up
|
||||
*
|
||||
* August 24 2005 Ported driver to user space (Peter Boonstoppel)
|
||||
* May 20 1995 Author: Michel R. Prevenier
|
||||
*/
|
||||
|
||||
|
||||
#include "sb16.h"
|
||||
|
||||
|
||||
FORWARD _PROTOTYPE( int mixer_init, (void));
|
||||
FORWARD _PROTOTYPE( int mixer_open, (const message *m_ptr));
|
||||
FORWARD _PROTOTYPE( int mixer_close, (const message *m_ptr));
|
||||
FORWARD _PROTOTYPE( int mixer_ioctl, (const message *m_ptr));
|
||||
FORWARD _PROTOTYPE( int mixer_get, (int reg));
|
||||
FORWARD _PROTOTYPE( int get_set_volume, (const message *m_ptr, int flag));
|
||||
FORWARD _PROTOTYPE( int get_set_input, (const message *m_ptr, int flag, int channel));
|
||||
FORWARD _PROTOTYPE( int get_set_output, (const message *m_ptr, int flag));
|
||||
|
||||
|
||||
PRIVATE int mixer_avail = 0; /* Mixer exists? */
|
||||
|
||||
|
||||
#define dprint (void)
|
||||
|
||||
/* SEF functions and variables. */
|
||||
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
|
||||
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
|
||||
|
||||
/*===========================================================================*
|
||||
* main
|
||||
*===========================================================================*/
|
||||
PUBLIC int main(int argc, char *argv[])
|
||||
{
|
||||
message mess;
|
||||
int ipc_status;
|
||||
int err, caller, proc_nr;
|
||||
|
||||
/* SEF local startup. */
|
||||
sef_local_startup();
|
||||
|
||||
/* Here is the main loop of the mixer task. It waits for a message, carries
|
||||
* it out, and sends a reply.
|
||||
*/
|
||||
while (TRUE) {
|
||||
driver_receive(ANY, &mess, &ipc_status);
|
||||
|
||||
caller = mess.m_source;
|
||||
proc_nr = mess.IO_ENDPT;
|
||||
|
||||
switch (caller) {
|
||||
case HARDWARE: /* Leftover interrupt. */
|
||||
continue;
|
||||
case VFS_PROC_NR: /* The only legitimate caller. */
|
||||
break;
|
||||
default:
|
||||
dprint("sb16: got message from %d\n", caller);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now carry out the work. */
|
||||
switch(mess.m_type) {
|
||||
case DEV_OPEN: err = mixer_open(&mess); break;
|
||||
case DEV_CLOSE: err = mixer_close(&mess); break;
|
||||
#ifdef DEV_IOCTL
|
||||
case DEV_IOCTL: err = mixer_ioctl(&mess); break;
|
||||
#endif
|
||||
default: err = EINVAL; break;
|
||||
}
|
||||
|
||||
/* Finally, prepare and send the reply message. */
|
||||
mess.m_type = TASK_REPLY;
|
||||
mess.REP_ENDPT = proc_nr;
|
||||
|
||||
dprint("%d %d", err, OK);
|
||||
|
||||
mess.REP_STATUS = err; /* error code */
|
||||
send(caller, &mess); /* send reply to caller */
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_local_startup *
|
||||
*===========================================================================*/
|
||||
PRIVATE void sef_local_startup()
|
||||
{
|
||||
/* Register init callbacks. */
|
||||
sef_setcb_init_fresh(sef_cb_init_fresh);
|
||||
sef_setcb_init_lu(sef_cb_init_fresh);
|
||||
sef_setcb_init_restart(sef_cb_init_fresh);
|
||||
|
||||
/* Register live update callbacks. */
|
||||
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
|
||||
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
|
||||
|
||||
/* Let SEF perform startup. */
|
||||
sef_startup();
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* sef_cb_init_fresh *
|
||||
*===========================================================================*/
|
||||
PRIVATE int sef_cb_init_fresh(int type, sef_init_info_t *info)
|
||||
{
|
||||
/* Initialize the sb16 mixer driver. */
|
||||
/* Announce we are up! */
|
||||
driver_announce();
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*=========================================================================*
|
||||
* mixer_open
|
||||
*=========================================================================*/
|
||||
PRIVATE int mixer_open(const message *m_ptr)
|
||||
{
|
||||
dprint("mixer_open\n");
|
||||
|
||||
/* try to detect the mixer type */
|
||||
if (!mixer_avail && mixer_init() != OK) return EIO;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*
|
||||
* mixer_close
|
||||
*=========================================================================*/
|
||||
PRIVATE int mixer_close(const message *m_ptr)
|
||||
{
|
||||
dprint("mixer_close\n");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*
|
||||
* mixer_ioctl
|
||||
*=========================================================================*/
|
||||
PRIVATE int mixer_ioctl(const message *m_ptr)
|
||||
{
|
||||
int status;
|
||||
|
||||
dprint("mixer: got ioctl %d\n", m_ptr->REQUEST);
|
||||
|
||||
|
||||
switch(m_ptr->REQUEST) {
|
||||
case MIXIOGETVOLUME: status = get_set_volume(m_ptr, 0); break;
|
||||
case MIXIOSETVOLUME: status = get_set_volume(m_ptr, 1); break;
|
||||
case MIXIOGETINPUTLEFT: status = get_set_input(m_ptr, 0, 0); break;
|
||||
case MIXIOGETINPUTRIGHT: status = get_set_input(m_ptr, 0, 1); break;
|
||||
case MIXIOGETOUTPUT: status = get_set_output(m_ptr, 0); break;
|
||||
case MIXIOSETINPUTLEFT: status = get_set_input(m_ptr, 1, 0); break;
|
||||
case MIXIOSETINPUTRIGHT: status = get_set_input(m_ptr, 1, 1); break;
|
||||
case MIXIOSETOUTPUT: status = get_set_output(m_ptr, 1); break;
|
||||
default: status = ENOTTY;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*
|
||||
* mixer_init
|
||||
*=========================================================================*/
|
||||
PRIVATE int mixer_init()
|
||||
{
|
||||
/* Try to detect the mixer by writing to MIXER_DAC_LEVEL if the
|
||||
* value written can be read back the mixer is there
|
||||
*/
|
||||
|
||||
mixer_set(MIXER_DAC_LEVEL, 0x10); /* write something to it */
|
||||
if(mixer_get(MIXER_DAC_LEVEL) != 0x10) {
|
||||
dprint("sb16: Mixer not detected\n");
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/* Enable Automatic Gain Control */
|
||||
mixer_set(MIXER_AGC, 0x01);
|
||||
|
||||
dprint("Mixer detected\n");
|
||||
|
||||
mixer_avail = 1;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*
|
||||
* mixer_get
|
||||
*=========================================================================*/
|
||||
PRIVATE int mixer_get(int reg)
|
||||
{
|
||||
int i;
|
||||
|
||||
sb16_outb(MIXER_REG, reg);
|
||||
for(i = 0; i < 100; i++);
|
||||
return sb16_inb(MIXER_DATA) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*
|
||||
* get_set_volume *
|
||||
*=========================================================================*/
|
||||
PRIVATE int get_set_volume(const message *m_ptr, int flag)
|
||||
/* flag 0 = get, 1 = set */
|
||||
{
|
||||
struct volume_level level;
|
||||
int cmd_left, cmd_right, shift, max_level;
|
||||
|
||||
sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)&level, (phys_bytes)sizeof(level));
|
||||
|
||||
shift = 3;
|
||||
max_level = 0x1F;
|
||||
|
||||
switch(level.device) {
|
||||
case Master:
|
||||
cmd_left = MIXER_MASTER_LEFT;
|
||||
cmd_right = MIXER_MASTER_RIGHT;
|
||||
break;
|
||||
case Dac:
|
||||
cmd_left = MIXER_DAC_LEFT;
|
||||
cmd_right = MIXER_DAC_RIGHT;
|
||||
break;
|
||||
case Fm:
|
||||
cmd_left = MIXER_FM_LEFT;
|
||||
cmd_right = MIXER_FM_RIGHT;
|
||||
break;
|
||||
case Cd:
|
||||
cmd_left = MIXER_CD_LEFT;
|
||||
cmd_right = MIXER_CD_RIGHT;
|
||||
break;
|
||||
case Line:
|
||||
cmd_left = MIXER_LINE_LEFT;
|
||||
cmd_right = MIXER_LINE_RIGHT;
|
||||
break;
|
||||
case Mic:
|
||||
cmd_left = cmd_right = MIXER_MIC_LEVEL;
|
||||
break;
|
||||
case Speaker:
|
||||
cmd_left = cmd_right = MIXER_PC_LEVEL;
|
||||
shift = 6;
|
||||
max_level = 0x03;
|
||||
break;
|
||||
case Treble:
|
||||
cmd_left = MIXER_TREBLE_LEFT;
|
||||
cmd_right = MIXER_TREBLE_RIGHT;
|
||||
shift = 4;
|
||||
max_level = 0x0F;
|
||||
break;
|
||||
case Bass:
|
||||
cmd_left = MIXER_BASS_LEFT;
|
||||
cmd_right = MIXER_BASS_RIGHT;
|
||||
shift = 4;
|
||||
max_level = 0x0F;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if(flag) { /* Set volume level */
|
||||
if(level.right < 0) level.right = 0;
|
||||
else if(level.right > max_level) level.right = max_level;
|
||||
if(level.left < 0) level.left = 0;
|
||||
else if(level.left > max_level) level.left = max_level;
|
||||
|
||||
mixer_set(cmd_right, (level.right << shift));
|
||||
mixer_set(cmd_left, (level.left << shift));
|
||||
} else { /* Get volume level */
|
||||
level.left = mixer_get(cmd_left);
|
||||
level.right = mixer_get(cmd_right);
|
||||
|
||||
level.left >>= shift;
|
||||
level.right >>= shift;
|
||||
|
||||
/* Copy back to user */
|
||||
sys_datacopy(SELF, (vir_bytes)&level, m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(level));
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*
|
||||
* get_set_input *
|
||||
*=========================================================================*/
|
||||
PRIVATE int get_set_input(const message *m_ptr, int flag, int channel)
|
||||
/*
|
||||
* flag 0 = get, 1 = set
|
||||
* channel 0 = left, 1 = right
|
||||
*/
|
||||
{
|
||||
struct inout_ctrl input;
|
||||
int input_cmd, input_mask, mask, del_mask, shift;
|
||||
|
||||
sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)&input, (phys_bytes)sizeof(input));
|
||||
|
||||
input_cmd = (channel == 0 ? MIXER_IN_LEFT : MIXER_IN_RIGHT);
|
||||
|
||||
mask = mixer_get(input_cmd);
|
||||
|
||||
switch (input.device) {
|
||||
case Fm:
|
||||
shift = 5;
|
||||
del_mask = 0x1F;
|
||||
break;
|
||||
case Cd:
|
||||
shift = 1;
|
||||
del_mask = 0x79;
|
||||
break;
|
||||
case Line:
|
||||
shift = 3;
|
||||
del_mask = 0x67;
|
||||
break;
|
||||
case Mic:
|
||||
shift = 0;
|
||||
del_mask = 0x7E;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (flag) { /* Set input */
|
||||
input_mask = ((input.left == ON ? 1 : 0) << 1) | (input.right == ON ? 1 : 0);
|
||||
|
||||
if (shift > 0) input_mask <<= shift;
|
||||
else input_mask >>= 1;
|
||||
|
||||
mask &= del_mask;
|
||||
mask |= input_mask;
|
||||
|
||||
mixer_set(input_cmd, mask);
|
||||
} else { /* Get input */
|
||||
if (shift > 0) {
|
||||
input.left = ((((mask >> (shift+1)) & 1) == 1) ? ON : OFF);
|
||||
input.right = ((((mask >> shift) & 1) == 1) ? ON : OFF);
|
||||
} else {
|
||||
input.left = (((mask & 1) == 1) ? ON : OFF);
|
||||
}
|
||||
|
||||
/* Copy back to user */
|
||||
sys_datacopy(SELF, (vir_bytes)&input, m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(input));
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*=========================================================================*
|
||||
* get_set_output *
|
||||
*=========================================================================*/
|
||||
PRIVATE int get_set_output(const message *m_ptr, int flag)
|
||||
/* flag 0 = get, 1 = set */
|
||||
{
|
||||
struct inout_ctrl output;
|
||||
int output_mask, mask, del_mask, shift;
|
||||
|
||||
sys_datacopy(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, SELF, (vir_bytes)&output, (phys_bytes)sizeof(output));
|
||||
|
||||
mask = mixer_get(MIXER_OUTPUT_CTRL);
|
||||
|
||||
switch (output.device) {
|
||||
case Cd:
|
||||
shift = 1;
|
||||
del_mask = 0x79;
|
||||
break;
|
||||
case Line:
|
||||
shift = 3;
|
||||
del_mask = 0x67;
|
||||
break;
|
||||
case Mic:
|
||||
shift = 0;
|
||||
del_mask = 0x7E;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (flag) { /* Set input */
|
||||
output_mask = ((output.left == ON ? 1 : 0) << 1) | (output.right == ON ? 1 : 0);
|
||||
|
||||
if (shift > 0) output_mask <<= shift;
|
||||
else output_mask >>= 1;
|
||||
|
||||
mask &= del_mask;
|
||||
mask |= output_mask;
|
||||
|
||||
mixer_set(MIXER_OUTPUT_CTRL, mask);
|
||||
} else { /* Get input */
|
||||
if (shift > 0) {
|
||||
output.left = ((((mask >> (shift+1)) & 1) == 1) ? ON : OFF);
|
||||
output.right = ((((mask >> shift) & 1) == 1) ? ON : OFF);
|
||||
} else {
|
||||
output.left = (((mask & 1) == 1) ? ON : OFF);
|
||||
}
|
||||
|
||||
/* Copy back to user */
|
||||
sys_datacopy(SELF, (vir_bytes)&output, m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(output));
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user