none
Problem enumerating a HID-over-I2C device RRS feed

  • Question

  • I'm developing a HID-over-I2C device but having some problems getting Windows to enumerate the top level HID collection. I see the (root? ACPI) device show up under "Human Interface Devices" in Device Manager but I don't see a child device representing the top level collection I need to interact with. This collection is very simple, containing a single input and a single output report, each making use of vendor-specific usages. Using a logic analyzer, I've verified that Windows is communicating with the device, reading the HID descriptor and the report descriptor, and that the values returned are what I expect in each case. I see no errors in Device Manager and my I2C HID Device entry states that the device is operating normally.

    I've built a USB device with exactly the same report descriptor and it enumerates fine with both entries appearing in Device Manager so this leaves me suspecting that the problem lies in my HID descriptor (given that it's different for USB and I2C cases). What I have seems correct to me but, re-reading the HID-over-I2C protocol spec, I have a couple of questions.

    1. I'm not entirely sure how to handle the wMaxInputLength and wMaxOutputLength fields. For wMaxInputLength, the spec states "This length field should also include the 2 Byte length field and the optional report ID. This length field should be identical to the largest Input Report’s length as identified in the Report Descriptor." These two sentences would appear to contradict one another since the 2 byte length header is not included in the report length as defined by the report descriptor. I assume that the HID descriptor length fields should be equivalent to the length of the longest input/output report + 2 to account for the additional 2 length bytes in the I2C protocol. Is this correct?

    2. Is there some requirement that the VID/PID reported in the HID descriptor correlate somehow with the device's entry in the DSDT? Currently, I'm using the same VID/PID that I do for the USB case in the HID(-over-I2C) descriptor. Could the fact that these don't relate to one another cause Windows not to create a Device Manager entry for my TLC?

    Any hints or tips anyone can provide would be greatly appreciated!

    Thursday, June 20, 2013 2:58 PM

Answers

  • I think you need an Application Collection (A1 01) wrapping you Logical Collection.
    Friday, June 28, 2013 5:18 PM
  • Thanks for the suggestion. If I have problems again, I'll give this a try. Since I posted the original question, though, the device has started working correctly so I suspect there must have been something else going wrong that was messing me up.
    Friday, June 28, 2013 5:40 PM

All replies

  • Here's a bit more information in case that helps.

    The HID descriptor in use is as follows:

    const tI2CHIDDescriptor g_sHIDDesc =
    {   
    .u16HIDDescLength = sizeof(tI2CHIDDescriptor), // 0x1E
    .ui8bcdVersion_H = 0x00,
        .ui8bcdVersion_L = 0x01,
        .ui16ReportDescLength = sizeof(g_pui8HIDReportDescriptor), // 0x21
        .ui16ReportDescRegister = HID_REPORT_DESC_REG, // 6
        .ui16InputRegister = HID_INPUT_REG, // 5
        .ui16InputMaxLength = INPUT_REPORT_SIZE, // 4
        .ui16OutputRegister = HID_OUTPUT_REG, // 4
        .ui16OutputMaxLength = OUTPUT_REPORT_SIZE, // 0x25
        .ui16CommandRegister = HID_COMMAND_REG, // 2
        .ui16DataRegister = HID_DATA_REG, // 3
        .ui16VendorID = HID_VENDOR_ID, // 0x1CBE
        .ui16ProductID = HID_PRODUCT_ID, // 0x00FF
        .ui16VersionID = HID_VERSION_ID, // 1
        .ui16Reserved0 = 0,
        .ui16Reserved1 = 0,
    };

    The report descriptor is as follows:

    const uint8_t g_pui8HIDReportDescriptor[] =
    {
        //
        // Vendor-specific HID device.
        //
        UsagePageVendor(USAGE_PAGE),                              // 0x06, 0x02, 0xFF
        UsageVendor(USAGE_COLLECTION),                            // 0x0A, 0x03, 0xFF
        Collection(USB_HID_LOGICAL),                              // 0xA1, 0x02
            ReportID(HID_OUTPUT_REPORT_ID),                       // 0x85, 0x0E
            LogicalMinimum(0),                                    // 0x15, 0x00
            LogicalMaximum(255),                                  // 0x25, 0xFF
            ReportSize(8),                                        // 0x75, 0x08
            ReportCount(OUTPUT_REPORT_PAYLOAD),                   // 0x95, 0x22
            UsageVendor(USAGE_OUTPUT),                            // 0x0A, 0xF3, 0xFF
            Output(USB_HID_OUTPUT_DATA | USB_HID_OUTPUT_ARRAY),   // 0x91, 0x00
            ReportID(HID_INPUT_REPORT_ID),                        // 0x85, 0x0D
            ReportCount(INPUT_REPORT_PAYLOAD),                    // 0x95, 0x01
            UsageVendor(USAGE_INPUT),                             // 0x0A, 0xF4, 0xFF
            Input(USB_HID_INPUT_DATA | USB_HID_INPUT_ARRAY),      // 0x81, 0x00
        EndCollection,                                            // 0xC0
    };
    OUTPUT_REPORT_SIZE is defined as (OUTPUT_REPORT_PAYLOAD + 3) and INPUT_REPORT_SIZE is (INPUT_REPORT_PAYLOAD + 3). In each case, the "+3" represents the additional 3 bytes of per-report overhead on caused by the 1 byte report ID (required in the USB case too) and the 2 byte length field (required only for the I2C case).

    Monday, June 24, 2013 6:45 PM
  • I think you need an Application Collection (A1 01) wrapping you Logical Collection.
    Friday, June 28, 2013 5:18 PM
  • Thanks for the suggestion. If I have problems again, I'll give this a try. Since I posted the original question, though, the device has started working correctly so I suspect there must have been something else going wrong that was messing me up.
    Friday, June 28, 2013 5:40 PM