From b7d24c2786a454ac012852660f5b253fcf938ef9 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Tue, 3 Jan 2017 14:58:42 +0000 Subject: [PATCH] Add the driver for CMI8738 sound card --- minix/drivers/audio/cmi8738/Makefile | 2 +- minix/drivers/audio/cmi8738/README | 5 - minix/drivers/audio/cmi8738/cmi8738.c | 470 ++++++++++---------------- minix/drivers/audio/cmi8738/cmi8738.h | 83 +++-- minix/drivers/audio/cmi8738/io.h | 24 +- minix/drivers/audio/cmi8738/mixer.c | 272 +++++++++++++++ minix/drivers/audio/cmi8738/mixer.h | 62 ++++ 7 files changed, 579 insertions(+), 339 deletions(-) create mode 100644 minix/drivers/audio/cmi8738/mixer.c create mode 100644 minix/drivers/audio/cmi8738/mixer.h diff --git a/minix/drivers/audio/cmi8738/Makefile b/minix/drivers/audio/cmi8738/Makefile index fe875766e..8e93ca517 100644 --- a/minix/drivers/audio/cmi8738/Makefile +++ b/minix/drivers/audio/cmi8738/Makefile @@ -1,6 +1,6 @@ # Makefile for the CMI8738 driver PROG= cmi8738 -SRCS= cmi8738.c +SRCS= cmi8738.c mixer.c DPADD+= ${LIBAUDIODRIVER} ${LIBCHARDRIVER} ${LIBSYS} LDADD+= -laudiodriver -lchardriver -lsys diff --git a/minix/drivers/audio/cmi8738/README b/minix/drivers/audio/cmi8738/README index 92bcbe4a7..d4b5b5a35 100644 --- a/minix/drivers/audio/cmi8738/README +++ b/minix/drivers/audio/cmi8738/README @@ -5,8 +5,3 @@ Linux(4.2.1) snd_cmipci driver and CMI8738 Audio Specification(Rev 2.2). Revision 1.0 2016/12/16 Authored by Jia-Ju Bai - -Something can be improved: -1. MIDI and MPU-401 ports are not supported. -2. Only supported 8 and 16 sample bits, and common sample rates (like 44100). -3. Multiple music files may not be played well at the same time. diff --git a/minix/drivers/audio/cmi8738/cmi8738.c b/minix/drivers/audio/cmi8738/cmi8738.c index 890673e78..3b49e3951 100644 --- a/minix/drivers/audio/cmi8738/cmi8738.c +++ b/minix/drivers/audio/cmi8738/cmi8738.c @@ -1,4 +1,5 @@ #include "cmi8738.h" +#include "mixer.h" /* global value */ DEV_STRUCT dev; @@ -7,25 +8,6 @@ sub_dev_t sub_dev[3]; special_file_t special_file[3]; drv_t drv; -#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 - /* internal function */ static int dev_probe(void); static int set_sample_rate(u32_t rate, int num); @@ -35,259 +17,215 @@ 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); -static void dev_set_default_volume(u32_t base); /* 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, +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_dac_dma(u32_t base, u32_t dma, u32_t len); -static void dev_set_adc_dma(u32_t base, u32_t dma, u32_t len); -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 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-defined function ======= */ -/* Write the data to mixer register (AC97 or SB16) (### WRITE_MIXER_REG ###) */ -static void dev_mixer_write(u32_t base, u32_t reg, u32_t val) { - sdr_out8(base, REG_SB_ADDR, reg); - sdr_out8(base, REG_SB_DATA, val); +/* ======= Developer implemented function ======= */ +/* ====== Self-defined function ====== */ +void dev_io_set_clear(u32_t base, u32_t reg, u32_t val, int flag) { + u32_t data; + data = sdr_in32(base, reg); + if (flag == 0) + data &= ~val; + else if (flag == 1) + data |= val; + sdr_out32(base, reg, data); } -/* Read the data from mixer register (AC97 or SB16) (### READ_MIXER_REG ###) */ -static u32_t dev_mixer_read(u32_t base, u32_t reg) { - sdr_out8(base, REG_SB_ADDR, reg); - return sdr_in8(base, REG_SB_DATA); +/* ====== 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 base0 = base[0]; + sdr_out8(base0, REG_SB_ADDR, reg); + sdr_out8(base0, REG_SB_DATA, val); +} + +/* Read the data from mixer register (### READ_MIXER_REG ###) */ +u32_t dev_mixer_read(u32_t *base, u32_t reg) { + u32_t base0 = base[0]; + sdr_out8(base0, REG_SB_ADDR, reg); + return sdr_in8(base0, REG_SB_DATA); } /* ====== 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 cmd = CMD_C0_PLAY; - u32_t data; - data = sdr_in32(base, REG_MISC_CTRL); - sdr_out32(base, REG_MISC_CTRL, CMD_RESET | data); - data = sdr_in32(base, REG_MISC_CTRL); - sdr_out32(base, REG_MISC_CTRL, ~CMD_RESET & data); - sdr_out32(base, REG_FUNC_CTRL, CMD_RESET_C0 | cmd); - sdr_out32(base, REG_FUNC_CTRL, ~CMD_RESET_C0 & cmd); - sdr_out32(base, REG_FUNC_CTRL, CMD_RESET_C1 | cmd); - sdr_out32(base, REG_FUNC_CTRL, ~CMD_RESET_C1 & cmd); +static int dev_reset(u32_t *base) { + u32_t data, base0 = base[0]; + dev_io_set_clear(base0, REG_MISC_CTRL, CMD_POWER_DOWN, 0); + dev_io_set_clear(base0, REG_MISC_CTRL, CMD_RESET, 1); + micro_delay(100); + dev_io_set_clear(base0, REG_MISC_CTRL, CMD_RESET, 0); return OK; } /* Configure hardware registers (### CONF_HARDWARE ###) */ -static void dev_configure(u32_t base) { - u32_t data; - sdr_out32(base, REG_INTR_CTRL, 0); - data = 0x00040000; - sdr_out32(base, REG_FUNC_CTRL, 0x00000001 | data); - sdr_out32(base, REG_FUNC_CTRL, 0x00000001 & (~data)); - data = 0x00080000; - sdr_out32(base, REG_FUNC_CTRL, 0x00000002 | data); - sdr_out32(base, REG_FUNC_CTRL, 0x00000002 & (~data)); - sdr_out32(base, REG_FUNC_CTRL, 0); - sdr_out32(base, REG_FUNC_CTRL1, 0); - sdr_out32(base, REG_FORMAT, 0); - data = sdr_in32(base, REG_MISC_CTRL); - sdr_out32(base, REG_MISC_CTRL, data | CMD_DDAC_ENA | CMD_SPK3D); - data = sdr_in32(base, REG_MISC_CTRL); - sdr_out32(base, REG_MISC_CTRL, data & (~CMD_EXDAC)); - data = sdr_in32(base, REG_FUNC_CTRL1); - sdr_out32(base, REG_FUNC_CTRL1, data | CMD_MASTER_ENA); +static void dev_configure(u32_t *base) { + u32_t data, base0 = base[0]; + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ADC_C0, 0); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ADC_C1, 1); + dev_io_set_clear(base0, REG_MISC_CTRL, CMD_N4SPK3D, 1); + dev_io_set_clear(base0, REG_FUNC_CTRL1, CMD_SPDIF_ENA, 0); + dev_io_set_clear(base0, REG_FUNC_CTRL1, CMD_SPDIF_LOOP, 0); + sdr_out8(base0, REG_EXT_INDEX, 0x03); + sdr_out8(base0, REG_MIX_INPUT, 0x0f); } /* Initialize the mixer (### INIT_MIXER ###) */ -static void dev_init_mixer(u32_t base) { +static void dev_init_mixer(u32_t *base) { dev_mixer_write(base, 0, 0); + dev_mixer_write(base, MIXER_ADCL, 0x1f); + dev_mixer_write(base, MIXER_ADCR, 0x7f); + dev_mixer_write(base, MIXER_OUT_MUTE, 0x7f); } /* Set DAC and ADC sample rate (### SET_SAMPLE_RATE ###) */ -static void dev_set_sample_rate(u32_t base, u16_t sample_rate) { +static void dev_set_sample_rate(u32_t *base, u16_t sample_rate) { int i; - u32_t data, rate; - + u32_t data, rate = 0, base0 = base[0]; for (i = 0; i < 8; i++) { if (sample_rate == g_sample_rate[i]) { rate = i; break; } } - data = (rate << 13) & 0x0000e000; - data |= (rate << 10) & 0x00001c00; - sdr_out32(base, REG_FUNC_CTRL1, data); + data = sdr_in32(base0, REG_FUNC_CTRL1); + data &=~ (0xe000 | 0x1c00); + data |= (rate << 13) & 0xe000; + data |= (rate << 10) & 0x1c00; + sdr_out32(base0, REG_FUNC_CTRL1, data); } /* Set DAC and ADC format (### SET_FORMAT ###)*/ -static void dev_set_format(u32_t base, u32_t bits, u32_t sign, +static void dev_set_format(u32_t *base, u32_t bits, u32_t sign, u32_t stereo, u32_t sample_count) { - u32_t format = 0; - u32_t data; + u32_t format = 0, data, base0 = base[0]; if (stereo == 1) format |= FMT_STEREO; if (bits == 16) format |= FMT_BIT16; - data = sdr_in32(base, REG_FORMAT); + data = sdr_in32(base0, REG_FORMAT); data &= ~0x00000003; data |= format << 0; data &= ~0x0000000c; data |= format << 2; - sdr_out32(base, REG_FORMAT, data); - sdr_out16(base, REG_DAC_SAMPLE_COUNT, sample_count - 1); - sdr_out16(base, REG_ADC_SAMPLE_COUNT, sample_count - 1); + sdr_out32(base0, REG_FORMAT, data); + dev_io_set_clear(base0, REG_EXT_MISC, 0x10000000, 0); + sdr_out16(base0, REG_DAC_SAMPLE_COUNT, sample_count - 1); + sdr_out16(base0, REG_ADC_SAMPLE_COUNT, sample_count - 1); } /* Start the channel (### START_CHANNEL ###) */ -static void dev_start_channel(u32_t base, int sub_dev) { - u32_t data; +static void dev_start_channel(u32_t *base, int sub_dev) { + u32_t data, base0 = base[0]; if (sub_dev == DAC) { - sdr_out32(base, REG_FUNC_CTRL, CMD_C0_PLAY & 0xfffffff0); - data = sdr_in32(base, REG_FUNC_CTRL); - sdr_out32(base, REG_FUNC_CTRL, data | CMD_ENA_C0); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C0, 1); } else if (sub_dev == ADC) { - sdr_out32(base, REG_FUNC_CTRL, CMD_C0_PLAY); - data = sdr_in32(base, REG_FUNC_CTRL); - sdr_out32(base, REG_FUNC_CTRL, data | CMD_ENA_C1); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C1, 1); } } /* Stop the channel (### STOP_CHANNEL ###) */ -static void dev_stop_channel(u32_t base, int sub_dev) { - u32_t data; +static void dev_stop_channel(u32_t *base, int sub_dev) { + u32_t data, base0 = base[0]; if (sub_dev == DAC) { - data = sdr_in32(base, REG_FUNC_CTRL); - sdr_out32(base, REG_FUNC_CTRL, data & (~CMD_ENA_C0)); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C0, 0); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C0, 1); + micro_delay(100); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C0, 0); } else if (sub_dev == ADC) { - data = sdr_in32(base, REG_FUNC_CTRL); - sdr_out32(base, REG_FUNC_CTRL, data & (~CMD_ENA_C1)); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C1, 0); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C1, 1); + micro_delay(100); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C1, 0); } } -/* Set DAC DMA address and length (### SET_DAC_DMA ###) */ -static void dev_set_dac_dma(u32_t base, u32_t dma, u32_t len) { - sdr_out32(dev.base, REG_DAC_DMA_ADDR, dma); - sdr_out16(dev.base, REG_DAC_DMA_LEN, len - 1); +/* 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_out16(base0, REG_DAC_DMA_LEN, len - 1); + } + else if (sub_dev == ADC) { + sdr_out32(base0, REG_ADC_DMA_ADDR, dma); + sdr_out16(base0, REG_ADC_DMA_LEN, len - 1); + } } -/* Set ADC DMA address and length (### SET_ADC_DMA ###) */ -static void dev_set_adc_dma(u32_t base, u32_t dma, u32_t len) { - sdr_out32(dev.base, REG_ADC_DMA_ADDR, dma); - sdr_out16(dev.base, REG_ADC_DMA_LEN, len - 1); -} - -/* Pause the DMA */ -static void dev_pause_dma(u32_t base, int sub_dev) { +/* 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) - sdr_out32(base, REG_FUNC_CTRL, CMD_PAUSE_C0 | CMD_C0_PLAY); + data = sdr_in16(base0, REG_DAC_CUR_ADDR); else if (sub_dev == ADC) - sdr_out32(base, REG_FUNC_CTRL, CMD_PAUSE_C1 | CMD_C0_PLAY); + data = sdr_in16(base0, REG_ADC_CUR_ADDR); + return data; } -/* Resume the DMA */ -static void dev_resume_dma(u32_t base, int sub_dev) { +/* Pause the DMA (### PAUSE_DMA ###) */ +static void dev_pause_dma(u32_t *base, int sub_dev) { + u32_t base0 = base[0]; if (sub_dev == DAC) - sdr_out32(base, REG_FUNC_CTRL, ~CMD_PAUSE_C0 & CMD_C0_PLAY); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C0, 1); else if (sub_dev == ADC) - sdr_out32(base, REG_FUNC_CTRL, ~CMD_PAUSE_C1 & CMD_C0_PLAY); + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C1, 1); } -/* Other interrupt handle */ -static void dev_intr_other(u32_t base, u32_t status) { +/* Resume the DMA (### RESUME_DMA ###) */ +static void dev_resume_dma(u32_t *base, int sub_dev) { + u32_t base0 = base[0]; + if (sub_dev == DAC) + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C0, 0); + else if (sub_dev == ADC) + dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C1, 0); } -#ifdef MIXER_SB16 -static int get_set_volume(u32_t base, struct volume_level *level, int flag) { - int max_level, shift, cmd_left, cmd_right; - - max_level = 0x1f; - shift = 3; - /* 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; +/* Read and clear interrupt status (### READ_CLEAR_INTR_STS ###) + * -- Return interrupt status */ +static u32_t dev_read_clear_intr_status(u32_t *base) { + u32_t data, base0 = base[0]; + data = sdr_in32(base0, REG_INTR_STS); + dev_intr_enable(base, INTR_DISABLE); + dev_intr_enable(base, INTR_ENABLE); + return data; } -#endif +/* Enable or disable interrupt (### INTR_ENBALE_DISABLE ###) */ +static void dev_intr_enable(u32_t *base, int flag) { + u32_t data, base0 = base[0]; + data = sdr_in32(base0, REG_INTR_STS); + if (flag == INTR_ENABLE) + sdr_out32(base0, REG_INTR_CTRL, data | CMD_INTR_ENABLE); + else if (flag == INTR_DISABLE) + sdr_out32(base0, REG_INTR_CTRL, data & ~CMD_INTR_ENABLE); +} + +/* ======= Common driver function ======= */ /* Probe the device */ static int dev_probe(void) { - u32_t device, size, base; - int devind, ioflag; - u16_t vid, did; + int devind, i, ioflag; + u32_t device, bar, size, base; + u16_t vid, did, temp; u8_t *reg; pci_init(); @@ -300,36 +238,43 @@ static int dev_probe(void) { if (vid != VENDOR_ID || did != DEVICE_ID) return EIO; pci_reserve(devind); - -#ifdef DMA_REG_MODE - if (pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) { - printf("SDR: Fail to get PCI BAR\n"); - return EIO; + + 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; } - if (ioflag) { - printf("SDR: PCI BAR is not for memory\n"); - return EIO; - } - 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 = (u32_t)reg; #else - dev.base = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0; + /* 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; - pci_attr_w16(devind, PCI_CR, 0x105); + 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); - printf("SDR: PCI base address is 0x%08x\n", dev.base); + 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; @@ -389,44 +334,15 @@ static int free_buf(u32_t *val, int *len, int num) { /* Get the current sample counter */ static int get_samples_in_buf(u32_t *result, int *len, int chan) { u32_t res; - if (chan == DAC) { - /* ### READ_DAC_CURRENT_ADDR ### */ - res = sdr_in32(dev.base, REG_DAC_CUR_ADDR); - *result = (u32_t)(sub_dev[chan].BufLength * 8192) + res; - } - else if (chan == ADC) { - /* ### READ_ADC_CURRENT_ADDR ### */ - res = sdr_in32(dev.base, REG_ADC_CUR_ADDR); - *result = (u32_t)(sub_dev[chan].BufLength * 8192) + res; - } + /* READ_DMA_CURRENT_ADDR */ + res = dev_read_dma_current(dev.base, chan); + *result = (u32_t)(sub_dev[chan].BufLength * 8192) + res; return OK; } -/* Set default mixer volume */ -static void dev_set_default_volume(u32_t base) { -#ifdef MIXER_SB16 - dev_mixer_write(dev.base, SB16_MASTER_LEFT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_MASTER_RIGHT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_DAC_LEFT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_DAC_RIGHT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_FM_LEFT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_FM_RIGHT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_CD_LEFT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_CD_RIGHT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_LINE_LEFT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_LINE_RIGHT, 0x12 << 3); - dev_mixer_write(dev.base, SB16_MIC_LEVEL, 0x12 << 3); - dev_mixer_write(dev.base, SB16_PC_LEVEL, 0x01 << 6); - dev_mixer_write(dev.base, SB16_TREBLE_LEFT, 0x08 << 4); - dev_mixer_write(dev.base, SB16_TREBLE_RIGHT, 0x08 << 4); - dev_mixer_write(dev.base, SB16_BASS_LEFT, 0x08 << 4); - dev_mixer_write(dev.base, SB16_BASS_RIGHT, 0x08 << 4); -#endif -} - /* ======= [Audio interface] Initialize data structure ======= */ int drv_init(void) { - drv.DriverName = "SDR"; + drv.DriverName = DRIVER_NAME; drv.NrOfSubDevices = 3; drv.NrOfSpecialFiles = 3; @@ -523,7 +439,7 @@ int drv_start(int sub_dev, int DmaMode) { dev_set_sample_rate(dev.base, aud_conf[sub_dev].sample_rate); sample_count = aud_conf[sub_dev].fragment_size; -#ifdef DMA_FRAME_LENGTH +#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 */ @@ -531,6 +447,8 @@ int drv_start(int sub_dev, int DmaMode) { 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); @@ -543,9 +461,8 @@ int drv_start(int sub_dev, int DmaMode) { int drv_stop(int sub_dev) { u32_t data; - /* ### DISABLE_INTR ### */ - data = sdr_in32(dev.base, REG_INTR_CTRL); - sdr_out32(dev.base, REG_INTR_CTRL, data & (~CMD_INTR_ENA)); + /* INTR_ENABLE_DISABLE */ + dev_intr_enable(dev.base, INTR_DISABLE); /* ### STOP_CHANNEL ### */ dev_stop_channel(dev.base, sub_dev); @@ -556,12 +473,8 @@ int drv_stop(int sub_dev) { /* ======= [Audio interface] Enable interrupt ======= */ int drv_reenable_int(int chan) { - u32_t data; - - /* ### ENABLE_INTR ### */ - data = sdr_in32(dev.base, REG_INTR_CTRL); - sdr_out32(dev.base, REG_INTR_CTRL, data & (~CMD_INTR_ENA)); - sdr_out32(dev.base, REG_INTR_CTRL, data | CMD_INTR_ENA); + /* INTR_ENABLE_DISABLE */ + dev_intr_enable(dev.base, INTR_ENABLE); return OK; } @@ -631,35 +544,29 @@ int drv_get_frag_size(u32_t *frag_size, int sub_dev) { /* ======= [Audio interface] Set DMA channel ======= */ int drv_set_dma(u32_t dma, u32_t length, int chan) { -#ifdef DMA_FRAME_LENGTH +#ifdef DMA_LENGTH_BY_FRAME length = length / (aud_conf[chan].nr_of_bits * (aud_conf[chan].stereo + 1) / 8); #endif - if (chan == DAC) { - /* ### SET_DAC_DMA ### */ - dev_set_dac_dma(dev.base, dma, length); - } - else if (chan == ADC) { - /* ### SET_ADC_DMA ### */ - dev_set_adc_dma(dev.base, dma, length); - } + /* ### 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_INTR_STS ### */ - status = sdr_in32(dev.base, REG_INTR_STS); - /* ### CHECK_INTR_DAC ### */ /* ### CHECK_INTR_ADC ### */ + /* ### 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 status, mask; - - /* ### READ_INTR_STS ### */ - status = sdr_in32(dev.base, REG_INTR_STS); + u32_t mask; /* ### CHECK_INTR_DAC ### */ if (sub_dev == DAC) @@ -668,18 +575,9 @@ int drv_int(int sub_dev) { else if (sub_dev == ADC) mask = INTR_STS_ADC; else - return EINVAL; - /* ### CLEAR_INTR_STS ### */ - sdr_out32(dev.base, REG_INTR_STS, CMD_INTR_CLR); + return 0; - /* ### OTHER_INTR_HANDLE ###*/ - dev_intr_other(dev.base, status); - - drv_reenable_int(sub_dev); -#ifdef MY_DEBUG - printf("SDR: Interrupt status is 0x%08x\n", status); -#endif - return status & mask; + return dev.intr_status & mask; } /* ======= [Audio interface] Pause DMA ======= */ diff --git a/minix/drivers/audio/cmi8738/cmi8738.h b/minix/drivers/audio/cmi8738/cmi8738.h index d282af56c..c3fdbf9d6 100644 --- a/minix/drivers/audio/cmi8738/cmi8738.h +++ b/minix/drivers/audio/cmi8738/cmi8738.h @@ -1,48 +1,39 @@ #ifndef _SDR_H #define _SDR_H +/* ======= General Parameter ======= */ +/* Global configure */ +#define DMA_LENGTH_BY_FRAME +#define MIXER_SB16 #include #include #include #include #include +#include #include "io.h" -/* ======= General Parameter ======= */ -/* Global configure */ -#define DMA_FRAME_LENGTH -#define MIXER_SB16 - /* Subdevice type */ #define DAC 0 #define ADC 1 #define MIX 2 -/* PCI number */ -#define VENDOR_ID 0x13f6 -#define DEVICE_ID 0x0111 +/* PCI number and driver name */ +#define VENDOR_ID 0x13f6 +#define DEVICE_ID 0x0111 +#define DRIVER_NAME "CMI8738" /* Volume option */ -#define GET_VOL 0 -#define SET_VOL 1 +#define GET_VOL 0 +#define SET_VOL 1 -/* Key internal register */ -#define REG_DAC_DMA_ADDR 0x80 -#define REG_DAC_DMA_LEN 0x84 -#define REG_DAC_CUR_ADDR 0x80 -#define REG_ADC_DMA_ADDR 0x88 -#define REG_ADC_DMA_LEN 0x8c -#define REG_ADC_CUR_ADDR 0x88 -#define REG_INTR_CTRL 0x0c -#define REG_INTR_STS 0x10 - -/* Key command */ -#define CMD_INTR_ENA 0x00030000 -#define CMD_INTR_CLR 0x00000000 +/* Interrupt control */ +#define INTR_ENABLE 1 +#define INTR_DISABLE 0 /* Interrupt status */ -#define INTR_STS_DAC 0x80000001 -#define INTR_STS_ADC 0x80000002 +#define INTR_STS_DAC 0x00000001 +#define INTR_STS_ADC 0x00000002 /* ======= Self-defined Parameter ======= */ #define REG_FUNC_CTRL 0x00 @@ -51,25 +42,44 @@ #define REG_MISC_CTRL 0x18 #define REG_SB_DATA 0x22 #define REG_SB_ADDR 0x23 +#define REG_MIX_INPUT 0x25 +#define REG_EXT_MISC 0x90 #define REG_DAC_SAMPLE_COUNT 0x86 #define REG_ADC_SAMPLE_COUNT 0x8e +#define REG_DAC_DMA_ADDR 0x80 +#define REG_DAC_DMA_LEN 0x84 +#define REG_DAC_CUR_ADDR 0x80 +#define REG_ADC_DMA_ADDR 0x88 +#define REG_ADC_DMA_LEN 0x8c +#define REG_ADC_CUR_ADDR 0x88 +#define REG_EXT_INDEX 0xf0 +#define REG_INTR_CTRL 0x0c +#define REG_INTR_STS 0x10 #define FMT_BIT16 0x02 #define FMT_STEREO 0x01 -#define CMD_MASTER_ENA 0x00000010 -#define CMD_EXDAC 0x00400000 -#define CMD_DDAC_ENA 0x00800000 -#define CMD_SPK3D 0x04000000 -#define CMD_M037 0x08000000 +#define MIXER_ADCL 0x3d +#define MIXER_ADCR 0x3e +#define MIXER_OUT_MUTE 0x3c + +#define CMD_POWER_DOWN 0x80000000 #define CMD_RESET 0x40000000 -#define CMD_RESET_C0 0x00040000 -#define CMD_RESET_C1 0x00080000 +#define CMD_ADC_C0 0x00000001 +#define CMD_ADC_C1 0x00000002 +#define CMD_N4SPK3D 0x04000000 +#define CMD_SPDIF_ENA 0x00000200 +#define CMD_SPDIF_LOOP 0x00000080 #define CMD_ENA_C0 0x00010000 #define CMD_ENA_C1 0x00020000 +#define CMD_INTR_C0 0x00010000 +#define CMD_INTR_C1 0x00020000 +#define CMD_RESET_C0 0x00040000 +#define CMD_RESET_C1 0x00080000 #define CMD_PAUSE_C0 0x00000004 #define CMD_PAUSE_C1 0x00000008 -#define CMD_C0_PLAY 0x00000002 + +#define CMD_INTR_ENABLE 0x00030000 static u32_t g_sample_rate[] = { 5512, 11025, 22050, 44100, 8000, 16000, 32000, 48000 @@ -91,10 +101,13 @@ typedef struct DEV_STRUCT { u16_t vid; u16_t did; u32_t devind; - u32_t base; - u32_t sb_base; + 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/cmi8738/io.h b/minix/drivers/audio/cmi8738/io.h index c94c6d66b..0c3e7cee1 100644 --- a/minix/drivers/audio/cmi8738/io.h +++ b/minix/drivers/audio/cmi8738/io.h @@ -9,8 +9,8 @@ static u8_t my_inb(u32_t port) { u32_t value; int r; -#ifdef DMA_REG_MODE - value = *(u8_t *)(port); +#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); @@ -22,8 +22,8 @@ static u8_t my_inb(u32_t port) { static u16_t my_inw(u32_t port) { u32_t value; int r; -#ifdef DMA_REG_MODE - value = *(u16_t *)(port); +#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); @@ -35,8 +35,8 @@ static u16_t my_inw(u32_t port) { static u32_t my_inl(u32_t port) { u32_t value; int r; -#ifdef DMA_REG_MODE - value = *(u32_t *)(port); +#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); @@ -47,8 +47,8 @@ static u32_t my_inl(u32_t port) { static void my_outb(u32_t port, u32_t value) { int r; -#ifdef DMA_REG_MODE - *(u8_t *)(port) = value; +#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); @@ -59,8 +59,8 @@ static void my_outb(u32_t port, u32_t value) { static void my_outw(u32_t port, u32_t value) { int r; -#ifdef DMA_REG_MODE - *(u16_t *)(port) = value; +#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); @@ -71,8 +71,8 @@ static void my_outw(u32_t port, u32_t value) { static void my_outl(u32_t port, u32_t value) { int r; -#ifdef DMA_REG_MODE - *(u32_t *)(port) = value; +#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); diff --git a/minix/drivers/audio/cmi8738/mixer.c b/minix/drivers/audio/cmi8738/mixer.c new file mode 100644 index 000000000..0e63249a0 --- /dev/null +++ b/minix/drivers/audio/cmi8738/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/cmi8738/mixer.h b/minix/drivers/audio/cmi8738/mixer.h new file mode 100644 index 000000000..e5d0d2144 --- /dev/null +++ b/minix/drivers/audio/cmi8738/mixer.h @@ -0,0 +1,62 @@ +#ifndef _MIXER_H +#define _MIXER_H + +#include "cmi8738.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