This commit is contained in:
Jia-Ju Bai 2017-01-03 14:59:46 +00:00 committed by GitHub
commit 9c9c5a67ba
25 changed files with 2549 additions and 15 deletions

View File

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

View File

@ -0,0 +1,7 @@
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/23
Authored by Jia-Ju Bai <baijiaju1990@163.com>

View File

@ -0,0 +1,639 @@
#include "als4000.h"
#include "mixer.h"
/* global value */
DEV_STRUCT dev;
aud_sub_dev_conf_t aud_conf[3];
sub_dev_t sub_dev[3];
special_file_t special_file[3];
drv_t drv;
/* internal function */
static int dev_probe(void);
static int set_sample_rate(u32_t rate, int num);
static int set_stereo(u32_t stereo, int num);
static int set_bits(u32_t bits, int sub_dev);
static int set_frag_size(u32_t frag_size, int num);
static int set_sign(u32_t val, int num);
static int get_frag_size(u32_t *val, int *len, int num);
static int free_buf(u32_t *val, int *len, int num);
/* developer interface */
static int dev_reset(u32_t *base);
static void dev_configure(u32_t *base);
static void dev_init_mixer(u32_t *base);
static void dev_set_sample_rate(u32_t *base, u16_t sample_rate);
static void dev_set_format(u32_t *base, u32_t bits, u32_t sign,
u32_t stereo, u32_t sample_count);
static void dev_start_channel(u32_t *base, int sub_dev);
static void dev_stop_channel(u32_t *base, int sub_dev);
static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev);
static u32_t dev_read_dma_current(u32_t *base, int sub_dev);
static void dev_pause_dma(u32_t *base, int sub_dev);
static void dev_resume_dma(u32_t *base, int sub_dev);
static void dev_intr_other(u32_t *base, u32_t status);
static u32_t dev_read_clear_intr_status(u32_t *base);
static void dev_intr_enable(u32_t *base, int flag);
/* ======= Developer implemented function ======= */
/* ====== Self-defined function ====== */
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;
}
}
printf("SDR: Fail to execute SB command\n");
}
/* ====== Mixer handling interface ====== */
/* Write the data to mixer register (### WRITE_MIXER_REG ###) */
void dev_mixer_write(u32_t *base, u32_t reg, u32_t val) {
sdr_out8(base[0] + REG_SB_BASE, REG_MIXER_ADDR, reg);
micro_delay(100);
sdr_out8(base[0] + REG_SB_BASE, REG_MIXER_DATA, val);
micro_delay(100);
}
/* Read the data from mixer register (### READ_MIXER_REG ###) */
u32_t dev_mixer_read(u32_t *base, u32_t reg) {
u32_t res;
sdr_out8(base[0] + REG_SB_BASE, REG_MIXER_ADDR, reg);
micro_delay(100);
res = sdr_in8(base[0] + REG_SB_BASE, REG_MIXER_DATA);
micro_delay(100);
return res;
}
/* ====== 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 i, base0 = base[0];
sdr_out8(base0, REG_SB_RESET, 1);
micro_delay(10);
sdr_out8(base0, REG_SB_RESET, 0);
micro_delay(30);
for (i = 0; i < 1000; i++) {
if (sdr_in8(base0 + REG_SB_BASE, REG_SB_DATA) & 0x80) {
if (sdr_in8(base0 + 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 i, data, base0 = base[0];
data = dev_mixer_read(base, REG_SB_CONFIG);
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));
for (i = 0x91; i <= 0x96; i++)
dev_gcr_write(base0, i, 0);
data = dev_gcr_read(base0, REG_DMA_EM_CTRL);
// dev_gcr_write(base0, REG_DMA_EM_CTRL, (data & ~0x07) | 0x04);
dev_gcr_write(base0, REG_DMA_EM_CTRL, data);
}
/* Initialize the mixer (### INIT_MIXER ###) */
static void dev_init_mixer(u32_t *base) {
// dev_mixer_write(base, 0, 0);
}
/* Set DAC and ADC sample rate (### SET_SAMPLE_RATE ###) */
static void dev_set_sample_rate(u32_t *base, u16_t sample_rate) {
u32_t base0 = base[0];
dev_command(base0, CMD_SAMPLE_RATE_OUT);
dev_command(base0, sample_rate >> 8);
dev_command(base0, sample_rate & 0xff);
}
static u32_t rec_format = 0;
/* 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, base0 = base[0];
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(base0, format);
if (sign == 0) {
if (stereo == 1) {
format = CMD_UNSIGN_STEREO;
rec_format |= CMD_REC_STEREO;
}
else
format = CMD_UNSIGN_MONO;
}
else {
rec_format |= CMD_REC_SIGN;
if (stereo == 1) {
format = CMD_SIGN_STEREO;
rec_format |= CMD_REC_STEREO;
}
else
format = CMD_SIGN_STEREO;
}
dev_command(base0, format);
if (bits == 16)
sample_count >>= 1;
sample_count--;
dev_command(base0, sample_count & 0xff);
dev_command(base0, sample_count >> 8);
dev_mixer_write(base, REG_SB_FIFO_LEN_LO|REG_SB_CTRL, sample_count & 0xff);
dev_mixer_write(base, REG_SB_FIFO_LEN_HI|REG_SB_CTRL, sample_count >> 8);
}
/* Start the channel (### START_CHANNEL ###) */
static void dev_start_channel(u32_t *base, int sub_dev) {
u32_t base0 = base[0];
dev_command(base0, CMD_SOUND_ON);
if (sub_dev == DAC) {
dev_command(base0, CMD_BIT16_DMA_ON);
dev_command(base0, CMD_BIT8_DMA_ON);
}
else if (sub_dev == ADC)
dev_mixer_write(base, REG_SB_FIFO_CTRL|REG_SB_CTRL, rec_format | 0x80);
}
/* Stop the channel (### STOP_CHANNEL ###) */
static void dev_stop_channel(u32_t *base, int sub_dev) {
u32_t base0 = base[0];
if (sub_dev == DAC) {
dev_command(base0, CMD_BIT16_DMA_OFF);
dev_command(base0, CMD_BIT8_DMA_OFF);
}
else if (sub_dev == ADC)
dev_mixer_write(base, REG_SB_FIFO_CTRL | REG_SB_CTRL, 0x00);
}
/* Set DMA address and length (### SET_DMA ###) */
static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev) {
u32_t base0 = base[0];
if (sub_dev == DAC) {
dev_gcr_write(base0, REG_DAC_DMA_ADDR, dma);
dev_gcr_write(base0, REG_DAC_DMA_LEN, (len - 1) | 0x180000);
}
else if (sub_dev == ADC) {
dev_gcr_write(base0, REG_ADC_DMA_ADDR, dma);
dev_gcr_write(base0, REG_ADC_DMA_LEN, len - 1);
}
}
/* Read current address (### READ_DMA_CURRENT_ADDR ###) */
static u32_t dev_read_dma_current(u32_t *base, int sub_dev) {
u32_t data, base0 = base[0];
if (sub_dev == DAC)
data = dev_gcr_read(base0, REG_DAC_CUR_ADDR);
else if (sub_dev == ADC)
data = dev_gcr_read(base0, REG_ADC_CUR_ADDR);
return data & 0xffff;
}
/* Pause the DMA (### PAUSE_DMA ###) */
static void dev_pause_dma(u32_t *base, int sub_dev) {
u32_t base0 = base[0];
if (sub_dev == DAC) {
dev_command(base0, CMD_BIT16_DMA_OFF);
dev_command(base0, CMD_BIT8_DMA_OFF);
}
else if (sub_dev == ADC)
dev_mixer_write(base, REG_SB_FIFO_CTRL | REG_SB_CTRL, 0x00);
}
/* Resume the DMA (### RESUME_DMA ###) */
static void dev_resume_dma(u32_t *base, int sub_dev) {
u32_t base0 = base[0];
if (sub_dev == DAC) {
dev_command(base0, CMD_BIT16_DMA_ON);
dev_command(base0, CMD_BIT8_DMA_ON);
}
else if (sub_dev == ADC)
dev_mixer_write(base, REG_SB_FIFO_CTRL|REG_SB_CTRL, rec_format | 0x80);
}
/* Read and clear interrupt status (### READ_CLEAR_INTR_STS ###)
* -- Return interrupt status */
static u32_t dev_read_clear_intr_status(u32_t *base) {
u32_t data, status, base0 = base[0];
status = sdr_in8(base0, REG_INTR_STS);
sdr_out8(base0, REG_INTR_STS, status);
data = dev_mixer_read(base, REG_SB_IRQ_STATUS);
if (data & 0x02)
sdr_in8(base0 + REG_SB_BASE, 0x0f);
else if (data & 0x01)
sdr_in8(base0 + REG_SB_BASE, 0x0e);
else if (data & 0x20)
sdr_in8(base0, 0x16);
return status;
}
/* Enable or disable interrupt (### INTR_ENABLE_DISABLE ###) */
static void dev_intr_enable(u32_t *base, int flag) {
u32_t data, base0 = base[0];
data = dev_gcr_read(base0, REG_INTR_CTRL);
if (flag == INTR_ENABLE)
dev_gcr_write(base0, REG_INTR_CTRL, data | CMD_INTR_ENABLE);
else if (flag == INTR_DISABLE)
dev_gcr_write(base0, REG_INTR_CTRL, data & ~CMD_INTR_ENABLE);
}
/* ======= Common driver function ======= */
/* Probe the device */
static int dev_probe(void) {
int devind, i, ioflag;
u32_t device, bar, size, base;
u16_t vid, did, temp;
u8_t *reg;
pci_init();
device = pci_first_dev(&devind, &vid, &did);
while (device > 0) {
if (vid == VENDOR_ID && did == DEVICE_ID)
break;
device = pci_next_dev(&devind, &vid, &did);
}
if (vid != VENDOR_ID || did != DEVICE_ID)
return EIO;
pci_reserve(devind);
for (i = 0; i < 6; i++)
dev.base[i] = 0;
#ifdef DMA_BASE_IOMAP
for (i = 0; i < 6; i++) {
if (pci_get_bar(devind, PCI_BAR + i * 4, &base, &size, &ioflag)) {
/* printf("SDR: Fail to get PCI BAR %d\n", i); */
continue;
}
if (ioflag) {
/* printf("SDR: PCI BAR %d is not for memory\n", i); */
continue;
}
if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) {
printf("SDR: Fail to map hardware registers from PCI\n");
return -EIO;
}
dev.base[i] = (u32_t)reg;
}
#else
/* Get PCI BAR0-5 */
for (i = 0; i < 6; i++)
dev.base[i] = pci_attr_r32(devind, PCI_BAR + i * 4) & 0xffffffe0;
#endif
dev.name = pci_dev_name(vid, did);
dev.irq = pci_attr_r8(devind, PCI_ILR);
dev.revision = pci_attr_r8(devind, PCI_REV);
dev.did = did;
dev.vid = vid;
dev.devind = devind;
temp = pci_attr_r16(devind, PCI_CR);
pci_attr_w16(devind, PCI_CR, temp | 0x105);
#ifdef MY_DEBUG
printf("SDR: Hardware name is %s\n", dev.name);
for (i = 0; i < 6; i++)
printf("SDR: PCI BAR%d is 0x%08x\n", i, dev.base[i]);
printf("SDR: IRQ number is 0x%02x\n", dev.irq);
#endif
return OK;
}
/* Set sample rate in configuration */
static int set_sample_rate(u32_t rate, int num) {
aud_conf[num].sample_rate = rate;
return OK;
}
/* Set stereo in configuration */
static int set_stereo(u32_t stereo, int num) {
aud_conf[num].stereo = stereo;
return OK;
}
/* Set sample bits in configuration */
static int set_bits(u32_t bits, int num) {
aud_conf[num].nr_of_bits = bits;
return OK;
}
/* Set fragment size in configuration */
static int set_frag_size(u32_t frag_size, int num) {
if (frag_size > (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments) ||
frag_size < sub_dev[num].MinFragmentSize) {
return EINVAL;
}
aud_conf[num].fragment_size = frag_size;
return OK;
}
/* Set frame sign in configuration */
static int set_sign(u32_t val, int num) {
aud_conf[num].sign = val;
return OK;
}
/* Get maximum fragment size */
static int get_max_frag_size(u32_t *val, int *len, int num) {
*len = sizeof(*val);
*val = (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments);
return OK;
}
/* Return 1 if there are free buffers */
static int free_buf(u32_t *val, int *len, int num) {
*len = sizeof(*val);
if (sub_dev[num].BufLength == sub_dev[num].NrOfExtraBuffers)
*val = 0;
else
*val = 1;
return OK;
}
/* Get the current sample counter */
static int get_samples_in_buf(u32_t *result, int *len, int chan) {
u32_t res;
/* READ_DMA_CURRENT_ADDR */
res = dev_read_dma_current(dev.base, chan);
*result = (u32_t)(sub_dev[chan].BufLength * 8192) + res;
return OK;
}
/* ======= [Audio interface] Initialize data structure ======= */
int drv_init(void) {
drv.DriverName = DRIVER_NAME;
drv.NrOfSubDevices = 3;
drv.NrOfSpecialFiles = 3;
sub_dev[DAC].readable = 0;
sub_dev[DAC].writable = 1;
sub_dev[DAC].DmaSize = 64 * 1024;
sub_dev[DAC].NrOfDmaFragments = 2;
sub_dev[DAC].MinFragmentSize = 1024;
sub_dev[DAC].NrOfExtraBuffers = 4;
sub_dev[ADC].readable = 1;
sub_dev[ADC].writable = 0;
sub_dev[ADC].DmaSize = 64 * 1024;
sub_dev[ADC].NrOfDmaFragments = 2;
sub_dev[ADC].MinFragmentSize = 1024;
sub_dev[ADC].NrOfExtraBuffers = 4;
sub_dev[MIX].writable = 0;
sub_dev[MIX].readable = 0;
special_file[0].minor_dev_nr = 0;
special_file[0].write_chan = DAC;
special_file[0].read_chan = NO_CHANNEL;
special_file[0].io_ctl = DAC;
special_file[1].minor_dev_nr = 1;
special_file[1].write_chan = NO_CHANNEL;
special_file[1].read_chan = ADC;
special_file[1].io_ctl = ADC;
special_file[2].minor_dev_nr = 2;
special_file[2].write_chan = NO_CHANNEL;
special_file[2].read_chan = NO_CHANNEL;
special_file[2].io_ctl = MIX;
return OK;
}
/* ======= [Audio interface] Initialize hardware ======= */
int drv_init_hw(void) {
int i;
/* Match the device */
if (dev_probe()) {
printf("SDR: No sound card found\n");
return EIO;
}
/* Reset the device */
/* ### RESET_HARDWARE_CAN_FAIL ### */
if (dev_reset(dev.base)) {
printf("SDR: Fail to reset the device\n");
return EIO;
}
/* Configure the hardware */
/* ### CONF_HARDWARE ### */
dev_configure(dev.base);
/* Initialize the mixer */
/* ### INIT_MIXER ### */
dev_init_mixer(dev.base);
/* Set default mixer volume */
dev_set_default_volume(dev.base);
/* Initialize subdevice data */
for (i = 0; i < drv.NrOfSubDevices; i++) {
if (i == MIX)
continue;
aud_conf[i].busy = 0;
aud_conf[i].stereo = 1;
aud_conf[i].sample_rate = 44100;
aud_conf[i].nr_of_bits = 16;
aud_conf[i].sign = 1;
aud_conf[i].fragment_size =
sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments;
}
return OK;
}
/* ======= [Audio interface] Driver reset =======*/
int drv_reset(void) {
/* ### RESET_HARDWARE_CAN_FAIL ### */
return dev_reset(dev.base);
}
/* ======= [Audio interface] Driver start ======= */
int drv_start(int sub_dev, int DmaMode) {
int sample_count;
/* Set DAC and ADC sample rate */
/* ### SET_SAMPLE_RATE ### */
dev_set_sample_rate(dev.base, aud_conf[sub_dev].sample_rate);
sample_count = aud_conf[sub_dev].fragment_size;
#ifdef DMA_LENGTH_BY_FRAME
sample_count = sample_count / (aud_conf[sub_dev].nr_of_bits * (aud_conf[sub_dev].stereo + 1) / 8);
#endif
/* Set DAC and ADC format */
/* ### SET_FORMAT ### */
dev_set_format(dev.base, aud_conf[sub_dev].nr_of_bits,
aud_conf[sub_dev].sign, aud_conf[sub_dev].stereo, sample_count);
drv_reenable_int(sub_dev);
/* Start the channel */
/* ### START_CHANNEL ### */
dev_start_channel(dev.base, sub_dev);
aud_conf[sub_dev].busy = 1;
return OK;
}
/* ======= [Audio interface] Driver start ======= */
int drv_stop(int sub_dev) {
u32_t data;
/* INTR_ENABLE_DISABLE */
dev_intr_enable(dev.base, INTR_DISABLE);
/* ### STOP_CHANNEL ### */
dev_stop_channel(dev.base, sub_dev);
aud_conf[sub_dev].busy = 0;
return OK;
}
/* ======= [Audio interface] Enable interrupt ======= */
int drv_reenable_int(int chan) {
/* INTR_ENABLE_DISABLE */
dev_intr_enable(dev.base, INTR_ENABLE);
return OK;
}
/* ======= [Audio interface] I/O control ======= */
int drv_io_ctl(unsigned long request, void *val, int *len, int sub_dev) {
int status;
switch (request) {
case DSPIORATE:
status = set_sample_rate(*((u32_t *)val), sub_dev);
break;
case DSPIOSTEREO:
status = set_stereo(*((u32_t *)val), sub_dev);
break;
case DSPIOBITS:
status = set_bits(*((u32_t *)val), sub_dev);
break;
case DSPIOSIZE:
status = set_frag_size(*((u32_t *)val), sub_dev);
break;
case DSPIOSIGN:
status = set_sign(*((u32_t *)val), sub_dev);
break;
case DSPIOMAX:
status = get_max_frag_size(val, len, sub_dev);
break;
case DSPIORESET:
status = drv_reset();
break;
case DSPIOFREEBUF:
status = free_buf(val, len, sub_dev);
break;
case DSPIOSAMPLESINBUF:
status = get_samples_in_buf(val, len, sub_dev);
break;
case DSPIOPAUSE:
status = drv_pause(sub_dev);
break;
case DSPIORESUME:
status = drv_resume(sub_dev);
break;
case MIXIOGETVOLUME:
/* ### GET_SET_VOLUME ### */
status = get_set_volume(dev.base, val, GET_VOL);
break;
case MIXIOSETVOLUME:
/* ### GET_SET_VOLUME ### */
status = get_set_volume(dev.base, val, SET_VOL);
break;
default:
status = EINVAL;
break;
}
return status;
}
/* ======= [Audio interface] Get request number ======= */
int drv_get_irq(char *irq) {
*irq = dev.irq;
return OK;
}
/* ======= [Audio interface] Get fragment size ======= */
int drv_get_frag_size(u32_t *frag_size, int sub_dev) {
*frag_size = aud_conf[sub_dev].fragment_size;
return OK;
}
/* ======= [Audio interface] Set DMA channel ======= */
int drv_set_dma(u32_t dma, u32_t length, int chan) {
#ifdef DMA_LENGTH_BY_FRAME
length = length / (aud_conf[chan].nr_of_bits * (aud_conf[chan].stereo + 1) / 8);
#endif
/* ### SET_DMA ### */
dev_set_dma(dev.base, dma, length, chan);
return OK;
}
/* ======= [Audio interface] Get interrupt summary status ======= */
int drv_int_sum(void) {
u32_t status;
/* ### READ_CLEAR_INTR_STS ### */
status = dev_read_clear_intr_status(dev.base);
dev.intr_status = status;
#ifdef MY_DEBUG
printf("SDR: Interrupt status is 0x%08x\n", status);
#endif
return (status & (INTR_STS_DAC | INTR_STS_ADC));
}
/* ======= [Audio interface] Handle interrupt status ======= */
int drv_int(int sub_dev) {
u32_t mask;
/* ### CHECK_INTR_DAC ### */
if (sub_dev == DAC)
mask = INTR_STS_DAC;
/* ### CHECK_INTR_ADC ### */
else if (sub_dev == ADC)
mask = INTR_STS_ADC;
else
return 0;
return dev.intr_status & mask;
}
/* ======= [Audio interface] Pause DMA ======= */
int drv_pause(int sub_dev) {
/* ### PAUSE_DMA ### */
dev_pause_dma(dev.base, sub_dev);
return OK;
}
/* ======= [Audio interface] Resume DMA ======= */
int drv_resume(int sub_dev) {
/* ### RESUME_DMA ### */
dev_resume_dma(dev.base, sub_dev);
return OK;
}

