If you have trouble with suspend/resume killing your usb devices try out the 
attached patch (ohci only, unless someone want to adapt to uhci).  I think I 
finally got it working, at least it works with my mouse and no panics if you 
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

-- 
Anish Mistry
diff -u usb.orig/ohci.c usb/ohci.c
--- 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);
 }
-
+#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 = splusb();
+	DPRINTF(("ohci_resume: start\n"));
+#if defined(__OpenBSD__)
+	printf(",");
+#else
+	printf("%s:", USBDEVNAME(sc->sc_bus.bdev));
+#endif
+	rev = 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 = sc->sc_control;
+	else
+		ctl = OREAD4(sc, OHCI_CONTROL);
+	ctl |= OHCI_HCFS_RESUME;
+	OWRITE4(sc, OHCI_CONTROL, ctl);
+	usb_delay_ms(&sc->sc_bus, USB_RESUME_DELAY);
+	ctl = (ctl & ~OHCI_HCFS_MASK) | OHCI_HCFS_OPERATIONAL;
+	OWRITE4(sc, OHCI_CONTROL, ctl);
+	usb_delay_ms(&sc->sc_bus, USB_RESUME_RECOVERY);
+	sc->sc_control = sc->sc_intre = 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 = OREAD4(sc, OHCI_CONTROL);
+	ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR);
+	ctl |= 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 = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT;
+	fm |= OHCI_FSMPS(ival) | ival;
+	OWRITE4(sc, OHCI_FM_INTERVAL, fm);
+	per = OHCI_PERIODIC(ival); /* 90% periodic */
+	OWRITE4(sc, OHCI_PERIODIC_START, per);
+
+	/* Fiddle the No OverCurrent Protection bit to avoid chip bug. */
+	desca = 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 = splhardusb();
+	ctl = OREAD4(sc, OHCI_CONTROL) & ~OHCI_HCFS_MASK;
+	ctl |= 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
--- 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;
 }
 
+/* implement suspend and resume */
+static int
+ohci_pci_suspend(device_t self)
+{
+       int err;
+       ohci_softc_t *sc = device_get_softc(self);
+       device_printf(self, "ohci_pci_suspend: power_state = 0x%08x\n",
+                                       pci_get_powerstate(self));
+       err = 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 = device_get_softc(self);
+       device_printf(self, "ohci_pci_resume: power_state = 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[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe, ohci_pci_probe),
 	DEVMETHOD(device_attach, ohci_pci_attach),
-	DEVMETHOD(device_shutdown, bus_generic_shutdown),
+	DEVMETHOD(device_suspend, ohci_pci_suspend),
+	DEVMETHOD(device_resume, ohci_pci_resume),
+ 	DEVMETHOD(device_shutdown, bus_generic_shutdown),
 
 	/* Bus interface */
 	DEVMETHOD(bus_print_child, bus_generic_print_child),
diff -u usb.orig/ohcivar.h usb/ohcivar.h
--- 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))
 
 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);

Attachment: pgp00000.pgp
Description: signature

Reply via email to