From c4e4398043f3bc3b3f4abd52622a7bb96a51c16e Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Fri, 16 Sep 2005 11:09:08 +0000 Subject: [PATCH] Update by paboonst@cs.vu.nl --- drivers/sb16/Makefile | 18 +- drivers/sb16/README | 21 +++ drivers/sb16/sb16.c | 46 +++++ drivers/sb16/sb16.h | 20 +- drivers/sb16/sb16.tar | Bin 0 -> 46592 bytes drivers/sb16/sb16_dsp.c | 175 +++++++++-------- drivers/sb16/sb16_mixer.c | 387 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 578 insertions(+), 89 deletions(-) create mode 100644 drivers/sb16/README create mode 100644 drivers/sb16/sb16.c create mode 100644 drivers/sb16/sb16.tar create mode 100644 drivers/sb16/sb16_mixer.c diff --git a/drivers/sb16/Makefile b/drivers/sb16/Makefile index 71070d046..24390b971 100644 --- a/drivers/sb16/Makefile +++ b/drivers/sb16/Makefile @@ -1,5 +1,4 @@ # Makefile for the Sound Blaster 16 driver (SB16) -DRIVER = sb16_dsp # directories u = /usr @@ -15,19 +14,20 @@ CFLAGS = -I$i LDFLAGS = -i LIBS = -lsys -lsysutil -OBJ = sb16_dsp.o # build local binary -all build: $(DRIVER) -$(DRIVER): $(OBJ) - $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) -# install -S 256w $(DRIVER) +all build: sb16_dsp sb16_mixer +sb16_dsp: sb16.o sb16_dsp.o + $(CC) -o $@ $(LDFLAGS) sb16.o sb16_dsp.o $(LIBS) +sb16_mixer: sb16.o sb16_mixer.o + $(CC) -o $@ $(LDFLAGS) sb16.o sb16_mixer.o $(LIBS) # install with other drivers -install: /usr/sbin/$(DRIVER) -/usr/sbin/$(DRIVER): $(DRIVER) +install: /usr/sbin/sb16_dsp /usr/sbin/sb16_mixer +/usr/sbin/sb16_dsp: sb16_dsp + install -o root -c $? $@ +/usr/sbin/sb16_mixer: sb16_mixer install -o root -c $? $@ -# install -o root -cs $? $@ # clean up local files clean: diff --git a/drivers/sb16/README b/drivers/sb16/README new file mode 100644 index 000000000..08e62a231 --- /dev/null +++ b/drivers/sb16/README @@ -0,0 +1,21 @@ + +Sound Blaster 16 ISA driver for Minix 3 + +Note: supports audio playback and volume control (mixer), +recording is not yet supported + + +Installation instructions SB16 driver Minix >= 3.0.7 + +- set IRQ and I/O address in sb16.h +(default 7 and 220) +- make install +- MAKEDEV /dev/audio (if /dev/audio doesn't allready exist) +- service up /usr/sbin/sb16_dsp -dev /dev/audio +- service up /usr/sbin/sb16_mixer -dev /dev/mixer +done... (you can include the last 2 lines in /usr/etc/rc) + + +Peter Boonstoppel - September 2005 +paboonst@cs.vu.nl + diff --git a/drivers/sb16/sb16.c b/drivers/sb16/sb16.c new file mode 100644 index 000000000..3257fa976 --- /dev/null +++ b/drivers/sb16/sb16.c @@ -0,0 +1,46 @@ +#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, value = -1; + + if ((s=sys_inb(port, &value)) != OK) + panic("SB16DSP","sys_inb() failed", 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("SB16DSP","sys_outb() failed", s); +} \ No newline at end of file diff --git a/drivers/sb16/sb16.h b/drivers/sb16/sb16.h index ae1becd64..3396743c1 100644 --- a/drivers/sb16/sb16.h +++ b/drivers/sb16/sb16.h @@ -1,8 +1,10 @@ #ifndef SB16_H #define SB16_H -#define SB_DEBUG 0 /* 1 = print debug info */ -#define SB_DEBUG_2 0 /* 1 = print more debug info */ +#include "../drivers.h" +#include +#include + #define SB_TIMEOUT 32000 /* timeout count */ @@ -32,6 +34,7 @@ #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 */ @@ -54,6 +57,7 @@ #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 */ @@ -69,12 +73,14 @@ # 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 @@ -89,6 +95,7 @@ #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 */ @@ -106,12 +113,14 @@ #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 */ @@ -160,8 +169,15 @@ #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 */ diff --git a/drivers/sb16/sb16.tar b/drivers/sb16/sb16.tar new file mode 100644 index 0000000000000000000000000000000000000000..854c41f959c592f2487ed1fe8372629c50620da8 GIT binary patch literal 46592 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 Xj{oP@|Ieh$zRcwd1-?+=VHEgZ$fo6t literal 0 HcmV?d00001 diff --git a/drivers/sb16/sb16_dsp.c b/drivers/sb16/sb16_dsp.c index 4e82d8b18..e378acbf5 100644 --- a/drivers/sb16/sb16_dsp.c +++ b/drivers/sb16/sb16_dsp.c @@ -1,6 +1,31 @@ +/* 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 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: + * + * 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 "sb16.h" -#include "../drivers.h" -#include + _PROTOTYPE(void main, (void)); FORWARD _PROTOTYPE( int dsp_open, (void) ); @@ -12,8 +37,6 @@ FORWARD _PROTOTYPE( void dsp_status, (message *m_ptr) ); FORWARD _PROTOTYPE( void reply, (int code, int replyee, int process, int status) ); FORWARD _PROTOTYPE( void init_buffer, (void) ); -FORWARD _PROTOTYPE( int dsp_inb, (int port) ); -FORWARD _PROTOTYPE( void dsp_outb, (int port, int value) ); FORWARD _PROTOTYPE( int dsp_init, (void) ); FORWARD _PROTOTYPE( int dsp_reset, (void) ); FORWARD _PROTOTYPE( int dsp_command, (int value) ); @@ -24,7 +47,6 @@ 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) ); -_PROTOTYPE(int mixer_set, (int reg, int data)); PRIVATE int irq_hook_id; /* id of irq hook at the kernel */ @@ -42,7 +64,6 @@ PRIVATE unsigned int DspSign = DEFAULT_SIGN; PRIVATE unsigned int DspFragmentSize = DSP_MAX_FRAGMENT_SIZE; PRIVATE int DspAvail = 0; PRIVATE int DspBusy = 0; -PRIVATE int DmaDone = 1; PRIVATE int DmaMode = 0; PRIVATE int DmaBusy = -1; PRIVATE int DmaFillNext = 0; @@ -55,6 +76,7 @@ PRIVATE int reviveProcNr; #define dprint (void) + /*===========================================================================* * main *===========================================================================*/ @@ -96,6 +118,7 @@ PUBLIC void main() } + /*===========================================================================* * dsp_open *===========================================================================*/ @@ -124,6 +147,7 @@ PRIVATE int dsp_open() return OK; } + /*===========================================================================* * dsp_close *===========================================================================*/ @@ -136,6 +160,7 @@ PRIVATE int dsp_close() return OK; } + /*===========================================================================* * dsp_ioctl *===========================================================================*/ @@ -176,6 +201,7 @@ message *m_ptr; return status; } + /*===========================================================================* * dsp_write *===========================================================================*/ @@ -191,6 +217,10 @@ message *m_ptr; reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINVAL); return; } + if(m_ptr->m_type != DmaMode && DmaBusy >= 0) { + reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EBUSY); + return; + } reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, SUSPEND); @@ -235,6 +265,7 @@ message *m_ptr; notify(m_ptr->m_source); } + /*===========================================================================* * dsp_hardware_msg *===========================================================================*/ @@ -245,10 +276,16 @@ PRIVATE void dsp_hardware_msg() 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; @@ -257,15 +294,19 @@ PRIVATE void dsp_hardware_msg() 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 */ - dsp_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL)); + sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL)); } + /*===========================================================================* * dsp_status * *===========================================================================*/ @@ -285,6 +326,7 @@ message *m_ptr; /* pointer to the newly arrived message */ send(m_ptr->m_source, m_ptr); /* send the message */ } + /*===========================================================================* * reply * *===========================================================================*/ @@ -303,6 +345,7 @@ int status; send(replyee, &m); } + /*===========================================================================* * init_buffer *===========================================================================*/ @@ -328,32 +371,6 @@ PRIVATE void init_buffer() #endif /* CHIP == INTEL */ } -/*===========================================================================* - * dsp_inb - *===========================================================================*/ -PRIVATE int dsp_inb(port) -int port; -{ - int s, value = -1; - - if ((s=sys_inb(port, &value)) != OK) - panic("SB16DSP","sys_inb() failed", s); - - return value; -} - -/*===========================================================================* - * dsp_outb - *===========================================================================*/ -PRIVATE void dsp_outb(port, value) -int port; -int value; -{ - int s; - - if ((s=sys_outb(port, value)) != OK) - panic("SB16DSP","sys_outb() failed", s); -} /*===========================================================================* * dsp_init @@ -371,11 +388,11 @@ PRIVATE int dsp_init() dsp_command(DSP_GET_VERSION); /* Get DSP version bytes */ for(i = 1000; i; i--) { - if(dsp_inb(DSP_DATA_AVL) & 0x80) { + if(sb16_inb(DSP_DATA_AVL) & 0x80) { if(DspVersion[0] == 0) { - DspVersion[0] = dsp_inb(DSP_READ); + DspVersion[0] = sb16_inb(DSP_READ); } else { - DspVersion[1] = dsp_inb(DSP_READ); + DspVersion[1] = sb16_inb(DSP_READ); break; } } @@ -402,6 +419,7 @@ PRIVATE int dsp_init() return OK; } + /*===========================================================================* * dsp_reset *===========================================================================*/ @@ -409,20 +427,20 @@ PRIVATE int dsp_reset() { int i; - dsp_outb(DSP_RESET, 1); + sb16_outb(DSP_RESET, 1); for(i = 0; i < 1000; i++); /* wait a while */ - dsp_outb(DSP_RESET, 0); + sb16_outb(DSP_RESET, 0); - for(i = 0; i < 1000 && !(dsp_inb(DSP_DATA_AVL) & 0x80); i++); + for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++); - if(dsp_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */ + if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */ DmaBusy = -1; - DmaDone = 1; return OK; } + /*===========================================================================* * dsp_command *===========================================================================*/ @@ -432,8 +450,8 @@ int value; int i, status; for (i = 0; i < SB_TIMEOUT; i++) { - if((dsp_inb(DSP_STATUS) & 0x80) == 0) { - dsp_outb(DSP_COMMAND, value); + if((sb16_inb(DSP_STATUS) & 0x80) == 0) { + sb16_outb(DSP_COMMAND, value); return OK; } } @@ -442,6 +460,7 @@ int value; return -1; } + /*===========================================================================* * dsp_set_size *===========================================================================*/ @@ -460,6 +479,7 @@ unsigned int size; return OK; } + /*===========================================================================* * dsp_set_speed *===========================================================================*/ @@ -491,6 +511,7 @@ unsigned int speed; return OK; } + /*===========================================================================* * dsp_set_stereo *===========================================================================*/ @@ -506,6 +527,7 @@ unsigned int stereo; return OK; } + /*===========================================================================* * dsp_set_bits *===========================================================================*/ @@ -522,6 +544,7 @@ unsigned int bits; return OK; } + /*===========================================================================* * dsp_set_sign *===========================================================================*/ @@ -535,6 +558,7 @@ unsigned int sign; return OK; } + /*===========================================================================* * dsp_dma_setup *===========================================================================*/ @@ -542,41 +566,50 @@ PRIVATE void dsp_dma_setup(address, count) 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--; - dsp_outb(DMA8_MASK, SB_DMA_8 | 0x04); /* Disable DMA channel */ - dsp_outb(DMA8_CLEAR, 0x00); /* Clear flip flop */ + 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 */ - dsp_outb(DMA8_MODE, (DmaMode == DEV_WRITE ? DMA8_AUTO_PLAY : DMA8_AUTO_REC)); - - dsp_outb(DMA8_ADDR, address >> 0); /* Low_byte of address */ - dsp_outb(DMA8_ADDR, address >> 8); /* High byte of address */ - dsp_outb(DMA8_PAGE, address >> 16); /* 64K page number */ - dsp_outb(DMA8_COUNT, count >> 0); /* Low byte of count */ - dsp_outb(DMA8_COUNT, count >> 8); /* High byte of count */ - dsp_outb(DMA8_MASK, SB_DMA_8); /* Enable DMA channel */ + pv_set(pvb[2], DMA8_MODE, (DmaMode == DEV_WRITE ? DMA8_AUTO_PLAY : DMA8_AUTO_REC)); + + pv_set(pvb[3], DMA8_ADDR, address >> 0); /* Low_byte of address */ + pv_set(pvb[4], DMA8_ADDR, address >> 8); /* High byte of address */ + pv_set(pvb[5], DMA8_PAGE, address >> 16); /* 64K page number */ + pv_set(pvb[6], DMA8_COUNT, count >> 0); /* Low byte of count */ + pv_set(pvb[7], DMA8_COUNT, count >> 8); /* 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; - dsp_outb(DMA16_MASK, (SB_DMA_16 & 3) | 0x04); /* Disable DMA channel */ - dsp_outb(DMA16_CLEAR, 0x00); /* Clear flip flop */ + 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 */ - dsp_outb(DMA16_MODE, (DmaMode == DEV_WRITE ? DMA16_AUTO_PLAY : DMA16_AUTO_REC)); - - dsp_outb(DMA16_ADDR, (address >> 1) & 0xFF); /* Low_byte of address */ - dsp_outb(DMA16_ADDR, (address >> 9) & 0xFF); /* High byte of address */ - dsp_outb(DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */ - dsp_outb(DMA16_COUNT, count >> 1); /* Low byte of count */ - dsp_outb(DMA16_COUNT, count >> 9); /* High byte of count */ - dsp_outb(DMA16_MASK, SB_DMA_16 & 3); /* Enable DMA channel */ + pv_set(pvb[2], DMA16_MODE, (DmaMode == DEV_WRITE ? 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); /* Low byte of count */ + pv_set(pvb[7], DMA16_COUNT, count >> 9); /* High byte of count */ + pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3); /* Enable DMA channel */ + + sys_voutb(pvb, 9); } } + /*===========================================================================* * dsp_setup() *===========================================================================*/ @@ -617,18 +650,4 @@ PRIVATE void dsp_setup() } } -/*===========================================================================* - * mixer_set - *===========================================================================*/ -PUBLIC int mixer_set(reg, data) -int reg; -int data; -{ - int i; - - dsp_outb(MIXER_REG, reg); - for(i = 0; i < 100; i++); - dsp_outb(MIXER_DATA, data); - - return OK; -} + diff --git a/drivers/sb16/sb16_mixer.c b/drivers/sb16/sb16_mixer.c new file mode 100644 index 000000000..3ec309775 --- /dev/null +++ b/drivers/sb16/sb16_mixer.c @@ -0,0 +1,387 @@ +/* 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 PROC_NR 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" + + +_PROTOTYPE(void main, (void)); +FORWARD _PROTOTYPE( int mixer_init, (void)); +FORWARD _PROTOTYPE( int mixer_open, (message *m_ptr)); +FORWARD _PROTOTYPE( int mixer_close, (message *m_ptr)); +FORWARD _PROTOTYPE( int mixer_ioctl, (message *m_ptr)); +FORWARD _PROTOTYPE( int mixer_get, (int reg)); +FORWARD _PROTOTYPE( int get_set_volume, (message *m_ptr, int flag)); +FORWARD _PROTOTYPE( int get_set_input, (message *m_ptr, int flag, int channel)); +FORWARD _PROTOTYPE( int get_set_output, (message *m_ptr, int flag)); + + +PRIVATE int mixer_avail = 0; /* Mixer exists? */ + + +#define dprint (void) + + +/*===========================================================================* + * main + *===========================================================================*/ +PUBLIC void main() { +message mess; + int err, caller, proc_nr; + + /* Here is the main loop of the mixer 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: + 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; + case DEV_IOCTL: err = mixer_ioctl(&mess); break; + default: err = EINVAL; break; + } + + /* Finally, prepare and send the reply message. */ + mess.m_type = TASK_REPLY; + mess.REP_PROC_NR = proc_nr; + + dprint("%d %d", err, OK); + + mess.REP_STATUS = err; /* error code */ + send(caller, &mess); /* send reply to caller */ + } +} + + +/*=========================================================================* + * mixer_open + *=========================================================================*/ +PRIVATE int mixer_open(m_ptr) +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(m_ptr) +message *m_ptr; +{ + dprint("mixer_close\n"); + + return OK; +} + + +/*=========================================================================* + * mixer_ioctl + *=========================================================================*/ +PRIVATE int mixer_ioctl(m_ptr) +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(reg) +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(m_ptr, flag) +message *m_ptr; +int flag; /* 0 = get, 1 = set */ +{ + phys_bytes user_phys; + struct volume_level level; + int cmd_left, cmd_right, shift, max_level; + + sys_datacopy(m_ptr->PROC_NR, (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->PROC_NR, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(level)); + } + + return OK; +} + + +/*=========================================================================* + * get_set_input * + *=========================================================================*/ +PRIVATE int get_set_input(m_ptr, flag, channel) +message *m_ptr; +int flag; /* 0 = get, 1 = set */ +int channel; /* 0 = left, 1 = right */ +{ + phys_bytes user_phys; + struct inout_ctrl input; + int input_cmd, input_mask, mask, del_mask, shift; + + sys_datacopy(m_ptr->PROC_NR, (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->PROC_NR, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(input)); + } + + return OK; +} + + +/*=========================================================================* + * get_set_output * + *=========================================================================*/ +PRIVATE int get_set_output(m_ptr, flag) +message *m_ptr; +int flag; /* 0 = get, 1 = set */ +{ + phys_bytes user_phys; + struct inout_ctrl output; + int output_mask, mask, del_mask, shift; + + sys_datacopy(m_ptr->PROC_NR, (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->PROC_NR, (vir_bytes)m_ptr->ADDRESS, (phys_bytes)sizeof(output)); + } + + return OK; +} \ No newline at end of file -- 2.44.0