Root/
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 | } |
382 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9