Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: fix char-device disconnect handling

This patch (as1198) fixes a conceptual bug: Somewhere along the line
we managed to confuse USB class devices with USB char devices. As a
result, the code to send a disconnect signal to userspace would not be
built if both CONFIG_USB_DEVICE_CLASS and CONFIG_USB_DEVICEFS were
disabled.

The usb_fs_classdev_common_remove() routine has been renamed to
usbdev_remove() and it is now called whenever any USB device is
removed, not just when a class device is unregistered. The notifier
registration and unregistration calls are no longer conditionally
compiled. And since the common removal code will always be called as
part of the char device interface, there's no need to call it again as
part of the usbfs interface; thus the invocation of
usb_fs_classdev_common_remove() has been taken out of
usbfs_remove_device().

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-by: Alon Bar-Lev <alon.barlev@gmail.com>
Tested-by: Alon Bar-Lev <alon.barlev@gmail.com>
Cc: stable <stable@kernel.org>


authored by

Alan Stern and committed by
Greg Kroah-Hartman
501950d8 a15d95a0

+12 -10
+12 -8
drivers/usb/core/devio.c
··· 1700 1700 .release = usbdev_release, 1701 1701 }; 1702 1702 1703 - void usb_fs_classdev_common_remove(struct usb_device *udev) 1703 + static void usbdev_remove(struct usb_device *udev) 1704 1704 { 1705 1705 struct dev_state *ps; 1706 1706 struct siginfo sinfo; ··· 1742 1742 { 1743 1743 if (dev->usb_classdev) 1744 1744 device_unregister(dev->usb_classdev); 1745 - usb_fs_classdev_common_remove(dev); 1746 1745 } 1747 1746 1748 - static int usb_classdev_notify(struct notifier_block *self, 1747 + #else 1748 + #define usb_classdev_add(dev) 0 1749 + #define usb_classdev_remove(dev) do {} while (0) 1750 + 1751 + #endif 1752 + 1753 + static int usbdev_notify(struct notifier_block *self, 1749 1754 unsigned long action, void *dev) 1750 1755 { 1751 1756 switch (action) { ··· 1760 1755 break; 1761 1756 case USB_DEVICE_REMOVE: 1762 1757 usb_classdev_remove(dev); 1758 + usbdev_remove(dev); 1763 1759 break; 1764 1760 } 1765 1761 return NOTIFY_OK; 1766 1762 } 1767 1763 1768 1764 static struct notifier_block usbdev_nb = { 1769 - .notifier_call = usb_classdev_notify, 1765 + .notifier_call = usbdev_notify, 1770 1766 }; 1771 - #endif 1772 1767 1773 1768 static struct cdev usb_device_cdev; 1774 1769 ··· 1803 1798 * to /sys/dev 1804 1799 */ 1805 1800 usb_classdev_class->dev_kobj = NULL; 1806 - 1807 - usb_register_notify(&usbdev_nb); 1808 1801 #endif 1802 + usb_register_notify(&usbdev_nb); 1809 1803 out: 1810 1804 return retval; 1811 1805 ··· 1815 1811 1816 1812 void usb_devio_cleanup(void) 1817 1813 { 1818 - #ifdef CONFIG_USB_DEVICE_CLASS 1819 1814 usb_unregister_notify(&usbdev_nb); 1815 + #ifdef CONFIG_USB_DEVICE_CLASS 1820 1816 class_destroy(usb_classdev_class); 1821 1817 #endif 1822 1818 cdev_del(&usb_device_cdev);
-1
drivers/usb/core/inode.c
··· 717 717 fs_remove_file (dev->usbfs_dentry); 718 718 dev->usbfs_dentry = NULL; 719 719 } 720 - usb_fs_classdev_common_remove(dev); 721 720 } 722 721 723 722 static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
-1
drivers/usb/core/usb.h
··· 152 152 extern const struct file_operations usbfs_devices_fops; 153 153 extern const struct file_operations usbdev_file_operations; 154 154 extern void usbfs_conn_disc_event(void); 155 - extern void usb_fs_classdev_common_remove(struct usb_device *udev); 156 155 157 156 extern int usb_devio_init(void); 158 157 extern void usb_devio_cleanup(void);