Subject: Re: Turtle Beach Santa Cruz sound card
To: =?iso-8859-1?Q?St=E9phane?= Witzmann <stephane.witzmann@gmail.com>
From: Lubomir Sedlacik <salo@Xtrmntr.org>
List: netbsd-users
Date: 10/27/2005 12:09:45
--NT59pYSnj1ZLVgEN
Content-Type: multipart/mixed; boundary="lBqJz4CGKwlWe7/k"
Content-Disposition: inline
--lBqJz4CGKwlWe7/k
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
On Thu, Oct 27, 2005 at 05:38:54AM +0200, St=E9phane Witzmann wrote:
> A few builds and reboots later... I was wrong again. What makes it work is
> just *luck*. The best (and only) fix I have found so far : reboot until it
> works.
the clcs(4) driver is notoriously known to have issues with
initialization (among other things..).
there is a patch from yasufumi itoh flying around which still doesn't
solve all the issues clcs(4) had but could help with the initialization
problems. i am attaching an old copy i used with T22 months ago.
regards,
--=20
-- Lubomir Sedlacik <salo@{NetBSD,Xtrmntr,silcnet}.org> --
--lBqJz4CGKwlWe7/k
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="clcs-20040414.diff"
Content-Transfer-Encoding: quoted-printable
diff -uF^[a-zA-Z_][a-z A-Z0-9_]*(.*[^;]$ cs4280.c.orig cs4280.c
--- cs4280.c.orig Tue May 6 09:57:51 2003
+++ cs4280.c Wed Apr 14 22:52:10 2004
@@ -92,6 +92,8 @@ __KERNEL_RCSID(0, "$NetBSD: cs4280.c,v 1
int cs4280_match(struct device *, struct cfdata *, void *);
void cs4280_attach(struct device *, struct device *, void *);
int cs4280_intr(void *);
+int cs4280_open(void *, int);
+void cs4280_close(void *);
int cs4280_query_encoding(void *, struct audio_encoding *);
int cs4280_set_params(void *, int, int, struct audio_params *, struct aud=
io_params *);
int cs4280_halt_output(void *);
@@ -102,6 +104,8 @@ int cs4280_trigger_output(void *, void=20
int cs4280_trigger_input(void *, void *, void *, int, void (*)(void *),
void *, struct audio_params *);
=20
+static int cs4280_reinit(struct cs428x_softc *, int);
+static void cs4280_reset_codec1(struct cs428x_softc *, int);
void cs4280_reset_codec(void *);
=20
/* For PowerHook */
@@ -110,11 +114,12 @@ void cs4280_power(int, void *);
/* Internal functions */
void cs4280_set_adc_rate(struct cs428x_softc *, int );
void cs4280_set_dac_rate(struct cs428x_softc *, int );
+void cs4280_clear_image(struct cs428x_softc *);
int cs4280_download(struct cs428x_softc *, const u_int32_t *, u_int32_t, =
u_int32_t);
int cs4280_download_image(struct cs428x_softc *);
void cs4280_reset(void *);
int cs4280_get_portnum_by_name(struct cs428x_softc *, char *, char *, cha=
r *);
-int cs4280_init(struct cs428x_softc *, int);
+int cs4280_init(struct cs428x_softc *, int, int);
void cs4280_clear_fifos(struct cs428x_softc *);
=20
#if CS4280_DEBUG > 10
@@ -124,8 +129,8 @@ int cs4280_checkimage(struct cs428x_sof
#endif
=20
struct audio_hw_if cs4280_hw_if =3D {
- cs428x_open,
- cs428x_close,
+ cs4280_open,
+ cs4280_close,
NULL,
cs4280_query_encoding,
cs4280_set_params,
@@ -265,7 +270,13 @@ cs4280_attach(parent, self, aux)
mem |=3D 0x00002000;
pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG, mem);
}
-=09
+
+ /* Initialization */
+ if (cs4280_init(sc, 1, 1) !=3D 0 &&
+ cs4280_init(sc, 1, 1) !=3D 0 &&
+ cs4280_init(sc, 1, 1))
+ return;
+
/* Map and establish the interrupt. */
if (pci_intr_map(pa, &ih)) {
aprint_error("%s: couldn't map interrupt\n",
@@ -285,10 +296,6 @@ cs4280_attach(parent, self, aux)
}
aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
=20
- /* Initialization */
- if(cs4280_init(sc, 1) !=3D 0)
- return;
-
sc->type =3D TYPE_CS4280;
sc->halt_input =3D cs4280_halt_input;
sc->halt_output =3D cs4280_halt_output;
@@ -497,6 +504,68 @@ cs4280_intr(p)
}
=20
int
+cs4280_open(void *addr, int flags)
+{
+ struct cs428x_softc *sc =3D addr;
+
+ /* re-init the device, in case it failed on the last close */
+ if (sc->sc_needs_reset || sc->sc_errstat !=3D CS428X_AC97_NOERR)
+ if (cs4280_reinit(sc, 0))
+ return EIO;
+
+ sc->sc_needs_reset =3D 0;
+
+ return 0;
+}
+
+void
+cs4280_close(void *addr)
+{
+ struct cs428x_softc *sc =3D addr;
+
+ if (sc->sc_needs_reset) {
+ if (cs4280_reinit(sc, 0))
+ return; /* failed */
+ sc->sc_needs_reset =3D 0;
+ }
+}
+
+static int
+cs4280_reinit(struct cs428x_softc *sc, int nowait)
+{
+ int i;
+
+ /*
+ * XXX this is probably overkill
+ *
+ * Playback/recording will sometimes become noisy
+ * when used repeatedly. I don't know how to avoid
+ * this, but resetting the chip should bring it to
+ * a sane state.
+ */
+ for (i =3D 0; i < 5; i++) {
+ sc->sc_errstat =3D CS428X_AC97_ABORT_ON_ERROR;
+
+ /* perform reset */
+ if (cs4280_init(sc, 0, nowait) !=3D 0)
+ continue;
+ cs4280_reset_codec1(sc, nowait);
+
+ /* restore ac97 registers */
+ (*sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+
+ if (sc->sc_errstat =3D=3D CS428X_AC97_ABORT_ON_ERROR) {
+ /* reninit complete */
+ sc->sc_errstat =3D CS428X_AC97_NOERR;
+ return 0;
+ }
+ }
+
+ printf("%s: cs4280_reinit: reinit failed\n", sc->sc_dev.dv_xname);
+ return 1;
+}
+
+int
cs4280_query_encoding(addr, fp)
void *addr;
struct audio_encoding *fp;
@@ -667,7 +736,15 @@ cs4280_halt_output(addr)
=09
mem =3D BA1READ4(sc, CS4280_PCTL);
BA1WRITE4(sc, CS4280_PCTL, mem & ~PCTL_MASK);
+#if 1
+ BA1WRITE4(sc, CS4280_SPCR, SPCR_RSTSP);
+ delay(100);
+ BA1WRITE4(sc, CS4280_SPCR, 0);
+ BA1WRITE4(sc, CS4280_SPCR, SPCR_RUN | SPCR_RUNFR);
+ delay(100);
+#endif
sc->sc_prun =3D 0;
+ sc->sc_needs_reset =3D 1;
return 0;
}
=20
@@ -680,7 +757,15 @@ cs4280_halt_input(addr)
=20
mem =3D BA1READ4(sc, CS4280_CCTL);
BA1WRITE4(sc, CS4280_CCTL, mem & ~CCTL_MASK);
+#if 1
+ BA1WRITE4(sc, CS4280_SPCR, SPCR_RSTSP);
+ delay(100);
+ BA1WRITE4(sc, CS4280_SPCR, 0);
+ BA1WRITE4(sc, CS4280_SPCR, SPCR_RUN | SPCR_RUNFR);
+ delay(100);
+#endif
sc->sc_rrun =3D 0;
+ sc->sc_needs_reset =3D 1;
return 0;
}
=20
@@ -780,6 +865,9 @@ cs4280_trigger_output(addr, start, end,=20
sc->sc_prate =3D param->sample_rate;
cs4280_set_dac_rate(sc, param->sample_rate);
=20
+#if 1
+ BA1WRITE4(sc, CS4280_SPCR, BA1READ4(sc, CS4280_SPCR) | SPCR_DRQEN);
+#endif
pctl =3D BA1READ4(sc, CS4280_PCTL) & ~PCTL_MASK;
pctl |=3D sc->pctl;
BA1WRITE4(sc, CS4280_PCTL, pctl);
@@ -854,6 +942,9 @@ cs4280_trigger_input(addr, start, end, b
sc->sc_rrate =3D param->sample_rate;
cs4280_set_adc_rate(sc, param->sample_rate);
=20
+#if 1
+ BA1WRITE4(sc, CS4280_SPCR, BA1READ4(sc, CS4280_SPCR) | SPCR_DRQEN);
+#endif
cctl =3D BA1READ4(sc, CS4280_CCTL) & ~CCTL_MASK;
cctl |=3D sc->cctl;
BA1WRITE4(sc, CS4280_CCTL, cctl);
@@ -907,11 +998,7 @@ cs4280_power(why, v)
return;
}
sc->sc_suspend =3D why;
- cs4280_init(sc, 0);
- cs4280_reset_codec(sc);
-
- /* restore ac97 registers */
- (*sc->codec_if->vtbl->restore_ports)(sc->codec_if);
+ cs4280_reinit(sc, 1);
=20
/* restore DMA related status */
if(sc->sc_prun) {
@@ -942,13 +1029,10 @@ cs4280_power(why, v)
=20
/* control AC97 codec */
void
-cs4280_reset_codec(void *addr)
+cs4280_reset_codec1(struct cs428x_softc *sc, int nosleep)
{
- struct cs428x_softc *sc;
int n;
=20
- sc =3D addr;
-
/* Reset codec */
BA0WRITE4(sc, CS428X_ACCTL, 0);
delay(100); /* delay 100us */
@@ -960,21 +1044,37 @@ cs4280_reset_codec(void *addr)
=20
/* Enable AC-link sync generation */
BA0WRITE4(sc, CS428X_ACCTL, ACCTL_ESYN | ACCTL_RSTN);
- delay(50*1000); /* XXX delay 50ms */
-=09
+ if (nosleep)
+ delay(50*1000); /* XXX delay 50ms */
+ else
+ tsleep(sc, PWAIT, "clcsa1", hz / 10);
+
/* Assert valid frame signal */
BA0WRITE4(sc, CS428X_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
=20
/* Wait for valid AC97 input slot */
n =3D 0;
- while ((BA0READ4(sc, CS428X_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) !=3D
- (ACISV_ISV3 | ACISV_ISV4)) {
- delay(1000);
+ do {
if (++n > 1000) {
printf("reset_codec: AC97 inputs slot ready timeout\n");
return;
}
- }
+ if (nosleep)
+ delay(1000);
+ else
+ tsleep(sc, PWAIT, "clcsa2", hz / 4);
+ } while ((BA0READ4(sc, CS428X_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) !=3D
+ (ACISV_ISV3 | ACISV_ISV4));
+#if CS4280_DEBUG > 1
+ if (n) printf("%s: cs4280_reset_codec: n %d\n", sc->sc_dev.dv_xname, n);
+#endif
+}
+
+void
+cs4280_reset_codec(void *addr)
+{
+
+ cs4280_reset_codec1(addr, 1);
}
=20
=20
@@ -1147,6 +1247,16 @@ cs4280_set_dac_rate(sc, rate)
BA1WRITE4(sc, CS4280_PPI, ppi);
}
=20
+void
+cs4280_clear_image(sc)
+ struct cs428x_softc *sc;
+{
+ u_int32_t adr;
+
+ for (adr =3D 0; adr < CS4280_BA1_SIZE; adr +=3D sizeof(u_int32_t))
+ BA1WRITE4(sc, adr, 0);
+}
+
/* Download Proceessor Code and Data image */
int
cs4280_download(sc, src, offset, len)
@@ -1194,6 +1304,8 @@ cs4280_download_image(sc)
int idx, err;
u_int32_t offset =3D 0;
=20
+ cs4280_clear_image(sc);
+
err =3D 0;
for (idx =3D 0; idx < BA1_MEMORY_COUNT; ++idx) {
err =3D cs4280_download(sc, &BA1Struct.map[offset],
@@ -1235,9 +1347,9 @@ cs4280_get_portnum_by_name(sc, class, de
}
=20
int
-cs4280_init(sc, init)
+cs4280_init(sc, init, nosleep)
struct cs428x_softc *sc;
- int init;
+ int init, nosleep;
{
int n;
u_int32_t mem;
@@ -1278,8 +1390,12 @@ cs4280_init(sc, init)
delay(50*1000); /* delay 50ms */
=09
/* Turn on clock */
+#if 0
mem =3D BA0READ4(sc, CS4280_CLKCR1) | CLKCR1_SWCE;
BA0WRITE4(sc, CS4280_CLKCR1, mem);
+#else
+ BA0WRITE4(sc, CS4280_CLKCR1, CLKCR1_PLLP|CLKCR1_SWCE);
+#endif
=09
/* Set the serial port FIFO pointer to the
* first sample in FIFO. (not documented) */
@@ -1297,29 +1413,41 @@ cs4280_init(sc, init)
=09
/* Wait for CODEC ready */
n =3D 0;
- while ((BA0READ4(sc, CS428X_ACSTS) & ACSTS_CRDY) =3D=3D 0) {
- delay(125);
+ do {
if (++n > 1000) {
printf("%s: codec ready timeout\n",
sc->sc_dev.dv_xname);
return(1);
}
- }
+ if (nosleep)
+ delay(125);
+ else
+ tsleep(sc, PWAIT, "clcs1", 2);
+ } while ((BA0READ4(sc, CS428X_ACSTS) & ACSTS_CRDY) =3D=3D 0);
+#if CS4280_DEBUG > 1
+ if (n > 1) printf("%s: cs4280_init: n1 %d\n", sc->sc_dev.dv_xname, n-1);
+#endif
=20
/* Assert valid frame signal */
BA0WRITE4(sc, CS428X_ACCTL, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
=20
/* Wait for valid AC97 input slot */
n =3D 0;
- while ((BA0READ4(sc, CS428X_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) !=3D
- (ACISV_ISV3 | ACISV_ISV4)) {
- delay(1000);
+ do {
if (++n > 1000) {
printf("AC97 inputs slot ready timeout\n");
return(1);
}
- }
-=09
+ if (nosleep)
+ delay(2000);
+ else
+ tsleep(sc, PWAIT, "clcs2", hz / 10);
+ } while ((BA0READ4(sc, CS428X_ACISV) & (ACISV_ISV3 | ACISV_ISV4)) !=3D
+ (ACISV_ISV3 | ACISV_ISV4));
+#if CS4280_DEBUG > 1
+ if (n > 1) printf("%s: cs4280_init: n2 %d\n", sc->sc_dev.dv_xname, n-1);
+#endif
+
/* Set AC97 output slot valid signals */
BA0WRITE4(sc, CS428X_ACOSV, ACOSV_SLV3 | ACOSV_SLV4);
=20
@@ -1358,22 +1486,28 @@ cs4280_init(sc, init)
=20
/* Monitor RUNFR bit in SPCR for 1 to 0 transition */
n =3D 0;
- while (BA1READ4(sc, CS4280_SPCR) & SPCR_RUNFR) {
- delay(10);
+ do {
if (++n > 1000) {
printf("SPCR 1->0 transition timeout\n");
return(1);
}
- }
-=09
- n =3D 0;
- while (!(BA1READ4(sc, CS4280_SPCS) & SPCS_SPRUN)) {
delay(10);
+ } while (BA1READ4(sc, CS4280_SPCR) & SPCR_RUNFR);
+#ifdef CS4280_DEBUG
+ if (n > 1) printf("%s: cs4280_init: n3 %d\n", sc->sc_dev.dv_xname, n-1);
+#endif
+
+ n =3D 0;
+ do {
if (++n > 1000) {
printf("SPCS 0->1 transition timeout\n");
return(1);
}
- }
+ delay(10);
+ } while (!(BA1READ4(sc, CS4280_SPCS) & SPCS_SPRUN));
+#ifdef CS4280_DEBUG
+ if (n > 1) printf("%s: cs4280_init: n4 %d\n", sc->sc_dev.dv_xname, n-1);
+#endif
/* Processor is now running !!! */
=20
/* Setup volume */
@@ -1431,6 +1565,11 @@ cs4280_clear_fifos(sc)
break;
}
}
+#ifdef CS4280_DEBUG
+ if (n)
+ printf("%s: clear_fifo: n %d (cnt %d)\n",
+ sc->sc_dev.dv_xname, n, cnt);
+#endif
BA0WRITE4(sc, CS4280_SERBAD, cnt);
BA0WRITE4(sc, CS4280_SERBCM, SERBCM_WRC);
}
diff -u cs428x.h.orig cs428x.h
--- cs428x.h.orig Tue May 6 09:57:51 2003
+++ cs428x.h Wed Apr 14 22:52:10 2004
@@ -118,10 +118,20 @@
=20
/*
* XXX
- * Actually thease 2 variables are needed only for CS4280.
+ * Actually thease 4 variables are needed only for CS4280.
*/
u_int32_t pctl;
u_int32_t cctl;
+ int sc_needs_reset;
+ int sc_needs_pciclk;
+
+ /* another XXX */
+ enum {
+ CS428X_AC97_NOERR,
+ CS428X_AC97_HAD_ERR,
+ CS428X_AC97_ABORT_ON_ERROR,
+ CS428X_AC97_ABORTED
+ } sc_errstat;
=20
/* AC97 CODEC */
struct ac97_codec_if *codec_if;
diff -uF^[a-zA-Z_][a-z A-Z0-9_]*(.*[^;]$ cs428x.c.orig cs428x.c
--- cs428x.c.orig Tue May 6 09:57:51 2003
+++ cs428x.c Wed Apr 14 22:52:10 2004
@@ -273,7 +273,7 @@ cs428x_read_codec(void *addr, u_int8_t a
n =3D 0;
while ((BA0READ4(sc, CS428X_ACSTS) & ACSTS_VSTS) =3D=3D 0) {
delay(1);
- while (++n > 1000) {
+ if (++n > 1000) {
printf("%s: AC97 read fail (VSTS=3D=3D0) for add=3D0x%0x\n",
sc->sc_dev.dv_xname, ac97_addr);
return 1;
@@ -302,6 +302,8 @@ cs428x_write_codec(void *addr, u_int8_t=20
BA0WRITE4(sc, CS428X_ACCTL, acctl);
=20
if (cs428x_src_wait(sc) < 0) {
+ if (sc->sc_errstat =3D=3D CS428X_AC97_ABORTED)
+ return 1; /* do not print error */
printf("%s: AC97 write fail (DCV!=3D0) for add=3D0x%02x data=3D"
"0x%04x\n", sc->sc_dev.dv_xname, ac97_addr, ac97_data);
return 1;
@@ -379,10 +381,16 @@ cs428x_src_wait(sc)
=20
n =3D 0;
while ((BA0READ4(sc, CS428X_ACCTL) & ACCTL_DCV)) {
+ if (sc->sc_errstat =3D=3D CS428X_AC97_ABORTED)
+ return -1;
delay(1000);
- while (++n > 1000) {
+ if (++n > 1000) {
printf("cs428x_src_wait: 0x%08x\n",
BA0READ4(sc, CS428X_ACCTL));
+ if (sc->sc_errstat =3D=3D CS428X_AC97_ABORT_ON_ERROR)
+ sc->sc_errstat =3D CS428X_AC97_ABORTED;
+ else
+ sc->sc_errstat =3D CS428X_AC97_HAD_ERR;
return -1;
}
}
--lBqJz4CGKwlWe7/k--
--NT59pYSnj1ZLVgEN
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.6 (NetBSD)
iD8DBQFDYKdoiwjDDlS8cmMRAvoxAJ94SuCulzwusxR+LzPaUP5eSWqkuQCfSWnJ
voKhQc8hnsxGt4X29Ab1GWI=
=BFLh
-----END PGP SIGNATURE-----
--NT59pYSnj1ZLVgEN--