112bd3c8bSSascha Wildner /* $NetBSD: usage.c,v 1.8 2000/10/10 19:23:58 is Exp $ */
212bd3c8bSSascha Wildner
312bd3c8bSSascha Wildner /*
412bd3c8bSSascha Wildner * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
512bd3c8bSSascha Wildner * All rights reserved.
612bd3c8bSSascha Wildner *
712bd3c8bSSascha Wildner * Redistribution and use in source and binary forms, with or without
812bd3c8bSSascha Wildner * modification, are permitted provided that the following conditions
912bd3c8bSSascha Wildner * are met:
1012bd3c8bSSascha Wildner * 1. Redistributions of source code must retain the above copyright
1112bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer.
1212bd3c8bSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
1312bd3c8bSSascha Wildner * notice, this list of conditions and the following disclaimer in the
1412bd3c8bSSascha Wildner * documentation and/or other materials provided with the distribution.
1512bd3c8bSSascha Wildner *
1612bd3c8bSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1712bd3c8bSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1812bd3c8bSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1912bd3c8bSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2012bd3c8bSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2112bd3c8bSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2212bd3c8bSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2312bd3c8bSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2412bd3c8bSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2512bd3c8bSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2612bd3c8bSSascha Wildner * SUCH DAMAGE.
27ee284e10SSascha Wildner *
28ee284e10SSascha Wildner * $FreeBSD: head/lib/libusbhid/usage.c 205728 2010-03-27 08:00:16Z kaiw $
2912bd3c8bSSascha Wildner */
3012bd3c8bSSascha Wildner
3112bd3c8bSSascha Wildner #include <sys/param.h>
3212bd3c8bSSascha Wildner #include <assert.h>
3312bd3c8bSSascha Wildner #include <ctype.h>
3412bd3c8bSSascha Wildner #include <err.h>
3512bd3c8bSSascha Wildner #include <stdio.h>
3612bd3c8bSSascha Wildner #include <stdlib.h>
3712bd3c8bSSascha Wildner #include <string.h>
3812bd3c8bSSascha Wildner
3912bd3c8bSSascha Wildner #include "usbhid.h"
4012bd3c8bSSascha Wildner
4112bd3c8bSSascha Wildner #define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages"
4212bd3c8bSSascha Wildner
4312bd3c8bSSascha Wildner struct usage_in_page {
4412bd3c8bSSascha Wildner const char *name;
4512bd3c8bSSascha Wildner int usage;
4612bd3c8bSSascha Wildner };
4712bd3c8bSSascha Wildner
4812bd3c8bSSascha Wildner static struct usage_page {
4912bd3c8bSSascha Wildner const char *name;
5012bd3c8bSSascha Wildner int usage;
5112bd3c8bSSascha Wildner struct usage_in_page *page_contents;
5212bd3c8bSSascha Wildner int pagesize, pagesizemax;
5312bd3c8bSSascha Wildner } *pages;
5412bd3c8bSSascha Wildner static int npages, npagesmax;
5512bd3c8bSSascha Wildner
5612bd3c8bSSascha Wildner #ifdef DEBUG
5712bd3c8bSSascha Wildner void
dump_hid_table(void)5812bd3c8bSSascha Wildner dump_hid_table(void)
5912bd3c8bSSascha Wildner {
6012bd3c8bSSascha Wildner int i, j;
6112bd3c8bSSascha Wildner
6212bd3c8bSSascha Wildner for (i = 0; i < npages; i++) {
6312bd3c8bSSascha Wildner printf("%d\t%s\n", pages[i].usage, pages[i].name);
6412bd3c8bSSascha Wildner for (j = 0; j < pages[i].pagesize; j++) {
6512bd3c8bSSascha Wildner printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
6612bd3c8bSSascha Wildner pages[i].page_contents[j].name);
6712bd3c8bSSascha Wildner }
6812bd3c8bSSascha Wildner }
6912bd3c8bSSascha Wildner }
7012bd3c8bSSascha Wildner #endif
7112bd3c8bSSascha Wildner
7212bd3c8bSSascha Wildner void
hid_init(const char * hidname)7312bd3c8bSSascha Wildner hid_init(const char *hidname)
7412bd3c8bSSascha Wildner {
7512bd3c8bSSascha Wildner FILE *f;
7612bd3c8bSSascha Wildner char line[100], name[100], *p, *n;
7712bd3c8bSSascha Wildner int no;
7812bd3c8bSSascha Wildner int lineno;
79*75d796baSSascha Wildner struct usage_page *curpage = NULL;
8012bd3c8bSSascha Wildner
81*75d796baSSascha Wildner if (hidname == NULL)
8212bd3c8bSSascha Wildner hidname = _PATH_HIDTABLE;
8312bd3c8bSSascha Wildner
8412bd3c8bSSascha Wildner f = fopen(hidname, "r");
8512bd3c8bSSascha Wildner if (f == NULL)
8612bd3c8bSSascha Wildner err(1, "%s", hidname);
8712bd3c8bSSascha Wildner for (lineno = 1; ; lineno++) {
8812bd3c8bSSascha Wildner if (fgets(line, sizeof line, f) == NULL)
8912bd3c8bSSascha Wildner break;
9012bd3c8bSSascha Wildner if (line[0] == '#')
9112bd3c8bSSascha Wildner continue;
9212bd3c8bSSascha Wildner for (p = line; *p && isspace(*p); p++)
9312bd3c8bSSascha Wildner ;
9412bd3c8bSSascha Wildner if (!*p)
9512bd3c8bSSascha Wildner continue;
9612bd3c8bSSascha Wildner if (sscanf(line, " * %[^\n]", name) == 1)
9712bd3c8bSSascha Wildner no = -1;
9812bd3c8bSSascha Wildner else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 &&
9912bd3c8bSSascha Wildner sscanf(line, " %d %[^\n]", &no, name) != 2)
10012bd3c8bSSascha Wildner errx(1, "file %s, line %d, syntax error",
10112bd3c8bSSascha Wildner hidname, lineno);
10212bd3c8bSSascha Wildner for (p = name; *p; p++)
10312bd3c8bSSascha Wildner if (isspace(*p) || *p == '.')
10412bd3c8bSSascha Wildner *p = '_';
10512bd3c8bSSascha Wildner n = strdup(name);
10612bd3c8bSSascha Wildner if (!n)
10712bd3c8bSSascha Wildner err(1, "strdup");
10812bd3c8bSSascha Wildner if (isspace(line[0])) {
10912bd3c8bSSascha Wildner if (!curpage)
11012bd3c8bSSascha Wildner errx(1, "file %s, line %d, syntax error",
11112bd3c8bSSascha Wildner hidname, lineno);
11212bd3c8bSSascha Wildner if (curpage->pagesize >= curpage->pagesizemax) {
11312bd3c8bSSascha Wildner curpage->pagesizemax += 10;
11412bd3c8bSSascha Wildner curpage->page_contents =
11512bd3c8bSSascha Wildner realloc(curpage->page_contents,
11612bd3c8bSSascha Wildner curpage->pagesizemax *
11712bd3c8bSSascha Wildner sizeof (struct usage_in_page));
11812bd3c8bSSascha Wildner if (!curpage->page_contents)
11912bd3c8bSSascha Wildner err(1, "realloc");
12012bd3c8bSSascha Wildner }
12112bd3c8bSSascha Wildner curpage->page_contents[curpage->pagesize].name = n;
12212bd3c8bSSascha Wildner curpage->page_contents[curpage->pagesize].usage = no;
12312bd3c8bSSascha Wildner curpage->pagesize++;
12412bd3c8bSSascha Wildner } else {
12512bd3c8bSSascha Wildner if (npages >= npagesmax) {
126*75d796baSSascha Wildner if (pages == NULL) {
12712bd3c8bSSascha Wildner npagesmax = 5;
12812bd3c8bSSascha Wildner pages = malloc(npagesmax *
12912bd3c8bSSascha Wildner sizeof (struct usage_page));
13012bd3c8bSSascha Wildner } else {
13112bd3c8bSSascha Wildner npagesmax += 5;
13212bd3c8bSSascha Wildner pages = realloc(pages,
13312bd3c8bSSascha Wildner npagesmax *
13412bd3c8bSSascha Wildner sizeof (struct usage_page));
13512bd3c8bSSascha Wildner }
13612bd3c8bSSascha Wildner if (!pages)
13712bd3c8bSSascha Wildner err(1, "alloc");
13812bd3c8bSSascha Wildner }
13912bd3c8bSSascha Wildner curpage = &pages[npages++];
14012bd3c8bSSascha Wildner curpage->name = n;
14112bd3c8bSSascha Wildner curpage->usage = no;
14212bd3c8bSSascha Wildner curpage->pagesize = 0;
14312bd3c8bSSascha Wildner curpage->pagesizemax = 10;
14412bd3c8bSSascha Wildner curpage->page_contents =
14512bd3c8bSSascha Wildner malloc(curpage->pagesizemax *
14612bd3c8bSSascha Wildner sizeof (struct usage_in_page));
14712bd3c8bSSascha Wildner if (!curpage->page_contents)
14812bd3c8bSSascha Wildner err(1, "malloc");
14912bd3c8bSSascha Wildner }
15012bd3c8bSSascha Wildner }
15112bd3c8bSSascha Wildner fclose(f);
15212bd3c8bSSascha Wildner #ifdef DEBUG
15312bd3c8bSSascha Wildner dump_hid_table();
15412bd3c8bSSascha Wildner #endif
15512bd3c8bSSascha Wildner }
15612bd3c8bSSascha Wildner
15712bd3c8bSSascha Wildner const char *
hid_usage_page(int i)15812bd3c8bSSascha Wildner hid_usage_page(int i)
15912bd3c8bSSascha Wildner {
16012bd3c8bSSascha Wildner static char b[10];
16112bd3c8bSSascha Wildner int k;
16212bd3c8bSSascha Wildner
16312bd3c8bSSascha Wildner if (!pages)
16412bd3c8bSSascha Wildner errx(1, "no hid table");
16512bd3c8bSSascha Wildner
16612bd3c8bSSascha Wildner for (k = 0; k < npages; k++)
16712bd3c8bSSascha Wildner if (pages[k].usage == i)
16812bd3c8bSSascha Wildner return pages[k].name;
16912bd3c8bSSascha Wildner sprintf(b, "0x%04x", i);
17012bd3c8bSSascha Wildner return b;
17112bd3c8bSSascha Wildner }
17212bd3c8bSSascha Wildner
17312bd3c8bSSascha Wildner const char *
hid_usage_in_page(unsigned int u)17412bd3c8bSSascha Wildner hid_usage_in_page(unsigned int u)
17512bd3c8bSSascha Wildner {
17612bd3c8bSSascha Wildner int page = HID_PAGE(u);
17712bd3c8bSSascha Wildner int i = HID_USAGE(u);
17812bd3c8bSSascha Wildner static char b[100];
17912bd3c8bSSascha Wildner int j, k, us;
18012bd3c8bSSascha Wildner
18112bd3c8bSSascha Wildner for (k = 0; k < npages; k++)
18212bd3c8bSSascha Wildner if (pages[k].usage == page)
18312bd3c8bSSascha Wildner break;
18412bd3c8bSSascha Wildner if (k >= npages)
18512bd3c8bSSascha Wildner goto bad;
18612bd3c8bSSascha Wildner for (j = 0; j < pages[k].pagesize; j++) {
18712bd3c8bSSascha Wildner us = pages[k].page_contents[j].usage;
18812bd3c8bSSascha Wildner if (us == -1) {
18912bd3c8bSSascha Wildner sprintf(b,
19012bd3c8bSSascha Wildner fmtcheck(pages[k].page_contents[j].name, "%d"),
19112bd3c8bSSascha Wildner i);
19212bd3c8bSSascha Wildner return b;
19312bd3c8bSSascha Wildner }
19412bd3c8bSSascha Wildner if (us == i)
19512bd3c8bSSascha Wildner return pages[k].page_contents[j].name;
19612bd3c8bSSascha Wildner }
19712bd3c8bSSascha Wildner bad:
19812bd3c8bSSascha Wildner sprintf(b, "0x%04x", i);
19912bd3c8bSSascha Wildner return b;
20012bd3c8bSSascha Wildner }
20112bd3c8bSSascha Wildner
20212bd3c8bSSascha Wildner int
hid_parse_usage_page(const char * name)20312bd3c8bSSascha Wildner hid_parse_usage_page(const char *name)
20412bd3c8bSSascha Wildner {
20512bd3c8bSSascha Wildner int k;
20612bd3c8bSSascha Wildner
20712bd3c8bSSascha Wildner if (!pages)
20812bd3c8bSSascha Wildner errx(1, "no hid table");
20912bd3c8bSSascha Wildner
21012bd3c8bSSascha Wildner for (k = 0; k < npages; k++)
21112bd3c8bSSascha Wildner if (strcmp(pages[k].name, name) == 0)
21212bd3c8bSSascha Wildner return pages[k].usage;
21312bd3c8bSSascha Wildner return -1;
21412bd3c8bSSascha Wildner }
21512bd3c8bSSascha Wildner
21612bd3c8bSSascha Wildner /* XXX handle hex */
21712bd3c8bSSascha Wildner int
hid_parse_usage_in_page(const char * name)21812bd3c8bSSascha Wildner hid_parse_usage_in_page(const char *name)
21912bd3c8bSSascha Wildner {
22012bd3c8bSSascha Wildner const char *sep;
22112bd3c8bSSascha Wildner int k, j;
22212bd3c8bSSascha Wildner unsigned int l;
22312bd3c8bSSascha Wildner
22412bd3c8bSSascha Wildner sep = strchr(name, ':');
22512bd3c8bSSascha Wildner if (sep == NULL)
22612bd3c8bSSascha Wildner return -1;
22712bd3c8bSSascha Wildner l = sep - name;
22812bd3c8bSSascha Wildner for (k = 0; k < npages; k++)
22912bd3c8bSSascha Wildner if (strncmp(pages[k].name, name, l) == 0)
23012bd3c8bSSascha Wildner goto found;
23112bd3c8bSSascha Wildner return -1;
23212bd3c8bSSascha Wildner found:
23312bd3c8bSSascha Wildner sep++;
23412bd3c8bSSascha Wildner for (j = 0; j < pages[k].pagesize; j++)
23512bd3c8bSSascha Wildner if (strcmp(pages[k].page_contents[j].name, sep) == 0)
23612bd3c8bSSascha Wildner return (pages[k].usage << 16) | pages[k].page_contents[j].usage;
23712bd3c8bSSascha Wildner return (-1);
23812bd3c8bSSascha Wildner }
239