1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-15 10:17:20 +00:00

update of Luigi's sound drivers...

this updates to 971117 plus a small sb change that was after that release..
This commit is contained in:
John-Mark Gurney 1997-11-23 07:03:21 +00:00
parent 8fddd06099
commit 60dc9be97b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=31361
16 changed files with 1012 additions and 467 deletions

View File

@ -197,7 +197,7 @@ mss_attach(struct isa_device *dev)
printf("mss_attach <%s>%d at 0x%x irq %d dma %d:%d flags 0x%x\n",
d->name, dev->id_unit,
d->io_base, d->irq, d->dma1, d->dma2, dev->id_flags);
d->io_base, d->irq, d->dbuf_out.chan, d->dbuf_in.chan, dev->id_flags);
dev->id_alive = 8 ; /* number of io ports */
/* should be already set but just in case... */
@ -220,18 +220,18 @@ mss_attach(struct isa_device *dev)
printf("[IRQ Conflict?]");
/* Write IRQ+DMA setup */
if (d->dma1 == d->dma2) /* single chan dma */
outb(dev->id_iobase, bits | dma_bits[d->dma1]);
if ( ! FULL_DUPLEX(d) ) /* single chan dma */
outb(dev->id_iobase, bits | dma_bits[d->dbuf_out.chan]);
else {
if (d->dma1 == 0 && d->dma2 == 1)
if (d->dbuf_out.chan == 0 && d->dbuf_in.chan == 1)
bits |= 5 ;
else if (d->dma1 == 1 && d->dma2 == 0)
else if (d->dbuf_out.chan == 1 && d->dbuf_in.chan == 0)
bits |= 6 ;
else if (d->dma1 == 3 && d->dma2 == 0)
else if (d->dbuf_out.chan == 3 && d->dbuf_in.chan == 0)
bits |= 7 ;
else {
printf("invalid dual dma config %d:%d\n",
d->dma1, d->dma2);
d->dbuf_out.chan, d->dbuf_in.chan);
dev->id_irq = 0 ;
dev->id_alive = 0 ; /* this makes attach fail. */
return 0 ;
@ -239,7 +239,7 @@ mss_attach(struct isa_device *dev)
outb(dev->id_iobase, bits );
}
}
if (d->dma1 != d->dma2)
if ( FULL_DUPLEX(d) )
d->audio_fmt |= AFMT_FULLDUPLEX ;
mss_reinit(d);
ad1848_mixer_reset(d);
@ -293,6 +293,9 @@ mss_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
if (flags & O_NONBLOCK)
d->flags |= SND_F_NBIO ;
@ -426,7 +429,7 @@ mss_callback(snddev_info *d, int reason)
if (retry == 0)
printf("start dma, failed to set bit 0x%02x 0x%02x\n",
m, ad_read(d, 9) ) ;
if (wr || (d->dma1 == d->dma2) )
if (wr || ! FULL_DUPLEX(d) )
ad_write_cnt(d, 14, cnt);
else
ad_write_cnt(d, 30, cnt);
@ -452,7 +455,7 @@ mss_callback(snddev_info *d, int reason)
* is needed, and it might cause false interrupts when the
* DMA is re-enabled later.
*/
if (wr || (d->dma1 == d->dma2) )
if (wr || ! FULL_DUPLEX(d) )
ad_write_cnt(d, 14, 0);
else
ad_write_cnt(d, 30, 0);
@ -492,7 +495,7 @@ mss_intr(int unit)
*/
for (i=10 ; i && inb(io_Status(d)) & 1 ; i-- ) {
/* get exact reason for full-duplex boards */
c = (d->dma1 == d->dma2) ? 0x30 : ad_read(d, 24);
c = FULL_DUPLEX(d) ? ad_read(d, 24) : 0x30 ;
c &= ~served ;
if ( d->dbuf_out.dl && (c & 0x10) ) {
served |= 0x10 ;
@ -505,10 +508,18 @@ mss_intr(int unit)
/*
* now ack the interrupt
*/
if (d->dma1 == d->dma2)
outb(io_Status(d), 0); /* Clear interrupt status */
else
if ( FULL_DUPLEX(d) )
ad_write(d, 24, ~c); /* ack selectively */
else
outb(io_Status(d), 0); /* Clear interrupt status */
}
if (served == 0) {
printf("How strange... mss_intr with no reason!\n");
/*
* this should not happen... I have no idea what to do now.
* maybe should do a sanity check and restart dmas ?
*/
outb(io_Status(d), 0); /* Clear interrupt status */
}
}
@ -534,7 +545,7 @@ opti931_intr(int unit)
i11 = ad_read(d, 11); /* XXX what's for ? */
again:
c=mc11 = (d->dma1 == d->dma2) ? 0xc : opti_read(d->conf_base, 11);
c=mc11 = FULL_DUPLEX(d) ? opti_read(d->conf_base, 11) : 0xc ;
mc11 &= 0x0c ;
if (c & 0x10) {
printf("Warning: CD interrupt\n");
@ -791,7 +802,7 @@ mss_set_recsrc(snddev_info *d, int mask)
*/
static char mix_cvt[101] = {
0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
0, 1, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,
65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,
80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,
@ -849,8 +860,12 @@ mss_mixer_set(snddev_info *d, int dev, int value)
regoffs = (*mix_d)[dev][LEFT_CHN].regno;
old = val = ad_read(d, regoffs);
if (regoffs != 0)
val = old & 0x7f ; /* clear mute bit. */
/*
* if volume is 0, mute chan. Otherwise, unmute.
*/
if (regoffs != 0) /* main input is different */
val = (left == 0 ) ? old | 0x80 : old & 0x7f ;
change_bits(mix_d, &val, dev, LEFT_CHN, left);
ad_write(d, regoffs, val);
DEB(printf("LEFT: dev %d reg %d old 0x%02x new 0x%02x\n",
@ -863,7 +878,7 @@ mss_mixer_set(snddev_info *d, int dev, int value)
regoffs = (*mix_d)[dev][RIGHT_CHN].regno;
old = val = ad_read(d, regoffs);
if (regoffs != 1)
val = old & 0x7f ; /* clear mute bit. */
val = (right == 0 ) ? old | 0x80 : old & 0x7f ;
change_bits(mix_d, &val, dev, RIGHT_CHN, right);
ad_write(d, regoffs, val);
DEB(printf("RIGHT: dev %d reg %d old 0x%02x new 0x%02x\n",
@ -1261,7 +1276,7 @@ mss_reinit(snddev_info *d)
* perhaps this is not the place to set mode2, should be done
* only once at attach time...
*/
if ( d->dma1 != d->dma2 && d->bd_id != MD_OPTI931)
if ( FULL_DUPLEX(d) && d->bd_id != MD_OPTI931)
/*
* set mode2 bit for dual dma op. This bit is not implemented
* on the OPTi931
@ -1282,7 +1297,7 @@ mss_reinit(snddev_info *d)
}
ad_write(d, 8, r) ;
if (d->dma1 != d->dma2) {
if ( FULL_DUPLEX(d) ) {
#if 0
if (d->bd_id == MD_GUSPNP && d->play_fmt == AFMT_MU_LAW) {
printf("warning, cannot do ulaw rec + play on the GUS\n");
@ -1298,7 +1313,7 @@ mss_reinit(snddev_info *d)
* not sure if this is really needed...
*/
ad_write_cnt(d, 14, 0 ); /* playback count */
if (d->dma1 != d->dma2)
if ( FULL_DUPLEX(d) )
ad_write_cnt(d, 30, 0 ); /* rec. count on dual dma */
ad_write(d, 10, 2 /* int enable */) ;
@ -1322,7 +1337,7 @@ static void cs423x_attach(u_long csn, u_long vend_id, char *name,
struct isa_device *dev);
static struct pnp_device cs423x = {
"cs423x/ymh0020",
"CS423x/Yamaha",
cs423x_probe,
cs423x_attach,
&nsnd, /* use this for all sound cards */
@ -1343,6 +1358,8 @@ cs423x_probe(u_long csn, u_long vend_id)
s = "CS4232" ;
else if ( id == 0x2000a865)
s = "Yamaha SA2";
else if ( id == 0x3000a865)
s = "Yamaha SA3";
else if (vend_id == 0x8140d315)
s = "SoundscapeVIVO";
if (s) {
@ -1376,8 +1393,8 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
if (d.flags & DV_PNP_SBCODEC) { /*** use sb-compatible codec ***/
dev->id_alive = 16 ; /* number of io ports ? */
tmp_d = sb_op_desc ;
if (vend_id == 0x2000a865 || vend_id == 0x8140d315) {
/* Yamaha SA2 or ENSONIQ SoundscapeVIVO ENS4081 */
if (vend_id==0x2000a865 || vend_id==0x3000a865 || vend_id==0x8140d315) {
/* Yamaha SA2/SA3 or ENSONIQ SoundscapeVIVO ENS4081 */
dev->id_iobase = d.port[0] ;
tmp_d.alt_base = d.port[1] ;
d.irq[1] = 0 ; /* only needed for the VIVO */
@ -1393,9 +1410,11 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
tmp_d.alt_base = d.port[2];
switch (vend_id & 0xff00ffff) {
case 0x2000a865: /* yamaha SA-2 */
case 0x2000a865: /* Yamaha SA2 */
case 0x3000a865: /* Yamaha SA3 */
dev->id_iobase = d.port[1];
tmp_d.alt_base = d.port[0];
tmp_d.conf_base = d.port[4];
tmp_d.bd_id = MD_YM0020 ;
break;
@ -1424,6 +1443,13 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
write_pnp_parms( &d, ldn );
enable_pnp_card();
if ( (vend_id & 0x2000ffff) == 0x2000a865 ) {
/* special volume setting for the Yamaha... */
outb(tmp_d.conf_base, 7 /* volume, left */);
outb(tmp_d.conf_base+1, 0 );
outb(tmp_d.conf_base, 8 /* volume, right */);
outb(tmp_d.conf_base+1, 0 );
}
dev->id_drq = d.drq[0] ; /* primary dma */
dev->id_irq = (1 << d.irq[0] ) ;
dev->id_intr = pcmintr ;

View File

@ -174,6 +174,9 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
d->flags = 0 ;
d->bd_flags &= ~BD_F_HISPEED ;
@ -273,25 +276,36 @@ sbintr(int unit)
*/
reason = 0 ;
if ( c & 1 ) { /* 8-bit dma */
if (d->dma1 < 4)
if (d->dbuf_out.chan < 4)
reason |= 1;
if (d->dma2 < 4)
if (d->dbuf_in.chan < 4)
reason |= 2;
}
if ( c & 2 ) { /* 16-bit dma */
if (d->dma1 >= 4)
if (d->dbuf_out.chan >= 4)
reason |= 1;
if (d->dma2 >= 4)
if (d->dbuf_in.chan >= 4)
reason |= 2;
}
}
/* XXX previous location of ack... */
DEB(printf("sbintr, flags 0x%08lx reason %d\n", d->flags, reason));
if ( d->dbuf_out.dl && (reason & 1) )
if ( reason & 1 ) { /* possibly a write interrupt */
if ( d->dbuf_out.dl )
dsp_wrintr(d);
if ( d->dbuf_in.dl && (reason & 2) )
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: wrintr but write DMA inactive!\n");
}
}
if ( reason & 2 ) {
if ( d->dbuf_in.dl )
dsp_rdintr(d);
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: rdintr but read DMA inactive!\n");
}
}
if ( c & 2 )
inb(DSP_DATA_AVL16); /* 16-bit int ack */
if (c & 1)
@ -307,7 +321,7 @@ sbintr(int unit)
/*
* device-specific function called back from the dma module.
* The reason of the callback is the second argument.
* NOTE: during operations, some ioctl can be done to change
* NOTE: during operations, some ioctl can be called to change
* settings (e.g. speed, channels, format), and the default
* ioctl handler will just record the change and set the
* flag SND_F_INIT. The callback routine is in charge of applying
@ -319,7 +333,8 @@ static int
sb_callback(snddev_info *d, int reason)
{
int rd = reason & SND_CB_RD ;
int l = (rd) ? d->dbuf_in.dl : d->dbuf_out.dl ;
snd_dbuf *b = (rd) ? & (d->dbuf_in) : & (d->dbuf_out) ;
int l = b->dl ;
switch (reason & SND_CB_REASON_MASK) {
case SND_CB_INIT : /* called with int enabled and no pending io */
@ -336,6 +351,8 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_START : /* called with int disabled */
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
/* the SB16 can do full duplex using one 16-bit channel
* and one 8-bit channel. It needs to be programmed to
* use split format though.
@ -347,63 +364,80 @@ sb_callback(snddev_info *d, int reason)
int swap = 1 ; /* default... */
if (rd) {
if (d->flags & SND_F_WRITING || d->dbuf_out.dl)
/* need not to swap if channel is already correct */
if ( d->rec_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->rec_fmt == AFMT_S16_LE && d->dma2 >=4)
if ( d->rec_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->rec_fmt != AFMT_S16_LE && d->dma2 <4)
if (swap && (d->flags & SND_F_WRITING || d->dbuf_out.dl)) {
/* cannot swap if writing is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break; /* XXX should return an error */
}
} else {
if (d->flags & SND_F_READING || d->dbuf_in.dl)
/* need not to swap if channel is already correct */
if ( d->play_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->play_fmt == AFMT_S16_LE && d->dma1 >=4)
if ( d->play_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->play_fmt != AFMT_S16_LE && d->dma1 <4)
if (swap && ( d->flags & SND_F_READING || d->dbuf_in.dl)) {
/* cannot swap if reading is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break ; /* XXX should return an error */
}
}
if (swap) {
int c = d->dma2 ;
d->dma2 = d->dma1;
d->dma1 = c ;
int c = d->dbuf_in.chan ;
d->dbuf_in.chan = d->dbuf_out.chan;
d->dbuf_out.chan = c ;
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
DEB(printf("START dma chan: play %d, rec %d\n",
d->dma1, d->dma2));
d->dbuf_out.chan, d->dbuf_in.chan));
}
}
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
if (rd) {
c = ((d->dma2 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_ADC ;
c1 = (d->rec_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->rec_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->rec_fmt == AFMT_S16_LE)
/*
* XXX note: c1 and l should be set basing on d->rec_fmt,
* but there is no choice once a 16 or 8-bit channel
* is assigned. This means that if the application
* tries to use a bad format, the sound will not be nice.
*/
if ( b->chan > 4 ) {
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
c1 = DSP_F16_SIGNED ;
l /= 2 ;
} else {
c = ((d->dma1 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_DAC ;
c1 = (d->play_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->play_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->play_fmt == AFMT_S16_LE)
l /= 2 ;
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA8 ;
c1 = 0 ;
}
c |= (rd) ? DSP_F16_ADC : DSP_F16_DAC ;
if (d->flags & SND_F_STEREO)
c1 |= DSP_F16_STEREO ;
sb_cmd(d->io_base, c );
sb_cmd3(d->io_base, c1 , l - 1) ;
} else {
/* code for the SB2 and SB3 */
} else if (d->bd_flags & BD_F_ESS) {
/* XXX this code is still incomplete */
sb_cmd2(d->io_base, 0xb8, rd ? 0x0e : 0x04 ); /* auto dma */
sb_cmd2(d->io_base, 0xa8, 2 /* chans */ );
sb_cmd2(d->io_base, 0xb9, 2); /* demand mode */
/*
input: 0xb8 -> 0x0e ;
0xa8 -> channels
0xb9 -> 2
mono,U8: 51, d0
mono,S16 71, f4
st, U8 51, 98
st, S16 71, bc
*/
} else { /* SBPro */
u_char c ;
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
/* code for the SB2 and SB3 */
if (d->bd_flags & BD_F_HISPEED)
c = (rd) ? DSP_CMD_HSADC_AUTO : DSP_CMD_HSDAC_AUTO ;
else
@ -416,18 +450,17 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_STOP :
{
int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */
if (d->bd_flags & BD_F_SB16) {
if ( (rd && d->dbuf_in.chan>4) || (!rd && d->dbuf_out.chan>4) )
if ( d->bd_flags & BD_F_SB16 && b->chan > 4 )
cmd = DSP_CMD_DMAPAUSE_16 ;
}
if (d->bd_flags & BD_F_HISPEED) {
sb_reset_dsp(d->io_base);
d->flags |= SND_F_INIT ;
} else {
sb_cmd(d->io_base, cmd); /* pause dma. */
/*
* This seems to have the side effect of blocking the other
* side as well so I have to re-enable it :(
* The above seems to have the undocumented side effect of
* blocking the other side as well. If the other
* channel was active (SB16) I have to re-enable it :(
*/
if ( (rd && d->dbuf_out.dl) ||
(!rd && d->dbuf_in.dl) )
@ -508,7 +541,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
break ;
case 2 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
d->bd_flags |= BD_F_DUP_MIDI ;
if (d->bd_id == 0x200)
@ -536,11 +569,11 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
else
sb_setmixer(io_base, IRQ_NR, x);
sb_setmixer(io_base, DMA_NR, (1 << d->dma1) | (1 << d->dma2));
sb_setmixer(io_base, DMA_NR, (1 << d->dbuf_out.chan) | (1 << d->dbuf_in.chan));
break ;
case 3 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
fmt = "SoundBlaster Pro %d.%d";
d->bd_flags |= BD_F_DUP_MIDI ;
d->bd_flags &= ~BD_F_MIX_MASK ;
@ -562,24 +595,48 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
ess_minor = inb(DSP_READ);
break;
}
}
} else
DELAY(20);
}
if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS488 based card (rev %d)\n",
ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS688 based card (rev %d)\n",
ess_minor & 0x0f);
printf("ESS488 (rev %d)\n", ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
if ( (ess_minor & 0xf) >= 8 )
printf("ESS1688 (rev %d)\n", ess_minor & 0x0f);
else
printf("ESS688 (rev %d)\n", ess_minor & 0x0f);
} else
break ;
d->bd_id = (ess_major << 8) | ess_minor ;
d->bd_flags |= BD_F_ESS;
/*
* ESS-specific initialization, taken from OSSFree 3.8
*/
{
static u_char irqs[16] = {
0, 0, 0x50, 0, 0, 0x54, 0, 0x58,
0, 0x50, 0x5c, 0, 0, 0, 0, 0 };
static u_char drqs[8] = {
0x51, 0x52, 0, 0x53, 0, 0, 0, 0 };
x = irqs[d->irq & 0xf];
if (x == 0)
printf("ESS : invalid IRQ %d\n", d->irq);
else {
sb_cmd(io_base, 0xb1 ); /* set IRQ */
sb_cmd(io_base, x );
x = drqs[ d->dbuf_out.chan & 0x7 ];
if (x == 0)
printf("ESS : invalid DRQ %d\n", d->dbuf_out.chan);
else {
sb_cmd(io_base, 0xb2 ); /* set DRQ */
sb_cmd(io_base, x );
}
}
}
}
if (d->bd_flags & BD_F_JAZZ16) {
if (d->bd_flags & BD_F_JAZZ16_2)
fmt = "SoundMan Wave %d.%d";
else
fmt = "MV Jazz16 %d.%d";
d->audio_fmt |= AFMT_S16_LE; /* 16 bits */
}
}
sprintf(d->name, fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff);
@ -714,6 +771,9 @@ dsp_speed(snddev_info *d)
u_long flags;
int max_speed = 44100, speed = d->play_speed ;
/*
* special code for the SB16
*/
if (d->bd_flags & BD_F_SB16) {
RANGE (speed, 5000, 45000);
d->play_speed = d->rec_speed = speed ;
@ -725,6 +785,26 @@ dsp_speed(snddev_info *d)
sb_cmd(d->io_base, d->rec_speed & 0xff );
return speed ;
}
/*
* special code for the ESS ...
*/
if (d->bd_flags & BD_F_ESS) {
int t;
RANGE (speed, 4000, 48000);
if (speed > 22000) {
t = (795500 + speed / 2) / speed;
speed = (795500 + t / 2) / t ;
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
} else {
t = (397700 + speed / 2) / speed;
speed = (397700 + t / 2) / t ;
t = 128 - (397700 + speed / 2) / speed ;
}
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
return speed ;
}
/*
* only some models can do stereo, and only if not
* simultaneously using midi.
@ -779,7 +859,7 @@ dsp_speed(snddev_info *d)
d->bd_flags |= BD_F_HISPEED ;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 65536 - (tconst << 8);
@ -791,7 +871,7 @@ dsp_speed(snddev_info *d)
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 256 - tconst;
@ -1044,7 +1124,7 @@ sb16pnp_probe(u_long csn, u_long vend_id)
* the vendor id, so I have just masked it for the time being...
* Reported values are:
* SB16 Value PnP: 0x2b008c0e
* SB AWE64 PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
*/
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
s = "SB16 PnP";

View File

@ -137,6 +137,7 @@ extern int sbc_major, sbc_minor ;
#define BD_F_SB16 0x0100 /* this is a SB16 */
#define BD_F_NOREC 0x0200 /* recording not supported on this board */
#define BD_F_MIDIBUSY 0x0400 /* midi busy */
#define BD_F_ESS 0x0800 /* this is an ESS chip */
/*

View File

@ -197,7 +197,7 @@ mss_attach(struct isa_device *dev)
printf("mss_attach <%s>%d at 0x%x irq %d dma %d:%d flags 0x%x\n",
d->name, dev->id_unit,
d->io_base, d->irq, d->dma1, d->dma2, dev->id_flags);
d->io_base, d->irq, d->dbuf_out.chan, d->dbuf_in.chan, dev->id_flags);
dev->id_alive = 8 ; /* number of io ports */
/* should be already set but just in case... */
@ -220,18 +220,18 @@ mss_attach(struct isa_device *dev)
printf("[IRQ Conflict?]");
/* Write IRQ+DMA setup */
if (d->dma1 == d->dma2) /* single chan dma */
outb(dev->id_iobase, bits | dma_bits[d->dma1]);
if ( ! FULL_DUPLEX(d) ) /* single chan dma */
outb(dev->id_iobase, bits | dma_bits[d->dbuf_out.chan]);
else {
if (d->dma1 == 0 && d->dma2 == 1)
if (d->dbuf_out.chan == 0 && d->dbuf_in.chan == 1)
bits |= 5 ;
else if (d->dma1 == 1 && d->dma2 == 0)
else if (d->dbuf_out.chan == 1 && d->dbuf_in.chan == 0)
bits |= 6 ;
else if (d->dma1 == 3 && d->dma2 == 0)
else if (d->dbuf_out.chan == 3 && d->dbuf_in.chan == 0)
bits |= 7 ;
else {
printf("invalid dual dma config %d:%d\n",
d->dma1, d->dma2);
d->dbuf_out.chan, d->dbuf_in.chan);
dev->id_irq = 0 ;
dev->id_alive = 0 ; /* this makes attach fail. */
return 0 ;
@ -239,7 +239,7 @@ mss_attach(struct isa_device *dev)
outb(dev->id_iobase, bits );
}
}
if (d->dma1 != d->dma2)
if ( FULL_DUPLEX(d) )
d->audio_fmt |= AFMT_FULLDUPLEX ;
mss_reinit(d);
ad1848_mixer_reset(d);
@ -293,6 +293,9 @@ mss_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
if (flags & O_NONBLOCK)
d->flags |= SND_F_NBIO ;
@ -426,7 +429,7 @@ mss_callback(snddev_info *d, int reason)
if (retry == 0)
printf("start dma, failed to set bit 0x%02x 0x%02x\n",
m, ad_read(d, 9) ) ;
if (wr || (d->dma1 == d->dma2) )
if (wr || ! FULL_DUPLEX(d) )
ad_write_cnt(d, 14, cnt);
else
ad_write_cnt(d, 30, cnt);
@ -452,7 +455,7 @@ mss_callback(snddev_info *d, int reason)
* is needed, and it might cause false interrupts when the
* DMA is re-enabled later.
*/
if (wr || (d->dma1 == d->dma2) )
if (wr || ! FULL_DUPLEX(d) )
ad_write_cnt(d, 14, 0);
else
ad_write_cnt(d, 30, 0);
@ -492,7 +495,7 @@ mss_intr(int unit)
*/
for (i=10 ; i && inb(io_Status(d)) & 1 ; i-- ) {
/* get exact reason for full-duplex boards */
c = (d->dma1 == d->dma2) ? 0x30 : ad_read(d, 24);
c = FULL_DUPLEX(d) ? ad_read(d, 24) : 0x30 ;
c &= ~served ;
if ( d->dbuf_out.dl && (c & 0x10) ) {
served |= 0x10 ;
@ -505,10 +508,18 @@ mss_intr(int unit)
/*
* now ack the interrupt
*/
if (d->dma1 == d->dma2)
outb(io_Status(d), 0); /* Clear interrupt status */
else
if ( FULL_DUPLEX(d) )
ad_write(d, 24, ~c); /* ack selectively */
else
outb(io_Status(d), 0); /* Clear interrupt status */
}
if (served == 0) {
printf("How strange... mss_intr with no reason!\n");
/*
* this should not happen... I have no idea what to do now.
* maybe should do a sanity check and restart dmas ?
*/
outb(io_Status(d), 0); /* Clear interrupt status */
}
}
@ -534,7 +545,7 @@ opti931_intr(int unit)
i11 = ad_read(d, 11); /* XXX what's for ? */
again:
c=mc11 = (d->dma1 == d->dma2) ? 0xc : opti_read(d->conf_base, 11);
c=mc11 = FULL_DUPLEX(d) ? opti_read(d->conf_base, 11) : 0xc ;
mc11 &= 0x0c ;
if (c & 0x10) {
printf("Warning: CD interrupt\n");
@ -791,7 +802,7 @@ mss_set_recsrc(snddev_info *d, int mask)
*/
static char mix_cvt[101] = {
0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
0, 1, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,
65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,
80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,
@ -849,8 +860,12 @@ mss_mixer_set(snddev_info *d, int dev, int value)
regoffs = (*mix_d)[dev][LEFT_CHN].regno;
old = val = ad_read(d, regoffs);
if (regoffs != 0)
val = old & 0x7f ; /* clear mute bit. */
/*
* if volume is 0, mute chan. Otherwise, unmute.
*/
if (regoffs != 0) /* main input is different */
val = (left == 0 ) ? old | 0x80 : old & 0x7f ;
change_bits(mix_d, &val, dev, LEFT_CHN, left);
ad_write(d, regoffs, val);
DEB(printf("LEFT: dev %d reg %d old 0x%02x new 0x%02x\n",
@ -863,7 +878,7 @@ mss_mixer_set(snddev_info *d, int dev, int value)
regoffs = (*mix_d)[dev][RIGHT_CHN].regno;
old = val = ad_read(d, regoffs);
if (regoffs != 1)
val = old & 0x7f ; /* clear mute bit. */
val = (right == 0 ) ? old | 0x80 : old & 0x7f ;
change_bits(mix_d, &val, dev, RIGHT_CHN, right);
ad_write(d, regoffs, val);
DEB(printf("RIGHT: dev %d reg %d old 0x%02x new 0x%02x\n",
@ -1261,7 +1276,7 @@ mss_reinit(snddev_info *d)
* perhaps this is not the place to set mode2, should be done
* only once at attach time...
*/
if ( d->dma1 != d->dma2 && d->bd_id != MD_OPTI931)
if ( FULL_DUPLEX(d) && d->bd_id != MD_OPTI931)
/*
* set mode2 bit for dual dma op. This bit is not implemented
* on the OPTi931
@ -1282,7 +1297,7 @@ mss_reinit(snddev_info *d)
}
ad_write(d, 8, r) ;
if (d->dma1 != d->dma2) {
if ( FULL_DUPLEX(d) ) {
#if 0
if (d->bd_id == MD_GUSPNP && d->play_fmt == AFMT_MU_LAW) {
printf("warning, cannot do ulaw rec + play on the GUS\n");
@ -1298,7 +1313,7 @@ mss_reinit(snddev_info *d)
* not sure if this is really needed...
*/
ad_write_cnt(d, 14, 0 ); /* playback count */
if (d->dma1 != d->dma2)
if ( FULL_DUPLEX(d) )
ad_write_cnt(d, 30, 0 ); /* rec. count on dual dma */
ad_write(d, 10, 2 /* int enable */) ;
@ -1322,7 +1337,7 @@ static void cs423x_attach(u_long csn, u_long vend_id, char *name,
struct isa_device *dev);
static struct pnp_device cs423x = {
"cs423x/ymh0020",
"CS423x/Yamaha",
cs423x_probe,
cs423x_attach,
&nsnd, /* use this for all sound cards */
@ -1343,6 +1358,8 @@ cs423x_probe(u_long csn, u_long vend_id)
s = "CS4232" ;
else if ( id == 0x2000a865)
s = "Yamaha SA2";
else if ( id == 0x3000a865)
s = "Yamaha SA3";
else if (vend_id == 0x8140d315)
s = "SoundscapeVIVO";
if (s) {
@ -1376,8 +1393,8 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
if (d.flags & DV_PNP_SBCODEC) { /*** use sb-compatible codec ***/
dev->id_alive = 16 ; /* number of io ports ? */
tmp_d = sb_op_desc ;
if (vend_id == 0x2000a865 || vend_id == 0x8140d315) {
/* Yamaha SA2 or ENSONIQ SoundscapeVIVO ENS4081 */
if (vend_id==0x2000a865 || vend_id==0x3000a865 || vend_id==0x8140d315) {
/* Yamaha SA2/SA3 or ENSONIQ SoundscapeVIVO ENS4081 */
dev->id_iobase = d.port[0] ;
tmp_d.alt_base = d.port[1] ;
d.irq[1] = 0 ; /* only needed for the VIVO */
@ -1393,9 +1410,11 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
tmp_d.alt_base = d.port[2];
switch (vend_id & 0xff00ffff) {
case 0x2000a865: /* yamaha SA-2 */
case 0x2000a865: /* Yamaha SA2 */
case 0x3000a865: /* Yamaha SA3 */
dev->id_iobase = d.port[1];
tmp_d.alt_base = d.port[0];
tmp_d.conf_base = d.port[4];
tmp_d.bd_id = MD_YM0020 ;
break;
@ -1424,6 +1443,13 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
write_pnp_parms( &d, ldn );
enable_pnp_card();
if ( (vend_id & 0x2000ffff) == 0x2000a865 ) {
/* special volume setting for the Yamaha... */
outb(tmp_d.conf_base, 7 /* volume, left */);
outb(tmp_d.conf_base+1, 0 );
outb(tmp_d.conf_base, 8 /* volume, right */);
outb(tmp_d.conf_base+1, 0 );
}
dev->id_drq = d.drq[0] ; /* primary dma */
dev->id_irq = (1 << d.irq[0] ) ;
dev->id_intr = pcmintr ;

View File

@ -174,6 +174,9 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
d->flags = 0 ;
d->bd_flags &= ~BD_F_HISPEED ;
@ -273,25 +276,36 @@ sbintr(int unit)
*/
reason = 0 ;
if ( c & 1 ) { /* 8-bit dma */
if (d->dma1 < 4)
if (d->dbuf_out.chan < 4)
reason |= 1;
if (d->dma2 < 4)
if (d->dbuf_in.chan < 4)
reason |= 2;
}
if ( c & 2 ) { /* 16-bit dma */
if (d->dma1 >= 4)
if (d->dbuf_out.chan >= 4)
reason |= 1;
if (d->dma2 >= 4)
if (d->dbuf_in.chan >= 4)
reason |= 2;
}
}
/* XXX previous location of ack... */
DEB(printf("sbintr, flags 0x%08lx reason %d\n", d->flags, reason));
if ( d->dbuf_out.dl && (reason & 1) )
if ( reason & 1 ) { /* possibly a write interrupt */
if ( d->dbuf_out.dl )
dsp_wrintr(d);
if ( d->dbuf_in.dl && (reason & 2) )
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: wrintr but write DMA inactive!\n");
}
}
if ( reason & 2 ) {
if ( d->dbuf_in.dl )
dsp_rdintr(d);
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: rdintr but read DMA inactive!\n");
}
}
if ( c & 2 )
inb(DSP_DATA_AVL16); /* 16-bit int ack */
if (c & 1)
@ -307,7 +321,7 @@ sbintr(int unit)
/*
* device-specific function called back from the dma module.
* The reason of the callback is the second argument.
* NOTE: during operations, some ioctl can be done to change
* NOTE: during operations, some ioctl can be called to change
* settings (e.g. speed, channels, format), and the default
* ioctl handler will just record the change and set the
* flag SND_F_INIT. The callback routine is in charge of applying
@ -319,7 +333,8 @@ static int
sb_callback(snddev_info *d, int reason)
{
int rd = reason & SND_CB_RD ;
int l = (rd) ? d->dbuf_in.dl : d->dbuf_out.dl ;
snd_dbuf *b = (rd) ? & (d->dbuf_in) : & (d->dbuf_out) ;
int l = b->dl ;
switch (reason & SND_CB_REASON_MASK) {
case SND_CB_INIT : /* called with int enabled and no pending io */
@ -336,6 +351,8 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_START : /* called with int disabled */
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
/* the SB16 can do full duplex using one 16-bit channel
* and one 8-bit channel. It needs to be programmed to
* use split format though.
@ -347,63 +364,80 @@ sb_callback(snddev_info *d, int reason)
int swap = 1 ; /* default... */
if (rd) {
if (d->flags & SND_F_WRITING || d->dbuf_out.dl)
/* need not to swap if channel is already correct */
if ( d->rec_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->rec_fmt == AFMT_S16_LE && d->dma2 >=4)
if ( d->rec_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->rec_fmt != AFMT_S16_LE && d->dma2 <4)
if (swap && (d->flags & SND_F_WRITING || d->dbuf_out.dl)) {
/* cannot swap if writing is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break; /* XXX should return an error */
}
} else {
if (d->flags & SND_F_READING || d->dbuf_in.dl)
/* need not to swap if channel is already correct */
if ( d->play_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->play_fmt == AFMT_S16_LE && d->dma1 >=4)
if ( d->play_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->play_fmt != AFMT_S16_LE && d->dma1 <4)
if (swap && ( d->flags & SND_F_READING || d->dbuf_in.dl)) {
/* cannot swap if reading is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break ; /* XXX should return an error */
}
}
if (swap) {
int c = d->dma2 ;
d->dma2 = d->dma1;
d->dma1 = c ;
int c = d->dbuf_in.chan ;
d->dbuf_in.chan = d->dbuf_out.chan;
d->dbuf_out.chan = c ;
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
DEB(printf("START dma chan: play %d, rec %d\n",
d->dma1, d->dma2));
d->dbuf_out.chan, d->dbuf_in.chan));
}
}
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
if (rd) {
c = ((d->dma2 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_ADC ;
c1 = (d->rec_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->rec_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->rec_fmt == AFMT_S16_LE)
/*
* XXX note: c1 and l should be set basing on d->rec_fmt,
* but there is no choice once a 16 or 8-bit channel
* is assigned. This means that if the application
* tries to use a bad format, the sound will not be nice.
*/
if ( b->chan > 4 ) {
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
c1 = DSP_F16_SIGNED ;
l /= 2 ;
} else {
c = ((d->dma1 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_DAC ;
c1 = (d->play_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->play_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->play_fmt == AFMT_S16_LE)
l /= 2 ;
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA8 ;
c1 = 0 ;
}
c |= (rd) ? DSP_F16_ADC : DSP_F16_DAC ;
if (d->flags & SND_F_STEREO)
c1 |= DSP_F16_STEREO ;
sb_cmd(d->io_base, c );
sb_cmd3(d->io_base, c1 , l - 1) ;
} else {
/* code for the SB2 and SB3 */
} else if (d->bd_flags & BD_F_ESS) {
/* XXX this code is still incomplete */
sb_cmd2(d->io_base, 0xb8, rd ? 0x0e : 0x04 ); /* auto dma */
sb_cmd2(d->io_base, 0xa8, 2 /* chans */ );
sb_cmd2(d->io_base, 0xb9, 2); /* demand mode */
/*
input: 0xb8 -> 0x0e ;
0xa8 -> channels
0xb9 -> 2
mono,U8: 51, d0
mono,S16 71, f4
st, U8 51, 98
st, S16 71, bc
*/
} else { /* SBPro */
u_char c ;
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
/* code for the SB2 and SB3 */
if (d->bd_flags & BD_F_HISPEED)
c = (rd) ? DSP_CMD_HSADC_AUTO : DSP_CMD_HSDAC_AUTO ;
else
@ -416,18 +450,17 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_STOP :
{
int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */
if (d->bd_flags & BD_F_SB16) {
if ( (rd && d->dbuf_in.chan>4) || (!rd && d->dbuf_out.chan>4) )
if ( d->bd_flags & BD_F_SB16 && b->chan > 4 )
cmd = DSP_CMD_DMAPAUSE_16 ;
}
if (d->bd_flags & BD_F_HISPEED) {
sb_reset_dsp(d->io_base);
d->flags |= SND_F_INIT ;
} else {
sb_cmd(d->io_base, cmd); /* pause dma. */
/*
* This seems to have the side effect of blocking the other
* side as well so I have to re-enable it :(
* The above seems to have the undocumented side effect of
* blocking the other side as well. If the other
* channel was active (SB16) I have to re-enable it :(
*/
if ( (rd && d->dbuf_out.dl) ||
(!rd && d->dbuf_in.dl) )
@ -508,7 +541,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
break ;
case 2 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
d->bd_flags |= BD_F_DUP_MIDI ;
if (d->bd_id == 0x200)
@ -536,11 +569,11 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
else
sb_setmixer(io_base, IRQ_NR, x);
sb_setmixer(io_base, DMA_NR, (1 << d->dma1) | (1 << d->dma2));
sb_setmixer(io_base, DMA_NR, (1 << d->dbuf_out.chan) | (1 << d->dbuf_in.chan));
break ;
case 3 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
fmt = "SoundBlaster Pro %d.%d";
d->bd_flags |= BD_F_DUP_MIDI ;
d->bd_flags &= ~BD_F_MIX_MASK ;
@ -562,24 +595,48 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
ess_minor = inb(DSP_READ);
break;
}
}
} else
DELAY(20);
}
if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS488 based card (rev %d)\n",
ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS688 based card (rev %d)\n",
ess_minor & 0x0f);
printf("ESS488 (rev %d)\n", ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
if ( (ess_minor & 0xf) >= 8 )
printf("ESS1688 (rev %d)\n", ess_minor & 0x0f);
else
printf("ESS688 (rev %d)\n", ess_minor & 0x0f);
} else
break ;
d->bd_id = (ess_major << 8) | ess_minor ;
d->bd_flags |= BD_F_ESS;
/*
* ESS-specific initialization, taken from OSSFree 3.8
*/
{
static u_char irqs[16] = {
0, 0, 0x50, 0, 0, 0x54, 0, 0x58,
0, 0x50, 0x5c, 0, 0, 0, 0, 0 };
static u_char drqs[8] = {
0x51, 0x52, 0, 0x53, 0, 0, 0, 0 };
x = irqs[d->irq & 0xf];
if (x == 0)
printf("ESS : invalid IRQ %d\n", d->irq);
else {
sb_cmd(io_base, 0xb1 ); /* set IRQ */
sb_cmd(io_base, x );
x = drqs[ d->dbuf_out.chan & 0x7 ];
if (x == 0)
printf("ESS : invalid DRQ %d\n", d->dbuf_out.chan);
else {
sb_cmd(io_base, 0xb2 ); /* set DRQ */
sb_cmd(io_base, x );
}
}
}
}
if (d->bd_flags & BD_F_JAZZ16) {
if (d->bd_flags & BD_F_JAZZ16_2)
fmt = "SoundMan Wave %d.%d";
else
fmt = "MV Jazz16 %d.%d";
d->audio_fmt |= AFMT_S16_LE; /* 16 bits */
}
}
sprintf(d->name, fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff);
@ -714,6 +771,9 @@ dsp_speed(snddev_info *d)
u_long flags;
int max_speed = 44100, speed = d->play_speed ;
/*
* special code for the SB16
*/
if (d->bd_flags & BD_F_SB16) {
RANGE (speed, 5000, 45000);
d->play_speed = d->rec_speed = speed ;
@ -725,6 +785,26 @@ dsp_speed(snddev_info *d)
sb_cmd(d->io_base, d->rec_speed & 0xff );
return speed ;
}
/*
* special code for the ESS ...
*/
if (d->bd_flags & BD_F_ESS) {
int t;
RANGE (speed, 4000, 48000);
if (speed > 22000) {
t = (795500 + speed / 2) / speed;
speed = (795500 + t / 2) / t ;
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
} else {
t = (397700 + speed / 2) / speed;
speed = (397700 + t / 2) / t ;
t = 128 - (397700 + speed / 2) / speed ;
}
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
return speed ;
}
/*
* only some models can do stereo, and only if not
* simultaneously using midi.
@ -779,7 +859,7 @@ dsp_speed(snddev_info *d)
d->bd_flags |= BD_F_HISPEED ;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 65536 - (tconst << 8);
@ -791,7 +871,7 @@ dsp_speed(snddev_info *d)
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 256 - tconst;
@ -1044,7 +1124,7 @@ sb16pnp_probe(u_long csn, u_long vend_id)
* the vendor id, so I have just masked it for the time being...
* Reported values are:
* SB16 Value PnP: 0x2b008c0e
* SB AWE64 PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
*/
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
s = "SB16 PnP";

View File

@ -137,6 +137,7 @@ extern int sbc_major, sbc_minor ;
#define BD_F_SB16 0x0100 /* this is a SB16 */
#define BD_F_NOREC 0x0200 /* recording not supported on this board */
#define BD_F_MIDIBUSY 0x0400 /* midi busy */
#define BD_F_ESS 0x0800 /* this is an ESS chip */
/*

View File

@ -174,6 +174,9 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
d->flags = 0 ;
d->bd_flags &= ~BD_F_HISPEED ;
@ -273,25 +276,36 @@ sbintr(int unit)
*/
reason = 0 ;
if ( c & 1 ) { /* 8-bit dma */
if (d->dma1 < 4)
if (d->dbuf_out.chan < 4)
reason |= 1;
if (d->dma2 < 4)
if (d->dbuf_in.chan < 4)
reason |= 2;
}
if ( c & 2 ) { /* 16-bit dma */
if (d->dma1 >= 4)
if (d->dbuf_out.chan >= 4)
reason |= 1;
if (d->dma2 >= 4)
if (d->dbuf_in.chan >= 4)
reason |= 2;
}
}
/* XXX previous location of ack... */
DEB(printf("sbintr, flags 0x%08lx reason %d\n", d->flags, reason));
if ( d->dbuf_out.dl && (reason & 1) )
if ( reason & 1 ) { /* possibly a write interrupt */
if ( d->dbuf_out.dl )
dsp_wrintr(d);
if ( d->dbuf_in.dl && (reason & 2) )
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: wrintr but write DMA inactive!\n");
}
}
if ( reason & 2 ) {
if ( d->dbuf_in.dl )
dsp_rdintr(d);
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: rdintr but read DMA inactive!\n");
}
}
if ( c & 2 )
inb(DSP_DATA_AVL16); /* 16-bit int ack */
if (c & 1)
@ -307,7 +321,7 @@ sbintr(int unit)
/*
* device-specific function called back from the dma module.
* The reason of the callback is the second argument.
* NOTE: during operations, some ioctl can be done to change
* NOTE: during operations, some ioctl can be called to change
* settings (e.g. speed, channels, format), and the default
* ioctl handler will just record the change and set the
* flag SND_F_INIT. The callback routine is in charge of applying
@ -319,7 +333,8 @@ static int
sb_callback(snddev_info *d, int reason)
{
int rd = reason & SND_CB_RD ;
int l = (rd) ? d->dbuf_in.dl : d->dbuf_out.dl ;
snd_dbuf *b = (rd) ? & (d->dbuf_in) : & (d->dbuf_out) ;
int l = b->dl ;
switch (reason & SND_CB_REASON_MASK) {
case SND_CB_INIT : /* called with int enabled and no pending io */
@ -336,6 +351,8 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_START : /* called with int disabled */
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
/* the SB16 can do full duplex using one 16-bit channel
* and one 8-bit channel. It needs to be programmed to
* use split format though.
@ -347,63 +364,80 @@ sb_callback(snddev_info *d, int reason)
int swap = 1 ; /* default... */
if (rd) {
if (d->flags & SND_F_WRITING || d->dbuf_out.dl)
/* need not to swap if channel is already correct */
if ( d->rec_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->rec_fmt == AFMT_S16_LE && d->dma2 >=4)
if ( d->rec_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->rec_fmt != AFMT_S16_LE && d->dma2 <4)
if (swap && (d->flags & SND_F_WRITING || d->dbuf_out.dl)) {
/* cannot swap if writing is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break; /* XXX should return an error */
}
} else {
if (d->flags & SND_F_READING || d->dbuf_in.dl)
/* need not to swap if channel is already correct */
if ( d->play_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->play_fmt == AFMT_S16_LE && d->dma1 >=4)
if ( d->play_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->play_fmt != AFMT_S16_LE && d->dma1 <4)
if (swap && ( d->flags & SND_F_READING || d->dbuf_in.dl)) {
/* cannot swap if reading is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break ; /* XXX should return an error */
}
}
if (swap) {
int c = d->dma2 ;
d->dma2 = d->dma1;
d->dma1 = c ;
int c = d->dbuf_in.chan ;
d->dbuf_in.chan = d->dbuf_out.chan;
d->dbuf_out.chan = c ;
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
DEB(printf("START dma chan: play %d, rec %d\n",
d->dma1, d->dma2));
d->dbuf_out.chan, d->dbuf_in.chan));
}
}
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
if (rd) {
c = ((d->dma2 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_ADC ;
c1 = (d->rec_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->rec_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->rec_fmt == AFMT_S16_LE)
/*
* XXX note: c1 and l should be set basing on d->rec_fmt,
* but there is no choice once a 16 or 8-bit channel
* is assigned. This means that if the application
* tries to use a bad format, the sound will not be nice.
*/
if ( b->chan > 4 ) {
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
c1 = DSP_F16_SIGNED ;
l /= 2 ;
} else {
c = ((d->dma1 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_DAC ;
c1 = (d->play_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->play_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->play_fmt == AFMT_S16_LE)
l /= 2 ;
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA8 ;
c1 = 0 ;
}
c |= (rd) ? DSP_F16_ADC : DSP_F16_DAC ;
if (d->flags & SND_F_STEREO)
c1 |= DSP_F16_STEREO ;
sb_cmd(d->io_base, c );
sb_cmd3(d->io_base, c1 , l - 1) ;
} else {
/* code for the SB2 and SB3 */
} else if (d->bd_flags & BD_F_ESS) {
/* XXX this code is still incomplete */
sb_cmd2(d->io_base, 0xb8, rd ? 0x0e : 0x04 ); /* auto dma */
sb_cmd2(d->io_base, 0xa8, 2 /* chans */ );
sb_cmd2(d->io_base, 0xb9, 2); /* demand mode */
/*
input: 0xb8 -> 0x0e ;
0xa8 -> channels
0xb9 -> 2
mono,U8: 51, d0
mono,S16 71, f4
st, U8 51, 98
st, S16 71, bc
*/
} else { /* SBPro */
u_char c ;
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
/* code for the SB2 and SB3 */
if (d->bd_flags & BD_F_HISPEED)
c = (rd) ? DSP_CMD_HSADC_AUTO : DSP_CMD_HSDAC_AUTO ;
else
@ -416,18 +450,17 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_STOP :
{
int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */
if (d->bd_flags & BD_F_SB16) {
if ( (rd && d->dbuf_in.chan>4) || (!rd && d->dbuf_out.chan>4) )
if ( d->bd_flags & BD_F_SB16 && b->chan > 4 )
cmd = DSP_CMD_DMAPAUSE_16 ;
}
if (d->bd_flags & BD_F_HISPEED) {
sb_reset_dsp(d->io_base);
d->flags |= SND_F_INIT ;
} else {
sb_cmd(d->io_base, cmd); /* pause dma. */
/*
* This seems to have the side effect of blocking the other
* side as well so I have to re-enable it :(
* The above seems to have the undocumented side effect of
* blocking the other side as well. If the other
* channel was active (SB16) I have to re-enable it :(
*/
if ( (rd && d->dbuf_out.dl) ||
(!rd && d->dbuf_in.dl) )
@ -508,7 +541,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
break ;
case 2 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
d->bd_flags |= BD_F_DUP_MIDI ;
if (d->bd_id == 0x200)
@ -536,11 +569,11 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
else
sb_setmixer(io_base, IRQ_NR, x);
sb_setmixer(io_base, DMA_NR, (1 << d->dma1) | (1 << d->dma2));
sb_setmixer(io_base, DMA_NR, (1 << d->dbuf_out.chan) | (1 << d->dbuf_in.chan));
break ;
case 3 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
fmt = "SoundBlaster Pro %d.%d";
d->bd_flags |= BD_F_DUP_MIDI ;
d->bd_flags &= ~BD_F_MIX_MASK ;
@ -562,24 +595,48 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
ess_minor = inb(DSP_READ);
break;
}
}
} else
DELAY(20);
}
if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS488 based card (rev %d)\n",
ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS688 based card (rev %d)\n",
ess_minor & 0x0f);
printf("ESS488 (rev %d)\n", ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
if ( (ess_minor & 0xf) >= 8 )
printf("ESS1688 (rev %d)\n", ess_minor & 0x0f);
else
printf("ESS688 (rev %d)\n", ess_minor & 0x0f);
} else
break ;
d->bd_id = (ess_major << 8) | ess_minor ;
d->bd_flags |= BD_F_ESS;
/*
* ESS-specific initialization, taken from OSSFree 3.8
*/
{
static u_char irqs[16] = {
0, 0, 0x50, 0, 0, 0x54, 0, 0x58,
0, 0x50, 0x5c, 0, 0, 0, 0, 0 };
static u_char drqs[8] = {
0x51, 0x52, 0, 0x53, 0, 0, 0, 0 };
x = irqs[d->irq & 0xf];
if (x == 0)
printf("ESS : invalid IRQ %d\n", d->irq);
else {
sb_cmd(io_base, 0xb1 ); /* set IRQ */
sb_cmd(io_base, x );
x = drqs[ d->dbuf_out.chan & 0x7 ];
if (x == 0)
printf("ESS : invalid DRQ %d\n", d->dbuf_out.chan);
else {
sb_cmd(io_base, 0xb2 ); /* set DRQ */
sb_cmd(io_base, x );
}
}
}
}
if (d->bd_flags & BD_F_JAZZ16) {
if (d->bd_flags & BD_F_JAZZ16_2)
fmt = "SoundMan Wave %d.%d";
else
fmt = "MV Jazz16 %d.%d";
d->audio_fmt |= AFMT_S16_LE; /* 16 bits */
}
}
sprintf(d->name, fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff);
@ -714,6 +771,9 @@ dsp_speed(snddev_info *d)
u_long flags;
int max_speed = 44100, speed = d->play_speed ;
/*
* special code for the SB16
*/
if (d->bd_flags & BD_F_SB16) {
RANGE (speed, 5000, 45000);
d->play_speed = d->rec_speed = speed ;
@ -725,6 +785,26 @@ dsp_speed(snddev_info *d)
sb_cmd(d->io_base, d->rec_speed & 0xff );
return speed ;
}
/*
* special code for the ESS ...
*/
if (d->bd_flags & BD_F_ESS) {
int t;
RANGE (speed, 4000, 48000);
if (speed > 22000) {
t = (795500 + speed / 2) / speed;
speed = (795500 + t / 2) / t ;
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
} else {
t = (397700 + speed / 2) / speed;
speed = (397700 + t / 2) / t ;
t = 128 - (397700 + speed / 2) / speed ;
}
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
return speed ;
}
/*
* only some models can do stereo, and only if not
* simultaneously using midi.
@ -779,7 +859,7 @@ dsp_speed(snddev_info *d)
d->bd_flags |= BD_F_HISPEED ;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 65536 - (tconst << 8);
@ -791,7 +871,7 @@ dsp_speed(snddev_info *d)
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 256 - tconst;
@ -1044,7 +1124,7 @@ sb16pnp_probe(u_long csn, u_long vend_id)
* the vendor id, so I have just masked it for the time being...
* Reported values are:
* SB16 Value PnP: 0x2b008c0e
* SB AWE64 PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
*/
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
s = "SB16 PnP";

View File

@ -174,6 +174,9 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
d->flags = 0 ;
d->bd_flags &= ~BD_F_HISPEED ;
@ -273,25 +276,36 @@ sbintr(int unit)
*/
reason = 0 ;
if ( c & 1 ) { /* 8-bit dma */
if (d->dma1 < 4)
if (d->dbuf_out.chan < 4)
reason |= 1;
if (d->dma2 < 4)
if (d->dbuf_in.chan < 4)
reason |= 2;
}
if ( c & 2 ) { /* 16-bit dma */
if (d->dma1 >= 4)
if (d->dbuf_out.chan >= 4)
reason |= 1;
if (d->dma2 >= 4)
if (d->dbuf_in.chan >= 4)
reason |= 2;
}
}
/* XXX previous location of ack... */
DEB(printf("sbintr, flags 0x%08lx reason %d\n", d->flags, reason));
if ( d->dbuf_out.dl && (reason & 1) )
if ( reason & 1 ) { /* possibly a write interrupt */
if ( d->dbuf_out.dl )
dsp_wrintr(d);
if ( d->dbuf_in.dl && (reason & 2) )
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: wrintr but write DMA inactive!\n");
}
}
if ( reason & 2 ) {
if ( d->dbuf_in.dl )
dsp_rdintr(d);
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: rdintr but read DMA inactive!\n");
}
}
if ( c & 2 )
inb(DSP_DATA_AVL16); /* 16-bit int ack */
if (c & 1)
@ -307,7 +321,7 @@ sbintr(int unit)
/*
* device-specific function called back from the dma module.
* The reason of the callback is the second argument.
* NOTE: during operations, some ioctl can be done to change
* NOTE: during operations, some ioctl can be called to change
* settings (e.g. speed, channels, format), and the default
* ioctl handler will just record the change and set the
* flag SND_F_INIT. The callback routine is in charge of applying
@ -319,7 +333,8 @@ static int
sb_callback(snddev_info *d, int reason)
{
int rd = reason & SND_CB_RD ;
int l = (rd) ? d->dbuf_in.dl : d->dbuf_out.dl ;
snd_dbuf *b = (rd) ? & (d->dbuf_in) : & (d->dbuf_out) ;
int l = b->dl ;
switch (reason & SND_CB_REASON_MASK) {
case SND_CB_INIT : /* called with int enabled and no pending io */
@ -336,6 +351,8 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_START : /* called with int disabled */
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
/* the SB16 can do full duplex using one 16-bit channel
* and one 8-bit channel. It needs to be programmed to
* use split format though.
@ -347,63 +364,80 @@ sb_callback(snddev_info *d, int reason)
int swap = 1 ; /* default... */
if (rd) {
if (d->flags & SND_F_WRITING || d->dbuf_out.dl)
/* need not to swap if channel is already correct */
if ( d->rec_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->rec_fmt == AFMT_S16_LE && d->dma2 >=4)
if ( d->rec_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->rec_fmt != AFMT_S16_LE && d->dma2 <4)
if (swap && (d->flags & SND_F_WRITING || d->dbuf_out.dl)) {
/* cannot swap if writing is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break; /* XXX should return an error */
}
} else {
if (d->flags & SND_F_READING || d->dbuf_in.dl)
/* need not to swap if channel is already correct */
if ( d->play_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->play_fmt == AFMT_S16_LE && d->dma1 >=4)
if ( d->play_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->play_fmt != AFMT_S16_LE && d->dma1 <4)
if (swap && ( d->flags & SND_F_READING || d->dbuf_in.dl)) {
/* cannot swap if reading is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break ; /* XXX should return an error */
}
}
if (swap) {
int c = d->dma2 ;
d->dma2 = d->dma1;
d->dma1 = c ;
int c = d->dbuf_in.chan ;
d->dbuf_in.chan = d->dbuf_out.chan;
d->dbuf_out.chan = c ;
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
DEB(printf("START dma chan: play %d, rec %d\n",
d->dma1, d->dma2));
d->dbuf_out.chan, d->dbuf_in.chan));
}
}
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
if (rd) {
c = ((d->dma2 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_ADC ;
c1 = (d->rec_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->rec_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->rec_fmt == AFMT_S16_LE)
/*
* XXX note: c1 and l should be set basing on d->rec_fmt,
* but there is no choice once a 16 or 8-bit channel
* is assigned. This means that if the application
* tries to use a bad format, the sound will not be nice.
*/
if ( b->chan > 4 ) {
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
c1 = DSP_F16_SIGNED ;
l /= 2 ;
} else {
c = ((d->dma1 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_DAC ;
c1 = (d->play_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->play_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->play_fmt == AFMT_S16_LE)
l /= 2 ;
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA8 ;
c1 = 0 ;
}
c |= (rd) ? DSP_F16_ADC : DSP_F16_DAC ;
if (d->flags & SND_F_STEREO)
c1 |= DSP_F16_STEREO ;
sb_cmd(d->io_base, c );
sb_cmd3(d->io_base, c1 , l - 1) ;
} else {
/* code for the SB2 and SB3 */
} else if (d->bd_flags & BD_F_ESS) {
/* XXX this code is still incomplete */
sb_cmd2(d->io_base, 0xb8, rd ? 0x0e : 0x04 ); /* auto dma */
sb_cmd2(d->io_base, 0xa8, 2 /* chans */ );
sb_cmd2(d->io_base, 0xb9, 2); /* demand mode */
/*
input: 0xb8 -> 0x0e ;
0xa8 -> channels
0xb9 -> 2
mono,U8: 51, d0
mono,S16 71, f4
st, U8 51, 98
st, S16 71, bc
*/
} else { /* SBPro */
u_char c ;
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
/* code for the SB2 and SB3 */
if (d->bd_flags & BD_F_HISPEED)
c = (rd) ? DSP_CMD_HSADC_AUTO : DSP_CMD_HSDAC_AUTO ;
else
@ -416,18 +450,17 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_STOP :
{
int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */
if (d->bd_flags & BD_F_SB16) {
if ( (rd && d->dbuf_in.chan>4) || (!rd && d->dbuf_out.chan>4) )
if ( d->bd_flags & BD_F_SB16 && b->chan > 4 )
cmd = DSP_CMD_DMAPAUSE_16 ;
}
if (d->bd_flags & BD_F_HISPEED) {
sb_reset_dsp(d->io_base);
d->flags |= SND_F_INIT ;
} else {
sb_cmd(d->io_base, cmd); /* pause dma. */
/*
* This seems to have the side effect of blocking the other
* side as well so I have to re-enable it :(
* The above seems to have the undocumented side effect of
* blocking the other side as well. If the other
* channel was active (SB16) I have to re-enable it :(
*/
if ( (rd && d->dbuf_out.dl) ||
(!rd && d->dbuf_in.dl) )
@ -508,7 +541,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
break ;
case 2 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
d->bd_flags |= BD_F_DUP_MIDI ;
if (d->bd_id == 0x200)
@ -536,11 +569,11 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
else
sb_setmixer(io_base, IRQ_NR, x);
sb_setmixer(io_base, DMA_NR, (1 << d->dma1) | (1 << d->dma2));
sb_setmixer(io_base, DMA_NR, (1 << d->dbuf_out.chan) | (1 << d->dbuf_in.chan));
break ;
case 3 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
fmt = "SoundBlaster Pro %d.%d";
d->bd_flags |= BD_F_DUP_MIDI ;
d->bd_flags &= ~BD_F_MIX_MASK ;
@ -562,24 +595,48 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
ess_minor = inb(DSP_READ);
break;
}
}
} else
DELAY(20);
}
if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS488 based card (rev %d)\n",
ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS688 based card (rev %d)\n",
ess_minor & 0x0f);
printf("ESS488 (rev %d)\n", ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
if ( (ess_minor & 0xf) >= 8 )
printf("ESS1688 (rev %d)\n", ess_minor & 0x0f);
else
printf("ESS688 (rev %d)\n", ess_minor & 0x0f);
} else
break ;
d->bd_id = (ess_major << 8) | ess_minor ;
d->bd_flags |= BD_F_ESS;
/*
* ESS-specific initialization, taken from OSSFree 3.8
*/
{
static u_char irqs[16] = {
0, 0, 0x50, 0, 0, 0x54, 0, 0x58,
0, 0x50, 0x5c, 0, 0, 0, 0, 0 };
static u_char drqs[8] = {
0x51, 0x52, 0, 0x53, 0, 0, 0, 0 };
x = irqs[d->irq & 0xf];
if (x == 0)
printf("ESS : invalid IRQ %d\n", d->irq);
else {
sb_cmd(io_base, 0xb1 ); /* set IRQ */
sb_cmd(io_base, x );
x = drqs[ d->dbuf_out.chan & 0x7 ];
if (x == 0)
printf("ESS : invalid DRQ %d\n", d->dbuf_out.chan);
else {
sb_cmd(io_base, 0xb2 ); /* set DRQ */
sb_cmd(io_base, x );
}
}
}
}
if (d->bd_flags & BD_F_JAZZ16) {
if (d->bd_flags & BD_F_JAZZ16_2)
fmt = "SoundMan Wave %d.%d";
else
fmt = "MV Jazz16 %d.%d";
d->audio_fmt |= AFMT_S16_LE; /* 16 bits */
}
}
sprintf(d->name, fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff);
@ -714,6 +771,9 @@ dsp_speed(snddev_info *d)
u_long flags;
int max_speed = 44100, speed = d->play_speed ;
/*
* special code for the SB16
*/
if (d->bd_flags & BD_F_SB16) {
RANGE (speed, 5000, 45000);
d->play_speed = d->rec_speed = speed ;
@ -725,6 +785,26 @@ dsp_speed(snddev_info *d)
sb_cmd(d->io_base, d->rec_speed & 0xff );
return speed ;
}
/*
* special code for the ESS ...
*/
if (d->bd_flags & BD_F_ESS) {
int t;
RANGE (speed, 4000, 48000);
if (speed > 22000) {
t = (795500 + speed / 2) / speed;
speed = (795500 + t / 2) / t ;
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
} else {
t = (397700 + speed / 2) / speed;
speed = (397700 + t / 2) / t ;
t = 128 - (397700 + speed / 2) / speed ;
}
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
return speed ;
}
/*
* only some models can do stereo, and only if not
* simultaneously using midi.
@ -779,7 +859,7 @@ dsp_speed(snddev_info *d)
d->bd_flags |= BD_F_HISPEED ;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 65536 - (tconst << 8);
@ -791,7 +871,7 @@ dsp_speed(snddev_info *d)
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 256 - tconst;
@ -1044,7 +1124,7 @@ sb16pnp_probe(u_long csn, u_long vend_id)
* the vendor id, so I have just masked it for the time being...
* Reported values are:
* SB16 Value PnP: 0x2b008c0e
* SB AWE64 PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
*/
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
s = "SB16 PnP";

