## diffname bitsy/devuda1341.c 2000/1103
## diff -e /dev/null /n/emeliedump/2000/1103/sys/src/9/bitsy/devuda1341.c
0a
/*
* SAC/UDA 1341 Audio driver for the Bitsy
*
* The Philips UDA 1341 sound chip is accessed through the Serial Audio
* Controller (SAC) of the StrongARM SA-1110. This is much more a SAC
* controller than a UDA controller, but we have a devsac.c already.
*
* The code morphs Nicolas Pitre's <nico@cam.org> Linux controller
* and Ken's Soundblaster controller.
*
* The interface should be identical to that of devaudio.c
*/
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#include "io.h"
/*
* GPIO based L3 bus support.
*
* This provides control of Philips L3 type devices.
* GPIO lines are used for clock, data and mode pins.
*
* Note: The L3 pins are shared with I2C devices. This should not present
* any problems as long as an I2C start sequence is not generated. This is
* defined as a 1->0 transition on the data lines when the clock is high.
* It is critical this code only allow data transitions when the clock
* is low. This is always legal in L3.
*
* The IIC interface requires the clock and data pin to be LOW when idle. We
* must make sure we leave them in this state.
*
* It appears the read data is generated on the falling edge of the clock
* and should be held stable during the clock high time.
*/
/*
* L3 setup and hold times (expressed in us)
*/
#define L3_DataSetupTime 1 /* 190 ns */
#define L3_DataHoldTime 1 /* 30 ns */
#define L3_ModeSetupTime 1 /* 190 ns */
#define L3_ModeHoldTime 1 /* 190 ns */
#define L3_ClockHighTime 100 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */
#define L3_ClockLowTime 100 /* 250 ns (min is 64*fs, 35us @ 44.1 Khz) */
#define L3_HaltTime 1 /* 190 ns */
/* UDA 1341 Registers */
enum {
/* Status0 register */
UdaStatusDC = 0, /* 1 bit */
UdaStatusIF = 1, /* 3 bits */
UdaStatusSC = 4, /* 2 bits */
UdaStatusRST = 6, /* 1 bit */
};
enum {
/* Status1 register */
UdaStatusPC = 0, /* 2 bits */
UdaStatusDS = 2, /* 1 bit */
UdaStatusPDA = 3, /* 1 bit */
UdaStatusPAD = 4, /* 1 bit */
UdaStatusIGS = 5, /* 1 bit */
UdaStatusOGS = 6, /* 1 bit */
};
/*
* UDA1341 L3 address and command types
*/
#define UDA1341_L3Addr 5
#define UDA1341_DATA0 0
#define UDA1341_DATA1 1
#define UDA1341_STATUS 2
typedef struct AQueue AQueue;
typedef struct Buf Buf;
enum
{
Qdir = 0,
Qaudio,
Qvolume,
Qstatus,
Fmono = 1,
Fin = 2,
Fout = 4,
Aclosed = 0,
Aread,
Awrite,
Vaudio = 0,
Vsynth,
Vcd,
Vline,
Vmic,
Vspeaker,
Vtreb,
Vbass,
Vspeed,
Nvol,
Bufsize = 16*1024, /* 92 ms each */
Nbuf = 16, /* 1.5 seconds total */
Speed = 44100,
Ncmd = 50, /* max volume command words */
};
Dirtab
audiodir[] =
{
"audio", {Qaudio}, 0, 0666,
"volume", {Qvolume}, 0, 0666,
"audiostat",{Qstatus}, 0, 0444,
};
struct Buf
{
uchar* virt;
ulong phys;
Buf* next;
};
struct AQueue
{
Lock;
Buf* first;
Buf* last;
};
static struct
{
QLock;
Rendez vous;
int bufinit; /* boolean if buffers allocated */
int curcount; /* how much data in current buffer */
int active; /* boolean dma running */
int intr; /* boolean an interrupt has happened */
int amode; /* Aclosed/Aread/Awrite for /audio */
int rivol[Nvol]; /* right/left input/output volumes */
int livol[Nvol];
int rovol[Nvol];
int lovol[Nvol];
int major; /* SB16 major version number (sb 4) */
int minor; /* SB16 minor version number */
ulong totcount; /* how many bytes processed since open */
vlong tottime; /* time at which totcount bytes were processed */
Buf buf[Nbuf]; /* buffers and queues */
AQueue empty;
AQueue full;
Buf* current;
Buf* filling;
} audio;
static struct
{
char* name;
int flag;
int ilval; /* initial values */
int irval;
} volumes[] =
{
[Vaudio] "audio", Fout, 50, 50,
[Vsynth] "synth", Fin|Fout, 0, 0,
[Vcd] "cd", Fin|Fout, 0, 0,
[Vline] "line", Fin|Fout, 0, 0,
[Vmic] "mic", Fin|Fout|Fmono, 0, 0,
[Vspeaker] "speaker", Fout|Fmono, 0, 0,
[Vtreb] "treb", Fout, 50, 50,
[Vbass] "bass", Fout, 50, 50,
[Vspeed] "speed", Fin|Fout|Fmono, Speed, Speed,
0
};
/*
* Grab control of the IIC/L3 shared pins
*/
static inline void L3_acquirepins(void)
{
GPSR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
GPDR |= (GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
}
/*
* Release control of the IIC/L3 shared pins
*/
static inline void L3_releasepins(void)
{
GPDR &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
GPCR = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
}
/*
* Initialize the interface
*/
static void __init L3_init(void)
{
GAFR &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o);
GPSR = GPIO_L3_MODE_o;
GPDR |= GPIO_L3_MODE_o;
L3_releasepins();
}
/*
* Get a bit. The clock is high on entry and on exit. Data is read after
* the clock low time has expired.
*/
static inline int L3_getbit(void)
{
int data;
GPCR = GPIO_L3_SCLK_o;
udelay(L3_ClockLowTime);
data = (GPLR & GPIO_L3_SDA_io) ? 1 : 0;
GPSR = GPIO_L3_SCLK_o;
udelay(L3_ClockHighTime);
return data;
}
/*
* Send a bit. The clock is high on entry and on exit. Data is sent only
* when the clock is low (I2C compatibility).
*/
static inline void L3_sendbit(int bit)
{
GPCR = GPIO_L3_SCLK_o;
if (bit & 1)
GPSR = GPIO_L3_SDA_io;
else
GPCR = GPIO_L3_SDA_io;
/* Assumes L3_DataSetupTime < L3_ClockLowTime */
udelay(L3_ClockLowTime);
GPSR = GPIO_L3_SCLK_o;
udelay(L3_ClockHighTime);
}
/*
* Send a byte. The mode line is set or pulsed based on the mode sequence
* count. The mode line is high on entry and exit. The mod line is pulsed
* before the second data byte and before ech byte thereafter.
*/
static void L3_sendbyte(char data, int mode)
{
int i;
L3_acquirepins();
switch(mode) {
case 0: /* Address mode */
GPCR = GPIO_L3_MODE_o;
break;
case 1: /* First data byte */
break;
default: /* Subsequent bytes */
GPCR = GPIO_L3_MODE_o;
udelay(L3_HaltTime);
GPSR = GPIO_L3_MODE_o;
break;
}
udelay(L3_ModeSetupTime);
for (i = 0; i < 8; i++)
L3_sendbit(data >> i);
if (mode == 0) /* Address mode */
GPSR = GPIO_L3_MODE_o;
udelay(L3_ModeHoldTime);
L3_releasepins();
}
/*
* Get a byte. The mode line is set or pulsed based on the mode sequence
* count. The mode line is high on entry and exit. The mod line is pulsed
* before the second data byte and before each byte thereafter. This
* function is never valid with mode == 0 (address cycle) as the address
* is always sent on the bus, not read.
*/
static char L3_getbyte(int mode)
{
char data = 0;
int i;
L3_acquirepins();
GPDR &= ~(GPIO_L3_SDA_io);
switch(mode) {
case 0: /* Address mode - never valid */
break;
case 1: /* First data byte */
break;
default: /* Subsequent bytes */
GPCR = GPIO_L3_MODE_o;
udelay(L3_HaltTime);
GPSR = GPIO_L3_MODE_o;
break;
}
udelay(L3_ModeSetupTime);
for (i = 0; i < 8; i++)
data |= (L3_getbit() << i);
udelay(L3_ModeHoldTime);
L3_releasepins();
return data;
}
/*
* Write data to a device on the L3 bus. The address is passed as well as
* the data and length. The length written is returned. The register space
* is encoded in the address (low two bits are set and device address is
* in the upper 6 bits).
*/
static int L3_write(char addr, char *data, int len)
{
int mode = 0;
int bytes = len;
L3_sendbyte(addr, mode++);
while(len--)
L3_sendbyte(*data++, mode++);
return bytes;
}
/*
* Read data from a device on the L3 bus. The address is passed as well as
* the data and length. The length read is returned. The register space
* is encoded in the address (low two bits are set and device address is
* in the upper 6 bits).
*/
static int L3_read(char addr, char * data, int len)
{
int mode = 0;
int bytes = len;
L3_sendbyte(addr, mode++);
while(len--)
*data++ = L3_getbyte(mode++);
return bytes;
}
static void swab(uchar*);
static char Emajor[] = "soundblaster not responding/wrong version";
static char Emode[] = "illegal open mode";
static char Evolume[] = "illegal volume specifier";
static int
sbcmd(int val)
{
int i, s;
for(i=1<<16; i!=0; i--) {
s = inb(blaster.wstatus);
if((s & 0x80) == 0) {
outb(blaster.write, val);
return 0;
}
}
/* print("#A: sbcmd (0x%.2x) timeout\n", val); /**/
return 1;
}
static int
sbread(void)
{
int i, s;
for(i=1<<16; i!=0; i--) {
s = inb(blaster.rstatus);
if((s & 0x80) != 0) {
return inb(blaster.read);
}
}
/* print("#A: sbread did not respond\n"); /**/
return -1;
}
static int
ess1688w(int reg, int val)
{
if(sbcmd(reg) || sbcmd(val))
return 1;
return 0;
}
static int
ess1688r(int reg)
{
if(sbcmd(0xC0) || sbcmd(reg))
return -1;
return sbread();
}
static int
mxcmd(int addr, int val)
{
outb(blaster.mixaddr, addr);
outb(blaster.mixdata, val);
return 1;
}
static int
mxread(int addr)
{
int s;
outb(blaster.mixaddr, addr);
s = inb(blaster.mixdata);
return s;
}
static void
mxcmds(int s, int v)
{
if(v > 100)
v = 100;
if(v < 0)
v = 0;
mxcmd(s, (v*255)/100);
}
static void
mxcmdt(int s, int v)
{
if(v > 100)
v = 100;
if(v <= 0)
mxcmd(s, 0);
else
mxcmd(s, 255-100+v);
}
static void
mxcmdu(int s, int v)
{
if(v > 100)
v = 100;
if(v <= 0)
v = 0;
mxcmd(s, 128-50+v);
}
static void
mxvolume(void)
{
int *left, *right;
int source;
if(audio.amode == Aread){
left = audio.livol;
right = audio.rivol;
}else{
left = audio.lovol;
right = audio.rovol;
}
ilock(&blaster);
mxcmd(0x30, 255); /* left master */
mxcmd(0x31, 255); /* right master */
mxcmd(0x3f, 0); /* left igain */
mxcmd(0x40, 0); /* right igain */
mxcmd(0x41, 0); /* left ogain */
mxcmd(0x42, 0); /* right ogain */
mxcmds(0x32, left[Vaudio]);
mxcmds(0x33, right[Vaudio]);
mxcmds(0x34, left[Vsynth]);
mxcmds(0x35, right[Vsynth]);
mxcmds(0x36, left[Vcd]);
mxcmds(0x37, right[Vcd]);
mxcmds(0x38, left[Vline]);
mxcmds(0x39, right[Vline]);
mxcmds(0x3a, left[Vmic]);
mxcmds(0x3b, left[Vspeaker]);
mxcmdu(0x44, left[Vtreb]);
mxcmdu(0x45, right[Vtreb]);
mxcmdu(0x46, left[Vbass]);
mxcmdu(0x47, right[Vbass]);
source = 0;
if(left[Vsynth])
source |= 1<<6;
if(right[Vsynth])
source |= 1<<5;
if(left[Vaudio])
source |= 1<<4;
if(right[Vaudio])
source |= 1<<3;
if(left[Vcd])
source |= 1<<2;
if(right[Vcd])
source |= 1<<1;
if(left[Vmic])
source |= 1<<0;
if(audio.amode == Aread)
mxcmd(0x3c, 0); /* output switch */
else
mxcmd(0x3c, source);
mxcmd(0x3d, source); /* input left switch */
mxcmd(0x3e, source); /* input right switch */
iunlock(&blaster);
}
static Buf*
getbuf(AQueue *q)
{
Buf *b;
ilock(q);
b = q->first;
if(b)
q->first = b->next;
iunlock(q);
return b;
}
static void
putbuf(AQueue *q, Buf *b)
{
ilock(q);
b->next = 0;
if(q->first)
q->last->next = b;
else
q->first = b;
q->last = b;
iunlock(q);
}
/*
* move the dma to the next buffer
*/
static void
contindma(void)
{
Buf *b;
if(!audio.active)
goto shutdown;
b = audio.current;
if(audio.amode == Aread) {
if(b) /* shouldn't happen */
putbuf(&audio.full, b);
b = getbuf(&audio.empty);
} else {
if(b) /* shouldn't happen */
putbuf(&audio.empty, b);
b = getbuf(&audio.full);
}
audio.current = b;
if(b == 0)
goto shutdown;
if(dmasetup(blaster.dma, b->virt, Bufsize, audio.amode == Aread) >= 0)
return;
print("#A: dmasetup fail\n");
putbuf(&audio.empty, b);
shutdown:
dmaend(blaster.dma);
sbcmd(0xd9); /* exit at end of count */
sbcmd(0xd5); /* pause */
audio.curcount = 0;
audio.active = 0;
}
/*
* cause sb to get an interrupt per buffer.
* start first dma
*/
static void
sb16startdma(void)
{
ulong count;
int speed;
ilock(&blaster);
dmaend(blaster.dma);
if(audio.amode == Aread) {
sbcmd(0x42); /* input sampling rate */
speed = audio.livol[Vspeed];
} else {
sbcmd(0x41); /* output sampling rate */
speed = audio.lovol[Vspeed];
}
sbcmd(speed>>8);
sbcmd(speed);
count = (Bufsize >> 1) - 1;
if(audio.amode == Aread)
sbcmd(0xbe); /* A/D, autoinit */
else
sbcmd(0xb6); /* D/A, autoinit */
sbcmd(0x30); /* stereo, 16 bit */
sbcmd(count);
sbcmd(count>>8);
audio.active = 1;
audio.tottime = todget(nil);
contindma();
iunlock(&blaster);
}
static int
ess1688reset(void)
{
int i;
outb(blaster.reset, 3);
delay(1); /* >3 υs */
outb(blaster.reset, 0);
delay(1);
i = sbread();
if(i != 0xAA) {
print("#A: no response 0x%.2x\n", i);
return 1;
}
if(sbcmd(0xC6)){ /* extended mode */
print("#A: barf 3\n");
return 1;
}
return 0;
}
static void
ess1688startdma(void)
{
ulong count;
int speed, x;
ilock(&blaster);
dmaend(blaster.dma);
if(audio.amode == Awrite)
ess1688reset();
if(audio.amode == Aread)
sbcmd(0xD3); /* speaker off */
/*
* Set the speed.
*/
if(audio.amode == Aread)
speed = audio.livol[Vspeed];
else
speed = audio.lovol[Vspeed];
if(speed < 4000)
speed = 4000;
else if(speed > 48000)
speed = 48000;
if(speed > 22000)
x = 0x80|(256-(795500+speed/2)/speed);
else
x = 128-(397700+speed/2)/speed;
ess1688w(0xA1, x & 0xFF);
speed = (speed * 9) / 20;
x = 256 - 7160000 / (speed * 82);
ess1688w(0xA2, x & 0xFF);
if(audio.amode == Aread)
ess1688w(0xB8, 0x0E); /* A/D, autoinit */
else
ess1688w(0xB8, 0x04); /* D/A, autoinit */
x = ess1688r(0xA8) & ~0x03;
ess1688w(0xA8, x|0x01); /* 2 channels */
ess1688w(0xB9, 2); /* demand mode, 4 bytes per request */
if(audio.amode == Awrite)
ess1688w(0xB6, 0);
ess1688w(0xB7, 0x71);
ess1688w(0xB7, 0xBC);
x = ess1688r(0xB1) & 0x0F;
ess1688w(0xB1, x|0x50);
x = ess1688r(0xB2) & 0x0F;
ess1688w(0xB2, x|0x50);
if(audio.amode == Awrite)
sbcmd(0xD1); /* speaker on */
count = -Bufsize;
ess1688w(0xA4, count & 0xFF);
ess1688w(0xA5, (count>>8) & 0xFF);
x = ess1688r(0xB8);
ess1688w(0xB8, x|0x05);
audio.active = 1;
audio.tottime = todget(nil);
contindma();
iunlock(&blaster);
}
/*
* if audio is stopped,
* start it up again.
*/
static void
pokeaudio(void)
{
if(!audio.active)
blaster.startdma();
}
static void
sb16intr(void)
{
int stat, dummy;
stat = mxread(0x82) & 7; /* get irq status */
if(stat) {
dummy = 0;
if(stat & 2) {
ilock(&blaster);
dummy = inb(blaster.clri16);
audio.totcount += Bufsize;
audio.tottime = todget(nil);
contindma();
iunlock(&blaster);
audio.intr = 1;
wakeup(&audio.vous);
}
if(stat & 1) {
dummy = inb(blaster.clri8);
}
if(stat & 4) {
dummy = inb(blaster.clri401);
}
USED(dummy);
}
}
static void
ess1688intr(void)
{
int dummy;
if(audio.active){
ilock(&blaster);
audio.totcount += Bufsize;
audio.tottime = todget(nil);
contindma();
dummy = inb(blaster.clri8);
iunlock(&blaster);
audio.intr = 1;
wakeup(&audio.vous);
USED(dummy);
}
else
print("#A: unexpected ess1688 interrupt\n");
}
void
audiosbintr(void)
{
/*
* Carrera interrupt interface.
*/
blaster.intr();
}
static void
pcaudiosbintr(Ureg*, void*)
{
/*
* x86 interrupt interface.
*/
blaster.intr();
}
void
audiodmaintr(void)
{
/* print("#A: dma interrupt\n"); /**/
}
static int
anybuf(void*)
{
return audio.intr;
}
/*
* wait for some output to get
* empty buffers back.
*/
static void
waitaudio(void)
{
audio.intr = 0;
pokeaudio();
tsleep(&audio.vous, anybuf, 0, 10*1000);
if(audio.intr == 0) {
/* print("#A: audio timeout\n"); /**/
audio.active = 0;
pokeaudio();
}
}
static void
sbbufinit(void)
{
int i;
void *p;
for(i=0; i<Nbuf; i++) {
p = xspanalloc(Bufsize, CACHELINESZ, 64*1024);
dcflush(p, Bufsize);
audio.buf[i].virt = UNCACHED(uchar, p);
audio.buf[i].phys = (ulong)PADDR(p);
}
}
static void
setempty(void)
{
int i;
ilock(&blaster);
audio.empty.first = 0;
audio.empty.last = 0;
audio.full.first = 0;
audio.full.last = 0;
audio.current = 0;
audio.filling = 0;
for(i=0; i<Nbuf; i++)
putbuf(&audio.empty, &audio.buf[i]);
audio.totcount = 0;
audio.tottime = 0LL;
iunlock(&blaster);
}
static void
resetlevel(void)
{
int i;
for(i=0; volumes[i].name; i++) {
audio.lovol[i] = volumes[i].ilval;
audio.rovol[i] = volumes[i].irval;
audio.livol[i] = volumes[i].ilval;
audio.rivol[i] = volumes[i].irval;
}
}
static int
ess1688(ISAConf* sbconf)
{
int i, major, minor;
/*
* Try for ESS1688.
*/
sbcmd(0xE7); /* get version */
major = sbread();
minor = sbread();
if(major != 0x68 || minor != 0x8B){
print("#A: model 0x%.2x 0x%.2x; not ESS1688 compatible\n", major, minor);
return 1;
}
ess1688reset();
switch(sbconf->irq){
case 2:
case 9:
i = 0x50|(0<<2);
break;
case 5:
i = 0x50|(1<<2);
break;
case 7:
i = 0x50|(2<<2);
break;
case 10:
i = 0x50|(3<<2);
break;
default:
print("#A: bad ESS1688 irq %lud\n", sbconf->irq);
return 1;
}
ess1688w(0xB1, i);
switch(sbconf->dma){
case 0:
i = 0x50|(1<<2);
break;
case 1:
i = 0xF0|(2<<2);
break;
case 3:
i = 0x50|(3<<2);
break;
default:
print("#A: bad ESS1688 dma %lud\n", sbconf->dma);
return 1;
}
ess1688w(0xB2, i);
ess1688reset();
blaster.startdma = ess1688startdma;
blaster.intr = ess1688intr;
return 0;
}
static void
audioinit(void)
{
int err;
/* Acquire and initialize DMA */
if( audio_init_dma( &output_stream, "UDA1341 DMA out" ) ||
audio_init_dma( &input_stream, "UDA1341 DMA in" ) ){
audio_clear_dma( &output_stream );
audio_clear_dma( &input_stream );
return -EBUSY;
}
L3_init();
audio_ssp_init();
audio_uda1341_reset();
init_waitqueue_head(&audio_waitq);
/* Set some default mixer values... */
STATUS_1.DAC_gain = 1;
STATUS_1.ADC_gain = 1;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, (char*)&STATUS_1, 1 );
DATA0_0.volume = 15;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_0, 1 );
DATA0_2.mode = 3;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_2, 1 );
DATA0_ext2.mixer_mode = 2;
DATA0_ext2.mic_level = 4;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext2, 2 );
DATA0_ext4.AGC_ctrl = 1;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext4, 2 );
DATA0_ext6.AGC_level = 3;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_DATA0, (char*)&DATA0_ext6, 2 );
/* register devices */
audio_dev_dsp = register_sound_dsp(&UDA1341_dsp_fops, -1);
audio_dev_mixer = register_sound_mixer(&UDA1341_mixer_fops, -1);
printk( AUDIO_NAME_VERBOSE " initialized\n" );
return 0;
}
.
## diffname bitsy/devuda1341.c 2000/1104
## diff -e /n/emeliedump/2000/1103/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1104/sys/src/9/bitsy/devuda1341.c
563,944d
367,536d
361,363d
233c
static void L3_sendbit(int bit)
.
214c
static int L3_getbit(void)
.
193c
static void L3_releasepins(void)
.
184c
static void L3_acquirepins(void)
.
156a
} input, output;
static struct
{
QLock;
Rendez vous;
int bufinit; /* boolean if buffers allocated */
int curcount; /* how much data in current buffer */
int active; /* boolean dma running */
int intr; /* boolean an interrupt has happened */
int amode; /* Aclosed/Aread/Awrite for /audio */
int rivol[Nvol]; /* right/left input/output volumes */
int livol[Nvol];
int rovol[Nvol];
int lovol[Nvol];
int major; /* SB16 major version number (sb 4) */
int minor; /* SB16 minor version number */
ulong totcount; /* how many bytes processed since open */
vlong tottime; /* time at which totcount bytes were processed */
Buf buf[Nbuf]; /* buffers and queues */
AQueue empty;
AQueue full;
Buf* current;
Buf* filling;
.
133a
.
127a
.
## diffname bitsy/devuda1341.c 2000/1107
## diff -e /n/emeliedump/2000/1104/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1107/sys/src/9/bitsy/devuda1341.c
462a
static void
audioinit(void)
{}
static Chan*
audioattach(char *param)
{
return devattach('A', param);
}
static int
audiowalk(Chan *c, char *name)
{
return devwalk(c, name, audiodir, nelem(audiodir), devgen);
}
static void
audiostat(Chan *c, char *db)
{
devstat(c, db, audiodir, nelem(audiodir), devgen);
}
static Chan*
audioopen(Chan *c, int omode)
{
int amode;
switch(c->qid.path & ~CHDIR) {
default:
error(Eperm);
break;
case Qstatus:
if((omode&7) != OREAD)
error(Eperm);
case Qvolume:
case Qdir:
break;
case Qaudio:
amode = Awrite;
switch (omode & 0x7)
case OREAD:
break;
case OWRITE
qlock(&audio);
if(audio.amode != Aclosed){
qunlock(&audio);
error(Einuse);
}
if(audio.bufinit == 0) {
audio.bufinit = 1;
sbbufinit();
}
audio.amode = amode;
setempty();
audio.curcount = 0;
qunlock(&audio);
mxvolume();
break;
}
c = devopen(c, omode, audiodir, nelem(audiodir), devgen);
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
static void
audioclose(Chan *c)
{
Buf *b;
switch(c->qid.path & ~CHDIR) {
default:
error(Eperm);
break;
case Qdir:
case Qvolume:
case Qstatus:
break;
case Qaudio:
if(c->flag & COPEN) {
qlock(&audio);
if(audio.amode == Awrite) {
/* flush out last partial buffer */
b = audio.filling;
if(b) {
audio.filling = 0;
memset(b->virt+audio.curcount, 0, Bufsize-audio.curcount);
swab(b->virt);
putbuf(&audio.full, b);
}
if(!audio.active && audio.full.first)
pokeaudio();
}
audio.amode = Aclosed;
if(waserror()){
qunlock(&audio);
nexterror();
}
while(audio.active)
waitaudio();
setempty();
poperror();
qunlock(&audio);
}
break;
}
}
static long
audioread(Chan *c, void *v, long n, vlong off)
{
int liv, riv, lov, rov;
long m, n0;
char buf[300];
Buf *b;
int j;
ulong offset = off;
char *a;
n0 = n;
a = v;
switch(c->qid.path & ~CHDIR) {
default:
error(Eperm);
break;
case Qdir:
return devdirread(c, a, n, audiodir, nelem(audiodir), devgen);
case Qaudio:
if(audio.amode != Aread)
error(Emode);
qlock(&audio);
if(waserror()){
qunlock(&audio);
nexterror();
}
while(n > 0) {
b = audio.filling;
if(b == 0) {
b = getbuf(&audio.full);
if(b == 0) {
waitaudio();
continue;
}
audio.filling = b;
swab(b->virt);
audio.curcount = 0;
}
m = Bufsize-audio.curcount;
if(m > n)
m = n;
memmove(a, b->virt+audio.curcount, m);
audio.curcount += m;
n -= m;
a += m;
if(audio.curcount >= Bufsize) {
audio.filling = 0;
putbuf(&audio.empty, b);
}
}
poperror();
qunlock(&audio);
break;
case Qstatus:
buf[0] = 0;
snprint(buf, sizeof(buf), "bytes %lud\ntime %lld\n",
audio.totcount, audio.tottime);
return readstr(offset, a, n, buf);
case Qvolume:
j = 0;
buf[0] = 0;
for(m=0; volumes[m].name; m++){
liv = audio.livol[m];
riv = audio.rivol[m];
lov = audio.lovol[m];
rov = audio.rovol[m];
j += snprint(buf+j, sizeof(buf)-j, "%s", volumes[m].name);
if((volumes[m].flag & Fmono) || liv==riv && lov==rov){
if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) && liv==lov)
j += snprint(buf+j, sizeof(buf)-j, " %d", liv);
else{
if(volumes[m].flag & Fin)
j += snprint(buf+j, sizeof(buf)-j,
" in %d", liv);
if(volumes[m].flag & Fout)
j += snprint(buf+j, sizeof(buf)-j,
" out %d", lov);
}
}else{
if((volumes[m].flag&(Fin|Fout))==(Fin|Fout) &&
liv==lov && riv==rov)
j += snprint(buf+j, sizeof(buf)-j,
" left %d right %d",
liv, riv);
else{
if(volumes[m].flag & Fin)
j += snprint(buf+j, sizeof(buf)-j,
" in left %d right %d",
liv, riv);
if(volumes[m].flag & Fout)
j += snprint(buf+j, sizeof(buf)-j,
" out left %d right %d",
lov, rov);
}
}
j += snprint(buf+j, sizeof(buf)-j, "\n");
}
return readstr(offset, a, n, buf);
}
return n0-n;
}
static long
audiowrite(Chan *c, void *vp, long n, vlong)
{
long m, n0;
int i, nf, v, left, right, in, out;
char buf[255], *field[Ncmd];
Buf *b;
char *a;
a = vp;
n0 = n;
switch(c->qid.path & ~CHDIR) {
default:
error(Eperm);
break;
case Qvolume:
v = Vaudio;
left = 1;
right = 1;
in = 1;
out = 1;
if(n > sizeof(buf)-1)
n = sizeof(buf)-1;
memmove(buf, a, n);
buf[n] = '\0';
nf = getfields(buf, field, Ncmd, 1, " \t\n");
for(i = 0; i < nf; i++){
/*
* a number is volume
*/
if(field[i][0] >= '0' && field[i][0] <= '9') {
m = strtoul(field[i], 0, 10);
if(left && out)
audio.lovol[v] = m;
if(left && in)
audio.livol[v] = m;
if(right && out)
audio.rovol[v] = m;
if(right && in)
audio.rivol[v] = m;
mxvolume();
goto cont0;
}
for(m=0; volumes[m].name; m++) {
if(strcmp(field[i], volumes[m].name) == 0) {
v = m;
in = 1;
out = 1;
left = 1;
right = 1;
goto cont0;
}
}
if(strcmp(field[i], "reset") == 0) {
resetlevel();
mxvolume();
goto cont0;
}
if(strcmp(field[i], "in") == 0) {
in = 1;
out = 0;
goto cont0;
}
if(strcmp(field[i], "out") == 0) {
in = 0;
out = 1;
goto cont0;
}
if(strcmp(field[i], "left") == 0) {
left = 1;
right = 0;
goto cont0;
}
if(strcmp(field[i], "right") == 0) {
left = 0;
right = 1;
goto cont0;
}
error(Evolume);
break;
cont0:;
}
break;
case Qaudio:
if(audio.amode != Awrite)
error(Emode);
qlock(&audio);
if(waserror()){
qunlock(&audio);
nexterror();
}
while(n > 0) {
b = audio.filling;
if(b == 0) {
b = getbuf(&audio.empty);
if(b == 0) {
waitaudio();
continue;
}
audio.filling = b;
audio.curcount = 0;
}
m = Bufsize-audio.curcount;
if(m > n)
m = n;
memmove(b->virt+audio.curcount, a, m);
audio.curcount += m;
n -= m;
a += m;
if(audio.curcount >= Bufsize) {
audio.filling = 0;
swab(b->virt);
putbuf(&audio.full, b);
}
}
poperror();
qunlock(&audio);
break;
}
return n0 - n;
}
Dev audiodevtab = {
'A',
"audio",
devreset,
audioinit,
audioattach,
devclone,
audiowalk,
audiostat,
audioopen,
devcreate,
audioclose,
audioread,
devbread,
audiowrite,
devbwrite,
devremove,
devwstat,
};
.
## diffname bitsy/devuda1341.c 2000/1108
## diff -e /n/emeliedump/2000/1107/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1108/sys/src/9/bitsy/devuda1341.c
515,517c
if (omode & AudioIn) {
/* read */
audio.amode |= AudioIn;
if((audio.bufinit & AudioIn) == 0) {
audio.bufinit |= AudioIn;
sbbufinit();
}
}
if (omode & 0x2) {
/* write */
audio.amode |= 0x2;
.
511c
omode++;
if(audio.amode & omode){
.
505,509c
if ((omode & 0x7) > 2)
error(Ebadarg);
.
## diffname bitsy/devuda1341.c 2000/1109
## diff -e /n/emeliedump/2000/1108/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1109/sys/src/9/bitsy/devuda1341.c
816c
qunlock(a);
.
808,812c
p += m;
if(a->filling->nbytes >= Bufsize) {
sendaudio(a);
a->filling++;
if (a->filling == &a->buf[Nbuf])
a->filling = a->buf;
.
806c
a->filling->nbytes += m;
.
804c
memmove(a->filling->buf + a->filling->nbytes, p, m);
.
801c
m = Bufsize - a->filling->nbytes;
.
790,799c
/* wait if dma in progress */
while (a->filling->active)
waitaudio(a);
.
786c
qunlock(a);
.
784c
a = &audio.o;
qlock(a);
.
782c
if((audio.amode & Awrite) == 0)
.
717c
memmove(buf, p, n);
.
702c
p = vp;
.
700c
char *p;
IOstate *a;
.
567,568d
560,564c
b = audio.o.filling;
if(audio.o.buf[b].count) {
.
558c
if(audio.amode & Awrite) {
.
529c
// mxvolume();
.
525,527d
523c
audio.amode |= Awrite;
if(audio.o.bufinit == 0)
bufinit(&audio.o);
setempty(&audio.o);
.
515,519c
audio.amode |= Aread;
if(audio.i.bufinit == 0)
bufinit(&audio.i);
setempty(&audio.i);
.
513c
if (omode & Aread) {
.
508d
505c
omode = (omode & 0x7) + 1;
if (omode & ~(Aread | Awrite))
.
490d
468d
465,466c
sendaudio(IOstat *b) {
if (dmastart(b->chan, b->current->virt, b->current->nbytes)) {
b->current->active++;
b->current++;
if (b->current == &b->buf[Nbuf])
b->current == &b->buf[0];
}
}
.
409,416c
for (i = 0; i < Nbuf; i++) {
b->buf[i].nbytes = 0;
b->buf[i].active = 0;
}
b->filling = b->buf;
b->current = b->buf;
.
407a
int i;
.
402,406c
static void
setempty(IOstate *b)
.
396,400c
for (i = 0; i < Nbuf; i++)
b->buf[i].virt = xalloc(Bufsize);
b->bufinit = 1;
};
.
394c
int i;
.
391,392c
static void
bufinit(IOstate *b)
.
164,183c
int amode; /* Aclosed/Aread/Awrite for /audio */
int intr; /* boolean an interrupt has happened */
int rivol[Nvol]; /* right/left input/output volumes */
int livol[Nvol];
int rovol[Nvol];
int lovol[Nvol];
ulong totcount; /* how many bytes processed since open */
vlong tottime; /* time at which totcount bytes were processed */
IOstate i;
IOstate o;
.
154,160d
140,152c
int bufinit; /* boolean, if buffers allocated */
Buf buf[Nbuf]; /* buffers and queues */
Buf *current; /* next candidate for dma */
Buf *filling; /* buffer being filled */
};
.
131,137d
129c
struct IOstate
.
125,126c
uint nbytes;
.
123a
int active; /* dma running */
.
107,108c
Bufsize = 8*1024, /* 46 ms each */
Nbuf = 32, /* 1.5 seconds total */
.
79a
typedef struct IOstate IOstate;
.
## diffname bitsy/devuda1341.c 2000/1110
## diff -e /n/emeliedump/2000/1109/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1110/sys/src/9/bitsy/devuda1341.c
770a
sendaudio(a);
.
767d
755,756c
while (a->active && a->filling == a->current)
sleep(&a->vous, audioqnotfull, a);
.
569,602d
540a
qunlock(&audio.o);
.
537,539c
if (audio.o.chan == c) {
/* closing the write end */
audio.amode &= ~Awrite;
while (audio.o.filling->nbytes) {
audio.o.filling++;
if (audio.o.filling == &audio.o.buf[Nbuf])
audio.o.filling = &audio.o.buf[0];
sendaudio(&audio.o);
}
while(!audioidle(&audio.o))
sleep(&audio.o.vous, audioidle, &audio.o);
audioamplifier(0);
setempty(&audio.o);
}
if (audio.i.chan == c) {
/* closing the read end */
audio.amode &= ~Aread;
setempty(&audio.i);
}
if (audio.amode == 0) {
/* turn audio off */
audiopower(0);
}
.
533a
qunlock(&audio.o);
.
525,532c
qlock(&audio.o);
.
510c
IOstate *b;
.
493a
audio.o.chan = c;
&audio.o.dma = dmaalloc(0, 0, 8, 2, AudioDMA, void *port, void (*f)(int, ulong))
.
489a
amplifierpower(1);
audiomute(0);
.
485a
audio.i.chan = c;
.
480a
audiopower(1);
.
474c
// if (omode & ~(Aread | Awrite))
if (omode & ~(Awrite))
.
435a
wakeup(s->vous);
.
434a
if (canlock(s)) {
sendaudio(s);
unlock(s);
}
.
430,432c
/* call this with lock held */
while (b->next != b->filling) {
assert(b->next->nbytes);
if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0)
break;
incref(&b->active);
b->next++;
if (b->next == &b->buf[Nbuf])
b->next == &b->buf[0];
}
}
static void
audiointr(void *x, ulong state) {
IOstate *s = x;
if (s == &audio.o) {
decref(&s->active);
/* Only interrupt routine touches s->current */
s->current->nbytes = 0;
s->current++;
.
423,424d
419,421c
print("audio enabled\n");
.
402a
sspregs->control0 = 0x10<<0 | 0x1<<4 | 1<<7 | 0x8<<8;
sspregs->control1 = 0<<3 + 0<<4 + 1<<5;
/* Enable the audio power */
set_bitsy_egpio(EGPIO_BITSY_CODEC_NRESET|EGPIO_BITSY_AUD_AMP_ON|EGPIO_BITSY_AUD_PWR_ON);
clr_bitsy_egpio(EGPIO_BITSY_QMUTE);
gpioregs->direction |= (GPIO_BITSY_CLK_SET0|GPIO_BITSY_CLK_SET1);
/* external clock configured for 44100 samples/sec */
GPSR = GPIO_BITSY_CLK_SET0;
GPCR = GPIO_BITSY_CLK_SET1;
printk("gpioregs->altfunc=%08x gpioregs->direction=%08x GPLR=%08x\n", gpioregs->altfunc, gpioregs->direction, GPLR);
printk("PPDR=%08x PPSR=%08x PPAR=%08x PPFR=%08x\n", PPDR, PPSR, PPAR, PPFR);
/* Wait for the UDA1341 to wake up */
mdelay(100);
printk("Ser4SSSR=%08x\n", Ser4SSSR);
audio_uda1341_reset();
.
401c
gpioregs->altfunc &= ~(GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM);
gpioregs->altfunc |= (GPIO_SSP_CLK);
gpioregs->direction &= ~(GPIO_SSP_CLK);
.
399c
/* Setup the uarts */
ppcregs->assignment &= ~(1<<18); /* Could be the other way round! */
.
397d
387,394d
385a
/* do nothing */
}
static void
audioenable(void)
{
.
382a
static int
audioqnotfull(IOstate *s)
{
/* called with lock */
return s->active == 0 || s->filling != s->current;
}
static int
audioqnotempty(IOstate *s)
{
/* called with lock */
return s->next != s->filling;
}
static int
audioidle(IOstate *s)
{
/* called with lock */
return s->active == 0;
}
.
380a
b->next = b->buf;
.
345c
static int
L3_read(char addr, char * data, int len)
.
327c
static int
L3_write(char addr, char *data, int len)
.
314c
µdelay(L3_ModeHoldTime);
.
309c
µdelay(L3_ModeSetupTime);
.
302,305c
default: /* Subsequent bytes */
gpioregs->clear = GPIO_L3_MODE_o;
µdelay(L3_HaltTime);
gpioregs->set = GPIO_L3_MODE_o;
.
300c
case 1: /* First data byte */
.
298c
case 0: /* Address mode - never valid */
.
295c
gpioregs->direction &= ~(GPIO_L3_SDA_io);
.
289c
static char
L3_getbyte(int mode)
.
277c
µdelay(L3_ModeHoldTime);
.
275c
gpioregs->set = GPIO_L3_MODE_o;
.
269c
µdelay(L3_ModeSetupTime);
.
262,265c
default: /* Subsequent bytes */
gpioregs->clear = GPIO_L3_MODE_o;
µdelay(L3_HaltTime);
gpioregs->set = GPIO_L3_MODE_o;
.
260c
case 1: /* First data byte */
.
257,258c
case 0: /* Address mode */
gpioregs->clear = GPIO_L3_MODE_o;
.
250c
static void
L3_sendbyte(char data, int mode)
.
241,242c
gpioregs->set = GPIO_L3_SCLK_o;
µdelay(L3_ClockHighTime);
.
239c
µdelay(L3_ClockLowTime);
.
236c
gpioregs->clear = GPIO_L3_SDA_io;
.
234c
gpioregs->set = GPIO_L3_SDA_io;
.
231c
gpioregs->clear = GPIO_L3_SCLK_o;
.
229c
static void
L3_sendbit(int bit)
.
219,220c
gpioregs->set = GPIO_L3_SCLK_o;
µdelay(L3_ClockHighTime);
.
217c
data = (gpioregs->level & GPIO_L3_SDA_io) ? 1 : 0;
.
214,215c
gpioregs->clear = GPIO_L3_SCLK_o;
µdelay(L3_ClockLowTime);
.
210c
static int
L3_getbit(void)
.
200,202c
gpioregs->altfunc &= ~(GPIO_L3_SDA_io | GPIO_L3_SCLK_o | GPIO_L3_MODE_o);
gpioregs->set = GPIO_L3_MODE_o;
gpioregs->direction |= GPIO_L3_MODE_o;
.
198c
static void
L3_init(void)
.
191,192c
gpioregs->direction &= ~(GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
gpioregs->clear = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
.
189c
static void
L3_releasepins(void)
.
182,183c
gpioregs->set = (GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
gpioregs->direction |= (GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
.
180c
static void
L3_acquirepins(void)
.
133,137c
Rendez vous;
Chan *chan; /* chan of open */
int dma; /* dma chan, alloc on open, free on close */
int bufinit; /* boolean, if buffers allocated */
Buf buf[Nbuf]; /* buffers and queues */
int active; /* # of dmas in progress */
volatile Buf *current; /* next dma to finish */
volatile Buf *next; /* next candidate for dma */
volatile Buf *filling; /* buffer being filled */
.
125d
19a
#include "sa1110dma.h"
.
## diffname bitsy/devuda1341.c 2000/1111
## diff -e /n/emeliedump/2000/1110/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1111/sys/src/9/bitsy/devuda1341.c
844c
Dev uda1341devtab = {
.
825c
memmove(a->filling->virt + a->filling->nbytes, p, m);
.
819c
while (a->active.ref && a->filling == a->current)
.
778,779c
// resetlevel();
// mxvolume();
.
762d
725d
651d
625c
amplifierpower(0);
.
592d
575c
audio.o.dma = dmaalloc(0, 0, 8, 2, AudioDMA, Port4MCP, audiointr, (void*)&audio.o);
.
568,569c
// amplifierpower(1);
// audiomute(0);
.
557c
audioenable();
.
510c
wakeup(&s->vous);
.
507c
unlock((Lock*)s);
.
503,505c
if (s->current == &s->buf[Nbuf])
s->current = &s->buf[0];
if (canlock((Lock*)s)) {
.
495c
audiointr(void *x, ulong) {
.
490c
b->next = &b->buf[0];
.
481c
sendaudio(IOstate *b) {
.
477c
/* write uda 1341 status[1] */
data[0] = 0x80 | 0x3<<UdaStatusPC | 1<<UdaStatusIGS | 1<<UdaStatusOGS;
L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1);
/* write uda 1341 data0[0] (volume) */
data[0] = 0x00 | /* volume */ 15 & 0x3f; /* 6 bits, others must be 0 */
L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 1);
/* write uda 1341 data0[2] (mode switch) */
data[0] = 0x80 | 3; /* mode = 3 */
L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 1);
/* set mixer mode and level */
data[0] = 0xc0 | 2 /* ext address */;
data[1] = 0xe0 | 2 | 4 << 2; /* mixer mode and mic level */
L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2);
/* set agc control and input amplifier gain */
data[0] = 0xc0 | 4 /* ext address */;
data[1] = 0xe0 | 1<<4 | 3; /* AGC control and input ampl gain */
L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2 );
/* set agc time constant and output level */
data[0] = 0xc0 | 6 /* ext address */;
data[1] = 0xe0 | 0<<2 | 3; /* agc time constant and output level */
L3_write(UDA1341_L3Addr<<2 | UDA1341_DATA0, data, 2 );
print("audio enabled\n");
.
475c
data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, data, 1 );
/* Reset done */
.
459,473c
gpioregs->clear = EGPIO_codec_reset;
gpioregs->set = EGPIO_codec_reset;
.
457c
/* Reset the chip */
data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */ | 1<<6 /* reset */;
L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );
.
454,455c
delay(100);
print("Ser4SSSR=0x%lux\n", sspregs->status);
.
450,452d
448a
gpioregs->direction |= (GPIO_CLK_SET0_o|GPIO_CLK_SET1_o);
/* external clock configured for 44100 samples/sec */
gpioregs->set = GPIO_CLK_SET0_o;
gpioregs->clear = GPIO_CLK_SET1_o;
.
442,447c
audiopower(1);
amplifierpower(1);
audiomute(0);
.
434,436c
gpioregs->altfunc &= ~(GPIO_SSP_TXD_o | GPIO_SSP_RXD_i | GPIO_SSP_SCLK_o | GPIO_SSP_SFRM_o);
gpioregs->altfunc |= (GPIO_SSP_CLK_i);
gpioregs->direction &= ~(GPIO_SSP_CLK_i);
.
427c
uchar data[2];
.
415c
return s->active.ref == 0;
.
413a
IOstate *s = x;
.
412c
audioidle(void *x)
.
401c
return s->active.ref == 0 || s->filling != s->current;
.
399a
IOstate *s = x;
.
398c
audioqnotfull(void *x)
.
390d
358c
L3_read(uchar addr, uchar *data, int len)
.
339c
L3_write(uchar addr, uchar *data, int len)
.
138c
Ref active; /* # of dmas in progress */
.
77a
#define UDA1341_L3Addr 5
.
74d
## diffname bitsy/devuda1341.c 2000/1113
## diff -e /n/emeliedump/2000/1111/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1113/sys/src/9/bitsy/devuda1341.c
822a
if (debug) print("#A: write %ld\n", n);
.
596a
if (debug) print("#A: open done\n");
.
500a
if (debug) print("#A: sendaudio\n");
.
495c
if (debug) print("#A: audio enabled\n");
.
387a
if (debug) print("#A: setempty\n");
.
377a
if (debug) print("#A: bufinit\n");
.
21a
static int debug = 1;
.
## diffname bitsy/devuda1341.c 2000/1114
## diff -e /n/emeliedump/2000/1113/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1114/sys/src/9/bitsy/devuda1341.c
598c
audio.o.dma = dmaalloc(0, 0, 8, 2, SSPXmitDMA, Port4SSP, audiointr, (void*)&audio.o);
.
587a
audio.i.chan = c;
audio.i.dma = dmaalloc(0, 0, 8, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o);
.
586d
## diffname bitsy/devuda1341.c 2000/1115
## diff -e /n/emeliedump/2000/1114/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1115/sys/src/9/bitsy/devuda1341.c
852a
if (debug > 1) print("#A: filled @%p\n", a->filling);
.
842a
}
.
841c
while (a->active.ref && a->filling == a->current) {
if (debug > 1) print("#A: sleep\n");
.
830c
if (debug > 1) print("#A: write %ld\n", n);
.
641c
if (audio.o.filling->nbytes) {
.
628a
if (debug > 1) print("#A: close\n");
.
602a
qunlock(&audio);
.
601d
528,531c
decref(&s->active);
sendaudio(s);
.
524c
if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current);
.
522d
514a
iunlock(&b->ilock);
.
510a
if (dmastart(b->dma, b->next->virt, b->next->nbytes) == 0) {
decref(&b->active);
break;
}
if (debug > 1) print("#A: dmastart @%p\n", b->next);
b->next->nbytes = 0;
.
508,509d
504,505c
/* interrupt routine calls this too */
if (debug > 1) print("#A: sendaudio\n");
ilock(&b->ilock);
.
498a
/* Reset the chip */
data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */ | 1<<6 /* reset */;
L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );
delay(10);
data[0] = 2<<4 /* system clock */ | 1<<1 /* lsb16 */;
L3_write( (UDA1341_L3Addr<<2)|UDA1341_STATUS, data, 1 );
/* Reset done */
.
465,466c
delay(10);
.
460a
gpioregs->clear = EGPIO_codec_reset;
gpioregs->set = EGPIO_codec_reset;
.
446a
sspregs->control0 |= 1<<7; /* enable */
.
444c
sspregs->control0 = 0xf<<0 | 0x1<<4 | 0x3<<8;
.
438c
ppcregs->assignment &= (1<<18); /* Could be the other way round! */
.
134a
Lock ilock;
.
## diffname bitsy/devuda1341.c 2000/1116
## diff -e /n/emeliedump/2000/1115/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1116/sys/src/9/bitsy/devuda1341.c
860c
while (!dmaidle(a->dma) && a->filling == a->current) {
.
682a
print("total dmas: %lud\n", iostats.totaldma);
print("dmas while idle: %lud\n", iostats.idledma);
print("dmas while busy: %lud\n", iostats.faildma);
.
669a
dmafree(audio.o.dma);
.
666,667c
delay(2000);
// dmawait(audio.o.dma);
if (!dmaidle(audio.o.dma))
print("dma still busy\n");
.
598a
memset(&iostats, 0, sizeof(iostats));
.
548,549c
if (ndma > 0)
sendaudio(s);
.
539c
audiointr(void *x, ulong ndma) {
.
528a
iostats.totaldma++;
if (n == 1) iostats.idledma++;
.
524,526c
if ((n = dmastart(b->dma, b->next->virt, b->next->nbytes)) == 0) {
iostats.faildma++;
.
519a
int n;
.
504,514c
if (debug) {
print("#A: audio enabled\n");
print("\tsspregs->control0 = 0x%lux\n", sspregs->control0);
print("\tsspregs->control1 = 0x%lux\n", sspregs->control1);
}
.
482c
data[0] = 15 & 0x3f; /* 6 bits, others must be 0 */
.
471,476d
469a
gpioregs->set = EGPIO_codec_reset;
gpioregs->clear = EGPIO_codec_reset;
/* write uda 1341 status[0] */
data[0] &= ~(1<<UdaStatusRST); /* clear reset */
L3_write(UDA1341_L3Addr<<2 | UDA1341_STATUS, data, 1 );
.
468c
data[0] = 2<<UdaStatusSC | 1<<UdaStatusIF | 1<<UdaStatusRST;
.
464,466d
462d
456,459c
/* This is purportedly the wrong way round: 0 should be set, 1 cleared */
gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
// gpioregs->clear = GPIO_CLK_SET1_o;
.
454a
/* external clock configured for 44100 samples/sec */
.
448,449d
445,446c
sspregs->control0 = 0;
sspregs->control0 = 0x031f; /* 16 bits, TI frames, serial clock rate 3 */
sspregs->control1 = 0x0020; /* ext clock */
sspregs->control0 = 0x039f; /* enable */
.
439c
ppcregs->assignment &= ~(1<<18);
.
410,424d
407c
return dmaidle(s->dma) || s->filling != s->current;
.
161a
static struct
{
ulong bytes;
ulong totaldma;
ulong idledma;
ulong faildma;
} iostats;
.
141d
## diffname bitsy/devuda1341.c 2000/1117
## diff -e /n/emeliedump/2000/1116/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1117/sys/src/9/bitsy/devuda1341.c
810,811c
resetlevel();
mxvolume();
.
674a
print("out of order dma: %lud\n", iostats.samedma);
.
671a
poperror();
.
669,670d
662a
indisable();
.
657,658c
setempty(s);
dmafree(s->dma);
qunlock(s);
poperror();
.
652,655c
dmawait(s->dma);
outdisable();
.
646,650c
if (s->filling->nbytes) {
/* send remaining partial buffer */
s->filling++;
if (s->filling == &s->buf[Nbuf])
s->filling = &s->buf[0];
sendaudio(s);
.
642a
s = &audio.o;
qlock(s);
if(waserror()){
qunlock(s);
nexterror();
}
.
638d
636d
620a
IOstate *s;
.
605c
mxvolume();
.
599,603c
if(s->bufinit == 0)
bufinit(s);
setempty(s);
s->chan = c;
s->dma = dmaalloc(0, 0, 4, 2, SSPXmitDMA, Port4SSP, audiointr, (void*)s);
.
594a
outenable();
s = &audio.o;
.
591,592c
s->chan = c;
s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)&audio.o);
.
585a
inenable();
s = &audio.i;
.
583c
enable();
.
559a
IOstate *s;
.
520c
iunlock(&s->ilock);
.
513,518c
switch (n) {
case 1:
iostats.idledma++;
break;
case 3:
iostats.faildma++;
break;
}
if (debug > 1) print("#A: dmastart @%p\n", s->next);
s->next->nbytes = 0;
s->next++;
if (s->next == &s->buf[Nbuf])
s->next = &s->buf[0];
.
505,508c
ilock(&s->ilock);
while (s->next != s->filling) {
assert(s->next->nbytes);
if ((n = dmastart(s->dma, s->next->virt, s->next->nbytes)) == 0) {
.
500c
outdisable(void) {
/* turn off DAC, clear output gain switch */
status1 &= ~0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
if (debug) {
print("uchar status1 = 0x%2.2ux\n", status1);
}
}
static void
inenable(void) {
/* turn on ADC, set input gain switch */
status1 |= 0x22;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
if (debug) {
print("uchar status1 = 0x%2.2ux\n", status1);
}
}
static void
indisable(void) {
/* turn off ADC, clear input gain switch */
status1 &= ~0x22;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
if (debug) {
print("uchar status1 = 0x%2.2ux\n", status1);
}
}
static void
sendaudio(IOstate *s) {
.
493,495c
print("uchar status1 = 0x%2.2ux\n", status1);
print("uchar data00 = 0x%2.2ux\n", data00);
.
491a
static void
outenable(void) {
/* turn on DAC, set output gain switch */
status1 |= 0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
/* set volume */
data00 |= 0xf;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1);
.
487,490c
}
.
482,485c
if(audio.amode & Aread){
left = audio.livol;
right = audio.rivol;
}
if(audio.amode & Awrite){
left = audio.lovol;
right = audio.rovol;
data00 &= ~0x3f;
data00 |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1);
if (debug) print("uchar data00 = 0x%2.2ux (audio out)\n", data00);
if (left[Vtreb]+right[Vtreb] <= 100
&& left[Vbass]+right[Vbass] <= 100) {
/* settings neutral */
data02 &= ~0x03;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1);
if (debug) print("uchar data02 = 0x%2.2ux (mode flat)\n", data02);
} else {
data02 |= 0x03;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1);
if (debug) print("uchar data02 = 0x%2.2ux (mode boost)\n", data02);
data01 |= ~0x3f;
data01 |= ((left[Vtreb]+right[Vtreb]-100)*0x3/100)&0x03;
data01 |= (((left[Vbass]+right[Vbass]-100)*0xf/100)&0xf)<<2;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data01, 1);
if (debug) print("uchar data01 = 0x%2.2ux (bass&treb)\n", data01);
}
}
.
477,480c
static void
mxvolume(void) {
int *left, *right;
.
473,475c
for(i=0; volumes[i].name; i++) {
audio.lovol[i] = volumes[i].ilval;
audio.rovol[i] = volumes[i].irval;
audio.livol[i] = volumes[i].ilval;
audio.rivol[i] = volumes[i].irval;
}
}
.
469,471c
static void
resetlevel(void)
{
int i;
.
465,467c
if (debug) {
print("uchar status0 = 0x%2.2ux\n", status0);
print("uchar status1 = 0x%2.2ux\n", status1);
print("uchar data02 = 0x%2.2ux\n", data02);
print("ushort data0e2 = 0x%4.4ux\n", data0e2);
print("ushort data0e4 = 0x%4.4ux\n", data0e4);
print("ushort data0e6 = 0x%4.4ux\n", data0e6);
print("#A: audio enabled\n");
print("\tsspregs->control0 = 0x%lux\n", sspregs->control0);
print("\tsspregs->control1 = 0x%lux\n", sspregs->control1);
}
}
.
462,463c
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status0, 1 );
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e2, 2);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 );
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e6, 2 );
.
460a
gpioregs->set = EGPIO_codec_reset;
.
457,459c
data = status0 | 1<<UdaStatusRST;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&data, 1 );
.
448,451c
gpioregs->set = GPIO_CLK_SET0_o;
gpioregs->clear = GPIO_CLK_SET1_o;
.
433,436d
431c
ppcregs->assignment &= ~(1<<18);
.
426c
ushort data;
.
424c
enable(void)
.
422a
uchar status0 = 0x22;
uchar status1 = 0x80;
uchar data00 = 0x00; /* volume control, bits 0 – 5 */
uchar data01 = 0x40;
uchar data02 = 0x90;
ushort data0e2 = 0xf2c2;
ushort data0e4 = 0xf3c4;
ushort data0e6 = 0xe3c6;
.
184,185c
[Vtreb] "treb", Fout|Fmono, 50, 50,
[Vbass] "bass", Fout|Fmono, 50, 50,
.
177,182c
[Vaudio] "audio", Fout|Fmono, 50, 50,
[Vmic] "mic", Fin, 0, 0,
.
166a
ulong samedma;
.
105d
101,103d
93c
Fin = 2,
.
79c
#define UDA1341_L3Addr 0x14
.
50,51c
#define L3_ClockHighTime 10 /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
#define L3_ClockLowTime 10 /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
.
44c
* L3 setup and hold times (expressed in µs)
.
## diffname bitsy/devuda1341.c 2000/1118
## diff -e /n/emeliedump/2000/1117/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1118/sys/src/9/bitsy/devuda1341.c
876a
if (m < 0 || m > 100)
error(Evolume);
.
838c
return readstr(offset, p, n, buf);
.
797c
return readstr(offset, p, n, buf);
.
791a
break;
.
790a
if (debug > 1) print("#A: read %ld\n", n);
if((audio.amode & Aread) == 0)
error(Emode);
s = &audio.o;
qlock(s);
if(waserror()){
qunlock(s);
nexterror();
}
while(n > 0) {
/* wait if dma in progress */
while (!dmaidle(s->dma) && s->emptying == s->next) {
if (debug > 1) print("#A: sleep\n");
sleep(&s->vous, audioqnotempty, s);
}
m = Bufsize - s->emptying->nbytes;
if(m > n)
m = n;
memmove(p, s->emptying->virt + s->emptying->nbytes, m);
s->emptying->nbytes -= m;
n -= m;
p += m;
if(s->emptying->nbytes == 0) {
if (debug > 1) print("#A: emptied @%p\n", s->emptying);
s->emptying++;
if (s->emptying == &s->buf[Nbuf])
s->emptying = s->buf;
sendaudio(s);
}
}
poperror();
qunlock(s);
.
788c
return devdirread(c, p, n, audiodir, nelem(audiodir), devgen);
.
781c
p = v;
.
778c
char *p;
IOstate *s;
.
753c
setempty(s);
dmafree(s->dma);
qunlock(s);
poperror();
.
751a
s = &audio.i;
qlock(s);
if(waserror()){
qunlock(s);
nexterror();
}
dmawait(s->dma);
.
731,733d
724a
/* closing the write end */
audio.amode &= ~Awrite;
.
673c
s->dma = dmaalloc(0, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s);
.
670,671c
bufinit(s);
setempty(s);
.
612a
} else if (s == &audio.i) {
/* Only interrupt routine touches s->current */
if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current);
s->current->nbytes = Bufsize;
s->current++;
if (s->current == &s->buf[Nbuf])
s->current = &s->buf[0];
if (ndma > 0)
recvaudio(s);
.
601a
recvaudio(IOstate *s) {
/* interrupt routine calls this too */
int n;
if (debug > 1) print("#A: recvaudio\n");
ilock(&s->ilock);
while (s->next != s->emptying) {
assert(s->next->nbytes == 0);
if ((n = dmastart(s->dma, s->next->phys, Bufsize)) == 0) {
iostats.faildma++;
break;
}
iostats.totaldma++;
switch (n) {
case 1:
iostats.idledma++;
break;
case 3:
iostats.faildma++;
break;
}
if (debug > 1) print("#A: dmastart @%p\n", s->next);
s->next++;
if (s->next == &s->buf[Nbuf])
s->next = &s->buf[0];
}
iunlock(&s->ilock);
}
static void
.
579c
if ((n = dmastart(s->dma, s->next->phys, s->next->nbytes)) == 0) {
.
497a
if (left[Vmic]+right[Vmic] == 0) {
/* Turn on automatic gain control (AGC) */
data0e4 |= 0x1000;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 );
} else {
int v;
/* Turn on manual gain control */
v = ((left[Vmic]+right[Vmic])*0x7f/200)&0x7f;
data0e4 &= ~0x1300;
data0e5 &= ~0x1f00;
data0e4 |= (v & 0x3)<<8;
data0e5 |= (v & 0x7c)<<6;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e4, 2 );
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data0e5, 2 );
}
.
462d
422c
/* there is no data0e3 */
ushort data0e4 = 0xe0c4;
ushort data0e5 = 0xe0c5;
.
420a
ushort data0e0 = 0xe0c0;
ushort data0e1 = 0xe0c1;
.
406d
401a
audioqnotempty(void *x)
{
IOstate *s = x;
return dmaidle(s->dma) || s->emptying != s->next;
}
static int
.
383a
b->buf[i].phys = PADDR(b->buf[i].virt);
}
.
382c
for (i = 0; i < Nbuf; i++) {
.
175c
[Vmic] "mic", Fin|Fmono, 0, 0,
.
139a
/* just be be cute (and to have defines like linux, a real operating system) */
#define emptying filling
.
124a
ulong phys;
.
80a
enum {
UDA1341_DATA0 = 0,
UDA1341_DATA1,
UDA1341_STATUS,
UDA1341_L3Addr = 0x14,
};
.
76,79d
46,52c
enum {
L3_DataSetupTime = 1, /* 190 ns */
L3_DataHoldTime = 1, /* 30 ns */
L3_ModeSetupTime = 1, /* 190 ns */
L3_ModeHoldTime = 1, /* 190 ns */
L3_ClockHighTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
L3_ClockLowTime = 10, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
L3_HaltTime = 1, /* 190 ns */
};
.
## diffname bitsy/devuda1341.c 2000/1120
## diff -e /n/emeliedump/2000/1118/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1120/sys/src/9/bitsy/devuda1341.c
1049a
mxvolume();
.
1025a
if(strcmp(field[i], "debug") == 0) {
debug = debug?0:1;
goto cont0;
}
.
1023d
905c
recvaudio(s);
.
762a
resetlevel();
.
557a
if (left[Vfilter]+right[Vfilter] == 0)
data02 &= ~0x10;
else
data02 |= 0x10;
if (left[Vinvert]+right[Vinvert] == 0)
status1 &= ~0x14;
else
status1 |= 0x14;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data00, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data01, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, (uchar*)&data02, 1);
if (debug) {
print("uchar status1 = 0x%2.2ux;\n", status1);
print("uchar data00 = 0x%2.2ux; /* audio out */\n", data00);
print("uchar data01 = 0x%2.2ux; /* bass&treb */\n", data01);
print("uchar data02 = 0x%2.2ux; /* mode */\n", data02);
}
.
555,556d
550,552c
data01 &= ~0x3f;
.
546,548c
else {
.
543c
&& left[Vbass]+right[Vbass] <= 100)
.
540,541d
514a
if (debug) print("mxvolume\n");
.
437c
uchar data02 = 0x80;
.
185,186c
[Vtreb] "treb", Fout|Fmono, 50, 50,
[Vbass] "bass", Fout|Fmono, 50, 50,
[Vfilter] "filter", Fout|Fmono, 0, 0,
[Vinvert] "invert", Fin|Fout|Fmono, 0, 0,
.
182,183c
[Vaudio] "audio", Fout|Fmono, 80, 80,
[Vmic] "mic", Fin|Fmono, 0, 0,
.
112c
Bufsize = 4*1024, /* 46 ms each */
.
109a
Vfilter,
Vinvert,
.
22c
static int debug = 0;
.
## diffname bitsy/devuda1341.c 2000/1121
## diff -e /n/emeliedump/2000/1120/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1121/sys/src/9/bitsy/devuda1341.c
916,922d
903c
while (!dmaidle(s->dma) && s->emptying == s->current) {
.
901a
if(s->emptying->nbytes == 0) {
if (debug > 1) print("#A: emptied @%p\n", s->emptying);
recvaudio(s);
s->emptying++;
if (s->emptying == &s->buf[Nbuf])
s->emptying = s->buf;
}
.
895c
s = &audio.i;
.
784,785c
c = devopen(c, mode, audiodir, nelem(audiodir), devgen);
c->mode = openmode(mode);
.
768,770d
765c
if (omode & Awrite) {
.
761a
s->emptying = &s->buf[Nbuf-1];
.
759c
if(s->bufinit == 0)
.
757d
744,745c
if (omode & ~(Aread | Awrite))
.
728a
int omode = mode;
.
726c
audioopen(Chan *c, int mode)
.
694,701c
else if (s == &audio.i)
.
686,692c
if (debug > 1) iprint("#A: audio interrupt @%p\n", s->current);
/* Only interrupt routine touches s->current */
s->current++;
if (s->current == &s->buf[Nbuf])
s->current = &s->buf[0];
if (ndma > 0) {
if (s == &audio.o)
.
593a
audiomute(1);
amplifierpower(0);
.
579a
amplifierpower(1);
audiomute(0);
.
467,468d
434c
/* Turn MCP operations off */
mcpregs = mapspecial(MCPREGS, 0x34);
mcpregs->status &= ~(1<<16);
sspregs = mapspecial(SSPREGS, 32);
.
430a
SSPregs *sspregs;
MCPregs *mcpregs;
.
420c
return dmaidle(s->dma) || s->emptying != s->current;
.
22c
static int debug = 2;
.
## diffname bitsy/devuda1341.c 2000/1122
## diff -e /n/emeliedump/2000/1121/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1122/sys/src/9/bitsy/devuda1341.c
1129a
audiopower,
.
856c
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0);
.
847d
832d
780c
if (debug) print("open done\n");
.
765c
s->dma = dmaalloc(1, 0, 4, 2, SSPRecvDMA, Port4SSP, audiointr, (void*)s);
.
695c
if (debug) {
if (debug > 1)
iprint("#A: audio interrupt @%p\n", s->current);
else
iprint("-");
}
.
683c
if (debug) {
if (debug > 1)
print("dmastart @%p\n", s->next);
else
iprint("+");
}
.
652c
if (debug) {
if (debug > 1)
print("dmastart @%p\n", s->next);
else
iprint("+");
}
.
630a
disable(void) {
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0);
}
static void
audiopower(int flag) {
if (flag) {
egpiobits(EGPIO_audio_power, 1);
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
} else {
/* power off */
egpiobits(EGPIO_audio_power, 0);
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 0);
}
}
static void
.
626c
print("indisable: status1 = 0x%2.2ux\n", status1);
.
621a
dmastop(audio.i.dma);
.
616c
print("inenable: status1 = 0x%2.2ux\n", status1);
.
612a
// egpiobits(EGPIO_audio_power, 1);
// audiomute(0);
.
607a
egpiobits(EGPIO_audio_power, 0);
.
606c
print("outdisable: status1 = 0x%2.2ux\n", status1);
.
602c
egpiobits(EGPIO_audio_power, 0);
.
599a
dmastop(audio.o.dma);
.
593,594c
print("outenable: status1 = 0x%2.2ux\n", status1);
print("outenable: data00 = 0x%2.2ux\n", data00);
.
585c
egpiobits(EGPIO_audio_power, 1);
.
579d
573,576c
print("mxvolume: status1 = 0x%2.2ux\n", status1);
print("mxvolume: data00 = 0x%2.2ux\n", data00);
print("mxvolume: data01 = 0x%2.2ux\n", data01);
print("mxvolume: data02 = 0x%2.2ux\n", data02);
.
567c
status1 |= 0x10;
.
565c
status1 &= ~0x10;
.
543c
if (left[Vinvert]+right[Vinvert] == 0)
status1 &= ~0x04;
else
status1 |= 0x04;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, (uchar*)&status1, 1);
if (debug) {
print("mxvolume: status1 = 0x%2.2ux\n", status1);
print("mxvolume: data0e4 = 0x%4.4ux\n", data0e4);
print("mxvolume: data0e5 = 0x%4.4ux\n", data0e5);
}
.
524d
495,503c
print("enable: status0 = 0x%2.2ux\n", status0);
print("enable: status1 = 0x%2.2ux\n", status1);
print("enable: data02 = 0x%2.2ux\n", data02);
print("enable: data0e2 = 0x%4.4ux\n", data0e2);
print("enable: data0e4 = 0x%4.4ux\n", data0e4);
print("enable: data0e6 = 0x%4.4ux\n", data0e6);
print("enable: sspregs->control0 = 0x%lux\n", sspregs->control0);
print("enable: sspregs->control1 = 0x%lux\n", sspregs->control1);
.
473c
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
.
406c
if (debug) print("setempty\n");
.
393c
if (debug) print("bufinit\n");
.
384a
void
audiomute(int on)
{
egpiobits(EGPIO_audio_mute, on);
}
.
22c
static int debug = 0;
.
## diffname bitsy/devuda1341.c 2000/1123
## diff -e /n/emeliedump/2000/1122/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1123/sys/src/9/bitsy/devuda1341.c
659,660c
if (audio.omode & Aread)
indisable();
if (audio.omode & Awrite)
outdisable();
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset | EGPIO_audio_power, 0);
.
653a
if (debug) {
iprint("audiopower %d\n", flag);
}
.
647,652c
void
.
627,628d
## diffname bitsy/devuda1341.c 2000/1125
## diff -e /n/emeliedump/2000/1123/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1125/sys/src/9/bitsy/devuda1341.c
823a
audio.amode |= Awrite;
.
813a
audio.amode |= Aread;
.
807d
733a
void
audiopower(int flag) {
IOstate *s;
if (debug) {
iprint("audiopower %d\n", flag);
}
if (flag) {
/* power on only when necessary */
if (audio.amode) {
egpiobits(EGPIO_audio_power | EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
enable();
if (audio.amode & Aread) {
inenable();
s = &audio.i;
dmareset(s->dma, 1, 0, 4, 2, SSPRecvDMA, Port4SSP);
recvaudio(s);
}
if (audio.amode & Awrite) {
outenable();
s = &audio.o;
dmareset(s->dma, 0, 0, 4, 2, SSPXmitDMA, Port4SSP);
sendaudio(s);
}
mxvolume();
}
} else {
/* power off */
if (audio.amode & Aread)
indisable();
if (audio.amode & Awrite)
outdisable();
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset | EGPIO_audio_power, 0);
}
}
.
645,662d
## diffname bitsy/devuda1341.c 2000/1130
## diff -e /n/emeliedump/2000/1125/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1130/sys/src/9/bitsy/devuda1341.c
925,928c
if (debug) {
print("total dmas: %lud\n", iostats.totaldma);
print("dmas while idle: %lud\n", iostats.idledma);
print("dmas while busy: %lud\n", iostats.faildma);
print("out of order dma: %lud\n", iostats.samedma);
}
.
## diffname bitsy/devuda1341.c 2000/1207
## diff -e /n/emeliedump/2000/1130/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1207/sys/src/9/bitsy/devuda1341.c
184,193c
[Vaudio] {"audio", Fout|Fmono, 80, 80},
[Vmic] {"mic", Fin|Fmono, 0, 0},
[Vtreb] {"treb", Fout|Fmono, 50, 50},
[Vbass] {"bass", Fout|Fmono, 50, 50},
[Vspeed] {"speed", Fin|Fout|Fmono, Speed, Speed},
[Vfilter] {"filter", Fout|Fmono, 0, 0},
[Vinvert] {"invert", Fin|Fout|Fmono, 0, 0},
[Nvol] {0}
.
## diffname bitsy/devuda1341.c 2000/1216
## diff -e /n/emeliedump/2000/1207/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2000/1216/sys/src/9/bitsy/devuda1341.c
842d
## diffname bitsy/devuda1341.c 2001/0331
## diff -e /n/emeliedump/2000/1216/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0331/sys/src/9/bitsy/devuda1341.c
942a
uchar voldata;
.
47,53c
L3_DataSetupTime = 10, /* 190 ns */
L3_DataHoldTime = 10, /* 30 ns */
L3_ModeSetupTime = 10, /* 190 ns */
L3_ModeHoldTime = 10, /* 190 ns */
L3_ClockHighTime = 100, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
L3_ClockLowTime = 100, /* 250 ns (min is 64*fs, 35µs @ 44.1 Khz) */
L3_HaltTime = 10, /* 190 ns */
.
## diffname bitsy/devuda1341.c 2001/0421
## diff -e /n/emeliedump/2001/0331/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0421/sys/src/9/bitsy/devuda1341.c
1127a
}
if(strcmp(field[i], "reg") == 0) {
if(nf < 3)
error(Evolume);
setreg(field[1], atoi(field[2]), nf == 4 ? atoi(field[3]):1);
return n0;
.
943d
639c
print("indisable: status1 = 0x%2.2ux\n", status1[0]);
.
636,637c
status1[0] &= ~0x22;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
.
628c
print("inenable: status1 = 0x%2.2ux\n", status1[0]);
.
625,626c
status1[0] |= 0x22;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
.
617c
print("outdisable: status1 = 0x%2.2ux\n", status1[0]);
.
614,615c
status1[0] &= ~0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
.
603,604c
print("outenable: status1 = 0x%2.2ux\n", status1[0]);
print("outenable: data00 = 0x%2.2ux\n", data00[0]);
.
600,601c
data00[0] |= 0xf;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1);
.
597,598c
status1[0] |= 0x41;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
.
592a
setreg(char *name, int val, int n)
{
uchar x[2];
int i;
x[0] = val;
x[1] = val>>8;
if(strcmp(name, "pause") == 0){
for(i = 0; i < n; i++)
µdelay(val);
return;
}
switch(n){
case 1:
case 2:
break;
default:
error("setreg");
}
if(strcmp(name, "status") == 0){
L3_write(UDA1341_L3Addr | UDA1341_STATUS, x, n);
} else if(strcmp(name, "data0") == 0){
L3_write(UDA1341_L3Addr | UDA1341_DATA0, x, n);
} else if(strcmp(name, "data1") == 0){
L3_write(UDA1341_L3Addr | UDA1341_DATA1, x, n);
} else
error("setreg");
}
static void
.
584,587c
print("mxvolume: status1 = 0x%2.2ux\n", status1[0]);
print("mxvolume: data00 = 0x%2.2ux\n", data00[0]);
print("mxvolume: data01 = 0x%2.2ux\n", data01[0]);
print("mxvolume: data02 = 0x%2.2ux\n", data02[0]);
.
578,582c
status1[0] |= 0x10;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data00, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data01, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1);
.
576c
status1[0] &= ~0x10;
.
574c
data02[0]|= 0x10;
.
572c
data02[0] &= ~0x10;
.
566,569c
data02[0] |= 0x03;
data01[0] &= ~0x3f;
data01[0] |= ((left[Vtreb]+right[Vtreb]-100)*0x3/100)&0x03;
data01[0] |= (((left[Vbass]+right[Vbass]-100)*0xf/100)&0xf)<<2;
.
564c
data02[0] &= ~0x03;
.
559,560c
data00[0] &= ~0x3f;
data00[0] |= ((200-left[Vaudio]-right[Vaudio])*0x3f/200)&0x3f;
.
551,553c
print("mxvolume: status1 = 0x%2.2ux\n", status1[0]);
print("mxvolume: data0e4 = 0x%4.4ux\n", data0e4[0]|data0e4[0]<<8);
print("mxvolume: data0e5 = 0x%4.4ux\n", data0e5[0]|data0e5[0]<<8);
.
548,549c
status1[0] |= 0x04;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
.
546c
status1[0] &= ~0x04;
.
538,543c
data0e4[1] &= ~0x13;
data0e5[1] &= ~0x1f;
data0e4[1] |= v & 0x3;
data0e5[0] |= (v & 0x7c)<<6;
data0e5[1] |= (v & 0x7c)>>2;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 );
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e5, 2 );
.
532,533c
data0e4[1] |= 0x10;
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e4, 2 );
.
499,504c
print("enable: status0 = 0x%2.2ux\n", status0[0]);
print("enable: status1 = 0x%2.2ux\n", status1[0]);
print("enable: data02 = 0x%2.2ux\n", data02[0]);
print("enable: data0e2 = 0x%4.4ux\n", data0e2[0] | data0e2[1]<<8);
print("enable: data0e4 = 0x%4.4ux\n", data0e4[0] | data0e4[1]<<8);
print("enable: data0e6 = 0x%4.4ux\n", data0e6[0] | data0e6[1]<<8);
.
492,496c
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1 );
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e2, 2);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e6, 2 );
.
487,488c
data[0] = status0[0] | 1<<UdaStatusRST;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, data, 1 );
.
464c
uchar data[1];
.
457,459c
uchar data0e4[2] = {0xc4, 0xe0};
uchar data0e5[2] = {0xc5, 0xe0};
uchar data0e6[2] = {0xc6, 0xe3};
.
448,455c
uchar status0[1] = {0x22};
uchar status1[1] = {0x80};
uchar data00[1] = {0x00}; /* volume control, bits 0 – 5 */
uchar data01[1] = {0x40};
uchar data02[1] = {0x80};
uchar data0e0[2] = {0xc0, 0xe0};
uchar data0e1[2] = {0xc1, 0xe0};
uchar data0e2[2] = {0xc2, 0xf2};
.
381a
*/
.
379c
L3_releasepins();
.
376a
gpioregs->direction &= ~(GPIO_L3_SDA_io);
.
375a
L3_acquirepins();
.
369c
* Commented out, not used
.
360c
L3_releasepins();
.
356a
L3_acquirepins();
.
318,319c
//suspect L3_acquirepins();
.
302c
//suspect L3_releasepins();
.
296a
µdelay(L3_ModeHoldTime);
.
277c
//suspect L3_acquirepins();
.
211d
201a
µdelay(2);
.
193a
static void setreg(char *name, int val, int n);
.
67,68c
UdaStatusPC = 0, /* 2 bits */
UdaStatusDS = 2, /* 1 bit */
.
62c
UdaStatusRST = 6, /* 1 bit */
.
47,53c
L3_DataSetupTime = 1, /* 190 ns */
L3_DataHoldTime = 1, /* 30 ns */
L3_ModeSetupTime = 1, /* 190 ns */
L3_ModeHoldTime = 1, /* 190 ns */
L3_ClockHighTime = 1, /* 100 ns */
L3_ClockLowTime = 1, /* 100 ns */
L3_HaltTime = 1, /* 190 ns */
.
## diffname bitsy/devuda1341.c 2001/0428
## diff -e /n/emeliedump/2001/0421/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0428/sys/src/9/bitsy/devuda1341.c
342,343d
322,323d
305,306d
299,300d
279,280d
223,224d
213c
gpioregs->direction &= ~(GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
µdelay(L3_ReleaseTime);
.
202,204c
gpioregs->set = (GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
gpioregs->direction |= (GPIO_L3_MODE_o | GPIO_L3_SCLK_o | GPIO_L3_SDA_io);
µdelay(L3_AcquireTime);
.
47,53c
L3_AcquireTime = 1,
L3_ReleaseTime = 1,
L3_DataSetupTime = (190+999)/1000, /* 190 ns */
L3_DataHoldTime = ( 30+999)/1000,
L3_ModeSetupTime = (190+999)/1000,
L3_ModeHoldTime = (190+999)/1000,
L3_ClockHighTime = (100+999)/1000,
L3_ClockLowTime = (100+999)/1000,
L3_HaltTime = (190+999)/1000,
.
## diffname bitsy/devuda1341.c 2001/0501
## diff -e /n/emeliedump/2001/0428/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0501/sys/src/9/bitsy/devuda1341.c
444a
.
22c
static int debug = 2;
.
## diffname bitsy/devuda1341.c 2001/0502
## diff -e /n/emeliedump/2001/0501/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0502/sys/src/9/bitsy/devuda1341.c
1012,1015c
m = (s->emptying->nbytes > n)? n: s->emptying->nbytes;
memmove(p, s->emptying->virt + Bufsize -
s->emptying->nbytes, m);
.
955d
935,949d
933d
931c
if ((audio.amode & Aread) == 0)
dmafree(s->dma);
.
928c
while(waserror()) {
dmawait(s->dma);
if (dmaidle(s->dma))
break;
}
.
917,920d
908,910c
if (audio.i.chan == c) {
/* closing the read end */
audio.amode &= ~Aread;
s = &audio.i;
qlock(s);
indisable();
setempty(s);
dmafree(s->dma);
qunlock(s);
if ((audio.amode & Awrite) == 0) {
s = &audio.o;
qlock(s);
while(waserror()) {
dmawait(s->dma);
if (dmaidle(s->dma))
break;
}
outdisable();
setempty(s);
dmafree(s->dma);
qunlock(s);
}
.
877a
if (audio.amode == Aread)
sendaudio(&audio.o);
.
874a
outenable();
.
873a
}
if (omode & Awrite) {
.
868d
865,866c
if (omode & (Aread|Awrite) && (audio.amode & Awrite) == 0) {
.
801c
} else if (s == &audio.i)
.
794,799c
if (s == &audio.i || (ndma & ~zerodma)) {
/* A dma, not of a zero buffer completed, update current
* Only interrupt routine touches s->current
*/
s->current->nbytes = (s == &audio.i)? Bufsize: 0;
s->current++;
if (s->current == &s->buf[Nbuf])
s->current = &s->buf[0];
}
if (ndma) {
if (s == &audio.o) {
zerodma &= ~ndma;
.
727c
switch (n >> 8) {
.
691c
switch (n >> 8) {
.
683a
if ((audio.amode & Aread) && s->next == s->filling && dmaidle(s->dma)) {
// send an empty buffer to provide an input clock
zerodma |= dmastart(s->dma, zeroes.phys, Bufsize) & 0xff;
if (zerodma == 0)
if (debug) print("emptyfail\n");
iostats.empties++;
iunlock(&s->ilock);
return;
}
.
401a
if (b == &audio.o) {
zeroes.virt = xalloc(Bufsize);
zeroes.phys = PADDR(b->buf[i].virt);
memset(zeroes.virt, 0, Bufsize);
}
.
399a
memset(b->buf[i].virt, 0xAA, Bufsize);
.
191,193c
[Vfilter] {"filter", Fout|Fmono, 0, 0},
[Vinvert] {"invert", Fin|Fout|Fmono, 0, 0},
[Nvol] {0}
.
186,189c
[Vaudio] {"audio", Fout|Fmono, 80, 80},
[Vmic] {"mic", Fin|Fmono, 0, 0},
[Vtreb] {"treb", Fout|Fmono, 50, 50},
[Vbass] {"bass", Fout|Fmono, 50, 50},
.
175a
ulong empties;
.
168a
Buf zeroes;
int zerodma; /* dma buffer used for sending zero */
.
150c
/* to have defines just like linux — there's a real operating system */
.
148c
volatile Buf *next; /* next candidate for dma */
.
142,146c
Rendez vous;
Chan *chan; /* chan of open */
int dma; /* dma chan, alloc on open, free on close */
int bufinit; /* boolean, if buffers allocated */
Buf buf[Nbuf]; /* buffers and queues */
.
22c
static int debug = 0;
.
## diffname bitsy/devuda1341.c 2001/0503
## diff -e /n/emeliedump/2001/0502/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0503/sys/src/9/bitsy/devuda1341.c
973,977c
while(waserror())
;
dmawait(s->dma);
poperror();
.
950,954c
while(waserror())
;
dmawait(s->dma);
poperror();
.
## diffname bitsy/devuda1341.c 2001/0504
## diff -e /n/emeliedump/2001/0503/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0504/sys/src/9/bitsy/devuda1341.c
905c
if (audio.amode & Aread)
.
## diffname bitsy/devuda1341.c 2001/0508
## diff -e /n/emeliedump/2001/0504/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0508/sys/src/9/bitsy/devuda1341.c
1221d
1217c
while (!dmaidle(a->dma) && !zerodma && a->filling == a->current) {
.
1121a
case Qspeed:
if(n > sizeof(buf)-1)
n = sizeof(buf)-1;
memmove(buf, p, n);
buf[n] = '\0';
nf = getfields(buf, field, Ncmd, 1, " \t\n");
if (nf != 2 && nf != 1) error(Ebadarg);
if (nf == 2) {
if (strcmp(field[0], "speed"))
error(Ebadarg);
i = 1;
}
else
i = 0;
mxspeed((int)strtol(field[i], (char **)nil, 0));
break;
.
1061a
case Qspeed:
buf[0] = '\0';
snprint(buf, sizeof(buf), "speed %d\n", rate);
return readstr(offset, p, n, buf);
.
930a
case Qspeed:
.
902a
mxspeed(Speed);
.
865a
case Qspeed:
.
697c
zerodma |= dmastart(s->dma, Flushbuf, Bufsize) & 0xff;
.
534a
mxspeed(int _rate)
{
uchar data;
egpiobits(EGPIO_audio_ic_power | EGPIO_codec_reset, 1);
/* set the external clock generator */
rate = _rate;
switch (rate) {
case 32000:
case 48000:
/* 00 */
gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
break;
default:
rate = 44100;
case 44100:
/* 01 */
gpioregs->set = GPIO_CLK_SET0_o;
gpioregs->clear = GPIO_CLK_SET1_o;
break;
case 8000:
case 16000:
/* 10 */
gpioregs->set = GPIO_CLK_SET1_o;
gpioregs->clear = GPIO_CLK_SET0_o;
break;
case 11025:
case 22050:
/* 11 */
gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
break;
}
delay(100);
switch (rate) {
case 8000:
case 11025:
data = SC512FS;
break;
case 16000:
case 22050:
case 44100:
case 48000:
data = SC256FS;
break;
case 32000:
data = SC384FS;
break;
}
data |= (LSB16 << 4)|0x2;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, &data, 1);
}
static void
.
472a
mxspeed(int _rate);
static void
.
407,412d
199a
static int rate = Speed; /* Current sample rate */
.
169d
127a
"speed", {Qspeed}, 0, 0666,
.
126c
"audio", {Qaudio}, 0, 0666,
.
122a
enum {
Flushbuf = 0xe0000000,
};
/* System Clock */
enum {
SC512FS = 0,
SC384FS = 1,
SC256FS = 2,
};
/* Format */
enum {
LSB16 = 1,
LSB18 = 2,
};
.
96a
Qspeed,
.
## diffname bitsy/devuda1341.c 2001/0509
## diff -e /n/emeliedump/2001/0508/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0509/sys/src/9/bitsy/devuda1341.c
1215c
i = (int)strtol(field[i], (char **)nil, 0);
switch (i) {
case 16000:
case 22050:
case 44100:
case 48000:
volumes[Vspeed].ilval = volumes[Vspeed].irval = rate = i;
break;
default:
error(Ebadarg);
}
.
975d
604a
static void
resetlevel(void)
{
int i;
for(i=0; volumes[i].name; i++) {
audio.lovol[i] = volumes[i].ilval;
audio.rovol[i] = volumes[i].irval;
audio.livol[i] = volumes[i].ilval;
audio.rivol[i] = volumes[i].irval;
}
}
.
603d
600,601c
data[0] = status0[0] | 1<<UdaStatusRST | clock;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, data, 1 );
if (debug)
print("enable: status0 = 0x%2.2ux\n", data[0]);
gpioregs->clear = EGPIO_codec_reset;
gpioregs->set = EGPIO_codec_reset;
/* write uda 1341 status[0] */
data[0] = status0[0] | clock;
L3_write(UDA1341_L3Addr | UDA1341_STATUS, data, 1);
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status1, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data02, 1);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e2, 2);
L3_write(UDA1341_L3Addr | UDA1341_DATA0, data0e6, 2 );
if (debug) {
print("enable: status0 = 0x%2.2ux\n", data[0]);
print("enable: status1 = 0x%2.2ux\n", status1[0]);
print("enable: data02 = 0x%2.2ux\n", data02[0]);
print("enable: data0e2 = 0x%4.4ux\n", data0e2[0] | data0e2[1]<<8);
print("enable: data0e4 = 0x%4.4ux\n", data0e4[0] | data0e4[1]<<8);
print("enable: data0e6 = 0x%4.4ux\n", data0e6[0] | data0e6[1]<<8);
print("enable: sspregs->control0 = 0x%lux\n", sspregs->control0);
print("enable: sspregs->control1 = 0x%lux\n", sspregs->control1);
}
.
597c
clock = SC384FS; /* Only works in MSB mode! */
.
594c
clock = SC256FS;
.
589a
default:
.
588c
clock = SC512FS; /* Only works in MSB mode! */
.
584a
/* Reset the chip */
.
582a
/* Wait for the UDA1341 to wake up */
.
507,557d
491c
uchar data[1], clock;
.
486,488d
472c
uchar status0[1] = {0x02};
.
137,138c
LSB16 = 1 << 1,
LSB18 = 2 << 1,
LSB20 = 3 << 1,
MSB = 4 << 1,
MSB16 = 5 << 1,
MSB18 = 6 << 1,
MSB20 = 7 << 1,
.
130,132c
SC512FS = 0 << 2,
SC384FS = 1 << 2,
SC256FS = 2 << 2,
.
128c
/* System Clock -- according to the manual, it seems that when the UDA is
configured in non MSB/I2S mode, it uses a divisor of 256 to the 12.288MHz
clock. The other rates are only supported in MSB mode, which should be
implemented at some point */
.
117c
Bufsize = /* 4* */ 1024, /* 46 ms each */
.
## diffname bitsy/devuda1341.c 2001/0510
## diff -e /n/emeliedump/2001/0509/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0510/sys/src/9/bitsy/devuda1341.c
1327c
if(a->filling->nbytes >= bufsize) {
.
1319c
m = bufsize - a->filling->nbytes;
.
1207,1216c
while (i < nf) {
int newval;
if (i + 1 >= nf) error(Ebadarg);
newval = (int)strtol(field[i + 1], (char **)nil, 0);
if (!strcmp(field[i], "speed"))
setrate(newval);
else if (!strcmp(field[i], "dmasize"))
setbufsize(newval);
else
error(Ebadarg);
i += 2;
}
.
1199,1205c
if (nf == 1)
/* The user just supplied a number */
setrate((int)strtol(field[0], (char **)nil, 0));
else {
.
1176a
static void
setrate(int newrate)
{
switch (newrate) {
case 16000:
case 22050:
case 44100:
case 48000:
volumes[Vspeed].ilval = volumes[Vspeed].irval = rate = newrate;
break;
default:
error(Ebadarg);
}
}
static void
setbufsize(int newbufsize)
{
if (newbufsize < 0 || newbufsize > 8 * 1024 || newbufsize % sizeof(ulong))
error(Ebadarg);
bufsize = newbufsize;
}
.
1130c
snprint(buf, sizeof(buf), "speed %d\ndmasize %d\n", rate, bufsize);
.
1110c
memmove(p, s->emptying->virt + bufsize -
.
882c
s->current->nbytes = (s == &audio.i)? bufsize: 0;
.
806c
if ((n = dmastart(s->dma, s->next->phys, bufsize)) == 0) {
.
761c
zerodma |= dmastart(s->dma, Flushbuf, bufsize) & 0xff;
.
226a
static int bufsize = Bufsize; /* Current buffer size */
.
225d
117c
Bufsize = 4* 1024, /* 46 ms each */
.
## diffname bitsy/devuda1341.c 2001/0512
## diff -e /n/emeliedump/2001/0510/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0512/sys/src/9/bitsy/devuda1341.c
118c
Nbuf = 10, /* 1.5 seconds total */
.
## diffname bitsy/devuda1341.c 2001/0526
## diff -e /n/emeliedump/2001/0512/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0526/sys/src/9/bitsy/devuda1341.c
1130c
snprint(buf, sizeof(buf), "speed %d\ndmasize %d\nsendbytes %d\n", rate, bufsize, nsendb);
.
1128a
s = &audio.o;
nbufs = s->filling - s->current;
if (nbufs < 0) nbufs = Nbuf + nbufs;
nsendb = (nbufs - 1) * bufsize + s->current->nbytes;
.
1067c
int liv, riv, lov, rov, nsendb, nbufs;
.
140,146c
LSB16 = 1 << 1,
LSB18 = 2 << 1,
LSB20 = 3 << 1,
MSB = 4 << 1,
MSB16 = 5 << 1,
MSB18 = 6 << 1,
MSB20 = 7 << 1,
.
121c
Ncmd = 50, /* max volume command words */
.
118c
Nbuf = 10, /* 1.5 seconds total */
.
102c
Fout = 4,
.
## diffname bitsy/devuda1341.c 2001/0528
## diff -e /n/emeliedump/2001/0526/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0528/sys/src/9/bitsy/devuda1341.c
1376d
1215c
switch((ulong)c->qid.path) {
.
1077c
switch((ulong)c->qid.path) {
.
989c
switch((ulong)c->qid.path) {
.
921c
switch((ulong)c->qid.path) {
.
912c
return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
.
909,910c
static int
audiostat(Chan *c, uchar *db, int n)
.
906c
return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
.
904c
audiowalk(Chan *c, Chan *nc, char **name, int nname)
.
774,789d
769,772c
s->next->nbytes &= ~0x3; /* must be a multiple of 4 */
if(s->next->nbytes) {
if ((n = dmastart(s->dma, s->next->phys, s->next->nbytes)) == 0) {
iostats.faildma++;
break;
}
iostats.totaldma++;
switch (n >> 8) {
case 1:
iostats.idledma++;
break;
case 3:
iostats.faildma++;
break;
}
if (debug) {
if (debug > 1)
print("dmastart @%p\n", s->next);
else
iprint("+");
}
s->next->nbytes = 0;
.
151a
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
.
12a
.
## diffname bitsy/devuda1341.c 2001/0529
## diff -e /n/emeliedump/2001/0528/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0529/sys/src/9/bitsy/devuda1341.c
907c
static Walkqid*
.
## diffname bitsy/devuda1341.c 2001/0530
## diff -e /n/emeliedump/2001/0529/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0530/sys/src/9/bitsy/devuda1341.c
118,119c
Bufsize = 4* 1024, /* 23 ms each */
Nbuf = 10, /* 230 ms total */
.
## diffname bitsy/devuda1341.c 2001/0605
## diff -e /n/emeliedump/2001/0530/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0605/sys/src/9/bitsy/devuda1341.c
1358c
if(a->filling->nbytes >= volumes[Vbufsize].ilval) {
.
1350c
m = volumes[Vbufsize].ilval - a->filling->nbytes;
.
1269,1278c
if (volumes[v].setval)
volumes[v].setval(in, out, left, right, m);
.
1224,1250d
1205c
volumes[Vbufsize].ilval = value;
.
1203c
if ((value % 8) != 0 || value < 8 || value >= Bufsize)
.
1201c
setbufsize(int, int, int, int, int value)
.
1197a
/* Wait for the UDA1341 to wake up */
delay(100);
/* Reset the chip */
status0[0] &= ~CLOCKMASK;
status0[0] |=clock;
volumes[Vspeed].ilval = speed;
.
1196c
speed = 44100;
case 44100:
/* 01 */
gpioregs->set = GPIO_CLK_SET0_o;
gpioregs->clear = GPIO_CLK_SET1_o;
clock = SC256FS;
break;
case 8000:
/* 10 */
gpioregs->set = GPIO_CLK_SET1_o;
gpioregs->clear = GPIO_CLK_SET0_o;
clock = SC512FS; /* Only works in MSB mode! */
break;
case 16000:
/* 10 */
gpioregs->set = GPIO_CLK_SET1_o;
gpioregs->clear = GPIO_CLK_SET0_o;
clock = SC256FS;
break;
case 11025:
/* 11 */
gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
clock = SC512FS; /* Only works in MSB mode! */
break;
case 22050:
/* 11 */
gpioregs->set = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
clock = SC256FS;
break;
.
1193c
/* 00 */
gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
clock = SC256FS;
.
1188,1191c
if (value < 0 || value > 100)
error(Evolume);
if(left && out)
audio.lovol[Vaudio] = value;
if(left && in)
audio.livol[Vaudio] = value;
if(right && out)
audio.rovol[Vaudio] = value;
if(right && in)
audio.rivol[Vaudio] = value;
}
static void
setspeed(int, int, int, int, int speed)
{
uchar clock;
/* external clock configured for 44100 samples/sec */
switch (speed) {
case 32000:
/* 00 */
gpioregs->clear = GPIO_CLK_SET0_o|GPIO_CLK_SET1_o;
clock = SC384FS; /* Only works in MSB mode! */
break;
.
1186c
setaudio(int in, int out, int left, int right, int value)
.
1145,1148c
if (m == Vaudio) {
liv = audio.livol[m];
riv = audio.rivol[m];
lov = audio.lovol[m];
rov = audio.rovol[m];
}
else {
lov = liv = volumes[m].ilval;
rov = riv = volumes[m].irval;
}
.
1132,1138c
case Qstats:
buf[0] = 0;
snprint(buf, sizeof(buf),
"bytes %lud\nRX dmas %lud, while idle %lud, while busy %lud, "
"out-of-order %lud, empty dmas %lud\n"
"TX dmas %lud, while idle %lud, while busy %lud, "
"out-of-order %lud, empty dmas %lud\n",
iostats.bytes, iostats.rx.totaldma, iostats.rx.idledma,
iostats.rx.faildma, iostats.rx.samedma, iostats.rx.empties,
iostats.tx.totaldma, iostats.tx.idledma,
iostats.tx.faildma, iostats.tx.samedma, iostats.tx.empties);
.
1114c
memmove(p, s->emptying->virt + volumes[Vbufsize].ilval -
.
1071c
int liv, riv, lov, rov;
.
1057,1062d
1001a
case Qstats:
.
1000d
934d
930a
case Qstats:
.
916c
return devstat(c, db, n, audiodir, nelem(audiodir), devgen);
.
910c
return devwalk(c, nc, name, nname, audiodir, nelem(audiodir), devgen);
.
886c
s->current->nbytes = (s == &audio.i)? volumes[Vbufsize].ilval: 0;
.
820c
iostats.rx.faildma++;
.
817c
iostats.rx.idledma++;
.
814c
iostats.rx.totaldma++;
.
810,811c
if ((n = dmastart(s->dma, s->next->phys, volumes[Vbufsize].ilval)) == 0) {
iostats.rx.faildma++;
.
783c
iostats.tx.faildma++;
.
780c
iostats.tx.idledma++;
.
777c
iostats.tx.totaldma++;
.
774c
iostats.tx.faildma++;
.
766c
iostats.tx.empties++;
.
763c
zerodma |= dmastart(s->dma, Flushbuf, volumes[Vbufsize].ilval) & 0xff;
.
603a
setspeed(0, 0, 0, 0, volumes[Vspeed].ilval);
if (!dmaidle(audio.i.dma) || !dmaidle(audio.o.dma))
L3_write(UDA1341_L3Addr | UDA1341_STATUS, status0, 1);
.
569a
if (debug)
print("enable: status0 = 0x%2.2ux\n", data[0]);
.
568c
data[0] = status0[0];
.
562,564d
540,560c
data[0] = status0[0] | 1 << UdaStatusRST;
.
513,538c
setspeed(0, 0, 0, 0, volumes[Vspeed].ilval);
.
498c
uchar data[1];
.
227,228d
218,224c
[Vaudio] {"audio", Fout|Fmono, 80, 80, setaudio },
[Vmic] {"mic", Fin|Fmono, 0, 0, nil },
[Vtreb] {"treb", Fout|Fmono, 50, 50, nil },
[Vbass] {"bass", Fout|Fmono, 50, 50, nil },
[Vspeed] {"speed", Fin|Fout|Fmono, Speed, Speed, setspeed },
[Vbufsize] {"bufsize", Fin|Fout|Fmono, Bufsize, Bufsize, setbufsize },
[Vfilter] {"filter", Fout|Fmono, 0, 0, nil },
[Vinvert] {"invert", Fin|Fout|Fmono, 0, 0, nil },
.
213,215c
int flag;
int ilval; /* initial values */
int irval;
void (*setval)(int, int, int, int, int);
.
209a
static void setaudio(int in, int out, int left, int right, int value);
static void setspeed(int in, int out, int left, int right, int value);
static void setbufsize(int in, int out, int left, int right, int value);
.
207a
} iostats_t;
static struct
{
ulong bytes;
iostats_t rx, tx;
.
200,202c
typedef struct {
.
153,157c
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"audio", {Qaudio}, 0, 0666,
"volume", {Qvolume}, 0, 0666,
"audiostatus", {Qstatus}, 0, 0444,
"audiostats", {Qstats}, 0, 0444,
.
136a
CLOCKMASK = 3 << 2,
.
118,119c
Bufsize = 4* 1024, /* 46 ms each */
Nbuf = 10, /* 1.5 seconds total */
.
113a
Vbufsize,
.
99a
Qstats,
.
98d
13d
## diffname bitsy/devuda1341.c 2001/0620
## diff -e /n/emeliedump/2001/0605/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0620/sys/src/9/bitsy/devuda1341.c
1086d
944a
qunlock(&audio);
.
942d
## diffname bitsy/devuda1341.c 2001/0810
## diff -e /n/emeliedump/2001/0620/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/0810/sys/src/9/bitsy/devuda1341.c
1023c
egpiobits(EGPIO_codec_reset, 0);
audioicpower(0);
.
837c
egpiobits(EGPIO_codec_reset, 0);
audioamppower(0);
audioicpower(0);
.
815c
audioamppower(1);
audioicpower(1);
egpiobits(EGPIO_codec_reset, 1);
.
699c
audioamppower(0);
.
693d
675c
audioamppower(1);
.
520c
audioicpower(1);
egpiobits(EGPIO_codec_reset, 1);
.
## diffname bitsy/devuda1341.c 2001/1117
## diff -e /n/emeliedump/2001/0810/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/1117/sys/src/9/bitsy/devuda1341.c
1273c
nf = tokenize(buf, field, Ncmd);
.
## diffname bitsy/devuda1341.c 2001/1121
## diff -e /n/emeliedump/2001/1117/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2001/1121/sys/src/9/bitsy/devuda1341.c
1334a
poperror();
free(cb);
.
1327c
setreg(cb->f[1], atoi(cb->f[2]), cb->nf == 4 ? atoi(cb->f[3]):1);
.
1324,1325c
if(strcmp(cb->f[i], "reg") == 0) {
if(cb->nf < 3)
.
1319c
if(strcmp(cb->f[i], "right") == 0) {
.
1314c
if(strcmp(cb->f[i], "left") == 0) {
.
1309c
if(strcmp(cb->f[i], "out") == 0) {
.
1304c
if(strcmp(cb->f[i], "in") == 0) {
.
1300c
if(strcmp(cb->f[i], "debug") == 0) {
.
1296c
if(strcmp(cb->f[i], "reset") == 0) {
.
1286c
if(strcmp(cb->f[i], volumes[m].name) == 0) {
.
1278,1279c
if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
m = strtoul(cb->f[i], 0, 10);
.
1273,1274c
for(i = 0; i < cb->nf; i++){
.
1268,1271c
cb = parsecmd(p, n);
if(waserror()){
free(cb);
nexterror();
}
.
1253a
Cmdbuf *cb;
.
1250,1251c
int i, v, left, right, in, out;
.
237a
.
## diffname bitsy/devuda1341.c 2002/0109
## diff -e /n/emeliedump/2001/1121/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2002/0109/sys/src/9/bitsy/devuda1341.c
1384a
devshutdown,
.
## diffname bitsy/devuda1341.c 2002/0606
## diff -e /n/emeliedump/2002/0109/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2002/0606/sys/src/9/bitsy/devuda1341.c
652c
microdelay(val);
.
377c
microdelay(L3_ModeHoldTime);
.
372c
microdelay(L3_ModeSetupTime);
.
367c
microdelay(L3_HaltTime);
.
344c
microdelay(L3_ModeHoldTime);
.
336c
microdelay(L3_ModeSetupTime);
.
331c
microdelay(L3_HaltTime);
.
310c
microdelay(L3_ClockHighTime);
.
307c
microdelay(L3_ClockLowTime);
.
287c
microdelay(L3_ClockHighTime);
.
282c
microdelay(L3_ClockLowTime);
.
259c
microdelay(L3_ReleaseTime);
.
249c
microdelay(L3_AcquireTime);
.
## diffname bitsy/devuda1341.c 2002/1112
## diff -e /n/emeliedump/2002/0606/sys/src/9/bitsy/devuda1341.c /n/emeliedump/2002/1112/sys/src/9/bitsy/devuda1341.c
488c
sspregs = mapspecial(SSPREGS, sizeof(SSPregs));
.
485c
mcpregs = mapspecial(MCPREGS, sizeof(MCPregs));
.
|