1 /* $OpenBSD: usage.c,v 1.17 2018/07/09 08:57:04 mpi Exp $ */
2 /* $NetBSD: usage.c,v 1.1 2001/12/28 17:45:27 augustss Exp $ */
3
4 /*
5 * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <ctype.h>
31 #include <err.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #include "usbhid.h"
38
39 #define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages"
40
41 struct usage_in_page {
42 const char *name;
43 int usage;
44 };
45
46 static struct usage_page {
47 const char *name;
48 int usage;
49 struct usage_in_page *page_contents;
50 int pagesize, pagesizemax;
51 } *pages;
52 static int npages, npagesmax;
53
54 #ifdef DEBUG
55 void
dump_hid_table(void)56 dump_hid_table(void)
57 {
58 int i, j;
59
60 for (i = 0; i < npages; i++) {
61 printf("%d\t%s\n", pages[i].usage, pages[i].name);
62 for (j = 0; j < pages[i].pagesize; j++) {
63 printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
64 pages[i].page_contents[j].name);
65 }
66 }
67 }
68 #endif
69
70 void
hid_init(const char * hidname)71 hid_init(const char *hidname)
72 {
73 if (hid_start(hidname) == -1)
74 errx(1, "hid_init: failed");
75 }
76
77 int
hid_start(const char * hidname)78 hid_start(const char *hidname)
79 {
80 char line[100], name[100], *p, *n;
81 struct usage_page *curpage = NULL;
82 int lineno, no;
83 FILE *f;
84
85 if (hidname == NULL)
86 hidname = _PATH_HIDTABLE;
87
88 f = fopen(hidname, "r");
89 if (f == NULL)
90 return -1;
91 for (lineno = 1; ; lineno++) {
92 if (fgets(line, sizeof line, f) == NULL)
93 break;
94 if (line[0] == '#')
95 continue;
96 for (p = line; isspace((unsigned char)*p); p++)
97 ;
98 if (!*p)
99 continue;
100 if (sscanf(line, " * %99[^\n]", name) == 1)
101 no = -1;
102 else if (sscanf(line, " 0x%x %99[^\n]", &no, name) != 2 &&
103 sscanf(line, " %d %99[^\n]", &no, name) != 2) {
104 warnx("file %s, line %d, syntax error",
105 hidname, lineno);
106 errno = EINVAL;
107 goto fail;
108 }
109 for (p = name; *p; p++)
110 if (isspace((unsigned char)*p) || *p == '.')
111 *p = '_';
112 n = strdup(name);
113 if (!n)
114 goto fail;
115
116 if (isspace((unsigned char)line[0])) {
117 if (!curpage) {
118 warnx("file %s, line %d, syntax error",
119 hidname, lineno);
120 free(n);
121 errno = EINVAL;
122 goto fail;
123 }
124 if (curpage->pagesize >= curpage->pagesizemax) {
125 void *new;
126 int len;
127
128 len = curpage->pagesizemax + 10;
129 new = reallocarray(curpage->page_contents,
130 len, sizeof(struct usage_in_page));
131 if (!new) {
132 free(curpage->page_contents);
133 curpage->page_contents = NULL;
134 free(n);
135 goto fail;
136 }
137 curpage->pagesizemax = len;
138 curpage->page_contents = new;
139 }
140 curpage->page_contents[curpage->pagesize].name = n;
141 curpage->page_contents[curpage->pagesize].usage = no;
142 curpage->pagesize++;
143 } else {
144 if (npages >= npagesmax) {
145 int len;
146 void *new;
147
148 if (pages == NULL) {
149 len = 5;
150 pages = calloc(len,
151 sizeof (struct usage_page));
152 } else {
153 len = npagesmax * 5;
154 new = reallocarray(pages,
155 len, sizeof(struct usage_page));
156 if (!new) {
157 free(n);
158 goto fail;
159 }
160 pages = new;
161 bzero(pages + npagesmax,
162 (len - npagesmax) *
163 sizeof(struct usage_page));
164 }
165 if (!pages) {
166 free(n);
167 goto fail;
168 }
169 npagesmax = len;
170 }
171 curpage = &pages[npages++];
172 curpage->name = n;
173 curpage->usage = no;
174 curpage->pagesize = 0;
175 curpage->pagesizemax = 10;
176 curpage->page_contents = calloc(curpage->pagesizemax,
177 sizeof (struct usage_in_page));
178 if (!curpage->page_contents)
179 goto fail;
180 }
181 }
182 fclose(f);
183 #ifdef DEBUG
184 dump_hid_table();
185 #endif
186 return 0;
187
188 fail:
189 if (f)
190 fclose(f);
191 if (pages) {
192 for (no = 0; no < npages; no++) {
193 if (pages[no].name)
194 free((char *)pages[no].name);
195 if (pages[no].page_contents)
196 free((char *)pages[no].page_contents);
197 }
198 free(pages);
199 pages = NULL;
200 }
201 npages = 0;
202 npagesmax = 0;
203 return -1;
204 }
205
206 const char *
hid_usage_page(int i)207 hid_usage_page(int i)
208 {
209 static char b[10];
210 int k;
211
212 if (!pages)
213 return NULL;
214
215 for (k = 0; k < npages; k++)
216 if (pages[k].usage == i)
217 return pages[k].name;
218 snprintf(b, sizeof b, "0x%04x", i);
219 return b;
220 }
221
222 const char *
hid_usage_in_page(unsigned int u)223 hid_usage_in_page(unsigned int u)
224 {
225 int i = HID_USAGE(u), j, k, us;
226 int page = HID_PAGE(u);
227 static char b[100];
228
229 for (k = 0; k < npages; k++)
230 if (pages[k].usage == page)
231 break;
232 if (k >= npages)
233 goto bad;
234 for (j = 0; j < pages[k].pagesize; j++) {
235 us = pages[k].page_contents[j].usage;
236 if (us == -1) {
237 snprintf(b, sizeof b,
238 pages[k].page_contents[j].name, i);
239 return b;
240 }
241 if (us == i)
242 return pages[k].page_contents[j].name;
243 }
244 bad:
245 snprintf(b, sizeof b, "0x%04x", i);
246 return b;
247 }
248
249 int
hid_parse_usage_page(const char * name)250 hid_parse_usage_page(const char *name)
251 {
252 int k;
253
254 if (!pages)
255 return 0;
256
257 for (k = 0; k < npages; k++)
258 if (strcmp(pages[k].name, name) == 0)
259 return pages[k].usage;
260 return -1;
261 }
262
263 /* XXX handle hex */
264 int
hid_parse_usage_in_page(const char * name)265 hid_parse_usage_in_page(const char *name)
266 {
267 const char *sep, *fmtsep, *errstr, *fmtname;
268 unsigned int l;
269 int k, j, us, pu, len;
270
271 sep = strchr(name, ':');
272 if (sep == NULL)
273 return -1;
274 l = sep - name;
275 for (k = 0; k < npages; k++)
276 if (strncmp(pages[k].name, name, l) == 0)
277 goto found;
278 return -1;
279 found:
280 sep++;
281 for (j = 0; j < pages[k].pagesize; j++) {
282 us = pages[k].page_contents[j].usage;
283 if (us == -1) {
284 fmtname = pages[k].page_contents[j].name;
285 fmtsep = strchr(fmtname, '%');
286 len = fmtsep - fmtname;
287 if (fmtsep != NULL && strncmp(sep, fmtname, len) == 0) {
288 pu = strtonum(sep + len, 0x1, 0xFFFF, &errstr);
289 if (errstr == NULL)
290 return (pages[k].usage << 16) | pu;
291 }
292 }
293 if (strcmp(pages[k].page_contents[j].name, sep) == 0)
294 return (pages[k].usage << 16) |
295 pages[k].page_contents[j].usage;
296 }
297 return -1;
298 }
299