]> git.itanic.dy.fi Git - glucose/blob - hiddev.c
_hiddev_open: Fix error messages
[glucose] / hiddev.c
1 /*
2  * Copyright (C) 2012 Timo Kokkonen <timo.t.kokkonen@iki.fi>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/ioctl.h>
24 #include <sys/types.h>
25 #include <linux/hiddev.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <dirent.h>
30
31 #include "hiddev.h"
32 #include "utils.h"
33
34 #define PRINT_FIELD(level, field) trace(level, #field ": %04x\n", field)
35
36 #define HIDDEV_PATH "/dev/usb/"
37
38 int hiddev_read(unsigned char *data, int bufsize, int fd)
39 {
40         struct hiddev_event readBuffer[READ_BUFFER_LENGTH];
41         int ret, n, i;
42
43         ret = read(fd, readBuffer, sizeof(readBuffer));
44         if (ret < 0)
45                 return ret;
46
47         n = ret / sizeof(readBuffer[0]);
48         for (i = 0; i < n && i < bufsize; i++)
49                 data[i] = readBuffer[i].value;
50         return n;
51 }
52
53 int hiddev_write(const unsigned char data[64], int fd , int usage_code)
54 {
55         int rc = 0, uindex, error;
56
57         struct hiddev_usage_ref uref;
58         struct hiddev_report_info rinfo;
59
60         uref.report_id = *data++;
61         uref.report_type = HID_REPORT_TYPE_OUTPUT;
62         uref.field_index = 0;
63
64         uref.usage_code = usage_code;
65
66         for (uindex = 0; uindex < 63; uindex++) {
67                 uref.usage_index = uindex;
68                 uref.value = *data++;
69
70                 rc = ioctl(fd, HIDIOCSUSAGE, &uref);
71                 if (rc != 0)
72                         goto err;
73         }
74
75         rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
76         rinfo.report_id =  0x0;
77         rinfo.num_fields = 1;
78
79         rc = ioctl(fd, HIDIOCSREPORT, &rinfo);
80         if (rc != 0)
81                 goto err2;
82
83         return 0;
84 err2:
85         printf("HIDIOCSREPORT\n");
86 err:
87         error = errno;
88         printf("Error in IOCTL: %s\n", strerror(error));
89
90         return rc;
91 }
92
93 static int get_usagecode(int fd)
94 {
95         struct hiddev_usage_ref uref;
96         int rc, error;
97
98         uref.report_type = HID_REPORT_TYPE_OUTPUT;
99         uref.report_id = 0x0;
100         uref.field_index = 0;
101         uref.usage_index = 0;
102
103         rc = ioctl(fd, HIDIOCGUCODE, &uref);
104         if (rc < 0) {
105                 error = errno;
106                 printf("Error gettin usage code: %s\n", strerror(error));
107                 return rc;
108         }
109
110         return uref.usage_code;
111 }
112
113 static int _hiddev_open(const char *device_path, int *usage_code,
114                         int vendor_id, int product_id)
115 {
116         struct hiddev_devinfo device_info;
117         struct hiddev_report_info rinfo;
118         int ret;
119         int fd;
120
121         trace(3, "Opening device %s\n", device_path);
122         fd = ret = open(device_path, O_RDWR);
123
124         if (fd < 0) {
125                 trace(0, "Error opening device %s: %m\n", device_path);
126                 return -1;
127         }
128
129         rinfo.report_type = HID_REPORT_TYPE_OUTPUT;
130         rinfo.report_id = HID_REPORT_ID_FIRST;
131         ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
132         if (ret < 0)
133                 goto err_ioctl;
134
135         PRINT_FIELD(3, rinfo.report_type);
136         PRINT_FIELD(3, rinfo.report_id);
137         PRINT_FIELD(3, rinfo.num_fields);
138
139         *usage_code = get_usagecode(fd);
140
141         if (*usage_code < 0)
142                 goto err_close;
143
144         ret = ioctl(fd, HIDIOCGDEVINFO, &device_info);
145
146         if (ret < 0)
147                 goto err_ioctl;
148
149         PRINT_FIELD(3, device_info.bustype);
150         PRINT_FIELD(3, device_info.busnum);
151         PRINT_FIELD(3, device_info.devnum);
152         PRINT_FIELD(3, device_info.ifnum);
153         PRINT_FIELD(3, device_info.vendor);
154         PRINT_FIELD(3, device_info.product);
155         PRINT_FIELD(3, device_info.version);
156         PRINT_FIELD(3, device_info.num_applications);
157
158         if (product_id && vendor_id) {
159                 if (product_id == device_info.product &&
160                         vendor_id == device_info.vendor)
161                         return fd;
162                 trace(3, "Vendor and product IDs don't match\n");
163                 ret = -1;
164                 goto err_close;
165         }
166
167         return fd;
168
169 err_ioctl:
170         trace(0, "Error issuing ioctl: %m\n");
171
172 err_close:
173         close(fd);
174
175         return ret;
176 }
177
178 int hiddev_open(const char *device_path, int *usage_code)
179 {
180         return _hiddev_open(device_path, usage_code, 0, 0);
181 }
182
183 int hiddev_open_by_id(int vendor_id, int product_id, int *usage_code)
184 {
185         struct dirent *dirent;
186         DIR *dir;
187         int error, fd;
188         char path[256];
189
190         dir = opendir(HIDDEV_PATH);
191         if (dir == NULL) {
192                 error = errno;
193                 trace(4, "Failed to open directory %s: %s\n", HIDDEV_PATH,
194                         strerror(error));
195                 return -error;
196         }
197
198         while (1) {
199                 dirent = readdir(dir);
200                 if (dirent == NULL)
201                         break;
202
203                 if (strncmp(dirent->d_name, "hiddev", sizeof("hiddev") - 1))
204                         continue;
205
206                 path[0] = 0;
207                 strncat(path, HIDDEV_PATH, sizeof(path) - 1);
208                 strncat(path, dirent->d_name, sizeof(path) - 1);
209
210                 fd = _hiddev_open(path, usage_code, vendor_id, product_id);
211                 if (fd < 0)
212                         continue;
213                 return fd;
214         }
215
216         if (errno) {
217                 error = errno;
218                 trace(0, "Error reading directory %s: %s\n", HIDDEV_PATH,
219                         strerror(error));
220                 return -error;
221         }
222
223         trace(0, "Canno't find any mathing hiddev devices\n");
224         return -1;
225 }