View File

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

View File

@ -0,0 +1,114 @@
#ifndef _SDR_H
#define _SDR_H
/* ======= General Parameter ======= */
/* Global configure */
#define MIXER_SB16
#include <minix/audio_fw.h>
#include <sys/types.h>
#include <sys/ioc_sound.h>
#include <minix/sound.h>
#include <machine/pci.h>
#include <sys/mman.h>
#include "io.h"
/* Subdevice type */
#define DAC 0
#define ADC 1
#define MIX 2
/* PCI number and driver name */
#define VENDOR_ID 0x4005
#define DEVICE_ID 0x4000
#define DRIVER_NAME "ALS4000"
/* Volume option */
#define GET_VOL 0
#define SET_VOL 1
/* Interrupt control */
#define INTR_ENABLE 1
#define INTR_DISABLE 0
/* Interrupt status */
#define INTR_STS_DAC 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_INTR_STS 0x0e
#define REG_INTR_CTRL 0x8c
#define REG_DMA_EM_CTRL 0x99
#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_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_SOUND_ON 0xd1
#define CMD_INTR_ENABLE 0x28000
#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_STEREO 0x20
#define CMD_REC_SIGN 0x10
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[6];
char irq;
char revision;
u32_t intr_status;
} DEV_STRUCT;
void dev_mixer_write(u32_t *base, u32_t reg, u32_t val);
u32_t dev_mixer_read(u32_t *base, u32_t reg);
#endif

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_BASE_IOMAP
value = *(volatile u8_t *)(port);
#else
if ((r = sys_inb(port, &value)) != OK)
printf("SDR: sys_inb failed: %d\n", r);
#endif
return (u8_t)value;
}
#define sdr_in8(port, offset) (my_inb((port) + (offset)))
static u16_t my_inw(u32_t port) {
u32_t value;
int r;
#ifdef DMA_BASE_IOMAP
value = *(volatile u16_t *)(port);
#else
if ((r = sys_inw(port, &value)) != OK)
printf("SDR: sys_inw failed: %d\n", r);
#endif
return (u16_t)value;
}
#define sdr_in16(port, offset) (my_inw((port) + (offset)))
static u32_t my_inl(u32_t port) {
u32_t value;
int r;
#ifdef DMA_BASE_IOMAP
value = *(volatile u32_t *)(port);
#else
if ((r = sys_inl(port, &value)) != OK)
printf("SDR: sys_inl failed: %d\n", r);
#endif
return value;
}
#define sdr_in32(port, offset) (my_inl((port) + (offset)))
static void my_outb(u32_t port, u32_t value) {
int r;
#ifdef DMA_BASE_IOMAP
*(volatile u8_t *)(port) = value;
#else
if ((r = sys_outb(port, (u8_t)value)) != OK)
printf("SDR: sys_outb failed: %d\n", r);
#endif
}
#define sdr_out8(port, offset, value) \
(my_outb(((port) + (offset)), (value)))
static void my_outw(u32_t port, u32_t value) {
int r;
#ifdef DMA_BASE_IOMAP
*(volatile u16_t *)(port) = value;
#else
if ((r = sys_outw(port, (u16_t)value)) != OK)
printf("SDR: sys_outw failed: %d\n", r);
#endif
}
#define sdr_out16(port, offset, value) \
(my_outw(((port) + (offset)), (value)))
static void my_outl(u32_t port, u32_t value) {
int r;
#ifdef DMA_BASE_IOMAP
*(volatile u32_t *)(port) = value;
#else
if ((r = sys_outl(port, value)) != OK)
printf("SDR: sys_outl failed: %d\n", r);
#endif
}
#define sdr_out32(port, offset, value) \
(my_outl(((port) + (offset)), (value)))
#endif

