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]; u32_t field[8];
u8_t data, polar; 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[0] = 0xffffffff; fieldlen[0] = 32;
field[1] = 0x0001; fieldlen[1] = 2; field[1] = 0x0001; fieldlen[1] = 2;
field[2] = 0x0002; fieldlen[2] = 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[4] = phy_reg; fieldlen[4] = 5;
field[5] = 0x0000; fieldlen[5] = 2; field[5] = 0x0000; fieldlen[5] = 2;
field[6] = 0x0000; fieldlen[6] = 16; field[6] = 0x0000; fieldlen[6] = 16;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
field[7] = 0x0000; fieldlen[7] = 1; field[7] = 0x0000; fieldlen[7] = 1;
polar = ic_in8(base, REG_PHY_CTRL) & 0x28; 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]; u32_t field[8];
u8_t data, polar; 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[0] = 0xffffffff; fieldlen[0] = 32;
field[1] = 0x0001; fieldlen[1] = 2; field[1] = 0x0001; fieldlen[1] = 2;
field[2] = 0x0001; fieldlen[2] = 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[4] = phy_reg; fieldlen[4] = 5;
field[5] = 0x0002; fieldlen[5] = 2; field[5] = 0x0002; fieldlen[5] = 2;
field[6] = val; fieldlen[6] = 16; field[6] = val; fieldlen[6] = 16;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
field[7] = 0x0000; fieldlen[7] = 1; field[7] = 0x0000; fieldlen[7] = 1;
polar = ic_in8(base, REG_PHY_CTRL) & 0x28; 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 ++) { for (i = 0; i < fieldlen[7]; i ++) {
ic_out8(base, REG_PHY_CTRL, polar); ic_out8(base, REG_PHY_CTRL, polar);
micro_delay(10); micro_delay(10);
<<<<<<< HEAD
field[7] |= ((ic_in8(base, REG_PHY_CTRL) & 0x02) >> 1)
=======
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); << (fieldlen[7] - i -1);
ic_out8(base, REG_PHY_CTRL, (data | 0x01)); ic_out8(base, REG_PHY_CTRL, (data | 0x01));
micro_delay(10); micro_delay(10);
@ -178,7 +202,11 @@ static int ic_real_reset(u32_t base) {
micro_delay(10000); micro_delay(10000);
if (ic_in32(base, REG_ASIC_CTRL) & AC_RESET_BUSY) if (ic_in32(base, REG_ASIC_CTRL) & AC_RESET_BUSY)
return -EIO; return -EIO;
<<<<<<< HEAD
return OK;
=======
return OK; return OK;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
} }
/* Intialize power (### POWER_INIT_CAN_FAIL ###) /* 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); pa[5] = (u8_t)((ic_in16(base, REG_STA_ADDR2) & 0xff00) >> 8);
} }
<<<<<<< HEAD
/* Check link status (### CHECK_LINK ###)
=======
/* Check link status (### CHECK_LINK ###) /* Check link status (### CHECK_LINK ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* -- Return LINK_UP or LINK_DOWN */ * -- Return LINK_UP or LINK_DOWN */
static int ic_check_link(u32_t base) { static int ic_check_link(u32_t base) {
u8_t phy_ctrl; u8_t phy_ctrl;
u32_t mac_ctrl; u32_t mac_ctrl;
int ret; int ret;
char speed[20], duplex[20]; char speed[20], duplex[20];
<<<<<<< HEAD
=======
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
phy_ctrl = ic_in8(base, REG_PHY_CTRL); phy_ctrl = ic_in8(base, REG_PHY_CTRL);
mac_ctrl = ic_in8(base, REG_MAC_CTRL); mac_ctrl = ic_in8(base, REG_MAC_CTRL);
switch (phy_ctrl & PC_LINK_SPEED) { 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); 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 ###) /* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* -- Return TRUE or FALSE */ * -- Return TRUE or FALSE */
static int ic_rx_status_ok(ic_desc *desc) { static int ic_rx_status_ok(ic_desc *desc) {
if ((desc->status & RFS_NORMAL) == RFS_NORMAL) if ((desc->status & RFS_NORMAL) == RFS_NORMAL)
@ -358,7 +398,11 @@ static int ic_rx_status_ok(ic_desc *desc) {
return FALSE; return FALSE;
} }
<<<<<<< HEAD
/* Get Rx data length from descriptor (### GET_RX_LEN ###)
=======
/* Get Rx data length from descriptor (### GET_RX_LEN ###) /* Get Rx data length from descriptor (### GET_RX_LEN ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* --- Return the length */ * --- Return the length */
static int ic_get_rx_len(ic_desc *desc) { static int ic_get_rx_len(ic_desc *desc) {
int totlen; 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) { static void ic_tx_desc_start(ic_desc *desc, size_t size) {
desc->status = TFS_TFD_DONE; desc->status = TFS_TFD_DONE;
desc->status |= (u64_t)(TFS_WORD_ALIGN | (TFS_FRAMEID & (g_driver.tx_head)) 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))); | (TFS_FRAG_COUNT & (1 << 24)));
desc->status |= TFS_TX_DMA_INDICATE; desc->status |= TFS_TX_DMA_INDICATE;
desc->frag_info |= TFI_FRAG_LEN & ((u64_t)((size >= 60 ? size : 60) & desc->frag_info |= TFI_FRAG_LEN & ((u64_t)((size >= 60 ? size : 60) &
0xffff) << 48); 0xffff) << 48);
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
desc->status &= (u64_t)(~(TFS_TFD_DONE)); 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); 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 ###) /* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* -- Return TRUE or FALSE */ * -- Return TRUE or FALSE */
static int ic_tx_status_ok(ic_desc *desc) { static int ic_tx_status_ok(ic_desc *desc) {
if (desc->status & TFS_TFD_DONE) if (desc->status & TFS_TFD_DONE)
@ -500,7 +555,11 @@ static int ic_probe(ic_driver *pdev, int instance) {
} }
pdev->base_addr = bar; pdev->base_addr = bar;
#endif #endif
<<<<<<< HEAD
=======
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
/* Get irq number */ /* Get irq number */
irq = pci_attr_r8(devind, PCI_ILR); irq = pci_attr_r8(devind, PCI_ILR);
pdev->irq = irq; pdev->irq = irq;
@ -747,7 +806,11 @@ static void ic_conf_addr(ic_driver *pdev, ether_addr_t *addr) {
} }
/* Stop the driver */ /* Stop the driver */
<<<<<<< HEAD
static void ic_stop(void) {
=======
static void ic_stop(void) { static void ic_stop(void) {
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
u32_t base = g_driver.base_addr; u32_t base = g_driver.base_addr;
/* Free Rx and Tx buffer*/ /* Free Rx and Tx buffer*/
@ -891,7 +954,11 @@ static void ic_intr(unsigned int mask) {
/* Real handler interrupt */ /* Real handler interrupt */
static void ic_handler(ic_driver *pdev) { static void ic_handler(ic_driver *pdev) {
<<<<<<< HEAD
u32_t base = pdev->base_addr;
=======
u32_t base = pdev->base_addr; u32_t base = pdev->base_addr;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
u16_t intr_status; u16_t intr_status;
int flag = 0, tx_head, tx_tail; int flag = 0, tx_head, tx_tail;
ic_desc *desc; ic_desc *desc;
@ -900,7 +967,11 @@ static void ic_handler(ic_driver *pdev) {
/* ### GET_INTR_STATUS ### */ /* ### GET_INTR_STATUS ### */
intr_status = ic_in16(base, REG_ISR); intr_status = ic_in16(base, REG_ISR);
<<<<<<< HEAD
/* Clear interrupt */
=======
/* Clear interrupt */ /* Clear interrupt */
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
/* ### CLEAR_INTR ### */ /* ### CLEAR_INTR ### */
ic_out16(base, REG_ISR, intr_status & INTR_ISR_CLEAR); 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 request status */
/* ### CHECK_RX_INTR ### */ /* ### CHECK_RX_INTR ### */
if (intr_status & INTR_ISR_RX_DONE) { if (intr_status & INTR_ISR_RX_DONE) {
<<<<<<< HEAD
pdev->recv_flag = TRUE;
=======
pdev->recv_flag = TRUE; pdev->recv_flag = TRUE;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
flag++; flag++;
} }
@ -960,7 +1035,11 @@ static void ic_handler(ic_driver *pdev) {
pdev->stat.ets_packetT++; pdev->stat.ets_packetT++;
pdev->tx[tx_tail].busy = FALSE; pdev->tx[tx_tail].busy = FALSE;
pdev->tx_busy_num--; pdev->tx_busy_num--;
<<<<<<< HEAD
=======
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
if (++tx_tail >= TX_DESC_NUM) if (++tx_tail >= TX_DESC_NUM)
tx_tail = 0; tx_tail = 0;
@ -1002,5 +1081,9 @@ static void ic_check_ints(ic_driver *pdev) {
} }
static void ic_stat(eth_stat_t *stat) { static void ic_stat(eth_stat_t *stat) {
<<<<<<< HEAD
memcpy(stat, &g_driver.stat, sizeof(*stat));
=======
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 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; type net;
descr "IC Plus 1000A Ethernet Card"; descr "IC Plus 1000A Ethernet Card";
system system
@ -13,3 +29,4 @@ service ip1000
pci inet lwip amddev pci inet lwip amddev
; ;
}; };
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc

View File

@ -7,6 +7,15 @@
/* Global configure */ /* Global configure */
#define DESC_BASE64 #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 */ /* Key internal register */
#define REG_RCR 0x88 #define REG_RCR 0x88
#define REG_ISR 0x5a #define REG_ISR 0x5a

View File

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

View File

@ -1,6 +1,6 @@
The vt6105 driver is for VIA Technology 6105/6106S Ethernet card. 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). Linux(4.2.1) via-rhine driver and VT6105 Rhine III Specification(Rev 1.2).
Revision 1.0 2016/10/18 Revision 1.0 2016/10/18
@ -10,7 +10,11 @@ Revision 1.1 2016/11/12
Modification: Remove and rewrite Linux-derived code Modification: Remove and rewrite Linux-derived code
Authored by Jia-Ju Bai <baijiaju1990@163.com> Authored by Jia-Ju Bai <baijiaju1990@163.com>
<<<<<<< HEAD
Something can be improved:
=======
Something can be improved: Something can be improved:
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
1. MII, WOL functions are not adequately defined and used. 1. MII, WOL functions are not adequately defined and used.
2. Link status report does not work well. 2. Link status report does not work well.
3. Ethernet address can not be modified at present. 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 ###) */ /* Intialize Tx descriptor (### TX_DESC_INIT ###) */
static void vt_init_tx_desc(vt_desc *desc, size_t size, phys_bytes dma) { static void vt_init_tx_desc(vt_desc *desc, size_t size, phys_bytes dma) {
desc->addr = dma; desc->addr = dma;
<<<<<<< HEAD
desc->length = size;
=======
desc->length = size; desc->length = size;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
} }
/* Real hardware reset (### RESET_HARDWARE_CAN_FAIL ###) /* 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) if (vt_in16(base, REG_CR) & CMD_RESET)
return -EIO; return -EIO;
} }
<<<<<<< HEAD
return OK;
=======
return OK; return OK;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
} }
/* Intialize power (### POWER_INIT_CAN_FAIL ###) /* 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); pa[i] = vt_in8(base, REG_ADDR + i);
} }
<<<<<<< HEAD
/* Check link status (### CHECK_LINK ###)
=======
/* Check link status (### CHECK_LINK ###) /* Check link status (### CHECK_LINK ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* -- Return LINK_UP or LINK_DOWN */ * -- Return LINK_UP or LINK_DOWN */
static int vt_check_link(u32_t base) { static int vt_check_link(u32_t base) {
u32_t r; u32_t r;
@ -128,17 +140,29 @@ static void vt_stop_rx_tx(u32_t base) {
vt_out16(base, REG_CR, CMD_STOP); 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 ###) /* Check whether Rx status OK (### CHECK_RX_STATUS_OK ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* -- Return TRUE or FALSE */ * -- Return TRUE or FALSE */
static int vt_rx_status_ok(vt_desc *desc) { static int vt_rx_status_ok(vt_desc *desc) {
if (!(desc->status & DESC_OWN)) { if (!(desc->status & DESC_OWN)) {
if ((desc->status & DESC_RX_NORMAL) == DESC_RX_NORMAL) if ((desc->status & DESC_RX_NORMAL) == DESC_RX_NORMAL)
return TRUE; return TRUE;
<<<<<<< HEAD
}
return FALSE;
}
/* Get Rx data length from descriptor (### GET_RX_LEN ###)
=======
} }
return FALSE; return FALSE;
} }
/* Get Rx data length from descriptor (### GET_RX_LEN ###) /* Get Rx data length from descriptor (### GET_RX_LEN ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* --- Return the length */ * --- Return the length */
static int vt_get_rx_len(vt_desc *desc) { static int vt_get_rx_len(vt_desc *desc) {
int len; int len;
@ -160,7 +184,11 @@ static void vt_wakeup_tx(u32_t base) {
vt_out8(base, REG_CR, cmd); 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 ###) /* Check whether Tx status OK (### CHECK_TX_STATUS_OK ###)
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
* -- Return TRUE or FALSE */ * -- Return TRUE or FALSE */
static int vt_tx_status_ok(vt_desc *desc) { static int vt_tx_status_ok(vt_desc *desc) {
if (!(desc->status & DESC_OWN)) if (!(desc->status & DESC_OWN))
@ -278,7 +306,11 @@ static int vt_probe(vt_driver *pdev, int instance) {
} }
pdev->base_addr = bar; pdev->base_addr = bar;
#endif #endif
<<<<<<< HEAD
=======
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
/* Get irq number */ /* Get irq number */
irq = pci_attr_r8(devind, PCI_ILR); irq = pci_attr_r8(devind, PCI_ILR);
pdev->irq = irq; pdev->irq = irq;
@ -525,16 +557,28 @@ static void vt_conf_addr(vt_driver *pdev, ether_addr_t *addr) {
} }
/* Stop the driver */ /* Stop the driver */
<<<<<<< HEAD
static void vt_stop(void) {
=======
static void vt_stop(void) { static void vt_stop(void) {
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
u32_t base = g_driver.base_addr; u32_t base = g_driver.base_addr;
/* Free Rx and Tx buffer*/ /* Free Rx and Tx buffer*/
free_contig(g_driver.buf, g_driver.buf_size); free_contig(g_driver.buf, g_driver.buf_size);
<<<<<<< HEAD
/* Stop interrupt */ /* Stop interrupt */
/* ### DISABLE_INTR ### */ /* ### DISABLE_INTR ### */
vt_out16(base, REG_IMR, INTR_IMR_DISABLE); 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 */
/* ### STOP_RX_TX ### */ /* ### STOP_RX_TX ### */
vt_stop_rx_tx(base); vt_stop_rx_tx(base);
@ -669,7 +713,11 @@ static void vt_intr(unsigned int mask) {
/* Real handler interrupt */ /* Real handler interrupt */
static void vt_handler(vt_driver *pdev) { static void vt_handler(vt_driver *pdev) {
<<<<<<< HEAD
u32_t base = pdev->base_addr;
=======
u32_t base = pdev->base_addr; u32_t base = pdev->base_addr;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
u16_t intr_status; u16_t intr_status;
int flag = 0, tx_head, tx_tail; int flag = 0, tx_head, tx_tail;
vt_desc *desc; vt_desc *desc;
@ -678,7 +726,11 @@ static void vt_handler(vt_driver *pdev) {
/* ### GET_INTR_STATUS ### */ /* ### GET_INTR_STATUS ### */
intr_status = vt_in16(base, REG_ISR); intr_status = vt_in16(base, REG_ISR);
<<<<<<< HEAD
/* Clear interrupt */
=======
/* Clear interrupt */ /* Clear interrupt */
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
/* ### CLEAR_INTR ### */ /* ### CLEAR_INTR ### */
vt_out16(base, REG_ISR, intr_status & INTR_ISR_CLEAR); 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 request status */
/* ### CHECK_RX_INTR ### */ /* ### CHECK_RX_INTR ### */
if (intr_status & INTR_ISR_RX_DONE) { if (intr_status & INTR_ISR_RX_DONE) {
<<<<<<< HEAD
pdev->recv_flag = TRUE;
=======
pdev->recv_flag = TRUE; pdev->recv_flag = TRUE;
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
flag++; flag++;
} }
@ -738,7 +794,11 @@ static void vt_handler(vt_driver *pdev) {
pdev->stat.ets_packetT++; pdev->stat.ets_packetT++;
pdev->tx[tx_tail].busy = FALSE; pdev->tx[tx_tail].busy = FALSE;
pdev->tx_busy_num--; pdev->tx_busy_num--;
<<<<<<< HEAD
=======
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
if (++tx_tail >= TX_DESC_NUM) if (++tx_tail >= TX_DESC_NUM)
tx_tail = 0; tx_tail = 0;
@ -780,5 +840,9 @@ static void vt_check_ints(vt_driver *pdev) {
} }
static void vt_stat(eth_stat_t *stat) { static void vt_stat(eth_stat_t *stat) {
<<<<<<< HEAD
memcpy(stat, &g_driver.stat, sizeof(*stat));
=======
memcpy(stat, &g_driver.stat, sizeof(*stat)); memcpy(stat, &g_driver.stat, sizeof(*stat));
>>>>>>> 3f862305f83a4a0421b5952d0686bebd9aeee0bc
} }

View File

@ -1,16 +1,17 @@
service vt6105 service vt6105
{ {
type net; type net;
descr "VIA Technology 6105/6106S Ethernet Card"; descr "VIA Technology 6105/6106S Ethernet Card";
system system
UMAP # 14 UMAP # 14
IRQCTL # 19 IRQCTL # 19
DEVIO # 21 DEVIO # 21
; ;
pci device 1106:3053; pci device 1106:3053;
pci device 1106:3106; pci device 1106:3106;
ipc ipc
SYSTEM pm rs log tty ds vm SYSTEM pm rs log tty ds vm
pci inet lwip amddev pci inet lwip amddev
; ;
}; };

View File

@ -7,6 +7,15 @@
/* Global configure */ /* Global configure */
#define DESC_BASE64 #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 */ /* Key internal register */
#define REG_RCR 0x06 #define REG_RCR 0x06
#define REG_ISR 0x0c #define REG_ISR 0x0c