Author: alfred
Date: Wed Sep  2 02:12:07 2009
New Revision: 196746
URL: http://svn.freebsd.org/changeset/base/196746

Log:
  MFC: r196489,196498
  Critical USB bugfixes for 8.0
  
  Approved by:    re

Modified:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/sys/dev/usb/input/ukbd.c
  stable/8/sys/dev/usb/usb_dev.c
  stable/8/sys/dev/usb/usb_device.c
  stable/8/sys/dev/usb/usb_device.h
  stable/8/sys/dev/usb/usb_handle_request.c
  stable/8/sys/dev/usb/usb_hub.c
  stable/8/sys/dev/usb/usb_process.c
  stable/8/sys/dev/usb/usb_process.h
  stable/8/sys/dev/usb/usb_transfer.c
  stable/8/sys/dev/xen/xenpci/   (props changed)

Modified: stable/8/sys/dev/usb/input/ukbd.c
==============================================================================
--- stable/8/sys/dev/usb/input/ukbd.c   Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/input/ukbd.c   Wed Sep  2 02:12:07 2009        
(r196746)
@@ -96,10 +96,14 @@ __FBSDID("$FreeBSD$");
 
 #if USB_DEBUG
 static int ukbd_debug = 0;
+static int ukbd_no_leds = 0;
 
 SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd");
 SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW,
     &ukbd_debug, 0, "Debug level");
+SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, no_leds, CTLFLAG_RW,
+    &ukbd_no_leds, 0, "Disables setting of keyboard leds");
+
 #endif
 
 #define        UPROTO_BOOT_KEYBOARD 1
@@ -165,6 +169,7 @@ struct ukbd_softc {
 #define        UKBD_FLAG_APPLE_EJECT   0x0040
 #define        UKBD_FLAG_APPLE_FN      0x0080
 #define        UKBD_FLAG_APPLE_SWAP    0x0100
+#define        UKBD_FLAG_TIMER_RUNNING 0x0200
 
        int32_t sc_mode;                /* input mode (K_XLATE,K_RAW,K_CODE) */
        int32_t sc_state;               /* shift/lock key state */
@@ -279,6 +284,25 @@ static device_attach_t ukbd_attach;
 static device_detach_t ukbd_detach;
 static device_resume_t ukbd_resume;
 
+static uint8_t
+ukbd_any_key_pressed(struct ukbd_softc *sc)
+{
+       uint8_t i;
+       uint8_t j;
+
+       for (j = i = 0; i < UKBD_NKEYCODE; i++)
+               j |= sc->sc_odata.keycode[i];
+
+       return (j ? 1 : 0);
+}
+
+static void
+ukbd_start_timer(struct ukbd_softc *sc)
+{
+       sc->sc_flags |= UKBD_FLAG_TIMER_RUNNING;
+       usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc);
+}
+
 static void
 ukbd_put_key(struct ukbd_softc *sc, uint32_t key)
 {
@@ -308,11 +332,15 @@ ukbd_do_poll(struct ukbd_softc *sc, uint
 
                usbd_transfer_poll(sc->sc_xfer, UKBD_N_TRANSFER);
 
-               DELAY(1000);    /* delay 1 ms */
+               /* Delay-optimised support for repetition of keys */
 
-               sc->sc_time_ms++;
+               if (ukbd_any_key_pressed(sc)) {
+                       /* a key is pressed - need timekeeping */
+                       DELAY(1000);
 
-               /* support repetition of keys: */
+                       /* 1 millisecond has passed */
+                       sc->sc_time_ms += 1;
+               }
 
                ukbd_interrupt(sc);
 
@@ -470,7 +498,11 @@ ukbd_timeout(void *arg)
        }
        ukbd_interrupt(sc);
 
-       usb_callout_reset(&sc->sc_callout, hz / 40, &ukbd_timeout, sc);
+       if (ukbd_any_key_pressed(sc)) {
+               ukbd_start_timer(sc);
+       } else {
+               sc->sc_flags &= ~UKBD_FLAG_TIMER_RUNNING;
+       }
 }
 
 static uint8_t
@@ -582,6 +614,12 @@ ukbd_intr_callback(struct usb_xfer *xfer
                        }
 
                        ukbd_interrupt(sc);
