Page 1 of 1

usbFunctionRead() not getting called

Posted: Mon Jun 06, 2016 2:09 pm
by dode
Hello!

I've build a simple USB device with an ATmega328p running at 12 MHz with a crystal, following the "typical circuit" on the V-USB homepage, but running at 5V with the two zener diodes at D+ and D-.

It is running fine; it is detected very reliably on a Linux PC and my kernel USB driver module is loaded when the device connects:

Code: Select all

[56524.707406] usb 2-1.1: new low-speed USB device number 64 using ehci-pci
[56524.807554] usb 2-1.1: New USB device found, idVendor=d0de, idProduct=0001
[56524.807563] usb 2-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[56524.807569] usb 2-1.1: Product: USBTherm
[56524.807574] usb 2-1.1: Manufacturer: Dode
[56525.387240] usbtherm: USB device was connected
[56525.387817] usbcore: registered new interface driver usbtherm


Getting the descriptor from the kernel driver like that works fine:

Code: Select all

usb_get_descriptor(dev->usbdev, USB_DT_DEVICE, 0x00,
         &usb_dev_desc, sizeof(usb_dev_desc));


Now I'd like to send a custom "vendor" request and have the driver send back a temperature value (max 8 bytes) read "on the fly". For that I have:
  • Set USB_CFG_IMPLEMENT_FN_READ to 1
  • make clean...
  • Implemented the function usbFunctionRead()
  • Return USB_NO_MSG from usbFunctionSetup()

From the kernel driver I am calling:

Code: Select all

unsigned char data[8];
usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, 0),
         0, USB_TYPE_VENDOR, 0, 0, data, sizeof(data), 1000);


In the device, usbFunctionSetup() is entered and USB_NO_MSG is returned, but usbFunctionRead() is never called and the timeout of 1 second is hit.

In Wireshark, I can see the "URB CONTROL out" request and the response when the timeout occurs and the response contains a strange URB status:

Code: Select all

URB status: No such file or directory (-ENOENT) (-2)


What could I be doing wrong?

Re: usbFunctionRead() not getting called

Posted: Tue Jun 07, 2016 1:20 am
by dode
Argh.

Finally I figured out that bRequestType is not just i.e. USB_TYPE_VENDOR but three fields.

From linux/usb/ch9.h:

Code: Select all

/*
 * USB directions
 *
 * This bit flag is used in endpoint descriptors' bEndpointAddress field.
 * It's also one of three fields in control requests bRequestType.
 */
#define USB_DIR_OUT         0      /* to device */
#define USB_DIR_IN         0x80      /* to host */

/*
 * USB types, the second of three bRequestType fields
 */
#define USB_TYPE_MASK         (0x03 << 5)
#define USB_TYPE_STANDARD      (0x00 << 5)
#define USB_TYPE_CLASS         (0x01 << 5)
#define USB_TYPE_VENDOR         (0x02 << 5)
#define USB_TYPE_RESERVED      (0x03 << 5)

/*
 * USB recipients, the third of three bRequestType fields
 */
#define USB_RECIP_MASK         0x1f
#define USB_RECIP_DEVICE      0x00
#define USB_RECIP_INTERFACE      0x01
#define USB_RECIP_ENDPOINT      0x02
#define USB_RECIP_OTHER         0x03
/* From Wireless USB 1.0 */
#define USB_RECIP_PORT         0x04
#define USB_RECIP_RPIPE      0x05


So the request now looks like this:

Code: Select all

usb_control_msg(dev->usbdev, usb_rcvctrlpipe(dev->usbdev, USB_DIR_OUT),
         USB_REQ_GET_STATUS, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
         0, 0, data, sizeof(data), 1000);


And it works just fine. And it's just right there in the examples... :oops: