xref: /dragonfly/lib/libu4bhid/usage.c (revision e65bc1c3)
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/param.h>
30 #include <assert.h>
31 #include <ctype.h>
32 #include <err.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.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
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
71 hid_init(const char *hidname)
72 {
73 	FILE *f;
74 	char line[100], name[100], *p, *n;
75 	int no;
76 	int lineno;
77 	struct usage_page *curpage = NULL;
78 
79 	if (hidname == NULL)
80 		hidname = _PATH_HIDTABLE;
81 
82 	f = fopen(hidname, "r");
83 	if (f == NULL)
84 		err(1, "%s", hidname);
85 	for (lineno = 1; ; lineno++) {
86 		if (fgets(line, sizeof line, f) == NULL)
87 			break;
88 		if (line[0] == '#')
89 			continue;
90 		for (p = line; *p && isspace(*p); p++)
91 			;
92 		if (!*p)
93 			continue;
94 		if (sscanf(line, " * %[^\n]", name) == 1)
95 			no = -1;
96 		else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 &&
97 			 sscanf(line, " %d %[^\n]", &no, name) != 2)
98 			errx(1, "file %s, line %d, syntax error",
99 			     hidname, lineno);
100 		for (p = name; *p; p++)
101 			if (isspace(*p) || *p == '.')
102 				*p = '_';
103 		n = strdup(name);
104 		if (!n)
105 			err(1, "strdup");
106 		if (isspace(line[0])) {
107 			if (!curpage)
108 				errx(1, "file %s, line %d, syntax error",
109 				     hidname, lineno);
110 			if (curpage->pagesize >= curpage->pagesizemax) {
111 				curpage->pagesizemax += 10;
112 				curpage->page_contents =
113 					realloc(curpage->page_contents,
114 						curpage->pagesizemax *
115 						sizeof (struct usage_in_page));
116 				if (!curpage->page_contents)
117 					err(1, "realloc");
118 			}
119 			curpage->page_contents[curpage->pagesize].name = n;
120 			curpage->page_contents[curpage->pagesize].usage = no;
121 			curpage->pagesize++;
122 		} else {
123 			if (npages >= npagesmax) {
124 				if (pages == NULL) {
125 					npagesmax = 5;
126 					pages = malloc(npagesmax *
127 						  sizeof (struct usage_page));
128 				} else {
129 					npagesmax += 5;
130 					pages = realloc(pages,
131 						   npagesmax *
132 						   sizeof (struct usage_page));
133 				}
134 				if (!pages)
135 					err(1, "alloc");
136 			}
137 			curpage = &pages[npages++];
138 			curpage->name = n;
139 			curpage->usage = no;
140 			curpage->pagesize = 0;
141 			curpage->pagesizemax = 10;
142 			curpage->page_contents =
143 				malloc(curpage->pagesizemax *
144 				       sizeof (struct usage_in_page));
145 			if (!curpage->page_contents)
146 				err(1, "malloc");
147 		}
148 	}
149 	fclose(f);
150 #ifdef DEBUG
151 	dump_hid_table();
152 #endif
153 }
154 
155 const char *
156 hid_usage_page(int i)
157 {
158 	static char b[10];
159 	int k;
160 
161 	if (!pages)
162 		errx(1, "no hid table");
163 
164 	for (k = 0; k < npages; k++)
165 		if (pages[k].usage == i)
166 			return pages[k].name;
167 	sprintf(b, "0x%04x", i);
168 	return b;
169 }
170 
171 const char *
172 hid_usage_in_page(unsigned int u)
173 {
174 	int page = HID_PAGE(u);
175 	int i = HID_USAGE(u);
176 	static char b[100];
177 	int j, k, us;
178 
179 	for (k = 0; k < npages; k++)
180 		if (pages[k].usage == page)
181 			break;
182 	if (k >= npages)
183 		goto bad;
184 	for (j = 0; j < pages[k].pagesize; j++) {
185 		us = pages[k].page_contents[j].usage;
186 		if (us == -1) {
187 			sprintf(b,
188 			    fmtcheck(pages[k].page_contents[j].name, "%d"),
189 			    i);
190 			return b;
191 		}
192 		if (us == i)
193 			return pages[k].page_contents[j].name;
194 	}
195  bad:
196 	sprintf(b, "0x%04x", i);
197 	return b;
198 }
199 
200 int
201 hid_parse_usage_page(const char *name)
202 {
203 	int k;
204 
205 	if (!pages)
206 		errx(1, "no hid table");
207 
208 	for (k = 0; k < npages; k++)
209 		if (strcmp(pages[k].name, name) == 0)
210 			return pages[k].usage;
211 	return -1;
212 }
213 
214 /* XXX handle hex */
215 int
216 hid_parse_usage_in_page(const char *name)
217 {
218 	const char *sep;
219 	int k, j;
220 	unsigned int l;
221 
222 	sep = strchr(name, ':');
223 	if (sep == NULL)
224 		return -1;
225 	l = sep - name;
226 	for (k = 0; k < npages; k++)
227 		if (strncmp(pages[k].name, name, l) == 0)
228 			goto found;
229 	return -1;
230  found:
231 	sep++;
232 	for (j = 0; j < pages[k].pagesize; j++)
233 		if (strcmp(pages[k].page_contents[j].name, sep) == 0)
234 			return (pages[k].usage << 16) | pages[k].page_contents[j].usage;
235 	return (-1);
236 }
237