1 /* 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. 5 */ 6 7 #include <hidapi/hidapi.h> 8 9 #include <stdlib.h> 10 #include <string.h> 11 #include <wchar.h> 12 13 #include "fido.h" 14 15 static size_t 16 fido_wcslen(const wchar_t *wcs) 17 { 18 size_t l = 0; 19 while (*wcs++ != L'\0') 20 l++; 21 return l; 22 } 23 24 static char * 25 wcs_to_cs(const wchar_t *wcs) 26 { 27 char *cs; 28 size_t i; 29 30 if (wcs == NULL || (cs = calloc(fido_wcslen(wcs) + 1, 1)) == NULL) 31 return NULL; 32 33 for (i = 0; i < fido_wcslen(wcs); i++) { 34 if (wcs[i] >= 128) { 35 /* give up on parsing non-ASCII text */ 36 free(cs); 37 return strdup("hidapi device"); 38 } 39 cs[i] = (char)wcs[i]; 40 } 41 42 return cs; 43 } 44 45 static int 46 copy_info(fido_dev_info_t *di, const struct hid_device_info *d) 47 { 48 memset(di, 0, sizeof(*di)); 49 50 if (d->path != NULL) 51 di->path = strdup(d->path); 52 else 53 di->path = strdup(""); 54 55 if (d->manufacturer_string != NULL) 56 di->manufacturer = wcs_to_cs(d->manufacturer_string); 57 else 58 di->manufacturer = strdup(""); 59 60 if (d->product_string != NULL) 61 di->product = wcs_to_cs(d->product_string); 62 else 63 di->product = strdup(""); 64 65 if (di->path == NULL || 66 di->manufacturer == NULL || 67 di->product == NULL) { 68 free(di->path); 69 free(di->manufacturer); 70 free(di->product); 71 return -1; 72 } 73 74 di->product_id = d->product_id; 75 di->vendor_id = d->vendor_id; 76 di->io = (fido_dev_io_t) { 77 &fido_hid_open, 78 &fido_hid_close, 79 &fido_hid_read, 80 &fido_hid_write, 81 }; 82 83 return 0; 84 } 85 86 void * 87 fido_hid_open(const char *path) 88 { 89 return hid_open_path(path); 90 } 91 92 void 93 fido_hid_close(void *hid_dev_handle) 94 { 95 hid_close(hid_dev_handle); 96 } 97 98 int 99 fido_hid_read(void *hid_dev_handle, unsigned char *buf, size_t len, int ms) 100 { 101 return hid_read_timeout(hid_dev_handle, buf, len, ms); 102 } 103 104 int 105 fido_hid_write(void *hid_dev_handle, const unsigned char *buf, size_t len) 106 { 107 return hid_write(hid_dev_handle, buf, len); 108 } 109 110 int 111 fido_hid_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen) 112 { 113 struct hid_device_info *hdi; 114 115 *olen = 0; 116 117 if (ilen == 0) 118 return FIDO_OK; /* nothing to do */ 119 if (devlist == NULL) 120 return FIDO_ERR_INVALID_ARGUMENT; 121 if ((hdi = hid_enumerate(0, 0)) == NULL) 122 return FIDO_OK; /* nothing to do */ 123 124 for (struct hid_device_info *d = hdi; d != NULL; d = d->next) { 125 #if defined(_WIN32) || defined(__APPLE__) 126 if (d->usage_page != 0xf1d0) 127 continue; 128 #endif 129 if (copy_info(&devlist[*olen], d) == 0) { 130 if (++(*olen) == ilen) 131 break; 132 } 133 } 134 135 hid_free_enumeration(hdi); 136 137 return FIDO_OK; 138 } 139