7 * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $
35 #include <sys/queue.h>
36 #include <bluetooth.h>
37 #include <dev/usb/usb.h>
38 #include <dev/usb/usbhid.h>
50 #define LOGCRIT LOG_CRIT
51 #define LOGERR LOG_ERR
52 #define LOGWARNING LOG_WARNING
55 #define SYSLOG fprintf
56 #define LOGCRIT stderr
58 #define LOGWARNING stderr
60 #endif /* ndef BTHIDCONTROL */
62 #include "bthid_config.h"
66 void yyerror (char const *);
67 static int32_t check_hid_device(hid_device_p hid_device);
68 static void free_hid_device (hid_device_p hid_device);
72 char const *config_file = BTHIDD_CONFFILE;
73 char const *hids_file = BTHIDD_HIDSFILE;
75 static char buffer[1024];
76 static int32_t hid_descriptor_size;
77 static hid_device_t *hid_device = NULL;
78 static LIST_HEAD(, hid_device) hid_devices;
87 %token <bdaddr> T_BDADDRSTRING
88 %token <num> T_HEXBYTE
89 %token T_DEVICE T_BDADDR T_CONTROL_PSM T_INTERRUPT_PSM T_RECONNECT_INITIATE
90 %token T_BATTERY_POWER T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR
91 %token T_TRUE T_FALSE T_ERROR
101 hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device));
102 if (hid_device == NULL) {
103 SYSLOG(LOGCRIT, "Could not allocate new " \
108 hid_device->new_device = 1;
112 if (check_hid_device(hid_device))
113 LIST_INSERT_HEAD(&hid_devices,hid_device,next);
115 free_hid_device(hid_device);
130 | normally_connectable
135 bdaddr: T_BDADDR T_BDADDRSTRING
137 memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr));
141 control_psm: T_CONTROL_PSM T_HEXBYTE
143 hid_device->control_psm = $2;
147 interrupt_psm: T_INTERRUPT_PSM T_HEXBYTE
149 hid_device->interrupt_psm = $2;
153 reconnect_initiate: T_RECONNECT_INITIATE T_TRUE
155 hid_device->reconnect_initiate = 1;
157 | T_RECONNECT_INITIATE T_FALSE
159 hid_device->reconnect_initiate = 0;
163 battery_power: T_BATTERY_POWER T_TRUE
165 hid_device->battery_power = 1;
167 | T_BATTERY_POWER T_FALSE
169 hid_device->battery_power = 0;
173 normally_connectable: T_NORMALLY_CONNECTABLE T_TRUE
175 hid_device->normally_connectable = 1;
177 | T_NORMALLY_CONNECTABLE T_FALSE
179 hid_device->normally_connectable = 0;
183 hid_descriptor: T_HID_DESCRIPTOR
185 hid_descriptor_size = 0;
187 '{' hid_descriptor_bytes '}'
189 if (hid_device->desc != NULL)
190 hid_dispose_report_desc(hid_device->desc);
192 hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size);
193 if (hid_device->desc == NULL) {
194 SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL);
200 hid_descriptor_bytes: hid_descriptor_byte
201 | hid_descriptor_bytes hid_descriptor_byte
204 hid_descriptor_byte: T_HEXBYTE
206 if (hid_descriptor_size >= (int32_t) sizeof(buffer)) {
207 SYSLOG(LOGCRIT, "HID descriptor is too big" EOL);
211 buffer[hid_descriptor_size ++] = $1;
215 parser_error: T_ERROR
222 /* Display parser error message */
224 yyerror(char const *message)
226 SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno);
229 /* Re-read config file */
231 read_config_file(void)
235 if (config_file == NULL) {
236 SYSLOG(LOGERR, "Unknown config file name!" EOL);
240 if ((yyin = fopen(config_file, "r")) == NULL) {
241 SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL,
242 config_file, strerror(errno), errno);
248 SYSLOG(LOGERR, "Could not parse config file '%s'" EOL,
264 while (!LIST_EMPTY(&hid_devices)) {
265 hid_device_p d = LIST_FIRST(&hid_devices);
267 LIST_REMOVE(d, next);
272 /* Lookup config entry */
274 get_hid_device(bdaddr_p bdaddr)
278 LIST_FOREACH(d, &hid_devices, next)
279 if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
285 /* Get next config entry */
287 get_next_hid_device(hid_device_p d)
289 return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next));
292 /* Print config entry */
294 print_hid_device(hid_device_p d, FILE *f)
296 /* XXX FIXME hack! */
299 unsigned char data[1];
301 /* XXX FIXME hack! */
303 struct report_desc *desc = (struct report_desc *) d->desc;
309 " control_psm 0x%x;\n" \
310 " interrupt_psm 0x%x;\n" \
311 " reconnect_initiate %s;\n" \
312 " battery_power %s;\n" \
313 " normally_connectable %s;\n" \
315 bt_ntoa(&d->bdaddr, NULL),
316 d->control_psm, d->interrupt_psm,
317 d->reconnect_initiate? "true" : "false",
318 d->battery_power? "true" : "false",
319 d->normally_connectable? "true" : "false");
321 for (i = 0; i < desc->size; i ++) {
325 fprintf(f, "0x%2.2x ", desc->data[i]);
334 /* Check config entry */
336 check_hid_device(hid_device_p d)
342 if (get_hid_device(&d->bdaddr) != NULL) {
343 SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL,
344 bt_ntoa(&d->bdaddr, NULL));
348 if (d->control_psm == 0) {
349 SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL);
353 if (d->interrupt_psm == 0) {
354 SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL);
358 if (d->desc == NULL) {
359 SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL);
363 /* XXX somehow need to make sure descriptor is valid */
364 for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) {
367 case hid_endcollection:
373 /* Check if the device may send keystrokes */
374 page = HID_PAGE(hi.usage);
375 if (page == HUP_KEYBOARD)
385 /* Free config entry */
387 free_hid_device(hid_device_p d)
390 hid_dispose_report_desc(d->desc);
392 memset(d, 0, sizeof(*d));
396 /* Re-read hids file */
406 if (hids_file == NULL) {
407 SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
411 if ((f = fopen(hids_file, "r")) == NULL) {
415 SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
416 hids_file, strerror(errno), errno);
420 for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) {
421 if ((line = strtok(buffer, "\r\n\t ")) == NULL)
422 continue; /* ignore empty lines */
424 if (!bt_aton(line, &bdaddr)) {
425 SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \
426 "%s:%d" EOL, hids_file, lineno);
430 if ((d = get_hid_device(&bdaddr)) != NULL)
439 /* Write hids file */
441 write_hids_file(void)
447 if (hids_file == NULL) {
448 SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
452 snprintf(path, sizeof(path), "%s.new", hids_file);
454 if ((f = fopen(path, "w")) == NULL) {
455 SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
456 path, strerror(errno), errno);
460 LIST_FOREACH(d, &hid_devices, next)
462 fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL));
466 if (rename(path, hids_file) < 0) {
467 SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \
468 "%s (%d)" EOL, path, hids_file, strerror(errno), errno);