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