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:
parent
8fddd06099
commit
60dc9be97b
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=31361
@ -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 ;
|
||||
|
@ -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";
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -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 ;
|
||||
|
@ -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";
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
@ -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 ;
|
||||
|
@ -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 ;
|
||||
|
@ -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));
|
||||
|
@ -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";
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -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) ;
|
||||
}
|
||||
|
@ -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) \
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user