I'm building a Linux kernel module that needs to read an HID device, to send data to a hypervisor using RPC communication. These assumptions are necessary, as I'm working in embedded Linux and the SoC I'm developing for, requires a kernel module to send this type of data and send back data through registered callbacks.
I know that there are libraries such as libusb / hidapi that can simply send a HID command and read HID data from userspace, like this:
hidapitester --vidpid 2752:0012 -l 8 --open --send-output 0x03,0x53,0x02,0x58 --read-input
Where an ID will point to the device, and we can send and read bytes according to the manufacturer spec. We can also do this writing a program using their library functions, which ultimately are based on HIDRAW.
The issue is, these are libraries that work on userspace, but compiling a kernel module with userspace functions is not possible, thus these libraries won't work. HIDRAW relies mostly on IOCTL so using the ioctl() calls was tried but not successful either.
How to write and read to an HID device that I know the ID of from a Linux kernel module?
I've tried using hidapi and hidraw functions or just the direct ioctl() call from the kernel module but I get:
error: implicit declaration of function 'ioctl'
or the equivalent with the library functions and after some research I realized these are userspace functions.
I managed to send an HID report/command with a kernel module.
To do so one has to create a module (read about the Linux kernel module structure if you are not familiar) and use the
struct hid_driver. Here is necessary to register some functions that will be called once our driver is recognized as the appropriate one for a given device:To make our driver be called when an HID device is connected, we use the
id_tablelike this:Where
ID OF THE VENDORandID OF THE PRODUCTcan be replaced for the hex values of vendor and product. These can be read manually once usinglsusborusb-devicesin userspace. Documentation of other drivers doing more specificity to select a device, or use a single module to target different types of devices is available at drivers/hid/ in the Linux kernel source tree.After that, the
->probe()function will be a good starting point as this is called when the driver is first assigned to a device. We get thehid_deviceas an argument when the device is connected and the function is called. Inside we should call some necessary functions likehid_parse(),hid_hw_start()andhid_hw_open(), then we are ready to send a report.Here we can use
hid_hw_request(), a function fromhid-core, for this purpose.If we want to send 5 bytes of the following data
[0x01,0xff,0x01,0x33,0x0f]we can do it like this:Keep in mind that ID and field are specific to how your HID device works, I just used the simplest configuration here.
If we want to do a reading, we can use
HID_INPUT_REPORTfor the enum andHID_REQ_GET_REPORTfor the argumenthid_hw_request().We can take a look at the documentation in include/linux/hid.h,
hid-coreand drivers/hid/ inside the Linux kernel source tree, to find practical examples as well as the different exposed functions to use the HID layers.Also https://www.kernel.org/doc/html/latest/hid/hid-transport.html can be useful if one is doing more low level operations.