xref: /openbsd-src/lib/libusbhid/usage.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: usage.c,v 1.4 2002/06/19 07:12:42 deraadt 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 
36 #include "usbhid.h"
37 
38 #define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages"
39 
40 struct usage_in_page {
41 	const char *name;
42 	int usage;
43 };
44 
45 static struct usage_page {
46 	const char *name;
47 	int usage;
48 	struct usage_in_page *page_contents;
49 	int pagesize, pagesizemax;
50 } *pages;
51 static int npages, npagesmax;
52 
53 #ifdef DEBUG
54 void
55 dump_hid_table(void)
56 {
57 	int i, j;
58 
59 	for (i = 0; i < npages; i++) {
60 		printf("%d\t%s\n", pages[i].usage, pages[i].name);
61 		for (j = 0; j < pages[i].pagesize; j++) {
62 			printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
63 			       pages[i].page_contents[j].name);
64 		}
65 	}
66 }
67 #endif
68 
69 void
70 hid_init(const char *hidname)
71 {
72 	FILE *f;
73 	char line[100], name[100], *p, *n;
74 	int no;
75 	int lineno;
76 	struct usage_page *curpage = 0;
77 
78 	if (hidname == 0)
79 		hidname = _PATH_HIDTABLE;
80 
81 	f = fopen(hidname, "r");
82 	if (f == NULL)
83 		err(1, "%s", hidname);
84 	for (lineno = 1; ; lineno++) {
85 		if (fgets(line, sizeof line, f) == NULL)
86 			break;
87 		if (line[0] == '#')
88 			continue;
89 		for (p = line; *p && isspace(*p); p++)
90 			;
91 		if (!*p)
92 			continue;
93 		if (sscanf(line, " * %[^\n]", name) == 1)
94 			no = -1;
95 		else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 &&
96 			 sscanf(line, " %d %[^\n]", &no, name) != 2)
97 			errx(1, "file %s, line %d, syntax error",
98 			     hidname, lineno);
99 		for (p = name; *p; p++)
100 			if (isspace(*p) || *p == '.')
101 				*p = '_';
102 		n = strdup(name);
103 		if (!n)
104 			err(1, "strdup");
105 		if (isspace(line[0])) {
106 			if (!curpage)
107 				errx(1, "file %s, line %d, syntax error",
108 				     hidname, lineno);
109 			if (curpage->pagesize >= curpage->pagesizemax) {
110 				curpage->pagesizemax += 10;
111 				curpage->page_contents =
112 					realloc(curpage->page_contents,
113 						curpage->pagesizemax *
114 						sizeof (struct usage_in_page));
115 				if (!curpage->page_contents)
116 					err(1, "realloc");
117 			}
118 			curpage->page_contents[curpage->pagesize].name = n;
119 			curpage->page_contents[curpage->pagesize].usage = no;
120 			curpage->pagesize++;
121 		} else {
122 			if (npages >= npagesmax) {
123 				if (pages == 0) {
124 					npagesmax = 5;
125 					pages = malloc(npagesmax *
126 						  sizeof (struct usage_page));
127 				} else {
128 					npagesmax += 5;
129 					pages = realloc(pages,
130 						   npagesmax *
131 						   sizeof (struct usage_page));
132 				}
133 				if (!pages)
134 					err(1, "alloc");
135 			}
136 			curpage = &pages[npages++];
137 			curpage->name = n;
138 			curpage->usage = no;
139 			curpage->pagesize = 0;
140 			curpage->pagesizemax = 10;
141 			curpage->page_contents =
142 				malloc(curpage->pagesizemax *
143 				       sizeof (struct usage_in_page));
144 			if (!curpage->page_contents)
145 				err(1, "malloc");
146 		}
147 	}
148 	fclose(f);
149 #ifdef DEBUG
150 	dump_hid_table();
151 #endif
152 }
153 
154 const char *
155 hid_usage_page(int i)
156 {
157 	static char b[10];
158 	int k;
159 
160 	if (!pages)
161 		errx(1, "no hid table");
162 
163 	for (k = 0; k < npages; k++)
164 		if (pages[k].usage == i)
165 			return pages[k].name;
166 	snprintf(b, sizeof b, "0x%04x", i);
167 	return b;
168 }
169 
170 const char *
171 hid_usage_in_page(unsigned int u)
172 {
173 	int page = HID_PAGE(u);
174 	int i = HID_USAGE(u);
175 	static char b[100];
176 	int j, k, us;
177 
178 	for (k = 0; k < npages; k++)
179 		if (pages[k].usage == page)
180 			break;
181 	if (k >= npages)
182 		goto bad;
183 	for (j = 0; j < pages[k].pagesize; j++) {
184 		us = pages[k].page_contents[j].usage;
185 		if (us == -1) {
186 			snprintf(b, sizeof b, "%s %d",
187 			    pages[k].page_contents[j].name, i);
188 			return b;
189 		}
190 		if (us == i)
191 			return pages[k].page_contents[j].name;
192 	}
193  bad:
194 	snprintf(b, sizeof b, "0x%04x", i);
195 	return b;
196 }
197 
198 int
199 hid_parse_usage_page(const char *name)
200 {
201 	int k;
202 
203 	if (!pages)
204 		errx(1, "no hid table");
205 
206 	for (k = 0; k < npages; k++)
207 		if (strcmp(pages[k].name, name) == 0)
208 			return pages[k].usage;
209 	return -1;
210 }
211 
212 /* XXX handle hex */
213 int
214 hid_parse_usage_in_page(const char *name)
215 {
216 	const char *sep;
217 	int k, j;
218 	unsigned int l;
219 
220 	sep = strchr(name, ':');
221 	if (sep == NULL)
222 		return -1;
223 	l = sep - name;
224 	for (k = 0; k < npages; k++)
225 		if (strncmp(pages[k].name, name, l) == 0)
226 			goto found;
227 	return -1;
228  found:
229 	sep++;
230 	for (j = 0; j < pages[k].pagesize; j++)
231 		if (strcmp(pages[k].page_contents[j].name, sep) == 0)
232 			return (pages[k].usage << 16) | pages[k].page_contents[j].usage;
233 	return (-1);
234 }
235