How to Implement Multiple HID Class Functionalities with a Single HID interface – KBA228479

Version 6

    Author: KandlaguntaR_36     Version: **

    In general, HID interface is used for a single HID functionality such as a Mouse, Keyboard, or Joystick. For two functionalities, say Mouse and Keyboard together, two HID interfaces need to be created (i.e., two endpoints, two report descriptors, two HID descriptors, two DMA channels). Instead of two interfaces, it can be done with a single interface (one endpoint, one report descriptor, one HID descriptors, one DMA channel).

    This KBA explains the implementation of Mouse and Keyboard functionalities with one HID interface.

    1. The report descriptor must have two collection applications, one for mouse and other for keyboard. In each collection application put a Report ID item for each application.
    2. In the report, the first byte must be Report ID, and the remaining bytes must be their report information.

    For example, if you use the Mouse for the first collection (N=1) and the Keyboard for the second (N=2), to report the Mouse state, you should send 0x01 followed by button flags and axis data. To report the Keyboard state, you should send 0x02 followed by the alternate keys byte and then the keycodes.

    The report descriptor and report formats are described below:

     

    Report Descriptor:

             0x05, 0x01, /* Usage Page (Generic Desktop)             */

             0x09, 0x02, /* Usage (Mouse)                            */

             0xA1, 0x01, /* Collection (Application)                 */

    0x09,    0x09, 0x01, /* Usage (Pointer)                         */

             0xA1, 0x00, /* Collection (Physical)                   */

             0x85, 0x01, /* Report ID  */

             0x05, 0x09, /* Usage Page (Buttons)                */

             0x19, 0x01, /* Usage Minimum (01)                  */

             0x29, 0x03, /* Usage Maximum (03)                  */

             0x15, 0x00, /* Logical Minimum (0)                 */

             0x25, 0x01, /* Logical Maximum (0)                 */

             0x95, 0x03, /* Report Count (3)                    */

             0x75, 0x01, /* Report Size (1)                     */

             0x81, 0x02, /* Input (Data, Variable, Absolute)    */

             0x95, 0x01, /* Report Count (1)                    */

             0x75, 0x05, /* Report Size (5)                     */

             0x81, 0x01, /* Input (Constant)    ;5 bit padding  */

             0x05, 0x01, /* Usage Page (Generic Desktop)        */

             0x09, 0x30, /* Usage (X)                           */

             0x09, 0x31, /* Usage (Y)                           */

             0x15, 0x81, /* Logical Minimum (-127)              */

             0x25, 0x7F, /* Logical Maximum (127)               */

             0x75, 0x08, /* Report Size (8)                     */

             0x95, 0x02, /* Report Count (2)                    */

             0x81, 0x06, /* Input (Data, Variable, Relative)    */

             0xC0, 0xC0, /* End Collection,End Collection            */

             0x09, 0x06, /* Usage (Keyboard)                    */

             0xA1, 0x01, /* Collection (Application)            */

             0x85, 0x02, /* Report ID  */

             0x05, 0x07, /* Usage Page(Keycodes)               */

    0x19, 224,  /*   Usage Minimum              */

    0x29, 231,  /*   Usage Maximum              */

    0x15, 0,    /*   Logical Minimum            */

    0x25, 1,    /*   Logical Maximum            */

    0x75, 1,    /*   Report Size = 1 bit        */

    0x95, 8,    /*   Report Count               */

    0x81, 2,    /*   Input(DataAbsolute) = Modifier byte */

    0x81, 1,    /*   Input(Constant) = Reserved byte */

    0x75, 8,    /*   Report Size = 1 byte */

    0x95, 3,    /*   Report Count = 3codes */

    // I only support printable ASCII keys (and CR)*/

    0x19, 0,    /*   Usage Minimum              */

    0x29, 0x38, /*   Usage Maximum         */

    0x15, 0,    /*   Logical Minimum            */

    0x25, 0x38, /*   Logical Maximum       */

    0x81, 0,    /*   Input(DataArray) = 3Keycodes */

    // Now declare the 5 bit input report for LEDs    */

    0x05, 0x08, /*   Usage Page(LEDs)           */

    0x19, 0x01, /*   Usage Minimum              */

    0x29, 0x05, /*   Usage Maximum              */

    0x15, 0,    /*   Logical Minimum            */

    0x25, 0x01, /*   Logical Maximum            */

    0x75, 0x01, /*   Report Size = 1 bit        */

    0x95, 0x05, /*   Report Count               */

    0x91, 0x02, /*   Output(DataAbsolute) = LEDs */

    0x95, 0x03, /*   Report Count               */

    0x91, 0x01, /*   Output(Constant) = LED padding to next byte boundary */

    0xC0        /*    End Collection            */

     

    Report Format for Mouse:

    CyU3PMemSet((uint8_t)outBuf.buffer , 0, 10);

    /* Copy Report Data into the output buffer */

    outBuf.buffer[0] = (uint8_t)(0x01); /* Report ID */

    outBuf.buffer[1] = (uint8_t)(0x00); /* Button Clicks */

    outBuf.buffer[2] = (uint8_t)(glMouseData[i]); /* X- Axis*/

    outBuf.buffer[3]= (uint8_t)(glMouseData[i + 1]);/*Y-Axis*/

    status = CyU3PDmaChannelCommitBuffer (&glChHandleIntrCPU2U, 4, 0);

     

    Report Format for Keyboard:

    CyU3PMemSet(outBuf.buffer, 0, 10);

    /* Copy Report Data into the output buffer */

    outBuf.buffer[0] = (uint8_t)(0x02); /* Report ID */

    outBuf.buffer[1] = (uint8_t)(0x02); /* Modifier */

    outBuf.buffer[2] = (uint8_t)(0x00); /* Cosntant Byte */

    outBuf.buffer[3] = (uint8_t)(0x06); /*C*/

    outBuf.buffer[4] = (uint8_t)(0x1C); /*Y */

    outBuf.buffer[5] = (uint8_t)(0x28); /*Enter */

    status = CyU3PDmaChannelCommitBuffer (&glChHandleIntrCPU2U, 6, 0);

     

    These changes are implemented in the MouseDemo example of FX3 SDK (The default SDK path: C:\Program Files (x86)\Cypress\EZ-USB FX3 SDK\1.3\firmware\hid_examples\cyfx3_hid) and attached with this KBA for reference.