4
votes

I want to communicate with and send data to a USB device. I am able to find the device but while attaching the device with the kernel driver it is giving USB Error: Resource Busy. The following is my code:

import usb

dev = usb.core.find(idVendor=0x0403, idProduct=0x6001)
dev.set_configuration()

cfg = dev.get_active_configuration()

dev.attach_kernel_driver(interface)

interface_number = cfg[(0, 0)].bInterfaceNumber
alternate_settting = usb.control.get_interface(interface_number)
intf = usb.util.find_descriptor(
    cfg, bInterfaceNumber=interface_number,
    bAlternateSetting=alternate_setting)

ep = usb.util.find_descriptor(
    intf, custom_match=lambda e:
    usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT)

dev.detach_kernel_driver(interface)

ep.write("\r" + linea1[:19] + "\n\r" + " " * (20 - len(linea2)) + linea2)
1
Give us more details - platform, PyUSB version, USB backend library. What is 'interface'? And why are you actually trying to attach kernel driver?Code Painters
One more thought: the device in question is FTDI232 USB to RS232 converter. Why don't you use a kernel driver and pySerial module? That would (in theory) make your code portable across various serial port types (both real RS232 and USB dongles).Code Painters

1 Answers

7
votes

Assuming your using Linux and libusb-1.0 as a PyUSB's backend library.

According to the libusb documentation:

// Detach a kernel driver from an interface.
// If successful, you will then be able to claim the interface and perform I/O.
int libusb_detach_kernel_driver (libusb_device_handle *dev, 
                                 int interface_number)  

// Re-attach an interface's kernel driver, which was previously 
// detached using libusb_detach_kernel_driver().
int libusb_attach_kernel_driver(libusb_device_handle *dev,
                                int interface_number)

So basically, you need to call detach_kernel_driver first to detach already attached kernel driver (if any) from the device's interface, so you can communicate with it in your code (it's either your code or some kernel driver talking to the device's interface). When you're done, you may want to call attach_kernel_driver to re-attach the kernel driver again.

I believe there's no need to call any of those C functions/Python methods if you can ensure that no kernel driver is loaded for a given device (or manually unload it before running your code).

Edit:

I just got this piece of code (based on your sample) working. Note: for simplicity I've hardcoded 0 as interface number for detach_kernel_driver and attach_kernel_driver - you should make it smarter, I suppose.

import usb

dev = usb.core.find(idVendor=0x0403, idProduct=0x6001)

reattach = False
if dev.is_kernel_driver_active(0):
    reattach = True
    dev.detach_kernel_driver(0)

dev.set_configuration() 
cfg = dev.get_active_configuration() 

interface_number = cfg[(0,0)].bInterfaceNumber 
alternate_settting = usb.control.get_interface(dev, interface_number) 
intf = usb.util.find_descriptor(cfg, bInterfaceNumber = interface_number, 
                            bAlternateSetting = alternate_settting) 

ep = usb.util.find_descriptor(intf,custom_match = \
      lambda e: \
    usb.util.endpoint_direction(e.bEndpointAddress) == \
    usb.util.ENDPOINT_OUT) 
ep.write("test\n\r")

# This is needed to release interface, otherwise attach_kernel_driver fails 
# due to "Resource busy"
usb.util.dispose_resources(dev)

# It may raise USBError if there's e.g. no kernel driver loaded at all
if reattach:
    dev.attach_kernel_driver(0)