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