Date: 16 Feb 2002 18:45:02 -0000 From: Mike Meyer <mwm@mired.org> To: FreeBSD-gnats-submit@freebsd.org Subject: kern/35012: [PATCH] SiS 7012 in the SiS 735 chips isn't supported. Message-ID: <20020216184502.7514.qmail@guru.mired.org>
next in thread | raw e-mail | index | archive | help
>Number: 35012 >Category: kern >Synopsis: [PATCH] SiS 7012 in the SiS 735 chips isn't supported. >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sat Feb 16 14:00:03 PST 2002 >Closed-Date: >Last-Modified: >Originator: Mike Meyer >Release: FreeBSD 4.5-STABLE i386 >Organization: Meyer Consulting >Environment: System: FreeBSD guru.mired.org 4.5-STABLE FreeBSD 4.5-STABLE #15: Sat Feb 16 00:40:53 CST 2002 mwm@guru.mired.org:/usr/src/sys/compile/GURU i386 Includes patches for both -current and -stable as of that date. >Description: The onboard sound on motherboards using the SiS 735 chipset - and possibly the 745 as well - is not recognized by the FreeBSD pcm drivers. >How-To-Repeat: Purchase such a board (they're cheap, and work well), enable the onboard sound and pcm in the kernel, then note that you don't have any pcm drivers after you boot. >Fix: The following patches to the ich driver cause it to recognize the SiS 7012, allow the user to manipulate the mixer, and play pcm back through it. Recording works, but apparently the hardware doesn't support variable rate recording, so it's not suitable for serious use. Patches for -current: --- ich.c-current Fri Feb 15 16:07:46 2002 +++ ich.c Sat Feb 16 12:31:26 2002 @@ -41,6 +40,8 @@ #define ICH_DEFAULT_BUFSZ 16384 #define ICH_MAX_BUFSZ 65536 +#define SIS7012ID 0x70121039 /* SiS 7012 needs special handling */ + /* buffer descriptor */ struct ich_desc { volatile u_int32_t buffer; @@ -69,6 +70,7 @@ device_t dev; int hasvra, hasvrm, hasmic; unsigned int chnum, bufsz; + int sample_size, swap_reg; struct resource *nambar, *nabmbar, *irq; int nambarid, nabmbarid, irqid; @@ -191,7 +193,8 @@ for (i = 0; i < ICH_DTBL_LENGTH; i++) { ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt)); - ch->dtbl[i].length = ICH_BDC_IOC | (ch->blksz / 2); + ch->dtbl[i].length = ICH_BDC_IOC + | (ch->blksz / ch->parent->sample_size); } } @@ -392,7 +395,9 @@ if ((ch->imask & gs) == 0) continue; gs &= ~ch->imask; - st = ich_rd(sc, ch->regbase + ICH_REG_X_SR, 2); + st = ich_rd(sc, ch->regbase + + (sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR), + 2); st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI; if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) { /* block complete - update buffer */ @@ -414,7 +419,9 @@ } /* clear status bit */ - ich_wr(sc, ch->regbase + ICH_REG_X_SR, st, 2); + ich_wr(sc, ch->regbase + + (sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR), + st, 2); } if (gs != 0) { device_printf(sc->dev, @@ -589,6 +597,10 @@ device_set_desc(dev, "Intel 82801CA (ICH3)"); return 0; + case SIS7012ID: + device_set_desc(dev, "SiS 7012"); + return 0; + default: return ENXIO; } @@ -610,6 +622,18 @@ bzero(sc, sizeof(*sc)); sc->dev = dev; + /* + * The SiS 7012 register set isn't quite like the standard ich. + * There really should be a general "quirks" mechanism. + */ + if (pci_get_devid(dev) == SIS7012ID) { + sc->swap_reg = 1; + sc->sample_size = 1; + } else { + sc->swap_reg = 0; + sc->sample_size = 2; + } + data = pci_read_config(dev, PCIR_COMMAND, 2); data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); pci_write_config(dev, PCIR_COMMAND, data, 2); Patches for -stable. This includes some changes from -current. Part of them are required to get recording to work at all - even on ich hardware - and the rest came along as well. A separate request has been made to MFC these changes, after which the patches to -current above should work on -stable. --- ich.c-stable Wed Feb 13 23:27:48 2002 +++ ich.c Sat Feb 16 12:31:26 2002 @@ -34,11 +32,15 @@ #include <pci/pcireg.h> #include <pci/pcivar.h> + /* -------------------------------------------------------------------- */ #define ICH_TIMEOUT 1000 /* semaphore timeout polling count */ #define ICH_DTBL_LENGTH 32 #define ICH_DEFAULT_BUFSZ 16384 +#define ICH_MAX_BUFSZ 65536 + +#define SIS7012ID 0x70121039 /* SiS 7012 needs special handling */ /* buffer descriptor */ struct ich_desc { @@ -50,8 +52,8 @@ /* channel registers */ struct sc_chinfo { - u_int32_t num, run; - u_int32_t blksz, blkcnt; + u_int32_t num:8, run:1, run_save:1; + u_int32_t blksz, blkcnt, spd; u_int32_t regbase, spdreg; u_int32_t imask; u_int32_t civ; @@ -66,8 +68,9 @@ /* device private data */ struct sc_info { device_t dev; - int hasvra, hasvrm; - int chnum; + int hasvra, hasvrm, hasmic; + unsigned int chnum, bufsz; + int sample_size, swap_reg; struct resource *nambar, *nabmbar, *irq; int nambarid, nabmbarid, irqid; @@ -190,7 +193,8 @@ for (i = 0; i < ICH_DTBL_LENGTH; i++) { ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt)); - ch->dtbl[i].length = ICH_BDC_IOC | (ch->blksz / 2); + ch->dtbl[i].length = ICH_BDC_IOC + | (ch->blksz / ch->parent->sample_size); } } @@ -229,7 +233,7 @@ { struct sc_info *sc = devinfo; struct sc_chinfo *ch; - int num; + unsigned int num; num = sc->chnum++; ch = &sc->ch[num]; @@ -240,7 +244,7 @@ ch->run = 0; ch->dtbl = sc->dtbl + (ch->num * ICH_DTBL_LENGTH); ch->blkcnt = 2; - ch->blksz = ICH_DEFAULT_BUFSZ / ch->blkcnt; + ch->blksz = sc->bufsz / ch->blkcnt; switch(ch->num) { case 0: /* play */ @@ -268,7 +272,7 @@ return NULL; } - if (sndbuf_alloc(ch->buffer, sc->dmat, ICH_DEFAULT_BUFSZ)) + if (sndbuf_alloc(ch->buffer, sc->dmat, sc->bufsz)) return NULL; ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4); @@ -292,12 +296,12 @@ int r; if (sc->ac97rate <= 32000 || sc->ac97rate >= 64000) sc->ac97rate = 48000; - r = speed * 48000 / sc->ac97rate; - return ac97_setrate(sc->codec, ch->spdreg, r) * - sc->ac97rate / 48000; + r = (speed * 48000) / sc->ac97rate; + ch->spd = (ac97_setrate(sc->codec, ch->spdreg, r) * sc->ac97rate) / 48000; } else { - return 48000; + ch->spd = 48000; } + return ch->spd; } static int @@ -323,7 +327,7 @@ case PCMTRIG_START: ch->run = 1; ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)vtophys(ch->dtbl), 4); - ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE | ICH_X_CR_FEIE, 1); + ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE, 1); break; case PCMTRIG_ABORT: @@ -391,7 +395,9 @@ if ((ch->imask & gs) == 0) continue; gs &= ~ch->imask; - st = ich_rd(sc, ch->regbase + ICH_REG_X_SR, 2); + st = ich_rd(sc, ch->regbase + + (sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR), + 2); st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI; if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) { /* block complete - update buffer */ @@ -413,7 +419,9 @@ } /* clear status bit */ - ich_wr(sc, ch->regbase + ICH_REG_X_SR, st, 2); + ich_wr(sc, ch->regbase + + (sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR), + st, 2); } if (gs != 0) { device_printf(sc->dev, @@ -520,6 +528,7 @@ printf(", will use %d Hz", sc->ac97rate); printf("\n"); } + return sc->ac97rate; } @@ -547,7 +556,9 @@ ich_wr(sc, ICH_REG_GLOB_CNT, ICH_GLOB_CTL_COLD | ICH_GLOB_CTL_PRES, 4); - if (ich_resetchan(sc, 0) || ich_resetchan(sc, 1) || ich_resetchan(sc, 2)) + if (ich_resetchan(sc, 0) || ich_resetchan(sc, 1)) + return ENXIO; + if (sc->hasmic && ich_resetchan(sc, 2)) return ENXIO; if (bus_dmamem_alloc(sc->dmat, (void **)&sc->dtbl, BUS_DMA_NOWAIT, &sc->dtmap)) @@ -586,6 +597,10 @@ device_set_desc(dev, "Intel 82801CA (ICH3)"); return 0; + case SIS7012ID: + device_set_desc(dev, "SiS 7012"); + return 0; + default: return ENXIO; } @@ -607,6 +622,18 @@ bzero(sc, sizeof(*sc)); sc->dev = dev; + /* + * The SiS 7012 register set isn't quite like the standard ich. + * There really should be a general "quirks" mechanism. + */ + if (pci_get_devid(dev) == SIS7012ID) { + sc->swap_reg = 1; + sc->sample_size = 1; + } else { + sc->swap_reg = 0; + sc->sample_size = 2; + } + data = pci_read_config(dev, PCIR_COMMAND, 2); data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); pci_write_config(dev, PCIR_COMMAND, data, 2); @@ -627,8 +654,9 @@ sc->nabmbart = rman_get_bustag(sc->nabmbar); sc->nabmbarh = rman_get_bushandle(sc->nabmbar); + sc->bufsz = ICH_DEFAULT_BUFSZ; if (bus_dma_tag_create(NULL, 8, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, - NULL, NULL, ICH_DEFAULT_BUFSZ, 1, 0x3ffff, 0, &sc->dmat) != 0) { + NULL, NULL, sc->bufsz, 1, 0x3ffff, 0, &sc->dmat) != 0) { device_printf(dev, "unable to create dma tag\n"); goto bad; } @@ -652,19 +680,22 @@ /* check and set VRA function */ extcaps = ac97_getextcaps(sc->codec); + sc->hasvra = extcaps & AC97_EXTCAP_VRA; sc->hasvrm = extcaps & AC97_EXTCAP_VRM; - ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm); + sc->hasmic = extcaps & 1; + ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm | sc->hasmic); - if (pcm_register(dev, sc, 1, 2)) + if (pcm_register(dev, sc, 1, sc->hasmic? 2 : 1)) goto bad; - pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc); - pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc); - pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc); + pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc); /* play */ + pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc); /* record */ + if (sc->hasmic) + pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc); /* record mic */ - snprintf(status, SND_STATUSLEN, "at io 0x%lx, 0x%lx irq %ld", - rman_get_start(sc->nambar), rman_get_start(sc->nabmbar), rman_get_start(sc->irq)); + snprintf(status, SND_STATUSLEN, "at io 0x%lx, 0x%lx irq %ld bufsz %u", + rman_get_start(sc->nambar), rman_get_start(sc->nabmbar), rman_get_start(sc->irq), sc->bufsz); pcm_setstatus(dev, status); @@ -676,16 +707,16 @@ bad: if (sc->codec) ac97_destroy(sc->codec); + if (sc->ih) + bus_teardown_intr(dev, sc->irq, sc->ih); + if (sc->irq) + bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); if (sc->nambar) bus_release_resource(dev, SYS_RES_IOPORT, sc->nambarid, sc->nambar); if (sc->nabmbar) bus_release_resource(dev, SYS_RES_IOPORT, sc->nabmbarid, sc->nabmbar); - if (sc->ih) - bus_teardown_intr(dev, sc->irq, sc->ih); - if (sc->irq) - bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); free(sc, M_DEVBUF); return ENXIO; } @@ -711,9 +742,29 @@ } static int +ich_pci_suspend(device_t dev) +{ + struct sc_info *sc; + int i; + + sc = pcm_getdevinfo(dev); + for (i = 0 ; i < 3; i++) { + sc->ch[i].run_save = sc->ch[i].run; + if (sc->ch[i].run) { + ichchan_trigger(0, &sc->ch[i], PCMTRIG_ABORT); + } + } + + /* ACLINK shut off */ + ich_wr(sc,ICH_REG_GLOB_CNT, ICH_GLOB_CTL_SHUT, 4); + return 0; +} + +static int ich_pci_resume(device_t dev) { struct sc_info *sc; + int i; sc = pcm_getdevinfo(dev); @@ -727,6 +778,15 @@ device_printf(dev, "unable to reinitialize the mixer\n"); return ENXIO; } + /* Re-start DMA engines */ + for (i = 0 ; i < 3; i++) { + struct sc_chinfo *ch = &sc->ch[i]; + if (sc->ch[i].run_save) { + ichchan_setblocksize(0, ch, ch->blksz); + ichchan_setspeed(0, ch, ch->spd); + ichchan_trigger(0, ch, PCMTRIG_START); + } + } return 0; } @@ -735,6 +795,7 @@ DEVMETHOD(device_probe, ich_pci_probe), DEVMETHOD(device_attach, ich_pci_attach), DEVMETHOD(device_detach, ich_pci_detach), + DEVMETHOD(device_suspend, ich_pci_suspend), DEVMETHOD(device_resume, ich_pci_resume), { 0, 0 } }; >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20020216184502.7514.qmail>