Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Aug 2003 01:41:03 -0400
From:      Anish Mistry <mistry.7@osu.edu>
To:        freebsd-current@freebsd.org
Subject:   [patch] usb ohci suspend/resume
Message-ID:  <200308280141.15917.mistry.7@osu.edu>

next in thread | raw e-mail | index | archive | help

--Boundary-03=_7XZT/u1uHkPwsle
Content-Type: multipart/mixed;
  boundary="Boundary-01=_vXZT/wFeAdpzUH5"
Content-Transfer-Encoding: 7bit
Content-Description: signed data
Content-Disposition: inline

--Boundary-01=_vXZT/wFeAdpzUH5
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Description: body text
Content-Disposition: inline

If you have trouble with suspend/resume killing your usb devices try out th=
e=20
attached patch (ohci only, unless someone want to adapt to uhci).  I think =
I=20
finally got it working, at least it works with my mouse and no panics if yo=
u=20
leave devices plugged during a suspend/resume cycle.

Same as attached in case it gets stripped.
http://am-productions.biz/docs/ohci-usb-suspend.patch

=2D-=20
Anish Mistry

--Boundary-01=_vXZT/wFeAdpzUH5
Content-Type: text/x-diff;
  charset="us-ascii";
  name="ohci-usb-suspend.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="ohci-usb-suspend.patch"

diff -u usb.orig/ohci.c usb/ohci.c
=2D-- usb.orig/ohci.c	Thu Aug 28 00:54:09 2003
+++ usb/ohci.c	Thu Aug 28 01:04:43 2003
@@ -1020,7 +1020,7 @@
 	DPRINTF(("ohci_shutdown: stopping the HC\n"));
 	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET);
 }
=2D
+#endif
 /*
  * Handle suspend/resume.
  *
@@ -1028,6 +1028,86 @@
  * called from an intterupt context.  This is all right since we
  * are almost suspended anyway.
  */
+usbd_status ohci_resume(struct ohci_softc *sc)
+{
+/*	return ohci_init(sc);*/
+	int s;
+	u_int32_t ctl, ival, hcr, fm, per, rev, desca;
+	s =3D splusb();
+	DPRINTF(("ohci_resume: start\n"));
+#if defined(__OpenBSD__)
+	printf(",");
+#else
+	printf("%s:", USBDEVNAME(sc->sc_bus.bdev));
+#endif
+	rev =3D OREAD4(sc, OHCI_REVISION);
+	printf(" OHCI version %d.%d%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),
+	       OHCI_REV_LEGACY(rev) ? ", legacy support" : "");
+	/* Some broken BIOSes do not recover these values */
+	OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma, 0));
+	OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr);
+	OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr);
+	if (sc->sc_intre)
+		OWRITE4(sc, OHCI_INTERRUPT_ENABLE,
+			sc->sc_intre & (OHCI_ALL_INTRS | OHCI_MIE));
+	if (sc->sc_control)
+		ctl =3D sc->sc_control;
+	else
+		ctl =3D OREAD4(sc, OHCI_CONTROL);
+	ctl |=3D OHCI_HCFS_RESUME;
+	OWRITE4(sc, OHCI_CONTROL, ctl);
+	usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
+	ctl =3D (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL;
+	OWRITE4(sc, OHCI_CONTROL, ctl);
+	usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
+	sc->sc_control =3D sc->sc_intre =3D 0;
+	/* disable all interrupts and then switch on all desired interrupts */
+	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
+	OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE);
+	/* switch on desired functional features */
+	ctl =3D OREAD4(sc, OHCI_CONTROL);
+	ctl &=3D ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR);
+	ctl |=3D OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE |
+		OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL;
+	/* And finally start it! */
+	OWRITE4(sc, OHCI_CONTROL, ctl);
+
+	/*
+	 * The controller is now OPERATIONAL.  Set a some final
+	 * registers that should be set earlier, but that the
+	 * controller ignores when in the SUSPEND state.
+	 */
+	fm =3D (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT;
+	fm |=3D OHCI_FSMPS(ival) | ival;
+	OWRITE4(sc, OHCI_FM_INTERVAL, fm);
+	per =3D OHCI_PERIODIC(ival); /* 90% periodic */
+	OWRITE4(sc, OHCI_PERIODIC_START, per);
+
+	/* Fiddle the No OverCurrent Protection bit to avoid chip bug. */
+	desca =3D OREAD4(sc, OHCI_RH_DESCRIPTOR_A);
+	OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP);
+	OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC); /* Enable port power */
+	usb_delay_ms(&sc->sc_bus, OHCI_ENABLE_POWER_DELAY);
+	OWRITE4(sc, OHCI_RH_DESCRIPTOR_A, desca);
+	splx(s);
+	return (USBD_NORMAL_COMPLETION);
+}
+
+usbd_status ohci_suspend(struct ohci_softc *sc)
+{
+       u_int32_t ctl,i;
+       int s;
+
+	s =3D splhardusb();
+	ctl =3D OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK;
+	ctl |=3D OHCI_HCFS_SUSPEND;
+	OWRITE4(sc, OHCI_CONTROL, ctl);
+	splx(s);
+
+        return (USBD_NORMAL_COMPLETION);
+}
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
 void
 ohci_power(int why, void *v)
 {
diff -u usb.orig/ohci_pci.c usb/ohci_pci.c
=2D-- usb.orig/ohci_pci.c	Thu Aug 28 00:54:09 2003
+++ usb/ohci_pci.c	Thu Aug 28 01:16:47 2003
@@ -295,11 +295,43 @@
 	return 0;
 }
