1 /*
2  * hidutils.c
3  *
4  * Utility functions for interfacing with the libusbhid userspace
5  * HID parsing library.
6  */
7 
8 /*
9  * Copyright (C) 2004-2005 Adam Kropelin
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of version 2 of the GNU General
13  * Public License as published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public
21  * License along with this program; if not, write to the Free
22  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23  * MA 02110-1335, USA.
24  */
25 
26 #include "apc.h"
27 
28 #include "hidutils.h"
29 #include <dev/usb/usb.h>
30 #include <dev/usb/usbhid.h>
31 
32 #define MAX_SANE_DESCRIPTOR_LEN 4096
33 
34 /*
35  * Fetch the report descriptor from the device given an fd for the
36  * device's control endpoint. Descriptor length is written to the
37  * rlen out paramter and a pointer to a malloc'ed buffer containing
38  * the descriptor is returned. Returns NULL on failure.
39  */
hidu_fetch_report_descriptor(int fd,int * rlen)40 unsigned char *hidu_fetch_report_descriptor(int fd, int *rlen)
41 {
42    int rc, i, rdesclen;
43    struct usb_config_desc cdesc;
44    struct usb_full_desc fdesc;
45    struct usb_ctl_request req;
46    int len;
47    unsigned char *ptr;
48 
49    /*
50     * In order to fetch the report descriptor we need to first
51     * determine that descriptor's length. Unlike the other std
52     * descriptors, report descriptors are not prefixed with their
53     * length. We must instead look in the HID descriptor. This is
54     * made especially painful because for some reason we cannot
55     * request the HID descriptor directly. The length bytes come
56     * back munged when we do that (bad, FreeBSD, bad!). So instead
57     * we ask for the set of all top level descriptors and dig the
58     * HID descriptor out of there. Then we can *finally* go about
59     * asking for the report descriptor itself.
60     */
61 
62    /*
63     * First, get the CONFIG descriptor alone so we can look up
64     * the length of the full descriptor set.
65     */
66    cdesc.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
67    rc = ioctl(fd, USB_GET_CONFIG_DESC, &cdesc);
68    if (rc) {
69       Dmsg(100, "Unable to get USB CONFIG descriptor.\n");
70       return NULL;
71    }
72 
73    len = UGETW(cdesc.ucd_desc.wTotalLength);
74    if (!len || len > MAX_SANE_DESCRIPTOR_LEN) {
75       Dmsg(100, "Unreasonable length %d.\n", len);
76       return NULL;
77    }
78 
79    /*
80     * Now get the full set of descriptors (does not include
81     * report descriptor).
82     */
83    fdesc.ufd_size = len;
84    fdesc.ufd_data = (u_char*)malloc(len);
85    fdesc.ufd_config_index = USB_CURRENT_CONFIG_INDEX;
86    rc = ioctl(fd, USB_GET_FULL_DESC, &fdesc);
87    if (rc) {
88       Dmsg(100, "Unable to get full descriptors.\n");
89       free(fdesc.ufd_data);
90       return NULL;
91    }
92 
93    Dmsg(300, "Full descriptors:\n");
94    hex_dump(300, fdesc.ufd_data, len);
95 
96    /* Search for the HID descriptor */
97    for (ptr = fdesc.ufd_data, i = 0; i < len; i += ptr[0], ptr += ptr[0])
98       if (ptr[1] == UDESC_HID)
99          break;
100 
101    if (i >= len) {
102       Dmsg(100, "Unable to locate HID descriptor.\n");
103       free(fdesc.ufd_data);
104       return NULL;
105    }
106 
107    /* We expect the first additional descriptor type to be report */
108    if (ptr[6] != UDESC_REPORT) {
109       Dmsg(100, "First extra descriptor not report.\n");
110       free(fdesc.ufd_data);
111       return NULL;
112    }
113 
114    /* Finally! The report descriptor's length! */
115    rdesclen = ptr[8] << 8 | ptr[7];
116    Dmsg(200, "Report desc len=0x%04x (%d)\n", rdesclen, rdesclen);
117 
118    /* That's all we needed from the buffer */
119    free(fdesc.ufd_data);
120 
121    if (!rdesclen || rdesclen > MAX_SANE_DESCRIPTOR_LEN) {
122       Dmsg(100, "Unreasonable rdesclen %d.\n", rdesclen);
123       return NULL;
124    }
125 
126    /*
127     * Now fetch the report descriptor itself. We use a raw USB request
128     * for this because the report descriptor is a class specific item.
129     */
130    req.ucr_flags = 0;
131    req.ucr_actlen = 0;
132    req.ucr_addr = 0;
133    req.ucr_data = malloc(rdesclen);
134    req.ucr_request.bmRequestType = UT_READ_INTERFACE;
135    req.ucr_request.bRequest = UR_GET_DESCRIPTOR;
136    USETW(req.ucr_request.wValue, UDESC_REPORT << 8);
137    USETW(req.ucr_request.wIndex, 0);
138    USETW(req.ucr_request.wLength, rdesclen);
139    rc = ioctl(fd, USB_DO_REQUEST, &req);
140    if (rc) {
141       Dmsg(100, "Unable to read report descriptor.\n");
142       free(req.ucr_data);
143       return NULL;
144    }
145 
146    Dmsg(300, "Report descriptor:\n");
147    hex_dump(300, req.ucr_data, rdesclen);
148 
149    *rlen = rdesclen;
150    return (unsigned char *)req.ucr_data;
151 }
152 
153 /* Push a value onto the collection stack */
154 #define PUSH_COLLECTION(c, v)             \
155 do                                        \
156 {                                         \
157     if (c##_idx<MAX_COLLECTION_NESTING-1) \
158     {                                     \
159         c##_idx++;                        \
160         c##_stack[c##_idx] = v;           \
161     }                                     \
162 } while(0)
163 
164 /* Remove a value from the collection stack */
165 #define POP_COLLECTION(c) \
166 do                        \
167 {                         \
168     if (c##_idx >= 0)     \
169         c##_idx--;        \
170 } while(0)
171 
172 /* Get the topmost item on the stack */
173 #define TOP_COLLECTION(c) \
174     ((c##_idx == -1) ? -1 : c##_stack[c##_idx])
175 
176 /* Collection types */
177 #define HIDCOL_PHYSICAL     0
178 #define HIDCOL_APPLICATION  1
179 #define HIDCOL_LOGICAL      2
180 #define MAX_COLLECTION_NESTING 10
181 
182 /* For pretty printing... */
183 #define KIND_TO_CHAR(x)                         \
184         ((x) == hid_input) ? 'I' :              \
185         ((x) == hid_output) ? 'O' :             \
186         ((x) == hid_feature) ? 'F' :            \
187         ((x) == hid_collection) ? 'C' :         \
188         ((x) == hid_endcollection) ? 'E' : '?'
189 
190 #define COLLECTION_TO_CHAR(x)   \
191         ((x) == 0) ? 'P' :      /* Physical */       \
192         ((x) == 1) ? 'A' :      /* Application */    \
193         ((x) == 2) ? 'L' :      /* Logical */        \
194         ((x) == 3) ? 'R' :      /* Report */         \
195         ((x) == 4) ? 'N' :      /* Named Array */    \
196         ((x) == 5) ? 'S' :      /* Usage Switch */   \
197         ((x) == 6) ? 'M' : '?'  /* Usage Modifier */ \
198 
199 
200 /*
201  * Locate an item matching the given parameters. If found, the
202  * item is copied to the supplied buffer. Returns true on success,
203  * false on failure. Any of usage, app, phys, logical, and kind
204  * may be set to -1 for "don't care".
205  */
hidu_locate_item(report_desc_t rdesc,int usage,int app,int phys,int logical,int kind,hid_item_t * outitem)206 int hidu_locate_item(report_desc_t rdesc, int usage, int app, int phys,
207    int logical, int kind, hid_item_t *outitem)
208 {
209    int rc;
210    hid_data_t cookie;
211    hid_item_t item;
212 
213    int phys_stack[MAX_COLLECTION_NESTING];
214    int app_stack[MAX_COLLECTION_NESTING];
215    int logical_stack[MAX_COLLECTION_NESTING];
216    int phys_idx = -1, app_idx = -1, logical_idx = -1;
217 
218    cookie = hid_start_parse(rdesc, HID_KIND_ALL, -1);
219    if (!cookie) {
220       Dmsg(100, "Unable to start hid parser\n");
221       return 0;
222    }
223 
224    while ((rc = hid_get_item(cookie, &item)) > 0) {
225       if (item.kind == hid_collection) {
226          if (item.collection == HIDCOL_PHYSICAL)
227             PUSH_COLLECTION(phys, item.usage);
228          else if (item.collection == HIDCOL_LOGICAL)
229             PUSH_COLLECTION(logical, item.usage);
230          else if (item.collection == HIDCOL_APPLICATION)
231             PUSH_COLLECTION(app, item.usage);
232       }
233 
234       if (usage != -1 && (unsigned int)usage != item.usage)
235          goto next;
236       if (app != -1 && app != TOP_COLLECTION(app))
237          goto next;
238       if (phys != -1 && phys != TOP_COLLECTION(phys))
239          goto next;
240       if (logical != -1 && logical != TOP_COLLECTION(logical))
241          goto next;
242       if (kind != -1 && ((1 << item.kind) & kind) == 0)
243          goto next;
244 
245       if (outitem)
246          memcpy(outitem, &item, sizeof(item));
247 
248       hid_end_parse(cookie);
249       return 1;
250 
251     next:
252       if (item.kind == hid_endcollection) {
253          if (item.collection == HIDCOL_PHYSICAL)
254             POP_COLLECTION(phys);
255          else if (item.collection == HIDCOL_LOGICAL)
256             POP_COLLECTION(logical);
257          else if (item.collection == HIDCOL_APPLICATION)
258             POP_COLLECTION(app);
259       }
260    }
261 
262    hid_end_parse(cookie);
263    return 0;
264 }
265 
266 /*
267  * Fetch a report from a device given an fd for the device's control
268  * endpoint, the populated item structure describing the report, a
269  * data buffer in which to store the result, and the report length.
270  * Returns actual report length (in bytes) on success and -1 on failure.
271  */
hidu_get_report(int fd,hid_item_t * item,unsigned char * data,int len)272 int hidu_get_report(int fd, hid_item_t *item, unsigned char *data, int len)
273 {
274    int rc;
275    struct usb_ctl_request req;
276 
277    Dmsg(200, "get_report: id=0x%02x, kind=%d, length=%d pos=%d\n",
278       item->report_ID, item->kind, len, item->pos);
279 
280    req.ucr_flags = USBD_SHORT_XFER_OK;
281    req.ucr_actlen = 0;
282    req.ucr_addr = 0;
283    req.ucr_data = data;
284    req.ucr_request.bmRequestType = UT_READ_CLASS_INTERFACE;
285    req.ucr_request.bRequest = UR_GET_REPORT;
286    USETW(req.ucr_request.wValue, ((item->kind + 1) << 8) | item->report_ID);
287    USETW(req.ucr_request.wIndex, 0);
288    USETW(req.ucr_request.wLength, len);
289 
290    Dmsg(200, "get_report: wValue=0x%04x, wLength=%d\n",
291       UGETW(req.ucr_request.wValue), UGETW(req.ucr_request.wLength));
292 
293    rc = ioctl(fd, USB_DO_REQUEST, &req);
294    if (rc) {
295       Dmsg(100, "Error getting report: %s\n", strerror(errno));
296       return -1;
297    }
298 
299    hex_dump(300, data, req.ucr_actlen);
300 
301    return req.ucr_actlen;
302 }
303 
304 /*
305  * Send a report to the device given an fd for the device's control
306  * endpoint, the populated item structure, the data to send, and the
307  * report length. Returns true on success, false on failure.
308  */
hidu_set_report(int fd,hid_item_t * item,unsigned char * data,int len)309 int hidu_set_report(int fd, hid_item_t *item, unsigned char *data, int len)
310 {
311    int rc;
312    struct usb_ctl_request req;
313 
314    Dmsg(200, "set_report: id=0x%02x, kind=%d, length=%d pos=%d\n",
315       item->report_ID, item->kind, len, item->pos);
316    hex_dump(300, data, len);
317 
318    req.ucr_flags = 0;
319    req.ucr_actlen = 0;
320    req.ucr_addr = 0;
321    req.ucr_data = data;
322    req.ucr_request.bmRequestType = UT_WRITE_CLASS_INTERFACE;
323    req.ucr_request.bRequest = UR_SET_REPORT;
324    USETW(req.ucr_request.wValue, ((item->kind + 1) << 8) | item->report_ID);
325    USETW(req.ucr_request.wIndex, 0);
326    USETW(req.ucr_request.wLength, len);
327 
328    Dmsg(200, "set_report: wValue=0x%04x, wLength=%d\n",
329       UGETW(req.ucr_request.wValue), UGETW(req.ucr_request.wLength));
330 
331    rc = ioctl(fd, USB_DO_REQUEST, &req);
332    if (rc) {
333       Dmsg(100, "Error setting report: (%d) %s\n", errno, strerror(errno));
334       return 0;
335    }
336 
337    return 1;
338 }
339 
340 /*
341  * Fetch a string descriptor from the device given an fd for the
342  * device's control endpoint and the string index. Returns a pointer
343  * to a static buffer containing the NUL-terminated string or NULL
344  * on failure.
345  */
hidu_get_string(int fd,int index)346 const char *hidu_get_string(int fd, int index)
347 {
348    int rc, i;
349    struct usb_string_desc sd;
350    static char string[128];
351 
352    sd.usd_string_index = index;
353    sd.usd_language_id = 0;
354    rc = ioctl(fd, USB_GET_STRING_DESC, &sd);
355    if (rc) {
356       Dmsg(100, "Error fetching string descriptor: %s\n", strerror(errno));
357       return NULL;
358    }
359 
360    Dmsg(200, "Got string of length=%d\n", sd.usd_desc.bLength);
361 
362    /*
363     * Convert from wide chars to bytes...just assume it's ASCII.
364     * Length is in bytes although structure is arranged as words
365     * and there always seems to be a byte of garbage on the end.
366     * (Not sure if the garbage is an APC bug, a kernel bug, or a
367     * bug in my understanding.)
368     */
369    for (i = 0; i < sd.usd_desc.bLength / 2 - 1 && i < (int)sizeof(string) - 1; i++)
370       string[i] = UGETW(sd.usd_desc.bString[i]);
371 
372    string[i] = '\0';
373    return string;
374 }
375