0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 #include <errno.h>
0041 #include <fcntl.h>
0042 #include <poll.h>
0043 #include <stdbool.h>
0044 #include <stdio.h>
0045 #include <stdlib.h>
0046 #include <string.h>
0047 #include <termios.h>
0048 #include <unistd.h>
0049 #include <linux/uhid.h>
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 static unsigned char rdesc[] = {
0113 0x05, 0x01,
0114 0x09, 0x02,
0115 0xa1, 0x01,
0116 0x09, 0x01,
0117 0xa1, 0x00,
0118 0x85, 0x01,
0119 0x05, 0x09,
0120 0x19, 0x01,
0121 0x29, 0x03,
0122 0x15, 0x00,
0123 0x25, 0x01,
0124 0x95, 0x03,
0125 0x75, 0x01,
0126 0x81, 0x02,
0127 0x95, 0x01,
0128 0x75, 0x05,
0129 0x81, 0x01,
0130 0x05, 0x01,
0131 0x09, 0x30,
0132 0x09, 0x31,
0133 0x09, 0x38,
0134 0x15, 0x81,
0135 0x25, 0x7f,
0136 0x75, 0x08,
0137 0x95, 0x03,
0138 0x81, 0x06,
0139 0xc0,
0140 0xc0,
0141 0x05, 0x01,
0142 0x09, 0x06,
0143 0xa1, 0x01,
0144 0x85, 0x02,
0145 0x05, 0x08,
0146 0x19, 0x01,
0147 0x29, 0x03,
0148 0x15, 0x00,
0149 0x25, 0x01,
0150 0x95, 0x03,
0151 0x75, 0x01,
0152 0x91, 0x02,
0153 0x95, 0x01,
0154 0x75, 0x05,
0155 0x91, 0x01,
0156 0xc0,
0157 };
0158
0159 static int uhid_write(int fd, const struct uhid_event *ev)
0160 {
0161 ssize_t ret;
0162
0163 ret = write(fd, ev, sizeof(*ev));
0164 if (ret < 0) {
0165 fprintf(stderr, "Cannot write to uhid: %m\n");
0166 return -errno;
0167 } else if (ret != sizeof(*ev)) {
0168 fprintf(stderr, "Wrong size written to uhid: %zd != %zu\n",
0169 ret, sizeof(ev));
0170 return -EFAULT;
0171 } else {
0172 return 0;
0173 }
0174 }
0175
0176 static int create(int fd)
0177 {
0178 struct uhid_event ev;
0179
0180 memset(&ev, 0, sizeof(ev));
0181 ev.type = UHID_CREATE;
0182 strcpy((char*)ev.u.create.name, "test-uhid-device");
0183 ev.u.create.rd_data = rdesc;
0184 ev.u.create.rd_size = sizeof(rdesc);
0185 ev.u.create.bus = BUS_USB;
0186 ev.u.create.vendor = 0x15d9;
0187 ev.u.create.product = 0x0a37;
0188 ev.u.create.version = 0;
0189 ev.u.create.country = 0;
0190
0191 return uhid_write(fd, &ev);
0192 }
0193
0194 static void destroy(int fd)
0195 {
0196 struct uhid_event ev;
0197
0198 memset(&ev, 0, sizeof(ev));
0199 ev.type = UHID_DESTROY;
0200
0201 uhid_write(fd, &ev);
0202 }
0203
0204
0205
0206
0207
0208 static void handle_output(struct uhid_event *ev)
0209 {
0210
0211 if (ev->u.output.rtype != UHID_OUTPUT_REPORT)
0212 return;
0213
0214 if (ev->u.output.size != 2)
0215 return;
0216
0217 if (ev->u.output.data[0] != 0x2)
0218 return;
0219
0220
0221 fprintf(stderr, "LED output report received with flags %x\n",
0222 ev->u.output.data[1]);
0223 }
0224
0225 static int event(int fd)
0226 {
0227 struct uhid_event ev;
0228 ssize_t ret;
0229
0230 memset(&ev, 0, sizeof(ev));
0231 ret = read(fd, &ev, sizeof(ev));
0232 if (ret == 0) {
0233 fprintf(stderr, "Read HUP on uhid-cdev\n");
0234 return -EFAULT;
0235 } else if (ret < 0) {
0236 fprintf(stderr, "Cannot read uhid-cdev: %m\n");
0237 return -errno;
0238 } else if (ret != sizeof(ev)) {
0239 fprintf(stderr, "Invalid size read from uhid-dev: %zd != %zu\n",
0240 ret, sizeof(ev));
0241 return -EFAULT;
0242 }
0243
0244 switch (ev.type) {
0245 case UHID_START:
0246 fprintf(stderr, "UHID_START from uhid-dev\n");
0247 break;
0248 case UHID_STOP:
0249 fprintf(stderr, "UHID_STOP from uhid-dev\n");
0250 break;
0251 case UHID_OPEN:
0252 fprintf(stderr, "UHID_OPEN from uhid-dev\n");
0253 break;
0254 case UHID_CLOSE:
0255 fprintf(stderr, "UHID_CLOSE from uhid-dev\n");
0256 break;
0257 case UHID_OUTPUT:
0258 fprintf(stderr, "UHID_OUTPUT from uhid-dev\n");
0259 handle_output(&ev);
0260 break;
0261 case UHID_OUTPUT_EV:
0262 fprintf(stderr, "UHID_OUTPUT_EV from uhid-dev\n");
0263 break;
0264 default:
0265 fprintf(stderr, "Invalid event from uhid-dev: %u\n", ev.type);
0266 }
0267
0268 return 0;
0269 }
0270
0271 static bool btn1_down;
0272 static bool btn2_down;
0273 static bool btn3_down;
0274 static signed char abs_hor;
0275 static signed char abs_ver;
0276 static signed char wheel;
0277
0278 static int send_event(int fd)
0279 {
0280 struct uhid_event ev;
0281
0282 memset(&ev, 0, sizeof(ev));
0283 ev.type = UHID_INPUT;
0284 ev.u.input.size = 5;
0285
0286 ev.u.input.data[0] = 0x1;
0287 if (btn1_down)
0288 ev.u.input.data[1] |= 0x1;
0289 if (btn2_down)
0290 ev.u.input.data[1] |= 0x2;
0291 if (btn3_down)
0292 ev.u.input.data[1] |= 0x4;
0293
0294 ev.u.input.data[2] = abs_hor;
0295 ev.u.input.data[3] = abs_ver;
0296 ev.u.input.data[4] = wheel;
0297
0298 return uhid_write(fd, &ev);
0299 }
0300
0301 static int keyboard(int fd)
0302 {
0303 char buf[128];
0304 ssize_t ret, i;
0305
0306 ret = read(STDIN_FILENO, buf, sizeof(buf));
0307 if (ret == 0) {
0308 fprintf(stderr, "Read HUP on stdin\n");
0309 return -EFAULT;
0310 } else if (ret < 0) {
0311 fprintf(stderr, "Cannot read stdin: %m\n");
0312 return -errno;
0313 }
0314
0315 for (i = 0; i < ret; ++i) {
0316 switch (buf[i]) {
0317 case '1':
0318 btn1_down = !btn1_down;
0319 ret = send_event(fd);
0320 if (ret)
0321 return ret;
0322 break;
0323 case '2':
0324 btn2_down = !btn2_down;
0325 ret = send_event(fd);
0326 if (ret)
0327 return ret;
0328 break;
0329 case '3':
0330 btn3_down = !btn3_down;
0331 ret = send_event(fd);
0332 if (ret)
0333 return ret;
0334 break;
0335 case 'a':
0336 abs_hor = -20;
0337 ret = send_event(fd);
0338 abs_hor = 0;
0339 if (ret)
0340 return ret;
0341 break;
0342 case 'd':
0343 abs_hor = 20;
0344 ret = send_event(fd);
0345 abs_hor = 0;
0346 if (ret)
0347 return ret;
0348 break;
0349 case 'w':
0350 abs_ver = -20;
0351 ret = send_event(fd);
0352 abs_ver = 0;
0353 if (ret)
0354 return ret;
0355 break;
0356 case 's':
0357 abs_ver = 20;
0358 ret = send_event(fd);
0359 abs_ver = 0;
0360 if (ret)
0361 return ret;
0362 break;
0363 case 'r':
0364 wheel = 1;
0365 ret = send_event(fd);
0366 wheel = 0;
0367 if (ret)
0368 return ret;
0369 break;
0370 case 'f':
0371 wheel = -1;
0372 ret = send_event(fd);
0373 wheel = 0;
0374 if (ret)
0375 return ret;
0376 break;
0377 case 'q':
0378 return -ECANCELED;
0379 default:
0380 fprintf(stderr, "Invalid input: %c\n", buf[i]);
0381 }
0382 }
0383
0384 return 0;
0385 }
0386
0387 int main(int argc, char **argv)
0388 {
0389 int fd;
0390 const char *path = "/dev/uhid";
0391 struct pollfd pfds[2];
0392 int ret;
0393 struct termios state;
0394
0395 ret = tcgetattr(STDIN_FILENO, &state);
0396 if (ret) {
0397 fprintf(stderr, "Cannot get tty state\n");
0398 } else {
0399 state.c_lflag &= ~ICANON;
0400 state.c_cc[VMIN] = 1;
0401 ret = tcsetattr(STDIN_FILENO, TCSANOW, &state);
0402 if (ret)
0403 fprintf(stderr, "Cannot set tty state\n");
0404 }
0405
0406 if (argc >= 2) {
0407 if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
0408 fprintf(stderr, "Usage: %s [%s]\n", argv[0], path);
0409 return EXIT_SUCCESS;
0410 } else {
0411 path = argv[1];
0412 }
0413 }
0414
0415 fprintf(stderr, "Open uhid-cdev %s\n", path);
0416 fd = open(path, O_RDWR | O_CLOEXEC);
0417 if (fd < 0) {
0418 fprintf(stderr, "Cannot open uhid-cdev %s: %m\n", path);
0419 return EXIT_FAILURE;
0420 }
0421
0422 fprintf(stderr, "Create uhid device\n");
0423 ret = create(fd);
0424 if (ret) {
0425 close(fd);
0426 return EXIT_FAILURE;
0427 }
0428
0429 pfds[0].fd = STDIN_FILENO;
0430 pfds[0].events = POLLIN;
0431 pfds[1].fd = fd;
0432 pfds[1].events = POLLIN;
0433
0434 fprintf(stderr, "Press 'q' to quit...\n");
0435 while (1) {
0436 ret = poll(pfds, 2, -1);
0437 if (ret < 0) {
0438 fprintf(stderr, "Cannot poll for fds: %m\n");
0439 break;
0440 }
0441 if (pfds[0].revents & POLLHUP) {
0442 fprintf(stderr, "Received HUP on stdin\n");
0443 break;
0444 }
0445 if (pfds[1].revents & POLLHUP) {
0446 fprintf(stderr, "Received HUP on uhid-cdev\n");
0447 break;
0448 }
0449
0450 if (pfds[0].revents & POLLIN) {
0451 ret = keyboard(fd);
0452 if (ret)
0453 break;
0454 }
0455 if (pfds[1].revents & POLLIN) {
0456 ret = event(fd);
0457 if (ret)
0458 break;
0459 }
0460 }
0461
0462 fprintf(stderr, "Destroy uhid device\n");
0463 destroy(fd);
0464 return EXIT_SUCCESS;
0465 }