diff options
author | cg <cg@FreeBSD.org> | 1999-12-12 02:30:19 +0000 |
---|---|---|
committer | cg <cg@FreeBSD.org> | 1999-12-12 02:30:19 +0000 |
commit | 99bed6d33e4b265f59b3246349fd4bc5b9d7f290 (patch) | |
tree | 2de4c3742d0aa34feb9901bda05065133d6ded33 /sys/dev/sound | |
parent | 7c2cd0059f46396427902ef62f11257e86fee985 (diff) | |
download | FreeBSD-src-99bed6d33e4b265f59b3246349fd4bc5b9d7f290.zip FreeBSD-src-99bed6d33e4b265f59b3246349fd4bc5b9d7f290.tar.gz |
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
Diffstat (limited to 'sys/dev/sound')
-rw-r--r-- | sys/dev/sound/isa/sb.c | 449 | ||||
-rw-r--r-- | sys/dev/sound/isa/sb.h | 94 | ||||
-rw-r--r-- | sys/dev/sound/isa/sb16.c | 449 | ||||
-rw-r--r-- | sys/dev/sound/isa/sb8.c | 449 | ||||
-rw-r--r-- | sys/dev/sound/isa/sbc.c | 411 |
5 files changed, 636 insertions, 1216 deletions
diff --git a/sys/dev/sound/isa/sb.c b/sys/dev/sound/isa/sb.c index 6aba674..ef55248 100644 --- a/sys/dev/sound/isa/sb.c +++ b/sys/dev/sound/isa/sb.c @@ -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) -{ - char *fmt = NULL; - static char buf[64]; - int essver = 0; - - sb_cmd(sb, DSP_CMD_GETVER); /* Get version */ - sb->bd_id = (sb_get_byte(sb) << 8) | sb_get_byte(sb); - - 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; - } - 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) +static void +sb16_swap(void *v, int dir) { - 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); + 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; + + 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; + + 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; } - } - 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 @@ -1253,101 +1075,21 @@ sbmix_setrecsrc(snd_mixer *m, u_int32_t 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 */ + + diff --git a/sys/dev/sound/isa/sb.h b/sys/dev/sound/isa/sb.h index 110eda0..0bb3496 100644 --- a/sys/dev/sound/isa/sb.h +++ b/sys/dev/sound/isa/sb.h @@ -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 diff --git a/sys/dev/sound/isa/sb16.c b/sys/dev/sound/isa/sb16.c index 6aba674..ef55248 100644 --- a/sys/dev/sound/isa/sb16.c +++ b/sys/dev/sound/isa/sb16.c @@ -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) -{ - char *fmt = NULL; - static char buf[64]; - int essver = 0; - - sb_cmd(sb, DSP_CMD_GETVER); /* Get version */ - sb->bd_id = (sb_get_byte(sb) << 8) | sb_get_byte(sb); - - 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; - } - 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) +static void +sb16_swap(void *v, int dir) { - 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); + 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; + + 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; + + 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; } - } - 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 @@ -1253,101 +1075,21 @@ sbmix_setrecsrc(snd_mixer *m, u_int32_t 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 */ + + diff --git a/sys/dev/sound/isa/sb8.c b/sys/dev/sound/isa/sb8.c index 6aba674..ef55248 100644 --- a/sys/dev/sound/isa/sb8.c +++ b/sys/dev/sound/isa/sb8.c @@ -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) -{ - char *fmt = NULL; - static char buf[64]; - int essver = 0; - - sb_cmd(sb, DSP_CMD_GETVER); /* Get version */ - sb->bd_id = (sb_get_byte(sb) << 8) | sb_get_byte(sb); - - 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; - } - 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) +static void +sb16_swap(void *v, int dir) { - 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); + 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; + + 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; + + 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; } - } - 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 @@ -1253,101 +1075,21 @@ sbmix_setrecsrc(snd_mixer *m, u_int32_t 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 */ + + diff --git a/sys/dev/sound/isa/sbc.c b/sys/dev/sound/isa/sbc.c index 67a367c..01d6c6b 100644 --- a/sys/dev/sound/isa/sbc.c +++ b/sys/dev/sound/isa/sbc.c @@ -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 */ -}; -typedef struct sbc_softc *sc_p; + u_int32_t bd_ver; +}; -#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; - - /* Check pnp ids */ - error = ISA_PNP_PROBE(device_get_parent(dev), dev, sbc_ids); - if (error) - return error; - else - return -100; + 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; + + 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; - scp = device_get_softc(dev); - unit = device_get_unit(dev); + 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); 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 */ + |