svn commit: r195960 - in head/sys/dev/usb: . controller input

Alfred Perlstein alfred at FreeBSD.org
Thu Jul 30 00:14:35 UTC 2009


Author: alfred
Date: Thu Jul 30 00:14:34 2009
New Revision: 195960
URL: http://svn.freebsd.org/changeset/base/195960

Log:
  USB CORE:
  - Add minimum polling support to drive UMASS
    and UKBD in case of panic.
  - Add extra check to ukbd probe to fix problem about
    mouse devices attaching like keyboards.
  - P4 ID: 166148
  
  Submitted by:	hps
  Approved by:	re

Modified:
  head/sys/dev/usb/controller/at91dci.c
  head/sys/dev/usb/controller/atmegadci.c
  head/sys/dev/usb/controller/avr32dci.c
  head/sys/dev/usb/controller/ehci.c
  head/sys/dev/usb/controller/musb_otg.c
  head/sys/dev/usb/controller/ohci.c
  head/sys/dev/usb/controller/uhci.c
  head/sys/dev/usb/controller/uss820dci.c
  head/sys/dev/usb/input/ukbd.c
  head/sys/dev/usb/usb_controller.h
  head/sys/dev/usb/usb_transfer.c

Modified: head/sys/dev/usb/controller/at91dci.c
==============================================================================
--- head/sys/dev/usb/controller/at91dci.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/at91dci.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -2326,4 +2326,5 @@ struct usb_bus_methods at91dci_bus_metho
 	.set_stall = &at91dci_set_stall,
 	.clear_stall = &at91dci_clear_stall,
 	.roothub_exec = &at91dci_roothub_exec,
+	.xfer_poll = &at91dci_do_poll,
 };

Modified: head/sys/dev/usb/controller/atmegadci.c
==============================================================================
--- head/sys/dev/usb/controller/atmegadci.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/atmegadci.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -2143,4 +2143,5 @@ struct usb_bus_methods atmegadci_bus_met
 	.set_stall = &atmegadci_set_stall,
 	.clear_stall = &atmegadci_clear_stall,
 	.roothub_exec = &atmegadci_roothub_exec,
+	.xfer_poll = &atmegadci_do_poll,
 };

Modified: head/sys/dev/usb/controller/avr32dci.c
==============================================================================
--- head/sys/dev/usb/controller/avr32dci.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/avr32dci.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -2081,4 +2081,5 @@ struct usb_bus_methods avr32dci_bus_meth
 	.set_stall = &avr32dci_set_stall,
 	.clear_stall = &avr32dci_clear_stall,
 	.roothub_exec = &avr32dci_roothub_exec,
+	.xfer_poll = &avr32dci_do_poll,
 };

Modified: head/sys/dev/usb/controller/ehci.c
==============================================================================
--- head/sys/dev/usb/controller/ehci.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/ehci.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -3828,4 +3828,5 @@ struct usb_bus_methods ehci_bus_methods 
 	.device_suspend = ehci_device_suspend,
 	.set_hw_power = ehci_set_hw_power,
 	.roothub_exec = ehci_roothub_exec,
+	.xfer_poll = ehci_do_poll,
 };

Modified: head/sys/dev/usb/controller/musb_otg.c
==============================================================================
--- head/sys/dev/usb/controller/musb_otg.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/musb_otg.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -2736,4 +2736,5 @@ struct usb_bus_methods musbotg_bus_metho
 	.set_stall = &musbotg_set_stall,
 	.clear_stall = &musbotg_clear_stall,
 	.roothub_exec = &musbotg_roothub_exec,
+	.xfer_poll = &musbotg_do_poll,
 };

Modified: head/sys/dev/usb/controller/ohci.c
==============================================================================
--- head/sys/dev/usb/controller/ohci.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/ohci.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -2756,4 +2756,5 @@ struct usb_bus_methods ohci_bus_methods 
 	.device_suspend = ohci_device_suspend,
 	.set_hw_power = ohci_set_hw_power,
 	.roothub_exec = ohci_roothub_exec,
+	.xfer_poll = ohci_do_poll,
 };

Modified: head/sys/dev/usb/controller/uhci.c
==============================================================================
--- head/sys/dev/usb/controller/uhci.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/uhci.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -3251,4 +3251,5 @@ struct usb_bus_methods uhci_bus_methods 
 	.device_suspend = uhci_device_suspend,
 	.set_hw_power = uhci_set_hw_power,
 	.roothub_exec = uhci_roothub_exec,
+	.xfer_poll = uhci_do_poll,
 };

