Update the pcm driver to the most recent version. This should
add support for Vibra16X, OPTi925, and bring in several assorted fixes to the code and documentation. Also present here are apm hooks so that laptops can properly reconfigure the hardware after suspend (tested on the Libretto50). Reviewed by: jordan
This commit is contained in:
parent
5df5f0b107
commit
8d4824c432
@ -4,7 +4,7 @@
|
||||
* Driver for Microsoft Sound System/Windows Sound System (mss)
|
||||
* -compatible boards. This includes:
|
||||
*
|
||||
* AD1848, CS4248, CS423x, OPTi931, Yamaha SA2 and many others.
|
||||
* AD1848, CS4248, CS423x, OPTi931, Yamaha OPL/SAx and many others.
|
||||
*
|
||||
* Copyright Luigi Rizzo, 1997,1998
|
||||
* Copyright by Hannu Savolainen 1994, 1995
|
||||
@ -239,8 +239,32 @@ mss_attach(struct isa_device *dev)
|
||||
outb(dev->id_iobase, bits );
|
||||
}
|
||||
}
|
||||
if (1) { /* machine-specific code for the Toshiba Libretto */
|
||||
u_char r6, r9;
|
||||
outb( 0x370, 6 /* dma config */ );
|
||||
outb( 0x371, 0xa9 /* config: DMA-B for rec, DMA-A for play */);
|
||||
r6 = inb( 0x371 /* read */ );
|
||||
outb( 0x370, 0xa /* version */ );
|
||||
r9 = inb( 0x371 /* read */ );
|
||||
DEB(printf("Yamaha: ver 0x%x DMA config 0x%x\n", r6, r9);)
|
||||
/*
|
||||
* yamaha - set volume to max
|
||||
*/
|
||||
outb( 0x370, 7 /* volume left */ );
|
||||
outb( 0x371, 0 /* max level */ );
|
||||
outb( 0x370, 8 /* volume right */ );
|
||||
outb( 0x371, 0 /* max level */ );
|
||||
}
|
||||
if ( FULL_DUPLEX(d) )
|
||||
d->audio_fmt |= AFMT_FULLDUPLEX ;
|
||||
if (d->bd_id == MD_YM0020) {
|
||||
DDB(printf("setting up yamaha registers\n"));
|
||||
outb(0x370, 6 /* dma config */ ) ;
|
||||
if (FULL_DUPLEX(d))
|
||||
outb(0x371, 0xa9 ); /* use both dma chans */
|
||||
else
|
||||
outb(0x371, 0x8b ); /* use low dma chan */
|
||||
}
|
||||
mss_reinit(d);
|
||||
ad1848_mixer_reset(d);
|
||||
return 0;
|
||||
@ -401,7 +425,7 @@ mss_callback(snddev_info *d, int reason)
|
||||
/*
|
||||
* perform all necessary initializations for i/o
|
||||
*/
|
||||
d->rec_fmt = d->play_fmt ; /* no split format on the WSS */
|
||||
d->rec_fmt = d->play_fmt ; /* no split format on the MSS */
|
||||
snd_set_blocksize(d);
|
||||
mss_reinit(d);
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
@ -561,15 +585,21 @@ again:
|
||||
if (mc11 & masked)
|
||||
printf("irq reset failed, mc11 0x%02x, masked 0x%02x\n", mc11, masked);
|
||||
masked |= mc11 ;
|
||||
/*
|
||||
* the nice OPTi931 sets the IRQ line before setting the bits in
|
||||
* mc11. So, on some occasions I have to retry (max 10 times).
|
||||
*/
|
||||
if ( mc11 == 0 ) { /* perhaps can return ... */
|
||||
reason = inb(io_Status(d));
|
||||
if (reason & 1) {
|
||||
printf("one more try...\n");
|
||||
goto again;
|
||||
DEB(printf("one more try...\n");)
|
||||
if (--loops)
|
||||
goto again;
|
||||
else
|
||||
DDB(printf("opti_intr: irq but mc11 not set!...\n");)
|
||||
}
|
||||
if (loops==10) {
|
||||
if (loops==10)
|
||||
printf("ouch, intr but nothing in mcir11 0x%02x\n", mc11);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -580,7 +610,8 @@ again:
|
||||
dsp_wrintr(d);
|
||||
}
|
||||
opti_write(d->conf_base, 11, ~mc11); /* ack */
|
||||
if (--loops) goto again;
|
||||
if (--loops)
|
||||
goto again;
|
||||
DEB(printf("xxx too many loops\n");)
|
||||
}
|
||||
|
||||
@ -657,7 +688,7 @@ ad_read(snddev_info *d, int reg)
|
||||
int x;
|
||||
|
||||
flags = spltty();
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 201);
|
||||
x = inb(io_Index_Addr(d)) & ~IA_AMASK ;
|
||||
outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;
|
||||
x = inb(io_Indexed_Data(d));
|
||||
@ -672,7 +703,7 @@ ad_write(snddev_info *d, int reg, u_char data)
|
||||
|
||||
int x ;
|
||||
flags = spltty();
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 1002);
|
||||
x = inb(io_Index_Addr(d)) & ~IA_AMASK ;
|
||||
outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;
|
||||
outb(io_Indexed_Data(d), data);
|
||||
@ -731,7 +762,7 @@ ad_enter_MCE(snddev_info *d)
|
||||
int prev;
|
||||
|
||||
d->bd_flags |= BD_F_MCE_BIT;
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 203);
|
||||
prev = inb(io_Index_Addr(d));
|
||||
prev &= ~IA_TRD ;
|
||||
outb(io_Index_Addr(d), prev | IA_MCE ) ;
|
||||
@ -853,10 +884,11 @@ mss_mixer_set(snddev_info *d, int dev, int value)
|
||||
|
||||
d->mix_levels[dev] = left | (right << 8);
|
||||
|
||||
#if 0
|
||||
/* Scale volumes */
|
||||
left = mix_cvt[left];
|
||||
right = mix_cvt[right];
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Set the left channel
|
||||
*/
|
||||
@ -919,6 +951,16 @@ ad1848_mixer_reset(snddev_info *d)
|
||||
ad_write(d, 20, 0x88);
|
||||
ad_write(d, 21, 0x88);
|
||||
break;
|
||||
|
||||
case MD_YM0020:
|
||||
/* set master volume to max */
|
||||
DDB(printf("set yamaha master volume to max"); )
|
||||
outb(0x370, 7) ;
|
||||
outb(0x371, 0) ;
|
||||
outb(0x370, 8) ;
|
||||
outb(0x371, 0) ;
|
||||
break;
|
||||
|
||||
case MD_GUSPNP:
|
||||
/* this is only necessary in mode 3 ... */
|
||||
ad_write(d, 22, 0x88);
|
||||
@ -997,7 +1039,7 @@ mss_format(snddev_info *d)
|
||||
arg = AFMT_U8 ;
|
||||
|
||||
/* ulaw/alaw seems broken on the opti931... */
|
||||
if (d->bd_id == MD_OPTI931) {
|
||||
if (d->bd_id == MD_OPTI931 || d->bd_id == MD_GUSPNP) {
|
||||
if (arg == AFMT_MU_LAW) {
|
||||
arg = AFMT_U8 ;
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
@ -1233,6 +1275,13 @@ mss_detect(struct isa_device *dev)
|
||||
d->bd_id = MD_AD1845;
|
||||
}
|
||||
ad_write(d, 23, tmp); /* Restore */
|
||||
DDB(printf("... try to identify the yamaha\n") ;)
|
||||
tmp = inb(0x370) ;
|
||||
outb(0x370, 6 /* dma config */ ) ;
|
||||
if (inb(0x370) != 6 ) /* not a yamaha... restore. */
|
||||
outb(0x370, tmp ) ;
|
||||
else
|
||||
d->bd_id = MD_YM0020 ;
|
||||
break;
|
||||
|
||||
case 0x83: /* CS4236 */
|
||||
@ -1244,7 +1293,6 @@ mss_detect(struct isa_device *dev)
|
||||
default: /* Assume CS4231 */
|
||||
BVDDB(printf("unknown id 0x%02x, assuming CS4231\n", id);)
|
||||
d->bd_id = MD_CS4231;
|
||||
|
||||
}
|
||||
}
|
||||
ad_write(d, 25, tmp1); /* Restore bits */
|
||||
@ -1354,7 +1402,7 @@ cs423x_probe(u_long csn, u_long vend_id)
|
||||
u_long id = vend_id & 0xff00ffff;
|
||||
if ( id == 0x3700630e )
|
||||
s = "CS4237" ;
|
||||
else if ( id == 0x3600630e )
|
||||
else if ( id == 0x3500630e || id == 0x3600630e )
|
||||
s = "CS4236" ;
|
||||
else if ( id == 0x3500630e )
|
||||
s = "CS4236B" ;
|
||||
@ -1364,7 +1412,7 @@ cs423x_probe(u_long csn, u_long vend_id)
|
||||
s = "Yamaha SA2";
|
||||
else if ( id == 0x3000a865)
|
||||
s = "Yamaha SA3";
|
||||
else if ( id == 0x0000a865)
|
||||
else if (vend_id == 0x0000a865)
|
||||
s = "Yamaha YMF719 OPL-SA3";
|
||||
else if (vend_id == 0x8140d315)
|
||||
s = "SoundscapeVIVO";
|
||||
@ -1399,7 +1447,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 == 0x0008a865 || vend_id==0x2000a865 || vend_id==0x3000a865 || vend_id==0x8140d315) {
|
||||
if (vend_id==0x2000a865 || vend_id==0x3000a865 ||
|
||||
vend_id==0x0008a865 || vend_id==0x8140d315) {
|
||||
/* Yamaha SA2/SA3 or ENSONIQ SoundscapeVIVO ENS4081 */
|
||||
dev->id_iobase = d.port[0] ;
|
||||
tmp_d.alt_base = d.port[1] ;
|
||||
@ -1418,7 +1467,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
|
||||
case 0x2000a865: /* Yamaha SA2 */
|
||||
case 0x3000a865: /* Yamaha SA3 */
|
||||
case 0x0000a865: /* Yamaha YMF719 */
|
||||
case 0x0000a865: /* Yamaha TMF719 SA3 */
|
||||
dev->id_iobase = d.port[1];
|
||||
tmp_d.alt_base = d.port[0];
|
||||
tmp_d.conf_base = d.port[4];
|
||||
@ -1436,6 +1485,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
tmp_d.bd_id = MD_CS4237 ;
|
||||
break;
|
||||
|
||||
case 0x3500630e: /* CS4236 */
|
||||
case 0x3600630e: /* CS4236 */
|
||||
case 0x3500630e: /* CS4236B */
|
||||
tmp_d.bd_id = MD_CS4236 ;
|
||||
@ -1451,7 +1501,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
write_pnp_parms( &d, ldn );
|
||||
enable_pnp_card();
|
||||
|
||||
if ( (vend_id & 0x2000ffff) == 0x2000a865 ) {
|
||||
if ( (vend_id & 0x0000ffff) == 0x0000a865 ) {
|
||||
/* special volume setting for the Yamaha... */
|
||||
outb(tmp_d.conf_base, 7 /* volume, left */);
|
||||
outb(tmp_d.conf_base+1, 0 );
|
||||
@ -1542,10 +1592,10 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
if (d.flags & DV_PNP_SBCODEC) { /* sb-compatible codec */
|
||||
/*
|
||||
* the 931 is not a real SB, it has important pieces of
|
||||
* hardware controlled by both the WSS and the SB port...
|
||||
* hardware controlled by both the MSS and the SB port...
|
||||
*/
|
||||
printf("--- opti931 in sb mode ---\n");
|
||||
opti_write(p, 6, 1); /* MCIR6 wss disable, sb enable */
|
||||
opti_write(p, 6, 1); /* MCIR6 mss disable, sb enable */
|
||||
/*
|
||||
* swap the main and alternate iobase address since we want
|
||||
* to work in sb mode.
|
||||
@ -1555,7 +1605,7 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
} else { /* mss-compatible codec */
|
||||
tmp_d.bd_id = MD_OPTI931 ; /* to short-circuit the detect routine */
|
||||
opti_write(p, 6 , 2); /* MCIR6: wss enable, sb disable */
|
||||
opti_write(p, 6 , 2); /* MCIR6: mss enable, sb disable */
|
||||
opti_write(p, 5, 0x28); /* MCIR5: codec in exp. mode,fifo */
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
tmp_d.audio_fmt |= AFMT_FULLDUPLEX ; /* not really well... */
|
||||
@ -1567,6 +1617,76 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = mss_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[1];
|
||||
tmp_d.alt_base = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
tmp_d.audio_fmt |= AFMT_FULLDUPLEX ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static void gus_mem_cfg(snddev_info *tmp);
|
||||
|
||||
static char *guspnp_probe(u_long csn, u_long vend_id);
|
||||
|
@ -150,7 +150,7 @@ ahead.
|
||||
|
||||
/*
|
||||
* Table of mixer registers. There is a default table for the
|
||||
* AD1848/CS423x clones, and one for the OPTI931. As more WSS
|
||||
* AD1848/CS423x clones, and one for the OPTI931. As more MSS
|
||||
* clones come out, there ought to be more tables.
|
||||
*
|
||||
* Fields in the table are : polarity, register, offset, bits
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* driver for the SoundBlaster and clones.
|
||||
*
|
||||
* Copyright 1997 Luigi Rizzo.
|
||||
* Copyright 1997,1998 Luigi Rizzo.
|
||||
*
|
||||
* Derived from files in the Voxware 3.5 distribution,
|
||||
* Copyright by Hannu Savolainen 1994, under the same copyright
|
||||
@ -74,6 +74,8 @@ static int dsp_speed(snddev_info *d);
|
||||
static void sb_mixer_reset(snddev_info *d);
|
||||
|
||||
u_int sb_get_byte(int io_base);
|
||||
int ess_write(int io_base, u_char reg, int val);
|
||||
int ess_read(int io_base, u_char reg);
|
||||
|
||||
/*
|
||||
* Then put here the descriptors for the various boards supported
|
||||
@ -151,6 +153,12 @@ sb_attach(struct isa_device *dev)
|
||||
* here are the main routines from the switches.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unlike MSS, the sb only supports a single open (does not mean
|
||||
* that only a single process is using it, since it can fork
|
||||
* afterwards, or pass the descriptor to another process).
|
||||
*
|
||||
*/
|
||||
static int
|
||||
sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
@ -196,10 +204,21 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
d->play_fmt = d->rec_fmt = AFMT_U8 ;
|
||||
break ;
|
||||
}
|
||||
if ( (flags & FREAD) == 0)
|
||||
/*
|
||||
* since the SB is not simmetric, I use the open mode to select
|
||||
* which channel should be privileged, and disable I/O in the
|
||||
* other direction.
|
||||
* In case the board is opened RW, we don't have enough
|
||||
* information on what to do. Temporarily, privilege the
|
||||
* playback channel, which is used more often, and set the other
|
||||
* one to U8.
|
||||
*/
|
||||
if ( (flags & FREAD) == 0) /* opened write only */
|
||||
d->rec_fmt = 0 ;
|
||||
if ( (flags & FWRITE) == 0)
|
||||
else if ( (flags & FWRITE) == 0) /* opened read only */
|
||||
d->play_fmt = 0 ;
|
||||
else /* opened read/write */
|
||||
d->rec_fmt = (d->play_fmt == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE ;
|
||||
|
||||
d->flags |= SND_F_BUSY ;
|
||||
d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ;
|
||||
@ -275,7 +294,10 @@ sb_intr(int unit)
|
||||
* SB < 4.0 is half duplex and has only 1 bit for int source,
|
||||
* so we fake it. SB 4.x (SB16) has the int source in a separate
|
||||
* register.
|
||||
* The Vibra16X has separate flags for 8 and 16 bit transfers, but
|
||||
* I have no idea how to tell capture from playback interrupts...
|
||||
*/
|
||||
#define PLAIN_SB16(x) ( ( (x) & (BD_F_SB16|BD_F_SB16X) ) == BD_F_SB16)
|
||||
again:
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
c = sb_getmixer(io_base, IRQ_STAT);
|
||||
@ -284,25 +306,26 @@ again:
|
||||
*/
|
||||
reason = 0 ;
|
||||
if ( c & 1 ) { /* 8-bit dma */
|
||||
if (d->dbuf_out.chan < 4)
|
||||
if (d->play_fmt == AFMT_U8 || d->play_fmt == AFMT_MU_LAW )
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan < 4)
|
||||
if (d->rec_fmt == AFMT_U8 || d->rec_fmt == AFMT_MU_LAW )
|
||||
reason |= 2;
|
||||
}
|
||||
if ( c & 2 ) { /* 16-bit dma */
|
||||
if (d->dbuf_out.chan >= 4)
|
||||
if (d->play_fmt == AFMT_S16_LE)
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan >= 4)
|
||||
if (d->rec_fmt == AFMT_S16_LE)
|
||||
reason |= 2;
|
||||
}
|
||||
}
|
||||
/* XXX previous location of ack... */
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d\n", d->flags, reason));
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n",
|
||||
d->flags, reason, c));
|
||||
if ( reason & 1 ) { /* possibly a write interrupt */
|
||||
if ( d->dbuf_out.dl )
|
||||
dsp_wrintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: wrintr but write DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -310,7 +333,7 @@ again:
|
||||
if ( d->dbuf_in.dl )
|
||||
dsp_rdintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: rdintr but read DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -346,20 +369,37 @@ sb_callback(snddev_info *d, int reason)
|
||||
|
||||
switch (reason & SND_CB_REASON_MASK) {
|
||||
case SND_CB_INIT : /* called with int enabled and no pending io */
|
||||
/*
|
||||
* set the speed
|
||||
*/
|
||||
dsp_speed(d);
|
||||
/*
|
||||
* set the desired DMA blocksize (influences select behaviour)
|
||||
*/
|
||||
snd_set_blocksize(d);
|
||||
/*
|
||||
* since native mulaw is not present, emulate it.
|
||||
*/
|
||||
if ( (d->play_fmt & AFMT_MU_LAW) || (d->rec_fmt & AFMT_MU_LAW) )
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
else
|
||||
d->flags &= ~SND_F_XLAT8 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
/*
|
||||
* there are too many flavours of SB for my taste... here i try to do
|
||||
* the proper initialization for each one.
|
||||
*/
|
||||
if (PLAIN_SB16(d->bd_flags)) {
|
||||
u_char c, c1 ;
|
||||
|
||||
/* the SB16 can do full duplex using one 16-bit channel
|
||||
/* the original SB16 (non-PnP, or PnP, or Vibra16C)
|
||||
* can do full duplex using one 16-bit channel
|
||||
* and one 8-bit channel. It needs to be programmed to
|
||||
* use split format though.
|
||||
* We use the following algorithm:
|
||||
* I DON'T do this for the Vibra16X because I have no idea
|
||||
* of what needs to be done there...
|
||||
*
|
||||
* I use the following algorithm:
|
||||
* 1. check which direction(s) are active;
|
||||
* 2. check if we should swap dma channels
|
||||
* 3. check if we can do the swap.
|
||||
@ -379,7 +419,11 @@ sb_callback(snddev_info *d, int reason)
|
||||
if ( d->play_fmt != AFMT_S16_LE && d->dbuf_out.chan < 4 )
|
||||
swap = 0;
|
||||
if ( d->rec_fmt ) {
|
||||
/* check for possible config errors. */
|
||||
/* check for possible config errors.
|
||||
* This cannot happen at open time since even in
|
||||
* case of opening rw we privilege the play
|
||||
* channel.
|
||||
*/
|
||||
if (d->rec_fmt == d->play_fmt) {
|
||||
DDB(printf("sorry, read DMA channel unavailable\n"));
|
||||
}
|
||||
@ -392,6 +436,29 @@ sb_callback(snddev_info *d, int reason)
|
||||
d->dbuf_in.chan = d->dbuf_out.chan;
|
||||
d->dbuf_out.chan = c ;
|
||||
}
|
||||
} else if (d->bd_flags & BD_F_ESS) {
|
||||
u_char c ;
|
||||
if (d->play_fmt == 0) {
|
||||
/* initialize for record */
|
||||
static u_char cmd[] = {
|
||||
0x51,0xd0,0x71,0xf4,0x51,0x98,0x71,0xbc
|
||||
};
|
||||
ess_write(d->io_base, 0xb8, 0x0e);
|
||||
c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ;
|
||||
if (d->flags & SND_F_STEREO)
|
||||
c++ ;
|
||||
ess_write(d->io_base, 0xa8, c);
|
||||
ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */
|
||||
/*
|
||||
* set format in b6, b7
|
||||
*/
|
||||
} else {
|
||||
/* initialize for play */
|
||||
static u_char cmd[] = {
|
||||
0x80,0x51,0xd0,0x00,0x71,0xf4,
|
||||
0x80,0x51,0x98,0x00,0x71,0xbc
|
||||
};
|
||||
}
|
||||
}
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
|
||||
@ -400,13 +467,45 @@ 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 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* just a guess: on the Vibra16X, the first
|
||||
* op started takes the first dma channel,
|
||||
* the second one takes the next...
|
||||
* The default is to be ready for play.
|
||||
*/
|
||||
int swap = 0 ;
|
||||
DEB(printf("start %s -- now dma %d:%d\n",
|
||||
rd ? "rd" : "wr",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan););
|
||||
/* swap only if both channels are idle
|
||||
* play: dl=0, since there is no pause;
|
||||
* rec: rl=0
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 && d->dbuf_in.rl == 0 ) {
|
||||
/* must swap channels, but also save dl */
|
||||
int c = d->dbuf_in.chan ;
|
||||
int dl = d->dbuf_in.dl ;
|
||||
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 );
|
||||
d->dbuf_in.dl = dl ;
|
||||
printf("swapped -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ) {
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
) {
|
||||
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
|
||||
c1 = DSP_F16_SIGNED ;
|
||||
l /= 2 ;
|
||||
@ -455,7 +554,10 @@ 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 && b->chan > 4 )
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
)
|
||||
cmd = DSP_CMD_DMAPAUSE_16 ;
|
||||
if (d->bd_flags & BD_F_HISPEED) {
|
||||
sb_reset_dsp(d->io_base);
|
||||
@ -474,6 +576,22 @@ sb_callback(snddev_info *d, int reason)
|
||||
sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ?
|
||||
0xd6 : 0xd4); /* continue other dma */
|
||||
}
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* restore possible swapped channels.
|
||||
* The default is to be ready for play.
|
||||
* XXX right now, it kills all input on overflow
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 ) {
|
||||
/* must swap channels ? */
|
||||
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 );
|
||||
printf("restored -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */
|
||||
break ;
|
||||
@ -618,6 +736,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
|
||||
printf("ESS1868 (rev %d)\n", rev);
|
||||
else
|
||||
printf("ESS688 (rev %d)\n", rev);
|
||||
/* d->audio_fmt |= AFMT_S16_LE; */ /* not yet... */
|
||||
break ; /* XXX */
|
||||
} else {
|
||||
printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n",
|
||||
@ -660,6 +779,14 @@ sb_mix_init(snddev_info *d)
|
||||
|
||||
/*
|
||||
* Common code for the midi and pcm functions
|
||||
*
|
||||
* sb_cmd write a single byte to the CMD port.
|
||||
* sb_cmd2 write a CMD + 1 byte arg
|
||||
* sb_cmd3 write a CMD + 2 byte arg
|
||||
* sb_get_byte returns a single byte from the DSP data port
|
||||
*
|
||||
* ess_write is actually sb_cmd2
|
||||
* ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
|
||||
*/
|
||||
|
||||
int
|
||||
@ -725,9 +852,9 @@ sb_getmixer(int io_base, u_int port)
|
||||
u_long flags;
|
||||
|
||||
flags = spltty();
|
||||
outb(io_base + 4, (u_char) (port & 0xff)); /* Select register */
|
||||
outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
|
||||
DELAY(10);
|
||||
val = inb(io_base + 5);
|
||||
val = inb(io_base + SB_MIX_DATA);
|
||||
DELAY(10);
|
||||
splx(flags);
|
||||
|
||||
@ -747,6 +874,19 @@ sb_get_byte(int io_base)
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
int
|
||||
ess_write(int io_base, u_char reg, int val)
|
||||
{
|
||||
return sb_cmd2(io_base, reg, val);
|
||||
}
|
||||
|
||||
int
|
||||
ess_read(int io_base, u_char reg)
|
||||
{
|
||||
if (!sb_cmd(io_base, 0xc0) || !sb_cmd(io_base, reg) )
|
||||
return 0xffff ;
|
||||
return sb_get_byte(io_base);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -785,17 +925,21 @@ dsp_speed(snddev_info *d)
|
||||
*/
|
||||
if (d->bd_flags & BD_F_ESS) {
|
||||
int t;
|
||||
RANGE (speed, 4000, 48000);
|
||||
RANGE (speed, 5000, 49000);
|
||||
if (speed > 22000) {
|
||||
t = (795500 + speed / 2) / speed;
|
||||
speed = (795500 + t / 2) / t ;
|
||||
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
|
||||
t = (256 - t ) | 0x80 ;
|
||||
} else {
|
||||
t = (397700 + speed / 2) / speed;
|
||||
speed = (397700 + t / 2) / t ;
|
||||
t = 128 - (397700 + speed / 2) / speed ;
|
||||
t = 128 - t ;
|
||||
}
|
||||
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
|
||||
ess_write(d->io_base, 0xa1, t); /* set time constant */
|
||||
d->play_speed = d->rec_speed = speed ;
|
||||
speed = (speed * 9 ) / 20 ;
|
||||
t = 256-7160000/(speed*82);
|
||||
ess_write(d->io_base,0xa2,t);
|
||||
return speed ;
|
||||
}
|
||||
|
||||
@ -1080,79 +1224,11 @@ ess1868_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = sb_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* A driver for some SB16pnp and compatibles...
|
||||
*
|
||||
* Avance Asound 100 -- 0x01009305
|
||||
* Avance Logic ALS100+ -- 0x10019305
|
||||
* xxx -- 0x2b008c0e
|
||||
*
|
||||
*/
|
||||
@ -1181,11 +1257,16 @@ sb16pnp_probe(u_long csn, u_long vend_id)
|
||||
* Reported values are:
|
||||
* SB16 Value PnP: 0x2b008c0e
|
||||
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
|
||||
* Vibra16X: 0xf0008c0e
|
||||
*/
|
||||
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
if (vend_id == 0xf0008c0e)
|
||||
s = "Vibra16X" ;
|
||||
else if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
s = "SB16 PnP";
|
||||
else if (vend_id == 0x01009305)
|
||||
s = "Avance Asound 100" ;
|
||||
else if (vend_id == 0x10019305)
|
||||
s = "Avance Logic 100+" ; /* Vibra16X-class */
|
||||
if (s) {
|
||||
struct pnp_cinfo d;
|
||||
read_pnp_parms(&d, 0);
|
||||
@ -1220,9 +1301,16 @@ sb16pnp_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
pcm_info[dev->id_unit] = tmp_d;
|
||||
pcm_info[dev->id_unit] = tmp_d; /* pcm_info[] will be reinitialized after */
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
if (vend_id == 0x10019305 || vend_id == 0xf0008c0e) {
|
||||
/*
|
||||
* XXX please add here the vend_id for other vibra16X cards...
|
||||
* And remember, must change tmp_d, not
|
||||
*/
|
||||
tmp_d.bd_flags |= BD_F_SB16X ;
|
||||
}
|
||||
pcmattach(dev);
|
||||
}
|
||||
#endif /* NPNP */
|
||||
|
@ -19,9 +19,9 @@ extern int sbc_major, sbc_minor ;
|
||||
#define DSP_DATA_AVAIL (io_base + 0xE)
|
||||
#define DSP_DATA_AVL16 (io_base + 0xF)
|
||||
|
||||
#define SB_MIX_ADDR 0x4
|
||||
#define SB_MIX_DATA 0x5
|
||||
#if 0
|
||||
#define MIXER_ADDR (io_base + 0x4)
|
||||
#define MIXER_DATA (io_base + 0x5)
|
||||
#define OPL3_LEFT (io_base + 0x0)
|
||||
#define OPL3_RIGHT (io_base + 0x2)
|
||||
#define OPL3_BOTH (io_base + 0x8)
|
||||
@ -138,9 +138,14 @@ extern int sbc_major, sbc_minor ;
|
||||
#define BD_F_MIX_CT1745 0x0030 /* CT1745 */
|
||||
|
||||
#define BD_F_SB16 0x0100 /* this is a SB16 */
|
||||
#define BD_F_NOREC 0x0200 /* recording not supported on this board */
|
||||
#define BD_F_SB16X 0x0200 /* this is a vibra16X or clone */
|
||||
#define BD_F_MIDIBUSY 0x0400 /* midi busy */
|
||||
#define BD_F_ESS 0x0800 /* this is an ESS chip */
|
||||
/*
|
||||
* on some SB16 cards, at times I swap DMA channels. Remember this
|
||||
* so that they can be restored later.
|
||||
*/
|
||||
#define BD_F_SWAPPED 0x1000 /* have swapped DMA channels */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Driver for Microsoft Sound System/Windows Sound System (mss)
|
||||
* -compatible boards. This includes:
|
||||
*
|
||||
* AD1848, CS4248, CS423x, OPTi931, Yamaha SA2 and many others.
|
||||
* AD1848, CS4248, CS423x, OPTi931, Yamaha OPL/SAx and many others.
|
||||
*
|
||||
* Copyright Luigi Rizzo, 1997,1998
|
||||
* Copyright by Hannu Savolainen 1994, 1995
|
||||
@ -239,8 +239,32 @@ mss_attach(struct isa_device *dev)
|
||||
outb(dev->id_iobase, bits );
|
||||
}
|
||||
}
|
||||
if (1) { /* machine-specific code for the Toshiba Libretto */
|
||||
u_char r6, r9;
|
||||
outb( 0x370, 6 /* dma config */ );
|
||||
outb( 0x371, 0xa9 /* config: DMA-B for rec, DMA-A for play */);
|
||||
r6 = inb( 0x371 /* read */ );
|
||||
outb( 0x370, 0xa /* version */ );
|
||||
r9 = inb( 0x371 /* read */ );
|
||||
DEB(printf("Yamaha: ver 0x%x DMA config 0x%x\n", r6, r9);)
|
||||
/*
|
||||
* yamaha - set volume to max
|
||||
*/
|
||||
outb( 0x370, 7 /* volume left */ );
|
||||
outb( 0x371, 0 /* max level */ );
|
||||
outb( 0x370, 8 /* volume right */ );
|
||||
outb( 0x371, 0 /* max level */ );
|
||||
}
|
||||
if ( FULL_DUPLEX(d) )
|
||||
d->audio_fmt |= AFMT_FULLDUPLEX ;
|
||||
if (d->bd_id == MD_YM0020) {
|
||||
DDB(printf("setting up yamaha registers\n"));
|
||||
outb(0x370, 6 /* dma config */ ) ;
|
||||
if (FULL_DUPLEX(d))
|
||||
outb(0x371, 0xa9 ); /* use both dma chans */
|
||||
else
|
||||
outb(0x371, 0x8b ); /* use low dma chan */
|
||||
}
|
||||
mss_reinit(d);
|
||||
ad1848_mixer_reset(d);
|
||||
return 0;
|
||||
@ -401,7 +425,7 @@ mss_callback(snddev_info *d, int reason)
|
||||
/*
|
||||
* perform all necessary initializations for i/o
|
||||
*/
|
||||
d->rec_fmt = d->play_fmt ; /* no split format on the WSS */
|
||||
d->rec_fmt = d->play_fmt ; /* no split format on the MSS */
|
||||
snd_set_blocksize(d);
|
||||
mss_reinit(d);
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
@ -561,15 +585,21 @@ again:
|
||||
if (mc11 & masked)
|
||||
printf("irq reset failed, mc11 0x%02x, masked 0x%02x\n", mc11, masked);
|
||||
masked |= mc11 ;
|
||||
/*
|
||||
* the nice OPTi931 sets the IRQ line before setting the bits in
|
||||
* mc11. So, on some occasions I have to retry (max 10 times).
|
||||
*/
|
||||
if ( mc11 == 0 ) { /* perhaps can return ... */
|
||||
reason = inb(io_Status(d));
|
||||
if (reason & 1) {
|
||||
printf("one more try...\n");
|
||||
goto again;
|
||||
DEB(printf("one more try...\n");)
|
||||
if (--loops)
|
||||
goto again;
|
||||
else
|
||||
DDB(printf("opti_intr: irq but mc11 not set!...\n");)
|
||||
}
|
||||
if (loops==10) {
|
||||
if (loops==10)
|
||||
printf("ouch, intr but nothing in mcir11 0x%02x\n", mc11);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -580,7 +610,8 @@ again:
|
||||
dsp_wrintr(d);
|
||||
}
|
||||
opti_write(d->conf_base, 11, ~mc11); /* ack */
|
||||
if (--loops) goto again;
|
||||
if (--loops)
|
||||
goto again;
|
||||
DEB(printf("xxx too many loops\n");)
|
||||
}
|
||||
|
||||
@ -657,7 +688,7 @@ ad_read(snddev_info *d, int reg)
|
||||
int x;
|
||||
|
||||
flags = spltty();
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 201);
|
||||
x = inb(io_Index_Addr(d)) & ~IA_AMASK ;
|
||||
outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;
|
||||
x = inb(io_Indexed_Data(d));
|
||||
@ -672,7 +703,7 @@ ad_write(snddev_info *d, int reg, u_char data)
|
||||
|
||||
int x ;
|
||||
flags = spltty();
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 1002);
|
||||
x = inb(io_Index_Addr(d)) & ~IA_AMASK ;
|
||||
outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;
|
||||
outb(io_Indexed_Data(d), data);
|
||||
@ -731,7 +762,7 @@ ad_enter_MCE(snddev_info *d)
|
||||
int prev;
|
||||
|
||||
d->bd_flags |= BD_F_MCE_BIT;
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 203);
|
||||
prev = inb(io_Index_Addr(d));
|
||||
prev &= ~IA_TRD ;
|
||||
outb(io_Index_Addr(d), prev | IA_MCE ) ;
|
||||
@ -853,10 +884,11 @@ mss_mixer_set(snddev_info *d, int dev, int value)
|
||||
|
||||
d->mix_levels[dev] = left | (right << 8);
|
||||
|
||||
#if 0
|
||||
/* Scale volumes */
|
||||
left = mix_cvt[left];
|
||||
right = mix_cvt[right];
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Set the left channel
|
||||
*/
|
||||
@ -919,6 +951,16 @@ ad1848_mixer_reset(snddev_info *d)
|
||||
ad_write(d, 20, 0x88);
|
||||
ad_write(d, 21, 0x88);
|
||||
break;
|
||||
|
||||
case MD_YM0020:
|
||||
/* set master volume to max */
|
||||
DDB(printf("set yamaha master volume to max"); )
|
||||
outb(0x370, 7) ;
|
||||
outb(0x371, 0) ;
|
||||
outb(0x370, 8) ;
|
||||
outb(0x371, 0) ;
|
||||
break;
|
||||
|
||||
case MD_GUSPNP:
|
||||
/* this is only necessary in mode 3 ... */
|
||||
ad_write(d, 22, 0x88);
|
||||
@ -997,7 +1039,7 @@ mss_format(snddev_info *d)
|
||||
arg = AFMT_U8 ;
|
||||
|
||||
/* ulaw/alaw seems broken on the opti931... */
|
||||
if (d->bd_id == MD_OPTI931) {
|
||||
if (d->bd_id == MD_OPTI931 || d->bd_id == MD_GUSPNP) {
|
||||
if (arg == AFMT_MU_LAW) {
|
||||
arg = AFMT_U8 ;
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
@ -1233,6 +1275,13 @@ mss_detect(struct isa_device *dev)
|
||||
d->bd_id = MD_AD1845;
|
||||
}
|
||||
ad_write(d, 23, tmp); /* Restore */
|
||||
DDB(printf("... try to identify the yamaha\n") ;)
|
||||
tmp = inb(0x370) ;
|
||||
outb(0x370, 6 /* dma config */ ) ;
|
||||
if (inb(0x370) != 6 ) /* not a yamaha... restore. */
|
||||
outb(0x370, tmp ) ;
|
||||
else
|
||||
d->bd_id = MD_YM0020 ;
|
||||
break;
|
||||
|
||||
case 0x83: /* CS4236 */
|
||||
@ -1244,7 +1293,6 @@ mss_detect(struct isa_device *dev)
|
||||
default: /* Assume CS4231 */
|
||||
BVDDB(printf("unknown id 0x%02x, assuming CS4231\n", id);)
|
||||
d->bd_id = MD_CS4231;
|
||||
|
||||
}
|
||||
}
|
||||
ad_write(d, 25, tmp1); /* Restore bits */
|
||||
@ -1354,7 +1402,7 @@ cs423x_probe(u_long csn, u_long vend_id)
|
||||
u_long id = vend_id & 0xff00ffff;
|
||||
if ( id == 0x3700630e )
|
||||
s = "CS4237" ;
|
||||
else if ( id == 0x3600630e )
|
||||
else if ( id == 0x3500630e || id == 0x3600630e )
|
||||
s = "CS4236" ;
|
||||
else if ( id == 0x3500630e )
|
||||
s = "CS4236B" ;
|
||||
@ -1364,7 +1412,7 @@ cs423x_probe(u_long csn, u_long vend_id)
|
||||
s = "Yamaha SA2";
|
||||
else if ( id == 0x3000a865)
|
||||
s = "Yamaha SA3";
|
||||
else if ( id == 0x0000a865)
|
||||
else if (vend_id == 0x0000a865)
|
||||
s = "Yamaha YMF719 OPL-SA3";
|
||||
else if (vend_id == 0x8140d315)
|
||||
s = "SoundscapeVIVO";
|
||||
@ -1399,7 +1447,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 == 0x0008a865 || vend_id==0x2000a865 || vend_id==0x3000a865 || vend_id==0x8140d315) {
|
||||
if (vend_id==0x2000a865 || vend_id==0x3000a865 ||
|
||||
vend_id==0x0008a865 || vend_id==0x8140d315) {
|
||||
/* Yamaha SA2/SA3 or ENSONIQ SoundscapeVIVO ENS4081 */
|
||||
dev->id_iobase = d.port[0] ;
|
||||
tmp_d.alt_base = d.port[1] ;
|
||||
@ -1418,7 +1467,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
|
||||
case 0x2000a865: /* Yamaha SA2 */
|
||||
case 0x3000a865: /* Yamaha SA3 */
|
||||
case 0x0000a865: /* Yamaha YMF719 */
|
||||
case 0x0000a865: /* Yamaha TMF719 SA3 */
|
||||
dev->id_iobase = d.port[1];
|
||||
tmp_d.alt_base = d.port[0];
|
||||
tmp_d.conf_base = d.port[4];
|
||||
@ -1436,6 +1485,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
tmp_d.bd_id = MD_CS4237 ;
|
||||
break;
|
||||
|
||||
case 0x3500630e: /* CS4236 */
|
||||
case 0x3600630e: /* CS4236 */
|
||||
case 0x3500630e: /* CS4236B */
|
||||
tmp_d.bd_id = MD_CS4236 ;
|
||||
@ -1451,7 +1501,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
write_pnp_parms( &d, ldn );
|
||||
enable_pnp_card();
|
||||
|
||||
if ( (vend_id & 0x2000ffff) == 0x2000a865 ) {
|
||||
if ( (vend_id & 0x0000ffff) == 0x0000a865 ) {
|
||||
/* special volume setting for the Yamaha... */
|
||||
outb(tmp_d.conf_base, 7 /* volume, left */);
|
||||
outb(tmp_d.conf_base+1, 0 );
|
||||
@ -1542,10 +1592,10 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
if (d.flags & DV_PNP_SBCODEC) { /* sb-compatible codec */
|
||||
/*
|
||||
* the 931 is not a real SB, it has important pieces of
|
||||
* hardware controlled by both the WSS and the SB port...
|
||||
* hardware controlled by both the MSS and the SB port...
|
||||
*/
|
||||
printf("--- opti931 in sb mode ---\n");
|
||||
opti_write(p, 6, 1); /* MCIR6 wss disable, sb enable */
|
||||
opti_write(p, 6, 1); /* MCIR6 mss disable, sb enable */
|
||||
/*
|
||||
* swap the main and alternate iobase address since we want
|
||||
* to work in sb mode.
|
||||
@ -1555,7 +1605,7 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
} else { /* mss-compatible codec */
|
||||
tmp_d.bd_id = MD_OPTI931 ; /* to short-circuit the detect routine */
|
||||
opti_write(p, 6 , 2); /* MCIR6: wss enable, sb disable */
|
||||
opti_write(p, 6 , 2); /* MCIR6: mss enable, sb disable */
|
||||
opti_write(p, 5, 0x28); /* MCIR5: codec in exp. mode,fifo */
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
tmp_d.audio_fmt |= AFMT_FULLDUPLEX ; /* not really well... */
|
||||
@ -1567,6 +1617,76 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = mss_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[1];
|
||||
tmp_d.alt_base = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
tmp_d.audio_fmt |= AFMT_FULLDUPLEX ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static void gus_mem_cfg(snddev_info *tmp);
|
||||
|
||||
static char *guspnp_probe(u_long csn, u_long vend_id);
|
||||
|
@ -150,7 +150,7 @@ ahead.
|
||||
|
||||
/*
|
||||
* Table of mixer registers. There is a default table for the
|
||||
* AD1848/CS423x clones, and one for the OPTI931. As more WSS
|
||||
* AD1848/CS423x clones, and one for the OPTI931. As more MSS
|
||||
* clones come out, there ought to be more tables.
|
||||
*
|
||||
* Fields in the table are : polarity, register, offset, bits
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* driver for the SoundBlaster and clones.
|
||||
*
|
||||
* Copyright 1997 Luigi Rizzo.
|
||||
* Copyright 1997,1998 Luigi Rizzo.
|
||||
*
|
||||
* Derived from files in the Voxware 3.5 distribution,
|
||||
* Copyright by Hannu Savolainen 1994, under the same copyright
|
||||
@ -74,6 +74,8 @@ static int dsp_speed(snddev_info *d);
|
||||
static void sb_mixer_reset(snddev_info *d);
|
||||
|
||||
u_int sb_get_byte(int io_base);
|
||||
int ess_write(int io_base, u_char reg, int val);
|
||||
int ess_read(int io_base, u_char reg);
|
||||
|
||||
/*
|
||||
* Then put here the descriptors for the various boards supported
|
||||
@ -151,6 +153,12 @@ sb_attach(struct isa_device *dev)
|
||||
* here are the main routines from the switches.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unlike MSS, the sb only supports a single open (does not mean
|
||||
* that only a single process is using it, since it can fork
|
||||
* afterwards, or pass the descriptor to another process).
|
||||
*
|
||||
*/
|
||||
static int
|
||||
sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
@ -196,10 +204,21 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
d->play_fmt = d->rec_fmt = AFMT_U8 ;
|
||||
break ;
|
||||
}
|
||||
if ( (flags & FREAD) == 0)
|
||||
/*
|
||||
* since the SB is not simmetric, I use the open mode to select
|
||||
* which channel should be privileged, and disable I/O in the
|
||||
* other direction.
|
||||
* In case the board is opened RW, we don't have enough
|
||||
* information on what to do. Temporarily, privilege the
|
||||
* playback channel, which is used more often, and set the other
|
||||
* one to U8.
|
||||
*/
|
||||
if ( (flags & FREAD) == 0) /* opened write only */
|
||||
d->rec_fmt = 0 ;
|
||||
if ( (flags & FWRITE) == 0)
|
||||
else if ( (flags & FWRITE) == 0) /* opened read only */
|
||||
d->play_fmt = 0 ;
|
||||
else /* opened read/write */
|
||||
d->rec_fmt = (d->play_fmt == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE ;
|
||||
|
||||
d->flags |= SND_F_BUSY ;
|
||||
d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ;
|
||||
@ -275,7 +294,10 @@ sb_intr(int unit)
|
||||
* SB < 4.0 is half duplex and has only 1 bit for int source,
|
||||
* so we fake it. SB 4.x (SB16) has the int source in a separate
|
||||
* register.
|
||||
* The Vibra16X has separate flags for 8 and 16 bit transfers, but
|
||||
* I have no idea how to tell capture from playback interrupts...
|
||||
*/
|
||||
#define PLAIN_SB16(x) ( ( (x) & (BD_F_SB16|BD_F_SB16X) ) == BD_F_SB16)
|
||||
again:
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
c = sb_getmixer(io_base, IRQ_STAT);
|
||||
@ -284,25 +306,26 @@ again:
|
||||
*/
|
||||
reason = 0 ;
|
||||
if ( c & 1 ) { /* 8-bit dma */
|
||||
if (d->dbuf_out.chan < 4)
|
||||
if (d->play_fmt == AFMT_U8 || d->play_fmt == AFMT_MU_LAW )
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan < 4)
|
||||
if (d->rec_fmt == AFMT_U8 || d->rec_fmt == AFMT_MU_LAW )
|
||||
reason |= 2;
|
||||
}
|
||||
if ( c & 2 ) { /* 16-bit dma */
|
||||
if (d->dbuf_out.chan >= 4)
|
||||
if (d->play_fmt == AFMT_S16_LE)
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan >= 4)
|
||||
if (d->rec_fmt == AFMT_S16_LE)
|
||||
reason |= 2;
|
||||
}
|
||||
}
|
||||
/* XXX previous location of ack... */
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d\n", d->flags, reason));
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n",
|
||||
d->flags, reason, c));
|
||||
if ( reason & 1 ) { /* possibly a write interrupt */
|
||||
if ( d->dbuf_out.dl )
|
||||
dsp_wrintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: wrintr but write DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -310,7 +333,7 @@ again:
|
||||
if ( d->dbuf_in.dl )
|
||||
dsp_rdintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: rdintr but read DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -346,20 +369,37 @@ sb_callback(snddev_info *d, int reason)
|
||||
|
||||
switch (reason & SND_CB_REASON_MASK) {
|
||||
case SND_CB_INIT : /* called with int enabled and no pending io */
|
||||
/*
|
||||
* set the speed
|
||||
*/
|
||||
dsp_speed(d);
|
||||
/*
|
||||
* set the desired DMA blocksize (influences select behaviour)
|
||||
*/
|
||||
snd_set_blocksize(d);
|
||||
/*
|
||||
* since native mulaw is not present, emulate it.
|
||||
*/
|
||||
if ( (d->play_fmt & AFMT_MU_LAW) || (d->rec_fmt & AFMT_MU_LAW) )
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
else
|
||||
d->flags &= ~SND_F_XLAT8 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
/*
|
||||
* there are too many flavours of SB for my taste... here i try to do
|
||||
* the proper initialization for each one.
|
||||
*/
|
||||
if (PLAIN_SB16(d->bd_flags)) {
|
||||
u_char c, c1 ;
|
||||
|
||||
/* the SB16 can do full duplex using one 16-bit channel
|
||||
/* the original SB16 (non-PnP, or PnP, or Vibra16C)
|
||||
* can do full duplex using one 16-bit channel
|
||||
* and one 8-bit channel. It needs to be programmed to
|
||||
* use split format though.
|
||||
* We use the following algorithm:
|
||||
* I DON'T do this for the Vibra16X because I have no idea
|
||||
* of what needs to be done there...
|
||||
*
|
||||
* I use the following algorithm:
|
||||
* 1. check which direction(s) are active;
|
||||
* 2. check if we should swap dma channels
|
||||
* 3. check if we can do the swap.
|
||||
@ -379,7 +419,11 @@ sb_callback(snddev_info *d, int reason)
|
||||
if ( d->play_fmt != AFMT_S16_LE && d->dbuf_out.chan < 4 )
|
||||
swap = 0;
|
||||
if ( d->rec_fmt ) {
|
||||
/* check for possible config errors. */
|
||||
/* check for possible config errors.
|
||||
* This cannot happen at open time since even in
|
||||
* case of opening rw we privilege the play
|
||||
* channel.
|
||||
*/
|
||||
if (d->rec_fmt == d->play_fmt) {
|
||||
DDB(printf("sorry, read DMA channel unavailable\n"));
|
||||
}
|
||||
@ -392,6 +436,29 @@ sb_callback(snddev_info *d, int reason)
|
||||
d->dbuf_in.chan = d->dbuf_out.chan;
|
||||
d->dbuf_out.chan = c ;
|
||||
}
|
||||
} else if (d->bd_flags & BD_F_ESS) {
|
||||
u_char c ;
|
||||
if (d->play_fmt == 0) {
|
||||
/* initialize for record */
|
||||
static u_char cmd[] = {
|
||||
0x51,0xd0,0x71,0xf4,0x51,0x98,0x71,0xbc
|
||||
};
|
||||
ess_write(d->io_base, 0xb8, 0x0e);
|
||||
c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ;
|
||||
if (d->flags & SND_F_STEREO)
|
||||
c++ ;
|
||||
ess_write(d->io_base, 0xa8, c);
|
||||
ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */
|
||||
/*
|
||||
* set format in b6, b7
|
||||
*/
|
||||
} else {
|
||||
/* initialize for play */
|
||||
static u_char cmd[] = {
|
||||
0x80,0x51,0xd0,0x00,0x71,0xf4,
|
||||
0x80,0x51,0x98,0x00,0x71,0xbc
|
||||
};
|
||||
}
|
||||
}
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
|
||||
@ -400,13 +467,45 @@ 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 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* just a guess: on the Vibra16X, the first
|
||||
* op started takes the first dma channel,
|
||||
* the second one takes the next...
|
||||
* The default is to be ready for play.
|
||||
*/
|
||||
int swap = 0 ;
|
||||
DEB(printf("start %s -- now dma %d:%d\n",
|
||||
rd ? "rd" : "wr",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan););
|
||||
/* swap only if both channels are idle
|
||||
* play: dl=0, since there is no pause;
|
||||
* rec: rl=0
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 && d->dbuf_in.rl == 0 ) {
|
||||
/* must swap channels, but also save dl */
|
||||
int c = d->dbuf_in.chan ;
|
||||
int dl = d->dbuf_in.dl ;
|
||||
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 );
|
||||
d->dbuf_in.dl = dl ;
|
||||
printf("swapped -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ) {
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
) {
|
||||
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
|
||||
c1 = DSP_F16_SIGNED ;
|
||||
l /= 2 ;
|
||||
@ -455,7 +554,10 @@ 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 && b->chan > 4 )
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
)
|
||||
cmd = DSP_CMD_DMAPAUSE_16 ;
|
||||
if (d->bd_flags & BD_F_HISPEED) {
|
||||
sb_reset_dsp(d->io_base);
|
||||
@ -474,6 +576,22 @@ sb_callback(snddev_info *d, int reason)
|
||||
sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ?
|
||||
0xd6 : 0xd4); /* continue other dma */
|
||||
}
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* restore possible swapped channels.
|
||||
* The default is to be ready for play.
|
||||
* XXX right now, it kills all input on overflow
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 ) {
|
||||
/* must swap channels ? */
|
||||
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 );
|
||||
printf("restored -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */
|
||||
break ;
|
||||
@ -618,6 +736,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
|
||||
printf("ESS1868 (rev %d)\n", rev);
|
||||
else
|
||||
printf("ESS688 (rev %d)\n", rev);
|
||||
/* d->audio_fmt |= AFMT_S16_LE; */ /* not yet... */
|
||||
break ; /* XXX */
|
||||
} else {
|
||||
printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n",
|
||||
@ -660,6 +779,14 @@ sb_mix_init(snddev_info *d)
|
||||
|
||||
/*
|
||||
* Common code for the midi and pcm functions
|
||||
*
|
||||
* sb_cmd write a single byte to the CMD port.
|
||||
* sb_cmd2 write a CMD + 1 byte arg
|
||||
* sb_cmd3 write a CMD + 2 byte arg
|
||||
* sb_get_byte returns a single byte from the DSP data port
|
||||
*
|
||||
* ess_write is actually sb_cmd2
|
||||
* ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
|
||||
*/
|
||||
|
||||
int
|
||||
@ -725,9 +852,9 @@ sb_getmixer(int io_base, u_int port)
|
||||
u_long flags;
|
||||
|
||||
flags = spltty();
|
||||
outb(io_base + 4, (u_char) (port & 0xff)); /* Select register */
|
||||
outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
|
||||
DELAY(10);
|
||||
val = inb(io_base + 5);
|
||||
val = inb(io_base + SB_MIX_DATA);
|
||||
DELAY(10);
|
||||
splx(flags);
|
||||
|
||||
@ -747,6 +874,19 @@ sb_get_byte(int io_base)
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
int
|
||||
ess_write(int io_base, u_char reg, int val)
|
||||
{
|
||||
return sb_cmd2(io_base, reg, val);
|
||||
}
|
||||
|
||||
int
|
||||
ess_read(int io_base, u_char reg)
|
||||
{
|
||||
if (!sb_cmd(io_base, 0xc0) || !sb_cmd(io_base, reg) )
|
||||
return 0xffff ;
|
||||
return sb_get_byte(io_base);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -785,17 +925,21 @@ dsp_speed(snddev_info *d)
|
||||
*/
|
||||
if (d->bd_flags & BD_F_ESS) {
|
||||
int t;
|
||||
RANGE (speed, 4000, 48000);
|
||||
RANGE (speed, 5000, 49000);
|
||||
if (speed > 22000) {
|
||||
t = (795500 + speed / 2) / speed;
|
||||
speed = (795500 + t / 2) / t ;
|
||||
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
|
||||
t = (256 - t ) | 0x80 ;
|
||||
} else {
|
||||
t = (397700 + speed / 2) / speed;
|
||||
speed = (397700 + t / 2) / t ;
|
||||
t = 128 - (397700 + speed / 2) / speed ;
|
||||
t = 128 - t ;
|
||||
}
|
||||
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
|
||||
ess_write(d->io_base, 0xa1, t); /* set time constant */
|
||||
d->play_speed = d->rec_speed = speed ;
|
||||
speed = (speed * 9 ) / 20 ;
|
||||
t = 256-7160000/(speed*82);
|
||||
ess_write(d->io_base,0xa2,t);
|
||||
return speed ;
|
||||
}
|
||||
|
||||
@ -1080,79 +1224,11 @@ ess1868_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = sb_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* A driver for some SB16pnp and compatibles...
|
||||
*
|
||||
* Avance Asound 100 -- 0x01009305
|
||||
* Avance Logic ALS100+ -- 0x10019305
|
||||
* xxx -- 0x2b008c0e
|
||||
*
|
||||
*/
|
||||
@ -1181,11 +1257,16 @@ sb16pnp_probe(u_long csn, u_long vend_id)
|
||||
* Reported values are:
|
||||
* SB16 Value PnP: 0x2b008c0e
|
||||
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
|
||||
* Vibra16X: 0xf0008c0e
|
||||
*/
|
||||
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
if (vend_id == 0xf0008c0e)
|
||||
s = "Vibra16X" ;
|
||||
else if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
s = "SB16 PnP";
|
||||
else if (vend_id == 0x01009305)
|
||||
s = "Avance Asound 100" ;
|
||||
else if (vend_id == 0x10019305)
|
||||
s = "Avance Logic 100+" ; /* Vibra16X-class */
|
||||
if (s) {
|
||||
struct pnp_cinfo d;
|
||||
read_pnp_parms(&d, 0);
|
||||
@ -1220,9 +1301,16 @@ sb16pnp_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
pcm_info[dev->id_unit] = tmp_d;
|
||||
pcm_info[dev->id_unit] = tmp_d; /* pcm_info[] will be reinitialized after */
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
if (vend_id == 0x10019305 || vend_id == 0xf0008c0e) {
|
||||
/*
|
||||
* XXX please add here the vend_id for other vibra16X cards...
|
||||
* And remember, must change tmp_d, not
|
||||
*/
|
||||
tmp_d.bd_flags |= BD_F_SB16X ;
|
||||
}
|
||||
pcmattach(dev);
|
||||
}
|
||||
#endif /* NPNP */
|
||||
|
@ -19,9 +19,9 @@ extern int sbc_major, sbc_minor ;
|
||||
#define DSP_DATA_AVAIL (io_base + 0xE)
|
||||
#define DSP_DATA_AVL16 (io_base + 0xF)
|
||||
|
||||
#define SB_MIX_ADDR 0x4
|
||||
#define SB_MIX_DATA 0x5
|
||||
#if 0
|
||||
#define MIXER_ADDR (io_base + 0x4)
|
||||
#define MIXER_DATA (io_base + 0x5)
|
||||
#define OPL3_LEFT (io_base + 0x0)
|
||||
#define OPL3_RIGHT (io_base + 0x2)
|
||||
#define OPL3_BOTH (io_base + 0x8)
|
||||
@ -138,9 +138,14 @@ extern int sbc_major, sbc_minor ;
|
||||
#define BD_F_MIX_CT1745 0x0030 /* CT1745 */
|
||||
|
||||
#define BD_F_SB16 0x0100 /* this is a SB16 */
|
||||
#define BD_F_NOREC 0x0200 /* recording not supported on this board */
|
||||
#define BD_F_SB16X 0x0200 /* this is a vibra16X or clone */
|
||||
#define BD_F_MIDIBUSY 0x0400 /* midi busy */
|
||||
#define BD_F_ESS 0x0800 /* this is an ESS chip */
|
||||
/*
|
||||
* on some SB16 cards, at times I swap DMA channels. Remember this
|
||||
* so that they can be restored later.
|
||||
*/
|
||||
#define BD_F_SWAPPED 0x1000 /* have swapped DMA channels */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* driver for the SoundBlaster and clones.
|
||||
*
|
||||
* Copyright 1997 Luigi Rizzo.
|
||||
* Copyright 1997,1998 Luigi Rizzo.
|
||||
*
|
||||
* Derived from files in the Voxware 3.5 distribution,
|
||||
* Copyright by Hannu Savolainen 1994, under the same copyright
|
||||
@ -74,6 +74,8 @@ static int dsp_speed(snddev_info *d);
|
||||
static void sb_mixer_reset(snddev_info *d);
|
||||
|
||||
u_int sb_get_byte(int io_base);
|
||||
int ess_write(int io_base, u_char reg, int val);
|
||||
int ess_read(int io_base, u_char reg);
|
||||
|
||||
/*
|
||||
* Then put here the descriptors for the various boards supported
|
||||
@ -151,6 +153,12 @@ sb_attach(struct isa_device *dev)
|
||||
* here are the main routines from the switches.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unlike MSS, the sb only supports a single open (does not mean
|
||||
* that only a single process is using it, since it can fork
|
||||
* afterwards, or pass the descriptor to another process).
|
||||
*
|
||||
*/
|
||||
static int
|
||||
sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
@ -196,10 +204,21 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
d->play_fmt = d->rec_fmt = AFMT_U8 ;
|
||||
break ;
|
||||
}
|
||||
if ( (flags & FREAD) == 0)
|
||||
/*
|
||||
* since the SB is not simmetric, I use the open mode to select
|
||||
* which channel should be privileged, and disable I/O in the
|
||||
* other direction.
|
||||
* In case the board is opened RW, we don't have enough
|
||||
* information on what to do. Temporarily, privilege the
|
||||
* playback channel, which is used more often, and set the other
|
||||
* one to U8.
|
||||
*/
|
||||
if ( (flags & FREAD) == 0) /* opened write only */
|
||||
d->rec_fmt = 0 ;
|
||||
if ( (flags & FWRITE) == 0)
|
||||
else if ( (flags & FWRITE) == 0) /* opened read only */
|
||||
d->play_fmt = 0 ;
|
||||
else /* opened read/write */
|
||||
d->rec_fmt = (d->play_fmt == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE ;
|
||||
|
||||
d->flags |= SND_F_BUSY ;
|
||||
d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ;
|
||||
@ -275,7 +294,10 @@ sb_intr(int unit)
|
||||
* SB < 4.0 is half duplex and has only 1 bit for int source,
|
||||
* so we fake it. SB 4.x (SB16) has the int source in a separate
|
||||
* register.
|
||||
* The Vibra16X has separate flags for 8 and 16 bit transfers, but
|
||||
* I have no idea how to tell capture from playback interrupts...
|
||||
*/
|
||||
#define PLAIN_SB16(x) ( ( (x) & (BD_F_SB16|BD_F_SB16X) ) == BD_F_SB16)
|
||||
again:
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
c = sb_getmixer(io_base, IRQ_STAT);
|
||||
@ -284,25 +306,26 @@ again:
|
||||
*/
|
||||
reason = 0 ;
|
||||
if ( c & 1 ) { /* 8-bit dma */
|
||||
if (d->dbuf_out.chan < 4)
|
||||
if (d->play_fmt == AFMT_U8 || d->play_fmt == AFMT_MU_LAW )
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan < 4)
|
||||
if (d->rec_fmt == AFMT_U8 || d->rec_fmt == AFMT_MU_LAW )
|
||||
reason |= 2;
|
||||
}
|
||||
if ( c & 2 ) { /* 16-bit dma */
|
||||
if (d->dbuf_out.chan >= 4)
|
||||
if (d->play_fmt == AFMT_S16_LE)
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan >= 4)
|
||||
if (d->rec_fmt == AFMT_S16_LE)
|
||||
reason |= 2;
|
||||
}
|
||||
}
|
||||
/* XXX previous location of ack... */
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d\n", d->flags, reason));
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n",
|
||||
d->flags, reason, c));
|
||||
if ( reason & 1 ) { /* possibly a write interrupt */
|
||||
if ( d->dbuf_out.dl )
|
||||
dsp_wrintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: wrintr but write DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -310,7 +333,7 @@ again:
|
||||
if ( d->dbuf_in.dl )
|
||||
dsp_rdintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: rdintr but read DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -346,20 +369,37 @@ sb_callback(snddev_info *d, int reason)
|
||||
|
||||
switch (reason & SND_CB_REASON_MASK) {
|
||||
case SND_CB_INIT : /* called with int enabled and no pending io */
|
||||
/*
|
||||
* set the speed
|
||||
*/
|
||||
dsp_speed(d);
|
||||
/*
|
||||
* set the desired DMA blocksize (influences select behaviour)
|
||||
*/
|
||||
snd_set_blocksize(d);
|
||||
/*
|
||||
* since native mulaw is not present, emulate it.
|
||||
*/
|
||||
if ( (d->play_fmt & AFMT_MU_LAW) || (d->rec_fmt & AFMT_MU_LAW) )
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
else
|
||||
d->flags &= ~SND_F_XLAT8 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
/*
|
||||
* there are too many flavours of SB for my taste... here i try to do
|
||||
* the proper initialization for each one.
|
||||
*/
|
||||
if (PLAIN_SB16(d->bd_flags)) {
|
||||
u_char c, c1 ;
|
||||
|
||||
/* the SB16 can do full duplex using one 16-bit channel
|
||||
/* the original SB16 (non-PnP, or PnP, or Vibra16C)
|
||||
* can do full duplex using one 16-bit channel
|
||||
* and one 8-bit channel. It needs to be programmed to
|
||||
* use split format though.
|
||||
* We use the following algorithm:
|
||||
* I DON'T do this for the Vibra16X because I have no idea
|
||||
* of what needs to be done there...
|
||||
*
|
||||
* I use the following algorithm:
|
||||
* 1. check which direction(s) are active;
|
||||
* 2. check if we should swap dma channels
|
||||
* 3. check if we can do the swap.
|
||||
@ -379,7 +419,11 @@ sb_callback(snddev_info *d, int reason)
|
||||
if ( d->play_fmt != AFMT_S16_LE && d->dbuf_out.chan < 4 )
|
||||
swap = 0;
|
||||
if ( d->rec_fmt ) {
|
||||
/* check for possible config errors. */
|
||||
/* check for possible config errors.
|
||||
* This cannot happen at open time since even in
|
||||
* case of opening rw we privilege the play
|
||||
* channel.
|
||||
*/
|
||||
if (d->rec_fmt == d->play_fmt) {
|
||||
DDB(printf("sorry, read DMA channel unavailable\n"));
|
||||
}
|
||||
@ -392,6 +436,29 @@ sb_callback(snddev_info *d, int reason)
|
||||
d->dbuf_in.chan = d->dbuf_out.chan;
|
||||
d->dbuf_out.chan = c ;
|
||||
}
|
||||
} else if (d->bd_flags & BD_F_ESS) {
|
||||
u_char c ;
|
||||
if (d->play_fmt == 0) {
|
||||
/* initialize for record */
|
||||
static u_char cmd[] = {
|
||||
0x51,0xd0,0x71,0xf4,0x51,0x98,0x71,0xbc
|
||||
};
|
||||
ess_write(d->io_base, 0xb8, 0x0e);
|
||||
c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ;
|
||||
if (d->flags & SND_F_STEREO)
|
||||
c++ ;
|
||||
ess_write(d->io_base, 0xa8, c);
|
||||
ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */
|
||||
/*
|
||||
* set format in b6, b7
|
||||
*/
|
||||
} else {
|
||||
/* initialize for play */
|
||||
static u_char cmd[] = {
|
||||
0x80,0x51,0xd0,0x00,0x71,0xf4,
|
||||
0x80,0x51,0x98,0x00,0x71,0xbc
|
||||
};
|
||||
}
|
||||
}
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
|
||||
@ -400,13 +467,45 @@ 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 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* just a guess: on the Vibra16X, the first
|
||||
* op started takes the first dma channel,
|
||||
* the second one takes the next...
|
||||
* The default is to be ready for play.
|
||||
*/
|
||||
int swap = 0 ;
|
||||
DEB(printf("start %s -- now dma %d:%d\n",
|
||||
rd ? "rd" : "wr",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan););
|
||||
/* swap only if both channels are idle
|
||||
* play: dl=0, since there is no pause;
|
||||
* rec: rl=0
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 && d->dbuf_in.rl == 0 ) {
|
||||
/* must swap channels, but also save dl */
|
||||
int c = d->dbuf_in.chan ;
|
||||
int dl = d->dbuf_in.dl ;
|
||||
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 );
|
||||
d->dbuf_in.dl = dl ;
|
||||
printf("swapped -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ) {
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
) {
|
||||
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
|
||||
c1 = DSP_F16_SIGNED ;
|
||||
l /= 2 ;
|
||||
@ -455,7 +554,10 @@ 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 && b->chan > 4 )
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
)
|
||||
cmd = DSP_CMD_DMAPAUSE_16 ;
|
||||
if (d->bd_flags & BD_F_HISPEED) {
|
||||
sb_reset_dsp(d->io_base);
|
||||
@ -474,6 +576,22 @@ sb_callback(snddev_info *d, int reason)
|
||||
sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ?
|
||||
0xd6 : 0xd4); /* continue other dma */
|
||||
}
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* restore possible swapped channels.
|
||||
* The default is to be ready for play.
|
||||
* XXX right now, it kills all input on overflow
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 ) {
|
||||
/* must swap channels ? */
|
||||
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 );
|
||||
printf("restored -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */
|
||||
break ;
|
||||
@ -618,6 +736,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
|
||||
printf("ESS1868 (rev %d)\n", rev);
|
||||
else
|
||||
printf("ESS688 (rev %d)\n", rev);
|
||||
/* d->audio_fmt |= AFMT_S16_LE; */ /* not yet... */
|
||||
break ; /* XXX */
|
||||
} else {
|
||||
printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n",
|
||||
@ -660,6 +779,14 @@ sb_mix_init(snddev_info *d)
|
||||
|
||||
/*
|
||||
* Common code for the midi and pcm functions
|
||||
*
|
||||
* sb_cmd write a single byte to the CMD port.
|
||||
* sb_cmd2 write a CMD + 1 byte arg
|
||||
* sb_cmd3 write a CMD + 2 byte arg
|
||||
* sb_get_byte returns a single byte from the DSP data port
|
||||
*
|
||||
* ess_write is actually sb_cmd2
|
||||
* ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
|
||||
*/
|
||||
|
||||
int
|
||||
@ -725,9 +852,9 @@ sb_getmixer(int io_base, u_int port)
|
||||
u_long flags;
|
||||
|
||||
flags = spltty();
|
||||
outb(io_base + 4, (u_char) (port & 0xff)); /* Select register */
|
||||
outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
|
||||
DELAY(10);
|
||||
val = inb(io_base + 5);
|
||||
val = inb(io_base + SB_MIX_DATA);
|
||||
DELAY(10);
|
||||
splx(flags);
|
||||
|
||||
@ -747,6 +874,19 @@ sb_get_byte(int io_base)
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
int
|
||||
ess_write(int io_base, u_char reg, int val)
|
||||
{
|
||||
return sb_cmd2(io_base, reg, val);
|
||||
}
|
||||
|
||||
int
|
||||
ess_read(int io_base, u_char reg)
|
||||
{
|
||||
if (!sb_cmd(io_base, 0xc0) || !sb_cmd(io_base, reg) )
|
||||
return 0xffff ;
|
||||
return sb_get_byte(io_base);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -785,17 +925,21 @@ dsp_speed(snddev_info *d)
|
||||
*/
|
||||
if (d->bd_flags & BD_F_ESS) {
|
||||
int t;
|
||||
RANGE (speed, 4000, 48000);
|
||||
RANGE (speed, 5000, 49000);
|
||||
if (speed > 22000) {
|
||||
t = (795500 + speed / 2) / speed;
|
||||
speed = (795500 + t / 2) / t ;
|
||||
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
|
||||
t = (256 - t ) | 0x80 ;
|
||||
} else {
|
||||
t = (397700 + speed / 2) / speed;
|
||||
speed = (397700 + t / 2) / t ;
|
||||
t = 128 - (397700 + speed / 2) / speed ;
|
||||
t = 128 - t ;
|
||||
}
|
||||
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
|
||||
ess_write(d->io_base, 0xa1, t); /* set time constant */
|
||||
d->play_speed = d->rec_speed = speed ;
|
||||
speed = (speed * 9 ) / 20 ;
|
||||
t = 256-7160000/(speed*82);
|
||||
ess_write(d->io_base,0xa2,t);
|
||||
return speed ;
|
||||
}
|
||||
|
||||
@ -1080,79 +1224,11 @@ ess1868_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = sb_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* A driver for some SB16pnp and compatibles...
|
||||
*
|
||||
* Avance Asound 100 -- 0x01009305
|
||||
* Avance Logic ALS100+ -- 0x10019305
|
||||
* xxx -- 0x2b008c0e
|
||||
*
|
||||
*/
|
||||
@ -1181,11 +1257,16 @@ sb16pnp_probe(u_long csn, u_long vend_id)
|
||||
* Reported values are:
|
||||
* SB16 Value PnP: 0x2b008c0e
|
||||
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
|
||||
* Vibra16X: 0xf0008c0e
|
||||
*/
|
||||
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
if (vend_id == 0xf0008c0e)
|
||||
s = "Vibra16X" ;
|
||||
else if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
s = "SB16 PnP";
|
||||
else if (vend_id == 0x01009305)
|
||||
s = "Avance Asound 100" ;
|
||||
else if (vend_id == 0x10019305)
|
||||
s = "Avance Logic 100+" ; /* Vibra16X-class */
|
||||
if (s) {
|
||||
struct pnp_cinfo d;
|
||||
read_pnp_parms(&d, 0);
|
||||
@ -1220,9 +1301,16 @@ sb16pnp_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
pcm_info[dev->id_unit] = tmp_d;
|
||||
pcm_info[dev->id_unit] = tmp_d; /* pcm_info[] will be reinitialized after */
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
if (vend_id == 0x10019305 || vend_id == 0xf0008c0e) {
|
||||
/*
|
||||
* XXX please add here the vend_id for other vibra16X cards...
|
||||
* And remember, must change tmp_d, not
|
||||
*/
|
||||
tmp_d.bd_flags |= BD_F_SB16X ;
|
||||
}
|
||||
pcmattach(dev);
|
||||
}
|
||||
#endif /* NPNP */
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* driver for the SoundBlaster and clones.
|
||||
*
|
||||
* Copyright 1997 Luigi Rizzo.
|
||||
* Copyright 1997,1998 Luigi Rizzo.
|
||||
*
|
||||
* Derived from files in the Voxware 3.5 distribution,
|
||||
* Copyright by Hannu Savolainen 1994, under the same copyright
|
||||
@ -74,6 +74,8 @@ static int dsp_speed(snddev_info *d);
|
||||
static void sb_mixer_reset(snddev_info *d);
|
||||
|
||||
u_int sb_get_byte(int io_base);
|
||||
int ess_write(int io_base, u_char reg, int val);
|
||||
int ess_read(int io_base, u_char reg);
|
||||
|
||||
/*
|
||||
* Then put here the descriptors for the various boards supported
|
||||
@ -151,6 +153,12 @@ sb_attach(struct isa_device *dev)
|
||||
* here are the main routines from the switches.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unlike MSS, the sb only supports a single open (does not mean
|
||||
* that only a single process is using it, since it can fork
|
||||
* afterwards, or pass the descriptor to another process).
|
||||
*
|
||||
*/
|
||||
static int
|
||||
sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
@ -196,10 +204,21 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
d->play_fmt = d->rec_fmt = AFMT_U8 ;
|
||||
break ;
|
||||
}
|
||||
if ( (flags & FREAD) == 0)
|
||||
/*
|
||||
* since the SB is not simmetric, I use the open mode to select
|
||||
* which channel should be privileged, and disable I/O in the
|
||||
* other direction.
|
||||
* In case the board is opened RW, we don't have enough
|
||||
* information on what to do. Temporarily, privilege the
|
||||
* playback channel, which is used more often, and set the other
|
||||
* one to U8.
|
||||
*/
|
||||
if ( (flags & FREAD) == 0) /* opened write only */
|
||||
d->rec_fmt = 0 ;
|
||||
if ( (flags & FWRITE) == 0)
|
||||
else if ( (flags & FWRITE) == 0) /* opened read only */
|
||||
d->play_fmt = 0 ;
|
||||
else /* opened read/write */
|
||||
d->rec_fmt = (d->play_fmt == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE ;
|
||||
|
||||
d->flags |= SND_F_BUSY ;
|
||||
d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ;
|
||||
@ -275,7 +294,10 @@ sb_intr(int unit)
|
||||
* SB < 4.0 is half duplex and has only 1 bit for int source,
|
||||
* so we fake it. SB 4.x (SB16) has the int source in a separate
|
||||
* register.
|
||||
* The Vibra16X has separate flags for 8 and 16 bit transfers, but
|
||||
* I have no idea how to tell capture from playback interrupts...
|
||||
*/
|
||||
#define PLAIN_SB16(x) ( ( (x) & (BD_F_SB16|BD_F_SB16X) ) == BD_F_SB16)
|
||||
again:
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
c = sb_getmixer(io_base, IRQ_STAT);
|
||||
@ -284,25 +306,26 @@ again:
|
||||
*/
|
||||
reason = 0 ;
|
||||
if ( c & 1 ) { /* 8-bit dma */
|
||||
if (d->dbuf_out.chan < 4)
|
||||
if (d->play_fmt == AFMT_U8 || d->play_fmt == AFMT_MU_LAW )
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan < 4)
|
||||
if (d->rec_fmt == AFMT_U8 || d->rec_fmt == AFMT_MU_LAW )
|
||||
reason |= 2;
|
||||
}
|
||||
if ( c & 2 ) { /* 16-bit dma */
|
||||
if (d->dbuf_out.chan >= 4)
|
||||
if (d->play_fmt == AFMT_S16_LE)
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan >= 4)
|
||||
if (d->rec_fmt == AFMT_S16_LE)
|
||||
reason |= 2;
|
||||
}
|
||||
}
|
||||
/* XXX previous location of ack... */
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d\n", d->flags, reason));
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n",
|
||||
d->flags, reason, c));
|
||||
if ( reason & 1 ) { /* possibly a write interrupt */
|
||||
if ( d->dbuf_out.dl )
|
||||
dsp_wrintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: wrintr but write DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -310,7 +333,7 @@ again:
|
||||
if ( d->dbuf_in.dl )
|
||||
dsp_rdintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: rdintr but read DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -346,20 +369,37 @@ sb_callback(snddev_info *d, int reason)
|
||||
|
||||
switch (reason & SND_CB_REASON_MASK) {
|
||||
case SND_CB_INIT : /* called with int enabled and no pending io */
|
||||
/*
|
||||
* set the speed
|
||||
*/
|
||||
dsp_speed(d);
|
||||
/*
|
||||
* set the desired DMA blocksize (influences select behaviour)
|
||||
*/
|
||||
snd_set_blocksize(d);
|
||||
/*
|
||||
* since native mulaw is not present, emulate it.
|
||||
*/
|
||||
if ( (d->play_fmt & AFMT_MU_LAW) || (d->rec_fmt & AFMT_MU_LAW) )
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
else
|
||||
d->flags &= ~SND_F_XLAT8 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
/*
|
||||
* there are too many flavours of SB for my taste... here i try to do
|
||||
* the proper initialization for each one.
|
||||
*/
|
||||
if (PLAIN_SB16(d->bd_flags)) {
|
||||
u_char c, c1 ;
|
||||
|
||||
/* the SB16 can do full duplex using one 16-bit channel
|
||||
/* the original SB16 (non-PnP, or PnP, or Vibra16C)
|
||||
* can do full duplex using one 16-bit channel
|
||||
* and one 8-bit channel. It needs to be programmed to
|
||||
* use split format though.
|
||||
* We use the following algorithm:
|
||||
* I DON'T do this for the Vibra16X because I have no idea
|
||||
* of what needs to be done there...
|
||||
*
|
||||
* I use the following algorithm:
|
||||
* 1. check which direction(s) are active;
|
||||
* 2. check if we should swap dma channels
|
||||
* 3. check if we can do the swap.
|
||||
@ -379,7 +419,11 @@ sb_callback(snddev_info *d, int reason)
|
||||
if ( d->play_fmt != AFMT_S16_LE && d->dbuf_out.chan < 4 )
|
||||
swap = 0;
|
||||
if ( d->rec_fmt ) {
|
||||
/* check for possible config errors. */
|
||||
/* check for possible config errors.
|
||||
* This cannot happen at open time since even in
|
||||
* case of opening rw we privilege the play
|
||||
* channel.
|
||||
*/
|
||||
if (d->rec_fmt == d->play_fmt) {
|
||||
DDB(printf("sorry, read DMA channel unavailable\n"));
|
||||
}
|
||||
@ -392,6 +436,29 @@ sb_callback(snddev_info *d, int reason)
|
||||
d->dbuf_in.chan = d->dbuf_out.chan;
|
||||
d->dbuf_out.chan = c ;
|
||||
}
|
||||
} else if (d->bd_flags & BD_F_ESS) {
|
||||
u_char c ;
|
||||
if (d->play_fmt == 0) {
|
||||
/* initialize for record */
|
||||
static u_char cmd[] = {
|
||||
0x51,0xd0,0x71,0xf4,0x51,0x98,0x71,0xbc
|
||||
};
|
||||
ess_write(d->io_base, 0xb8, 0x0e);
|
||||
c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ;
|
||||
if (d->flags & SND_F_STEREO)
|
||||
c++ ;
|
||||
ess_write(d->io_base, 0xa8, c);
|
||||
ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */
|
||||
/*
|
||||
* set format in b6, b7
|
||||
*/
|
||||
} else {
|
||||
/* initialize for play */
|
||||
static u_char cmd[] = {
|
||||
0x80,0x51,0xd0,0x00,0x71,0xf4,
|
||||
0x80,0x51,0x98,0x00,0x71,0xbc
|
||||
};
|
||||
}
|
||||
}
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
|
||||
@ -400,13 +467,45 @@ 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 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* just a guess: on the Vibra16X, the first
|
||||
* op started takes the first dma channel,
|
||||
* the second one takes the next...
|
||||
* The default is to be ready for play.
|
||||
*/
|
||||
int swap = 0 ;
|
||||
DEB(printf("start %s -- now dma %d:%d\n",
|
||||
rd ? "rd" : "wr",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan););
|
||||
/* swap only if both channels are idle
|
||||
* play: dl=0, since there is no pause;
|
||||
* rec: rl=0
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 && d->dbuf_in.rl == 0 ) {
|
||||
/* must swap channels, but also save dl */
|
||||
int c = d->dbuf_in.chan ;
|
||||
int dl = d->dbuf_in.dl ;
|
||||
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 );
|
||||
d->dbuf_in.dl = dl ;
|
||||
printf("swapped -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ) {
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
) {
|
||||
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
|
||||
c1 = DSP_F16_SIGNED ;
|
||||
l /= 2 ;
|
||||
@ -455,7 +554,10 @@ 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 && b->chan > 4 )
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
)
|
||||
cmd = DSP_CMD_DMAPAUSE_16 ;
|
||||
if (d->bd_flags & BD_F_HISPEED) {
|
||||
sb_reset_dsp(d->io_base);
|
||||
@ -474,6 +576,22 @@ sb_callback(snddev_info *d, int reason)
|
||||
sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ?
|
||||
0xd6 : 0xd4); /* continue other dma */
|
||||
}
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* restore possible swapped channels.
|
||||
* The default is to be ready for play.
|
||||
* XXX right now, it kills all input on overflow
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 ) {
|
||||
/* must swap channels ? */
|
||||
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 );
|
||||
printf("restored -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */
|
||||
break ;
|
||||
@ -618,6 +736,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
|
||||
printf("ESS1868 (rev %d)\n", rev);
|
||||
else
|
||||
printf("ESS688 (rev %d)\n", rev);
|
||||
/* d->audio_fmt |= AFMT_S16_LE; */ /* not yet... */
|
||||
break ; /* XXX */
|
||||
} else {
|
||||
printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n",
|
||||
@ -660,6 +779,14 @@ sb_mix_init(snddev_info *d)
|
||||
|
||||
/*
|
||||
* Common code for the midi and pcm functions
|
||||
*
|
||||
* sb_cmd write a single byte to the CMD port.
|
||||
* sb_cmd2 write a CMD + 1 byte arg
|
||||
* sb_cmd3 write a CMD + 2 byte arg
|
||||
* sb_get_byte returns a single byte from the DSP data port
|
||||
*
|
||||
* ess_write is actually sb_cmd2
|
||||
* ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
|
||||
*/
|
||||
|
||||
int
|
||||
@ -725,9 +852,9 @@ sb_getmixer(int io_base, u_int port)
|
||||
u_long flags;
|
||||
|
||||
flags = spltty();
|
||||
outb(io_base + 4, (u_char) (port & 0xff)); /* Select register */
|
||||
outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
|
||||
DELAY(10);
|
||||
val = inb(io_base + 5);
|
||||
val = inb(io_base + SB_MIX_DATA);
|
||||
DELAY(10);
|
||||
splx(flags);
|
||||
|
||||
@ -747,6 +874,19 @@ sb_get_byte(int io_base)
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
int
|
||||
ess_write(int io_base, u_char reg, int val)
|
||||
{
|
||||
return sb_cmd2(io_base, reg, val);
|
||||
}
|
||||
|
||||
int
|
||||
ess_read(int io_base, u_char reg)
|
||||
{
|
||||
if (!sb_cmd(io_base, 0xc0) || !sb_cmd(io_base, reg) )
|
||||
return 0xffff ;
|
||||
return sb_get_byte(io_base);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -785,17 +925,21 @@ dsp_speed(snddev_info *d)
|
||||
*/
|
||||
if (d->bd_flags & BD_F_ESS) {
|
||||
int t;
|
||||
RANGE (speed, 4000, 48000);
|
||||
RANGE (speed, 5000, 49000);
|
||||
if (speed > 22000) {
|
||||
t = (795500 + speed / 2) / speed;
|
||||
speed = (795500 + t / 2) / t ;
|
||||
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
|
||||
t = (256 - t ) | 0x80 ;
|
||||
} else {
|
||||
t = (397700 + speed / 2) / speed;
|
||||
speed = (397700 + t / 2) / t ;
|
||||
t = 128 - (397700 + speed / 2) / speed ;
|
||||
t = 128 - t ;
|
||||
}
|
||||
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
|
||||
ess_write(d->io_base, 0xa1, t); /* set time constant */
|
||||
d->play_speed = d->rec_speed = speed ;
|
||||
speed = (speed * 9 ) / 20 ;
|
||||
t = 256-7160000/(speed*82);
|
||||
ess_write(d->io_base,0xa2,t);
|
||||
return speed ;
|
||||
}
|
||||
|
||||
@ -1080,79 +1224,11 @@ ess1868_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = sb_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* A driver for some SB16pnp and compatibles...
|
||||
*
|
||||
* Avance Asound 100 -- 0x01009305
|
||||
* Avance Logic ALS100+ -- 0x10019305
|
||||
* xxx -- 0x2b008c0e
|
||||
*
|
||||
*/
|
||||
@ -1181,11 +1257,16 @@ sb16pnp_probe(u_long csn, u_long vend_id)
|
||||
* Reported values are:
|
||||
* SB16 Value PnP: 0x2b008c0e
|
||||
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
|
||||
* Vibra16X: 0xf0008c0e
|
||||
*/
|
||||
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
if (vend_id == 0xf0008c0e)
|
||||
s = "Vibra16X" ;
|
||||
else if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
s = "SB16 PnP";
|
||||
else if (vend_id == 0x01009305)
|
||||
s = "Avance Asound 100" ;
|
||||
else if (vend_id == 0x10019305)
|
||||
s = "Avance Logic 100+" ; /* Vibra16X-class */
|
||||
if (s) {
|
||||
struct pnp_cinfo d;
|
||||
read_pnp_parms(&d, 0);
|
||||
@ -1220,9 +1301,16 @@ sb16pnp_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
pcm_info[dev->id_unit] = tmp_d;
|
||||
pcm_info[dev->id_unit] = tmp_d; /* pcm_info[] will be reinitialized after */
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
if (vend_id == 0x10019305 || vend_id == 0xf0008c0e) {
|
||||
/*
|
||||
* XXX please add here the vend_id for other vibra16X cards...
|
||||
* And remember, must change tmp_d, not
|
||||
*/
|
||||
tmp_d.bd_flags |= BD_F_SB16X ;
|
||||
}
|
||||
pcmattach(dev);
|
||||
}
|
||||
#endif /* NPNP */
|
||||
|
@ -39,12 +39,20 @@ CS4232: PnP id 0x3242630e
|
||||
and working in playback mode in MSS emulation.
|
||||
Also have reports from some user that it works ok.
|
||||
|
||||
OPTi931: PnP id 0x3109143e
|
||||
--------------------------
|
||||
CHIPSET:
|
||||
OPTi931: PnP id 0x3109143e
|
||||
|
||||
http://www.opti.com/ opti931_21.pdf
|
||||
MANUFACTURER:
|
||||
ExpertColor MED931 (europe)
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.opti.com/ opti931_21.pdf
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 1 os enable port0 0x534 port2 0x220 port3 0xe0d irq0 10 drq0 1 drq1 6
|
||||
|
||||
COMMENTS:
|
||||
The data sheets of this chip are very cryptic and do not match
|
||||
what the cards I have seem to do. I have it working
|
||||
in WSS emulation, in full duplex and all modes.
|
||||
@ -61,21 +69,45 @@ OPTi931: PnP id 0x3109143e
|
||||
does a conversion in software (much like the SBPro). Of course
|
||||
you lose 4-5 bits of dynamic range in the process.
|
||||
- in full duplex (and single DMA mode), the card occasionally
|
||||
misses interrupts, or generates spurious ones. Spurious ints are
|
||||
not problematic since they can be ignored, but missed ones are
|
||||
as you can imagine... This is fixed by auto-dma mode.
|
||||
misses interrupts, or generates spurious ones, or generates
|
||||
interrupts before setting the status bits in the registers.
|
||||
Spurious ints are not problematic since they can be easily
|
||||
ignored, but missing interrupts are a nightmare to handle...
|
||||
The only way to have this card work semi-reliably is to use
|
||||
auto-dma mode (which is the default mode of operation in the
|
||||
driver).
|
||||
In any case, these cards are very cheap and widely available and
|
||||
are a reasonable solution if you cannot find some other decent WSS
|
||||
device.
|
||||
|
||||
SB16 PnP: PnP id 0x__008c0e
|
||||
-------------------------------
|
||||
CHIPSET:
|
||||
SB16: PnP id 0x__008c0e
|
||||
Vibra16X: PnP id 0xf0008c0e
|
||||
|
||||
http://www.creative.com sbhwpg.pdf or SBHWPG.EXE
|
||||
MANUFACTURER:
|
||||
CreativeLabs
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.creative.com sbhwpg.pdf or SBHWPG.EXE
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x220 irq0 5 drq0 1 drq1 5
|
||||
|
||||
There are many such cards (plain SB16 PnP, AWE32, AWE64, Vibra16,
|
||||
etc.) all differing in the PnP id. They have different synthesis
|
||||
devices, which we do not support, so we are not affected by these
|
||||
differences. Don't worry if the driver identifies the card as a
|
||||
different SB16 than the one you have.
|
||||
COMMENTS:
|
||||
SB16 really refers to a large number of different cards, starting
|
||||
from the original, non-PnP SB16, to more modern cards (SB16PnP,
|
||||
Vibra16C) and other including Wavetable Synthesis (AWE32, AWE64,
|
||||
etc.). All these cards have different PnP ID. They have
|
||||
different synthesis devices, which we do not support, so we
|
||||
are not affected by these differences. Don't worry if the driver
|
||||
identifies the card as a different SB16 than the one you have.
|
||||
|
||||
BEWARE -- all recent (1998 ?) SB16 use a new codec, Vibra16X,
|
||||
which is sufficiently different from the old one to not work with
|
||||
this driver in capture mode or in full duplex. Documentation is
|
||||
not available from Creative. I suggest to stay away from these
|
||||
cards (and from SB16 in general).
|
||||
|
||||
Full duplex support of this card is tricky since one channel can
|
||||
work in 16-bit and the other in 8-bit mode. You will need to use
|
||||
@ -84,7 +116,7 @@ SB16 PnP: PnP id 0x__008c0e
|
||||
is much lower than in 16-bit.
|
||||
|
||||
Full duplex operation is unsupported by Creative. It seems to
|
||||
work, although on my Vibra16 the command to stop DMA transfer
|
||||
work, although on my Vibra16C the command to stop DMA transfer
|
||||
seems to erroneously affect both channels instead of the one
|
||||
they are issued for. The driver has a workaround, but I cannot
|
||||
guarantee that it works for everybody. I have had several
|
||||
@ -93,67 +125,111 @@ SB16 PnP: PnP id 0x__008c0e
|
||||
Some docs on how to use this card with the voxware driver
|
||||
are at http://multiverse.com/~rhh/awedrv
|
||||
|
||||
NOTE: 980122 I have had a couple of reports from people using
|
||||
the Vibra16X (and clones, e.g. based on the Avance Logic
|
||||
chipsets) which appears to use two 8-bit DMA channels. It
|
||||
might be possible that new SB16 are able to do true full duplex!
|
||||
The driver _does not_ support these boards although the fix
|
||||
should be relatively easy.
|
||||
--------------------------
|
||||
CHIPSET:
|
||||
ALS100, ALS110, ...
|
||||
Avance Asound 100: PnP id 0x01009305
|
||||
|
||||
ASound:
|
||||
Avance Logic makes SB clones, and apparently documentation
|
||||
is available at
|
||||
MANUFACTURER:
|
||||
Realtek (also Avance Asound and possibly other names)
|
||||
|
||||
|
||||
http://www.realtek.com.tw/cp/cp.html
|
||||
DOCUMENTATION:
|
||||
|
||||
http://www.realtek.com.tw/cp/cp.html
|
||||
but not very useful or detailed.
|
||||
|
||||
these card should be recognised as SB16 clones.
|
||||
COMMENTS:
|
||||
These card should be recognised as SB16 clones. Some of them
|
||||
emulate the Vibra16X, so the comments above apply.
|
||||
|
||||
Yamaha SA2/SA3
|
||||
|
||||
http://www.yamaha.com ? YM711.pdf
|
||||
(this is a huge file containing a few pages scanned and converted
|
||||
to pdf. Not very useful or detailed.)
|
||||
------------------------------
|
||||
CHIPSET:
|
||||
Yamaha SA2/SA3 . Both PnP and non-PnP versions.
|
||||
OPL3-SA2 Sound Chip: PnP id 0x2000a865
|
||||
OPL/SA3 : PnP id 0x3000a865
|
||||
|
||||
pnp 1 0 os enable port0 0x220 port1 0x530 irq0 5 drq0 1 drq1 5
|
||||
MANUFACTURER:
|
||||
no-name cards, and also used in various laptops, e.g. Toshiba
|
||||
Libretto and others. I
|
||||
|
||||
DATA SHEETS:
|
||||
http://www.yamaha.com ? YM711.pdf
|
||||
|
||||
This is a huge file containing a few pages scanned and converted
|
||||
to pdf. Not very detailed. Luckily, this chipset appears to do a
|
||||
good (i.e. bug-free) emulation of the WSS, so it is fully
|
||||
supported by the driver.
|
||||
|
||||
pnp 1 0 os enable port0 0x220 port1 0x530 port2 0x388 port3 0x370 irq0 5 drq0 1 drq1 0
|
||||
|
||||
this card emulates a WSS or SB. Have reports that it works, although
|
||||
it has incomplete mixer support (Yamaha defines an additional set
|
||||
of registers to control some mixer functions, such as the master
|
||||
output volume). Currently we set the master volume to 100%.
|
||||
Driver reported to work also on Toshiba DynaBook Portege 300CT
|
||||
with OPL3SA-3(non-PNP)
|
||||
output volume -- this is at 0x370 or 0x310). Currently we set
|
||||
the master volume to 100% for the PnP card. Will put in code to do the
|
||||
same for the non PnP card as soon as I find out how to tell
|
||||
the Yamaha from other cards.
|
||||
Driver reported to work also on
|
||||
Toshiba DynaBook Portege 300CT with OPL3SA-3(non-PNP), and on the
|
||||
Libretto50CT (has the non-PnP device).
|
||||
|
||||
Ensoniq Soundscape VIVO
|
||||
------------------------
|
||||
CHIPSET:
|
||||
ENSONIQ SoundscapeVIVO ENS4081: PnP id 0x8140d315
|
||||
MANUFACTURER:
|
||||
Ensoniq Soundscape VIVO
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x220 port1 0x530 irq0 5 drq0 1 drq1 5
|
||||
|
||||
COMMENTS:
|
||||
this card emulates a WSS or SB. Have reports that it works.
|
||||
|
||||
GusPnP: PnP id 0x0100561e
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
AMD...
|
||||
|
||||
MANUFACTURER:
|
||||
GusPnP: PnP id 0x0100561e
|
||||
|
||||
PNP CONFIG:
|
||||
pnp 1 0 os enable port0 0x220 port1 0x320 port2 0x32c irq0 5 drq0 7 drq1 5
|
||||
|
||||
COMMENTS:
|
||||
It works in U8 and S16 mode, ulaw support still not working.
|
||||
The Gus has been discontinued, so support for this card is only
|
||||
there for historical reasons (the Gus used to be the only card
|
||||
well supported in full duplex mode).
|
||||
|
||||
|
||||
NOT WORKING YET:
|
||||
---- THE FOLLOWING CARDS ARE NOT FULLY SUPPORTED: ----
|
||||
|
||||
OPTI925: PnP id 0x2509143e
|
||||
CHIPSET:
|
||||
OPTI925: PnP id 0x2509143e
|
||||
|
||||
COMMENTS:
|
||||
there is code to recognize it as a SB clone. I have reports that
|
||||
it probes ok, but not sure if it works.
|
||||
|
||||
OPTI924: PnP
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
OPTI924: PnP
|
||||
|
||||
COMMENT:
|
||||
I have this card but it is still unsupported.
|
||||
|
||||
OPTI930:
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
OPTI930:
|
||||
|
||||
should work as an MSS clone, but support for it is not implemented
|
||||
yet.
|
||||
|
||||
ESS1868
|
||||
ESS688
|
||||
CHIPSET:
|
||||
ESS1868
|
||||
ESS688
|
||||
|
||||
http://www.esstech.com
|
||||
|
||||
@ -168,12 +244,13 @@ ESS688
|
||||
(the ESS688 is used on many notebooks. It is probably able to do 8
|
||||
and 16-bit, half duplex).
|
||||
|
||||
PCI cards:
|
||||
-------------------------
|
||||
CHIPSET:
|
||||
various PCI cards from Ensoniq, OPTI, CreativeLabs.
|
||||
|
||||
some vendors have PCI cards. This code _cannot_ work on these
|
||||
cards as it is now, since they cannot obviously use the ISA DMA
|
||||
controller. As there are no data sheets available for these PCI
|
||||
cards, none of them is supported at the moment, although support
|
||||
should be easy as soon as I can put my hands on the data sheets
|
||||
and cards.
|
||||
This code _cannot_ work on these cards as it is now, since I
|
||||
don't think they can use the ISA DMA controller. As there are
|
||||
no data sheets available for these PCI cards, none of them is
|
||||
supported at the moment.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
@ -13,15 +13,18 @@ of the Voxware ioctl() audio calls, so that many applications --
|
||||
even commercial ones -- will run unmodified with this driver. On
|
||||
the other hand, at the moment this driver does not support /dev/midi
|
||||
and /dev/synth, or some ioctl() used in xquake. Do not expect
|
||||
/dev/synth to be supported before summer'98.
|
||||
/dev/synth to be supported anytime soon.
|
||||
|
||||
I also have implemented a new software interface with an independent
|
||||
set of ioctl(), to support some functions which were not easy to
|
||||
express with the existing software interface (e.g. full duplex on
|
||||
the SB16). To make an effective use of the new functionalities you
|
||||
need to recompile applications by replacing the audio module(s).
|
||||
old SB16 cards). To make an effective use of the new functionalities
|
||||
you need to recompile applications by replacing the audio module(s).
|
||||
Such modified driver modules are present in the misc/ directory
|
||||
for several applications.
|
||||
|
||||
Updated versions of this code will available at the following URL:
|
||||
This file gives quick information on how to install the driver.
|
||||
Updated versions of this code will be available at the following URL:
|
||||
|
||||
http://www.iet.unipi.it/~luigi/FreeBSD.html
|
||||
|
||||
@ -49,10 +52,18 @@ APPLICATIONS:
|
||||
- xanim
|
||||
- various mpeg players (mpg123, amp, ...);
|
||||
|
||||
WITH SPECIAL DRIVER MODULE (supplied)
|
||||
- speak_freely, full duplex (requires removing the definition of
|
||||
HALF_DUPLEX in the Makefile);
|
||||
- the realaudio player (3.0, dynamically linked);
|
||||
- vat, full duplex (the version in ports is already modified);
|
||||
- timidity, a software midi-to-pcm converter;
|
||||
|
||||
NOT WORKING
|
||||
- xquake (we do not support mmapped buffers yet);
|
||||
|
||||
---INSTALLATION---
|
||||
|
||||
---INSTALLATION---
|
||||
|
||||
* add the following lines to your kernel configuration file:
|
||||
|
||||
@ -108,14 +119,14 @@ APPLICATIONS:
|
||||
"flags 0x13" specifies that you have a dual dma board with
|
||||
channel 3 as secondary DMA channel.
|
||||
|
||||
* build the kernel using the following steps
|
||||
* build the kernel using the standard steps
|
||||
|
||||
config MYKERNEL
|
||||
cd /sys/compile/MYKERNEL
|
||||
make depend
|
||||
make
|
||||
|
||||
* PnP support:
|
||||
* note for PnP cards:
|
||||
|
||||
For PnP cards, only the line for "pcm0" is needed (the code
|
||||
will allocate entries for more cards if found), but IT MUST
|
||||
@ -145,8 +156,8 @@ APPLICATIONS:
|
||||
|
||||
WHAT IF THIS DRIVER DOES NOT WORK:
|
||||
|
||||
If the driver does not work with your hardware, I am willing to
|
||||
help but I need the following:
|
||||
If the driver does not work with your hardware, I might to help
|
||||
but I need the following information:
|
||||
|
||||
- relevant lines in your config file;
|
||||
- dmesg output
|
||||
@ -200,8 +211,8 @@ this driver. In particular I would like to thank:
|
||||
* Jim Lowe for his suggestion on the block-mode select;
|
||||
* Allison Mankin and Brad Karp at ISI-East for supplying a GUS PnP
|
||||
which allowed me to support this card;
|
||||
* Eric J. Schwertfeger for donating sn ES1868 card for writing the
|
||||
driver.
|
||||
* Eric J. Schwertfeger for donating an ES1868 card for writing the
|
||||
driver (which i haven't done yet...).
|
||||
* and many people who had the patience to try the driver
|
||||
on their cards and report success/fauilure and useful
|
||||
information.
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Driver for Microsoft Sound System/Windows Sound System (mss)
|
||||
* -compatible boards. This includes:
|
||||
*
|
||||
* AD1848, CS4248, CS423x, OPTi931, Yamaha SA2 and many others.
|
||||
* AD1848, CS4248, CS423x, OPTi931, Yamaha OPL/SAx and many others.
|
||||
*
|
||||
* Copyright Luigi Rizzo, 1997,1998
|
||||
* Copyright by Hannu Savolainen 1994, 1995
|
||||
@ -239,8 +239,32 @@ mss_attach(struct isa_device *dev)
|
||||
outb(dev->id_iobase, bits );
|
||||
}
|
||||
}
|
||||
if (1) { /* machine-specific code for the Toshiba Libretto */
|
||||
u_char r6, r9;
|
||||
outb( 0x370, 6 /* dma config */ );
|
||||
outb( 0x371, 0xa9 /* config: DMA-B for rec, DMA-A for play */);
|
||||
r6 = inb( 0x371 /* read */ );
|
||||
outb( 0x370, 0xa /* version */ );
|
||||
r9 = inb( 0x371 /* read */ );
|
||||
DEB(printf("Yamaha: ver 0x%x DMA config 0x%x\n", r6, r9);)
|
||||
/*
|
||||
* yamaha - set volume to max
|
||||
*/
|
||||
outb( 0x370, 7 /* volume left */ );
|
||||
outb( 0x371, 0 /* max level */ );
|
||||
outb( 0x370, 8 /* volume right */ );
|
||||
outb( 0x371, 0 /* max level */ );
|
||||
}
|
||||
if ( FULL_DUPLEX(d) )
|
||||
d->audio_fmt |= AFMT_FULLDUPLEX ;
|
||||
if (d->bd_id == MD_YM0020) {
|
||||
DDB(printf("setting up yamaha registers\n"));
|
||||
outb(0x370, 6 /* dma config */ ) ;
|
||||
if (FULL_DUPLEX(d))
|
||||
outb(0x371, 0xa9 ); /* use both dma chans */
|
||||
else
|
||||
outb(0x371, 0x8b ); /* use low dma chan */
|
||||
}
|
||||
mss_reinit(d);
|
||||
ad1848_mixer_reset(d);
|
||||
return 0;
|
||||
@ -401,7 +425,7 @@ mss_callback(snddev_info *d, int reason)
|
||||
/*
|
||||
* perform all necessary initializations for i/o
|
||||
*/
|
||||
d->rec_fmt = d->play_fmt ; /* no split format on the WSS */
|
||||
d->rec_fmt = d->play_fmt ; /* no split format on the MSS */
|
||||
snd_set_blocksize(d);
|
||||
mss_reinit(d);
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
@ -561,15 +585,21 @@ again:
|
||||
if (mc11 & masked)
|
||||
printf("irq reset failed, mc11 0x%02x, masked 0x%02x\n", mc11, masked);
|
||||
masked |= mc11 ;
|
||||
/*
|
||||
* the nice OPTi931 sets the IRQ line before setting the bits in
|
||||
* mc11. So, on some occasions I have to retry (max 10 times).
|
||||
*/
|
||||
if ( mc11 == 0 ) { /* perhaps can return ... */
|
||||
reason = inb(io_Status(d));
|
||||
if (reason & 1) {
|
||||
printf("one more try...\n");
|
||||
goto again;
|
||||
DEB(printf("one more try...\n");)
|
||||
if (--loops)
|
||||
goto again;
|
||||
else
|
||||
DDB(printf("opti_intr: irq but mc11 not set!...\n");)
|
||||
}
|
||||
if (loops==10) {
|
||||
if (loops==10)
|
||||
printf("ouch, intr but nothing in mcir11 0x%02x\n", mc11);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -580,7 +610,8 @@ again:
|
||||
dsp_wrintr(d);
|
||||
}
|
||||
opti_write(d->conf_base, 11, ~mc11); /* ack */
|
||||
if (--loops) goto again;
|
||||
if (--loops)
|
||||
goto again;
|
||||
DEB(printf("xxx too many loops\n");)
|
||||
}
|
||||
|
||||
@ -657,7 +688,7 @@ ad_read(snddev_info *d, int reg)
|
||||
int x;
|
||||
|
||||
flags = spltty();
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 201);
|
||||
x = inb(io_Index_Addr(d)) & ~IA_AMASK ;
|
||||
outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;
|
||||
x = inb(io_Indexed_Data(d));
|
||||
@ -672,7 +703,7 @@ ad_write(snddev_info *d, int reg, u_char data)
|
||||
|
||||
int x ;
|
||||
flags = spltty();
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 1002);
|
||||
x = inb(io_Index_Addr(d)) & ~IA_AMASK ;
|
||||
outb(io_Index_Addr(d), (u_char) (reg & IA_AMASK) | x ) ;
|
||||
outb(io_Indexed_Data(d), data);
|
||||
@ -731,7 +762,7 @@ ad_enter_MCE(snddev_info *d)
|
||||
int prev;
|
||||
|
||||
d->bd_flags |= BD_F_MCE_BIT;
|
||||
AD_WAIT_INIT(d, 100);
|
||||
AD_WAIT_INIT(d, 203);
|
||||
prev = inb(io_Index_Addr(d));
|
||||
prev &= ~IA_TRD ;
|
||||
outb(io_Index_Addr(d), prev | IA_MCE ) ;
|
||||
@ -853,10 +884,11 @@ mss_mixer_set(snddev_info *d, int dev, int value)
|
||||
|
||||
d->mix_levels[dev] = left | (right << 8);
|
||||
|
||||
#if 0
|
||||
/* Scale volumes */
|
||||
left = mix_cvt[left];
|
||||
right = mix_cvt[right];
|
||||
|
||||
#endif
|
||||
/*
|
||||
* Set the left channel
|
||||
*/
|
||||
@ -919,6 +951,16 @@ ad1848_mixer_reset(snddev_info *d)
|
||||
ad_write(d, 20, 0x88);
|
||||
ad_write(d, 21, 0x88);
|
||||
break;
|
||||
|
||||
case MD_YM0020:
|
||||
/* set master volume to max */
|
||||
DDB(printf("set yamaha master volume to max"); )
|
||||
outb(0x370, 7) ;
|
||||
outb(0x371, 0) ;
|
||||
outb(0x370, 8) ;
|
||||
outb(0x371, 0) ;
|
||||
break;
|
||||
|
||||
case MD_GUSPNP:
|
||||
/* this is only necessary in mode 3 ... */
|
||||
ad_write(d, 22, 0x88);
|
||||
@ -997,7 +1039,7 @@ mss_format(snddev_info *d)
|
||||
arg = AFMT_U8 ;
|
||||
|
||||
/* ulaw/alaw seems broken on the opti931... */
|
||||
if (d->bd_id == MD_OPTI931) {
|
||||
if (d->bd_id == MD_OPTI931 || d->bd_id == MD_GUSPNP) {
|
||||
if (arg == AFMT_MU_LAW) {
|
||||
arg = AFMT_U8 ;
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
@ -1233,6 +1275,13 @@ mss_detect(struct isa_device *dev)
|
||||
d->bd_id = MD_AD1845;
|
||||
}
|
||||
ad_write(d, 23, tmp); /* Restore */
|
||||
DDB(printf("... try to identify the yamaha\n") ;)
|
||||
tmp = inb(0x370) ;
|
||||
outb(0x370, 6 /* dma config */ ) ;
|
||||
if (inb(0x370) != 6 ) /* not a yamaha... restore. */
|
||||
outb(0x370, tmp ) ;
|
||||
else
|
||||
d->bd_id = MD_YM0020 ;
|
||||
break;
|
||||
|
||||
case 0x83: /* CS4236 */
|
||||
@ -1244,7 +1293,6 @@ mss_detect(struct isa_device *dev)
|
||||
default: /* Assume CS4231 */
|
||||
BVDDB(printf("unknown id 0x%02x, assuming CS4231\n", id);)
|
||||
d->bd_id = MD_CS4231;
|
||||
|
||||
}
|
||||
}
|
||||
ad_write(d, 25, tmp1); /* Restore bits */
|
||||
@ -1354,7 +1402,7 @@ cs423x_probe(u_long csn, u_long vend_id)
|
||||
u_long id = vend_id & 0xff00ffff;
|
||||
if ( id == 0x3700630e )
|
||||
s = "CS4237" ;
|
||||
else if ( id == 0x3600630e )
|
||||
else if ( id == 0x3500630e || id == 0x3600630e )
|
||||
s = "CS4236" ;
|
||||
else if ( id == 0x3500630e )
|
||||
s = "CS4236B" ;
|
||||
@ -1364,7 +1412,7 @@ cs423x_probe(u_long csn, u_long vend_id)
|
||||
s = "Yamaha SA2";
|
||||
else if ( id == 0x3000a865)
|
||||
s = "Yamaha SA3";
|
||||
else if ( id == 0x0000a865)
|
||||
else if (vend_id == 0x0000a865)
|
||||
s = "Yamaha YMF719 OPL-SA3";
|
||||
else if (vend_id == 0x8140d315)
|
||||
s = "SoundscapeVIVO";
|
||||
@ -1399,7 +1447,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 == 0x0008a865 || vend_id==0x2000a865 || vend_id==0x3000a865 || vend_id==0x8140d315) {
|
||||
if (vend_id==0x2000a865 || vend_id==0x3000a865 ||
|
||||
vend_id==0x0008a865 || vend_id==0x8140d315) {
|
||||
/* Yamaha SA2/SA3 or ENSONIQ SoundscapeVIVO ENS4081 */
|
||||
dev->id_iobase = d.port[0] ;
|
||||
tmp_d.alt_base = d.port[1] ;
|
||||
@ -1418,7 +1467,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
|
||||
case 0x2000a865: /* Yamaha SA2 */
|
||||
case 0x3000a865: /* Yamaha SA3 */
|
||||
case 0x0000a865: /* Yamaha YMF719 */
|
||||
case 0x0000a865: /* Yamaha TMF719 SA3 */
|
||||
dev->id_iobase = d.port[1];
|
||||
tmp_d.alt_base = d.port[0];
|
||||
tmp_d.conf_base = d.port[4];
|
||||
@ -1436,6 +1485,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
tmp_d.bd_id = MD_CS4237 ;
|
||||
break;
|
||||
|
||||
case 0x3500630e: /* CS4236 */
|
||||
case 0x3600630e: /* CS4236 */
|
||||
case 0x3500630e: /* CS4236B */
|
||||
tmp_d.bd_id = MD_CS4236 ;
|
||||
@ -1451,7 +1501,7 @@ cs423x_attach(u_long csn, u_long vend_id, char *name,
|
||||
write_pnp_parms( &d, ldn );
|
||||
enable_pnp_card();
|
||||
|
||||
if ( (vend_id & 0x2000ffff) == 0x2000a865 ) {
|
||||
if ( (vend_id & 0x0000ffff) == 0x0000a865 ) {
|
||||
/* special volume setting for the Yamaha... */
|
||||
outb(tmp_d.conf_base, 7 /* volume, left */);
|
||||
outb(tmp_d.conf_base+1, 0 );
|
||||
@ -1542,10 +1592,10 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
if (d.flags & DV_PNP_SBCODEC) { /* sb-compatible codec */
|
||||
/*
|
||||
* the 931 is not a real SB, it has important pieces of
|
||||
* hardware controlled by both the WSS and the SB port...
|
||||
* hardware controlled by both the MSS and the SB port...
|
||||
*/
|
||||
printf("--- opti931 in sb mode ---\n");
|
||||
opti_write(p, 6, 1); /* MCIR6 wss disable, sb enable */
|
||||
opti_write(p, 6, 1); /* MCIR6 mss disable, sb enable */
|
||||
/*
|
||||
* swap the main and alternate iobase address since we want
|
||||
* to work in sb mode.
|
||||
@ -1555,7 +1605,7 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
} else { /* mss-compatible codec */
|
||||
tmp_d.bd_id = MD_OPTI931 ; /* to short-circuit the detect routine */
|
||||
opti_write(p, 6 , 2); /* MCIR6: wss enable, sb disable */
|
||||
opti_write(p, 6 , 2); /* MCIR6: mss enable, sb disable */
|
||||
opti_write(p, 5, 0x28); /* MCIR5: codec in exp. mode,fifo */
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
tmp_d.audio_fmt |= AFMT_FULLDUPLEX ; /* not really well... */
|
||||
@ -1567,6 +1617,76 @@ opti931_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = mss_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[1];
|
||||
tmp_d.alt_base = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | d.drq[1] ;
|
||||
tmp_d.audio_fmt |= AFMT_FULLDUPLEX ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static void gus_mem_cfg(snddev_info *tmp);
|
||||
|
||||
static char *guspnp_probe(u_long csn, u_long vend_id);
|
||||
|
@ -184,7 +184,9 @@ dsp_wrintr(snddev_info *d)
|
||||
/* for any reason, size has changed. Stop and restart */
|
||||
DEB(printf("wrintr: bsz change from %d to %d, rp %d rl %d\n",
|
||||
b->dl, l, b->rp, b->rl));
|
||||
d->callback(d, SND_CB_WR | SND_CB_STOP );
|
||||
DEB(printf("wrintr: dl %d -> %d\n", b->dl, l);)
|
||||
if (b->dl != 0)
|
||||
d->callback(d, SND_CB_WR | SND_CB_STOP );
|
||||
/*
|
||||
* at high speed, it might well be that the count
|
||||
* changes in the meantime. So we try to update b->rl
|
||||
@ -270,10 +272,10 @@ dsp_write_body(snddev_info *d, struct uio *buf)
|
||||
else
|
||||
timeout = 1 ;
|
||||
ret = tsleep( (caddr_t)b, PRIBIO|PCATCH, "dspwr", timeout);
|
||||
if (ret == EINTR || ret == ERESTART)
|
||||
if (ret == EINTR)
|
||||
d->flags |= SND_F_ABORTING ;
|
||||
splx(s);
|
||||
if (ret == EINTR)
|
||||
if (ret == EINTR || ret == ERESTART)
|
||||
break ;
|
||||
continue;
|
||||
}
|
||||
@ -457,10 +459,12 @@ dsp_rdintr(snddev_info *d)
|
||||
( FULL_DUPLEX(d) || (d->flags & SND_F_WRITING) == 0 ) ) {
|
||||
int l = min(b->fl - 0x100, d->rec_blocksize);
|
||||
l &= DMA_ALIGN_MASK ; /* realign sizes */
|
||||
DEB(printf("rdintr: dl %d -> %d\n", b->dl, l);)
|
||||
if (l != b->dl) {
|
||||
/* for any reason, size has changed. Stop and restart */
|
||||
if (b->dl > 0 )
|
||||
d->callback(d, SND_CB_RD | SND_CB_STOP );
|
||||
b->dl = l ;
|
||||
d->callback(d, SND_CB_RD | SND_CB_STOP );
|
||||
d->callback(d, SND_CB_RD | SND_CB_START );
|
||||
}
|
||||
} else {
|
||||
@ -553,10 +557,10 @@ dsp_read_body(snddev_info *d, struct uio *buf)
|
||||
else
|
||||
timeout = 1; /* maybe data will be ready earlier */
|
||||
ret = tsleep( (caddr_t)b, PRIBIO | PCATCH , "dsprd", timeout ) ;
|
||||
if (ret == EINTR || ret == ERESTART)
|
||||
if (ret == EINTR)
|
||||
d->flags |= SND_F_ABORTING ;
|
||||
splx(s);
|
||||
if (ret == EINTR)
|
||||
if (ret == EINTR || ret == ERESTART)
|
||||
break ;
|
||||
continue;
|
||||
}
|
||||
@ -593,7 +597,7 @@ dsp_read_body(snddev_info *d, struct uio *buf)
|
||||
s = spltty(); /* no interrupts here ... */
|
||||
d->flags &= ~SND_F_READING ;
|
||||
if (d->flags & SND_F_ABORTING) {
|
||||
d->flags |= ~SND_F_ABORTING;
|
||||
d->flags &= ~SND_F_ABORTING; /* XXX */
|
||||
splx(s);
|
||||
dsp_rdabort(d, 1 /* restart */);
|
||||
/* XXX return EINTR ? */
|
||||
@ -761,7 +765,8 @@ snd_flush(snddev_info *d)
|
||||
return -1 ;
|
||||
}
|
||||
if ( ret && --count == 0) {
|
||||
printf("timeout flushing dbuf_out.chan, cnt 0x%x flags 0x%08lx\n",
|
||||
printf("timeout flushing dbuf_out, chan %d cnt 0x%x flags 0x%08lx\n",
|
||||
b->chan,
|
||||
b->rl, d->flags);
|
||||
break;
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ ahead.
|
||||
|
||||
/*
|
||||
* Table of mixer registers. There is a default table for the
|
||||
* AD1848/CS423x clones, and one for the OPTI931. As more WSS
|
||||
* AD1848/CS423x clones, and one for the OPTI931. As more MSS
|
||||
* clones come out, there ought to be more tables.
|
||||
*
|
||||
* Fields in the table are : polarity, register, offset, bits
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* driver for the SoundBlaster and clones.
|
||||
*
|
||||
* Copyright 1997 Luigi Rizzo.
|
||||
* Copyright 1997,1998 Luigi Rizzo.
|
||||
*
|
||||
* Derived from files in the Voxware 3.5 distribution,
|
||||
* Copyright by Hannu Savolainen 1994, under the same copyright
|
||||
@ -74,6 +74,8 @@ static int dsp_speed(snddev_info *d);
|
||||
static void sb_mixer_reset(snddev_info *d);
|
||||
|
||||
u_int sb_get_byte(int io_base);
|
||||
int ess_write(int io_base, u_char reg, int val);
|
||||
int ess_read(int io_base, u_char reg);
|
||||
|
||||
/*
|
||||
* Then put here the descriptors for the various boards supported
|
||||
@ -151,6 +153,12 @@ sb_attach(struct isa_device *dev)
|
||||
* here are the main routines from the switches.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Unlike MSS, the sb only supports a single open (does not mean
|
||||
* that only a single process is using it, since it can fork
|
||||
* afterwards, or pass the descriptor to another process).
|
||||
*
|
||||
*/
|
||||
static int
|
||||
sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
{
|
||||
@ -196,10 +204,21 @@ sb_dsp_open(dev_t dev, int flags, int mode, struct proc * p)
|
||||
d->play_fmt = d->rec_fmt = AFMT_U8 ;
|
||||
break ;
|
||||
}
|
||||
if ( (flags & FREAD) == 0)
|
||||
/*
|
||||
* since the SB is not simmetric, I use the open mode to select
|
||||
* which channel should be privileged, and disable I/O in the
|
||||
* other direction.
|
||||
* In case the board is opened RW, we don't have enough
|
||||
* information on what to do. Temporarily, privilege the
|
||||
* playback channel, which is used more often, and set the other
|
||||
* one to U8.
|
||||
*/
|
||||
if ( (flags & FREAD) == 0) /* opened write only */
|
||||
d->rec_fmt = 0 ;
|
||||
if ( (flags & FWRITE) == 0)
|
||||
else if ( (flags & FWRITE) == 0) /* opened read only */
|
||||
d->play_fmt = 0 ;
|
||||
else /* opened read/write */
|
||||
d->rec_fmt = (d->play_fmt == AFMT_S16_LE) ? AFMT_U8 : AFMT_S16_LE ;
|
||||
|
||||
d->flags |= SND_F_BUSY ;
|
||||
d->play_speed = d->rec_speed = DSP_DEFAULT_SPEED ;
|
||||
@ -275,7 +294,10 @@ sb_intr(int unit)
|
||||
* SB < 4.0 is half duplex and has only 1 bit for int source,
|
||||
* so we fake it. SB 4.x (SB16) has the int source in a separate
|
||||
* register.
|
||||
* The Vibra16X has separate flags for 8 and 16 bit transfers, but
|
||||
* I have no idea how to tell capture from playback interrupts...
|
||||
*/
|
||||
#define PLAIN_SB16(x) ( ( (x) & (BD_F_SB16|BD_F_SB16X) ) == BD_F_SB16)
|
||||
again:
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
c = sb_getmixer(io_base, IRQ_STAT);
|
||||
@ -284,25 +306,26 @@ again:
|
||||
*/
|
||||
reason = 0 ;
|
||||
if ( c & 1 ) { /* 8-bit dma */
|
||||
if (d->dbuf_out.chan < 4)
|
||||
if (d->play_fmt == AFMT_U8 || d->play_fmt == AFMT_MU_LAW )
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan < 4)
|
||||
if (d->rec_fmt == AFMT_U8 || d->rec_fmt == AFMT_MU_LAW )
|
||||
reason |= 2;
|
||||
}
|
||||
if ( c & 2 ) { /* 16-bit dma */
|
||||
if (d->dbuf_out.chan >= 4)
|
||||
if (d->play_fmt == AFMT_S16_LE)
|
||||
reason |= 1;
|
||||
if (d->dbuf_in.chan >= 4)
|
||||
if (d->rec_fmt == AFMT_S16_LE)
|
||||
reason |= 2;
|
||||
}
|
||||
}
|
||||
/* XXX previous location of ack... */
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d\n", d->flags, reason));
|
||||
DEB(printf("sb_intr, flags 0x%08lx reason %d c 0x%x\n",
|
||||
d->flags, reason, c));
|
||||
if ( reason & 1 ) { /* possibly a write interrupt */
|
||||
if ( d->dbuf_out.dl )
|
||||
dsp_wrintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: wrintr but write DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -310,7 +333,7 @@ again:
|
||||
if ( d->dbuf_in.dl )
|
||||
dsp_rdintr(d);
|
||||
else {
|
||||
if (d->bd_flags & BD_F_SB16)
|
||||
if (PLAIN_SB16(d->bd_flags))
|
||||
printf("WARNING: rdintr but read DMA inactive!\n");
|
||||
}
|
||||
}
|
||||
@ -346,20 +369,37 @@ sb_callback(snddev_info *d, int reason)
|
||||
|
||||
switch (reason & SND_CB_REASON_MASK) {
|
||||
case SND_CB_INIT : /* called with int enabled and no pending io */
|
||||
/*
|
||||
* set the speed
|
||||
*/
|
||||
dsp_speed(d);
|
||||
/*
|
||||
* set the desired DMA blocksize (influences select behaviour)
|
||||
*/
|
||||
snd_set_blocksize(d);
|
||||
/*
|
||||
* since native mulaw is not present, emulate it.
|
||||
*/
|
||||
if ( (d->play_fmt & AFMT_MU_LAW) || (d->rec_fmt & AFMT_MU_LAW) )
|
||||
d->flags |= SND_F_XLAT8 ;
|
||||
else
|
||||
d->flags &= ~SND_F_XLAT8 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16) {
|
||||
/*
|
||||
* there are too many flavours of SB for my taste... here i try to do
|
||||
* the proper initialization for each one.
|
||||
*/
|
||||
if (PLAIN_SB16(d->bd_flags)) {
|
||||
u_char c, c1 ;
|
||||
|
||||
/* the SB16 can do full duplex using one 16-bit channel
|
||||
/* the original SB16 (non-PnP, or PnP, or Vibra16C)
|
||||
* can do full duplex using one 16-bit channel
|
||||
* and one 8-bit channel. It needs to be programmed to
|
||||
* use split format though.
|
||||
* We use the following algorithm:
|
||||
* I DON'T do this for the Vibra16X because I have no idea
|
||||
* of what needs to be done there...
|
||||
*
|
||||
* I use the following algorithm:
|
||||
* 1. check which direction(s) are active;
|
||||
* 2. check if we should swap dma channels
|
||||
* 3. check if we can do the swap.
|
||||
@ -379,7 +419,11 @@ sb_callback(snddev_info *d, int reason)
|
||||
if ( d->play_fmt != AFMT_S16_LE && d->dbuf_out.chan < 4 )
|
||||
swap = 0;
|
||||
if ( d->rec_fmt ) {
|
||||
/* check for possible config errors. */
|
||||
/* check for possible config errors.
|
||||
* This cannot happen at open time since even in
|
||||
* case of opening rw we privilege the play
|
||||
* channel.
|
||||
*/
|
||||
if (d->rec_fmt == d->play_fmt) {
|
||||
DDB(printf("sorry, read DMA channel unavailable\n"));
|
||||
}
|
||||
@ -392,6 +436,29 @@ sb_callback(snddev_info *d, int reason)
|
||||
d->dbuf_in.chan = d->dbuf_out.chan;
|
||||
d->dbuf_out.chan = c ;
|
||||
}
|
||||
} else if (d->bd_flags & BD_F_ESS) {
|
||||
u_char c ;
|
||||
if (d->play_fmt == 0) {
|
||||
/* initialize for record */
|
||||
static u_char cmd[] = {
|
||||
0x51,0xd0,0x71,0xf4,0x51,0x98,0x71,0xbc
|
||||
};
|
||||
ess_write(d->io_base, 0xb8, 0x0e);
|
||||
c = ( ess_read(d->io_base, 0xa8) & 0xfc ) | 1 ;
|
||||
if (d->flags & SND_F_STEREO)
|
||||
c++ ;
|
||||
ess_write(d->io_base, 0xa8, c);
|
||||
ess_write(d->io_base, 0xb9, 2); /* 4bytes/transfer */
|
||||
/*
|
||||
* set format in b6, b7
|
||||
*/
|
||||
} else {
|
||||
/* initialize for play */
|
||||
static u_char cmd[] = {
|
||||
0x80,0x51,0xd0,0x00,0x71,0xf4,
|
||||
0x80,0x51,0x98,0x00,0x71,0xbc
|
||||
};
|
||||
}
|
||||
}
|
||||
reset_dbuf(& (d->dbuf_in), SND_CHAN_RD );
|
||||
reset_dbuf(& (d->dbuf_out), SND_CHAN_WR );
|
||||
@ -400,13 +467,45 @@ 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 ;
|
||||
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* just a guess: on the Vibra16X, the first
|
||||
* op started takes the first dma channel,
|
||||
* the second one takes the next...
|
||||
* The default is to be ready for play.
|
||||
*/
|
||||
int swap = 0 ;
|
||||
DEB(printf("start %s -- now dma %d:%d\n",
|
||||
rd ? "rd" : "wr",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan););
|
||||
/* swap only if both channels are idle
|
||||
* play: dl=0, since there is no pause;
|
||||
* rec: rl=0
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 && d->dbuf_in.rl == 0 ) {
|
||||
/* must swap channels, but also save dl */
|
||||
int c = d->dbuf_in.chan ;
|
||||
int dl = d->dbuf_in.dl ;
|
||||
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 );
|
||||
d->dbuf_in.dl = dl ;
|
||||
printf("swapped -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ) {
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
) {
|
||||
c = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_DMA16 ;
|
||||
c1 = DSP_F16_SIGNED ;
|
||||
l /= 2 ;
|
||||
@ -455,7 +554,10 @@ 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 && b->chan > 4 )
|
||||
if ( b->chan > 4
|
||||
|| (rd && d->rec_fmt == AFMT_S16_LE)
|
||||
|| (!rd && d->play_fmt == AFMT_S16_LE)
|
||||
)
|
||||
cmd = DSP_CMD_DMAPAUSE_16 ;
|
||||
if (d->bd_flags & BD_F_HISPEED) {
|
||||
sb_reset_dsp(d->io_base);
|
||||
@ -474,6 +576,22 @@ sb_callback(snddev_info *d, int reason)
|
||||
sb_cmd(d->io_base, cmd == DSP_CMD_DMAPAUSE_8 ?
|
||||
0xd6 : 0xd4); /* continue other dma */
|
||||
}
|
||||
if (d->bd_flags & BD_F_SB16X) {
|
||||
/* restore possible swapped channels.
|
||||
* The default is to be ready for play.
|
||||
* XXX right now, it kills all input on overflow
|
||||
*/
|
||||
if ( rd && d->dbuf_out.dl == 0 ) {
|
||||
/* must swap channels ? */
|
||||
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 );
|
||||
printf("restored -- now dma %d:%d\n",
|
||||
d->dbuf_out.chan, d->dbuf_in.chan);
|
||||
}
|
||||
}
|
||||
}
|
||||
DEB( sb_cmd(d->io_base, DSP_CMD_SPKOFF) ); /* speaker off */
|
||||
break ;
|
||||
@ -618,6 +736,7 @@ sb_dsp_init(snddev_info *d, struct isa_device *dev)
|
||||
printf("ESS1868 (rev %d)\n", rev);
|
||||
else
|
||||
printf("ESS688 (rev %d)\n", rev);
|
||||
/* d->audio_fmt |= AFMT_S16_LE; */ /* not yet... */
|
||||
break ; /* XXX */
|
||||
} else {
|
||||
printf("Unknown card 0x%x 0x%x -- hope it is SBPRO\n",
|
||||
@ -660,6 +779,14 @@ sb_mix_init(snddev_info *d)
|
||||
|
||||
/*
|
||||
* Common code for the midi and pcm functions
|
||||
*
|
||||
* sb_cmd write a single byte to the CMD port.
|
||||
* sb_cmd2 write a CMD + 1 byte arg
|
||||
* sb_cmd3 write a CMD + 2 byte arg
|
||||
* sb_get_byte returns a single byte from the DSP data port
|
||||
*
|
||||
* ess_write is actually sb_cmd2
|
||||
* ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte
|
||||
*/
|
||||
|
||||
int
|
||||
@ -725,9 +852,9 @@ sb_getmixer(int io_base, u_int port)
|
||||
u_long flags;
|
||||
|
||||
flags = spltty();
|
||||
outb(io_base + 4, (u_char) (port & 0xff)); /* Select register */
|
||||
outb(io_base + SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
|
||||
DELAY(10);
|
||||
val = inb(io_base + 5);
|
||||
val = inb(io_base + SB_MIX_DATA);
|
||||
DELAY(10);
|
||||
splx(flags);
|
||||
|
||||
@ -747,6 +874,19 @@ sb_get_byte(int io_base)
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
int
|
||||
ess_write(int io_base, u_char reg, int val)
|
||||
{
|
||||
return sb_cmd2(io_base, reg, val);
|
||||
}
|
||||
|
||||
int
|
||||
ess_read(int io_base, u_char reg)
|
||||
{
|
||||
if (!sb_cmd(io_base, 0xc0) || !sb_cmd(io_base, reg) )
|
||||
return 0xffff ;
|
||||
return sb_get_byte(io_base);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
@ -785,17 +925,21 @@ dsp_speed(snddev_info *d)
|
||||
*/
|
||||
if (d->bd_flags & BD_F_ESS) {
|
||||
int t;
|
||||
RANGE (speed, 4000, 48000);
|
||||
RANGE (speed, 5000, 49000);
|
||||
if (speed > 22000) {
|
||||
t = (795500 + speed / 2) / speed;
|
||||
speed = (795500 + t / 2) / t ;
|
||||
t = ( 256 - (795500 + speed / 2) / speed ) | 0x80 ;
|
||||
t = (256 - t ) | 0x80 ;
|
||||
} else {
|
||||
t = (397700 + speed / 2) / speed;
|
||||
speed = (397700 + t / 2) / t ;
|
||||
t = 128 - (397700 + speed / 2) / speed ;
|
||||
t = 128 - t ;
|
||||
}
|
||||
sb_cmd2(d->io_base, 0xa1, t); /* set time constant */
|
||||
ess_write(d->io_base, 0xa1, t); /* set time constant */
|
||||
d->play_speed = d->rec_speed = speed ;
|
||||
speed = (speed * 9 ) / 20 ;
|
||||
t = 256-7160000/(speed*82);
|
||||
ess_write(d->io_base,0xa2,t);
|
||||
return speed ;
|
||||
}
|
||||
|
||||
@ -1080,79 +1224,11 @@ ess1868_attach(u_long csn, u_long vend_id, char *name,
|
||||
pcmattach(dev);
|
||||
}
|
||||
|
||||
static char *opti925_probe(u_long csn, u_long vend_id);
|
||||
static void opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev);
|
||||
|
||||
static struct pnp_device opti925 = {
|
||||
"opti925",
|
||||
opti925_probe,
|
||||
opti925_attach,
|
||||
&nsnd, /* use this for all sound cards */
|
||||
&tty_imask /* imask */
|
||||
};
|
||||
DATA_SET (pnpdevice_set, opti925);
|
||||
|
||||
static char *
|
||||
opti925_probe(u_long csn, u_long vend_id)
|
||||
{
|
||||
if (vend_id == 0x2509143e) {
|
||||
struct pnp_cinfo d ;
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
if (d.enable == 0) {
|
||||
printf("This is an OPTi925, but LDN 1 is disabled\n");
|
||||
return NULL;
|
||||
}
|
||||
return "OPTi925" ;
|
||||
}
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
static void
|
||||
opti925_attach(u_long csn, u_long vend_id, char *name,
|
||||
struct isa_device *dev)
|
||||
{
|
||||
struct pnp_cinfo d ;
|
||||
snddev_info tmp_d ; /* patched copy of the basic snddev_info */
|
||||
int the_irq = 0 ;
|
||||
|
||||
tmp_d = sb_op_desc;
|
||||
snddev_last_probed = &tmp_d;
|
||||
|
||||
read_pnp_parms ( &d , 3 ); /* disable LDN 3 */
|
||||
the_irq = d.irq[0];
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 3 );
|
||||
|
||||
read_pnp_parms ( &d , 2 ); /* disable LDN 2 */
|
||||
d.port[0] = 0 ;
|
||||
d.enable = 0 ;
|
||||
write_pnp_parms ( &d , 2 );
|
||||
|
||||
read_pnp_parms ( &d , 1 ) ;
|
||||
d.irq[0] = the_irq ;
|
||||
dev->id_iobase = d.port[0];
|
||||
write_pnp_parms ( &d , 1 );
|
||||
enable_pnp_card();
|
||||
|
||||
tmp_d.conf_base = d.port[3];
|
||||
|
||||
dev->id_drq = d.drq[0] ; /* primary dma */
|
||||
dev->id_irq = (1 << d.irq[0] ) ;
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
pcmattach(dev);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* A driver for some SB16pnp and compatibles...
|
||||
*
|
||||
* Avance Asound 100 -- 0x01009305
|
||||
* Avance Logic ALS100+ -- 0x10019305
|
||||
* xxx -- 0x2b008c0e
|
||||
*
|
||||
*/
|
||||
@ -1181,11 +1257,16 @@ sb16pnp_probe(u_long csn, u_long vend_id)
|
||||
* Reported values are:
|
||||
* SB16 Value PnP: 0x2b008c0e
|
||||
* SB AWExx PnP: 0x39008c0e 0x9d008c0e 0xc3008c0e
|
||||
* Vibra16X: 0xf0008c0e
|
||||
*/
|
||||
if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
if (vend_id == 0xf0008c0e)
|
||||
s = "Vibra16X" ;
|
||||
else if ( (vend_id & 0xffffff) == (0x9d008c0e & 0xffffff) )
|
||||
s = "SB16 PnP";
|
||||
else if (vend_id == 0x01009305)
|
||||
s = "Avance Asound 100" ;
|
||||
else if (vend_id == 0x10019305)
|
||||
s = "Avance Logic 100+" ; /* Vibra16X-class */
|
||||
if (s) {
|
||||
struct pnp_cinfo d;
|
||||
read_pnp_parms(&d, 0);
|
||||
@ -1220,9 +1301,16 @@ sb16pnp_attach(u_long csn, u_long vend_id, char *name,
|
||||
dev->id_intr = pcmintr ;
|
||||
dev->id_flags = DV_F_DUAL_DMA | (d.drq[1] ) ;
|
||||
|
||||
pcm_info[dev->id_unit] = tmp_d;
|
||||
pcm_info[dev->id_unit] = tmp_d; /* pcm_info[] will be reinitialized after */
|
||||
snddev_last_probed->probe(dev); /* not really necessary but doesn't harm */
|
||||
|
||||
if (vend_id == 0x10019305 || vend_id == 0xf0008c0e) {
|
||||
/*
|
||||
* XXX please add here the vend_id for other vibra16X cards...
|
||||
* And remember, must change tmp_d, not
|
||||
*/
|
||||
tmp_d.bd_flags |= BD_F_SB16X ;
|
||||
}
|
||||
pcmattach(dev);
|
||||
}
|
||||
#endif /* NPNP */
|
||||
|
@ -19,9 +19,9 @@ extern int sbc_major, sbc_minor ;
|
||||
#define DSP_DATA_AVAIL (io_base + 0xE)
|
||||
#define DSP_DATA_AVL16 (io_base + 0xF)
|
||||
|
||||
#define SB_MIX_ADDR 0x4
|
||||
#define SB_MIX_DATA 0x5
|
||||
#if 0
|
||||
#define MIXER_ADDR (io_base + 0x4)
|
||||
#define MIXER_DATA (io_base + 0x5)
|
||||
#define OPL3_LEFT (io_base + 0x0)
|
||||
#define OPL3_RIGHT (io_base + 0x2)
|
||||
#define OPL3_BOTH (io_base + 0x8)
|
||||
@ -138,9 +138,14 @@ extern int sbc_major, sbc_minor ;
|
||||
#define BD_F_MIX_CT1745 0x0030 /* CT1745 */
|
||||
|
||||
#define BD_F_SB16 0x0100 /* this is a SB16 */
|
||||
#define BD_F_NOREC 0x0200 /* recording not supported on this board */
|
||||
#define BD_F_SB16X 0x0200 /* this is a vibra16X or clone */
|
||||
#define BD_F_MIDIBUSY 0x0400 /* midi busy */
|
||||
#define BD_F_ESS 0x0800 /* this is an ESS chip */
|
||||
/*
|
||||
* on some SB16 cards, at times I swap DMA channels. Remember this
|
||||
* so that they can be restored later.
|
||||
*/
|
||||
#define BD_F_SWAPPED 0x1000 /* have swapped DMA channels */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -57,10 +57,10 @@
|
||||
#include <sys/devfsext.h>
|
||||
#endif /* DEVFS */
|
||||
|
||||
|
||||
#if NPCM > 0 /* from "pcm.h" via disgusting #include in snd/sound.h */
|
||||
|
||||
extern struct isa_driver pcmdriver;
|
||||
|
||||
extern struct isa_driver pcmdriver ;
|
||||
#define SNDSTAT_BUF_SIZE 4000
|
||||
static char status_buf[SNDSTAT_BUF_SIZE] ;
|
||||
static int status_len = 0 ;
|
||||
@ -91,6 +91,75 @@ snddev_info synth_info[NPCM_MAX] ;
|
||||
|
||||
u_long nsnd = NPCM ; /* total number of sound devices */
|
||||
|
||||
/*
|
||||
* Hooks for APM support, but code not operational yet.
|
||||
*/
|
||||
|
||||
#include "apm.h"
|
||||
#include <i386/include/apm_bios.h>
|
||||
#if NAPM > 0
|
||||
|
||||
static int
|
||||
sound_suspend(void *arg)
|
||||
{
|
||||
/*
|
||||
* I think i can safely do nothing here and
|
||||
* reserve all the work for wakeup time
|
||||
*/
|
||||
printf("Called APM sound suspend hook for unit %d\n", (int)arg);
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
static int
|
||||
sound_resume(void *arg)
|
||||
{
|
||||
snddev_info *d = NULL ;
|
||||
|
||||
d = &pcm_info[(int)arg] ;
|
||||
/*
|
||||
* reinitialize card registers.
|
||||
* Flush buffers and reinitialize DMA channels.
|
||||
* If a write was pending, pretend it is done
|
||||
* (and issue any wakeup we need).
|
||||
* If a read is pending, restart it.
|
||||
*/
|
||||
if (d->bd_id == MD_YM0020) {
|
||||
DDB(printf("setting up yamaha registers\n"));
|
||||
outb(0x370, 6 /* dma config */ ) ;
|
||||
if (FULL_DUPLEX(d))
|
||||
outb(0x371, 0xa9 ); /* use both dma chans */
|
||||
else
|
||||
outb(0x371, 0x8b ); /* use low dma chan */
|
||||
}
|
||||
printf("Called APM sound resume hook for unit %d\n", (int)arg);
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
static void
|
||||
init_sound_apm(int unit)
|
||||
{
|
||||
struct apmhook *ap;
|
||||
|
||||
ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT);
|
||||
bzero(ap, sizeof *ap);
|
||||
|
||||
ap->ah_fun = sound_resume;
|
||||
ap->ah_arg = (void *)unit;
|
||||
ap->ah_name = "pcm resume handler";
|
||||
ap->ah_order = APM_MID_ORDER;
|
||||
apm_hook_establish(APM_HOOK_RESUME, ap);
|
||||
|
||||
ap = malloc(sizeof *ap, M_DEVBUF, M_NOWAIT);
|
||||
bzero(ap, sizeof *ap);
|
||||
|
||||
ap->ah_fun = sound_suspend;
|
||||
ap->ah_arg = (void *)unit;
|
||||
ap->ah_name = "pcm suspend handler";
|
||||
ap->ah_order = APM_MID_ORDER;
|
||||
apm_hook_establish(APM_HOOK_SUSPEND, ap);
|
||||
}
|
||||
#endif /* NAPM */
|
||||
|
||||
/*
|
||||
* the probe routine can only return an int to the upper layer. Hence,
|
||||
* it leaves the pointer to the last successfully
|
||||
@ -121,7 +190,7 @@ static snddev_info *sb_devs[] = { /* all SB clones */
|
||||
NULL,
|
||||
} ;
|
||||
|
||||
static snddev_info *mss_devs[] = { /* all WSS clones */
|
||||
static snddev_info *mss_devs[] = { /* all MSS clones */
|
||||
&mss_op_desc,
|
||||
NULL,
|
||||
} ;
|
||||
@ -194,7 +263,10 @@ pcmattach(struct isa_device * dev)
|
||||
d->dbuf_in.chan = dev->id_flags & DV_F_DRQ_MASK ;
|
||||
else
|
||||
d->dbuf_in.chan = d->dbuf_out.chan ;
|
||||
/* XXX should also set bd_id from flags ? */
|
||||
#if 1 /* does this cause trouble with PnP cards ? */
|
||||
if (d->bd_id == 0)
|
||||
d->bd_id = (dev->id_flags & DV_F_DEV_MASK) >> DV_F_DEV_SHIFT ;
|
||||
#endif
|
||||
d->status_ptr = 0;
|
||||
|
||||
/*
|
||||
@ -224,7 +296,11 @@ pcmattach(struct isa_device * dev)
|
||||
cdevsw_add(&isadev, &snd_cdevsw, NULL);
|
||||
|
||||
#ifdef DEVFS
|
||||
#define GID_SND GID_GAMES
|
||||
#ifndef GID_GAMES
|
||||
#define GID_SND UID_ROOT
|
||||
#else
|
||||
#define GID_SND GID_GAMES /* i am not really sure this is a good one. */
|
||||
#endif
|
||||
#define UID_SND UID_ROOT
|
||||
#define PERM_SND 0660
|
||||
/*
|
||||
@ -294,6 +370,9 @@ pcmattach(struct isa_device * dev)
|
||||
#endif
|
||||
snddev_last_probed = NULL ;
|
||||
|
||||
#if NAPM > 0
|
||||
init_sound_apm(dev->id_unit);
|
||||
#endif
|
||||
return stat ;
|
||||
}
|
||||
|
||||
@ -738,7 +817,7 @@ sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
snd_chan_param *p = (snd_chan_param *)arg;
|
||||
d->play_speed = p->play_rate;
|
||||
d->rec_speed = p->play_rate; /* XXX one speed allowed */
|
||||
if (p->play_format & SND_F_STEREO)
|
||||
if (p->play_format & AFMT_STEREO)
|
||||
d->flags |= SND_F_STEREO ;
|
||||
else
|
||||
d->flags &= ~SND_F_STEREO ;
|
||||
@ -805,7 +884,7 @@ sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
break;
|
||||
|
||||
case FIOASYNC: /*set/clear async i/o */
|
||||
printf("FIOASYNC\n");
|
||||
DEB( printf("FIOASYNC\n") ; )
|
||||
break;
|
||||
|
||||
case SNDCTL_DSP_NONBLOCK :
|
||||
@ -1055,7 +1134,7 @@ sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
|
||||
* really sndpoll. Second arg for poll is not "rw" but "events"
|
||||
*/
|
||||
int
|
||||
sndselect(dev_t i_dev, int rw, struct proc *p)
|
||||
sndselect(dev_t i_dev, int rw, struct proc * p)
|
||||
{
|
||||
int dev, unit, c = 1 /* default: success */ ;
|
||||
snddev_info *d ;
|
||||
@ -1220,7 +1299,7 @@ init_status(snddev_info *d)
|
||||
if (status_len != 0) /* only do init once */
|
||||
return ;
|
||||
sprintf(status_buf,
|
||||
"FreeBSD Audio Driver (980215) " __DATE__ " " __TIME__ "\n"
|
||||
"FreeBSD Audio Driver (981002) " __DATE__ " " __TIME__ "\n"
|
||||
"Installed devices:\n");
|
||||
|
||||
for (i = 0; i < NPCM_MAX; i++) {
|
||||
|
@ -65,7 +65,10 @@
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <machine/clock.h> /* for DELAY */
|
||||
|
||||
/* To minimize changes with the code in 2.2.X */
|
||||
/*
|
||||
* the following assumes that FreeBSD 3.X uses poll(2) instead of select(2).
|
||||
* This change dates to late 1997.
|
||||
*/
|
||||
#include <sys/poll.h>
|
||||
#define d_select_t d_poll_t
|
||||
|
||||
@ -158,7 +161,7 @@ struct _snddev_info {
|
||||
*/
|
||||
|
||||
int io_base ; /* primary I/O address for the board */
|
||||
int alt_base ; /* some codecs are accessible as SB+WSS... */
|
||||
int alt_base ; /* some codecs are accessible as SB+MSS... */
|
||||
int conf_base ; /* and the opti931 also has a config space */
|
||||
int mix_base ; /* base for the mixer... */
|
||||
int midi_base ; /* base for the midi */
|
||||
|
Loading…
x
Reference in New Issue
Block a user