2007-06-02 22:44:08

by Justin Piszcz

[permalink] [raw]
Subject: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

I use nut-2.0.4-4 with a UPS attached via USB and from 2.6.21.3 ->
2.6.22-rc3 it stops working, see below. My .config is attached.

2.6.21.3:

p34:~# /lib/nut/newhidups -u nut -DDDDDD auto
Checking device (050D/0912) (005/002)
- VendorID: 050d
- ProductID: 0912
- Manufacturer:
- Product: UPS
- Serial Number: unknown
- Bus: 005
Trying to match device
Device matches
HID descriptor retrieved (Reportlen = 820)
Size read for the report descriptor: 820
Report descriptor retrieved (Reportlen = 820)
Found HID device
Network UPS Tools: New USB/HID UPS driver 0.28 (2.0.4)

Report Descriptor size = 820
Report Descriptor: (200 bytes) => 05 84 09 04 A1 01 05 86 09 26 A1 02 85 01 75 08
Detected a UPS: /UPS
Using subdriver: Belkin HID 0.1
Looking up 00840004
Looking up 00860026
Looking up 00860040
entering string_to_path()
parsing UPS
Looking up UPS
hid_lookup_usage: found 840004
parsing BELKINConfig
Looking up BELKINConfig
hid_lookup_usage: found 860026
parsing BELKINConfigVoltage
Looking up BELKINConfigVoltage
hid_lookup_usage: found 860040
Path depth = 3
0: UPage(84), Usage(4)
1: UPage(86), Usage(26)
2: UPage(86), Usage(40)
Entering libusb_get_report
=>> Before exponent: 120, 0/0)
=>> After conversion: 120.000000 (120), 0/0)
Report : (8 bytes) => 01 78 80 00 00 00 00 00
Path: UPS.BELKINConfig.BELKINConfigVoltage, Type: Feature, Value: 120.000000
Looking up 00840004
Looking up 00860026
Looking up 00860042

(works fine)

2.6.22-rc3:

p34:~# /lib/nut/newhidups -u nut -DDDDDD auto
Checking device (050D/0912) (005/002)
- VendorID: 050d
- ProductID: 0912
- Manufacturer: unknown
- Product: unknown
- Serial Number: unknown
- Bus: 005
Trying to match device
Device matches
failed to claim USB device, trying 2 more time(s)...
detaching kernel driver from USB device...
failed to detach kernel driver from USB device...
trying again to claim USB device...
failed to claim USB device, trying 1 more time(s)...
detaching kernel driver from USB device...
failed to detach kernel driver from USB device...
trying again to claim USB device...
failed to claim USB device, trying 0 more time(s)...
detaching kernel driver from USB device...
failed to detach kernel driver from USB device...
trying again to claim USB device...
Unable to get HID descriptor (error sending control message: Operation not permitted)


Attachments:
config-2.6.22-rc3.bz2 (7.48 kB)

2007-06-03 09:49:56

by Jiri Kosina

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

On Sat, 2 Jun 2007, Justin Piszcz wrote:

> p34:~# /lib/nut/newhidups -u nut -DDDDDD auto
> Checking device (050D/0912) (005/002)
> - VendorID: 050d
> - ProductID: 0912
> - Manufacturer: unknown
> - Product: unknown
> - Serial Number: unknown
> - Bus: 005
> Trying to match device
> Device matches
> failed to claim USB device, trying 2 more time(s)...
> detaching kernel driver from USB device...

Could you please provide strace outputs (or put it on the web somewhere if
it's too big) for the failing and succeeding claiming of the device?

Thanks,

--
Jiri Kosina

2007-06-03 09:56:16

by Jiri Kosina

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

I have looked into NUT source and it seems that this error message is
output after interaction with libusb, not hiddev. It looks like libusb's
usb_claim_interface() or usb_control_msg() in in 2.6.22-rc3 is failing
with -EPERM.

So I am adding USB devel mailinglist into CC and leaving the original
message below for reference.

On Sat, 2 Jun 2007, Justin Piszcz wrote:

> I use nut-2.0.4-4 with a UPS attached via USB and from 2.6.21.3 -> 2.6.22-rc3
> it stops working, see below. My .config is attached.
>
> 2.6.21.3:
>
> p34:~# /lib/nut/newhidups -u nut -DDDDDD auto
> Checking device (050D/0912) (005/002)
> - VendorID: 050d
> - ProductID: 0912
> - Manufacturer:
> - Product: UPS
> - Serial Number: unknown
> - Bus: 005
> Trying to match device
> Device matches
> HID descriptor retrieved (Reportlen = 820)
> Size read for the report descriptor: 820
> Report descriptor retrieved (Reportlen = 820)
> Found HID device
> Network UPS Tools: New USB/HID UPS driver 0.28 (2.0.4)
>
> Report Descriptor size = 820
> Report Descriptor: (200 bytes) => 05 84 09 04 A1 01 05 86 09 26 A1 02 85 01 75
> 08
> Detected a UPS: /UPS
> Using subdriver: Belkin HID 0.1
> Looking up 00840004
> Looking up 00860026
> Looking up 00860040
> entering string_to_path()
> parsing UPS
> Looking up UPS
> hid_lookup_usage: found 840004
> parsing BELKINConfig
> Looking up BELKINConfig
> hid_lookup_usage: found 860026
> parsing BELKINConfigVoltage
> Looking up BELKINConfigVoltage
> hid_lookup_usage: found 860040
> Path depth = 3
> 0: UPage(84), Usage(4)
> 1: UPage(86), Usage(26)
> 2: UPage(86), Usage(40)
> Entering libusb_get_report
> =>> Before exponent: 120, 0/0)
> =>> After conversion: 120.000000 (120), 0/0)
> Report : (8 bytes) => 01 78 80 00 00 00 00 00
> Path: UPS.BELKINConfig.BELKINConfigVoltage, Type: Feature, Value: 120.000000
> Looking up 00840004
> Looking up 00860026
> Looking up 00860042
>
> (works fine)
>
> 2.6.22-rc3:
>
> p34:~# /lib/nut/newhidups -u nut -DDDDDD auto
> Checking device (050D/0912) (005/002)
> - VendorID: 050d
> - ProductID: 0912
> - Manufacturer: unknown
> - Product: unknown
> - Serial Number: unknown
> - Bus: 005
> Trying to match device
> Device matches
> failed to claim USB device, trying 2 more time(s)...
> detaching kernel driver from USB device...
> failed to detach kernel driver from USB device...
> trying again to claim USB device...
> failed to claim USB device, trying 1 more time(s)...
> detaching kernel driver from USB device...
> failed to detach kernel driver from USB device...
> trying again to claim USB device...
> failed to claim USB device, trying 0 more time(s)...
> detaching kernel driver from USB device...
> failed to detach kernel driver from USB device...
> trying again to claim USB device...
> Unable to get HID descriptor (error sending control message: Operation not
> permitted)
>
>

--
Jiri Kosina

2007-06-03 10:36:16

by Justin Piszcz

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)



On Sun, 3 Jun 2007, Jiri Kosina wrote:

> On Sat, 2 Jun 2007, Justin Piszcz wrote:
>
>> p34:~# /lib/nut/newhidups -u nut -DDDDDD auto
>> Checking device (050D/0912) (005/002)
>> - VendorID: 050d
>> - ProductID: 0912
>> - Manufacturer: unknown
>> - Product: unknown
>> - Serial Number: unknown
>> - Bus: 005
>> Trying to match device
>> Device matches
>> failed to claim USB device, trying 2 more time(s)...
>> detaching kernel driver from USB device...
>
> Could you please provide strace outputs (or put it on the web somewhere if
> it's too big) for the failing and succeeding claiming of the device?
>
> Thanks,
>
> --
> Jiri Kosina
>

Sure, they are attached:

$ du -sh nut*
4.0K nut-bad.txt.bz2 (2.6.22-rc3)
12K nut-good.txt.bz2 (2.6.21.3)

Let me know if they are of any use.

Thanks,

Justin.


Attachments:
nut-bad.txt.bz2 (3.09 kB)
nut-good.txt.bz2 (8.15 kB)
Download all attachments

2007-06-03 11:01:16

by Jiri Kosina

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

On Sun, 3 Jun 2007, Justin Piszcz wrote:

> Sure, they are attached:
> $ du -sh nut*
> 4.0K nut-bad.txt.bz2 (2.6.22-rc3)
> 12K nut-good.txt.bz2 (2.6.21.3)
> Let me know if they are of any use.

Thanks. Does by any chance reverting
the commit 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?

--
Jiri Kosina

2007-06-03 11:16:55

by Justin Piszcz

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)



On Sun, 3 Jun 2007, Jiri Kosina wrote:

> On Sun, 3 Jun 2007, Justin Piszcz wrote:
>
>> Sure, they are attached:
>> $ du -sh nut*
>> 4.0K nut-bad.txt.bz2 (2.6.22-rc3)
>> 12K nut-good.txt.bz2 (2.6.21.3)
>> Let me know if they are of any use.
>
> Thanks. Does by any chance reverting
> the commit 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?
>
> --
> Jiri Kosina
>

I have not played around with git/etc enough to back it out, if you have a
patch that applies on top of 2.6.22-rc3 that backs it out I can give it a
try.

Justin.

2007-06-03 11:22:39

by Jiri Kosina

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

On Sun, 3 Jun 2007, Justin Piszcz wrote:

