xref: /openbmc/linux/samples/uhid/uhid-example.c (revision 5148fa52a12fa1b97c730b2fe321f2aad7ea041c)
1*5148fa52SDavid Herrmann /*
2*5148fa52SDavid Herrmann  * UHID Example
3*5148fa52SDavid Herrmann  *
4*5148fa52SDavid Herrmann  * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
5*5148fa52SDavid Herrmann  *
6*5148fa52SDavid Herrmann  * The code may be used by anyone for any purpose,
7*5148fa52SDavid Herrmann  * and can serve as a starting point for developing
8*5148fa52SDavid Herrmann  * applications using uhid.
9*5148fa52SDavid Herrmann  */
10*5148fa52SDavid Herrmann 
11*5148fa52SDavid Herrmann /* UHID Example
12*5148fa52SDavid Herrmann  * This example emulates a basic 3 buttons mouse with wheel over UHID. Run this
13*5148fa52SDavid Herrmann  * program as root and then use the following keys to control the mouse:
14*5148fa52SDavid Herrmann  *   q: Quit the application
15*5148fa52SDavid Herrmann  *   1: Toggle left button (down, up, ...)
16*5148fa52SDavid Herrmann  *   2: Toggle right button
17*5148fa52SDavid Herrmann  *   3: Toggle middle button
18*5148fa52SDavid Herrmann  *   a: Move mouse left
19*5148fa52SDavid Herrmann  *   d: Move mouse right
20*5148fa52SDavid Herrmann  *   w: Move mouse up
21*5148fa52SDavid Herrmann  *   s: Move mouse down
22*5148fa52SDavid Herrmann  *   r: Move wheel up
23*5148fa52SDavid Herrmann  *   f: Move wheel down
24*5148fa52SDavid Herrmann  *
25*5148fa52SDavid Herrmann  * If uhid is not available as /dev/uhid, then you can pass a different path as
26*5148fa52SDavid Herrmann  * first argument.
27*5148fa52SDavid Herrmann  * If <linux/uhid.h> is not installed in /usr, then compile this with:
28*5148fa52SDavid Herrmann  *   gcc -o ./uhid_test -Wall -I./include ./samples/uhid/uhid-example.c
29*5148fa52SDavid Herrmann  * And ignore the warning about kernel headers. However, it is recommended to
30*5148fa52SDavid Herrmann  * use the installed uhid.h if available.
31*5148fa52SDavid Herrmann  */
32*5148fa52SDavid Herrmann 
33*5148fa52SDavid Herrmann #include <errno.h>
34*5148fa52SDavid Herrmann #include <fcntl.h>
35*5148fa52SDavid Herrmann #include <poll.h>
36*5148fa52SDavid Herrmann #include <stdbool.h>
37*5148fa52SDavid Herrmann #include <stdio.h>
38*5148fa52SDavid Herrmann #include <stdlib.h>
39*5148fa52SDavid Herrmann #include <string.h>
40*5148fa52SDavid Herrmann #include <termios.h>
41*5148fa52SDavid Herrmann #include <unistd.h>
42*5148fa52SDavid Herrmann #include <linux/uhid.h>
43*5148fa52SDavid Herrmann 
44*5148fa52SDavid Herrmann /* HID Report Desciptor
45*5148fa52SDavid Herrmann  * We emulate a basic 3 button mouse with wheel. This is the report-descriptor
46*5148fa52SDavid Herrmann  * as the kernel will parse it:
47*5148fa52SDavid Herrmann  *
48*5148fa52SDavid Herrmann  * INPUT[INPUT]
49*5148fa52SDavid Herrmann  *   Field(0)
50*5148fa52SDavid Herrmann  *     Physical(GenericDesktop.Pointer)
51*5148fa52SDavid Herrmann  *     Application(GenericDesktop.Mouse)
52*5148fa52SDavid Herrmann  *     Usage(3)
53*5148fa52SDavid Herrmann  *       Button.0001
54*5148fa52SDavid Herrmann  *       Button.0002
55*5148fa52SDavid Herrmann  *       Button.0003
56*5148fa52SDavid Herrmann  *     Logical Minimum(0)
57*5148fa52SDavid Herrmann  *     Logical Maximum(1)
58*5148fa52SDavid Herrmann  *     Report Size(1)
59*5148fa52SDavid Herrmann  *     Report Count(3)
60*5148fa52SDavid Herrmann  *     Report Offset(0)
61*5148fa52SDavid Herrmann  *     Flags( Variable Absolute )
62*5148fa52SDavid Herrmann  *   Field(1)
63*5148fa52SDavid Herrmann  *     Physical(GenericDesktop.Pointer)
64*5148fa52SDavid Herrmann  *     Application(GenericDesktop.Mouse)
65*5148fa52SDavid Herrmann  *     Usage(3)
66*5148fa52SDavid Herrmann  *       GenericDesktop.X
67*5148fa52SDavid Herrmann  *       GenericDesktop.Y
68*5148fa52SDavid Herrmann  *       GenericDesktop.Wheel
69*5148fa52SDavid Herrmann  *     Logical Minimum(-128)
70*5148fa52SDavid Herrmann  *     Logical Maximum(127)
71*5148fa52SDavid Herrmann  *     Report Size(8)
72*5148fa52SDavid Herrmann  *     Report Count(3)
73*5148fa52SDavid Herrmann  *     Report Offset(8)
74*5148fa52SDavid Herrmann  *     Flags( Variable Relative )
75*5148fa52SDavid Herrmann  *
76*5148fa52SDavid Herrmann  * This is the mapping that we expect:
77*5148fa52SDavid Herrmann  *   Button.0001 ---> Key.LeftBtn
78*5148fa52SDavid Herrmann  *   Button.0002 ---> Key.RightBtn
79*5148fa52SDavid Herrmann  *   Button.0003 ---> Key.MiddleBtn
80*5148fa52SDavid Herrmann  *   GenericDesktop.X ---> Relative.X
81*5148fa52SDavid Herrmann  *   GenericDesktop.Y ---> Relative.Y
82*5148fa52SDavid Herrmann  *   GenericDesktop.Wheel ---> Relative.Wheel
83*5148fa52SDavid Herrmann  *
84*5148fa52SDavid Herrmann  * This information can be verified by reading /sys/kernel/debug/hid/<dev>/rdesc
85*5148fa52SDavid Herrmann  * This file should print the same information as showed above.
86*5148fa52SDavid Herrmann  */
87*5148fa52SDavid Herrmann 
88*5148fa52SDavid Herrmann static unsigned char rdesc[] = {
89*5148fa52SDavid Herrmann 	0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01,
90*5148fa52SDavid Herrmann 	0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
91*5148fa52SDavid Herrmann 	0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
92*5148fa52SDavid Herrmann 	0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
93*5148fa52SDavid Herrmann 	0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
94*5148fa52SDavid Herrmann 	0x15, 0x80, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03,
95*5148fa52SDavid Herrmann 	0x81, 0x06, 0xc0, 0xc0,
96*5148fa52SDavid Herrmann };
97*5148fa52SDavid Herrmann 
98*5148fa52SDavid Herrmann static int uhid_write(int fd, const struct uhid_event *ev)
99*5148fa52SDavid Herrmann {
100*5148fa52SDavid Herrmann 	ssize_t ret;
101*5148fa52SDavid Herrmann 
102*5148fa52SDavid Herrmann 	ret = write(fd, ev, sizeof(*ev));
103*5148fa52SDavid Herrmann 	if (ret < 0) {
104*5148fa52SDavid Herrmann 		fprintf(stderr, "Cannot write to uhid: %m\n");
105*5148fa52SDavid Herrmann 		return -errno;
106*5148fa52SDavid Herrmann 	} else if (ret != sizeof(*ev)) {
107*5148fa52SDavid Herrmann 		fprintf(stderr, "Wrong size written to uhid: %ld != %lu\n",
108*5148fa52SDavid Herrmann 			ret, sizeof(ev));
109*5148fa52SDavid Herrmann 		return -EFAULT;
110*5148fa52SDavid Herrmann 	} else {
111*5148fa52SDavid Herrmann 		return 0;
112*5148fa52SDavid Herrmann 	}
113*5148fa52SDavid Herrmann }
114*5148fa52SDavid Herrmann 
115*5148fa52SDavid Herrmann static int create(int fd)
116*5148fa52SDavid Herrmann {
117*5148fa52SDavid Herrmann 	struct uhid_event ev;
118*5148fa52SDavid Herrmann 
119*5148fa52SDavid Herrmann 	memset(&ev, 0, sizeof(ev));
120*5148fa52SDavid Herrmann 	ev.type = UHID_CREATE;
121*5148fa52SDavid Herrmann 	strcpy((char*)ev.u.create.name, "test-uhid-device");
122*5148fa52SDavid Herrmann 	ev.u.create.rd_data = rdesc;
123*5148fa52SDavid Herrmann 	ev.u.create.rd_size = sizeof(rdesc);
124*5148fa52SDavid Herrmann 	ev.u.create.bus = BUS_USB;
125*5148fa52SDavid Herrmann 	ev.u.create.vendor = 0x15d9;
126*5148fa52SDavid Herrmann 	ev.u.create.product = 0x0a37;
127*5148fa52SDavid Herrmann 	ev.u.create.version = 0;
128*5148fa52SDavid Herrmann 	ev.u.create.country = 0;
129*5148fa52SDavid Herrmann 
130*5148fa52SDavid Herrmann 	return uhid_write(fd, &ev);
131*5148fa52SDavid Herrmann }
132*5148fa52SDavid Herrmann 
133*5148fa52SDavid Herrmann static void destroy(int fd)
134*5148fa52SDavid Herrmann {
135*5148fa52SDavid Herrmann 	struct uhid_event ev;
136*5148fa52SDavid Herrmann 
137*5148fa52SDavid Herrmann 	memset(&ev, 0, sizeof(ev));
138*5148fa52SDavid Herrmann 	ev.type = UHID_DESTROY;
139*5148fa52SDavid Herrmann 
140*5148fa52SDavid Herrmann 	uhid_write(fd, &ev);
141*5148fa52SDavid Herrmann }
142*5148fa52SDavid Herrmann 
143*5148fa52SDavid Herrmann static int event(int fd)
144*5148fa52SDavid Herrmann {
145*5148fa52SDavid Herrmann 	struct uhid_event ev;
146*5148fa52SDavid Herrmann 	ssize_t ret;
147*5148fa52SDavid Herrmann 
148*5148fa52SDavid Herrmann 	memset(&ev, 0, sizeof(ev));
149*5148fa52SDavid Herrmann 	ret = read(fd, &ev, sizeof(ev));
150*5148fa52SDavid Herrmann 	if (ret == 0) {
151*5148fa52SDavid Herrmann 		fprintf(stderr, "Read HUP on uhid-cdev\n");
152*5148fa52SDavid Herrmann 		return -EFAULT;
153*5148fa52SDavid Herrmann 	} else if (ret < 0) {
154*5148fa52SDavid Herrmann 		fprintf(stderr, "Cannot read uhid-cdev: %m\n");
155*5148fa52SDavid Herrmann 		return -errno;
156*5148fa52SDavid Herrmann 	} else if (ret != sizeof(ev)) {
157*5148fa52SDavid Herrmann 		fprintf(stderr, "Invalid size read from uhid-dev: %ld != %lu\n",
158*5148fa52SDavid Herrmann 			ret, sizeof(ev));
159*5148fa52SDavid Herrmann 		return -EFAULT;
160*5148fa52SDavid Herrmann 	}
161*5148fa52SDavid Herrmann 
162*5148fa52SDavid Herrmann 	switch (ev.type) {
163*5148fa52SDavid Herrmann 	case UHID_START:
164*5148fa52SDavid Herrmann 		fprintf(stderr, "UHID_START from uhid-dev\n");
165*5148fa52SDavid Herrmann 		break;
166*5148fa52SDavid Herrmann 	case UHID_STOP:
167*5148fa52SDavid Herrmann 		fprintf(stderr, "UHID_STOP from uhid-dev\n");
168*5148fa52SDavid Herrmann 		break;
169*5148fa52SDavid Herrmann 	case UHID_OPEN:
170*5148fa52SDavid Herrmann 		fprintf(stderr, "UHID_OPEN from uhid-dev\n");
171*5148fa52SDavid Herrmann 		break;
172*5148fa52SDavid Herrmann 	case UHID_CLOSE:
173*5148fa52SDavid Herrmann 		fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
174*5148fa52SDavid Herrmann 		break;
175*5148fa52SDavid Herrmann 	case UHID_OUTPUT:
176*5148fa52SDavid Herrmann 		fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
177*5148fa52SDavid Herrmann 		break;
178*5148fa52SDavid Herrmann 	case UHID_OUTPUT_EV:
179*5148fa52SDavid Herrmann 		fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
180*5148fa52SDavid Herrmann 		break;
181*5148fa52SDavid Herrmann 	default:
182*5148fa52SDavid Herrmann 		fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
183*5148fa52SDavid Herrmann 	}
184*5148fa52SDavid Herrmann 
185*5148fa52SDavid Herrmann 	return 0;
186*5148fa52SDavid Herrmann }
187*5148fa52SDavid Herrmann 
188*5148fa52SDavid Herrmann static bool btn1_down;
189*5148fa52SDavid Herrmann static bool btn2_down;
190*5148fa52SDavid Herrmann static bool btn3_down;
191*5148fa52SDavid Herrmann static signed char abs_hor;
192*5148fa52SDavid Herrmann static signed char abs_ver;
193*5148fa52SDavid Herrmann static signed char wheel;
194*5148fa52SDavid Herrmann 
195*5148fa52SDavid Herrmann static int send_event(int fd)
196*5148fa52SDavid Herrmann {
197*5148fa52SDavid Herrmann 	struct uhid_event ev;
198*5148fa52SDavid Herrmann 
199*5148fa52SDavid Herrmann 	memset(&ev, 0, sizeof(ev));
200*5148fa52SDavid Herrmann 	ev.type = UHID_INPUT;
201*5148fa52SDavid Herrmann 	ev.u.input.size = 4;
202*5148fa52SDavid Herrmann 
203*5148fa52SDavid Herrmann 	if (btn1_down)
204*5148fa52SDavid Herrmann 		ev.u.input.data[0] |= 0x1;
205*5148fa52SDavid Herrmann 	if (btn2_down)
206*5148fa52SDavid Herrmann 		ev.u.input.data[0] |= 0x2;
207*5148fa52SDavid Herrmann 	if (btn3_down)
208*5148fa52SDavid Herrmann 		ev.u.input.data[0] |= 0x4;
209*5148fa52SDavid Herrmann 
210*5148fa52SDavid Herrmann 	ev.u.input.data[1] = abs_hor;
211*5148fa52SDavid Herrmann 	ev.u.input.data[2] = abs_ver;
212*5148fa52SDavid Herrmann 	ev.u.input.data[3] = wheel;
213*5148fa52SDavid Herrmann 
214*5148fa52SDavid Herrmann 	return uhid_write(fd, &ev);
215*5148fa52SDavid Herrmann }
216*5148fa52SDavid Herrmann 
217*5148fa52SDavid Herrmann static int keyboard(int fd)
218*5148fa52SDavid Herrmann {
219*5148fa52SDavid Herrmann 	char buf[128];
220*5148fa52SDavid Herrmann 	ssize_t ret, i;
221*5148fa52SDavid Herrmann 
222*5148fa52SDavid Herrmann 	ret = read(STDIN_FILENO, buf, sizeof(buf));
223*5148fa52SDavid Herrmann 	if (ret == 0) {
224*5148fa52SDavid Herrmann 		fprintf(stderr, "Read HUP on stdin\n");
225*5148fa52SDavid Herrmann 		return -EFAULT;
226*5148fa52SDavid Herrmann 	} else if (ret < 0) {
227*5148fa52SDavid Herrmann 		fprintf(stderr, "Cannot read stdin: %m\n");
228*5148fa52SDavid Herrmann 		return -errno;
229*5148fa52SDavid Herrmann 	}
230*5148fa52SDavid Herrmann 
231*5148fa52SDavid Herrmann 	for (i = 0; i < ret; ++i) {
232*5148fa52SDavid Herrmann 		switch (buf[i]) {
233*5148fa52SDavid Herrmann 		case '1':
234*5148fa52SDavid Herrmann 			btn1_down = !btn1_down;
235*5148fa52SDavid Herrmann 			ret = send_event(fd);
236*5148fa52SDavid Herrmann 			if (ret)
237*5148fa52SDavid Herrmann 				return ret;
238*5148fa52SDavid Herrmann 			break;
239*5148fa52SDavid Herrmann 		case '2':
240*5148fa52SDavid Herrmann 			btn2_down = !btn2_down;
241*5148fa52SDavid Herrmann 			ret = send_event(fd);
242*5148fa52SDavid Herrmann 			if (ret)
243*5148fa52SDavid Herrmann 				return ret;
244*5148fa52SDavid Herrmann 			break;
245*5148fa52SDavid Herrmann 		case '3':
246*5148fa52SDavid Herrmann 			btn3_down = !btn3_down;
247*5148fa52SDavid Herrmann 			ret = send_event(fd);
248*5148fa52SDavid Herrmann 			if (ret)
249*5148fa52SDavid Herrmann 				return ret;
250*5148fa52SDavid Herrmann 			break;
251*5148fa52SDavid Herrmann 		case 'a':
252*5148fa52SDavid Herrmann 			abs_hor = -20;
253*5148fa52SDavid Herrmann 			ret = send_event(fd);
254*5148fa52SDavid Herrmann 			abs_hor = 0;
255*5148fa52SDavid Herrmann 			if (ret)
256*5148fa52SDavid Herrmann 				return ret;
257*5148fa52SDavid Herrmann 			break;
258*5148fa52SDavid Herrmann 		case 'd':
259*5148fa52SDavid Herrmann 			abs_hor = 20;
260*5148fa52SDavid Herrmann 			ret = send_event(fd);
261*5148fa52SDavid Herrmann 			abs_hor = 0;
262*5148fa52SDavid Herrmann 			if (ret)
263*5148fa52SDavid Herrmann 				return ret;
264*5148fa52SDavid Herrmann 			break;
265*5148fa52SDavid Herrmann 		case 'w':
266*5148fa52SDavid Herrmann 			abs_ver = -20;
267*5148fa52SDavid Herrmann 			ret = send_event(fd);
268*5148fa52SDavid Herrmann 			abs_ver = 0;
269*5148fa52SDavid Herrmann 			if (ret)
270*5148fa52SDavid Herrmann 				return ret;
271*5148fa52SDavid Herrmann 			break;
272*5148fa52SDavid Herrmann 		case 's':
273*5148fa52SDavid Herrmann 			abs_ver = 20;
274*5148fa52SDavid Herrmann 			ret = send_event(fd);
275*5148fa52SDavid Herrmann 			abs_ver = 0;
276*5148fa52SDavid Herrmann 			if (ret)
277*5148fa52SDavid Herrmann 				return ret;
278*5148fa52SDavid Herrmann 			break;
279*5148fa52SDavid Herrmann 		case 'r':
280*5148fa52SDavid Herrmann 			wheel = 1;
281*5148fa52SDavid Herrmann 			ret = send_event(fd);
282*5148fa52SDavid Herrmann 			wheel = 0;
283*5148fa52SDavid Herrmann 			if (ret)
284*5148fa52SDavid Herrmann 				return ret;
285*5148fa52SDavid Herrmann 			break;
286*5148fa52SDavid Herrmann 		case 'f':
287*5148fa52SDavid Herrmann 			wheel = -1;
288*5148fa52SDavid Herrmann 			ret = send_event(fd);
289*5148fa52SDavid Herrmann 			wheel = 0;
290*5148fa52SDavid Herrmann 			if (ret)
291*5148fa52SDavid Herrmann 				return ret;
292*5148fa52SDavid Herrmann 			break;
293*5148fa52SDavid Herrmann 		case 'q':
294*5148fa52SDavid Herrmann 			return -ECANCELED;
295*5148fa52SDavid Herrmann 		default:
296*5148fa52SDavid Herrmann 			fprintf(stderr, "Invalid input: %c\n", buf[i]);
297*5148fa52SDavid Herrmann 		}
298*5148fa52SDavid Herrmann 	}
299*5148fa52SDavid Herrmann 
300*5148fa52SDavid Herrmann 	return 0;
301*5148fa52SDavid Herrmann }
302*5148fa52SDavid Herrmann 
303*5148fa52SDavid Herrmann int main(int argc, char **argv)
304*5148fa52SDavid Herrmann {
305*5148fa52SDavid Herrmann 	int fd;
306*5148fa52SDavid Herrmann 	const char *path = "/dev/uhid";
307*5148fa52SDavid Herrmann 	struct pollfd pfds[2];
308*5148fa52SDavid Herrmann 	int ret;
309*5148fa52SDavid Herrmann 	struct termios state;
310*5148fa52SDavid Herrmann 
311*5148fa52SDavid Herrmann 	ret = tcgetattr(STDIN_FILENO, &state);
312*5148fa52SDavid Herrmann 	if (ret) {
313*5148fa52SDavid Herrmann 		fprintf(stderr, "Cannot get tty state\n");
314*5148fa52SDavid Herrmann 	} else {
315*5148fa52SDavid Herrmann 		state.c_lflag &= ~ICANON;
316*5148fa52SDavid Herrmann 		state.c_cc[VMIN] = 1;
317*5148fa52SDavid Herrmann 		ret = tcsetattr(STDIN_FILENO, TCSANOW, &state);
318*5148fa52SDavid Herrmann 		if (ret)
319*5148fa52SDavid Herrmann 			fprintf(stderr, "Cannot set tty state\n");
320*5148fa52SDavid Herrmann 	}
321*5148fa52SDavid Herrmann 
322*5148fa52SDavid Herrmann 	if (argc >= 2) {
323*5148fa52SDavid Herrmann 		if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
324*5148fa52SDavid Herrmann 			fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
325*5148fa52SDavid Herrmann 			return EXIT_SUCCESS;
326*5148fa52SDavid Herrmann 		} else {
327*5148fa52SDavid Herrmann 			path = argv[1];
328*5148fa52SDavid Herrmann 		}
329*5148fa52SDavid Herrmann 	}
330*5148fa52SDavid Herrmann 
331*5148fa52SDavid Herrmann 	fprintf(stderr, "Open uhid-cdev %s\n", path);
332*5148fa52SDavid Herrmann 	fd = open(path, O_RDWR | O_CLOEXEC);
333*5148fa52SDavid Herrmann 	if (fd < 0) {
334*5148fa52SDavid Herrmann 		fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path);
335*5148fa52SDavid Herrmann 		return EXIT_FAILURE;
336*5148fa52SDavid Herrmann 	}
337*5148fa52SDavid Herrmann 
338*5148fa52SDavid Herrmann 	fprintf(stderr, "Create uhid device\n");
339*5148fa52SDavid Herrmann 	ret = create(fd);
340*5148fa52SDavid Herrmann 	if (ret) {
341*5148fa52SDavid Herrmann 		close(fd);
342*5148fa52SDavid Herrmann 		return EXIT_FAILURE;
343*5148fa52SDavid Herrmann 	}
344*5148fa52SDavid Herrmann 
345*5148fa52SDavid Herrmann 	pfds[0].fd = STDIN_FILENO;
346*5148fa52SDavid Herrmann 	pfds[0].events = POLLIN;
347*5148fa52SDavid Herrmann 	pfds[1].fd = fd;
348*5148fa52SDavid Herrmann 	pfds[1].events = POLLIN;
349*5148fa52SDavid Herrmann 
350*5148fa52SDavid Herrmann 	fprintf(stderr, "Press 'q' to quit...\n");
351*5148fa52SDavid Herrmann 	while (1) {
352*5148fa52SDavid Herrmann 		ret = poll(pfds, 2, -1);
353*5148fa52SDavid Herrmann 		if (ret < 0) {
354*5148fa52SDavid Herrmann 			fprintf(stderr, "Cannot poll for fds: %m\n");
355*5148fa52SDavid Herrmann 			break;
356*5148fa52SDavid Herrmann 		}
357*5148fa52SDavid Herrmann 		if (pfds[0].revents & POLLHUP) {
358*5148fa52SDavid Herrmann 			fprintf(stderr, "Received HUP on stdin\n");
359*5148fa52SDavid Herrmann 			break;
360*5148fa52SDavid Herrmann 		}
361*5148fa52SDavid Herrmann 		if (pfds[1].revents & POLLHUP) {
362*5148fa52SDavid Herrmann 			fprintf(stderr, "Received HUP on uhid-cdev\n");
363*5148fa52SDavid Herrmann 			break;
364*5148fa52SDavid Herrmann 		}
365*5148fa52SDavid Herrmann 
366*5148fa52SDavid Herrmann 		if (pfds[0].revents & POLLIN) {
367*5148fa52SDavid Herrmann 			ret = keyboard(fd);
368*5148fa52SDavid Herrmann 			if (ret)
369*5148fa52SDavid Herrmann 				break;
370*5148fa52SDavid Herrmann 		}
371*5148fa52SDavid Herrmann 		if (pfds[1].revents & POLLIN) {
372*5148fa52SDavid Herrmann 			ret = event(fd);
373*5148fa52SDavid Herrmann 			if (ret)
374*5148fa52SDavid Herrmann 				break;
375*5148fa52SDavid Herrmann 		}
376*5148fa52SDavid Herrmann 	}
377*5148fa52SDavid Herrmann 
378*5148fa52SDavid Herrmann 	fprintf(stderr, "Destroy uhid device\n");
379*5148fa52SDavid Herrmann 	destroy(fd);
380*5148fa52SDavid Herrmann 	return EXIT_SUCCESS;
381*5148fa52SDavid Herrmann }
382