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