aboutsummaryrefslogtreecommitdiffstats
path: root/samples
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@googlemail.com>2012-06-10 09:16:27 -0400
committerJiri Kosina <jkosina@suse.cz>2012-06-18 07:42:03 -0400
commit5148fa52a12fa1b97c730b2fe321f2aad7ea041c (patch)
tree4d0db495f3c5b34dad9cb0dd47043c77bc48e617 /samples
parentd99b8bad7663c8b920b366877a27b4176dece062 (diff)
HID: uhid: add example program
This adds an example user-space program that emulates a 3 button mouse with wheel. It detects keyboard presses and moves the mouse accordingly. It register a fake HID device to feed the raw HID reports into the kernel. In this example, you could use uinput to get the same result, but this shows how to get the same behavior with uhid so you don't need HID parsers in user-space. Signed-off-by: David Herrmann <dh.herrmann@googlemail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'samples')
-rw-r--r--samples/uhid/Makefile10
-rw-r--r--samples/uhid/uhid-example.c381
2 files changed, 391 insertions, 0 deletions
diff --git a/samples/uhid/Makefile b/samples/uhid/Makefile
new file mode 100644
index 000000000000..c95a696560a7
--- /dev/null
+++ b/samples/uhid/Makefile
@@ -0,0 +1,10 @@
1# kbuild trick to avoid linker error. Can be omitted if a module is built.
2obj- := dummy.o
3
4# List of programs to build
5hostprogs-y := uhid-example
6
7# Tell kbuild to always build the programs
8always := $(hostprogs-y)
9
10HOSTCFLAGS_uhid-example.o += -I$(objtree)/usr/include
diff --git a/samples/uhid/uhid-example.c b/samples/uhid/uhid-example.c
new file mode 100644
index 000000000000..03ce3c059a5e
--- /dev/null
+++ b/samples/uhid/uhid-example.c
@@ -0,0 +1,381 @@
1/*
2 * UHID Example
3 *
4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
5 *
6 * The code may be used by anyone for any purpose,
7 * and can serve as a starting point for developing
8 * applications using uhid.
9 */
10
11/* UHID Example
12 * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
13 * program as root and then use the following keys to control the mouse:
14 * q: Quit the application
15 * 1: Toggle left button (down, up, ...)
16 * 2: Toggle right button
17 * 3: Toggle middle button
18 * a: Move mouse left
19 * d: Move mouse right
20 * w: Move mouse up
21 * s: Move mouse down
22 * r: Move wheel up
23 * f: Move wheel down
24 *
25 * If uhid is not available as /dev/uhid, then you can pass a different path as
26 * first argument.
27 * If <linux/uhid.h> is not installed in /usr, then compile this with:
28 * gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c
29 * And ignore the warning about kernel headers. However, it is recommended to
30 * use the installed uhid.h if available.
31 */
32
33#include <errno.h>
34#include <fcntl.h>
35#include <poll.h>
36#include <stdbool.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <termios.h>
41#include <unistd.h>
42#include <linux/uhid.h>
43
44/* HID Report Desciptor
45 * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
46 * as the kernel will parse it:
47 *
48 * INPUT[INPUT]
49 * Field(0)
50 * Physical(GenericDesktop.Pointer)
51 * Application(GenericDesktop.Mouse)
52 * Usage(3)
53 * Button.0001
54 * Button.0002
55 * Button.0003
56 * Logical Minimum(0)
57 * Logical Maximum(1)
58 * Report Size(1)
59 * Report Count(3)
60 * Report Offset(0)
61 * Flags( Variable Absolute )
62 * Field(1)
63 * Physical(GenericDesktop.Pointer)
64 * Application(GenericDesktop.Mouse)
65 * Usage(3)
66 * GenericDesktop.X
67 * GenericDesktop.Y
68 * GenericDesktop.Wheel
69 * Logical Minimum(-128)
70 * Logical Maximum(127)
71 * Report Size(8)
72 * Report Count(3)
73 * Report Offset(8)
74 * Flags( Variable Relative )
75 *
76 * This is the mapping that we expect:
77 * Button.0001 ---> Key.LeftBtn
78 * Button.0002 ---> Key.RightBtn
79 * Button.0003 ---> Key.MiddleBtn
80 * GenericDesktop.X ---> Relative.X
81 * GenericDesktop.Y ---> Relative.Y
82 * GenericDesktop.Wheel ---> Relative.Wheel
83 *
84 * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
85 * This file should print the same information as showed above.
86 */
87
88static unsigned char rdesc[] = {
89 0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
90 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
91 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
92 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
93 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
94 0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
95 0x81, 0x06, 0xc0, 0xc0,
96};
97
98static int uhid_write(int fd, const struct uhid_event *ev)
99{
100 ssize_t ret;
101
102 ret = write(fd, ev, sizeof(*ev));
103 if (ret < 0) {
104 fprintf(stderr, "Cannot write to uhid: %m\n");
105 return -errno;
106 } else if (ret != sizeof(*ev)) {
107 fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n",
108 ret, sizeof(ev));
109 return -EFAULT;
110 } else {
111 return 0;
112 }
113}
114
115static int create(int fd)
116{
117 struct uhid_event ev;
118
119 memset(&ev, 0, sizeof(ev));
120 ev.type = UHID_CREATE;
121 strcpy((char*)ev.u.create.name, "test-uhid-device");
122 ev.u.create.rd_data = rdesc;
123 ev.u.create.rd_size = sizeof(rdesc);
124 ev.u.create.bus = BUS_USB;
125 ev.u.create.vendor = 0x15d9;
126 ev.u.create.product = 0x0a37;
127 ev.u.create.version = 0;
128 ev.u.create.country = 0;
129
130 return uhid_write(fd, &ev);
131}
132
133static void destroy(int fd)
134{
135 struct uhid_event ev;
136
137 memset(&ev, 0, sizeof(ev));
138 ev.type = UHID_DESTROY;
139
140 uhid_write(fd, &ev);
141}
142
143static int event(int fd)
144{
145 struct uhid_event ev;
146 ssize_t ret;
147
148 memset(&ev, 0, sizeof(ev));
149 ret = read(fd, &ev, sizeof(ev));
150 if (ret == 0) {
151 fprintf(stderr, "Read HUP on uhid-cdev\n");
152 return -EFAULT;
153 } else if (ret < 0) {
154 fprintf(stderr, "Cannot read uhid-cdev: %m\n");
155 return -errno;
156 } else if (ret != sizeof(ev)) {
157 fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n",
158 ret, sizeof(ev));
159 return -EFAULT;
160 }
161
162 switch (ev.type) {
163 case UHID_START:
164 fprintf(stderr, "UHID_START from uhid-dev\n");
165 break;
166 case UHID_STOP:
167 fprintf(stderr, "UHID_STOP from uhid-dev\n");
168 break;
169 case UHID_OPEN:
170 fprintf(stderr, "UHID_OPEN from uhid-dev\n");
171 break;
172 case UHID_CLOSE:
173 fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
174 break;
175 case UHID_OUTPUT:
176 fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
177 break;
178 case UHID_OUTPUT_EV:
179 fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
180 break;
181 default:
182 fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
183 }
184