xref: /openbsd/lib/libusbhid/usage.c (revision 88a81472)
1*88a81472Smatthieu /*	$OpenBSD: usage.c,v 1.5 2003/12/20 18:33:41 matthieu Exp $	*/
27517eab2Snate /*	$NetBSD: usage.c,v 1.1 2001/12/28 17:45:27 augustss Exp $	*/
3be8f1931Spvalchev 
4be8f1931Spvalchev /*
5be8f1931Spvalchev  * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
6be8f1931Spvalchev  * All rights reserved.
7be8f1931Spvalchev  *
8be8f1931Spvalchev  * Redistribution and use in source and binary forms, with or without
9be8f1931Spvalchev  * modification, are permitted provided that the following conditions
10be8f1931Spvalchev  * are met:
11be8f1931Spvalchev  * 1. Redistributions of source code must retain the above copyright
12be8f1931Spvalchev  *    notice, this list of conditions and the following disclaimer.
13be8f1931Spvalchev  * 2. Redistributions in binary form must reproduce the above copyright
14be8f1931Spvalchev  *    notice, this list of conditions and the following disclaimer in the
15be8f1931Spvalchev  *    documentation and/or other materials provided with the distribution.
16be8f1931Spvalchev  *
17be8f1931Spvalchev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18be8f1931Spvalchev  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19be8f1931Spvalchev  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20be8f1931Spvalchev  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21be8f1931Spvalchev  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22be8f1931Spvalchev  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23be8f1931Spvalchev  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24be8f1931Spvalchev  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25be8f1931Spvalchev  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26be8f1931Spvalchev  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27be8f1931Spvalchev  * SUCH DAMAGE.
28be8f1931Spvalchev  */
29be8f1931Spvalchev 
30be8f1931Spvalchev #include <ctype.h>
31be8f1931Spvalchev #include <err.h>
32be8f1931Spvalchev #include <stdio.h>
33be8f1931Spvalchev #include <stdlib.h>
34be8f1931Spvalchev #include <string.h>
35be8f1931Spvalchev 
36be8f1931Spvalchev #include "usbhid.h"
37be8f1931Spvalchev 
38be8f1931Spvalchev #define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages"
39be8f1931Spvalchev 
40be8f1931Spvalchev struct usage_in_page {
41be8f1931Spvalchev 	const char *name;
42be8f1931Spvalchev 	int usage;
43be8f1931Spvalchev };
44be8f1931Spvalchev 
45be8f1931Spvalchev static struct usage_page {
46be8f1931Spvalchev 	const char *name;
47be8f1931Spvalchev 	int usage;
48be8f1931Spvalchev 	struct usage_in_page *page_contents;
49be8f1931Spvalchev 	int pagesize, pagesizemax;
50be8f1931Spvalchev } *pages;
51be8f1931Spvalchev static int npages, npagesmax;
52be8f1931Spvalchev 
53be8f1931Spvalchev #ifdef DEBUG
54be8f1931Spvalchev void
55be8f1931Spvalchev dump_hid_table(void)
56be8f1931Spvalchev {
57be8f1931Spvalchev 	int i, j;
58be8f1931Spvalchev 
59be8f1931Spvalchev 	for (i = 0; i < npages; i++) {
60be8f1931Spvalchev 		printf("%d\t%s\n", pages[i].usage, pages[i].name);
61be8f1931Spvalchev 		for (j = 0; j < pages[i].pagesize; j++) {
62be8f1931Spvalchev 			printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
63be8f1931Spvalchev 			       pages[i].page_contents[j].name);
64be8f1931Spvalchev 		}
65be8f1931Spvalchev 	}
66be8f1931Spvalchev }
67be8f1931Spvalchev #endif
68be8f1931Spvalchev 
69be8f1931Spvalchev void
70be8f1931Spvalchev hid_init(const char *hidname)
71be8f1931Spvalchev {
72be8f1931Spvalchev 	FILE *f;
73be8f1931Spvalchev 	char line[100], name[100], *p, *n;
74be8f1931Spvalchev 	int no;
75be8f1931Spvalchev 	int lineno;
76be8f1931Spvalchev 	struct usage_page *curpage = 0;
77be8f1931Spvalchev 
78be8f1931Spvalchev 	if (hidname == 0)
79be8f1931Spvalchev 		hidname = _PATH_HIDTABLE;
80be8f1931Spvalchev 
81be8f1931Spvalchev 	f = fopen(hidname, "r");
82be8f1931Spvalchev 	if (f == NULL)
83be8f1931Spvalchev 		err(1, "%s", hidname);
84be8f1931Spvalchev 	for (lineno = 1; ; lineno++) {
85be8f1931Spvalchev 		if (fgets(line, sizeof line, f) == NULL)
86be8f1931Spvalchev 			break;
87be8f1931Spvalchev 		if (line[0] == '#')
88be8f1931Spvalchev 			continue;
89be8f1931Spvalchev 		for (p = line; *p && isspace(*p); p++)
90be8f1931Spvalchev 			;
91be8f1931Spvalchev 		if (!*p)
92be8f1931Spvalchev 			continue;
93*88a81472Smatthieu 		if (sscanf(line, " * %99[^\n]", name) == 1)
94be8f1931Spvalchev 			no = -1;
95*88a81472Smatthieu 		else if (sscanf(line, " 0x%x %99[^\n]", &no, name) != 2 &&
96*88a81472Smatthieu 			 sscanf(line, " %d %99[^\n]", &no, name) != 2)
970072e412Sjsyn 			errx(1, "file %s, line %d, syntax error",
98be8f1931Spvalchev 			     hidname, lineno);
99be8f1931Spvalchev 		for (p = name; *p; p++)
100be8f1931Spvalchev 			if (isspace(*p) || *p == '.')
101be8f1931Spvalchev 				*p = '_';
102be8f1931Spvalchev 		n = strdup(name);
103be8f1931Spvalchev 		if (!n)
104be8f1931Spvalchev 			err(1, "strdup");
105be8f1931Spvalchev 		if (isspace(line[0])) {
106be8f1931Spvalchev 			if (!curpage)
1070072e412Sjsyn 				errx(1, "file %s, line %d, syntax error",
108be8f1931Spvalchev 				     hidname, lineno);
109be8f1931Spvalchev 			if (curpage->pagesize >= curpage->pagesizemax) {
110be8f1931Spvalchev 				curpage->pagesizemax += 10;
111be8f1931Spvalchev 				curpage->page_contents =
112be8f1931Spvalchev 					realloc(curpage->page_contents,
113be8f1931Spvalchev 						curpage->pagesizemax *
114be8f1931Spvalchev 						sizeof (struct usage_in_page));
115be8f1931Spvalchev 				if (!curpage->page_contents)
116be8f1931Spvalchev 					err(1, "realloc");
117be8f1931Spvalchev 			}
118be8f1931Spvalchev 			curpage->page_contents[curpage->pagesize].name = n;
119be8f1931Spvalchev 			curpage->page_contents[curpage->pagesize].usage = no;
120be8f1931Spvalchev 			curpage->pagesize++;
121be8f1931Spvalchev 		} else {
122be8f1931Spvalchev 			if (npages >= npagesmax) {
123be8f1931Spvalchev 				if (pages == 0) {
124be8f1931Spvalchev 					npagesmax = 5;
125be8f1931Spvalchev 					pages = malloc(npagesmax *
126be8f1931Spvalchev 						  sizeof (struct usage_page));
127be8f1931Spvalchev 				} else {
128be8f1931Spvalchev 					npagesmax += 5;
129be8f1931Spvalchev 					pages = realloc(pages,
130be8f1931Spvalchev 						   npagesmax *
131be8f1931Spvalchev 						   sizeof (struct usage_page));
132be8f1931Spvalchev 				}
133be8f1931Spvalchev 				if (!pages)
134be8f1931Spvalchev 					err(1, "alloc");
135be8f1931Spvalchev 			}
136be8f1931Spvalchev 			curpage = &pages[npages++];
137be8f1931Spvalchev 			curpage->name = n;
138be8f1931Spvalchev 			curpage->usage = no;
139be8f1931Spvalchev 			curpage->pagesize = 0;
140be8f1931Spvalchev 			curpage->pagesizemax = 10;
141be8f1931Spvalchev 			curpage->page_contents =
142be8f1931Spvalchev 				malloc(curpage->pagesizemax *
143be8f1931Spvalchev 				       sizeof (struct usage_in_page));
144be8f1931Spvalchev 			if (!curpage->page_contents)
145be8f1931Spvalchev 				err(1, "malloc");
146be8f1931Spvalchev 		}
147be8f1931Spvalchev 	}
148be8f1931Spvalchev 	fclose(f);
149be8f1931Spvalchev #ifdef DEBUG
150be8f1931Spvalchev 	dump_hid_table();
151be8f1931Spvalchev #endif
152be8f1931Spvalchev }
153be8f1931Spvalchev 
154be8f1931Spvalchev const char *
155be8f1931Spvalchev hid_usage_page(int i)
156be8f1931Spvalchev {
157be8f1931Spvalchev 	static char b[10];
158be8f1931Spvalchev 	int k;
159be8f1931Spvalchev 
160be8f1931Spvalchev 	if (!pages)
1610072e412Sjsyn 		errx(1, "no hid table");
162be8f1931Spvalchev 
163be8f1931Spvalchev 	for (k = 0; k < npages; k++)
164be8f1931Spvalchev 		if (pages[k].usage == i)
165be8f1931Spvalchev 			return pages[k].name;
166d4d01661Sderaadt 	snprintf(b, sizeof b, "0x%04x", i);
167be8f1931Spvalchev 	return b;
168be8f1931Spvalchev }
169be8f1931Spvalchev 
170be8f1931Spvalchev const char *
171be8f1931Spvalchev hid_usage_in_page(unsigned int u)
172be8f1931Spvalchev {
173be8f1931Spvalchev 	int page = HID_PAGE(u);
174be8f1931Spvalchev 	int i = HID_USAGE(u);
175be8f1931Spvalchev 	static char b[100];
176be8f1931Spvalchev 	int j, k, us;
177be8f1931Spvalchev 
178be8f1931Spvalchev 	for (k = 0; k < npages; k++)
179be8f1931Spvalchev 		if (pages[k].usage == page)
180be8f1931Spvalchev 			break;
181be8f1931Spvalchev 	if (k >= npages)
182be8f1931Spvalchev 		goto bad;
183be8f1931Spvalchev 	for (j = 0; j < pages[k].pagesize; j++) {
184be8f1931Spvalchev 		us = pages[k].page_contents[j].usage;
185be8f1931Spvalchev 		if (us == -1) {
186be8f1931Spvalchev 			snprintf(b, sizeof b, "%s %d",
187be8f1931Spvalchev 			    pages[k].page_contents[j].name, i);
188be8f1931Spvalchev 			return b;
189be8f1931Spvalchev 		}
190be8f1931Spvalchev 		if (us == i)
191be8f1931Spvalchev 			return pages[k].page_contents[j].name;
192be8f1931Spvalchev 	}
193be8f1931Spvalchev  bad:
194d4d01661Sderaadt 	snprintf(b, sizeof b, "0x%04x", i);
195be8f1931Spvalchev 	return b;
196be8f1931Spvalchev }
197be8f1931Spvalchev 
198be8f1931Spvalchev int
199be8f1931Spvalchev hid_parse_usage_page(const char *name)
200be8f1931Spvalchev {
201be8f1931Spvalchev 	int k;
202be8f1931Spvalchev 
203be8f1931Spvalchev 	if (!pages)
2040072e412Sjsyn 		errx(1, "no hid table");
205be8f1931Spvalchev 
206be8f1931Spvalchev 	for (k = 0; k < npages; k++)
207be8f1931Spvalchev 		if (strcmp(pages[k].name, name) == 0)
208be8f1931Spvalchev 			return pages[k].usage;
209be8f1931Spvalchev 	return -1;
210be8f1931Spvalchev }
211be8f1931Spvalchev 
212be8f1931Spvalchev /* XXX handle hex */
213be8f1931Spvalchev int
214be8f1931Spvalchev hid_parse_usage_in_page(const char *name)
215be8f1931Spvalchev {
2167517eab2Snate 	const char *sep;
217be8f1931Spvalchev 	int k, j;
218be8f1931Spvalchev 	unsigned int l;
219be8f1931Spvalchev 
2207517eab2Snate 	sep = strchr(name, ':');
221be8f1931Spvalchev 	if (sep == NULL)
222be8f1931Spvalchev 		return -1;
223be8f1931Spvalchev 	l = sep - name;
224be8f1931Spvalchev 	for (k = 0; k < npages; k++)
225be8f1931Spvalchev 		if (strncmp(pages[k].name, name, l) == 0)
226be8f1931Spvalchev 			goto found;
227be8f1931Spvalchev 	return -1;
228be8f1931Spvalchev  found:
229be8f1931Spvalchev 	sep++;
230be8f1931Spvalchev 	for (j = 0; j < pages[k].pagesize; j++)
231be8f1931Spvalchev 		if (strcmp(pages[k].page_contents[j].name, sep) == 0)
232be8f1931Spvalchev 			return (pages[k].usage << 16) | pages[k].page_contents[j].usage;
233be8f1931Spvalchev 	return (-1);
234be8f1931Spvalchev }
235