1 /* $NetBSD: usage.c,v 1.8 2000/10/10 19:23:58 is Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5 * 6 * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <sys/param.h> 35 #include <assert.h> 36 #include <ctype.h> 37 #include <err.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 42 #include "usbhid.h" 43 44 #define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages" 45 46 struct usage_in_page { 47 const char *name; 48 int usage; 49 }; 50 51 static struct usage_page { 52 const char *name; 53 int usage; 54 struct usage_in_page *page_contents; 55 int pagesize, pagesizemax; 56 } *pages; 57 static int npages, npagesmax; 58 59 #ifdef DEBUG 60 void 61 dump_hid_table(void) 62 { 63 int i, j; 64 65 for (i = 0; i < npages; i++) { 66 printf("%d\t%s\n", pages[i].usage, pages[i].name); 67 for (j = 0; j < pages[i].pagesize; j++) { 68 printf("\t%d\t%s\n", pages[i].page_contents[j].usage, 69 pages[i].page_contents[j].name); 70 } 71 } 72 } 73 #endif 74 75 void 76 hid_init(const char *hidname) 77 { 78 FILE *f; 79 char line[100], name[100], *p, *n; 80 int no; 81 int lineno; 82 struct usage_page *curpage = NULL; 83 84 if (hidname == NULL) 85 hidname = _PATH_HIDTABLE; 86 87 f = fopen(hidname, "r"); 88 if (f == NULL) 89 err(1, "%s", hidname); 90 for (lineno = 1; ; lineno++) { 91 if (fgets(line, sizeof line, f) == NULL) 92 break; 93 if (line[0] == '#') 94 continue; 95 for (p = line; *p && isspace(*p); p++) 96 ; 97 if (!*p) 98 continue; 99 if (sscanf(line, " * %[^\n]", name) == 1) 100 no = -1; 101 else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 && 102 sscanf(line, " %d %[^\n]", &no, name) != 2) 103 errx(1, "file %s, line %d, syntax error", 104 hidname, lineno); 105 for (p = name; *p; p++) 106 if (isspace(*p) || *p == '.') 107 *p = '_'; 108 n = strdup(name); 109 if (!n) 110 err(1, "strdup"); 111 if (isspace(line[0])) { 112 if (!curpage) 113 errx(1, "file %s, line %d, syntax error", 114 hidname, lineno); 115 if (curpage->pagesize >= curpage->pagesizemax) { 116 curpage->pagesizemax += 10; 117 curpage->page_contents = 118 realloc(curpage->page_contents, 119 curpage->pagesizemax * 120 sizeof (struct usage_in_page)); 121 if (!curpage->page_contents) 122 err(1, "realloc"); 123 } 124 curpage->page_contents[curpage->pagesize].name = n; 125 curpage->page_contents[curpage->pagesize].usage = no; 126 curpage->pagesize++; 127 } else { 128 if (npages >= npagesmax) { 129 if (pages == NULL) { 130 npagesmax = 5; 131 pages = malloc(npagesmax * 132 sizeof (struct usage_page)); 133 } else { 134 npagesmax += 5; 135 pages = realloc(pages, 136 npagesmax * 137 sizeof (struct usage_page)); 138 } 139 if (!pages) 140 err(1, "alloc"); 141 } 142 curpage = &pages[npages++]; 143 curpage->name = n; 144 curpage->usage = no; 145 curpage->pagesize = 0; 146 curpage->pagesizemax = 10; 147 curpage->page_contents = 148 malloc(curpage->pagesizemax * 149 sizeof (struct usage_in_page)); 150 if (!curpage->page_contents) 151 err(1, "malloc"); 152 } 153 } 154 fclose(f); 155 #ifdef DEBUG 156 dump_hid_table(); 157 #endif 158 } 159 160 const char * 161 hid_usage_page(int i) 162 { 163 static char b[10]; 164 int k; 165 166 if (!pages) 167 errx(1, "no hid table"); 168 169 for (k = 0; k < npages; k++) 170 if (pages[k].usage == i) 171 return pages[k].name; 172 sprintf(b, "0x%04x", i); 173 return b; 174 } 175 176 const char * 177 hid_usage_in_page(unsigned int u) 178 { 179 int page = HID_PAGE(u); 180 int i = HID_USAGE(u); 181 static char b[100]; 182 int j, k, us; 183 184 for (k = 0; k < npages; k++) 185 if (pages[k].usage == page) 186 break; 187 if (k >= npages) 188 goto bad; 189 for (j = 0; j < pages[k].pagesize; j++) { 190 us = pages[k].page_contents[j].usage; 191 if (us == -1) { 192 sprintf(b, 193 fmtcheck(pages[k].page_contents[j].name, "%d"), 194 i); 195 return b; 196 } 197 if (us == i) 198 return pages[k].page_contents[j].name; 199 } 200 bad: 201 sprintf(b, "0x%04x", i); 202 return b; 203 } 204 205 int 206 hid_parse_usage_page(const char *name) 207 { 208 int k; 209 210 if (!pages) 211 errx(1, "no hid table"); 212 213 for (k = 0; k < npages; k++) 214 if (strcmp(pages[k].name, name) == 0) 215 return pages[k].usage; 216 return -1; 217 } 218 219 /* XXX handle hex */ 220 int 221 hid_parse_usage_in_page(const char *name) 222 { 223 const char *sep; 224 int k, j; 225 unsigned int l; 226 227 sep = strchr(name, ':'); 228 if (sep == NULL) 229 return -1; 230 l = sep - name; 231 for (k = 0; k < npages; k++) 232 if (strncmp(pages[k].name, name, l) == 0) 233 goto found; 234 return -1; 235 found: 236 sep++; 237 for (j = 0; j < pages[k].pagesize; j++) 238 if (strcmp(pages[k].page_contents[j].name, sep) == 0) 239 return (pages[k].usage << 16) | pages[k].page_contents[j].usage; 240 return (-1); 241 } 242