Subject: kern/15431: support varriable rate and resume/suspend in auich driver
To: None <gnats-bugs@gnats.netbsd.org>
From: None <ura@hiru.aoba.yokohama.jp>
List: netbsd-bugs
Date: 01/31/2002 04:08:58
>Number:         15431
>Category:       kern
>Synopsis:       support varriable rate and resume/suspend in auich driver
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Jan 30 11:10:01 PST 2002
>Closed-Date:
>Last-Modified:
>Originator:     URA Hiroshi
>Release:        NetBSD 1.5ZA (2002/01/28)
>Organization:
>Environment:
System: NetBSD fumizuki.hiru.aoba.yokohama.jp 1.5ZA NetBSD 1.5ZA (FUMIZUKI) #55: Wed Jan 30 21:35:25 JST 2002 ura@fumizuki.hiru.aoba.yokohama.jp:/usr/src/sys/arch/i386/compile/FUMIZUKI i386
Architecture: i386
Machine: i386
>Description:
The auich driver supports only 48KHz sample rate and doesn't support
resume/suspend. 


>How-To-Repeat:

>Fix:
I wrote the following patch that includes as following:
  - suuport varriable rate
  - support resume/suspend, from OpenBSD

Index: dev/pci/auich.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/pci/auich.c,v
retrieving revision 1.8
diff -u -u -r1.8 auich.c
--- auich.c	2002/01/14 01:29:13	1.8
+++ auich.c	2002/01/30 18:34:06
@@ -168,11 +168,18 @@
 
 	struct auich_dma *sc_dmas;
 
+	int  sc_fixed_rate;
+
 	void (*sc_pintr)(void *);
 	void *sc_parg;
 
 	void (*sc_rintr)(void *);
 	void *sc_rarg;
+
+	/* Power Management */
+	void *sc_powerhook;
+	int sc_suspend;
+	u_int16_t ext_status;
 };
 
 /* Debug */
@@ -222,6 +229,8 @@
 	    struct auich_dma *);
 int	auich_freemem(struct auich_softc *, struct auich_dma *);
 
+void	auich_powerhook(int, void *);
+
 struct audio_hw_if auich_hw_if = {
 	auich_open,
 	auich_close,
@@ -314,6 +323,7 @@
 	pcireg_t csr;
 	const char *intrstr;
 	const struct auich_devtype *d;
+	u_int16_t ext_id, ext_status;
 
 	d = auich_lookup(pa);
 	if (d == NULL)
@@ -380,7 +390,24 @@
 	if (ac97_attach(&sc->host_if) != 0)
 		return;
 
+	auich_read_codec(sc, AC97_REG_EXTENDED_ID, &ext_id);
+        if ((ext_id & (AC97_CODEC_DOES_VRA | AC97_CODEC_DOES_MICVRA)) != 0) {
+		auich_read_codec(sc, AC97_REG_EXTENDED_STATUS, &ext_status);
+        	if ((ext_id & AC97_CODEC_DOES_VRA) !=0)
+                	ext_status |= AC97_ENAB_VRA;
+        	if ((ext_id & AC97_CODEC_DOES_MICVRA) !=0)
+                	ext_status |= AC97_ENAB_MICVRA;
+        	auich_write_codec(sc, AC97_REG_EXTENDED_STATUS, ext_status);
+		sc->sc_fixed_rate = 0;
+	} else {
+		sc->sc_fixed_rate = 48000;
+	}
+
 	audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev);
+
+	/* Watch for power change */
+	sc->sc_suspend = PWR_RESUME;
+	sc->sc_powerhook = powerhook_establish(auich_powerhook, sc);
 }
 
 int
@@ -547,11 +574,14 @@
 			continue;
 
 		inout = mode == AUMODE_PLAY ? ICH_PM_PCMO : ICH_PM_PCMI;
-
-		/*
-		 * XXX NEED TO DETERMINE WHICH RATES THE CODEC SUPPORTS!
-		 */
-		if (p->sample_rate != 48000)
+		
+		if ((p->sample_rate !=  8000) &&
+		    (p->sample_rate != 11025) &&
+		    (p->sample_rate != 16000) &&
+		    (p->sample_rate != 22050) &&
+		    (p->sample_rate != 32000) &&
+		    (p->sample_rate != 44100) &&
+		    (p->sample_rate != 48000))
 			return (EINVAL);
 
 		p->factor = 1;
@@ -636,7 +666,7 @@
 		auich_write_codec(sc, AC97_REG_POWER, val | inout);
 
 		auich_write_codec(sc, AC97_REG_PCM_FRONT_DAC_RATE,
-		    p->sample_rate);
+		    sc->sc_fixed_rate ? sc->sc_fixed_rate : p->sample_rate);
 		auich_read_codec(sc, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
 		p->sample_rate = rate;
 
@@ -1127,4 +1157,41 @@
 	bus_dmamem_free(sc->dmat, &seg, rseg);
  fail_0:
 	return (error);
+}
+
+void
+auich_powerhook(int why, void *addr)
+{
+	struct auich_softc *sc = (struct auich_softc *)addr;
+
+	switch (why) {
+	case PWR_SUSPEND:
+	case PWR_STANDBY:
+		/* Power down */
+		DPRINTF(1, ("%s: power down\n", sc->sc_dev.dv_xname));
+		sc->sc_suspend = why;
+		auich_read_codec(sc, AC97_REG_EXTENDED_STATUS, &sc->ext_status);
+		break;
+
+	case PWR_RESUME:
+		/* Wake up */
+		DPRINTF(1, ("%s: power resume\n", sc->sc_dev.dv_xname));
+		if (sc->sc_suspend == PWR_RESUME) {
+			printf("%s: resume without suspend.\n",
+			    sc->sc_dev.dv_xname);
+			sc->sc_suspend = why;
+			return;
+		}
+		sc->sc_suspend = why;
+		auich_reset_codec(sc);
+		DELAY(1000);
+		(sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+		auich_write_codec(sc, AC97_REG_EXTENDED_STATUS, sc->ext_status);
+		break;
+
+	case PWR_SOFTSUSPEND:
+	case PWR_SOFTSTANDBY:
+	case PWR_SOFTRESUME:
+		break;
+	}
 }
Index: dev/ic/ac97reg.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/ic/ac97reg.h,v
retrieving revision 1.3
diff -u -u -r1.3 ac97reg.h
--- ac97reg.h	2001/01/05 03:32:46	1.3
+++ ac97reg.h	2002/01/30 18:34:25
@@ -52,6 +52,7 @@
 /* AC'97 2.0 extensions -- 0x28-0x3a */
 #define	AC97_REG_EXTENDED_ID		0x28
 #define		AC97_CODEC_DOES_VRA		0x0001
+#define		AC97_CODEC_DOES_MICVRA		0x0004
 #define	AC97_REG_EXTENDED_STATUS	0x2a
 #define		AC97_ENAB_VRA			0x0001
 #define		AC97_ENAB_MICVRA		0x0004
>Release-Note:
>Audit-Trail:
>Unformatted: