xref: /netbsd/lib/libusbhid/usage.c (revision c4a72b64)
1 /*	$NetBSD: usage.c,v 1.2 2002/07/20 08:36:23 grant Exp $	*/
2 
3 /*
4  * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <assert.h>
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 	sprintf(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 			sprintf(b,
187 			    fmtcheck(pages[k].page_contents[j].name, "%d"),
188 			    i);
189 			return b;
190 		}
191 		if (us == i)
192 			return pages[k].page_contents[j].name;
193 	}
194  bad:
195 	sprintf(b, "0x%04x", i);
196 	return b;
197 }
198 
199 int
200 hid_parse_usage_page(const char *name)
201 {
202 	int k;
203 
204 	if (!pages)
205 		errx(1, "no hid table");
206 
207 	for (k = 0; k < npages; k++)
208 		if (strcmp(pages[k].name, name) == 0)
209 			return pages[k].usage;
210 	return -1;
211 }
212 
213 /* XXX handle hex */
214 int
215 hid_parse_usage_in_page(const char *name)
216 {
217 	const char *sep;
218 	int k, j;
219 	unsigned int l;
220 
221 	_DIAGASSERT(name != NULL);
222 
223 	sep = strchr(name, ':');
224 	if (sep == NULL)
225 		return -1;
226 	l = sep - name;
227 	for (k = 0; k < npages; k++)
228 		if (strncmp(pages[k].name, name, l) == 0)
229 			goto found;
230 	return -1;
231  found:
232 	sep++;
233 	for (j = 0; j < pages[k].pagesize; j++)
234 		if (strcmp(pages[k].page_contents[j].name, sep) == 0)
235 			return (pages[k].usage << 16) | pages[k].page_contents[j].usage;
236 	return (-1);
237 }
238