> > Thanks. Does by any chance reverting the commit
> > 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?
> I have not played around with git/etc enough to back it out, if you have a
> patch that applies on top of 2.6.22-rc3 that backs it out I can give it a try.

Please try this

diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index f493fb1..2fc0f88 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -31,30 +31,7 @@ config USB_DEVICEFS
For the format of the various /proc/bus/usb/ files, please read
<file:Documentation/usb/proc_usb_info.txt>.

- Usbfs files can't handle Access Control Lists (ACL), which are the
- default way to grant access to USB devices for untrusted users of a
- desktop system. The usbfs functionality is replaced by real
- device-nodes managed by udev. These nodes live in /dev/bus/usb and
- are used by libusb.
-
-config USB_DEVICE_CLASS
- bool "USB device class-devices (DEPRECATED)"
- depends on USB
- default n
- ---help---
- Userspace access to USB devices is granted by device-nodes exported
- directly from the usbdev in sysfs. Old versions of the driver
- core and udev needed additional class devices to export device nodes.
-
- These additional devices are difficult to handle in userspace, if
- information about USB interfaces must be available. One device contains
- the device node, the other device contains the interface data. Both
- devices are at the same level in sysfs (siblings) and one can't access
- the other. The device node created directly by the usbdev is the parent
- device of the interface and therefore easily accessible from the interface
- event.
-
- This option provides backward compatibility if needed.
+ Most users want to say Y here.

config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 927a181..4fcbef1 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -57,6 +57,7 @@

#define USB_MAXBUS 64
#define USB_DEVICE_MAX USB_MAXBUS * 128
+static struct class *usb_device_class;

/* Mutual exclusion for removal, open, and release */
DEFINE_MUTEX(usbfs_mutex);
@@ -513,25 +514,22 @@ static int check_ctrlrecip(struct dev_st
return ret;
}

-static int __match_minor(struct device *dev, void *data)
+static struct usb_device *usbdev_lookup_minor(int minor)
{
- int minor = *((int *)data);
+ struct device *device;
+ struct usb_device *udev = NULL;

- if (dev->devt == MKDEV(USB_DEVICE_MAJOR, minor))
- return 1;
- return 0;
-}
-
-static struct usb_device *usbdev_lookup_by_minor(int minor)
-{
- struct device *dev;
+ down(&usb_device_class->sem);
+ list_for_each_entry(device, &usb_device_class->devices, node) {
+ if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+ udev = device->platform_data;
+ break;
+ }
+ }
+ up(&usb_device_class->sem);

- dev = bus_find_device(&usb_bus_type, NULL, &minor, __match_minor);
- if (!dev)
- return NULL;
- put_device(dev);
- return container_of(dev, struct usb_device, dev);
-}
+ return udev;
+};

/*
* file operations
@@ -550,14 +548,11 @@ static int usbdev_open(struct inode *ino
goto out;

ret = -ENOENT;
- /* usbdev device-node */
+ /* check if we are called from a real node or usbfs */
if (imajor(inode) == USB_DEVICE_MAJOR)
- dev = usbdev_lookup_by_minor(iminor(inode));
-#ifdef CONFIG_USB_DEVICEFS
- /* procfs file */
+ dev = usbdev_lookup_minor(iminor(inode));
if (!dev)
dev = inode->i_private;
-#endif
if (!dev)
goto out;
ret = usb_autoresume_device(dev);
@@ -1575,7 +1570,7 @@ static unsigned int usbdev_poll(struct f
return mask;
}

-const struct file_operations usbdev_file_operations = {
+const struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@@ -1584,53 +1579,50 @@ const struct file_operations usbdev_file
.release = usbdev_release,
};

-#ifdef CONFIG_USB_DEVICE_CLASS
-static struct class *usb_classdev_class;
-
-static int usb_classdev_add(struct usb_device *dev)
+static int usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);

- dev->usb_classdev = device_create(usb_classdev_class, &dev->dev,
+ dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
MKDEV(USB_DEVICE_MAJOR, minor),
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
- if (IS_ERR(dev->usb_classdev))
- return PTR_ERR(dev->usb_classdev);
+ if (IS_ERR(dev->usbfs_dev))
+ return PTR_ERR(dev->usbfs_dev);

+ dev->usbfs_dev->platform_data = dev;
return 0;
}

-static void usb_classdev_remove(struct usb_device *dev)
+static void usbdev_remove(struct usb_device *dev)
{
- device_unregister(dev->usb_classdev);
+ device_unregister(dev->usbfs_dev);
}

-static int usb_classdev_notify(struct notifier_block *self,
- unsigned long action, void *dev)
+static int usbdev_notify(struct notifier_block *self, unsigned long action,
+ void *dev)
{
switch (action) {
case USB_DEVICE_ADD:
- if (usb_classdev_add(dev))
+ if (usbdev_add(dev))
return NOTIFY_BAD;
break;
case USB_DEVICE_REMOVE:
- usb_classdev_remove(dev);
+ usbdev_remove(dev);
break;
}
return NOTIFY_OK;
}

