This commit is contained in:
Jia-Ju Bai 2016-12-29 21:37:52 +00:00 committed by GitHub
commit 64746325c0
21 changed files with 2064 additions and 15 deletions

View File

@ -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 <minix.service.mk>

View File

@ -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 <baijiaju1990@163.com>
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.

View File

@ -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;
}

View File

@ -0,0 +1,10 @@
service als4000
{
system
UMAP # 14
IRQCTL # 19
DEVIO # 21
;
pci device 4005:4000;
};

View File

@ -0,0 +1,110 @@
#ifndef _SDR_H
#define _SDR_H
#include <minix/audio_fw.h>
#include <sys/types.h>
#include <sys/ioc_sound.h>
#include <minix/sound.h>
#include <machine/pci.h>
#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

View File

@ -0,0 +1,84 @@
#ifndef _IO_H
#define _IO_H
#include <sys/types.h>
#include <minix/syslib.h>
#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

View File

@ -0,0 +1,8 @@
# Makefile for the CMI8738 driver
PROG= cmi8738
SRCS= cmi8738.c
DPADD+= ${LIBAUDIODRIVER} ${LIBCHARDRIVER} ${LIBSYS}
LDADD+= -laudiodriver -lchardriver -lsys
.include <minix.service.mk>

View File

@ -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 <baijiaju1990@163.com>
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.

View File

@ -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;
}

View File

@ -0,0 +1,10 @@
service cmi8738
{
system
UMAP # 14
IRQCTL # 19
DEVIO # 21
;
pci device 13f6:0111;
};

View File

@ -0,0 +1,100 @@
#ifndef _SDR_H
#define _SDR_H
#include <minix/audio_fw.h>
#include <sys/types.h>
#include <sys/ioc_sound.h>
#include <minix/sound.h>
#include <machine/pci.h>
#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

View File

@ -0,0 +1,84 @@
#ifndef _IO_H
#define _IO_H
#include <sys/types.h>
#include <minix/syslib.h>
#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

0
minix/drivers/net/ip1000/Makefile Normal file → Executable file
View File

View File

@ -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
}

17
minix/drivers/net/ip1000/ip1000.conf Normal file → Executable file
View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
# Makefile for the VIA Technology 6105/6106S Ethernet driver (vt6105)
PROG= vt6105
PROG= vt6105
SRCS= vt6105.c
FILES=${PROG}.conf

View File

@ -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 <baijiaju1990@163.com>
<<<<<<< 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.

View File

@ -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
}

View File

@ -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
;
};

View File

@ -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