es1370 driver and updated es1371 and framework by Pieter Hijma.
This commit is contained in:
parent
0d2d8c6db2
commit
c67a56708e
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
***** Minix 3 Audio drivers *****
|
||||
|
||||
Directories:
|
||||
framework/ Generic driver framework
|
||||
sb16/ SB16 ISA driver
|
||||
es1370/ ES1370 driver
|
||||
es1371/ ES1371 driver
|
||||
|
||||
|
||||
|
|
@ -18,11 +18,12 @@ Creating special files:
|
|||
* mknod rec c 13 1
|
||||
* mknod mixer c 13 2
|
||||
* chmod 666 audio rec mixer
|
||||
(for es1371 one can add a special file for the second DAC-channel, major 13, minor 3)
|
||||
(one can add a special file for the second DAC-channel, major 13, minor 3)
|
||||
|
||||
|
||||
Running the driver:
|
||||
* service up /usr/sbin/sb16 -dev /dev/audio
|
||||
* service up /usr/sbin/es1370 -dev /dev/audio
|
||||
or:
|
||||
* service up /usr/sbin/es1371 -dev /dev/audio
|
||||
|
||||
|
|
|
|||
39
drivers/audio/es1370/Makefile
Normal file
39
drivers/audio/es1370/Makefile
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Makefile for the ES1371 sounddriver (SB16)
|
||||
|
||||
# directories
|
||||
u = /usr
|
||||
i = $u/include
|
||||
s = $i/sys
|
||||
m = $i/minix
|
||||
b = $i/ibm
|
||||
gen_drv_dir = ../../gen_drivers/cyclic_dma
|
||||
|
||||
# programs, flags, etc.
|
||||
CC = exec cc
|
||||
CFLAGS = -I$i
|
||||
LDFLAGS = -i
|
||||
LIBS = -lsys -lsysutil
|
||||
|
||||
# build local binary
|
||||
all: es1370
|
||||
|
||||
es1370: es1370.o ak4531.o audio_fw.o pci_helper.o
|
||||
$(CC) -o $@ $(LDFLAGS) es1370.o ak4531.o audio_fw.o pci_helper.o $(LIBS)
|
||||
|
||||
audio_fw.o: ../framework/audio_fw.c ../framework/audio_fw.h
|
||||
$(CC) -c ../framework/audio_fw.c
|
||||
|
||||
install: /usr/sbin/es1370
|
||||
/usr/sbin/es1370: es1370
|
||||
install -o root -S 1024k -c $? $@
|
||||
|
||||
# clean up local files
|
||||
clean:
|
||||
rm -f *.o *.bak core es1370
|
||||
|
||||
depend:
|
||||
/usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend
|
||||
|
||||
# Include generated dependencies.
|
||||
include .depend
|
||||
|
||||
177
drivers/audio/es1370/ak4531.c
Normal file
177
drivers/audio/es1370/ak4531.c
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/* best viewed with tabsize 4 */
|
||||
|
||||
|
||||
#include "ak4531.h"
|
||||
#include "pci_helper.h"
|
||||
|
||||
|
||||
#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
|
||||
|
||||
#define RESET_AND_POWER_DOWN 0x16
|
||||
#define PD 0x02
|
||||
#define RST 0x01
|
||||
|
||||
#define AD_INPUT_SELECT 0x18
|
||||
#define MIC_AMP_GAIN 0x19
|
||||
|
||||
#define MUTE 0x80
|
||||
|
||||
|
||||
FORWARD _PROTOTYPE( int ak4531_write, (u8_t address, u8_t data) );
|
||||
FORWARD _PROTOTYPE( int ak4531_finished, (void) );
|
||||
FORWARD _PROTOTYPE( int set_volume, (struct volume_level *level,
|
||||
int cmd_left, int cmd_right, int max_level) );
|
||||
|
||||
PRIVATE u16_t base_address;
|
||||
PRIVATE u16_t status_register;
|
||||
PRIVATE u16_t status_bit;
|
||||
PRIVATE u16_t poll_address;
|
||||
|
||||
u8_t mixer_values[0x20] = {
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08, /* 0x08 - 0x0f */
|
||||
0x7e, 0x3d, 0x01, 0x01, 0x00, 0x00, 0x03, 0x00, /* 0x10 - 0x17 */
|
||||
0x00, 0x01 /* 0x18 - 0x19 */
|
||||
};
|
||||
#if 0
|
||||
u8_t mixer_values[0x20] = {
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x00 - 0x07 */
|
||||
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, /* 0x08 - 0x0f */
|
||||
0x7f, 0x3d, 0x55, 0x26, 0xf7, 0xef, 0x03, 0x00, /* 0x10 - 0x17 */
|
||||
0x00, 0x01 /* 0x18 - 0x19 */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
PRIVATE int ak4531_finished(void) {
|
||||
int i;
|
||||
u16_t cstat;
|
||||
for (i = 0; i < 0x40000; i++) {
|
||||
cstat = pci_inw(status_register);
|
||||
if (!(cstat & status_bit)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int ak4531_write (u8_t address, u8_t data) {
|
||||
u16_t to_be_written;
|
||||
|
||||
|
||||
if (address < MASTER_VOLUME_LCH || address > MIC_AMP_GAIN) return -1;
|
||||
|
||||
to_be_written = (u16_t)((address << 8) | data);
|
||||
|
||||
if (!ak4531_finished()) return -1;
|
||||
pci_outw(base_address, to_be_written);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PUBLIC int ak4531_init(u16_t base, u16_t status_reg, u16_t bit,
|
||||
u16_t poll) {
|
||||
int i;
|
||||
|
||||
base_address = base;
|
||||
status_register = status_reg;
|
||||
status_bit = bit;
|
||||
poll_address = poll;
|
||||
|
||||
for (i=0; i<100; i++) {
|
||||
pci_inb(poll_address);
|
||||
}
|
||||
if(ak4531_write(RESET_AND_POWER_DOWN, PD|RST) < 0) return -1;
|
||||
|
||||
for (i=0; i<100; i++) {
|
||||
pci_inb(poll_address);
|
||||
}
|
||||
|
||||
ak4531_write(AD_INPUT_SELECT, 0x00);
|
||||
|
||||
for (i = MASTER_VOLUME_LCH ; i <= MIC_AMP_GAIN; i++) {
|
||||
if (ak4531_write(i, mixer_values[i]) < 0) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PUBLIC int ak4531_get_set_volume(struct volume_level *level, int flag) {
|
||||
int cmd_left, cmd_right, max_level;
|
||||
|
||||
max_level = 0x1f;
|
||||
|
||||
switch(level->device) {
|
||||
case Master:
|
||||
cmd_left = MASTER_VOLUME_LCH;
|
||||
cmd_right = MASTER_VOLUME_RCH;
|
||||
break;
|
||||
case Dac:
|
||||
return EINVAL;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
case Bass:
|
||||
return EINVAL;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (flag) { /* set volume */
|
||||
return set_volume(level, cmd_left, cmd_right, max_level);
|
||||
}
|
||||
else { /* get volume */
|
||||
level->left = - ((int) (mixer_values[cmd_left] & ~MUTE)) + 0x1f;
|
||||
level->right = - ((int) (mixer_values[cmd_right] & ~MUTE)) + 0x1f;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_volume(struct volume_level *level, int cmd_left, int cmd_right,
|
||||
int max_level) {
|
||||
|
||||
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;
|
||||
|
||||
mixer_values[cmd_left] = (-level->left)+0x1f;
|
||||
ak4531_write(cmd_left, mixer_values[cmd_left]);
|
||||
mixer_values[cmd_right] = (-level->right)+0x1f;
|
||||
ak4531_write(cmd_right, mixer_values[cmd_right]);
|
||||
|
||||
return OK;
|
||||
}
|
||||
12
drivers/audio/es1370/ak4531.h
Normal file
12
drivers/audio/es1370/ak4531.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef AK4531_H
|
||||
#define AK4531_H
|
||||
/* best viewed with tabsize=4 */
|
||||
|
||||
#include "../../drivers.h"
|
||||
#include <minix/sound.h>
|
||||
|
||||
_PROTOTYPE( int ak4531_init, (u16_t base, u16_t status_reg, u16_t bit,
|
||||
u16_t poll) );
|
||||
_PROTOTYPE( int ak4531_get_set_volume, (struct volume_level *level, int flag) );
|
||||
|
||||
#endif
|
||||
653
drivers/audio/es1370/es1370.c
Normal file
653
drivers/audio/es1370/es1370.c
Normal file
|
|
@ -0,0 +1,653 @@
|
|||
/* Best viewed with tabsize 4 */
|
||||
|
||||
/* Ensoniq ES1370 driver
|
||||
*
|
||||
* aka AudioPCI '97
|
||||
*
|
||||
* This is the main file of the ES1370 sound driver. There is no main function
|
||||
* over here, instead the main function is located in the generic dma driver.
|
||||
* All this driver does is implement the interface audio/audio_fw.h. All
|
||||
* functions having the prefix 'drv_' are dictated by audio/audio_fw.h. The
|
||||
* function prototypes you see below define a set of private helper functions.
|
||||
* Control over the AK4531 codec is delegated ak4531.c.
|
||||
*
|
||||
* September 2007 ES1370 driver (Pieter Hijma),
|
||||
* based on ES1371 driver by Laurens Bronwasser
|
||||
*/
|
||||
|
||||
#include <ibm/pci.h>
|
||||
|
||||
#include "../framework/audio_fw.h"
|
||||
#include "es1370.h"
|
||||
#include "ak4531.h"
|
||||
#include "pci_helper.h"
|
||||
|
||||
|
||||
/* reg(n) will be the device specific addresses */
|
||||
#define reg(n) dev.base + n
|
||||
|
||||
|
||||
/* prototypes of private functions */
|
||||
FORWARD _PROTOTYPE( int detect_hw, (void) );
|
||||
FORWARD _PROTOTYPE( int disable_int, (int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_stereo, (u32_t stereo, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_bits, (u32_t nr_of_bits, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_sample_rate, (u32_t rate, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_sign, (u32_t val, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int get_max_frag_size,
|
||||
(u32_t * val, int *len, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_frag_size, (u32_t fragment_size, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_int_cnt, (int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int free_buf, (u32_t *val, int *len, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int get_samples_in_buf,
|
||||
(u32_t *val, int *len, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int get_set_volume, (struct volume_level *level, int *len,
|
||||
int sub_dev, int flag) );
|
||||
FORWARD _PROTOTYPE( int reset, (int sub_dev) );
|
||||
|
||||
|
||||
DEV_STRUCT dev;
|
||||
aud_sub_dev_conf_t aud_conf[4];
|
||||
|
||||
|
||||
PUBLIC sub_dev_t sub_dev[4];
|
||||
PUBLIC special_file_t special_file[4];
|
||||
PUBLIC drv_t drv;
|
||||
|
||||
|
||||
PUBLIC int drv_init(void) {
|
||||
drv.DriverName = DRIVER_NAME;
|
||||
drv.NrOfSubDevices = 4;
|
||||
drv.NrOfSpecialFiles = 4;
|
||||
|
||||
sub_dev[DAC1_CHAN].readable = 0;
|
||||
sub_dev[DAC1_CHAN].writable = 1;
|
||||
sub_dev[DAC1_CHAN].DmaSize = 64 * 1024;
|
||||
sub_dev[DAC1_CHAN].NrOfDmaFragments = 2;
|
||||
sub_dev[DAC1_CHAN].MinFragmentSize = 1024;
|
||||
sub_dev[DAC1_CHAN].NrOfExtraBuffers = 4;
|
||||
|
||||
sub_dev[ADC1_CHAN].readable = 1;
|
||||
sub_dev[ADC1_CHAN].writable = 0;
|
||||
sub_dev[ADC1_CHAN].DmaSize = 64 * 1024;
|
||||
sub_dev[ADC1_CHAN].NrOfDmaFragments = 2;
|
||||
sub_dev[ADC1_CHAN].MinFragmentSize = 1024;
|
||||
sub_dev[ADC1_CHAN].NrOfExtraBuffers = 4;
|
||||
|
||||
sub_dev[MIXER].writable = 0;
|
||||
sub_dev[MIXER].readable = 0;
|
||||
|
||||
sub_dev[DAC2_CHAN].readable = 0;
|
||||
sub_dev[DAC2_CHAN].writable = 1;
|
||||
sub_dev[DAC2_CHAN].DmaSize = 64 * 1024;
|
||||
sub_dev[DAC2_CHAN].NrOfDmaFragments = 2;
|
||||
sub_dev[DAC2_CHAN].MinFragmentSize = 1024;
|
||||
sub_dev[DAC2_CHAN].NrOfExtraBuffers = 4;
|
||||
|
||||
special_file[0].minor_dev_nr = 0;
|
||||
special_file[0].write_chan = DAC1_CHAN;
|
||||
special_file[0].read_chan = NO_CHANNEL;
|
||||
special_file[0].io_ctl = DAC1_CHAN;
|
||||
|
||||
special_file[1].minor_dev_nr = 1;
|
||||
special_file[1].write_chan = NO_CHANNEL;
|
||||
special_file[1].read_chan = ADC1_CHAN;
|
||||
special_file[1].io_ctl = ADC1_CHAN;
|
||||
|
||||
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 = MIXER;
|
||||
|
||||
special_file[3].minor_dev_nr = 3;
|
||||
special_file[3].write_chan = DAC2_CHAN;
|
||||
special_file[3].read_chan = NO_CHANNEL;
|
||||
special_file[3].io_ctl = DAC2_CHAN;
|
||||
}
|
||||
|
||||
|
||||
PUBLIC int drv_init_hw (void) {
|
||||
u16_t i, j;
|
||||
u16_t chip_sel_ctrl_reg;
|
||||
|
||||
/* First, detect the hardware */
|
||||
if (detect_hw() != OK) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/* PCI command register
|
||||
* enable the SERR# driver, PCI bus mastering and I/O access
|
||||
*/
|
||||
pci_attr_w16 (dev.devind, PCI_CR, SERR_EN|PCI_MASTER|IO_ACCESS);
|
||||
|
||||
/* turn everything off */
|
||||
pci_outl(reg(CHIP_SEL_CTRL), 0x0UL);
|
||||
|
||||
/* turn off legacy (legacy control is undocumented) */
|
||||
pci_outl(reg(LEGACY), 0x0UL);
|
||||
pci_outl(reg(LEGACY+4), 0x0UL);
|
||||
|
||||
/* turn off serial interface */
|
||||
pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x0UL);
|
||||
/*pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x3UL);*/
|
||||
|
||||
|
||||
/* enable the codec */
|
||||
chip_sel_ctrl_reg = pci_inw(reg(CHIP_SEL_CTRL));
|
||||
chip_sel_ctrl_reg |= XCTL0 | CDC_EN;
|
||||
pci_outw(reg(CHIP_SEL_CTRL), chip_sel_ctrl_reg);
|
||||
|
||||
/* initialize the codec */
|
||||
if (ak4531_init(reg(CODEC_WRITE_ADDRESS),
|
||||
reg(INTERRUPT_STATUS), CWRIP, reg(0)) < 0) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/* clear all the memory */
|
||||
for (i = 0; i < 0x10; ++i) {
|
||||
pci_outb(reg(MEM_PAGE), i);
|
||||
for (j = 0; j < 0x10; j += 4) {
|
||||
pci_outl (reg(MEMORY) + j, 0x0UL);
|
||||
}
|
||||
}
|
||||
|
||||
/* initialize variables for each sub_device */
|
||||
for (i = 0; i < drv.NrOfSubDevices; i++) {
|
||||
if(i != MIXER) {
|
||||
aud_conf[i].busy = 0;
|
||||
aud_conf[i].stereo = DEFAULT_STEREO;
|
||||
aud_conf[i].sample_rate = DEFAULT_RATE;
|
||||
aud_conf[i].nr_of_bits = DEFAULT_NR_OF_BITS;
|
||||
aud_conf[i].sign = DEFAULT_SIGNED;
|
||||
aud_conf[i].fragment_size =
|
||||
sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int detect_hw(void) {
|
||||
u32_t device;
|
||||
int devind;
|
||||
u16_t v_id, d_id;
|
||||
|
||||
/* detect_hw tries to find device and get IRQ and base address
|
||||
with a little (much) help from the PCI library.
|
||||
This code is quite device independent and you can copy it.
|
||||
(just make sure to get the bugs out first)*/
|
||||
|
||||
pci_init();
|
||||
/* get first device and then search through the list */
|
||||
device = pci_first_dev(&devind, &v_id, &d_id);
|
||||
while( device > 0 ) {
|
||||
/* if we have a match...break */
|
||||
if (v_id == VENDOR_ID && d_id == DEVICE_ID) break;
|
||||
device = pci_next_dev(&devind, &v_id, &d_id);
|
||||
}
|
||||
|
||||
/* did we find anything? */
|
||||
if (v_id != VENDOR_ID || d_id != DEVICE_ID) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
pci_reserve(devind);
|
||||
|
||||
dev.name = pci_dev_name(v_id, d_id);
|
||||
|
||||
/* get base address of our device, ignore least signif. bit
|
||||
this last bit thing could be device dependent, i don't know */
|
||||
dev.base = pci_attr_r32(devind, PCI_BAR) & 0xfffffffe;
|
||||
|
||||
/* get IRQ */
|
||||
dev.irq = pci_attr_r8(devind, PCI_ILR);
|
||||
dev.revision = pci_attr_r8(devind, PCI_REV);
|
||||
dev.d_id = d_id;
|
||||
dev.v_id = v_id;
|
||||
dev.devind = devind; /* pci device identifier */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int reset(int chan) {
|
||||
drv_stop(chan);
|
||||
sub_dev[chan].OutOfData = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_reset() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_start(int sub_dev, int DmaMode) {
|
||||
u32_t enable_bit, result = 0;
|
||||
u32_t debug;
|
||||
|
||||
/* Write default values to device in case user failed to configure.
|
||||
If user did configure properly, everything is written twice.
|
||||
please raise your hand if you object against to this strategy...*/
|
||||
result |= set_sample_rate(aud_conf[sub_dev].sample_rate, sub_dev);
|
||||
result |= set_stereo(aud_conf[sub_dev].stereo, sub_dev);
|
||||
result |= set_bits(aud_conf[sub_dev].nr_of_bits, sub_dev);
|
||||
result |= set_sign(aud_conf[sub_dev].sign, sub_dev);
|
||||
|
||||
/* set the interrupt count */
|
||||
result |= set_int_cnt(sub_dev);
|
||||
|
||||
if (result) {
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/* if device currently paused, resume */
|
||||
drv_resume(sub_dev);
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: enable_bit = ADC1_EN;break;
|
||||
case DAC1_CHAN: enable_bit = DAC1_EN;break;
|
||||
case DAC2_CHAN: enable_bit = DAC2_EN;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* enable interrupts from 'sub device' */
|
||||
drv_reenable_int(sub_dev);
|
||||
|
||||
/* this means play!!! */
|
||||
pci_outw(reg(CHIP_SEL_CTRL), pci_inw(reg(CHIP_SEL_CTRL)) | enable_bit);
|
||||
|
||||
aud_conf[sub_dev].busy = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_stop(int sub_dev)
|
||||
{
|
||||
u32_t enable_bit;
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: enable_bit = ADC1_EN;break;
|
||||
case DAC1_CHAN: enable_bit = DAC1_EN;break;
|
||||
case DAC2_CHAN: enable_bit = DAC2_EN;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* stop the specified channel */
|
||||
pci_outw(reg(CHIP_SEL_CTRL),
|
||||
pci_inw(reg(CHIP_SEL_CTRL)) & ~enable_bit);
|
||||
aud_conf[sub_dev].busy = 0;
|
||||
disable_int(sub_dev);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/* all IO-ctl's sent to the upper driver are passed to this function */
|
||||
int drv_io_ctl(int 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 = reset(sub_dev); 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:
|
||||
status = get_set_volume(val, len, sub_dev, 0); break;
|
||||
case MIXIOSETVOLUME:
|
||||
status = get_set_volume(val, len, sub_dev, 1); break;
|
||||
default:
|
||||
status = EINVAL; break;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_get_irq(char *irq) {
|
||||
*irq = dev.irq;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_get_frag_size(u32_t *frag_size, int sub_dev) {
|
||||
*frag_size = aud_conf[sub_dev].fragment_size;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_set_dma(u32_t dma, u32_t length, int chan) {
|
||||
/* dma length in bytes,
|
||||
max is 64k long words for es1370 = 256k bytes */
|
||||
u32_t page, frame_count_reg, dma_add_reg;
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: page = ADC_MEM_PAGE;
|
||||
frame_count_reg = ADC_BUFFER_SIZE;
|
||||
dma_add_reg = ADC_PCI_ADDRESS;
|
||||
break;
|
||||
case DAC1_CHAN: page = DAC_MEM_PAGE;
|
||||
frame_count_reg = DAC1_BUFFER_SIZE;
|
||||
dma_add_reg = DAC1_PCI_ADDRESS;
|
||||
break;;
|
||||
case DAC2_CHAN: page = DAC_MEM_PAGE;
|
||||
frame_count_reg = DAC2_BUFFER_SIZE;
|
||||
dma_add_reg = DAC2_PCI_ADDRESS;
|
||||
break;;
|
||||
default: return EIO;
|
||||
}
|
||||
pci_outb(reg(MEM_PAGE), page);
|
||||
pci_outl(reg(dma_add_reg), dma);
|
||||
|
||||
/* device expects long word count in stead of bytes */
|
||||
length /= 4;
|
||||
|
||||
/* It seems that register _CURRENT_COUNT is overwritten, but this is
|
||||
* the way to go. The register frame_count_reg is only longword
|
||||
* addressable.
|
||||
* It expects length -1
|
||||
*/
|
||||
pci_outl(reg(frame_count_reg), (u32_t) (length - 1));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/* return status of the interrupt summary bit */
|
||||
int drv_int_sum(void) {
|
||||
return pci_inl(reg(INTERRUPT_STATUS)) & INTR;
|
||||
}
|
||||
|
||||
|
||||
int drv_int(int sub_dev) {
|
||||
u32_t int_status;
|
||||
u32_t bit;
|
||||
u32_t debug;
|
||||
|
||||
/* return status of interrupt bit of specified channel*/
|
||||
switch (sub_dev) {
|
||||
case DAC1_CHAN: bit = DAC1;break;
|
||||
case DAC2_CHAN: bit = DAC2;break;
|
||||
case ADC1_CHAN: bit = ADC;break;
|
||||
}
|
||||
|
||||
int_status = pci_inl(reg(INTERRUPT_STATUS)) & bit;
|
||||
|
||||
return int_status;
|
||||
}
|
||||
|
||||
|
||||
int drv_reenable_int(int chan) {
|
||||
u16_t ser_interface, int_en_bit;
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: int_en_bit = R1_INT_EN; break;
|
||||
case DAC1_CHAN: int_en_bit = P1_INTR_EN; break;
|
||||
case DAC2_CHAN: int_en_bit = P2_INTR_EN; break;
|
||||
default: EINVAL;
|
||||
}
|
||||
|
||||
/* clear and reenable an interrupt */
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit);
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface | int_en_bit);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_pause(int sub_dev) {
|
||||
u32_t pause_bit;
|
||||
|
||||
disable_int(sub_dev); /* don't send interrupts */
|
||||
|
||||
switch(sub_dev) {
|
||||
case DAC1_CHAN: pause_bit = P1_PAUSE;break;
|
||||
case DAC2_CHAN: pause_bit = P2_PAUSE;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* pause */
|
||||
pci_outl(reg(SERIAL_INTERFACE_CTRL),
|
||||
pci_inl(reg(SERIAL_INTERFACE_CTRL)) | pause_bit);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_resume(int sub_dev) {
|
||||
u32_t pause_bit = 0;
|
||||
|
||||
drv_reenable_int(sub_dev); /* enable interrupts */
|
||||
|
||||
switch(sub_dev) {
|
||||
case DAC1_CHAN: pause_bit = P1_PAUSE;break;
|
||||
case DAC2_CHAN: pause_bit = P2_PAUSE;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* clear pause bit */
|
||||
pci_outl(reg(SERIAL_INTERFACE_CTRL),
|
||||
pci_inl(reg(SERIAL_INTERFACE_CTRL)) & ~pause_bit);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_bits(u32_t nr_of_bits, int sub_dev) {
|
||||
/* set format bits for specified channel. */
|
||||
u16_t size_16_bit, ser_interface;
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: size_16_bit = R1_S_EB; break;
|
||||
case DAC1_CHAN: size_16_bit = P1_S_EB; break;
|
||||
case DAC2_CHAN: size_16_bit = P2_S_EB; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
ser_interface &= ~size_16_bit;
|
||||
switch(nr_of_bits) {
|
||||
case 16: ser_interface |= size_16_bit;break;
|
||||
case 8: break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface);
|
||||
aud_conf[sub_dev].nr_of_bits = nr_of_bits;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_stereo(u32_t stereo, int sub_dev) {
|
||||
/* set format bits for specified channel. */
|
||||
u16_t stereo_bit, ser_interface;
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: stereo_bit = R1_S_MB; break;
|
||||
case DAC1_CHAN: stereo_bit = P1_S_MB; break;
|
||||
case DAC2_CHAN: stereo_bit = P2_S_MB; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
ser_interface &= ~stereo_bit;
|
||||
if (stereo) {
|
||||
ser_interface |= stereo_bit;
|
||||
}
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface);
|
||||
aud_conf[sub_dev].stereo = stereo;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_sign(u32_t val, int sub_dev) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_frag_size(u32_t fragment_size, int sub_dev_nr) {
|
||||
if (fragment_size > (sub_dev[sub_dev_nr].DmaSize /
|
||||
sub_dev[sub_dev_nr].NrOfDmaFragments) ||
|
||||
fragment_size < sub_dev[sub_dev_nr].MinFragmentSize) {
|
||||
return EINVAL;
|
||||
}
|
||||
aud_conf[sub_dev_nr].fragment_size = fragment_size;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_sample_rate(u32_t rate, int sub_dev) {
|
||||
/* currently only 44.1kHz */
|
||||
u32_t controlRegister;
|
||||
|
||||
if (rate > MAX_RATE || rate < MIN_RATE) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
controlRegister = pci_inl(reg(CHIP_SEL_CTRL));
|
||||
controlRegister |= FREQ_44K100;
|
||||
pci_outl(reg(CHIP_SEL_CTRL), controlRegister);
|
||||
|
||||
aud_conf[sub_dev].sample_rate = rate;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_int_cnt(int chan) {
|
||||
/* Write interrupt count for specified channel.
|
||||
After <DspFragmentSize> bytes, an interrupt will be generated */
|
||||
|
||||
int sample_count;
|
||||
u16_t int_cnt_reg;
|
||||
|
||||
if (aud_conf[chan].fragment_size >
|
||||
(sub_dev[chan].DmaSize / sub_dev[chan].NrOfDmaFragments)
|
||||
|| aud_conf[chan].fragment_size < sub_dev[chan].MinFragmentSize) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: int_cnt_reg = ADC_SAMP_CT; break;
|
||||
case DAC1_CHAN: int_cnt_reg = DAC1_SAMP_CT; break;
|
||||
case DAC2_CHAN: int_cnt_reg = DAC2_SAMP_CT; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
sample_count = aud_conf[chan].fragment_size;
|
||||
|
||||
/* adjust sample count according to sample format */
|
||||
if( aud_conf[chan].stereo == TRUE ) sample_count >>= 1;
|
||||
switch(aud_conf[chan].nr_of_bits) {
|
||||
case 16: sample_count >>= 1;break;
|
||||
case 8: break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* set the sample count - 1 for the specified channel. */
|
||||
pci_outw(reg(int_cnt_reg), sample_count - 1);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int get_max_frag_size(u32_t * val, int * len, int sub_dev_nr) {
|
||||
*len = sizeof(*val);
|
||||
*val = (sub_dev[sub_dev_nr].DmaSize /
|
||||
sub_dev[sub_dev_nr].NrOfDmaFragments);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int disable_int(int chan) {
|
||||
u16_t ser_interface, int_en_bit;
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: int_en_bit = R1_INT_EN; break;
|
||||
case DAC1_CHAN: int_en_bit = P1_INTR_EN; break;
|
||||
case DAC2_CHAN: int_en_bit = P2_INTR_EN; break;
|
||||
default: EINVAL;
|
||||
}
|
||||
/* clear the interrupt */
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit);
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int get_samples_in_buf (u32_t *samples_in_buf, int *len, int chan) {
|
||||
u16_t samp_ct_reg;
|
||||
u16_t curr_samp_ct_reg;
|
||||
u16_t samp_ct; /* nr of samples - 1 that will be played back */
|
||||
u16_t curr_samp_ct; /* counts back from SAMP_CT till 0 */
|
||||
|
||||
*len = sizeof(*samples_in_buf);
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN:
|
||||
curr_samp_ct_reg = ADC_CURR_SAMP_CT;
|
||||
samp_ct_reg = ADC_SAMP_CT; break;
|
||||
case DAC1_CHAN:
|
||||
curr_samp_ct_reg = DAC1_CURR_SAMP_CT;
|
||||
samp_ct_reg = DAC1_SAMP_CT; break;
|
||||
case DAC2_CHAN:
|
||||
curr_samp_ct_reg = DAC2_CURR_SAMP_CT;
|
||||
samp_ct_reg = DAC2_SAMP_CT; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
samp_ct = pci_inw(reg(samp_ct_reg));
|
||||
curr_samp_ct = pci_inw(reg(curr_samp_ct_reg));
|
||||
|
||||
*samples_in_buf = (u32_t) (sub_dev[chan].BufLength * 8192) +
|
||||
curr_samp_ct;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/* returns 1 if there are free buffers */
|
||||
PRIVATE int free_buf (u32_t *val, int *len, int sub_dev_nr) {
|
||||
*len = sizeof(*val);
|
||||
if (sub_dev[sub_dev_nr].BufLength ==
|
||||
sub_dev[sub_dev_nr].NrOfExtraBuffers) {
|
||||
*val = 0;
|
||||
}
|
||||
else {
|
||||
*val = 1;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int get_set_volume(struct volume_level *level, int *len, int sub_dev,
|
||||
int flag) {
|
||||
*len = sizeof(struct volume_level);
|
||||
if (sub_dev == MIXER) {
|
||||
return ak4531_get_set_volume(level, flag);
|
||||
}
|
||||
else {
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
125
drivers/audio/es1370/es1370.h
Normal file
125
drivers/audio/es1370/es1370.h
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#ifndef ES1370_H
|
||||
#define ES1370_H
|
||||
/* best viewed with tabsize=4 */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "../../drivers.h"
|
||||
#include <sys/ioc_sound.h>
|
||||
|
||||
|
||||
/* set your vendor and device ID's here */
|
||||
#define VENDOR_ID 0x1274
|
||||
#define DEVICE_ID 0x5000
|
||||
#define DRIVER_NAME "ES1370"
|
||||
|
||||
|
||||
/* channels or subdevices */
|
||||
#define DAC1_CHAN 0
|
||||
#define ADC1_CHAN 1
|
||||
#define MIXER 2
|
||||
#define DAC2_CHAN 3
|
||||
|
||||
|
||||
/* PCI command register defines */
|
||||
#define SERR_EN 0x0100
|
||||
#define PCI_MASTER 0x0004
|
||||
#define IO_ACCESS 0x0001
|
||||
|
||||
|
||||
/* Interrupt/Chip Select Control */
|
||||
#define CHIP_SEL_CTRL 0x00
|
||||
#define FREQ_44K100 0x3000 /* 44.1 Khz */
|
||||
#define CDC_EN 0x0002 /* codec enable */
|
||||
#define ADC1_EN 0x0010
|
||||
#define DAC1_EN 0x0040
|
||||
#define DAC2_EN 0x0020
|
||||
#define XCTL0 0x0100
|
||||
#define CCB_INTRM 0x0400
|
||||
|
||||
|
||||
/* Interrupt/Chip Select Status */
|
||||
#define INTERRUPT_STATUS 0x04
|
||||
#define ADC 0x0001
|
||||
#define DAC2 0x0002
|
||||
#define DAC1 0x0004
|
||||
#define CSTAT 0x0400 /* == CBUSY || CWRIP */
|
||||
#define CWRIP 0x0100 /* == CBUSY || CWRIP */
|
||||
#define INTR 0x80000000
|
||||
|
||||
|
||||
/* AK4531 address */
|
||||
#define CODEC_WRITE_ADDRESS 0x10
|
||||
|
||||
|
||||
/* Legacy address */
|
||||
#define LEGACY 0x18
|
||||
|
||||
|
||||
/* Memory related defines */
|
||||
#define MEM_PAGE 0x0c
|
||||
#define ADC_MEM_PAGE 0x0d
|
||||
#define DAC_MEM_PAGE 0x0c /* for DAC1 and DAC2 */
|
||||
|
||||
#define MEMORY 0x30
|
||||
#define ADC_BUFFER_SIZE 0x34
|
||||
#define DAC1_BUFFER_SIZE 0x34
|
||||
#define DAC2_BUFFER_SIZE 0X3c
|
||||
#define ADC_PCI_ADDRESS 0x30
|
||||
#define DAC1_PCI_ADDRESS 0x30
|
||||
#define DAC2_PCI_ADDRESS 0x38
|
||||
|
||||
|
||||
/* Serial Interface Control */
|
||||
#define SERIAL_INTERFACE_CTRL 0x20
|
||||
#define P1_S_MB 0x0001 /* DAC1 Stereo/Mono bit */
|
||||
#define P1_S_EB 0x0002 /* DAC1 Sixteen/Eight bit */
|
||||
#define P2_S_MB 0x0004 /* DAC2 Stereo/Mono bit */
|
||||
#define P2_S_EB 0x0008 /* DAC2 Sixteen/Eight bit */
|
||||
#define R1_S_MB 0x0010 /* ADC Stereo/Mono bit */
|
||||
#define R1_S_EB 0x0020 /* ADC Sixteen/Eight bit */
|
||||
#define P1_INTR_EN 0x0100
|
||||
#define P2_INTR_EN 0x0200
|
||||
#define R1_INT_EN 0x0400
|
||||
#define P1_PAUSE 0x0800
|
||||
#define P2_PAUSE 0x1000
|
||||
|
||||
|
||||
#define DAC1_SAMP_CT 0x24
|
||||
#define DAC1_CURR_SAMP_CT 0x26
|
||||
#define DAC2_SAMP_CT 0x28
|
||||
#define DAC2_CURR_SAMP_CT 0x2a
|
||||
#define ADC_SAMP_CT 0x2c
|
||||
#define ADC_CURR_SAMP_CT 0x2e
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32_t stereo;
|
||||
u16_t sample_rate;
|
||||
u32_t nr_of_bits;
|
||||
u32_t sign;
|
||||
u32_t busy;
|
||||
u32_t fragment_size;
|
||||
} aud_sub_dev_conf_t;
|
||||
|
||||
/* Some defaults for the aud_sub_dev_conf_t*/
|
||||
#define DEFAULT_RATE 44100 /* Sample rate */
|
||||
#define DEFAULT_NR_OF_BITS 16 /* Nr. of bits per sample per chan */
|
||||
#define DEFAULT_SIGNED 0 /* 0 = unsigned, 1 = signed */
|
||||
#define DEFAULT_STEREO 1 /* 0 = mono, 1 = stereo */
|
||||
#define MAX_RATE 44100 /* Max sample speed in KHz */
|
||||
#define MIN_RATE 4000 /* Min sample speed in KHz */
|
||||
|
||||
|
||||
typedef struct DEVSTRUCT {
|
||||
char* name;
|
||||
u16_t v_id; /* vendor id */
|
||||
u16_t d_id; /* device id */
|
||||
u32_t devind; /* minix pci device id, for
|
||||
* pci configuration space */
|
||||
u32_t base; /* changed to 32 bits */
|
||||
char irq;
|
||||
char revision; /* version of the device */
|
||||
} DEV_STRUCT;
|
||||
|
||||
|
||||
#endif /* ES1370_H */
|
||||
65
drivers/audio/es1370/pci_helper.c
Normal file
65
drivers/audio/es1370/pci_helper.c
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* best viewed with tabsize 4 */
|
||||
|
||||
#include "../../drivers.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <minix/sysutil.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include "pci_helper.h"
|
||||
|
||||
#include "es1370.h"
|
||||
|
||||
/*===========================================================================*
|
||||
* helper functions for I/O *
|
||||
*===========================================================================*/
|
||||
PUBLIC unsigned pci_inb(U16_t port) {
|
||||
u32_t value;
|
||||
int s;
|
||||
if ((s=sys_inb(port, &value)) !=OK)
|
||||
printf("%s: warning, sys_inb failed: %d\n", DRIVER_NAME, s);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
PUBLIC unsigned pci_inw(U16_t port) {
|
||||
u32_t value;
|
||||
int s;
|
||||
if ((s=sys_inw(port, &value)) !=OK)
|
||||
printf("%s: warning, sys_inw failed: %d\n", DRIVER_NAME, s);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
PUBLIC unsigned pci_inl(U16_t port) {
|
||||
U32_t value;
|
||||
int s;
|
||||
if ((s=sys_inl(port, &value)) !=OK)
|
||||
printf("%s: warning, sys_inl failed: %d\n", DRIVER_NAME, s);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
PUBLIC void pci_outb(U16_t port, U8_t value) {
|
||||
int s;
|
||||
if ((s=sys_outb(port, value)) !=OK)
|
||||
printf("%s: warning, sys_outb failed: %d\n", DRIVER_NAME, s);
|
||||
}
|
||||
|
||||
|
||||
PUBLIC void pci_outw(U16_t port, U16_t value) {
|
||||
int s;
|
||||
if ((s=sys_outw(port, value)) !=OK)
|
||||
printf("%s: warning, sys_outw failed: %d\n", DRIVER_NAME, s);
|
||||
}
|
||||
|
||||
|
||||
PUBLIC void pci_outl(U16_t port, U32_t value) {
|
||||
int s;
|
||||
if ((s=sys_outl(port, value)) !=OK)
|
||||
printf("%s: warning, sys_outl failed: %d\n", DRIVER_NAME, s);
|
||||
}
|
||||
|
||||
12
drivers/audio/es1370/pci_helper.h
Normal file
12
drivers/audio/es1370/pci_helper.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef PCI_HELPER
|
||||
#define PCI_HELPER
|
||||
|
||||
_PROTOTYPE( unsigned pci_inb, (U16_t port) );
|
||||
_PROTOTYPE( unsigned pci_inw, (U16_t port) );
|
||||
_PROTOTYPE( unsigned pci_inl, (U16_t port) );
|
||||
|
||||
_PROTOTYPE( void pci_outb, (U16_t port, U8_t value) );
|
||||
_PROTOTYPE( void pci_outw, (U16_t port, U16_t value) );
|
||||
_PROTOTYPE( void pci_outl, (U16_t port, U32_t value) );
|
||||
|
||||
#endif
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
|
||||
SRC.o: ../../drivers.h
|
||||
SRC.o: ../../libpci/pci.h
|
||||
SRC.o: /usr/include/ansi.h
|
||||
SRC.o: /usr/include/errno.h
|
||||
SRC.o: /usr/include/ibm/bios.h
|
||||
SRC.o: /usr/include/ibm/interrupt.h
|
||||
SRC.o: /usr/include/ibm/ports.h
|
||||
SRC.o: /usr/include/limits.h
|
||||
SRC.o: /usr/include/minix/bitmap.h
|
||||
SRC.o: /usr/include/minix/callnr.h
|
||||
SRC.o: /usr/include/minix/com.h
|
||||
SRC.o: /usr/include/minix/config.h
|
||||
SRC.o: /usr/include/minix/const.h
|
||||
SRC.o: /usr/include/minix/devio.h
|
||||
SRC.o: /usr/include/minix/dmap.h
|
||||
SRC.o: /usr/include/minix/ioctl.h
|
||||
SRC.o: /usr/include/minix/ipc.h
|
||||
SRC.o: /usr/include/minix/sys_config.h
|
||||
SRC.o: /usr/include/minix/syslib.h
|
||||
SRC.o: /usr/include/minix/sysutil.h
|
||||
SRC.o: /usr/include/minix/type.h
|
||||
SRC.o: /usr/include/signal.h
|
||||
SRC.o: /usr/include/stddef.h
|
||||
SRC.o: /usr/include/stdlib.h
|
||||
SRC.o: /usr/include/string.h
|
||||
SRC.o: /usr/include/sys/dir.h
|
||||
SRC.o: /usr/include/sys/ioc_sound.h
|
||||
SRC.o: /usr/include/sys/types.h
|
||||
SRC.o: /usr/include/unistd.h
|
||||
SRC.o: SRC.c
|
||||
SRC.o: SRC.h
|
||||
SRC.o: es1371.h
|
||||
SRC.o: wait.h
|
||||
|
||||
codec.o: ../../drivers.h
|
||||
codec.o: ../../libpci/pci.h
|
||||
codec.o: ../AC97.h
|
||||
codec.o: /usr/include/ansi.h
|
||||
codec.o: /usr/include/errno.h
|
||||
codec.o: /usr/include/ibm/bios.h
|
||||
codec.o: /usr/include/ibm/interrupt.h
|
||||
codec.o: /usr/include/ibm/ports.h
|
||||
codec.o: /usr/include/limits.h
|
||||
codec.o: /usr/include/minix/bitmap.h
|
||||
codec.o: /usr/include/minix/callnr.h
|
||||
codec.o: /usr/include/minix/com.h
|
||||
codec.o: /usr/include/minix/config.h
|
||||
codec.o: /usr/include/minix/const.h
|
||||
codec.o: /usr/include/minix/devio.h
|
||||
codec.o: /usr/include/minix/dmap.h
|
||||
codec.o: /usr/include/minix/ioctl.h
|
||||
codec.o: /usr/include/minix/ipc.h
|
||||
codec.o: /usr/include/minix/sys_config.h
|
||||
codec.o: /usr/include/minix/syslib.h
|
||||
codec.o: /usr/include/minix/sysutil.h
|
||||
codec.o: /usr/include/minix/type.h
|
||||
codec.o: /usr/include/signal.h
|
||||
codec.o: /usr/include/stddef.h
|
||||
codec.o: /usr/include/stdlib.h
|
||||
codec.o: /usr/include/string.h
|
||||
codec.o: /usr/include/sys/dir.h
|
||||
codec.o: /usr/include/sys/ioc_sound.h
|
||||
codec.o: /usr/include/sys/types.h
|
||||
codec.o: /usr/include/unistd.h
|
||||
codec.o: SRC.h
|
||||
codec.o: codec.c
|
||||
codec.o: codec.h
|
||||
codec.o: es1371.h
|
||||
codec.o: wait.h
|
||||
|
||||
es1371.o: ../../drivers.h
|
||||
es1371.o: ../../libpci/pci.h
|
||||
es1371.o: ../AC97.h
|
||||
es1371.o: ../framework/../../drivers.h
|
||||
es1371.o: ../framework/audio_fw.h
|
||||
es1371.o: /usr/include/ansi.h
|
||||
es1371.o: /usr/include/errno.h
|
||||
es1371.o: /usr/include/ibm/bios.h
|
||||
es1371.o: /usr/include/ibm/interrupt.h
|
||||
es1371.o: /usr/include/ibm/ports.h
|
||||
es1371.o: /usr/include/limits.h
|
||||
es1371.o: /usr/include/minix/bitmap.h
|
||||
es1371.o: /usr/include/minix/callnr.h
|
||||
es1371.o: /usr/include/minix/com.h
|
||||
es1371.o: /usr/include/minix/config.h
|
||||
es1371.o: /usr/include/minix/const.h
|
||||
es1371.o: /usr/include/minix/devio.h
|
||||
es1371.o: /usr/include/minix/dmap.h
|
||||
es1371.o: /usr/include/minix/ioctl.h
|
||||
es1371.o: /usr/include/minix/ipc.h
|
||||
es1371.o: /usr/include/minix/sys_config.h
|
||||
es1371.o: /usr/include/minix/syslib.h
|
||||
es1371.o: /usr/include/minix/sysutil.h
|
||||
es1371.o: /usr/include/minix/type.h
|
||||
es1371.o: /usr/include/signal.h
|
||||
es1371.o: /usr/include/stddef.h
|
||||
es1371.o: /usr/include/stdlib.h
|
||||
es1371.o: /usr/include/string.h
|
||||
es1371.o: /usr/include/sys/dir.h
|
||||
es1371.o: /usr/include/sys/ioc_sound.h
|
||||
es1371.o: /usr/include/sys/types.h
|
||||
es1371.o: /usr/include/unistd.h
|
||||
es1371.o: SRC.h
|
||||
es1371.o: codec.h
|
||||
es1371.o: es1371.c
|
||||
es1371.o: es1371.h
|
||||
es1371.o: wait.h
|
||||
|
||||
wait.o: ../../drivers.h
|
||||
wait.o: ../../libpci/pci.h
|
||||
wait.o: /usr/include/ansi.h
|
||||
wait.o: /usr/include/errno.h
|
||||
wait.o: /usr/include/ibm/bios.h
|
||||
wait.o: /usr/include/ibm/interrupt.h
|
||||
wait.o: /usr/include/ibm/ports.h
|
||||
wait.o: /usr/include/limits.h
|
||||
wait.o: /usr/include/minix/bitmap.h
|
||||
wait.o: /usr/include/minix/callnr.h
|
||||
wait.o: /usr/include/minix/com.h
|
||||
wait.o: /usr/include/minix/config.h
|
||||
wait.o: /usr/include/minix/const.h
|
||||
wait.o: /usr/include/minix/devio.h
|
||||
wait.o: /usr/include/minix/dmap.h
|
||||
wait.o: /usr/include/minix/ipc.h
|
||||
wait.o: /usr/include/minix/sys_config.h
|
||||
wait.o: /usr/include/minix/syslib.h
|
||||
wait.o: /usr/include/minix/sysutil.h
|
||||
wait.o: /usr/include/minix/type.h
|
||||
wait.o: /usr/include/signal.h
|
||||
wait.o: /usr/include/stddef.h
|
||||
wait.o: /usr/include/stdlib.h
|
||||
wait.o: /usr/include/string.h
|
||||
wait.o: /usr/include/sys/dir.h
|
||||
wait.o: /usr/include/sys/types.h
|
||||
wait.o: /usr/include/time.h
|
||||
wait.o: /usr/include/unistd.h
|
||||
wait.o: wait.c
|
||||
|
|
@ -6,39 +6,51 @@ i = $u/include
|
|||
s = $i/sys
|
||||
m = $i/minix
|
||||
b = $i/ibm
|
||||
pci_dir = ../../libpci
|
||||
gen_drv_dir = ../../gen_drivers/cyclic_dma
|
||||
|
||||
# programs, flags, etc.
|
||||
CC = exec cc
|
||||
CFLAGS = -I$i
|
||||
LDFLAGS = -i
|
||||
LIBS = -lsys -lsysutil
|
||||
PCI = $(pci_dir)/pci.o $(pci_dir)/pci_table.o
|
||||
|
||||
PROGRAM_NAME = es1371
|
||||
INSTALL_BIN = /usr/sbin/$(PROGRAM_NAME)
|
||||
OBJ = es1371.o AC97.o audio_fw.o pci_helper.o wait.o sample_rate_converter.o
|
||||
|
||||
|
||||
|
||||
# build local binary
|
||||
all: es1371
|
||||
all: $(PROGRAM_NAME)
|
||||
|
||||
|
||||
$(PROGRAM_NAME): $(OBJ)
|
||||
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
|
||||
|
||||
es1371: es1371.o SRC.o codec.o wait.o audio_fw.o $(PCI)
|
||||
$(CC) -o $@ $(LDFLAGS) es1371.o SRC.o codec.o wait.o audio_fw.o $(PCI) $(LIBS)
|
||||
|
||||
audio_fw.o: ../framework/audio_fw.c ../framework/audio_fw.h
|
||||
$(CC) -c ../framework/audio_fw.c
|
||||
|
||||
install: /usr/sbin/es1371
|
||||
/usr/sbin/es1371: es1371
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
|
||||
install: $(INSTALL_BIN)
|
||||
|
||||
|
||||
$(INSTALL_BIN): $(PROGRAM_NAME)
|
||||
install -o root -S 1024k -c $? $@
|
||||
|
||||
$(PCI):
|
||||
cd $(pci_dir) && $(MAKE)
|
||||
|
||||
# clean up local files
|
||||
clean:
|
||||
rm -f *.o *.bak core es1371
|
||||
rm -f $(OBJ) $(PROGRAM_NAME) core
|
||||
|
||||
|
||||
depend:
|
||||
/usr/bin/mkdep "$(CC) -E $(CPPFLAGS)" *.c > .depend
|
||||
|
||||
|
||||
# Include generated dependencies.
|
||||
include .depend
|
||||
|
||||
|
|
|
|||
|
|
@ -1,40 +1,58 @@
|
|||
/* This is the main file of the ES1371 sound driver
|
||||
* There is no main function over here, instead the main function
|
||||
* is located in the generic dma driver. All this driver does is
|
||||
* implement the interface audio/audio_fw.h. All functions having the
|
||||
* prefix 'drv_' are dictated by audio/audio_fw.h. The function
|
||||
* prototypes you see below define a set of private helper functions.
|
||||
* Control over the sample rate converter and the codec is delegated
|
||||
* to SRC.c and codec.c respectively.
|
||||
*
|
||||
/* Best viewed with tabsize 4 */
|
||||
|
||||
/* Original:
|
||||
* November 2005 ES1371 driver (Laurens Bronwasser)
|
||||
*/
|
||||
|
||||
/* Ensoniq ES1371 driver
|
||||
*
|
||||
* aka AudioPCI '97
|
||||
*
|
||||
* This is the main file of the ES1371 sound driver. There is no main function
|
||||
* over here, instead the main function is located in the generic dma driver.
|
||||
* All this driver does is implement the interface audio/audio_fw.h. All
|
||||
* functions having the prefix 'drv_' are dictated by audio/audio_fw.h. The
|
||||
* function prototypes you see below define a set of private helper functions.
|
||||
* Control over the AC97 codec is delegated AC97.c.
|
||||
*
|
||||
* October 2007 ES1371 driver (Pieter Hijma),
|
||||
* based on ES1370 driver which is based on the ES1371 driver
|
||||
* by Laurens Bronwasser
|
||||
*/
|
||||
|
||||
#include <ibm/pci.h>
|
||||
|
||||
#include "../framework/audio_fw.h"
|
||||
#include "es1371.h"
|
||||
#include "codec.h"
|
||||
#include "SRC.h"
|
||||
#include "../AC97.h"
|
||||
#include "AC97.h"
|
||||
#include "sample_rate_converter.h"
|
||||
#include "pci_helper.h"
|
||||
|
||||
|
||||
/* reg(n) will be the device specific addresses */
|
||||
#define reg(n) dev.base + n
|
||||
|
||||
|
||||
/* prototypes of private functions */
|
||||
FORWARD _PROTOTYPE( int detect_hw, (void) );
|
||||
FORWARD _PROTOTYPE( int disable_int, (int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_stereo, (u32_t stereo, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_bits, (u32_t nr_of_bits, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_sample_rate, (u32_t rate, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_sign, (u32_t val, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int get_max_frag_size, (u32_t * val, int *len, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int get_max_frag_size,
|
||||
(u32_t * val, int *len, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_frag_size, (u32_t fragment_size, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int set_int_cnt, (int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int AC97Write, (u16_t wAddr, u16_t wData));
|
||||
FORWARD _PROTOTYPE( int AC97Read, (u16_t wAddr, u16_t *data));
|
||||
FORWARD _PROTOTYPE( void set_nice_volume, (void) );
|
||||
FORWARD _PROTOTYPE( int free_buf, (u32_t *val, int *len, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int get_samples_in_buf,
|
||||
(u32_t *val, int *len, int sub_dev) );
|
||||
FORWARD _PROTOTYPE( int get_set_volume, (struct volume_level *level, int *len,
|
||||
int sub_dev, int flag) );
|
||||
FORWARD _PROTOTYPE( int reset, (int sub_dev) );
|
||||
|
||||
|
||||
DEV_STRUCT dev;
|
||||
u32_t base = 0;
|
||||
aud_sub_dev_conf_t aud_conf[4];
|
||||
|
||||
|
||||
|
|
@ -44,7 +62,7 @@ PUBLIC drv_t drv;
|
|||
|
||||
|
||||
PUBLIC int drv_init(void) {
|
||||
drv.DriverName = "ES1371";
|
||||
drv.DriverName = DRIVER_NAME;
|
||||
drv.NrOfSubDevices = 4;
|
||||
drv.NrOfSpecialFiles = 4;
|
||||
|
||||
|
|
@ -93,47 +111,48 @@ PUBLIC int drv_init(void) {
|
|||
special_file[3].io_ctl = DAC2_CHAN;
|
||||
}
|
||||
|
||||
int drv_init_hw (void)
|
||||
{
|
||||
|
||||
PUBLIC int drv_init_hw (void) {
|
||||
u16_t i, j;
|
||||
u16_t chip_sel_ctrl_reg;
|
||||
|
||||
/* First, detect the hardware */
|
||||
if (detect_hw() != OK) {
|
||||
return EIO;
|
||||
}
|
||||
/*
|
||||
Put HW in a nice state ... all devices enabled except joystick,
|
||||
NMI enables off, clear pending NMIs if any */
|
||||
|
||||
/* PCI command register */
|
||||
pci_attr_w16 (dev.devind, PCI_CR, 0x0105);
|
||||
/* set power management control/status register */
|
||||
pci_attr_w16 (dev.devind, 0xE0, 0x0000);
|
||||
/* PCI command register
|
||||
* enable the SERR# driver, PCI bus mastering and I/O access
|
||||
*/
|
||||
pci_attr_w16 (dev.devind, PCI_CR, SERR_EN|PCI_MASTER|IO_ACCESS);
|
||||
|
||||
pci_outb(reg(CONC_bDEVCTL_OFF), 0x00);
|
||||
pci_outb(reg(CONC_bMISCCTL_OFF), 0x00);
|
||||
pci_outb(reg(CONC_b4SPKR_OFF), 0x00);
|
||||
pci_outb(reg(CONC_bNMIENA_OFF), 0x00);
|
||||
pci_outb(reg(CONC_bNMICTL_OFF), 0x08);
|
||||
pci_outw(reg(CONC_wNMISTAT_OFF), 0x0000);
|
||||
pci_outb(reg(CONC_bSERCTL_OFF), 0x00);
|
||||
/* turn everything off */
|
||||
pci_outl(reg(CHIP_SEL_CTRL), 0x0UL);
|
||||
|
||||
/* clear all cache RAM */
|
||||
for( i = 0; i < 0x10; ++i )
|
||||
{
|
||||
pci_outb(reg(CONC_bMEMPAGE_OFF), i);
|
||||
for( j = 0; j < 0x10; j += 4 )
|
||||
pci_outl (reg(CONC_MEMBASE_OFF) + j, 0UL);
|
||||
/* turn off legacy (legacy control is undocumented) */
|
||||
pci_outl(reg(LEGACY), 0x0UL);
|
||||
pci_outl(reg(LEGACY+4), 0x0UL);
|
||||
|
||||
/* turn off serial interface */
|
||||
pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x0UL);
|
||||
/*pci_outl(reg(SERIAL_INTERFACE_CTRL), 0x3UL);*/
|
||||
|
||||
|
||||
/* clear all the memory */
|
||||
for (i = 0; i < 0x10; ++i) {
|
||||
pci_outb(reg(MEM_PAGE), i);
|
||||
for (j = 0; j < 0x10; j += 4) {
|
||||
pci_outl (reg(MEMORY) + j, 0x0UL);
|
||||
}
|
||||
/* DO NOT SWITCH THE ORDER OF SRCInit and CODECInit function calls!!! */
|
||||
/* The effect is only noticable after a cold reset (reboot) */
|
||||
if (SRCInit(&dev) != OK) {
|
||||
}
|
||||
|
||||
/* Sample Rate Converter initialization */
|
||||
if (src_init(&dev) != OK) {
|
||||
return EIO;
|
||||
}
|
||||
if (CODECInit(&dev) != OK) {
|
||||
if (AC97_init(&dev) != OK) {
|
||||
return EIO;
|
||||
}
|
||||
set_nice_volume(); /* of course we need a nice mixer to do this */
|
||||
|
||||
/* initialize variables for each sub_device */
|
||||
for (i = 0; i < drv.NrOfSubDevices; i++) {
|
||||
|
|
@ -143,7 +162,8 @@ int drv_init_hw (void)
|
|||
aud_conf[i].sample_rate = DEFAULT_RATE;
|
||||
aud_conf[i].nr_of_bits = DEFAULT_NR_OF_BITS;
|
||||
aud_conf[i].sign = DEFAULT_SIGNED;
|
||||
aud_conf[i].fragment_size = sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments;
|
||||
aud_conf[i].fragment_size =
|
||||
sub_dev[i].DmaSize / sub_dev[i].NrOfDmaFragments;
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
|
|
@ -151,8 +171,7 @@ int drv_init_hw (void)
|
|||
|
||||
|
||||
PRIVATE int detect_hw(void) {
|
||||
|
||||
u32_t r;
|
||||
u32_t device;
|
||||
int devind;
|
||||
u16_t v_id, d_id;
|
||||
|
||||
|
|
@ -163,58 +182,53 @@ PRIVATE int detect_hw(void) {
|
|||
|
||||
pci_init();
|
||||
/* get first device and then search through the list */
|
||||
r = pci_first_dev(&devind, &v_id, &d_id);
|
||||
while( r > 0 ) {
|
||||
device = pci_first_dev(&devind, &v_id, &d_id);
|
||||
while( device > 0 ) {
|
||||
/* if we have a match...break */
|
||||
if (v_id == VENDOR_ID && d_id == DEVICE_ID) break;
|
||||
r = pci_next_dev(&devind, &v_id, &d_id);
|
||||
device = pci_next_dev(&devind, &v_id, &d_id);
|
||||
}
|
||||
|
||||
/* did we find anything? */
|
||||
if (v_id != VENDOR_ID || d_id != DEVICE_ID) {
|
||||
return EIO;
|
||||
}
|
||||
/* right here we should reserve the device, but the pci library
|
||||
doesn't support global reservation of devices yet. This would
|
||||
be a problem if more ES1371's were installed on this system. */
|
||||
|
||||
pci_reserve(devind);
|
||||
|
||||
dev.name = pci_dev_name(v_id, d_id);
|
||||
|
||||
/* get base address of our device, ignore least signif. bit
|
||||
this last bit thing could be device dependent, i don't know */
|
||||
dev.base = pci_attr_r32(devind, PCI_BAR) & 0xfffffffe;
|
||||
|
||||
/* get IRQ */
|
||||
dev.irq = pci_attr_r8(devind, PCI_ILR);
|
||||
dev.revision = pci_attr_r8(devind, 0x08);
|
||||
dev.revision = pci_attr_r8(devind, PCI_REV);
|
||||
dev.d_id = d_id;
|
||||
dev.v_id = v_id;
|
||||
dev.devind = devind; /* pci device identifier */
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_reset(void)
|
||||
{
|
||||
/* make a WARM reset */
|
||||
u16_t i;
|
||||
PRIVATE int reset(int chan) {
|
||||
drv_stop(chan);
|
||||
sub_dev[chan].OutOfData = 1;
|
||||
|
||||
/* set SYNC_RES bit */
|
||||
pci_outl(reg(CONC_bDEVCTL_OFF),
|
||||
pci_inl(reg(CONC_bDEVCTL_OFF)) | SYNC_RES_BIT);
|
||||
|
||||
/* got to delay at least 1 usec, try 18 usec */
|
||||
for (i=0; i<100; i++) {
|
||||
pci_inb(reg(0));
|
||||
}
|
||||
/* clear SYNC_RES bit */
|
||||
pci_outl(reg(CONC_bDEVCTL_OFF),
|
||||
pci_inl(reg(CONC_bDEVCTL_OFF)) & ~SYNC_RES_BIT);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_start(int sub_dev, int DmaMode)
|
||||
{
|
||||
int drv_reset() {
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_start(int sub_dev, int DmaMode) {
|
||||
u32_t enable_bit, result = 0;
|
||||
u32_t debug;
|
||||
|
||||
/* Write default values to device in case user failed to configure.
|
||||
If user did configure properly, everything is written twice.
|
||||
|
|
@ -235,19 +249,20 @@ int drv_start(int sub_dev, int DmaMode)
|
|||
drv_resume(sub_dev);
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: enable_bit = ADC1_EN_BIT;break;
|
||||
case DAC1_CHAN: enable_bit = DAC1_EN_BIT;break;
|
||||
case DAC2_CHAN: enable_bit = DAC2_EN_BIT;break;
|
||||
case ADC1_CHAN: enable_bit = ADC1_EN;break;
|
||||
case DAC1_CHAN: enable_bit = DAC1_EN;break;
|
||||
case DAC2_CHAN: enable_bit = DAC2_EN;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* enable interrupts from 'sub device' */
|
||||
drv_reenable_int(sub_dev);
|
||||
|
||||
/* this means GO!!! */
|
||||
pci_outl(reg(CONC_bDEVCTL_OFF),
|
||||
pci_inl(reg(CONC_bDEVCTL_OFF)) | enable_bit);
|
||||
/* this means play!!! */
|
||||
pci_outw(reg(CHIP_SEL_CTRL), pci_inw(reg(CHIP_SEL_CTRL)) | enable_bit);
|
||||
|
||||
aud_conf[sub_dev].busy = 1;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -257,17 +272,18 @@ int drv_stop(int sub_dev)
|
|||
u32_t enable_bit;
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: enable_bit = ADC1_EN_BIT;break;
|
||||
case DAC1_CHAN: enable_bit = DAC1_EN_BIT;break;
|
||||
case DAC2_CHAN: enable_bit = DAC2_EN_BIT;break;
|
||||
case ADC1_CHAN: enable_bit = ADC1_EN;break;
|
||||
case DAC1_CHAN: enable_bit = DAC1_EN;break;
|
||||
case DAC2_CHAN: enable_bit = DAC2_EN;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
/* stop the codec */
|
||||
pci_outl(reg(CONC_bDEVCTL_OFF),
|
||||
pci_inl(reg(CONC_bDEVCTL_OFF)) & ~enable_bit);
|
||||
|
||||
/* stop the specified channel */
|
||||
pci_outw(reg(CHIP_SEL_CTRL),
|
||||
pci_inw(reg(CHIP_SEL_CTRL)) & ~enable_bit);
|
||||
aud_conf[sub_dev].busy = 0;
|
||||
disable_int(sub_dev);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -278,16 +294,34 @@ int drv_io_ctl(int 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 AC97READ: status = AC97Read (*((u16_t *)val), ((u16_t *) val+2));break;
|
||||
case AC97WRITE: status = AC97Write(*((u16_t *)val), *((u16_t *) val+2));break;
|
||||
default: status = EINVAL; break;
|
||||
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 = reset(sub_dev); 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:
|
||||
status = get_set_volume(val, len, sub_dev, 0); break;
|
||||
case MIXIOSETVOLUME:
|
||||
status = get_set_volume(val, len, sub_dev, 1); break;
|
||||
default:
|
||||
status = EINVAL; break;
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
|
@ -312,146 +346,160 @@ int drv_set_dma(u32_t dma, u32_t length, int chan) {
|
|||
u32_t page, frame_count_reg, dma_add_reg;
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: page = CONC_ADCCTL_PAGE;
|
||||
frame_count_reg = CONC_wADCFC_OFF;
|
||||
dma_add_reg = CONC_dADCPADDR_OFF;
|
||||
case ADC1_CHAN: page = ADC_MEM_PAGE;
|
||||
frame_count_reg = ADC_BUFFER_SIZE;
|
||||
dma_add_reg = ADC_PCI_ADDRESS;
|
||||
break;
|
||||
case DAC1_CHAN: page = CONC_SYNCTL_PAGE;
|
||||
frame_count_reg = CONC_wSYNFC_OFF;
|
||||
dma_add_reg = CONC_dSYNPADDR_OFF;
|
||||
case DAC1_CHAN: page = DAC_MEM_PAGE;
|
||||
frame_count_reg = DAC1_BUFFER_SIZE;
|
||||
dma_add_reg = DAC1_PCI_ADDRESS;
|
||||
break;;
|
||||
case DAC2_CHAN: page = CONC_DACCTL_PAGE;
|
||||
frame_count_reg = CONC_wDACFC_OFF;
|
||||
dma_add_reg = CONC_dDACPADDR_OFF;
|
||||
case DAC2_CHAN: page = DAC_MEM_PAGE;
|
||||
frame_count_reg = DAC2_BUFFER_SIZE;
|
||||
dma_add_reg = DAC2_PCI_ADDRESS;
|
||||
break;;
|
||||
default: return EIO;
|
||||
}
|
||||
pci_outb(reg(CONC_bMEMPAGE_OFF), page);
|
||||
pci_outb(reg(MEM_PAGE), page);
|
||||
pci_outl(reg(dma_add_reg), dma);
|
||||
|
||||
/* device expects long word count in stead of bytes */
|
||||
length /= 4;
|
||||
/* device expects length -1 */
|
||||
|
||||
/* It seems that register _CURRENT_COUNT is overwritten, but this is
|
||||
* the way to go. The register frame_count_reg is only longword
|
||||
* addressable.
|
||||
* It expects length -1
|
||||
*/
|
||||
pci_outl(reg(frame_count_reg), (u32_t) (length - 1));
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/* return status of the interrupt summary bit */
|
||||
int drv_int_sum(void) {
|
||||
u32_t int_status;
|
||||
int_status = pci_inl(reg(CONC_bINTSTAT_OFF)) & 0x80000000UL;
|
||||
return int_status;
|
||||
return pci_inl(reg(INTERRUPT_STATUS)) & INTR;
|
||||
}
|
||||
|
||||
|
||||
int drv_int(int sub_dev) {
|
||||
u32_t int_status;
|
||||
char bit;
|
||||
u32_t bit;
|
||||
u32_t debug;
|
||||
|
||||
/* return status of interrupt bit of specified channel*/
|
||||
|
||||
switch (sub_dev) {
|
||||
case DAC1_CHAN: bit = DAC1_INT_STATUS_BIT;break;
|
||||
case DAC2_CHAN: bit = DAC2_INT_STATUS_BIT;break;
|
||||
case ADC1_CHAN: bit = ADC1_INT_STATUS_BIT;break;
|
||||
case DAC1_CHAN: bit = DAC1;break;
|
||||
case DAC2_CHAN: bit = DAC2;break;
|
||||
case ADC1_CHAN: bit = ADC;break;
|
||||
}
|
||||
int_status = pci_inl(reg(CONC_bINTSTAT_OFF)) & bit;
|
||||
|
||||
int_status = pci_inl(reg(INTERRUPT_STATUS)) & bit;
|
||||
|
||||
return int_status;
|
||||
}
|
||||
|
||||
|
||||
int drv_reenable_int(int chan) {
|
||||
u32_t i, int_en_bit;
|
||||
u16_t ser_interface, int_en_bit;
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: int_en_bit = ADC1_INT_EN_BIT;break;
|
||||
case DAC1_CHAN: int_en_bit = DAC1_INT_EN_BIT;break;
|
||||
case DAC2_CHAN: int_en_bit = DAC2_INT_EN_BIT;break;
|
||||
case ADC1_CHAN: int_en_bit = R1_INT_EN; break;
|
||||
case DAC1_CHAN: int_en_bit = P1_INTR_EN; break;
|
||||
case DAC2_CHAN: int_en_bit = P2_INTR_EN; break;
|
||||
default: EINVAL;
|
||||
}
|
||||
|
||||
/* clear and reenable an interrupt */
|
||||
i = pci_inl(reg(CONC_bSERFMT_OFF));
|
||||
pci_outl(reg(CONC_bSERFMT_OFF), i & ~int_en_bit);
|
||||
pci_outl(reg(CONC_bSERFMT_OFF), i | int_en_bit);
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit);
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface | int_en_bit);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_pause(int sub_dev)
|
||||
{
|
||||
int drv_pause(int sub_dev) {
|
||||
u32_t pause_bit;
|
||||
|
||||
disable_int(sub_dev); /* don't send interrupts */
|
||||
|
||||
switch(sub_dev) {
|
||||
case DAC1_CHAN: pause_bit = DAC1_PAUSE_BIT;break;
|
||||
case DAC2_CHAN: pause_bit = DAC2_PAUSE_BIT;break;
|
||||
case DAC1_CHAN: pause_bit = P1_PAUSE;break;
|
||||
case DAC2_CHAN: pause_bit = P2_PAUSE;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* pause */
|
||||
pci_outl(reg(CONC_bSERFMT_OFF),
|
||||
pci_inl(reg(CONC_bSERFMT_OFF)) | pause_bit);
|
||||
pci_outl(reg(SERIAL_INTERFACE_CTRL),
|
||||
pci_inl(reg(SERIAL_INTERFACE_CTRL)) | pause_bit);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int drv_resume(int sub_dev)
|
||||
{
|
||||
int drv_resume(int sub_dev) {
|
||||
u32_t pause_bit = 0;
|
||||
|
||||
/* todo: drv_reenable_int(sub_dev); *//* enable interrupts */
|
||||
drv_reenable_int(sub_dev); /* enable interrupts */
|
||||
|
||||
switch(sub_dev) {
|
||||
case DAC1_CHAN: pause_bit = DAC1_PAUSE_BIT;break;
|
||||
case DAC2_CHAN: pause_bit = DAC2_PAUSE_BIT;break;
|
||||
case DAC1_CHAN: pause_bit = P1_PAUSE;break;
|
||||
case DAC2_CHAN: pause_bit = P2_PAUSE;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* clear pause bit */
|
||||
pci_outl(reg(CONC_bSERFMT_OFF),
|
||||
pci_inl(reg(CONC_bSERFMT_OFF)) & ~pause_bit);
|
||||
pci_outl(reg(SERIAL_INTERFACE_CTRL),
|
||||
pci_inl(reg(SERIAL_INTERFACE_CTRL)) & ~pause_bit);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_bits(u32_t nr_of_bits, int sub_dev) {
|
||||
|
||||
/* set format bits for specified channel. */
|
||||
u32_t size_16_bit, i;
|
||||
u16_t size_16_bit, ser_interface;
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: size_16_bit = ADC1_16_8_BIT;break;
|
||||
case DAC1_CHAN: size_16_bit = DAC1_16_8_BIT;break;
|
||||
case DAC2_CHAN: size_16_bit = DAC2_16_8_BIT;break;
|
||||
case ADC1_CHAN: size_16_bit = R1_S_EB; break;
|
||||
case DAC1_CHAN: size_16_bit = P1_S_EB; break;
|
||||
case DAC2_CHAN: size_16_bit = P2_S_EB; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
i = pci_inb(reg(CONC_bSERFMT_OFF));
|
||||
i &= ~size_16_bit;
|
||||
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
ser_interface &= ~size_16_bit;
|
||||
switch(nr_of_bits) {
|
||||
case 16: i |= size_16_bit;break;
|
||||
case 16: ser_interface |= size_16_bit;break;
|
||||
case 8: break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
pci_outb(reg(CONC_bSERFMT_OFF), i);
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface);
|
||||
aud_conf[sub_dev].nr_of_bits = nr_of_bits;
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_stereo(u32_t stereo, int sub_dev) {
|
||||
|
||||
/* set format bits for specified channel. */
|
||||
u32_t stereo_bit, i;
|
||||
u16_t stereo_bit, ser_interface;
|
||||
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: stereo_bit = ADC1_STEREO_BIT;break;
|
||||
case DAC1_CHAN: stereo_bit = DAC1_STEREO_BIT;break;
|
||||
case DAC2_CHAN: stereo_bit = DAC2_STEREO_BIT;break;
|
||||
case ADC1_CHAN: stereo_bit = R1_S_MB; break;
|
||||
case DAC1_CHAN: stereo_bit = P1_S_MB; break;
|
||||
case DAC2_CHAN: stereo_bit = P2_S_MB; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
i = pci_inb(reg(CONC_bSERFMT_OFF));
|
||||
i &= ~stereo_bit;
|
||||
if( stereo == TRUE ) {
|
||||
i |= stereo_bit;
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
ser_interface &= ~stereo_bit;
|
||||
if (stereo) {
|
||||
ser_interface |= stereo_bit;
|
||||
}
|
||||
pci_outb(reg(CONC_bSERFMT_OFF), i);
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface);
|
||||
aud_conf[sub_dev].stereo = stereo;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -462,28 +510,31 @@ PRIVATE int set_sign(u32_t val, int sub_dev) {
|
|||
|
||||
|
||||
PRIVATE int set_frag_size(u32_t fragment_size, int sub_dev_nr) {
|
||||
if (fragment_size > (sub_dev[sub_dev_nr].DmaSize / sub_dev[sub_dev_nr].NrOfDmaFragments) || fragment_size < sub_dev[sub_dev_nr].MinFragmentSize) {
|
||||
if (fragment_size > (sub_dev[sub_dev_nr].DmaSize /
|
||||
sub_dev[sub_dev_nr].NrOfDmaFragments) ||
|
||||
fragment_size < sub_dev[sub_dev_nr].MinFragmentSize) {
|
||||
return EINVAL;
|
||||
}
|
||||
aud_conf[sub_dev_nr].fragment_size = fragment_size;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int set_sample_rate(u32_t rate, int sub_dev) {
|
||||
u32_t SRCBaseReg;
|
||||
u32_t src_base_reg;
|
||||
|
||||
if (rate > MAX_RATE || rate < MIN_RATE) {
|
||||
return EINVAL;
|
||||
}
|
||||
/* set the sample rate for the specified channel*/
|
||||
switch(sub_dev) {
|
||||
case ADC1_CHAN: SRCBaseReg = SRC_ADC_BASE;break;
|
||||
case DAC1_CHAN: SRCBaseReg = SRC_SYNTH_BASE;break;
|
||||
case DAC2_CHAN: SRCBaseReg = SRC_DAC_BASE;break;
|
||||
case ADC1_CHAN: src_base_reg = SRC_ADC_BASE;break;
|
||||
case DAC1_CHAN: src_base_reg = SRC_SYNTH_BASE;break;
|
||||
case DAC2_CHAN: src_base_reg = SRC_DAC_BASE;break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
SRCSetRate(&dev, SRCBaseReg, rate);
|
||||
src_set_rate(&dev, src_base_reg, rate);
|
||||
aud_conf[sub_dev].sample_rate = rate;
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -493,17 +544,19 @@ PRIVATE int set_int_cnt(int chan) {
|
|||
/* Write interrupt count for specified channel.
|
||||
After <DspFragmentSize> bytes, an interrupt will be generated */
|
||||
|
||||
int sample_count; u16_t int_cnt_reg;
|
||||
int sample_count;
|
||||
u16_t int_cnt_reg;
|
||||
|
||||
if (aud_conf[chan].fragment_size > (sub_dev[chan].DmaSize / sub_dev[chan].NrOfDmaFragments)
|
||||
if (aud_conf[chan].fragment_size >
|
||||
(sub_dev[chan].DmaSize / sub_dev[chan].NrOfDmaFragments)
|
||||
|| aud_conf[chan].fragment_size < sub_dev[chan].MinFragmentSize) {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: int_cnt_reg = CONC_wADCIC_OFF;break;
|
||||
case DAC1_CHAN: int_cnt_reg = CONC_wSYNIC_OFF;break;
|
||||
case DAC2_CHAN: int_cnt_reg = CONC_wDACIC_OFF;break;
|
||||
case ADC1_CHAN: int_cnt_reg = ADC_SAMP_CT; break;
|
||||
case DAC1_CHAN: int_cnt_reg = DAC1_SAMP_CT; break;
|
||||
case DAC2_CHAN: int_cnt_reg = DAC2_SAMP_CT; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -516,73 +569,89 @@ PRIVATE int set_int_cnt(int chan) {
|
|||
case 8: break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* set the sample count - 1 for the specified channel. */
|
||||
pci_outw(reg(int_cnt_reg), sample_count - 1);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int get_max_frag_size(u32_t * val, int * len, int sub_dev_nr) {
|
||||
*len = sizeof(*val);
|
||||
*val = (sub_dev[sub_dev_nr].DmaSize / sub_dev[sub_dev_nr].NrOfDmaFragments);
|
||||
*val = (sub_dev[sub_dev_nr].DmaSize /
|
||||
sub_dev[sub_dev_nr].NrOfDmaFragments);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int disable_int(int chan) {
|
||||
u32_t i, int_en_bit;
|
||||
u16_t ser_interface, int_en_bit;
|
||||
|
||||
switch(chan) {
|
||||
case ADC1_CHAN: int_en_bit = ADC1_INT_EN_BIT;break;
|
||||
case DAC1_CHAN: int_en_bit = DAC1_INT_EN_BIT;break;
|
||||
case DAC2_CHAN: int_en_bit = DAC2_INT_EN_BIT;break;
|
||||
case ADC1_CHAN: int_en_bit = R1_INT_EN; break;
|
||||
case DAC1_CHAN: int_en_bit = P1_INTR_EN; break;
|
||||
case DAC2_CHAN: int_en_bit = P2_INTR_EN; break;
|
||||
default: EINVAL;
|
||||
}
|
||||
/* clear the interrupt */
|
||||
i = pci_inl(reg(CONC_bSERFMT_OFF));
|
||||
pci_outl(reg(CONC_bSERFMT_OFF), i & ~int_en_bit);
|
||||
ser_interface = pci_inw(reg(SERIAL_INTERFACE_CTRL));
|
||||
pci_outw(reg(SERIAL_INTERFACE_CTRL), ser_interface & ~int_en_bit);
|
||||
}
|
||||
|
||||
|
||||
PRIVATE void set_nice_volume(void) {
|
||||
/* goofy code to set the DAC1 channel to an audibe volume
|
||||
to be able to test it without using the mixer */
|
||||
PRIVATE int get_samples_in_buf (u32_t *samples_in_buf, int *len, int chan) {
|
||||
u16_t samp_ct_reg;
|
||||
u16_t curr_samp_ct_reg;
|
||||
u16_t samp_ct; /* nr of samples - 1 that will be played back */
|
||||
u16_t curr_samp_ct; /* counts back from SAMP_CT till 0 */
|
||||
|
||||
AC97Write(AC97_PCM_OUT_VOLUME, 0x0808);/* the higher, the softer */
|
||||
AC97Write(AC97_MASTER_VOLUME, 0x0101);
|
||||
AC97Write(0x38, 0); /* not crucial */
|
||||
*len = sizeof(*samples_in_buf);
|
||||
|
||||
AC97Write(AC97_LINE_IN_VOLUME, 0x0303);
|
||||
AC97Write(AC97_MIC_VOLUME, 0x0303);
|
||||
switch(chan) {
|
||||
case ADC1_CHAN:
|
||||
curr_samp_ct_reg = ADC_CURR_SAMP_CT;
|
||||
samp_ct_reg = ADC_SAMP_CT; break;
|
||||
case DAC1_CHAN:
|
||||
curr_samp_ct_reg = DAC1_CURR_SAMP_CT;
|
||||
samp_ct_reg = DAC1_SAMP_CT; break;
|
||||
case DAC2_CHAN:
|
||||
curr_samp_ct_reg = DAC2_CURR_SAMP_CT;
|
||||
samp_ct_reg = DAC2_SAMP_CT; break;
|
||||
default: return EINVAL;
|
||||
}
|
||||
|
||||
/* mute record gain */
|
||||
AC97Write(AC97_RECORD_GAIN_VOLUME, 0xFFFF);
|
||||
samp_ct = pci_inw(reg(samp_ct_reg));
|
||||
curr_samp_ct = pci_inw(reg(curr_samp_ct_reg));
|
||||
|
||||
/* Also, to be able test recording without mixer:
|
||||
select ONE channel as input below. */
|
||||
*samples_in_buf = (u32_t) (sub_dev[chan].BufLength * 8192) +
|
||||
curr_samp_ct;
|
||||
|
||||
/* select LINE IN */
|
||||
/*CodecWrite(AC97_RECORD_SELECT, 0x0404);*/
|
||||
|
||||
/* select MIC */
|
||||
AC97Write(AC97_RECORD_SELECT, 0x0000);
|
||||
|
||||
/* unmute record gain */
|
||||
AC97Write(AC97_RECORD_GAIN_VOLUME, 0x0000);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/* The following two functions can be used by the mixer to
|
||||
control and read volume settings. */
|
||||
PRIVATE int AC97Write (u16_t addr, u16_t data)
|
||||
{
|
||||
/* todo: only allow volume control,
|
||||
no serial data or dev ctl please*/
|
||||
return CodecWriteUnsynced(&dev, addr, data);
|
||||
/* returns 1 if there are free buffers */
|
||||
PRIVATE int free_buf (u32_t *val, int *len, int sub_dev_nr) {
|
||||
*len = sizeof(*val);
|
||||
if (sub_dev[sub_dev_nr].BufLength ==
|
||||
sub_dev[sub_dev_nr].NrOfExtraBuffers) {
|
||||
*val = 0;
|
||||
}
|
||||
else {
|
||||
*val = 1;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int AC97Read (u16_t addr, u16_t *data)
|
||||
{
|
||||
return CodecReadUnsynced(&dev, addr, data);
|
||||
PRIVATE int get_set_volume(struct volume_level *level, int *len, int sub_dev,
|
||||
int flag) {
|
||||
*len = sizeof(struct volume_level);
|
||||
if (sub_dev == MIXER) {
|
||||
return AC97_get_set_volume(level, flag);
|
||||
}
|
||||
else {
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,108 +1,97 @@
|
|||
#ifndef ES1371_H
|
||||
#define ES1371_H
|
||||
/* best viewed with tabsize=4 */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "../../drivers.h"
|
||||
#include "../../libpci/pci.h"
|
||||
#include <sys/ioc_sound.h>
|
||||
#include <minix/sound.h>
|
||||
|
||||
|
||||
/* set your vendor and device ID's here */
|
||||
#define VENDOR_ID 0x1274
|
||||
#define DEVICE_ID 0x1371
|
||||
#define DRIVER_NAME "ES1371"
|
||||
|
||||
|
||||
/* channels or subdevices */
|
||||
#define DAC1_CHAN 0
|
||||
#define ADC1_CHAN 1
|
||||
#define MIXER 2
|
||||
#define DAC2_CHAN 3
|
||||
|
||||
/* set your vendor and device ID's here */
|
||||
#define VENDOR_ID 0x1274
|
||||
#define DEVICE_ID 0x1371
|
||||
|
||||
/* Concert97 direct register offset defines */
|
||||
#define CONC_bDEVCTL_OFF 0x00 /* Device control/enable */
|
||||
#define CONC_bMISCCTL_OFF 0x01 /* Miscellaneous control */
|
||||
#define CONC_bGPIO_OFF 0x02 /* General purpose I/O control */
|
||||
#define CONC_bJOYCTL_OFF 0x03 /* Joystick control (decode) */
|
||||
#define CONC_bINTSTAT_OFF 0x04 /* Device interrupt status */
|
||||
#define CONC_bCODECSTAT_OFF 0x05 /* CODEC interface status */
|
||||
#define CONC_bINTSUMM_OFF 0x07 /* Interrupt summary status */
|
||||
#define CONC_b4SPKR_OFF 0x07 /* Also 4 speaker config reg */
|
||||
#define CONC_bSPDIF_ROUTE_OFF 0x07 /* Also S/PDIF route control reg */
|
||||
#define CONC_bUARTDATA_OFF 0x08 /* UART data R/W - read clears RX int */
|
||||
#define CONC_bUARTCSTAT_OFF 0x09 /* UART control and status */
|
||||
#define CONC_bUARTTEST_OFF 0x0a /* UART test control reg */
|
||||
#define CONC_bMEMPAGE_OFF 0x0c /* Memory page select */
|
||||
#define CONC_dSRCIO_OFF 0x10 /* I/O ctl/stat/data for SRC RAM */
|
||||
#define CONC_dCODECCTL_OFF 0x14 /* CODEC control - u32_t read/write */
|
||||
#define CONC_wNMISTAT_OFF 0x18 /* Legacy NMI status */
|
||||
#define CONC_bNMIENA_OFF 0x1a /* Legacy NMI enable */
|
||||
#define CONC_bNMICTL_OFF 0x1b /* Legacy control */
|
||||
#define CONC_bSERFMT_OFF 0x20 /* Serial device format */
|
||||
#define CONC_bSERCTL_OFF 0x21 /* Serial device control */
|
||||
#define CONC_bSKIPC_OFF 0x22 /* DAC skip count reg */
|
||||
#define CONC_wSYNIC_OFF 0x24 /* Synth int count in sample frames */
|
||||
#define CONC_wSYNCIC_OFF 0x26 /* Synth current int count */
|
||||
#define CONC_wDACIC_OFF 0x28 /* DAC int count in sample frames */
|
||||
#define CONC_wDACCIC_OFF 0x2a /* DAC current int count */
|
||||
#define CONC_wADCIC_OFF 0x2c /* ADC int count in sample frames */
|
||||
#define CONC_wADCCIC_OFF 0x2e /* ADC current int count */
|
||||
#define CONC_MEMBASE_OFF 0x30 /* Memory window base - 16 byte window */
|
||||
|
||||
/* Concert memory page-banked register offset defines */
|
||||
#define CONC_dSYNPADDR_OFF 0x30 /* Synth host frame PCI phys addr */
|
||||
#define CONC_wSYNFC_OFF 0x34 /* Synth host frame count in u32_t'S */
|
||||
#define CONC_wSYNCFC_OFF 0x36 /* Synth host current frame count */
|
||||
#define CONC_dDACPADDR_OFF 0x38 /* DAC host frame PCI phys addr */
|
||||
#define CONC_wDACFC_OFF 0x3c /* DAC host frame count in u32_t'S */
|
||||
#define CONC_wDACCFC_OFF 0x3e /* DAC host current frame count */
|
||||
#define CONC_dADCPADDR_OFF 0x30 /* ADC host frame PCI phys addr */
|
||||
#define CONC_wADCFC_OFF 0x34 /* ADC host frame count in u32_t'S */
|
||||
#define CONC_wADCCFC_OFF 0x36 /* ADC host current frame count */
|
||||
|
||||
/* memory page number defines */
|
||||
#define CONC_SYNRAM_PAGE 0x00 /* Synth host/serial I/F RAM */
|
||||
#define CONC_DACRAM_PAGE 0x04 /* DAC host/serial I/F RAM */
|
||||
#define CONC_ADCRAM_PAGE 0x08 /* ADC host/serial I/F RAM */
|
||||
#define CONC_SYNCTL_PAGE 0x0c /* Page bank for synth host control */
|
||||
#define CONC_DACCTL_PAGE 0x0c /* Page bank for DAC host control */
|
||||
#define CONC_ADCCTL_PAGE 0x0d /* Page bank for ADC host control */
|
||||
#define CONC_FIFO0_PAGE 0x0e /* page 0 of UART "FIFO" (rx stash) */
|
||||
#define CONC_FIFO1_PAGE 0x0f /* page 1 of UART "FIFO" (rx stash) */
|
||||
/* PCI command register defines */
|
||||
#define SERR_EN 0x0100
|
||||
#define PCI_MASTER 0x0004
|
||||
#define IO_ACCESS 0x0001
|
||||
|
||||
|
||||
/* Interrupt/Chip Select Control */
|
||||
#define CHIP_SEL_CTRL 0x00
|
||||
#define ADC1_EN 0x0010
|
||||
#define DAC1_EN 0x0040
|
||||
#define DAC2_EN 0x0020
|
||||
#define CCB_INTRM 0x0400
|
||||
|
||||
/* bits for Interrupt/Chip Select Control Register (offset 0x00)*/
|
||||
#define DAC1_EN_BIT bit(6)
|
||||
#define DAC2_EN_BIT bit(5)
|
||||
#define ADC1_EN_BIT bit(4)
|
||||
#define SYNC_RES_BIT bit(14)
|
||||
|
||||
/* bits for Interrupt/Chip Select Status Register (offset 0x04)*/
|
||||
#define DAC1_INT_STATUS_BIT bit(2)
|
||||
#define DAC2_INT_STATUS_BIT bit(1)
|
||||
#define ADC1_INT_STATUS_BIT bit(0)
|
||||
/* Interrupt/Chip Select Status */
|
||||
#define INTERRUPT_STATUS 0x04
|
||||
#define ADC 0x0001
|
||||
#define DAC2 0x0002
|
||||
#define DAC1 0x0004
|
||||
#define INTR 0x80000000
|
||||
|
||||
/* some bits for Serial Interface Control Register (CONC_bSERFMT_OFF 20H) */
|
||||
#define DAC1_STEREO_BIT bit(0) /* stereo or mono format */
|
||||
#define DAC1_16_8_BIT bit(1) /* 16 or 8 bit format */
|
||||
#define DAC2_STEREO_BIT bit(2)
|
||||
#define DAC2_16_8_BIT bit(3)
|
||||
#define ADC1_STEREO_BIT bit(4)
|
||||
#define ADC1_16_8_BIT bit(5)
|
||||
#define DAC1_INT_EN_BIT bit(8) /* interupt enable bits */
|
||||
#define DAC2_INT_EN_BIT bit(9)
|
||||
#define ADC1_INT_EN_BIT bit(10)
|
||||
#define DAC1_PAUSE_BIT bit(11)
|
||||
#define DAC2_PAUSE_BIT bit(12)
|
||||
|
||||
/* Some return values */
|
||||
#define SRC_SUCCESS 0
|
||||
#define CONC_SUCCESS 0
|
||||
/* Timeout waiting for: */
|
||||
#define SRC_ERR_NOT_BUSY_TIMEOUT -1 /* SRC not busy */
|
||||
#define CONC_ERR_NO_PCI_BIOS -2
|
||||
#define CONC_ERR_DEVICE_NOT_FOUND -3
|
||||
#define CONC_ERR_SPDIF_NOT_AVAIL -4
|
||||
#define CONC_ERR_SPDIF_ROUTING_NOT_AVAIL -5
|
||||
#define CONC_ERR_4SPEAKER_NOT_AVAIL -6
|
||||
#define CONC_ERR_ECHO_NOT_AVAIL -7
|
||||
/* Sample Rate Converter */
|
||||
#define SAMPLE_RATE_CONV 0x10
|
||||
|
||||
|
||||
/* CODEC Write/Read register */
|
||||
#define CODEC_WRITE 0x14
|
||||
#define CODEC_READ 0x14
|
||||
|
||||
|
||||
/* Legacy address */
|
||||
#define LEGACY 0x18
|
||||
|
||||
|
||||
/* Memory related defines */
|
||||
#define MEM_PAGE 0x0c
|
||||
#define ADC_MEM_PAGE 0x0d
|
||||
#define DAC_MEM_PAGE 0x0c /* for DAC1 and DAC2 */
|
||||
|
||||
#define MEMORY 0x30
|
||||
#define ADC_BUFFER_SIZE 0x34
|
||||
#define DAC1_BUFFER_SIZE 0x34
|
||||
#define DAC2_BUFFER_SIZE 0X3c
|
||||
#define ADC_PCI_ADDRESS 0x30
|
||||
#define DAC1_PCI_ADDRESS 0x30
|
||||
#define DAC2_PCI_ADDRESS 0x38
|
||||
|
||||
|
||||
/* Serial Interface Control */
|
||||
#define SERIAL_INTERFACE_CTRL 0x20
|
||||
#define P1_S_MB 0x0001 /* DAC1 Stereo/Mono bit */
|
||||
#define P1_S_EB 0x0002 /* DAC1 Sixteen/Eight bit */
|
||||
#define P2_S_MB 0x0004 /* DAC2 Stereo/Mono bit */
|
||||
#define P2_S_EB 0x0008 /* DAC2 Sixteen/Eight bit */
|
||||
#define R1_S_MB 0x0010 /* ADC Stereo/Mono bit */
|
||||
#define R1_S_EB 0x0020 /* ADC Sixteen/Eight bit */
|
||||
#define P1_INTR_EN 0x0100
|
||||
#define P2_INTR_EN 0x0200
|
||||
#define R1_INT_EN 0x0400
|
||||
#define P1_PAUSE 0x0800
|
||||
#define P2_PAUSE 0x1000
|
||||
|
||||
|
||||
#define DAC1_SAMP_CT 0x24
|
||||
#define DAC1_CURR_SAMP_CT 0x26
|
||||
#define DAC2_SAMP_CT 0x28
|
||||
#define DAC2_CURR_SAMP_CT 0x2a
|
||||
#define ADC_SAMP_CT 0x2c
|
||||
#define ADC_CURR_SAMP_CT 0x2e
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32_t stereo;
|
||||
|
|
@ -115,7 +104,7 @@ typedef struct {
|
|||
|
||||
/* Some defaults for the aud_sub_dev_conf_t*/
|
||||
#define DEFAULT_RATE 44100 /* Sample rate */
|
||||
#define DEFAULT_NR_OF_BITS 16 /* Nr. of bits per sample per channel*/
|
||||
#define DEFAULT_NR_OF_BITS 16 /* Nr. of bits per sample per chan */
|
||||
#define DEFAULT_SIGNED 0 /* 0 = unsigned, 1 = signed */
|
||||
#define DEFAULT_STEREO 1 /* 0 = mono, 1 = stereo */
|
||||
#define MAX_RATE 44100 /* Max sample speed in KHz */
|
||||
|
|
@ -126,13 +115,14 @@ typedef struct DEVSTRUCT {
|
|||
char* name;
|
||||
u16_t v_id; /* vendor id */
|
||||
u16_t d_id; /* device id */
|
||||
u32_t devind; /* minix pci device id, for pci configuration space */
|
||||
u32_t devind; /* minix pci device id, for
|
||||
* pci configuration space */
|
||||
u32_t base; /* changed to 32 bits */
|
||||
char irq;
|
||||
char revision; /* version of the device */
|
||||
} DEV_STRUCT;
|
||||
|
||||
#define bit(n) 1UL << n
|
||||
|
||||
#define SRC_ERR_NOT_BUSY_TIMEOUT -1 /* SRC not busy */
|
||||
#define SRC_SUCCESS 0
|
||||
|
||||
#endif /* ES1371_H */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
#include "../../drivers.h"
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include "../../libpci/pci.h"
|
||||
#include "pci_helper.h"
|
||||
|
||||
|
||||
int WaitBitd (int paddr, int bitno, int state, long tmout)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#ifndef WAIT_H
|
||||
#define WAIT_H
|
||||
/* WAIT.H
|
||||
// General purpose waiting routines
|
||||
|
||||
|
|
@ -8,3 +10,4 @@ int WaitBitw (int paddr, int bitno, int state, long tmout);
|
|||
int WaitBitd (int paddr, int bitno, int state, long tmout);
|
||||
int MemWaitw (unsigned int volatile *gaddr, int bitno, int state, long tmout);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
/* This file contains a standard driver for audio devices.
|
||||
/* Best viewed with tabsize 4
|
||||
*
|
||||
* This file contains a standard driver for audio devices.
|
||||
* It supports double dma buffering and can be configured to use
|
||||
* extra buffer space beside the dma buffer.
|
||||
* This driver also support sub devices, which can be independently
|
||||
|
|
@ -6,17 +8,17 @@
|
|||
*
|
||||
* The driver supports the following operations:
|
||||
*
|
||||
* m_type DEVICE PROC_NR COUNT POSITION ADRRESS
|
||||
* m_type DEVICE IO_ENDPT COUNT POSITION ADRRESS
|
||||
* -----------------------------------------------------------------
|
||||
* | DEV_OPEN | device | proc nr | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_CLOSE | device | proc nr | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_READ | device | proc nr | bytes | | buf ptr |
|
||||
* | DEV_READ_S | device | proc nr | bytes | | buf ptr |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_WRITE | device | proc nr | bytes | | buf ptr |
|
||||
* | DEV_WRITE_S | device | proc nr | bytes | | buf ptr |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_IOCTL | device | proc nr |func code| | buf ptr |
|
||||
* | DEV_IOCTL_S | device | proc nr |func code| | buf ptr |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
* | DEV_STATUS | | | | | |
|
||||
* |-------------+---------+---------+---------+---------+---------|
|
||||
|
|
@ -29,14 +31,20 @@
|
|||
*
|
||||
* main: main entry when driver is brought up
|
||||
*
|
||||
* February 2006 Updated audio framework, changed driver-framework relation (Peter Boonstoppel)
|
||||
* October 2007 Updated audio framework to work with mplayer, added
|
||||
* savecopies (Pieter Hijma)
|
||||
* February 2006 Updated audio framework,
|
||||
* changed driver-framework relation (Peter Boonstoppel)
|
||||
* November 2005 Created generic DMA driver framework (Laurens Bronwasser)
|
||||
* August 24 2005 Ported audio driver to user space (only audio playback) (Peter Boonstoppel)
|
||||
* August 24 2005 Ported audio driver to user space
|
||||
* (only audio playback) (Peter Boonstoppel)
|
||||
* May 20 1995 SB16 Driver: Michel R. Prevenier
|
||||
*/
|
||||
|
||||
|
||||
#include "audio_fw.h"
|
||||
|
||||
|
||||
FORWARD _PROTOTYPE( int msg_open, (int minor_dev_nr) );
|
||||
FORWARD _PROTOTYPE( int msg_close, (int minor_dev_nr) );
|
||||
FORWARD _PROTOTYPE( int msg_ioctl, (message *m_ptr) );
|
||||
|
|
@ -79,44 +87,38 @@ PUBLIC void main(void)
|
|||
while(1) {
|
||||
receive(ANY, &mess);
|
||||
caller = mess.m_source;
|
||||
proc_nr = mess.PROC_NR;
|
||||
proc_nr = mess.IO_ENDPT;
|
||||
|
||||
|
||||
/* Now carry out the work. */
|
||||
switch(mess.m_type) {
|
||||
case DEV_OPEN: /* open the special file ( = parameter) */
|
||||
r = msg_open(mess.DEVICE);break;
|
||||
|
||||
case DEV_CLOSE: /* close the special file ( = parameter) */
|
||||
r = msg_close(mess.DEVICE); break;
|
||||
|
||||
case DEV_IOCTL:
|
||||
case DEV_IOCTL_S:
|
||||
r = msg_ioctl(&mess); break;
|
||||
|
||||
case DEV_READ:
|
||||
case DEV_READ_S:
|
||||
msg_read(&mess); continue; /* don't reply */
|
||||
|
||||
case DEV_WRITE:
|
||||
case DEV_WRITE_S:
|
||||
msg_write(&mess); continue; /* don't reply */
|
||||
|
||||
case DEV_STATUS:
|
||||
msg_status(&mess);continue; /* don't reply */
|
||||
|
||||
case HARD_INT:
|
||||
msg_hardware();continue; /* don't reply */
|
||||
|
||||
case SYS_SIG:
|
||||
msg_sig_stop(); continue; /* don't reply */
|
||||
|
||||
default:
|
||||
r = EINVAL; dprint("%s: %d uncaught msg!\n", mess.m_type ,drv.DriverName);
|
||||
r = EINVAL;
|
||||
dprint("%s: %d uncaught msg!\n", drv.DriverName, mess.m_type);
|
||||
break;
|
||||
}
|
||||
/* Finally, prepare and send the reply message. */
|
||||
reply(TASK_REPLY, caller, proc_nr, r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
PRIVATE int init_driver(void) {
|
||||
u32_t i; char irq;
|
||||
static int executed = 0;
|
||||
|
|
@ -182,11 +184,13 @@ PRIVATE int msg_open (int minor_dev_nr) {
|
|||
io_ctl = special_file_ptr->io_ctl;
|
||||
|
||||
if (read_chan==NO_CHANNEL && write_chan==NO_CHANNEL && io_ctl==NO_CHANNEL) {
|
||||
error("%s: No channel specified for minor device!\n", drv.DriverName, minor_dev_nr);
|
||||
error("%s: No channel specified for minor device!\n",
|
||||
drv.DriverName, minor_dev_nr);
|
||||
return EIO;
|
||||
}
|
||||
if (read_chan == write_chan && read_chan != NO_CHANNEL) {
|
||||
error("%s: Read and write channels are equal!\n", drv.DriverName,minor_dev_nr);
|
||||
error("%s: Read and write channels are equal!\n",
|
||||
drv.DriverName, minor_dev_nr);
|
||||
return EIO;
|
||||
}
|
||||
/* init driver */
|
||||
|
|
@ -201,10 +205,10 @@ PRIVATE int msg_open (int minor_dev_nr) {
|
|||
/* open the sub devices specified in the interface header file */
|
||||
if (write_chan != NO_CHANNEL) {
|
||||
/* open sub device for writing */
|
||||
if (open_sub_dev(write_chan, DEV_WRITE) != OK) return EIO;
|
||||
if (open_sub_dev(write_chan, DEV_WRITE_S) != OK) return EIO;
|
||||
}
|
||||
if (read_chan != NO_CHANNEL) {
|
||||
if (open_sub_dev(read_chan, DEV_READ) != OK) return EIO;
|
||||
if (open_sub_dev(read_chan, DEV_READ_S) != OK) return EIO;
|
||||
}
|
||||
if (read_chan == io_ctl || write_chan == io_ctl) {
|
||||
/* io_ctl is already opened because it's the same as read or write */
|
||||
|
|
@ -224,7 +228,8 @@ PRIVATE int open_sub_dev(int sub_dev_nr, int dma_mode) {
|
|||
|
||||
/* Only one open at a time per sub device */
|
||||
if (sub_dev_ptr->Opened) {
|
||||
error("%s: Sub device %d is already opened\n", drv.DriverName, sub_dev_nr);
|
||||
error("%s: Sub device %d is already opened\n",
|
||||
drv.DriverName, sub_dev_nr);
|
||||
return EBUSY;
|
||||
}
|
||||
if (sub_dev_ptr->DmaBusy) {
|
||||
|
|
@ -280,7 +285,7 @@ PRIVATE int msg_close(int minor_dev_nr) {
|
|||
/* io_ctl is already closed because it's the same as read or write */
|
||||
return r; /* we're done */
|
||||
}
|
||||
/* Ioctl differs from read/write channels... */
|
||||
/* ioctl differs from read/write channels... */
|
||||
if (io_ctl != NO_CHANNEL) {
|
||||
if (close_sub_dev(io_ctl) != OK) r = EIO; /* ...close it explicitly */
|
||||
}
|
||||
|
|
@ -291,8 +296,7 @@ PRIVATE int msg_close(int minor_dev_nr) {
|
|||
PRIVATE int close_sub_dev(int sub_dev_nr) {
|
||||
sub_dev_t *sub_dev_ptr;
|
||||
sub_dev_ptr = &sub_dev[sub_dev_nr];
|
||||
|
||||
if (sub_dev_ptr->DmaMode == DEV_WRITE && !sub_dev_ptr->OutOfData) {
|
||||
if (sub_dev_ptr->DmaMode == DEV_WRITE_S && !sub_dev_ptr->OutOfData) {
|
||||
/* do nothing, still data in buffers that has to be transferred */
|
||||
sub_dev_ptr->Opened = FALSE; /* keep DMA busy */
|
||||
return OK;
|
||||
|
|
@ -340,25 +344,37 @@ PRIVATE int msg_ioctl(message *m_ptr)
|
|||
return EIO;
|
||||
}
|
||||
|
||||
|
||||
/* this is a hack...todo: may we intercept reset calls? */
|
||||
/*
|
||||
if(m_ptr->REQUEST == DSPIORESET) {
|
||||
device_available = FALSE;
|
||||
}
|
||||
/* this is confusing, _IOC_OUT bit means that there is incoming data */
|
||||
if (m_ptr->REQUEST & _IOC_OUT) { /* if there is data for us, copy it */
|
||||
*/
|
||||
|
||||
|
||||
if (m_ptr->REQUEST & _IOC_IN) { /* if there is data for us, copy it */
|
||||
len = io_ctl_length(m_ptr->REQUEST);
|
||||
sys_vircopy(m_ptr->PROC_NR, D,
|
||||
(vir_bytes)m_ptr->ADDRESS, SELF, D,
|
||||
(vir_bytes)io_ctl_buf, len);
|
||||
|
||||
if(sys_safecopyfrom(m_ptr->IO_ENDPT,
|
||||
(vir_bytes)m_ptr->ADDRESS, 0,
|
||||
(vir_bytes)io_ctl_buf, len, D) != OK) {
|
||||
printf("%s:%d: safecopyfrom failed\n", __FILE__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
/* all ioctl's are passed to the device specific part of the driver */
|
||||
status = drv_io_ctl(m_ptr->REQUEST, (void *)io_ctl_buf, &len, chan);
|
||||
|
||||
/* _IOC_IN bit -> user expects data */
|
||||
if (status == OK && m_ptr->REQUEST & _IOC_IN) {
|
||||
/* _IOC_OUT bit -> user expects data */
|
||||
if (status == OK && m_ptr->REQUEST & _IOC_OUT) {
|
||||
/* copy result back to user */
|
||||
sys_vircopy(SELF, D, (vir_bytes)io_ctl_buf, m_ptr->PROC_NR, D, (vir_bytes)m_ptr->ADDRESS, len);
|
||||
|
||||
if(sys_safecopyto(m_ptr->IO_ENDPT, (vir_bytes)m_ptr->ADDRESS, 0,
|
||||
(vir_bytes)io_ctl_buf, len, D) != OK) {
|
||||
printf("%s:%d: safecopyto failed\n", __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
|
@ -376,7 +392,7 @@ PRIVATE void msg_write(message *m_ptr)
|
|||
|
||||
if (chan == NO_CHANNEL) {
|
||||
error("%s: No write channel specified!\n", drv.DriverName);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
|
||||
return;
|
||||
}
|
||||
/* get pointer to sub device data */
|
||||
|
|
@ -390,20 +406,20 @@ PRIVATE void msg_write(message *m_ptr)
|
|||
}
|
||||
if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
|
||||
error("Fragment size does not match user's buffer length\n");
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINVAL);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
|
||||
return;
|
||||
}
|
||||
/* if we are busy with something else than writing, return EBUSY */
|
||||
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE) {
|
||||
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_WRITE_S) {
|
||||
error("Already busy with something else then writing\n");
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EBUSY);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
|
||||
return;
|
||||
}
|
||||
/* unblock the FileSystem, but keep user process blocked until REVIVE*/
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, SUSPEND);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);
|
||||
sub_dev_ptr->RevivePending = TRUE;
|
||||
sub_dev_ptr->ReviveProcNr = m_ptr->PROC_NR;
|
||||
sub_dev_ptr->UserBuf = m_ptr->ADDRESS;
|
||||
sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
|
||||
sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
|
||||
sub_dev_ptr->NotifyProcNr = m_ptr->m_source;
|
||||
|
||||
data_from_user(sub_dev_ptr);
|
||||
|
|
@ -411,7 +427,7 @@ PRIVATE void msg_write(message *m_ptr)
|
|||
if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */
|
||||
dprint("starting audio device\n");
|
||||
get_started(sub_dev_ptr);
|
||||
sub_dev_ptr->DmaMode = DEV_WRITE; /* Dma mode is writing */
|
||||
sub_dev_ptr->DmaMode = DEV_WRITE_S; /* Dma mode is writing */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -428,7 +444,7 @@ PRIVATE void msg_read(message *m_ptr)
|
|||
|
||||
if (chan == NO_CHANNEL) {
|
||||
error("%s: No read channel specified!\n", drv.DriverName);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
|
||||
return;
|
||||
}
|
||||
/* get pointer to sub device data */
|
||||
|
|
@ -437,30 +453,30 @@ PRIVATE void msg_read(message *m_ptr)
|
|||
if (!sub_dev_ptr->DmaBusy) { /* get fragment size on first read */
|
||||
if (drv_get_frag_size(&(sub_dev_ptr->FragSize), sub_dev_ptr->Nr) != OK){
|
||||
error("%s: Could not retrieve fragment size!\n", drv.DriverName);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EIO);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EIO);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(m_ptr->COUNT != sub_dev_ptr->FragSize) {
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EINVAL);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EINVAL);
|
||||
error("fragment size does not match message size\n");
|
||||
return;
|
||||
}
|
||||
/* if we are busy with something else than reading, reply EBUSY */
|
||||
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ) {
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EBUSY);
|
||||
if(sub_dev_ptr->DmaBusy && sub_dev_ptr->DmaMode != DEV_READ_S) {
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, EBUSY);
|
||||
return;
|
||||
}
|
||||
/* unblock the FileSystem, but keep user process blocked until REVIVE*/
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, SUSPEND);
|
||||
reply(TASK_REPLY, m_ptr->m_source, m_ptr->IO_ENDPT, SUSPEND);
|
||||
sub_dev_ptr->RevivePending = TRUE;
|
||||
sub_dev_ptr->ReviveProcNr = m_ptr->PROC_NR;
|
||||
sub_dev_ptr->UserBuf = m_ptr->ADDRESS;
|
||||
sub_dev_ptr->ReviveProcNr = m_ptr->IO_ENDPT;
|
||||
sub_dev_ptr->ReviveGrant = (cp_grant_id_t) m_ptr->ADDRESS;
|
||||
sub_dev_ptr->NotifyProcNr = m_ptr->m_source;
|
||||
|
||||
if(!sub_dev_ptr->DmaBusy) { /* Dma tranfer not yet started */
|
||||
get_started(sub_dev_ptr);
|
||||
sub_dev_ptr->DmaMode = DEV_READ; /* Dma mode is reading */
|
||||
sub_dev_ptr->DmaMode = DEV_READ_S; /* Dma mode is reading */
|
||||
return; /* no need to get data from DMA buffer at this point */
|
||||
}
|
||||
/* check if data is available and possibly fill user's buffer */
|
||||
|
|
@ -482,8 +498,8 @@ PRIVATE void msg_hardware(void) {
|
|||
/* if interrupt from sub device and Dma transfer
|
||||
was actually busy, take care of business */
|
||||
if( drv_int(i) && sub_dev[i].DmaBusy ) {
|
||||
if (sub_dev[i].DmaMode == DEV_WRITE) handle_int_write(i);
|
||||
if (sub_dev[i].DmaMode == DEV_READ) handle_int_read(i);
|
||||
if (sub_dev[i].DmaMode == DEV_WRITE_S) handle_int_write(i);
|
||||
if (sub_dev[i].DmaMode == DEV_READ_S) handle_int_read(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -500,7 +516,8 @@ PRIVATE void msg_status(message *m_ptr)
|
|||
if(sub_dev[i].ReadyToRevive)
|
||||
{
|
||||
m_ptr->m_type = DEV_REVIVE; /* build message */
|
||||
m_ptr->REP_PROC_NR = sub_dev[i].ReviveProcNr;
|
||||
m_ptr->REP_ENDPT = sub_dev[i].ReviveProcNr;
|
||||
m_ptr->REP_IO_GRANT = sub_dev[i].ReviveGrant;
|
||||
m_ptr->REP_STATUS = sub_dev[i].ReviveStatus;
|
||||
send(m_ptr->m_source, m_ptr); /* send the message */
|
||||
|
||||
|
|
@ -540,7 +557,7 @@ PRIVATE void msg_sig_stop(void)
|
|||
}
|
||||
|
||||
|
||||
/* handle interrupt for specified sub device; DmaMode == DEV_WRITE*/
|
||||
/* handle interrupt for specified sub device; DmaMode == DEV_WRITE_S*/
|
||||
PRIVATE void handle_int_write(int sub_dev_nr)
|
||||
{
|
||||
sub_dev_t *sub_dev_ptr;
|
||||
|
|
@ -549,18 +566,24 @@ PRIVATE void handle_int_write(int sub_dev_nr)
|
|||
sub_dev_ptr = &sub_dev[sub_dev_nr];
|
||||
|
||||
dprint("Finished playing dma[%d] ", sub_dev_ptr->DmaReadNext);
|
||||
sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->DmaReadNext =
|
||||
(sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->DmaLength -= 1;
|
||||
|
||||
if (sub_dev_ptr->BufLength != 0) { /* Data in extra buf, copy to Dma buf */
|
||||
|
||||
dprint(" buf[%d] -> dma[%d] ", sub_dev_ptr->BufReadNext, sub_dev_ptr->DmaFillNext);
|
||||
memcpy(sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize,
|
||||
sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize,
|
||||
dprint(" buf[%d] -> dma[%d] ",
|
||||
sub_dev_ptr->BufReadNext, sub_dev_ptr->DmaFillNext);
|
||||
memcpy(sub_dev_ptr->DmaPtr +
|
||||
sub_dev_ptr->DmaFillNext * sub_dev_ptr->FragSize,
|
||||
sub_dev_ptr->ExtraBuf +
|
||||
sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize,
|
||||
sub_dev_ptr->FragSize);
|
||||
|
||||
sub_dev_ptr->BufReadNext = (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
|
||||
sub_dev_ptr->DmaFillNext = (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->BufReadNext =
|
||||
(sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
|
||||
sub_dev_ptr->DmaFillNext =
|
||||
(sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
|
||||
sub_dev_ptr->BufLength -= 1;
|
||||
sub_dev_ptr->DmaLength += 1;
|
||||
|
|
@ -594,7 +617,7 @@ PRIVATE void handle_int_write(int sub_dev_nr)
|
|||
}
|
||||
|
||||
|
||||
/* handle interrupt for specified sub device; DmaMode == DEV_READ */
|
||||
/* handle interrupt for specified sub device; DmaMode == DEV_READ_S */
|
||||
PRIVATE void handle_int_read(int sub_dev_nr)
|
||||
{
|
||||
sub_dev_t *sub_dev_ptr; int r,i;
|
||||
|
|
@ -603,30 +626,38 @@ PRIVATE void handle_int_read(int sub_dev_nr)
|
|||
|
||||
dprint("Device filled dma[%d]\n", sub_dev_ptr->DmaFillNext);
|
||||
sub_dev_ptr->DmaLength += 1;
|
||||
sub_dev_ptr->DmaFillNext = (sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->DmaFillNext =
|
||||
(sub_dev_ptr->DmaFillNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
|
||||
/* possibly copy data to user (if it is waiting for us) */
|
||||
data_to_user(sub_dev_ptr);
|
||||
|
||||
if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) { /* if dma buffer full */
|
||||
if (sub_dev_ptr->DmaLength == sub_dev_ptr->NrOfDmaFragments) {
|
||||
/* if dma buffer full */
|
||||
|
||||
if (sub_dev_ptr->BufLength == sub_dev_ptr->NrOfExtraBuffers) {
|
||||
error("All buffers full, we have a problem.\n");
|
||||
drv_stop(sub_dev_nr); /* stop the sub device */
|
||||
sub_dev_ptr->DmaBusy = FALSE;
|
||||
sub_dev_ptr->ReviveStatus = 0; /* no data for user, this is a sad story */
|
||||
sub_dev_ptr->ReviveStatus = 0; /* no data for user,
|
||||
this is a sad story */
|
||||
sub_dev_ptr->ReadyToRevive = TRUE; /* wake user up */
|
||||
return;
|
||||
}
|
||||
else { /* dma full, still room in extra buf; copy from dma to extra buf */
|
||||
dprint("dma full: going to copy buf[%d] <- dma[%d]\n", sub_dev_ptr->BufFillNext,
|
||||
sub_dev_ptr->DmaReadNext);
|
||||
memcpy(sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize,
|
||||
sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize,
|
||||
else { /* dma full, still room in extra buf;
|
||||
copy from dma to extra buf */
|
||||
dprint("dma full: going to copy buf[%d] <- dma[%d]\n",
|
||||
sub_dev_ptr->BufFillNext, sub_dev_ptr->DmaReadNext);
|
||||
memcpy(sub_dev_ptr->ExtraBuf +
|
||||
sub_dev_ptr->BufFillNext * sub_dev_ptr->FragSize,
|
||||
sub_dev_ptr->DmaPtr +
|
||||
sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize,
|
||||
sub_dev_ptr->FragSize);
|
||||
sub_dev_ptr->DmaLength -= 1;
|
||||
sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->BufFillNext = (sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
|
||||
sub_dev_ptr->DmaReadNext =
|
||||
(sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->BufFillNext =
|
||||
(sub_dev_ptr->BufFillNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
|
||||
}
|
||||
}
|
||||
/* confirm interrupt, and reenable interrupt from this sub dev*/
|
||||
|
|
@ -649,7 +680,8 @@ PRIVATE int get_started(sub_dev_t *sub_dev_ptr) {
|
|||
}
|
||||
/* let the lower part of the driver start the device */
|
||||
if (drv_start(sub_dev_ptr->Nr, sub_dev_ptr->DmaMode) != OK) {
|
||||
error("%s: Could not start device %d\n", drv.DriverName, sub_dev_ptr->Nr);
|
||||
error("%s: Could not start device %d\n",
|
||||
drv.DriverName, sub_dev_ptr->Nr);
|
||||
}
|
||||
|
||||
sub_dev_ptr->DmaBusy = TRUE; /* Dma is busy from now on */
|
||||
|
|
@ -668,31 +700,33 @@ PRIVATE void data_from_user(sub_dev_t *subdev) {
|
|||
if (subdev->RevivePending &&
|
||||
subdev->ReadyToRevive) return; /* we already got this data */
|
||||
|
||||
|
||||
if (subdev->DmaLength < subdev->NrOfDmaFragments) { /* room in dma buf */
|
||||
|
||||
sys_datacopy(subdev->ReviveProcNr,
|
||||
(vir_bytes)subdev->UserBuf,
|
||||
SELF,
|
||||
(vir_bytes)subdev->DmaPtr + subdev->DmaFillNext * subdev->FragSize,
|
||||
(phys_bytes)subdev->FragSize);
|
||||
sys_safecopyfrom(subdev->ReviveProcNr,
|
||||
(vir_bytes)subdev->ReviveGrant, 0,
|
||||
(vir_bytes)subdev->DmaPtr +
|
||||
subdev->DmaFillNext * subdev->FragSize,
|
||||
(phys_bytes)subdev->FragSize, D);
|
||||
|
||||
|
||||
dprint(" user -> dma[%d]\n", subdev->DmaFillNext);
|
||||
subdev->DmaLength += 1;
|
||||
subdev->DmaFillNext = (subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments;
|
||||
subdev->DmaFillNext =
|
||||
(subdev->DmaFillNext + 1) % subdev->NrOfDmaFragments;
|
||||
|
||||
} else { /* room in extra buf */
|
||||
|
||||
sys_datacopy(subdev->ReviveProcNr,
|
||||
(vir_bytes)subdev->UserBuf,
|
||||
SELF,
|
||||
(vir_bytes)subdev->ExtraBuf + subdev->BufFillNext * subdev->FragSize,
|
||||
(phys_bytes)subdev->FragSize);
|
||||
sys_safecopyfrom(subdev->ReviveProcNr,
|
||||
(vir_bytes)subdev->ReviveGrant, 0,
|
||||
(vir_bytes)subdev->ExtraBuf +
|
||||
subdev->BufFillNext * subdev->FragSize,
|
||||
(phys_bytes)subdev->FragSize, D);
|
||||
|
||||
dprint(" user -> buf[%d]\n", subdev->BufFillNext);
|
||||
subdev->BufLength += 1;
|
||||
|
||||
subdev->BufFillNext = (subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers;
|
||||
subdev->BufFillNext =
|
||||
(subdev->BufFillNext + 1) % subdev->NrOfExtraBuffers;
|
||||
|
||||
}
|
||||
if(subdev->OutOfData) { /* if device paused (because of lack of data) */
|
||||
|
|
@ -703,7 +737,6 @@ PRIVATE void data_from_user(sub_dev_t *subdev) {
|
|||
error("%s: Couldn't enable IRQ", drv.DriverName);
|
||||
}
|
||||
drv_resume(subdev->Nr); /* resume resume the sub device */
|
||||
|
||||
}
|
||||
|
||||
subdev->ReviveStatus = subdev->FragSize;
|
||||
|
|
@ -712,8 +745,7 @@ PRIVATE void data_from_user(sub_dev_t *subdev) {
|
|||
}
|
||||
|
||||
|
||||
PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr)
|
||||
{
|
||||
PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr) {
|
||||
if (!sub_dev_ptr->RevivePending) return; /* nobody is wating for data */
|
||||
if (sub_dev_ptr->ReadyToRevive) return;/* we already filled user's buffer */
|
||||
if (sub_dev_ptr->BufLength == 0 && sub_dev_ptr->DmaLength == 0) return;
|
||||
|
|
@ -721,32 +753,38 @@ PRIVATE void data_to_user(sub_dev_t *sub_dev_ptr)
|
|||
|
||||
if(sub_dev_ptr->BufLength != 0) { /* data in extra buffer available */
|
||||
|
||||
sys_datacopy(SELF,
|
||||
(vir_bytes)sub_dev_ptr->ExtraBuf + sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize,
|
||||
sub_dev_ptr->ReviveProcNr,
|
||||
(vir_bytes)sub_dev_ptr->UserBuf,
|
||||
(phys_bytes)sub_dev_ptr->FragSize);
|
||||
sys_safecopyto(sub_dev_ptr->ReviveProcNr,
|
||||
(vir_bytes)sub_dev_ptr->ReviveGrant,
|
||||
0, (vir_bytes)sub_dev_ptr->ExtraBuf +
|
||||
sub_dev_ptr->BufReadNext * sub_dev_ptr->FragSize,
|
||||
(phys_bytes)sub_dev_ptr->FragSize, D);
|
||||
|
||||
dprint(" copied buf[%d] to user\n", sub_dev_ptr->BufReadNext);
|
||||
|
||||
/* adjust the buffer status variables */
|
||||
sub_dev_ptr->BufReadNext = (sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
|
||||
sub_dev_ptr->BufReadNext =
|
||||
(sub_dev_ptr->BufReadNext + 1) % sub_dev_ptr->NrOfExtraBuffers;
|
||||
sub_dev_ptr->BufLength -= 1;
|
||||
|
||||
} else { /* extra buf empty, but data in dma buf*/
|
||||
|
||||
sys_datacopy(SELF,
|
||||
(vir_bytes)sub_dev_ptr->DmaPtr + sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize,
|
||||
sys_safecopyto(
|
||||
sub_dev_ptr->ReviveProcNr,
|
||||
(vir_bytes)sub_dev_ptr->UserBuf,
|
||||
(phys_bytes)sub_dev_ptr->FragSize);
|
||||
(vir_bytes)sub_dev_ptr->ReviveGrant, 0,
|
||||
(vir_bytes)sub_dev_ptr->DmaPtr +
|
||||
sub_dev_ptr->DmaReadNext * sub_dev_ptr->FragSize,
|
||||
(phys_bytes)sub_dev_ptr->FragSize, D);
|
||||
|
||||
dprint(" copied dma[%d] to user\n", sub_dev_ptr->DmaReadNext);
|
||||
|
||||
/* adjust the buffer status variables */
|
||||
sub_dev_ptr->DmaReadNext = (sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->DmaReadNext =
|
||||
(sub_dev_ptr->DmaReadNext + 1) % sub_dev_ptr->NrOfDmaFragments;
|
||||
sub_dev_ptr->DmaLength -= 1;
|
||||
}
|
||||
|
||||
sub_dev_ptr->ReviveStatus = sub_dev_ptr->FragSize;
|
||||
sub_dev_ptr->ReadyToRevive = TRUE; /* drv_status will send REVIVE mess to FS*/
|
||||
sub_dev_ptr->ReadyToRevive = TRUE;
|
||||
/* drv_status will send REVIVE mess to FS*/
|
||||
notify(sub_dev_ptr->NotifyProcNr); /* notify the File Systam to make it
|
||||
send DEV_STATUS messages*/
|
||||
}
|
||||
|
|
@ -759,12 +797,16 @@ PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) {
|
|||
|
||||
/* allocate dma buffer space */
|
||||
if (!(sub_dev_ptr->DmaBuf = malloc(sub_dev_ptr->DmaSize + 64 * 1024))) {
|
||||
error("%s: failed to allocate dma buffer for channel %d\n", drv.DriverName,i);
|
||||
error("%s: failed to allocate dma buffer for channel %d\n",
|
||||
drv.DriverName,i);
|
||||
return EIO;
|
||||
}
|
||||
/* allocate extra buffer space */
|
||||
if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers * sub_dev_ptr->DmaSize / sub_dev_ptr->NrOfDmaFragments))) {
|
||||
error("%s failed to allocate extra buffer for channel %d\n", drv.DriverName,i);
|
||||
if (!(sub_dev_ptr->ExtraBuf = malloc(sub_dev_ptr->NrOfExtraBuffers *
|
||||
sub_dev_ptr->DmaSize /
|
||||
sub_dev_ptr->NrOfDmaFragments))) {
|
||||
error("%s failed to allocate extra buffer for channel %d\n",
|
||||
drv.DriverName,i);
|
||||
return EIO;
|
||||
}
|
||||
|
||||
|
|
@ -777,13 +819,16 @@ PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) {
|
|||
if (i != OK) {
|
||||
return EIO;
|
||||
}
|
||||
if((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) < sub_dev_ptr->DmaSize) {
|
||||
/* First half of buffer crosses a 64K boundary, can't DMA into that */
|
||||
if ((left = dma_bytes_left(sub_dev_ptr->DmaPhys)) <
|
||||
sub_dev_ptr->DmaSize) {
|
||||
/* First half of buffer crosses a 64K boundary,
|
||||
* can't DMA into that */
|
||||
sub_dev_ptr->DmaPtr += left;
|
||||
sub_dev_ptr->DmaPhys += left;
|
||||
}
|
||||
/* write the physical dma address and size to the device */
|
||||
drv_set_dma(sub_dev_ptr->DmaPhys, sub_dev_ptr->DmaSize, sub_dev_ptr->Nr);
|
||||
drv_set_dma(sub_dev_ptr->DmaPhys,
|
||||
sub_dev_ptr->DmaSize, sub_dev_ptr->Nr);
|
||||
return OK;
|
||||
|
||||
#else /* CHIP != INTEL */
|
||||
|
|
@ -793,13 +838,12 @@ PRIVATE int init_buffers(sub_dev_t *sub_dev_ptr) {
|
|||
}
|
||||
|
||||
|
||||
PRIVATE void reply(int code, int replyee, int process, int status)
|
||||
{
|
||||
PRIVATE void reply(int code, int replyee, int process, int status) {
|
||||
message m;
|
||||
|
||||
m.m_type = code; /* TASK_REPLY or REVIVE */
|
||||
m.REP_STATUS = status; /* result of device operation */
|
||||
m.REP_PROC_NR = process; /* which user made the request */
|
||||
m.REP_ENDPT = process; /* which user made the request */
|
||||
send(replyee, &m);
|
||||
}
|
||||
|
||||
|
|
@ -819,7 +863,8 @@ PRIVATE special_file_t* get_special_file(int minor_dev_nr) {
|
|||
}
|
||||
}
|
||||
|
||||
error("%s: No subdevice specified for minor device %d!\n", drv.DriverName, minor_dev_nr);
|
||||
error("%s: No subdevice specified for minor device %d!\n",
|
||||
drv.DriverName, minor_dev_nr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -5,8 +5,15 @@
|
|||
#include <sys/ioc_sound.h>
|
||||
|
||||
|
||||
/* change '(void)' to 'printf' to print debug info and error messages */
|
||||
/* change to DEBUG to 1 to print debug info and error messages */
|
||||
|
||||
#define DEBUG 0
|
||||
|
||||
#if DEBUG
|
||||
#define dprint printf
|
||||
#else
|
||||
#define dprint (void)
|
||||
#endif
|
||||
#define error printf
|
||||
|
||||
|
||||
|
|
@ -51,6 +58,7 @@ typedef struct {
|
|||
int RevivePending; /* process waiting for this dev? */
|
||||
int ReviveStatus; /* return val when proc unblocked */
|
||||
int ReviveProcNr; /* the process to unblock */
|
||||
cp_grant_id_t ReviveGrant; /* grant id associated with io */
|
||||
void *UserBuf; /* address of user's data buffer */
|
||||
int ReadyToRevive; /* are we ready to revive process?*/
|
||||
int NotifyProcNr; /* process to send notify to (FS) */
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
|
||||
mixer.o: ../framework/../../drivers.h
|
||||
mixer.o: ../framework/audio_fw.h
|
||||
mixer.o: /usr/include/ansi.h
|
||||
mixer.o: /usr/include/errno.h
|
||||
mixer.o: /usr/include/ibm/bios.h
|
||||
mixer.o: /usr/include/ibm/interrupt.h
|
||||
mixer.o: /usr/include/ibm/ports.h
|
||||
mixer.o: /usr/include/limits.h
|
||||
mixer.o: /usr/include/minix/bitmap.h
|
||||
mixer.o: /usr/include/minix/callnr.h
|
||||
mixer.o: /usr/include/minix/com.h
|
||||
mixer.o: /usr/include/minix/config.h
|
||||
mixer.o: /usr/include/minix/const.h
|
||||
mixer.o: /usr/include/minix/devio.h
|
||||
mixer.o: /usr/include/minix/dmap.h
|
||||
mixer.o: /usr/include/minix/ioctl.h
|
||||
mixer.o: /usr/include/minix/ipc.h
|
||||
mixer.o: /usr/include/minix/sound.h
|
||||
mixer.o: /usr/include/minix/sys_config.h
|
||||
mixer.o: /usr/include/minix/syslib.h
|
||||
mixer.o: /usr/include/minix/sysutil.h
|
||||
mixer.o: /usr/include/minix/type.h
|
||||
mixer.o: /usr/include/signal.h
|
||||
mixer.o: /usr/include/stddef.h
|
||||
mixer.o: /usr/include/stdlib.h
|
||||
mixer.o: /usr/include/string.h
|
||||
mixer.o: /usr/include/sys/dir.h
|
||||
mixer.o: /usr/include/sys/ioc_sound.h
|
||||
mixer.o: /usr/include/sys/types.h
|
||||
mixer.o: /usr/include/unistd.h
|
||||
mixer.o: mixer.c
|
||||
mixer.o: mixer.h
|
||||
mixer.o: sb16.h
|
||||
|
||||
sb16.o: ../framework/../../drivers.h
|
||||
sb16.o: ../framework/audio_fw.h
|
||||
sb16.o: /usr/include/ansi.h
|
||||
sb16.o: /usr/include/errno.h
|
||||
sb16.o: /usr/include/ibm/bios.h
|
||||
sb16.o: /usr/include/ibm/interrupt.h
|
||||
sb16.o: /usr/include/ibm/ports.h
|
||||
sb16.o: /usr/include/limits.h
|
||||
sb16.o: /usr/include/minix/bitmap.h
|
||||
sb16.o: /usr/include/minix/callnr.h
|
||||
sb16.o: /usr/include/minix/com.h
|
||||
sb16.o: /usr/include/minix/config.h
|
||||
sb16.o: /usr/include/minix/const.h
|
||||
sb16.o: /usr/include/minix/devio.h
|
||||
sb16.o: /usr/include/minix/dmap.h
|
||||
sb16.o: /usr/include/minix/ioctl.h
|
||||
sb16.o: /usr/include/minix/ipc.h
|
||||
sb16.o: /usr/include/minix/sound.h
|
||||
sb16.o: /usr/include/minix/sys_config.h
|
||||
sb16.o: /usr/include/minix/syslib.h
|
||||
sb16.o: /usr/include/minix/sysutil.h
|
||||
sb16.o: /usr/include/minix/type.h
|
||||
sb16.o: /usr/include/signal.h
|
||||
sb16.o: /usr/include/stddef.h
|
||||
sb16.o: /usr/include/stdlib.h
|
||||
sb16.o: /usr/include/string.h
|
||||
sb16.o: /usr/include/sys/dir.h
|
||||
sb16.o: /usr/include/sys/ioc_sound.h
|
||||
sb16.o: /usr/include/sys/types.h
|
||||
sb16.o: /usr/include/unistd.h
|
||||
sb16.o: mixer.h
|
||||
sb16.o: sb16.c
|
||||
sb16.o: sb16.h
|
||||
|
|
@ -241,4 +241,29 @@ driver orinoco
|
|||
uid 0;
|
||||
};
|
||||
|
||||
driver es1370
|
||||
{
|
||||
system
|
||||
SAFECOPYFROM
|
||||
SAFECOPYTO
|
||||
UMAP
|
||||
SETGRANT
|
||||
IRQCTL # 19
|
||||
DEVIO # 21
|
||||
;
|
||||
pci device 1274/5000;
|
||||
};
|
||||
|
||||
driver es1371
|
||||
{
|
||||
system
|
||||
SAFECOPYFROM
|
||||
SAFECOPYTO
|
||||
UMAP
|
||||
SETGRANT
|
||||
IRQCTL # 19
|
||||
DEVIO # 21
|
||||
;
|
||||
pci device 1274/1371;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -9,13 +9,17 @@
|
|||
#include <minix/ioctl.h>
|
||||
|
||||
/* Soundcard DSP ioctls. */
|
||||
#define DSPIORATE _IOR('s', 1, unsigned int)
|
||||
#define DSPIOSTEREO _IOR('s', 2, unsigned int)
|
||||
#define DSPIOSIZE _IOR('s', 3, unsigned int)
|
||||
#define DSPIOBITS _IOR('s', 4, unsigned int)
|
||||
#define DSPIOSIGN _IOR('s', 5, unsigned int)
|
||||
#define DSPIOMAX _IOW('s', 6, unsigned int)
|
||||
#define DSPIORATE _IOW('s', 1, unsigned int)
|
||||
#define DSPIOSTEREO _IOW('s', 2, unsigned int)
|
||||
#define DSPIOSIZE _IOW('s', 3, unsigned int)
|
||||
#define DSPIOBITS _IOW('s', 4, unsigned int)
|
||||
#define DSPIOSIGN _IOW('s', 5, unsigned int)
|
||||
#define DSPIOMAX _IOR('s', 6, unsigned int)
|
||||
#define DSPIORESET _IO ('s', 7)
|
||||
#define DSPIOFREEBUF _IOR('s', 30, unsigned int)
|
||||
#define DSPIOSAMPLESINBUF _IOR('s', 31, unsigned int)
|
||||
#define DSPIOPAUSE _IO ('s', 32)
|
||||
#define DSPIORESUME _IO ('s', 33)
|
||||
|
||||
/* Soundcard mixer ioctls. */
|
||||
#define MIXIOGETVOLUME _IORW('s', 10, struct volume_level)
|
||||
|
|
@ -27,7 +31,4 @@
|
|||
#define MIXIOSETINPUTRIGHT _IORW('s', 22, struct inout_ctrl)
|
||||
#define MIXIOSETOUTPUT _IORW('s', 23, struct inout_ctrl)
|
||||
|
||||
#define AC97READ _IOW('s', 8, u16_t[2])
|
||||
#define AC97WRITE _IOR('s', 9, u16_t[2])
|
||||
|
||||
#endif /* _S_I_SOUND_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user