4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
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.
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
25 * If uhid is not available as /dev/uhid, then you can pass a different path as
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.
42 #include <linux/uhid.h>
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:
50 * Physical(GenericDesktop.Pointer)
51 * Application(GenericDesktop.Mouse)
61 * Flags( Variable Absolute )
63 * Physical(GenericDesktop.Pointer)
64 * Application(GenericDesktop.Mouse)
68 * GenericDesktop.Wheel
69 * Logical Minimum(-128)
70 * Logical Maximum(127)
74 * Flags( Variable Relative )
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
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.
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,
98 static int uhid_write(int fd
, const struct uhid_event
*ev
)
102 ret
= write(fd
, ev
, sizeof(*ev
));
104 fprintf(stderr
, "Cannot write to uhid: %m\n");
106 } else if (ret
!= sizeof(*ev
)) {
107 fprintf(stderr
, "Wrong size written to uhid: %ld != %lu\n",
115 static int create(int fd
)
117 struct uhid_event ev
;
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;
130 return uhid_write(fd
, &ev
);
133 static void destroy(int fd
)
135 struct uhid_event ev
;
137 memset(&ev
, 0, sizeof(ev
));
138 ev
.type
= UHID_DESTROY
;
143 static int event(int fd
)
145 struct uhid_event ev
;
148 memset(&ev
, 0, sizeof(ev
));
149 ret
= read(fd
, &ev
, sizeof(ev
));
151 fprintf(stderr
, "Read HUP on uhid-cdev\n");
153 } else if (ret
< 0) {
154 fprintf(stderr
, "Cannot read uhid-cdev: %m\n");
156 } else if (ret
!= sizeof(ev
)) {
157 fprintf(stderr
, "Invalid size read from uhid-dev: %ld != %lu\n",
164 fprintf(stderr
, "UHID_START from uhid-dev\n");
167 fprintf(stderr
, "UHID_STOP from uhid-dev\n");
170 fprintf(stderr
, "UHID_OPEN from uhid-dev\n");
173 fprintf(stderr
, "UHID_CLOSE from uhid-dev\n");
176 fprintf(stderr
, "UHID_OUTPUT from uhid-dev\n");
179 fprintf(stderr
, "UHID_OUTPUT_EV from uhid-dev\n");
182 fprintf(stderr
, "Invalid event from uhid-dev: %u\n", ev
.type
);
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
;
195 static int send_event(int fd
)
197 struct uhid_event ev
;
199 memset(&ev
, 0, sizeof(ev
));
200 ev
.type
= UHID_INPUT
;
204 ev
.u
.input
.data
[0] |= 0x1;
206 ev
.u
.input
.data
[0] |= 0x2;
208 ev
.u
.input
.data
[0] |= 0x4;
210 ev
.u
.input
.data
[1] = abs_hor
;
211 ev
.u
.input
.data
[2] = abs_ver
;
212 ev
.u
.input
.data
[3] = wheel
;
214 return uhid_write(fd
, &ev
);
217 static int keyboard(int fd
)
222 ret
= read(STDIN_FILENO
, buf
, sizeof(buf
));
224 fprintf(stderr
, "Read HUP on stdin\n");
226 } else if (ret
< 0) {
227 fprintf(stderr
, "Cannot read stdin: %m\n");
231 for (i
= 0; i
< ret
; ++i
) {
234 btn1_down
= !btn1_down
;
235 ret
= send_event(fd
);
240 btn2_down
= !btn2_down
;
241 ret
= send_event(fd
);
246 btn3_down
= !btn3_down
;
247 ret
= send_event(fd
);
253 ret
= send_event(fd
);
260 ret
= send_event(fd
);
267 ret
= send_event(fd
);
274 ret
= send_event(fd
);
281 ret
= send_event(fd
);
288 ret
= send_event(fd
);
296 fprintf(stderr
, "Invalid input: %c\n", buf
[i
]);
303 int main(int argc
, char **argv
)
306 const char *path
= "/dev/uhid";
307 struct pollfd pfds
[2];
309 struct termios state
;
311 ret
= tcgetattr(STDIN_FILENO
, &state
);
313 fprintf(stderr
, "Cannot get tty state\n");
315 state
.c_lflag
&= ~ICANON
;
316 state
.c_cc
[VMIN
] = 1;
317 ret
= tcsetattr(STDIN_FILENO
, TCSANOW
, &state
);
319 fprintf(stderr
, "Cannot set tty state\n");
323 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help")) {
324 fprintf(stderr
, "Usage: %s [%s]\n", argv
[0], path
);
331 fprintf(stderr
, "Open uhid-cdev %s\n", path
);
332 fd
= open(path
, O_RDWR
| O_CLOEXEC
);
334 fprintf(stderr
, "Cannot open uhid-cdev %s: %m\n", path
);
338 fprintf(stderr
, "Create uhid device\n");
345 pfds
[0].fd
= STDIN_FILENO
;
346 pfds
[0].events
= POLLIN
;
348 pfds
[1].events
= POLLIN
;
350 fprintf(stderr
, "Press 'q' to quit...\n");
352 ret
= poll(pfds
, 2, -1);
354 fprintf(stderr
, "Cannot poll for fds: %m\n");
357 if (pfds
[0].revents
& POLLHUP
) {
358 fprintf(stderr
, "Received HUP on stdin\n");
361 if (pfds
[1].revents
& POLLHUP
) {
362 fprintf(stderr
, "Received HUP on uhid-cdev\n");
366 if (pfds
[0].revents
& POLLIN
) {
371 if (pfds
[1].revents
& POLLIN
) {
378 fprintf(stderr
, "Destroy uhid device\n");