7 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
9 * Copyright (c) 2006 Maksim Yevmenkin <m_evmenkin@yahoo.com>
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * $Id: parser.y,v 1.7 2006/09/07 21:06:53 max Exp $
37 #include <sys/queue.h>
38 #define L2CAP_SOCKET_CHECKED
39 #include <bluetooth.h>
40 #include <dev/usb/usb.h>
41 #include <dev/usb/usbhid.h>
54 #define LOGCRIT LOG_CRIT
55 #define LOGERR LOG_ERR
56 #define LOGWARNING LOG_WARNING
59 #define SYSLOG fprintf
60 #define LOGCRIT stderr
62 #define LOGWARNING stderr
64 #endif /* ndef BTHIDCONTROL */
66 #define NAMELESS_DEVICE "No Name"
68 #include "bthid_config.h"
71 void yyerror (char const *);
72 static int32_t check_hid_device(hid_device_p hid_device);
73 static void free_hid_device (hid_device_p hid_device);
77 char const *config_file = BTHIDD_CONFFILE;
78 char const *hids_file = BTHIDD_HIDSFILE;
80 static char buffer[1024];
81 static int32_t hid_descriptor_size;
82 static hid_device_t *hid_device = NULL;
83 static LIST_HEAD(, hid_device) hid_devices;
93 %token <bdaddr> T_BDADDRSTRING
94 %token <num> T_HEXBYTE
95 %token <num> T_HEXWORD
96 %token <string> T_STRING
98 %token T_DEVICE T_BDADDR T_VENDOR_ID T_PRODUCT_ID T_VERSION T_CONTROL_PSM
99 %token T_INTERRUPT_PSM T_RECONNECT_INITIATE T_BATTERY_POWER
100 %token T_NORMALLY_CONNECTABLE T_HID_DESCRIPTOR
101 %token T_TRUE T_FALSE T_ERROR
111 hid_device = (hid_device_t *) calloc(1, sizeof(*hid_device));
112 if (hid_device == NULL) {
113 SYSLOG(LOGCRIT, "Could not allocate new " \
118 hid_device->new_device = 1;
122 if (check_hid_device(hid_device))
123 LIST_INSERT_HEAD(&hid_devices,hid_device,next);
125 free_hid_device(hid_device);
144 | normally_connectable
149 bdaddr: T_BDADDR T_BDADDRSTRING
151 memcpy(&hid_device->bdaddr, &$2, sizeof(hid_device->bdaddr));
155 name: T_NAME T_STRING
157 if (hid_device->name != NULL) {
158 free(hid_device->name);
159 hid_device->name = NULL;
162 if (strcmp($2, NAMELESS_DEVICE)) {
163 hid_device->name = strdup($2);
164 if (hid_device->name == NULL) {
165 SYSLOG(LOGCRIT, "Could not allocate new " \
173 vendor_id: T_VENDOR_ID T_HEXWORD
175 hid_device->vendor_id = $2;
179 product_id: T_PRODUCT_ID T_HEXWORD
181 hid_device->product_id = $2;
185 version: T_VERSION T_HEXWORD
187 hid_device->version = $2;
191 control_psm: T_CONTROL_PSM T_HEXBYTE
193 hid_device->control_psm = $2;
197 interrupt_psm: T_INTERRUPT_PSM T_HEXBYTE
199 hid_device->interrupt_psm = $2;
203 reconnect_initiate: T_RECONNECT_INITIATE T_TRUE
205 hid_device->reconnect_initiate = 1;
207 | T_RECONNECT_INITIATE T_FALSE
209 hid_device->reconnect_initiate = 0;
213 battery_power: T_BATTERY_POWER T_TRUE
215 hid_device->battery_power = 1;
217 | T_BATTERY_POWER T_FALSE
219 hid_device->battery_power = 0;
223 normally_connectable: T_NORMALLY_CONNECTABLE T_TRUE
225 hid_device->normally_connectable = 1;
227 | T_NORMALLY_CONNECTABLE T_FALSE
229 hid_device->normally_connectable = 0;
233 hid_descriptor: T_HID_DESCRIPTOR
235 hid_descriptor_size = 0;
237 '{' hid_descriptor_bytes '}'
239 if (hid_device->desc != NULL)
240 hid_dispose_report_desc(hid_device->desc);
242 hid_device->desc = hid_use_report_desc((unsigned char *) buffer, hid_descriptor_size);
243 if (hid_device->desc == NULL) {
244 SYSLOG(LOGCRIT, "Could not use HID descriptor" EOL);
250 hid_descriptor_bytes: hid_descriptor_byte
251 | hid_descriptor_bytes hid_descriptor_byte
254 hid_descriptor_byte: T_HEXBYTE
256 if (hid_descriptor_size >= (int32_t) sizeof(buffer)) {
257 SYSLOG(LOGCRIT, "HID descriptor is too big" EOL);
261 buffer[hid_descriptor_size ++] = $1;
265 parser_error: T_ERROR
272 /* Display parser error message */
274 yyerror(char const *message)
276 SYSLOG(LOGERR, "%s in line %d" EOL, message, yylineno);
279 /* Re-read config file */
281 read_config_file(void)
285 if (config_file == NULL) {
286 SYSLOG(LOGERR, "Unknown config file name!" EOL);
290 if ((yyin = fopen(config_file, "r")) == NULL) {
291 SYSLOG(LOGERR, "Could not open config file '%s'. %s (%d)" EOL,
292 config_file, strerror(errno), errno);
298 SYSLOG(LOGERR, "Could not parse config file '%s'" EOL,
314 while (!LIST_EMPTY(&hid_devices)) {
315 hid_device_p d = LIST_FIRST(&hid_devices);
317 LIST_REMOVE(d, next);
322 /* Lookup config entry */
324 get_hid_device(bdaddr_p bdaddr)
328 LIST_FOREACH(d, &hid_devices, next)
329 if (memcmp(&d->bdaddr, bdaddr, sizeof(bdaddr_t)) == 0)
335 /* Get next config entry */
337 get_next_hid_device(hid_device_p d)
339 return ((d == NULL)? LIST_FIRST(&hid_devices) : LIST_NEXT(d, next));
342 /* Print config entry */
344 print_hid_device(hid_device_p d, FILE *f)
346 /* XXX FIXME hack! */
349 unsigned char data[1];
351 /* XXX FIXME hack! */
353 struct report_desc *desc = (struct report_desc *) d->desc;
360 " vendor_id 0x%04x;\n" \
361 " product_id 0x%04x;\n" \
362 " version 0x%04x;\n" \
363 " control_psm 0x%x;\n" \
364 " interrupt_psm 0x%x;\n" \
365 " reconnect_initiate %s;\n" \
366 " battery_power %s;\n" \
367 " normally_connectable %s;\n" \
369 bt_ntoa(&d->bdaddr, NULL),
370 (d->name != NULL)? d->name : NAMELESS_DEVICE,
371 d->vendor_id, d->product_id, d->version,
372 d->control_psm, d->interrupt_psm,
373 d->reconnect_initiate? "true" : "false",
374 d->battery_power? "true" : "false",
375 d->normally_connectable? "true" : "false");
377 for (i = 0; i < desc->size; i ++) {
381 fprintf(f, "0x%2.2x ", desc->data[i]);
390 /* Check config entry */
392 check_hid_device(hid_device_p d)
396 int32_t page, mdepth;
398 if (get_hid_device(&d->bdaddr) != NULL) {
399 SYSLOG(LOGERR, "Ignoring duplicated entry for bdaddr %s" EOL,
400 bt_ntoa(&d->bdaddr, NULL));
404 if (d->control_psm == 0) {
405 SYSLOG(LOGERR, "Ignoring entry with invalid control PSM" EOL);
409 if (d->interrupt_psm == 0) {
410 SYSLOG(LOGERR, "Ignoring entry with invalid interrupt PSM" EOL);
414 if (d->desc == NULL) {
415 SYSLOG(LOGERR, "Ignoring entry without HID descriptor" EOL);
421 /* XXX somehow need to make sure descriptor is valid */
422 for (hd = hid_start_parse(d->desc, ~0, -1); hid_get_item(hd, &hi) > 0; ) {
427 else if (hi.collection == 1 &&
429 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
432 case hid_endcollection:
441 /* Check if the device may send keystrokes */
442 page = HID_PAGE(hi.usage);
443 if (page == HUP_KEYBOARD)
445 if (page == HUP_CONSUMER &&
446 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == 0)
448 /* Check if the device may send relative motion events */
452 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
453 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
456 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
457 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
460 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL) &&
461 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
464 HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN) &&
465 (hi.flags & (HIO_CONST|HIO_RELATIVE)) == HIO_RELATIVE)
475 /* Free config entry */
477 free_hid_device(hid_device_p d)
480 hid_dispose_report_desc(d->desc);
483 memset(d, 0, sizeof(*d));
487 /* Re-read hids file */
497 if (hids_file == NULL) {
498 SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
502 if ((f = fopen(hids_file, "r")) == NULL) {
506 SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
507 hids_file, strerror(errno), errno);
511 for (lineno = 1; fgets(buffer, sizeof(buffer), f) != NULL; lineno ++) {
512 if ((line = strtok(buffer, "\r\n\t ")) == NULL)
513 continue; /* ignore empty lines */
515 if (!bt_aton(line, &bdaddr)) {
516 SYSLOG(LOGWARNING, "Ignoring unparseable BD_ADDR in " \
517 "%s:%d" EOL, hids_file, lineno);
521 if ((d = get_hid_device(&bdaddr)) != NULL)
530 /* Write hids file */
532 write_hids_file(void)
538 if (hids_file == NULL) {
539 SYSLOG(LOGERR, "Unknown HIDs file name!" EOL);
543 snprintf(path, sizeof(path), "%s.new", hids_file);
545 if ((f = fopen(path, "w")) == NULL) {
546 SYSLOG(LOGERR, "Could not open HIDs file '%s'. %s (%d)" EOL,
547 path, strerror(errno), errno);
551 LIST_FOREACH(d, &hid_devices, next)
553 fprintf(f, "%s\n", bt_ntoa(&d->bdaddr, NULL));
557 if (rename(path, hids_file) < 0) {
558 SYSLOG(LOGERR, "Could not rename new HIDs file '%s' to '%s'. " \
559 "%s (%d)" EOL, path, hids_file, strerror(errno), errno);