^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Hidraw Userspace Example
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2010 Alan Ott <alan@signal11.us>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (c) 2010 Signal 11 Software
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * The code may be used by anyone for any purpose,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * and can serve as a starting point for developing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * applications using hidraw.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) /* Linux */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/hidraw.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * Ugly hack to work around failing compilation on systems that don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * yet populate new version of hidraw.h to userspace.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #ifndef HIDIOCSFEATURE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #warning Please have your distro update the userspace kernel headers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) /* Unix */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <sys/ioctl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* C */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) const char *bus_str(int bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int main(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int i, res, desc_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) char buf[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct hidraw_report_descriptor rpt_desc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) struct hidraw_devinfo info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) char *device = "/dev/hidraw0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (argc > 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) device = argv[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* Open the Device with non-blocking reads. In real life,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) don't use a hard coded path; use libudev instead. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) fd = open(device, O_RDWR|O_NONBLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (fd < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) perror("Unable to open device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) memset(&rpt_desc, 0x0, sizeof(rpt_desc));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) memset(&info, 0x0, sizeof(info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) memset(buf, 0x0, sizeof(buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) /* Get Report Descriptor Size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) res = ioctl(fd, HIDIOCGRDESCSIZE, &desc_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) perror("HIDIOCGRDESCSIZE");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) printf("Report Descriptor Size: %d\n", desc_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Get Report Descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) rpt_desc.size = desc_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) res = ioctl(fd, HIDIOCGRDESC, &rpt_desc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (res < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) perror("HIDIOCGRDESC");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) printf("Report Descriptor:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) for (i = 0; i < rpt_desc.size; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) printf("%hhx ", rpt_desc.value[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) puts("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* Get Raw Name */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) res = ioctl(fd, HIDIOCGRAWNAME(256), buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) perror("HIDIOCGRAWNAME");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) printf("Raw Name: %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /* Get Physical Location */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) res = ioctl(fd, HIDIOCGRAWPHYS(256), buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) perror("HIDIOCGRAWPHYS");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) printf("Raw Phys: %s\n", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* Get Raw Info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) res = ioctl(fd, HIDIOCGRAWINFO, &info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (res < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) perror("HIDIOCGRAWINFO");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) printf("Raw Info:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) printf("\tbustype: %d (%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) info.bustype, bus_str(info.bustype));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) printf("\tvendor: 0x%04hx\n", info.vendor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) printf("\tproduct: 0x%04hx\n", info.product);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* Set Feature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) buf[0] = 0x9; /* Report Number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) buf[1] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) buf[2] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) buf[3] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) res = ioctl(fd, HIDIOCSFEATURE(4), buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (res < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) perror("HIDIOCSFEATURE");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) printf("ioctl HIDIOCSFEATURE returned: %d\n", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* Get Feature */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) buf[0] = 0x9; /* Report Number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) res = ioctl(fd, HIDIOCGFEATURE(256), buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (res < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) perror("HIDIOCGFEATURE");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) printf("ioctl HIDIOCGFEATURE returned: %d\n", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) printf("Report data (not containing the report number):\n\t");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) for (i = 0; i < res; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) printf("%hhx ", buf[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) puts("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* Send a Report to the Device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) buf[0] = 0x1; /* Report Number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) buf[1] = 0x77;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) res = write(fd, buf, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (res < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) printf("Error: %d\n", errno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) perror("write");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) printf("write() wrote %d bytes\n", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* Get a report from the device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) res = read(fd, buf, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (res < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) perror("read");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) printf("read() read %d bytes:\n\t", res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) for (i = 0; i < res; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) printf("%hhx ", buf[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) puts("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) const char *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) bus_str(int bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) switch (bus) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) case BUS_USB:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return "USB";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) case BUS_HIL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return "HIL";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) case BUS_BLUETOOTH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) return "Bluetooth";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) case BUS_VIRTUAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return "Virtual";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return "Other";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }