diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2013-08-28 14:11:28 -0700 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2013-08-28 14:11:28 -0700 |
commit | e3cc40084ce4c02e6912fae157b0010b24c862db (patch) | |
tree | 539892435377de8c6d01d38b1aeb0ae4674fc22a | |
parent | 721faa6d139e0f268b7dee0676176f226531274e (diff) | |
download | bluez-e3cc40084ce4c02e6912fae157b0010b24c862db.tar.gz |
tools: Remove libusb dependency from hid2hci
-rw-r--r-- | tools/hid2hci.c | 174 |
1 files changed, 108 insertions, 66 deletions
diff --git a/tools/hid2hci.c b/tools/hid2hci.c index e3a5b2ef7..bb8a52123 100644 --- a/tools/hid2hci.c +++ b/tools/hid2hci.c @@ -29,28 +29,86 @@ #include <stdio.h> #include <errno.h> #include <fcntl.h> +#include <unistd.h> #include <stdint.h> +#include <stdlib.h> #include <string.h> +#include <dirent.h> #include <getopt.h> #include <sys/ioctl.h> #include <linux/types.h> #include <linux/hiddev.h> -#include <usb.h> #include "libudev.h" +#define USB_REQ_SET_CONFIGURATION 0x09 + +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 + +#define USB_ENDPOINT_OUT 0x00 + +struct usbfs_ctrltransfer { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + uint32_t timeout; /* in milliseconds */ + void *data; /* pointer to data */ +}; + + +#define USBFS_DISCONNECT_IF_DRIVER 0x01 +#define USBFS_DISCONNECT_EXCEPT_DRIVER 0x02 + +struct usbfs_disconnect{ + unsigned int interface; + unsigned int flags; + char driver[256]; +}; + +#define USBFS_IOCTL_CONTROL _IOWR('U', 0, struct usbfs_ctrltransfer) +#define USBFS_IOCTL_DISCONNECT _IOR('U', 27, struct usbfs_disconnect) + +static int control_message(int fd, int requesttype, int request, + int value, int index, + char *bytes, int size, int timeout) +{ + struct usbfs_ctrltransfer transfer; + + transfer.bmRequestType = requesttype; + transfer.bRequest = request; + transfer.wValue = value; + transfer.wIndex = index; + transfer.wLength = size, + transfer.timeout = timeout; + transfer.data = bytes; + + if (ioctl(fd, USBFS_IOCTL_CONTROL, &transfer) < 0) { + fprintf(stderr, "Control transfer failed: %s (%d)\n", + strerror(errno), errno); + return -1; + } + + return 0; +} + enum mode { HCI = 0, HID = 1, }; -static int usb_switch_csr(struct usb_dev_handle *dev, enum mode mode) +static int usb_switch_csr(int fd, enum mode mode) { int err; - err = usb_control_msg(dev, - USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, mode, 0, NULL, 0, 10000); + err = control_message(fd, USB_ENDPOINT_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, + 0, mode, 0, NULL, 0, 10000); if (err == 0) { err = -1; errno = EALREADY; @@ -119,9 +177,10 @@ out: return err; } -static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode) +static int usb_switch_dell(int fd, enum mode mode) { char report[] = { 0x7f, 0x00, 0x00, 0x00 }; + struct usbfs_disconnect disconnect; int err; switch (mode) { @@ -133,17 +192,21 @@ static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode) break; } - /* Don't need to check return, as might not be in use */ - usb_detach_kernel_driver_np(dev, 0); - - if (usb_claim_interface(dev, 0) < 0) - return -EIO; + disconnect.interface = 0; + disconnect.flags = USBFS_DISCONNECT_EXCEPT_DRIVER; + strcpy(disconnect.driver, "usbfs"); - err = usb_control_msg(dev, - USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - USB_REQ_SET_CONFIGURATION, 0x7f | (0x03 << 8), 0, - report, sizeof(report), 5000); + if (ioctl(fd, USBFS_IOCTL_DISCONNECT, &disconnect) < 0) { + fprintf(stderr, "Can't claim interface: %s (%d)\n", + strerror(errno), errno); + return -1; + } + err = control_message(fd, USB_ENDPOINT_OUT | USB_TYPE_CLASS | + USB_RECIP_INTERFACE, + USB_REQ_SET_CONFIGURATION, + 0x7f | (0x03 << 8), 0, + report, sizeof(report), 5000); if (err == 0) { err = -1; errno = EALREADY; @@ -151,57 +214,34 @@ static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode) if (errno == ETIMEDOUT) err = 0; } + return err; } -/* - * libusb needs to scan and open all devices, just to to find the - * device we already have. This should be fixed in libusb. - */ -static struct usb_device *usb_device_open_from_udev(struct udev_device *usb_dev) +static int find_device(struct udev_device *udev_dev) { - struct usb_bus *bus; - const char *str; - int busnum; - int devnum; - - str = udev_device_get_sysattr_value(usb_dev, "busnum"); - if (str == NULL) - return NULL; - busnum = strtol(str, NULL, 0); - - str = udev_device_get_sysattr_value(usb_dev, "devnum"); - if (str == NULL) - return NULL; - devnum = strtol(str, NULL, 0); - - usb_init(); - usb_find_busses(); - usb_find_devices(); - - for (bus = usb_get_busses(); bus; bus = bus->next) { - struct usb_device *dev; - - if (strtol(bus->dirname, NULL, 10) != busnum) - continue; - - for (dev = bus->devices; dev; dev = dev->next) { - if (dev->devnum == devnum) - return dev; - } - } + char path[PATH_MAX]; + const char *busnum, *devnum; + int fd; - return NULL; -} + busnum = udev_device_get_sysattr_value(udev_dev, "busnum"); + if (!busnum) + return -1; -static struct usb_dev_handle *find_device(struct udev_device *udev_dev) -{ - struct usb_device *dev; + devnum = udev_device_get_sysattr_value(udev_dev, "devnum"); + if (!devnum) + return -1; + + snprintf(path, sizeof(path), "/dev/bus/usb/%s/%s", busnum, devnum); + + fd = open(path, O_RDWR, O_CLOEXEC); + if (fd < 0) { + fprintf(stderr, "Can't open device: %s (%d)\n", + strerror(errno), errno); + return -1; + } - dev = usb_device_open_from_udev(udev_dev); - if (dev == NULL) - return NULL; - return usb_open(dev); + return fd; } static void usage(const char *error) @@ -212,9 +252,9 @@ static void usage(const char *error) printf("hid2hci - Bluetooth HID to HCI mode switching utility\n\n"); printf("Usage: hid2hci [options]\n" - " --mode= mode to switch to [hid|hci] (default hci)\n" - " --devpath= sys device path\n" - " --method= method to use to switch [csr|logitech-hid|dell]\n" + " --mode= mode to switch to [hid|hci] (default hci)\n" + " --devpath= sys device path\n" + " --method= method to use to switch [csr|logitech-hid|dell]\n" " --help\n\n"); } @@ -236,7 +276,7 @@ int main(int argc, char *argv[]) struct udev *udev; struct udev_device *udev_dev = NULL; char syspath[PATH_MAX]; - int (*usb_switch)(struct usb_dev_handle *dev, enum mode mode) = NULL; + int (*usb_switch)(int fd, enum mode mode) = NULL; enum mode mode = HCI; const char *devpath = NULL; int err = -1; @@ -302,14 +342,15 @@ int main(int argc, char *argv[]) case METHOD_CSR: case METHOD_DELL: { struct udev_device *dev; - struct usb_dev_handle *handle; + int handle; const char *type; /* get the parent usb_device if needed */ dev = udev_dev; type = udev_device_get_devtype(dev); if (type == NULL || strcmp(type, "usb_device") != 0) { - dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device"); + dev = udev_device_get_parent_with_subsystem_devtype(dev, + "usb", "usb_device"); if (dev == NULL) { fprintf(stderr, "error: could not find usb_device for '%s'\n", devpath); goto exit; @@ -317,12 +358,13 @@ int main(int argc, char *argv[]) } handle = find_device(dev); - if (handle == NULL) { + if (handle < 0) { fprintf(stderr, "error: unable to handle '%s'\n", udev_device_get_syspath(dev)); goto exit; } err = usb_switch(handle, mode); + close(handle); break; } case METHOD_LOGITECH_HID: { |