Using Pi Zero W to simulate HID keyboard and mouse - usb

My intention is to use a PiZeroW as an HID keyboard and mouse USB input device to computers.
I have consulted the following
https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ a good overview with links to usb.org's documentation
https://eleccelerator.com/usbdescreqparser/ a parser to check the report file
example code for hid keyboard, joystick, mouse https://github.com/msemtd/promicro-joypad/blob/master/HID.cpp
also, http://www.isticktoit.net/?p=1383
I thought I could just combine the keyboard and mouse descriptors into one file, adding REPORT_ID to each
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0x65, // Usage Maximum (0x65)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x02, // Usage (Mouse)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x85, 0x02, // Report ID (2)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x03, // Usage Maximum (0x03)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x05, // Report Size (5)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
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,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0xC0, // End Collection
// 117 bytes
And then, it's a matter of setting up rc.local to automatically execute /usr/bin/isticktoit_usb, i.e.
#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p isticktoit
cd isticktoit
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
#echo 0x1d6b > idVendor # Linux Foundation
#echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x2341 > idVendor # pretend leonardo
echo 0x8036 > idProduct # pretend leonardo
mkdir -p strings/0x409
echo "fedcba9876543210" > strings/0x409/serialnumber
echo "pi zero w HID" > strings/0x409/manufacturer
echo "iSticktoit.net USB Device" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower
# Add functions here
# see gadget configurations below
# End functions
# Add functions here
mkdir -p functions/hid.usb0
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
echo 8 > functions/hid.usb0/report_length
echo -ne \\x05\\x01\\x09\\x06\\xA1\\x01\\x85\\x01\\x05\\x07\\x19\\xE0\\x29\\xE7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xC0\\x05\\x01\\x09\\x02\\xA1\\x01\\x09\\x01\\xA1\\x00\\x85\\x02\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7F\\x75\\x08\\x95\\x02\\x81\\x06\\xC0\\xC0 > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/
# End functions
echo 0x80 > configs/c.1/bmAttributes
echo 200 > configs/c.1/MaxPower # 200 mA
ls /sys/class/udc > UDC
chown pi /dev/hidg0
sleep 3
The chown line is just to let user pi access the hidg0 port, with a test program such as
#!/usr/bin/python3
import time
time.sleep(3)
NULL_CHAR = chr(0)
def write_report(report):
with open('/dev/hidg0', 'rb+') as fd:
fd.write(report.encode())
# Press a
write_report(chr(2) + NULL_CHAR*2+chr(4)+NULL_CHAR*5)
# Release keys
write_report(chr(2)+ NULL_CHAR*8)
# Press B
write_report(chr(2) + chr(32) + NULL_CHAR + chr(5)+NULL_CHAR*5)
# Release keys
write_report(chr(2) + NULL_CHAR*8)
The first character says the report is meant for REPORT_ID 2, i.e. the keyboard.
I was able to get the PZW to emulate a keyboard. But adding REPORT_ID and the mouse descriptor seems to make the emulation unrecognizable as a USB device.
The test program returns with
Traceback (most recent call last):
File "./composite.py", line 14, in <module>
write_report(chr(2) + NULL_CHAR*2+chr(4)+NULL_CHAR*5)
File "./composite.py", line 11, in write_report
fd.write(report.encode())
BrokenPipeError: [Errno 108] Cannot send after transport endpoint shutdown
Where did I go wrong?