View File

@ -0,0 +1,272 @@
#include "mixer.h"
#ifdef MIXER_AK4531
u8_t mixer_value[] = {
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08,
0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00,
0x00, 0x01
};
int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
int max_level, cmd_left, cmd_right;
max_level = 0x1f;
/* Check device */
switch (level->device) {
case Master:
cmd_left = MASTER_VOLUME_LCH;
cmd_right = MASTER_VOLUME_RCH;
break;
case Dac:
return EINVAL;
case Fm:
cmd_left = FM_VOLUME_LCH;
cmd_right = FM_VOLUME_RCH;
break;
case Cd:
cmd_left = CD_AUDIO_VOLUME_LCH;
cmd_right = CD_AUDIO_VOLUME_RCH;
break;
case Line:
cmd_left = LINE_VOLUME_LCH;
cmd_right = LINE_VOLUME_RCH;
break;
case Mic:
cmd_left = cmd_right = MIC_VOLUME;
break;
case Speaker:
cmd_left = cmd_right = MONO_OUT_VOLUME;
max_level = 0x03;
break;
case Treble:
return EINVAL;
case Bass:
return EINVAL;
default:
return EINVAL;
}
/* Set volume */
if (flag) {
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_left, 0x1f - level->left);
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_right, 0x1f - level->right);
mixer_value[cmd_left] = 0x1f - level->left;
mixer_value[cmd_right] = 0x1f - level->right;
}
/* Get volume (mixer register can not be read in ak4531 codec) */
else {
/* ### READ_MIXER_REG ### */
dev_mixer_read(base, cmd_left);
/* ### READ_MIXER_REG ### */
dev_mixer_read(base, cmd_right);
level->left = 0x1f - mixer_value[cmd_left];
level->right = 0x1f - mixer_value[cmd_right];
}
return OK;
}
#endif
#ifdef MIXER_SB16
int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
int max_level, shift, cmd_left, cmd_right;
max_level = 0x0f;
shift = 4;
/* Check device */
switch (level->device) {
case Master:
cmd_left = SB16_MASTER_LEFT;
cmd_right = SB16_MASTER_RIGHT;
break;
case Dac:
cmd_left = SB16_DAC_LEFT;
cmd_right = SB16_DAC_RIGHT;
break;
case Fm:
cmd_left = SB16_FM_LEFT;
cmd_right = SB16_FM_RIGHT;
break;
case Cd:
cmd_left = SB16_CD_LEFT;
cmd_right = SB16_CD_RIGHT;
break;
case Line:
cmd_left = SB16_LINE_LEFT;
cmd_left = SB16_LINE_RIGHT;
break;
case Mic:
cmd_left = cmd_right = SB16_MIC_LEVEL;
break;
case Speaker:
cmd_left = cmd_right = SB16_PC_LEVEL;
shift = 6;
max_level = 0x03;
break;
case Treble:
cmd_left = SB16_TREBLE_LEFT;
cmd_right = SB16_TREBLE_RIGHT;
shift = 4;
max_level = 0x0f;
break;
case Bass:
cmd_left = SB16_BASS_LEFT;
cmd_right = SB16_BASS_RIGHT;
shift = 4;
max_level = 0x0f;
break;
default:
return EINVAL;
}
/* Set volume */
if (flag) {
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_left, level->left << shift);
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_right, level->right << shift);
}
/* Get volume */
else {
/* ### READ_MIXER_REG ### */
level->left = dev_mixer_read(base, cmd_left);
/* ### READ_MIXER_REG ### */
level->right = dev_mixer_read(base, cmd_right);
level->left >>= shift;
level->right >>= shift;
}
return OK;
}
#endif
#ifdef MIXER_AC97
int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
int max_level, cmd, data;
max_level = 0x1f;
/* Check device */
switch (level->device) {
case Master:
cmd = AC97_MASTER_VOLUME;
break;
case Dac:
return EINVAL;
case Fm:
cmd = AC97_PCM_OUT_VOLUME;
break;
case Cd:
cmd = AC97_CD_VOLUME;
break;
case Line:
cmd = AC97_LINE_IN_VOLUME;
break;
case Mic:
cmd = AC97_MIC_VOLUME;
break;
case Speaker:
return EINVAL;
case Treble:
return EINVAL;
case Bass:
return EINVAL;
default:
return EINVAL;
}
/* Set volume */
if (flag) {
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
data = (max_level - level->left) << 8 | (max_level - level->right);
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd, data);
}
/* Get volume */
else {
/* ### READ_MIXER_REG ### */
data = dev_mixer_read(base, cmd);
level->left = (u16_t)(data >> 8);
level->right = (u16_t)(data & 0xff);
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
level->left = max_level - level->left;
level->right = max_level - level->right;
}
return OK;
}
#endif
/* Set default mixer volume */
void dev_set_default_volume(u32_t *base) {
int i;
#ifdef MIXER_AK4531
for (i = 0; i <= 0x19; i++)
dev_mixer_write(base, i, mixer_value[i]);
#endif
#ifdef MIXER_SB16
dev_mixer_write(base, SB16_MASTER_LEFT, 0x18 << 3);
dev_mixer_write(base, SB16_MASTER_RIGHT, 0x18 << 3);
dev_mixer_write(base, SB16_DAC_LEFT, 0x0f << 4);
dev_mixer_write(base, SB16_DAC_RIGHT, 0x0f << 4);
dev_mixer_write(base, SB16_FM_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_FM_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_CD_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_CD_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_LINE_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_LINE_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_MIC_LEVEL, 0x0f << 4);
dev_mixer_write(base, SB16_PC_LEVEL, 0x02 << 6);
dev_mixer_write(base, SB16_TREBLE_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_TREBLE_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_BASS_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_BASS_RIGHT, 0x08 << 4);
#endif
#ifdef MIXER_AC97
dev_mixer_write(base, AC97_POWERDOWN, 0x0000);
for (i = 0; i < 50000; i++) {
if (dev_mixer_read(base, AC97_POWERDOWN) & 0x03)
break;
micro_delay(100);
}
if (i == 50000)
printf("SDR: AC97 is not ready\n");
dev_mixer_write(base, AC97_MASTER_VOLUME, 0x0000);
dev_mixer_write(base, AC97_MONO_VOLUME, 0x8000);
dev_mixer_write(base, AC97_PHONE_VOLUME, 0x8008);
dev_mixer_write(base, AC97_MIC_VOLUME, 0x0000);
dev_mixer_write(base, AC97_LINE_IN_VOLUME, 0x0303);
dev_mixer_write(base, AC97_CD_VOLUME, 0x0808);
dev_mixer_write(base, AC97_AUX_IN_VOLUME, 0x0808);
dev_mixer_write(base, AC97_PCM_OUT_VOLUME, 0x0808);
dev_mixer_write(base, AC97_RECORD_GAIN_VOLUME, 0x0000);
dev_mixer_write(base, AC97_RECORD_SELECT, 0x0000);
dev_mixer_write(base, AC97_GENERAL_PURPOSE, 0x0000);
#endif
}

