16490c2ffSMaksim Yevmenkin %{
26490c2ffSMaksim Yevmenkin /*
36490c2ffSMaksim Yevmenkin * parser.y
47aebfa93SMaksim Yevmenkin */
57aebfa93SMaksim Yevmenkin
67aebfa93SMaksim Yevmenkin /*-
7*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
81de7b4b8SPedro F. Giffuni *
97aebfa93SMaksim Yevmenkin * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
106490c2ffSMaksim Yevmenkin * All rights reserved.
116490c2ffSMaksim Yevmenkin *
126490c2ffSMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without
136490c2ffSMaksim Yevmenkin * modification, are permitted provided that the following conditions
146490c2ffSMaksim Yevmenkin * are met:
156490c2ffSMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright
166490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer.
176490c2ffSMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright
186490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the
196490c2ffSMaksim Yevmenkin * documentation and/or other materials provided with the distribution.
206490c2ffSMaksim Yevmenkin *
216490c2ffSMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
226490c2ffSMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
236490c2ffSMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
246490c2ffSMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
256490c2ffSMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
266490c2ffSMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
276490c2ffSMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
286490c2ffSMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
296490c2ffSMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
306490c2ffSMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
316490c2ffSMaksim Yevmenkin * SUCH DAMAGE.
326490c2ffSMaksim Yevmenkin *
337aebfa93SMaksim Yevmenkin * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $
346490c2ffSMaksim Yevmenkin */
356490c2ffSMaksim Yevmenkin
366490c2ffSMaksim Yevmenkin #include <sys/queue.h>
378d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED
386490c2ffSMaksim Yevmenkin #include <bluetooth.h>
397aebfa93SMaksim Yevmenkin #include <dev/usb/usb.h>
407aebfa93SMaksim Yevmenkin #include <dev/usb/usbhid.h>
416490c2ffSMaksim Yevmenkin #include <errno.h>
426490c2ffSMaksim Yevmenkin #include <limits.h>
436490c2ffSMaksim Yevmenkin #include <stdio.h>
445e2a209aSBaptiste Daroussin #include <stdlib.h>
456490c2ffSMaksim Yevmenkin #include <string.h>
466490c2ffSMaksim Yevmenkin #include <unistd.h>
473adfd74aSMaksim Yevmenkin #include <usbhid.h>
486490c2ffSMaksim Yevmenkin
496490c2ffSMaksim Yevmenkin #ifndef BTHIDCONTROL
506490c2ffSMaksim Yevmenkin #include <stdarg.h>
516490c2ffSMaksim Yevmenkin #include <syslog.h>
526490c2ffSMaksim Yevmenkin #define SYSLOG syslog
536490c2ffSMaksim Yevmenkin #define LOGCRIT LOG_CRIT
546490c2ffSMaksim Yevmenkin #define LOGERR LOG_ERR
556490c2ffSMaksim Yevmenkin #define LOGWARNING LOG_WARNING
566490c2ffSMaksim Yevmenkin #define EOL
576490c2ffSMaksim Yevmenkin #else
586490c2ffSMaksim Yevmenkin #define SYSLOG fprintf
596490c2ffSMaksim Yevmenkin #define LOGCRIT stderr
606490c2ffSMaksim Yevmenkin #define LOGERR stderr
616490c2ffSMaksim Yevmenkin #define LOGWARNING stderr
626490c2ffSMaksim Yevmenkin #define EOL "\n"
636490c2ffSMaksim Yevmenkin #endif /* ndef BTHIDCONTROL */
646490c2ffSMaksim Yevmenkin
65e6508069SVladimir Kondratyev #define NAMELESS_DEVICE "No Name"
66e6508069SVladimir Kondratyev
676490c2ffSMaksim Yevmenkin #include "bthid_config.h"
686490c2ffSMaksim Yevmenkin
696490c2ffSMaksim Yevmenkin int yylex (void);
707aebfa93SMaksim Yevmenkin void yyerror (char const *);
717aebfa93SMaksim Yevmenkin static int32_t check_hid_device(hid_device_p hid_device);
726490c2ffSMaksim Yevmenkin static void free_hid_device (hid_device_p hid_device);
736490c2ffSMaksim Yevmenkin
747aebfa93SMaksim Yevmenkin extern FILE *yyin;
756490c2ffSMaksim Yevmenkin extern int yylineno;
767aebfa93SMaksim Yevmenkin char const *config_file = BTHIDD_CONFFILE;
777aebfa93SMaksim Yevmenkin char const *hids_file = BTHIDD_HIDSFILE;
786490c2ffSMaksim Yevmenkin
796490c2ffSMaksim Yevmenkin static char buffer[1024];
807aebfa93SMaksim Yevmenkin static int32_t hid_descriptor_size;
816490c2ffSMaksim Yevmenkin static hid_device_t *hid_device = NULL;
826490c2ffSMaksim Yevmenkin static LIST_HEAD(, hid_device) hid_devices;
836490c2ffSMaksim Yevmenkin
846490c2ffSMaksim Yevmenkin %}
856490c2ffSMaksim Yevmenkin
866490c2ffSMaksim Yevmenkin %union {
876490c2ffSMaksim Yevmenkin bdaddr_t bdaddr;
887aebfa93SMaksim Yevmenkin int32_t num;
89e6508069SVladimir Kondratyev char *string;
906490c2ffSMaksim Yevmenkin }
916490c2ffSMaksim Yevmenkin
926490c2ffSMaksim Yevmenkin %token <bdaddr> T_BDADDRSTRING
936490c2ffSMaksim Yevmenkin %token <num> T_HEXBYTE
946032284eSVladimir Kondratyev %token <num> T_HEXWORD
95e6508069SVladimir Kondratyev %token <string> T_STRING
96e6508069SVladimir Kondratyev %token T_NAME
976032284eSVladimir Kondratyev %token T_DEVICE T_BDADDR T_VENDOR_ID T_PRODUCT_ID T_VERSION T_CONTROL_PSM
986032284eSVladimir Kondratyev %token T_INTERRUPT_PSM T_RECONNECT_INITIATE T_BATTERY_POWER
996032284eSVladimir Kondratyev %token T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR
1006490c2ffSMaksim Yevmenkin %token T_TRUE T_FALSE T_ERROR
1016490c2ffSMaksim Yevmenkin
1026490c2ffSMaksim Yevmenkin %%
1036490c2ffSMaksim Yevmenkin
1046490c2ffSMaksim Yevmenkin config: line
1056490c2ffSMaksim Yevmenkin | config line
1066490c2ffSMaksim Yevmenkin ;
1076490c2ffSMaksim Yevmenkin
1086490c2ffSMaksim Yevmenkin line: T_DEVICE
1096490c2ffSMaksim Yevmenkin {
1106490c2ffSMaksim Yevmenkin hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device));
1116490c2ffSMaksim Yevmenkin if (hid_device == NULL) {
1126490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "Could not allocate new " \
1136490c2ffSMaksim Yevmenkin "config entry" EOL);
1146490c2ffSMaksim Yevmenkin YYABORT;
1156490c2ffSMaksim Yevmenkin }
1166490c2ffSMaksim Yevmenkin
1176490c2ffSMaksim Yevmenkin hid_device->new_device = 1;
1186490c2ffSMaksim Yevmenkin }
1196490c2ffSMaksim Yevmenkin '{' options '}'
1206490c2ffSMaksim Yevmenkin {
1216490c2ffSMaksim Yevmenkin if (check_hid_device(hid_device))
1226490c2ffSMaksim Yevmenkin LIST_INSERT_HEAD(&hid_devices,hid_device,next);
1236490c2ffSMaksim Yevmenkin else
1246490c2ffSMaksim Yevmenkin free_hid_device(hid_device);
1256490c2ffSMaksim Yevmenkin
1266490c2ffSMaksim Yevmenkin hid_device = NULL;
1276490c2ffSMaksim Yevmenkin }
1286490c2ffSMaksim Yevmenkin ;
1296490c2ffSMaksim Yevmenkin
1306490c2ffSMaksim Yevmenkin options: option ';'
1316490c2ffSMaksim Yevmenkin | options option ';'
1326490c2ffSMaksim Yevmenkin ;
1336490c2ffSMaksim Yevmenkin
1346490c2ffSMaksim Yevmenkin option: bdaddr
135e6508069SVladimir Kondratyev | name
1366032284eSVladimir Kondratyev | vendor_id
1376032284eSVladimir Kondratyev | product_id
1386032284eSVladimir Kondratyev | version
1396490c2ffSMaksim Yevmenkin | control_psm
1406490c2ffSMaksim Yevmenkin | interrupt_psm
1416490c2ffSMaksim Yevmenkin | reconnect_initiate
1426490c2ffSMaksim Yevmenkin | battery_power
1436490c2ffSMaksim Yevmenkin | normally_connectable
1446490c2ffSMaksim Yevmenkin | hid_descriptor
1456490c2ffSMaksim Yevmenkin | parser_error
1466490c2ffSMaksim Yevmenkin ;
1476490c2ffSMaksim Yevmenkin
1486490c2ffSMaksim Yevmenkin bdaddr: T_BDADDR T_BDADDRSTRING
1496490c2ffSMaksim Yevmenkin {
1506490c2ffSMaksim Yevmenkin memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr));
1516490c2ffSMaksim Yevmenkin }
1526490c2ffSMaksim Yevmenkin ;
1536490c2ffSMaksim Yevmenkin
154e6508069SVladimir Kondratyev name: T_NAME T_STRING
155e6508069SVladimir Kondratyev {
156e6508069SVladimir Kondratyev if (hid_device->name != NULL) {
157e6508069SVladimir Kondratyev free(hid_device->name);
158e6508069SVladimir Kondratyev hid_device->name = NULL;
159e6508069SVladimir Kondratyev }
160e6508069SVladimir Kondratyev
161e6508069SVladimir Kondratyev if (strcmp($2, NAMELESS_DEVICE)) {
162e6508069SVladimir Kondratyev hid_device->name = strdup($2);
163e6508069SVladimir Kondratyev if (hid_device->name == NULL) {
164e6508069SVladimir Kondratyev SYSLOG(LOGCRIT, "Could not allocate new " \
165e6508069SVladimir Kondratyev "device name" EOL);
166e6508069SVladimir Kondratyev YYABORT;
167e6508069SVladimir Kondratyev }
168e6508069SVladimir Kondratyev }
169e6508069SVladimir Kondratyev }
170e6508069SVladimir Kondratyev ;
171e6508069SVladimir Kondratyev
1726032284eSVladimir Kondratyev vendor_id: T_VENDOR_ID T_HEXWORD
1736032284eSVladimir Kondratyev {
1746032284eSVladimir Kondratyev hid_device->vendor_id = $2;
1756032284eSVladimir Kondratyev }
1766032284eSVladimir Kondratyev ;
1776032284eSVladimir Kondratyev
1786032284eSVladimir Kondratyev product_id: T_PRODUCT_ID T_HEXWORD
1796032284eSVladimir Kondratyev {
1806032284eSVladimir Kondratyev hid_device->product_id = $2;
1816032284eSVladimir Kondratyev }
1826032284eSVladimir Kondratyev ;
1836032284eSVladimir Kondratyev
1846032284eSVladimir Kondratyev version: T_VERSION T_HEXWORD
1856032284eSVladimir Kondratyev {
1866032284eSVladimir Kondratyev hid_device->version = $2;
1876032284eSVladimir Kondratyev }
1886032284eSVladimir Kondratyev ;
1896032284eSVladimir Kondratyev
1906490c2ffSMaksim Yevmenkin control_psm: T_CONTROL_PSM T_HEXBYTE
1916490c2ffSMaksim Yevmenkin {
1926490c2ffSMaksim Yevmenkin hid_device->control_psm = $2;
1936490c2ffSMaksim Yevmenkin }
1946490c2ffSMaksim Yevmenkin ;
1956490c2ffSMaksim Yevmenkin
1966490c2ffSMaksim Yevmenkin interrupt_psm: T_INTERRUPT_PSM T_HEXBYTE
1976490c2ffSMaksim Yevmenkin {
1986490c2ffSMaksim Yevmenkin hid_device->interrupt_psm = $2;
1996490c2ffSMaksim Yevmenkin }
2006490c2ffSMaksim Yevmenkin ;
2016490c2ffSMaksim Yevmenkin
2026490c2ffSMaksim Yevmenkin reconnect_initiate: T_RECONNECT_INITIATE T_TRUE
2036490c2ffSMaksim Yevmenkin {
2046490c2ffSMaksim Yevmenkin hid_device->reconnect_initiate = 1;
2056490c2ffSMaksim Yevmenkin }
2066490c2ffSMaksim Yevmenkin | T_RECONNECT_INITIATE T_FALSE
2076490c2ffSMaksim Yevmenkin {
2086490c2ffSMaksim Yevmenkin hid_device->reconnect_initiate = 0;
2096490c2ffSMaksim Yevmenkin }
2106490c2ffSMaksim Yevmenkin ;
2116490c2ffSMaksim Yevmenkin
2126490c2ffSMaksim Yevmenkin battery_power: T_BATTERY_POWER T_TRUE
2136490c2ffSMaksim Yevmenkin {
2146490c2ffSMaksim Yevmenkin hid_device->battery_power = 1;
2156490c2ffSMaksim Yevmenkin }
2166490c2ffSMaksim Yevmenkin | T_BATTERY_POWER T_FALSE
2176490c2ffSMaksim Yevmenkin {
2186490c2ffSMaksim Yevmenkin hid_device->battery_power = 0;
2196490c2ffSMaksim Yevmenkin }
2206490c2ffSMaksim Yevmenkin ;
2216490c2ffSMaksim Yevmenkin
2226490c2ffSMaksim Yevmenkin normally_connectable: T_NORMALLY_CONNECTABLE T_TRUE
2236490c2ffSMaksim Yevmenkin {
2246490c2ffSMaksim Yevmenkin hid_device->normally_connectable = 1;
2256490c2ffSMaksim Yevmenkin }
2266490c2ffSMaksim Yevmenkin | T_NORMALLY_CONNECTABLE T_FALSE
2276490c2ffSMaksim Yevmenkin {
2286490c2ffSMaksim Yevmenkin hid_device->normally_connectable = 0;
2296490c2ffSMaksim Yevmenkin }
2306490c2ffSMaksim Yevmenkin ;
2316490c2ffSMaksim Yevmenkin
2326490c2ffSMaksim Yevmenkin hid_descriptor: T_HID_DESCRIPTOR
2336490c2ffSMaksim Yevmenkin {
2346490c2ffSMaksim Yevmenkin hid_descriptor_size = 0;
2356490c2ffSMaksim Yevmenkin }
2366490c2ffSMaksim Yevmenkin '{' hid_descriptor_bytes '}'
2376490c2ffSMaksim Yevmenkin {
2386490c2ffSMaksim Yevmenkin if (hid_device->desc != NULL)
2396490c2ffSMaksim Yevmenkin hid_dispose_report_desc(hid_device->desc);
2406490c2ffSMaksim Yevmenkin
2416e9bee64SMaksim Yevmenkin hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size);
2426490c2ffSMaksim Yevmenkin if (hid_device->desc == NULL) {
2436490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL);
2446490c2ffSMaksim Yevmenkin YYABORT;
2456490c2ffSMaksim Yevmenkin }
2466490c2ffSMaksim Yevmenkin }
2476490c2ffSMaksim Yevmenkin ;
2486490c2ffSMaksim Yevmenkin
2496490c2ffSMaksim Yevmenkin hid_descriptor_bytes: hid_descriptor_byte
2506490c2ffSMaksim Yevmenkin | hid_descriptor_bytes hid_descriptor_byte
2516490c2ffSMaksim Yevmenkin ;
2526490c2ffSMaksim Yevmenkin
2536490c2ffSMaksim Yevmenkin hid_descriptor_byte: T_HEXBYTE
2546490c2ffSMaksim Yevmenkin {
2557aebfa93SMaksim Yevmenkin if (hid_descriptor_size >= (int32_t) sizeof(buffer)) {
2566490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "HID descriptor is too big" EOL);
2576490c2ffSMaksim Yevmenkin YYABORT;
2586490c2ffSMaksim Yevmenkin }
2596490c2ffSMaksim Yevmenkin
2606490c2ffSMaksim Yevmenkin buffer[hid_descriptor_size ++] = $1;
2616490c2ffSMaksim Yevmenkin }
2626490c2ffSMaksim Yevmenkin ;
2636490c2ffSMaksim Yevmenkin
2646490c2ffSMaksim Yevmenkin parser_error: T_ERROR
2656490c2ffSMaksim Yevmenkin {
2666490c2ffSMaksim Yevmenkin YYABORT;
2676490c2ffSMaksim Yevmenkin }
2686490c2ffSMaksim Yevmenkin
2696490c2ffSMaksim Yevmenkin %%
2706490c2ffSMaksim Yevmenkin
2716490c2ffSMaksim Yevmenkin /* Display parser error message */
2726490c2ffSMaksim Yevmenkin void
2736490c2ffSMaksim Yevmenkin yyerror(char const *message)
2746490c2ffSMaksim Yevmenkin {
2756490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno);
2766490c2ffSMaksim Yevmenkin }
2776490c2ffSMaksim Yevmenkin
2786490c2ffSMaksim Yevmenkin /* Re-read config file */
2797aebfa93SMaksim Yevmenkin int32_t
read_config_file(void)2806490c2ffSMaksim Yevmenkin read_config_file(void)
2816490c2ffSMaksim Yevmenkin {
2827aebfa93SMaksim Yevmenkin int32_t e;
2836490c2ffSMaksim Yevmenkin
2846490c2ffSMaksim Yevmenkin if (config_file == NULL) {
2856490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown config file name!" EOL);
2866490c2ffSMaksim Yevmenkin return (-1);
2876490c2ffSMaksim Yevmenkin }
2886490c2ffSMaksim Yevmenkin
2896490c2ffSMaksim Yevmenkin if ((yyin = fopen(config_file, "r")) == NULL) {
2906490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL,
2916490c2ffSMaksim Yevmenkin config_file, strerror(errno), errno);
2926490c2ffSMaksim Yevmenkin return (-1);
2936490c2ffSMaksim Yevmenkin }
2946490c2ffSMaksim Yevmenkin
2956490c2ffSMaksim Yevmenkin clean_config();
2966490c2ffSMaksim Yevmenkin if (yyparse() < 0) {
2976490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not parse config file '%s'" EOL,
2986490c2ffSMaksim Yevmenkin config_file);
2996490c2ffSMaksim Yevmenkin e = -1;
3006490c2ffSMaksim Yevmenkin } else
3016490c2ffSMaksim Yevmenkin e = 0;
3026490c2ffSMaksim Yevmenkin
3036490c2ffSMaksim Yevmenkin fclose(yyin);
3046490c2ffSMaksim Yevmenkin yyin = NULL;
3056490c2ffSMaksim Yevmenkin
3066490c2ffSMaksim Yevmenkin return (e);
3076490c2ffSMaksim Yevmenkin }
3086490c2ffSMaksim Yevmenkin
3096490c2ffSMaksim Yevmenkin /* Clean config */
3106490c2ffSMaksim Yevmenkin void
clean_config(void)3116490c2ffSMaksim Yevmenkin clean_config(void)
3126490c2ffSMaksim Yevmenkin {
3136490c2ffSMaksim Yevmenkin while (!LIST_EMPTY(&hid_devices)) {
3147aebfa93SMaksim Yevmenkin hid_device_p d = LIST_FIRST(&hid_devices);
3156490c2ffSMaksim Yevmenkin
3167aebfa93SMaksim Yevmenkin LIST_REMOVE(d, next);
3177aebfa93SMaksim Yevmenkin free_hid_device(d);
3186490c2ffSMaksim Yevmenkin }
3196490c2ffSMaksim Yevmenkin }
3206490c2ffSMaksim Yevmenkin
3216490c2ffSMaksim Yevmenkin /* Lookup config entry */
3226490c2ffSMaksim Yevmenkin hid_device_p
get_hid_device(bdaddr_p bdaddr)3236490c2ffSMaksim Yevmenkin get_hid_device(bdaddr_p bdaddr)
3246490c2ffSMaksim Yevmenkin {
3257aebfa93SMaksim Yevmenkin hid_device_p d;
3266490c2ffSMaksim Yevmenkin
3277aebfa93SMaksim Yevmenkin LIST_FOREACH(d, &hid_devices, next)
3287aebfa93SMaksim Yevmenkin if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
3296490c2ffSMaksim Yevmenkin break;
3306490c2ffSMaksim Yevmenkin
3317aebfa93SMaksim Yevmenkin return (d);
3326490c2ffSMaksim Yevmenkin }
3336490c2ffSMaksim Yevmenkin
3346490c2ffSMaksim Yevmenkin /* Get next config entry */
3356490c2ffSMaksim Yevmenkin hid_device_p
get_next_hid_device(hid_device_p d)3366490c2ffSMaksim Yevmenkin get_next_hid_device(hid_device_p d)
3376490c2ffSMaksim Yevmenkin {
3386490c2ffSMaksim Yevmenkin return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next));
3396490c2ffSMaksim Yevmenkin }
3406490c2ffSMaksim Yevmenkin
3416490c2ffSMaksim Yevmenkin /* Print config entry */
3426490c2ffSMaksim Yevmenkin void
print_hid_device(hid_device_p d,FILE * f)3437aebfa93SMaksim Yevmenkin print_hid_device(hid_device_p d, FILE *f)
3446490c2ffSMaksim Yevmenkin {
3456490c2ffSMaksim Yevmenkin /* XXX FIXME hack! */
3466490c2ffSMaksim Yevmenkin struct report_desc {
3476490c2ffSMaksim Yevmenkin unsigned int size;
3486490c2ffSMaksim Yevmenkin unsigned char data[1];
3496490c2ffSMaksim Yevmenkin };
3506490c2ffSMaksim Yevmenkin /* XXX FIXME hack! */
3516490c2ffSMaksim Yevmenkin
3527aebfa93SMaksim Yevmenkin struct report_desc *desc = (struct report_desc *) d->desc;
3537aebfa93SMaksim Yevmenkin uint32_t i;
3546490c2ffSMaksim Yevmenkin
3556490c2ffSMaksim Yevmenkin fprintf(f,
3566490c2ffSMaksim Yevmenkin "device {\n" \
3576490c2ffSMaksim Yevmenkin " bdaddr %s;\n" \
358e6508069SVladimir Kondratyev " name \"%s\";\n" \
3596032284eSVladimir Kondratyev " vendor_id 0x%04x;\n" \
3606032284eSVladimir Kondratyev " product_id 0x%04x;\n" \
3616032284eSVladimir Kondratyev " version 0x%04x;\n" \
3626490c2ffSMaksim Yevmenkin " control_psm 0x%x;\n" \
3639fbe483aSMaksim Yevmenkin " interrupt_psm 0x%x;\n" \
3646490c2ffSMaksim Yevmenkin " reconnect_initiate %s;\n" \
3656490c2ffSMaksim Yevmenkin " battery_power %s;\n" \
3666490c2ffSMaksim Yevmenkin " normally_connectable %s;\n" \
3676490c2ffSMaksim Yevmenkin " hid_descriptor {",
3687aebfa93SMaksim Yevmenkin bt_ntoa(&d->bdaddr, NULL),
369e6508069SVladimir Kondratyev (d->name != NULL)? d->name : NAMELESS_DEVICE,
3706032284eSVladimir Kondratyev d->vendor_id, d->product_id, d->version,
3717aebfa93SMaksim Yevmenkin d->control_psm, d->interrupt_psm,
3727aebfa93SMaksim Yevmenkin d->reconnect_initiate? "true" : "false",
3737aebfa93SMaksim Yevmenkin d->battery_power? "true" : "false",
3747aebfa93SMaksim Yevmenkin d->normally_connectable? "true" : "false");
3756490c2ffSMaksim Yevmenkin
3766490c2ffSMaksim Yevmenkin for (i = 0; i < desc->size; i ++) {
3776490c2ffSMaksim Yevmenkin if ((i % 8) == 0)
378c46a9ea8SMaksim Yevmenkin fprintf(f, "\n ");
3796490c2ffSMaksim Yevmenkin
3806490c2ffSMaksim Yevmenkin fprintf(f, "0x%2.2x ", desc->data[i]);
3816490c2ffSMaksim Yevmenkin }
3826490c2ffSMaksim Yevmenkin
383c46a9ea8SMaksim Yevmenkin fprintf(f,
3846490c2ffSMaksim Yevmenkin "\n" \
3856490c2ffSMaksim Yevmenkin " };\n" \
3866490c2ffSMaksim Yevmenkin "}\n");
3876490c2ffSMaksim Yevmenkin }
3886490c2ffSMaksim Yevmenkin
3896490c2ffSMaksim Yevmenkin /* Check config entry */
3907aebfa93SMaksim Yevmenkin static int32_t
check_hid_device(hid_device_p d)3917aebfa93SMaksim Yevmenkin check_hid_device(hid_device_p d)
3926490c2ffSMaksim Yevmenkin {
3937aebfa93SMaksim Yevmenkin hid_data_t hd;
3947aebfa93SMaksim Yevmenkin hid_item_t hi;
39544af5666SVladimir Kondratyev int32_t page, mdepth;
3967aebfa93SMaksim Yevmenkin
3977aebfa93SMaksim Yevmenkin if (get_hid_device(&d->bdaddr) != NULL) {
3986490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL,
3997aebfa93SMaksim Yevmenkin bt_ntoa(&d->bdaddr, NULL));
4006490c2ffSMaksim Yevmenkin return (0);
4016490c2ffSMaksim Yevmenkin }
4026490c2ffSMaksim Yevmenkin
4037aebfa93SMaksim Yevmenkin if (d->control_psm == 0) {
4046490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL);
4056490c2ffSMaksim Yevmenkin return (0);
4066490c2ffSMaksim Yevmenkin }
4076490c2ffSMaksim Yevmenkin
4087aebfa93SMaksim Yevmenkin if (d->interrupt_psm == 0) {
4096490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL);
4106490c2ffSMaksim Yevmenkin return (0);
4116490c2ffSMaksim Yevmenkin }
4126490c2ffSMaksim Yevmenkin
4137aebfa93SMaksim Yevmenkin if (d->desc == NULL) {
4146490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL);
4156490c2ffSMaksim Yevmenkin return (0);
4166490c2ffSMaksim Yevmenkin }
4176490c2ffSMaksim Yevmenkin
41844af5666SVladimir Kondratyev mdepth = 0;
41944af5666SVladimir Kondratyev
4207aebfa93SMaksim Yevmenkin /* XXX somehow need to make sure descriptor is valid */
4217aebfa93SMaksim Yevmenkin for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) {
4227aebfa93SMaksim Yevmenkin switch (hi.kind) {
4237aebfa93SMaksim Yevmenkin case hid_collection:
42444af5666SVladimir Kondratyev if (mdepth != 0)
42544af5666SVladimir Kondratyev mdepth++;
42644af5666SVladimir Kondratyev else if (hi.collection == 1 &&
42744af5666SVladimir Kondratyev hi.usage ==
42844af5666SVladimir Kondratyev HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
42944af5666SVladimir Kondratyev mdepth++;
43044af5666SVladimir Kondratyev break;
4317aebfa93SMaksim Yevmenkin case hid_endcollection:
43244af5666SVladimir Kondratyev if (mdepth != 0)
43344af5666SVladimir Kondratyev mdepth--;
43444af5666SVladimir Kondratyev break;
4357aebfa93SMaksim Yevmenkin case hid_output:
4367aebfa93SMaksim Yevmenkin case hid_feature:
4377aebfa93SMaksim Yevmenkin break;
4387aebfa93SMaksim Yevmenkin
4397aebfa93SMaksim Yevmenkin case hid_input:
4407aebfa93SMaksim Yevmenkin /* Check if the device may send keystrokes */
4417aebfa93SMaksim Yevmenkin page = HID_PAGE(hi.usage);
44206912ebaSMaksim Yevmenkin if (page == HUP_KEYBOARD)
4437aebfa93SMaksim Yevmenkin d->keyboard = 1;
44444af5666SVladimir Kondratyev if (page == HUP_CONSUMER &&
44544af5666SVladimir Kondratyev (hi.flags & (HIO_CONST|HIO_RELATIVE)) == 0)
44644af5666SVladimir Kondratyev d->has_cons = 1;
44744af5666SVladimir Kondratyev /* Check if the device may send relative motion events */
44844af5666SVladimir Kondratyev if (mdepth == 0)
44944af5666SVladimir Kondratyev break;
45044af5666SVladimir Kondratyev if (hi.usage ==
45144af5666SVladimir Kondratyev HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
45244af5666SVladimir Kondratyev (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
45344af5666SVladimir Kondratyev d->mouse = 1;
45444af5666SVladimir Kondratyev if (hi.usage ==
45544af5666SVladimir Kondratyev HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
45644af5666SVladimir Kondratyev (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
45744af5666SVladimir Kondratyev d->mouse = 1;
45844af5666SVladimir Kondratyev if (hi.usage ==
45944af5666SVladimir Kondratyev HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL) &&
46044af5666SVladimir Kondratyev (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
46144af5666SVladimir Kondratyev d->has_wheel = 1;
46244af5666SVladimir Kondratyev if (hi.usage ==
46344af5666SVladimir Kondratyev HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN) &&
46444af5666SVladimir Kondratyev (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
46544af5666SVladimir Kondratyev d->has_hwheel = 1;
4667aebfa93SMaksim Yevmenkin break;
4677aebfa93SMaksim Yevmenkin }
4687aebfa93SMaksim Yevmenkin }
4697aebfa93SMaksim Yevmenkin hid_end_parse(hd);
4707aebfa93SMaksim Yevmenkin
4716490c2ffSMaksim Yevmenkin return (1);
4726490c2ffSMaksim Yevmenkin }
4736490c2ffSMaksim Yevmenkin
4746490c2ffSMaksim Yevmenkin /* Free config entry */
4756490c2ffSMaksim Yevmenkin static void
free_hid_device(hid_device_p d)4767aebfa93SMaksim Yevmenkin free_hid_device(hid_device_p d)
4776490c2ffSMaksim Yevmenkin {
4787aebfa93SMaksim Yevmenkin if (d->desc != NULL)
4797aebfa93SMaksim Yevmenkin hid_dispose_report_desc(d->desc);
4806490c2ffSMaksim Yevmenkin
481e6508069SVladimir Kondratyev free(d->name);
4827aebfa93SMaksim Yevmenkin memset(d, 0, sizeof(*d));
4837aebfa93SMaksim Yevmenkin free(d);
4846490c2ffSMaksim Yevmenkin }
4856490c2ffSMaksim Yevmenkin
4866490c2ffSMaksim Yevmenkin /* Re-read hids file */
4877aebfa93SMaksim Yevmenkin int32_t
read_hids_file(void)4886490c2ffSMaksim Yevmenkin read_hids_file(void)
4896490c2ffSMaksim Yevmenkin {
4907aebfa93SMaksim Yevmenkin FILE *f;
4917aebfa93SMaksim Yevmenkin hid_device_t *d;
4927aebfa93SMaksim Yevmenkin char *line;
4936490c2ffSMaksim Yevmenkin bdaddr_t bdaddr;
4947aebfa93SMaksim Yevmenkin int32_t lineno;
4956490c2ffSMaksim Yevmenkin
4966490c2ffSMaksim Yevmenkin if (hids_file == NULL) {
4976490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
4986490c2ffSMaksim Yevmenkin return (-1);
4996490c2ffSMaksim Yevmenkin }
5006490c2ffSMaksim Yevmenkin
5016490c2ffSMaksim Yevmenkin if ((f = fopen(hids_file, "r")) == NULL) {
5026490c2ffSMaksim Yevmenkin if (errno == ENOENT)
5036490c2ffSMaksim Yevmenkin return (0);
5046490c2ffSMaksim Yevmenkin
5056490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
5066490c2ffSMaksim Yevmenkin hids_file, strerror(errno), errno);
5076490c2ffSMaksim Yevmenkin return (-1);
5086490c2ffSMaksim Yevmenkin }
5096490c2ffSMaksim Yevmenkin
5106490c2ffSMaksim Yevmenkin for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) {
5116490c2ffSMaksim Yevmenkin if ((line = strtok(buffer, "\r\n\t ")) == NULL)
5126490c2ffSMaksim Yevmenkin continue; /* ignore empty lines */
5136490c2ffSMaksim Yevmenkin
5146490c2ffSMaksim Yevmenkin if (!bt_aton(line, &bdaddr)) {
5156490c2ffSMaksim Yevmenkin SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \
5166490c2ffSMaksim Yevmenkin "%s:%d" EOL, hids_file, lineno);
5176490c2ffSMaksim Yevmenkin continue;
5186490c2ffSMaksim Yevmenkin }
5196490c2ffSMaksim Yevmenkin
5207aebfa93SMaksim Yevmenkin if ((d = get_hid_device(&bdaddr)) != NULL)
5217aebfa93SMaksim Yevmenkin d->new_device = 0;
5226490c2ffSMaksim Yevmenkin }
5236490c2ffSMaksim Yevmenkin
5246490c2ffSMaksim Yevmenkin fclose(f);
5256490c2ffSMaksim Yevmenkin
5266490c2ffSMaksim Yevmenkin return (0);
5276490c2ffSMaksim Yevmenkin }
5286490c2ffSMaksim Yevmenkin
5296490c2ffSMaksim Yevmenkin /* Write hids file */
5307aebfa93SMaksim Yevmenkin int32_t
write_hids_file(void)5316490c2ffSMaksim Yevmenkin write_hids_file(void)
5326490c2ffSMaksim Yevmenkin {
5336490c2ffSMaksim Yevmenkin char path[PATH_MAX];
5347aebfa93SMaksim Yevmenkin FILE *f;
5357aebfa93SMaksim Yevmenkin hid_device_t *d;
5366490c2ffSMaksim Yevmenkin
5376490c2ffSMaksim Yevmenkin if (hids_file == NULL) {
5386490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
5396490c2ffSMaksim Yevmenkin return (-1);
5406490c2ffSMaksim Yevmenkin }
5416490c2ffSMaksim Yevmenkin
5426490c2ffSMaksim Yevmenkin snprintf(path, sizeof(path), "%s.new", hids_file);
5436490c2ffSMaksim Yevmenkin
5446490c2ffSMaksim Yevmenkin if ((f = fopen(path, "w")) == NULL) {
5456490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
5466490c2ffSMaksim Yevmenkin path, strerror(errno), errno);
5476490c2ffSMaksim Yevmenkin return (-1);
5486490c2ffSMaksim Yevmenkin }
5496490c2ffSMaksim Yevmenkin
5507aebfa93SMaksim Yevmenkin LIST_FOREACH(d, &hid_devices, next)
5517aebfa93SMaksim Yevmenkin if (!d->new_device)
5527aebfa93SMaksim Yevmenkin fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL));
5536490c2ffSMaksim Yevmenkin
5546490c2ffSMaksim Yevmenkin fclose(f);
5556490c2ffSMaksim Yevmenkin
5566490c2ffSMaksim Yevmenkin if (rename(path, hids_file) < 0) {
5576490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \
5586490c2ffSMaksim Yevmenkin "%s (%d)" EOL, path, hids_file, strerror(errno), errno);
5596490c2ffSMaksim Yevmenkin unlink(path);
5606490c2ffSMaksim Yevmenkin return (-1);
5616490c2ffSMaksim Yevmenkin }
5626490c2ffSMaksim Yevmenkin
5636490c2ffSMaksim Yevmenkin return (0);
5646490c2ffSMaksim Yevmenkin }
5656490c2ffSMaksim Yevmenkin
566