This remains a good tutorial https://www.rmedgar.com/blog/using-rpi-zero-as-keyboard-setup-and-device-definition/
Here are the files I have used
(1) /usr/bin/isticktoit_usb
#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p isticktoit
cd isticktoit
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
#echo 0x1d6b > idVendor # Linux Foundation
#echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x2341 > idVendor # pretend leonardo
echo 0x8036 > idProduct # pretend leonardo
mkdir -p strings/0x409
echo "fedcba9876543210" > strings/0x409/serialnumber
echo "pi zero w HID" > strings/0x409/manufacturer
echo "iSticktoit.net USB Device" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1: ECM network" > configs/c.1/strings/0x409/configuration
echo 250 > configs/c.1/MaxPower
# Add functions here
# see gadget configurations below
# End functions
# Add functions here
mkdir -p functions/hid.usb0
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
echo 8 > functions/hid.usb0/report_length
echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x85\\x01\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x09\\x38\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x03\\x81\\x06\\xc0\\xc0\\x05\\x01\\x09\\x06\\xa1\\x01\\x85\\x02\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/
# End functions
echo 0x80 > configs/c.1/bmAttributes
echo 200 > configs/c.1/MaxPower # 200 mA
sleep 10
ls /sys/class/udc > UDC
sleep 2
chown pi /dev/hidg0
sleep 2
(2) test.py
#!/usr/bin/python3
import time
time.sleep(3)
NULL_CHAR = chr(0)
def write_report(report):
with open('/dev/hidg0', 'rb+') as fd:
fd.write(report.encode())
# Press a
write_report(chr(2) + NULL_CHAR*2+chr(4)+NULL_CHAR*5)
# Release keys
write_report(chr(2)+ NULL_CHAR*8)
# Press B
write_report(chr(2) + chr(32) + NULL_CHAR + chr(5)+NULL_CHAR*5)
# Release keys
write_report(chr(2) + NULL_CHAR*8)
# testing mouse
write_report(chr(1)+NULL_CHAR+chr(100)+chr(0)+NULL_CHAR)
time.sleep(2)
write_report(chr(1)+NULL_CHAR+chr(100)+chr(100)+NULL_CHAR)
time.sleep(2)
write_report(chr(1)+NULL_CHAR+chr(228)+chr(228)+NULL_CHAR)

Related

Alternative to sprintf() for bytes buffer in C

Hello guys I have an issue when i try to put my bytes buffer into a sql buffer for sqlite3.c.
For example, I have this buffer:
static unsigned char bytes_buffer[] = {
0x30, 0x82, 0x01, 0x4b, 0x30, 0x82, 0x01, 0x03, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x30, 0x81, 0xf7, 0x02, 0x01, 0x01, 0x30,
0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x21,
0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00}
My function to add this info into a sqlite3 query and insert into my database is the following:
unsigned char *sql=(unsigned char *)malloc((size_t)(sizeof(unsigned char)*SQL_SIZE));
sprintf(sql,"UPDATE table SET buffer='%s', WHERE id=%d",bytes_buffer,id);
printf("SQL: %s\n",sql);
if (sqlite3_exec(db, sql, NULL, NULL, NULL) != SQLITE_OK)
{
return SQLITE_ERROR;
}
else
return SQLITE_OK;
}
The problem is when i try to show the query content, because in the buffer parameter sprintf() stops when a null character (0x00) appears. I need a function similar to sprintf() where I can manage the parameters size. I tried snprintf() and also fails. Thank you so much.

USB HID difference between "Get Input Report" and "Input report"

