Linux下HID 设备,如果非标准的输入设备(Keypad/MOUSE/JoyStick/input event device).
将会把信息转入hid device的设备结点。
这一点可以参见内核的关于hiddev的文档
它在 Documentation/usb/hiddev.txt 目录下,大致有这样一个流程,
usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event]
|
|
--> hiddev.c ----> POWER / MONITOR CONTROL
关于操作非标准的HID设备,可以参见如下文档.
http://www.wetlogic.net/hiddev/
在设备文件系统中,会产生的/dev/hiddev0这样的结点,这类设备主设备号为 180,从设备号最低为96
mknod /dev/hiddev0 c 180 96
mknod /dev/hiddev1 c 180 97
mknod /dev/hiddev2 c 180 98
mknod /dev/hiddev3 c 180 99
...
mknod /dev/hiddev15 c 180 111
对此设备结点的处理有两种接口,一种是read(),另一种是ioctl();
-
read():
This is the event interface. When the HID device performs an interrupt
transfer, indicating a change of state, data will be made available at
the associated hiddev device with the content
of a struct hiddev_event:struct hiddev_event { unsigned hid; signed int value; }; containing the HID usage identifier for the status that changed, and the value that it was changed to.
-
ioctl(): This is the control interface. There are a number of controls:
HIDIOCGVERSION
|
int (read)
|
Gets the version code out of the hiddev driver.
|
HIDIOCAPPLICATION
|
(none)
|
This ioctl
call returns the HID application usage associated with the hid device.
The third argument to ioctl() specifies which application index to get.
This is useful when the device has more than
one application collection. If the index is invalid (greater or equal
to the number of application collections this device has) the ioctl
returns -1. You can find out beforehand how many application collections
the device has from the num_applications field
from the hiddev_devinfo structure.
|
HIDIOCGDEVINFO
|
struct hiddev_devinfo (read)
|
Gets a hiddev_devinfo structure which describes the device.
|
HIDIOCGSTRING
|
struct struct hiddev_string_descriptor (read/write)
|
Gets a string
descriptor from the device. The caller must fill in the "index" field to
indicate which descriptor should be returned.
|
HIDIOCINITREPORT
|
|
Instructs the
kernel to retrieve all input and feature report values from the device.
At this point, all the usage structures will contain current values for
the device, and will maintain it as the device
changes.
|
HIDIOCGNAME
|
string (variable length)
|
Gets the device name
|
HIDIOCGREPORT
|
struct hiddev_report_info (write)
|
Instructs the
kernel to get a feature or input report from the device, in order to
selectively update the usage structures (in contrast to INITREPORT).
|
HIDIOCSREPORT
|
struct hiddev_report_info (write)
|
Instructs the kernel to send a report to the device. This report can be filled in by the user throughHIDIOCSUSAGE calls (below) to fill in
individual usage values in the report before sending the report in full to the device.
|
HIDIOCGREPORTINFO
|
struct hiddev_report_info (read/write)
|
Fills in a
hiddev_report_info structure for the user. The report is looked up by
type (input, output or feature) and id, so these fields must be filled
in by the user. The ID can be absolute -- the actual
report id as reported by the device -- or relative -- HID_REPORT_ID_FIRST for the first report, and (HID_REPORT_ID_NEXT |
report_id) for
the next report after report_id. Without a-priori information about
report ids, the right way to use this ioctl is to use the relative IDs
above to enumerate the valid IDs. The ioctl returns non-zero when there
is no more next ID. The real report ID is filled
into the returned hiddev_report_info structure.
|
HIDIOCGFIELDINFO
|
struct hiddev_field_info (read/write)
|
Returns the
field information associated with a report in a hiddev_field_info
structure. The user must fill in report_id and report_type in this
structure, as above. The field_index should also be filled
in, which should be a number from 0 and maxfield-1, as returned from a
previous HIDIOCGREPORTINFO call.
|
HIDIOCGUCODE
|
struct hiddev_usage_ref (read/write)
|
Returns the
usage_code in a hiddev_usage_ref structure, given that given its report
type, report id, field index, and index within the field have already
been filled into the structure.
|
HIDIOCGUSAGE
|
struct hiddev_usage_ref (read/write)
|
Returns the
value of a usage in a hiddev_usage_ref structure. The usage to be
retrieved can be specified as above, or the user can choose to fill in
the report_type field and specify the report_id asHID_REPORT_ID_UNKNOWN.
In this case, the hiddev_usage_ref will be filled in with the report
and field infomation associated with this usage if it is found.
|
HIDIOCSUSAGE
|
struct hiddev_usage_ref (write)
|
Sets the value of a usage in an output report.
|
测试代码
-
/*
-
Author : Andrew Huang <bluedrum@163.com>
-
<<Care and feeding of your Human Interface Devices>>
-
http://lxr.free-electrons.com/source/Documentation/usb/hiddev.txt?v=2.6.30
-
http://www.wetlogic.net/hiddev/
-
*/
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <sys/types.h>
-
#include <sys/stat.h>
-
#include <fcntl.h>
-
#include <time.h>
-
#include <sys/ioctl.h>
-
#include <linux/hiddev.h>
-
-
static void showReports(int fd, unsigned report_type);
-
static void show_all_report(int fd);
-
static int read_event(int fd);
-
-
int main()
-
{
-
char dev_name[64] = "/dev/hiddev0";
-
int fd = -1;
-
int version;
-
char name[100];
-
struct hiddev_devinfo dinfo;
-
-
-
fd = open(dev_name,O_RDWR);
-
if(fd == -1)
-
{
-
fprintf(stderr,"open %s failure\n",dev_name);
-
return -1;
-
}
-
-
-
printf("%s infor\n",dev_name);
-
-
if (ioctl(fd, HIDIOCGVERSION, &version) < 0)
-
perror("HIDIOCGVERSION");
-
else
-
{
-
printf("HIDIOCGVERSION: %d.%d\n", (version>>16) & 0xFFFF, version & 0xFFFF);
-
if (version != HID_VERSION)
-
printf("WARNING: version does not match compile-time version\n");
-
}
-
-
if (ioctl(fd, HIDIOCGDEVINFO, &dinfo) < 0)
-
perror("HIDIOCGDEVINFO");
-
else
-
{
-
printf("HIDIOCGDEVINFO: bustype=%d busnum=%d devnum=%d ifnum=%d\n"
-
"\tvendor=0x%04hx product=0x%04hx version=0x%04hx\n"
-
"\tnum_applications=%d\n",
-
dinfo.bustype, dinfo.busnum, dinfo.devnum, dinfo.ifnum,
-
dinfo.vendor, dinfo.product, dinfo.version, dinfo.num_applications);
-
}
-
-
if (ioctl(fd, HIDIOCGNAME(99), name) < 0)
-
perror("HIDIOCGNAME");
-
else
-
{
-
name[99] = 0;
-
printf("HIDIOCGNAME: %s\n", name);
-
}
-
-
#if 0
-
printf("\n*** INPUT:\n"); showReports(fd, HID_REPORT_TYPE_INPUT);
-
printf("\n*** OUTPUT:\n"); showReports(fd, HID_REPORT_TYPE_OUTPUT);
-
printf("\n*** FEATURE:\n"); showReports(fd, HID_REPORT_TYPE_FEATURE);
-
#endif
-
show_all_report(fd);
-
-
read_event(fd);
-
-
close(fd);
-
-
-
-
}
-
-
-
-
-
static void showReports(int fd, unsigned report_type)
-
{
-
struct hiddev_report_info rinfo;
-
struct hiddev_field_info finfo;
-
struct hiddev_usage_ref uref;
-
int i, j, ret;
-
-
rinfo.report_type = report_type;
-
rinfo.report_id = HID_REPORT_ID_FIRST;
-
ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
-
while (ret >= 0)
-
{
-
printf("HIDIOCGREPORTINFO: report_id=0x%X (%u fields)\n",
-
rinfo.report_id, rinfo.num_fields);
-
for (i = 0; i < rinfo.num_fields; i++)
-
{
-
finfo.report_type = rinfo.report_type;
-
finfo.report_id = rinfo.report_id;
-
finfo.field_index = i;
-
ioctl(fd, HIDIOCGFIELDINFO, &finfo);
-
-
printf("HIDIOCGFIELDINFO: field_index=%u maxusage=%u flags=0x%X\n"
-
"\tphysical=0x%X logical=0x%X application=0x%X\n"
-
"\tlogical_minimum=%d,maximum=%d physical_minimum=%d,maximum=%d\n",
-
finfo.field_index, finfo.maxusage, finfo.flags,
-
finfo.physical, finfo.logical, finfo.application,
-
finfo.logical_minimum, finfo.logical_maximum,
-
finfo.physical_minimum, finfo.physical_maximum);
-
-
for (j = 0; j < finfo.maxusage; j++)
-
{
-
uref.report_type = finfo.report_type;
-
uref.report_id = finfo.report_id;
-
uref.field_index = i;
-
uref.usage_index = j;
-
ioctl(fd, HIDIOCGUCODE, &uref);
-
ioctl(fd, HIDIOCGUSAGE, &uref);
-
-
printf(" >> usage_index=%u usage_code=0x%X () value=%d\n",
-
uref.usage_index,
-
uref.usage_code,
-
// controlName(uref.usage_code),
-
uref.value);
-
-
}
-
}
-
printf("\n");
-
-
rinfo.report_id |= HID_REPORT_ID_NEXT;
-
ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
-
}
-
}
-
-
-
void show_all_report(int fd)
-
{
-
-
struct hiddev_report_info rinfo;
-
struct hiddev_field_info finfo;
-
struct hiddev_usage_ref uref;
-
int rtype, i, j;
-
char *rtype_str;
-
-
for (rtype = HID_REPORT_TYPE_MIN; rtype <= HID_REPORT_TYPE_MAX;
-
rtype++) {
-
switch (rtype) {
-
case HID_REPORT_TYPE_INPUT: rtype_str = "Input"; break;
-
case HID_REPORT_TYPE_OUTPUT: rtype_str = "Output"; break;
-
case HID_REPORT_TYPE_FEATURE: rtype_str = "Feature"; break;
-
default: rtype_str = "Unknown"; break;
-
}
-
fprintf(stdout, "Reports of type %s (%d):\n", rtype_str, rtype);
-
rinfo.report_type = rtype;
-
rinfo.report_id = HID_REPORT_ID_FIRST;
-
while (ioctl(fd, HIDIOCGREPORTINFO, &rinfo) >= 0) {
-
fprintf(stdout, " Report id: %d (%d fields)\n",
-
rinfo.report_id, rinfo.num_fields);
-
for (i = 0; i < rinfo.num_fields; i++) {
-
memset(&finfo, 0, sizeof(finfo));
-
finfo.report_type = rinfo.report_type;
-
finfo.report_id = rinfo.report_id;
-
finfo.field_index = i;
-
ioctl(fd, HIDIOCGFIELDINFO, &finfo);
-
fprintf(stdout, " Field: %d: app: %04x phys %04x "
-
"flags %x (%d usages) unit %x exp %d\n",
-
i, finfo.application, finfo.physical, finfo.flags,
-
finfo.maxusage, finfo.unit, finfo.unit_exponent);
-
memset(&uref, 0, sizeof(uref));
-
for (j = 0; j < finfo.maxusage; j++) {
-
uref.report_type = finfo.report_type;
-
uref.report_id = finfo.report_id;
-
uref.field_index = i;
-
uref.usage_index = j;
-
ioctl(fd, HIDIOCGUCODE, &uref);
-
ioctl(fd, HIDIOCGUSAGE, &uref);
-
fprintf(stdout, " Usage: %04x val %d\n",
-
uref.usage_code, uref.value);
-
}
-
}
-
rinfo.report_id |= HID_REPORT_ID_NEXT;
-
}
-
}
-
// if (!run_as_daemon)
-
fprintf(stdout, "Waiting for events ... (interrupt to exit)\n");
-
-
}
-
-
int read_event(int fd)
-
{
-
struct hiddev_event ev[64];
-
int i,rd;
-
time_t curr_time;
-
char name[100];
-
-
while(1)
-
{
-
rd = read(fd, ev, sizeof(ev));
-
if (rd < (int) sizeof(ev[0])) {
-
if (rd < 0)
-
perror("\nevtest: error reading");
-
-
return -1;
-
}
-
-
for (i = 0; i < rd / sizeof(ev[0]); i++) {
-
//int idx = info_idx(ev[i].hid);
-
int idx = ev[i].hid;
-
curr_time = time(NULL);
-
strftime(name, sizeof(name), "%b
%d %T",
-
localtime(&curr_time));
-
fprintf(stdout, "%s: Event: usage %x ( ), value %d\n",
-
name, ev[i].hid,
-
/* (idx >= 0) ? ups_info[idx].label : "Unknown",*/
-
ev[i].value);
-
}
-
-
}
-
-
return 0;
-
-
}