=20
+/* implement suspend and resume */
+static int
+ohci_pci_suspend(device_t self)
+{
+       int err;
+       ohci_softc_t *sc =3D device_get_softc(self);
+       device_printf(self, "ohci_pci_suspend: power_state =3D 0x%08x\n",
+                                       pci_get_powerstate(self));
+       err =3D bus_generic_suspend(self);
+       if (err)
+               return err;
+       ohci_suspend(sc);
+	/*usb_delay_ms(&sc->sc_bus, USB_RESUME_WAIT);*/
+       return 0;
+}
+
+static int
+ohci_pci_resume(device_t self)
+{
+       ohci_softc_t *sc =3D device_get_softc(self);
+       device_printf(self, "ohci_pci_resume: power_state =3D 0x%08x\n",
+                                       pci_get_powerstate(self));
+       ohci_resume(sc);
+       usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
+       usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
+	bus_generic_resume(self);
+
+       return 0;
+}
+
 static device_method_t ohci_methods[] =3D {
 	/* Device interface */
 	DEVMETHOD(device_probe, ohci_pci_probe),
 	DEVMETHOD(device_attach, ohci_pci_attach),
=2D	DEVMETHOD(device_shutdown, bus_generic_shutdown),
+	DEVMETHOD(device_suspend, ohci_pci_suspend),
+	DEVMETHOD(device_resume, ohci_pci_resume),
+ 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
=20
 	/* Bus interface */
 	DEVMETHOD(bus_print_child, bus_generic_print_child),
diff -u usb.orig/ohcivar.h usb/ohcivar.h
=2D-- usb.orig/ohcivar.h	Thu Aug 28 00:54:09 2003
+++ usb/ohcivar.h	Wed Aug 27 19:36:47 2003
@@ -158,6 +158,8 @@
 #define OXFER(xfer) ((struct ohci_xfer *)(xfer))
=20
 usbd_status	ohci_init(ohci_softc_t *);
+usbd_status	ohci_suspend(ohci_softc_t *);
+usbd_status	ohci_resume(ohci_softc_t *);
 int		ohci_intr(void *);
 #if defined(__NetBSD__) || defined(__OpenBSD__)
 int		ohci_detach(ohci_softc_t *, int);

--Boundary-01=_vXZT/wFeAdpzUH5--

--Boundary-03=_7XZT/u1uHkPwsle
Content-Type: application/pgp-signature
Content-Description: signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (FreeBSD)

iD8DBQA/TZX7xqA5ziudZT0RAkvCAKCVFiITB88SzGA4n3mtGnQRq97B4QCePJb8
61dQkS9Z5NP5Sj+l88GXdhM=
=9M5u
-----END PGP SIGNATURE-----

--Boundary-03=_7XZT/u1uHkPwsle--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200308280141.15917.mistry.7>