I'm implementing a custom HID device that has the following interface:
0x06, 0xA0, 0xFF, // Usage Page (Vendor Defined 0xFFA0)
0x09, 0x01, // Usage (0x01)
0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x01, 0x00, // Logical Maximum (1)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x85, 0x01, // Report ID (1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0x01, 0x00, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x02, // Report Count (2)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x06, // Report Size (6)
0x95, 0x01, // Report Count (1)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x85, 0x03, // Report ID (1)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0xFF, // Logical Maximum (65535)
0x75, 0x10, // Report Size (16)
0x95, 0x01, // Report Count (1)
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0xC0, // End Collection
When I plug this device into the computer through a USB logic analyzer I see it enumerate, then something (I'm not sure what, any ideas?) uses the HID report descriptor to intelligently grab a bunch of reports:
(control)(endpoint 0) Get Input Report[1]
(control)(endpoint 0) Get Feature Report[1]
The "Get Input Report" entry confused me as I thought input reports were sent via an interrupt transfer. If I use usbhid's hid_write, I see the following entry, so I must be at least half right about input reports being sent via interrupt transfers...:
(interrupt)(endpoint 1) Input Report[1]"
I have been unable to find information that describes the difference between control "get input reports" and interrupt "input report" transfers which I am hoping one of you will know about.
Why do control "get input reports" exist?
Why not just have the spec mandate a "get feature report" entry exist for every "input report" id entry?
Why is whatever is grabbing input/feature reports for every defined input/feature report using a control transfer for the input reports vs. an interrupt transfer?
Have a look at USB HID v1.1. There is definition for Get_Report request on page 51:
This request is useful at initialization time for absolute items and for determining the state of feature items. This request is not intended to be used for polling the device state on a regular basis.
Here, this is exactly what the driver is doing: it is retrieving the various reports to initialize its current state. Note the host cannot request the device to send a report on its interrupt pipe. Hence the request on control pipe.
Chapter 4.4 explains various endpoints usage.
Also note feature reports and input reports do not address the same data, even if they have the same report ID (report IDs are per report type).

STM32 USB HID reports

For the past two weeks I have been trying to configure my card (STM32F4) to dialogue with USB HID with a PC under Windows 7. I make success with this descriptor:
__ALIGN_BEGIN static uint8_t HID_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0xFF, 0x00, // USAGE_PAGE (Vendor Page: 0xFF00)
0x09, 0x01, // USAGE (Demo Kit)
0xa1, 0x01, // COLLECTION (Application)
//0x85, 0x01, // REPORT_ID (1)
0x09, 0x02, // USAGE (DATA)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff,0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0 // END_COLLECTION
};
Like this, Windows recognizeS my card like a compliant HID component.
Now if I want to send 32 bit data like a uint32, Windows recognizes the card, but it sees an error to tell that it can't start it! My descriptor:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0xFF, 0x00, // USAGE_PAGE (Vendor Page: 0xFF00)
0x09, 0x01, // USAGE (Demo Kit)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x02, // USAGE (DATA)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x27, 0xff,0xff,0xff,0xff, // LOGICAL_MAXIMUM (65535)
0x75, 0x20, // REPORT_SIZE (32)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0 // END_COLLECTION
};
I didn't understand why it din't work!
After that, I use USBlyser to scan my other USB device on my PC, and I take this descriptor about my spacespilot 3D mouse:
Endpoint Descriptor 83 3 In, Interrupt, 16 ms
Offset Field Size Value Description
0 bLength 1 07h
1 bDescriptorType 1 05h Endpoint
2 bEndpointAddress 1 83h 3 In
3 bmAttributes 1 03h Interrupt
1..0: Transfer Type ......11 Interrupt
7..2: Reserved 000000..
4 wMaxPacketSize 2 0007h 7 bytes
6 bInterval 1 08h 16 ms
Interface 1 HID Report Descriptor Multi-Axis Controller
Item Tag (Value) Raw Data
Usage Page (Generic Desktop) 05 01
Usage (Multi-Axis Controller) 09 08
Collection (Application) A1 01
Collection (Physical) A1 00
Report ID (1) 85 01
Logical Minimum (-500) 16 0C FE
Logical Maximum (500) 26 F4 01
Physical Minimum (-32768) 36 00 80
Physical Maximum (32767) 46 FF 7F
Usage (X) 09 30
Usage (Y) 09 31
Usage (Z) 09 32
Report Size (16) 75 10
Report Count (3) 95 03
Input (Data,Var,Abs,NWrp,Lin,Pref,NNul,Bit) 81 02
End Collection C0
If I try this, it works fine:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x08, //Usage (Multi-Axis Controller)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // Collection (Physical)
0x85, 0x01, // Report ID (1)
0x16,0x0c,0xfe, // Logical minimum (-500)
0x26,0xf4,0x01, // Logical maximum (500)
0x35,0x00, // Physical Minimum (0)
0x46,0xff,0x00, // Physical Maximum (255)
0x09,0x30, // Usage(X)
0x09,0x31, // Usage(Y)
0x09,0x32, // Usage(Z)
0x09,0x33, // Usage(RX)
0x09,0x34, // Usage(RY)
0x09,0x35, // //Usage(RZ)
0x75, 0x08, // REPORT_SIZE (16)
0x95, 0x06, // REPORT_COUNT (6)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
But if I try the same descriptor that my 3D mouse:
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x08, // Usage (Multi-Axis Controller)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // Collection (Physical)
0x85, 0x01, // Report ID (1)
0x16,0x0c,0xfe, // Logical minimum (-500)
0x26,0xf4,0x01, // Logical maximum (500)
0x35,0x00,0x80, // Physical Minimum (-32768)
0x46,0xff,0x7f, // Physical Maximum (32767)
0x09,0x30, // Usage(X)
0x09,0x31, // Usage(Y)
0x09,0x32, // Usage(Z)
0x75, 0x10, // REPORT_SIZE (16)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x02, // INPUT (Data,Var,Abs,Vol)
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
};
Windows gives me the same error, and it can't start the device!!!
What is wrong? Do I need a special driver for Windows to send 32 bit data (int32)? For information, I use the HID library for my application PC side.
How can I resolve this?
The LOGICAL_MAXIMUM four-byte descriptor tag (0x27) is only valid up to 0x7FFFFFFF as it is describing a maximum for a signed int data field. If you want to describe an unsigned int data field you would need to use the LOGICAL_MAXIMUM 8 byte descriptor tag like this:
0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00
Your second example would work, I think. Except for the typo for the Physical maximum descriptor tag. It should be 0x36, not 0x35.
When I tried your last descriptor (using my Arduino USBComposite library for STM32F1), Windows gave me an error about the descriptor having an unknown item. But when I changed the 0x35 in the Physical Minimum line to 0x36, Windows recognized the item.