View File

@ -0,0 +1,62 @@
#ifndef _MIXER_H
#define _MIXER_H
#include "als4000.h"
#ifdef MIXER_AK4531
#define MASTER_VOLUME_LCH 0x00
#define MASTER_VOLUME_RCH 0x01
#define FM_VOLUME_LCH 0x04
#define FM_VOLUME_RCH 0x05
#define CD_AUDIO_VOLUME_LCH 0x06
#define CD_AUDIO_VOLUME_RCH 0x07
#define LINE_VOLUME_LCH 0x08
#define LINE_VOLUME_RCH 0x09
#define MIC_VOLUME 0x0e
#define MONO_OUT_VOLUME 0x0f
#endif
#ifdef MIXER_SB16
#define SB16_MASTER_LEFT 0x30
#define SB16_MASTER_RIGHT 0x31
#define SB16_DAC_LEFT 0x32
#define SB16_DAC_RIGHT 0x33
#define SB16_FM_LEFT 0x34
#define SB16_FM_RIGHT 0x35
#define SB16_CD_LEFT 0x36
#define SB16_CD_RIGHT 0x37
#define SB16_LINE_LEFT 0x38
#define SB16_LINE_RIGHT 0x39
#define SB16_MIC_LEVEL 0x3a
#define SB16_PC_LEVEL 0x3b
#define SB16_TREBLE_LEFT 0x44
#define SB16_TREBLE_RIGHT 0x45
#define SB16_BASS_LEFT 0x46
#define SB16_BASS_RIGHT 0x47
#endif
#ifdef MIXER_AC97
#define AC97_MASTER_VOLUME 0x02
#define AC97_AUX_OUT_VOLUME 0x04
#define AC97_MONO_VOLUME 0x06
#define AC97_MASTER_TONE 0x08
#define AC97_PC_BEEP_VOLUME 0x0a
#define AC97_PHONE_VOLUME 0x0c
#define AC97_MIC_VOLUME 0x0e
#define AC97_LINE_IN_VOLUME 0x10
#define AC97_CD_VOLUME 0x12
#define AC97_VIDEO_VOLUME 0x14
#define AC97_AUX_IN_VOLUME 0x16
#define AC97_PCM_OUT_VOLUME 0x18
#define AC97_RECORD_GAIN_VOLUME 0x1c
#define AC97_RECORD_GAIN_MIC_VOL 0x1e
#define AC97_GENERAL_PURPOSE 0x20
#define AC97_POWERDOWN 0x26
#define AC97_RECORD_SELECT 0x1a
#define AC97_RESET 0x00
#endif
int get_set_volume(u32_t *pbase, struct volume_level *level, int flag);
void dev_set_default_volume(u32_t *pbase);
#endif

View File

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

View File

@ -0,0 +1,7 @@
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>

View File

