16490c2ffSMaksim Yevmenkin %{ 26490c2ffSMaksim Yevmenkin /* 36490c2ffSMaksim Yevmenkin * parser.y 46490c2ffSMaksim Yevmenkin * 56490c2ffSMaksim Yevmenkin * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 66490c2ffSMaksim Yevmenkin * All rights reserved. 76490c2ffSMaksim Yevmenkin * 86490c2ffSMaksim Yevmenkin * Redistribution and use in source and binary forms, with or without 96490c2ffSMaksim Yevmenkin * modification, are permitted provided that the following conditions 106490c2ffSMaksim Yevmenkin * are met: 116490c2ffSMaksim Yevmenkin * 1. Redistributions of source code must retain the above copyright 126490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer. 136490c2ffSMaksim Yevmenkin * 2. Redistributions in binary form must reproduce the above copyright 146490c2ffSMaksim Yevmenkin * notice, this list of conditions and the following disclaimer in the 156490c2ffSMaksim Yevmenkin * documentation and/or other materials provided with the distribution. 166490c2ffSMaksim Yevmenkin * 176490c2ffSMaksim Yevmenkin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 186490c2ffSMaksim Yevmenkin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 196490c2ffSMaksim Yevmenkin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 206490c2ffSMaksim Yevmenkin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 216490c2ffSMaksim Yevmenkin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 226490c2ffSMaksim Yevmenkin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 236490c2ffSMaksim Yevmenkin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 246490c2ffSMaksim Yevmenkin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 256490c2ffSMaksim Yevmenkin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 266490c2ffSMaksim Yevmenkin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 276490c2ffSMaksim Yevmenkin * SUCH DAMAGE. 286490c2ffSMaksim Yevmenkin * 293adfd74aSMaksim Yevmenkin * $Id: parser.y,v 1.4 2004/11/17 21:59:42 max Exp $ 306490c2ffSMaksim Yevmenkin * $FreeBSD$ 316490c2ffSMaksim Yevmenkin */ 326490c2ffSMaksim Yevmenkin 336490c2ffSMaksim Yevmenkin #include <sys/queue.h> 346490c2ffSMaksim Yevmenkin #include <bluetooth.h> 356490c2ffSMaksim Yevmenkin #include <errno.h> 366490c2ffSMaksim Yevmenkin #include <limits.h> 376490c2ffSMaksim Yevmenkin #include <stdio.h> 386490c2ffSMaksim Yevmenkin #include <string.h> 396490c2ffSMaksim Yevmenkin #include <unistd.h> 403adfd74aSMaksim Yevmenkin #include <usbhid.h> 416490c2ffSMaksim Yevmenkin 426490c2ffSMaksim Yevmenkin #ifndef BTHIDCONTROL 436490c2ffSMaksim Yevmenkin #include <stdarg.h> 446490c2ffSMaksim Yevmenkin #include <syslog.h> 456490c2ffSMaksim Yevmenkin #define SYSLOG syslog 466490c2ffSMaksim Yevmenkin #define LOGCRIT LOG_CRIT 476490c2ffSMaksim Yevmenkin #define LOGERR LOG_ERR 486490c2ffSMaksim Yevmenkin #define LOGWARNING LOG_WARNING 496490c2ffSMaksim Yevmenkin #define EOL 506490c2ffSMaksim Yevmenkin #else 516490c2ffSMaksim Yevmenkin #define SYSLOG fprintf 526490c2ffSMaksim Yevmenkin #define LOGCRIT stderr 536490c2ffSMaksim Yevmenkin #define LOGERR stderr 546490c2ffSMaksim Yevmenkin #define LOGWARNING stderr 556490c2ffSMaksim Yevmenkin #define EOL "\n" 566490c2ffSMaksim Yevmenkin #endif /* ndef BTHIDCONTROL */ 576490c2ffSMaksim Yevmenkin 586490c2ffSMaksim Yevmenkin #include "bthid_config.h" 596490c2ffSMaksim Yevmenkin 606490c2ffSMaksim Yevmenkin int yyparse (void); 616490c2ffSMaksim Yevmenkin int yylex (void); 626490c2ffSMaksim Yevmenkin static int check_hid_device(hid_device_p hid_device); 636490c2ffSMaksim Yevmenkin static void free_hid_device (hid_device_p hid_device); 646490c2ffSMaksim Yevmenkin 656490c2ffSMaksim Yevmenkin extern int yylineno; 666490c2ffSMaksim Yevmenkin char *config_file = BTHIDD_CONFFILE; 676490c2ffSMaksim Yevmenkin char *hids_file = BTHIDD_HIDSFILE; 686490c2ffSMaksim Yevmenkin 696490c2ffSMaksim Yevmenkin static char buffer[1024]; 706490c2ffSMaksim Yevmenkin static int hid_descriptor_size; 716490c2ffSMaksim Yevmenkin static hid_device_t *hid_device = NULL; 726490c2ffSMaksim Yevmenkin static LIST_HEAD(, hid_device) hid_devices; 736490c2ffSMaksim Yevmenkin 746490c2ffSMaksim Yevmenkin %} 756490c2ffSMaksim Yevmenkin 766490c2ffSMaksim Yevmenkin %union { 776490c2ffSMaksim Yevmenkin bdaddr_t bdaddr; 786490c2ffSMaksim Yevmenkin int num; 796490c2ffSMaksim Yevmenkin } 806490c2ffSMaksim Yevmenkin 816490c2ffSMaksim Yevmenkin %token <bdaddr> T_BDADDRSTRING 826490c2ffSMaksim Yevmenkin %token <num> T_HEXBYTE 836490c2ffSMaksim Yevmenkin %token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE 846490c2ffSMaksim Yevmenkin %token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR 856490c2ffSMaksim Yevmenkin %token T_TRUE T_FALSE T_ERROR 866490c2ffSMaksim Yevmenkin 876490c2ffSMaksim Yevmenkin %% 886490c2ffSMaksim Yevmenkin 896490c2ffSMaksim Yevmenkin config: line 906490c2ffSMaksim Yevmenkin | config line 916490c2ffSMaksim Yevmenkin ; 926490c2ffSMaksim Yevmenkin 936490c2ffSMaksim Yevmenkin line: T_DEVICE 946490c2ffSMaksim Yevmenkin { 956490c2ffSMaksim Yevmenkin hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device)); 966490c2ffSMaksim Yevmenkin if (hid_device == NULL) { 976490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "Could not allocate new " \ 986490c2ffSMaksim Yevmenkin "config entry" EOL); 996490c2ffSMaksim Yevmenkin YYABORT; 1006490c2ffSMaksim Yevmenkin } 1016490c2ffSMaksim Yevmenkin 1026490c2ffSMaksim Yevmenkin hid_device->new_device = 1; 1036490c2ffSMaksim Yevmenkin } 1046490c2ffSMaksim Yevmenkin '{' options '}' 1056490c2ffSMaksim Yevmenkin { 1066490c2ffSMaksim Yevmenkin if (check_hid_device(hid_device)) 1076490c2ffSMaksim Yevmenkin LIST_INSERT_HEAD(&hid_devices,hid_device,next); 1086490c2ffSMaksim Yevmenkin else 1096490c2ffSMaksim Yevmenkin free_hid_device(hid_device); 1106490c2ffSMaksim Yevmenkin 1116490c2ffSMaksim Yevmenkin hid_device = NULL; 1126490c2ffSMaksim Yevmenkin } 1136490c2ffSMaksim Yevmenkin ; 1146490c2ffSMaksim Yevmenkin 1156490c2ffSMaksim Yevmenkin options: option ';' 1166490c2ffSMaksim Yevmenkin | options option ';' 1176490c2ffSMaksim Yevmenkin ; 1186490c2ffSMaksim Yevmenkin 1196490c2ffSMaksim Yevmenkin option: bdaddr 1206490c2ffSMaksim Yevmenkin | control_psm 1216490c2ffSMaksim Yevmenkin | interrupt_psm 1226490c2ffSMaksim Yevmenkin | reconnect_initiate 1236490c2ffSMaksim Yevmenkin | battery_power 1246490c2ffSMaksim Yevmenkin | normally_connectable 1256490c2ffSMaksim Yevmenkin | hid_descriptor 1266490c2ffSMaksim Yevmenkin | parser_error 1276490c2ffSMaksim Yevmenkin ; 1286490c2ffSMaksim Yevmenkin 1296490c2ffSMaksim Yevmenkin bdaddr: T_BDADDR T_BDADDRSTRING 1306490c2ffSMaksim Yevmenkin { 1316490c2ffSMaksim Yevmenkin memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr)); 1326490c2ffSMaksim Yevmenkin } 1336490c2ffSMaksim Yevmenkin ; 1346490c2ffSMaksim Yevmenkin 1356490c2ffSMaksim Yevmenkin control_psm: T_CONTROL_PSM T_HEXBYTE 1366490c2ffSMaksim Yevmenkin { 1376490c2ffSMaksim Yevmenkin hid_device->control_psm = $2; 1386490c2ffSMaksim Yevmenkin } 1396490c2ffSMaksim Yevmenkin ; 1406490c2ffSMaksim Yevmenkin 1416490c2ffSMaksim Yevmenkin interrupt_psm: T_INTERRUPT_PSM T_HEXBYTE 1426490c2ffSMaksim Yevmenkin { 1436490c2ffSMaksim Yevmenkin hid_device->interrupt_psm = $2; 1446490c2ffSMaksim Yevmenkin } 1456490c2ffSMaksim Yevmenkin ; 1466490c2ffSMaksim Yevmenkin 1476490c2ffSMaksim Yevmenkin reconnect_initiate: T_RECONNECT_INITIATE T_TRUE 1486490c2ffSMaksim Yevmenkin { 1496490c2ffSMaksim Yevmenkin hid_device->reconnect_initiate = 1; 1506490c2ffSMaksim Yevmenkin } 1516490c2ffSMaksim Yevmenkin | T_RECONNECT_INITIATE T_FALSE 1526490c2ffSMaksim Yevmenkin { 1536490c2ffSMaksim Yevmenkin hid_device->reconnect_initiate = 0; 1546490c2ffSMaksim Yevmenkin } 1556490c2ffSMaksim Yevmenkin ; 1566490c2ffSMaksim Yevmenkin 1576490c2ffSMaksim Yevmenkin battery_power: T_BATTERY_POWER T_TRUE 1586490c2ffSMaksim Yevmenkin { 1596490c2ffSMaksim Yevmenkin hid_device->battery_power = 1; 1606490c2ffSMaksim Yevmenkin } 1616490c2ffSMaksim Yevmenkin | T_BATTERY_POWER T_FALSE 1626490c2ffSMaksim Yevmenkin { 1636490c2ffSMaksim Yevmenkin hid_device->battery_power = 0; 1646490c2ffSMaksim Yevmenkin } 1656490c2ffSMaksim Yevmenkin ; 1666490c2ffSMaksim Yevmenkin 1676490c2ffSMaksim Yevmenkin normally_connectable: T_NORMALLY_CONNECTABLE T_TRUE 1686490c2ffSMaksim Yevmenkin { 1696490c2ffSMaksim Yevmenkin hid_device->normally_connectable = 1; 1706490c2ffSMaksim Yevmenkin } 1716490c2ffSMaksim Yevmenkin | T_NORMALLY_CONNECTABLE T_FALSE 1726490c2ffSMaksim Yevmenkin { 1736490c2ffSMaksim Yevmenkin hid_device->normally_connectable = 0; 1746490c2ffSMaksim Yevmenkin } 1756490c2ffSMaksim Yevmenkin ; 1766490c2ffSMaksim Yevmenkin 1776490c2ffSMaksim Yevmenkin hid_descriptor: T_HID_DESCRIPTOR 1786490c2ffSMaksim Yevmenkin { 1796490c2ffSMaksim Yevmenkin hid_descriptor_size = 0; 1806490c2ffSMaksim Yevmenkin } 1816490c2ffSMaksim Yevmenkin '{' hid_descriptor_bytes '}' 1826490c2ffSMaksim Yevmenkin { 1836490c2ffSMaksim Yevmenkin if (hid_device->desc != NULL) 1846490c2ffSMaksim Yevmenkin hid_dispose_report_desc(hid_device->desc); 1856490c2ffSMaksim Yevmenkin 1866490c2ffSMaksim Yevmenkin hid_device->desc = hid_use_report_desc(buffer, hid_descriptor_size); 1876490c2ffSMaksim Yevmenkin if (hid_device->desc == NULL) { 1886490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL); 1896490c2ffSMaksim Yevmenkin YYABORT; 1906490c2ffSMaksim Yevmenkin } 1916490c2ffSMaksim Yevmenkin } 1926490c2ffSMaksim Yevmenkin ; 1936490c2ffSMaksim Yevmenkin 1946490c2ffSMaksim Yevmenkin hid_descriptor_bytes: hid_descriptor_byte 1956490c2ffSMaksim Yevmenkin | hid_descriptor_bytes hid_descriptor_byte 1966490c2ffSMaksim Yevmenkin ; 1976490c2ffSMaksim Yevmenkin 1986490c2ffSMaksim Yevmenkin hid_descriptor_byte: T_HEXBYTE 1996490c2ffSMaksim Yevmenkin { 2006490c2ffSMaksim Yevmenkin if (hid_descriptor_size >= sizeof(buffer)) { 2016490c2ffSMaksim Yevmenkin SYSLOG(LOGCRIT, "HID descriptor is too big" EOL); 2026490c2ffSMaksim Yevmenkin YYABORT; 2036490c2ffSMaksim Yevmenkin } 2046490c2ffSMaksim Yevmenkin 2056490c2ffSMaksim Yevmenkin buffer[hid_descriptor_size ++] = $1; 2066490c2ffSMaksim Yevmenkin } 2076490c2ffSMaksim Yevmenkin ; 2086490c2ffSMaksim Yevmenkin 2096490c2ffSMaksim Yevmenkin parser_error: T_ERROR 2106490c2ffSMaksim Yevmenkin { 2116490c2ffSMaksim Yevmenkin YYABORT; 2126490c2ffSMaksim Yevmenkin } 2136490c2ffSMaksim Yevmenkin 2146490c2ffSMaksim Yevmenkin %% 2156490c2ffSMaksim Yevmenkin 2166490c2ffSMaksim Yevmenkin /* Display parser error message */ 2176490c2ffSMaksim Yevmenkin void 2186490c2ffSMaksim Yevmenkin yyerror(char const *message) 2196490c2ffSMaksim Yevmenkin { 2206490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno); 2216490c2ffSMaksim Yevmenkin } 2226490c2ffSMaksim Yevmenkin 2236490c2ffSMaksim Yevmenkin /* Re-read config file */ 2246490c2ffSMaksim Yevmenkin int 2256490c2ffSMaksim Yevmenkin read_config_file(void) 2266490c2ffSMaksim Yevmenkin { 2276490c2ffSMaksim Yevmenkin extern FILE *yyin; 2286490c2ffSMaksim Yevmenkin int e; 2296490c2ffSMaksim Yevmenkin 2306490c2ffSMaksim Yevmenkin if (config_file == NULL) { 2316490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown config file name!" EOL); 2326490c2ffSMaksim Yevmenkin return (-1); 2336490c2ffSMaksim Yevmenkin } 2346490c2ffSMaksim Yevmenkin 2356490c2ffSMaksim Yevmenkin if ((yyin = fopen(config_file, "r")) == NULL) { 2366490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL, 2376490c2ffSMaksim Yevmenkin config_file, strerror(errno), errno); 2386490c2ffSMaksim Yevmenkin return (-1); 2396490c2ffSMaksim Yevmenkin } 2406490c2ffSMaksim Yevmenkin 2416490c2ffSMaksim Yevmenkin clean_config(); 2426490c2ffSMaksim Yevmenkin if (yyparse() < 0) { 2436490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not parse config file '%s'" EOL, 2446490c2ffSMaksim Yevmenkin config_file); 2456490c2ffSMaksim Yevmenkin e = -1; 2466490c2ffSMaksim Yevmenkin } else 2476490c2ffSMaksim Yevmenkin e = 0; 2486490c2ffSMaksim Yevmenkin 2496490c2ffSMaksim Yevmenkin fclose(yyin); 2506490c2ffSMaksim Yevmenkin yyin = NULL; 2516490c2ffSMaksim Yevmenkin 2526490c2ffSMaksim Yevmenkin return (e); 2536490c2ffSMaksim Yevmenkin } 2546490c2ffSMaksim Yevmenkin 2556490c2ffSMaksim Yevmenkin /* Clean config */ 2566490c2ffSMaksim Yevmenkin void 2576490c2ffSMaksim Yevmenkin clean_config(void) 2586490c2ffSMaksim Yevmenkin { 2596490c2ffSMaksim Yevmenkin while (!LIST_EMPTY(&hid_devices)) { 2606490c2ffSMaksim Yevmenkin hid_device_p hid_device = LIST_FIRST(&hid_devices); 2616490c2ffSMaksim Yevmenkin 2626490c2ffSMaksim Yevmenkin LIST_REMOVE(hid_device, next); 2636490c2ffSMaksim Yevmenkin free_hid_device(hid_device); 2646490c2ffSMaksim Yevmenkin } 2656490c2ffSMaksim Yevmenkin } 2666490c2ffSMaksim Yevmenkin 2676490c2ffSMaksim Yevmenkin /* Lookup config entry */ 2686490c2ffSMaksim Yevmenkin hid_device_p 2696490c2ffSMaksim Yevmenkin get_hid_device(bdaddr_p bdaddr) 2706490c2ffSMaksim Yevmenkin { 2716490c2ffSMaksim Yevmenkin hid_device_p hid_device; 2726490c2ffSMaksim Yevmenkin 2736490c2ffSMaksim Yevmenkin LIST_FOREACH(hid_device, &hid_devices, next) 2746490c2ffSMaksim Yevmenkin if (memcmp(&hid_device->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0) 2756490c2ffSMaksim Yevmenkin break; 2766490c2ffSMaksim Yevmenkin 2776490c2ffSMaksim Yevmenkin return (hid_device); 2786490c2ffSMaksim Yevmenkin } 2796490c2ffSMaksim Yevmenkin 2806490c2ffSMaksim Yevmenkin /* Get next config entry */ 2816490c2ffSMaksim Yevmenkin hid_device_p 2826490c2ffSMaksim Yevmenkin get_next_hid_device(hid_device_p d) 2836490c2ffSMaksim Yevmenkin { 2846490c2ffSMaksim Yevmenkin return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next)); 2856490c2ffSMaksim Yevmenkin } 2866490c2ffSMaksim Yevmenkin 2876490c2ffSMaksim Yevmenkin /* Print config entry */ 2886490c2ffSMaksim Yevmenkin void 2896490c2ffSMaksim Yevmenkin print_hid_device(hid_device_p hid_device, FILE *f) 2906490c2ffSMaksim Yevmenkin { 2916490c2ffSMaksim Yevmenkin /* XXX FIXME hack! */ 2926490c2ffSMaksim Yevmenkin struct report_desc { 2936490c2ffSMaksim Yevmenkin unsigned int size; 2946490c2ffSMaksim Yevmenkin unsigned char data[1]; 2956490c2ffSMaksim Yevmenkin }; 2966490c2ffSMaksim Yevmenkin /* XXX FIXME hack! */ 2976490c2ffSMaksim Yevmenkin 2986490c2ffSMaksim Yevmenkin struct report_desc *desc = (struct report_desc *) hid_device->desc; 2996490c2ffSMaksim Yevmenkin int i; 3006490c2ffSMaksim Yevmenkin 3016490c2ffSMaksim Yevmenkin fprintf(f, 3026490c2ffSMaksim Yevmenkin "device {\n" \ 3036490c2ffSMaksim Yevmenkin " bdaddr %s;\n" \ 3046490c2ffSMaksim Yevmenkin " control_psm 0x%x;\n" \ 3056490c2ffSMaksim Yevmenkin " interrupt_psm 0x%d;\n" \ 3066490c2ffSMaksim Yevmenkin " reconnect_initiate %s;\n" \ 3076490c2ffSMaksim Yevmenkin " battery_power %s;\n" \ 3086490c2ffSMaksim Yevmenkin " normally_connectable %s;\n" \ 3096490c2ffSMaksim Yevmenkin " hid_descriptor {", 3106490c2ffSMaksim Yevmenkin bt_ntoa(&hid_device->bdaddr, NULL), 3116490c2ffSMaksim Yevmenkin hid_device->control_psm, hid_device->interrupt_psm, 3126490c2ffSMaksim Yevmenkin hid_device->reconnect_initiate? "true" : "false", 3136490c2ffSMaksim Yevmenkin hid_device->battery_power? "true" : "false", 3146490c2ffSMaksim Yevmenkin hid_device->normally_connectable? "true" : "false"); 3156490c2ffSMaksim Yevmenkin 3166490c2ffSMaksim Yevmenkin for (i = 0; i < desc->size; i ++) { 3176490c2ffSMaksim Yevmenkin if ((i % 8) == 0) 3186490c2ffSMaksim Yevmenkin fprintf(stdout, "\n "); 3196490c2ffSMaksim Yevmenkin 3206490c2ffSMaksim Yevmenkin fprintf(f, "0x%2.2x ", desc->data[i]); 3216490c2ffSMaksim Yevmenkin } 3226490c2ffSMaksim Yevmenkin 3236490c2ffSMaksim Yevmenkin fprintf(stdout, 3246490c2ffSMaksim Yevmenkin "\n" \ 3256490c2ffSMaksim Yevmenkin " };\n" \ 3266490c2ffSMaksim Yevmenkin "}\n"); 3276490c2ffSMaksim Yevmenkin } 3286490c2ffSMaksim Yevmenkin 3296490c2ffSMaksim Yevmenkin /* Check config entry */ 3306490c2ffSMaksim Yevmenkin static int 3316490c2ffSMaksim Yevmenkin check_hid_device(hid_device_p hid_device) 3326490c2ffSMaksim Yevmenkin { 3336490c2ffSMaksim Yevmenkin if (get_hid_device(&hid_device->bdaddr) != NULL) { 3346490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL, 3356490c2ffSMaksim Yevmenkin bt_ntoa(&hid_device->bdaddr, NULL)); 3366490c2ffSMaksim Yevmenkin return (0); 3376490c2ffSMaksim Yevmenkin } 3386490c2ffSMaksim Yevmenkin 3396490c2ffSMaksim Yevmenkin if (hid_device->control_psm == 0) { 3406490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL); 3416490c2ffSMaksim Yevmenkin return (0); 3426490c2ffSMaksim Yevmenkin } 3436490c2ffSMaksim Yevmenkin 3446490c2ffSMaksim Yevmenkin if (hid_device->interrupt_psm == 0) { 3456490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL); 3466490c2ffSMaksim Yevmenkin return (0); 3476490c2ffSMaksim Yevmenkin } 3486490c2ffSMaksim Yevmenkin 3496490c2ffSMaksim Yevmenkin if (hid_device->desc == NULL) { 3506490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL); 3516490c2ffSMaksim Yevmenkin return (0); 3526490c2ffSMaksim Yevmenkin } 3536490c2ffSMaksim Yevmenkin 3546490c2ffSMaksim Yevmenkin return (1); 3556490c2ffSMaksim Yevmenkin } 3566490c2ffSMaksim Yevmenkin 3576490c2ffSMaksim Yevmenkin /* Free config entry */ 3586490c2ffSMaksim Yevmenkin static void 3596490c2ffSMaksim Yevmenkin free_hid_device(hid_device_p hid_device) 3606490c2ffSMaksim Yevmenkin { 3616490c2ffSMaksim Yevmenkin if (hid_device->desc != NULL) 3626490c2ffSMaksim Yevmenkin hid_dispose_report_desc(hid_device->desc); 3636490c2ffSMaksim Yevmenkin 3646490c2ffSMaksim Yevmenkin memset(hid_device, 0, sizeof(*hid_device)); 3656490c2ffSMaksim Yevmenkin free(hid_device); 3666490c2ffSMaksim Yevmenkin } 3676490c2ffSMaksim Yevmenkin 3686490c2ffSMaksim Yevmenkin /* Re-read hids file */ 3696490c2ffSMaksim Yevmenkin int 3706490c2ffSMaksim Yevmenkin read_hids_file(void) 3716490c2ffSMaksim Yevmenkin { 3726490c2ffSMaksim Yevmenkin FILE *f = NULL; 3736490c2ffSMaksim Yevmenkin hid_device_t *hid_device = NULL; 3746490c2ffSMaksim Yevmenkin char *line = NULL; 3756490c2ffSMaksim Yevmenkin bdaddr_t bdaddr; 3766490c2ffSMaksim Yevmenkin int lineno; 3776490c2ffSMaksim Yevmenkin 3786490c2ffSMaksim Yevmenkin if (hids_file == NULL) { 3796490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 3806490c2ffSMaksim Yevmenkin return (-1); 3816490c2ffSMaksim Yevmenkin } 3826490c2ffSMaksim Yevmenkin 3836490c2ffSMaksim Yevmenkin if ((f = fopen(hids_file, "r")) == NULL) { 3846490c2ffSMaksim Yevmenkin if (errno == ENOENT) 3856490c2ffSMaksim Yevmenkin return (0); 3866490c2ffSMaksim Yevmenkin 3876490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 3886490c2ffSMaksim Yevmenkin hids_file, strerror(errno), errno); 3896490c2ffSMaksim Yevmenkin return (-1); 3906490c2ffSMaksim Yevmenkin } 3916490c2ffSMaksim Yevmenkin 3926490c2ffSMaksim Yevmenkin for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) { 3936490c2ffSMaksim Yevmenkin if ((line = strtok(buffer, "\r\n\t ")) == NULL) 3946490c2ffSMaksim Yevmenkin continue; /* ignore empty lines */ 3956490c2ffSMaksim Yevmenkin 3966490c2ffSMaksim Yevmenkin if (!bt_aton(line, &bdaddr)) { 3976490c2ffSMaksim Yevmenkin SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \ 3986490c2ffSMaksim Yevmenkin "%s:%d" EOL, hids_file, lineno); 3996490c2ffSMaksim Yevmenkin continue; 4006490c2ffSMaksim Yevmenkin } 4016490c2ffSMaksim Yevmenkin 4026490c2ffSMaksim Yevmenkin if ((hid_device = get_hid_device(&bdaddr)) != NULL) 4036490c2ffSMaksim Yevmenkin hid_device->new_device = 0; 4046490c2ffSMaksim Yevmenkin } 4056490c2ffSMaksim Yevmenkin 4066490c2ffSMaksim Yevmenkin fclose(f); 4076490c2ffSMaksim Yevmenkin 4086490c2ffSMaksim Yevmenkin return (0); 4096490c2ffSMaksim Yevmenkin } 4106490c2ffSMaksim Yevmenkin 4116490c2ffSMaksim Yevmenkin /* Write hids file */ 4126490c2ffSMaksim Yevmenkin int 4136490c2ffSMaksim Yevmenkin write_hids_file(void) 4146490c2ffSMaksim Yevmenkin { 4156490c2ffSMaksim Yevmenkin char path[PATH_MAX]; 4166490c2ffSMaksim Yevmenkin FILE *f = NULL; 4176490c2ffSMaksim Yevmenkin hid_device_t *hid_device = NULL; 4186490c2ffSMaksim Yevmenkin 4196490c2ffSMaksim Yevmenkin if (hids_file == NULL) { 4206490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Unknown HIDs file name!" EOL); 4216490c2ffSMaksim Yevmenkin return (-1); 4226490c2ffSMaksim Yevmenkin } 4236490c2ffSMaksim Yevmenkin 4246490c2ffSMaksim Yevmenkin snprintf(path, sizeof(path), "%s.new", hids_file); 4256490c2ffSMaksim Yevmenkin 4266490c2ffSMaksim Yevmenkin if ((f = fopen(path, "w")) == NULL) { 4276490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL, 4286490c2ffSMaksim Yevmenkin path, strerror(errno), errno); 4296490c2ffSMaksim Yevmenkin return (-1); 4306490c2ffSMaksim Yevmenkin } 4316490c2ffSMaksim Yevmenkin 4326490c2ffSMaksim Yevmenkin LIST_FOREACH(hid_device, &hid_devices, next) 4336490c2ffSMaksim Yevmenkin if (!hid_device->new_device) 4346490c2ffSMaksim Yevmenkin fprintf(f, "%s\n", bt_ntoa(&hid_device->bdaddr, NULL)); 4356490c2ffSMaksim Yevmenkin 4366490c2ffSMaksim Yevmenkin fclose(f); 4376490c2ffSMaksim Yevmenkin 4386490c2ffSMaksim Yevmenkin if (rename(path, hids_file) < 0) { 4396490c2ffSMaksim Yevmenkin SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \ 4406490c2ffSMaksim Yevmenkin "%s (%d)" EOL, path, hids_file, strerror(errno), errno); 4416490c2ffSMaksim Yevmenkin unlink(path); 4426490c2ffSMaksim Yevmenkin return (-1); 4436490c2ffSMaksim Yevmenkin } 4446490c2ffSMaksim Yevmenkin 4456490c2ffSMaksim Yevmenkin return (0); 4466490c2ffSMaksim Yevmenkin } 4476490c2ffSMaksim Yevmenkin 448