From c67a56708e37056910e97b807bf0ed80b41e4d76 Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Fri, 23 Nov 2007 11:40:33 +0000 Subject: [PATCH] es1370 driver and updated es1371 and framework by Pieter Hijma. --- drivers/audio/README | 5 +- drivers/audio/es1370/Makefile | 39 + drivers/audio/es1370/ak4531.c | 177 +++++ drivers/audio/es1370/ak4531.h | 12 + drivers/audio/es1370/es1370.c | 653 ++++++++++++++++ drivers/audio/es1370/es1370.h | 125 +++ drivers/audio/es1370/pci_helper.c | 65 ++ drivers/audio/es1370/pci_helper.h | 12 + drivers/audio/es1371/.depend | 138 ---- drivers/audio/es1371/Makefile | 40 +- drivers/audio/es1371/es1371.c | 905 +++++++++++---------- drivers/audio/es1371/es1371.h | 224 +++--- drivers/audio/es1371/wait.c | 3 +- drivers/audio/es1371/wait.h | 3 + drivers/audio/framework/audio_fw.c | 1171 +++++++++++++++------------- drivers/audio/framework/audio_fw.h | 12 +- drivers/audio/sb16/.depend | 68 -- etc/drivers.conf | 25 + include/sys/ioc_sound.h | 21 +- 19 files changed, 2365 insertions(+), 1333 deletions(-) create mode 100644 drivers/audio/es1370/Makefile create mode 100644 drivers/audio/es1370/ak4531.c create mode 100644 drivers/audio/es1370/ak4531.h create mode 100644 drivers/audio/es1370/es1370.c create mode 100644 drivers/audio/es1370/es1370.h create mode 100644 drivers/audio/es1370/pci_helper.c create mode 100644 drivers/audio/es1370/pci_helper.h delete mode 100755 drivers/audio/es1371/.depend delete mode 100755 drivers/audio/sb16/.depend diff --git a/drivers/audio/README b/drivers/audio/README index b60763d3c..4e16a3a69 100644 --- a/drivers/audio/README +++ b/drivers/audio/README @@ -1,9 +1,9 @@ - ***** Minix 3 Audio drivers ***** Directories: framework/ Generic driver framework sb16/ SB16 ISA driver +es1370/ ES1370 driver es1371/ ES1371 driver @@ -18,11 +18,12 @@ Creating special files: * mknod rec c 13 1 * mknod mixer c 13 2 * chmod 666 audio rec mixer -(for es1371 one can add a special file for the second DAC-channel, major 13, minor 3) +(one can add a special file for the second DAC-channel, major 13, minor 3) Running the driver: * service up /usr/sbin/sb16 -dev /dev/audio +* service up /usr/sbin/es1370 -dev /dev/audio or: * service up /usr/sbin/es1371 -dev /dev/audio diff --git a/drivers/audio/es1370/Makefile b/drivers/audio/es1370/Makefile new file mode 100644 index 000000000..dafa0a5ab --- /dev/null +++ b/drivers/audio/es1370/Makefile @@ -0,0 +1,39 @@ +# Makefile for the ES1371 sounddriver (SB16) + +# directories +u = /usr +i = $u/include +s = $i/sys +m = $i/minix +b = $i/ibm +gen_drv_dir = ../../gen_drivers/cyclic_dma + +# programs, flags, etc. +CC = exec cc +CFLAGS = -I$i +LDFLAGS = -i +LIBS = -lsys -lsysutil + +# build local binary +all: es1370 + +es1370: es1370.o ak4531.o audio_fw.o pci_helper.o + $(CC) -o $@ $(LDFLAGS) es1370.o ak4531.o audio_fw.o pci_helper.o $(LIBS) + +audio_fw.o: ../framework/audio_fw.c ../framework/audio_fw.h + $(CC) -c ../framework/audio_fw.c + +install: /usr/sbin/es1370 +/usr/sbin/es1370: es1370 + install -o root -S 1024k -c $? $@ + +# clean up local files +clean: + rm -f *.o *.bak core es1370 + +depend: + /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + +# Include generated dependencies. +include .depend + diff --git a/drivers/audio/es1370/ak4531.c b/drivers/audio/es1370/ak4531.c new file mode 100644 index 000000000..027bc83f9 --- /dev/null +++ b/drivers/audio/es1370/ak4531.c @@ -0,0 +1,177 @@ +/* best viewed with tabsize 4 */ + + +#include "ak4531.h" +#include "pci_helper.h" + + +#define MASTER_VOLUME_LCH 0x00 +#define MASTER_VOLUME_RCH 0x01 +#define FM_VOLUME_LCH 0x04 +#define FM_VOLUME_RCH 0x05 +#define CD_AUDIO_VOLUME_LCH 0x06 +#define CD_AUDIO_VOLUME_RCH 0x07 +#define LINE_VOLUME_LCH 0x08 +#define LINE_VOLUME_RCH 0x09 +#define MIC_VOLUME 0x0e +#define MONO_OUT_VOLUME 0x0f + +#define RESET_AND_POWER_DOWN 0x16 +#define PD 0x02 +#define RST 0x01 + +#define AD_INPUT_SELECT 0x18 +#define MIC_AMP_GAIN 0x19 + +#define MUTE 0x80 + + +FORWARD _PROTOTYPE( int ak4531_write, (u8_t address, u8_t data) ); +FORWARD _PROTOTYPE( int ak4531_finished, (void) ); +FORWARD _PROTOTYPE( int set_volume, (struct volume_level *level, + int cmd_left, int cmd_right, int max_level) ); + +PRIVATE u16_t base_address; +PRIVATE u16_t status_register; +PRIVATE u16_t status_bit; +PRIVATE u16_t poll_address; + +u8_t mixer_values[0x20] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, /* 0x08 - 0x0f */ + 0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00, /* 0x10 - 0x17 */ + 0x00, 0x01 /* 0x18 - 0x19 */ +}; +#if 0 +u8_t mixer_values[0x20] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */ + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x08 - 0x0f */ + 0x7f, 0x3d, 0x55, 0x26, 0xf7, 0xef, 0x03, 0x00, /* 0x10 - 0x17 */ + 0x00, 0x01 /* 0x18 - 0x19 */ +}; +#endif + + + +PRIVATE int ak4531_finished(void) { + int i; + u16_t cstat; + for (i = 0; i < 0x40000; i++) { + cstat = pci_inw(status_register); + if (!(cstat & status_bit)) { + return 1; + } + } + return 0; +} + + +PRIVATE int ak4531_write (u8_t address, u8_t data) { + u16_t to_be_written; + + + if (address < MASTER_VOLUME_LCH || address > MIC_AMP_GAIN) return -1; + + to_be_written = (u16_t)((address << 8) | data); + + if (!ak4531_finished()) return -1; + pci_outw(base_address, to_be_written); + return 0; +} + + +PUBLIC int ak4531_init(u16_t base, u16_t status_reg, u16_t bit, + u16_t poll) { + int i; + + base_address = base; + status_register = status_reg; + status_bit = bit; + poll_address = poll; + + for (i=0; i<100; i++) { + pci_inb(poll_address); + } + if(ak4531_write(RESET_AND_POWER_DOWN, PD|RST) < 0) return -1; + + for (i=0; i<100; i++) { + pci_inb(poll_address); + } + + ak4531_write(AD_INPUT_SELECT, 0x00); + + for (i = MASTER_VOLUME_LCH ; i <= MIC_AMP_GAIN; i++) { + if (ak4531_write(i, mixer_values[i]) < 0) return -1; + } + return 0; +} + + +PUBLIC int ak4531_get_set_volume(struct volume_level *level, int flag) { + int cmd_left, cmd_right, max_level; + + max_level = 0x1f; + + switch(level->device) { + case Master: + cmd_left = MASTER_VOLUME_LCH; + cmd_right = MASTER_VOLUME_RCH; + break; + case Dac: + return EINVAL; + break; + case Fm: + cmd_left = FM_VOLUME_LCH; + cmd_right = FM_VOLUME_RCH; + break; + case Cd: + cmd_left = CD_AUDIO_VOLUME_LCH; + cmd_right = CD_AUDIO_VOLUME_RCH; + break; + case Line: + cmd_left = LINE_VOLUME_LCH; + cmd_right = LINE_VOLUME_RCH; + break; + case Mic: + cmd_left = cmd_right = MIC_VOLUME; + break; + case Speaker: + cmd_left = cmd_right = MONO_OUT_VOLUME; + max_level = 0x03; + break; + case Treble: + return EINVAL; + break; + case Bass: + return EINVAL; + break; + default: + return EINVAL; + } + + if (flag) { /* set volume */ + return set_volume(level, cmd_left, cmd_right, max_level); + } + else { /* get volume */ + level->left = - ((int) (mixer_values[cmd_left] & ~MUTE)) + 0x1f; + level->right = - ((int) (mixer_values[cmd_right] & ~MUTE)) + 0x1f; + return OK; + } +} + + +PRIVATE int set_volume(struct volume_level *level, int cmd_left, int cmd_right, + int max_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_values[cmd_left] = (-level->left)+0x1f; + ak4531_write(cmd_left, mixer_values[cmd_left]); + mixer_values[cmd_right] = (-level->right)+0x1f; + ak4531_write(cmd_right, mixer_values[cmd_right]); + + return OK; +} diff --git a/drivers/audio/es1370/ak4531.h b/drivers/audio/es1370/ak4531.h new file mode 100644 index 000000000..561da2ec7 --- /dev/null +++ b/drivers/audio/es1370/ak4531.h @@ -0,0 +1,12 @@ +#ifndef AK4531_H +#define AK4531_H +/* best viewed with tabsize=4 */ + +#include "../../drivers.h" +#include + +_PROTOTYPE( int ak4531_init, (u16_t base, u16_t status_reg, u16_t bit, + u16_t poll) ); +_PROTOTYPE( int ak4531_get_set_volume, (struct volume_level *level, int flag) ); + +#endif diff --git a/drivers/audio/es1370/es1370.c b/drivers/audio/es1370/es1370.c new file mode 100644 index 000000000..d9f222acb --- /dev/null +++ b/drivers/audio/es1370/es1370.c @@ -0,0 +1,653 @@ +/* Best viewed with tabsize 4 */ + +/* Ensoniq ES1370 driver + * + * aka AudioPCI '97 + * + * This is the main file of the ES1370 sound driver. There is no main function + * over here, instead the main function is located in the generic dma driver. + * All this driver does is implement the interface audio/audio_fw.h. All + * functions having the prefix 'drv_' are dictated by audio/audio_fw.h. The + * function prototypes you see below define a set of private helper functions. + * Control over the AK4531 codec is delegated ak4531.c. + * + * September 2007 ES1370 driver (Pieter Hijma), + * based on ES1371 driver by Laurens Bronwasser + */ + +#include + +#include "../framework/audio_fw.h" +#include "es1370.h" +#include "ak4531.h" +#include "pci_helper.h" + + +/* reg(n) will be the device specific addresses */ +#define reg(n) dev.base + n + + +/* prototypes of private functions */ +FORWARD _PROTOTYPE( int detect_hw, (void) ); +FORWARD _PROTOTYPE( int disable_int, (int sub_dev) ); +FORWARD _PROTOTYPE( int set_stereo, (u32_t stereo, int sub_dev) ); +FORWARD _PROTOTYPE( int set_bits, (u32_t nr_of_bits, int sub_dev) ); +FORWARD _PROTOTYPE( int set_sample_rate, (u32_t rate, int sub_dev) ); +FORWARD _PROTOTYPE( int set_sign, (u32_t val, int sub_dev) ); +FORWARD _PROTOTYPE( int get_max_frag_size, + (u32_t * val, int *len, int sub_dev) ); +FORWARD _PROTOTYPE( int set_frag_size, (u32_t fragment_size, int sub_dev) ); +FORWARD _PROTOTYPE( int set_int_cnt, (int sub_dev) ); +FORWARD _PROTOTYPE( int free_buf, (u32_t *val, int *len, int sub_dev) ); +FORWARD _PROTOTYPE( int get_samples_in_buf, + (u32_t *val, int *len, int sub_dev) ); +FORWARD _PROTOTYPE( int get_set_volume, (struct volume_level *level, int *len, + int sub_dev, int flag) ); +FORWARD _PROTOTYPE( int reset, (int sub_dev) ); + + +DEV_STRUCT dev; +aud_sub_dev_conf_t aud_conf[4]; + + +PUBLIC sub_dev_t sub_dev[4]; +PUBLIC special_file_t special_file[4]; +PUBLIC drv_t drv; + + +PUBLIC int drv_init(void) { + drv.DriverName = DRIVER_NAME; + drv.NrOfSubDevices = 4; + drv.NrOfSpecialFiles = 4; + + sub_dev[DAC1_CHAN].readable = 0; + sub_dev[DAC1_CHAN].writable = 1; + sub_dev[DAC1_CHAN].DmaSize = 64 * 1024; + sub_dev[DAC1_CHAN].NrOfDmaFragments = 2; + sub_dev[DAC1_CHAN].MinFragmentSize = 1024; + sub_dev[DAC1_CHAN].NrOfExtraBuffers = 4; + + sub_dev[ADC1_CHAN].readable = 1; + sub_dev[ADC1_CHAN].writable = 0; + sub_dev[ADC1_CHAN].DmaSize = 64 * 1024; + sub_dev[ADC1_CHAN].NrOfDmaFragments = 2; + sub_dev[ADC1_CHAN].MinFragmentSize = 1024; + sub_dev[ADC1_CHAN].NrOfExtraBuffers = 4; + + sub_dev[MIXER].writable = 0; + sub_dev[MIXER].readable = 0; + + sub_dev[DAC2_CHAN].readable = 0; + sub_dev[DAC2_CHAN].writable = 1; + sub_dev[DAC2_CHAN].DmaSize = 64 * 1024; + sub_dev[DAC2_CHAN].NrOfDmaFragments = 2; + sub_dev[DAC2_CHAN].MinFragmentSize = 1024; + sub_dev[DAC2_CHAN].NrOfExtraBuffers = 4; + + special_file[0].minor_dev_nr = 0; + special_file[0].write_chan = DAC1_CHAN; + special_file[0].read_chan = NO_CHANNEL; + special_file[0].io_ctl = DAC1_CHAN; + + special_file[1].minor_dev_nr = 1; + special_file[1].write_chan = NO_CHANNEL; + special_file[1].read_chan = ADC1_CHAN; + special_file[1].io_ctl = ADC1_CHAN; + + special_file[2].minor_dev_nr = 2; + special_file[2].write_chan = NO_CHANNEL; + special_file[2].read_chan = NO_CHANNEL; + special_file[2].io_ctl = MIXER; + + special_file[3].minor_dev_nr = 3; + special_file[3].write_chan = DAC2_CHAN; + special_file[3].read_chan = NO_CHANNEL; + special_file[3].io_ctl = DAC2_CHAN; +} + + +PUBLIC int drv_init_hw (void) { + u16_t i, j; + u16_t chip_sel_ctrl_reg; + + /* First, detect the hardware */ + if (detect_hw() != OK) { + return EIO; + } + + /* PCI command register + * enable the SERR# driver, PCI bus mastering and I/O access + */ + pci_attr_w16 (dev.devind, PCI_CR, SERR_EN|PCI_MASTER|IO_ACCESS); + + /* turn everything off */ + pci_outl(reg(CHIP_SEL_CTRL), 0x0UL); + + /* turn off legacy (legacy control is undocumented) */ + pci_outl(reg(LEGACY), 0x0UL); + pci_outl(reg(LEGACY+4), 0x0UL); + + /* turn off serial interface */ + pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x0UL); + /*pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x3UL);*/ + + + /* enable the codec */ + chip_sel_ctrl_reg = pci_inw(reg(CHIP_SEL_CTRL)); + chip_sel_ctrl_reg |= XCTL0 | CDC_EN; + pci_outw(reg(CHIP_SEL_CTRL), chip_sel_ctrl_reg); + + /* initialize the codec */ + if (ak4531_init(reg(CODEC_WRITE_ADDRESS), + reg(INTERRUPT_STATUS), CWRIP, reg(0)) < 0) { + return EINVAL; + } + + /* clear all the memory */ + for (i = 0; i < 0x10; ++i) { + pci_outb(reg(MEM_PAGE), i); + for (j = 0; j < 0x10; j += 4) { + pci_outl (reg(MEMORY) + j, 0x0UL); + } + } + + /* initialize variables for each sub_device */ + for (i = 0; i < drv.NrOfSubDevices; i++) { + if(i != MIXER) { + aud_conf[i].busy = 0; + aud_conf[i].stereo = DEFAULT_STEREO; + aud_conf[i].sample_rate = DEFAULT_RATE; + aud_conf[i].nr_of_bits = DEFAULT_NR_OF_BITS; + aud_conf[i].sign = DEFAULT_SIGNED; + aud_conf[i].fragment_size = + sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments; + } + } + return OK; +} + + +PRIVATE int detect_hw(void) { + u32_t device; + int devind; + u16_t v_id, d_id; + + /* detect_hw tries to find device and get IRQ and base address + with a little (much) help from the PCI library. + This code is quite device independent and you can copy it. + (just make sure to get the bugs out first)*/ + + pci_init(); + /* get first device and then search through the list */ + device = pci_first_dev(&devind, &v_id, &d_id); + while( device > 0 ) { + /* if we have a match...break */ + if (v_id == VENDOR_ID && d_id == DEVICE_ID) break; + device = pci_next_dev(&devind, &v_id, &d_id); + } + + /* did we find anything? */ + if (v_id != VENDOR_ID || d_id != DEVICE_ID) { + return EIO; + } + + pci_reserve(devind); + + dev.name = pci_dev_name(v_id, d_id); + + /* get base address of our device, ignore least signif. bit + this last bit thing could be device dependent, i don't know */ + dev.base = pci_attr_r32(devind, PCI_BAR) & 0xfffffffe; + + /* get IRQ */ + dev.irq = pci_attr_r8(devind, PCI_ILR); + dev.revision = pci_attr_r8(devind, PCI_REV); + dev.d_id = d_id; + dev.v_id = v_id; + dev.devind = devind; /* pci device identifier */ + + return OK; +} + + +PRIVATE int reset(int chan) { + drv_stop(chan); + sub_dev[chan].OutOfData = 1; + + return OK; +} + + +int drv_reset() { + return OK; +} + + +int drv_start(int sub_dev, int DmaMode) { + u32_t enable_bit, result = 0; + u32_t debug; + + /* Write default values to device in case user failed to configure. + If user did configure properly, everything is written twice. + please raise your hand if you object against to this strategy...*/ + result |= set_sample_rate(aud_conf[sub_dev].sample_rate, sub_dev); + result |= set_stereo(aud_conf[sub_dev].stereo, sub_dev); + result |= set_bits(aud_conf[sub_dev].nr_of_bits, sub_dev); + result |= set_sign(aud_conf[sub_dev].sign, sub_dev); + + /* set the interrupt count */ + result |= set_int_cnt(sub_dev); + + if (result) { + return EIO; + } + + /* if device currently paused, resume */ + drv_resume(sub_dev); + + switch(sub_dev) { + case ADC1_CHAN: enable_bit = ADC1_EN;break; + case DAC1_CHAN: enable_bit = DAC1_EN;break; + case DAC2_CHAN: enable_bit = DAC2_EN;break; + default: return EINVAL; + } + + /* enable interrupts from 'sub device' */ + drv_reenable_int(sub_dev); + + /* this means play!!! */ + pci_outw(reg(CHIP_SEL_CTRL), pci_inw(reg(CHIP_SEL_CTRL)) | enable_bit); + + aud_conf[sub_dev].busy = 1; + + return OK; +} + + +int drv_stop(int sub_dev) +{ + u32_t enable_bit; + + switch(sub_dev) { + case ADC1_CHAN: enable_bit = ADC1_EN;break; + case DAC1_CHAN: enable_bit = DAC1_EN;break; + case DAC2_CHAN: enable_bit = DAC2_EN;break; + default: return EINVAL; + } + + /* stop the specified channel */ + pci_outw(reg(CHIP_SEL_CTRL), + pci_inw(reg(CHIP_SEL_CTRL)) & ~enable_bit); + aud_conf[sub_dev].busy = 0; + disable_int(sub_dev); + + return OK; +} + + +/* all IO-ctl's sent to the upper driver are passed to this function */ +int drv_io_ctl(int request, void * val, int * len, int sub_dev) { + + int status; + + switch(request) { + case DSPIORATE: + status = set_sample_rate(*((u32_t *) val), sub_dev); break; + case DSPIOSTEREO: + status = set_stereo(*((u32_t *) val), sub_dev); break; + case DSPIOBITS: + status = set_bits(*((u32_t *) val), sub_dev); break; + case DSPIOSIZE: + status = set_frag_size(*((u32_t *) val), sub_dev); break; + case DSPIOSIGN: + status = set_sign(*((u32_t *) val), sub_dev); break; + case DSPIOMAX: + status = get_max_frag_size(val, len, sub_dev); break; + case DSPIORESET: + status = reset(sub_dev); break; + case DSPIOFREEBUF: + status = free_buf(val, len, sub_dev); break; + case DSPIOSAMPLESINBUF: + status = get_samples_in_buf(val, len, sub_dev); break; + case DSPIOPAUSE: + status = drv_pause(sub_dev); break; + case DSPIORESUME: + status = drv_resume(sub_dev); break; + case MIXIOGETVOLUME: + status = get_set_volume(val, len, sub_dev, 0); break; + case MIXIOSETVOLUME: + status = get_set_volume(val, len, sub_dev, 1); break; + default: + status = EINVAL; break; + } + + return OK; +} + + +int drv_get_irq(char *irq) { + *irq = dev.irq; + return OK; +} + + +int drv_get_frag_size(u32_t *frag_size, int sub_dev) { + *frag_size = aud_conf[sub_dev].fragment_size; + return OK; +} + + +int drv_set_dma(u32_t dma, u32_t length, int chan) { + /* dma length in bytes, + max is 64k long words for es1370 = 256k bytes */ + u32_t page, frame_count_reg, dma_add_reg; + + switch(chan) { + case ADC1_CHAN: page = ADC_MEM_PAGE; + frame_count_reg = ADC_BUFFER_SIZE; + dma_add_reg = ADC_PCI_ADDRESS; + break; + case DAC1_CHAN: page = DAC_MEM_PAGE; + frame_count_reg = DAC1_BUFFER_SIZE; + dma_add_reg = DAC1_PCI_ADDRESS; + break;; + case DAC2_CHAN: page = DAC_MEM_PAGE; + frame_count_reg = DAC2_BUFFER_SIZE; + dma_add_reg = DAC2_PCI_ADDRESS; + break;; + default: return EIO; + } + pci_outb(reg(MEM_PAGE), page); + pci_outl(reg(dma_add_reg), dma); + + /* device expects long word count in stead of bytes */ + length /= 4; + + /* It seems that register _CURRENT_COUNT is overwritten, but this is + * the way to go. The register frame_count_reg is only longword + * addressable. + * It expects length -1 + */ + pci_outl(reg(frame_count_reg), (u32_t) (length - 1)); + + return OK; +} + + +/* return status of the interrupt summary bit */ +int drv_int_sum(void) { + return pci_inl(reg(INTERRUPT_STATUS)) & INTR; +} + + +int drv_int(int sub_dev) { + u32_t int_status; + u32_t bit; + u32_t debug; + + /* return status of interrupt bit of specified channel*/ + switch (sub_dev) { + case DAC1_CHAN: bit = DAC1;break; + case DAC2_CHAN: bit = DAC2;break; + case ADC1_CHAN: bit = ADC;break; + } + + int_status = pci_inl(reg(INTERRUPT_STATUS)) & bit; + + return int_status; +} + + +int drv_reenable_int(int chan) { + u16_t ser_interface, int_en_bit; + + switch(chan) { + case ADC1_CHAN: int_en_bit = R1_INT_EN; break; + case DAC1_CHAN: int_en_bit = P1_INTR_EN; break; + case DAC2_CHAN: int_en_bit = P2_INTR_EN; break; + default: EINVAL; + } + + /* clear and reenable an interrupt */ + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit); + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface | int_en_bit); + + return OK; +} + + +int drv_pause(int sub_dev) { + u32_t pause_bit; + + disable_int(sub_dev); /* don't send interrupts */ + + switch(sub_dev) { + case DAC1_CHAN: pause_bit = P1_PAUSE;break; + case DAC2_CHAN: pause_bit = P2_PAUSE;break; + default: return EINVAL; + } + + /* pause */ + pci_outl(reg(SERIAL_INTERFACE_CTRL), + pci_inl(reg(SERIAL_INTERFACE_CTRL)) | pause_bit); + + return OK; +} + + +int drv_resume(int sub_dev) { + u32_t pause_bit = 0; + + drv_reenable_int(sub_dev); /* enable interrupts */ + + switch(sub_dev) { + case DAC1_CHAN: pause_bit = P1_PAUSE;break; + case DAC2_CHAN: pause_bit = P2_PAUSE;break; + default: return EINVAL; + } + + /* clear pause bit */ + pci_outl(reg(SERIAL_INTERFACE_CTRL), + pci_inl(reg(SERIAL_INTERFACE_CTRL)) & ~pause_bit); + + return OK; +} + + +PRIVATE int set_bits(u32_t nr_of_bits, int sub_dev) { + /* set format bits for specified channel. */ + u16_t size_16_bit, ser_interface; + + switch(sub_dev) { + case ADC1_CHAN: size_16_bit = R1_S_EB; break; + case DAC1_CHAN: size_16_bit = P1_S_EB; break; + case DAC2_CHAN: size_16_bit = P2_S_EB; break; + default: return EINVAL; + } + + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + ser_interface &= ~size_16_bit; + switch(nr_of_bits) { + case 16: ser_interface |= size_16_bit;break; + case 8: break; + default: return EINVAL; + } + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface); + aud_conf[sub_dev].nr_of_bits = nr_of_bits; + return OK; +} + + +PRIVATE int set_stereo(u32_t stereo, int sub_dev) { + /* set format bits for specified channel. */ + u16_t stereo_bit, ser_interface; + + switch(sub_dev) { + case ADC1_CHAN: stereo_bit = R1_S_MB; break; + case DAC1_CHAN: stereo_bit = P1_S_MB; break; + case DAC2_CHAN: stereo_bit = P2_S_MB; break; + default: return EINVAL; + } + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + ser_interface &= ~stereo_bit; + if (stereo) { + ser_interface |= stereo_bit; + } + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface); + aud_conf[sub_dev].stereo = stereo; + + return OK; +} + + +PRIVATE int set_sign(u32_t val, int sub_dev) { + return OK; +} + + +PRIVATE int set_frag_size(u32_t fragment_size, int sub_dev_nr) { + if (fragment_size > (sub_dev[sub_dev_nr].DmaSize / + sub_dev[sub_dev_nr].NrOfDmaFragments) || + fragment_size < sub_dev[sub_dev_nr].MinFragmentSize) { + return EINVAL; + } + aud_conf[sub_dev_nr].fragment_size = fragment_size; + + return OK; +} + + +PRIVATE int set_sample_rate(u32_t rate, int sub_dev) { + /* currently only 44.1kHz */ + u32_t controlRegister; + + if (rate > MAX_RATE || rate < MIN_RATE) { + return EINVAL; + } + + controlRegister = pci_inl(reg(CHIP_SEL_CTRL)); + controlRegister |= FREQ_44K100; + pci_outl(reg(CHIP_SEL_CTRL), controlRegister); + + aud_conf[sub_dev].sample_rate = rate; + + return OK; +} + + +PRIVATE int set_int_cnt(int chan) { + /* Write interrupt count for specified channel. + After bytes, an interrupt will be generated */ + + int sample_count; + u16_t int_cnt_reg; + + if (aud_conf[chan].fragment_size > + (sub_dev[chan].DmaSize / sub_dev[chan].NrOfDmaFragments) + || aud_conf[chan].fragment_size < sub_dev[chan].MinFragmentSize) { + return EINVAL; + } + + switch(chan) { + case ADC1_CHAN: int_cnt_reg = ADC_SAMP_CT; break; + case DAC1_CHAN: int_cnt_reg = DAC1_SAMP_CT; break; + case DAC2_CHAN: int_cnt_reg = DAC2_SAMP_CT; break; + default: return EINVAL; + } + + sample_count = aud_conf[chan].fragment_size; + + /* adjust sample count according to sample format */ + if( aud_conf[chan].stereo == TRUE ) sample_count >>= 1; + switch(aud_conf[chan].nr_of_bits) { + case 16: sample_count >>= 1;break; + case 8: break; + default: return EINVAL; + } + + /* set the sample count - 1 for the specified channel. */ + pci_outw(reg(int_cnt_reg), sample_count - 1); + + return OK; +} + + +PRIVATE int get_max_frag_size(u32_t * val, int * len, int sub_dev_nr) { + *len = sizeof(*val); + *val = (sub_dev[sub_dev_nr].DmaSize / + sub_dev[sub_dev_nr].NrOfDmaFragments); + return OK; +} + + +PRIVATE int disable_int(int chan) { + u16_t ser_interface, int_en_bit; + + switch(chan) { + case ADC1_CHAN: int_en_bit = R1_INT_EN; break; + case DAC1_CHAN: int_en_bit = P1_INTR_EN; break; + case DAC2_CHAN: int_en_bit = P2_INTR_EN; break; + default: EINVAL; + } + /* clear the interrupt */ + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit); +} + + +PRIVATE int get_samples_in_buf (u32_t *samples_in_buf, int *len, int chan) { + u16_t samp_ct_reg; + u16_t curr_samp_ct_reg; + u16_t samp_ct; /* nr of samples - 1 that will be played back */ + u16_t curr_samp_ct; /* counts back from SAMP_CT till 0 */ + + *len = sizeof(*samples_in_buf); + + switch(chan) { + case ADC1_CHAN: + curr_samp_ct_reg = ADC_CURR_SAMP_CT; + samp_ct_reg = ADC_SAMP_CT; break; + case DAC1_CHAN: + curr_samp_ct_reg = DAC1_CURR_SAMP_CT; + samp_ct_reg = DAC1_SAMP_CT; break; + case DAC2_CHAN: + curr_samp_ct_reg = DAC2_CURR_SAMP_CT; + samp_ct_reg = DAC2_SAMP_CT; break; + default: return EINVAL; + } + + samp_ct = pci_inw(reg(samp_ct_reg)); + curr_samp_ct = pci_inw(reg(curr_samp_ct_reg)); + + *samples_in_buf = (u32_t) (sub_dev[chan].BufLength * 8192) + + curr_samp_ct; + + return OK; +} + + +/* returns 1 if there are free buffers */ +PRIVATE int free_buf (u32_t *val, int *len, int sub_dev_nr) { + *len = sizeof(*val); + if (sub_dev[sub_dev_nr].BufLength == + sub_dev[sub_dev_nr].NrOfExtraBuffers) { + *val = 0; + } + else { + *val = 1; + } + return OK; +} + + +PRIVATE int get_set_volume(struct volume_level *level, int *len, int sub_dev, + int flag) { + *len = sizeof(struct volume_level); + if (sub_dev == MIXER) { + return ak4531_get_set_volume(level, flag); + } + else { + return EINVAL; + } +} diff --git a/drivers/audio/es1370/es1370.h b/drivers/audio/es1370/es1370.h new file mode 100644 index 000000000..faabee25b --- /dev/null +++ b/drivers/audio/es1370/es1370.h @@ -0,0 +1,125 @@ +#ifndef ES1370_H +#define ES1370_H +/* best viewed with tabsize=4 */ + +#include +#include "../../drivers.h" +#include + + +/* set your vendor and device ID's here */ +#define VENDOR_ID 0x1274 +#define DEVICE_ID 0x5000 +#define DRIVER_NAME "ES1370" + + +/* channels or subdevices */ +#define DAC1_CHAN 0 +#define ADC1_CHAN 1 +#define MIXER 2 +#define DAC2_CHAN 3 + + +/* PCI command register defines */ +#define SERR_EN 0x0100 +#define PCI_MASTER 0x0004 +#define IO_ACCESS 0x0001 + + +/* Interrupt/Chip Select Control */ +#define CHIP_SEL_CTRL 0x00 +#define FREQ_44K100 0x3000 /* 44.1 Khz */ +#define CDC_EN 0x0002 /* codec enable */ +#define ADC1_EN 0x0010 +#define DAC1_EN 0x0040 +#define DAC2_EN 0x0020 +#define XCTL0 0x0100 +#define CCB_INTRM 0x0400 + + +/* Interrupt/Chip Select Status */ +#define INTERRUPT_STATUS 0x04 +#define ADC 0x0001 +#define DAC2 0x0002 +#define DAC1 0x0004 +#define CSTAT 0x0400 /* == CBUSY || CWRIP */ +#define CWRIP 0x0100 /* == CBUSY || CWRIP */ +#define INTR 0x80000000 + + +/* AK4531 address */ +#define CODEC_WRITE_ADDRESS 0x10 + + +/* Legacy address */ +#define LEGACY 0x18 + + +/* Memory related defines */ +#define MEM_PAGE 0x0c +#define ADC_MEM_PAGE 0x0d +#define DAC_MEM_PAGE 0x0c /* for DAC1 and DAC2 */ + +#define MEMORY 0x30 +#define ADC_BUFFER_SIZE 0x34 +#define DAC1_BUFFER_SIZE 0x34 +#define DAC2_BUFFER_SIZE 0X3c +#define ADC_PCI_ADDRESS 0x30 +#define DAC1_PCI_ADDRESS 0x30 +#define DAC2_PCI_ADDRESS 0x38 + + +/* Serial Interface Control */ +#define SERIAL_INTERFACE_CTRL 0x20 +#define P1_S_MB 0x0001 /* DAC1 Stereo/Mono bit */ +#define P1_S_EB 0x0002 /* DAC1 Sixteen/Eight bit */ +#define P2_S_MB 0x0004 /* DAC2 Stereo/Mono bit */ +#define P2_S_EB 0x0008 /* DAC2 Sixteen/Eight bit */ +#define R1_S_MB 0x0010 /* ADC Stereo/Mono bit */ +#define R1_S_EB 0x0020 /* ADC Sixteen/Eight bit */ +#define P1_INTR_EN 0x0100 +#define P2_INTR_EN 0x0200 +#define R1_INT_EN 0x0400 +#define P1_PAUSE 0x0800 +#define P2_PAUSE 0x1000 + + +#define DAC1_SAMP_CT 0x24 +#define DAC1_CURR_SAMP_CT 0x26 +#define DAC2_SAMP_CT 0x28 +#define DAC2_CURR_SAMP_CT 0x2a +#define ADC_SAMP_CT 0x2c +#define ADC_CURR_SAMP_CT 0x2e + + +typedef struct { + u32_t stereo; + u16_t sample_rate; + u32_t nr_of_bits; + u32_t sign; + u32_t busy; + u32_t fragment_size; +} aud_sub_dev_conf_t; + +/* Some defaults for the aud_sub_dev_conf_t*/ +#define DEFAULT_RATE 44100 /* Sample rate */ +#define DEFAULT_NR_OF_BITS 16 /* Nr. of bits per sample per chan */ +#define DEFAULT_SIGNED 0 /* 0 = unsigned, 1 = signed */ +#define DEFAULT_STEREO 1 /* 0 = mono, 1 = stereo */ +#define MAX_RATE 44100 /* Max sample speed in KHz */ +#define MIN_RATE 4000 /* Min sample speed in KHz */ + + +typedef struct DEVSTRUCT { + char* name; + u16_t v_id; /* vendor id */ + u16_t d_id; /* device id */ + u32_t devind; /* minix pci device id, for + * pci configuration space */ + u32_t base; /* changed to 32 bits */ + char irq; + char revision; /* version of the device */ +} DEV_STRUCT; + + +#endif /* ES1370_H */ diff --git a/drivers/audio/es1370/pci_helper.c b/drivers/audio/es1370/pci_helper.c new file mode 100644 index 000000000..4c3ff124d --- /dev/null +++ b/drivers/audio/es1370/pci_helper.c @@ -0,0 +1,65 @@ +/* best viewed with tabsize 4 */ + +#include "../../drivers.h" + +#include +#include +#include +#include +#include + + +#include "pci_helper.h" + +#include "es1370.h" + +/*===========================================================================* + * helper functions for I/O * + *===========================================================================*/ +PUBLIC unsigned pci_inb(U16_t port) { + u32_t value; + int s; + if ((s=sys_inb(port, &value)) !=OK) + printf("%s: warning, sys_inb failed: %d\n", DRIVER_NAME, s); + return value; +} + + +PUBLIC unsigned pci_inw(U16_t port) { + u32_t value; + int s; + if ((s=sys_inw(port, &value)) !=OK) + printf("%s: warning, sys_inw failed: %d\n", DRIVER_NAME, s); + return value; +} + + +PUBLIC unsigned pci_inl(U16_t port) { + U32_t value; + int s; + if ((s=sys_inl(port, &value)) !=OK) + printf("%s: warning, sys_inl failed: %d\n", DRIVER_NAME, s); + return value; +} + + +PUBLIC void pci_outb(U16_t port, U8_t value) { + int s; + if ((s=sys_outb(port, value)) !=OK) + printf("%s: warning, sys_outb failed: %d\n", DRIVER_NAME, s); +} + + +PUBLIC void pci_outw(U16_t port, U16_t value) { + int s; + if ((s=sys_outw(port, value)) !=OK) + printf("%s: warning, sys_outw failed: %d\n", DRIVER_NAME, s); +} + + +PUBLIC void pci_outl(U16_t port, U32_t value) { + int s; + if ((s=sys_outl(port, value)) !=OK) + printf("%s: warning, sys_outl failed: %d\n", DRIVER_NAME, s); +} + diff --git a/drivers/audio/es1370/pci_helper.h b/drivers/audio/es1370/pci_helper.h new file mode 100644 index 000000000..5c91c6993 --- /dev/null +++ b/drivers/audio/es1370/pci_helper.h @@ -0,0 +1,12 @@ +#ifndef PCI_HELPER +#define PCI_HELPER + +_PROTOTYPE( unsigned pci_inb, (U16_t port) ); +_PROTOTYPE( unsigned pci_inw, (U16_t port) ); +_PROTOTYPE( unsigned pci_inl, (U16_t port) ); + +_PROTOTYPE( void pci_outb, (U16_t port, U8_t value) ); +_PROTOTYPE( void pci_outw, (U16_t port, U16_t value) ); +_PROTOTYPE( void pci_outl, (U16_t port, U32_t value) ); + +#endif diff --git a/drivers/audio/es1371/.depend b/drivers/audio/es1371/.depend deleted file mode 100755 index deb8a3336..000000000 --- a/drivers/audio/es1371/.depend +++ /dev/null @@ -1,138 +0,0 @@ - -SRC.o: ../../drivers.h -SRC.o: ../../libpci/pci.h -SRC.o: /usr/include/ansi.h -SRC.o: /usr/include/errno.h -SRC.o: /usr/include/ibm/bios.h -SRC.o: /usr/include/ibm/interrupt.h -SRC.o: /usr/include/ibm/ports.h -SRC.o: /usr/include/limits.h -SRC.o: /usr/include/minix/bitmap.h -SRC.o: /usr/include/minix/callnr.h -SRC.o: /usr/include/minix/com.h -SRC.o: /usr/include/minix/config.h -SRC.o: /usr/include/minix/const.h -SRC.o: /usr/include/minix/devio.h -SRC.o: /usr/include/minix/dmap.h -SRC.o: /usr/include/minix/ioctl.h -SRC.o: /usr/include/minix/ipc.h -SRC.o: /usr/include/minix/sys_config.h -SRC.o: /usr/include/minix/syslib.h -SRC.o: /usr/include/minix/sysutil.h -SRC.o: /usr/include/minix/type.h -SRC.o: /usr/include/signal.h -SRC.o: /usr/include/stddef.h -SRC.o: /usr/include/stdlib.h -SRC.o: /usr/include/string.h -SRC.o: /usr/include/sys/dir.h -SRC.o: /usr/include/sys/ioc_sound.h -SRC.o: /usr/include/sys/types.h -SRC.o: /usr/include/unistd.h -SRC.o: SRC.c -SRC.o: SRC.h -SRC.o: es1371.h -SRC.o: wait.h - -codec.o: ../../drivers.h -codec.o: ../../libpci/pci.h -codec.o: ../AC97.h -codec.o: /usr/include/ansi.h -codec.o: /usr/include/errno.h -codec.o: /usr/include/ibm/bios.h -codec.o: /usr/include/ibm/interrupt.h -codec.o: /usr/include/ibm/ports.h -codec.o: /usr/include/limits.h -codec.o: /usr/include/minix/bitmap.h -codec.o: /usr/include/minix/callnr.h -codec.o: /usr/include/minix/com.h -codec.o: /usr/include/minix/config.h -codec.o: /usr/include/minix/const.h -codec.o: /usr/include/minix/devio.h -codec.o: /usr/include/minix/dmap.h -codec.o: /usr/include/minix/ioctl.h -codec.o: /usr/include/minix/ipc.h -codec.o: /usr/include/minix/sys_config.h -codec.o: /usr/include/minix/syslib.h -codec.o: /usr/include/minix/sysutil.h -codec.o: /usr/include/minix/type.h -codec.o: /usr/include/signal.h -codec.o: /usr/include/stddef.h -codec.o: /usr/include/stdlib.h -codec.o: /usr/include/string.h -codec.o: /usr/include/sys/dir.h -codec.o: /usr/include/sys/ioc_sound.h -codec.o: /usr/include/sys/types.h -codec.o: /usr/include/unistd.h -codec.o: SRC.h -codec.o: codec.c -codec.o: codec.h -codec.o: es1371.h -codec.o: wait.h - -es1371.o: ../../drivers.h -es1371.o: ../../libpci/pci.h -es1371.o: ../AC97.h -es1371.o: ../framework/../../drivers.h -es1371.o: ../framework/audio_fw.h -es1371.o: /usr/include/ansi.h -es1371.o: /usr/include/errno.h -es1371.o: /usr/include/ibm/bios.h -es1371.o: /usr/include/ibm/interrupt.h -es1371.o: /usr/include/ibm/ports.h -es1371.o: /usr/include/limits.h -es1371.o: /usr/include/minix/bitmap.h -es1371.o: /usr/include/minix/callnr.h -es1371.o: /usr/include/minix/com.h -es1371.o: /usr/include/minix/config.h -es1371.o: /usr/include/minix/const.h -es1371.o: /usr/include/minix/devio.h -es1371.o: /usr/include/minix/dmap.h -es1371.o: /usr/include/minix/ioctl.h -es1371.o: /usr/include/minix/ipc.h -es1371.o: /usr/include/minix/sys_config.h -es1371.o: /usr/include/minix/syslib.h -es1371.o: /usr/include/minix/sysutil.h -es1371.o: /usr/include/minix/type.h -es1371.o: /usr/include/signal.h -es1371.o: /usr/include/stddef.h -es1371.o: /usr/include/stdlib.h -es1371.o: /usr/include/string.h -es1371.o: /usr/include/sys/dir.h -es1371.o: /usr/include/sys/ioc_sound.h -es1371.o: /usr/include/sys/types.h -es1371.o: /usr/include/unistd.h -es1371.o: SRC.h -es1371.o: codec.h -es1371.o: es1371.c -es1371.o: es1371.h -es1371.o: wait.h - -wait.o: ../../drivers.h -wait.o: ../../libpci/pci.h -wait.o: /usr/include/ansi.h -wait.o: /usr/include/errno.h -wait.o: /usr/include/ibm/bios.h -wait.o: /usr/include/ibm/interrupt.h -wait.o: /usr/include/ibm/ports.h -wait.o: /usr/include/limits.h -wait.o: /usr/include/minix/bitmap.h -wait.o: /usr/include/minix/callnr.h -wait.o: /usr/include/minix/com.h -wait.o: /usr/include/minix/config.h -wait.o: /usr/include/minix/const.h -wait.o: /usr/include/minix/devio.h -wait.o: /usr/include/minix/dmap.h -wait.o: /usr/include/minix/ipc.h -wait.o: /usr/include/minix/sys_config.h -wait.o: /usr/include/minix/syslib.h -wait.o: /usr/include/minix/sysutil.h -wait.o: /usr/include/minix/type.h -wait.o: /usr/include/signal.h -wait.o: /usr/include/stddef.h -wait.o: /usr/include/stdlib.h -wait.o: /usr/include/string.h -wait.o: /usr/include/sys/dir.h -wait.o: /usr/include/sys/types.h -wait.o: /usr/include/time.h -wait.o: /usr/include/unistd.h -wait.o: wait.c diff --git a/drivers/audio/es1371/Makefile b/drivers/audio/es1371/Makefile index 3d32211b3..20fba19c1 100755 --- a/drivers/audio/es1371/Makefile +++ b/drivers/audio/es1371/Makefile @@ -6,39 +6,51 @@ i = $u/include s = $i/sys m = $i/minix b = $i/ibm -pci_dir = ../../libpci -gen_drv_dir = ../../gen_drivers/cyclic_dma # programs, flags, etc. -CC = exec cc -CFLAGS = -I$i +CC = exec cc +CFLAGS = -I$i LDFLAGS = -i -LIBS = -lsys -lsysutil -PCI = $(pci_dir)/pci.o $(pci_dir)/pci_table.o +LIBS = -lsys -lsysutil + +PROGRAM_NAME = es1371 +INSTALL_BIN = /usr/sbin/$(PROGRAM_NAME) +OBJ = es1371.o AC97.o audio_fw.o pci_helper.o wait.o sample_rate_converter.o + + # build local binary -all: es1371 +all: $(PROGRAM_NAME) + + +$(PROGRAM_NAME): $(OBJ) + $(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS) -es1371: es1371.o SRC.o codec.o wait.o audio_fw.o $(PCI) - $(CC) -o $@ $(LDFLAGS) es1371.o SRC.o codec.o wait.o audio_fw.o $(PCI) $(LIBS) audio_fw.o: ../framework/audio_fw.c ../framework/audio_fw.h $(CC) -c ../framework/audio_fw.c -install: /usr/sbin/es1371 -/usr/sbin/es1371: es1371 + +%.o: %.c + $(CC) $(CFLAGS) -c $< + + +install: $(INSTALL_BIN) + + +$(INSTALL_BIN): $(PROGRAM_NAME) install -o root -S 1024k -c $? $@ -$(PCI): - cd $(pci_dir) && $(MAKE) # clean up local files clean: - rm -f *.o *.bak core es1371 + rm -f $(OBJ) $(PROGRAM_NAME) core + depend: /usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend + # Include generated dependencies. include .depend diff --git a/drivers/audio/es1371/es1371.c b/drivers/audio/es1371/es1371.c index f83d5031a..0ce25df60 100755 --- a/drivers/audio/es1371/es1371.c +++ b/drivers/audio/es1371/es1371.c @@ -1,40 +1,58 @@ -/* This is the main file of the ES1371 sound driver - * There is no main function over here, instead the main function - * is located in the generic dma driver. All this driver does is - * implement the interface audio/audio_fw.h. All functions having the - * prefix 'drv_' are dictated by audio/audio_fw.h. The function - * prototypes you see below define a set of private helper functions. - * Control over the sample rate converter and the codec is delegated - * to SRC.c and codec.c respectively. - * +/* Best viewed with tabsize 4 */ + +/* Original: * November 2005 ES1371 driver (Laurens Bronwasser) */ +/* Ensoniq ES1371 driver + * + * aka AudioPCI '97 + * + * This is the main file of the ES1371 sound driver. There is no main function + * over here, instead the main function is located in the generic dma driver. + * All this driver does is implement the interface audio/audio_fw.h. All + * functions having the prefix 'drv_' are dictated by audio/audio_fw.h. The + * function prototypes you see below define a set of private helper functions. + * Control over the AC97 codec is delegated AC97.c. + * + * October 2007 ES1371 driver (Pieter Hijma), + * based on ES1370 driver which is based on the ES1371 driver + * by Laurens Bronwasser + */ + +#include #include "../framework/audio_fw.h" #include "es1371.h" -#include "codec.h" -#include "SRC.h" -#include "../AC97.h" +#include "AC97.h" +#include "sample_rate_converter.h" +#include "pci_helper.h" +/* reg(n) will be the device specific addresses */ #define reg(n) dev.base + n + +/* prototypes of private functions */ FORWARD _PROTOTYPE( int detect_hw, (void) ); FORWARD _PROTOTYPE( int disable_int, (int sub_dev) ); FORWARD _PROTOTYPE( int set_stereo, (u32_t stereo, int sub_dev) ); FORWARD _PROTOTYPE( int set_bits, (u32_t nr_of_bits, int sub_dev) ); FORWARD _PROTOTYPE( int set_sample_rate, (u32_t rate, int sub_dev) ); FORWARD _PROTOTYPE( int set_sign, (u32_t val, int sub_dev) ); -FORWARD _PROTOTYPE( int get_max_frag_size, (u32_t * val, int *len, int sub_dev) ); +FORWARD _PROTOTYPE( int get_max_frag_size, + (u32_t * val, int *len, int sub_dev) ); FORWARD _PROTOTYPE( int set_frag_size, (u32_t fragment_size, int sub_dev) ); FORWARD _PROTOTYPE( int set_int_cnt, (int sub_dev) ); -FORWARD _PROTOTYPE( int AC97Write, (u16_t wAddr, u16_t wData)); -FORWARD _PROTOTYPE( int AC97Read, (u16_t wAddr, u16_t *data)); -FORWARD _PROTOTYPE( void set_nice_volume, (void) ); +FORWARD _PROTOTYPE( int free_buf, (u32_t *val, int *len, int sub_dev) ); +FORWARD _PROTOTYPE( int get_samples_in_buf, + (u32_t *val, int *len, int sub_dev) ); +FORWARD _PROTOTYPE( int get_set_volume, (struct volume_level *level, int *len, + int sub_dev, int flag) ); +FORWARD _PROTOTYPE( int reset, (int sub_dev) ); + DEV_STRUCT dev; -u32_t base = 0; aud_sub_dev_conf_t aud_conf[4]; @@ -44,10 +62,10 @@ PUBLIC drv_t drv; PUBLIC int drv_init(void) { - drv.DriverName = "ES1371"; + drv.DriverName = DRIVER_NAME; drv.NrOfSubDevices = 4; drv.NrOfSpecialFiles = 4; - + sub_dev[DAC1_CHAN].readable = 0; sub_dev[DAC1_CHAN].writable = 1; sub_dev[DAC1_CHAN].DmaSize = 64 * 1024; @@ -71,7 +89,7 @@ PUBLIC int drv_init(void) { sub_dev[DAC2_CHAN].NrOfDmaFragments = 2; sub_dev[DAC2_CHAN].MinFragmentSize = 1024; sub_dev[DAC2_CHAN].NrOfExtraBuffers = 4; - + special_file[0].minor_dev_nr = 0; special_file[0].write_chan = DAC1_CHAN; special_file[0].read_chan = NO_CHANNEL; @@ -93,496 +111,547 @@ PUBLIC int drv_init(void) { special_file[3].io_ctl = DAC2_CHAN; } -int drv_init_hw (void) -{ - u16_t i, j; - - /* First, detect the hardware */ - if (detect_hw() != OK) { - return EIO; - } - /* - Put HW in a nice state ... all devices enabled except joystick, - NMI enables off, clear pending NMIs if any */ - - /* PCI command register */ - pci_attr_w16 (dev.devind, PCI_CR, 0x0105); - /* set power management control/status register */ - pci_attr_w16 (dev.devind, 0xE0, 0x0000); - - pci_outb(reg(CONC_bDEVCTL_OFF), 0x00); - pci_outb(reg(CONC_bMISCCTL_OFF), 0x00); - pci_outb(reg(CONC_b4SPKR_OFF), 0x00); - pci_outb(reg(CONC_bNMIENA_OFF), 0x00); - pci_outb(reg(CONC_bNMICTL_OFF), 0x08); - pci_outw(reg(CONC_wNMISTAT_OFF), 0x0000); - pci_outb(reg(CONC_bSERCTL_OFF), 0x00); - - /* clear all cache RAM */ - for( i = 0; i < 0x10; ++i ) - { - pci_outb(reg(CONC_bMEMPAGE_OFF), i); - for( j = 0; j < 0x10; j += 4 ) - pci_outl (reg(CONC_MEMBASE_OFF) + j, 0UL); - } - /* DO NOT SWITCH THE ORDER OF SRCInit and CODECInit function calls!!! */ - /* The effect is only noticable after a cold reset (reboot) */ - if (SRCInit(&dev) != OK) { - return EIO; - } - if (CODECInit(&dev) != OK) { - return EIO; - } - set_nice_volume(); /* of course we need a nice mixer to do this */ - - /* initialize variables for each sub_device */ - for (i = 0; i < drv.NrOfSubDevices; i++) { - if(i != MIXER) { - aud_conf[i].busy = 0; - aud_conf[i].stereo = DEFAULT_STEREO; - aud_conf[i].sample_rate = DEFAULT_RATE; - aud_conf[i].nr_of_bits = DEFAULT_NR_OF_BITS; - aud_conf[i].sign = DEFAULT_SIGNED; - aud_conf[i].fragment_size = sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments; - } - } - return OK; + +PUBLIC int drv_init_hw (void) { + u16_t i, j; + u16_t chip_sel_ctrl_reg; + + /* First, detect the hardware */ + if (detect_hw() != OK) { + return EIO; + } + + /* PCI command register + * enable the SERR# driver, PCI bus mastering and I/O access + */ + pci_attr_w16 (dev.devind, PCI_CR, SERR_EN|PCI_MASTER|IO_ACCESS); + + /* turn everything off */ + pci_outl(reg(CHIP_SEL_CTRL), 0x0UL); + + /* turn off legacy (legacy control is undocumented) */ + pci_outl(reg(LEGACY), 0x0UL); + pci_outl(reg(LEGACY+4), 0x0UL); + + /* turn off serial interface */ + pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x0UL); + /*pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x3UL);*/ + + + /* clear all the memory */ + for (i = 0; i < 0x10; ++i) { + pci_outb(reg(MEM_PAGE), i); + for (j = 0; j < 0x10; j += 4) { + pci_outl (reg(MEMORY) + j, 0x0UL); + } + } + + /* Sample Rate Converter initialization */ + if (src_init(&dev) != OK) { + return EIO; + } + if (AC97_init(&dev) != OK) { + return EIO; + } + + /* initialize variables for each sub_device */ + for (i = 0; i < drv.NrOfSubDevices; i++) { + if(i != MIXER) { + aud_conf[i].busy = 0; + aud_conf[i].stereo = DEFAULT_STEREO; + aud_conf[i].sample_rate = DEFAULT_RATE; + aud_conf[i].nr_of_bits = DEFAULT_NR_OF_BITS; + aud_conf[i].sign = DEFAULT_SIGNED; + aud_conf[i].fragment_size = + sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments; + } + } + return OK; } PRIVATE int detect_hw(void) { + u32_t device; + int devind; + u16_t v_id, d_id; + + /* detect_hw tries to find device and get IRQ and base address + with a little (much) help from the PCI library. + This code is quite device independent and you can copy it. + (just make sure to get the bugs out first)*/ + + pci_init(); + /* get first device and then search through the list */ + device = pci_first_dev(&devind, &v_id, &d_id); + while( device > 0 ) { + /* if we have a match...break */ + if (v_id == VENDOR_ID && d_id == DEVICE_ID) break; + device = pci_next_dev(&devind, &v_id, &d_id); + } + + /* did we find anything? */ + if (v_id != VENDOR_ID || d_id != DEVICE_ID) { + return EIO; + } + + pci_reserve(devind); + + dev.name = pci_dev_name(v_id, d_id); + + /* get base address of our device, ignore least signif. bit + this last bit thing could be device dependent, i don't know */ + dev.base = pci_attr_r32(devind, PCI_BAR) & 0xfffffffe; + + /* get IRQ */ + dev.irq = pci_attr_r8(devind, PCI_ILR); + dev.revision = pci_attr_r8(devind, PCI_REV); + dev.d_id = d_id; + dev.v_id = v_id; + dev.devind = devind; /* pci device identifier */ - u32_t r; - int devind; - u16_t v_id, d_id; - - /* detect_hw tries to find device and get IRQ and base address - with a little (much) help from the PCI library. - This code is quite device independent and you can copy it. - (just make sure to get the bugs out first)*/ - - pci_init(); - /* get first device and then search through the list */ - r = pci_first_dev(&devind, &v_id, &d_id); - while( r > 0 ) { - /* if we have a match...break */ - if (v_id == VENDOR_ID && d_id == DEVICE_ID) break; - r = pci_next_dev(&devind, &v_id, &d_id); - } - - /* did we find anything? */ - if (v_id != VENDOR_ID || d_id != DEVICE_ID) { - return EIO; - } - /* right here we should reserve the device, but the pci library - doesn't support global reservation of devices yet. This would - be a problem if more ES1371's were installed on this system. */ - - dev.name = pci_dev_name(v_id, d_id); - /* get base address of our device, ignore least signif. bit - this last bit thing could be device dependent, i don't know */ - dev.base = pci_attr_r32(devind, PCI_BAR) & 0xfffffffe; - /* get IRQ */ - dev.irq = pci_attr_r8(devind, PCI_ILR); - dev.revision = pci_attr_r8(devind, 0x08); - dev.d_id = d_id; - dev.v_id = v_id; - dev.devind = devind; /* pci device identifier */ - return OK; + return OK; } -int drv_reset(void) -{ - /* make a WARM reset */ - u16_t i; - - /* set SYNC_RES bit */ - pci_outl(reg(CONC_bDEVCTL_OFF), - pci_inl(reg(CONC_bDEVCTL_OFF)) | SYNC_RES_BIT); - - /* got to delay at least 1 usec, try 18 usec */ - for (i=0; i<100; i++) { - pci_inb(reg(0)); - } - /* clear SYNC_RES bit */ - pci_outl(reg(CONC_bDEVCTL_OFF), - pci_inl(reg(CONC_bDEVCTL_OFF)) & ~SYNC_RES_BIT); - return OK; +PRIVATE int reset(int chan) { + drv_stop(chan); + sub_dev[chan].OutOfData = 1; + + return OK; } -int drv_start(int sub_dev, int DmaMode) -{ - u32_t enable_bit, result = 0; - - /* Write default values to device in case user failed to configure. - If user did configure properly, everything is written twice. - please raise your hand if you object against to this strategy...*/ - result |= set_sample_rate(aud_conf[sub_dev].sample_rate, sub_dev); - result |= set_stereo(aud_conf[sub_dev].stereo, sub_dev); - result |= set_bits(aud_conf[sub_dev].nr_of_bits, sub_dev); - result |= set_sign(aud_conf[sub_dev].sign, sub_dev); - - /* set the interrupt count */ - result |= set_int_cnt(sub_dev); - - if (result) { - return EIO; - } - - /* if device currently paused, resume */ - drv_resume(sub_dev); - - switch(sub_dev) { - case ADC1_CHAN: enable_bit = ADC1_EN_BIT;break; - case DAC1_CHAN: enable_bit = DAC1_EN_BIT;break; - case DAC2_CHAN: enable_bit = DAC2_EN_BIT;break; - default: return EINVAL; - } - /* enable interrupts from 'sub device' */ - drv_reenable_int(sub_dev); - - /* this means GO!!! */ - pci_outl(reg(CONC_bDEVCTL_OFF), - pci_inl(reg(CONC_bDEVCTL_OFF)) | enable_bit); - - aud_conf[sub_dev].busy = 1; - return OK; +int drv_reset() { + return OK; +} + + +int drv_start(int sub_dev, int DmaMode) { + u32_t enable_bit, result = 0; + u32_t debug; + + /* Write default values to device in case user failed to configure. + If user did configure properly, everything is written twice. + please raise your hand if you object against to this strategy...*/ + result |= set_sample_rate(aud_conf[sub_dev].sample_rate, sub_dev); + result |= set_stereo(aud_conf[sub_dev].stereo, sub_dev); + result |= set_bits(aud_conf[sub_dev].nr_of_bits, sub_dev); + result |= set_sign(aud_conf[sub_dev].sign, sub_dev); + + /* set the interrupt count */ + result |= set_int_cnt(sub_dev); + + if (result) { + return EIO; + } + + /* if device currently paused, resume */ + drv_resume(sub_dev); + + switch(sub_dev) { + case ADC1_CHAN: enable_bit = ADC1_EN;break; + case DAC1_CHAN: enable_bit = DAC1_EN;break; + case DAC2_CHAN: enable_bit = DAC2_EN;break; + default: return EINVAL; + } + + /* enable interrupts from 'sub device' */ + drv_reenable_int(sub_dev); + + /* this means play!!! */ + pci_outw(reg(CHIP_SEL_CTRL), pci_inw(reg(CHIP_SEL_CTRL)) | enable_bit); + + aud_conf[sub_dev].busy = 1; + + return OK; } int drv_stop(int sub_dev) { - u32_t enable_bit; - - switch(sub_dev) { - case ADC1_CHAN: enable_bit = ADC1_EN_BIT;break; - case DAC1_CHAN: enable_bit = DAC1_EN_BIT;break; - case DAC2_CHAN: enable_bit = DAC2_EN_BIT;break; - default: return EINVAL; - } - /* stop the codec */ - pci_outl(reg(CONC_bDEVCTL_OFF), - pci_inl(reg(CONC_bDEVCTL_OFF)) & ~enable_bit); - - aud_conf[sub_dev].busy = 0; - disable_int(sub_dev); - return OK; + u32_t enable_bit; + + switch(sub_dev) { + case ADC1_CHAN: enable_bit = ADC1_EN;break; + case DAC1_CHAN: enable_bit = DAC1_EN;break; + case DAC2_CHAN: enable_bit = DAC2_EN;break; + default: return EINVAL; + } + + /* stop the specified channel */ + pci_outw(reg(CHIP_SEL_CTRL), + pci_inw(reg(CHIP_SEL_CTRL)) & ~enable_bit); + aud_conf[sub_dev].busy = 0; + disable_int(sub_dev); + + return OK; } /* all IO-ctl's sent to the upper driver are passed to this function */ int drv_io_ctl(int request, void * val, int * len, int sub_dev) { - int status; - - switch(request) { - case DSPIORATE: status = set_sample_rate(*((u32_t *) val), sub_dev); break; - case DSPIOSTEREO: status = set_stereo(*((u32_t *) val), sub_dev); break; - case DSPIOBITS: status = set_bits(*((u32_t *) val), sub_dev); break; - case DSPIOSIZE: status = set_frag_size(*((u32_t *) val), sub_dev); break; - case DSPIOSIGN: status = set_sign(*((u32_t *) val), sub_dev); break; - case DSPIOMAX: status = get_max_frag_size(val, len, sub_dev);break; - case DSPIORESET: status = drv_reset(); break; - case AC97READ: status = AC97Read (*((u16_t *)val), ((u16_t *) val+2));break; - case AC97WRITE: status = AC97Write(*((u16_t *)val), *((u16_t *) val+2));break; - default: status = EINVAL; break; + int status; + + switch(request) { + case DSPIORATE: + status = set_sample_rate(*((u32_t *) val), sub_dev); break; + case DSPIOSTEREO: + status = set_stereo(*((u32_t *) val), sub_dev); break; + case DSPIOBITS: + status = set_bits(*((u32_t *) val), sub_dev); break; + case DSPIOSIZE: + status = set_frag_size(*((u32_t *) val), sub_dev); break; + case DSPIOSIGN: + status = set_sign(*((u32_t *) val), sub_dev); break; + case DSPIOMAX: + status = get_max_frag_size(val, len, sub_dev); break; + case DSPIORESET: + status = reset(sub_dev); break; + case DSPIOFREEBUF: + status = free_buf(val, len, sub_dev); break; + case DSPIOSAMPLESINBUF: + status = get_samples_in_buf(val, len, sub_dev); break; + case DSPIOPAUSE: + status = drv_pause(sub_dev); break; + case DSPIORESUME: + status = drv_resume(sub_dev); break; + case MIXIOGETVOLUME: + status = get_set_volume(val, len, sub_dev, 0); break; + case MIXIOSETVOLUME: + status = get_set_volume(val, len, sub_dev, 1); break; + default: + status = EINVAL; break; } - - return OK; + + return OK; } int drv_get_irq(char *irq) { - *irq = dev.irq; - return OK; + *irq = dev.irq; + return OK; } int drv_get_frag_size(u32_t *frag_size, int sub_dev) { - *frag_size = aud_conf[sub_dev].fragment_size; - return OK; + *frag_size = aud_conf[sub_dev].fragment_size; + return OK; } int drv_set_dma(u32_t dma, u32_t length, int chan) { - /* dma length in bytes, - max is 64k long words for es1371 = 256k bytes */ - u32_t page, frame_count_reg, dma_add_reg; - - switch(chan) { - case ADC1_CHAN: page = CONC_ADCCTL_PAGE; - frame_count_reg = CONC_wADCFC_OFF; - dma_add_reg = CONC_dADCPADDR_OFF; - break; - case DAC1_CHAN: page = CONC_SYNCTL_PAGE; - frame_count_reg = CONC_wSYNFC_OFF; - dma_add_reg = CONC_dSYNPADDR_OFF; - break;; - case DAC2_CHAN: page = CONC_DACCTL_PAGE; - frame_count_reg = CONC_wDACFC_OFF; - dma_add_reg = CONC_dDACPADDR_OFF; - break;; - default: return EIO; - } - pci_outb(reg(CONC_bMEMPAGE_OFF), page); - pci_outl(reg(dma_add_reg), dma); - /* device expects long word count in stead of bytes */ - length /= 4; - /* device expects length -1 */ - pci_outl(reg(frame_count_reg), (u32_t) (length - 1)); + /* dma length in bytes, + max is 64k long words for es1371 = 256k bytes */ + u32_t page, frame_count_reg, dma_add_reg; + + switch(chan) { + case ADC1_CHAN: page = ADC_MEM_PAGE; + frame_count_reg = ADC_BUFFER_SIZE; + dma_add_reg = ADC_PCI_ADDRESS; + break; + case DAC1_CHAN: page = DAC_MEM_PAGE; + frame_count_reg = DAC1_BUFFER_SIZE; + dma_add_reg = DAC1_PCI_ADDRESS; + break;; + case DAC2_CHAN: page = DAC_MEM_PAGE; + frame_count_reg = DAC2_BUFFER_SIZE; + dma_add_reg = DAC2_PCI_ADDRESS; + break;; + default: return EIO; + } + pci_outb(reg(MEM_PAGE), page); + pci_outl(reg(dma_add_reg), dma); + + /* device expects long word count in stead of bytes */ + length /= 4; + + /* It seems that register _CURRENT_COUNT is overwritten, but this is + * the way to go. The register frame_count_reg is only longword + * addressable. + * It expects length -1 + */ + pci_outl(reg(frame_count_reg), (u32_t) (length - 1)); + + return OK; } /* return status of the interrupt summary bit */ int drv_int_sum(void) { - u32_t int_status; - int_status = pci_inl(reg(CONC_bINTSTAT_OFF)) & 0x80000000UL; - return int_status; + return pci_inl(reg(INTERRUPT_STATUS)) & INTR; } int drv_int(int sub_dev) { - u32_t int_status; - char bit; - - /* return status of interrupt bit of specified channel*/ - - switch (sub_dev) { - case DAC1_CHAN: bit = DAC1_INT_STATUS_BIT;break; - case DAC2_CHAN: bit = DAC2_INT_STATUS_BIT;break; - case ADC1_CHAN: bit = ADC1_INT_STATUS_BIT;break; - } - int_status = pci_inl(reg(CONC_bINTSTAT_OFF)) & bit; - return int_status; + u32_t int_status; + u32_t bit; + u32_t debug; + + /* return status of interrupt bit of specified channel*/ + switch (sub_dev) { + case DAC1_CHAN: bit = DAC1;break; + case DAC2_CHAN: bit = DAC2;break; + case ADC1_CHAN: bit = ADC;break; + } + + int_status = pci_inl(reg(INTERRUPT_STATUS)) & bit; + + return int_status; } int drv_reenable_int(int chan) { - u32_t i, int_en_bit; - - switch(chan) { - case ADC1_CHAN: int_en_bit = ADC1_INT_EN_BIT;break; - case DAC1_CHAN: int_en_bit = DAC1_INT_EN_BIT;break; - case DAC2_CHAN: int_en_bit = DAC2_INT_EN_BIT;break; - default: EINVAL; - } - /* clear and reenable an interrupt */ - i = pci_inl(reg(CONC_bSERFMT_OFF)); - pci_outl(reg(CONC_bSERFMT_OFF), i & ~int_en_bit); - pci_outl(reg(CONC_bSERFMT_OFF), i | int_en_bit); + u16_t ser_interface, int_en_bit; + + switch(chan) { + case ADC1_CHAN: int_en_bit = R1_INT_EN; break; + case DAC1_CHAN: int_en_bit = P1_INTR_EN; break; + case DAC2_CHAN: int_en_bit = P2_INTR_EN; break; + default: EINVAL; + } + + /* clear and reenable an interrupt */ + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit); + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface | int_en_bit); + + return OK; } -int drv_pause(int sub_dev) -{ - u32_t pause_bit; - - disable_int(sub_dev); /* don't send interrupts */ - - switch(sub_dev) { - case DAC1_CHAN: pause_bit = DAC1_PAUSE_BIT;break; - case DAC2_CHAN: pause_bit = DAC2_PAUSE_BIT;break; - default: return EINVAL; - } - /* pause */ - pci_outl(reg(CONC_bSERFMT_OFF), - pci_inl(reg(CONC_bSERFMT_OFF)) | pause_bit); - return OK; +int drv_pause(int sub_dev) { + u32_t pause_bit; + + disable_int(sub_dev); /* don't send interrupts */ + + switch(sub_dev) { + case DAC1_CHAN: pause_bit = P1_PAUSE;break; + case DAC2_CHAN: pause_bit = P2_PAUSE;break; + default: return EINVAL; + } + + /* pause */ + pci_outl(reg(SERIAL_INTERFACE_CTRL), + pci_inl(reg(SERIAL_INTERFACE_CTRL)) | pause_bit); + + return OK; } -int drv_resume(int sub_dev) -{ - u32_t pause_bit = 0; - - /* todo: drv_reenable_int(sub_dev); *//* enable interrupts */ - - switch(sub_dev) { - case DAC1_CHAN: pause_bit = DAC1_PAUSE_BIT;break; - case DAC2_CHAN: pause_bit = DAC2_PAUSE_BIT;break; - default: return EINVAL; - } - /* clear pause bit */ - pci_outl(reg(CONC_bSERFMT_OFF), - pci_inl(reg(CONC_bSERFMT_OFF)) & ~pause_bit); - return OK; +int drv_resume(int sub_dev) { + u32_t pause_bit = 0; + + drv_reenable_int(sub_dev); /* enable interrupts */ + + switch(sub_dev) { + case DAC1_CHAN: pause_bit = P1_PAUSE;break; + case DAC2_CHAN: pause_bit = P2_PAUSE;break; + default: return EINVAL; + } + + /* clear pause bit */ + pci_outl(reg(SERIAL_INTERFACE_CTRL), + pci_inl(reg(SERIAL_INTERFACE_CTRL)) & ~pause_bit); + + return OK; } PRIVATE int set_bits(u32_t nr_of_bits, int sub_dev) { - - /* set format bits for specified channel. */ - u32_t size_16_bit, i; - - switch(sub_dev) { - case ADC1_CHAN: size_16_bit = ADC1_16_8_BIT;break; - case DAC1_CHAN: size_16_bit = DAC1_16_8_BIT;break; - case DAC2_CHAN: size_16_bit = DAC2_16_8_BIT;break; - default: return EINVAL; - } - i = pci_inb(reg(CONC_bSERFMT_OFF)); - i &= ~size_16_bit; - switch(nr_of_bits) { - case 16: i |= size_16_bit;break; - case 8: break; - default: return EINVAL; - } - pci_outb(reg(CONC_bSERFMT_OFF), i); - aud_conf[sub_dev].nr_of_bits = nr_of_bits; - return OK; + /* set format bits for specified channel. */ + u16_t size_16_bit, ser_interface; + + switch(sub_dev) { + case ADC1_CHAN: size_16_bit = R1_S_EB; break; + case DAC1_CHAN: size_16_bit = P1_S_EB; break; + case DAC2_CHAN: size_16_bit = P2_S_EB; break; + default: return EINVAL; + } + + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + ser_interface &= ~size_16_bit; + switch(nr_of_bits) { + case 16: ser_interface |= size_16_bit;break; + case 8: break; + default: return EINVAL; + } + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface); + aud_conf[sub_dev].nr_of_bits = nr_of_bits; + return OK; } PRIVATE int set_stereo(u32_t stereo, int sub_dev) { - - /* set format bits for specified channel. */ - u32_t stereo_bit, i; - switch(sub_dev) { - case ADC1_CHAN: stereo_bit = ADC1_STEREO_BIT;break; - case DAC1_CHAN: stereo_bit = DAC1_STEREO_BIT;break; - case DAC2_CHAN: stereo_bit = DAC2_STEREO_BIT;break; - default: return EINVAL; - } - i = pci_inb(reg(CONC_bSERFMT_OFF)); - i &= ~stereo_bit; - if( stereo == TRUE ) { - i |= stereo_bit; - } - pci_outb(reg(CONC_bSERFMT_OFF), i); - aud_conf[sub_dev].stereo = stereo; - return OK; + /* set format bits for specified channel. */ + u16_t stereo_bit, ser_interface; + + switch(sub_dev) { + case ADC1_CHAN: stereo_bit = R1_S_MB; break; + case DAC1_CHAN: stereo_bit = P1_S_MB; break; + case DAC2_CHAN: stereo_bit = P2_S_MB; break; + default: return EINVAL; + } + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + ser_interface &= ~stereo_bit; + if (stereo) { + ser_interface |= stereo_bit; + } + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface); + aud_conf[sub_dev].stereo = stereo; + + return OK; } PRIVATE int set_sign(u32_t val, int sub_dev) { - return OK; + return OK; } PRIVATE int set_frag_size(u32_t fragment_size, int sub_dev_nr) { - if (fragment_size > (sub_dev[sub_dev_nr].DmaSize / sub_dev[sub_dev_nr].NrOfDmaFragments) || fragment_size < sub_dev[sub_dev_nr].MinFragmentSize) { - return EINVAL; - } - aud_conf[sub_dev_nr].fragment_size = fragment_size; - return OK; + if (fragment_size > (sub_dev[sub_dev_nr].DmaSize / + sub_dev[sub_dev_nr].NrOfDmaFragments) || + fragment_size < sub_dev[sub_dev_nr].MinFragmentSize) { + return EINVAL; + } + aud_conf[sub_dev_nr].fragment_size = fragment_size; + + return OK; } PRIVATE int set_sample_rate(u32_t rate, int sub_dev) { - u32_t SRCBaseReg; - - if (rate > MAX_RATE || rate < MIN_RATE) { - return EINVAL; - } - /* set the sample rate for the specified channel*/ - switch(sub_dev) { - case ADC1_CHAN: SRCBaseReg = SRC_ADC_BASE;break; - case DAC1_CHAN: SRCBaseReg = SRC_SYNTH_BASE;break; - case DAC2_CHAN: SRCBaseReg = SRC_DAC_BASE;break; - default: return EINVAL; - } - SRCSetRate(&dev, SRCBaseReg, rate); - aud_conf[sub_dev].sample_rate = rate; - return OK; + u32_t src_base_reg; + + if (rate > MAX_RATE || rate < MIN_RATE) { + return EINVAL; + } + /* set the sample rate for the specified channel*/ + switch(sub_dev) { + case ADC1_CHAN: src_base_reg = SRC_ADC_BASE;break; + case DAC1_CHAN: src_base_reg = SRC_SYNTH_BASE;break; + case DAC2_CHAN: src_base_reg = SRC_DAC_BASE;break; + default: return EINVAL; + } + src_set_rate(&dev, src_base_reg, rate); + aud_conf[sub_dev].sample_rate = rate; + return OK; } PRIVATE int set_int_cnt(int chan) { - /* Write interrupt count for specified channel. - After bytes, an interrupt will be generated */ - - int sample_count; u16_t int_cnt_reg; - - if (aud_conf[chan].fragment_size > (sub_dev[chan].DmaSize / sub_dev[chan].NrOfDmaFragments) - || aud_conf[chan].fragment_size < sub_dev[chan].MinFragmentSize) { - return EINVAL; - } - - switch(chan) { - case ADC1_CHAN: int_cnt_reg = CONC_wADCIC_OFF;break; - case DAC1_CHAN: int_cnt_reg = CONC_wSYNIC_OFF;break; - case DAC2_CHAN: int_cnt_reg = CONC_wDACIC_OFF;break; - default: return EINVAL; - } - - sample_count = aud_conf[chan].fragment_size; - - /* adjust sample count according to sample format */ - if( aud_conf[chan].stereo == TRUE ) sample_count >>= 1; - switch(aud_conf[chan].nr_of_bits) { - case 16: sample_count >>= 1;break; - case 8: break; - default: return EINVAL; - } - /* set the sample count - 1 for the specified channel. */ - pci_outw(reg(int_cnt_reg), sample_count - 1); - return OK; + /* Write interrupt count for specified channel. + After bytes, an interrupt will be generated */ + + int sample_count; + u16_t int_cnt_reg; + + if (aud_conf[chan].fragment_size > + (sub_dev[chan].DmaSize / sub_dev[chan].NrOfDmaFragments) + || aud_conf[chan].fragment_size < sub_dev[chan].MinFragmentSize) { + return EINVAL; + } + + switch(chan) { + case ADC1_CHAN: int_cnt_reg = ADC_SAMP_CT; break; + case DAC1_CHAN: int_cnt_reg = DAC1_SAMP_CT; break; + case DAC2_CHAN: int_cnt_reg = DAC2_SAMP_CT; break; + default: return EINVAL; + } + + sample_count = aud_conf[chan].fragment_size; + + /* adjust sample count according to sample format */ + if( aud_conf[chan].stereo == TRUE ) sample_count >>= 1; + switch(aud_conf[chan].nr_of_bits) { + case 16: sample_count >>= 1;break; + case 8: break; + default: return EINVAL; + } + + /* set the sample count - 1 for the specified channel. */ + pci_outw(reg(int_cnt_reg), sample_count - 1); + + return OK; } PRIVATE int get_max_frag_size(u32_t * val, int * len, int sub_dev_nr) { - *len = sizeof(*val); - *val = (sub_dev[sub_dev_nr].DmaSize / sub_dev[sub_dev_nr].NrOfDmaFragments); - return OK; + *len = sizeof(*val); + *val = (sub_dev[sub_dev_nr].DmaSize / + sub_dev[sub_dev_nr].NrOfDmaFragments); + return OK; } PRIVATE int disable_int(int chan) { - u32_t i, int_en_bit; - - switch(chan) { - case ADC1_CHAN: int_en_bit = ADC1_INT_EN_BIT;break; - case DAC1_CHAN: int_en_bit = DAC1_INT_EN_BIT;break; - case DAC2_CHAN: int_en_bit = DAC2_INT_EN_BIT;break; - default: EINVAL; - } - /* clear the interrupt */ - i = pci_inl(reg(CONC_bSERFMT_OFF)); - pci_outl(reg(CONC_bSERFMT_OFF), i & ~int_en_bit); + u16_t ser_interface, int_en_bit; + + switch(chan) { + case ADC1_CHAN: int_en_bit = R1_INT_EN; break; + case DAC1_CHAN: int_en_bit = P1_INTR_EN; break; + case DAC2_CHAN: int_en_bit = P2_INTR_EN; break; + default: EINVAL; + } + /* clear the interrupt */ + ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL)); + pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit); } -PRIVATE void set_nice_volume(void) { - /* goofy code to set the DAC1 channel to an audibe volume - to be able to test it without using the mixer */ - - AC97Write(AC97_PCM_OUT_VOLUME, 0x0808);/* the higher, the softer */ - AC97Write(AC97_MASTER_VOLUME, 0x0101); - AC97Write(0x38, 0); /* not crucial */ - - AC97Write(AC97_LINE_IN_VOLUME, 0x0303); - AC97Write(AC97_MIC_VOLUME, 0x0303); - - /* mute record gain */ - AC97Write(AC97_RECORD_GAIN_VOLUME, 0xFFFF); - - /* Also, to be able test recording without mixer: - select ONE channel as input below. */ - - /* select LINE IN */ - /*CodecWrite(AC97_RECORD_SELECT, 0x0404);*/ - - /* select MIC */ - AC97Write(AC97_RECORD_SELECT, 0x0000); - - /* unmute record gain */ - AC97Write(AC97_RECORD_GAIN_VOLUME, 0x0000); +PRIVATE int get_samples_in_buf (u32_t *samples_in_buf, int *len, int chan) { + u16_t samp_ct_reg; + u16_t curr_samp_ct_reg; + u16_t samp_ct; /* nr of samples - 1 that will be played back */ + u16_t curr_samp_ct; /* counts back from SAMP_CT till 0 */ + + *len = sizeof(*samples_in_buf); + + switch(chan) { + case ADC1_CHAN: + curr_samp_ct_reg = ADC_CURR_SAMP_CT; + samp_ct_reg = ADC_SAMP_CT; break; + case DAC1_CHAN: + curr_samp_ct_reg = DAC1_CURR_SAMP_CT; + samp_ct_reg = DAC1_SAMP_CT; break; + case DAC2_CHAN: + curr_samp_ct_reg = DAC2_CURR_SAMP_CT; + samp_ct_reg = DAC2_SAMP_CT; break; + default: return EINVAL; + } + + samp_ct = pci_inw(reg(samp_ct_reg)); + curr_samp_ct = pci_inw(reg(curr_samp_ct_reg)); + + *samples_in_buf = (u32_t) (sub_dev[chan].BufLength * 8192) + + curr_samp_ct; + + return OK; } -/* The following two functions can be used by the mixer to - control and read volume settings. */ -PRIVATE int AC97Write (u16_t addr, u16_t data) -{ - /* todo: only allow volume control, - no serial data or dev ctl please*/ - return CodecWriteUnsynced(&dev, addr, data); -} +/* returns 1 if there are free buffers */ +PRIVATE int free_buf (u32_t *val, int *len, int sub_dev_nr) { + *len = sizeof(*val); + if (sub_dev[sub_dev_nr].BufLength == + sub_dev[sub_dev_nr].NrOfExtraBuffers) { + *val = 0; + } + else { + *val = 1; + } + return OK; +} -PRIVATE int AC97Read (u16_t addr, u16_t *data) -{ - return CodecReadUnsynced(&dev, addr, data); +PRIVATE int get_set_volume(struct volume_level *level, int *len, int sub_dev, + int flag) { + *len = sizeof(struct volume_level); + if (sub_dev == MIXER) { + return AC97_get_set_volume(level, flag); + } + else { + return EINVAL; + } } diff --git a/drivers/audio/es1371/es1371.h b/drivers/audio/es1371/es1371.h index 309b1c0b4..c3df78793 100755 --- a/drivers/audio/es1371/es1371.h +++ b/drivers/audio/es1371/es1371.h @@ -1,138 +1,128 @@ #ifndef ES1371_H #define ES1371_H - +/* best viewed with tabsize=4 */ + #include #include "../../drivers.h" -#include "../../libpci/pci.h" #include +#include -#define DAC1_CHAN 0 -#define ADC1_CHAN 1 -#define MIXER 2 -#define DAC2_CHAN 3 /* set your vendor and device ID's here */ -#define VENDOR_ID 0x1274 -#define DEVICE_ID 0x1371 - -/* Concert97 direct register offset defines */ -#define CONC_bDEVCTL_OFF 0x00 /* Device control/enable */ -#define CONC_bMISCCTL_OFF 0x01 /* Miscellaneous control */ -#define CONC_bGPIO_OFF 0x02 /* General purpose I/O control */ -#define CONC_bJOYCTL_OFF 0x03 /* Joystick control (decode) */ -#define CONC_bINTSTAT_OFF 0x04 /* Device interrupt status */ -#define CONC_bCODECSTAT_OFF 0x05 /* CODEC interface status */ -#define CONC_bINTSUMM_OFF 0x07 /* Interrupt summary status */ -#define CONC_b4SPKR_OFF 0x07 /* Also 4 speaker config reg */ -#define CONC_bSPDIF_ROUTE_OFF 0x07 /* Also S/PDIF route control reg */ -#define CONC_bUARTDATA_OFF 0x08 /* UART data R/W - read clears RX int */ -#define CONC_bUARTCSTAT_OFF 0x09 /* UART control and status */ -#define CONC_bUARTTEST_OFF 0x0a /* UART test control reg */ -#define CONC_bMEMPAGE_OFF 0x0c /* Memory page select */ -#define CONC_dSRCIO_OFF 0x10 /* I/O ctl/stat/data for SRC RAM */ -#define CONC_dCODECCTL_OFF 0x14 /* CODEC control - u32_t read/write */ -#define CONC_wNMISTAT_OFF 0x18 /* Legacy NMI status */ -#define CONC_bNMIENA_OFF 0x1a /* Legacy NMI enable */ -#define CONC_bNMICTL_OFF 0x1b /* Legacy control */ -#define CONC_bSERFMT_OFF 0x20 /* Serial device format */ -#define CONC_bSERCTL_OFF 0x21 /* Serial device control */ -#define CONC_bSKIPC_OFF 0x22 /* DAC skip count reg */ -#define CONC_wSYNIC_OFF 0x24 /* Synth int count in sample frames */ -#define CONC_wSYNCIC_OFF 0x26 /* Synth current int count */ -#define CONC_wDACIC_OFF 0x28 /* DAC int count in sample frames */ -#define CONC_wDACCIC_OFF 0x2a /* DAC current int count */ -#define CONC_wADCIC_OFF 0x2c /* ADC int count in sample frames */ -#define CONC_wADCCIC_OFF 0x2e /* ADC current int count */ -#define CONC_MEMBASE_OFF 0x30 /* Memory window base - 16 byte window */ - -/* Concert memory page-banked register offset defines */ -#define CONC_dSYNPADDR_OFF 0x30 /* Synth host frame PCI phys addr */ -#define CONC_wSYNFC_OFF 0x34 /* Synth host frame count in u32_t'S */ -#define CONC_wSYNCFC_OFF 0x36 /* Synth host current frame count */ -#define CONC_dDACPADDR_OFF 0x38 /* DAC host frame PCI phys addr */ -#define CONC_wDACFC_OFF 0x3c /* DAC host frame count in u32_t'S */ -#define CONC_wDACCFC_OFF 0x3e /* DAC host current frame count */ -#define CONC_dADCPADDR_OFF 0x30 /* ADC host frame PCI phys addr */ -#define CONC_wADCFC_OFF 0x34 /* ADC host frame count in u32_t'S */ -#define CONC_wADCCFC_OFF 0x36 /* ADC host current frame count */ - -/* memory page number defines */ -#define CONC_SYNRAM_PAGE 0x00 /* Synth host/serial I/F RAM */ -#define CONC_DACRAM_PAGE 0x04 /* DAC host/serial I/F RAM */ -#define CONC_ADCRAM_PAGE 0x08 /* ADC host/serial I/F RAM */ -#define CONC_SYNCTL_PAGE 0x0c /* Page bank for synth host control */ -#define CONC_DACCTL_PAGE 0x0c /* Page bank for DAC host control */ -#define CONC_ADCCTL_PAGE 0x0d /* Page bank for ADC host control */ -#define CONC_FIFO0_PAGE 0x0e /* page 0 of UART "FIFO" (rx stash) */ -#define CONC_FIFO1_PAGE 0x0f /* page 1 of UART "FIFO" (rx stash) */ - - - -/* bits for Interrupt/Chip Select Control Register (offset 0x00)*/ -#define DAC1_EN_BIT bit(6) -#define DAC2_EN_BIT bit(5) -#define ADC1_EN_BIT bit(4) -#define SYNC_RES_BIT bit(14) - -/* bits for Interrupt/Chip Select Status Register (offset 0x04)*/ -#define DAC1_INT_STATUS_BIT bit(2) -#define DAC2_INT_STATUS_BIT bit(1) -#define ADC1_INT_STATUS_BIT bit(0) - -/* some bits for Serial Interface Control Register (CONC_bSERFMT_OFF 20H) */ -#define DAC1_STEREO_BIT bit(0) /* stereo or mono format */ -#define DAC1_16_8_BIT bit(1) /* 16 or 8 bit format */ -#define DAC2_STEREO_BIT bit(2) -#define DAC2_16_8_BIT bit(3) -#define ADC1_STEREO_BIT bit(4) -#define ADC1_16_8_BIT bit(5) -#define DAC1_INT_EN_BIT bit(8) /* interupt enable bits */ -#define DAC2_INT_EN_BIT bit(9) -#define ADC1_INT_EN_BIT bit(10) -#define DAC1_PAUSE_BIT bit(11) -#define DAC2_PAUSE_BIT bit(12) - -/* Some return values */ -#define SRC_SUCCESS 0 -#define CONC_SUCCESS 0 - /* Timeout waiting for: */ -#define SRC_ERR_NOT_BUSY_TIMEOUT -1 /* SRC not busy */ -#define CONC_ERR_NO_PCI_BIOS -2 -#define CONC_ERR_DEVICE_NOT_FOUND -3 -#define CONC_ERR_SPDIF_NOT_AVAIL -4 -#define CONC_ERR_SPDIF_ROUTING_NOT_AVAIL -5 -#define CONC_ERR_4SPEAKER_NOT_AVAIL -6 -#define CONC_ERR_ECHO_NOT_AVAIL -7 +#define VENDOR_ID 0x1274 +#define DEVICE_ID 0x1371 +#define DRIVER_NAME "ES1371" + + +/* channels or subdevices */ +#define DAC1_CHAN 0 +#define ADC1_CHAN 1 +#define MIXER 2 +#define DAC2_CHAN 3 + + +/* PCI command register defines */ +#define SERR_EN 0x0100 +#define PCI_MASTER 0x0004 +#define IO_ACCESS 0x0001 + + +/* Interrupt/Chip Select Control */ +#define CHIP_SEL_CTRL 0x00 +#define ADC1_EN 0x0010 +#define DAC1_EN 0x0040 +#define DAC2_EN 0x0020 +#define CCB_INTRM 0x0400 + + +/* Interrupt/Chip Select Status */ +#define INTERRUPT_STATUS 0x04 +#define ADC 0x0001 +#define DAC2 0x0002 +#define DAC1 0x0004 +#define INTR 0x80000000 + + +/* Sample Rate Converter */ +#define SAMPLE_RATE_CONV 0x10 + + +/* CODEC Write/Read register */ +#define CODEC_WRITE 0x14 +#define CODEC_READ 0x14 + + +/* Legacy address */ +#define LEGACY 0x18 + + +/* Memory related defines */ +#define MEM_PAGE 0x0c +#define ADC_MEM_PAGE 0x0d +#define DAC_MEM_PAGE 0x0c /* for DAC1 and DAC2 */ + +#define MEMORY 0x30 +#define ADC_BUFFER_SIZE 0x34 +#define DAC1_BUFFER_SIZE 0x34 +#define DAC2_BUFFER_SIZE 0X3c +#define ADC_PCI_ADDRESS 0x30 +#define DAC1_PCI_ADDRESS 0x30 +#define DAC2_PCI_ADDRESS 0x38 + + +/* Serial Interface Control */ +#define SERIAL_INTERFACE_CTRL 0x20 +#define P1_S_MB 0x0001 /* DAC1 Stereo/Mono bit */ +#define P1_S_EB 0x0002 /* DAC1 Sixteen/Eight bit */ +#define P2_S_MB 0x0004 /* DAC2 Stereo/Mono bit */ +#define P2_S_EB 0x0008 /* DAC2 Sixteen/Eight bit */ +#define R1_S_MB 0x0010 /* ADC Stereo/Mono bit */ +#define R1_S_EB 0x0020 /* ADC Sixteen/Eight bit */ +#define P1_INTR_EN 0x0100 +#define P2_INTR_EN 0x0200 +#define R1_INT_EN 0x0400 +#define P1_PAUSE 0x0800 +#define P2_PAUSE 0x1000 + + +#define DAC1_SAMP_CT 0x24 +#define DAC1_CURR_SAMP_CT 0x26 +#define DAC2_SAMP_CT 0x28 +#define DAC2_CURR_SAMP_CT 0x2a +#define ADC_SAMP_CT 0x2c +#define ADC_CURR_SAMP_CT 0x2e + typedef struct { - u32_t stereo; - u16_t sample_rate; - u32_t nr_of_bits; - u32_t sign; - u32_t busy; - u32_t fragment_size; + u32_t stereo; + u16_t sample_rate; + u32_t nr_of_bits; + u32_t sign; + u32_t busy; + u32_t fragment_size; } aud_sub_dev_conf_t; /* Some defaults for the aud_sub_dev_conf_t*/ #define DEFAULT_RATE 44100 /* Sample rate */ -#define DEFAULT_NR_OF_BITS 16 /* Nr. of bits per sample per channel*/ -#define DEFAULT_SIGNED 0 /* 0 = unsigned, 1 = signed */ -#define DEFAULT_STEREO 1 /* 0 = mono, 1 = stereo */ -#define MAX_RATE 44100 /* Max sample speed in KHz */ -#define MIN_RATE 4000 /* Min sample speed in KHz */ +#define DEFAULT_NR_OF_BITS 16 /* Nr. of bits per sample per chan */ +#define DEFAULT_SIGNED 0 /* 0 = unsigned, 1 = signed */ +#define DEFAULT_STEREO 1 /* 0 = mono, 1 = stereo */ +#define MAX_RATE 44100 /* Max sample speed in KHz */ +#define MIN_RATE 4000 /* Min sample speed in KHz */ typedef struct DEVSTRUCT { - char* name; - u16_t v_id; /* vendor id */ - u16_t d_id; /* device id */ - u32_t devind; /* minix pci device id, for pci configuration space */ - u32_t base; /* changed to 32 bits */ - char irq; - char revision;/* version of the device */ + char* name; + u16_t v_id; /* vendor id */ + u16_t d_id; /* device id */ + u32_t devind; /* minix pci device id, for + * pci configuration space */ + u32_t base; /* changed to 32 bits */ + char irq; + char revision; /* version of the device */ } DEV_STRUCT; -#define bit(n) 1UL << n - +#define SRC_ERR_NOT_BUSY_TIMEOUT -1 /* SRC not busy */ +#define SRC_SUCCESS 0 #endif /* ES1371_H */ diff --git a/drivers/audio/es1371/wait.c b/drivers/audio/es1371/wait.c index 00db6bfae..afe6bda3a 100755 --- a/drivers/audio/es1371/wait.c +++ b/drivers/audio/es1371/wait.c @@ -1,7 +1,8 @@ #include "../../drivers.h" #include #include -#include "../../libpci/pci.h" +#include "pci_helper.h" + int WaitBitd (int paddr, int bitno, int state, long tmout) { diff --git a/drivers/audio/es1371/wait.h b/drivers/audio/es1371/wait.h index 5df6a39a1..1d8cf8bc6 100755 --- a/drivers/audio/es1371/wait.h +++ b/drivers/audio/es1371/wait.h @@ -1,3 +1,5 @@ +#ifndef WAIT_H +#define WAIT_H /* WAIT.H // General purpose waiting routines @@ -8,3 +10,4 @@ int WaitBitw (int paddr, int bitno, int state, long tmout); int WaitBitd (int paddr, int bitno, int state, long tmout); int MemWaitw (unsigned int volatile *gaddr, int bitno, int state, long tmout); +#endif diff --git a/drivers/audio/framework/audio_fw.c b/drivers/audio/framework/audio_fw.c index bd380990a..dbdcd3d92 100755 --- a/drivers/audio/framework/audio_fw.c +++ b/drivers/audio/framework/audio_fw.c @@ -1,4 +1,6 @@ -/* This file contains a standard driver for audio devices. +/* Best viewed with tabsize 4 + * + * This file contains a standard driver for audio devices. * It supports double dma buffering and can be configured to use * extra buffer space beside the dma buffer. * This driver also support sub devices, which can be independently @@ -6,37 +8,43 @@ * * The driver supports the following operations: * - * m_type DEVICE PROC_NR COUNT POSITION ADRRESS + * m_type DEVICE IO_ENDPT COUNT POSITION ADRRESS * ----------------------------------------------------------------- - * | DEV_OPEN | device | proc nr | | | | + * | DEV_OPEN | device | proc nr | | | | * |-------------+---------+---------+---------+---------+---------| - * | DEV_CLOSE | device | proc nr | | | | + * | DEV_CLOSE | device | proc nr | | | | * |-------------+---------+---------+---------+---------+---------| - * | DEV_READ | device | proc nr | bytes | | buf ptr | + * | DEV_READ_S | device | proc nr | bytes | | buf ptr | * |-------------+---------+---------+---------+---------+---------| - * | DEV_WRITE | device | proc nr | bytes | | buf ptr | + * | DEV_WRITE_S | device | proc nr | bytes | | buf ptr | * |-------------+---------+---------+---------+---------+---------| - * | DEV_IOCTL | device | proc nr |func code| | buf ptr | + * | DEV_IOCTL_S | device | proc nr |func code| | buf ptr | * |-------------+---------+---------+---------+---------+---------| - * | DEV_STATUS | | | | | | + * | DEV_STATUS | | | | | | * |-------------+---------+---------+---------+---------+---------| - * | HARD_INT | | | | | | + * | HARD_INT | | | | | | * |-------------+---------+---------+---------+---------+---------| - * | SIG_STOP | | | | | | + * | SIG_STOP | | | | | | * ----------------------------------------------------------------- * * The file contains one entry point: * * main: main entry when driver is brought up * - * February 2006 Updated audio framework, changed driver-framework relation (Peter Boonstoppel) + * October 2007 Updated audio framework to work with mplayer, added + * savecopies (Pieter Hijma) + * February 2006 Updated audio framework, + * changed driver-framework relation (Peter Boonstoppel) * November 2005 Created generic DMA driver framework (Laurens Bronwasser) - * August 24 2005 Ported audio driver to user space (only audio playback) (Peter Boonstoppel) + * August 24 2005 Ported audio driver to user space + * (only audio playback) (Peter Boonstoppel) * May 20 1995 SB16 Driver: Michel R. Prevenier */ - + + #include "audio_fw.h" + FORWARD _PROTOTYPE( int msg_open, (int minor_dev_nr) ); FORWARD _PROTOTYPE( int msg_close, (int minor_dev_nr) ); FORWARD _PROTOTYPE( int msg_ioctl, (message *m_ptr) ); @@ -73,242 +81,238 @@ PUBLIC void main(void) drv_init(); /* Here is the main loop of the dma driver. It waits for a message, - carries it out, and sends a reply. */ + carries it out, and sends a reply. */ printf("%s up and running\n", drv.DriverName); - + while(1) { receive(ANY, &mess); caller = mess.m_source; - proc_nr = mess.PROC_NR; + proc_nr = mess.IO_ENDPT; + /* Now carry out the work. */ switch(mess.m_type) { case DEV_OPEN: /* open the special file ( = parameter) */ - r = msg_open(mess.DEVICE);break; - + r = msg_open(mess.DEVICE);break; case DEV_CLOSE: /* close the special file ( = parameter) */ - r = msg_close(mess.DEVICE); break; - - case DEV_IOCTL: - r = msg_ioctl(&mess); break; - - case DEV_READ: - msg_read(&mess); continue; /* don't reply */ - - case DEV_WRITE: - msg_write(&mess); continue; /* don't reply */ - - case DEV_STATUS: - msg_status(&mess);continue; /* don't reply */ - + r = msg_close(mess.DEVICE); break; + case DEV_IOCTL_S: + r = msg_ioctl(&mess); break; + case DEV_READ_S: + msg_read(&mess); continue; /* don't reply */ + case DEV_WRITE_S: + msg_write(&mess); continue; /* don't reply */ + case DEV_STATUS: + msg_status(&mess);continue; /* don't reply */ case HARD_INT: - msg_hardware();continue; /* don't reply */ - + msg_hardware();continue; /* don't reply */ case SYS_SIG: - msg_sig_stop(); continue; /* don't reply */ - + msg_sig_stop(); continue; /* don't reply */ default: - r = EINVAL; dprint("%s: %d uncaught msg!\n", mess.m_type ,drv.DriverName); - break; + r = EINVAL; + dprint("%s: %d uncaught msg!\n", drv.DriverName, mess.m_type); + break; } /* Finally, prepare and send the reply message. */ reply(TASK_REPLY, caller, proc_nr, r); } - } + PRIVATE int init_driver(void) { - u32_t i; char irq; - static int executed = 0; - sub_dev_t* sub_dev_ptr; - - /* init variables, get dma buffers */ - for (i = 0; i < drv.NrOfSubDevices; i++) { - - sub_dev_ptr = &sub_dev[i]; - - sub_dev_ptr->Opened = FALSE; - sub_dev_ptr->DmaBusy = FALSE; - sub_dev_ptr->DmaMode = NO_DMA; - sub_dev_ptr->DmaReadNext = 0; - sub_dev_ptr->DmaFillNext = 0; - sub_dev_ptr->DmaLength = 0; - sub_dev_ptr->BufReadNext = 0; - sub_dev_ptr->BufFillNext = 0; - sub_dev_ptr->RevivePending = FALSE; - sub_dev_ptr->OutOfData = FALSE; - sub_dev_ptr->Nr = i; - } - - /* initialize hardware*/ - if (drv_init_hw() != OK) { - error("%s: Could not initialize hardware\n", drv.DriverName, 0); - return EIO; - } - + u32_t i; char irq; + static int executed = 0; + sub_dev_t* sub_dev_ptr; + + /* init variables, get dma buffers */ + for (i = 0; i < drv.NrOfSubDevices; i++) { + + sub_dev_ptr = &sub_dev[i]; + + sub_dev_ptr->Opened = FALSE; + sub_dev_ptr->DmaBusy = FALSE; + sub_dev_ptr->DmaMode = NO_DMA; + sub_dev_ptr->DmaReadNext = 0; + sub_dev_ptr->DmaFillNext = 0; + sub_dev_ptr->DmaLength = 0; + sub_dev_ptr->BufReadNext = 0; + sub_dev_ptr->BufFillNext = 0; + sub_dev_ptr->RevivePending = FALSE; + sub_dev_ptr->OutOfData = FALSE; + sub_dev_ptr->Nr = i; + } + + /* initialize hardware*/ + if (drv_init_hw() != OK) { + error("%s: Could not initialize hardware\n", drv.DriverName, 0); + return EIO; + } + /* get irq from device driver...*/ if (drv_get_irq(&irq) != OK) { - error("%s: init driver couldn't get IRQ", drv.DriverName, i); - return EIO; + error("%s: init driver couldn't get IRQ", drv.DriverName, i); + return EIO; } /* todo: execute the rest of this function only once - we don't want to set irq policy twice */ - if (executed) return OK; - executed = TRUE; - + we don't want to set irq policy twice */ + if (executed) return OK; + executed = TRUE; + /* ...and register interrupt vector */ - if ((i=sys_irqsetpolicy(irq, 0, &irq_hook_id )) != OK){ - error("%s: init driver couldn't set IRQ policy", drv.DriverName, i); - return EIO; - } - irq_hook_set = TRUE; /* now msg_sig_stop knows it must unregister policy*/ + if ((i=sys_irqsetpolicy(irq, 0, &irq_hook_id )) != OK){ + error("%s: init driver couldn't set IRQ policy", drv.DriverName, i); + return EIO; + } + irq_hook_set = TRUE; /* now msg_sig_stop knows it must unregister policy*/ return OK; } PRIVATE int msg_open (int minor_dev_nr) { - int r, read_chan, write_chan, io_ctl; - special_file_t* special_file_ptr; - - dprint("%s: msg_open() special file %d\n", drv.DriverName, minor_dev_nr); - - special_file_ptr = get_special_file(minor_dev_nr); - if(special_file_ptr == NULL) { - return EIO; - } - - read_chan = special_file_ptr->read_chan; - write_chan = special_file_ptr->write_chan; - io_ctl = special_file_ptr->io_ctl; - - if (read_chan==NO_CHANNEL && write_chan==NO_CHANNEL && io_ctl==NO_CHANNEL) { - error("%s: No channel specified for minor device!\n", drv.DriverName, minor_dev_nr); - return EIO; - } - if (read_chan == write_chan && read_chan != NO_CHANNEL) { - error("%s: Read and write channels are equal!\n", drv.DriverName,minor_dev_nr); - return EIO; - } - /* init driver */ - if (!device_available) { - if (init_driver() != OK) { - error("%s: Couldn't init driver!\n", drv.DriverName, minor_dev_nr); - return EIO; - } else { - device_available = TRUE; - } - } - /* open the sub devices specified in the interface header file */ - if (write_chan != NO_CHANNEL) { - /* open sub device for writing */ - if (open_sub_dev(write_chan, DEV_WRITE) != OK) return EIO; - } - if (read_chan != NO_CHANNEL) { - if (open_sub_dev(read_chan, DEV_READ) != OK) return EIO; - } - if (read_chan == io_ctl || write_chan == io_ctl) { - /* io_ctl is already opened because it's the same as read or write */ - return OK; /* we're done */ - } - if (io_ctl != NO_CHANNEL) { /* Ioctl differs from read/write channels, */ - r = open_sub_dev(io_ctl, NO_DMA); /* open it explicitly */ - if (r != OK) return EIO; - } - return OK; + int r, read_chan, write_chan, io_ctl; + special_file_t* special_file_ptr; + + dprint("%s: msg_open() special file %d\n", drv.DriverName, minor_dev_nr); + + special_file_ptr = get_special_file(minor_dev_nr); + if(special_file_ptr == NULL) { + return EIO; + } + + read_chan = special_file_ptr->read_chan; + write_chan = special_file_ptr->write_chan; + io_ctl = special_file_ptr->io_ctl; + + if (read_chan==NO_CHANNEL && write_chan==NO_CHANNEL && io_ctl==NO_CHANNEL) { + error("%s: No channel specified for minor device!\n", + drv.DriverName, minor_dev_nr); + return EIO; + } + if (read_chan == write_chan && read_chan != NO_CHANNEL) { + error("%s: Read and write channels are equal!\n", + drv.DriverName, minor_dev_nr); + return EIO; + } + /* init driver */ + if (!device_available) { + if (init_driver() != OK) { + error("%s: Couldn't init driver!\n", drv.DriverName, minor_dev_nr); + return EIO; + } else { + device_available = TRUE; + } + } + /* open the sub devices specified in the interface header file */ + if (write_chan != NO_CHANNEL) { + /* open sub device for writing */ + if (open_sub_dev(write_chan, DEV_WRITE_S) != OK) return EIO; + } + if (read_chan != NO_CHANNEL) { + if (open_sub_dev(read_chan, DEV_READ_S) != OK) return EIO; + } + if (read_chan == io_ctl || write_chan == io_ctl) { + /* io_ctl is already opened because it's the same as read or write */ + return OK; /* we're done */ + } + if (io_ctl != NO_CHANNEL) { /* Ioctl differs from read/write channels, */ + r = open_sub_dev(io_ctl, NO_DMA); /* open it explicitly */ + if (r != OK) return EIO; + } + return OK; } PRIVATE int open_sub_dev(int sub_dev_nr, int dma_mode) { - sub_dev_t* sub_dev_ptr; int i; - sub_dev_ptr = &sub_dev[sub_dev_nr]; - - /* Only one open at a time per sub device */ + sub_dev_t* sub_dev_ptr; int i; + sub_dev_ptr = &sub_dev[sub_dev_nr]; + + /* Only one open at a time per sub device */ if (sub_dev_ptr->Opened) { - error("%s: Sub device %d is already opened\n", drv.DriverName, sub_dev_nr); - return EBUSY; - } + error("%s: Sub device %d is already opened\n", + drv.DriverName, sub_dev_nr); + return EBUSY; + } if (sub_dev_ptr->DmaBusy) { - error("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr); - return EBUSY; - } + error("%s: Sub device %d is still busy\n", drv.DriverName, sub_dev_nr); + return EBUSY; + } /* Setup variables */ sub_dev_ptr->Opened = TRUE; sub_dev_ptr->DmaReadNext = 0; sub_dev_ptr->DmaFillNext = 0; sub_dev_ptr->DmaLength = 0; sub_dev_ptr->DmaMode = dma_mode; - sub_dev_ptr->BufReadNext = 0; - sub_dev_ptr->BufFillNext = 0; - sub_dev_ptr->BufLength = 0; + sub_dev_ptr->BufReadNext = 0; + sub_dev_ptr->BufFillNext = 0; + sub_dev_ptr->BufLength = 0; sub_dev_ptr->RevivePending = FALSE; sub_dev_ptr->OutOfData = TRUE; - - /* arrange DMA */ - if (dma_mode != NO_DMA) { /* sub device uses DMA */ - /* allocate dma buffer and extra buffer space - and configure sub device for dma */ - if (init_buffers(sub_dev_ptr) != OK ) return EIO; - } - return OK; + + /* arrange DMA */ + if (dma_mode != NO_DMA) { /* sub device uses DMA */ + /* allocate dma buffer and extra buffer space + and configure sub device for dma */ + if (init_buffers(sub_dev_ptr) != OK ) return EIO; + } + return OK; } PRIVATE int msg_close(int minor_dev_nr) { - int r, read_chan, write_chan, io_ctl; - special_file_t* special_file_ptr; - - dprint("%s: msg_close() minor device %d\n", drv.DriverName, minor_dev_nr); - - special_file_ptr = get_special_file(minor_dev_nr); - if(special_file_ptr == NULL) { - return EIO; - } - - read_chan = special_file_ptr->read_chan; - write_chan = special_file_ptr->write_chan; - io_ctl = special_file_ptr->io_ctl; - - /* close all sub devices */ - if (write_chan != NO_CHANNEL) { - if (close_sub_dev(write_chan) != OK) r = EIO; - } - if (read_chan != NO_CHANNEL) { - if (close_sub_dev(read_chan) != OK) r = EIO; - } - if (read_chan == io_ctl || write_chan == io_ctl) { - /* io_ctl is already closed because it's the same as read or write */ - return r; /* we're done */ - } - /* Ioctl differs from read/write channels... */ - if (io_ctl != NO_CHANNEL) { - if (close_sub_dev(io_ctl) != OK) r = EIO; /* ...close it explicitly */ - } - return r; + int r, read_chan, write_chan, io_ctl; + special_file_t* special_file_ptr; + + dprint("%s: msg_close() minor device %d\n", drv.DriverName, minor_dev_nr); + + special_file_ptr = get_special_file(minor_dev_nr); + if(special_file_ptr == NULL) { + return EIO; + } + + read_chan = special_file_ptr->read_chan; + write_chan = special_file_ptr->write_chan; + io_ctl = special_file_ptr->io_ctl; + + /* close all sub devices */ + if (write_chan != NO_CHANNEL) { + if (close_sub_dev(write_chan) != OK) r = EIO; + } + if (read_chan != NO_CHANNEL) { + if (close_sub_dev(read_chan) != OK) r = EIO; + } + if (read_chan == io_ctl || write_chan == io_ctl) { + /* io_ctl is already closed because it's the same as read or write */ + return r; /* we're done */ + } + /* ioctl differs from read/write channels... */ + if (io_ctl != NO_CHANNEL) { + if (close_sub_dev(io_ctl) != OK) r = EIO; /* ...close it explicitly */ + } + return r; } PRIVATE int close_sub_dev(int sub_dev_nr) { - sub_dev_t *sub_dev_ptr; - sub_dev_ptr = &sub_dev[sub_dev_nr]; - - if (sub_dev_ptr->DmaMode == DEV_WRITE && !sub_dev_ptr->OutOfData) { - /* do nothing, still data in buffers that has to be transferred */ - sub_dev_ptr->Opened = FALSE; /* keep DMA busy */ - return OK; - } - if (sub_dev_ptr->DmaMode == NO_DMA) { - /* do nothing, there is no dma going on */ - sub_dev_ptr->Opened = FALSE; - return OK; - } - sub_dev_ptr->Opened = FALSE; - sub_dev_ptr->DmaBusy = FALSE; - /* stop the device */ - drv_stop(sub_dev_ptr->Nr); - /* free the buffers */ - free(sub_dev_ptr->DmaBuf); - free(sub_dev_ptr->ExtraBuf); + sub_dev_t *sub_dev_ptr; + sub_dev_ptr = &sub_dev[sub_dev_nr]; + if (sub_dev_ptr->DmaMode == DEV_WRITE_S && !sub_dev_ptr->OutOfData) { + /* do nothing, still data in buffers that has to be transferred */ + sub_dev_ptr->Opened = FALSE; /* keep DMA busy */ + return OK; + } + if (sub_dev_ptr->DmaMode == NO_DMA) { + /* do nothing, there is no dma going on */ + sub_dev_ptr->Opened = FALSE; + return OK; + } + sub_dev_ptr->Opened = FALSE; + sub_dev_ptr->DmaBusy = FALSE; + /* stop the device */ + drv_stop(sub_dev_ptr->Nr); + /* free the buffers */ + free(sub_dev_ptr->DmaBuf); + free(sub_dev_ptr->ExtraBuf); } @@ -316,49 +320,61 @@ PRIVATE int msg_ioctl(message *m_ptr) { int status, len, chan; phys_bytes user_phys; - sub_dev_t *sub_dev_ptr; - special_file_t* special_file_ptr; - - dprint("%s: msg_ioctl() device %d\n", drv.DriverName, m_ptr->DEVICE); - - special_file_ptr = get_special_file(m_ptr->DEVICE); - if(special_file_ptr == NULL) { - return EIO; - } - - chan = special_file_ptr->io_ctl; - + sub_dev_t *sub_dev_ptr; + special_file_t* special_file_ptr; + + dprint("%s: msg_ioctl() device %d\n", drv.DriverName, m_ptr->DEVICE); + + special_file_ptr = get_special_file(m_ptr->DEVICE); + if(special_file_ptr == NULL) { + return EIO; + } + + chan = special_file_ptr->io_ctl; + if (chan == NO_CHANNEL) { - error("%s: No io control channel specified!\n", drv.DriverName); - return EIO; + error("%s: No io control channel specified!\n", drv.DriverName); + return EIO; } /* get pointer to sub device data */ sub_dev_ptr = &sub_dev[chan]; - - if(!sub_dev_ptr->Opened) { - error("%s: io control impossible - not opened!\n", drv.DriverName); - return EIO; - } - /* this is a hack...todo: may we intercept reset calls? */ + if(!sub_dev_ptr->Opened) { + error("%s: io control impossible - not opened!\n", drv.DriverName); + return EIO; + } + + + /* this is a hack...todo: may we intercept reset calls? */ + /* if(m_ptr->REQUEST == DSPIORESET) { - device_available = FALSE; - } - /* this is confusing, _IOC_OUT bit means that there is incoming data */ - if (m_ptr->REQUEST & _IOC_OUT) { /* if there is data for us, copy it */ - len = io_ctl_length(m_ptr->REQUEST); - sys_vircopy(m_ptr->PROC_NR, D, - (vir_bytes)m_ptr->ADDRESS, SELF, D, - (vir_bytes)io_ctl_buf, len); - } - - /* all ioctl's are passed to the device specific part of the driver */ - status = drv_io_ctl(m_ptr->REQUEST, (void *)io_ctl_buf, &len, chan); - - /* _IOC_IN bit -> user expects data */ - if (status == OK && m_ptr->REQUEST & _IOC_IN) { - /* copy result back to user */ - sys_vircopy(SELF, D, (vir_bytes)io_ctl_buf, m_ptr->PROC_NR, D, (vir_bytes)m_ptr->ADDRESS, len); + device_available = FALSE; + } + */ + + + if (m_ptr->REQUEST & _IOC_IN) { /* if there is data for us, copy it */ + len = io_ctl_length(m_ptr->REQUEST); + + if(sys_safecopyfrom(m_ptr->IO_ENDPT, + (vir_bytes)m_ptr->ADDRESS, 0, + (vir_bytes)io_ctl_buf, len, D) != OK) { + printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__); + } + } + + /* all ioctl's are passed to the device specific part of the driver */ + status = drv_io_ctl(m_ptr->REQUEST, (void *)io_ctl_buf, &len, chan); + + /* _IOC_OUT bit -> user expects data */ + if (status == OK && m_ptr->REQUEST & _IOC_OUT) { + /* copy result back to user */ + + if(sys_safecopyto(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, 0, + (vir_bytes)io_ctl_buf, len, D) != OK) { + printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__); + } + } return status; } @@ -366,460 +382,489 @@ PRIVATE int msg_ioctl(message *m_ptr) PRIVATE void msg_write(message *m_ptr) { - int s, chan; sub_dev_t *sub_dev_ptr; - special_file_t* special_file_ptr; - - dprint("%s: msg_write() device %d\n", drv.DriverName, m_ptr->DEVICE); - - special_file_ptr = get_special_file(m_ptr->DEVICE); - chan = special_file_ptr->write_chan; - + int s, chan; sub_dev_t *sub_dev_ptr; + special_file_t* special_file_ptr; + + dprint("%s: msg_write() device %d\n", drv.DriverName, m_ptr->DEVICE); + + special_file_ptr = get_special_file(m_ptr->DEVICE); + chan = special_file_ptr->write_chan; + if (chan == NO_CHANNEL) { - error("%s: No write channel specified!\n", drv.DriverName); - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO); - return; + error("%s: No write channel specified!\n", drv.DriverName); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO); + return; } /* get pointer to sub device data */ sub_dev_ptr = &sub_dev[chan]; - - if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first write */ - if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ - error("%s; Failed to get fragment size!\n", drv.DriverName, 0); - return; - } - } + + if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first write */ + if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ + error("%s; Failed to get fragment size!\n", drv.DriverName, 0); + return; + } + } if(m_ptr->COUNT != sub_dev_ptr->FragSize) { error("Fragment size does not match user's buffer length\n"); - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINVAL); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL); return; } /* if we are busy with something else than writing, return EBUSY */ - if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE) { - error("Already busy with something else then writing\n"); - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EBUSY); + if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE_S) { + error("Already busy with something else then writing\n"); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY); return; } /* unblock the FileSystem, but keep user process blocked until REVIVE*/ - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, SUSPEND); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND); sub_dev_ptr->RevivePending = TRUE; - sub_dev_ptr->ReviveProcNr = m_ptr->PROC_NR; - sub_dev_ptr->UserBuf = m_ptr->ADDRESS; + sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT; + sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS; sub_dev_ptr->NotifyProcNr = m_ptr->m_source; - data_from_user(sub_dev_ptr); - + data_from_user(sub_dev_ptr); + if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */ - dprint("starting audio device\n"); - get_started(sub_dev_ptr); - sub_dev_ptr->DmaMode = DEV_WRITE; /* Dma mode is writing */ + dprint("starting audio device\n"); + get_started(sub_dev_ptr); + sub_dev_ptr->DmaMode = DEV_WRITE_S; /* Dma mode is writing */ } } PRIVATE void msg_read(message *m_ptr) { - int s, chan; sub_dev_t *sub_dev_ptr; - special_file_t* special_file_ptr; - - dprint("%s: msg_read() device %d\n", drv.DriverName, m_ptr->DEVICE); - - special_file_ptr = get_special_file(m_ptr->DEVICE); - chan = special_file_ptr->read_chan; - + int s, chan; sub_dev_t *sub_dev_ptr; + special_file_t* special_file_ptr; + + dprint("%s: msg_read() device %d\n", drv.DriverName, m_ptr->DEVICE); + + special_file_ptr = get_special_file(m_ptr->DEVICE); + chan = special_file_ptr->read_chan; + if (chan == NO_CHANNEL) { - error("%s: No read channel specified!\n", drv.DriverName); - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO); - return; + error("%s: No read channel specified!\n", drv.DriverName); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO); + return; } /* get pointer to sub device data */ sub_dev_ptr = &sub_dev[chan]; - - if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */ - if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ - error("%s: Could not retrieve fragment size!\n", drv.DriverName); - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO); - return; - } - } + + if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */ + if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){ + error("%s: Could not retrieve fragment size!\n", drv.DriverName); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO); + return; + } + } if(m_ptr->COUNT != sub_dev_ptr->FragSize) { - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINVAL); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL); error("fragment size does not match message size\n"); return; } /* if we are busy with something else than reading, reply EBUSY */ - if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ) { - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EBUSY); + if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ_S) { + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY); return; } /* unblock the FileSystem, but keep user process blocked until REVIVE*/ - reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, SUSPEND); + reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND); sub_dev_ptr->RevivePending = TRUE; - sub_dev_ptr->ReviveProcNr = m_ptr->PROC_NR; - sub_dev_ptr->UserBuf = m_ptr->ADDRESS; + sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT; + sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS; sub_dev_ptr->NotifyProcNr = m_ptr->m_source; if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */ - get_started(sub_dev_ptr); - sub_dev_ptr->DmaMode = DEV_READ; /* Dma mode is reading */ + get_started(sub_dev_ptr); + sub_dev_ptr->DmaMode = DEV_READ_S; /* Dma mode is reading */ return; /* no need to get data from DMA buffer at this point */ } - /* check if data is available and possibly fill user's buffer */ - data_to_user(sub_dev_ptr); + /* check if data is available and possibly fill user's buffer */ + data_to_user(sub_dev_ptr); } PRIVATE void msg_hardware(void) { - - u32_t i; - int j = 0; - - dprint("%s: handling hardware message\n", drv.DriverName); - - /* while we have an interrupt */ - while ( drv_int_sum()) { - /* loop over all sub devices */ - for ( i = 0; i < drv.NrOfSubDevices; i++) { - /* if interrupt from sub device and Dma transfer - was actually busy, take care of business */ - if( drv_int(i) && sub_dev[i].DmaBusy ) { - if (sub_dev[i].DmaMode == DEV_WRITE) handle_int_write(i); - if (sub_dev[i].DmaMode == DEV_READ) handle_int_read(i); - } - } - } + + u32_t i; + int j = 0; + + dprint("%s: handling hardware message\n", drv.DriverName); + + /* while we have an interrupt */ + while ( drv_int_sum()) { + /* loop over all sub devices */ + for ( i = 0; i < drv.NrOfSubDevices; i++) { + /* if interrupt from sub device and Dma transfer + was actually busy, take care of business */ + if( drv_int(i) && sub_dev[i].DmaBusy ) { + if (sub_dev[i].DmaMode == DEV_WRITE_S) handle_int_write(i); + if (sub_dev[i].DmaMode == DEV_READ_S) handle_int_read(i); + } + } + } } PRIVATE void msg_status(message *m_ptr) { - int i; - - dprint("got a status message\n"); - for (i = 0; i < drv.NrOfSubDevices; i++) { - - if(sub_dev[i].ReadyToRevive) - { - m_ptr->m_type = DEV_REVIVE; /* build message */ - m_ptr->REP_PROC_NR = sub_dev[i].ReviveProcNr; - m_ptr->REP_STATUS = sub_dev[i].ReviveStatus; - send(m_ptr->m_source, m_ptr); /* send the message */ - - /* reset variables */ - sub_dev[i].ReadyToRevive = FALSE; - sub_dev[i].RevivePending = 0; - - return; /* stop after one mess, - file system will get back for other processes */ - } - } - m_ptr->m_type = DEV_NO_STATUS; - m_ptr->REP_STATUS = 0; - send(m_ptr->m_source, m_ptr); /* send DEV_NO_STATUS message */ + int i; + + dprint("got a status message\n"); + for (i = 0; i < drv.NrOfSubDevices; i++) { + + if(sub_dev[i].ReadyToRevive) + { + m_ptr->m_type = DEV_REVIVE; /* build message */ + m_ptr->REP_ENDPT = sub_dev[i].ReviveProcNr; + m_ptr->REP_IO_GRANT = sub_dev[i].ReviveGrant; + m_ptr->REP_STATUS = sub_dev[i].ReviveStatus; + send(m_ptr->m_source, m_ptr); /* send the message */ + + /* reset variables */ + sub_dev[i].ReadyToRevive = FALSE; + sub_dev[i].RevivePending = 0; + + return; /* stop after one mess, + file system will get back for other processes */ + } + } + m_ptr->m_type = DEV_NO_STATUS; + m_ptr->REP_STATUS = 0; + send(m_ptr->m_source, m_ptr); /* send DEV_NO_STATUS message */ } PRIVATE void msg_sig_stop(void) { - int i; char irq; - for (i = 0; i < drv.NrOfSubDevices; i++) { - drv_stop(i); /* stop all sub devices */ - } - if (irq_hook_set) { - if (sys_irqdisable(&irq_hook_id) != OK) { - error("Could not disable IRQ\n"); - } - /* get irq from device driver*/ - if (drv_get_irq(&irq) != OK) { - error("Msg SIG_STOP Couldn't get IRQ"); - } - /* remove the policy */ - if (sys_irqrmpolicy(irq, &irq_hook_id) != OK) { - error("%s: Could not disable IRQ\n",drv.DriverName); - } - } + int i; char irq; + for (i = 0; i < drv.NrOfSubDevices; i++) { + drv_stop(i); /* stop all sub devices */ + } + if (irq_hook_set) { + if (sys_irqdisable(&irq_hook_id) != OK) { + error("Could not disable IRQ\n"); + } + /* get irq from device driver*/ + if (drv_get_irq(&irq) != OK) { + error("Msg SIG_STOP Couldn't get IRQ"); + } + /* remove the policy */ + if (sys_irqrmpolicy(irq, &irq_hook_id) != OK) { + error("%s: Could not disable IRQ\n",drv.DriverName); + } + } } -/* handle interrupt for specified sub device; DmaMode == DEV_WRITE*/ +/* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/ PRIVATE void handle_int_write(int sub_dev_nr) { - sub_dev_t *sub_dev_ptr; - int r; - - sub_dev_ptr = &sub_dev[sub_dev_nr]; - - dprint("Finished playing dma[%d] ", sub_dev_ptr->DmaReadNext); - sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; + sub_dev_t *sub_dev_ptr; + int r; + + sub_dev_ptr = &sub_dev[sub_dev_nr]; + + dprint("Finished playing dma[%d] ", sub_dev_ptr->DmaReadNext); + sub_dev_ptr->DmaReadNext = + (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; sub_dev_ptr->DmaLength -= 1; - - if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */ - - dprint(" buf[%d] -> dma[%d] ", sub_dev_ptr->BufReadNext, sub_dev_ptr->DmaFillNext); - memcpy(sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize, - sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, - sub_dev_ptr->FragSize); - - sub_dev_ptr->BufReadNext = (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; - sub_dev_ptr->DmaFillNext = (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; - + + if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */ + + dprint(" buf[%d] -> dma[%d] ", + sub_dev_ptr->BufReadNext, sub_dev_ptr->DmaFillNext); + memcpy(sub_dev_ptr->DmaPtr + + sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize, + sub_dev_ptr->ExtraBuf + + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, + sub_dev_ptr->FragSize); + + sub_dev_ptr->BufReadNext = + (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; + sub_dev_ptr->DmaFillNext = + (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; + sub_dev_ptr->BufLength -= 1; - sub_dev_ptr->DmaLength += 1; - } - - /* space became available, possibly copy new data from user */ + sub_dev_ptr->DmaLength += 1; + } + + /* space became available, possibly copy new data from user */ data_from_user(sub_dev_ptr); - - if(sub_dev_ptr->DmaLength == 0) { /* Dma buffer empty, stop Dma transfer */ - - sub_dev_ptr->OutOfData = TRUE; /* we're out of data */ - dprint("No more work...!\n"); - if (!sub_dev_ptr->Opened) { - close_sub_dev(sub_dev_ptr->Nr); - dprint("Stopping sub device %d\n", sub_dev_ptr->Nr); - return; - } - dprint("Pausing sub device %d\n",sub_dev_ptr->Nr); - drv_pause(sub_dev_ptr->Nr); - return; - } - - dprint("\n"); - - /* confirm and reenable interrupt from this sub dev */ - drv_reenable_int(sub_dev_nr); - /* reenable irq_hook*/ + + if(sub_dev_ptr->DmaLength == 0) { /* Dma buffer empty, stop Dma transfer */ + + sub_dev_ptr->OutOfData = TRUE; /* we're out of data */ + dprint("No more work...!\n"); + if (!sub_dev_ptr->Opened) { + close_sub_dev(sub_dev_ptr->Nr); + dprint("Stopping sub device %d\n", sub_dev_ptr->Nr); + return; + } + dprint("Pausing sub device %d\n",sub_dev_ptr->Nr); + drv_pause(sub_dev_ptr->Nr); + return; + } + + dprint("\n"); + + /* confirm and reenable interrupt from this sub dev */ + drv_reenable_int(sub_dev_nr); + /* reenable irq_hook*/ if ((r=sys_irqenable(&irq_hook_id)) != OK) { - error("%s Couldn't enable IRQ\n", drv.DriverName); - } + error("%s Couldn't enable IRQ\n", drv.DriverName); + } } -/* handle interrupt for specified sub device; DmaMode == DEV_READ */ +/* handle interrupt for specified sub device; DmaMode == DEV_READ_S */ PRIVATE void handle_int_read(int sub_dev_nr) { - sub_dev_t *sub_dev_ptr; int r,i; - - sub_dev_ptr = &sub_dev[sub_dev_nr]; - - dprint("Device filled dma[%d]\n", sub_dev_ptr->DmaFillNext); - sub_dev_ptr->DmaLength += 1; - sub_dev_ptr->DmaFillNext = (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; - - /* possibly copy data to user (if it is waiting for us) */ - data_to_user(sub_dev_ptr); - - if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) { /* if dma buffer full */ - - if (sub_dev_ptr->BufLength == sub_dev_ptr->NrOfExtraBuffers) { - error("All buffers full, we have a problem.\n"); - drv_stop(sub_dev_nr); /* stop the sub device */ - sub_dev_ptr->DmaBusy = FALSE; - sub_dev_ptr->ReviveStatus = 0; /* no data for user, this is a sad story */ - sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */ - return; - } - else { /* dma full, still room in extra buf; copy from dma to extra buf */ - dprint("dma full: going to copy buf[%d] <- dma[%d]\n", sub_dev_ptr->BufFillNext, - sub_dev_ptr->DmaReadNext); - memcpy(sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize, - sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, - sub_dev_ptr->FragSize); - sub_dev_ptr->DmaLength -= 1; - sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; - sub_dev_ptr->BufFillNext = (sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers; - } - } - /* confirm interrupt, and reenable interrupt from this sub dev*/ - drv_reenable_int(sub_dev_ptr->Nr); - - /* reenable irq_hook*/ - if ((r=sys_irqenable(&irq_hook_id)) != OK) { - error("%s: Couldn't reenable IRQ", drv.DriverName); - } + sub_dev_t *sub_dev_ptr; int r,i; + + sub_dev_ptr = &sub_dev[sub_dev_nr]; + + dprint("Device filled dma[%d]\n", sub_dev_ptr->DmaFillNext); + sub_dev_ptr->DmaLength += 1; + sub_dev_ptr->DmaFillNext = + (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments; + + /* possibly copy data to user (if it is waiting for us) */ + data_to_user(sub_dev_ptr); + + if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) { + /* if dma buffer full */ + + if (sub_dev_ptr->BufLength == sub_dev_ptr->NrOfExtraBuffers) { + error("All buffers full, we have a problem.\n"); + drv_stop(sub_dev_nr); /* stop the sub device */ + sub_dev_ptr->DmaBusy = FALSE; + sub_dev_ptr->ReviveStatus = 0; /* no data for user, + this is a sad story */ + sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */ + return; + } + else { /* dma full, still room in extra buf; + copy from dma to extra buf */ + dprint("dma full: going to copy buf[%d] <- dma[%d]\n", + sub_dev_ptr->BufFillNext, sub_dev_ptr->DmaReadNext); + memcpy(sub_dev_ptr->ExtraBuf + + sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize, + sub_dev_ptr->DmaPtr + + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, + sub_dev_ptr->FragSize); + sub_dev_ptr->DmaLength -= 1; + sub_dev_ptr->DmaReadNext = + (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; + sub_dev_ptr->BufFillNext = + (sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers; + } + } + /* confirm interrupt, and reenable interrupt from this sub dev*/ + drv_reenable_int(sub_dev_ptr->Nr); + + /* reenable irq_hook*/ + if ((r=sys_irqenable(&irq_hook_id)) != OK) { + error("%s: Couldn't reenable IRQ", drv.DriverName); + } } PRIVATE int get_started(sub_dev_t *sub_dev_ptr) { - u32_t i;char c; - - /* enable interrupt messages from MINIX */ - if ((i=sys_irqenable(&irq_hook_id)) != OK) { - error("%s: Couldn't enable IRQs",drv.DriverName); - return EIO; - } - /* let the lower part of the driver start the device */ - if (drv_start(sub_dev_ptr->Nr, sub_dev_ptr->DmaMode) != OK) { - error("%s: Could not start device %d\n", drv.DriverName, sub_dev_ptr->Nr); - } - - sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */ + u32_t i;char c; + + /* enable interrupt messages from MINIX */ + if ((i=sys_irqenable(&irq_hook_id)) != OK) { + error("%s: Couldn't enable IRQs",drv.DriverName); + return EIO; + } + /* let the lower part of the driver start the device */ + if (drv_start(sub_dev_ptr->Nr, sub_dev_ptr->DmaMode) != OK) { + error("%s: Could not start device %d\n", + drv.DriverName, sub_dev_ptr->Nr); + } + + sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */ sub_dev_ptr->DmaReadNext = 0; - return OK; + return OK; } PRIVATE void data_from_user(sub_dev_t *subdev) { - if (subdev->DmaLength == subdev->NrOfDmaFragments && - subdev->BufLength == subdev->NrOfExtraBuffers) return; /* no space */ - - if (!subdev->RevivePending) return; /* no new data waiting to be copied */ - - if (subdev->RevivePending && - subdev->ReadyToRevive) return; /* we already got this data */ - - - if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ - - sys_datacopy(subdev->ReviveProcNr, - (vir_bytes)subdev->UserBuf, - SELF, - (vir_bytes)subdev->DmaPtr + subdev->DmaFillNext * subdev->FragSize, - (phys_bytes)subdev->FragSize); - - dprint(" user -> dma[%d]\n", subdev->DmaFillNext); - subdev->DmaLength += 1; - subdev->DmaFillNext = (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments; - - } else { /* room in extra buf */ - - sys_datacopy(subdev->ReviveProcNr, - (vir_bytes)subdev->UserBuf, - SELF, - (vir_bytes)subdev->ExtraBuf + subdev->BufFillNext * subdev->FragSize, - (phys_bytes)subdev->FragSize); - + if (subdev->DmaLength == subdev->NrOfDmaFragments && + subdev->BufLength == subdev->NrOfExtraBuffers) return;/* no space */ + + if (!subdev->RevivePending) return; /* no new data waiting to be copied */ + + if (subdev->RevivePending && + subdev->ReadyToRevive) return; /* we already got this data */ + + if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */ + + sys_safecopyfrom(subdev->ReviveProcNr, + (vir_bytes)subdev->ReviveGrant, 0, + (vir_bytes)subdev->DmaPtr + + subdev->DmaFillNext * subdev->FragSize, + (phys_bytes)subdev->FragSize, D); + + + dprint(" user -> dma[%d]\n", subdev->DmaFillNext); + subdev->DmaLength += 1; + subdev->DmaFillNext = + (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments; + + } else { /* room in extra buf */ + + sys_safecopyfrom(subdev->ReviveProcNr, + (vir_bytes)subdev->ReviveGrant, 0, + (vir_bytes)subdev->ExtraBuf + + subdev->BufFillNext * subdev->FragSize, + (phys_bytes)subdev->FragSize, D); + dprint(" user -> buf[%d]\n", subdev->BufFillNext); subdev->BufLength += 1; - - subdev->BufFillNext = (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers; + + subdev->BufFillNext = + (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers; } if(subdev->OutOfData) { /* if device paused (because of lack of data) */ - subdev->OutOfData = FALSE; - drv_reenable_int(subdev->Nr); - /* reenable irq_hook*/ - if ((sys_irqenable(&irq_hook_id)) != OK) { - error("%s: Couldn't enable IRQ", drv.DriverName); - } - drv_resume(subdev->Nr); /* resume resume the sub device */ - - } - + subdev->OutOfData = FALSE; + drv_reenable_int(subdev->Nr); + /* reenable irq_hook*/ + if ((sys_irqenable(&irq_hook_id)) != OK) { + error("%s: Couldn't enable IRQ", drv.DriverName); + } + drv_resume(subdev->Nr); /* resume resume the sub device */ + } + subdev->ReviveStatus = subdev->FragSize; subdev->ReadyToRevive = TRUE; notify(subdev->NotifyProcNr); } -PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr) -{ - if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */ - if (sub_dev_ptr->ReadyToRevive) return; /* we already filled user's buffer */ - if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return; - /* no data for user */ - - if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */ - - sys_datacopy(SELF, - (vir_bytes)sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, - sub_dev_ptr->ReviveProcNr, - (vir_bytes)sub_dev_ptr->UserBuf, - (phys_bytes)sub_dev_ptr->FragSize); - +PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr) { + if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */ + if (sub_dev_ptr->ReadyToRevive) return;/* we already filled user's buffer */ + if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return; + /* no data for user */ + + if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */ + + sys_safecopyto(sub_dev_ptr->ReviveProcNr, + (vir_bytes)sub_dev_ptr->ReviveGrant, + 0, (vir_bytes)sub_dev_ptr->ExtraBuf + + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize, + (phys_bytes)sub_dev_ptr->FragSize, D); + dprint(" copied buf[%d] to user\n", sub_dev_ptr->BufReadNext); + /* adjust the buffer status variables */ - sub_dev_ptr->BufReadNext = (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; + sub_dev_ptr->BufReadNext = + (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers; sub_dev_ptr->BufLength -= 1; - + } else { /* extra buf empty, but data in dma buf*/ + sys_safecopyto( + sub_dev_ptr->ReviveProcNr, + (vir_bytes)sub_dev_ptr->ReviveGrant, 0, + (vir_bytes)sub_dev_ptr->DmaPtr + + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, + (phys_bytes)sub_dev_ptr->FragSize, D); - sys_datacopy(SELF, - (vir_bytes)sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize, - sub_dev_ptr->ReviveProcNr, - (vir_bytes)sub_dev_ptr->UserBuf, - (phys_bytes)sub_dev_ptr->FragSize); - dprint(" copied dma[%d] to user\n", sub_dev_ptr->DmaReadNext); + /* adjust the buffer status variables */ - sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; + sub_dev_ptr->DmaReadNext = + (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments; sub_dev_ptr->DmaLength -= 1; } + sub_dev_ptr->ReviveStatus = sub_dev_ptr->FragSize; - sub_dev_ptr->ReadyToRevive = TRUE; /* drv_status will send REVIVE mess to FS*/ - notify(sub_dev_ptr->NotifyProcNr); /* notify the File Systam to make it - send DEV_STATUS messages*/ + sub_dev_ptr->ReadyToRevive = TRUE; + /* drv_status will send REVIVE mess to FS*/ + notify(sub_dev_ptr->NotifyProcNr); /* notify the File Systam to make it + send DEV_STATUS messages*/ } -PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) { + PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) { #if (CHIP == INTEL) - unsigned left; - u32_t i; - - /* allocate dma buffer space */ - if (!(sub_dev_ptr->DmaBuf = malloc(sub_dev_ptr->DmaSize + 64 * 1024))) { - error("%s: failed to allocate dma buffer for channel %d\n", drv.DriverName,i); - return EIO; - } - /* allocate extra buffer space */ - if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers * sub_dev_ptr->DmaSize / sub_dev_ptr->NrOfDmaFragments))) { - error("%s failed to allocate extra buffer for channel %d\n", drv.DriverName,i); - return EIO; - } - - sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf; - i = sys_umap(SELF, D, - (vir_bytes) sub_dev_ptr->DmaBuf, - (phys_bytes) sizeof(sub_dev_ptr->DmaBuf), - &(sub_dev_ptr->DmaPhys)); - - if (i != OK) { - return EIO; - } - if((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) < sub_dev_ptr->DmaSize) { - /* First half of buffer crosses a 64K boundary, can't DMA into that */ - sub_dev_ptr->DmaPtr += left; - sub_dev_ptr->DmaPhys += left; - } - /* write the physical dma address and size to the device */ - drv_set_dma(sub_dev_ptr->DmaPhys, sub_dev_ptr->DmaSize, sub_dev_ptr->Nr); - return OK; - + unsigned left; + u32_t i; + + /* allocate dma buffer space */ + if (!(sub_dev_ptr->DmaBuf = malloc(sub_dev_ptr->DmaSize + 64 * 1024))) { + error("%s: failed to allocate dma buffer for channel %d\n", + drv.DriverName,i); + return EIO; + } + /* allocate extra buffer space */ + if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers * + sub_dev_ptr->DmaSize / + sub_dev_ptr->NrOfDmaFragments))) { + error("%s failed to allocate extra buffer for channel %d\n", + drv.DriverName,i); + return EIO; + } + + sub_dev_ptr->DmaPtr = sub_dev_ptr->DmaBuf; + i = sys_umap(SELF, D, + (vir_bytes) sub_dev_ptr->DmaBuf, + (phys_bytes) sizeof(sub_dev_ptr->DmaBuf), + &(sub_dev_ptr->DmaPhys)); + + if (i != OK) { + return EIO; + } + if ((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) < + sub_dev_ptr->DmaSize) { + /* First half of buffer crosses a 64K boundary, + * can't DMA into that */ + sub_dev_ptr->DmaPtr += left; + sub_dev_ptr->DmaPhys += left; + } + /* write the physical dma address and size to the device */ + drv_set_dma(sub_dev_ptr->DmaPhys, + sub_dev_ptr->DmaSize, sub_dev_ptr->Nr); + return OK; + #else /* CHIP != INTEL */ - error("%s: init_buffer() failed, CHIP != INTEL", drv.DriverName); - return EIO; + error("%s: init_buffer() failed, CHIP != INTEL", drv.DriverName); + return EIO; #endif /* CHIP == INTEL */ -} + } -PRIVATE void reply(int code, int replyee, int process, int status) -{ +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_PROC_NR = process; /* which user made the request */ + m.REP_ENDPT = process; /* which user made the request */ send(replyee, &m); } PRIVATE int io_ctl_length(int io_request) { - io_request >>= 16; - return io_request & _IOCPARM_MASK; + io_request >>= 16; + return io_request & _IOCPARM_MASK; } PRIVATE special_file_t* get_special_file(int minor_dev_nr) { int i; - + for(i = 0; i < drv.NrOfSpecialFiles; i++) { if(special_file[i].minor_dev_nr == minor_dev_nr) { return &special_file[i]; } } - error("%s: No subdevice specified for minor device %d!\n", drv.DriverName, minor_dev_nr); - + error("%s: No subdevice specified for minor device %d!\n", + drv.DriverName, minor_dev_nr); + return NULL; -} \ No newline at end of file +} diff --git a/drivers/audio/framework/audio_fw.h b/drivers/audio/framework/audio_fw.h index bad32803d..ea3b6e7a1 100755 --- a/drivers/audio/framework/audio_fw.h +++ b/drivers/audio/framework/audio_fw.h @@ -5,8 +5,15 @@ #include -/* change '(void)' to 'printf' to print debug info and error messages */ -#define dprint (void) +/* change to DEBUG to 1 to print debug info and error messages */ + +#define DEBUG 0 + +#if DEBUG +#define dprint printf +#else +#define dprint (void) +#endif #define error printf @@ -51,6 +58,7 @@ typedef struct { int RevivePending; /* process waiting for this dev? */ int ReviveStatus; /* return val when proc unblocked */ int ReviveProcNr; /* the process to unblock */ + cp_grant_id_t ReviveGrant; /* grant id associated with io */ void *UserBuf; /* address of user's data buffer */ int ReadyToRevive; /* are we ready to revive process?*/ int NotifyProcNr; /* process to send notify to (FS) */ diff --git a/drivers/audio/sb16/.depend b/drivers/audio/sb16/.depend deleted file mode 100755 index 418f83b1b..000000000 --- a/drivers/audio/sb16/.depend +++ /dev/null @@ -1,68 +0,0 @@ - -mixer.o: ../framework/../../drivers.h -mixer.o: ../framework/audio_fw.h -mixer.o: /usr/include/ansi.h -mixer.o: /usr/include/errno.h -mixer.o: /usr/include/ibm/bios.h -mixer.o: /usr/include/ibm/interrupt.h -mixer.o: /usr/include/ibm/ports.h -mixer.o: /usr/include/limits.h -mixer.o: /usr/include/minix/bitmap.h -mixer.o: /usr/include/minix/callnr.h -mixer.o: /usr/include/minix/com.h -mixer.o: /usr/include/minix/config.h -mixer.o: /usr/include/minix/const.h -mixer.o: /usr/include/minix/devio.h -mixer.o: /usr/include/minix/dmap.h -mixer.o: /usr/include/minix/ioctl.h -mixer.o: /usr/include/minix/ipc.h -mixer.o: /usr/include/minix/sound.h -mixer.o: /usr/include/minix/sys_config.h -mixer.o: /usr/include/minix/syslib.h -mixer.o: /usr/include/minix/sysutil.h -mixer.o: /usr/include/minix/type.h -mixer.o: /usr/include/signal.h -mixer.o: /usr/include/stddef.h -mixer.o: /usr/include/stdlib.h -mixer.o: /usr/include/string.h -mixer.o: /usr/include/sys/dir.h -mixer.o: /usr/include/sys/ioc_sound.h -mixer.o: /usr/include/sys/types.h -mixer.o: /usr/include/unistd.h -mixer.o: mixer.c -mixer.o: mixer.h -mixer.o: sb16.h - -sb16.o: ../framework/../../drivers.h -sb16.o: ../framework/audio_fw.h -sb16.o: /usr/include/ansi.h -sb16.o: /usr/include/errno.h -sb16.o: /usr/include/ibm/bios.h -sb16.o: /usr/include/ibm/interrupt.h -sb16.o: /usr/include/ibm/ports.h -sb16.o: /usr/include/limits.h -sb16.o: /usr/include/minix/bitmap.h -sb16.o: /usr/include/minix/callnr.h -sb16.o: /usr/include/minix/com.h -sb16.o: /usr/include/minix/config.h -sb16.o: /usr/include/minix/const.h -sb16.o: /usr/include/minix/devio.h -sb16.o: /usr/include/minix/dmap.h -sb16.o: /usr/include/minix/ioctl.h -sb16.o: /usr/include/minix/ipc.h -sb16.o: /usr/include/minix/sound.h -sb16.o: /usr/include/minix/sys_config.h -sb16.o: /usr/include/minix/syslib.h -sb16.o: /usr/include/minix/sysutil.h -sb16.o: /usr/include/minix/type.h -sb16.o: /usr/include/signal.h -sb16.o: /usr/include/stddef.h -sb16.o: /usr/include/stdlib.h -sb16.o: /usr/include/string.h -sb16.o: /usr/include/sys/dir.h -sb16.o: /usr/include/sys/ioc_sound.h -sb16.o: /usr/include/sys/types.h -sb16.o: /usr/include/unistd.h -sb16.o: mixer.h -sb16.o: sb16.c -sb16.o: sb16.h diff --git a/etc/drivers.conf b/etc/drivers.conf index 57b1a6d02..bd52e0ad7 100644 --- a/etc/drivers.conf +++ b/etc/drivers.conf @@ -241,4 +241,29 @@ driver orinoco uid 0; }; +driver es1370 +{ + system + SAFECOPYFROM + SAFECOPYTO + UMAP + SETGRANT + IRQCTL # 19 + DEVIO # 21 + ; + pci device 1274/5000; +}; + +driver es1371 +{ + system + SAFECOPYFROM + SAFECOPYTO + UMAP + SETGRANT + IRQCTL # 19 + DEVIO # 21 + ; + pci device 1274/1371; +}; diff --git a/include/sys/ioc_sound.h b/include/sys/ioc_sound.h index 59ed32a1d..f875ab3b5 100755 --- a/include/sys/ioc_sound.h +++ b/include/sys/ioc_sound.h @@ -9,13 +9,17 @@ #include /* Soundcard DSP ioctls. */ -#define DSPIORATE _IOR('s', 1, unsigned int) -#define DSPIOSTEREO _IOR('s', 2, unsigned int) -#define DSPIOSIZE _IOR('s', 3, unsigned int) -#define DSPIOBITS _IOR('s', 4, unsigned int) -#define DSPIOSIGN _IOR('s', 5, unsigned int) -#define DSPIOMAX _IOW('s', 6, unsigned int) -#define DSPIORESET _IO ('s', 7) +#define DSPIORATE _IOW('s', 1, unsigned int) +#define DSPIOSTEREO _IOW('s', 2, unsigned int) +#define DSPIOSIZE _IOW('s', 3, unsigned int) +#define DSPIOBITS _IOW('s', 4, unsigned int) +#define DSPIOSIGN _IOW('s', 5, unsigned int) +#define DSPIOMAX _IOR('s', 6, unsigned int) +#define DSPIORESET _IO ('s', 7) +#define DSPIOFREEBUF _IOR('s', 30, unsigned int) +#define DSPIOSAMPLESINBUF _IOR('s', 31, unsigned int) +#define DSPIOPAUSE _IO ('s', 32) +#define DSPIORESUME _IO ('s', 33) /* Soundcard mixer ioctls. */ #define MIXIOGETVOLUME _IORW('s', 10, struct volume_level) @@ -27,7 +31,4 @@ #define MIXIOSETINPUTRIGHT _IORW('s', 22, struct inout_ctrl) #define MIXIOSETOUTPUT _IORW('s', 23, struct inout_ctrl) -#define AC97READ _IOW('s', 8, u16_t[2]) -#define AC97WRITE _IOR('s', 9, u16_t[2]) - #endif /* _S_I_SOUND_H */ -- 2.44.0