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