static struct notifier_block usbdev_nb = {
- .notifier_call = usb_classdev_notify,
+ .notifier_call = usbdev_notify,
};
-#endif

static struct cdev usb_device_cdev = {
.kobj = {.name = "usb_device", },
.owner = THIS_MODULE,
};

-int __init usb_devio_init(void)
+int __init usbdev_init(void)
{
int retval;

@@ -1640,38 +1632,38 @@ int __init usb_devio_init(void)
err("unable to register minors for usb_device");
goto out;
}
- cdev_init(&usb_device_cdev, &usbdev_file_operations);
+ cdev_init(&usb_device_cdev, &usbfs_device_file_operations);
retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
if (retval) {
err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
goto error_cdev;
}
-#ifdef CONFIG_USB_DEVICE_CLASS
- usb_classdev_class = class_create(THIS_MODULE, "usb_device");
- if (IS_ERR(usb_classdev_class)) {
+ usb_device_class = class_create(THIS_MODULE, "usb_device");
+ if (IS_ERR(usb_device_class)) {
err("unable to register usb_device class");
- retval = PTR_ERR(usb_classdev_class);
- cdev_del(&usb_device_cdev);
- usb_classdev_class = NULL;
- goto out;
+ retval = PTR_ERR(usb_device_class);
+ goto error_class;
}

usb_register_notify(&usbdev_nb);
-#endif
+
out:
return retval;

+error_class:
+ usb_device_class = NULL;
+ cdev_del(&usb_device_cdev);
+
error_cdev:
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
goto out;
}

-void usb_devio_cleanup(void)
+void usbdev_cleanup(void)
{
-#ifdef CONFIG_USB_DEVICE_CLASS
usb_unregister_notify(&usbdev_nb);
- class_destroy(usb_classdev_class);
-#endif
+ class_destroy(usb_device_class);
cdev_del(&usb_device_cdev);
unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
}
+
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 2619986..a2dd98c 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -574,10 +574,23 @@ static int usb_device_match(struct devic
}

#ifdef CONFIG_HOTPLUG
+
+/*
+ * This sends an uevent to userspace, typically helping to load driver
+ * or other modules, configure the device, and more. Drivers can provide
+ * a MODULE_DEVICE_TABLE to help with module loading subtasks.
+ *
+ * We're called either from khubd (the typical case) or from root hub
+ * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
+ * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
+ * device (and this configuration!) are still present.
+ */
static int usb_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
+ struct usb_interface *intf;
struct usb_device *usb_dev;
+ struct usb_host_interface *alt;
int i = 0;
int length = 0;

