Usb hid device linux

USB Human Interface Device (HID) Configuration

There are two options for using a USB mouse or a USB keyboard — the standalone Boot Protocol (HIDBP) way and the full featured HID driver way. The Boot Protocol way is generally inferior, and this document describes the full featured way. The Boot Protocol way may be appropriate for embedded systems and other systems with resource constraints and no real need for the full keyboard and mouse capabilities.

It is important to remember that the HID driver handles those devices (or actually those interfaces on each device) that claim to comply with the Human Interface Device (HID) specification . However the HID specification doesn’t say anything about what the HID driver should do with information received from a HID device, or where the information that is sent to a device comes from, since this is obviously dependent on what the device is supposed to be doing, and what the operating system is. Linux (at the operating system kernel level) supports four interfaces to a HID device — keyboard, mouse, joystick and a generic interface, known as the event interface. These are implemented by the Input device level.

HID Mouse Configuration

In the kernel configuration stage, you need to turn on USB Human Interface Device (HID) support in the USB support and Mouse Support in the Input core support . You don’t need to worry about the screen resolution entries for a normal mouse — these are for mouse-like devices such as a graphics tablet. Do not turn on USB HIDBP Mouse support . Perform the normal kernel rebuild and installation steps. If you are installing as modules, you need to load the input.o , hid.o and mousedev.o modules.

Plug in a USB mouse and check that your mouse has been correctly sensed by the kernel. If you don’t have a kernel message, look for the changes to /proc/bus/usb/devices .

Since USB supports multiple identical devices, you can have multiple mice plugged in. You can get each mouse seperately, or you can get them all mixed together. You almost always want the mixed version, and that is what will be used in this example. You need to set up a device node entry for the mixed mice. It is customary to create the entries for this device in the /dev/input/ directory. Use the following commands:

mkdir /dev/input mknod /dev/input/mice c 13 63

If you cat /dev/input/mice you should see some bizarre looking characters as you move the mouse or click any of the buttons.

If you want to use the mouse under X, you have various options. Which one you select is dependent on what version of XFree86 you are using and whether you are using only USB for your mouse (or mice), or whether you want to use a USB mouse and some other kind of pointer device.

You need to edit the XF86Config file (usually /usr/X11R6/lib/X11/XF86Config or /etc/X11/XF86Config ).

If you are using XFree86 version 4.0 or later, add a InputDevice section that looks like the following:

Section «InputDevice» Identifier «USB Mice» Driver «mouse» Option «Protocol» «IMPS/2» Option «Device» «/dev/input/mice» EndSection

Section «InputDevice» Identifier «USB Mice» Driver «mouse» Option «Protocol» «IMPS/2» Option «Device» «/dev/input/mice» Option «ZAxisMapping» «4 5» Option «Buttons» «5» EndSection

may be more useful. Consult the XFree86 documentation for a detailed explaination and more examples.

You also need to add an entry to each applicable ServerLayout Section. These are normally at the end of the configuration file. If you only have a USB mouse (or USB mice), then replace the line with the «CorePointer» entry with the following line:

InputDevice «USB Mice» «CorePointer»

If you want to use both a USB mouse (or USB mice) and some other kind of pointer device, then add (do not replace) the following line to the applicable ServerLayout sections:

Читайте также:  Mac access linux server

InputDevice «USB Mice» «SendCoreEvents»

If you are using only a USB mouse (or USB mice) with XFree86 3.3, edit the Pointer section so that it looks like the following:

Section «Pointer» Protocol «IMPS/2» Device «/dev/input/mice» EndSection

If you are trying to use a USB mouse (or USB mice) in addition to another pointer type device with XFree86 3.3, then you need to use the XInput extensions. Keep the existing Pointer (or modify it as required for the other device if you are doing an initial installation), and add the following entry (anywhere sensible, ideally in the Input devices area):

Section «Xinput» SubSection «Mouse» DeviceName «USB Mice» Protocol «IMPS/2» Port «/dev/input/mice» AlwaysCore EndSubSection EndSection

Restart the X server. If you don’t have any mouse support at this point, remember that Ctrl-Alt-F1 will get you a virtual terminal that you can use to kill the xserver and start debugging from the error messages.

If you want to use the mouse under gpm, run (or kill and restart if it is already running) gpm with the following options. gpm -m /dev/input/mice -t imps2 (as superuser remember). You can make this the default if you edit the initialisation files. These are typically named something like rc.d and are in /etc/rc.d/ on RedHat distributions.

If you have both a USB mouse (or USB mice) and some other kind of pointer device, you may wish to use gpm in repeater mode. If you have a PS/2 mouse on /dev/psaux and a USB mouse (or USB mice) on /dev/input/mice , then the following gpm command would probably be appropriate: gpm -m /dev/input/mice -t imps2 -M -m /dev/psaux -t ps2 -R imps2 . Note that this will make the output appear on /dev/gpmdata , which is a FIFO and does not need to be created in advance. You can use this as the mouse «device» to non-X programs, and both mice will work together.

