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