@@ -587,11 +600,13 @@ static int usb_uevent(struct device *dev
/* driver is often null here; dev_dbg() would oops */
pr_debug ("usb %s: uevent\n", dev->bus_id);

- if (is_usb_device(dev))
+ if (is_usb_device(dev)) {
usb_dev = to_usb_device(dev);
- else {
- struct usb_interface *intf = to_usb_interface(dev);
+ alt = NULL;
+ } else {
+ intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev(intf);
+ alt = intf->cur_altsetting;
}

if (usb_dev->devnum < 0) {
@@ -606,7 +621,9 @@ static int usb_uevent(struct device *dev
#ifdef CONFIG_USB_DEVICEFS
/* If this is available, userspace programs can directly read
* all the device descriptors we don't tell them about. Or
- * act as usermode drivers.
+ * even act as usermode drivers.
+ *
+ * FIXME reduce hardwired intelligence here
*/
if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
@@ -633,29 +650,44 @@ static int usb_uevent(struct device *dev
usb_dev->descriptor.bDeviceProtocol))
return -ENOMEM;

- if (add_uevent_var(envp, num_envp, &i,
+ if (!is_usb_device(dev)) {
+
+ if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
- "BUSNUM=%03d",
- usb_dev->bus->busnum))
- return -ENOMEM;
+ "INTERFACE=%d/%d/%d",
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
+ return -ENOMEM;

- if (add_uevent_var(envp, num_envp, &i,
+ if (add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
- "DEVNUM=%03d",
- usb_dev->devnum))
- return -ENOMEM;
+ "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice),
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol,
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
+ return -ENOMEM;
+ }

envp[i] = NULL;
+
return 0;
}

#else

static int usb_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+ int num_envp, char *buffer, int buffer_size)
{
return -ENODEV;
}
+
#endif /* CONFIG_HOTPLUG */

/**
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index caaa46f..9ac5eec 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1366,15 +1366,11 @@ int usb_new_device(struct usb_device *ud
}
#endif

- /* export the usbdev device-node for libusb */
- udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
- (((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
-
/* Register the device. The device driver is responsible
- * for adding the device files to sysfs and for configuring
- * the device.
+ * for adding the device files to usbfs and sysfs and for
+ * configuring the device.
*/
- err = device_add(&udev->dev);
+ err = device_add (&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index cd4f111..22413a7 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -661,7 +661,7 @@ static void usbfs_add_device(struct usb_
sprintf (name, "%03d", dev->devnum);
dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG,
dev->bus->usbfs_dentry, dev,
- &usbdev_file_operations,
+ &usbfs_device_file_operations,
devuid, devgid);
if (dev->usbfs_dentry == NULL) {
err ("error creating usbfs device entry");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f9fed34..ba49204 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1314,7 +1314,7 @@ int usb_reset_configuration(struct usb_d
return 0;
}

-void usb_release_interface(struct device *dev)
+static void release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
@@ -1324,67 +1324,6 @@ void usb_release_interface(struct device
kfree(intf);
}

-#ifdef CONFIG_HOTPLUG
-static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
-{
- struct usb_device *usb_dev;
- struct usb_interface *intf;
- struct usb_host_interface *alt;
- int i = 0;
- int length = 0;
-
- if (!dev)
- return -ENODEV;
-
- /* driver is often null here; dev_dbg() would oops */
- pr_debug ("usb %s: uevent\n", dev->bus_id);
-
- intf = to_usb_interface(dev);
- usb_dev = interface_to_usbdev(intf);
- alt = intf->cur_altsetting;
-
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "INTERFACE=%d/%d/%d",
- alt->desc.bInterfaceClass,
- alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
- return -ENOMEM;
-
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
- le16_to_cpu(usb_dev->descriptor.idVendor),
- le16_to_cpu(usb_dev->descriptor.idProduct),
- le16_to_cpu(usb_dev->descriptor.bcdDevice),
- usb_dev->descriptor.bDeviceClass,
- usb_dev->descriptor.bDeviceSubClass,
- usb_dev->descriptor.bDeviceProtocol,
- alt->desc.bInterfaceClass,
- alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
- return -ENOMEM;
-
- envp[i] = NULL;
- return 0;
-}
-
-#else
-
-static int usb_if_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
-{
- return -ENODEV;
-}
-#endif /* CONFIG_HOTPLUG */
-
-struct device_type usb_if_device_type = {
- .name = "usb_interface",
- .release = usb_release_interface,
- .uevent = usb_if_uevent,
-};
-
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
@@ -1548,8 +1487,8 @@ free_interfaces:
intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
- intf->dev.type = &usb_if_device_type;
intf->dev.dma_mask = dev->dev.dma_mask;
+ intf->dev.release = release_interface;
device_initialize (&intf->dev);
mark_quiesced(intf);
sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 80627b6..55e7df8 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -196,11 +196,6 @@ static void usb_release_dev(struct devic
kfree(udev);
}

-struct device_type usb_device_type = {
- .name = "usb_device",
- .release = usb_release_dev,
-};
-
#ifdef CONFIG_PM

static int ksuspend_usb_init(void)
@@ -255,10 +250,13 @@ usb_alloc_dev(struct usb_device *parent,

device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
- dev->dev.type = &usb_device_type;
dev->dev.dma_mask = bus->controller->dma_mask;
+ dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;

+ /* This magic assignment distinguishes devices from interfaces */
+ dev->dev.platform_data = &usb_generic_driver;
+
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
@@ -887,9 +885,9 @@ static int __init usb_init(void)
retval = usb_register(&usbfs_driver);
if (retval)
goto driver_register_failed;
- retval = usb_devio_init();
+ retval = usbdev_init();
if (retval)
- goto usb_devio_init_failed;
+ goto usbdevice_init_failed;
retval = usbfs_init();
if (retval)
goto fs_init_failed;
@@ -904,8 +902,8 @@ static int __init usb_init(void)
hub_init_failed:
usbfs_cleanup();
fs_init_failed:
- usb_devio_cleanup();
-usb_devio_init_failed:
+ usbdev_cleanup();
+usbdevice_init_failed:
usb_deregister(&usbfs_driver);
driver_register_failed:
usb_major_cleanup();
@@ -932,7 +930,7 @@ static void __exit usb_exit(void)
usb_major_cleanup();
usbfs_cleanup();
usb_deregister(&usbfs_driver);
- usb_devio_cleanup();
+ usbdev_cleanup();
usb_hub_cleanup();
usb_host_cleanup();
bus_unregister(&usb_bus_type);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index bf2eb0d..c94379e 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -78,13 +78,15 @@ static inline int usb_autoresume_device(

extern struct workqueue_struct *ksuspend_usb_wq;
extern struct bus_type usb_bus_type;
-extern struct device_type usb_device_type;
-extern struct device_type usb_if_device_type;
extern struct usb_device_driver usb_generic_driver;

+/* Here's how we tell apart devices and interfaces. Luckily there's
+ * no such thing as a platform USB device, so we can steal the use
+ * of the platform_data field. */
+
static inline int is_usb_device(const struct device *dev)
{
- return dev->type == &usb_device_type;
+ return dev->platform_data == &usb_generic_driver;
}

/* Do the same for device drivers and interface drivers. */
@@ -120,11 +122,11 @@ extern const char *usbcore_name;
extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
extern const struct file_operations usbfs_devices_fops;
-extern const struct file_operations usbdev_file_operations;
+extern const struct file_operations usbfs_device_file_operations;
extern void usbfs_conn_disc_event(void);

-extern int usb_devio_init(void);
-extern void usb_devio_cleanup(void);
+extern int usbdev_init(void);
+extern void usbdev_cleanup(void);

struct dev_state {
struct list_head list; /* state list */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 94bd38a..1957674 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -299,9 +299,8 @@ struct usb_bus {
int bandwidth_int_reqs; /* number of Interrupt requests */
int bandwidth_isoc_reqs; /* number of Isoc. requests */

-#ifdef CONFIG_USB_DEVICEFS
struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
-#endif
+
struct class_device *class_dev; /* class device for this bus */

#if defined(CONFIG_USB_MON)
@@ -374,12 +373,9 @@ struct usb_device {
char *serial; /* iSerialNumber string, if present */

struct list_head filelist;
-#ifdef CONFIG_USB_DEVICE_CLASS
- struct device *usb_classdev;
-#endif
-#ifdef CONFIG_USB_DEVICEFS
+ struct device *usbfs_dev;
struct dentry *usbfs_dentry; /* usbfs dentry entry for the device */
-#endif
+
/*
* Child devices - these can be either new devices
* (if this is a hub device), or different instances

2007-06-03 11:52:40

by Justin Piszcz

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)



On Sun, 3 Jun 2007, Jiri Kosina wrote:

> On Sun, 3 Jun 2007, Justin Piszcz wrote:
>
>>> Thanks. Does by any chance reverting the commit
>>> 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?
>> I have not played around with git/etc enough to back it out, if you have a
>> patch that applies on top of 2.6.22-rc3 that backs it out I can give it a try.
>
> Please try this

[[ .. snip .. ]]

The patch was successful and now my USB device is working again!

p34:/usr/src/linux-2.6.22-rc3# patch -p1 < ../usb.patch
patching file drivers/usb/core/Kconfig
patching file drivers/usb/core/devio.c
patching file drivers/usb/core/driver.c
patching file drivers/usb/core/hub.c
patching file drivers/usb/core/inode.c
patching file drivers/usb/core/message.c
patching file drivers/usb/core/usb.c
patching file drivers/usb/core/usb.h
patching file include/linux/usb.h
p34:/usr/src/linux-2.6.22-rc3#

[[ .. recompile/reboot .. ]]

p34:~# upsc belkin@localhost
battery.charge: 100
battery.charge.low: 30
battery.charge.warning: 50
battery.runtime: 210
battery.type: PbAc
battery.voltage: 27.1
battery.voltage.nominal: 24
driver.name: newhidups
driver.parameter.pollfreq: 5
driver.parameter.port: auto
driver.version: 2.0.4
driver.version.data: Belkin HID 0.1
driver.version.internal: 0.28
input.frequency: 59.8
input.frequency.nominal: 60
input.sensitivity: normal
input.transfer.high: 136
input.transfer.high.max: 141
input.transfer.high.min: 131
input.transfer.low: 90
input.transfer.low.max: 95
input.transfer.low.min: 85
input.voltage: 122.8
input.voltage.nominal: 120
output.frequency: 59.8
output.voltage: 122.0
ups.beeper.status: enabled
ups.delay.restart: 0
ups.delay.shutdown: 0
ups.firmware: 4
ups.load: 43
ups.load.high: 100
ups.mfr: Belkin
ups.mfr.date: 2002/03/01
ups.model: UPS
ups.power.nominal: 1200
ups.serial: D2002337105
ups.status: OL CHRG
ups.test.result: No test initiated
ups.type: offline
p34:~#

p34:~# uname -a
Linux p34.internal.lan 2.6.22-rc3 #2 SMP Sun Jun 3 07:45:09 EDT 2007 x86_64 GNU/Linux
p34:~#

It looks good to me, very nice-- hopefully it will get into 2.6.22 final?

Thanks!

Justin.

2007-06-03 12:28:16

by Oliver Neukum

[permalink] [raw]
Subject: Re: [linux-usb-devel] Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

Am Sonntag, 3. Juni 2007 11:55 schrieb Jiri Kosina:
> I have looked into NUT source and it seems that this error message is
> output after interaction with libusb, not hiddev. It looks like libusb's
> usb_claim_interface() or usb_control_msg() in in 2.6.22-rc3 is failing
> with -EPERM.

Yes, strace and lsusb -v please.

Regards
Oliver

2007-06-03 12:28:29

by Oliver Neukum

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

Am Sonntag, 3. Juni 2007 12:36 schrieb Justin Piszcz:
>
> On Sun, 3 Jun 2007, Jiri Kosina wrote:
>
> > On Sat, 2 Jun 2007, Justin Piszcz wrote:

> >> failed to claim USB device, trying 2 more time(s)...
> >> detaching kernel driver from USB device...
> >
> > Could you please provide strace outputs (or put it on the web somewhere if
> > it's too big) for the failing and succeeding claiming of the device?

static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
void __user *p = (void __user *)arg;
int ret = -ENOTTY;

if (!(file->f_mode & FMODE_WRITE))
return -EPERM;

That check fails as your application falls back to opening read only in
case of insufficient permissions. Did you change some udev rules?

Regards
Oliver

2007-06-03 12:29:43

by Justin Piszcz

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)



On Sun, 3 Jun 2007, Oliver Neukum wrote:

> Am Sonntag, 3. Juni 2007 12:36 schrieb Justin Piszcz:
>>
>> On Sun, 3 Jun 2007, Jiri Kosina wrote:
>>
>>> On Sat, 2 Jun 2007, Justin Piszcz wrote:
>
>>>> failed to claim USB device, trying 2 more time(s)...
>>>> detaching kernel driver from USB device...
>>>
>>> Could you please provide strace outputs (or put it on the web somewhere if
>>> it's too big) for the failing and succeeding claiming of the device?
>
> static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
> {
> struct dev_state *ps = file->private_data;
> struct usb_device *dev = ps->dev;
> void __user *p = (void __user *)arg;
> int ret = -ENOTTY;
>
> if (!(file->f_mode & FMODE_WRITE))
> return -EPERM;
>
> That check fails as your application falls back to opening read only in
> case of insufficient permissions. Did you change some udev rules?
>
> Regards
> Oliver
>

Nope and just to verify that I made sure I tested this a couple times.
Booted 2.6.21.3 no problems, then booted 2.6.23-rc3 w/out your patch,
problem happens again.

Justin.

2007-06-03 12:35:24

by Kay Sievers

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

On 6/3/07, Justin Piszcz <[email protected]> wrote:
> On Sun, 3 Jun 2007, Jiri Kosina wrote:
>
> > On Sun, 3 Jun 2007, Justin Piszcz wrote:
> >
> >>> Thanks. Does by any chance reverting the commit
> >>> 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?
> >> I have not played around with git/etc enough to back it out, if you have a
> >> patch that applies on top of 2.6.22-rc3 that backs it out I can give it a try.
> >
> > Please try this
>
> [[ .. snip .. ]]
>
> The patch was successful and now my USB device is working again!

Please set:
CONFIG_USB_DEVICE_CLASS=y
there should be no patch needed. The option already defaults to yes in
the latest kernel.

Thanks,
Kay

2007-06-03 12:40:26

by Justin Piszcz

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)



On Sun, 3 Jun 2007, Kay Sievers wrote:

> On 6/3/07, Justin Piszcz <[email protected]> wrote:
>> On Sun, 3 Jun 2007, Jiri Kosina wrote:
>>
>> > On Sun, 3 Jun 2007, Justin Piszcz wrote:
>> >
>> >>> Thanks. Does by any chance reverting the commit
>> >>> 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?
>> >> I have not played around with git/etc enough to back it out, if you have
>> a
>> >> patch that applies on top of 2.6.22-rc3 that backs it out I can give it
>> a try.
>> >
>> > Please try this
>>
>> [[ .. snip .. ]]
>>
>> The patch was successful and now my USB device is working again!
>
> Please set:
> CONFIG_USB_DEVICE_CLASS=y
> there should be no patch needed. The option already defaults to yes in
> the latest kernel.
>
> Thanks,
> Kay
>

USB device class-devices (DEPRECATED) (USB_DEVICE_CLASS) [N/y/?] (NEW) y

Why is it deprecated if (nut/usb/etc fails) when its not used? Does nut
or udev have to play catch-up to adhere to the new kernel changes?

Compiling with this option and testing now.


2007-06-03 12:44:23

by Justin Piszcz

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)



On Sun, 3 Jun 2007, Justin Piszcz wrote:

>
>
> On Sun, 3 Jun 2007, Kay Sievers wrote:
>
>> On 6/3/07, Justin Piszcz <[email protected]> wrote:
>>> On Sun, 3 Jun 2007, Jiri Kosina wrote:
>>>
>>> > On Sun, 3 Jun 2007, Justin Piszcz wrote:
>>> >
>>> >>> Thanks. Does by any chance reverting the commit
>>> >>> 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?
>>> >> I have not played around with git/etc enough to back it out, if you
>>> have a
>>> >> patch that applies on top of 2.6.22-rc3 that backs it out I can give it
>>> a try.
>>> >
>>> > Please try this
>>>
>>> [[ .. snip .. ]]
>>>
>>> The patch was successful and now my USB device is working again!
>>
>> Please set:
>> CONFIG_USB_DEVICE_CLASS=y
>> there should be no patch needed. The option already defaults to yes in
>> the latest kernel.
>>
>> Thanks,
>> Kay
>>
>
> USB device class-devices (DEPRECATED) (USB_DEVICE_CLASS) [N/y/?] (NEW) y
>
> Why is it deprecated if (nut/usb/etc fails) when its not used? Does nut or
> udev have to play catch-up to adhere to the new kernel changes?
>
> Compiling with this option and testing now.
>
>
>

With that option enabled, it is successful.

$ upsc belkin@localhost
battery.charge: 100
battery.charge.low: 30
battery.charge.warning: 50
battery.runtime: 210
battery.type: PbAc
battery.voltage: 27.1
battery.voltage.nominal: 24
driver.name: newhidups
driver.parameter.pollfreq: 5
driver.parameter.port: auto
driver.version: 2.0.4
driver.version.data: Belkin HID 0.1
driver.version.internal: 0.28
input.frequency: 59.8
input.frequency.nominal: 60
input.sensitivity: normal
input.transfer.high: 136
input.transfer.high.max: 141
input.transfer.high.min: 131
input.transfer.low: 90
input.transfer.low.max: 95
input.transfer.low.min: 85
input.voltage: 122.0
input.voltage.nominal: 120
output.frequency: 59.8
output.voltage: 121.6
ups.beeper.status: enabled
ups.delay.restart: 0
ups.delay.shutdown: 0
ups.firmware: 4
ups.load: 33
ups.load.high: 100
ups.mfr: Belkin
ups.mfr.date: 2002/03/01
ups.model: UPS
ups.power.nominal: 1200
ups.serial: D2002337105
ups.status: OL CHRG
ups.test.result: No test initiated
ups.type: offline

2007-06-03 16:52:22

by Kay Sievers

[permalink] [raw]
Subject: Re: Kernel 2.6.22-rc3 breaks USB: Unable to get HID descriptor (error sending control message: Operation not permitted)

On Sun, 2007-06-03 at 08:40 -0400, Justin Piszcz wrote:
> On Sun, 3 Jun 2007, Kay Sievers wrote:
>
> > On 6/3/07, Justin Piszcz <[email protected]> wrote:
> >> On Sun, 3 Jun 2007, Jiri Kosina wrote:
> >>
> >> > On Sun, 3 Jun 2007, Justin Piszcz wrote:
> >> >
> >> >>> Thanks. Does by any chance reverting the commit
> >> >>> 9f8b17e643fe6aa505629658445849397bda4e4f improve the situation?
> >> >> I have not played around with git/etc enough to back it out, if you have
> >> a
> >> >> patch that applies on top of 2.6.22-rc3 that backs it out I can give it
> >> a try.
> >> >
> >> > Please try this
> >>
> >> [[ .. snip .. ]]
> >>
> >> The patch was successful and now my USB device is working again!
> >
> > Please set:
> > CONFIG_USB_DEVICE_CLASS=y
> > there should be no patch needed. The option already defaults to yes in
> > the latest kernel.

> USB device class-devices (DEPRECATED) (USB_DEVICE_CLASS) [N/y/?] (NEW) y
>
> Why is it deprecated if (nut/usb/etc fails) when its not used? Does nut
> or udev have to play catch-up to adhere to the new kernel changes?

The usb_device class was created to replace the /proc usbfs device nodes
which can't handle access-control-lists for logged-in users.
The device nodes worked fine, but plugging into the device events to
trigger userspace device handling created a bunch of problems with the
event timing. We have several open bugs, that can't be fixed properly
with using the usb_device-devices.

We changed the driver core to allow us to export device nodes directly
by bus-devices, instead of forcing us to create artificial devices like
the usb_device-class, just to export device nodes to userspace. If
systems set CONFIG_USB_DEVICE_CLASS=n (which defaults to yes now), one
new udev rule is needed, to replace the functionality of the
usb_device-class devices. Also the next version of HAL (which is where
nut receives the events from) will depend on the new device nodes, and
will not longer use usb_device devices. No changes to nut should be
needed.

Thanks,
Kay