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: