16490c2ffSMaksim Yevmenkin %{ 26490c2ffSMaksim Yevmenkin /* 36490c2ffSMaksim Yevmenkin * parser.y 47aebfa93SMaksim Yevmenkin */ 57aebfa93SMaksim Yevmenkin 67aebfa93SMaksim Yevmenkin /*- 71de7b4b8SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 356490c2ffSMaksim Yevmenkin */ 366490c2ffSMaksim Yevmenkin 376490c2ffSMaksim Yevmenkin #include <sys/queue.h> 388d6f425dSTakanori Watanabe #define L2CAP_SOCKET_CHECKED 396490c2ffSMaksim Yevmenkin #include <bluetooth.h> 407aebfa93SMaksim Yevmenkin #include <dev/usb/usb.h> 417aebfa93SMaksim Yevmenkin #include <dev/usb/usbhid.h> 426490c2ffSMaksim Yevmenkin #include <errno.h> 436490c2ffSMaksim Yevmenkin #include <limits.h> 446490c2ffSMaksim Yevmenkin #include <stdio.h> 455e2a209aSBaptiste Daroussin #include <stdlib.h> 466490c2ffSMaksim Yevmenkin #include <string.h> 476490c2ffSMaksim Yevmenkin #include <unistd.h> 483adfd74aSMaksim Yevmenkin #include <usbhid.h> 496490c2ffSMaksim Yevmenkin 506490c2ffSMaksim Yevmenkin #ifndef BTHIDCONTROL 516490c2ffSMaksim Yevmenkin #include <stdarg.h> 526490c2ffSMaksim Yevmenkin #include <syslog.h> 536490c2ffSMaksim Yevmenkin #define SYSLOG syslog 546490c2ffSMaksim Yevmenkin #define LOGCRIT LOG_CRIT 556490c2ffSMaksim Yevmenkin #define LOGERR LOG_ERR 566490c2ffSMaksim Yevmenkin #define LOGWARNING LOG_WARNING 576490c2ffSMaksim Yevmenkin #define EOL 586490c2ffSMaksim Yevmenkin #else 596490c2ffSMaksim Yevmenkin #define SYSLOG fprintf 606490c2ffSMaksim Yevmenkin #define LOGCRIT stderr 616490c2ffSMaksim Yevmenkin #define LOGERR stderr 626490c2ffSMaksim Yevmenkin #define LOGWARNING stderr 636490c2ffSMaksim Yevmenkin #define EOL "\n" 646490c2ffSMaksim Yevmenkin #endif /* ndef BTHIDCONTROL */ 656490c2ffSMaksim Yevmenkin 66*e6508069SVladimir Kondratyev #define NAMELESS_DEVICE "No Name" 67*e6508069SVladimir Kondratyev 686490c2ffSMaksim Yevmenkin #include "bthid_config.h" 696490c2ffSMaksim Yevmenkin 706490c2ffSMaksim Yevmenkin int yylex (void); 717aebfa93SMaksim Yevmenkin void yyerror (char const *); 727aebfa93SMaksim Yevmenkin static int32_t check_hid_device(hid_device_p hid_device); 736490c2ffSMaksim Yevmenkin static void free_hid_device (hid_device_p hid_device); 746490c2ffSMaksim Yevmenkin 757aebfa93SMaksim Yevmenkin extern FILE *yyin; 766490c2ffSMaksim Yevmenkin extern int yylineno; 777aebfa93SMaksim Yevmenkin char const *config_file = BTHIDD_CONFFILE; 787aebfa93SMaksim Yevmenkin char const *hids_file = BTHIDD_HIDSFILE; 796490c2ffSMaksim Yevmenkin 806490c2ffSMaksim Yevmenkin static char buffer[1024]; 817aebfa93SMaksim Yevmenkin static int32_t hid_descriptor_size; 826490c2ffSMaksim Yevmenkin static hid_device_t *hid_device = NULL; 836490c2ffSMaksim Yevmenkin static LIST_HEAD(, hid_device) hid_devices; 846490c2ffSMaksim Yevmenkin 856490c2ffSMaksim Yevmenkin %} 866490c2ffSMaksim Yevmenkin 876490c2ffSMaksim Yevmenkin %union { 886490c2ffSMaksim Yevmenkin bdaddr_t bdaddr; 897aebfa93SMaksim Yevmenkin int32_t num; 90*e6508069SVladimir Kondratyev char *string; 916490c2ffSMaksim Yevmenkin } 926490c2ffSMaksim Yevmenkin 936490c2ffSMaksim Yevmenkin %token <bdaddr> T_BDADDRSTRING 946490c2ffSMaksim Yevmenkin %token <num> T_HEXBYTE 956032284eSVladimir Kondratyev %token <num> T_HEXWORD 96*e6508069SVladimir Kondratyev %token <string> T_STRING 97*e6508069SVladimir Kondratyev %token T_NAME 986032284eSVladimir Kondratyev %token T_DEVICE T_BDADDR T_VENDOR_ID T_PRODUCT_ID T_VERSION T_CONTROL_PSM 996032284eSVladimir Kondratyev %token T_INTERRUPT_PSM T_RECONNECT_INITIATE T_BATTERY_POWER 1006032284eSVladimir Kondratyev %token T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR 1016490c2ffSMaksim Yevmenkin %token T_TRUE T_FALSE T_ERROR 1026490c2ffSMaksim Yevmenkin 1036490c2ffSMaksim Yevmenkin %% 1046490c2ffSMaksim Yevmenkin 1056490c2ffSMaksim Yevmenkin config: line 1066490c2ffSMaksim Yevmenkin | config line 1076490c2ffSMaksim Yevmenkin ; 1086490c2ffSMaksim Yevmenkin 1096490c2ffSMaksim Yevmenkin line: T_DEVICE 1106490c2ffSMaksim Yevmenkin { 1116490c2ffSMaksim Yevmenkin hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device)); 1126490c2ffSMaksim Yevmenkin if (hid_device == NULL) { 1136490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "Could not allocate new " \ 1146490c2ffSMaksim Yevmenkin "config entry" EOL); 1156490c2ffSMaksim Yevmenkin YYABORT; 1166490c2ffSMaksim Yevmenkin } 1176490c2ffSMaksim Yevmenkin 1186490c2ffSMaksim Yevmenkin hid_device->new_device = 1; 1196490c2ffSMaksim Yevmenkin } 1206490c2ffSMaksim Yevmenkin '{' options '}' 1216490c2ffSMaksim Yevmenkin { 1226490c2ffSMaksim Yevmenkin if (check_hid_device(hid_device)) 1236490c2ffSMaksim Yevmenkin LIST_INSERT_HEAD(&hid_devices,hid_device,next); 1246490c2ffSMaksim Yevmenkin else 1256490c2ffSMaksim Yevmenkin free_hid_device(hid_device); 1266490c2ffSMaksim Yevmenkin 1276490c2ffSMaksim Yevmenkin hid_device = NULL; 1286490c2ffSMaksim Yevmenkin } 1296490c2ffSMaksim Yevmenkin ; 1306490c2ffSMaksim Yevmenkin 1316490c2ffSMaksim Yevmenkin options: option ';' 1326490c2ffSMaksim Yevmenkin | options option ';' 1336490c2ffSMaksim Yevmenkin ; 1346490c2ffSMaksim Yevmenkin 1356490c2ffSMaksim Yevmenkin option: bdaddr 136*e6508069SVladimir Kondratyev | name 1376032284eSVladimir Kondratyev | vendor_id 1386032284eSVladimir Kondratyev | product_id 1396032284eSVladimir Kondratyev | version 1406490c2ffSMaksim Yevmenkin | control_psm 1416490c2ffSMaksim Yevmenkin | interrupt_psm 1426490c2ffSMaksim Yevmenkin | reconnect_initiate 1436490c2ffSMaksim Yevmenkin | battery_power 1446490c2ffSMaksim Yevmenkin | normally_connectable 1456490c2ffSMaksim Yevmenkin | hid_descriptor 1466490c2ffSMaksim Yevmenkin | parser_error 1476490c2ffSMaksim Yevmenkin ; 1486490c2ffSMaksim Yevmenkin 1496490c2ffSMaksim Yevmenkin bdaddr: T_BDADDR T_BDADDRSTRING 1506490c2ffSMaksim Yevmenkin { 1516490c2ffSMaksim Yevmenkin memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr)); 1526490c2ffSMaksim Yevmenkin } 1536490c2ffSMaksim Yevmenkin ; 1546490c2ffSMaksim Yevmenkin 155*e6508069SVladimir Kondratyev name: T_NAME T_STRING 156*e6508069SVladimir Kondratyev { 157*e6508069SVladimir Kondratyev if (hid_device->name != NULL) { 158*e6508069SVladimir Kondratyev free(hid_device->name); 159*e6508069SVladimir Kondratyev hid_device->name = NULL; 160*e6508069SVladimir Kondratyev } 161*e6508069SVladimir Kondratyev 162*e6508069SVladimir Kondratyev if (strcmp($2, NAMELESS_DEVICE)) { 163*e6508069SVladimir Kondratyev hid_device->name = strdup($2); 164*e6508069SVladimir Kondratyev if (hid_device->name == NULL) { 165*e6508069SVladimir Kondratyev SYSLOG(LOGCRIT, "Could not allocate new " \ 166*e6508069SVladimir Kondratyev "device name" EOL); 167*e6508069SVladimir Kondratyev YYABORT; 168*e6508069SVladimir Kondratyev } 169*e6508069SVladimir Kondratyev } 170*e6508069SVladimir Kondratyev } 171*e6508069SVladimir Kondratyev ; 172*e6508069SVladimir Kondratyev 1736032284eSVladimir Kondratyev vendor_id: T_VENDOR_ID T_HEXWORD 1746032284eSVladimir Kondratyev { 1756032284eSVladimir Kondratyev hid_device->vendor_id = $2; 1766032284eSVladimir Kondratyev } 1776032284eSVladimir Kondratyev ; 1786032284eSVladimir Kondratyev 1796032284eSVladimir Kondratyev product_id: T_PRODUCT_ID T_HEXWORD 1806032284eSVladimir Kondratyev { 1816032284eSVladimir Kondratyev hid_device->product_id = $2; 1826032284eSVladimir Kondratyev } 1836032284eSVladimir Kondratyev ; 1846032284eSVladimir Kondratyev 1856032284eSVladimir Kondratyev version: T_VERSION T_HEXWORD 1866032284eSVladimir Kondratyev { 1876032284eSVladimir Kondratyev hid_device->version = $2; 1886032284eSVladimir Kondratyev } 1896032284eSVladimir Kondratyev ; 1906032284eSVladimir Kondratyev 1916490c2ffSMaksim Yevmenkin control_psm: T_CONTROL_PSM T_HEXBYTE 1926490c2ffSMaksim Yevmenkin { 1936490c2ffSMaksim Yevmenkin hid_device->control_psm = $2; 1946490c2ffSMaksim Yevmenkin } 1956490c2ffSMaksim Yevmenkin ; 1966490c2ffSMaksim Yevmenkin 1976490c2ffSMaksim Yevmenkin interrupt_psm: T_INTERRUPT_PSM T_HEXBYTE 1986490c2ffSMaksim Yevmenkin { 1996490c2ffSMaksim Yevmenkin hid_device->interrupt_psm = $2; 2006490c2ffSMaksim Yevmenkin } 2016490c2ffSMaksim Yevmenkin ; 2026490c2ffSMaksim Yevmenkin 2036490c2ffSMaksim Yevmenkin reconnect_initiate: T_RECONNECT_INITIATE T_TRUE 2046490c2ffSMaksim Yevmenkin { 2056490c2ffSMaksim Yevmenkin hid_device->reconnect_initiate = 1; 2066490c2ffSMaksim Yevmenkin } 2076490c2ffSMaksim Yevmenkin | T_RECONNECT_INITIATE T_FALSE 2086490c2ffSMaksim Yevmenkin { 2096490c2ffSMaksim Yevmenkin hid_device->reconnect_initiate = 0; 2106490c2ffSMaksim Yevmenkin } 2116490c2ffSMaksim Yevmenkin ; 2126490c2ffSMaksim Yevmenkin 2136490c2ffSMaksim Yevmenkin battery_power: T_BATTERY_POWER T_TRUE 2146490c2ffSMaksim Yevmenkin { 2156490c2ffSMaksim Yevmenkin hid_device->battery_power = 1; 2166490c2ffSMaksim Yevmenkin } 2176490c2ffSMaksim Yevmenkin | T_BATTERY_POWER T_FALSE 2186490c2ffSMaksim Yevmenkin { 2196490c2ffSMaksim Yevmenkin hid_device->battery_power = 0; 2206490c2ffSMaksim Yevmenkin } 2216490c2ffSMaksim Yevmenkin ; 2226490c2ffSMaksim Yevmenkin 2236490c2ffSMaksim Yevmenkin normally_connectable: T_NORMALLY_CONNECTABLE T_TRUE 2246490c2ffSMaksim Yevmenkin { 2256490c2ffSMaksim Yevmenkin hid_device->normally_connectable = 1; 2266490c2ffSMaksim Yevmenkin } 2276490c2ffSMaksim Yevmenkin | T_NORMALLY_CONNECTABLE T_FALSE 2286490c2ffSMaksim Yevmenkin { 2296490c2ffSMaksim Yevmenkin hid_device->normally_connectable = 0; 2306490c2ffSMaksim Yevmenkin } 2316490c2ffSMaksim Yevmenkin ; 2326490c2ffSMaksim Yevmenkin 2336490c2ffSMaksim Yevmenkin hid_descriptor: T_HID_DESCRIPTOR 2346490c2ffSMaksim Yevmenkin { 2356490c2ffSMaksim Yevmenkin hid_descriptor_size = 0; 2366490c2ffSMaksim Yevmenkin } 2376490c2ffSMaksim Yevmenkin '{' hid_descriptor_bytes '}' 2386490c2ffSMaksim Yevmenkin { 2396490c2ffSMaksim Yevmenkin if (hid_device->desc != NULL) 2406490c2ffSMaksim Yevmenkin hid_dispose_report_desc(hid_device->desc); 2416490c2ffSMaksim Yevmenkin 2426e9bee64SMaksim Yevmenkin hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size); 2436490c2ffSMaksim Yevmenkin if (hid_device->desc == NULL) { 2446490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL); 2456490c2ffSMaksim Yevmenkin YYABORT; 2466490c2ffSMaksim Yevmenkin } 2476490c2ffSMaksim Yevmenkin } 2486490c2ffSMaksim Yevmenkin ; 2496490c2ffSMaksim Yevmenkin 2506490c2ffSMaksim Yevmenkin hid_descriptor_bytes: hid_descriptor_byte 2516490c2ffSMaksim Yevmenkin | hid_descriptor_bytes hid_descriptor_byte 2526490c2ffSMaksim Yevmenkin ; 2536490c2ffSMaksim Yevmenkin 2546490c2ffSMaksim Yevmenkin hid_descriptor_byte: T_HEXBYTE 2556490c2ffSMaksim Yevmenkin { 2567aebfa93SMaksim Yevmenkin if (hid_descriptor_size >= (int32_t) sizeof(buffer)) { 2576490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "HID descriptor is too big" EOL); 2586490c2ffSMaksim Yevmenkin YYABORT; 2596490c2ffSMaksim Yevmenkin } 2606490c2ffSMaksim Yevmenkin 2616490c2ffSMaksim Yevmenkin buffer[hid_descriptor_size ++] = $1; 2626490c2ffSMaksim Yevmenkin } 2636490c2ffSMaksim Yevmenkin ; 2646490c2ffSMaksim Yevmenkin 2656490c2ffSMaksim Yevmenkin parser_error: T_ERROR 2666490c2ffSMaksim Yevmenkin { 2676490c2ffSMaksim Yevmenkin YYABORT; 2686490c2ffSMaksim Yevmenkin } 2696490c2ffSMaksim Yevmenkin 2706490c2ffSMaksim Yevmenkin %% 2716490c2ffSMaksim Yevmenkin 2726490c2ffSMaksim Yevmenkin /* Display parser error message */ 2736490c2ffSMaksim Yevmenkin void 2746490c2ffSMaksim Yevmenkin yyerror(char const *message) 2756490c2ffSMaksim Yevmenkin { 2766490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno); 2776490c2ffSMaksim Yevmenkin } 2786490c2ffSMaksim Yevmenkin 2796490c2ffSMaksim Yevmenkin /* Re-read config file */ 2807aebfa93SMaksim Yevmenkin int32_t 2816490c2ffSMaksim Yevmenkin read_config_file(void) 2826490c2ffSMaksim Yevmenkin { 2837aebfa93SMaksim Yevmenkin int32_t e; 2846490c2ffSMaksim Yevmenkin 2856490c2ffSMaksim Yevmenkin if (config_file == NULL) { 2866490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown config file name!" EOL); 2876490c2ffSMaksim Yevmenkin return (-1); 2886490c2ffSMaksim Yevmenkin } 2896490c2ffSMaksim Yevmenkin 2906490c2ffSMaksim Yevmenkin if ((yyin = fopen(config_file, "r")) == NULL) { 2916490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL, 2926490c2ffSMaksim Yevmenkin config_file, strerror(errno), errno); 2936490c2ffSMaksim Yevmenkin return (-1); 2946490c2ffSMaksim Yevmenkin } 2956490c2ffSMaksim Yevmenkin 2966490c2ffSMaksim Yevmenkin clean_config(); 2976490c2ffSMaksim Yevmenkin if (yyparse() < 0) { 2986490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not parse config file '%s'" EOL, 2996490c2ffSMaksim Yevmenkin config_file); 3006490c2ffSMaksim Yevmenkin e = -1; 3016490c2ffSMaksim Yevmenkin } else 3026490c2ffSMaksim Yevmenkin e = 0; 3036490c2ffSMaksim Yevmenkin 3046490c2ffSMaksim Yevmenkin fclose(yyin); 3056490c2ffSMaksim Yevmenkin yyin = NULL; 3066490c2ffSMaksim Yevmenkin 3076490c2ffSMaksim Yevmenkin return (e); 3086490c2ffSMaksim Yevmenkin } 3096490c2ffSMaksim Yevmenkin 3106490c2ffSMaksim Yevmenkin /* Clean config */ 3116490c2ffSMaksim Yevmenkin void 3126490c2ffSMaksim Yevmenkin clean_config(void) 3136490c2ffSMaksim Yevmenkin { 3146490c2ffSMaksim Yevmenkin while (!LIST_EMPTY(&hid_devices)) { 3157aebfa93SMaksim Yevmenkin hid_device_p d = LIST_FIRST(&hid_devices); 3166490c2ffSMaksim Yevmenkin 3177aebfa93SMaksim Yevmenkin LIST_REMOVE(d, next); 3187aebfa93SMaksim Yevmenkin free_hid_device(d); 3196490c2ffSMaksim Yevmenkin } 3206490c2ffSMaksim Yevmenkin } 3216490c2ffSMaksim Yevmenkin 3226490c2ffSMaksim Yevmenkin /* Lookup config entry */ 3236490c2ffSMaksim Yevmenkin hid_device_p 3246490c2ffSMaksim Yevmenkin get_hid_device(bdaddr_p bdaddr) 3256490c2ffSMaksim Yevmenkin { 3267aebfa93SMaksim Yevmenkin hid_device_p d; 3276490c2ffSMaksim Yevmenkin 3287aebfa93SMaksim Yevmenkin LIST_FOREACH(d, &hid_devices, next) 3297aebfa93SMaksim Yevmenkin if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0) 3306490c2ffSMaksim Yevmenkin break; 3316490c2ffSMaksim Yevmenkin 3327aebfa93SMaksim Yevmenkin return (d); 3336490c2ffSMaksim Yevmenkin } 3346490c2ffSMaksim Yevmenkin 3356490c2ffSMaksim Yevmenkin /* Get next config entry */ 3366490c2ffSMaksim Yevmenkin hid_device_p 3376490c2ffSMaksim Yevmenkin get_next_hid_device(hid_device_p d) 3386490c2ffSMaksim Yevmenkin { 3396490c2ffSMaksim Yevmenkin return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next)); 3406490c2ffSMaksim Yevmenkin } 3416490c2ffSMaksim Yevmenkin 3426490c2ffSMaksim Yevmenkin /* Print config entry */ 3436490c2ffSMaksim Yevmenkin void 3447aebfa93SMaksim Yevmenkin print_hid_device(hid_device_p d, FILE *f) 3456490c2ffSMaksim Yevmenkin { 3466490c2ffSMaksim Yevmenkin /* XXX FIXME hack! */ 3476490c2ffSMaksim Yevmenkin struct report_desc { 3486490c2ffSMaksim Yevmenkin unsigned int size; 3496490c2ffSMaksim Yevmenkin unsigned char data[1]; 3506490c2ffSMaksim Yevmenkin }; 3516490c2ffSMaksim Yevmenkin /* XXX FIXME hack! */ 3526490c2ffSMaksim Yevmenkin 3537aebfa93SMaksim Yevmenkin struct report_desc *desc = (struct report_desc *) d->desc; 3547aebfa93SMaksim Yevmenkin uint32_t i; 3556490c2ffSMaksim Yevmenkin 3566490c2ffSMaksim Yevmenkin fprintf(f, 3576490c2ffSMaksim Yevmenkin "device {\n" \ 3586490c2ffSMaksim Yevmenkin " bdaddr %s;\n" \ 359*e6508069SVladimir Kondratyev " name \"%s\";\n" \ 3606032284eSVladimir Kondratyev " vendor_id 0x%04x;\n" \ 3616032284eSVladimir Kondratyev " product_id 0x%04x;\n" \ 3626032284eSVladimir Kondratyev " version 0x%04x;\n" \ 3636490c2ffSMaksim Yevmenkin " control_psm 0x%x;\n" \ 3649fbe483aSMaksim Yevmenkin " interrupt_psm 0x%x;\n" \ 3656490c2ffSMaksim Yevmenkin " reconnect_initiate %s;\n" \ 3666490c2ffSMaksim Yevmenkin " battery_power %s;\n" \ 3676490c2ffSMaksim Yevmenkin " normally_connectable %s;\n" \ 3686490c2ffSMaksim Yevmenkin " hid_descriptor {", 3697aebfa93SMaksim Yevmenkin bt_ntoa(&d->bdaddr, NULL), 370*e6508069SVladimir Kondratyev (d->name != NULL)? d->name : NAMELESS_DEVICE, 3716032284eSVladimir Kondratyev d->vendor_id, d->product_id, d->version, 3727aebfa93SMaksim Yevmenkin d->control_psm, d->interrupt_psm, 3737aebfa93SMaksim Yevmenkin d->reconnect_initiate? "true" : "false", 3747aebfa93SMaksim Yevmenkin d->battery_power? "true" : "false", 3757aebfa93SMaksim Yevmenkin d->normally_connectable? "true" : "false"); 3766490c2ffSMaksim Yevmenkin 3776490c2ffSMaksim Yevmenkin for (i = 0; i < desc->size; i ++) { 3786490c2ffSMaksim Yevmenkin if ((i % 8) == 0) 379c46a9ea8SMaksim Yevmenkin fprintf(f, "\n "); 3806490c2ffSMaksim Yevmenkin 3816490c2ffSMaksim Yevmenkin fprintf(f, "0x%2.2x ", desc->data[i]); 3826490c2ffSMaksim Yevmenkin } 3836490c2ffSMaksim Yevmenkin 384c46a9ea8SMaksim Yevmenkin fprintf(f, 3856490c2ffSMaksim Yevmenkin "\n" \ 3866490c2ffSMaksim Yevmenkin " };\n" \ 3876490c2ffSMaksim Yevmenkin "}\n"); 3886490c2ffSMaksim Yevmenkin } 3896490c2ffSMaksim Yevmenkin 3906490c2ffSMaksim Yevmenkin /* Check config entry */ 3917aebfa93SMaksim Yevmenkin static int32_t 3927aebfa93SMaksim Yevmenkin check_hid_device(hid_device_p d) 3936490c2ffSMaksim Yevmenkin { 3947aebfa93SMaksim Yevmenkin hid_data_t hd; 3957aebfa93SMaksim Yevmenkin hid_item_t hi; 3967aebfa93SMaksim Yevmenkin int32_t page; 3977aebfa93SMaksim Yevmenkin 3987aebfa93SMaksim Yevmenkin if (get_hid_device(&d->bdaddr) != NULL) { 3996490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL, 4007aebfa93SMaksim Yevmenkin bt_ntoa(&d->bdaddr, NULL)); 4016490c2ffSMaksim Yevmenkin return (0); 4026490c2ffSMaksim Yevmenkin } 4036490c2ffSMaksim Yevmenkin 4047aebfa93SMaksim Yevmenkin if (d->control_psm == 0) { 4056490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL); 4066490c2ffSMaksim Yevmenkin return (0); 4076490c2ffSMaksim Yevmenkin } 4086490c2ffSMaksim Yevmenkin 4097aebfa93SMaksim Yevmenkin if (d->interrupt_psm == 0) { 4106490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL); 4116490c2ffSMaksim Yevmenkin return (0); 4126490c2ffSMaksim Yevmenkin } 4136490c2ffSMaksim Yevmenkin 4147aebfa93SMaksim Yevmenkin if (d->desc == NULL) { 4156490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL); 4166490c2ffSMaksim Yevmenkin return (0); 4176490c2ffSMaksim Yevmenkin } 4186490c2ffSMaksim Yevmenkin 4197aebfa93SMaksim Yevmenkin /* XXX somehow need to make sure descriptor is valid */ 4207aebfa93SMaksim Yevmenkin for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) { 4217aebfa93SMaksim Yevmenkin switch (hi.kind) { 4227aebfa93SMaksim Yevmenkin case hid_collection: 4237aebfa93SMaksim Yevmenkin case hid_endcollection: 4247aebfa93SMaksim Yevmenkin case hid_output: 4257aebfa93SMaksim Yevmenkin case hid_feature: 4267aebfa93SMaksim Yevmenkin break; 4277aebfa93SMaksim Yevmenkin 4287aebfa93SMaksim Yevmenkin case hid_input: 4297aebfa93SMaksim Yevmenkin /* Check if the device may send keystrokes */ 4307aebfa93SMaksim Yevmenkin page = HID_PAGE(hi.usage); 43106912ebaSMaksim Yevmenkin if (page == HUP_KEYBOARD) 4327aebfa93SMaksim Yevmenkin d->keyboard = 1; 4337aebfa93SMaksim Yevmenkin break; 4347aebfa93SMaksim Yevmenkin } 4357aebfa93SMaksim Yevmenkin } 4367aebfa93SMaksim Yevmenkin hid_end_parse(hd); 4377aebfa93SMaksim Yevmenkin 4386490c2ffSMaksim Yevmenkin return (1); 4396490c2ffSMaksim Yevmenkin } 4406490c2ffSMaksim Yevmenkin 4416490c2ffSMaksim Yevmenkin /* Free config entry */ 4426490c2ffSMaksim Yevmenkin static void 4437aebfa93SMaksim Yevmenkin free_hid_device(hid_device_p d) 4446490c2ffSMaksim Yevmenkin { 4457aebfa93SMaksim Yevmenkin if (d->desc != NULL) 4467aebfa93SMaksim Yevmenkin hid_dispose_report_desc(d->desc); 4476490c2ffSMaksim Yevmenkin 448*e6508069SVladimir Kondratyev free(d->name); 4497aebfa93SMaksim Yevmenkin memset(d, 0, sizeof(*d)); 4507aebfa93SMaksim Yevmenkin free(d); 4516490c2ffSMaksim Yevmenkin } 4526490c2ffSMaksim Yevmenkin 4536490c2ffSMaksim Yevmenkin /* Re-read hids file */ 4547aebfa93SMaksim Yevmenkin int32_t 4556490c2ffSMaksim Yevmenkin read_hids_file(void) 4566490c2ffSMaksim Yevmenkin { 4577aebfa93SMaksim Yevmenkin FILE *f; 4587aebfa93SMaksim Yevmenkin hid_device_t *d; 4597aebfa93SMaksim Yevmenkin char *line; 4606490c2ffSMaksim Yevmenkin bdaddr_t bdaddr; 4617aebfa93SMaksim Yevmenkin int32_t lineno; 4626490c2ffSMaksim Yevmenkin 4636490c2ffSMaksim Yevmenkin if (hids_file == NULL) { 4646490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 4656490c2ffSMaksim Yevmenkin return (-1); 4666490c2ffSMaksim Yevmenkin } 4676490c2ffSMaksim Yevmenkin 4686490c2ffSMaksim Yevmenkin if ((f = fopen(hids_file, "r")) == NULL) { 4696490c2ffSMaksim Yevmenkin if (errno == ENOENT) 4706490c2ffSMaksim Yevmenkin return (0); 4716490c2ffSMaksim Yevmenkin 4726490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 4736490c2ffSMaksim Yevmenkin hids_file, strerror(errno), errno); 4746490c2ffSMaksim Yevmenkin return (-1); 4756490c2ffSMaksim Yevmenkin } 4766490c2ffSMaksim Yevmenkin 4776490c2ffSMaksim Yevmenkin for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) { 4786490c2ffSMaksim Yevmenkin if ((line = strtok(buffer, "\r\n\t ")) == NULL) 4796490c2ffSMaksim Yevmenkin continue; /* ignore empty lines */ 4806490c2ffSMaksim Yevmenkin 4816490c2ffSMaksim Yevmenkin if (!bt_aton(line, &bdaddr)) { 4826490c2ffSMaksim Yevmenkin SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \ 4836490c2ffSMaksim Yevmenkin "%s:%d" EOL, hids_file, lineno); 4846490c2ffSMaksim Yevmenkin continue; 4856490c2ffSMaksim Yevmenkin } 4866490c2ffSMaksim Yevmenkin 4877aebfa93SMaksim Yevmenkin if ((d = get_hid_device(&bdaddr)) != NULL) 4887aebfa93SMaksim Yevmenkin d->new_device = 0; 4896490c2ffSMaksim Yevmenkin } 4906490c2ffSMaksim Yevmenkin 4916490c2ffSMaksim Yevmenkin fclose(f); 4926490c2ffSMaksim Yevmenkin 4936490c2ffSMaksim Yevmenkin return (0); 4946490c2ffSMaksim Yevmenkin } 4956490c2ffSMaksim Yevmenkin 4966490c2ffSMaksim Yevmenkin /* Write hids file */ 4977aebfa93SMaksim Yevmenkin int32_t 4986490c2ffSMaksim Yevmenkin write_hids_file(void) 4996490c2ffSMaksim Yevmenkin { 5006490c2ffSMaksim Yevmenkin char path[PATH_MAX]; 5017aebfa93SMaksim Yevmenkin FILE *f; 5027aebfa93SMaksim Yevmenkin hid_device_t *d; 5036490c2ffSMaksim Yevmenkin 5046490c2ffSMaksim Yevmenkin if (hids_file == NULL) { 5056490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 5066490c2ffSMaksim Yevmenkin return (-1); 5076490c2ffSMaksim Yevmenkin } 5086490c2ffSMaksim Yevmenkin 5096490c2ffSMaksim Yevmenkin snprintf(path, sizeof(path), "%s.new", hids_file); 5106490c2ffSMaksim Yevmenkin 5116490c2ffSMaksim Yevmenkin if ((f = fopen(path, "w")) == NULL) { 5126490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 5136490c2ffSMaksim Yevmenkin path, strerror(errno), errno); 5146490c2ffSMaksim Yevmenkin return (-1); 5156490c2ffSMaksim Yevmenkin } 5166490c2ffSMaksim Yevmenkin 5177aebfa93SMaksim Yevmenkin LIST_FOREACH(d, &hid_devices, next) 5187aebfa93SMaksim Yevmenkin if (!d->new_device) 5197aebfa93SMaksim Yevmenkin fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL)); 5206490c2ffSMaksim Yevmenkin 5216490c2ffSMaksim Yevmenkin fclose(f); 5226490c2ffSMaksim Yevmenkin 5236490c2ffSMaksim Yevmenkin if (rename(path, hids_file) < 0) { 5246490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \ 5256490c2ffSMaksim Yevmenkin "%s (%d)" EOL, path, hids_file, strerror(errno), errno); 5266490c2ffSMaksim Yevmenkin unlink(path); 5276490c2ffSMaksim Yevmenkin return (-1); 5286490c2ffSMaksim Yevmenkin } 5296490c2ffSMaksim Yevmenkin 5306490c2ffSMaksim Yevmenkin return (0); 5316490c2ffSMaksim Yevmenkin } 5326490c2ffSMaksim Yevmenkin 533