summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/usb_device.c
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2009-08-24 05:05:38 +0000
committeralfred <alfred@FreeBSD.org>2009-08-24 05:05:38 +0000
commit52d0adc8f68b84e4f3af6d83cf3502ed56aafe3d (patch)
treed200d383126920559f7a10faf77a906d8a006992 /sys/dev/usb/usb_device.c
parentd1d25e4acf9faef5a904928fe3345533e15d2575 (diff)
downloadFreeBSD-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.c80
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));
+}
OpenPOWER on IntegriCloud