Hi Chris, On 03/11/2014 05:27 PM, Chris Dickens wrote:
Hi Hans,Are you sure this is what was happening ? Can you perhaps try again with a printf added at a strategic place to ensure this is really what is going on? Here's the debug output right after the DISCONNECT_CLAIM fails: [ 0.004913] [00007d79] libusb: debug [libusb_claim_interface] interface 1 [ 0.004930] [00007d79] libusb: debug [detach_kernel_driver_and_claim] ioctl DISCONNECT_CLAIM error -1 errno 22 Looking at: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/core/devio.c?id=22763c5cf3690a681551162c15d34d935308c8d7 (22763c5c is the commit id responding to the v2.6.32 tag) I see the following in there: 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; ... switch (cmd) { case USBDEVFS_CONTROL: ... } return ret; } This code path is used for calls from both 64 bit and 32 bit userspace apps, so 32 bit apps should see -ENOTTY to for an unknown cmd code. The code for RHEL's 2.6.32 kernel is a bit different, but essentially boils down to the same thing. (I was referencing http://ftp.redhat.com/redhat/linux/enterprise/6Workstation/en/os/SRPMS/kernel-2.6.32-431.5.1.el6.src.rpm) Doing a bit more research, I've found this is actually happening further up the call stack, before usbfs is ever involved. I noticed this in the kernel log: ioctl32(pcs:32121): Unknown cmd fd(11) cmd(8108551b){t:'U';sz:264} arg(f59b4c50) on /dev/bus/usb/001/079 This message is generating from https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/compat_ioctl.c?id=22763c5cf3690a681551162c15d34d935308c8d7#n2769 This is called from inside the compat_sys_ioctl function (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/fs/compat_ioctl.c?id=22763c5cf3690a681551162c15d34d935308c8d7#n2857) and is called when the file operations table does not provide a compat_ioctl function and no handler is found. usbfs indeed does not provide this, thus after failing to find a handler it prints this error and as you can see right after returns EINVAL.
Ah yes I see now, and there is a big honking list of compatible ioctls (so which are compat without needing translation from 32 <-> 64 bit) higher up in the file. Which of course does no contain the new ioctls. So now we have a different return code when running in native 32 bit versus when running 32 bits code under a 64 bit kernel how nice (not). Ok, so treating EINVAL as ENOTTY is going to be the only solution then, can you try the attached patch? Thanks & Regards, Hans
>From 18d6da51580f8910223833815c3f8b1bef8d32bf Mon Sep 17 00:00:00 2001 From: Hans de Goede <hdego...@redhat.com> Date: Tue, 11 Mar 2014 18:43:13 +0100 Subject: [PATCH] linux_usbfs: Treat EINVAL as ENOTTY in cases where we may get ENOTTY Older 64 bit kernels will return EINVAL to 32 bits userspace for unknown ioctls. So in places where we check for ENOTTY also check for EINVAL, and use the fallback path for EINVAL too. Note that if there really is an invalid parameter in the detach_kernel_driver_and_claim case, then the fallback path will detect and report this. Signed-off-by: Hans de Goede <hdego...@redhat.com> --- libusb/os/linux_usbfs.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index 8962aba..00c8090 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -1285,7 +1285,8 @@ static int op_open(struct libusb_device_handle *handle) r = ioctl(hpriv->fd, IOCTL_USBFS_GET_CAPABILITIES, &hpriv->caps); if (r < 0) { - if (errno == ENOTTY) + /* Older 64 bit kernels return EINVAL to 32 bit apps */ + if (errno == ENOTTY || errno == EINVAL) usbi_dbg("getcap not available"); else usbi_err(HANDLE_CTX(handle), "getcap failed (%d)", errno); @@ -1631,15 +1632,13 @@ static int detach_kernel_driver_and_claim(struct libusb_device_handle *handle, strcpy(dc.driver, "usbfs"); dc.flags = USBFS_DISCONNECT_CLAIM_EXCEPT_DRIVER; r = ioctl(fd, IOCTL_USBFS_DISCONNECT_CLAIM, &dc); - if (r == 0 || (r != 0 && errno != ENOTTY)) { - if (r == 0) - return 0; - + if (r == 0) + return 0; + /* Older 64 bit kernels return EINVAL to 32 bit apps */ + if (errno != ENOTTY && errno != EINVAL) { switch (errno) { case EBUSY: return LIBUSB_ERROR_BUSY; - case EINVAL: - return LIBUSB_ERROR_INVALID_PARAM; case ENODEV: return LIBUSB_ERROR_NO_DEVICE; } -- 1.8.4.2
------------------------------------------------------------------------------ Learn Graph Databases - Download FREE O'Reilly Book "Graph Databases" is the definitive new guide to graph databases and their applications. Written by three acclaimed leaders in the field, this first edition is now available. Download your free book today! http://p.sf.net/sfu/13534_NeoTech
_______________________________________________ libusbx-devel mailing list libusbx-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libusbx-devel