diff options
| -rw-r--r-- | sys/dev/pcm/isa/mss.c | 78 | ||||
| -rw-r--r-- | sys/dev/pcm/isa/sb.c | 212 | ||||
| -rw-r--r-- | sys/dev/pcm/isa/sb.h | 1 | ||||
| -rw-r--r-- | sys/dev/sound/isa/mss.c | 78 | ||||
| -rw-r--r-- | sys/dev/sound/isa/sb.c | 212 | ||||
| -rw-r--r-- | sys/dev/sound/isa/sb.h | 1 | ||||
| -rw-r--r-- | sys/dev/sound/isa/sb16.c | 212 | ||||
| -rw-r--r-- | sys/dev/sound/isa/sb8.c | 212 | ||||
| -rw-r--r-- | sys/i386/isa/snd/ad1848.c | 78 | ||||
| -rw-r--r-- | sys/i386/isa/snd/clones.c | 2 | ||||
| -rw-r--r-- | sys/i386/isa/snd/dmabuf.c | 50 | ||||
| -rw-r--r-- | sys/i386/isa/snd/sb_dsp.c | 212 | ||||
| -rw-r--r-- | sys/i386/isa/snd/sbcard.h | 1 | ||||
| -rw-r--r-- | sys/i386/isa/snd/sound.c | 91 | ||||
| -rw-r--r-- | sys/i386/isa/snd/sound.h | 5 | ||||
| -rw-r--r-- | sys/i386/isa/snd/soundcard.h | 34 |
16 files changed, 1012 insertions, 467 deletions
diff --git a/sys/dev/pcm/isa/mss.c b/sys/dev/pcm/isa/mss.c index 0cd2dfdd8614..a6bf62485f9b 100644 --- a/sys/dev/pcm/isa/mss.c +++ b/sys/dev/pcm/isa/mss.c @@ -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 ; diff --git a/sys/dev/pcm/isa/sb.c b/sys/dev/pcm/isa/sb.c index d4825c145260..09440e1008f2 100644 --- a/sys/dev/pcm/isa/sb.c +++ b/sys/dev/pcm/isa/sb.c @@ -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 @@ again: */ 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 @@ again: /* * 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,25 +595,49 @@ 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); - } - - if (d->bd_flags & BD_F_JAZZ16) { - if (d->bd_flags & BD_F_JAZZ16_2) - fmt = "SoundMan Wave %d.%d"; + 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 - fmt = "MV Jazz16 %d.%d"; - d->audio_fmt |= AFMT_S16_LE; /* 16 bits */ + 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 ); } } + } + } + + } 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"; diff --git a/sys/dev/pcm/isa/sb.h b/sys/dev/pcm/isa/sb.h index d7a24d5ba501..1735c142c002 100644 --- a/sys/dev/pcm/isa/sb.h +++ b/sys/dev/pcm/isa/sb.h @@ -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 */ /* diff --git a/sys/dev/sound/isa/mss.c b/sys/dev/sound/isa/mss.c index 0cd2dfdd8614..a6bf62485f9b 100644 --- a/sys/dev/sound/isa/mss.c +++ b/sys/dev/sound/isa/mss.c @@ -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 ; diff --git a/sys/dev/sound/isa/sb.c b/sys/dev/sound/isa/sb.c index d4825c145260..09440e1008f2 100644 --- a/sys/dev/sound/isa/sb.c +++ b/sys/dev/sound/isa/sb.c @@ -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 @@ again: */ 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 @@ again: /* * 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,25 +595,49 @@ 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); - } - - if (d->bd_flags & BD_F_JAZZ16) { - if (d->bd_flags & BD_F_JAZZ16_2) - fmt = "SoundMan Wave %d.%d"; + 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 - fmt = "MV Jazz16 %d.%d"; - d->audio_fmt |= AFMT_S16_LE; /* 16 bits */ + 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 ); } } + } + } + + } 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"; diff --git a/sys/dev/sound/isa/sb.h b/sys/dev/sound/isa/sb.h index d7a24d5ba501..1735c142c002 100644 --- a/sys/dev/sound/isa/sb.h +++ b/sys/dev/sound/isa/sb.h @@ -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 */ /* diff --git a/sys/dev/sound/isa/sb16.c b/sys/dev/sound/isa/sb16.c index d4825c145260..09440e1008f2 100644 --- a/sys/dev/sound/isa/sb16.c +++ b/sys/dev/sound/isa/sb16.c @@ -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 @@ again: */ 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 @@ again: /* * 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,25 +595,49 @@ 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); - } - - if (d->bd_flags & BD_F_JAZZ16) { - if (d->bd_flags & BD_F_JAZZ16_2) - fmt = "SoundMan Wave %d.%d"; + 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 - fmt = "MV Jazz16 %d.%d"; - d->audio_fmt |= AFMT_S16_LE; /* 16 bits */ + 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 ); } } + } + } + + } 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"; diff --git a/sys/dev/sound/isa/sb8.c b/sys/dev/sound/isa/sb8.c index d4825c145260..09440e1008f2 100644 --- a/sys/dev/sound/isa/sb8.c +++ b/sys/dev/sound/isa/sb8.c @@ -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 @@ again: */ 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 @@ again: /* * 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,25 +595,49 @@ 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); - } - - if (d->bd_flags & BD_F_JAZZ16) { - if (d->bd_flags & BD_F_JAZZ16_2) - fmt = "SoundMan Wave %d.%d"; + 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 - fmt = "MV Jazz16 %d.%d"; - d->audio_fmt |= AFMT_S16_LE; /* 16 bits */ + 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 ); } } + } + } + + } 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"; diff --git a/sys/i386/isa/snd/ad1848.c b/sys/i386/isa/snd/ad1848.c index 0cd2dfdd8614..a6bf62485f9b 100644 --- a/sys/i386/isa/snd/ad1848.c +++ b/sys/i386/isa/snd/ad1848.c @@ -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 ; diff --git a/sys/i386/isa/snd/clones.c b/sys/i386/isa/snd/clones.c index edb64f68e14e..344deac6c6cd 100644 --- a/sys/i386/isa/snd/clones.c +++ b/sys/i386/isa/snd/clones.c @@ -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 ; diff --git a/sys/i386/isa/snd/dmabuf.c b/sys/i386/isa/snd/dmabuf.c index d9a5f37d0a3a..c6b1c5737762 100644 --- a/sys/i386/isa/snd/dmabuf.c +++ b/sys/i386/isa/snd/dmabuf.c @@ -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)); diff --git a/sys/i386/isa/snd/sb_dsp.c b/sys/i386/isa/snd/sb_dsp.c index d4825c145260..09440e1008f2 100644 --- a/sys/i386/isa/snd/sb_dsp.c +++ b/sys/i386/isa/snd/sb_dsp.c @@ -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 @@ again: */ 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 @@ again: /* * 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,25 +595,49 @@ 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); - } - - if (d->bd_flags & BD_F_JAZZ16) { - if (d->bd_flags & BD_F_JAZZ16_2) - fmt = "SoundMan Wave %d.%d"; + 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 - fmt = "MV Jazz16 %d.%d"; - d->audio_fmt |= AFMT_S16_LE; /* 16 bits */ + 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 ); } } + } + } + + } 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"; diff --git a/sys/i386/isa/snd/sbcard.h b/sys/i386/isa/snd/sbcard.h index d7a24d5ba501..1735c142c002 100644 --- a/sys/i386/isa/snd/sbcard.h +++ b/sys/i386/isa/snd/sbcard.h @@ -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 */ /* diff --git a/sys/i386/isa/snd/sound.c b/sys/i386/isa/snd/sound.c index 920680f0342c..b7c4d6fe1852 100644 --- a/sys/i386/isa/snd/sound.c +++ b/sys/i386/isa/snd/sound.c @@ -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) ; } diff --git a/sys/i386/isa/snd/sound.h b/sys/i386/isa/snd/sound.h index 55ed6541b372..5ab9986c916f 100644 --- a/sys/i386/isa/snd/sound.h +++ b/sys/i386/isa/snd/sound.h @@ -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) \ diff --git a/sys/i386/isa/snd/soundcard.h b/sys/i386/isa/snd/soundcard.h index 276b936a222c..726cbb56c709 100644 --- a/sys/i386/isa/snd/soundcard.h +++ b/sys/i386/isa/snd/soundcard.h @@ -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) |
