xref: /netbsd-src/lib/libusbhid/usage.c (revision cce5ae2abda7c62ef1d560c63cf461a6efa87e88)
1*cce5ae2aSnia /*	$NetBSD: usage.c,v 1.12 2021/11/03 16:18:09 nia Exp $	*/
28ac1932eSaugustss 
38ac1932eSaugustss /*
499410184Ssalo  * Copyright (c) 1999 Lennart Augustsson <augustss@NetBSD.org>
58ac1932eSaugustss  * All rights reserved.
68ac1932eSaugustss  *
78ac1932eSaugustss  * Redistribution and use in source and binary forms, with or without
88ac1932eSaugustss  * modification, are permitted provided that the following conditions
98ac1932eSaugustss  * are met:
108ac1932eSaugustss  * 1. Redistributions of source code must retain the above copyright
118ac1932eSaugustss  *    notice, this list of conditions and the following disclaimer.
128ac1932eSaugustss  * 2. Redistributions in binary form must reproduce the above copyright
138ac1932eSaugustss  *    notice, this list of conditions and the following disclaimer in the
148ac1932eSaugustss  *    documentation and/or other materials provided with the distribution.
158ac1932eSaugustss  *
168ac1932eSaugustss  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
178ac1932eSaugustss  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
188ac1932eSaugustss  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
198ac1932eSaugustss  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
208ac1932eSaugustss  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
218ac1932eSaugustss  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
228ac1932eSaugustss  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
238ac1932eSaugustss  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
248ac1932eSaugustss  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
258ac1932eSaugustss  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
268ac1932eSaugustss  * SUCH DAMAGE.
278ac1932eSaugustss  */
288ac1932eSaugustss 
29e2d78706Slukem #include <sys/cdefs.h>
30*cce5ae2aSnia __RCSID("$NetBSD: usage.c,v 1.12 2021/11/03 16:18:09 nia Exp $");
31e2d78706Slukem 
328ac1932eSaugustss #include <assert.h>
338ac1932eSaugustss #include <ctype.h>
348ac1932eSaugustss #include <err.h>
358ac1932eSaugustss #include <stdio.h>
368ac1932eSaugustss #include <stdlib.h>
378ac1932eSaugustss #include <string.h>
388ac1932eSaugustss 
398ac1932eSaugustss #include "usbhid.h"
408ac1932eSaugustss 
418ac1932eSaugustss #define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages"
428ac1932eSaugustss 
438ac1932eSaugustss struct usage_in_page {
448ac1932eSaugustss 	const char *name;
458ac1932eSaugustss 	int usage;
468ac1932eSaugustss };
478ac1932eSaugustss 
488ac1932eSaugustss static struct usage_page {
498ac1932eSaugustss 	const char *name;
508ac1932eSaugustss 	int usage;
518ac1932eSaugustss 	struct usage_in_page *page_contents;
528ac1932eSaugustss 	int pagesize, pagesizemax;
538ac1932eSaugustss } *pages;
548ac1932eSaugustss static int npages, npagesmax;
558ac1932eSaugustss 
568ac1932eSaugustss #ifdef DEBUG
57ac579202Schristos static void dump_hid_table(void);
58ac579202Schristos static void
dump_hid_table(void)598ac1932eSaugustss dump_hid_table(void)
608ac1932eSaugustss {
618ac1932eSaugustss 	int i, j;
628ac1932eSaugustss 
638ac1932eSaugustss 	for (i = 0; i < npages; i++) {
648ac1932eSaugustss 		printf("%d\t%s\n", pages[i].usage, pages[i].name);
658ac1932eSaugustss 		for (j = 0; j < pages[i].pagesize; j++) {
668ac1932eSaugustss 			printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
678ac1932eSaugustss 			       pages[i].page_contents[j].name);
688ac1932eSaugustss 		}
698ac1932eSaugustss 	}
708ac1932eSaugustss }
718ac1932eSaugustss #endif
728ac1932eSaugustss 
738ac1932eSaugustss void
hid_init(const char * hidname)748ac1932eSaugustss hid_init(const char *hidname)
758ac1932eSaugustss {
768ac1932eSaugustss 	FILE *f;
778ac1932eSaugustss 	char line[100], name[100], *p, *n;
788ac1932eSaugustss 	int no;
798ac1932eSaugustss 	int lineno;
808ac1932eSaugustss 	struct usage_page *curpage = 0;
818ac1932eSaugustss 
828ac1932eSaugustss 	if (hidname == 0)
838ac1932eSaugustss 		hidname = _PATH_HIDTABLE;
848ac1932eSaugustss 
858ac1932eSaugustss 	f = fopen(hidname, "r");
868ac1932eSaugustss 	if (f == NULL)
878ac1932eSaugustss 		err(1, "%s", hidname);
888ac1932eSaugustss 	for (lineno = 1; ; lineno++) {
8910deb451Schristos 		if (fgets(line, (int)sizeof(line), f) == NULL)
908ac1932eSaugustss 			break;
918ac1932eSaugustss 		if (line[0] == '#')
928ac1932eSaugustss 			continue;
931793b7ddSdsl 		for (p = line; *p && isspace((unsigned char)*p); p++)
948ac1932eSaugustss 			;
958ac1932eSaugustss 		if (!*p)
968ac1932eSaugustss 			continue;
978ac1932eSaugustss 		if (sscanf(line, " * %[^\n]", name) == 1)
988ac1932eSaugustss 			no = -1;
998ac1932eSaugustss 		else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 &&
1008ac1932eSaugustss 			 sscanf(line, " %d %[^\n]", &no, name) != 2)
1016742cb18Sgrant 			errx(1, "file %s, line %d, syntax error",
1028ac1932eSaugustss 			     hidname, lineno);
1038ac1932eSaugustss 		for (p = name; *p; p++)
1041793b7ddSdsl 			if (isspace((unsigned char)*p) || *p == '.')
1058ac1932eSaugustss 				*p = '_';
1068ac1932eSaugustss 		n = strdup(name);
1078ac1932eSaugustss 		if (!n)
1088ac1932eSaugustss 			err(1, "strdup");
1091793b7ddSdsl 		if (isspace((unsigned char)line[0])) {
1108ac1932eSaugustss 			if (!curpage)
1116742cb18Sgrant 				errx(1, "file %s, line %d, syntax error",
1128ac1932eSaugustss 				     hidname, lineno);
1138ac1932eSaugustss 			if (curpage->pagesize >= curpage->pagesizemax) {
1148ac1932eSaugustss 				curpage->pagesizemax += 10;
115*cce5ae2aSnia 				if (reallocarr(&curpage->page_contents,
116*cce5ae2aSnia 						curpage->pagesizemax,
117*cce5ae2aSnia 						sizeof (struct usage_in_page)) != 0)
1188ac1932eSaugustss 					err(1, "realloc");
1198ac1932eSaugustss 			}
1208ac1932eSaugustss 			curpage->page_contents[curpage->pagesize].name = n;
1218ac1932eSaugustss 			curpage->page_contents[curpage->pagesize].usage = no;
1228ac1932eSaugustss 			curpage->pagesize++;
1238ac1932eSaugustss 		} else {
1248ac1932eSaugustss 			if (npages >= npagesmax) {
125*cce5ae2aSnia 				if (pages == NULL) {
1268ac1932eSaugustss 					npagesmax = 5;
1278ac1932eSaugustss 				} else {
1288ac1932eSaugustss 					npagesmax += 5;
1298ac1932eSaugustss 				}
130*cce5ae2aSnia 				if (reallocarr(&pages, npagesmax,
131*cce5ae2aSnia 				       sizeof (struct usage_page)) != 0)
1328ac1932eSaugustss 					err(1, "alloc");
1338ac1932eSaugustss 			}
1348ac1932eSaugustss 			curpage = &pages[npages++];
1358ac1932eSaugustss 			curpage->name = n;
1368ac1932eSaugustss 			curpage->usage = no;
1378ac1932eSaugustss 			curpage->pagesize = 0;
1388ac1932eSaugustss 			curpage->pagesizemax = 10;
139*cce5ae2aSnia 			curpage->page_contents = NULL;
140*cce5ae2aSnia 			if (reallocarr(&curpage->page_contents,
141*cce5ae2aSnia 				       curpage->pagesizemax,
142*cce5ae2aSnia 				       sizeof (struct usage_in_page)) != 0)
1438ac1932eSaugustss 				err(1, "malloc");
1448ac1932eSaugustss 		}
1458ac1932eSaugustss 	}
1468ac1932eSaugustss 	fclose(f);
1478ac1932eSaugustss #ifdef DEBUG
1488ac1932eSaugustss 	dump_hid_table();
1498ac1932eSaugustss #endif
1508ac1932eSaugustss }
1518ac1932eSaugustss 
1528ac1932eSaugustss const char *
hid_usage_page(int i)1538ac1932eSaugustss hid_usage_page(int i)
1548ac1932eSaugustss {
1558ac1932eSaugustss 	static char b[10];
1568ac1932eSaugustss 	int k;
1578ac1932eSaugustss 
1588ac1932eSaugustss 	if (!pages)
1596742cb18Sgrant 		errx(1, "no hid table");
1608ac1932eSaugustss 
1618ac1932eSaugustss 	for (k = 0; k < npages; k++)
1628ac1932eSaugustss 		if (pages[k].usage == i)
1638ac1932eSaugustss 			return pages[k].name;
1648ac1932eSaugustss 	sprintf(b, "0x%04x", i);
1658ac1932eSaugustss 	return b;
1668ac1932eSaugustss }
1678ac1932eSaugustss 
1688ac1932eSaugustss const char *
hid_usage_in_page(unsigned int u)1698ac1932eSaugustss hid_usage_in_page(unsigned int u)
1708ac1932eSaugustss {
1718ac1932eSaugustss 	int page = HID_PAGE(u);
1728ac1932eSaugustss 	int i = HID_USAGE(u);
1738ac1932eSaugustss 	static char b[100];
1748ac1932eSaugustss 	int j, k, us;
1758ac1932eSaugustss 
1768ac1932eSaugustss 	for (k = 0; k < npages; k++)
1778ac1932eSaugustss 		if (pages[k].usage == page)
1788ac1932eSaugustss 			break;
1798ac1932eSaugustss 	if (k >= npages)
1808ac1932eSaugustss 		goto bad;
1818ac1932eSaugustss 	for (j = 0; j < pages[k].pagesize; j++) {
1828ac1932eSaugustss 		us = pages[k].page_contents[j].usage;
1838ac1932eSaugustss 		if (us == -1) {
1848ac1932eSaugustss 			sprintf(b,
1858ac1932eSaugustss 			    fmtcheck(pages[k].page_contents[j].name, "%d"),
1868ac1932eSaugustss 			    i);
1878ac1932eSaugustss 			return b;
1888ac1932eSaugustss 		}
1898ac1932eSaugustss 		if (us == i)
1908ac1932eSaugustss 			return pages[k].page_contents[j].name;
1918ac1932eSaugustss 	}
1928ac1932eSaugustss  bad:
1938ac1932eSaugustss 	sprintf(b, "0x%04x", i);
1948ac1932eSaugustss 	return b;
1958ac1932eSaugustss }
1968ac1932eSaugustss 
1978ac1932eSaugustss int
hid_parse_usage_page(const char * name)1988ac1932eSaugustss hid_parse_usage_page(const char *name)
1998ac1932eSaugustss {
2008ac1932eSaugustss 	int k;
2018ac1932eSaugustss 
2028ac1932eSaugustss 	if (!pages)
2036742cb18Sgrant 		errx(1, "no hid table");
2048ac1932eSaugustss 
2058ac1932eSaugustss 	for (k = 0; k < npages; k++)
2068ac1932eSaugustss 		if (strcmp(pages[k].name, name) == 0)
2078ac1932eSaugustss 			return pages[k].usage;
2088ac1932eSaugustss 	return -1;
2098ac1932eSaugustss }
2108ac1932eSaugustss 
2118ac1932eSaugustss int
hid_parse_usage_in_page(const char * name)2128ac1932eSaugustss hid_parse_usage_in_page(const char *name)
2138ac1932eSaugustss {
2148ac1932eSaugustss 	const char *sep;
2158ac1932eSaugustss 	int k, j;
2168ac1932eSaugustss 	unsigned int l;
21710deb451Schristos 	size_t len;
2188ac1932eSaugustss 
2198ac1932eSaugustss 	_DIAGASSERT(name != NULL);
2208ac1932eSaugustss 
2218ac1932eSaugustss 	sep = strchr(name, ':');
2228ac1932eSaugustss 	if (sep == NULL)
2238ac1932eSaugustss 		return -1;
22410deb451Schristos 	len = sep - name;
2258ac1932eSaugustss 	for (k = 0; k < npages; k++)
22610deb451Schristos 		if (strncmp(pages[k].name, name, len) == 0)
2278ac1932eSaugustss 			goto found;
228aaf9a451Sjakllsch 	if (sscanf(name, "%x:%x", &k, &j) == 2) {
229f76ca308Sfox 		return (((uint32_t)k) << 16) | j;
230aaf9a451Sjakllsch 	}
2318ac1932eSaugustss 	return -1;
2328ac1932eSaugustss  found:
2338ac1932eSaugustss 	sep++;
2348ac1932eSaugustss 	for (j = 0; j < pages[k].pagesize; j++)
235f5863ab3Sjakllsch 		if (pages[k].page_contents[j].usage == -1) {
236f5863ab3Sjakllsch 			if (sscanf(sep, fmtcheck(
237f5863ab3Sjakllsch 			    pages[k].page_contents[j].name, "%u"), &l) == 1) {
238f76ca308Sfox 				return (((uint32_t)pages[k].usage) << 16) | l;
239f5863ab3Sjakllsch 			}
240f5863ab3Sjakllsch 		} else if (strcmp(pages[k].page_contents[j].name, sep) == 0)
241f76ca308Sfox 			return (((uint32_t)pages[k].usage) << 16) | pages[k].page_contents[j].usage;
2428ac1932eSaugustss 	return (-1);
2438ac1932eSaugustss }
244