]> git.itanic.dy.fi Git - glucose/blob - hiddev.c
Fix crossed vendor and product IDs
[glucose] / hiddev.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <sys/ioctl.h>
5 #include <sys/types.h>
6 #include <linux/hiddev.h>
7 #include <errno.h>
8 #include <string.h>
9 #include <fcntl.h>
10 #include <dirent.h>
11
12 #include "hiddev.h"
13 #include "utils.h"
14
15 #define PRINT_FIELD(level, field) trace(level, #field ": %04x\n", field)
16
17 #define HIDDEV_PATH "/dev/usb/"
18
19 int hiddev_read(unsigned char *data, int bufsize, int fd)
20 {
21         struct hiddev_event readBuffer[READ_BUFFER_LENGTH];
22         int ret, n, i;
23
24         ret = read(fd, readBuffer, sizeof(readBuffer));
25         if (ret < 0)
26                 return ret;
27
28         n = ret / sizeof(readBuffer[0]);
29         for (i = 0; i < n && i < bufsize; i++)
30                 data[i] = readBuffer[i].value;
31         return n;
32 }
33
34 int hiddev_write(const unsigned char data[64], int fd , int usage_code)
35 {
36         int rc = 0, uindex, error;
37
38         struct hiddev_usage_ref uref;
39         struct hiddev_report_info rinfo;
40
41         uref.report_id = *data++;
42         uref.report_type = HID_REPORT_TYPE_OUTPUT;
43         uref.field_index = 0;
44
45         uref.usage_code = usage_code;
46
47         for (uindex = 0; uindex < 63; uindex++) {
48                 uref.usage_index = uindex;
49                 uref.value = *data++;
50
51                 rc = ioctl(fd, HIDIOCSUSAGE, &uref);
52                 if (rc != 0)
53                         goto err;
54         }
55
56         rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
57         rinfo.report_id =  0x0;
58         rinfo.num_fields = 1;
59
60         rc = ioctl(fd, HIDIOCSREPORT, &rinfo);
61         if (rc != 0)
62                 goto err2;
63
64         return 0;
65 err2:
66         printf("HIDIOCSREPORT\n");
67 err:
68         error = errno;
69         printf("Error in IOCTL: %s\n", strerror(error));
70
71         return rc;
72 }
73
74 static int get_usagecode(int fd)
75 {
76         struct hiddev_usage_ref uref;
77         int rc, error;
78
79         uref.report_type = HID_REPORT_TYPE_OUTPUT;
80         uref.report_id = 0x0;
81         uref.field_index = 0;
82         uref.usage_index = 0;
83
84         rc = ioctl(fd, HIDIOCGUCODE, &uref);
85         if (rc < 0) {
86                 error = errno;
87                 printf("Error gettin usage code: %s\n", strerror(error));
88                 return rc;
89         }
90
91         return uref.usage_code;
92 }
93
94 static int _hiddev_open(const char *device_path, int *usage_code,
95                         int vendor_id, int product_id)
96 {
97         struct hiddev_devinfo device_info;
98         struct hiddev_report_info rinfo;
99         int ret, error;
100         int fd;
101
102         trace(3, "Opening device %s\n", device_path);
103         fd = ret = open(device_path, O_RDWR);
104
105         if (fd < 0)
106                 goto err;
107
108         rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
109         rinfo.report_id = HID_REPORT_ID_FIRST;
110         ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
111         if (ret < 0)
112                 goto err_close;
113
114         PRINT_FIELD(3, rinfo.report_type);
115         PRINT_FIELD(3, rinfo.report_id);
116         PRINT_FIELD(3, rinfo.num_fields);
117
118         *usage_code = get_usagecode(fd);
119
120         if (*usage_code < 0)
121                 goto err_close;
122
123         ret = ioctl(fd, HIDIOCGDEVINFO, &device_info);
124
125         if (ret < 0)
126                 goto err_close;
127
128         PRINT_FIELD(3, device_info.bustype);
129         PRINT_FIELD(3, device_info.busnum);
130         PRINT_FIELD(3, device_info.devnum);
131         PRINT_FIELD(3, device_info.ifnum);
132         PRINT_FIELD(3, device_info.vendor);
133         PRINT_FIELD(3, device_info.product);
134         PRINT_FIELD(3, device_info.version);
135         PRINT_FIELD(3, device_info.num_applications);
136
137         if (product_id && vendor_id) {
138                 if (product_id == device_info.product &&
139                         vendor_id == device_info.vendor)
140                         return fd;
141                 trace(3, "Vendor and product IDs don't match\n");
142                 ret = -1;
143                 goto err_close;
144         }
145
146         return fd;
147
148 err_close:
149         close(fd);
150 err:
151         error = errno;
152         if (error)
153                 printf("Error opening device %s: %s\n", device_path,
154                         strerror(error));
155         return ret;
156 }
157
158 int hiddev_open(const char *device_path, int *usage_code)
159 {
160         return _hiddev_open(device_path, usage_code, 0, 0);
161 }
162
163 int hiddev_open_by_id(int vendor_id, int product_id, int *usage_code)
164 {
165         struct dirent *dirent;
166         DIR *dir;
167         int error, fd;
168         char path[256];
169
170         dir = opendir(HIDDEV_PATH);
171         if (dir == NULL) {
172                 error = errno;
173                 printf("Failed to open directory %s: %s\n", HIDDEV_PATH,
174                         strerror(error));
175                 return -error;
176         }
177
178         while (1) {
179                 dirent = readdir(dir);
180                 if (dirent == NULL)
181                         break;
182
183                 if (strncmp(dirent->d_name, "hiddev", sizeof("hiddev") - 1))
184                         continue;
185
186                 path[0] = 0;
187                 strncat(path, HIDDEV_PATH, sizeof(path) - 1);
188                 strncat(path, dirent->d_name, sizeof(path) - 1);
189
190                 fd = _hiddev_open(path, usage_code, vendor_id, product_id);
191                 if (fd < 0)
192                         continue;
193                 return fd;
194         }
195
196         if (errno) {
197                 error = errno;
198                 trace(0, "Error reading directory %s: %s\n", HIDDEV_PATH,
199                         strerror(error));
200                 return -error;
201         }
202
203         trace(0, "Canno't find any mathing hiddev devices\n");
204         return -1;
205 }