-
***** Minix 3 Audio drivers *****
Directories:
framework/ Generic driver framework
sb16/ SB16 ISA driver
+es1370/ ES1370 driver
es1371/ ES1371 driver
* 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
--- /dev/null
+# 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
+
--- /dev/null
+/* 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;
+}
--- /dev/null
+#ifndef AK4531_H
+#define AK4531_H
+/* best viewed with tabsize=4 */
+
+#include "../../drivers.h"
+#include <minix/sound.h>
+
+_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
--- /dev/null
+/* 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 <ibm/pci.h>
+
+#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 <DspFragmentSize> 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;
+ }
+}
--- /dev/null
+#ifndef ES1370_H
+#define ES1370_H
+/* best viewed with tabsize=4 */
+
+#include <sys/types.h>
+#include "../../drivers.h"
+#include <sys/ioc_sound.h>
+
+
+/* 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 */
--- /dev/null
+/* best viewed with tabsize 4 */
+
+#include "../../drivers.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <minix/sysutil.h>
+#include <errno.h>
+
+
+#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);
+}
+
--- /dev/null
+#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
+++ /dev/null
-
-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
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
-/* 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 <ibm/pci.h>
#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];
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;
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[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 <DspFragmentSize> 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 <DspFragmentSize> 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;
+ }
}
#ifndef ES1371_H
#define ES1371_H
-
+/* best viewed with tabsize=4 */
+
#include <sys/types.h>
#include "../../drivers.h"
-#include "../../libpci/pci.h"
#include <sys/ioc_sound.h>
+#include <minix/sound.h>
-#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 */
#include "../../drivers.h"
#include <sys/types.h>
#include <time.h>
-#include "../../libpci/pci.h"
+#include "pci_helper.h"
+
int WaitBitd (int paddr, int bitno, int state, long tmout)
{
+#ifndef WAIT_H
+#define WAIT_H
/* WAIT.H
// General purpose waiting routines
int WaitBitd (int paddr, int bitno, int state, long tmout);
int MemWaitw (unsigned int volatile *gaddr, int bitno, int state, long tmout);
+#endif
-/* 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
*
* 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) );
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);
}
{
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;
}
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
+}
#include <sys/ioc_sound.h>
-/* 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
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) */
+++ /dev/null
-
-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
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;
+};
#include <minix/ioctl.h>
/* 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)
#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 */