How do I org.bluetooth.characteristic.report_map for more than one type of report?

Alright, I'm building a keyboard with an integrated touch-screen used as a mouse, I'm sending the data generated over BLE via HID OVER GATT. This works fine for org.bluetooth.characteristic.boot_keyboard_input_report & org.bluetooth.characteristic.boot_mouse_input_report, but I'm not very certain how to configure the report_map and what I need to send according to these declarations.
The Main question is really, because there is no hybrid type of Usage, I need to use two Usage. But do I need a second Usage Page? How do you define the Collection (Application) for such a hybrid device?
Usage Page
Usage Keyboard
??Usage Page
Usage Mouse
So I defined my report_map like this:
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x05, 0x07, // Usage Page (Key Codes);
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x81, 0x02, // Input (Data, Variable, Absolute), ; Modifier-Byte 8 bit
0x95, 0x01, // Report Count (1),
0x75, 0x08, // Report Size (8),
0x81, 0x01, // Input (Constant), ; Reserved byte 8 bit
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (Page# for LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute), ; LED byte 5 bits
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x01, // Output (Constant), ; Padding of 3 bits
0x95, 0x06, // Report Count (6),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x65, // Logical Maximum(101),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x65, // Usage Maximum (101),
0x81, 0x00, // Input (Data, Array),
0xC0, // End Collection
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x02, // COLLECTION (Logical)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
// ------------------------------ Buttons
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x05, // USAGE_MAXIMUM (Button 5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x02, // INPUT (Data,Var,Abs)
// ------------------------------ Padding
0x75, 0x05, // REPORT_SIZE (5)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
// ------------------------------ X,Y position
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,Var,Rel)
0xa1, 0x02, // COLLECTION (Logical)
// ------------------------------ Vertical wheel res multiplier
0x09, 0x48, // USAGE (Resolution Multiplier)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x01, // PHYSICAL_MINIMUM (1)
0x45, 0x04, // PHYSICAL_MAXIMUM (4)
0x75, 0x02, // REPORT_SIZE (2)
0x95, 0x01, // REPORT_COUNT (1)
0xa4, // PUSH
0xb1, 0x02, // FEATURE (Data,Var,Abs)
// ------------------------------ Vertical wheel
0x09, 0x38, // USAGE (Wheel)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xa1, 0x02, // COLLECTION (Logical)
// ------------------------------ Horizontal wheel res multiplier
0x09, 0x48, // USAGE (Resolution Multiplier)
0xb4, // POP
0xb1, 0x02, // FEATURE (Data,Var,Abs)
// ------------------------------ Padding for Feature report
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
0x75, 0x04, // REPORT_SIZE (4)
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
// ------------------------------ Horizontal wheel
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
0x0a, 0x38, 0x02, // USAGE (AC Pan)
0x15, 0x81, // LOGICAL_MINIMUM (-127)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x06, // INPUT (Data,Var,Rel)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0xc0 // END_COLLECTION
I'm not entirely sure, if I am allowed to define two Usage Pages, or if I need to create a collection and but all of the reports in there.
The second thing I'm not sure of, is how I create the values for specific INPUT Reports. Do they have some numbering system via report-id's that I don't get? Or do they have to be send all at once (I'm guessing this is right).
In my case the reports would look like this:
// Output Report
//
// Byte | D7 D6 D5 D4 D3 D2 D1 D0
// ------+---------------------------------------------------------------------
// 0 | NUM_LOCK CAPS_LOCK SCROLL_LOCK COMPOSE KANA CONSTANT CONSTANT CONSTANT
// Input Report for Keyboard
// Byte | D7 D6 D5 D4 D3 D2 D1 D0
// ------+---------------------------------------------------------------------
// 0 | LEFT_CTRL LEFT_SHIFT LEFT_ALT LEFT_OS RIGHT_CTRL RIGHT_SHIFT RIGHT_ALT RIGHT_OS
// 1 | Reserved please leave at 0
// 2-7 | Keycodes
// Input Report for Pointer
// Byte | D7 D6 D5 D4 D3 D2 D1 D0
// ------+---------------------------------------------------------------------
// 0 | 0 0 0 Forward Back Middle Right Left (Button)
// 1 | X
// 2 | Y
// 3 | Vertical Wheel
// 4 | Horizontal (Tilt) Wheel
Thanks in advance.

