diff options
author | alfred <alfred@FreeBSD.org> | 2009-08-24 05:05:38 +0000 |
---|---|---|
committer | alfred <alfred@FreeBSD.org> | 2009-08-24 05:05:38 +0000 |
commit | 52d0adc8f68b84e4f3af6d83cf3502ed56aafe3d (patch) | |
tree | d200d383126920559f7a10faf77a906d8a006992 /sys/dev/usb/usb_device.c | |
parent | d1d25e4acf9faef5a904928fe3345533e15d2575 (diff) | |
download | FreeBSD-src-52d0adc8f68b84e4f3af6d83cf3502ed56aafe3d.zip FreeBSD-src-52d0adc8f68b84e4f3af6d83cf3502ed56aafe3d.tar.gz |
- Patch to allow USB controller to resume operation after
being polled.
- Remove the need for Giant from the USB HUB driver.
- Leave device unconfigured instead of disabling the USB port
when Huawei Autoinstall disk detection triggers. This should
fix problems that the Huawei device is not detected after
Autoinstall eject is issued.
- Reported by: Nikolay Antsiferov
- Fix memory use after free race for USB character devices.
- Reported by: Lucius Windschuh
- Factor out the enumeration lock into three functions to make the
coming newbus lock conversion more easy.
- usbd_enum_lock
- usbd_enum_unlock
- usbd_enum_is_locked
Submitted by: hps
Diffstat (limited to 'sys/dev/usb/usb_device.c')
-rw-r--r-- | sys/dev/usb/usb_device.c | 80 |
1 files changed, 58 insertions, 22 deletions
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c index 2d34017..635a9b1 100644 --- a/sys/dev/usb/usb_device.c +++ b/sys/dev/usb/usb_device.c @@ -402,11 +402,11 @@ usb_unconfigure(struct usb_device *udev, uint8_t flag) 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, uint8_t flag) 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 *udev, uint8_t index) 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_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); } if (iface == NULL) { err = USB_ERR_INVAL; @@ -863,9 +861,9 @@ usbd_set_alt_interface_index(struct usb_device *udev, 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 *udev, uint8_t iface_index) 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 *udev, uint8_t iface_index) } } 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 *udev) { 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)); +} |