From: Jia-Ju Bai Date: Wed, 4 Jan 2017 13:55:10 +0000 (+0000) Subject: Add the driver for CS4281 sound card X-Git-Url: http://zhaoyanbai.com/repos/%22http:/www.isc.org/icons/ddns-confgen.html?a=commitdiff_plain;h=refs%2Fchanges%2F87%2F3387%2F1;p=minix.git Add the driver for CS4281 sound card Change-Id: Ifc1b7c129578c5efa5e328664d10d07ee5df786b --- diff --git a/distrib/sets/lists/minix-base/md.i386 b/distrib/sets/lists/minix-base/md.i386 index ad60ac20c..2a948084c 100644 --- a/distrib/sets/lists/minix-base/md.i386 +++ b/distrib/sets/lists/minix-base/md.i386 @@ -10,6 +10,7 @@ ./etc/system.conf.d/amddev minix-base ./etc/system.conf.d/atl2 minix-base ./etc/system.conf.d/cmi8738 minix-base +./etc/system.conf.d/cs4281 minix-base ./etc/system.conf.d/dec21140A minix-base ./etc/system.conf.d/dp8390 minix-base ./etc/system.conf.d/dpeth minix-base @@ -35,6 +36,7 @@ ./service/at_wini minix-base ./service/atl2 minix-base ./service/cmi8738 minix-base +./service/cs4281 minix-base ./service/dec21140A minix-base ./service/dp8390 minix-base ./service/dpeth minix-base diff --git a/distrib/sets/lists/minix-debug/md.i386 b/distrib/sets/lists/minix-debug/md.i386 index 109e8fcb0..d8ad97c0c 100644 --- a/distrib/sets/lists/minix-debug/md.i386 +++ b/distrib/sets/lists/minix-debug/md.i386 @@ -18,6 +18,7 @@ ./usr/libdata/debug/service/at_wini.debug minix-debug debug ./usr/libdata/debug/service/atl2.debug minix-debug debug ./usr/libdata/debug/service/cmi8738.debug minix-debug debug +./usr/libdata/debug/service/cs4281.debug minix-debug debug ./usr/libdata/debug/service/dec21140A.debug minix-debug debug ./usr/libdata/debug/service/dp8390.debug minix-debug debug ./usr/libdata/debug/service/dpeth.debug minix-debug debug diff --git a/minix/drivers/audio/Makefile b/minix/drivers/audio/Makefile index dbcdb9a91..67ba29e69 100644 --- a/minix/drivers/audio/Makefile +++ b/minix/drivers/audio/Makefile @@ -3,6 +3,7 @@ .if ${MACHINE_ARCH} == "i386" SUBDIR+= als4000 SUBDIR+= cmi8738 +SUBDIR+= cs4281 SUBDIR+= es1370 SUBDIR+= es1371 SUBDIR+= sb16 diff --git a/minix/drivers/audio/cs4281/Makefile b/minix/drivers/audio/cs4281/Makefile new file mode 100644 index 000000000..a6c1136ab --- /dev/null +++ b/minix/drivers/audio/cs4281/Makefile @@ -0,0 +1,12 @@ +# Makefile for the CS4281 driver +PROG= cs4281 +SRCS= cs4281.c mixer.c + +FILES=${PROG}.conf +FILESNAME=${PROG} +FILESDIR= /etc/system.conf.d + +DPADD+= ${LIBAUDIODRIVER} ${LIBCHARDRIVER} ${LIBSYS} +LDADD+= -laudiodriver -lchardriver -lsys + +.include diff --git a/minix/drivers/audio/cs4281/README b/minix/drivers/audio/cs4281/README new file mode 100644 index 000000000..8326fd9a3 --- /dev/null +++ b/minix/drivers/audio/cs4281/README @@ -0,0 +1,7 @@ +The cs4281 driver is for Cirrus Logic 4281 (CrystalClear PCI) sound card. + +This driver is referred to Minix(3.4.0) es1371 driver, +Linux snd_cs4281 driver and Cirrus Logic 4281 Datasheet (Rev 1.1). + +Revision 1.0 2016/12/28 +Authored by Jia-Ju Bai diff --git a/minix/drivers/audio/cs4281/cs4281.c b/minix/drivers/audio/cs4281/cs4281.c new file mode 100644 index 000000000..5ffceaf9c --- /dev/null +++ b/minix/drivers/audio/cs4281/cs4281.c @@ -0,0 +1,670 @@ +#include "cs4281.h" +#include "mixer.h" + +/* global value */ +DEV_STRUCT dev; +aud_sub_dev_conf_t aud_conf[3]; +sub_dev_t sub_dev[3]; +special_file_t special_file[3]; +drv_t drv; + +/* internal function */ +static int dev_probe(void); +static int set_sample_rate(u32_t rate, int num); +static int set_stereo(u32_t stereo, int num); +static int set_bits(u32_t bits, int sub_dev); +static int set_frag_size(u32_t frag_size, int num); +static int set_sign(u32_t val, int num); +static int get_frag_size(u32_t *val, int *len, int num); +static int free_buf(u32_t *val, int *len, int num); + +/* developer interface */ +static int dev_reset(u32_t *base); +static void dev_configure(u32_t *base); +static void dev_init_mixer(u32_t *base); +static void dev_set_sample_rate(u32_t *base, u16_t sample_rate); +static void dev_set_format(u32_t *base, u32_t bits, u32_t sign, + u32_t stereo, u32_t sample_count); +static void dev_start_channel(u32_t *base, int sub_dev); +static void dev_stop_channel(u32_t *base, int sub_dev); +static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev); +static u32_t dev_read_dma_current(u32_t *base, int sub_dev); +static void dev_pause_dma(u32_t *base, int sub_dev); +static void dev_resume_dma(u32_t *base, int sub_dev); +static void dev_intr_other(u32_t *base, u32_t status); +static u32_t dev_read_clear_intr_status(u32_t *base); +static void dev_intr_enable(u32_t *base, int flag); + +/* ======= Developer implemented function ======= */ +/* ====== Self-defined function ====== */ + +/* ====== Mixer handling interface ======*/ +/* Write the data to mixer register (### WRITE_MIXER_REG ###) */ +void dev_mixer_write(u32_t *base, u32_t reg, u32_t val) { + u32_t i, data, base0 = base[0]; + sdr_out32(base0, REG_CODEC_ADDR, reg); + sdr_out32(base0, REG_CODEC_DATA, val); + sdr_out32(base0, REG_CODEC_CTRL, 0x0e); + + for (i = 0; i < 50000; i++) { + micro_delay(10); + data = sdr_in32(base0, REG_CODEC_CTRL); + if (!(data & STS_CODEC_DONE)) + break; + } + if (i == 50000) + printf("SDR: Codec is not ready in write\n"); +} + +/* Read the data from mixer register (### READ_MIXER_REG ###) */ +u32_t dev_mixer_read(u32_t *base, u32_t reg) { + u32_t i, data, base0 = base[0]; + sdr_in32(base0, REG_CODEC_SDA); + sdr_out32(base0, REG_CODEC_ADDR, reg & 0xff); + sdr_out32(base0, REG_CODEC_DATA, 0); + sdr_out32(base0, REG_CODEC_CTRL, 0x1e); + for (i = 0; i < 50000; i++) { + micro_delay(10); + data = sdr_in32(base0, REG_CODEC_CTRL); + if (!(data & STS_CODEC_DONE)) + break; + } + if (i == 50000) + printf("SDR: Codec is not ready in read1\n"); + for (i = 0; i < 50000; i++) { + micro_delay(10); + data = sdr_in32(base0, REG_CODEC_STATUS); + if (data & STS_CODEC_VALID) + break; + } + if (i == 50000) + printf("SDR: Codec is not ready in read2\n"); + return sdr_in32(base0, REG_CODEC_SDA); +} + +/* ====== Developer interface ======*/ + +/* Reset the device (### RESET_HARDWARE_CAN_FAIL ###) + * -- Return OK means success, Others means failure */ +static int dev_reset(u32_t *base) { + u32_t data, base0 = base[0]; + data = sdr_in32(base0, REG_POWER_EXT); + if (data & CMD_POWER_DOWN) + sdr_out32(base0, REG_POWER_EXT, data & ~CMD_POWER_DOWN); + data = sdr_in32(base0, REG_CONF_LOAD); + if (data != 0x01) + sdr_out32(base0, REG_CONF_LOAD, 0x01); + sdr_out32(base0, REG_CONF_WRITE, 0x4281); + sdr_out32(base0, REG_SOUND_POWER, 0x3f); + sdr_out32(base0, REG_CLK_CTRL, 0); + sdr_out32(base0, REG_MASTER_CTRL, 0); + sdr_out32(base0, REG_CODEC_CTRL, 0); + micro_delay(100); + sdr_out32(base0, REG_SPOWER_CTRL, 0); + micro_delay(100); + sdr_out32(base0, REG_SPOWER_CTRL, 0x01); + micro_delay(100); + sdr_out32(base0, REG_MASTER_CTRL, 0x00010003); + return OK; +} + +/* Configure hardware registers (### CONF_HARDWARE ###) */ +static void dev_configure(u32_t *base) { + u32_t i, data, base0 = base[0]; + sdr_out32(base0, REG_MASTER_CTRL, CMD_PORT_TIMING | CMD_AC97_MODE | + CMD_MASTER_SERIAL); + sdr_out32(base0, REG_CLK_CTRL, 0x10); + micro_delay(50); + sdr_out32(base0, REG_CLK_CTRL, 0x30); + micro_delay(500); + sdr_out32(base0, REG_CODEC_CTRL, 0x02); + micro_delay(500); + sdr_out32(base0, REG_CODEC_CTRL, 0x06); + micro_delay(500); + sdr_out32(base0, REG_CODEC_OSV, 0x03); + sdr_out32(base0, REG_PCM_LVOL, 0x07); + sdr_out32(base0, REG_PCM_RVOL, 0x07); +} + +/* Initialize the mixer (### INIT_MIXER ###) */ +static void dev_init_mixer(u32_t *base) { + dev_mixer_write(base, 0, 0); +} + +/* Set DAC and ADC sample rate (### SET_SAMPLE_RATE ###) */ +static void dev_set_sample_rate(u32_t *base, u16_t sample_rate) { + u32_t i, data = 0, base0 = base[0]; + for (i = 0; i < 6; i++) { + if (g_sample_rate[i] == sample_rate) { + data = i; + break; + } + } + sdr_out32(base0, REG_DAC_SAMPLE_RATE, data); + sdr_out32(base0, REG_ADC_SAMPLE_RATE, data); +} + +/* Set DAC and ADC format (### SET_FORMAT ###)*/ +static void dev_set_format(u32_t *base, u32_t bits, u32_t sign, + u32_t stereo, u32_t sample_count) { + u32_t base0 = base[0]; + dmr_data = CMD_DMR_INIT; + if (stereo == 0) + dmr_data |= CMD_DMR_MONO; + if (sign == 0) + dmr_data |= CMD_DMR_UNSIGN; + if (bits == 8) { + dmr_data |= CMD_DMR_BIT8; + if (stereo == 0) + dmr_data |= CMD_DMR_SWAP; + } + else if (bits == 32) + dmr_data |= CMD_DMR_BIT32; +} + +/* Start the channel (### START_CHANNEL ###) */ +static void dev_start_channel(u32_t *base, int sub_dev) { + u32_t temp, base0 = base[0]; + + dcr_data = 0x30001; + if (sub_dev == DAC) + fcr_data = CMD_DAC_FCR_INIT; + if (sub_dev == ADC) + fcr_data = CMD_ADC_FCR_INIT; + dmr_data |= CMD_DMR_DMA; + dcr_data &= ~CMD_DCR_MASK; + fcr_data |= CMD_FCR_FEN; + if (sub_dev == DAC) { + dmr_data |= CMD_DMR_WRITE; + sdr_out32(base0, REG_DAC_FSIC, 0); + sdr_out32(base0, REG_DAC_DMR, dmr_data & ~CMD_DMR_DMA); + sdr_out32(base0, REG_DAC_DMR, dmr_data); + sdr_out32(base0, REG_DAC_FCR, fcr_data); + sdr_out32(base0, REG_DAC_DCR, dcr_data); + } + else if (sub_dev == ADC) { + dmr_data |= CMD_DMR_READ; + sdr_out32(base0, REG_ADC_FSIC, 0); + sdr_out32(base0, REG_ADC_DMR, dmr_data & ~CMD_DMR_DMA); + sdr_out32(base0, REG_ADC_DMR, dmr_data); + sdr_out32(base0, REG_ADC_FCR, fcr_data); + sdr_out32(base0, REG_ADC_DCR, dcr_data); + } + +} + +/* Stop the channel (### STOP_CHANNEL ###) */ +static void dev_stop_channel(u32_t *base, int sub_dev) { + u32_t base0 = base[0]; + dmr_data &= ~(CMD_DMR_DMA | CMD_DMR_POLL); + dcr_data |= ~CMD_DCR_MASK; + fcr_data &= ~CMD_FCR_FEN; + if (sub_dev == DAC) { + sdr_out32(base0, REG_DAC_DMR, dmr_data); + sdr_out32(base0, REG_DAC_FCR, fcr_data); + sdr_out32(base0, REG_DAC_DCR, dcr_data); + } + else if (sub_dev == ADC) { + sdr_out32(base0, REG_ADC_DMR, dmr_data); + sdr_out32(base0, REG_ADC_FCR, fcr_data); + sdr_out32(base0, REG_ADC_DCR, dcr_data); + } +} + +/* Set DMA address and length (### SET_DMA ###) */ +static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev) { + u32_t base0 = base[0]; + + if (sub_dev == DAC) { + sdr_out32(base0, REG_DAC_DMA_ADDR, dma); + sdr_out32(base0, REG_DAC_DMA_LEN, len - 1); + } + else if (sub_dev == ADC) { + sdr_out32(base0, REG_ADC_DMA_ADDR, dma); + sdr_out32(base0, REG_ADC_DMA_LEN, len - 1); + } +} + +/* Read current address (### READ_DMA_CURRENT_ADDR ###) */ +static u32_t dev_read_dma_current(u32_t *base, int sub_dev) { + u32_t data, base0 = base[0]; + if (sub_dev == DAC) + data = sdr_in32(base0, REG_DAC_DCC); + else if (sub_dev == ADC) + data = sdr_in16(base0, REG_ADC_DCC); + data &= 0xffff; + return (u16_t)data; +} + +/* Pause the DMA (### PAUSE_DMA ###) */ +static void dev_pause_dma(u32_t *base, int sub_dev) { + u32_t base0 = base[0]; + dcr_data |= CMD_DCR_MASK; + fcr_data |= CMD_FCR_FEN; + if (sub_dev == DAC) { + sdr_out32(base0, REG_DAC_DMR, dmr_data); + sdr_out32(base0, REG_DAC_FCR, fcr_data); + sdr_out32(base0, REG_DAC_DCR, dcr_data); + } + if (sub_dev == ADC) { + sdr_out32(base0, REG_ADC_DMR, dmr_data); + sdr_out32(base0, REG_ADC_FCR, fcr_data); + sdr_out32(base0, REG_ADC_DCR, dcr_data); + } +} + +/* Resume the DMA (### RESUME_DMA ###) */ +static void dev_resume_dma(u32_t *base, int sub_dev) { + u32_t base0 = base[0]; + dcr_data &= ~CMD_DCR_MASK; + fcr_data &= ~CMD_FCR_FEN; + if (sub_dev == DAC) { + sdr_out32(base0, REG_DAC_DMR, dmr_data); + sdr_out32(base0, REG_DAC_FCR, fcr_data); + sdr_out32(base0, REG_DAC_DCR, dcr_data); + } + if (sub_dev == ADC) { + sdr_out32(base0, REG_ADC_DMR, dmr_data); + sdr_out32(base0, REG_ADC_FCR, fcr_data); + sdr_out32(base0, REG_ADC_DCR, dcr_data); + } +} + +/* Read and clear interrupt stats (### READ_CLEAR_INTR_STS ###) + * -- Return interrupt status */ +static u32_t dev_read_clear_intr_status(u32_t *base) { + u32_t status, base0 = base[0]; + status = sdr_in32(base0, REG_INTR_STS); + sdr_in32(base0, REG_DAC_HDSR); + sdr_in32(base0, REG_ADC_HDSR); + sdr_out32(base0, REG_INTR_CTRL, CMD_INTR_ENABLE); + return status; +} + +/* Enable or disable interrupt (### INTR_ENABLE_DISABLE ###) */ +static void dev_intr_enable(u32_t *base, int flag) { + u32_t data, base0 = base[0]; + if (flag == INTR_ENABLE) { + sdr_out32(base0, REG_INTR_CTRL, CMD_INTR_ENABLE); + sdr_out32(base0, REG_INTR_MASK, ~(CMD_INTR_DMA | CMD_INTR_DMA0 | + CMD_INTR_DMA1)); + } + else if (flag == INTR_DISABLE) { + sdr_out32(base0, REG_INTR_CTRL, ~CMD_INTR_ENABLE); + sdr_out32(base0, REG_INTR_MASK, 0x7fffffff); + } +} + +/* ======= Common driver function ======= */ +/* Probe the device */ +static int dev_probe(void) { + int devind, i, ioflag; + u32_t device, bar, size, base; + u16_t vid, did, temp; + u8_t *reg; + + pci_init(); + device = pci_first_dev(&devind, &vid, &did); + while (device > 0) { + if (vid == VENDOR_ID && did == DEVICE_ID) + break; + device = pci_next_dev(&devind, &vid, &did); + } + if (vid != VENDOR_ID || did != DEVICE_ID) + return EIO; + pci_reserve(devind); + + for (i = 0; i < 6; i++) + dev.base[i] = 0; +#ifdef DMA_BASE_IOMAP + for (i = 0; i < 6; i++) { + if (pci_get_bar(devind, PCI_BAR + i * 4, &base, &size, &ioflag)) { + /* printf("SDR: Fail to get PCI BAR %d\n", i); */ + continue; + } + if (ioflag) { + /* printf("SDR: PCI BAR %d is not for memory\n", i); */ + continue; + } + if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) { + printf("SDR: Fail to map hardware registers from PCI\n"); + return -EIO; + } + dev.base[i] = (u32_t)reg; + } +#else + /* Get PCI BAR0-5 */ + for (i = 0; i < 6; i++) + dev.base[i] = pci_attr_r32(devind, PCI_BAR + i * 4) & 0xffffffe0; +#endif + dev.name = pci_dev_name(vid, did); + dev.irq = pci_attr_r8(devind, PCI_ILR); + dev.revision = pci_attr_r8(devind, PCI_REV); + dev.did = did; + dev.vid = vid; + dev.devind = devind; + temp = pci_attr_r16(devind, PCI_CR); + pci_attr_w16(devind, PCI_CR, temp | 0x105); + +#ifdef MY_DEBUG + printf("SDR: Hardware name is %s\n", dev.name); + for (i = 0; i < 6; i++) + printf("SDR: PCI BAR%d is 0x%08x\n", i, dev.base[i]); + printf("SDR: IRQ number is 0x%02x\n", dev.irq); +#endif + return OK; +} + +/* Set sample rate in configuration */ +static int set_sample_rate(u32_t rate, int num) { + aud_conf[num].sample_rate = rate; + return OK; +} + +/* Set stereo in configuration */ +static int set_stereo(u32_t stereo, int num) { + aud_conf[num].stereo = stereo; + return OK; +} + +/* Set sample bits in configuration */ +static int set_bits(u32_t bits, int num) { + aud_conf[num].nr_of_bits = bits; + return OK; +} + +/* Set fragment size in configuration */ +static int set_frag_size(u32_t frag_size, int num) { + if (frag_size > (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments) || + frag_size < sub_dev[num].MinFragmentSize) { + return EINVAL; + } + aud_conf[num].fragment_size = frag_size; + return OK; +} + +/* Set frame sign in configuration */ +static int set_sign(u32_t val, int num) { + aud_conf[num].sign = val; + return OK; +} + +/* Get maximum fragment size */ +static int get_max_frag_size(u32_t *val, int *len, int num) { + *len = sizeof(*val); + *val = (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments); + return OK; +} + +/* Return 1 if there are free buffers */ +static int free_buf(u32_t *val, int *len, int num) { + *len = sizeof(*val); + if (sub_dev[num].BufLength == sub_dev[num].NrOfExtraBuffers) + *val = 0; + else + *val = 1; + return OK; +} + +/* Get the current sample counter */ +static int get_samples_in_buf(u32_t *result, int *len, int chan) { + u32_t res; + /* READ_DMA_CURRENT_ADDR */ + res = dev_read_dma_current(dev.base, chan); + *result = (u32_t)(sub_dev[chan].BufLength * 8192) + res; + return OK; +} + +/* ======= [Audio interface] Initialize data structure ======= */ +int drv_init(void) { + drv.DriverName = DRIVER_NAME; + drv.NrOfSubDevices = 3; + drv.NrOfSpecialFiles = 3; + + sub_dev[DAC].readable = 0; + sub_dev[DAC].writable = 1; + sub_dev[DAC].DmaSize = 64 * 1024; + sub_dev[DAC].NrOfDmaFragments = 2; + sub_dev[DAC].MinFragmentSize = 1024; + sub_dev[DAC].NrOfExtraBuffers = 4; + + sub_dev[ADC].readable = 1; + sub_dev[ADC].writable = 0; + sub_dev[ADC].DmaSize = 64 * 1024; + sub_dev[ADC].NrOfDmaFragments = 2; + sub_dev[ADC].MinFragmentSize = 1024; + sub_dev[ADC].NrOfExtraBuffers = 4; + + sub_dev[MIX].writable = 0; + sub_dev[MIX].readable = 0; + + special_file[0].minor_dev_nr = 0; + special_file[0].write_chan = DAC; + special_file[0].read_chan = NO_CHANNEL; + special_file[0].io_ctl = DAC; + + special_file[1].minor_dev_nr = 1; + special_file[1].write_chan = NO_CHANNEL; + special_file[1].read_chan = ADC; + special_file[1].io_ctl = ADC; + + 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 = MIX; + + return OK; +} + +/* ======= [Audio interface] Initialize hardware ======= */ +int drv_init_hw(void) { + int i; + + /* Match the device */ + if (dev_probe()) { + printf("SDR: No sound card found\n"); + return EIO; + } + + /* Reset the device */ + /* ### RESET_HARDWARE_CAN_FAIL ### */ + if (dev_reset(dev.base)) { + printf("SDR: Fail to reset the device\n"); + return EIO; + } + + /* Configure the hardware */ + /* ### CONF_HARDWARE ### */ + dev_configure(dev.base); + + /* Initialize the mixer */ + /* ### INIT_MIXER ### */ + dev_init_mixer(dev.base); + + /* Set default mixer volume */ + dev_set_default_volume(dev.base); + + /* Initialize subdevice data */ + for (i = 0; i < drv.NrOfSubDevices; i++) { + if (i == MIX) + continue; + aud_conf[i].busy = 0; + aud_conf[i].stereo = 1; + aud_conf[i].sample_rate = 44100; + aud_conf[i].nr_of_bits = 16; + aud_conf[i].sign = 1; + aud_conf[i].fragment_size = + sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments; + } + return OK; +} + +/* ======= [Audio interface] Driver reset =======*/ +int drv_reset(void) { + /* ### RESET_HARDWARE_CAN_FAIL ### */ + return dev_reset(dev.base); +} + +/* ======= [Audio interface] Driver start ======= */ +int drv_start(int sub_dev, int DmaMode) { + int sample_count; + + /* Set DAC and ADC sample rate */ + /* ### SET_SAMPLE_RATE ### */ + dev_set_sample_rate(dev.base, aud_conf[sub_dev].sample_rate); + + sample_count = aud_conf[sub_dev].fragment_size; +#ifdef DMA_LENGTH_BY_FRAME + sample_count = sample_count / (aud_conf[sub_dev].nr_of_bits * (aud_conf[sub_dev].stereo + 1) / 8); +#endif + /* Set DAC and ADC format */ + /* ### SET_FORMAT ### */ + dev_set_format(dev.base, aud_conf[sub_dev].nr_of_bits, + aud_conf[sub_dev].sign, aud_conf[sub_dev].stereo, sample_count); + + drv_reenable_int(sub_dev); + + /* Start the channel */ + /* ### START_CHANNEL ### */ + dev_start_channel(dev.base, sub_dev); + aud_conf[sub_dev].busy = 1; + + return OK; +} + +/* ======= [Audio interface] Driver start ======= */ +int drv_stop(int sub_dev) { + u32_t data; + + /* INTR_ENABLE_DISABLE */ + dev_intr_enable(dev.base, INTR_DISABLE); + + /* ### STOP_CHANNEL ### */ + dev_stop_channel(dev.base, sub_dev); + + aud_conf[sub_dev].busy = 0; + return OK; +} + +/* ======= [Audio interface] Enable interrupt ======= */ +int drv_reenable_int(int chan) { + /* INTR_ENABLE_DISABLE */ + dev_intr_enable(dev.base, INTR_ENABLE); + return OK; +} + +/* ======= [Audio interface] I/O control ======= */ +int drv_io_ctl(unsigned long 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 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: + /* ### GET_SET_VOLUME ### */ + status = get_set_volume(dev.base, val, GET_VOL); + break; + case MIXIOSETVOLUME: + /* ### GET_SET_VOLUME ### */ + status = get_set_volume(dev.base, val, SET_VOL); + break; + default: + status = EINVAL; + break; + } + return status; +} + +/* ======= [Audio interface] Get request number ======= */ +int drv_get_irq(char *irq) { + *irq = dev.irq; + return OK; +} + +/* ======= [Audio interface] Get fragment size ======= */ +int drv_get_frag_size(u32_t *frag_size, int sub_dev) { + *frag_size = aud_conf[sub_dev].fragment_size; + return OK; +} + +/* ======= [Audio interface] Set DMA channel ======= */ +int drv_set_dma(u32_t dma, u32_t length, int chan) { +#ifdef DMA_LENGTH_BY_FRAME + length = length / (aud_conf[chan].nr_of_bits * (aud_conf[chan].stereo + 1) / 8); +#endif + /* ### SET_DMA ### */ + dev_set_dma(dev.base, dma, length, chan); + return OK; +} + +/* ======= [Audio interface] Get interrupt summary status ======= */ +int drv_int_sum(void) { + u32_t status; + /* ### READ_CLEAR_INTR_STS ### */ + status = dev_read_clear_intr_status(dev.base); + dev.intr_status = status; +#ifdef MY_DEBUG + printf("SDR: Interrupt status is 0x%08x\n", status); +#endif + return (status & (INTR_STS_DAC | INTR_STS_ADC)); +} + +/* ======= [Audio interface] Handle interrupt status ======= */ +int drv_int(int sub_dev) { + u32_t mask; + + /* ### CHECK_INTR_DAC ### */ + if (sub_dev == DAC) + mask = INTR_STS_DAC; + /* ### CHECK_INTR_ADC ### */ + else if (sub_dev == ADC) + mask = INTR_STS_ADC; + else + return 0; + + return dev.intr_status & mask; +} + +/* ======= [Audio interface] Pause DMA ======= */ +int drv_pause(int sub_dev) { + /* ### PAUSE_DMA ### */ + dev_pause_dma(dev.base, sub_dev); + return OK; +} + +/* ======= [Audio interface] Resume DMA ======= */ +int drv_resume(int sub_dev) { + /* ### RESUME_DMA ### */ + dev_resume_dma(dev.base, sub_dev); + return OK; +} diff --git a/minix/drivers/audio/cs4281/cs4281.conf b/minix/drivers/audio/cs4281/cs4281.conf new file mode 100644 index 000000000..4c3fd48aa --- /dev/null +++ b/minix/drivers/audio/cs4281/cs4281.conf @@ -0,0 +1,10 @@ +service cs4281 +{ + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + ; + pci device 1013:6005; +}; + diff --git a/minix/drivers/audio/cs4281/cs4281.h b/minix/drivers/audio/cs4281/cs4281.h new file mode 100644 index 000000000..00dc7f2d0 --- /dev/null +++ b/minix/drivers/audio/cs4281/cs4281.h @@ -0,0 +1,139 @@ +#ifndef _SDR_H +#define _SDR_H +/* ======= General Parameter ======= */ +/* Global configure */ +#define DMA_LENGTH_BY_FRAME +#define DMA_BASE_IOMAP +#define MIXER_AC97 + +#include +#include +#include +#include +#include +#include +#include "io.h" + +/* Subdevice type */ +#define DAC 0 +#define ADC 1 +#define MIX 2 + +/* PCI number and driver name */ +#define VENDOR_ID 0x1013 +#define DEVICE_ID 0x6005 +#define DRIVER_NAME "CS4281" + +/* Volume option */ +#define GET_VOL 0 +#define SET_VOL 1 + +/* Interrupt control */ +#define INTR_ENABLE 1 +#define INTR_DISABLE 0 + +/* Interrupt status */ +#define INTR_STS_DAC 0x0100 +#define INTR_STS_ADC 0x0200 + +/* ======= Self-defined Parameter ======= */ +#define REG_INTR_STS 0x0000 +#define REG_INTR_CTRL 0x0008 +#define REG_INTR_MASK 0x000c + +#define REG_CONF_WRITE 0x03e0 +#define REG_POWER_EXT 0x03e4 +#define REG_SPOWER_CTRL 0x03ec +#define REG_CONF_LOAD 0x03f0 +#define REG_CLK_CTRL 0x0400 +#define REG_MASTER_CTRL 0x0420 +#define REG_CODEC_CTRL 0x0460 +#define REG_CODEC_STATUS 0x0464 +#define REG_CODEC_OSV 0x0468 +#define REG_CODEC_ADDR 0x046c +#define REG_CODEC_DATA 0x0470 +#define REG_CODEC_SDA 0x047c +#define REG_SOUND_POWER 0x0740 +#define REG_DAC_SAMPLE_RATE 0x0744 +#define REG_ADC_SAMPLE_RATE 0x0748 +#define REG_SRC_SLOT 0x075c +#define REG_PCM_LVOL 0x0760 +#define REG_PCM_RVOL 0x0764 + +#define REG_DAC_HDSR 0x00f0 +#define REG_DAC_DCC 0x0114 +#define REG_DAC_DMR 0x0150 +#define REG_DAC_DCR 0x0154 +#define REG_DAC_FCR 0x0180 +#define REG_DAC_FSIC 0x0214 +#define REG_ADC_HDSR 0x00f4 +#define REG_ADC_DCC 0x0124 +#define REG_ADC_DMR 0x0158 +#define REG_ADC_DCR 0x015c +#define REG_ADC_FCR 0x0184 +#define REG_ADC_FSIC 0x0214 + +#define REG_DAC_DMA_ADDR 0x0118 +#define REG_DAC_DMA_LEN 0x011c +#define REG_ADC_DMA_ADDR 0x0128 +#define REG_ADC_DMA_LEN 0x012c + +#define CODEC_REG_POWER 0x26 + +#define STS_CODEC_DONE 0x0008 +#define STS_CODEC_VALID 0x0002 + +#define CMD_POWER_DOWN (1 << 14) +#define CMD_PORT_TIMING (1 << 16) +#define CMD_AC97_MODE (1 << 1) +#define CMD_MASTER_SERIAL (1 << 0) +#define CMD_INTR_ENABLE 0x03 +#define CMD_INTR_DMA 0x00040000 +#define CMD_INTR_DMA0 0x0100 +#define CMD_INTR_DMA1 0x0200 +#define CMD_DMR_INIT 0x50 +#define CMD_DMR_WRITE 0x08 +#define CMD_DMR_READ 0x04 +#define CMD_DMR_BIT8 (1 << 16) +#define CMD_DMR_MONO (1 << 17) +#define CMD_DMR_UNSIGN (1 << 19) +#define CMD_DMR_BIT32 (1 << 20) +#define CMD_DMR_SWAP (1 << 22) +#define CMD_DMR_POLL (1 << 28) +#define CMD_DMR_DMA (1 << 29) +#define CMD_DCR_MASK (1 << 0) +#define CMD_FCR_FEN (1 << 31) +#define CMD_DAC_FCR_INIT 0x01002000 +#define CMD_ADC_FCR_INIT 0x0b0a2020 + +static u32_t dcr_data, dmr_data, fcr_data; +static u32_t g_sample_rate[] = { + 48000, 44100, 22050, 16000, 11025, 8000 +}; + +/* Driver Data Structure */ +typedef struct aud_sub_dev_conf_t { + u32_t stereo; + u16_t sample_rate; + u32_t nr_of_bits; + u32_t sign; + u32_t busy; + u32_t fragment_size; + u8_t format; +} aud_sub_dev_conf_t; + +typedef struct DEV_STRUCT { + char *name; + u16_t vid; + u16_t did; + u32_t devind; + u32_t base[6]; + char irq; + char revision; + u32_t intr_status; +} DEV_STRUCT; + +void dev_mixer_write(u32_t *base, u32_t reg, u32_t val); +u32_t dev_mixer_read(u32_t *base, u32_t reg); + +#endif diff --git a/minix/drivers/audio/cs4281/io.h b/minix/drivers/audio/cs4281/io.h new file mode 100644 index 000000000..9c7caf48f --- /dev/null +++ b/minix/drivers/audio/cs4281/io.h @@ -0,0 +1,84 @@ +#ifndef _IO_H +#define _IO_H + +#include +#include +#include "cs4281.h" + +/* I/O function */ +static u8_t my_inb(u32_t port) { + u32_t value; + int r; +#ifdef DMA_BASE_IOMAP + value = *(volatile u8_t *)(port); +#else + if ((r = sys_inb(port, &value)) != OK) + printf("SDR: sys_inb failed: %d\n", r); +#endif + return (u8_t)value; +} +#define sdr_in8(port, offset) (my_inb((port) + (offset))) + +static u16_t my_inw(u32_t port) { + u32_t value; + int r; +#ifdef DMA_BASE_IOMAP + value = *(volatile u16_t *)(port); +#else + if ((r = sys_inw(port, &value)) != OK) + printf("SDR: sys_inw failed: %d\n", r); +#endif + return (u16_t)value; +} +#define sdr_in16(port, offset) (my_inw((port) + (offset))) + +static u32_t my_inl(u32_t port) { + u32_t value; + int r; +#ifdef DMA_BASE_IOMAP + value = *(volatile u32_t *)(port); +#else + if ((r = sys_inl(port, &value)) != OK) + printf("SDR: sys_inl failed: %d\n", r); +#endif + return value; +} +#define sdr_in32(port, offset) (my_inl((port) + (offset))) + +static void my_outb(u32_t port, u32_t value) { + int r; +#ifdef DMA_BASE_IOMAP + *(volatile u8_t *)(port) = value; +#else + if ((r = sys_outb(port, (u8_t)value)) != OK) + printf("SDR: sys_outb failed: %d\n", r); +#endif +} +#define sdr_out8(port, offset, value) \ + (my_outb(((port) + (offset)), (value))) + +static void my_outw(u32_t port, u32_t value) { + int r; +#ifdef DMA_BASE_IOMAP + *(volatile u16_t *)(port) = value; +#else + if ((r = sys_outw(port, (u16_t)value)) != OK) + printf("SDR: sys_outw failed: %d\n", r); +#endif +} +#define sdr_out16(port, offset, value) \ + (my_outw(((port) + (offset)), (value))) + +static void my_outl(u32_t port, u32_t value) { + int r; +#ifdef DMA_BASE_IOMAP + *(volatile u32_t *)(port) = value; +#else + if ((r = sys_outl(port, value)) != OK) + printf("SDR: sys_outl failed: %d\n", r); +#endif +} +#define sdr_out32(port, offset, value) \ + (my_outl(((port) + (offset)), (value))) + +#endif diff --git a/minix/drivers/audio/cs4281/mixer.c b/minix/drivers/audio/cs4281/mixer.c new file mode 100644 index 000000000..c07d1f2b2 --- /dev/null +++ b/minix/drivers/audio/cs4281/mixer.c @@ -0,0 +1,272 @@ +#include "mixer.h" + +#ifdef MIXER_AK4531 +u8_t mixer_value[] = { + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, + 0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x01 +}; +int get_set_volume(u32_t *base, struct volume_level *level, int flag) { + int max_level, cmd_left, cmd_right; + + max_level = 0x1f; + /* Check device */ + switch (level->device) { + case Master: + cmd_left = MASTER_VOLUME_LCH; + cmd_right = MASTER_VOLUME_RCH; + break; + case Dac: + return EINVAL; + 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; + case Bass: + return EINVAL; + default: + return EINVAL; + } + /* Set volume */ + if (flag) { + 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; + /* ### WRITE_MIXER_REG ### */ + dev_mixer_write(base, cmd_left, 0x1f - level->left); + /* ### WRITE_MIXER_REG ### */ + dev_mixer_write(base, cmd_right, 0x1f - level->right); + mixer_value[cmd_left] = 0x1f - level->left; + mixer_value[cmd_right] = 0x1f - level->right; + } + /* Get volume (mixer register can not be read in ak4531 codec) */ + else { + /* ### READ_MIXER_REG ### */ + dev_mixer_read(base, cmd_left); + /* ### READ_MIXER_REG ### */ + dev_mixer_read(base, cmd_right); + level->left = 0x1f - mixer_value[cmd_left]; + level->right = 0x1f - mixer_value[cmd_right]; + } + return OK; +} +#endif + +#ifdef MIXER_SB16 +int get_set_volume(u32_t *base, struct volume_level *level, int flag) { + int max_level, shift, cmd_left, cmd_right; + + max_level = 0x0f; + shift = 4; + /* Check device */ + switch (level->device) { + case Master: + cmd_left = SB16_MASTER_LEFT; + cmd_right = SB16_MASTER_RIGHT; + break; + case Dac: + cmd_left = SB16_DAC_LEFT; + cmd_right = SB16_DAC_RIGHT; + break; + case Fm: + cmd_left = SB16_FM_LEFT; + cmd_right = SB16_FM_RIGHT; + break; + case Cd: + cmd_left = SB16_CD_LEFT; + cmd_right = SB16_CD_RIGHT; + break; + case Line: + cmd_left = SB16_LINE_LEFT; + cmd_left = SB16_LINE_RIGHT; + break; + case Mic: + cmd_left = cmd_right = SB16_MIC_LEVEL; + break; + case Speaker: + cmd_left = cmd_right = SB16_PC_LEVEL; + shift = 6; + max_level = 0x03; + break; + case Treble: + cmd_left = SB16_TREBLE_LEFT; + cmd_right = SB16_TREBLE_RIGHT; + shift = 4; + max_level = 0x0f; + break; + case Bass: + cmd_left = SB16_BASS_LEFT; + cmd_right = SB16_BASS_RIGHT; + shift = 4; + max_level = 0x0f; + break; + default: + return EINVAL; + } + /* Set volume */ + if (flag) { + 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; + /* ### WRITE_MIXER_REG ### */ + dev_mixer_write(base, cmd_left, level->left << shift); + /* ### WRITE_MIXER_REG ### */ + dev_mixer_write(base, cmd_right, level->right << shift); + } + /* Get volume */ + else { + /* ### READ_MIXER_REG ### */ + level->left = dev_mixer_read(base, cmd_left); + /* ### READ_MIXER_REG ### */ + level->right = dev_mixer_read(base, cmd_right); + level->left >>= shift; + level->right >>= shift; + } + return OK; +} +#endif + +#ifdef MIXER_AC97 +int get_set_volume(u32_t *base, struct volume_level *level, int flag) { + int max_level, cmd, data; + + max_level = 0x1f; + /* Check device */ + switch (level->device) { + case Master: + cmd = AC97_MASTER_VOLUME; + break; + case Dac: + return EINVAL; + case Fm: + cmd = AC97_PCM_OUT_VOLUME; + break; + case Cd: + cmd = AC97_CD_VOLUME; + break; + case Line: + cmd = AC97_LINE_IN_VOLUME; + break; + case Mic: + cmd = AC97_MIC_VOLUME; + break; + case Speaker: + return EINVAL; + case Treble: + return EINVAL; + case Bass: + return EINVAL; + default: + return EINVAL; + } + /* Set volume */ + if (flag) { + 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; + data = (max_level - level->left) << 8 | (max_level - level->right); + /* ### WRITE_MIXER_REG ### */ + dev_mixer_write(base, cmd, data); + } + /* Get volume */ + else { + /* ### READ_MIXER_REG ### */ + data = dev_mixer_read(base, cmd); + level->left = (u16_t)(data >> 8); + level->right = (u16_t)(data & 0xff); + 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; + level->left = max_level - level->left; + level->right = max_level - level->right; + } + return OK; +} +#endif + +/* Set default mixer volume */ +void dev_set_default_volume(u32_t *base) { + int i; +#ifdef MIXER_AK4531 + for (i = 0; i <= 0x19; i++) + dev_mixer_write(base, i, mixer_value[i]); +#endif +#ifdef MIXER_SB16 + dev_mixer_write(base, SB16_MASTER_LEFT, 0x18 << 3); + dev_mixer_write(base, SB16_MASTER_RIGHT, 0x18 << 3); + dev_mixer_write(base, SB16_DAC_LEFT, 0x0f << 4); + dev_mixer_write(base, SB16_DAC_RIGHT, 0x0f << 4); + dev_mixer_write(base, SB16_FM_LEFT, 0x08 << 4); + dev_mixer_write(base, SB16_FM_RIGHT, 0x08 << 4); + dev_mixer_write(base, SB16_CD_LEFT, 0x08 << 4); + dev_mixer_write(base, SB16_CD_RIGHT, 0x08 << 4); + dev_mixer_write(base, SB16_LINE_LEFT, 0x08 << 4); + dev_mixer_write(base, SB16_LINE_RIGHT, 0x08 << 4); + dev_mixer_write(base, SB16_MIC_LEVEL, 0x0f << 4); + dev_mixer_write(base, SB16_PC_LEVEL, 0x02 << 6); + dev_mixer_write(base, SB16_TREBLE_LEFT, 0x08 << 4); + dev_mixer_write(base, SB16_TREBLE_RIGHT, 0x08 << 4); + dev_mixer_write(base, SB16_BASS_LEFT, 0x08 << 4); + dev_mixer_write(base, SB16_BASS_RIGHT, 0x08 << 4); +#endif + +#ifdef MIXER_AC97 + dev_mixer_write(base, AC97_POWERDOWN, 0x0000); + for (i = 0; i < 50000; i++) { + if (dev_mixer_read(base, AC97_POWERDOWN) & 0x03) + break; + micro_delay(100); + } + if (i == 50000) + printf("SDR: AC97 is not ready\n"); + dev_mixer_write(base, AC97_MASTER_VOLUME, 0x0000); + dev_mixer_write(base, AC97_MONO_VOLUME, 0x8000); + dev_mixer_write(base, AC97_PHONE_VOLUME, 0x8008); + dev_mixer_write(base, AC97_MIC_VOLUME, 0x0000); + dev_mixer_write(base, AC97_LINE_IN_VOLUME, 0x0303); + dev_mixer_write(base, AC97_CD_VOLUME, 0x0808); + dev_mixer_write(base, AC97_AUX_IN_VOLUME, 0x0808); + dev_mixer_write(base, AC97_PCM_OUT_VOLUME, 0x0808); + dev_mixer_write(base, AC97_RECORD_GAIN_VOLUME, 0x0000); + dev_mixer_write(base, AC97_RECORD_SELECT, 0x0000); + dev_mixer_write(base, AC97_GENERAL_PURPOSE, 0x0000); +#endif +} diff --git a/minix/drivers/audio/cs4281/mixer.h b/minix/drivers/audio/cs4281/mixer.h new file mode 100644 index 000000000..8d042426b --- /dev/null +++ b/minix/drivers/audio/cs4281/mixer.h @@ -0,0 +1,62 @@ +#ifndef _MIXER_H +#define _MIXER_H + +#include "cs4281.h" + +#ifdef MIXER_AK4531 +#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 +#endif + +#ifdef MIXER_SB16 +#define SB16_MASTER_LEFT 0x30 +#define SB16_MASTER_RIGHT 0x31 +#define SB16_DAC_LEFT 0x32 +#define SB16_DAC_RIGHT 0x33 +#define SB16_FM_LEFT 0x34 +#define SB16_FM_RIGHT 0x35 +#define SB16_CD_LEFT 0x36 +#define SB16_CD_RIGHT 0x37 +#define SB16_LINE_LEFT 0x38 +#define SB16_LINE_RIGHT 0x39 +#define SB16_MIC_LEVEL 0x3a +#define SB16_PC_LEVEL 0x3b +#define SB16_TREBLE_LEFT 0x44 +#define SB16_TREBLE_RIGHT 0x45 +#define SB16_BASS_LEFT 0x46 +#define SB16_BASS_RIGHT 0x47 +#endif + +#ifdef MIXER_AC97 +#define AC97_MASTER_VOLUME 0x02 +#define AC97_AUX_OUT_VOLUME 0x04 +#define AC97_MONO_VOLUME 0x06 +#define AC97_MASTER_TONE 0x08 +#define AC97_PC_BEEP_VOLUME 0x0a +#define AC97_PHONE_VOLUME 0x0c +#define AC97_MIC_VOLUME 0x0e +#define AC97_LINE_IN_VOLUME 0x10 +#define AC97_CD_VOLUME 0x12 +#define AC97_VIDEO_VOLUME 0x14 +#define AC97_AUX_IN_VOLUME 0x16 +#define AC97_PCM_OUT_VOLUME 0x18 +#define AC97_RECORD_GAIN_VOLUME 0x1c +#define AC97_RECORD_GAIN_MIC_VOL 0x1e +#define AC97_GENERAL_PURPOSE 0x20 +#define AC97_POWERDOWN 0x26 +#define AC97_RECORD_SELECT 0x1a +#define AC97_RESET 0x00 +#endif + +int get_set_volume(u32_t *pbase, struct volume_level *level, int flag); +void dev_set_default_volume(u32_t *pbase); + +#endif diff --git a/minix/fs/procfs/service.c b/minix/fs/procfs/service.c index 004fb3fd4..493f74eee 100644 --- a/minix/fs/procfs/service.c +++ b/minix/fs/procfs/service.c @@ -43,6 +43,7 @@ service_get_policies(struct policies * pol, index_t slot) /* audio */ { .label = "als4000", .policy_str = "reset" }, { .label = "cmi8738", .policy_str = "reset" }, + { .label = "cs4281", .policy_str = "reset" }, { .label = "es1370", .policy_str = "reset" }, { .label = "es1371", .policy_str = "reset" }, { .label = "sb16", .policy_str = "reset" },