Dynamic HidReportDescriptor length

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
klaute_
Posts: 2
Joined: Thu Feb 11, 2010 1:57 pm
Location: Germany
Contact:

Dynamic HidReportDescriptor length

Post by klaute_ » Sat Feb 12, 2011 5:39 pm

Hello,

i got a problem with the dynamic and ram declaration of the HidReportDescriptor.

My circuit is based on the with-zener.sch with a atmega168-20pu (running at 20MHz) which also contains a working
USBASP bootloader. I tested my hardware with the Hid-Mouse example successful and I'm using the V-USB 20100715 version.

Now to my firmware, it is able to change mostly all of the possible usb-hid, -string and -configuration values at runtime.
Have a look at the code sniplet of my usbconfig.h.

usbconfig.h:

Code: Select all

...

/* See USB specification if you want to conform to an existing device class or
 * protocol. The following classes must be set at interface level:
 * HID class is 3, no subclass and protocol required (but may be useful!)
 * CDC class is 2, use subclass 2 and protocol 1 for ACM
 */
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH        100
/* Define this to the length of the HID report descriptor, if you implement
 * an HID device. Otherwise don't define it or define it to 0.
 * If you use this define, you must add a PROGMEM character array named
 * "usbHidReportDescriptor" to your code which contains the report descriptor.
 * Don't forget to keep the array and this define in sync!
 */

...

#define USB_CFG_DESCR_PROPS_DEVICE                  ( USB_PROP_IS_RAM | USB_PROP_LENGTH(18) )
#define USB_CFG_DESCR_PROPS_CONFIGURATION           0
#define USB_CFG_DESCR_PROPS_STRINGS                 0
#define USB_CFG_DESCR_PROPS_STRING_0                0
#define USB_CFG_DESCR_PROPS_STRING_VENDOR           ( USB_PROP_IS_RAM | USB_PROP_IS_DYNAMIC )
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT          ( USB_PROP_IS_RAM | USB_PROP_IS_DYNAMIC )
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER    ( USB_PROP_IS_RAM | USB_PROP_IS_DYNAMIC )
#define USB_CFG_DESCR_PROPS_HID                     0
#define USB_CFG_DESCR_PROPS_HID_REPORT              ( USB_PROP_IS_RAM | USB_PROP_IS_DYNAMIC )
#define USB_CFG_DESCR_PROPS_UNKNOWN                 0

...


The firmware is also able to change the HidReportDescriptors at runtime, so i put this into the RAM and marked it as dynamic.
As you can see in my code sniplet of the usbFunctionDescriptor, this function returns maxUSBHidReportDescriptorBytes.
It represent the actual amount of the HidReportDescriptor bytes.

main.c:

Code: Select all

...

uchar usbFunctionDescriptor(usbRequest_t *rq)
{

    switch ( rq->wValue.bytes[1] )
    {
        case USBDESCR_HID_REPORT :
            cleanDescriptor();
            usbMsgPtr = (uchar *)usbHidReportDescriptor;
            return maxUSBHidReportDescriptorBytes; // return size

...



This works fine if the descriptor is smaller as, or it's size equals to, the in
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH defined size. But only if I plug my hardware into a Linux
system (tested on Ubuntu 10.4 with a 2.6.32-29-generic kernel).

But it does not work on Windows (tested on XP professional x86, Win Vista x86 Home premium, Win 7 x86 prof, Win 7 x64 prof/home premium).
The windows error message is something like "The device could not started (Code 10)".

After many hours of debugging, using the search function of this forum and google i figured out that
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH has to be the correct size of the actual amount of bytes of the
given HidReportDescriptor to get it work on a Windows system.

If i define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH to the correct size of the startup HidReportDescriptor,
it works well at windows and linux.

Here is the part of the usbdrv.c, which i figured out as the problem. The USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH is
placed in FLASH memory, so the HidReportDescriptor could not be defined as "is dynamic" without defining USB_CFG_DESCR_PROPS_CONFIGURATION as "in ram" and "is dynamic" too.

usbdrv.c:

Code: Select all

    USB_CFG_INTERFACE_SUBCLASS,
    USB_CFG_INTERFACE_PROTOCOL,
    0,          /* string index for interface */
#if (USB_CFG_DESCR_PROPS_HID & 0xff)    /* HID descriptor */
    9,          /* sizeof(usbDescrHID): length of descriptor in bytes */
    USBDESCR_HID,   /* descriptor type: HID */
    0x01, 0x01, /* BCD representation of HID version */
    0x00,       /* target country code */
    0x01,       /* number of HID Report (or other HID class) Descriptor infos to follow */
    0x22,       /* descriptor type: report */
    USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH, 0,  /* total length of report descriptor */
#endif
#if USB_CFG_HAVE_INTRIN_ENDPOINT    /* endpoint descriptor for endpoint 1 */
    7,          /* sizeof(usbDescrEndpoint) */
    USBDESCR_ENDPOINT,  /* descriptor type = endpoint */
    (char)0x81, /* IN endpoint number 1 */
    0x03,       /* attrib: Interrupt endpoint */


It looks like it could solve my problem by defining it like this, in order to change the size in
usbDescriptorConfiguration[25,26 !?] at runtime.

But i'm not sure, so feel free to post any suggestions, questions...

Post Reply