diff options
author | James Morris <james.l.morris@oracle.com> | 2012-08-17 06:42:30 -0400 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2012-08-17 06:42:30 -0400 |
commit | 51b743fe87d7fb3dba7a2ff4a1fe23bb65dc2245 (patch) | |
tree | f8b8f601713a3ecb264eb9f145636343d9350520 /samples | |
parent | 9f99798ff49e73dded73a8c674044ea6fb6af651 (diff) | |
parent | d9875690d9b89a866022ff49e3fcea892345ad92 (diff) |
Merge tag 'v3.6-rc2' into next
Linux 3.6-rc2
Resync with Linus.
Diffstat (limited to 'samples')
-rw-r--r-- | samples/uhid/Makefile | 10 | ||||
-rw-r--r-- | samples/uhid/uhid-example.c | 381 |
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. | ||
2 | obj- := dummy.o | ||
3 | |||
4 | # List of programs to build | ||
5 | hostprogs-y := uhid-example | ||
6 | |||
7 | # Tell kbuild to always build the programs | ||
8 | always := $(hostprogs-y) | ||
9 | |||
10 | HOSTCFLAGS_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 | |||
88 | static 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 | |||
98 | static 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 | |||
115 | static 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 | |||
133 | static 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 | |||
143 | static 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 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static bool btn1_down; | ||
189 | static bool btn2_down; | ||
190 | static bool btn3_down; | ||
191 | static signed char abs_hor; | ||
192 | static signed char abs_ver; | ||
193 | static signed char wheel; | ||
194 | |||
195 | static int send_event(int fd) | ||
196 | { | ||
197 | struct uhid_event ev; | ||
198 | |||
199 | memset(&ev, 0, sizeof(ev)); | ||
200 | ev.type = UHID_INPUT; | ||
201 | ev.u.input.size = 4; | ||
202 | |||
203 | if (btn1_down) | ||
204 | ev.u.input.data[0] |= 0x1; | ||
205 | if (btn2_down) | ||
206 | ev.u.input.data[0] |= 0x2; | ||
207 | if (btn3_down) | ||
208 | ev.u.input.data[0] |= 0x4; | ||
209 | |||
210 | ev.u.input.data[1] = abs_hor; | ||
211 | ev.u.input.data[2] = abs_ver; | ||
212 | ev.u.input.data[3] = wheel; | ||
213 | |||
214 | return uhid_write(fd, &ev); | ||
215 | } | ||
216 | |||
217 | static int keyboard(int fd) | ||
218 | { | ||
219 | char buf[128]; | ||
220 | ssize_t ret, i; | ||
221 | |||
222 | ret = read(STDIN_FILENO, buf, sizeof(buf)); | ||
223 | if (ret == 0) { | ||
224 | fprintf(stderr, "Read HUP on stdin\n"); | ||
225 | return -EFAULT; | ||
226 | } else if (ret < 0) { | ||
227 | fprintf(stderr, "Cannot read stdin: %m\n"); | ||
228 | return -errno; | ||
229 | } | ||
230 | |||
231 | for (i = 0; i < ret; ++i) { | ||
232 | switch (buf[i]) { | ||
233 | case '1': | ||
234 | btn1_down = !btn1_down; | ||
235 | ret = send_event(fd); | ||
236 | if (ret) | ||
237 | return ret; | ||
238 | break; | ||
239 | case '2': | ||
240 | btn2_down = !btn2_down; | ||
241 | ret = send_event(fd); | ||
242 | if (ret) | ||
243 | return ret; | ||
244 | break; | ||
245 | case '3': | ||
246 | btn3_down = !btn3_down; | ||
247 | ret = send_event(fd); | ||
248 | if (ret) | ||
249 | return ret; | ||
250 | break; | ||
251 | case 'a': | ||
252 | abs_hor = -20; | ||
253 | ret = send_event(fd); | ||
254 | abs_hor = 0; | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | break; | ||
258 | case 'd': | ||
259 | abs_hor = 20; | ||
260 | ret = send_event(fd); | ||
261 | abs_hor = 0; | ||
262 | if (ret) | ||
263 | return ret; | ||
264 | break; | ||
265 | case 'w': | ||
266 | abs_ver = -20; | ||
267 | ret = send_event(fd); | ||
268 | abs_ver = 0; | ||
269 | if (ret) | ||
270 | return ret; | ||
271 | break; | ||
272 | case 's': | ||
273 | abs_ver = 20; | ||
274 | ret = send_event(fd); | ||
275 | abs_ver = 0; | ||
276 | if (ret) | ||
277 | return ret; | ||
278 | break; | ||
279 | case 'r': | ||
280 | wheel = 1; | ||
281 | ret = send_event(fd); | ||
282 | wheel = 0; | ||
283 | if (ret) | ||
284 | return ret; | ||
285 | break; | ||
286 | case 'f': | ||
287 | wheel = -1; | ||
288 | ret = send_event(fd); | ||
289 | wheel = 0; | ||
290 | if (ret) | ||
291 | return ret; | ||
292 | break; | ||
293 | case 'q': | ||
294 | return -ECANCELED; | ||
295 | default: | ||
296 | fprintf(stderr, "Invalid input: %c\n", buf[i]); | ||
297 | } | ||
298 | } | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | int main(int argc, char **argv) | ||
304 | { | ||
305 | int fd; | ||
306 | const char *path = "/dev/uhid"; | ||
307 | struct pollfd pfds[2]; | ||
308 | int ret; | ||
309 | struct termios state; | ||
310 | |||
311 | ret = tcgetattr(STDIN_FILENO, &state); | ||
312 | if (ret) { | ||
313 | fprintf(stderr, "Cannot get tty state\n"); | ||
314 | } else { | ||
315 | state.c_lflag &= ~ICANON; | ||
316 | state.c_cc[VMIN] = 1; | ||
317 | ret = tcsetattr(STDIN_FILENO, TCSANOW, &state); | ||
318 | if (ret) | ||
319 | fprintf(stderr, "Cannot set tty state\n"); | ||
320 | } | ||
321 | |||
322 | if (argc >= 2) { | ||
323 | if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { | ||
324 | fprintf(stderr, "Usage: %s [%s]\n", argv[0], path); | ||
325 | return EXIT_SUCCESS; | ||
326 | } else { | ||
327 | path = argv[1]; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | fprintf(stderr, "Open uhid-cdev %s\n", path); | ||
332 | fd = open(path, O_RDWR | O_CLOEXEC); | ||
333 | if (fd < 0) { | ||
334 | fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path); | ||
335 | return EXIT_FAILURE; | ||
336 | } | ||
337 | |||
338 | fprintf(stderr, "Create uhid device\n"); | ||
339 | ret = create(fd); | ||
340 | if (ret) { | ||
341 | close(fd); | ||
342 | return EXIT_FAILURE; | ||
343 | } | ||
344 | |||
345 | pfds[0].fd = STDIN_FILENO; | ||
346 | pfds[0].events = POLLIN; | ||
347 | pfds[1].fd = fd; | ||
348 | pfds[1].events = POLLIN; | ||
349 | |||
350 | fprintf(stderr, "Press 'q' to quit...\n"); | ||
351 | while (1) { | ||
352 | ret = poll(pfds, 2, -1); | ||
353 | if (ret < 0) { | ||
354 | fprintf(stderr, "Cannot poll for fds: %m\n"); | ||
355 | break; | ||
356 | } | ||
357 | if (pfds[0].revents & POLLHUP) { | ||
358 | fprintf(stderr, "Received HUP on stdin\n"); | ||
359 | break; | ||
360 | } | ||
361 | if (pfds[1].revents & POLLHUP) { | ||
362 | fprintf(stderr, "Received HUP on uhid-cdev\n"); | ||
363 | break; | ||
364 | } | ||
365 | |||
366 | if (pfds[0].revents & POLLIN) { | ||
367 | ret = keyboard(fd); | ||
368 | if (ret) | ||
369 | break; | ||
370 | } | ||
371 | if (pfds[1].revents & POLLIN) { | ||
372 | ret = event(fd); | ||
373 | if (ret) | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | fprintf(stderr, "Destroy uhid device\n"); | ||
379 | destroy(fd); | ||
380 | return EXIT_SUCCESS; | ||
381 | } | ||