@ -0,0 +1,595 @@
#include "cmi8738.h"
#include "mixer.h"
/* global value */
DEV_STRUCT dev;
aud_sub_dev_conf_t aud_conf[3];
sub_dev_t sub_dev[3];
special_file_t special_file[3];
drv_t drv;
/* internal function */
static int dev_probe(void);
static int set_sample_rate(u32_t rate, int num);
static int set_stereo(u32_t stereo, int num);
static int set_bits(u32_t bits, int sub_dev);
static int set_frag_size(u32_t frag_size, int num);
static int set_sign(u32_t val, int num);
static int get_frag_size(u32_t *val, int *len, int num);
static int free_buf(u32_t *val, int *len, int num);
/* developer interface */
static int dev_reset(u32_t *base);
static void dev_configure(u32_t *base);
static void dev_init_mixer(u32_t *base);
static void dev_set_sample_rate(u32_t *base, u16_t sample_rate);
static void dev_set_format(u32_t *base, u32_t bits, u32_t sign,
u32_t stereo, u32_t sample_count);
static void dev_start_channel(u32_t *base, int sub_dev);
static void dev_stop_channel(u32_t *base, int sub_dev);
static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev);
static u32_t dev_read_dma_current(u32_t *base, int sub_dev);
static void dev_pause_dma(u32_t *base, int sub_dev);
static void dev_resume_dma(u32_t *base, int sub_dev);
static void dev_intr_other(u32_t *base, u32_t status);
static u32_t dev_read_clear_intr_status(u32_t *base);
static void dev_intr_enable(u32_t *base, int flag);
/* ======= Developer implemented function ======= */
/* ====== Self-defined function ====== */
void dev_io_set_clear(u32_t base, u32_t reg, u32_t val, int flag) {
u32_t data;
data = sdr_in32(base, reg);
if (flag == 0)
data &= ~val;
else if (flag == 1)
data |= val;
sdr_out32(base, reg, data);
}
/* ====== Mixer handling interface ======*/
/* Write the data to mixer register (### WRITE_MIXER_REG ###) */
void dev_mixer_write(u32_t *base, u32_t reg, u32_t val) {
u32_t base0 = base[0];
sdr_out8(base0, REG_SB_ADDR, reg);
sdr_out8(base0, REG_SB_DATA, val);
}
/* Read the data from mixer register (### READ_MIXER_REG ###) */
u32_t dev_mixer_read(u32_t *base, u32_t reg) {
u32_t base0 = base[0];
sdr_out8(base0, REG_SB_ADDR, reg);
return sdr_in8(base0, REG_SB_DATA);
}
/* ====== Developer interface ======*/
/* Reset the device (### RESET_HARDWARE_CAN_FAIL ###)
* -- Return OK means success, Others means failure */
static int dev_reset(u32_t *base) {
u32_t data, base0 = base[0];
dev_io_set_clear(base0, REG_MISC_CTRL, CMD_POWER_DOWN, 0);
dev_io_set_clear(base0, REG_MISC_CTRL, CMD_RESET, 1);
micro_delay(100);
dev_io_set_clear(base0, REG_MISC_CTRL, CMD_RESET, 0);
return OK;
}
/* Configure hardware registers (### CONF_HARDWARE ###) */
static void dev_configure(u32_t *base) {
u32_t data, base0 = base[0];
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ADC_C0, 0);
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ADC_C1, 1);
dev_io_set_clear(base0, REG_MISC_CTRL, CMD_N4SPK3D, 1);
dev_io_set_clear(base0, REG_FUNC_CTRL1, CMD_SPDIF_ENA, 0);
dev_io_set_clear(base0, REG_FUNC_CTRL1, CMD_SPDIF_LOOP, 0);
sdr_out8(base0, REG_EXT_INDEX, 0x03);
sdr_out8(base0, REG_MIX_INPUT, 0x0f);
}
/* Initialize the mixer (### INIT_MIXER ###) */
static void dev_init_mixer(u32_t *base) {
dev_mixer_write(base, 0, 0);
dev_mixer_write(base, MIXER_ADCL, 0x1f);
dev_mixer_write(base, MIXER_ADCR, 0x7f);
dev_mixer_write(base, MIXER_OUT_MUTE, 0x7f);
}
/* Set DAC and ADC sample rate (### SET_SAMPLE_RATE ###) */
static void dev_set_sample_rate(u32_t *base, u16_t sample_rate) {
int i;
u32_t data, rate = 0, base0 = base[0];
for (i = 0; i < 8; i++) {
if (sample_rate == g_sample_rate[i]) {
rate = i;
break;
}
}
data = sdr_in32(base0, REG_FUNC_CTRL1);
data &=~ (0xe000 | 0x1c00);
data |= (rate << 13) & 0xe000;
data |= (rate << 10) & 0x1c00;
sdr_out32(base0, REG_FUNC_CTRL1, data);
}
/* Set DAC and ADC format (### SET_FORMAT ###)*/
static void dev_set_format(u32_t *base, u32_t bits, u32_t sign,
u32_t stereo, u32_t sample_count) {
u32_t format = 0, data, base0 = base[0];
if (stereo == 1)
format |= FMT_STEREO;
if (bits == 16)
format |= FMT_BIT16;
data = sdr_in32(base0, REG_FORMAT);
data &= ~0x00000003;
data |= format << 0;
data &= ~0x0000000c;
data |= format << 2;
sdr_out32(base0, REG_FORMAT, data);
dev_io_set_clear(base0, REG_EXT_MISC, 0x10000000, 0);
sdr_out16(base0, REG_DAC_SAMPLE_COUNT, sample_count - 1);
sdr_out16(base0, REG_ADC_SAMPLE_COUNT, sample_count - 1);
}
/* Start the channel (### START_CHANNEL ###) */
static void dev_start_channel(u32_t *base, int sub_dev) {
u32_t data, base0 = base[0];
if (sub_dev == DAC) {
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C0, 1);
}
else if (sub_dev == ADC) {
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C1, 1);
}
}
/* Stop the channel (### STOP_CHANNEL ###) */
static void dev_stop_channel(u32_t *base, int sub_dev) {
u32_t data, base0 = base[0];
if (sub_dev == DAC) {
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C0, 0);
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C0, 1);
micro_delay(100);
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C0, 0);
}
else if (sub_dev == ADC) {
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_ENA_C1, 0);
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C1, 1);
micro_delay(100);
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_RESET_C1, 0);
}
}
/* Set DMA address and length (### SET_DMA ###) */
static void dev_set_dma(u32_t *base, u32_t dma, u32_t len, int sub_dev) {
u32_t base0 = base[0];
if (sub_dev == DAC) {
sdr_out32(base0, REG_DAC_DMA_ADDR, dma);
sdr_out16(base0, REG_DAC_DMA_LEN, len - 1);
}
else if (sub_dev == ADC) {
sdr_out32(base0, REG_ADC_DMA_ADDR, dma);
sdr_out16(base0, REG_ADC_DMA_LEN, len - 1);
}
}
/* Read current address (### READ_DMA_CURRENT_ADDR ###) */
static u32_t dev_read_dma_current(u32_t *base, int sub_dev) {
u32_t data, base0 = base[0];
if (sub_dev == DAC)
data = sdr_in16(base0, REG_DAC_CUR_ADDR);
else if (sub_dev == ADC)
data = sdr_in16(base0, REG_ADC_CUR_ADDR);
return data;
}
/* Pause the DMA (### PAUSE_DMA ###) */
static void dev_pause_dma(u32_t *base, int sub_dev) {
u32_t base0 = base[0];
if (sub_dev == DAC)
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C0, 1);
else if (sub_dev == ADC)
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C1, 1);
}
/* Resume the DMA (### RESUME_DMA ###) */
static void dev_resume_dma(u32_t *base, int sub_dev) {
u32_t base0 = base[0];
if (sub_dev == DAC)
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C0, 0);
else if (sub_dev == ADC)
dev_io_set_clear(base0, REG_FUNC_CTRL, CMD_PAUSE_C1, 0);
}
/* Read and clear interrupt status (### READ_CLEAR_INTR_STS ###)
* -- Return interrupt status */
static u32_t dev_read_clear_intr_status(u32_t *base) {
u32_t data, base0 = base[0];
data = sdr_in32(base0, REG_INTR_STS);
dev_intr_enable(base, INTR_DISABLE);
dev_intr_enable(base, INTR_ENABLE);
return data;
}
/* Enable or disable interrupt (### INTR_ENBALE_DISABLE ###) */
static void dev_intr_enable(u32_t *base, int flag) {
u32_t data, base0 = base[0];
data = sdr_in32(base0, REG_INTR_STS);
if (flag == INTR_ENABLE)
sdr_out32(base0, REG_INTR_CTRL, data | CMD_INTR_ENABLE);
else if (flag == INTR_DISABLE)
sdr_out32(base0, REG_INTR_CTRL, data & ~CMD_INTR_ENABLE);
}
/* ======= Common driver function ======= */
/* Probe the device */
static int dev_probe(void) {
int devind, i, ioflag;
u32_t device, bar, size, base;
u16_t vid, did, temp;
u8_t *reg;
pci_init();
device = pci_first_dev(&devind, &vid, &did);
while (device > 0) {
if (vid == VENDOR_ID && did == DEVICE_ID)
break;
device = pci_next_dev(&devind, &vid, &did);
}
if (vid != VENDOR_ID || did != DEVICE_ID)
return EIO;
pci_reserve(devind);
for (i = 0; i < 6; i++)
dev.base[i] = 0;
#ifdef DMA_BASE_IOMAP
for (i = 0; i < 6; i++) {
if (pci_get_bar(devind, PCI_BAR + i * 4, &base, &size, &ioflag)) {
/* printf("SDR: Fail to get PCI BAR %d\n", i); */
continue;
}
if (ioflag) {
/* printf("SDR: PCI BAR %d is not for memory\n", i); */
continue;
}
if ((reg = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED) {
printf("SDR: Fail to map hardware registers from PCI\n");
return -EIO;
}
dev.base[i] = (u32_t)reg;
}
#else
/* Get PCI BAR0-5 */
for (i = 0; i < 6; i++)
dev.base[i] = pci_attr_r32(devind, PCI_BAR + i * 4) & 0xffffffe0;
#endif
dev.name = pci_dev_name(vid, did);
dev.irq = pci_attr_r8(devind, PCI_ILR);
dev.revision = pci_attr_r8(devind, PCI_REV);
dev.did = did;
dev.vid = vid;
dev.devind = devind;
temp = pci_attr_r16(devind, PCI_CR);
pci_attr_w16(devind, PCI_CR, temp | 0x105);
#ifdef MY_DEBUG
printf("SDR: Hardware name is %s\n", dev.name);
for (i = 0; i < 6; i++)
printf("SDR: PCI BAR%d is 0x%08x\n", i, dev.base[i]);
printf("SDR: IRQ number is 0x%02x\n", dev.irq);
#endif
return OK;
}
/* Set sample rate in configuration */
static int set_sample_rate(u32_t rate, int num) {
aud_conf[num].sample_rate = rate;
return OK;
}
/* Set stereo in configuration */
static int set_stereo(u32_t stereo, int num) {
aud_conf[num].stereo = stereo;
return OK;
}
/* Set sample bits in configuration */
static int set_bits(u32_t bits, int num) {
aud_conf[num].nr_of_bits = bits;
return OK;
}
/* Set fragment size in configuration */
static int set_frag_size(u32_t frag_size, int num) {
if (frag_size > (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments) ||
frag_size < sub_dev[num].MinFragmentSize) {
return EINVAL;
}
aud_conf[num].fragment_size = frag_size;
return OK;
}
/* Set frame sign in configuration */
static int set_sign(u32_t val, int num) {
aud_conf[num].sign = val;
return OK;
}
/* Get maximum fragment size */
static int get_max_frag_size(u32_t *val, int *len, int num) {
*len = sizeof(*val);
*val = (sub_dev[num].DmaSize / sub_dev[num].NrOfDmaFragments);
return OK;
}
/* Return 1 if there are free buffers */
static int free_buf(u32_t *val, int *len, int num) {
*len = sizeof(*val);
if (sub_dev[num].BufLength == sub_dev[num].NrOfExtraBuffers)
*val = 0;
else
*val = 1;
return OK;
}
/* Get the current sample counter */
static int get_samples_in_buf(u32_t *result, int *len, int chan) {
u32_t res;
/* READ_DMA_CURRENT_ADDR */
res = dev_read_dma_current(dev.base, chan);
*result = (u32_t)(sub_dev[chan].BufLength * 8192) + res;
return OK;
}
/* ======= [Audio interface] Initialize data structure ======= */
int drv_init(void) {
drv.DriverName = DRIVER_NAME;
drv.NrOfSubDevices = 3;
drv.NrOfSpecialFiles = 3;
sub_dev[DAC].readable = 0;
sub_dev[DAC].writable = 1;
sub_dev[DAC].DmaSize = 64 * 1024;
sub_dev[DAC].NrOfDmaFragments = 2;
sub_dev[DAC].MinFragmentSize = 1024;
sub_dev[DAC].NrOfExtraBuffers = 4;
sub_dev[ADC].readable = 1;
sub_dev[ADC].writable = 0;
sub_dev[ADC].DmaSize = 64 * 1024;
sub_dev[ADC].NrOfDmaFragments = 2;
sub_dev[ADC].MinFragmentSize = 1024;
sub_dev[ADC].NrOfExtraBuffers = 4;
sub_dev[MIX].writable = 0;
sub_dev[MIX].readable = 0;
special_file[0].minor_dev_nr = 0;
special_file[0].write_chan = DAC;
special_file[0].read_chan = NO_CHANNEL;
special_file[0].io_ctl = DAC;
special_file[1].minor_dev_nr = 1;
special_file[1].write_chan = NO_CHANNEL;
special_file[1].read_chan = ADC;
special_file[1].io_ctl = ADC;
special_file[2].minor_dev_nr = 2;
special_file[2].write_chan = NO_CHANNEL;
special_file[2].read_chan = NO_CHANNEL;
special_file[2].io_ctl = MIX;
return OK;
}
/* ======= [Audio interface] Initialize hardware ======= */
int drv_init_hw(void) {
int i;
/* Match the device */
if (dev_probe()) {
printf("SDR: No sound card found\n");
return EIO;
}
/* Reset the device */
/* ### RESET_HARDWARE_CAN_FAIL ### */
if (dev_reset(dev.base)) {
printf("SDR: Fail to reset the device\n");
return EIO;
}
/* Configure the hardware */
/* ### CONF_HARDWARE ### */
dev_configure(dev.base);
/* Initialize the mixer */
/* ### INIT_MIXER ### */
dev_init_mixer(dev.base);
/* Set default mixer volume */
dev_set_default_volume(dev.base);
/* Initialize subdevice data */
for (i = 0; i < drv.NrOfSubDevices; i++) {
if (i == MIX)
continue;
aud_conf[i].busy = 0;
aud_conf[i].stereo = 1;
aud_conf[i].sample_rate = 44100;
aud_conf[i].nr_of_bits = 16;
aud_conf[i].sign = 1;
aud_conf[i].fragment_size =
sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments;
}
return OK;
}
/* ======= [Audio interface] Driver reset =======*/
int drv_reset(void) {
/* ### RESET_HARDWARE_CAN_FAIL ### */
return dev_reset(dev.base);
}
/* ======= [Audio interface] Driver start ======= */
int drv_start(int sub_dev, int DmaMode) {
int sample_count;
/* Set DAC and ADC sample rate */
/* ### SET_SAMPLE_RATE ### */
dev_set_sample_rate(dev.base, aud_conf[sub_dev].sample_rate);
sample_count = aud_conf[sub_dev].fragment_size;
#ifdef DMA_LENGTH_BY_FRAME
sample_count = sample_count / (aud_conf[sub_dev].nr_of_bits * (aud_conf[sub_dev].stereo + 1) / 8);
#endif
/* Set DAC and ADC format */
/* ### SET_FORMAT ### */
dev_set_format(dev.base, aud_conf[sub_dev].nr_of_bits,
aud_conf[sub_dev].sign, aud_conf[sub_dev].stereo, sample_count);
drv_reenable_int(sub_dev);
/* Start the channel */
/* ### START_CHANNEL ### */
dev_start_channel(dev.base, sub_dev);
aud_conf[sub_dev].busy = 1;
return OK;
}
/* ======= [Audio interface] Driver start ======= */
int drv_stop(int sub_dev) {
u32_t data;
/* INTR_ENABLE_DISABLE */
dev_intr_enable(dev.base, INTR_DISABLE);
/* ### STOP_CHANNEL ### */
dev_stop_channel(dev.base, sub_dev);
aud_conf[sub_dev].busy = 0;
return OK;
}
/* ======= [Audio interface] Enable interrupt ======= */
int drv_reenable_int(int chan) {
/* INTR_ENABLE_DISABLE */
dev_intr_enable(dev.base, INTR_ENABLE);
return OK;
}
/* ======= [Audio interface] I/O control ======= */
int drv_io_ctl(unsigned long request, void *val, int *len, int sub_dev) {
int status;
switch (request) {
case DSPIORATE:
status = set_sample_rate(*((u32_t *)val), sub_dev);
break;
case DSPIOSTEREO:
status = set_stereo(*((u32_t *)val), sub_dev);
break;
case DSPIOBITS:
status = set_bits(*((u32_t *)val), sub_dev);
break;
case DSPIOSIZE:
status = set_frag_size(*((u32_t *)val), sub_dev);
break;
case DSPIOSIGN:
status = set_sign(*((u32_t *)val), sub_dev);
break;
case DSPIOMAX:
status = get_max_frag_size(val, len, sub_dev);
break;
case DSPIORESET:
status = drv_reset();
break;
case DSPIOFREEBUF:
status = free_buf(val, len, sub_dev);
break;
case DSPIOSAMPLESINBUF:
status = get_samples_in_buf(val, len, sub_dev);
break;
case DSPIOPAUSE:
status = drv_pause(sub_dev);
break;
case DSPIORESUME:
status = drv_resume(sub_dev);
break;
case MIXIOGETVOLUME:
/* ### GET_SET_VOLUME ### */
status = get_set_volume(dev.base, val, GET_VOL);
break;
case MIXIOSETVOLUME:
/* ### GET_SET_VOLUME ### */
status = get_set_volume(dev.base, val, SET_VOL);
break;
default:
status = EINVAL;
break;
}
return status;
}
/* ======= [Audio interface] Get request number ======= */
int drv_get_irq(char *irq) {
*irq = dev.irq;
return OK;
}
/* ======= [Audio interface] Get fragment size ======= */
int drv_get_frag_size(u32_t *frag_size, int sub_dev) {
*frag_size = aud_conf[sub_dev].fragment_size;
return OK;
}
/* ======= [Audio interface] Set DMA channel ======= */
int drv_set_dma(u32_t dma, u32_t length, int chan) {
#ifdef DMA_LENGTH_BY_FRAME
length = length / (aud_conf[chan].nr_of_bits * (aud_conf[chan].stereo + 1) / 8);
#endif
/* ### SET_DMA ### */
dev_set_dma(dev.base, dma, length, chan);
return OK;
}
/* ======= [Audio interface] Get interrupt summary status ======= */
int drv_int_sum(void) {
u32_t status;
/* ### READ_CLEAR_INTR_STS ### */
status = dev_read_clear_intr_status(dev.base);
dev.intr_status = status;
#ifdef MY_DEBUG
printf("SDR: Interrupt status is 0x%08x\n", status);
#endif
return (status & (INTR_STS_DAC | INTR_STS_ADC));
}
/* ======= [Audio interface] Handle interrupt status ======= */
int drv_int(int sub_dev) {
u32_t mask;
/* ### CHECK_INTR_DAC ### */
if (sub_dev == DAC)
mask = INTR_STS_DAC;
/* ### CHECK_INTR_ADC ### */
else if (sub_dev == ADC)
mask = INTR_STS_ADC;
else
return 0;
return dev.intr_status & mask;
}
/* ======= [Audio interface] Pause DMA ======= */
int drv_pause(int sub_dev) {
/* ### PAUSE_DMA ### */
dev_pause_dma(dev.base, sub_dev);
return OK;
}
/* ======= [Audio interface] Resume DMA ======= */
int drv_resume(int sub_dev) {
/* ### RESUME_DMA ### */
dev_resume_dma(dev.base, sub_dev);
return OK;
}

View File

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

View File

@ -0,0 +1,113 @@
#ifndef _SDR_H
#define _SDR_H
/* ======= General Parameter ======= */
/* Global configure */
#define DMA_LENGTH_BY_FRAME
#define MIXER_SB16
#include <minix/audio_fw.h>
#include <sys/types.h>
#include <sys/ioc_sound.h>
#include <minix/sound.h>
#include <machine/pci.h>
#include <sys/mman.h>
#include "io.h"
/* Subdevice type */
#define DAC 0
#define ADC 1
#define MIX 2
/* PCI number and driver name */
#define VENDOR_ID 0x13f6
#define DEVICE_ID 0x0111
#define DRIVER_NAME "CMI8738"
/* Volume option */
#define GET_VOL 0
#define SET_VOL 1
/* Interrupt control */
#define INTR_ENABLE 1
#define INTR_DISABLE 0
/* Interrupt status */
#define INTR_STS_DAC 0x00000001
#define INTR_STS_ADC 0x00000002
/* ======= 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_MIX_INPUT 0x25
#define REG_EXT_MISC 0x90
#define REG_DAC_SAMPLE_COUNT 0x86
#define REG_ADC_SAMPLE_COUNT 0x8e
#define REG_DAC_DMA_ADDR 0x80
#define REG_DAC_DMA_LEN 0x84
#define REG_DAC_CUR_ADDR 0x80
#define REG_ADC_DMA_ADDR 0x88
#define REG_ADC_DMA_LEN 0x8c
#define REG_ADC_CUR_ADDR 0x88
#define REG_EXT_INDEX 0xf0
#define REG_INTR_CTRL 0x0c
#define REG_INTR_STS 0x10
#define FMT_BIT16 0x02
#define FMT_STEREO 0x01
#define MIXER_ADCL 0x3d
#define MIXER_ADCR 0x3e
#define MIXER_OUT_MUTE 0x3c
#define CMD_POWER_DOWN 0x80000000
#define CMD_RESET 0x40000000
#define CMD_ADC_C0 0x00000001
#define CMD_ADC_C1 0x00000002
#define CMD_N4SPK3D 0x04000000
#define CMD_SPDIF_ENA 0x00000200
#define CMD_SPDIF_LOOP 0x00000080
#define CMD_ENA_C0 0x00010000
#define CMD_ENA_C1 0x00020000
#define CMD_INTR_C0 0x00010000
#define CMD_INTR_C1 0x00020000
#define CMD_RESET_C0 0x00040000
#define CMD_RESET_C1 0x00080000
#define CMD_PAUSE_C0 0x00000004
#define CMD_PAUSE_C1 0x00000008
#define CMD_INTR_ENABLE 0x00030000
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[6];
char irq;
char revision;
u32_t intr_status;
} DEV_STRUCT;
void dev_mixer_write(u32_t *base, u32_t reg, u32_t val);
u32_t dev_mixer_read(u32_t *base, u32_t reg);
#endif

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_BASE_IOMAP
value = *(volatile u8_t *)(port);
#else
if ((r = sys_inb(port, &value)) != OK)
printf("SDR: sys_inb failed: %d\n", r);
#endif
return (u8_t)value;
}
#define sdr_in8(port, offset) (my_inb((port) + (offset)))
static u16_t my_inw(u32_t port) {
u32_t value;
int r;
#ifdef DMA_BASE_IOMAP
value = *(volatile u16_t *)(port);
#else
if ((r = sys_inw(port, &value)) != OK)
printf("SDR: sys_inw failed: %d\n", r);
#endif
return (u16_t)value;
}
#define sdr_in16(port, offset) (my_inw((port) + (offset)))
static u32_t my_inl(u32_t port) {
u32_t value;
int r;
#ifdef DMA_BASE_IOMAP
value = *(volatile u32_t *)(port);
#else
if ((r = sys_inl(port, &value)) != OK)
printf("SDR: sys_inl failed: %d\n", r);
#endif
return value;
}
#define sdr_in32(port, offset) (my_inl((port) + (offset)))
static void my_outb(u32_t port, u32_t value) {
int r;
#ifdef DMA_BASE_IOMAP
*(volatile u8_t *)(port) = value;
#else
if ((r = sys_outb(port, (u8_t)value)) != OK)
printf("SDR: sys_outb failed: %d\n", r);
#endif
}
#define sdr_out8(port, offset, value) \
(my_outb(((port) + (offset)), (value)))
static void my_outw(u32_t port, u32_t value) {
int r;
#ifdef DMA_BASE_IOMAP
*(volatile u16_t *)(port) = value;
#else
if ((r = sys_outw(port, (u16_t)value)) != OK)
printf("SDR: sys_outw failed: %d\n", r);
#endif
}
#define sdr_out16(port, offset, value) \
(my_outw(((port) + (offset)), (value)))
static void my_outl(u32_t port, u32_t value) {
int r;
#ifdef DMA_BASE_IOMAP
*(volatile u32_t *)(port) = value;
#else
if ((r = sys_outl(port, value)) != OK)
printf("SDR: sys_outl failed: %d\n", r);
#endif
}
#define sdr_out32(port, offset, value) \
(my_outl(((port) + (offset)), (value)))
#endif

View File

@ -0,0 +1,272 @@
#include "mixer.h"
#ifdef MIXER_AK4531
u8_t mixer_value[] = {
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08,
0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00,
0x00, 0x01
};
int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
int max_level, cmd_left, cmd_right;
max_level = 0x1f;
/* Check device */
switch (level->device) {
case Master:
cmd_left = MASTER_VOLUME_LCH;
cmd_right = MASTER_VOLUME_RCH;
break;
case Dac:
return EINVAL;
case Fm:
cmd_left = FM_VOLUME_LCH;
cmd_right = FM_VOLUME_RCH;
break;
case Cd:
cmd_left = CD_AUDIO_VOLUME_LCH;
cmd_right = CD_AUDIO_VOLUME_RCH;
break;
case Line:
cmd_left = LINE_VOLUME_LCH;
cmd_right = LINE_VOLUME_RCH;
break;
case Mic:
cmd_left = cmd_right = MIC_VOLUME;
break;
case Speaker:
cmd_left = cmd_right = MONO_OUT_VOLUME;
max_level = 0x03;
break;
case Treble:
return EINVAL;
case Bass:
return EINVAL;
default:
return EINVAL;
}
/* Set volume */
if (flag) {
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_left, 0x1f - level->left);
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_right, 0x1f - level->right);
mixer_value[cmd_left] = 0x1f - level->left;
mixer_value[cmd_right] = 0x1f - level->right;
}
/* Get volume (mixer register can not be read in ak4531 codec) */
else {
/* ### READ_MIXER_REG ### */
dev_mixer_read(base, cmd_left);
/* ### READ_MIXER_REG ### */
dev_mixer_read(base, cmd_right);
level->left = 0x1f - mixer_value[cmd_left];
level->right = 0x1f - mixer_value[cmd_right];
}
return OK;
}
#endif
#ifdef MIXER_SB16
int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
int max_level, shift, cmd_left, cmd_right;
max_level = 0x0f;
shift = 4;
/* Check device */
switch (level->device) {
case Master:
cmd_left = SB16_MASTER_LEFT;
cmd_right = SB16_MASTER_RIGHT;
break;
case Dac:
cmd_left = SB16_DAC_LEFT;
cmd_right = SB16_DAC_RIGHT;
break;
case Fm:
cmd_left = SB16_FM_LEFT;
cmd_right = SB16_FM_RIGHT;
break;
case Cd:
cmd_left = SB16_CD_LEFT;
cmd_right = SB16_CD_RIGHT;
break;
case Line:
cmd_left = SB16_LINE_LEFT;
cmd_left = SB16_LINE_RIGHT;
break;
case Mic:
cmd_left = cmd_right = SB16_MIC_LEVEL;
break;
case Speaker:
cmd_left = cmd_right = SB16_PC_LEVEL;
shift = 6;
max_level = 0x03;
break;
case Treble:
cmd_left = SB16_TREBLE_LEFT;
cmd_right = SB16_TREBLE_RIGHT;
shift = 4;
max_level = 0x0f;
break;
case Bass:
cmd_left = SB16_BASS_LEFT;
cmd_right = SB16_BASS_RIGHT;
shift = 4;
max_level = 0x0f;
break;
default:
return EINVAL;
}
/* Set volume */
if (flag) {
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_left, level->left << shift);
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd_right, level->right << shift);
}
/* Get volume */
else {
/* ### READ_MIXER_REG ### */
level->left = dev_mixer_read(base, cmd_left);
/* ### READ_MIXER_REG ### */
level->right = dev_mixer_read(base, cmd_right);
level->left >>= shift;
level->right >>= shift;
}
return OK;
}
#endif
#ifdef MIXER_AC97
int get_set_volume(u32_t *base, struct volume_level *level, int flag) {
int max_level, cmd, data;
max_level = 0x1f;
/* Check device */
switch (level->device) {
case Master:
cmd = AC97_MASTER_VOLUME;
break;
case Dac:
return EINVAL;
case Fm:
cmd = AC97_PCM_OUT_VOLUME;
break;
case Cd:
cmd = AC97_CD_VOLUME;
break;
case Line:
cmd = AC97_LINE_IN_VOLUME;
break;
case Mic:
cmd = AC97_MIC_VOLUME;
break;
case Speaker:
return EINVAL;
case Treble:
return EINVAL;
case Bass:
return EINVAL;
default:
return EINVAL;
}
/* Set volume */
if (flag) {
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
data = (max_level - level->left) << 8 | (max_level - level->right);
/* ### WRITE_MIXER_REG ### */
dev_mixer_write(base, cmd, data);
}
/* Get volume */
else {
/* ### READ_MIXER_REG ### */
data = dev_mixer_read(base, cmd);
level->left = (u16_t)(data >> 8);
level->right = (u16_t)(data & 0xff);
if (level->right < 0)
level->right = 0;
else if (level->right > max_level)
level->right = max_level;
if (level->left < 0)
level->left = 0;
else if (level->left > max_level)
level->left = max_level;
level->left = max_level - level->left;
level->right = max_level - level->right;
}
return OK;
}
#endif
/* Set default mixer volume */
void dev_set_default_volume(u32_t *base) {
int i;
#ifdef MIXER_AK4531
for (i = 0; i <= 0x19; i++)
dev_mixer_write(base, i, mixer_value[i]);
#endif
#ifdef MIXER_SB16
dev_mixer_write(base, SB16_MASTER_LEFT, 0x18 << 3);
dev_mixer_write(base, SB16_MASTER_RIGHT, 0x18 << 3);
dev_mixer_write(base, SB16_DAC_LEFT, 0x0f << 4);
dev_mixer_write(base, SB16_DAC_RIGHT, 0x0f << 4);
dev_mixer_write(base, SB16_FM_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_FM_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_CD_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_CD_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_LINE_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_LINE_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_MIC_LEVEL, 0x0f << 4);
dev_mixer_write(base, SB16_PC_LEVEL, 0x02 << 6);
dev_mixer_write(base, SB16_TREBLE_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_TREBLE_RIGHT, 0x08 << 4);
dev_mixer_write(base, SB16_BASS_LEFT, 0x08 << 4);
dev_mixer_write(base, SB16_BASS_RIGHT, 0x08 << 4);
#endif
#ifdef MIXER_AC97
dev_mixer_write(base, AC97_POWERDOWN, 0x0000);
for (i = 0; i < 50000; i++) {
if (dev_mixer_read(base, AC97_POWERDOWN) & 0x03)
break;
micro_delay(100);
}
if (i == 50000)
printf("SDR: AC97 is not ready\n");
dev_mixer_write(base, AC97_MASTER_VOLUME, 0x0000);
dev_mixer_write(base, AC97_MONO_VOLUME, 0x8000);
dev_mixer_write(base, AC97_PHONE_VOLUME, 0x8008);
dev_mixer_write(base, AC97_MIC_VOLUME, 0x0000);
dev_mixer_write(base, AC97_LINE_IN_VOLUME, 0x0303);
dev_mixer_write(base, AC97_CD_VOLUME, 0x0808);
dev_mixer_write(base, AC97_AUX_IN_VOLUME, 0x0808);
dev_mixer_write(base, AC97_PCM_OUT_VOLUME, 0x0808);
dev_mixer_write(base, AC97_RECORD_GAIN_VOLUME, 0x0000);
dev_mixer_write(base, AC97_RECORD_SELECT, 0x0000);
dev_mixer_write(base, AC97_GENERAL_PURPOSE, 0x0000);
#endif
}