+
+                       if (!(sc->sc_flags & UKBD_FLAG_TIMER_RUNNING)) {
+                               if (ukbd_any_key_pressed(sc)) {
+                                       ukbd_start_timer(sc);
+                               }
+                       }
                }
        case USB_ST_SETUP:
 tr_setup:
@@ -613,6 +651,11 @@ ukbd_set_leds_callback(struct usb_xfer *
        uint8_t buf[2];
        struct ukbd_softc *sc = usbd_xfer_softc(xfer);
 
+#if USB_DEBUG
+       if (ukbd_no_leds)
+               return;
+#endif
+
        switch (USB_GET_STATE(xfer)) {
        case USB_ST_TRANSFERRED:
        case USB_ST_SETUP:
@@ -647,11 +690,11 @@ ukbd_set_leds_callback(struct usb_xfer *
                        usbd_xfer_set_frames(xfer, 2);
                        usbd_transfer_submit(xfer);
                }
-               return;
+               break;
 
        default:                        /* Error */
                DPRINTFN(0, "error=%s\n", usbd_errstr(error));
-               return;
+               break;
        }
 }
 
@@ -745,8 +788,6 @@ ukbd_attach(device_t dev)
        uint16_t n;
        uint16_t hid_len;
 
-       mtx_assert(&Giant, MA_OWNED);
-
        kbd_init_struct(kbd, UKBD_DRIVER_NAME, KB_OTHER, unit, 0, 0, 0);
 
        kbd->kb_data = (void *)sc;
@@ -831,7 +872,7 @@ ukbd_attach(device_t dev)
        }
 
        /* ignore if SETIDLE fails, hence it is not crucial */
-       err = usbd_req_set_idle(sc->sc_udev, &Giant, sc->sc_iface_index, 0, 0);
+       err = usbd_req_set_idle(sc->sc_udev, NULL, sc->sc_iface_index, 0, 0);
 
        ukbd_ioctl(kbd, KDSETLED, (caddr_t)&sc->sc_state);
 
@@ -862,9 +903,6 @@ ukbd_attach(device_t dev)
 
        usbd_transfer_start(sc->sc_xfer[UKBD_INTR_DT]);
 
-       /* start the timer */
-
-       ukbd_timeout(sc);
        mtx_unlock(&Giant);
        return (0);                     /* success */
 
@@ -879,8 +917,6 @@ ukbd_detach(device_t dev)
        struct ukbd_softc *sc = device_get_softc(dev);
        int error;
 
-       mtx_assert(&Giant, MA_OWNED);
-
        DPRINTF("\n");
 
        if (sc->sc_flags & UKBD_FLAG_POLLING) {
@@ -927,8 +963,6 @@ ukbd_resume(device_t dev)
 {
        struct ukbd_softc *sc = device_get_softc(dev);
 
-       mtx_assert(&Giant, MA_OWNED);
-
        ukbd_clear_state(&sc->sc_kbd);
 
        return (0);
@@ -945,7 +979,6 @@ ukbd_configure(int flags)
 static int
 ukbd__probe(int unit, void *arg, int flags)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (ENXIO);
 }
 
@@ -953,7 +986,6 @@ ukbd__probe(int unit, void *arg, int fla
 static int
 ukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (ENXIO);
 }
 
@@ -961,7 +993,6 @@ ukbd_init(int unit, keyboard_t **kbdp, v
 static int
 ukbd_test_if(keyboard_t *kbd)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (0);
 }
 
@@ -969,7 +1000,6 @@ ukbd_test_if(keyboard_t *kbd)
 static int
 ukbd_term(keyboard_t *kbd)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (ENXIO);
 }
 
@@ -977,7 +1007,6 @@ ukbd_term(keyboard_t *kbd)
 static int
 ukbd_intr(keyboard_t *kbd, void *arg)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (0);
 }
 
@@ -985,7 +1014,6 @@ ukbd_intr(keyboard_t *kbd, void *arg)
 static int
 ukbd_lock(keyboard_t *kbd, int lock)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (1);
 }
 
@@ -1004,7 +1032,6 @@ ukbd_enable(keyboard_t *kbd)
                mtx_unlock(&Giant);
                return (retval);
        }
-       mtx_assert(&Giant, MA_OWNED);
        KBD_ACTIVATE(kbd);
        return (0);
 }
