diff --git a/minix/drivers/audio/als4000/Makefile b/minix/drivers/audio/als4000/Makefile new file mode 100644 index 000000000..038d43d4e --- /dev/null +++ b/minix/drivers/audio/als4000/Makefile @@ -0,0 +1,8 @@ +# Makefile for the Sound Blaster 16 driver (SB16) +PROG= als4000 +SRCS= als4000.c + +DPADD+= ${LIBAUDIODRIVER} ${LIBCHARDRIVER} ${LIBSYS} +LDADD+= -laudiodriver -lchardriver -lsys + +.include diff --git a/minix/drivers/audio/als4000/README b/minix/drivers/audio/als4000/README new file mode 100755 index 000000000..64b57be00 --- /dev/null +++ b/minix/drivers/audio/als4000/README @@ -0,0 +1,12 @@ +The als4000 driver is for Avance Logic ALS4000 sound card. + +This driver is referred to Minix(3.4.0) es1371 driver, +Linux(4.2.1) snd_als4000 driver and ALS4000 Media Audio Specification(Rev 1.0). + +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/als4000/als4000.c b/minix/drivers/audio/als4000/als4000.c new file mode 100644 index 000000000..30069b02e --- /dev/null +++ b/minix/drivers/audio/als4000/als4000.c @@ -0,0 +1,727 @@ +#include "als4000.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; + +#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); +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); +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, + 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); + +/* ======= Developer-defined function ======= */ +/* ====== Self-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_BASE, REG_MIXER_ADDR, reg); + micro_delay(100); + sdr_out8(base + REG_SB_BASE, REG_MIXER_DATA, val); + micro_delay(100); +} + +/* Read the data from mixer register (AC97 or SB16) (### READ_MIXER_REG ###) */ +static u32_t dev_mixer_read(u32_t base, u32_t reg) { + u32_t res; + sdr_out8(base + REG_SB_BASE, REG_MIXER_ADDR, reg); + micro_delay(100); + res = sdr_in8(base + REG_SB_BASE, REG_MIXER_DATA); + micro_delay(100); + return res; +} + +static u32_t dev_gcr_read(u32_t base, u32_t reg) { + u32_t res; + sdr_out8(base, REG_GCR_INDEX, reg); + res = sdr_in32(base, REG_GCR_DATA); + return res; +} + +static void dev_gcr_write(u32_t base, u32_t reg, u32_t val) { + sdr_out8(base, REG_GCR_INDEX, reg); + sdr_out32(base, REG_GCR_DATA, val); +} + +static void dev_command(u32_t base, u32_t cmd) { + int i; + for (i = 0; i < 1000; i++) { + if ((sdr_in8(base + REG_SB_BASE, REG_SB_CMD) & 0x80) == 0) { + sdr_out8(base + REG_SB_BASE, REG_SB_CMD, cmd); + return; + } + } +} + +/* ====== Developer interface ======*/ + +/* Reset the device (### RESET_HARDWARE_CAN_FAIL ###) + * -- Return OK means success, Others means failure */ +static int dev_reset(u32_t base) { + int i; + sdr_out8(base, REG_SB_RESET, 1); + micro_delay(10); + sdr_out8(base, REG_SB_RESET, 0); + micro_delay(30); + for (i = 0; i < 1000; i++) { + if (sdr_in8(base + REG_SB_BASE, REG_SB_DATA) & 0x80) { + if (sdr_in8(base + REG_SB_BASE, REG_SB_READ) == 0xaa) + break; + else + return EIO; + } + } + return OK; +} + +/* Configure hardware registers (### CONF_HARDWARE ###) */ +static void dev_configure(u32_t base) { + u32_t data; + data = dev_mixer_read(base, REG_SB_CONFIG | REG_SB_CTRL); + dev_mixer_write(base, REG_SB_CONFIG | REG_SB_CTRL, + data | CMD_MIXER_WRITE_ENABLE); + dev_mixer_write(base, REG_SB_DMA_SETUP, 0x01); + dev_mixer_write(base, REG_SB_CONFIG | REG_SB_CTRL, + (data & ~CMD_MIXER_WRITE_ENABLE)); + data = dev_gcr_read(base, REG_DMA_EM_CTRL); + dev_gcr_write(base, REG_DMA_EM_CTRL, (data & ~0x07) | 0x04); +} + +/* 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) { + dev_command(base, CMD_SAMPLE_RATE_OUT); + dev_command(base, sample_rate >> 8); + dev_command(base, sample_rate); +} + +/* 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 format = 0, rec_format; + + if (bits == 16) { + format = CMD_BIT16_AI; + rec_format = 0; + } + else if (bits == 8) { + format = CMD_BIT8_AI; + rec_format = CMD_REC_WIDTH8; + } + dev_command(base, format); + if (sign == 0) { + if (stereo == 1) { + format = CMD_UNSIGN_STEREO; + rec_format |= CMD_REC_STEREO; + } + else { + format = CMD_UNSIGN_MONO; + rec_format |= CMD_REC_MONO; + } + } + else { + rec_format |= CMD_REC_SIGN; + if (stereo == 1) { + format = CMD_SIGN_STEREO; + rec_format |= CMD_REC_STEREO; + } + else { + format = CMD_SIGN_STEREO; + rec_format |= CMD_REC_MONO; + } + } + dev_command(base, format); + dev_mixer_write(base, REG_SB_FIFO_CTRL | REG_SB_CTRL, rec_format); + if (bits == 16) + sample_count >>= 1; + sample_count--; + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, sample_count & 0xff); + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, sample_count >> 8); + dev_mixer_write(base, REG_SB_FIFO_LEN_LO, sample_count & 0xff); + dev_mixer_write(base, REG_SB_FIFO_LEN_HI, sample_count >> 8); +} + +/* Start the channel (### START_CHANNEL ###) */ +static void dev_start_channel(u32_t base, int sub_dev) { + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT16_DMA_ON); + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT8_DMA_ON); +} + +/* Stop the channel (### STOP_CHANNEL ###) */ +static void dev_stop_channel(u32_t base, int sub_dev) { + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT16_DMA_OFF); + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT8_DMA_OFF); +} + +/* Set DAC DMA address and length (### SET_DAC_DMA ###) */ +static void dev_set_dac_dma(u32_t base, u32_t dma, u32_t len) { + dev_gcr_write(base, REG_DAC_DMA_ADDR, dma); + dev_gcr_write(base, REG_DAC_DMA_LEN, (len - 1) | 0x180000); +} + +/* Set ADC DMA address and length (### SET_ADC_DMA ###) */ +static void dev_set_adc_dma(u32_t base, u32_t dma, u32_t len) { + dev_gcr_write(base, REG_ADC_DMA_ADDR, dma); + dev_gcr_write(base, REG_ADC_DMA_LEN, len - 1); +} + +/* Pause the DMA */ +static void dev_pause_dma(u32_t base, int sub_dev) { + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT16_DMA_OFF); + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT8_DMA_OFF); +} + +/* Resume the DMA */ +static void dev_resume_dma(u32_t base, int sub_dev) { + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT16_DMA_ON); + sdr_out8(base, REG_SB_CMD + REG_SB_BASE, CMD_BIT8_DMA_ON); +} + +/* Other interrupt handle */ +static void dev_intr_other(u32_t base, u32_t status) { + u32_t data; + data = dev_mixer_read(base, REG_SB_IRQ_STATUS); + if (data & 0x02) + sdr_in8(base + REG_SB_BASE, 0x0f); + else if (data & 0x01) + sdr_in8(base + REG_SB_BASE, 0x0e); + else if (data & 0x20) + sdr_in8(base, 0x16); +} + +#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; +} +#endif + +/* Probe the device */ +static int dev_probe(void) { + u32_t device, size, base; + int devind, ioflag; + u16_t vid, did; + 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); + +#ifdef DMA_REG_MODE + if (pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) { + printf("SDR: Fail to get PCI BAR\n"); + return EIO; + } + 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; +#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); + +#ifdef MY_DEBUG + printf("SDR: Hardware name is %s\n", dev.name); + printf("SDR: PCI base address is 0x%08x\n", dev.base); + 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; + if (chan == DAC) { + /* ### READ_DAC_CURRENT_ADDR ### */ + res = dev_gcr_read(dev.base, REG_DAC_CUR_ADDR); + *result = (u32_t)(sub_dev[chan].BufLength * 8192) + res; + } + else if (chan == ADC) { + /* ### READ_ADC_CURRENT_ADDR ### */ + res = dev_gcr_read(dev.base, REG_ADC_CUR_ADDR); + *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.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_FRAME_LENGTH + 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); + + /* 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; + + /* ### DISABLE_INTR ### */ + data = dev_gcr_read(dev.base, REG_INTR_CTRL); + dev_gcr_write(dev.base, REG_INTR_CTRL, data & (~CMD_INTR_ENA)); + + /* ### 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) { + u32_t data; + + /* ### ENABLE_INTR ### */ + data = dev_gcr_read(dev.base, REG_INTR_CTRL); + dev_gcr_write(dev.base, REG_INTR_CTRL, data & (~CMD_INTR_ENA)); + dev_gcr_write(dev.base, REG_INTR_CTRL, data | CMD_INTR_ENA); + 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_FRAME_LENGTH + 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); + } + return OK; +} + +/* ======= [Audio interface] Get interrupt summary status ======= */ +int drv_int_sum(void) { + u32_t status; + /* ### READ_INTR_STS ### */ + status = sdr_in8(dev.base, REG_INTR_STS); + /* ### CHECK_INTR_DAC ### */ /* ### CHECK_INTR_ADC ### */ + 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_in8(dev.base, REG_INTR_STS); + + /* ### 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 EINVAL; + /* ### CLEAR_INTR_STS ### */ + sdr_out8(dev.base, REG_INTR_STS, CMD_INTR_CLR); + + /* ### 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; +} + +/* ======= [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/als4000/als4000.conf b/minix/drivers/audio/als4000/als4000.conf new file mode 100644 index 000000000..bbba0ad0b --- /dev/null +++ b/minix/drivers/audio/als4000/als4000.conf @@ -0,0 +1,10 @@ +service als4000 +{ + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + ; + pci device 4005:4000; +}; + diff --git a/minix/drivers/audio/als4000/als4000.h b/minix/drivers/audio/als4000/als4000.h new file mode 100644 index 000000000..dc813aeaf --- /dev/null +++ b/minix/drivers/audio/als4000/als4000.h @@ -0,0 +1,110 @@ +#ifndef _SDR_H +#define _SDR_H + +#include +#include +#include +#include +#include +#include "io.h" + +/* ======= General Parameter ======= */ +/* Global configure */ +#define MIXER_SB16 + +/* Subdevice type */ +#define DAC 0 +#define ADC 1 +#define MIX 2 + +/* PCI number */ +#define VENDOR_ID 0x4005 +#define DEVICE_ID 0x4000 + +/* Volume option */ +#define GET_VOL 0 +#define SET_VOL 1 + +/* Key internal register */ +#define REG_DAC_DMA_ADDR 0x91 +#define REG_DAC_DMA_LEN 0x92 +#define REG_DAC_CUR_ADDR 0xa0 +#define REG_ADC_DMA_ADDR 0xa2 +#define REG_ADC_DMA_LEN 0xa3 +#define REG_ADC_CUR_ADDR 0xa4 +#define REG_INTR_CTRL 0x8c +#define REG_INTR_STS 0x0e + +/* Key command */ +#define CMD_INTR_ENA 0x8000 +#define CMD_INTR_CLR 0x0000 + +/* Interrupt status */ +#define INTR_STS_DAC 0x80 +#define INTR_STS_ADC 0x40 + +/* ======= Self-defined Parameter ======= */ +#define REG_MIXER_ADDR 0x04 +#define REG_MIXER_DATA 0x05 +#define REG_GCR_DATA 0x08 +#define REG_GCR_INDEX 0x0c +#define REG_DMA_EM_CTRL 0x99 + +#define REG_SB_CONFIG 0x00 +#define REG_SB_RESET 0x06 +#define REG_SB_READ 0x0a +#define REG_SB_CMD 0x0c +#define REG_SB_DATA 0x0e +#define REG_SB_BASE 0x10 +#define REG_SB_FIFO_LEN_LO 0x1c +#define REG_SB_FIFO_LEN_HI 0x1d +#define REG_SB_FIFO_CTRL 0x1e +#define REG_SB_DMA_SETUP 0x81 +#define REG_SB_IRQ_STATUS 0x82 +#define REG_SB_CTRL 0xc0 + +#define CMD_MIXER_WRITE_ENABLE 0x80 +#define CMD_SAMPLE_RATE_OUT 0x41 +#define CMD_SIGN_MONO 0x10 +#define CMD_SIGN_STEREO 0x30 +#define CMD_UNSIGN_MONO 0x00 +#define CMD_UNSIGN_STEREO 0x20 +#define CMD_BIT16_AI 0xb6 +#define CMD_BIT16_DMA_OFF 0xd5 +#define CMD_BIT16_DMA_ON 0xd6 +#define CMD_BIT8_AI 0xc6 +#define CMD_BIT8_DMA_OFF 0xd0 +#define CMD_BIT8_DMA_ON 0xd4 + +#define CMD_REC_WIDTH8 0x04 +#define CMD_REC_SIGN 0x10 +#define CMD_REC_MONO 0x80 +#define CMD_REC_STEREO 0xa0 + +static u32_t g_sample_rate[] = { + 5512, 11025, 22050, 44100, 8000, 16000, 32000, 48000 +}; + +/* 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; + u32_t sb_base; + char irq; + char revision; +} DEV_STRUCT; + +#endif diff --git a/minix/drivers/audio/als4000/io.h b/minix/drivers/audio/als4000/io.h new file mode 100644 index 000000000..91c91c37f --- /dev/null +++ b/minix/drivers/audio/als4000/io.h @@ -0,0 +1,84 @@ +#ifndef _IO_H +#define _IO_H + +#include +#include +#include "als4000.h" + +/* I/O function */ +static u8_t my_inb(u32_t port) { + u32_t value; + int r; +#ifdef DMA_REG_MODE + value = *(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_REG_MODE + value = *(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_REG_MODE + value = *(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_REG_MODE + *(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_REG_MODE + *(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_REG_MODE + *(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/cmi8738/Makefile b/minix/drivers/audio/cmi8738/Makefile new file mode 100644 index 000000000..fe875766e --- /dev/null +++ b/minix/drivers/audio/cmi8738/Makefile @@ -0,0 +1,8 @@ +# Makefile for the CMI8738 driver +PROG= cmi8738 +SRCS= cmi8738.c + +DPADD+= ${LIBAUDIODRIVER} ${LIBCHARDRIVER} ${LIBSYS} +LDADD+= -laudiodriver -lchardriver -lsys + +.include diff --git a/minix/drivers/audio/cmi8738/README b/minix/drivers/audio/cmi8738/README new file mode 100644 index 000000000..92bcbe4a7 --- /dev/null +++ b/minix/drivers/audio/cmi8738/README @@ -0,0 +1,12 @@ +The cmi8738 driver is for C-Media 8738/8768 sound card. + +This driver is referred to Minix(3.4.0) es1371 driver, +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 new file mode 100644 index 000000000..890673e78 --- /dev/null +++ b/minix/drivers/audio/cmi8738/cmi8738.c @@ -0,0 +1,697 @@ +#include "cmi8738.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; + +#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); +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); +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, + 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); + +/* ======= 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); +} + +/* 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); +} + +/* ====== 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); + 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); +} + +/* 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) { + int i; + u32_t data, rate; + + 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); +} + +/* 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 format = 0; + u32_t data; + if (stereo == 1) + format |= FMT_STEREO; + if (bits == 16) + format |= FMT_BIT16; + data = sdr_in32(base, 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); +} + +/* Start the channel (### START_CHANNEL ###) */ +static void dev_start_channel(u32_t base, int sub_dev) { + u32_t data; + 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); + } + 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); + } +} + +/* Stop the channel (### STOP_CHANNEL ###) */ +static void dev_stop_channel(u32_t base, int sub_dev) { + u32_t data; + if (sub_dev == DAC) { + data = sdr_in32(base, REG_FUNC_CTRL); + sdr_out32(base, REG_FUNC_CTRL, data & (~CMD_ENA_C0)); + } + else if (sub_dev == ADC) { + data = sdr_in32(base, REG_FUNC_CTRL); + sdr_out32(base, REG_FUNC_CTRL, data & (~CMD_ENA_C1)); + } +} + +/* 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 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) { + if (sub_dev == DAC) + sdr_out32(base, REG_FUNC_CTRL, CMD_PAUSE_C0 | CMD_C0_PLAY); + else if (sub_dev == ADC) + sdr_out32(base, REG_FUNC_CTRL, CMD_PAUSE_C1 | CMD_C0_PLAY); +} + +/* Resume the DMA */ +static void dev_resume_dma(u32_t base, int sub_dev) { + if (sub_dev == DAC) + sdr_out32(base, REG_FUNC_CTRL, ~CMD_PAUSE_C0 & CMD_C0_PLAY); + else if (sub_dev == ADC) + sdr_out32(base, REG_FUNC_CTRL, ~CMD_PAUSE_C1 & CMD_C0_PLAY); +} + +/* Other interrupt handle */ +static void dev_intr_other(u32_t base, u32_t status) { +} + +#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; +} +#endif + +/* Probe the device */ +static int dev_probe(void) { + u32_t device, size, base; + int devind, ioflag; + u16_t vid, did; + 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); + +#ifdef DMA_REG_MODE + if (pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) { + printf("SDR: Fail to get PCI BAR\n"); + return EIO; + } + 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; +#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); + +#ifdef MY_DEBUG + printf("SDR: Hardware name is %s\n", dev.name); + printf("SDR: PCI base address is 0x%08x\n", dev.base); + 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; + 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; + } + 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.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_FRAME_LENGTH + 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); + + /* 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; + + /* ### DISABLE_INTR ### */ + data = sdr_in32(dev.base, REG_INTR_CTRL); + sdr_out32(dev.base, REG_INTR_CTRL, data & (~CMD_INTR_ENA)); + + /* ### 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) { + 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); + 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_FRAME_LENGTH + 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); + } + 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 ### */ + 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); + + /* ### 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 EINVAL; + /* ### CLEAR_INTR_STS ### */ + sdr_out32(dev.base, REG_INTR_STS, CMD_INTR_CLR); + + /* ### 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; +} + +/* ======= [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/cmi8738/cmi8738.conf b/minix/drivers/audio/cmi8738/cmi8738.conf new file mode 100644 index 000000000..d96491ba0 --- /dev/null +++ b/minix/drivers/audio/cmi8738/cmi8738.conf @@ -0,0 +1,10 @@ +service cmi8738 +{ + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + ; + pci device 13f6:0111; +}; + diff --git a/minix/drivers/audio/cmi8738/cmi8738.h b/minix/drivers/audio/cmi8738/cmi8738.h new file mode 100644 index 000000000..d282af56c --- /dev/null +++ b/minix/drivers/audio/cmi8738/cmi8738.h @@ -0,0 +1,100 @@ +#ifndef _SDR_H +#define _SDR_H + +#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 + +/* Volume option */ +#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 status */ +#define INTR_STS_DAC 0x80000001 +#define INTR_STS_ADC 0x80000002 + +/* ======= Self-defined Parameter ======= */ +#define REG_FUNC_CTRL 0x00 +#define REG_FUNC_CTRL1 0x04 +#define REG_FORMAT 0x08 +#define REG_MISC_CTRL 0x18 +#define REG_SB_DATA 0x22 +#define REG_SB_ADDR 0x23 +#define REG_DAC_SAMPLE_COUNT 0x86 +#define REG_ADC_SAMPLE_COUNT 0x8e + +#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 CMD_RESET 0x40000000 +#define CMD_RESET_C0 0x00040000 +#define CMD_RESET_C1 0x00080000 +#define CMD_ENA_C0 0x00010000 +#define CMD_ENA_C1 0x00020000 +#define CMD_PAUSE_C0 0x00000004 +#define CMD_PAUSE_C1 0x00000008 +#define CMD_C0_PLAY 0x00000002 + +static u32_t g_sample_rate[] = { + 5512, 11025, 22050, 44100, 8000, 16000, 32000, 48000 +}; + +/* 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; + u32_t sb_base; + char irq; + char revision; +} DEV_STRUCT; + +#endif diff --git a/minix/drivers/audio/cmi8738/io.h b/minix/drivers/audio/cmi8738/io.h new file mode 100644 index 000000000..c94c6d66b --- /dev/null +++ b/minix/drivers/audio/cmi8738/io.h @@ -0,0 +1,84 @@ +#ifndef _IO_H +#define _IO_H + +#include +#include +#include "cmi8738.h" + +/* I/O function */ +static u8_t my_inb(u32_t port) { + u32_t value; + int r; +#ifdef DMA_REG_MODE + value = *(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_REG_MODE + value = *(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_REG_MODE + value = *(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_REG_MODE + *(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_REG_MODE + *(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_REG_MODE + *(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/net/ip1000/Makefile b/minix/drivers/net/ip1000/Makefile old mode 100644 new mode 100755 diff --git a/minix/drivers/net/ip1000/ip1000.c b/minix/drivers/net/ip1000/ip1000.c index 7da45e301..78b18235a 100644 --- a/minix/drivers/net/ip1000/ip1000.c +++ b/minix/drivers/net/ip1000/ip1000.c @@ -70,6 +70,15 @@ static u16_t read_phy_reg(u32_t base, int phy_addr, int phy_reg) { u32_t field[8]; u8_t data, polar; +<<<<<<< HEAD + field[0] = 0xffffffff; fieldlen[0] = 32; + field[1] = 0x0001; fieldlen[1] = 2; + field[2] = 0x0002; fieldlen[2] = 2; + field[3] = phy_addr; fieldlen[3] = 5; + field[4] = phy_reg; fieldlen[4] = 5; + field[5] = 0x0000; fieldlen[5] = 2; + field[6] = 0x0000; fieldlen[6] = 16; +======= field[0] = 0xffffffff; fieldlen[0] = 32; field[1] = 0x0001; fieldlen[1] = 2; field[2] = 0x0002; fieldlen[2] = 2; @@ -77,6 +86,7 @@ static u16_t read_phy_reg(u32_t base, int phy_addr, int phy_reg) { field[4] = phy_reg; fieldlen[4] = 5; field[5] = 0x0000; fieldlen[5] = 2; field[6] = 0x0000; fieldlen[6] = 16; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc field[7] = 0x0000; fieldlen[7] = 1; polar = ic_in8(base, REG_PHY_CTRL) & 0x28; @@ -123,6 +133,15 @@ static void write_phy_reg(u32_t base, int phy_addr, int phy_reg, u16_t val) { u32_t field[8]; u8_t data, polar; +<<<<<<< HEAD + field[0] = 0xffffffff; fieldlen[0] = 32; + field[1] = 0x0001; fieldlen[1] = 2; + field[2] = 0x0001; fieldlen[2] = 2; + field[3] = phy_addr; fieldlen[3] = 5; + field[4] = phy_reg; fieldlen[4] = 5; + field[5] = 0x0002; fieldlen[5] = 2; + field[6] = val; fieldlen[6] = 16; +======= field[0] = 0xffffffff; fieldlen[0] = 32; field[1] = 0x0001; fieldlen[1] = 2; field[2] = 0x0001; fieldlen[2] = 2; @@ -130,6 +149,7 @@ static void write_phy_reg(u32_t base, int phy_addr, int phy_reg, u16_t val) { field[4] = phy_reg; fieldlen[4] = 5; field[5] = 0x0002; fieldlen[5] = 2; field[6] = val; fieldlen[6] = 16; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc field[7] = 0x0000; fieldlen[7] = 1; polar = ic_in8(base, REG_PHY_CTRL) & 0x28; @@ -146,7 +166,11 @@ static void write_phy_reg(u32_t base, int phy_addr, int phy_reg, u16_t val) { for (i = 0; i < fieldlen[7]; i ++) { ic_out8(base, REG_PHY_CTRL, polar); micro_delay(10); +<<<<<<< HEAD + field[7] |= ((ic_in8(base, REG_PHY_CTRL) & 0x02) >> 1) +======= field[7] |= ((ic_in8(base, REG_PHY_CTRL) & 0x02) >> 1) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc << (fieldlen[7] - i -1); ic_out8(base, REG_PHY_CTRL, (data | 0x01)); micro_delay(10); @@ -178,7 +202,11 @@ static int ic_real_reset(u32_t base) { micro_delay(10000); if (ic_in32(base, REG_ASIC_CTRL) & AC_RESET_BUSY) return -EIO; +<<<<<<< HEAD + return OK; +======= return OK; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc } /* Intialize power (### POWER_INIT_CAN_FAIL ###) @@ -304,14 +332,22 @@ static void ic_get_addr(u32_t base, u8_t *pa) { pa[5] = (u8_t)((ic_in16(base, REG_STA_ADDR2) & 0xff00) >> 8); } +<<<<<<< HEAD +/* Check link status (### CHECK_LINK ###) +======= /* Check link status (### CHECK_LINK ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * -- Return LINK_UP or LINK_DOWN */ static int ic_check_link(u32_t base) { u8_t phy_ctrl; u32_t mac_ctrl; int ret; char speed[20], duplex[20]; +<<<<<<< HEAD + +======= +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc phy_ctrl = ic_in8(base, REG_PHY_CTRL); mac_ctrl = ic_in8(base, REG_MAC_CTRL); switch (phy_ctrl & PC_LINK_SPEED) { @@ -350,7 +386,11 @@ static void ic_stop_rx_tx(u32_t base) { ic_out32(base, REG_ASIC_CTRL, AC_RESET_ALL); } +<<<<<<< HEAD +/* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###) +======= /* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * -- Return TRUE or FALSE */ static int ic_rx_status_ok(ic_desc *desc) { if ((desc->status & RFS_NORMAL) == RFS_NORMAL) @@ -358,7 +398,11 @@ static int ic_rx_status_ok(ic_desc *desc) { return FALSE; } +<<<<<<< HEAD +/* Get Rx data length from descriptor (### GET_RX_LEN ###) +======= /* Get Rx data length from descriptor (### GET_RX_LEN ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * --- Return the length */ static int ic_get_rx_len(ic_desc *desc) { int totlen; @@ -370,10 +414,17 @@ static int ic_get_rx_len(ic_desc *desc) { static void ic_tx_desc_start(ic_desc *desc, size_t size) { desc->status = TFS_TFD_DONE; desc->status |= (u64_t)(TFS_WORD_ALIGN | (TFS_FRAMEID & (g_driver.tx_head)) +<<<<<<< HEAD + | (TFS_FRAG_COUNT & (1 << 24))); + desc->status |= TFS_TX_DMA_INDICATE; + desc->frag_info |= TFI_FRAG_LEN & ((u64_t)((size >= 60 ? size : 60) & + 0xffff) << 48); +======= | (TFS_FRAG_COUNT & (1 << 24))); desc->status |= TFS_TX_DMA_INDICATE; desc->frag_info |= TFI_FRAG_LEN & ((u64_t)((size >= 60 ? size : 60) & 0xffff) << 48); +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc desc->status &= (u64_t)(~(TFS_TFD_DONE)); } @@ -382,7 +433,11 @@ static void ic_wakeup_tx(u32_t base) { ic_out32(base, REG_DMA_CTRL, 0x00001000); } +<<<<<<< HEAD +/* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###) +======= /* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * -- Return TRUE or FALSE */ static int ic_tx_status_ok(ic_desc *desc) { if (desc->status & TFS_TFD_DONE) @@ -500,7 +555,11 @@ static int ic_probe(ic_driver *pdev, int instance) { } pdev->base_addr = bar; #endif +<<<<<<< HEAD + +======= +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc /* Get irq number */ irq = pci_attr_r8(devind, PCI_ILR); pdev->irq = irq; @@ -747,7 +806,11 @@ static void ic_conf_addr(ic_driver *pdev, ether_addr_t *addr) { } /* Stop the driver */ +<<<<<<< HEAD +static void ic_stop(void) { +======= static void ic_stop(void) { +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc u32_t base = g_driver.base_addr; /* Free Rx and Tx buffer*/ @@ -891,7 +954,11 @@ static void ic_intr(unsigned int mask) { /* Real handler interrupt */ static void ic_handler(ic_driver *pdev) { +<<<<<<< HEAD + u32_t base = pdev->base_addr; +======= u32_t base = pdev->base_addr; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc u16_t intr_status; int flag = 0, tx_head, tx_tail; ic_desc *desc; @@ -900,7 +967,11 @@ static void ic_handler(ic_driver *pdev) { /* ### GET_INTR_STATUS ### */ intr_status = ic_in16(base, REG_ISR); +<<<<<<< HEAD + /* Clear interrupt */ +======= /* Clear interrupt */ +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc /* ### CLEAR_INTR ### */ ic_out16(base, REG_ISR, intr_status & INTR_ISR_CLEAR); @@ -928,7 +999,11 @@ static void ic_handler(ic_driver *pdev) { /* Check Rx request status */ /* ### CHECK_RX_INTR ### */ if (intr_status & INTR_ISR_RX_DONE) { +<<<<<<< HEAD + pdev->recv_flag = TRUE; +======= pdev->recv_flag = TRUE; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc flag++; } @@ -960,7 +1035,11 @@ static void ic_handler(ic_driver *pdev) { pdev->stat.ets_packetT++; pdev->tx[tx_tail].busy = FALSE; pdev->tx_busy_num--; +<<<<<<< HEAD + +======= +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc if (++tx_tail >= TX_DESC_NUM) tx_tail = 0; @@ -1002,5 +1081,9 @@ static void ic_check_ints(ic_driver *pdev) { } static void ic_stat(eth_stat_t *stat) { +<<<<<<< HEAD + memcpy(stat, &g_driver.stat, sizeof(*stat)); +======= memcpy(stat, &g_driver.stat, sizeof(*stat)); +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc } diff --git a/minix/drivers/net/ip1000/ip1000.conf b/minix/drivers/net/ip1000/ip1000.conf old mode 100644 new mode 100755 index d52af889a..b9f1eedd3 --- a/minix/drivers/net/ip1000/ip1000.conf +++ b/minix/drivers/net/ip1000/ip1000.conf @@ -1,5 +1,21 @@ service ip1000 { +<<<<<<< HEAD + type net; + descr "IC Plus 1000A Ethernet Card"; + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + ; + pci device 13f0:1023; + ipc + SYSTEM pm rs log tty ds vm + pci inet lwip amddev + ; +}; + +======= type net; descr "IC Plus 1000A Ethernet Card"; system @@ -13,3 +29,4 @@ service ip1000 pci inet lwip amddev ; }; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc diff --git a/minix/drivers/net/ip1000/ip1000.h b/minix/drivers/net/ip1000/ip1000.h index 3219fdc68..65e91bec6 100644 --- a/minix/drivers/net/ip1000/ip1000.h +++ b/minix/drivers/net/ip1000/ip1000.h @@ -7,6 +7,15 @@ /* Global configure */ #define DESC_BASE64 +<<<<<<< HEAD +/* Rx/Tx buffer parameter */ +#define RX_BUF_SIZE 1536 +#define TX_BUF_SIZE 1536 +#define RX_DESC_NUM 64 +#define TX_DESC_NUM 64 + +======= +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc /* Key internal register */ #define REG_RCR 0x88 #define REG_ISR 0x5a diff --git a/minix/drivers/net/vt6105/Makefile b/minix/drivers/net/vt6105/Makefile index 8ac42452f..50d1e75ea 100644 --- a/minix/drivers/net/vt6105/Makefile +++ b/minix/drivers/net/vt6105/Makefile @@ -1,5 +1,5 @@ # Makefile for the VIA Technology 6105/6106S Ethernet driver (vt6105) -PROG= vt6105 +PROG= vt6105 SRCS= vt6105.c FILES=${PROG}.conf diff --git a/minix/drivers/net/vt6105/README b/minix/drivers/net/vt6105/README index 93dc8063f..3ba540cb5 100644 --- a/minix/drivers/net/vt6105/README +++ b/minix/drivers/net/vt6105/README @@ -1,6 +1,6 @@ The vt6105 driver is for VIA Technology 6105/6106S Ethernet card. -This driver is referred to Minix(3.4.0) rtl8169 driver, +This driver is referred to Minix(3.4.0) rtl8169 driver, Linux(4.2.1) via-rhine driver and VT6105 Rhine III Specification(Rev 1.2). Revision 1.0 2016/10/18 @@ -10,7 +10,11 @@ Revision 1.1 2016/11/12 Modification: Remove and rewrite Linux-derived code Authored by Jia-Ju Bai +<<<<<<< HEAD +Something can be improved: +======= Something can be improved: +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc 1. MII, WOL functions are not adequately defined and used. 2. Link status report does not work well. 3. Ethernet address can not be modified at present. diff --git a/minix/drivers/net/vt6105/vt6105.c b/minix/drivers/net/vt6105/vt6105.c index b0baee8ff..cc1653595 100644 --- a/minix/drivers/net/vt6105/vt6105.c +++ b/minix/drivers/net/vt6105/vt6105.c @@ -54,7 +54,11 @@ static void vt_init_rx_desc(vt_desc *desc, size_t size, phys_bytes dma) { /* Intialize Tx descriptor (### TX_DESC_INIT ###) */ static void vt_init_tx_desc(vt_desc *desc, size_t size, phys_bytes dma) { desc->addr = dma; +<<<<<<< HEAD + desc->length = size; +======= desc->length = size; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc } /* Real hardware reset (### RESET_HARDWARE_CAN_FAIL ###) @@ -68,7 +72,11 @@ static int vt_real_reset(u32_t base) { if (vt_in16(base, REG_CR) & CMD_RESET) return -EIO; } +<<<<<<< HEAD + return OK; +======= return OK; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc } /* Intialize power (### POWER_INIT_CAN_FAIL ###) @@ -109,7 +117,11 @@ static void vt_get_addr(u32_t base, u8_t *pa) { pa[i] = vt_in8(base, REG_ADDR + i); } +<<<<<<< HEAD +/* Check link status (### CHECK_LINK ###) +======= /* Check link status (### CHECK_LINK ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * -- Return LINK_UP or LINK_DOWN */ static int vt_check_link(u32_t base) { u32_t r; @@ -128,17 +140,29 @@ static void vt_stop_rx_tx(u32_t base) { vt_out16(base, REG_CR, CMD_STOP); } +<<<<<<< HEAD +/* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###) +======= /* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * -- Return TRUE or FALSE */ static int vt_rx_status_ok(vt_desc *desc) { if (!(desc->status & DESC_OWN)) { if ((desc->status & DESC_RX_NORMAL) == DESC_RX_NORMAL) return TRUE; +<<<<<<< HEAD + } + return FALSE; +} + +/* Get Rx data length from descriptor (### GET_RX_LEN ###) +======= } return FALSE; } /* Get Rx data length from descriptor (### GET_RX_LEN ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * --- Return the length */ static int vt_get_rx_len(vt_desc *desc) { int len; @@ -160,7 +184,11 @@ static void vt_wakeup_tx(u32_t base) { vt_out8(base, REG_CR, cmd); } +<<<<<<< HEAD +/* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###) +======= /* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###) +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc * -- Return TRUE or FALSE */ static int vt_tx_status_ok(vt_desc *desc) { if (!(desc->status & DESC_OWN)) @@ -278,7 +306,11 @@ static int vt_probe(vt_driver *pdev, int instance) { } pdev->base_addr = bar; #endif +<<<<<<< HEAD + +======= +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc /* Get irq number */ irq = pci_attr_r8(devind, PCI_ILR); pdev->irq = irq; @@ -525,16 +557,28 @@ static void vt_conf_addr(vt_driver *pdev, ether_addr_t *addr) { } /* Stop the driver */ +<<<<<<< HEAD +static void vt_stop(void) { +======= static void vt_stop(void) { +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc u32_t base = g_driver.base_addr; /* Free Rx and Tx buffer*/ free_contig(g_driver.buf, g_driver.buf_size); +<<<<<<< HEAD /* Stop interrupt */ /* ### DISABLE_INTR ### */ vt_out16(base, REG_IMR, INTR_IMR_DISABLE); +======= + + /* Stop interrupt */ + /* ### DISABLE_INTR ### */ + vt_out16(base, REG_IMR, INTR_IMR_DISABLE); + +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc /* Stop Rx/Tx */ /* ### STOP_RX_TX ### */ vt_stop_rx_tx(base); @@ -669,7 +713,11 @@ static void vt_intr(unsigned int mask) { /* Real handler interrupt */ static void vt_handler(vt_driver *pdev) { +<<<<<<< HEAD + u32_t base = pdev->base_addr; +======= u32_t base = pdev->base_addr; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc u16_t intr_status; int flag = 0, tx_head, tx_tail; vt_desc *desc; @@ -678,7 +726,11 @@ static void vt_handler(vt_driver *pdev) { /* ### GET_INTR_STATUS ### */ intr_status = vt_in16(base, REG_ISR); +<<<<<<< HEAD + /* Clear interrupt */ +======= /* Clear interrupt */ +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc /* ### CLEAR_INTR ### */ vt_out16(base, REG_ISR, intr_status & INTR_ISR_CLEAR); @@ -706,7 +758,11 @@ static void vt_handler(vt_driver *pdev) { /* Check Rx request status */ /* ### CHECK_RX_INTR ### */ if (intr_status & INTR_ISR_RX_DONE) { +<<<<<<< HEAD + pdev->recv_flag = TRUE; +======= pdev->recv_flag = TRUE; +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc flag++; } @@ -738,7 +794,11 @@ static void vt_handler(vt_driver *pdev) { pdev->stat.ets_packetT++; pdev->tx[tx_tail].busy = FALSE; pdev->tx_busy_num--; +<<<<<<< HEAD + +======= +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc if (++tx_tail >= TX_DESC_NUM) tx_tail = 0; @@ -780,5 +840,9 @@ static void vt_check_ints(vt_driver *pdev) { } static void vt_stat(eth_stat_t *stat) { +<<<<<<< HEAD + memcpy(stat, &g_driver.stat, sizeof(*stat)); +======= memcpy(stat, &g_driver.stat, sizeof(*stat)); +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc } diff --git a/minix/drivers/net/vt6105/vt6105.conf b/minix/drivers/net/vt6105/vt6105.conf index 00076ca69..5fb39f8ae 100644 --- a/minix/drivers/net/vt6105/vt6105.conf +++ b/minix/drivers/net/vt6105/vt6105.conf @@ -1,16 +1,17 @@ service vt6105 { - type net; - descr "VIA Technology 6105/6106S Ethernet Card"; - system - UMAP # 14 - IRQCTL # 19 - DEVIO # 21 - ; - pci device 1106:3053; - pci device 1106:3106; - ipc - SYSTEM pm rs log tty ds vm - pci inet lwip amddev - ; + type net; + descr "VIA Technology 6105/6106S Ethernet Card"; + system + UMAP # 14 + IRQCTL # 19 + DEVIO # 21 + ; + pci device 1106:3053; + pci device 1106:3106; + ipc + SYSTEM pm rs log tty ds vm + pci inet lwip amddev + ; }; + diff --git a/minix/drivers/net/vt6105/vt6105.h b/minix/drivers/net/vt6105/vt6105.h index c675ccb28..14bd78afc 100644 --- a/minix/drivers/net/vt6105/vt6105.h +++ b/minix/drivers/net/vt6105/vt6105.h @@ -7,6 +7,15 @@ /* Global configure */ #define DESC_BASE64 +<<<<<<< HEAD +/* Rx/Tx buffer parameter */ +#define RX_BUF_SIZE 1536 +#define TX_BUF_SIZE 1536 +#define RX_DESC_NUM 64 +#define TX_DESC_NUM 64 + +======= +>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc /* Key internal register */ #define REG_RCR 0x06 #define REG_ISR 0x0c