summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2013-08-28 14:11:28 -0700
committerMarcel Holtmann <marcel@holtmann.org>2013-08-28 14:11:28 -0700
commite3cc40084ce4c02e6912fae157b0010b24c862db (patch)
tree539892435377de8c6d01d38b1aeb0ae4674fc22a
parent721faa6d139e0f268b7dee0676176f226531274e (diff)
downloadbluez-e3cc40084ce4c02e6912fae157b0010b24c862db.tar.gz
tools: Remove libusb dependency from hid2hci
-rw-r--r--tools/hid2hci.c174
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: {