#include <hid.h>
#include <stdio.h>
#include <string.h>
bool match_serial_number(struct usb_dev_handle* usbdev, void* custom, unsigned int len)
{
bool ret;
char* buffer = (char*)malloc(len);
usb_get_string_simple(usbdev, usb_device(usbdev)->descriptor.iSerialNumber,
buffer, len);
ret = strncmp(buffer, (char*)custom, len) == 0;
free(buffer);
return ret;
}
int main(void)
{
HIDInterface* hid;
hid_return ret;
/* How to use a custom matcher function:
*
* The third member of the HIDInterfaceMatcher is a function pointer, and
* the forth member will be passed to it on invocation, together with the
* USB device handle. The fifth member holds the length of the buffer
* passed. See above. This can be used to do custom selection e.g. if you
* have multiple identical devices which differ in the serial number.
*
* char const* const serial = "01518";
* HIDInterfaceMatcher matcher = {
* 0x06c2, // vendor ID
* 0x0038, // product ID
* match_serial_number, // custom matcher function pointer
* (void*)serial, // custom matching data
* strlen(serial)+1 // length of custom data
* };
*
* If you do not want to use this, set the third member to NULL.
* Then the match will only be on vendor and product ID.
*/
// HIDInterfaceMatcher matcher = { 0x0925, 0x1237, NULL, NULL, 0 };
HIDInterfaceMatcher matcher = { 0x51d, 0x0002, NULL, NULL, 0 };
/* see include/debug.h for possible values */
hid_set_debug(HID_DEBUG_ALL);
hid_set_debug_stream(stderr);
/* passed directly to libusb */
hid_set_usb_debug(0);
ret = hid_init();
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_init failed with return code %d\n", ret);
return 1;
}
hid = hid_new_HIDInterface();
if (hid == 0) {
fprintf(stderr, "hid_new_HIDInterface() failed, out of memory?\n");
return 1;
}
/* How to detach a device from the kernel HID driver:
*
* The hid.o or usbhid.ko kernel modules claim a HID device on insertion,
* usually. To be able to use it with libhid, you need to blacklist the
* device (which requires a kernel recompilation), or simply tell libhid to
* detach it for you. hid_open just opens the device, hid_force_open will
* try n times to detach the device before failing.
* In the following, n == 3.
*
* To open the HID, you need permission to the file in the /proc usbfs
* (which must be mounted -- most distros do that by default):
* mount -t usbfs none /proc/bus/usb
* You can use hotplug to automatically give permissions to the device on
* connection. Please see
* http://cvs.ailab.ch/cgi-bin/viewcvs.cgi/external/libphidgets/hotplug/
* for an example. Try NOT to work as root!
*/
ret = hid_force_open(hid, 0, &matcher, 3);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_force_open failed with return code %d\n", ret);
return 1;
}
ret = hid_write_identification(stdout, hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_write_identification failed with return code %d\n", ret);
return 1;
}
ret = hid_dump_tree(stdout, hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_dump_tree failed with return code %d\n", ret);
return 1;
}
/* How to write to and read from a device:
*
* Writing to a device requires the HID usage path, a buffer, and the length
* of the latter. You must also know the exact length of a packet expected
* by the device, and the protocol to speak over HID.
*
* libhid uses the MGE hidparser, which parses the HID usage tree and places
* the available usages at its leafs (leaves?). The path information can be
* read from the `lsusb -vvv` output, or by inspecting the output of
* hid_dump_tree. In the output, 0x80 denotes an input endoint (sent by the
* device), and 0x90 an output endpoint (sent to the device). These are then
* used to communicate with the device.
*
* In the example of the Phidgets QuadServoController (www.phidgets.com, and
* libphidgets.alioth.debian.org), the following two paths identify the
* input and output descriptors respectively.
*
* unsigned char const PATHLEN = 3;
* int const PATH_IN[PATHLEN] = { 0xffa00001, 0xffa00002, 0xffa10003 };
* int const PATH_OUT[PATHLEN] = { 0xffa00001, 0xffa00002, 0xffa10004 };
*
* This is derived from the output of `lsusb -d 0x06c2:0x0038 -vvv` as
* follows. You need to run `libhid_detach_device 06c2:0038` before lsusb
* will output this info:
*
* Bus 001 Device 028: ID 06c2:0038 GLAB Chester 4-Motor PhidgetServo v3.0
* Device Descriptor:
* [...]
* Configuration Descriptor:
* [...]
* Interface Descriptor:
* [...]
* iInterface
* HID Device Descriptor:
* [...]
* Report Descriptor:
* [...]
* Item(Global): Usage Page, data= [ 0xa0 0xff ] 65440
* [...]
* Item(Local ): Usage, data= [ 0x01 ] 1
* [...]
*
* Item(Local ): Usage, data= [ 0x02 ] 2
* [...]
*
* Item(Global): Usage Page, data= [ 0xa1 0xff ] 65441
* [...]
*
* Item(Local ): Usage, data= [ 0x03 ] 3
* [...]
* Item(Main ): Input, data= [ 0x02 ] 2
* [...]
*
* Item(Local ): Usage, data= [ 0x04 ] 4
* [...]
* Item(Main ): Output, data= [ 0x02 ] 2
* [...]
*
* So working backwards,
* "Item(Main) Output" is usage 4 of usage page 65441,
* which is rooted at "Item(Local) ... 2" of usage page 65440,
* which is rooted at "Item(Local) ... 1" of usage page 65440
*
* A path component is 32 bits, the high 16 bits identify the usage page,
* and the low 16 bits the item number. Thus (now working forwards):
*
* 65440 << 16 + 1 -> 0xffa00001
* 65440 << 16 + 2 -> 0xffa00002
* 65441 << 16 + 4 -> 0xffa10004
*
* which gives the path the the output usage of the HID. The input usage may
* be found analogously.
*
* Now, to send 6 bytes:
*
* unsigned char const SEND_PACKET_LEN = 6;
* // fill an example packet:
* char const PACKET[SEND_PACKET_LEN] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5 };
*
* ret = hid_set_output_report(hid, PATH_IN, PATHLEN, PACKET, SEND_PACKET_LEN);
* if (ret != HID_RET_SUCCESS) {
* fprintf(stderr, "hid_set_output_report failed with return code %d\n", ret);
* }
*
* And reading works similarly:
* char packet[RECV_PACKET_LEN];
* ret = hid_get_input_report(hid, PATH_OUT, PATHLEN, packet, RECV_PACKET_LEN);
* if (ret != HID_RET_SUCCESS) {
* fprintf(stderr, "hid_get_input_report failed with return code %d\n", ret);
* }
* // now use the RECV_PACKET_LEN bytes starting at *packet.
*/
ret = hid_close(hid);
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_close failed with return code %d\n", ret);
return 1;
}
hid_delete_HIDInterface(&hid);
ret = hid_cleanup();
if (ret != HID_RET_SUCCESS) {
fprintf(stderr, "hid_cleanup failed with return code %d\n", ret);
return 1;
}
return 0;
}
/* COPYRIGHT --
*
* This file is part of libhid, a user-space HID access library.
* libhid is (c) 2003-2005
* Martin F. Krafft <libhid@pobox.madduck.net>
* Charles Lepple <clepple@ghz.cc>
* Arnaud Quette <arnaud.quette@free.fr> && <arnaud.quette@mgeups.com>
* and distributed under the terms of the GNU General Public License.
* See the file ./COPYING in the source distribution for more information.
*
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
syntax highlighted by Code2HTML, v. 0.9.1