Keyboard Configuration

You may not need any operating system support at all to use a USB keyboard if you have a PC architecture. There are several BIOS available where the BIOS can provide USB support from a keyboard plugged into the root hub on the motherboard. This may or may not work through other hubs and does not normally work with add-in boards, so you might want to add in support anyway. You definately want to add keyboard support if you add any operating system support, as the Linux USB support will disable the BIOS support. You also need to use Linux USB keyboard support if you want to use any of the «multimedia» types keys that are provided with some USB keybords.

In the kernel configuration stage, you need to turn on USB Human Interface Device (HID) support in USB support and Keyboard support in Input core support . Do not turn on USB HIDBP Keyboard support . Perform the normal kernel rebuild and installation steps. If you are installing as modules, you need to load the hid.o , input.o and keybdev.o modules.

Check the kernel logs to ensure that your keyboard is being correctly sensed by the kernel.

At this point, you should be able to use your USB keyboard as a normal keyboard. Be aware that LILO is not USB aware, and that unless your BIOS supports a USB keyboard, you may not be able to select a non-default boot image using the USB keyboard. I have personally used only a USB keyboard (and USB mouse) and have experienced no problems.

USB Joystick and Gamepad support

In the kernel configuration stage, you need to turn on USB Human Interface Device (HID) support in USB support and Joystick support in Input core support . Perform the normal kernel rebuild and installation steps. If you are installing as modules, you need to load the hid.o , input.o and joydev.o modules.

You need to set up a device node entry for the joystick. It is customary to create the entries for USB device in the /dev/input/ directory. You can use the following commands to create four device nodes, although there is no reason why you can not use more:

mknod /dev/input/js0 c 13 0 mknod /dev/input/js1 c 13 1 mknod /dev/input/js2 c 13 2 mknod /dev/input/js3 c 13 3

If you plug in a gamepad or joystick and cat /dev/input/js0 you should see some bizarre looking characters as you move the stick or click any of the buttons.

You should now be able to use the USB joystick or gamepad with any of the normal games or other joystick compatible applications.

Источник

Linux USB HID gadget driver¶

The HID Gadget driver provides emulation of USB Human Interface Devices (HID). The basic HID handling is done in the kernel, and HID reports can be sent/received through I/O on the /dev/hidgX character devices.

For more details about HID, see the developer page on https://www.usb.org/developers/hidpage/

Configuration¶

g_hid is a platform driver, so to use it you need to add struct platform_device(s) to your platform code defining the HID function descriptors you want to use — E.G. something like:

#include #include /* 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, >;

You can add as many HID functions as you want, only limited by the amount of interrupt endpoints your gadget driver supports.

Configuration with configfs¶

Instead of adding fake platform devices and drivers in order to pass some data to the kernel, if HID is a part of a gadget composed with configfs the hidg_func_descriptor.report_desc is passed to the kernel by writing the appropriate stream of bytes to a configfs attribute.

Send and receive HID reports¶

HID reports can be sent/received using read/write on the /dev/hidgX character devices. See below for an example program to do this.

hid_gadget_test is a small interactive program to test the HID gadget driver. To use, point it at a hidg device and set the device type (keyboard / mouse / joystick) — E.G.:

# hid_gadget_test /dev/hidg0 keyboard

You are now in the prompt of hid_gadget_test. You can type any combination of options and values. Available options and values are listed at program start. In keyboard mode you can send up to six values.

For example type: g i s t r —left-shift

Hit return and the corresponding report will be sent by the HID gadget.

Another interesting example is the caps lock test. Type —caps-lock and hit return. A report is then sent by the gadget and you should receive the host answer, corresponding to the caps lock LED status:

# hid_gadget_test /dev/hidg1 mouse

You can test the mouse emulation. Values are two signed numbers.

/* hid_gadget_test */ #include #include #include #include #include #include #include #include #include #define BUF_LEN 512 struct options < const char *opt; unsigned char val; >; static struct options kmod[] = < , , , , , , , , >; static struct options kval[] = < , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , >; int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold) < char *tok = strtok(buf, " "); int key = 0; int i = 0; for (; tok != NULL; tok = strtok(NULL, " ")) < if (strcmp(tok, "--quit") == 0) return -1; if (strcmp(tok, "--hold") == 0) < *hold = 1; continue; >if (key < 6) < for (i = 0; kval[i].opt != NULL; i++) if (strcmp(tok, kval[i].opt) == 0) < report[2 + key++] = kval[i].val; break; >if (kval[i].opt != NULL) continue; > if (key < 6) if (islower(tok[0])) < report[2 + key++] = (tok[0] - ('a' - 0x04)); continue; >for (i = 0; kmod[i].opt != NULL; i++) if (strcmp(tok, kmod[i].opt) == 0) < report[0] = report[0] | kmod[i].val; break; >if (kmod[i].opt != NULL) continue; if (key < 6) fprintf(stderr, "unknown option: %s\n", tok); >return 8; > static struct options mmod[] = < , , , >; int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) < char *tok = strtok(buf, " "); int mvt = 0; int i = 0; for (; tok != NULL; tok = strtok(NULL, " ")) < if (strcmp(tok, "--quit") == 0) return -1; if (strcmp(tok, "--hold") == 0) < *hold = 1; continue; >for (i = 0; mmod[i].opt != NULL; i++) if (strcmp(tok, mmod[i].opt) == 0) < report[0] = report[0] | mmod[i].val; break; >if (mmod[i].opt != NULL) continue; if (!(tok[0] == '-' && tok[1] == '-') && mvt < 2) < errno = 0; report[1 + mvt++] = (char)strtol(tok, NULL, 0); if (errno != 0) < fprintf(stderr, "Bad value:'%s'\n", tok); report[1 + mvt--] = 0; >continue; > fprintf(stderr, "unknown option: %s\n", tok); > return 3; > static struct options jmod[] = < , , , , , , , , , >; int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold) < char *tok = strtok(buf, " "); int mvt = 0; int i = 0; *hold = 1; /* set default hat position: neutral */ report[3] = 0x04; for (; tok != NULL; tok = strtok(NULL, " ")) < if (strcmp(tok, "--quit") == 0) return -1; for (i = 0; jmod[i].opt != NULL; i++) if (strcmp(tok, jmod[i].opt) == 0) < report[3] = (report[3] & 0xF0) | jmod[i].val; break; >if (jmod[i].opt != NULL) continue; if (!(tok[0] == '-' && tok[1] == '-') && mvt < 3) < errno = 0; report[mvt++] = (char)strtol(tok, NULL, 0); if (errno != 0) < fprintf(stderr, "Bad value:'%s'\n", tok); report[mvt--] = 0; >continue; > fprintf(stderr, "unknown option: %s\n", tok); > return 4; > void print_options(char c) < int i = 0; if (c == 'k') < printf(" keyboard options:\n" " --hold\n"); for (i = 0; kmod[i].opt != NULL; i++) printf("\t\t%s\n", kmod[i].opt); printf("\n keyboard values:\n" " [a-z] or\n"); for (i = 0; kval[i].opt != NULL; i++) printf("\t\t%-8s%s", kval[i].opt, i % 2 ? "\n" : ""); printf("\n"); >else if (c == 'm') < printf(" mouse options:\n" " --hold\n"); for (i = 0; mmod[i].opt != NULL; i++) printf("\t\t%s\n", mmod[i].opt); printf("\n mouse values:\n" " Two signed numbers\n" "--quit to close\n"); >else < printf(" joystick options:\n"); for (i = 0; jmod[i].opt != NULL; i++) printf("\t\t%s\n", jmod[i].opt); printf("\n joystick values:\n" " three signed numbers\n" "--quit to close\n"); >> int main(int argc, const char *argv[]) < const char *filename = NULL; int fd = 0; char buf[BUF_LEN]; int cmd_len; char report[8]; int to_send = 8; int hold = 0; fd_set rfds; int retval, i; if (argc < 3) < fprintf(stderr, "Usage: %s devname mouse|keyboard|joystick\n", argv[0]); return 1; >if (argv[2][0] != 'k' && argv[2][0] != 'm' && argv[2][0] != 'j') return 2; filename = argv[1]; if ((fd = open(filename, O_RDWR, 0666)) == -1) < perror(filename); return 3; >print_options(argv[2][0]); while (42) < FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); FD_SET(fd, &rfds); retval = select(fd + 1, &rfds, NULL, NULL, NULL); if (retval == -1 && errno == EINTR) continue; if (retval < 0) < perror("select()"); return 4; >if (FD_ISSET(fd, &rfds)) < cmd_len = read(fd, buf, BUF_LEN - 1); printf("recv report:"); for (i = 0; i < cmd_len; i++) printf(" %02x", buf[i]); printf("\n"); >if (FD_ISSET(STDIN_FILENO, &rfds)) < memset(report, 0x0, sizeof(report)); cmd_len = read(STDIN_FILENO, buf, BUF_LEN - 1); if (cmd_len == 0) break; buf[cmd_len - 1] = '\0'; hold = 0; memset(report, 0x0, sizeof(report)); if (argv[2][0] == 'k') to_send = keyboard_fill_report(report, buf, &hold); else if (argv[2][0] == 'm') to_send = mouse_fill_report(report, buf, &hold); else to_send = joystick_fill_report(report, buf, &hold); if (to_send == -1) break; if (write(fd, report, to_send) != to_send) < perror(filename); return 5; >if (!hold) < memset(report, 0x0, sizeof(report)); if (write(fd, report, to_send) != to_send) < perror(filename); return 6; >> > > close(fd); return 0; >

Источник

Оцените статью
Adblock
detector