Diff between 721faa6d139e0f268b7dee0676176f226531274e and e3cc40084ce4c02e6912fae157b0010b24c862db

Changed Files

File Additions Deletions Status
tools/hid2hci.c +108 -66 modified

Full Patch

diff --git a/tools/hid2hci.c b/tools/hid2hci.c
index e3a5b2e..bb8a521 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: {