2 * Copyright (c) 2019 Google LLC. All rights reserved.
3 * Use of this source code is governed by a BSD-style
4 * license that can be found in the LICENSE file.
9 #include <linux/hidraw.h>
10 #include <linux/input.h>
23 size_t report_out_len;
27 fido_wcslen(const wchar_t *wcs)
30 while (*wcs++ != L'\0')
36 wcs_to_cs(const wchar_t *wcs)
41 if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL)
44 for (i = 0; i < fido_wcslen(wcs); i++) {
46 /* give up on parsing non-ASCII text */
48 return strdup("hidapi device");
57 copy_info(fido_dev_info_t *di, const struct hid_device_info *d)
59 memset(di, 0, sizeof(*di));
62 di->path = strdup(d->path);
64 di->path = strdup("");
66 if (d->manufacturer_string != NULL)
67 di->manufacturer = wcs_to_cs(d->manufacturer_string);
69 di->manufacturer = strdup("");
71 if (d->product_string != NULL)
72 di->product = wcs_to_cs(d->product_string);
74 di->product = strdup("");
76 if (di->path == NULL ||
77 di->manufacturer == NULL ||
78 di->product == NULL) {
80 free(di->manufacturer);
82 explicit_bzero(di, sizeof(*di));
86 di->product_id = (int16_t)d->product_id;
87 di->vendor_id = (int16_t)d->vendor_id;
88 di->io = (fido_dev_io_t) {
100 get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd)
106 if ((fd = fido_hid_unix_open(path)) == -1) {
107 fido_log_debug("%s: fido_hid_unix_open", __func__);
111 if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESCSIZE), &s) < 0 || s < 0 ||
112 (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
113 fido_log_error(errno, "%s: ioctl HIDIOCGRDESCSIZE", __func__);
117 hrd->size = (unsigned)s;
119 if (ioctl(fd, IOCTL_REQ(HIDIOCGRDESC), hrd) < 0) {
120 fido_log_error(errno, "%s: ioctl HIDIOCGRDESC", __func__);
133 is_fido(const struct hid_device_info *hdi)
135 uint32_t usage_page = 0;
136 struct hidraw_report_descriptor hrd;
138 memset(&hrd, 0, sizeof(hrd));
140 if (get_report_descriptor(hdi->path, &hrd) < 0 ||
141 fido_hid_get_usage(hrd.value, hrd.size, &usage_page) < 0) {
145 return usage_page == 0xf1d0;
147 #elif defined(_WIN32) || defined(__APPLE__)
149 is_fido(const struct hid_device_info *hdi)
151 return hdi->usage_page == 0xf1d0;
155 is_fido(const struct hid_device_info *hdi)
158 fido_log_debug("%s: assuming FIDO HID", __func__);
164 fido_hid_open(const char *path)
166 struct hid_hidapi *ctx;
168 if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
172 if ((ctx->handle = hid_open_path(path)) == NULL) {
177 ctx->report_in_len = ctx->report_out_len = CTAP_MAX_REPORT_LEN;
183 fido_hid_close(void *handle)
185 struct hid_hidapi *ctx = handle;
187 hid_close(ctx->handle);
192 fido_hid_set_sigmask(void *handle, const fido_sigset_t *sigmask)
197 return (FIDO_ERR_INTERNAL);
201 fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
203 struct hid_hidapi *ctx = handle;
205 if (len != ctx->report_in_len) {
206 fido_log_debug("%s: len %zu", __func__, len);
210 return hid_read_timeout(ctx->handle, buf, len, ms);
214 fido_hid_write(void *handle, const unsigned char *buf, size_t len)
216 struct hid_hidapi *ctx = handle;
218 if (len != ctx->report_out_len + 1) {
219 fido_log_debug("%s: len %zu", __func__, len);
223 return hid_write(ctx->handle, buf, len);
227 fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
229 struct hid_device_info *hdi;
234 return FIDO_OK; /* nothing to do */
236 return FIDO_ERR_INVALID_ARGUMENT;
237 if ((hdi = hid_enumerate(0, 0)) == NULL)
238 return FIDO_OK; /* nothing to do */
240 for (struct hid_device_info *d = hdi; d != NULL; d = d->next) {
241 if (is_fido(d) == false)
243 if (copy_info(&devlist[*olen], d) == 0) {
244 if (++(*olen) == ilen)
249 hid_free_enumeration(hdi);
255 fido_hid_report_in_len(void *handle)
257 struct hid_hidapi *ctx = handle;
259 return (ctx->report_in_len);
263 fido_hid_report_out_len(void *handle)
265 struct hid_hidapi *ctx = handle;
267 return (ctx->report_out_len);