View File

@ -0,0 +1,62 @@
#ifndef _MIXER_H
#define _MIXER_H
#include "cmi8738.h"
#ifdef MIXER_AK4531
#define MASTER_VOLUME_LCH 0x00
#define MASTER_VOLUME_RCH 0x01
#define FM_VOLUME_LCH 0x04
#define FM_VOLUME_RCH 0x05
#define CD_AUDIO_VOLUME_LCH 0x06
#define CD_AUDIO_VOLUME_RCH 0x07
#define LINE_VOLUME_LCH 0x08
#define LINE_VOLUME_RCH 0x09
#define MIC_VOLUME 0x0e
#define MONO_OUT_VOLUME 0x0f
#endif
#ifdef MIXER_SB16
#define SB16_MASTER_LEFT 0x30
#define SB16_MASTER_RIGHT 0x31
#define SB16_DAC_LEFT 0x32
#define SB16_DAC_RIGHT 0x33
#define SB16_FM_LEFT 0x34
#define SB16_FM_RIGHT 0x35
#define SB16_CD_LEFT 0x36
#define SB16_CD_RIGHT 0x37
#define SB16_LINE_LEFT 0x38
#define SB16_LINE_RIGHT 0x39
#define SB16_MIC_LEVEL 0x3a
#define SB16_PC_LEVEL 0x3b
#define SB16_TREBLE_LEFT 0x44
#define SB16_TREBLE_RIGHT 0x45
#define SB16_BASS_LEFT 0x46
#define SB16_BASS_RIGHT 0x47
#endif
#ifdef MIXER_AC97
#define AC97_MASTER_VOLUME 0x02
#define AC97_AUX_OUT_VOLUME 0x04
#define AC97_MONO_VOLUME 0x06
#define AC97_MASTER_TONE 0x08
#define AC97_PC_BEEP_VOLUME 0x0a
#define AC97_PHONE_VOLUME 0x0c
#define AC97_MIC_VOLUME 0x0e
#define AC97_LINE_IN_VOLUME 0x10
#define AC97_CD_VOLUME 0x12
#define AC97_VIDEO_VOLUME 0x14
#define AC97_AUX_IN_VOLUME 0x16
#define AC97_PCM_OUT_VOLUME 0x18
#define AC97_RECORD_GAIN_VOLUME 0x1c
#define AC97_RECORD_GAIN_MIC_VOL 0x1e
#define AC97_GENERAL_PURPOSE 0x20
#define AC97_POWERDOWN 0x26
#define AC97_RECORD_SELECT 0x1a
#define AC97_RESET 0x00
#endif
int get_set_volume(u32_t *pbase, struct volume_level *level, int flag);
void dev_set_default_volume(u32_t *pbase);
#endif

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

View File

@ -70,6 +70,7 @@ 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[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 +78,15 @@ 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;
=======
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;
>>>>>>> 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,7 @@ 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[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 +141,15 @@ 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;
=======
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;
>>>>>>> 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))); | (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);
=======
| (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)); 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,6 @@
service ip1000 service ip1000
{ {
<<<<<<< HEAD
type net; type net;
descr "IC Plus 1000A Ethernet Card"; descr "IC Plus 1000A Ethernet Card";
system system
@ -13,3 +14,19 @@ service ip1000
pci inet lwip amddev pci inet lwip amddev
; ;
}; };
=======
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
;
};
>>>>>>> 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

@ -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; return FALSE;
} }
/* Get Rx data length from descriptor (### GET_RX_LEN ###) /* Get Rx data length from descriptor (### GET_RX_LEN ###)
=======
}
return FALSE;
}
/* 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

@ -14,3 +14,4 @@ service vt6105
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