Skip site navigation (1)Skip section navigation (2)
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>