make sb dependant on sbc
add support for non-pnp cards to sbc move card identification to sbc channel-swapping code is in sb now instead of dsp vibra16x support is still broken, but will be fixed soon note: sbc is now compulsory for sb cards for pnp cards use: device sbc0 for non-pnp cards eg: device sbc0 at isa? port 0x240 irq 5 drq 3 flags 0x15 (hints as oldpcm) both in addition to: device pcm0 Reviewed by: tanimura,dfr Said he liked it: peter
This commit is contained in:
parent
fefaab10f0
commit
d4a72b067c
@ -60,6 +60,7 @@ static int esschan_setblocksize(void *data, u_int32_t blocksize);
|
||||
static int esschan_trigger(void *data, int go);
|
||||
static int esschan_getptr(void *data);
|
||||
static pcmchan_caps *esschan_getcaps(void *data);
|
||||
|
||||
static pcmchan_caps sb_playcaps = {
|
||||
4000, 22050,
|
||||
AFMT_U8,
|
||||
@ -84,18 +85,24 @@ static pcmchan_caps sbpro_reccaps = {
|
||||
AFMT_STEREO | AFMT_U8
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16_playcaps = {
|
||||
static pcmchan_caps sb16_hcaps = {
|
||||
5000, 45000,
|
||||
AFMT_STEREO | AFMT_S16_LE,
|
||||
AFMT_STEREO | AFMT_S16_LE
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16_reccaps = {
|
||||
static pcmchan_caps sb16_lcaps = {
|
||||
5000, 45000,
|
||||
AFMT_STEREO | AFMT_U8,
|
||||
AFMT_STEREO | AFMT_U8
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16x_caps = {
|
||||
5000, 49000,
|
||||
AFMT_STEREO | AFMT_U8 /* | AFMT_S16_LE */,
|
||||
AFMT_STEREO | AFMT_U8 /* AFMT_S16_LE */
|
||||
};
|
||||
|
||||
static pcmchan_caps ess_playcaps = {
|
||||
5000, 49000,
|
||||
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
|
||||
@ -144,16 +151,11 @@ struct sb_chinfo {
|
||||
|
||||
struct sb_info {
|
||||
struct resource *io_base; /* I/O address for the board */
|
||||
int io_rid;
|
||||
struct resource *irq;
|
||||
int irq_rid;
|
||||
struct resource *drq1; /* play */
|
||||
int drq1_rid;
|
||||
struct resource *drq2; /* rec */
|
||||
int drq2_rid;
|
||||
struct resource *drq1;
|
||||
struct resource *drq2;
|
||||
bus_dma_tag_t parent_dmat;
|
||||
|
||||
int dma16, dma8;
|
||||
int bd_id;
|
||||
u_long bd_flags; /* board-specific flags */
|
||||
struct sb_chinfo pch, rch;
|
||||
@ -166,31 +168,25 @@ static int sb_cmd(struct sb_info *sb, u_char val);
|
||||
static int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
|
||||
static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
|
||||
static u_int sb_get_byte(struct sb_info *sb);
|
||||
static int ess_write(struct sb_info *sb, u_char reg, int val);
|
||||
static int ess_read(struct sb_info *sb, u_char reg);
|
||||
|
||||
/*
|
||||
* in the SB, there is a set of indirect "mixer" registers with
|
||||
* address at offset 4, data at offset 5
|
||||
*/
|
||||
static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
|
||||
static int sb_getmixer(struct sb_info *sb, u_int port);
|
||||
|
||||
static void sb_intr(void *arg);
|
||||
static void ess_intr(void *arg);
|
||||
static int sb_init(device_t dev, struct sb_info *sb);
|
||||
static int sb_reset_dsp(struct sb_info *sb);
|
||||
|
||||
static void sb_intr(void *arg);
|
||||
static int sb_format(struct sb_chinfo *ch, u_int32_t format);
|
||||
static int sb_speed(struct sb_chinfo *ch, int speed);
|
||||
static int sb_start(struct sb_chinfo *ch);
|
||||
static int sb_stop(struct sb_chinfo *ch);
|
||||
|
||||
static int ess_write(struct sb_info *sb, u_char reg, int val);
|
||||
static int ess_read(struct sb_info *sb, u_char reg);
|
||||
static void ess_intr(void *arg);
|
||||
static int ess_format(struct sb_chinfo *ch, u_int32_t format);
|
||||
static int ess_speed(struct sb_chinfo *ch, int speed);
|
||||
static int ess_start(struct sb_chinfo *ch);
|
||||
static int ess_stop(struct sb_chinfo *ch);
|
||||
static int ess_abort(struct sb_chinfo *ch);
|
||||
|
||||
static int sbmix_init(snd_mixer *m);
|
||||
static int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
|
||||
static int sbmix_setrecsrc(snd_mixer *m, u_int32_t src);
|
||||
@ -377,20 +373,19 @@ sb_release_resources(struct sb_info *sb, device_t dev)
|
||||
{
|
||||
/* should we bus_teardown_intr here? */
|
||||
if (sb->irq) {
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sb->irq_rid, sb->irq);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
|
||||
sb->irq = 0;
|
||||
}
|
||||
if (sb->drq1) {
|
||||
bus_release_resource(dev, SYS_RES_DRQ, sb->drq1_rid, sb->drq1);
|
||||
bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
|
||||
sb->drq1 = 0;
|
||||
}
|
||||
if (sb->drq2) {
|
||||
bus_release_resource(dev, SYS_RES_DRQ, sb->drq2_rid, sb->drq2);
|
||||
bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
|
||||
sb->drq2 = 0;
|
||||
}
|
||||
if (sb->io_base) {
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, sb->io_rid,
|
||||
sb->io_base);
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
|
||||
sb->io_base = 0;
|
||||
}
|
||||
free(sb, M_DEVBUF);
|
||||
@ -399,184 +394,66 @@ sb_release_resources(struct sb_info *sb, device_t dev)
|
||||
static int
|
||||
sb_alloc_resources(struct sb_info *sb, device_t dev)
|
||||
{
|
||||
int rid;
|
||||
|
||||
rid = 0;
|
||||
if (!sb->io_base)
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
rid = 0;
|
||||
if (!sb->irq)
|
||||
sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
|
||||
&sb->irq_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
rid = 0;
|
||||
if (!sb->drq1)
|
||||
sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
|
||||
&sb->drq1_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
if (!sb->drq2 && sb->drq2_rid > 0)
|
||||
rid = 1;
|
||||
if (!sb->drq2)
|
||||
sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
|
||||
&sb->drq2_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
|
||||
if (sb->io_base && sb->drq1 && sb->irq) {
|
||||
sb->dma8 = rman_get_start(sb->drq1);
|
||||
isa_dma_acquire(sb->dma8);
|
||||
isa_dmainit(sb->dma8, DSP_BUFFSIZE);
|
||||
isa_dma_acquire(rman_get_start(sb->drq1));
|
||||
isa_dmainit(rman_get_start(sb->drq1), DSP_BUFFSIZE);
|
||||
|
||||
if (sb->drq2) {
|
||||
sb->dma16 = rman_get_start(sb->drq2);
|
||||
isa_dma_acquire(sb->dma16);
|
||||
isa_dmainit(sb->dma16, DSP_BUFFSIZE);
|
||||
} else sb->dma16 = sb->dma8;
|
||||
|
||||
if (sb->dma8 > sb->dma16) {
|
||||
int tmp = sb->dma16;
|
||||
sb->dma16 = sb->dma8;
|
||||
sb->dma8 = tmp;
|
||||
isa_dma_acquire(rman_get_start(sb->drq2));
|
||||
isa_dmainit(rman_get_start(sb->drq2), DSP_BUFFSIZE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_identify_board(device_t dev, struct sb_info *sb)
|
||||
static void
|
||||
sb16_swap(void *v, int dir)
|
||||
{
|
||||
char *fmt = NULL;
|
||||
static char buf[64];
|
||||
int essver = 0;
|
||||
struct sb_info *sb = v;
|
||||
int pb = sb->pch.buffer->dl;
|
||||
int rb = sb->rch.buffer->dl;
|
||||
int pc = sb->pch.buffer->chan;
|
||||
int rc = sb->rch.buffer->chan;
|
||||
int swp = 0;
|
||||
|
||||
sb_cmd(sb, DSP_CMD_GETVER); /* Get version */
|
||||
sb->bd_id = (sb_get_byte(sb) << 8) | sb_get_byte(sb);
|
||||
if (!pb && !rb) {
|
||||
if (dir == PCMDIR_PLAY && pc < 4) swp = 1;
|
||||
else if (dir == PCMDIR_REC && rc < 4) swp = 1;
|
||||
if (sb->bd_flags & BD_F_SB16X) swp = !swp;
|
||||
if (swp) {
|
||||
int t;
|
||||
|
||||
switch (sb->bd_id >> 8) {
|
||||
case 1: /* old sound blaster has nothing... */
|
||||
case 2:
|
||||
fmt = "SoundBlaster %d.%d" ; /* default */
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fmt = "SoundBlaster Pro %d.%d";
|
||||
if (sb->bd_id == 0x301) {
|
||||
int rev;
|
||||
|
||||
/* Try to detect ESS chips. */
|
||||
sb_cmd(sb, DSP_CMD_GETID); /* Return ident. bytes. */
|
||||
essver = (sb_get_byte(sb) << 8) | sb_get_byte(sb);
|
||||
rev = essver & 0x000f;
|
||||
essver &= 0xfff0;
|
||||
if (essver == 0x4880) {
|
||||
/* the ESS488 can be treated as an SBPRO */
|
||||
fmt = "SoundBlaster Pro (ESS488 rev %d)";
|
||||
} else if (essver == 0x6880) {
|
||||
if (rev < 8) fmt = "ESS688 rev %d";
|
||||
else fmt = "ESS1868 rev %d";
|
||||
sb->bd_flags |= BD_F_ESS;
|
||||
} else return ENXIO;
|
||||
sb->bd_id &= 0xff00;
|
||||
sb->bd_id |= ((essver & 0xf000) >> 8) | rev;
|
||||
t = sb->pch.buffer->chan;
|
||||
sb->pch.buffer->chan = sb->rch.buffer->chan;
|
||||
sb->rch.buffer->chan = t;
|
||||
sb->pch.buffer->dir = B_WRITE;
|
||||
sb->rch.buffer->dir = B_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
sb->bd_flags |= BD_F_SB16;
|
||||
if (sb->bd_flags & BD_F_SB16X) fmt = "SB16 ViBRA16X %d.%d";
|
||||
else fmt = "SoundBlaster 16 %d.%d";
|
||||
break;
|
||||
|
||||
default:
|
||||
device_printf(dev, "failed to get SB version (%x)\n",
|
||||
sb->bd_id);
|
||||
return ENXIO;
|
||||
}
|
||||
if (essver) snprintf(buf, sizeof buf, fmt, sb->bd_id & 0x000f);
|
||||
else snprintf(buf, sizeof buf, fmt, sb->bd_id >> 8, sb->bd_id & 0xff);
|
||||
device_set_desc_copy(dev, buf);
|
||||
return sb_reset_dsp(sb);
|
||||
}
|
||||
|
||||
static int
|
||||
sb_init(device_t dev, struct sb_info *sb)
|
||||
{
|
||||
int x, irq;
|
||||
|
||||
sb->bd_flags &= ~BD_F_MIX_MASK;
|
||||
/* do various initializations depending on board id. */
|
||||
switch (sb->bd_id >> 8) {
|
||||
case 1: /* old sound blaster has nothing... */
|
||||
break;
|
||||
|
||||
case 2:
|
||||
sb->bd_flags |= BD_F_DUP_MIDI;
|
||||
if (sb->bd_id > 0x200) sb->bd_flags |= BD_F_MIX_CT1335;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
sb->bd_flags |= BD_F_DUP_MIDI | BD_F_MIX_CT1345;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
sb->bd_flags |= BD_F_SB16 | BD_F_MIX_CT1745;
|
||||
if (sb->dma16 != sb->dma8) sb->bd_flags |= BD_F_DUPLEX;
|
||||
|
||||
/* soft irq/dma configuration */
|
||||
x = -1;
|
||||
irq = rman_get_start(sb->irq);
|
||||
if (irq == 5) x = 2;
|
||||
else if (irq == 7) x = 4;
|
||||
else if (irq == 9) x = 1;
|
||||
else if (irq == 10) x = 8;
|
||||
if (x == -1) device_printf(dev,
|
||||
"bad irq %d (5/7/9/10 valid)\n",
|
||||
irq);
|
||||
else sb_setmixer(sb, IRQ_NR, x);
|
||||
sb_setmixer(sb, DMA_NR, (1 << sb->dma16) | (1 << sb->dma8));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_probe(device_t dev)
|
||||
{
|
||||
snddev_info *d = device_get_softc(dev);
|
||||
struct sb_info *sb;
|
||||
int allocated, i;
|
||||
int error;
|
||||
|
||||
if (isa_get_vendorid(dev)) return ENXIO; /* not yet */
|
||||
|
||||
device_set_desc(dev, "SoundBlaster");
|
||||
bzero(d, sizeof *d);
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
allocated = 0;
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &sb->io_rid,
|
||||
0, ~0, 16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
BVDDB(printf("sb_probe: no addr, trying (0x220, 0x240)\n"));
|
||||
allocated = 1;
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x220, 0x22f,
|
||||
16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x240,
|
||||
0x24f, 16, RF_ACTIVE);
|
||||
}
|
||||
}
|
||||
if (!sb->io_base) return ENXIO;
|
||||
|
||||
error = sb_reset_dsp(sb);
|
||||
if (error) goto no;
|
||||
error = sb_identify_board(dev, sb);
|
||||
if (error) goto no;
|
||||
no:
|
||||
i = sb->io_rid;
|
||||
sb_release_resources(sb, dev);
|
||||
if (allocated) bus_delete_resource(dev, SYS_RES_IOPORT, i);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@ -584,29 +461,21 @@ sb_doattach(device_t dev, struct sb_info *sb)
|
||||
{
|
||||
snddev_info *d = device_get_softc(dev);
|
||||
void *ih;
|
||||
int error;
|
||||
char status[SND_STATUSLEN];
|
||||
|
||||
sb->irq_rid = 0;
|
||||
sb->drq1_rid = 0;
|
||||
sb->drq2_rid = 1;
|
||||
if (sb_alloc_resources(sb, dev)) goto no;
|
||||
error = sb_reset_dsp(sb);
|
||||
if (error) goto no;
|
||||
error = sb_identify_board(dev, sb);
|
||||
if (error) goto no;
|
||||
|
||||
sb_init(dev, sb);
|
||||
if (sb_reset_dsp(sb)) goto no;
|
||||
mixer_init(d, &sb_mixer, sb);
|
||||
|
||||
if (sb->bd_flags & BD_F_ESS)
|
||||
bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, ess_intr, sb, &ih);
|
||||
else
|
||||
bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih);
|
||||
|
||||
if (sb->bd_flags & BD_F_SB16)
|
||||
pcm_setflags(dev, pcm_getflags(dev) | SD_F_EVILSB16);
|
||||
if (sb->dma16 == sb->dma8)
|
||||
if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X))
|
||||
pcm_setswap(dev, sb16_swap);
|
||||
if (!sb->drq2)
|
||||
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
|
||||
|
||||
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
|
||||
/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
|
||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||
@ -618,11 +487,11 @@ sb_doattach(device_t dev, struct sb_info *sb)
|
||||
goto no;
|
||||
}
|
||||
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d",
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
|
||||
rman_get_start(sb->io_base), rman_get_start(sb->irq),
|
||||
sb->dma8);
|
||||
if (sb->dma16 != sb->dma8) snprintf(status + strlen(status),
|
||||
SND_STATUSLEN - strlen(status), ":%d", sb->dma16);
|
||||
rman_get_start(sb->drq1));
|
||||
if (sb->drq2) snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
|
||||
":%ld", rman_get_start(sb->drq2));
|
||||
|
||||
if (pcm_register(dev, sb, 1, 1)) goto no;
|
||||
if (sb->bd_flags & BD_F_ESS) {
|
||||
@ -641,57 +510,6 @@ no:
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
int flags = device_get_flags(dev);
|
||||
|
||||
if (flags & DV_F_DUAL_DMA) {
|
||||
bus_set_resource(dev, SYS_RES_DRQ, 1,
|
||||
flags & DV_F_DRQ_MASK, 1);
|
||||
}
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
/* XXX in probe should set io resource to right val instead of this */
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &sb->io_rid,
|
||||
0, ~0, 16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
BVDDB(printf("sb_probe: no addr, trying (0x220, 0x240)\n"));
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x220, 0x22f,
|
||||
16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x240,
|
||||
0x24f, 16, RF_ACTIVE);
|
||||
}
|
||||
}
|
||||
if (!sb->io_base) return ENXIO;
|
||||
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
static device_method_t sb_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, sb_probe),
|
||||
DEVMETHOD(device_attach, sb_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t sb_driver = {
|
||||
"pcm",
|
||||
sb_methods,
|
||||
sizeof(snddev_info),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(sb, isa, sb_driver, pcm_devclass, 0, 0);
|
||||
|
||||
static void
|
||||
sb_intr(void *arg)
|
||||
{
|
||||
@ -829,6 +647,7 @@ sb_start(struct sb_chinfo *ch)
|
||||
int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
|
||||
int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
|
||||
int l = ch->buffer->dl;
|
||||
int dh = ch->buffer->chan > 3;
|
||||
u_char i1, i2 = 0;
|
||||
|
||||
if (b16) l >>= 1;
|
||||
@ -837,7 +656,7 @@ sb_start(struct sb_chinfo *ch)
|
||||
if (sb->bd_flags & BD_F_SB16) {
|
||||
i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON |
|
||||
(play? DSP_F16_DAC : DSP_F16_ADC);
|
||||
i1 |= (b16 && (sb->bd_flags & BD_F_DUPLEX))? DSP_DMA16 : DSP_DMA8;
|
||||
i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8;
|
||||
i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0);
|
||||
sb_cmd(sb, i1);
|
||||
sb_cmd2(sb, i2, l);
|
||||
@ -999,7 +818,8 @@ sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
|
||||
ch->buffer = b;
|
||||
ch->buffer->bufsize = DSP_BUFFSIZE;
|
||||
if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) return NULL;
|
||||
ch->buffer->chan = (dir == PCMDIR_PLAY)? sb->dma16 : sb->dma8;
|
||||
ch->buffer->chan = (dir == PCMDIR_PLAY)? rman_get_start(sb->drq2)
|
||||
: rman_get_start(sb->drq1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
@ -1053,12 +873,14 @@ sbchan_getcaps(void *data)
|
||||
{
|
||||
struct sb_chinfo *ch = data;
|
||||
int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
|
||||
if (ch->parent->bd_id <= 0x200)
|
||||
if (ch->parent->bd_id < 0x300)
|
||||
return p? &sb_playcaps : &sb_reccaps;
|
||||
else if (ch->parent->bd_id >= 0x400)
|
||||
return p? &sb16_playcaps : &sb16_reccaps;
|
||||
else
|
||||
else if (ch->parent->bd_id < 0x400)
|
||||
return p? &sbpro_playcaps : &sbpro_reccaps;
|
||||
else if (ch->parent->bd_flags & BD_F_SB16X)
|
||||
return &sb16x_caps;
|
||||
else
|
||||
return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps;
|
||||
}
|
||||
/* channel interface for ESS18xx */
|
||||
#ifdef notyet
|
||||
@ -1252,102 +1074,22 @@ sbmix_setrecsrc(snd_mixer *m, u_int32_t src)
|
||||
return src;
|
||||
}
|
||||
|
||||
static int
|
||||
sbpnp_probe(device_t dev)
|
||||
{
|
||||
char *s = NULL;
|
||||
u_int32_t logical_id = isa_get_logicalid(dev);
|
||||
|
||||
switch(logical_id) {
|
||||
case 0x01000000: /* @@@0001 */
|
||||
s = "Avance Asound 100";
|
||||
break;
|
||||
|
||||
case 0x01100000: /* @@@1001 */
|
||||
s = "Avance Asound 110";
|
||||
break;
|
||||
|
||||
case 0x01200000: /* @@@2001 */
|
||||
s = "Avance Logic ALS120";
|
||||
break;
|
||||
|
||||
case 0x68187316: /* ESS1868 */
|
||||
s = "ESS1868";
|
||||
break;
|
||||
|
||||
case 0x69187316: /* ESS1869 */
|
||||
case 0xacb0110e: /* Compaq's Presario 1621 ESS1869 */
|
||||
s = "ESS1869";
|
||||
break;
|
||||
|
||||
case 0x79187316: /* ESS1879 */
|
||||
s = "ESS1879";
|
||||
break;
|
||||
|
||||
case 0x88187316: /* ESS1888 */
|
||||
s = "ESS1888";
|
||||
break;
|
||||
}
|
||||
if (s) {
|
||||
device_set_desc(dev, s);
|
||||
return (0);
|
||||
}
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sbpnp_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
u_int32_t vend_id = isa_get_vendorid(dev);
|
||||
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
switch(vend_id) {
|
||||
case 0xf0008c0e:
|
||||
case 0x10019305:
|
||||
case 0x20019305:
|
||||
/* XXX add here the vend_id for other vibra16X cards... */
|
||||
sb->bd_flags = BD_F_SB16X;
|
||||
}
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
static device_method_t sbpnp_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, sbpnp_probe),
|
||||
DEVMETHOD(device_attach, sbpnp_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t sbpnp_driver = {
|
||||
"pcm",
|
||||
sbpnp_methods,
|
||||
sizeof(snddev_info),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(sbpnp, isa, sbpnp_driver, pcm_devclass, 0, 0);
|
||||
|
||||
#if NSBC > 0
|
||||
#define DESCSTR " PCM Audio"
|
||||
static int
|
||||
sbsbc_probe(device_t dev)
|
||||
{
|
||||
char *s = NULL;
|
||||
struct sndcard_func *func;
|
||||
char buf[64];
|
||||
u_int32_t func, ver, r;
|
||||
|
||||
/* The parent device has already been probed. */
|
||||
|
||||
func = device_get_ivars(dev);
|
||||
if (func == NULL || func->func != SCF_PCM)
|
||||
r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
|
||||
if (func != SCF_PCM)
|
||||
return (ENXIO);
|
||||
|
||||
s = "SB PCM Audio";
|
||||
r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
|
||||
ver &= 0x0000ffff;
|
||||
snprintf(buf, sizeof buf, "SB DSP %d.%02d", ver >> 8, ver & 0xff);
|
||||
device_set_desc_copy(dev, buf);
|
||||
|
||||
device_set_desc(dev, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1355,22 +1097,16 @@ static int
|
||||
sbsbc_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
u_int32_t vend_id;
|
||||
device_t sbc;
|
||||
u_int32_t ver;
|
||||
|
||||
sbc = device_get_parent(dev);
|
||||
vend_id = isa_get_vendorid(sbc);
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
switch(vend_id) {
|
||||
case 0xf0008c0e:
|
||||
case 0x10019305:
|
||||
case 0x20019305:
|
||||
/* XXX add here the vend_id for other vibra16X cards... */
|
||||
sb->bd_flags = BD_F_SB16X;
|
||||
}
|
||||
BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
|
||||
sb->bd_id = ver & 0x0000ffff;
|
||||
sb->bd_flags = (ver & 0xffff0000) >> 16;
|
||||
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
@ -1390,4 +1126,5 @@ static driver_t sbsbc_driver = {
|
||||
|
||||
DRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0);
|
||||
|
||||
#endif /* NSBC > 0 */
|
||||
|
||||
|
||||
|
@ -3,11 +3,6 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
typedef struct _sbdev_info {
|
||||
|
||||
} sbdev_info ;
|
||||
|
||||
extern int sbc_major, sbc_minor ;
|
||||
/*
|
||||
* sound blaster registers
|
||||
*/
|
||||
@ -150,6 +145,47 @@ extern int sbc_major, sbc_minor ;
|
||||
#define BD_F_DMARUN 0x2000
|
||||
#define BD_F_DMARUN2 0x4000
|
||||
#define BD_F_DUPLEX 0x8000
|
||||
|
||||
/*
|
||||
* Mixer registers of SB Pro
|
||||
*/
|
||||
#define VOC_VOL 0x04
|
||||
#define MIC_VOL 0x0A
|
||||
#define MIC_MIX 0x0A
|
||||
#define RECORD_SRC 0x0C
|
||||
#define IN_FILTER 0x0C
|
||||
#define OUT_FILTER 0x0E
|
||||
#define MASTER_VOL 0x22
|
||||
#define FM_VOL 0x26
|
||||
#define CD_VOL 0x28
|
||||
#define LINE_VOL 0x2E
|
||||
#define IRQ_NR 0x80
|
||||
#define DMA_NR 0x81
|
||||
#define IRQ_STAT 0x82
|
||||
|
||||
/*
|
||||
* Additional registers on the SG NX Pro
|
||||
*/
|
||||
#define COVOX_VOL 0x42
|
||||
#define TREBLE_LVL 0x44
|
||||
#define BASS_LVL 0x46
|
||||
|
||||
#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */
|
||||
#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */
|
||||
#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */
|
||||
#define FILT_OFF (1 << 5)
|
||||
|
||||
#define MONO_DAC 0x00
|
||||
#define STEREO_DAC 0x02
|
||||
|
||||
/*
|
||||
* Mixer registers of SB16
|
||||
*/
|
||||
#define SB16_IMASK_L 0x3d
|
||||
#define SB16_IMASK_R 0x3e
|
||||
#define SB16_OMASK 0x3c
|
||||
|
||||
#ifndef SB_NOMIXER
|
||||
/*
|
||||
* sound/sb_mixer.h
|
||||
*
|
||||
@ -210,52 +246,6 @@ extern int sbc_major, sbc_minor ;
|
||||
SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
|
||||
SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
|
||||
|
||||
/*
|
||||
* Mixer registers
|
||||
*
|
||||
* NOTE! RECORD_SRC == IN_FILTER
|
||||
*/
|
||||
|
||||
/*
|
||||
* Mixer registers of SB Pro
|
||||
*/
|
||||
#define VOC_VOL 0x04
|
||||
#define MIC_VOL 0x0A
|
||||
#define MIC_MIX 0x0A
|
||||
#define RECORD_SRC 0x0C
|
||||
#define IN_FILTER 0x0C
|
||||
#define OUT_FILTER 0x0E
|
||||
#define MASTER_VOL 0x22
|
||||
#define FM_VOL 0x26
|
||||
#define CD_VOL 0x28
|
||||
#define LINE_VOL 0x2E
|
||||
#define IRQ_NR 0x80
|
||||
#define DMA_NR 0x81
|
||||
#define IRQ_STAT 0x82
|
||||
|
||||
/*
|
||||
* Additional registers on the SG NX Pro
|
||||
*/
|
||||
#define COVOX_VOL 0x42
|
||||
#define TREBLE_LVL 0x44
|
||||
#define BASS_LVL 0x46
|
||||
|
||||
#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */
|
||||
#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */
|
||||
#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */
|
||||
#define FILT_OFF (1 << 5)
|
||||
|
||||
#define MONO_DAC 0x00
|
||||
#define STEREO_DAC 0x02
|
||||
|
||||
/*
|
||||
* Mixer registers of SB16
|
||||
*/
|
||||
#define SB16_IMASK_L 0x3d
|
||||
#define SB16_IMASK_R 0x3e
|
||||
#define SB16_OMASK 0x3c
|
||||
|
||||
|
||||
#ifndef __SB_MIXER_C__
|
||||
mixer_tab sbpro_mix;
|
||||
mixer_tab ess_mix;
|
||||
@ -379,4 +369,4 @@ static u_char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
|
||||
#define SRC_CD 3 /* Select CD recording source */
|
||||
#define SRC_LINE 7 /* Use Line-in for recording source */
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -60,6 +60,7 @@ static int esschan_setblocksize(void *data, u_int32_t blocksize);
|
||||
static int esschan_trigger(void *data, int go);
|
||||
static int esschan_getptr(void *data);
|
||||
static pcmchan_caps *esschan_getcaps(void *data);
|
||||
|
||||
static pcmchan_caps sb_playcaps = {
|
||||
4000, 22050,
|
||||
AFMT_U8,
|
||||
@ -84,18 +85,24 @@ static pcmchan_caps sbpro_reccaps = {
|
||||
AFMT_STEREO | AFMT_U8
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16_playcaps = {
|
||||
static pcmchan_caps sb16_hcaps = {
|
||||
5000, 45000,
|
||||
AFMT_STEREO | AFMT_S16_LE,
|
||||
AFMT_STEREO | AFMT_S16_LE
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16_reccaps = {
|
||||
static pcmchan_caps sb16_lcaps = {
|
||||
5000, 45000,
|
||||
AFMT_STEREO | AFMT_U8,
|
||||
AFMT_STEREO | AFMT_U8
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16x_caps = {
|
||||
5000, 49000,
|
||||
AFMT_STEREO | AFMT_U8 /* | AFMT_S16_LE */,
|
||||
AFMT_STEREO | AFMT_U8 /* AFMT_S16_LE */
|
||||
};
|
||||
|
||||
static pcmchan_caps ess_playcaps = {
|
||||
5000, 49000,
|
||||
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
|
||||
@ -144,16 +151,11 @@ struct sb_chinfo {
|
||||
|
||||
struct sb_info {
|
||||
struct resource *io_base; /* I/O address for the board */
|
||||
int io_rid;
|
||||
struct resource *irq;
|
||||
int irq_rid;
|
||||
struct resource *drq1; /* play */
|
||||
int drq1_rid;
|
||||
struct resource *drq2; /* rec */
|
||||
int drq2_rid;
|
||||
struct resource *drq1;
|
||||
struct resource *drq2;
|
||||
bus_dma_tag_t parent_dmat;
|
||||
|
||||
int dma16, dma8;
|
||||
int bd_id;
|
||||
u_long bd_flags; /* board-specific flags */
|
||||
struct sb_chinfo pch, rch;
|
||||
@ -166,31 +168,25 @@ static int sb_cmd(struct sb_info *sb, u_char val);
|
||||
static int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
|
||||
static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
|
||||
static u_int sb_get_byte(struct sb_info *sb);
|
||||
static int ess_write(struct sb_info *sb, u_char reg, int val);
|
||||
static int ess_read(struct sb_info *sb, u_char reg);
|
||||
|
||||
/*
|
||||
* in the SB, there is a set of indirect "mixer" registers with
|
||||
* address at offset 4, data at offset 5
|
||||
*/
|
||||
static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
|
||||
static int sb_getmixer(struct sb_info *sb, u_int port);
|
||||
|
||||
static void sb_intr(void *arg);
|
||||
static void ess_intr(void *arg);
|
||||
static int sb_init(device_t dev, struct sb_info *sb);
|
||||
static int sb_reset_dsp(struct sb_info *sb);
|
||||
|
||||
static void sb_intr(void *arg);
|
||||
static int sb_format(struct sb_chinfo *ch, u_int32_t format);
|
||||
static int sb_speed(struct sb_chinfo *ch, int speed);
|
||||
static int sb_start(struct sb_chinfo *ch);
|
||||
static int sb_stop(struct sb_chinfo *ch);
|
||||
|
||||
static int ess_write(struct sb_info *sb, u_char reg, int val);
|
||||
static int ess_read(struct sb_info *sb, u_char reg);
|
||||
static void ess_intr(void *arg);
|
||||
static int ess_format(struct sb_chinfo *ch, u_int32_t format);
|
||||
static int ess_speed(struct sb_chinfo *ch, int speed);
|
||||
static int ess_start(struct sb_chinfo *ch);
|
||||
static int ess_stop(struct sb_chinfo *ch);
|
||||
static int ess_abort(struct sb_chinfo *ch);
|
||||
|
||||
static int sbmix_init(snd_mixer *m);
|
||||
static int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
|
||||
static int sbmix_setrecsrc(snd_mixer *m, u_int32_t src);
|
||||
@ -377,20 +373,19 @@ sb_release_resources(struct sb_info *sb, device_t dev)
|
||||
{
|
||||
/* should we bus_teardown_intr here? */
|
||||
if (sb->irq) {
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sb->irq_rid, sb->irq);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
|
||||
sb->irq = 0;
|
||||
}
|
||||
if (sb->drq1) {
|
||||
bus_release_resource(dev, SYS_RES_DRQ, sb->drq1_rid, sb->drq1);
|
||||
bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
|
||||
sb->drq1 = 0;
|
||||
}
|
||||
if (sb->drq2) {
|
||||
bus_release_resource(dev, SYS_RES_DRQ, sb->drq2_rid, sb->drq2);
|
||||
bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
|
||||
sb->drq2 = 0;
|
||||
}
|
||||
if (sb->io_base) {
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, sb->io_rid,
|
||||
sb->io_base);
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
|
||||
sb->io_base = 0;
|
||||
}
|
||||
free(sb, M_DEVBUF);
|
||||
@ -399,184 +394,66 @@ sb_release_resources(struct sb_info *sb, device_t dev)
|
||||
static int
|
||||
sb_alloc_resources(struct sb_info *sb, device_t dev)
|
||||
{
|
||||
int rid;
|
||||
|
||||
rid = 0;
|
||||
if (!sb->io_base)
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
rid = 0;
|
||||
if (!sb->irq)
|
||||
sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
|
||||
&sb->irq_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
rid = 0;
|
||||
if (!sb->drq1)
|
||||
sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
|
||||
&sb->drq1_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
if (!sb->drq2 && sb->drq2_rid > 0)
|
||||
rid = 1;
|
||||
if (!sb->drq2)
|
||||
sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
|
||||
&sb->drq2_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
|
||||
if (sb->io_base && sb->drq1 && sb->irq) {
|
||||
sb->dma8 = rman_get_start(sb->drq1);
|
||||
isa_dma_acquire(sb->dma8);
|
||||
isa_dmainit(sb->dma8, DSP_BUFFSIZE);
|
||||
isa_dma_acquire(rman_get_start(sb->drq1));
|
||||
isa_dmainit(rman_get_start(sb->drq1), DSP_BUFFSIZE);
|
||||
|
||||
if (sb->drq2) {
|
||||
sb->dma16 = rman_get_start(sb->drq2);
|
||||
isa_dma_acquire(sb->dma16);
|
||||
isa_dmainit(sb->dma16, DSP_BUFFSIZE);
|
||||
} else sb->dma16 = sb->dma8;
|
||||
|
||||
if (sb->dma8 > sb->dma16) {
|
||||
int tmp = sb->dma16;
|
||||
sb->dma16 = sb->dma8;
|
||||
sb->dma8 = tmp;
|
||||
isa_dma_acquire(rman_get_start(sb->drq2));
|
||||
isa_dmainit(rman_get_start(sb->drq2), DSP_BUFFSIZE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_identify_board(device_t dev, struct sb_info *sb)
|
||||
static void
|
||||
sb16_swap(void *v, int dir)
|
||||
{
|
||||
char *fmt = NULL;
|
||||
static char buf[64];
|
||||
int essver = 0;
|
||||
struct sb_info *sb = v;
|
||||
int pb = sb->pch.buffer->dl;
|
||||
int rb = sb->rch.buffer->dl;
|
||||
int pc = sb->pch.buffer->chan;
|
||||
int rc = sb->rch.buffer->chan;
|
||||
int swp = 0;
|
||||
|
||||
sb_cmd(sb, DSP_CMD_GETVER); /* Get version */
|
||||
sb->bd_id = (sb_get_byte(sb) << 8) | sb_get_byte(sb);
|
||||
if (!pb && !rb) {
|
||||
if (dir == PCMDIR_PLAY && pc < 4) swp = 1;
|
||||
else if (dir == PCMDIR_REC && rc < 4) swp = 1;
|
||||
if (sb->bd_flags & BD_F_SB16X) swp = !swp;
|
||||
if (swp) {
|
||||
int t;
|
||||
|
||||
switch (sb->bd_id >> 8) {
|
||||
case 1: /* old sound blaster has nothing... */
|
||||
case 2:
|
||||
fmt = "SoundBlaster %d.%d" ; /* default */
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fmt = "SoundBlaster Pro %d.%d";
|
||||
if (sb->bd_id == 0x301) {
|
||||
int rev;
|
||||
|
||||
/* Try to detect ESS chips. */
|
||||
sb_cmd(sb, DSP_CMD_GETID); /* Return ident. bytes. */
|
||||
essver = (sb_get_byte(sb) << 8) | sb_get_byte(sb);
|
||||
rev = essver & 0x000f;
|
||||
essver &= 0xfff0;
|
||||
if (essver == 0x4880) {
|
||||
/* the ESS488 can be treated as an SBPRO */
|
||||
fmt = "SoundBlaster Pro (ESS488 rev %d)";
|
||||
} else if (essver == 0x6880) {
|
||||
if (rev < 8) fmt = "ESS688 rev %d";
|
||||
else fmt = "ESS1868 rev %d";
|
||||
sb->bd_flags |= BD_F_ESS;
|
||||
} else return ENXIO;
|
||||
sb->bd_id &= 0xff00;
|
||||
sb->bd_id |= ((essver & 0xf000) >> 8) | rev;
|
||||
t = sb->pch.buffer->chan;
|
||||
sb->pch.buffer->chan = sb->rch.buffer->chan;
|
||||
sb->rch.buffer->chan = t;
|
||||
sb->pch.buffer->dir = B_WRITE;
|
||||
sb->rch.buffer->dir = B_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
sb->bd_flags |= BD_F_SB16;
|
||||
if (sb->bd_flags & BD_F_SB16X) fmt = "SB16 ViBRA16X %d.%d";
|
||||
else fmt = "SoundBlaster 16 %d.%d";
|
||||
break;
|
||||
|
||||
default:
|
||||
device_printf(dev, "failed to get SB version (%x)\n",
|
||||
sb->bd_id);
|
||||
return ENXIO;
|
||||
}
|
||||
if (essver) snprintf(buf, sizeof buf, fmt, sb->bd_id & 0x000f);
|
||||
else snprintf(buf, sizeof buf, fmt, sb->bd_id >> 8, sb->bd_id & 0xff);
|
||||
device_set_desc_copy(dev, buf);
|
||||
return sb_reset_dsp(sb);
|
||||
}
|
||||
|
||||
static int
|
||||
sb_init(device_t dev, struct sb_info *sb)
|
||||
{
|
||||
int x, irq;
|
||||
|
||||
sb->bd_flags &= ~BD_F_MIX_MASK;
|
||||
/* do various initializations depending on board id. */
|
||||
switch (sb->bd_id >> 8) {
|
||||
case 1: /* old sound blaster has nothing... */
|
||||
break;
|
||||
|
||||
case 2:
|
||||
sb->bd_flags |= BD_F_DUP_MIDI;
|
||||
if (sb->bd_id > 0x200) sb->bd_flags |= BD_F_MIX_CT1335;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
sb->bd_flags |= BD_F_DUP_MIDI | BD_F_MIX_CT1345;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
sb->bd_flags |= BD_F_SB16 | BD_F_MIX_CT1745;
|
||||
if (sb->dma16 != sb->dma8) sb->bd_flags |= BD_F_DUPLEX;
|
||||
|
||||
/* soft irq/dma configuration */
|
||||
x = -1;
|
||||
irq = rman_get_start(sb->irq);
|
||||
if (irq == 5) x = 2;
|
||||
else if (irq == 7) x = 4;
|
||||
else if (irq == 9) x = 1;
|
||||
else if (irq == 10) x = 8;
|
||||
if (x == -1) device_printf(dev,
|
||||
"bad irq %d (5/7/9/10 valid)\n",
|
||||
irq);
|
||||
else sb_setmixer(sb, IRQ_NR, x);
|
||||
sb_setmixer(sb, DMA_NR, (1 << sb->dma16) | (1 << sb->dma8));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_probe(device_t dev)
|
||||
{
|
||||
snddev_info *d = device_get_softc(dev);
|
||||
struct sb_info *sb;
|
||||
int allocated, i;
|
||||
int error;
|
||||
|
||||
if (isa_get_vendorid(dev)) return ENXIO; /* not yet */
|
||||
|
||||
device_set_desc(dev, "SoundBlaster");
|
||||
bzero(d, sizeof *d);
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
allocated = 0;
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &sb->io_rid,
|
||||
0, ~0, 16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
BVDDB(printf("sb_probe: no addr, trying (0x220, 0x240)\n"));
|
||||
allocated = 1;
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x220, 0x22f,
|
||||
16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x240,
|
||||
0x24f, 16, RF_ACTIVE);
|
||||
}
|
||||
}
|
||||
if (!sb->io_base) return ENXIO;
|
||||
|
||||
error = sb_reset_dsp(sb);
|
||||
if (error) goto no;
|
||||
error = sb_identify_board(dev, sb);
|
||||
if (error) goto no;
|
||||
no:
|
||||
i = sb->io_rid;
|
||||
sb_release_resources(sb, dev);
|
||||
if (allocated) bus_delete_resource(dev, SYS_RES_IOPORT, i);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@ -584,29 +461,21 @@ sb_doattach(device_t dev, struct sb_info *sb)
|
||||
{
|
||||
snddev_info *d = device_get_softc(dev);
|
||||
void *ih;
|
||||
int error;
|
||||
char status[SND_STATUSLEN];
|
||||
|
||||
sb->irq_rid = 0;
|
||||
sb->drq1_rid = 0;
|
||||
sb->drq2_rid = 1;
|
||||
if (sb_alloc_resources(sb, dev)) goto no;
|
||||
error = sb_reset_dsp(sb);
|
||||
if (error) goto no;
|
||||
error = sb_identify_board(dev, sb);
|
||||
if (error) goto no;
|
||||
|
||||
sb_init(dev, sb);
|
||||
if (sb_reset_dsp(sb)) goto no;
|
||||
mixer_init(d, &sb_mixer, sb);
|
||||
|
||||
if (sb->bd_flags & BD_F_ESS)
|
||||
bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, ess_intr, sb, &ih);
|
||||
else
|
||||
bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih);
|
||||
|
||||
if (sb->bd_flags & BD_F_SB16)
|
||||
pcm_setflags(dev, pcm_getflags(dev) | SD_F_EVILSB16);
|
||||
if (sb->dma16 == sb->dma8)
|
||||
if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X))
|
||||
pcm_setswap(dev, sb16_swap);
|
||||
if (!sb->drq2)
|
||||
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
|
||||
|
||||
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
|
||||
/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
|
||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||
@ -618,11 +487,11 @@ sb_doattach(device_t dev, struct sb_info *sb)
|
||||
goto no;
|
||||
}
|
||||
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d",
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
|
||||
rman_get_start(sb->io_base), rman_get_start(sb->irq),
|
||||
sb->dma8);
|
||||
if (sb->dma16 != sb->dma8) snprintf(status + strlen(status),
|
||||
SND_STATUSLEN - strlen(status), ":%d", sb->dma16);
|
||||
rman_get_start(sb->drq1));
|
||||
if (sb->drq2) snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
|
||||
":%ld", rman_get_start(sb->drq2));
|
||||
|
||||
if (pcm_register(dev, sb, 1, 1)) goto no;
|
||||
if (sb->bd_flags & BD_F_ESS) {
|
||||
@ -641,57 +510,6 @@ no:
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
int flags = device_get_flags(dev);
|
||||
|
||||
if (flags & DV_F_DUAL_DMA) {
|
||||
bus_set_resource(dev, SYS_RES_DRQ, 1,
|
||||
flags & DV_F_DRQ_MASK, 1);
|
||||
}
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
/* XXX in probe should set io resource to right val instead of this */
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &sb->io_rid,
|
||||
0, ~0, 16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
BVDDB(printf("sb_probe: no addr, trying (0x220, 0x240)\n"));
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x220, 0x22f,
|
||||
16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x240,
|
||||
0x24f, 16, RF_ACTIVE);
|
||||
}
|
||||
}
|
||||
if (!sb->io_base) return ENXIO;
|
||||
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
static device_method_t sb_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, sb_probe),
|
||||
DEVMETHOD(device_attach, sb_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t sb_driver = {
|
||||
"pcm",
|
||||
sb_methods,
|
||||
sizeof(snddev_info),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(sb, isa, sb_driver, pcm_devclass, 0, 0);
|
||||
|
||||
static void
|
||||
sb_intr(void *arg)
|
||||
{
|
||||
@ -829,6 +647,7 @@ sb_start(struct sb_chinfo *ch)
|
||||
int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
|
||||
int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
|
||||
int l = ch->buffer->dl;
|
||||
int dh = ch->buffer->chan > 3;
|
||||
u_char i1, i2 = 0;
|
||||
|
||||
if (b16) l >>= 1;
|
||||
@ -837,7 +656,7 @@ sb_start(struct sb_chinfo *ch)
|
||||
if (sb->bd_flags & BD_F_SB16) {
|
||||
i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON |
|
||||
(play? DSP_F16_DAC : DSP_F16_ADC);
|
||||
i1 |= (b16 && (sb->bd_flags & BD_F_DUPLEX))? DSP_DMA16 : DSP_DMA8;
|
||||
i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8;
|
||||
i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0);
|
||||
sb_cmd(sb, i1);
|
||||
sb_cmd2(sb, i2, l);
|
||||
@ -999,7 +818,8 @@ sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
|
||||
ch->buffer = b;
|
||||
ch->buffer->bufsize = DSP_BUFFSIZE;
|
||||
if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) return NULL;
|
||||
ch->buffer->chan = (dir == PCMDIR_PLAY)? sb->dma16 : sb->dma8;
|
||||
ch->buffer->chan = (dir == PCMDIR_PLAY)? rman_get_start(sb->drq2)
|
||||
: rman_get_start(sb->drq1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
@ -1053,12 +873,14 @@ sbchan_getcaps(void *data)
|
||||
{
|
||||
struct sb_chinfo *ch = data;
|
||||
int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
|
||||
if (ch->parent->bd_id <= 0x200)
|
||||
if (ch->parent->bd_id < 0x300)
|
||||
return p? &sb_playcaps : &sb_reccaps;
|
||||
else if (ch->parent->bd_id >= 0x400)
|
||||
return p? &sb16_playcaps : &sb16_reccaps;
|
||||
else
|
||||
else if (ch->parent->bd_id < 0x400)
|
||||
return p? &sbpro_playcaps : &sbpro_reccaps;
|
||||
else if (ch->parent->bd_flags & BD_F_SB16X)
|
||||
return &sb16x_caps;
|
||||
else
|
||||
return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps;
|
||||
}
|
||||
/* channel interface for ESS18xx */
|
||||
#ifdef notyet
|
||||
@ -1252,102 +1074,22 @@ sbmix_setrecsrc(snd_mixer *m, u_int32_t src)
|
||||
return src;
|
||||
}
|
||||
|
||||
static int
|
||||
sbpnp_probe(device_t dev)
|
||||
{
|
||||
char *s = NULL;
|
||||
u_int32_t logical_id = isa_get_logicalid(dev);
|
||||
|
||||
switch(logical_id) {
|
||||
case 0x01000000: /* @@@0001 */
|
||||
s = "Avance Asound 100";
|
||||
break;
|
||||
|
||||
case 0x01100000: /* @@@1001 */
|
||||
s = "Avance Asound 110";
|
||||
break;
|
||||
|
||||
case 0x01200000: /* @@@2001 */
|
||||
s = "Avance Logic ALS120";
|
||||
break;
|
||||
|
||||
case 0x68187316: /* ESS1868 */
|
||||
s = "ESS1868";
|
||||
break;
|
||||
|
||||
case 0x69187316: /* ESS1869 */
|
||||
case 0xacb0110e: /* Compaq's Presario 1621 ESS1869 */
|
||||
s = "ESS1869";
|
||||
break;
|
||||
|
||||
case 0x79187316: /* ESS1879 */
|
||||
s = "ESS1879";
|
||||
break;
|
||||
|
||||
case 0x88187316: /* ESS1888 */
|
||||
s = "ESS1888";
|
||||
break;
|
||||
}
|
||||
if (s) {
|
||||
device_set_desc(dev, s);
|
||||
return (0);
|
||||
}
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sbpnp_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
u_int32_t vend_id = isa_get_vendorid(dev);
|
||||
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
switch(vend_id) {
|
||||
case 0xf0008c0e:
|
||||
case 0x10019305:
|
||||
case 0x20019305:
|
||||
/* XXX add here the vend_id for other vibra16X cards... */
|
||||
sb->bd_flags = BD_F_SB16X;
|
||||
}
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
static device_method_t sbpnp_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, sbpnp_probe),
|
||||
DEVMETHOD(device_attach, sbpnp_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t sbpnp_driver = {
|
||||
"pcm",
|
||||
sbpnp_methods,
|
||||
sizeof(snddev_info),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(sbpnp, isa, sbpnp_driver, pcm_devclass, 0, 0);
|
||||
|
||||
#if NSBC > 0
|
||||
#define DESCSTR " PCM Audio"
|
||||
static int
|
||||
sbsbc_probe(device_t dev)
|
||||
{
|
||||
char *s = NULL;
|
||||
struct sndcard_func *func;
|
||||
char buf[64];
|
||||
u_int32_t func, ver, r;
|
||||
|
||||
/* The parent device has already been probed. */
|
||||
|
||||
func = device_get_ivars(dev);
|
||||
if (func == NULL || func->func != SCF_PCM)
|
||||
r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
|
||||
if (func != SCF_PCM)
|
||||
return (ENXIO);
|
||||
|
||||
s = "SB PCM Audio";
|
||||
r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
|
||||
ver &= 0x0000ffff;
|
||||
snprintf(buf, sizeof buf, "SB DSP %d.%02d", ver >> 8, ver & 0xff);
|
||||
device_set_desc_copy(dev, buf);
|
||||
|
||||
device_set_desc(dev, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1355,22 +1097,16 @@ static int
|
||||
sbsbc_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
u_int32_t vend_id;
|
||||
device_t sbc;
|
||||
u_int32_t ver;
|
||||
|
||||
sbc = device_get_parent(dev);
|
||||
vend_id = isa_get_vendorid(sbc);
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
switch(vend_id) {
|
||||
case 0xf0008c0e:
|
||||
case 0x10019305:
|
||||
case 0x20019305:
|
||||
/* XXX add here the vend_id for other vibra16X cards... */
|
||||
sb->bd_flags = BD_F_SB16X;
|
||||
}
|
||||
BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
|
||||
sb->bd_id = ver & 0x0000ffff;
|
||||
sb->bd_flags = (ver & 0xffff0000) >> 16;
|
||||
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
@ -1390,4 +1126,5 @@ static driver_t sbsbc_driver = {
|
||||
|
||||
DRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0);
|
||||
|
||||
#endif /* NSBC > 0 */
|
||||
|
||||
|
||||
|
@ -60,6 +60,7 @@ static int esschan_setblocksize(void *data, u_int32_t blocksize);
|
||||
static int esschan_trigger(void *data, int go);
|
||||
static int esschan_getptr(void *data);
|
||||
static pcmchan_caps *esschan_getcaps(void *data);
|
||||
|
||||
static pcmchan_caps sb_playcaps = {
|
||||
4000, 22050,
|
||||
AFMT_U8,
|
||||
@ -84,18 +85,24 @@ static pcmchan_caps sbpro_reccaps = {
|
||||
AFMT_STEREO | AFMT_U8
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16_playcaps = {
|
||||
static pcmchan_caps sb16_hcaps = {
|
||||
5000, 45000,
|
||||
AFMT_STEREO | AFMT_S16_LE,
|
||||
AFMT_STEREO | AFMT_S16_LE
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16_reccaps = {
|
||||
static pcmchan_caps sb16_lcaps = {
|
||||
5000, 45000,
|
||||
AFMT_STEREO | AFMT_U8,
|
||||
AFMT_STEREO | AFMT_U8
|
||||
};
|
||||
|
||||
static pcmchan_caps sb16x_caps = {
|
||||
5000, 49000,
|
||||
AFMT_STEREO | AFMT_U8 /* | AFMT_S16_LE */,
|
||||
AFMT_STEREO | AFMT_U8 /* AFMT_S16_LE */
|
||||
};
|
||||
|
||||
static pcmchan_caps ess_playcaps = {
|
||||
5000, 49000,
|
||||
AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
|
||||
@ -144,16 +151,11 @@ struct sb_chinfo {
|
||||
|
||||
struct sb_info {
|
||||
struct resource *io_base; /* I/O address for the board */
|
||||
int io_rid;
|
||||
struct resource *irq;
|
||||
int irq_rid;
|
||||
struct resource *drq1; /* play */
|
||||
int drq1_rid;
|
||||
struct resource *drq2; /* rec */
|
||||
int drq2_rid;
|
||||
struct resource *drq1;
|
||||
struct resource *drq2;
|
||||
bus_dma_tag_t parent_dmat;
|
||||
|
||||
int dma16, dma8;
|
||||
int bd_id;
|
||||
u_long bd_flags; /* board-specific flags */
|
||||
struct sb_chinfo pch, rch;
|
||||
@ -166,31 +168,25 @@ static int sb_cmd(struct sb_info *sb, u_char val);
|
||||
static int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
|
||||
static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
|
||||
static u_int sb_get_byte(struct sb_info *sb);
|
||||
static int ess_write(struct sb_info *sb, u_char reg, int val);
|
||||
static int ess_read(struct sb_info *sb, u_char reg);
|
||||
|
||||
/*
|
||||
* in the SB, there is a set of indirect "mixer" registers with
|
||||
* address at offset 4, data at offset 5
|
||||
*/
|
||||
static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
|
||||
static int sb_getmixer(struct sb_info *sb, u_int port);
|
||||
|
||||
static void sb_intr(void *arg);
|
||||
static void ess_intr(void *arg);
|
||||
static int sb_init(device_t dev, struct sb_info *sb);
|
||||
static int sb_reset_dsp(struct sb_info *sb);
|
||||
|
||||
static void sb_intr(void *arg);
|
||||
static int sb_format(struct sb_chinfo *ch, u_int32_t format);
|
||||
static int sb_speed(struct sb_chinfo *ch, int speed);
|
||||
static int sb_start(struct sb_chinfo *ch);
|
||||
static int sb_stop(struct sb_chinfo *ch);
|
||||
|
||||
static int ess_write(struct sb_info *sb, u_char reg, int val);
|
||||
static int ess_read(struct sb_info *sb, u_char reg);
|
||||
static void ess_intr(void *arg);
|
||||
static int ess_format(struct sb_chinfo *ch, u_int32_t format);
|
||||
static int ess_speed(struct sb_chinfo *ch, int speed);
|
||||
static int ess_start(struct sb_chinfo *ch);
|
||||
static int ess_stop(struct sb_chinfo *ch);
|
||||
static int ess_abort(struct sb_chinfo *ch);
|
||||
|
||||
static int sbmix_init(snd_mixer *m);
|
||||
static int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
|
||||
static int sbmix_setrecsrc(snd_mixer *m, u_int32_t src);
|
||||
@ -377,20 +373,19 @@ sb_release_resources(struct sb_info *sb, device_t dev)
|
||||
{
|
||||
/* should we bus_teardown_intr here? */
|
||||
if (sb->irq) {
|
||||
bus_release_resource(dev, SYS_RES_IRQ, sb->irq_rid, sb->irq);
|
||||
bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
|
||||
sb->irq = 0;
|
||||
}
|
||||
if (sb->drq1) {
|
||||
bus_release_resource(dev, SYS_RES_DRQ, sb->drq1_rid, sb->drq1);
|
||||
bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
|
||||
sb->drq1 = 0;
|
||||
}
|
||||
if (sb->drq2) {
|
||||
bus_release_resource(dev, SYS_RES_DRQ, sb->drq2_rid, sb->drq2);
|
||||
bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
|
||||
sb->drq2 = 0;
|
||||
}
|
||||
if (sb->io_base) {
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, sb->io_rid,
|
||||
sb->io_base);
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
|
||||
sb->io_base = 0;
|
||||
}
|
||||
free(sb, M_DEVBUF);
|
||||
@ -399,184 +394,66 @@ sb_release_resources(struct sb_info *sb, device_t dev)
|
||||
static int
|
||||
sb_alloc_resources(struct sb_info *sb, device_t dev)
|
||||
{
|
||||
int rid;
|
||||
|
||||
rid = 0;
|
||||
if (!sb->io_base)
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
rid = 0;
|
||||
if (!sb->irq)
|
||||
sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
|
||||
&sb->irq_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
rid = 0;
|
||||
if (!sb->drq1)
|
||||
sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
|
||||
&sb->drq1_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
if (!sb->drq2 && sb->drq2_rid > 0)
|
||||
rid = 1;
|
||||
if (!sb->drq2)
|
||||
sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
|
||||
&sb->drq2_rid, 0, ~0, 1,
|
||||
&rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
|
||||
if (sb->io_base && sb->drq1 && sb->irq) {
|
||||
sb->dma8 = rman_get_start(sb->drq1);
|
||||
isa_dma_acquire(sb->dma8);
|
||||
isa_dmainit(sb->dma8, DSP_BUFFSIZE);
|
||||
isa_dma_acquire(rman_get_start(sb->drq1));
|
||||
isa_dmainit(rman_get_start(sb->drq1), DSP_BUFFSIZE);
|
||||
|
||||
if (sb->drq2) {
|
||||
sb->dma16 = rman_get_start(sb->drq2);
|
||||
isa_dma_acquire(sb->dma16);
|
||||
isa_dmainit(sb->dma16, DSP_BUFFSIZE);
|
||||
} else sb->dma16 = sb->dma8;
|
||||
|
||||
if (sb->dma8 > sb->dma16) {
|
||||
int tmp = sb->dma16;
|
||||
sb->dma16 = sb->dma8;
|
||||
sb->dma8 = tmp;
|
||||
isa_dma_acquire(rman_get_start(sb->drq2));
|
||||
isa_dmainit(rman_get_start(sb->drq2), DSP_BUFFSIZE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} else return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_identify_board(device_t dev, struct sb_info *sb)
|
||||
static void
|
||||
sb16_swap(void *v, int dir)
|
||||
{
|
||||
char *fmt = NULL;
|
||||
static char buf[64];
|
||||
int essver = 0;
|
||||
struct sb_info *sb = v;
|
||||
int pb = sb->pch.buffer->dl;
|
||||
int rb = sb->rch.buffer->dl;
|
||||
int pc = sb->pch.buffer->chan;
|
||||
int rc = sb->rch.buffer->chan;
|
||||
int swp = 0;
|
||||
|
||||
sb_cmd(sb, DSP_CMD_GETVER); /* Get version */
|
||||
sb->bd_id = (sb_get_byte(sb) << 8) | sb_get_byte(sb);
|
||||
if (!pb && !rb) {
|
||||
if (dir == PCMDIR_PLAY && pc < 4) swp = 1;
|
||||
else if (dir == PCMDIR_REC && rc < 4) swp = 1;
|
||||
if (sb->bd_flags & BD_F_SB16X) swp = !swp;
|
||||
if (swp) {
|
||||
int t;
|
||||
|
||||
switch (sb->bd_id >> 8) {
|
||||
case 1: /* old sound blaster has nothing... */
|
||||
case 2:
|
||||
fmt = "SoundBlaster %d.%d" ; /* default */
|
||||
break;
|
||||
|
||||
case 3:
|
||||
fmt = "SoundBlaster Pro %d.%d";
|
||||
if (sb->bd_id == 0x301) {
|
||||
int rev;
|
||||
|
||||
/* Try to detect ESS chips. */
|
||||
sb_cmd(sb, DSP_CMD_GETID); /* Return ident. bytes. */
|
||||
essver = (sb_get_byte(sb) << 8) | sb_get_byte(sb);
|
||||
rev = essver & 0x000f;
|
||||
essver &= 0xfff0;
|
||||
if (essver == 0x4880) {
|
||||
/* the ESS488 can be treated as an SBPRO */
|
||||
fmt = "SoundBlaster Pro (ESS488 rev %d)";
|
||||
} else if (essver == 0x6880) {
|
||||
if (rev < 8) fmt = "ESS688 rev %d";
|
||||
else fmt = "ESS1868 rev %d";
|
||||
sb->bd_flags |= BD_F_ESS;
|
||||
} else return ENXIO;
|
||||
sb->bd_id &= 0xff00;
|
||||
sb->bd_id |= ((essver & 0xf000) >> 8) | rev;
|
||||
t = sb->pch.buffer->chan;
|
||||
sb->pch.buffer->chan = sb->rch.buffer->chan;
|
||||
sb->rch.buffer->chan = t;
|
||||
sb->pch.buffer->dir = B_WRITE;
|
||||
sb->rch.buffer->dir = B_READ;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
sb->bd_flags |= BD_F_SB16;
|
||||
if (sb->bd_flags & BD_F_SB16X) fmt = "SB16 ViBRA16X %d.%d";
|
||||
else fmt = "SoundBlaster 16 %d.%d";
|
||||
break;
|
||||
|
||||
default:
|
||||
device_printf(dev, "failed to get SB version (%x)\n",
|
||||
sb->bd_id);
|
||||
return ENXIO;
|
||||
}
|
||||
if (essver) snprintf(buf, sizeof buf, fmt, sb->bd_id & 0x000f);
|
||||
else snprintf(buf, sizeof buf, fmt, sb->bd_id >> 8, sb->bd_id & 0xff);
|
||||
device_set_desc_copy(dev, buf);
|
||||
return sb_reset_dsp(sb);
|
||||
}
|
||||
|
||||
static int
|
||||
sb_init(device_t dev, struct sb_info *sb)
|
||||
{
|
||||
int x, irq;
|
||||
|
||||
sb->bd_flags &= ~BD_F_MIX_MASK;
|
||||
/* do various initializations depending on board id. */
|
||||
switch (sb->bd_id >> 8) {
|
||||
case 1: /* old sound blaster has nothing... */
|
||||
break;
|
||||
|
||||
case 2:
|
||||
sb->bd_flags |= BD_F_DUP_MIDI;
|
||||
if (sb->bd_id > 0x200) sb->bd_flags |= BD_F_MIX_CT1335;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
sb->bd_flags |= BD_F_DUP_MIDI | BD_F_MIX_CT1345;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
sb->bd_flags |= BD_F_SB16 | BD_F_MIX_CT1745;
|
||||
if (sb->dma16 != sb->dma8) sb->bd_flags |= BD_F_DUPLEX;
|
||||
|
||||
/* soft irq/dma configuration */
|
||||
x = -1;
|
||||
irq = rman_get_start(sb->irq);
|
||||
if (irq == 5) x = 2;
|
||||
else if (irq == 7) x = 4;
|
||||
else if (irq == 9) x = 1;
|
||||
else if (irq == 10) x = 8;
|
||||
if (x == -1) device_printf(dev,
|
||||
"bad irq %d (5/7/9/10 valid)\n",
|
||||
irq);
|
||||
else sb_setmixer(sb, IRQ_NR, x);
|
||||
sb_setmixer(sb, DMA_NR, (1 << sb->dma16) | (1 << sb->dma8));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_probe(device_t dev)
|
||||
{
|
||||
snddev_info *d = device_get_softc(dev);
|
||||
struct sb_info *sb;
|
||||
int allocated, i;
|
||||
int error;
|
||||
|
||||
if (isa_get_vendorid(dev)) return ENXIO; /* not yet */
|
||||
|
||||
device_set_desc(dev, "SoundBlaster");
|
||||
bzero(d, sizeof *d);
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
allocated = 0;
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &sb->io_rid,
|
||||
0, ~0, 16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
BVDDB(printf("sb_probe: no addr, trying (0x220, 0x240)\n"));
|
||||
allocated = 1;
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x220, 0x22f,
|
||||
16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x240,
|
||||
0x24f, 16, RF_ACTIVE);
|
||||
}
|
||||
}
|
||||
if (!sb->io_base) return ENXIO;
|
||||
|
||||
error = sb_reset_dsp(sb);
|
||||
if (error) goto no;
|
||||
error = sb_identify_board(dev, sb);
|
||||
if (error) goto no;
|
||||
no:
|
||||
i = sb->io_rid;
|
||||
sb_release_resources(sb, dev);
|
||||
if (allocated) bus_delete_resource(dev, SYS_RES_IOPORT, i);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@ -584,29 +461,21 @@ sb_doattach(device_t dev, struct sb_info *sb)
|
||||
{
|
||||
snddev_info *d = device_get_softc(dev);
|
||||
void *ih;
|
||||
int error;
|
||||
char status[SND_STATUSLEN];
|
||||
|
||||
sb->irq_rid = 0;
|
||||
sb->drq1_rid = 0;
|
||||
sb->drq2_rid = 1;
|
||||
if (sb_alloc_resources(sb, dev)) goto no;
|
||||
error = sb_reset_dsp(sb);
|
||||
if (error) goto no;
|
||||
error = sb_identify_board(dev, sb);
|
||||
if (error) goto no;
|
||||
|
||||
sb_init(dev, sb);
|
||||
if (sb_reset_dsp(sb)) goto no;
|
||||
mixer_init(d, &sb_mixer, sb);
|
||||
|
||||
if (sb->bd_flags & BD_F_ESS)
|
||||
bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, ess_intr, sb, &ih);
|
||||
else
|
||||
bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih);
|
||||
|
||||
if (sb->bd_flags & BD_F_SB16)
|
||||
pcm_setflags(dev, pcm_getflags(dev) | SD_F_EVILSB16);
|
||||
if (sb->dma16 == sb->dma8)
|
||||
if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X))
|
||||
pcm_setswap(dev, sb16_swap);
|
||||
if (!sb->drq2)
|
||||
pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
|
||||
|
||||
if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
|
||||
/*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
|
||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||
@ -618,11 +487,11 @@ sb_doattach(device_t dev, struct sb_info *sb)
|
||||
goto no;
|
||||
}
|
||||
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %d",
|
||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
|
||||
rman_get_start(sb->io_base), rman_get_start(sb->irq),
|
||||
sb->dma8);
|
||||
if (sb->dma16 != sb->dma8) snprintf(status + strlen(status),
|
||||
SND_STATUSLEN - strlen(status), ":%d", sb->dma16);
|
||||
rman_get_start(sb->drq1));
|
||||
if (sb->drq2) snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
|
||||
":%ld", rman_get_start(sb->drq2));
|
||||
|
||||
if (pcm_register(dev, sb, 1, 1)) goto no;
|
||||
if (sb->bd_flags & BD_F_ESS) {
|
||||
@ -641,57 +510,6 @@ no:
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
int flags = device_get_flags(dev);
|
||||
|
||||
if (flags & DV_F_DUAL_DMA) {
|
||||
bus_set_resource(dev, SYS_RES_DRQ, 1,
|
||||
flags & DV_F_DRQ_MASK, 1);
|
||||
}
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
/* XXX in probe should set io resource to right val instead of this */
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &sb->io_rid,
|
||||
0, ~0, 16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
BVDDB(printf("sb_probe: no addr, trying (0x220, 0x240)\n"));
|
||||
sb->io_rid = 0;
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x220, 0x22f,
|
||||
16, RF_ACTIVE);
|
||||
if (!sb->io_base) {
|
||||
sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&sb->io_rid, 0x240,
|
||||
0x24f, 16, RF_ACTIVE);
|
||||
}
|
||||
}
|
||||
if (!sb->io_base) return ENXIO;
|
||||
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
static device_method_t sb_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, sb_probe),
|
||||
DEVMETHOD(device_attach, sb_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t sb_driver = {
|
||||
"pcm",
|
||||
sb_methods,
|
||||
sizeof(snddev_info),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(sb, isa, sb_driver, pcm_devclass, 0, 0);
|
||||
|
||||
static void
|
||||
sb_intr(void *arg)
|
||||
{
|
||||
@ -829,6 +647,7 @@ sb_start(struct sb_chinfo *ch)
|
||||
int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
|
||||
int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
|
||||
int l = ch->buffer->dl;
|
||||
int dh = ch->buffer->chan > 3;
|
||||
u_char i1, i2 = 0;
|
||||
|
||||
if (b16) l >>= 1;
|
||||
@ -837,7 +656,7 @@ sb_start(struct sb_chinfo *ch)
|
||||
if (sb->bd_flags & BD_F_SB16) {
|
||||
i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON |
|
||||
(play? DSP_F16_DAC : DSP_F16_ADC);
|
||||
i1 |= (b16 && (sb->bd_flags & BD_F_DUPLEX))? DSP_DMA16 : DSP_DMA8;
|
||||
i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8;
|
||||
i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0);
|
||||
sb_cmd(sb, i1);
|
||||
sb_cmd2(sb, i2, l);
|
||||
@ -999,7 +818,8 @@ sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
|
||||
ch->buffer = b;
|
||||
ch->buffer->bufsize = DSP_BUFFSIZE;
|
||||
if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) return NULL;
|
||||
ch->buffer->chan = (dir == PCMDIR_PLAY)? sb->dma16 : sb->dma8;
|
||||
ch->buffer->chan = (dir == PCMDIR_PLAY)? rman_get_start(sb->drq2)
|
||||
: rman_get_start(sb->drq1);
|
||||
return ch;
|
||||
}
|
||||
|
||||
@ -1053,12 +873,14 @@ sbchan_getcaps(void *data)
|
||||
{
|
||||
struct sb_chinfo *ch = data;
|
||||
int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
|
||||
if (ch->parent->bd_id <= 0x200)
|
||||
if (ch->parent->bd_id < 0x300)
|
||||
return p? &sb_playcaps : &sb_reccaps;
|
||||
else if (ch->parent->bd_id >= 0x400)
|
||||
return p? &sb16_playcaps : &sb16_reccaps;
|
||||
else
|
||||
else if (ch->parent->bd_id < 0x400)
|
||||
return p? &sbpro_playcaps : &sbpro_reccaps;
|
||||
else if (ch->parent->bd_flags & BD_F_SB16X)
|
||||
return &sb16x_caps;
|
||||
else
|
||||
return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps;
|
||||
}
|
||||
/* channel interface for ESS18xx */
|
||||
#ifdef notyet
|
||||
@ -1252,102 +1074,22 @@ sbmix_setrecsrc(snd_mixer *m, u_int32_t src)
|
||||
return src;
|
||||
}
|
||||
|
||||
static int
|
||||
sbpnp_probe(device_t dev)
|
||||
{
|
||||
char *s = NULL;
|
||||
u_int32_t logical_id = isa_get_logicalid(dev);
|
||||
|
||||
switch(logical_id) {
|
||||
case 0x01000000: /* @@@0001 */
|
||||
s = "Avance Asound 100";
|
||||
break;
|
||||
|
||||
case 0x01100000: /* @@@1001 */
|
||||
s = "Avance Asound 110";
|
||||
break;
|
||||
|
||||
case 0x01200000: /* @@@2001 */
|
||||
s = "Avance Logic ALS120";
|
||||
break;
|
||||
|
||||
case 0x68187316: /* ESS1868 */
|
||||
s = "ESS1868";
|
||||
break;
|
||||
|
||||
case 0x69187316: /* ESS1869 */
|
||||
case 0xacb0110e: /* Compaq's Presario 1621 ESS1869 */
|
||||
s = "ESS1869";
|
||||
break;
|
||||
|
||||
case 0x79187316: /* ESS1879 */
|
||||
s = "ESS1879";
|
||||
break;
|
||||
|
||||
case 0x88187316: /* ESS1888 */
|
||||
s = "ESS1888";
|
||||
break;
|
||||
}
|
||||
if (s) {
|
||||
device_set_desc(dev, s);
|
||||
return (0);
|
||||
}
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sbpnp_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
u_int32_t vend_id = isa_get_vendorid(dev);
|
||||
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
switch(vend_id) {
|
||||
case 0xf0008c0e:
|
||||
case 0x10019305:
|
||||
case 0x20019305:
|
||||
/* XXX add here the vend_id for other vibra16X cards... */
|
||||
sb->bd_flags = BD_F_SB16X;
|
||||
}
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
static device_method_t sbpnp_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, sbpnp_probe),
|
||||
DEVMETHOD(device_attach, sbpnp_attach),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t sbpnp_driver = {
|
||||
"pcm",
|
||||
sbpnp_methods,
|
||||
sizeof(snddev_info),
|
||||
};
|
||||
|
||||
DRIVER_MODULE(sbpnp, isa, sbpnp_driver, pcm_devclass, 0, 0);
|
||||
|
||||
#if NSBC > 0
|
||||
#define DESCSTR " PCM Audio"
|
||||
static int
|
||||
sbsbc_probe(device_t dev)
|
||||
{
|
||||
char *s = NULL;
|
||||
struct sndcard_func *func;
|
||||
char buf[64];
|
||||
u_int32_t func, ver, r;
|
||||
|
||||
/* The parent device has already been probed. */
|
||||
|
||||
func = device_get_ivars(dev);
|
||||
if (func == NULL || func->func != SCF_PCM)
|
||||
r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
|
||||
if (func != SCF_PCM)
|
||||
return (ENXIO);
|
||||
|
||||
s = "SB PCM Audio";
|
||||
r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
|
||||
ver &= 0x0000ffff;
|
||||
snprintf(buf, sizeof buf, "SB DSP %d.%02d", ver >> 8, ver & 0xff);
|
||||
device_set_desc_copy(dev, buf);
|
||||
|
||||
device_set_desc(dev, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1355,22 +1097,16 @@ static int
|
||||
sbsbc_attach(device_t dev)
|
||||
{
|
||||
struct sb_info *sb;
|
||||
u_int32_t vend_id;
|
||||
device_t sbc;
|
||||
u_int32_t ver;
|
||||
|
||||
sbc = device_get_parent(dev);
|
||||
vend_id = isa_get_vendorid(sbc);
|
||||
sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
|
||||
if (!sb) return ENXIO;
|
||||
bzero(sb, sizeof *sb);
|
||||
|
||||
switch(vend_id) {
|
||||
case 0xf0008c0e:
|
||||
case 0x10019305:
|
||||
case 0x20019305:
|
||||
/* XXX add here the vend_id for other vibra16X cards... */
|
||||
sb->bd_flags = BD_F_SB16X;
|
||||
}
|
||||
BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
|
||||
sb->bd_id = ver & 0x0000ffff;
|
||||
sb->bd_flags = (ver & 0xffff0000) >> 16;
|
||||
|
||||
return sb_doattach(dev, sb);
|
||||
}
|
||||
|
||||
@ -1390,4 +1126,5 @@ static driver_t sbsbc_driver = {
|
||||
|
||||
DRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0);
|
||||
|
||||
#endif /* NSBC > 0 */
|
||||
|
||||
|
||||
|
@ -28,114 +28,298 @@
|
||||
|
||||
#include "isa.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/module.h>
|
||||
#include <machine/resource.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/soundcard.h>
|
||||
#include <dev/sound/chip.h>
|
||||
|
||||
#if NISA > 0
|
||||
#include <isa/isavar.h>
|
||||
#include <isa/isa_common.h>
|
||||
#ifdef __alpha__ /* XXX workaround a stupid warning */
|
||||
#include <alpha/isa/isavar.h>
|
||||
#endif
|
||||
#endif /* NISA > 0 */
|
||||
#include <dev/sound/pcm/sound.h>
|
||||
#define __SB_MIXER_C__ /* XXX warning... */
|
||||
#define SB_NOMIXER
|
||||
#include <dev/sound/isa/sb.h>
|
||||
|
||||
/* Here is the parameter structure per a device. */
|
||||
struct sbc_softc {
|
||||
device_t dev; /* device */
|
||||
|
||||
int io_rid[3]; /* io port rids */
|
||||
struct resource *io[3]; /* io port resources */
|
||||
int io_alloced[3]; /* io port alloc flag */
|
||||
|
||||
int irq_rid; /* irq rids */
|
||||
struct resource *irq; /* irq resources */
|
||||
int irq_alloced; /* irq alloc flag */
|
||||
|
||||
int drq_rid[2]; /* drq rids */
|
||||
struct resource *drq[2]; /* drq resources */
|
||||
int drq_alloced[2]; /* drq alloc flag */
|
||||
|
||||
u_int32_t bd_ver;
|
||||
};
|
||||
|
||||
typedef struct sbc_softc *sc_p;
|
||||
|
||||
#if NISA > 0
|
||||
static int sbc_probe(device_t dev);
|
||||
static int sbc_attach(device_t dev);
|
||||
#endif /* NISA > 0 */
|
||||
static struct resource *sbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
u_long start, u_long end, u_long count, u_int flags);
|
||||
u_long start, u_long end, u_long count, u_int flags);
|
||||
static int sbc_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *r);
|
||||
struct resource *r);
|
||||
|
||||
static int alloc_resource(sc_p scp);
|
||||
static int release_resource(sc_p scp);
|
||||
static int alloc_resource(struct sbc_softc *scp);
|
||||
static int release_resource(struct sbc_softc *scp);
|
||||
|
||||
static devclass_t sbc_devclass;
|
||||
|
||||
#if NISA > 0
|
||||
static int io_range[3] = {0x10, 0x2, 0x4};
|
||||
|
||||
static int sb_rd(struct resource *io, int reg);
|
||||
static void sb_wr(struct resource *io, int reg, u_int8_t val);
|
||||
static int sb_dspready(struct resource *io);
|
||||
static int sb_cmd(struct resource *io, u_char val);
|
||||
static u_int sb_get_byte(struct resource *io);
|
||||
static void sb_setmixer(struct resource *io, u_int port, u_int value);
|
||||
|
||||
static int
|
||||
sb_rd(struct resource *io, int reg)
|
||||
{
|
||||
return bus_space_read_1(rman_get_bustag(io),
|
||||
rman_get_bushandle(io),
|
||||
reg);
|
||||
}
|
||||
|
||||
static void
|
||||
sb_wr(struct resource *io, int reg, u_int8_t val)
|
||||
{
|
||||
return bus_space_write_1(rman_get_bustag(io),
|
||||
rman_get_bushandle(io),
|
||||
reg, val);
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dspready(struct resource *io)
|
||||
{
|
||||
return ((sb_rd(io, SBDSP_STATUS) & 0x80) == 0);
|
||||
}
|
||||
|
||||
static int
|
||||
sb_dspwr(struct resource *io, u_char val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
if (sb_dspready(io)) {
|
||||
sb_wr(io, SBDSP_CMD, val);
|
||||
return 1;
|
||||
}
|
||||
if (i > 10) DELAY((i > 100)? 1000 : 10);
|
||||
}
|
||||
printf("sb_dspwr(0x%02x) timed out.\n", val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_cmd(struct resource *io, u_char val)
|
||||
{
|
||||
return sb_dspwr(io, val);
|
||||
}
|
||||
|
||||
static void
|
||||
sb_setmixer(struct resource *io, u_int port, u_int value)
|
||||
{
|
||||
u_long flags;
|
||||
|
||||
flags = spltty();
|
||||
sb_wr(io, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
|
||||
DELAY(10);
|
||||
sb_wr(io, SB_MIX_DATA, (u_char) (value & 0xff));
|
||||
DELAY(10);
|
||||
splx(flags);
|
||||
}
|
||||
|
||||
static u_int
|
||||
sb_get_byte(struct resource *io)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1000; i > 0; i--) {
|
||||
if (sb_rd(io, DSP_DATA_AVAIL) & 0x80)
|
||||
return sb_rd(io, DSP_READ);
|
||||
else
|
||||
DELAY(20);
|
||||
}
|
||||
return 0xffff;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_reset_dsp(struct resource *io)
|
||||
{
|
||||
sb_wr(io, SBDSP_RST, 3);
|
||||
DELAY(100);
|
||||
sb_wr(io, SBDSP_RST, 0);
|
||||
return (sb_get_byte(io) == 0xAA)? 0 : ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
sb_identify_board(struct resource *io)
|
||||
{
|
||||
int ver, essver, rev;
|
||||
|
||||
sb_cmd(io, DSP_CMD_GETVER); /* Get version */
|
||||
ver = (sb_get_byte(io) << 8) | sb_get_byte(io);
|
||||
if (ver < 0x100 || ver > 0x4ff) return 0;
|
||||
if (ver == 0x0301) {
|
||||
/* Try to detect ESS chips. */
|
||||
sb_cmd(io, DSP_CMD_GETID); /* Return ident. bytes. */
|
||||
essver = (sb_get_byte(io) << 8) | sb_get_byte(io);
|
||||
rev = essver & 0x000f;
|
||||
essver &= 0xfff0;
|
||||
if (essver == 0x4880) ver |= 0x1000;
|
||||
else if (essver == 0x6880) ver = 0x0500 | rev;
|
||||
}
|
||||
return ver;
|
||||
}
|
||||
|
||||
static struct isa_pnp_id sbc_ids[] = {
|
||||
#if notdef
|
||||
{0x0000630e, "CS423x"},
|
||||
#endif
|
||||
{0x01008c0e, "Creative ViBRA16C PnP"},
|
||||
{0x41008c0e, "Creative ViBRA16CL PnP"},
|
||||
{0x43008c0e, "Creative ViBRA16X PnP"},
|
||||
{0x31008c0e, "Creative SB16 PnP/SB32"},
|
||||
{0x01008c0e, "Creative ViBRA16C"},
|
||||
{0x31008c0e, "Creative SB16/SB32"},
|
||||
{0x41008c0e, "Creative SB16/SB32"},
|
||||
{0x42008c0e, "Creative SB AWE64"}, /* CTL00c1 */
|
||||
{0x43008c0e, "Creative ViBRA16X"},
|
||||
{0x44008c0e, "Creative SB AWE64 Gold"},
|
||||
{0x45008c0e, "Creative SB AWE64"}, /* CTL0045 */
|
||||
#if notdef
|
||||
{0x01200001, "Avance Logic ALS120"},
|
||||
|
||||
{0x01000000, "Avance Asound 100"},
|
||||
{0x01100001, "Avance Asound 110"},
|
||||
{0x68187316, "ESS ES1868 Plug and Play AudioDrive"}, /* ESS1868 */
|
||||
{0x79187316, "ESS ES1879 Plug and Play AudioDrive"}, /* ESS1879 */
|
||||
{0x2100a865, "Yamaha OPL3-SA2/SAX Sound Board"},
|
||||
{0x80719304, "Terratec Soundsystem Base 1"},
|
||||
#endif
|
||||
{0x01200001, "Avance Logic ALS120"},
|
||||
|
||||
{0x68187316, "ESS ES1868"}, /* ESS1868 */
|
||||
{0x69187316, "ESS ES1869"}, /* ESS1869 */
|
||||
{0xacb0110e, "ESS ES1869 (Compaq OEM)"},
|
||||
{0x79187316, "ESS ES1879"}, /* ESS1879 */
|
||||
{0x88187316, "ESS ES1888"}, /* ESS1888 */
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
static int
|
||||
sbc_probe(device_t dev)
|
||||
{
|
||||
int error;
|
||||
char *s = NULL;
|
||||
u_int32_t logical_id = isa_get_logicalid(dev);
|
||||
if (logical_id) {
|
||||
/* Check pnp ids */
|
||||
return ISA_PNP_PROBE(device_get_parent(dev), dev, sbc_ids);
|
||||
} else {
|
||||
int rid = 0, ver;
|
||||
struct resource *io;
|
||||
|
||||
/* Check pnp ids */
|
||||
error = ISA_PNP_PROBE(device_get_parent(dev), dev, sbc_ids);
|
||||
if (error)
|
||||
return error;
|
||||
else
|
||||
return -100;
|
||||
io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
|
||||
0, ~0, 16, RF_ACTIVE);
|
||||
if (!io) goto bad;
|
||||
if (sb_reset_dsp(io)) goto bad2;
|
||||
ver = sb_identify_board(io);
|
||||
if (ver == 0) goto bad2;
|
||||
switch ((ver & 0x00000f00) >> 8) {
|
||||
case 1:
|
||||
case 2:
|
||||
s = "Soundblaster";
|
||||
break;
|
||||
|
||||
case 3:
|
||||
s = (ver & 0x0000f000)? "ESS 488" : "Soundblaster Pro";
|
||||
break;
|
||||
|
||||
case 4:
|
||||
s = "Soundblaster 16";
|
||||
break;
|
||||
|
||||
case 5:
|
||||
s = (ver & 0x00000008)? "ESS 688" : "ESS 1688";
|
||||
break;
|
||||
}
|
||||
if (s) device_set_desc(dev, s);
|
||||
bad2: bus_release_resource(dev, SYS_RES_IOPORT, rid, io);
|
||||
bad: return s? 0 : ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
sbc_attach(device_t dev)
|
||||
{
|
||||
sc_p scp;
|
||||
device_t child;
|
||||
int unit;
|
||||
struct sbc_softc *scp;
|
||||
struct sndcard_func *func;
|
||||
device_t child;
|
||||
u_int32_t logical_id = isa_get_logicalid(dev);
|
||||
int flags = device_get_flags(dev);
|
||||
int f = 0, dh = -1, dl = -1;
|
||||
|
||||
if (!logical_id && (flags & DV_F_DUAL_DMA)) {
|
||||
bus_set_resource(dev, SYS_RES_DRQ, 1,
|
||||
flags & DV_F_DRQ_MASK, 1);
|
||||
}
|
||||
|
||||
scp = device_get_softc(dev);
|
||||
unit = device_get_unit(dev);
|
||||
|
||||
bzero(scp, sizeof(*scp));
|
||||
|
||||
scp->dev = dev;
|
||||
if (alloc_resource(scp)) {
|
||||
release_resource(scp);
|
||||
return (ENXIO);
|
||||
if (alloc_resource(scp)) goto bad;
|
||||
|
||||
if (sb_reset_dsp(scp->io[0])) goto bad;
|
||||
scp->bd_ver = sb_identify_board(scp->io[0]) & 0x00000fff;
|
||||
if (scp->bd_ver == 0) goto bad;
|
||||
switch ((scp->bd_ver & 0x0f00) >> 8) {
|
||||
case 1: /* old sound blaster has nothing... */
|
||||
break;
|
||||
|
||||
case 2:
|
||||
f |= BD_F_DUP_MIDI;
|
||||
if (scp->bd_ver > 0x200) f |= BD_F_MIX_CT1335;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
f |= BD_F_ESS;
|
||||
scp->bd_ver = 0x0301;
|
||||
case 3:
|
||||
f |= BD_F_DUP_MIDI | BD_F_MIX_CT1345;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
f |= BD_F_SB16 | BD_F_MIX_CT1745;
|
||||
if (scp->drq[0]) dl = rman_get_start(scp->drq[0]);
|
||||
if (scp->drq[1]) dh = rman_get_start(scp->drq[1]); else dh = dl;
|
||||
if (dh != dl) f |= BD_F_DUPLEX;
|
||||
if (dh < dl) {
|
||||
struct resource *r;
|
||||
r = scp->drq[0];
|
||||
scp->drq[0] = scp->drq[1];
|
||||
scp->drq[1] = r;
|
||||
dl = rman_get_start(scp->drq[0]);
|
||||
dh = rman_get_start(scp->drq[1]);
|
||||
}
|
||||
if (!logical_id) {
|
||||
/* soft irq/dma configuration */
|
||||
int x = -1, irq = rman_get_start(scp->irq);
|
||||
if (irq == 5) x = 2;
|
||||
else if (irq == 7) x = 4;
|
||||
else if (irq == 9) x = 1;
|
||||
else if (irq == 10) x = 8;
|
||||
if (x == -1) device_printf(dev,
|
||||
"bad irq %d (5/7/9/10 valid)\n",
|
||||
irq);
|
||||
else sb_setmixer(scp->io[0], IRQ_NR, x);
|
||||
sb_setmixer(scp->io[0], DMA_NR, (1 << dh) | (1 << dl));
|
||||
device_printf(dev, "setting non-pnp card to irq %d, drq %d", irq, dl);
|
||||
if (dl != dh) printf(", %d", dh);
|
||||
printf("\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (logical_id) {
|
||||
case 0x01008c0e: /* CTL0001 */
|
||||
case 0x43008c0e: /* CTL0043 */
|
||||
f |= BD_F_SB16X;
|
||||
break;
|
||||
}
|
||||
scp->bd_ver |= f << 16;
|
||||
|
||||
/* PCM Audio */
|
||||
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
|
||||
if (func == NULL)
|
||||
return (ENOMEM);
|
||||
if (func == NULL) goto bad;
|
||||
bzero(func, sizeof(*func));
|
||||
func->func = SCF_PCM;
|
||||
child = device_add_child(dev, "pcm", -1);
|
||||
@ -144,8 +328,7 @@ sbc_attach(device_t dev)
|
||||
#if notyet
|
||||
/* Midi Interface */
|
||||
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
|
||||
if (func == NULL)
|
||||
return (ENOMEM);
|
||||
if (func == NULL) goto bad;
|
||||
bzero(func, sizeof(*func));
|
||||
func->func = SCF_MIDI;
|
||||
child = device_add_child(dev, "midi", -1);
|
||||
@ -153,25 +336,27 @@ sbc_attach(device_t dev)
|
||||
|
||||
/* OPL FM Synthesizer */
|
||||
func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT);
|
||||
if (func == NULL)
|
||||
return (ENOMEM);
|
||||
if (func == NULL) goto bad;
|
||||
bzero(func, sizeof(*func));
|
||||
func->func = SCF_SYNTH;
|
||||
child = device_add_child(dev, "midi", -1);
|
||||
device_set_ivars(child, func);
|
||||
#endif /* notyet */
|
||||
|
||||
/* probe/attach kids */
|
||||
bus_generic_attach(dev);
|
||||
|
||||
return (0);
|
||||
|
||||
bad: release_resource(scp);
|
||||
return (ENXIO);
|
||||
}
|
||||
#endif /* NISA > 0 */
|
||||
|
||||
static struct resource *
|
||||
sbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
u_long start, u_long end, u_long count, u_int flags)
|
||||
{
|
||||
sc_p scp;
|
||||
struct sbc_softc *scp;
|
||||
int *alloced, rid_max, alloced_max;
|
||||
struct resource **res;
|
||||
|
||||
@ -183,18 +368,18 @@ sbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
rid_max = 2;
|
||||
alloced_max = 1;
|
||||
break;
|
||||
case SYS_RES_IRQ:
|
||||
alloced = &scp->irq_alloced;
|
||||
res = &scp->irq;
|
||||
rid_max = 0;
|
||||
alloced_max = 2; /* pcm and mpu may share the irq. */
|
||||
break;
|
||||
case SYS_RES_DRQ:
|
||||
alloced = scp->drq_alloced;
|
||||
res = scp->drq;
|
||||
rid_max = 1;
|
||||
alloced_max = 1;
|
||||
break;
|
||||
case SYS_RES_IRQ:
|
||||
alloced = &scp->irq_alloced;
|
||||
res = &scp->irq;
|
||||
rid_max = 0;
|
||||
alloced_max = 2; /* pcm and mpu may share the irq. */
|
||||
break;
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
@ -203,14 +388,14 @@ sbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
return (NULL);
|
||||
|
||||
alloced[*rid]++;
|
||||
return (res[*rid]);
|
||||
return (res[*rid]);
|
||||
}
|
||||
|
||||
static int
|
||||
sbc_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
struct resource *r)
|
||||
{
|
||||
sc_p scp;
|
||||
struct sbc_softc *scp;
|
||||
int *alloced, rid_max;
|
||||
|
||||
scp = device_get_softc(bus);
|
||||
@ -219,14 +404,14 @@ sbc_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
alloced = scp->io_alloced;
|
||||
rid_max = 2;
|
||||
break;
|
||||
case SYS_RES_IRQ:
|
||||
alloced = &scp->irq_alloced;
|
||||
rid_max = 0;
|
||||
break;
|
||||
case SYS_RES_DRQ:
|
||||
alloced = scp->drq_alloced;
|
||||
rid_max = 1;
|
||||
break;
|
||||
case SYS_RES_IRQ:
|
||||
alloced = &scp->irq_alloced;
|
||||
rid_max = 0;
|
||||
break;
|
||||
default:
|
||||
return (1);
|
||||
}
|
||||
@ -238,9 +423,44 @@ sbc_release_resource(device_t bus, device_t child, int type, int rid,
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int io_range[3] = {0x10, 0x4, 0x4};
|
||||
static int
|
||||
alloc_resource(sc_p scp)
|
||||
sbc_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result)
|
||||
{
|
||||
struct sbc_softc *scp = device_get_softc(bus);
|
||||
struct sndcard_func *func = device_get_ivars(dev);
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
*result = func->func;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
*result = scp->bd_ver;
|
||||
break;
|
||||
|
||||
default:
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
sbc_write_ivar(device_t bus, device_t dev,
|
||||
int index, uintptr_t value)
|
||||
{
|
||||
switch (index) {
|
||||
case 0:
|
||||
case 1:
|
||||
return EINVAL;
|
||||
|
||||
default:
|
||||
return (ENOENT);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
alloc_resource(struct sbc_softc *scp)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -249,34 +469,34 @@ alloc_resource(sc_p scp)
|
||||
scp->io_rid[i] = i;
|
||||
scp->io[i] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[i],
|
||||
0, ~0, io_range[i], RF_ACTIVE);
|
||||
if (scp->io[i] == NULL)
|
||||
if (i == 0 && scp->io[i] == NULL)
|
||||
return (1);
|
||||
scp->io_alloced[i] = 0;
|
||||
}
|
||||
}
|
||||
if (scp->irq == NULL) {
|
||||
scp->irq_rid = 0;
|
||||
scp->irq = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid,
|
||||
0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
|
||||
if (scp->irq == NULL)
|
||||
return (1);
|
||||
scp->irq_alloced = 0;
|
||||
}
|
||||
for (i = 0 ; i < sizeof(scp->drq) / sizeof(*scp->drq) ; i++) {
|
||||
if (scp->drq[i] == NULL) {
|
||||
scp->drq_rid[i] = i;
|
||||
scp->drq[i] = bus_alloc_resource(scp->dev, SYS_RES_DRQ, &scp->drq_rid[i],
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (scp->drq[i] == NULL)
|
||||
if (i == 0 && scp->drq[i] == NULL)
|
||||
return (1);
|
||||
scp->drq_alloced[i] = 0;
|
||||
}
|
||||
}
|
||||
if (scp->irq == NULL) {
|
||||
scp->irq_rid = 0;
|
||||
scp->irq = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid,
|
||||
0, ~0, 1, RF_ACTIVE);
|
||||
if (scp->irq == NULL)
|
||||
return (1);
|
||||
scp->irq_alloced = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
release_resource(sc_p scp)
|
||||
release_resource(struct sbc_softc *scp)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -299,7 +519,6 @@ release_resource(sc_p scp)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if NISA > 0
|
||||
static device_method_t sbc_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, sbc_probe),
|
||||
@ -310,6 +529,8 @@ static device_method_t sbc_methods[] = {
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* Bus interface */
|
||||
DEVMETHOD(bus_read_ivar, sbc_read_ivar),
|
||||
DEVMETHOD(bus_write_ivar, sbc_write_ivar),
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
DEVMETHOD(bus_alloc_resource, sbc_alloc_resource),
|
||||
DEVMETHOD(bus_release_resource, sbc_release_resource),
|
||||
@ -327,8 +548,6 @@ static driver_t sbc_driver = {
|
||||
sizeof(struct sbc_softc),
|
||||
};
|
||||
|
||||
/*
|
||||
* sbc can be attached to an isa bus.
|
||||
*/
|
||||
/* sbc can be attached to an isa bus. */
|
||||
DRIVER_MODULE(sbc, isa, sbc_driver, sbc_devclass, 0, 0);
|
||||
#endif /* NISA > 0 */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user