omap_udc.c g_hid.c hid gadget on beagleboard with angstrom linux

To use the beagleboard xm as an HID peripheral I plan to do the following:
Discover how to build things with angstrom.
Get the kernel source 2.6.32.
Compile omap_udc and g_hid
Insert those modules into the kernel
Compile the example from gadget_hid.txt
Send keyboard commands with hid_gadget_test /dev/hidg0 keyboard
Is that a good way to do what I want?
http://www.edaboard.com/thread145675.html is a somewhat related issue from '09.
Looking for Example Embedded Linux HID Device Code is very similar.
I figured I would post this here because I looked and looked for an answer but to no avail so I had to get creative.
First
Go here and get the Kernel
http://eewiki.net/display/linuxonarm/BeagleBone
Second in
The KERNEL/arch/arm/mach-omap2/board-am335xevm.c
Add:
enter code here
#include <linux/usb/g_hid.h>
/* hid descriptor for a keyboard */
static struct hidg_func_descriptor my_hid_data = {
.subclass = 0, /* No subclass */
.protocol = 1, /* Keyboard */
.report_length = 8,
.report_desc_length = 63,
.report_desc = {
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x06, /* USAGE (Keyboard) */
0xa1, 0x01, /* COLLECTION (Application) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0xe0, /* USAGE_MINIMUM (Keyboard LeftControl) */
0x29, 0xe7, /* USAGE_MAXIMUM (Keyboard Right GUI) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x95, 0x08, /* REPORT_COUNT (8) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
0x95, 0x05, /* REPORT_COUNT (5) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x05, 0x08, /* USAGE_PAGE (LEDs) */
0x19, 0x01, /* USAGE_MINIMUM (Num Lock) */
0x29, 0x05, /* USAGE_MAXIMUM (Kana) */
0x91, 0x02, /* OUTPUT (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x03, /* REPORT_SIZE (3) */
0x91, 0x03, /* OUTPUT (Cnst,Var,Abs) */
0x95, 0x06, /* REPORT_COUNT (6) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x65, /* LOGICAL_MAXIMUM (101) */
0x05, 0x07, /* USAGE_PAGE (Keyboard) */
0x19, 0x00, /* USAGE_MINIMUM (Reserved) */
0x29, 0x65, /* USAGE_MAXIMUM (Keyboard Application) */
0x81, 0x00, /* INPUT (Data,Ary,Abs) */
0xc0 /* END_COLLECTION */
}
};
static struct platform_device my_hid = {
.name = "hidg",
.id = 0,
.num_resources = 0,
.resource = 0,
.dev = {
.platform_data = &my_hid_data,
},
};
static void __init am33xx_hidg_init(void)
{
int ret;
ret = platform_device_register(&my_hid);
if (ret)
printk("HID Gadget registration failed\n");
}
In the:
static void __init am335x_evm_init(void)
{
am33xx_cpuidle_init();
am33xx_mux_init(board_mux);
omap_serial_init();
am335x_rtc_init();
**am33xx_hidg_init();**
clkout2_enable();
}
Build the kernel following the Guide from earlier
In the makemenu config section of the kernel build
go to the device drivers->usb support-> USB Gadget Support-> USB Gadget Drivers -> Compile HID Gadget as Module ( you may have to hunt for it but it's around this section in a couple more sub menus)
Take the sample code section from the kernel documentation
or this page http://www.mjmwired.net/kernel/Documentation/usb/gadget_hid.txt
Compile with GCC
insmod the g_hid.ko driver
and then run the compiled sample code