xref: /netbsd-src/external/bsd/libfido2/dist/src/hid_hidapi.c (revision 8ecbf5f02b752fcb7debe1a8fab1dc82602bc760)
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