Modified: head/sys/dev/usb/controller/uss820dci.c
==============================================================================
--- head/sys/dev/usb/controller/uss820dci.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/controller/uss820dci.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -2360,4 +2360,5 @@ struct usb_bus_methods uss820dci_bus_met
 	.set_stall = &uss820dci_set_stall,
 	.clear_stall = &uss820dci_clear_stall,
 	.roothub_exec = &uss820dci_roothub_exec,
+	.xfer_poll = &uss820dci_do_poll,
 };

Modified: head/sys/dev/usb/input/ukbd.c
==============================================================================
--- head/sys/dev/usb/input/ukbd.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/input/ukbd.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -299,6 +299,28 @@ ukbd_put_key(struct ukbd_softc *sc, uint
 	}
 }
 
+static void
+ukbd_do_poll(struct ukbd_softc *sc, uint8_t wait)
+{
+	DPRINTFN(2, "polling\n");
+
+	while (sc->sc_inputs == 0) {
+
+		usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER);
+
+		DELAY(1000);	/* delay 1 ms */
+
+		sc->sc_time_ms++;
+
+		/* support repetition of keys: */
+
+		ukbd_interrupt(sc);
+
+		if (!wait)
+			break;
+	}
+}
+
 static int32_t
 ukbd_get_key(struct ukbd_softc *sc, uint8_t wait)
 {
@@ -311,24 +333,7 @@ ukbd_get_key(struct ukbd_softc *sc, uint
 		usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]);
 	}
 	if (sc->sc_flags & UKBD_FLAG_POLLING) {
-		DPRINTFN(2, "polling\n");
-
-		while (sc->sc_inputs == 0) {
-
-			usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER);
-
-			DELAY(1000);	/* delay 1 ms */
-
-			sc->sc_time_ms++;
-
-			/* support repetition of keys: */
-
-			ukbd_interrupt(sc);
-
-			if (!wait) {
-				break;
-			}
-		}
+		ukbd_do_poll(sc, wait);
 	}
 	if (sc->sc_inputs == 0) {
 		c = -1;
@@ -706,7 +711,15 @@ ukbd_probe(device_t dev)
 	if (error)
 		return (ENXIO);
 
+	/* 
+	 * NOTE: we currently don't support USB mouse and USB keyboard
+	 * on the same USB endpoint.
+	 */
 	if (hid_is_collection(d_ptr, d_len,
+	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) {
+		/* most likely a mouse */
+		error = ENXIO;
+	} else if (hid_is_collection(d_ptr, d_len,
 	    HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) {
 		if (usb_test_quirk(uaa, UQ_KBD_IGNORE))
 			error = ENXIO;
@@ -983,6 +996,14 @@ ukbd_lock(keyboard_t *kbd, int lock)
 static int
 ukbd_enable(keyboard_t *kbd)
 {
+	if (!mtx_owned(&Giant)) {
+		/* XXX cludge */
+		int retval;
+		mtx_lock(&Giant);
+		retval = ukbd_enable(kbd);
+		mtx_unlock(&Giant);
+		return (retval);
+	}
 	mtx_assert(&Giant, MA_OWNED);
 	KBD_ACTIVATE(kbd);
 	return (0);
@@ -992,6 +1013,14 @@ ukbd_enable(keyboard_t *kbd)
 static int
 ukbd_disable(keyboard_t *kbd)
 {
+	if (!mtx_owned(&Giant)) {
+		/* XXX cludge */
+		int retval;
+		mtx_lock(&Giant);
+		retval = ukbd_disable(kbd);
+		mtx_unlock(&Giant);
+		return (retval);
+	}
 	mtx_assert(&Giant, MA_OWNED);
 	KBD_DEACTIVATE(kbd);
 	return (0);
@@ -1003,14 +1032,26 @@ ukbd_check(keyboard_t *kbd)
 {
 	struct ukbd_softc *sc = kbd->kb_data;
 
-	if (!mtx_owned(&Giant)) {
-		return (0);		/* XXX */
+	if (!KBD_IS_ACTIVE(kbd))
+		return (0);
+
+	if (sc->sc_flags & UKBD_FLAG_POLLING) {
+		if (!mtx_owned(&Giant)) {
+			/* XXX cludge */
+			int retval;
+			mtx_lock(&Giant);
+			retval = ukbd_check(kbd);
+			mtx_unlock(&Giant);
+			return (retval);
+		}
+		ukbd_do_poll(sc, 0);
+	} else {
+		/* XXX the keyboard layer requires Giant */
+		if (!mtx_owned(&Giant))
+			return (0);
 	}
 	mtx_assert(&Giant, MA_OWNED);
 
-	if (!KBD_IS_ACTIVE(kbd)) {
-		return (0);
-	}
 #ifdef UKBD_EMULATE_ATSCANCODE
 	if (sc->sc_buffered_char[0]) {
 		return (1);
@@ -1028,14 +1069,25 @@ ukbd_check_char(keyboard_t *kbd)
 {
 	struct ukbd_softc *sc = kbd->kb_data;
 
-	if (!mtx_owned(&Giant)) {
-		return (0);		/* XXX */
+	if (!KBD_IS_ACTIVE(kbd))
+		return (0);
+
+	if (sc->sc_flags & UKBD_FLAG_POLLING) {
+		if (!mtx_owned(&Giant)) {
+			/* XXX cludge */
+			int retval;
+			mtx_lock(&Giant);
+			retval = ukbd_check_char(kbd);
+			mtx_unlock(&Giant);
+			return (retval);
+		}
+	} else {
+		/* XXX the keyboard layer requires Giant */
+		if (!mtx_owned(&Giant))
+			return (0);
 	}
 	mtx_assert(&Giant, MA_OWNED);
 
-	if (!KBD_IS_ACTIVE(kbd)) {
-		return (0);
-	}
 	if ((sc->sc_composed_char > 0) &&
 	    (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) {
 		return (1);
@@ -1056,9 +1108,22 @@ ukbd_read(keyboard_t *kbd, int wait)
 	uint32_t scancode;
 
 #endif
+	if (!KBD_IS_ACTIVE(kbd))
+		return (-1);
 
-	if (!mtx_owned(&Giant)) {
-		return -1;		/* XXX */
+	if (sc->sc_flags & UKBD_FLAG_POLLING) {
+		if (!mtx_owned(&Giant)) {
+			/* XXX cludge */
+			int retval;
+			mtx_lock(&Giant);
+			retval = ukbd_read(kbd, wait);
+			mtx_unlock(&Giant);
+			return (retval);
+		}
+	} else {
+		/* XXX the keyboard layer requires Giant */
+		if (!mtx_owned(&Giant))
+			return (-1);
 	}
 	mtx_assert(&Giant, MA_OWNED);
 
@@ -1077,9 +1142,9 @@ ukbd_read(keyboard_t *kbd, int wait)
 
 	/* XXX */
 	usbcode = ukbd_get_key(sc, (wait == FALSE) ? 0 : 1);
-	if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) {
-		return -1;
-	}
+	if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1))
+		return (-1);
+
 	++(kbd->kb_count);
 
 #ifdef UKBD_EMULATE_ATSCANCODE
@@ -1107,8 +1172,23 @@ ukbd_read_char(keyboard_t *kbd, int wait
 	uint32_t scancode;
 
 #endif
-	if (!mtx_owned(&Giant)) {
-		return (NOKEY);		/* XXX */
+
+	if (!KBD_IS_ACTIVE(kbd))
+		return (NOKEY);
+
+	if (sc->sc_flags & UKBD_FLAG_POLLING) {
+		if (!mtx_owned(&Giant)) {
+			/* XXX cludge */
+			int retval;
+			mtx_lock(&Giant);
+			retval = ukbd_read_char(kbd, wait);
+			mtx_unlock(&Giant);
+			return (retval);
+		}
+	} else {
+		/* XXX the keyboard layer requires Giant */
+		if (!mtx_owned(&Giant))
+			return (NOKEY);
 	}
 	mtx_assert(&Giant, MA_OWNED);
 
@@ -1485,7 +1565,12 @@ ukbd_poll(keyboard_t *kbd, int on)
 	struct ukbd_softc *sc = kbd->kb_data;
 
 	if (!mtx_owned(&Giant)) {
-		return (0);		/* XXX */
+		/* XXX cludge */
+		int retval;
+		mtx_lock(&Giant);
+		retval = ukbd_poll(kbd, on);
+		mtx_unlock(&Giant);
+		return (retval);
 	}
 	mtx_assert(&Giant, MA_OWNED);
 

Modified: head/sys/dev/usb/usb_controller.h
==============================================================================
--- head/sys/dev/usb/usb_controller.h	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/usb_controller.h	Thu Jul 30 00:14:34 2009	(r195960)
@@ -99,6 +99,9 @@ struct usb_bus_methods {
 	void    (*set_stall) (struct usb_device *udev, struct usb_xfer *xfer, struct usb_endpoint *ep, uint8_t *did_stall);
 	void    (*clear_stall) (struct usb_device *udev, struct usb_endpoint *ep);
 
+	/* Optional transfer polling support */
+
+	void	(*xfer_poll) (struct usb_bus *);
 };
 
 /*

Modified: head/sys/dev/usb/usb_transfer.c
==============================================================================
--- head/sys/dev/usb/usb_transfer.c	Thu Jul 30 00:13:09 2009	(r195959)
+++ head/sys/dev/usb/usb_transfer.c	Thu Jul 30 00:14:34 2009	(r195960)
@@ -2853,15 +2853,99 @@ usbd_clear_stall_callback(struct usb_xfe
 	return (1);			/* Clear Stall Finished */
 }
 
+/*------------------------------------------------------------------------*
+ *	usbd_transfer_poll
+ *
+ * The following function gets called from the USB keyboard driver and
+ * UMASS when the system has paniced.
+ *
+ * NOTE: It is currently not possible to resume normal operation on
+ * the USB controller which has been polled, due to clearing of the
+ * "up_dsleep" and "up_msleep" flags.
+ *------------------------------------------------------------------------*/
 void
 usbd_transfer_poll(struct usb_xfer **ppxfer, uint16_t max)
 {
-	static uint8_t once = 0;
-	/* polling is currently not supported */
-	if (!once) {
-		once = 1;
-		printf("usbd_transfer_poll: USB polling is "
-		    "not supported!\n");
+	struct usb_xfer *xfer;
+	struct usb_xfer_root *xroot;
+	struct usb_device *udev;
+	struct usb_proc_msg *pm;
+	uint16_t n;
+	uint16_t drop_bus;
+	uint16_t drop_xfer;
+
+	for (n = 0; n != max; n++) {
+		/* Extra checks to avoid panic */
+		xfer = ppxfer[n];
+		if (xfer == NULL)
+			continue;	/* no USB transfer */
+		xroot = xfer->xroot;
+		if (xroot == NULL)
+			continue;	/* no USB root */
+		udev = xroot->udev;
+		if (udev == NULL)
+			continue;	/* no USB device */
+		if (udev->bus == NULL)
+			continue;	/* no BUS structure */
+		if (udev->bus->methods == NULL)
+			continue;	/* no BUS methods */
+		if (udev->bus->methods->xfer_poll == NULL)
+			continue;	/* no poll method */
+
+		/* make sure that the BUS mutex is not locked */
+		drop_bus = 0;
+		while (mtx_owned(&xroot->udev->bus->bus_mtx)) {
+			mtx_unlock(&xroot->udev->bus->bus_mtx);
+			drop_bus++;
+		}
+
+		/* make sure that the transfer mutex is not locked */
+		drop_xfer = 0;
+		while (mtx_owned(xroot->xfer_mtx)) {
+			mtx_unlock(xroot->xfer_mtx);
+			drop_xfer++;
+		}
+
+		/* Make sure cv_signal() and cv_broadcast() is not called */
+		udev->bus->control_xfer_proc.up_dsleep = 0;
+		udev->bus->control_xfer_proc.up_msleep = 0;
+		udev->bus->explore_proc.up_dsleep = 0;
+		udev->bus->explore_proc.up_msleep = 0;
+		udev->bus->giant_callback_proc.up_dsleep = 0;
+		udev->bus->giant_callback_proc.up_msleep = 0;
+		udev->bus->non_giant_callback_proc.up_dsleep = 0;
+		udev->bus->non_giant_callback_proc.up_msleep = 0;
+
+		/* poll USB hardware */
+		(udev->bus->methods->xfer_poll) (udev->bus);
+
+		USB_BUS_LOCK(xroot->bus);
+
+		/* check for clear stall */
+		if (udev->default_xfer[1] != NULL) {
+
+			/* poll clear stall start */
+			pm = &udev->cs_msg[0].hdr;
+			(pm->pm_callback) (pm);
+			/* poll clear stall done thread */
+			pm = &udev->default_xfer[1]->
+			    xroot->done_m[0].hdr;
+			(pm->pm_callback) (pm);
+		}
+
+		/* poll done thread */
+		pm = &xroot->done_m[0].hdr;
+		(pm->pm_callback) (pm);
+
+		USB_BUS_UNLOCK(xroot->bus);
+
+		/* restore transfer mutex */
+		while (drop_xfer--)
+			mtx_lock(xroot->xfer_mtx);
+
+		/* restore BUS mutex */
+		while (drop_bus--)
+			mtx_lock(&xroot->udev->bus->bus_mtx);
 	}
 }
 


More information about the svn-src-all mailing list