@@ -1021,7 +1048,6 @@ ukbd_disable(keyboard_t *kbd)
                mtx_unlock(&Giant);
                return (retval);
        }
-       mtx_assert(&Giant, MA_OWNED);
        KBD_DEACTIVATE(kbd);
        return (0);
 }
@@ -1050,7 +1076,6 @@ ukbd_check(keyboard_t *kbd)
                if (!mtx_owned(&Giant))
                        return (0);
        }
-       mtx_assert(&Giant, MA_OWNED);
 
 #ifdef UKBD_EMULATE_ATSCANCODE
        if (sc->sc_buffered_char[0]) {
@@ -1086,7 +1111,6 @@ ukbd_check_char(keyboard_t *kbd)
                if (!mtx_owned(&Giant))
                        return (0);
        }
-       mtx_assert(&Giant, MA_OWNED);
 
        if ((sc->sc_composed_char > 0) &&
            (!(sc->sc_flags & UKBD_FLAG_COMPOSE))) {
@@ -1125,7 +1149,6 @@ ukbd_read(keyboard_t *kbd, int wait)
                if (!mtx_owned(&Giant))
                        return (-1);
        }
-       mtx_assert(&Giant, MA_OWNED);
 
 #ifdef UKBD_EMULATE_ATSCANCODE
        if (sc->sc_buffered_char[0]) {
@@ -1190,7 +1213,6 @@ ukbd_read_char(keyboard_t *kbd, int wait
                if (!mtx_owned(&Giant))
                        return (NOKEY);
        }
-       mtx_assert(&Giant, MA_OWNED);
 
 next_code:
 
@@ -1393,7 +1415,6 @@ ukbd_ioctl(keyboard_t *kbd, u_long cmd, 
                 */
                return (EINVAL);
        }
-       mtx_assert(&Giant, MA_OWNED);
 
        switch (cmd) {
        case KDGKBMODE:         /* get keyboard mode */
@@ -1527,7 +1548,6 @@ ukbd_clear_state(keyboard_t *kbd)
        if (!mtx_owned(&Giant)) {
                return;                 /* XXX */
        }
-       mtx_assert(&Giant, MA_OWNED);
 
        sc->sc_flags &= ~(UKBD_FLAG_COMPOSE | UKBD_FLAG_POLLING);
        sc->sc_state &= LOCK_MASK;      /* preserve locking key state */
@@ -1547,7 +1567,6 @@ ukbd_clear_state(keyboard_t *kbd)
 static int
 ukbd_get_state(keyboard_t *kbd, void *buf, size_t len)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (len == 0) ? 1 : -1;
 }
 
@@ -1555,7 +1574,6 @@ ukbd_get_state(keyboard_t *kbd, void *bu
 static int
 ukbd_set_state(keyboard_t *kbd, void *buf, size_t len)
 {
-       mtx_assert(&Giant, MA_OWNED);
        return (EINVAL);
 }
 
@@ -1572,7 +1590,6 @@ ukbd_poll(keyboard_t *kbd, int on)
                mtx_unlock(&Giant);
                return (retval);
        }
-       mtx_assert(&Giant, MA_OWNED);
 
        if (on) {
                sc->sc_flags |= UKBD_FLAG_POLLING;

Modified: stable/8/sys/dev/usb/usb_dev.c
==============================================================================
--- stable/8/sys/dev/usb/usb_dev.c      Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_dev.c      Wed Sep  2 02:12:07 2009        
(r196746)
@@ -217,7 +217,7 @@ usb_ref_device(struct usb_cdev_privdata 
                 * We need to grab the sx-lock before grabbing the
                 * FIFO refs to avoid deadlock at detach!
                 */
-               sx_xlock(cpd->udev->default_sx + 1);
+               usbd_enum_lock(cpd->udev);
 
                mtx_lock(&usb_ref_lock);
 
@@ -275,14 +275,12 @@ usb_ref_device(struct usb_cdev_privdata 
        }
        mtx_unlock(&usb_ref_lock);
 
-       if (crd->is_uref) {
-               mtx_lock(&Giant);       /* XXX */
-       }
        return (0);
 
 error:
        if (crd->is_uref) {
-               sx_unlock(cpd->udev->default_sx + 1);
+               usbd_enum_unlock(cpd->udev);
+
                if (--(cpd->udev->refcount) == 0) {
                        cv_signal(cpd->udev->default_cv + 1);
                }
@@ -334,10 +332,9 @@ usb_unref_device(struct usb_cdev_privdat
 
        DPRINTFN(2, "cpd=%p is_uref=%d\n", cpd, crd->is_uref);
 
-       if (crd->is_uref) {
-               mtx_unlock(&Giant);     /* XXX */
-               sx_unlock(cpd->udev->default_sx + 1);
-       }
+       if (crd->is_uref)
+               usbd_enum_unlock(cpd->udev);
+
        mtx_lock(&usb_ref_lock);
        if (crd->is_read) {
                if (--(crd->rxfifo->refcount) == 0) {
@@ -1042,9 +1039,9 @@ usb_ioctl(struct cdev *dev, u_long cmd, 
         * reference if we need it!
         */
        err = usb_ref_device(cpd, &refs, 0 /* no uref */ );
-       if (err) {
+       if (err)
                return (ENXIO);
-       }
+
        fflags = cpd->fflags;
 
        f = NULL;                       /* set default value */

Modified: stable/8/sys/dev/usb/usb_device.c
==============================================================================
--- stable/8/sys/dev/usb/usb_device.c   Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_device.c   Wed Sep  2 02:12:07 2009        
(r196746)
@@ -402,11 +402,11 @@ usb_unconfigure(struct usb_device *udev,
        uint8_t do_unlock;
 
        /* automatic locking */
-       if (sx_xlocked(udev->default_sx + 1)) {
+       if (usbd_enum_is_locked(udev)) {
                do_unlock = 0;
        } else {
                do_unlock = 1;
-               sx_xlock(udev->default_sx + 1);
+               usbd_enum_lock(udev);
        }
 
        /* detach all interface drivers */
@@ -442,9 +442,8 @@ usb_unconfigure(struct usb_device *udev,
        udev->curr_config_no = USB_UNCONFIG_NO;
        udev->curr_config_index = USB_UNCONFIG_INDEX;
 
-       if (do_unlock) {
-               sx_unlock(udev->default_sx + 1);
-       }
+       if (do_unlock)
+               usbd_enum_unlock(udev);
 }
 
 /*------------------------------------------------------------------------*
@@ -472,11 +471,11 @@ usbd_set_config_index(struct usb_device 
        DPRINTFN(6, "udev=%p index=%d\n", udev, index);
 
        /* automatic locking */
-       if (sx_xlocked(udev->default_sx + 1)) {
+       if (usbd_enum_is_locked(udev)) {
                do_unlock = 0;
        } else {
                do_unlock = 1;
-               sx_xlock(udev->default_sx + 1);
+               usbd_enum_lock(udev);
        }
 
        usb_unconfigure(udev, USB_UNCFG_FLAG_FREE_SUBDEV);
@@ -585,9 +584,8 @@ done:
        if (err) {
                usb_unconfigure(udev, USB_UNCFG_FLAG_FREE_SUBDEV);
        }
-       if (do_unlock) {
-               sx_unlock(udev->default_sx + 1);
-       }
+       if (do_unlock)
+               usbd_enum_unlock(udev);
        return (err);
 }
 
@@ -823,11 +821,11 @@ usbd_set_alt_interface_index(struct usb_
        uint8_t do_unlock;
 
        /* automatic locking */
-       if (sx_xlocked(udev->default_sx + 1)) {
+       if (usbd_enum_is_locked(udev)) {
                do_unlock = 0;
        } else {
                do_unlock = 1;
-               sx_xlock(udev->default_sx + 1);
+               usbd_enum_lock(udev);
        }
        if (iface == NULL) {
                err = USB_ERR_INVAL;
@@ -863,9 +861,9 @@ usbd_set_alt_interface_index(struct usb_
            iface->idesc->bAlternateSetting);
 
 done:
-       if (do_unlock) {
-               sx_unlock(udev->default_sx + 1);
-       }
+       if (do_unlock)
+               usbd_enum_unlock(udev);
+
        return (err);
 }
 
@@ -1230,11 +1228,11 @@ usb_probe_and_attach(struct usb_device *
                return (USB_ERR_INVAL);
        }
        /* automatic locking */
-       if (sx_xlocked(udev->default_sx + 1)) {
+       if (usbd_enum_is_locked(udev)) {
                do_unlock = 0;
        } else {
                do_unlock = 1;
-               sx_xlock(udev->default_sx + 1);
+               usbd_enum_lock(udev);
        }
 
        if (udev->curr_config_index == USB_UNCONFIG_INDEX) {
@@ -1315,9 +1313,9 @@ usb_probe_and_attach(struct usb_device *
                }
        }
 done:
-       if (do_unlock) {
-               sx_unlock(udev->default_sx + 1);
-       }
+       if (do_unlock)
+               usbd_enum_unlock(udev);
+
        return (0);
 }
 
@@ -1779,7 +1777,8 @@ repeat_set_config:
                        }
                } else if (usb_test_huawei_autoinst_p(udev, &uaa) == 0) {
                        DPRINTFN(0, "Found Huawei auto-install disk!\n");
-                       err = USB_ERR_STALLED;  /* fake an error */
+                       /* leave device unconfigured */
+                       usb_unconfigure(udev, USB_UNCFG_FLAG_FREE_SUBDEV);
                }
        } else {
                err = 0;                /* set success */
@@ -1902,15 +1901,18 @@ static void
 usb_cdev_free(struct usb_device *udev)
 {
        struct usb_fs_privdata* pd;
+       struct cdev* pcdev;
 
        DPRINTFN(2, "Freeing device nodes\n");
 
        while ((pd = LIST_FIRST(&udev->pd_list)) != NULL) {
                KASSERT(pd->cdev->si_drv1 == pd, ("privdata corrupt"));
 
-               destroy_dev_sched_cb(pd->cdev, usb_cdev_cleanup, pd);
+               pcdev = pd->cdev;
                pd->cdev = NULL;
                LIST_REMOVE(pd, pd_next);
+               if (pcdev != NULL)
+                       destroy_dev_sched_cb(pcdev, usb_cdev_cleanup, pd);
        }
 }
 
@@ -2448,3 +2450,37 @@ usbd_device_attached(struct usb_device *
 {
        return (udev->state > USB_STATE_DETACHED);
 }
+
+/* The following function locks enumerating the given USB device. */
+
+void
+usbd_enum_lock(struct usb_device *udev)
+{
+       sx_xlock(udev->default_sx + 1);
+       /* 
+        * NEWBUS LOCK NOTE: We should check if any parent SX locks
+        * are locked before locking Giant. Else the lock can be
+        * locked multiple times.
+        */
+       mtx_lock(&Giant);
+}
+
+/* The following function unlocks enumerating the given USB device. */
+
+void
+usbd_enum_unlock(struct usb_device *udev)
+{
+       mtx_unlock(&Giant);
+       sx_xunlock(udev->default_sx + 1);
+}
+
+/*
+ * The following function checks the enumerating lock for the given
+ * USB device.
+ */
+
+uint8_t
+usbd_enum_is_locked(struct usb_device *udev)
+{
+       return (sx_xlocked(udev->default_sx + 1));
+}

Modified: stable/8/sys/dev/usb/usb_device.h
==============================================================================
--- stable/8/sys/dev/usb/usb_device.h   Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_device.h   Wed Sep  2 02:12:07 2009        
(r196746)
@@ -211,5 +211,8 @@ uint8_t     usb_peer_can_wakeup(struct usb_d
 struct usb_endpoint *usb_endpoint_foreach(struct usb_device *udev, struct 
usb_endpoint *ep);
 void   usb_set_device_state(struct usb_device *udev,
            enum usb_dev_state state);
+void   usbd_enum_lock(struct usb_device *);
+void   usbd_enum_unlock(struct usb_device *);
+uint8_t usbd_enum_is_locked(struct usb_device *);
 
 #endif                                 /* _USB_DEVICE_H_ */

Modified: stable/8/sys/dev/usb/usb_handle_request.c
==============================================================================
--- stable/8/sys/dev/usb/usb_handle_request.c   Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_handle_request.c   Wed Sep  2 02:12:07 2009        
(r196746)
@@ -152,8 +152,8 @@ usb_handle_set_config(struct usb_xfer *x
         * attach:
         */
        USB_XFER_UNLOCK(xfer);
-       mtx_lock(&Giant);               /* XXX */
-       sx_xlock(udev->default_sx + 1);
+
+       usbd_enum_lock(udev);
 
        if (conf_no == USB_UNCONFIG_NO) {
                conf_no = USB_UNCONFIG_INDEX;
@@ -176,8 +176,7 @@ usb_handle_set_config(struct usb_xfer *x
                goto done;
        }
 done:
-       mtx_unlock(&Giant);             /* XXX */
-       sx_unlock(udev->default_sx + 1);
+       usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (err);
 }
@@ -190,19 +189,19 @@ usb_check_alt_setting(struct usb_device 
        usb_error_t err = 0;
 
        /* automatic locking */
-       if (sx_xlocked(udev->default_sx + 1)) {
+       if (usbd_enum_is_locked(udev)) {
                do_unlock = 0;
        } else {
                do_unlock = 1;
-               sx_xlock(udev->default_sx + 1);
+               usbd_enum_lock(udev);
        }
 
        if (alt_index >= usbd_get_no_alts(udev->cdesc, iface->idesc))
                err = USB_ERR_INVAL;
 
-       if (do_unlock) {
-               sx_unlock(udev->default_sx + 1);
-       }
+       if (do_unlock)
+               usbd_enum_unlock(udev);
+
        return (err);
 }
 
@@ -236,8 +235,8 @@ usb_handle_iface_request(struct usb_xfer
         * attach:
         */
        USB_XFER_UNLOCK(xfer);
-       mtx_lock(&Giant);               /* XXX */
-       sx_xlock(udev->default_sx + 1);
+
+       usbd_enum_lock(udev);
 
        error = ENXIO;
 
@@ -353,20 +352,17 @@ tr_repeat:
                goto tr_stalled;
        }
 tr_valid:
-       mtx_unlock(&Giant);
-       sx_unlock(udev->default_sx + 1);
+       usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (0);
 
 tr_short:
-       mtx_unlock(&Giant);
-       sx_unlock(udev->default_sx + 1);
+       usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (USB_ERR_SHORT_XFER);
 
 tr_stalled:
-       mtx_unlock(&Giant);
-       sx_unlock(udev->default_sx + 1);
+       usbd_enum_unlock(udev);
        USB_XFER_LOCK(xfer);
        return (USB_ERR_STALLED);
 }

Modified: stable/8/sys/dev/usb/usb_hub.c
==============================================================================
--- stable/8/sys/dev/usb/usb_hub.c      Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_hub.c      Wed Sep  2 02:12:07 2009        
(r196746)
@@ -96,6 +96,7 @@ struct uhub_current_state {
 struct uhub_softc {
        struct uhub_current_state sc_st;/* current state */
        device_t sc_dev;                /* base device */
+       struct mtx sc_mtx;              /* our mutex */
        struct usb_device *sc_udev;     /* USB device */
        struct usb_xfer *sc_xfer[UHUB_N_TRANSFER];      /* interrupt xfer */
        uint8_t sc_flags;
@@ -428,7 +429,6 @@ repeat:
                mode = USB_MODE_HOST;
 
        /* need to create a new child */
-
        child = usb_alloc_device(sc->sc_dev, udev->bus, udev,
            udev->depth + 1, portno - 1, portno, speed, mode);
        if (child == NULL) {
@@ -691,6 +691,8 @@ uhub_attach(device_t dev)
        sc->sc_udev = udev;
        sc->sc_dev = dev;
 
+       mtx_init(&sc->sc_mtx, "USB HUB mutex", NULL, MTX_DEF);
+
        snprintf(sc->sc_name, sizeof(sc->sc_name), "%s",
            device_get_nameunit(dev));
 
@@ -774,7 +776,7 @@ uhub_attach(device_t dev)
        } else {
                /* normal HUB */
                err = usbd_transfer_setup(udev, &iface_index, sc->sc_xfer,
-                   uhub_config, UHUB_N_TRANSFER, sc, &Giant);
+                   uhub_config, UHUB_N_TRANSFER, sc, &sc->sc_mtx);
        }
        if (err) {
                DPRINTFN(0, "cannot setup interrupt transfer, "
@@ -850,9 +852,9 @@ uhub_attach(device_t dev)
        /* Start the interrupt endpoint, if any */
 
        if (sc->sc_xfer[0] != NULL) {
-               USB_XFER_LOCK(sc->sc_xfer[0]);
+               mtx_lock(&sc->sc_mtx);
                usbd_transfer_start(sc->sc_xfer[0]);
-               USB_XFER_UNLOCK(sc->sc_xfer[0]);
+               mtx_unlock(&sc->sc_mtx);
        }
 
        /* Enable automatic power save on all USB HUBs */
@@ -868,6 +870,9 @@ error:
                free(udev->hub, M_USBDEV);
                udev->hub = NULL;
        }
+
+       mtx_destroy(&sc->sc_mtx);
+
        return (ENXIO);
 }
 
@@ -908,6 +913,9 @@ uhub_detach(device_t dev)
 
        free(hub, M_USBDEV);
        sc->sc_udev->hub = NULL;
+
+       mtx_destroy(&sc->sc_mtx);
+
        return (0);
 }
 
@@ -1775,10 +1783,13 @@ usb_dev_resume_peer(struct usb_device *u
                /* always update hardware power! */
                (bus->methods->set_hw_power) (bus);
        }
-       sx_xlock(udev->default_sx + 1);
+
+       usbd_enum_lock(udev);
+
        /* notify all sub-devices about resume */
        err = usb_suspend_resume(udev, 0);
-       sx_unlock(udev->default_sx + 1);
+
+       usbd_enum_unlock(udev);
 
        /* check if peer has wakeup capability */
        if (usb_peer_can_wakeup(udev)) {
@@ -1844,10 +1855,12 @@ repeat:
                }
        }
 
-       sx_xlock(udev->default_sx + 1);
+       usbd_enum_lock(udev);
+
        /* notify all sub-devices about suspend */
        err = usb_suspend_resume(udev, 1);
-       sx_unlock(udev->default_sx + 1);
+
+       usbd_enum_unlock(udev);
 
        if (usb_peer_can_wakeup(udev)) {
                /* allow device to do remote wakeup */

Modified: stable/8/sys/dev/usb/usb_process.c
==============================================================================
--- stable/8/sys/dev/usb/usb_process.c  Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_process.c  Wed Sep  2 02:12:07 2009        
(r196746)
@@ -457,3 +457,29 @@ usb_proc_drain(struct usb_process *up)
        }
        mtx_unlock(up->up_mtx);
 }
+
+/*------------------------------------------------------------------------*
+ *     usb_proc_rewakeup
+ *
+ * This function is called to re-wakeup the the given USB
+ * process. This usually happens after that the USB system has been in
+ * polling mode, like during a panic. This function must be called
+ * having "up->up_mtx" locked.
+ *------------------------------------------------------------------------*/
+void
+usb_proc_rewakeup(struct usb_process *up)
+{
+       /* check if not initialised */
+       if (up->up_mtx == NULL)
+               return;
+       /* check if gone */
+       if (up->up_gone)
+               return;
+
+       mtx_assert(up->up_mtx, MA_OWNED);
+
+       if (up->up_msleep == 0) {
+               /* re-wakeup */
+               cv_signal(&up->up_cv);
+       }
+}

Modified: stable/8/sys/dev/usb/usb_process.h
==============================================================================
--- stable/8/sys/dev/usb/usb_process.h  Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_process.h  Wed Sep  2 02:12:07 2009        
(r196746)
@@ -75,5 +75,6 @@ void  usb_proc_drain(struct usb_process *
 void   usb_proc_mwait(struct usb_process *up, void *pm0, void *pm1);
 void   usb_proc_free(struct usb_process *up);
 void   *usb_proc_msignal(struct usb_process *up, void *pm0, void *pm1);
+void   usb_proc_rewakeup(struct usb_process *up);
 
 #endif                                 /* _USB_PROCESS_H_ */

Modified: stable/8/sys/dev/usb/usb_transfer.c
==============================================================================
--- stable/8/sys/dev/usb/usb_transfer.c Wed Sep  2 00:39:59 2009        
(r196745)
+++ stable/8/sys/dev/usb/usb_transfer.c Wed Sep  2 02:12:07 2009        
(r196746)
@@ -2907,13 +2907,9 @@ usbd_transfer_poll(struct usb_xfer **ppx
                }
 
                /* 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 */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to