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