View File

@ -197,7 +197,7 @@ mss_attach(struct isa_device *dev)
printf("mss_attach <%s>%d at 0x%x irq %d dma %d:%d flags 0x%x\n",
d->name, dev->id_unit,
d->io_base, d->irq, d->dma1, d->dma2, dev->id_flags);
d->io_base, d->irq, d->dbuf_out.chan, d->dbuf_in.chan, dev->id_flags);
dev->id_alive = 8 ; /* number of io ports */
/* should be already set but just in case... */
@ -220,18 +220,18 @@ mss_attach(struct isa_device *dev)
printf("[IRQ Conflict?]");
/* Write IRQ+DMA setup */
if (d->dma1 == d->dma2) /* single chan dma */
outb(dev->id_iobase, bits | dma_bits[d->dma1]);
if ( ! FULL_DUPLEX(d) ) /* single chan dma */
outb(dev->id_iobase, bits | dma_bits[d->dbuf_out.chan]);
else {
if (d->dma1 == 0 && d->dma2 == 1)
if (d->dbuf_out.chan == 0 && d->dbuf_in.chan == 1)
bits |= 5 ;
else if (d->dma1 == 1 && d->dma2 == 0)
else if (d->dbuf_out.chan == 1 && d->dbuf_in.chan == 0)
bits |= 6 ;
else if (d->dma1 == 3 && d->dma2 == 0)
else if (d->dbuf_out.chan == 3 && d->dbuf_in.chan == 0)
bits |= 7 ;
else {
printf("invalid dual dma config %d:%d\n",
d->dma1, d->dma2);
d->dbuf_out.chan, d->dbuf_in.chan);
dev->id_irq = 0 ;
dev->id_alive = 0 ; /* this makes attach fail. */
return 0 ;
@ -239,7 +239,7 @@ mss_attach(struct isa_device *dev)
outb(dev->id_iobase, bits );
}
}
if (d->dma1 != d->dma2)
if ( FULL_DUPLEX(d) )
d->audio_fmt |= AFMT_FULLDUPLEX ;
mss_reinit(d);
ad1848_mixer_reset(d);
@ -293,6 +293,9 @@ mss_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
if (flags & O_NONBLOCK)
d->flags |= SND_F_NBIO ;
@ -426,7 +429,7 @@ mss_callback(snddev_info *d, int reason)
if (retry == 0)
printf("start dma, failed to set bit 0x%02x 0x%02x\n",
m, ad_read(d, 9) ) ;
if (wr || (d->dma1 == d->dma2) )
if (wr || ! FULL_DUPLEX(d) )
ad_write_cnt(d, 14, cnt);
else
ad_write_cnt(d, 30, cnt);
@ -452,7 +455,7 @@ mss_callback(snddev_info *d, int reason)
* is needed, and it might cause false interrupts when the
* DMA is re-enabled later.
*/
if (wr || (d->dma1 == d->dma2) )
if (wr || ! FULL_DUPLEX(d) )
ad_write_cnt(d, 14, 0);
else
ad_write_cnt(d, 30, 0);
@ -492,7 +495,7 @@ mss_intr(int unit)
*/
for (i=10 ; i && inb(io_Status(d)) & 1 ; i-- ) {
/* get exact reason for full-duplex boards */
c = (d->dma1 == d->dma2) ? 0x30 : ad_read(d, 24);
c = FULL_DUPLEX(d) ? ad_read(d, 24) : 0x30 ;
c &= ~served ;
if ( d->dbuf_out.dl && (c & 0x10) ) {
served |= 0x10 ;
@ -505,10 +508,18 @@ mss_intr(int unit)
/*
* now ack the interrupt
*/
if (d->dma1 == d->dma2)
outb(io_Status(d), 0); /* Clear interrupt status */
else
if ( FULL_DUPLEX(d) )
ad_write(d, 24, ~c); /* ack selectively */
else
outb(io_Status(d), 0); /* Clear interrupt status */
}
if (served == 0) {
printf("How strange... mss_intr with no reason!\n");
/*
* this should not happen... I have no idea what to do now.
* maybe should do a sanity check and restart dmas ?
*/
outb(io_Status(d), 0); /* Clear interrupt status */
}
}
@ -534,7 +545,7 @@ opti931_intr(int unit)
i11 = ad_read(d, 11); /* XXX what's for ? */
again:
c=mc11 = (d->dma1 == d->dma2) ? 0xc : opti_read(d->conf_base, 11);
c=mc11 = FULL_DUPLEX(d) ? opti_read(d->conf_base, 11) : 0xc ;
mc11 &= 0x0c ;
if (c & 0x10) {
printf("Warning: CD interrupt\n");
@ -791,7 +802,7 @@ mss_set_recsrc(snddev_info *d, int mask)
*/
static char mix_cvt[101] = {
0, 0, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
0, 1, 3, 7,10,13,16,19,21,23,26,28,30,32,34,35,37,39,40,42,
43,45,46,47,49,50,51,52,53,55,56,57,58,59,60,61,62,63,64,65,
65,66,67,68,69,70,70,71,72,73,73,74,75,75,76,77,77,78,79,79,
80,81,81,82,82,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,
@ -849,8 +860,12 @@ mss_mixer_set(snddev_info *d, int dev, int value)
regoffs = (*mix_d)[dev][LEFT_CHN].regno;
old = val = ad_read(d, regoffs);
if (regoffs != 0)
val = old & 0x7f ; /* clear mute bit. */
/*
* if volume is 0, mute chan. Otherwise, unmute.
*/
if (regoffs != 0) /* main input is different */
val = (left == 0 ) ? old | 0x80 : old & 0x7f ;
change_bits(mix_d, &val, dev, LEFT_CHN, left);
ad_write(d, regoffs, val);
DEB(printf("LEFT: dev %d reg %d old 0x%02x new 0x%02x\n",
@ -863,7 +878,7 @@ mss_mixer_set(snddev_info *d, int dev, int value)
regoffs = (*mix_d)[dev][RIGHT_CHN].regno;
old = val = ad_read(d, regoffs);
if (regoffs != 1)
val = old & 0x7f ; /* clear mute bit. */
val = (right == 0 ) ? old | 0x80 : old & 0x7f ;
change_bits(mix_d, &val, dev, RIGHT_CHN, right);
ad_write(d, regoffs, val);
DEB(printf("RIGHT: dev %d reg %d old 0x%02x new 0x%02x\n",
@ -1261,7 +1276,7 @@ mss_reinit(snddev_info *d)
* perhaps this is not the place to set mode2, should be done
* only once at attach time...
*/
if ( d->dma1 != d->dma2 && d->bd_id != MD_OPTI931)
if ( FULL_DUPLEX(d) && d->bd_id != MD_OPTI931)
/*
* set mode2 bit for dual dma op. This bit is not implemented
* on the OPTi931
@ -1282,7 +1297,7 @@ mss_reinit(snddev_info *d)
}
ad_write(d, 8, r) ;
if (d->dma1 != d->dma2) {
if ( FULL_DUPLEX(d) ) {
#if 0
if (d->bd_id == MD_GUSPNP && d->play_fmt == AFMT_MU_LAW) {
printf("warning, cannot do ulaw rec + play on the GUS\n");
@ -1298,7 +1313,7 @@ mss_reinit(snddev_info *d)
* not sure if this is really needed...
*/
ad_write_cnt(d, 14, 0 ); /* playback count */
if (d->dma1 != d->dma2)
if ( FULL_DUPLEX(d) )
ad_write_cnt(d, 30, 0 ); /* rec. count on dual dma */
ad_write(d, 10, 2 /* int enable */) ;
@ -1322,7 +1337,7 @@ static void cs423x_attach(u_long csn, u_long vend_id, char *name,
struct isa_device *dev);
static struct pnp_device cs423x = {
"cs423x/ymh0020",
"CS423x/Yamaha",
cs423x_probe,
cs423x_attach,
&nsnd, /* use this for all sound cards */
@ -1343,6 +1358,8 @@ cs423x_probe(u_long csn, u_long vend_id)
s = "CS4232" ;
else if ( id == 0x2000a865)
s = "Yamaha SA2";
else if ( id == 0x3000a865)
s = "Yamaha SA3";
else if (vend_id == 0x8140d315)
s = "SoundscapeVIVO";
if (s) {
@ -1376,8 +1393,8 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
if (d.flags & DV_PNP_SBCODEC) { /*** use sb-compatible codec ***/
dev->id_alive = 16 ; /* number of io ports ? */
tmp_d = sb_op_desc ;
if (vend_id == 0x2000a865 || vend_id == 0x8140d315) {
/* Yamaha SA2 or ENSONIQ SoundscapeVIVO ENS4081 */
if (vend_id==0x2000a865 || vend_id==0x3000a865 || vend_id==0x8140d315) {
/* Yamaha SA2/SA3 or ENSONIQ SoundscapeVIVO ENS4081 */
dev->id_iobase = d.port[0] ;
tmp_d.alt_base = d.port[1] ;
d.irq[1] = 0 ; /* only needed for the VIVO */
@ -1393,9 +1410,11 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
tmp_d.alt_base = d.port[2];
switch (vend_id & 0xff00ffff) {
case 0x2000a865: /* yamaha SA-2 */
case 0x2000a865: /* Yamaha SA2 */
case 0x3000a865: /* Yamaha SA3 */
dev->id_iobase = d.port[1];
tmp_d.alt_base = d.port[0];
tmp_d.conf_base = d.port[4];
tmp_d.bd_id = MD_YM0020 ;
break;
@ -1424,6 +1443,13 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
write_pnp_parms( &d, ldn );
enable_pnp_card();
if ( (vend_id & 0x2000ffff) == 0x2000a865 ) {
/* special volume setting for the Yamaha... */
outb(tmp_d.conf_base, 7 /* volume, left */);
outb(tmp_d.conf_base+1, 0 );
outb(tmp_d.conf_base, 8 /* volume, right */);
outb(tmp_d.conf_base+1, 0 );
}
dev->id_drq = d.drq[0] ; /* primary dma */
dev->id_irq = (1 << d.irq[0] ) ;
dev->id_intr = pcmintr ;

View File

@ -237,7 +237,7 @@ initialize_ProSonic16(snddev_info *d)
if (sb_cmd(sb_probed.io_base, 0xFB) && /* set DMA and irq */
sb_cmd(sb_probed.io_base,
(dma_translat[JAZZ_DMA16]<<4)|dma_translat[sb_probed.dma1]) &&
(dma_translat[JAZZ_DMA16]<<4)|dma_translat[sb_probed.dbuf_out.chan]) &&
sb_cmd(sb_probed.io_base,
(int_translat[mpu_irq]<<4)|int_translat[sb_probed.irq])) {
d->bf_flags |= BD_F_JAZZ16 ;

View File

@ -46,30 +46,28 @@ static void dsp_rd_dmadone(snddev_info *d);
We use a circular buffer to store samples directed to the DAC.
The buffer is split into two variable-size regions, each identified
by an offset in the buffer (rp,fp) and a lenght (rl,fl). dl contains
the length of the current DMA transfer, dl=0 means that the dma is
idle.
by an offset in the buffer (rp,fp) and a length (rl,fl):
0 rp,rl fp,fl bufsize
|__________>____________>________|
FREE d READY w FREE
READY region: contains data written from the process and ready
to be sent to the DAC;
READY: data written from the process and ready to be sent to the DAC;
FREE: free part of the buffer.
FREE region: is the empty region of the buffer, where a process
can write new data.
Both the "READY" and "FREE" regions can wrap around the end of the
buffer. At initialization, READY is empty, FREE takes all the
available space, and dma is idle.
Both regions can wrap around the end of the buffer. At initialization,
READY is empty, FREE takes all the available space, and dma is
idle. dl contains the length of the current DMA transfer, dl=0
means that the dma is idle.
The two boundaries (rp,fp) in the buffers are advanced by DMA [d]
and write() [w] operations. The first block of the READY region
and write() [w] operations. The first portion of the READY region
is used for DMA transfers. The transfer is started at rp and with
chunks of length dl. During DMA operations, rp advances and rl,fl
are updated by dsp_wr_dmaupdate(). When a new block is written,
fp advances and rl,fl are updated accordingly.
chunks of length dl. During DMA operations, dsp_wr_dmaupdate()
updates rp, rl and fl tracking the ISA DMA engine as the transfer
makes progress.
When a new block is written, fp advances and rl,fl are updated
accordingly.
The code works as follows: the user write routine dsp_write_body()
fills up the READY region with new data (reclaiming space from the
@ -82,8 +80,8 @@ In some cases, the code tries to track the current status of DMA
operations by calling dsp_wr_dmaupdate() which changes rp, rl and fl.
The sistem tries to make all DMA transfers use the same size,
play_blocksize or rec_blocksize. The size is either selected
by the user, or computed by the system to correspond to about .25s of
play_blocksize or rec_blocksize. The size is either selected by
the user, or computed by the system to correspond to about .25s of
audio. The blocksize must be within a range which is currently:
min(5ms, 40 bytes) ... 1/2 buffer size.
@ -91,8 +89,8 @@ audio. The blocksize must be within a range which is currently:
When there aren't enough data (write) or space (read), a transfer
is started with a reduced size.
To reduce problems in case of overruns, the routine which fills up the
buffer should initialize (e.g. by repeating the last value) a
To reduce problems in case of overruns, the routine which fills up
the buffer should initialize (e.g. by repeating the last value) a
reasonably long area after the last block so that no noise is
produced on overruns.
@ -142,6 +140,7 @@ dsp_wr_dmaupdate(snd_dbuf *b)
b->rp = tmp;
b->rl -= delta ;
b->fl += delta ;
b->total += delta ;
}
/*
@ -164,7 +163,7 @@ dsp_wrintr(snddev_info *d)
/*
* start another dma operation only if have ready data in the buffer,
* there is no pending abort, have a full-duplex device
* (dbuf_out.chan != dbuf_in.chan) or have half duplex device
* or have half duplex device
* and there is no * pending op on the other side.
*
* Force transfers to be aligned to a boundary of 4, which is
@ -173,8 +172,7 @@ dsp_wrintr(snddev_info *d)
*/
if ( b->rl >= DMA_ALIGN_THRESHOLD &&
! (d->flags & SND_F_ABORTING) &&
( (d->dbuf_out.chan != d->dbuf_in.chan) ||
! (d->flags & SND_F_READING) ) ) {
( FULL_DUPLEX(d) || ! (d->flags & SND_F_READING) ) ) {
int l = min(b->rl, d->play_blocksize ); /* avoid too large transfer */
l &= DMA_ALIGN_MASK ; /* realign things */
@ -201,7 +199,7 @@ dsp_wrintr(snddev_info *d)
/*
* if switching to read, should start the read dma...
*/
if ( d->dbuf_out.chan == d->dbuf_in.chan && (d->flags & SND_F_READING) )
if ( !FULL_DUPLEX(d) && (d->flags & SND_F_READING) )
dsp_rdintr(d);
}
}
@ -422,6 +420,7 @@ dsp_rd_dmaupdate(snd_dbuf *b)
b->fp = tmp;
b->fl -= delta ;
b->rl += delta ;
b->total += delta ;
}
/*
@ -444,8 +443,7 @@ dsp_rdintr(snddev_info *d)
*/
if ( b->fl > 0x200 &&
(d->flags & (SND_F_ABORTING|SND_F_CLOSING)) == 0 &&
( d->dbuf_out.chan != d->dbuf_in.chan ||
(d->flags & SND_F_WRITING) == 0 ) ) {
( FULL_DUPLEX(d) || (d->flags & SND_F_WRITING) == 0 ) ) {
int l = min(b->fl - 0x100, d->rec_blocksize);
l &= DMA_ALIGN_MASK ; /* realign sizes */
if (l != b->dl) {
@ -462,7 +460,7 @@ dsp_rdintr(snddev_info *d)
/*
* if switching to write, start write dma engine
*/
if ( d->dbuf_out.chan == d->dbuf_in.chan && (d->flags & SND_F_WRITING) )
if ( ! FULL_DUPLEX(d) && (d->flags & SND_F_WRITING) )
dsp_wrintr(d) ;
DEB(printf("cannot start rd-dma rl %d fl %d\n",
b->rl, b->fl));

View File

@ -174,6 +174,9 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
d->rsel.si_pid = 0;
d->rsel.si_flags = 0;
d->dbuf_out.total = d->dbuf_out.prev_total = 0 ;
d->dbuf_in.total = d->dbuf_in.prev_total = 0 ;
d->flags = 0 ;
d->bd_flags &= ~BD_F_HISPEED ;
@ -273,25 +276,36 @@ sbintr(int unit)
*/
reason = 0 ;
if ( c & 1 ) { /* 8-bit dma */
if (d->dma1 < 4)
if (d->dbuf_out.chan < 4)
reason |= 1;
if (d->dma2 < 4)
if (d->dbuf_in.chan < 4)
reason |= 2;
}
if ( c & 2 ) { /* 16-bit dma */
if (d->dma1 >= 4)
if (d->dbuf_out.chan >= 4)
reason |= 1;
if (d->dma2 >= 4)
if (d->dbuf_in.chan >= 4)
reason |= 2;
}
}
/* XXX previous location of ack... */
DEB(printf("sbintr, flags 0x%08lx reason %d\n", d->flags, reason));
if ( d->dbuf_out.dl && (reason & 1) )
if ( reason & 1 ) { /* possibly a write interrupt */
if ( d->dbuf_out.dl )
dsp_wrintr(d);
if ( d->dbuf_in.dl && (reason & 2) )
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: wrintr but write DMA inactive!\n");
}
}
if ( reason & 2 ) {
if ( d->dbuf_in.dl )
dsp_rdintr(d);
else {
if (d->bd_flags & BD_F_SB16)
printf("WARNING: rdintr but read DMA inactive!\n");
}
}
if ( c & 2 )
inb(DSP_DATA_AVL16); /* 16-bit int ack */
if (c & 1)
@ -307,7 +321,7 @@ sbintr(int unit)
/*
* device-specific function called back from the dma module.
* The reason of the callback is the second argument.
* NOTE: during operations, some ioctl can be done to change
* NOTE: during operations, some ioctl can be called to change
* settings (e.g. speed, channels, format), and the default
* ioctl handler will just record the change and set the
* flag SND_F_INIT. The callback routine is in charge of applying
@ -319,7 +333,8 @@ static int
sb_callback(snddev_info *d, int reason)
{
int rd = reason & SND_CB_RD ;
int l = (rd) ? d->dbuf_in.dl : d->dbuf_out.dl ;
snd_dbuf *b = (rd) ? & (d->dbuf_in) : & (d->dbuf_out) ;
int l = b->dl ;
switch (reason & SND_CB_REASON_MASK) {
case SND_CB_INIT : /* called with int enabled and no pending io */
@ -336,6 +351,8 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_START : /* called with int disabled */
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
/* the SB16 can do full duplex using one 16-bit channel
* and one 8-bit channel. It needs to be programmed to
* use split format though.
@ -347,63 +364,80 @@ sb_callback(snddev_info *d, int reason)
int swap = 1 ; /* default... */
if (rd) {
if (d->flags & SND_F_WRITING || d->dbuf_out.dl)
/* need not to swap if channel is already correct */
if ( d->rec_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->rec_fmt == AFMT_S16_LE && d->dma2 >=4)
if ( d->rec_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->rec_fmt != AFMT_S16_LE && d->dma2 <4)
if (swap && (d->flags & SND_F_WRITING || d->dbuf_out.dl)) {
/* cannot swap if writing is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break; /* XXX should return an error */
}
} else {
if (d->flags & SND_F_READING || d->dbuf_in.dl)
/* need not to swap if channel is already correct */
if ( d->play_fmt == AFMT_S16_LE && b->chan > 4 )
swap = 0;
if (d->play_fmt == AFMT_S16_LE && d->dma1 >=4)
if ( d->play_fmt != AFMT_S16_LE && b->chan < 4 )
swap = 0;
if (d->play_fmt != AFMT_S16_LE && d->dma1 <4)
if (swap && ( d->flags & SND_F_READING || d->dbuf_in.dl)) {
/* cannot swap if reading is already active */
DDB(printf("sorry, DMA channel unavailable\n"));
swap = 0;
break ; /* XXX should return an error */
}
}
if (swap) {
int c = d->dma2 ;
d->dma2 = d->dma1;
d->dma1 = c ;
int c = d->dbuf_in.chan ;
d->dbuf_in.chan = d->dbuf_out.chan;
d->dbuf_out.chan = c ;
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
DEB(printf("START dma chan: play %d, rec %d\n",
d->dma1, d->dma2));
d->dbuf_out.chan, d->dbuf_in.chan));
}
}
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
if (d->bd_flags & BD_F_SB16) {
u_char c, c1 ;
if (rd) {
c = ((d->dma2 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_ADC ;
c1 = (d->rec_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->rec_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->rec_fmt == AFMT_S16_LE)
/*
* XXX note: c1 and l should be set basing on d->rec_fmt,
* but there is no choice once a 16 or 8-bit channel
* is assigned. This means that if the application
* tries to use a bad format, the sound will not be nice.
*/
if ( b->chan > 4 ) {
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
c1 = DSP_F16_SIGNED ;
l /= 2 ;
} else {
c = ((d->dma1 > 3) ? DSP_DMA16 : DSP_DMA8) |
DSP_F16_AUTO |
DSP_F16_FIFO_ON | DSP_F16_DAC ;
c1 = (d->play_fmt == AFMT_U8) ? 0 : DSP_F16_SIGNED ;
if (d->play_fmt == AFMT_MU_LAW) c1 = 0 ;
if (d->play_fmt == AFMT_S16_LE)
l /= 2 ;
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA8 ;
c1 = 0 ;
}
c |= (rd) ? DSP_F16_ADC : DSP_F16_DAC ;
if (d->flags & SND_F_STEREO)
c1 |= DSP_F16_STEREO ;
sb_cmd(d->io_base, c );
sb_cmd3(d->io_base, c1 , l - 1) ;
} else {
/* code for the SB2 and SB3 */
} else if (d->bd_flags & BD_F_ESS) {
/* XXX this code is still incomplete */
sb_cmd2(d->io_base, 0xb8, rd ? 0x0e : 0x04 ); /* auto dma */
sb_cmd2(d->io_base, 0xa8, 2 /* chans */ );
sb_cmd2(d->io_base, 0xb9, 2); /* demand mode */
/*
input: 0xb8 -> 0x0e ;
0xa8 -> channels
0xb9 -> 2
mono,U8: 51, d0
mono,S16 71, f4
st, U8 51, 98
st, S16 71, bc
*/
} else { /* SBPro */
u_char c ;
if (!rd)
sb_cmd(d->io_base, DSP_CMD_SPKON);
/* code for the SB2 and SB3 */
if (d->bd_flags & BD_F_HISPEED)
c = (rd) ? DSP_CMD_HSADC_AUTO : DSP_CMD_HSDAC_AUTO ;
else
@ -416,18 +450,17 @@ sb_callback(snddev_info *d, int reason)
case SND_CB_STOP :
{
int cmd = DSP_CMD_DMAPAUSE_8 ; /* default: halt 8 bit chan */
if (d->bd_flags & BD_F_SB16) {
if ( (rd && d->dbuf_in.chan>4) || (!rd && d->dbuf_out.chan>4) )
if ( d->bd_flags & BD_F_SB16 && b->chan > 4 )
cmd = DSP_CMD_DMAPAUSE_16 ;
}
if (d->bd_flags & BD_F_HISPEED) {
sb_reset_dsp(d->io_base);
d->flags |= SND_F_INIT ;
} else {
sb_cmd(d->io_base, cmd); /* pause dma. */
/*
* This seems to have the side effect of blocking the other
* side as well so I have to re-enable it :(
* The above seems to have the undocumented side effect of
* blocking the other side as well. If the other
* channel was active (SB16) I have to re-enable it :(
*/
if ( (rd && d->dbuf_out.dl) ||
(!rd && d->dbuf_in.dl) )
@ -508,7 +541,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
break ;
case 2 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
d->bd_flags |= BD_F_DUP_MIDI ;
if (d->bd_id == 0x200)
@ -536,11 +569,11 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
else
sb_setmixer(io_base, IRQ_NR, x);
sb_setmixer(io_base, DMA_NR, (1 << d->dma1) | (1 << d->dma2));
sb_setmixer(io_base, DMA_NR, (1 << d->dbuf_out.chan) | (1 << d->dbuf_in.chan));
break ;
case 3 :
d->dma2 = d->dma1 ; /* half duplex */
d->dbuf_in.chan = d->dbuf_out.chan ; /* half duplex */
fmt = "SoundBlaster Pro %d.%d";
d->bd_flags |= BD_F_DUP_MIDI ;
d->bd_flags &= ~BD_F_MIX_MASK ;
@ -562,24 +595,48 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
ess_minor = inb(DSP_READ);
break;
}
}
} else
DELAY(20);
}
if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS488 based card (rev %d)\n",
ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
printf("Hmm... Could this be an ESS688 based card (rev %d)\n",
ess_minor & 0x0f);
printf("ESS488 (rev %d)\n", ess_minor & 0x0f);
else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
if ( (ess_minor & 0xf) >= 8 )
printf("ESS1688 (rev %d)\n", ess_minor & 0x0f);
else
printf("ESS688 (rev %d)\n", ess_minor & 0x0f);
} else
break ;
d->bd_id = (ess_major << 8) | ess_minor ;
d->bd_flags |= BD_F_ESS;
/*
* ESS-specific initialization, taken from OSSFree 3.8
*/
{
static u_char irqs[16] = {
0, 0, 0x50, 0, 0, 0x54, 0, 0x58,
0, 0x50, 0x5c, 0, 0, 0, 0, 0 };
static u_char drqs[8] = {
0x51, 0x52, 0, 0x53, 0, 0, 0, 0 };
x = irqs[d->irq & 0xf];
if (x == 0)
printf("ESS : invalid IRQ %d\n", d->irq);
else {
sb_cmd(io_base, 0xb1 ); /* set IRQ */
sb_cmd(io_base, x );
x = drqs[ d->dbuf_out.chan & 0x7 ];
if (x == 0)
printf("ESS : invalid DRQ %d\n", d->dbuf_out.chan);
else {
sb_cmd(io_base, 0xb2 ); /* set DRQ */
sb_cmd(io_base, x );
}
}
}
}
if (d->bd_flags & BD_F_JAZZ16) {
if (d->bd_flags & BD_F_JAZZ16_2)
fmt = "SoundMan Wave %d.%d";
else
fmt = "MV Jazz16 %d.%d";
d->audio_fmt |= AFMT_S16_LE; /* 16 bits */
}
}
sprintf(d->name, fmt, (d->bd_id >> 8) &0xff, d->bd_id & 0xff);
@ -714,6 +771,9 @@ dsp_speed(snddev_info *d)
u_long flags;
int max_speed = 44100, speed = d->play_speed ;
/*
* special code for the SB16
*/
if (d->bd_flags & BD_F_SB16) {
RANGE (speed, 5000, 45000);
d->play_speed = d->rec_speed = speed ;
@ -725,6 +785,26 @@ dsp_speed(snddev_info *d)
sb_cmd(d->io_base, d->rec_speed & 0xff );
return speed ;
}
/*
* special code for the ESS ...
*/
if (d->bd_flags & BD_F_ESS) {
int t;
RANGE (speed, 4000, 48000);
if (speed > 22000) {
t = (795500 + speed / 2) / speed;
speed = (795500 + t / 2) / t ;
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
} else {
t = (397700 + speed / 2) / speed;
speed = (397700 + t / 2) / t ;
t = 128 - (397700 + speed / 2) / speed ;
}
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
return speed ;
}
/*
* only some models can do stereo, and only if not
* simultaneously using midi.
@ -779,7 +859,7 @@ dsp_speed(snddev_info *d)
d->bd_flags |= BD_F_HISPEED ;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 65536 - (tconst << 8);
@ -791,7 +871,7 @@ dsp_speed(snddev_info *d)
tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff;
flags = spltty();
sb_cmd2(d->io_base, DSP_CMD_TCONST, tconst);
sb_cmd2(d->io_base, 0x40, tconst); /* set time constant */
splx(flags);
tmp = 256 - tconst;
@ -1044,7 +1124,7 @@ sb16pnp_probe(u_long csn, u_long vend_id)
* the vendor id, so I have just masked it for the time being...
* Reported values are:
* SB16 Value PnP: 0x2b008c0e
* SB AWE64 PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
*/
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
s = "SB16 PnP";

View File

@ -137,6 +137,7 @@ extern int sbc_major, sbc_minor ;
#define BD_F_SB16 0x0100 /* this is a SB16 */
#define BD_F_NOREC 0x0200 /* recording not supported on this board */
#define BD_F_MIDIBUSY 0x0400 /* midi busy */
#define BD_F_ESS 0x0800 /* this is an ESS chip */
/*

View File

@ -180,11 +180,11 @@ pcmattach(struct isa_device * dev)
d->io_base = dev->id_iobase ;
d->irq = ffs(dev->id_irq) - 1 ;
d->dma1 = dev->id_drq ;
d->dbuf_out.chan = dev->id_drq ;
if (dev->id_flags != -1 && dev->id_flags & DV_F_DUAL_DMA) /* enable dma2 */
d->dma2 = dev->id_flags & DV_F_DRQ_MASK ;
d->dbuf_in.chan = dev->id_flags & DV_F_DRQ_MASK ;
else
d->dma2 = d->dma1 ;
d->dbuf_in.chan = d->dbuf_out.chan ;
/* XXX should also set bd_id from flags ? */
d->status_ptr = 0;
@ -198,9 +198,9 @@ pcmattach(struct isa_device * dev)
alloc_dbuf( &(d->dbuf_out), d->bufsize );
alloc_dbuf( &(d->dbuf_in), d->bufsize );
isa_dma_acquire(d->dma1);
if (d->dma2 != d->dma1)
isa_dma_acquire(d->dma2);
isa_dma_acquire(d->dbuf_out.chan);
if (FULL_DUPLEX(d))
isa_dma_acquire(d->dbuf_in.chan);
/*
* initialize standard parameters for the device. This can be
* overridden by device-specific configurations but better do
@ -359,7 +359,7 @@ sndopen(dev_t i_dev, int flags, int mode, struct proc * p)
default:
if (d->open == NULL) {
printf("open: bad unit %d, perhaps you want unit %d ?\n",
printf("open: unit %d not configured, perhaps you want unit %d ?\n",
unit, unit+1 );
return (ENXIO) ;
} else
@ -445,7 +445,7 @@ sndread(dev_t i_dev, struct uio * buf, int flag)
DDB(printf("read denied, another reader is in\n"));
return EBUSY ;
}
if (d->dma1 == d->dma2) { /* half duplex */
if ( ! FULL_DUPLEX(d) ) { /* half duplex */
if ( d->flags & SND_F_WRITING ) {
/* another writer is in, deny request */
splx(s);
@ -516,7 +516,7 @@ sndwrite(dev_t i_dev, struct uio * buf, int flag)
DDB(printf("write denied, another writer is in\n"));
return EBUSY ;
}
if (d->dma1 == d->dma2) { /* half duplex */
if ( ! FULL_DUPLEX(d) ) { /* half duplex */
if ( d->flags & SND_F_READING ) {
DDB(printf("write denied, half duplex and a reader is in\n"));
/* another reader is in, deny request */
@ -825,7 +825,7 @@ sndioctl(dev_t i_dev, int cmd, caddr_t arg, int mode, struct proc * p)
case SNDCTL_DSP_SETFRAGMENT:
/* XXX watch out, this is RW! */
printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg);
DEB(printf("SNDCTL_DSP_SETFRAGMENT 0x%08x\n", *(int *)arg));
{
int bytes, count;
bytes = *(int *)arg & 0xffff ;
@ -850,24 +850,65 @@ sndioctl(dev_t i_dev, int cmd, caddr_t arg, int mode, struct proc * p)
case SNDCTL_DSP_GETISPACE:
/* return space available in the input queue */
((audio_buf_info *)arg)->bytes = d->dbuf_in.fl ;
((audio_buf_info *)arg)->fragments = 1 ;
((audio_buf_info *)arg)->fragstotal =
d->dbuf_in.bufsize / d->rec_blocksize ;
((audio_buf_info *)arg)->fragsize = d->rec_blocksize ;
{
audio_buf_info *a = (audio_buf_info *)arg;
snd_dbuf *b = &(d->dbuf_in);
if (b->dl)
dsp_rd_dmaupdate( b );
a->bytes = d->dbuf_in.fl ;
a->fragments = 1 ;
a->fragstotal = b->bufsize / d->rec_blocksize ;
a->fragsize = d->rec_blocksize ;
}
break ;
case SNDCTL_DSP_GETOSPACE:
/* return space available in the output queue */
((audio_buf_info *)arg)->bytes = d->dbuf_out.fl ;
((audio_buf_info *)arg)->fragments = 1 ;
((audio_buf_info *)arg)->fragstotal =
d->dbuf_out.bufsize / d->play_blocksize ;
((audio_buf_info *)arg)->fragsize = d->play_blocksize ;
{
audio_buf_info *a = (audio_buf_info *)arg;
snd_dbuf *b = &(d->dbuf_out);
if (b->dl)
dsp_wr_dmaupdate( b );
a->bytes = d->dbuf_out.fl ;
a->fragments = 1 ;
a->fragstotal = b->bufsize / d->play_blocksize ;
a->fragsize = d->play_blocksize ;
}
break ;
case SNDCTL_DSP_GETIPTR:
{
count_info *a = (count_info *)arg;
snd_dbuf *b = &(d->dbuf_in);
if (b->dl)
dsp_rd_dmaupdate( b );
a->bytes = b->total;
a->blocks = (b->total - b->prev_total +
d->rec_blocksize -1 ) / d->rec_blocksize ;
a->ptr = b->fp ; /* XXX not sure... */
b->prev_total = b->total ;
}
break;
case SNDCTL_DSP_GETOPTR:
{
count_info *a = (count_info *)arg;
snd_dbuf *b = &(d->dbuf_out);
if (b->dl)
dsp_wr_dmaupdate( b );
a->bytes = b->total;
a->blocks = (b->total - b->prev_total +
d->play_blocksize -1 ) / d->play_blocksize ;
a->ptr = b->rp ; /* XXX not sure... */
b->prev_total = b->total ;
}
break ;
case SNDCTL_DSP_GETCAPS :
printf("dsp getcaps\n");
*(int *) arg = 0x0 ; /* revision */
if (FULL_DUPLEX(d))
*(int *) arg |= DSP_CAP_DUPLEX ;
*(int *) arg |= DSP_CAP_REALTIME ;
break ;
case SOUND_PCM_READ_BITS:
@ -1087,7 +1128,7 @@ init_status(snddev_info *d)
if (status_len != 0) /* only do init once */
return ;
sprintf(status_buf,
"FreeBSD Audio Driver (971023) " __DATE__ " " __TIME__ "\n"
"FreeBSD Audio Driver (971117) " __DATE__ " " __TIME__ "\n"
"Installed devices:\n");
for (i = 0; i < NPCM_MAX; i++) {
@ -1096,19 +1137,19 @@ init_status(snddev_info *d)
"pcm%d: <%s> at 0x%x irq %d dma %d:%d\n",
i, pcm_info[i].name, pcm_info[i].io_base,
pcm_info[i].irq,
pcm_info[i].dma1, pcm_info[i].dma2);
pcm_info[i].dbuf_out.chan, pcm_info[i].dbuf_in.chan);
if (midi_info[i].open)
sprintf(status_buf + strlen(status_buf),
"midi%d: <%s> at 0x%x irq %d dma %d:%d\n",
i, midi_info[i].name, midi_info[i].io_base,
midi_info[i].irq,
midi_info[i].dma1, midi_info[i].dma2);
midi_info[i].dbuf_out.chan, midi_info[i].dbuf_in.chan);
if (synth_info[i].open)
sprintf(status_buf + strlen(status_buf),
"synth%d: <%s> at 0x%x irq %d dma %d:%d\n",
i, synth_info[i].name, synth_info[i].io_base,
synth_info[i].irq,
synth_info[i].dma1, synth_info[i].dma2);
synth_info[i].dbuf_out.chan, synth_info[i].dbuf_in.chan);
}
status_len = strlen(status_buf) ;
}

View File

@ -97,6 +97,8 @@ typedef struct _snd_dbuf {
int chan; /* dma channel */
int sample_size ; /* 1, 2, 4 */
struct selinfo sel;
u_long total; /* total bytes processed */
u_long prev_total; /* copy of the above when GETxPTR called */
} snd_dbuf ;
/*
@ -160,8 +162,6 @@ struct _snddev_info {
int synth_base ; /* base for the synth */
int irq ;
#define dma1 dbuf_out.chan
#define dma2 dbuf_in.chan
int bd_id ; /* used to hold board-id info, eg. sb version,
* mss codec type, etc. etc.
*/
@ -426,6 +426,7 @@ typedef struct mixer_def mixer_tab[32][2];
#ifdef KERNEL
#define FULL_DUPLEX(d) (d->dbuf_out.chan != d->dbuf_in.chan)
#define MIX_ENT(name, reg_l, pol_l, pos_l, len_l, reg_r, pol_r, pos_r, len_r) \
{{reg_l, pol_l, pos_l, len_l}, {reg_r, pol_r, pos_r, len_r}}
#define PMIX_ENT(name, reg_l, pos_l, len_l, reg_r, pos_r, len_r) \

View File

@ -258,7 +258,7 @@ struct seq_event_rec {
* Sample loading mechanism for internal synthesizers (/dev/sequencer)
* The following patch_info structure has been designed to support
* Gravis UltraSound. It tries to be universal format for uploading
* sample based patches but is propably too limited.
* sample based patches but is probably too limited.
*/
struct patch_info {
@ -619,7 +619,8 @@ struct synth_info { /* Read only */
#define FM_TYPE_ADLIB 0x00
#define FM_TYPE_OPL3 0x01
#define SAMPLE_TYPE_GUS 0x10
#define SAMPLE_TYPE_BASIC 0x10
#define SAMPLE_TYPE_GUS SAMPLE_TYPE_BASIC
int perc_mode; /* No longer supported */
int nr_voices;
@ -816,7 +817,7 @@ typedef struct copr_msg {
* the devices supported by the particular mixer.
*/
#define SOUND_MIXER_NRDEVICES 17
#define SOUND_MIXER_NRDEVICES 25
#define SOUND_MIXER_VOLUME 0
#define SOUND_MIXER_BASS 1
#define SOUND_MIXER_TREBLE 2
@ -840,6 +841,15 @@ typedef struct copr_msg {
#define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */
#define SOUND_MIXER_LINE2 15 /* Input source 2 (aux2) */
#define SOUND_MIXER_LINE3 16 /* Input source 3 (line) */
#define SOUND_MIXER_DIGITAL1 17 /* Digital (input) 1 */
#define SOUND_MIXER_DIGITAL2 18 /* Digital (input) 2 */
#define SOUND_MIXER_DIGITAL3 19 /* Digital (input) 3 */
#define SOUND_MIXER_PHONEIN 20 /* Phone input */
#define SOUND_MIXER_PHONEOUT 21 /* Phone output */
#define SOUND_MIXER_VIDEO 22 /* Video/TV (audio) in */
#define SOUND_MIXER_RADIO 23 /* Radio in */
#define SOUND_MIXER_MONITOR 24 /* Monitor (usually mic) volume */
/*
* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX)
@ -852,16 +862,19 @@ typedef struct copr_msg {
#define SOUND_MIXER_LOUD 30 /* 0 or 1 */
/* Note! Number 31 cannot be used since the sign bit is reserved */
#define SOUND_MIXER_NONE 31
#define SOUND_DEVICE_LABELS { \
"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \
"Mic ", "CD ", "Mix ", "Pcm2 ", "Rec ", "IGain", "OGain", \
"Line1", "Line2", "Line3"}
"Line1", "Line2", "Line3", "Digital1", "Digital2", "Digital3", \
"PhoneIn", "PhoneOut", "Video", "Radio", "Monitor"}
#define SOUND_DEVICE_NAMES { \
"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \
"mic", "cd", "mix", "pcm2", "rec", "igain", "ogain", \
"line1", "line2", "line3"}
"line1", "line2", "line3", "dig1", "dig2", "dig3", \
"phin", "phout", "video", "radio", "monitor"}
/* Device bitmask identifiers */
@ -891,7 +904,16 @@ typedef struct copr_msg {
#define SOUND_MASK_LINE1 (1 << SOUND_MIXER_LINE1)
#define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2)
#define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3)
#define SOUND_MASK_DIGITAL1 (1 << SOUND_MIXER_DIGITAL1)
#define SOUND_MASK_DIGITAL2 (1 << SOUND_MIXER_DIGITAL2)
#define SOUND_MASK_DIGITAL3 (1 << SOUND_MIXER_DIGITAL3)
#define SOUND_MASK_PHONEIN (1 << SOUND_MIXER_PHONEIN)
#define SOUND_MASK_PHONEOUT (1 << SOUND_MIXER_PHONEOUT)
#define SOUND_MASK_RADIO (1 << SOUND_MIXER_RADIO)
#define SOUND_MASK_VIDEO (1 << SOUND_MIXER_VIDEO)
#define SOUND_MASK_MONITOR (1 << SOUND_MIXER_MONITOR)
/* Obsolete macros */
#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE)
#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE)
#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD)
@ -914,6 +936,8 @@ typedef struct copr_msg {
#define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1)
#define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2)
#define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3)
/* Obsolete macros */
#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE)
#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE)
#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD)