Index: etc/bluetooth/Makefile =================================================================== RCS file: /home/ncvs/src/etc/bluetooth/Makefile,v retrieving revision 1.2 diff -u -p -r1.2 Makefile --- etc/bluetooth/Makefile 14 Oct 2005 15:26:23 -0000 1.2 +++ etc/bluetooth/Makefile 10 Nov 2007 15:10:02 -0000 @@ -2,7 +2,7 @@ # $FreeBSD: src/etc/bluetooth/Makefile,v 1.2 2005/10/14 15:26:23 ru Exp $ FILESDIR= /etc/bluetooth -FILES= hcsecd.conf hosts protocols +FILES= hcsecd.conf hosts protocols ubthidtbl FILESMODE_hcsecd.conf= 600 FILESMODE_hosts= 644 Index: etc/bluetooth/ubthidtbl =================================================================== RCS file: etc/bluetooth/ubthidtbl diff -N etc/bluetooth/ubthidtbl --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ etc/bluetooth/ubthidtbl 3 Oct 2007 11:48:54 -0000 @@ -0,0 +1,15 @@ +# +# $FreeBSD$ +# +# The following table lists the devices that ubthidctl(1) should switch +# from HID to HCI and vice versa. +# + +# Apple +HID 0x05ac 0x1000 + +# Cambridge Silicon Radio +HID 0x0a12 0x1000 + +# KYE Systems +HID 0x0458 0x1000 Index: etc/defaults/rc.conf =================================================================== RCS file: /home/ncvs/src/etc/defaults/rc.conf,v retrieving revision 1.321 diff -u -p -r1.321 rc.conf --- etc/defaults/rc.conf 15 Oct 2007 20:00:18 -0000 1.321 +++ etc/defaults/rc.conf 10 Nov 2007 15:08:42 -0000 @@ -375,6 +375,9 @@ bthidd_enable="NO" # Enable bthidd(8) ( bthidd_config="/etc/bluetooth/bthidd.conf" # bthidd(8) configuration file bthidd_hids="/var/db/bthidd.hids" # bthidd(8) known HID devices file +ubthidctl_enable="NO" +ubthidctl_table="/etc/bluetooth/ubthidtbl" + ### Miscellaneous network options: ### icmp_bmcastecho="NO" # respond to broadcast ping packets Index: etc/rc.d/ubthidctl =================================================================== RCS file: etc/rc.d/ubthidctl diff -N etc/rc.d/ubthidctl --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ etc/rc.d/ubthidctl 10 Nov 2007 15:09:33 -0000 @@ -0,0 +1,19 @@ +#!/bin/sh +# +# $FreeBSD$ +# + +# PROVIDE: ubthidctl +# REQUIRE: cleanvar + +. /etc/rc.subr + +name="ubthidctl" +rcvar=`set_rcvar` +command="/usr/bin/${name}" + +load_rc_config $name +table="${ubtidctl_table:-/etc/bluetooth/ubthidtbl}" +command_args="-t ${table}" +required_files="${table}" +run_rc_command "$1" Index: usr.bin/bluetooth/Makefile =================================================================== RCS file: /home/ncvs/src/usr.bin/bluetooth/Makefile,v retrieving revision 1.3 diff -u -p -r1.3 Makefile --- usr.bin/bluetooth/Makefile 12 Oct 2003 22:04:21 -0000 1.3 +++ usr.bin/bluetooth/Makefile 3 Oct 2007 12:03:24 -0000 @@ -1,10 +1,17 @@ # $Id $ # $FreeBSD: src/usr.bin/bluetooth/Makefile,v 1.3 2003/10/12 22:04:21 emax Exp $ +.include + SUBDIR= \ bthost \ btsockstat \ - rfcomm_sppd + rfcomm_sppd \ + ${_ubthidctl} + +.if ${MK_USB} != "no" +_ubthidctl= ubthidctl +.endif .include Index: usr.bin/bluetooth/ubthidctl/Makefile =================================================================== RCS file: usr.bin/bluetooth/ubthidctl/Makefile diff -N usr.bin/bluetooth/ubthidctl/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/bluetooth/ubthidctl/Makefile 3 Oct 2007 11:48:54 -0000 @@ -0,0 +1,6 @@ +# $FreeBSD$ + +PROG= ubthidctl +WARNS?= 6 + +.include Index: usr.bin/bluetooth/ubthidctl/ubthidctl.1 =================================================================== RCS file: usr.bin/bluetooth/ubthidctl/ubthidctl.1 diff -N usr.bin/bluetooth/ubthidctl/ubthidctl.1 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/bluetooth/ubthidctl/ubthidctl.1 26 Dec 2007 15:01:51 -0000 @@ -0,0 +1,93 @@ +.\" +.\" Copyright (c) 2007 Rui Paulo +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 5, 2007 +.Dt UBTHIDCTL 1 +.Sh NAME +.Nm ubthidctl +.Nd "Bluetooth USB HID-HCI proxy switcher" +.Sh SYNOPSIS +.Nm +.Fl f Ar device +.Fl a Ar addr +.Op Fl m Ar mode +.Nm +.Fl t Ar tablefile +.Sh DESCRIPTION +The +.Nm +utility changes Bluetooth controllers from HID (Human Interface Device) +to HCI (Host Controller Interface) and vice-versa. +HCI is the interface used by Bluetooth devices and HID is the interface +used by some USB devices. The device will reattach every time you switch +modes. +.Pp +Some Bluetooth controllers present themselves to the BIOS as +an +.Xr uhid 4 +device. +This is done so that the user can use a Bluetooth keyboard and a Bluetooth +mouse with BIOS implementations that already support USB. +After the operating system boots, it's the system administrator's +responsibility to switch the device to HCI mode. +.Pp +This utility supports two modes of operation. +In the first one you run the utility with the exact location of the +device (device entry, address and an optional mode). +In the other mode, the utility reads a filename with several vendors +and product identifiers. If your system has a device listed in +.Pa tablefile +it will be switched to the appropriate mode automatically. +.Sh FILES +.Bl -tag -width indent +.It Pa /usr/share/misc/ubthidtbl +The location of the table file. +.El +.Sh EXAMPLES +First mode of operation: +.Bd -literal -offset indent +ubthidctl -f /dev/usb3 -a 2 +.Ed +.Pp +Second mode of operation: +.Bd -literal -offset indent +ubthidctl -t /usr/share/misc/ubthidtbl +.Ed +.Sh SEE ALSO +.Xr ng_ubt 4 , +.Xr uhid 4 , +.Xr usb 4 +.Sh HISTORY +The +.Nm +utility first appeared in +.Fx 8.0 . +.Pp +It was based on the hid2hci utility for Linux written by +.An Marcel Holtmann Aq marcel@holtmann.org +.Sh AUTHORS +.An Rui Paulo Aq rpaulo@fnop.net Index: usr.bin/bluetooth/ubthidctl/ubthidctl.c =================================================================== RCS file: usr.bin/bluetooth/ubthidctl/ubthidctl.c diff -N usr.bin/bluetooth/ubthidctl/ubthidctl.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ usr.bin/bluetooth/ubthidctl/ubthidctl.c 26 Dec 2007 14:59:02 -0000 @@ -0,0 +1,235 @@ +/*- + * Copyright (c) 2007 Rui Paulo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * Based on bluez-utils hid2hci tool written by + * Marcel Holtmann + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include + +typedef enum { + HCI = 0, + HID = 1 +} hidmode_t; + +typedef struct { + hidmode_t mode; + uint16_t vendor; + uint16_t product; +} tblentry_t; + +typedef struct { + int devno; + int devaddr; +} devinfo_t; + + +static void switchmode(const char *dev, const int devaddr, hidmode_t mode); + + +static devinfo_t +finddevice(tblentry_t tblentry) +{ + struct usb_device_info usbdev; + char filename[16]; + devinfo_t dev; + int i; + int j; + int fd; + + dev.devno = -1; + + for (i = 0; i < 20; i++) { + snprintf(filename, sizeof(filename) - 1, "/dev/usb%d", i); + fd = open(filename, O_RDONLY); + if (fd < 0) + return dev; + + for (j = USB_START_ADDR; j < USB_MAX_DEVICES; j++) { + memset(&usbdev, 0, sizeof(usbdev)); + usbdev.udi_addr = j; + ioctl(fd, USB_DEVICEINFO, &usbdev); + if (tblentry.vendor == usbdev.udi_vendorNo && + tblentry.product == usbdev.udi_productNo) { + dev.devno = i; + dev.devaddr = j; + close(fd); + return dev; + } + } + close(fd); + } + + return dev; +} + +static void +parsetable(const char *filename) +{ + FILE *fp; + tblentry_t tblentry; + unsigned int vendor; + unsigned int product; + char modestr[4]; + devinfo_t dev; + char usbname[16]; + char buf[1024]; + char *p; + + fp = fopen(filename, "r"); + if (!fp) + err(1, "fopen %s", filename); + + while (!feof(fp)) { + fgets(buf, sizeof(buf) - 1, fp); + for (p = buf; *p == ' '; p++); + if (*p == '#' || *p == '\n') + continue; + + sscanf(p, "%3s 0x%x 0x%x\n", modestr, &vendor, &product); + tblentry.vendor = vendor; + tblentry.product = product; + + if (!strncmp(modestr, "HCI", 3)) + tblentry.mode = HCI; + else if (!strncmp(modestr, "HID", 3)) + tblentry.mode = HID; + else { + warnx("invalid mode: %s", modestr); + continue; + } + dev = finddevice(tblentry); + if (dev.devno != -1) { + snprintf(usbname, sizeof(usbname), "/dev/usb%d", + dev.devno); + switchmode(usbname, dev.devaddr, tblentry.mode); + } + + } + fclose(fp); +} + +static void +switchmode(const char *dev, const int devaddr, hidmode_t mode) +{ + int fd; + struct usb_ctl_request req; + + fd = open(dev, O_RDWR, 0); + if (fd < 0) + err(1, "open %s", dev); + + memset(&req, 0, sizeof(req)); + req.ucr_addr = devaddr; + USETW(req.ucr_request.wValue, mode); + USETW(req.ucr_request.wIndex, 0); + USETW(req.ucr_request.wLength, 0); + req.ucr_data = NULL; + req.ucr_flags = USBD_SHORT_XFER_OK; + req.ucr_request.bmRequestType = UT_VENDOR; + req.ucr_request.bRequest = 0; + ioctl(fd, USB_REQUEST, &req); + + /* + * The return value of ioctl() will always be EIO, so it's up + * to the user to check whether the device was switched sucessfuly. + */ + close(fd); +} + +static void +usage(void) +{ + fprintf(stderr, "usage:\t%s -f device -a addr [-m mode]\n" + "\t%s -t tablefile\n", getprogname(), getprogname()); + + exit(1); +} + +int +main(int argc, char *argv[]) +{ + char ch; + char *dev; + char *tablefile; + int devaddr; + int mode; + + dev = NULL; + devaddr = -1; + mode = HCI; + tablefile = NULL; + + while ((ch = getopt(argc, argv, "f:m:a:t:?")) != -1) { + switch (ch) { + case 'f': + dev = optarg; + break; + case 'm': + mode = atoi(optarg); + if (mode < 0 || mode > 1) + usage(); + break; + case 'a': + devaddr = atoi(optarg); + if (devaddr < 0) + usage(); + break; + case 't': + tablefile = optarg; + break; + case '?': + default: + usage(); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + if (tablefile) { + parsetable(tablefile); + return 0; + } + if (dev == NULL || devaddr == -1) + usage(); + switchmode(dev, devaddr, mode); + + return 0; +}