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