2011-04-28 09:08:47

by Kay Sievers

[permalink] [raw]
Subject: [Patch] Update hid2hci tool from udev codebase

commit 4a2b9643b6e81d12c3c5fb863d1cca353437e102
Author: Kay Sievers <[email protected]>
Date: Thu Apr 28 11:02:24 2011 +0200

Update hid2hci tool from udev codebase

diff --git a/Makefile.tools b/Makefile.tools
index 364db37..1bf21b2 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -102,7 +102,7 @@ endif
if HID2HCI
sbin_PROGRAMS += tools/hid2hci

-tools_hid2hci_LDADD = @USB_LIBS@
+tools_hid2hci_LDADD = @USB_LIBS@ @UDEV_LIBS@

dist_man_MANS += tools/hid2hci.8
else
diff --git a/acinclude.m4 b/acinclude.m4
index 22fcd5c..a27cd22 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -148,6 +148,12 @@ AC_DEFUN([AC_PATH_USB], [
[Define to 1 if you need the usb_interrupt_read() function.]))
])

+AC_DEFUN([AC_PATH_UDEV], [
+ PKG_CHECK_MODULES(UDEV, libudev, udev_found=yes, udev_found=no)
+ AC_SUBST(UDEV_CFLAGS)
+ AC_SUBST(UDEV_LIBS)
+])
+
AC_DEFUN([AC_PATH_SNDFILE], [
PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no)
AC_SUBST(SNDFILE_CFLAGS)
diff --git a/configure.ac b/configure.ac
index 4447f79..cf32e01 100644
--- a/configure.ac
+++ b/configure.ac
@@ -40,6 +40,7 @@ AC_PATH_GLIB
AC_PATH_ALSA
AC_PATH_GSTREAMER
AC_PATH_USB
+AC_PATH_UDEV
AC_PATH_SNDFILE
AC_PATH_OUI
AC_PATH_READLINE
diff --git a/scripts/bluetooth-hid2hci.rules b/scripts/bluetooth-hid2hci.rules
index 1b231d1..3b36629 100644
--- a/scripts/bluetooth-hid2hci.rules
+++ b/scripts/bluetooth-hid2hci.rules
@@ -1,36 +1,30 @@
-# Variety of Dell Bluetooth devices
-#
-# it looks like a bit of an odd rule, because it is matching
-# on a mouse device that is self powered, but that is where
-# a HID report needs to be sent to switch modes.
-#
-# Known supported devices:
-# 413c:8154
-# 413c:8158
-# 413c:8162
-ACTION=="add", ENV{ID_VENDOR}=="413c", ENV{ID_CLASS}=="mouse", ATTRS{bmAttributes}=="e0", KERNEL=="mouse*", RUN+="/usr/sbin/hid2hci --method dell -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+# do not edit this file, it will be overwritten on update
+
+ACTION=="remove", GOTO="hid2hci_end"
+SUBSYSTEM!="usb", GOTO="hid2hci_end"
+
+# Variety of Dell Bluetooth devices - match on a mouse device that is
+# self powered and where a HID report needs to be sent to switch modes
+# Known supported devices: 413c:8154, 413c:8158, 413c:8162
+ATTR{bInterfaceClass}=="03", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="02", \
+ ATTRS{bDeviceClass}=="00", ATTRS{idVendor}=="413c", ATTRS{bmAttributes}=="e0", \
+ RUN+="hid2hci --method=dell --devpath=%p", ENV{HID2HCI_SWITCH}="1"

# Logitech devices
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c703" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c704" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c705" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70a" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70b" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70c" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c70e" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c713" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c714" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c71b" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="046d", ENV{ID_MODEL}=="c71c" RUN+="/usr/sbin/hid2hci --method logitech -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+KERNEL=="hiddev*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c70[35e]", \
+ RUN+="hid2hci --method=logitech-hid --devpath=%p"
+KERNEL=="hidraw*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c70[4abc]|c71[34bc]", \
+ RUN+="hid2hci --method=logitech-hid --devpath=%p"
+
+ENV{DEVTYPE}!="usb_device", GOTO="hid2hci_end"
+
+# When a Dell device recovers from S3, the mouse child needs to be repoked
+# Unfortunately the only event seen is the BT device disappearing, so the mouse
+# device needs to be chased down on the USB bus.
+ATTR{bDeviceClass}=="e0", ATTR{bDeviceSubClass}=="01", ATTR{bDeviceProtocol}=="01", ATTR{idVendor}=="413c", \
+ ENV{REMOVE_CMD}="/sbin/udevadm trigger --action=change --subsystem-match=usb --property-match=HID2HCI_SWITCH=1"

-# CSR devices (in HID mode)
-ACTION=="add", ENV{ID_VENDOR}=="0a12", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="0458", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
-ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="1000" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hci"
+# CSR devices
+ATTR{idVendor}=="0a12|0458|05ac", ATTR{idProduct}=="1000", RUN+="hid2hci --method=csr --devpath=%p"

-# CSR devices (in HCI mode)
-#ACTION=="add", ENV{ID_VENDOR}=="0a12", ENV{ID_MODEL}=="0001" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="0458", ENV{ID_MODEL}=="003f" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8203" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8204" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
-#ACTION=="add", ENV{ID_VENDOR}=="05ac", ENV{ID_MODEL}=="8207" RUN+="/usr/sbin/hid2hci --method csr -v $env{ID_VENDOR} -p $env{ID_MODEL} --mode hid"
+LABEL="hid2hci_end"
diff --git a/tools/hid2hci.8 b/tools/hid2hci.8
index 5d35274..6ea7ed8 100644
--- a/tools/hid2hci.8
+++ b/tools/hid2hci.8
@@ -29,23 +29,18 @@ is used to set up switch supported Bluetooth devices into the HCI
mode and back.
.SH OPTIONS
.TP
-.BI -h
-Gives a list of possible options.
-.TP
-.BI -q
-Don't display any messages.
-.TP
-.BI -r [hid,hci]
+.B --mode= [hid, hci]
Sets the mode to switch the device into
.TP
-.BI -v
-Specifies the 4 digit vendor ID assigned to the device being switched
+.B --method= [csr, logitech-hid, dell]
+Which vendor method to use for switching the device.
.TP
-.BI -p
-Specifies the 4 digit product ID assigned to the device being switched
+.B --devpath=
+Specifies the device path in /sys
+.TP
+.B --help
+Gives a list of possible options.
.TP
-.BI -m [csr, logitech, dell]
-Which vendor method to use for switching the device.
.SH AUTHOR
Written by Marcel Holtmann <[email protected]>.
.br
diff --git a/tools/hid2hci.c b/tools/hid2hci.c
index a640772..dea3974 100644
--- a/tools/hid2hci.c
+++ b/tools/hid2hci.c
@@ -1,9 +1,10 @@
/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
+ * hid2hci : switch the radio on devices that support
+ * it from HID to HCI and back
*
* Copyright (C) 2003-2010 Marcel Holtmann <[email protected]>
- *
+ * Copyright (C) 2008-2009 Mario Limonciello <[email protected]>
+ * Copyright (C) 2009-2011 Kay Sievers <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -32,79 +33,24 @@
#include <string.h>
#include <getopt.h>
#include <sys/ioctl.h>
-
+#include <linux/types.h>
+#include <linux/hiddev.h>
#include <usb.h>

-#ifdef NEED_USB_GET_BUSSES
-static inline struct usb_bus *usb_get_busses(void)
-{
- return usb_busses;
-}
-#endif
-
-#ifndef USB_DIR_OUT
-#define USB_DIR_OUT 0x00
-#endif
-
-static char devpath[PATH_MAX + 1] = "/dev";
-
-struct hiddev_devinfo {
- unsigned int bustype;
- unsigned int busnum;
- unsigned int devnum;
- unsigned int ifnum;
- short vendor;
- short product;
- short version;
- unsigned num_applications;
-};
+#include "libudev.h"

-struct hiddev_report_info {
- unsigned report_type;
- unsigned report_id;
- unsigned num_fields;
+enum mode {
+ HCI = 0,
+ HID = 1,
};

-typedef __signed__ int __s32;
-
-struct hiddev_usage_ref {
- unsigned report_type;
- unsigned report_id;
- unsigned field_index;
- unsigned usage_index;
- unsigned usage_code;
- __s32 value;
-};
-
-#define HIDIOCGDEVINFO _IOR('H', 0x03, struct hiddev_devinfo)
-#define HIDIOCINITREPORT _IO('H', 0x05)
-#define HIDIOCSREPORT _IOW('H', 0x08, struct hiddev_report_info)
-#define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref)
-
-#define HID_REPORT_TYPE_OUTPUT 2
-
-#define HCI 0
-#define HID 1
-
-struct device_info {
- struct usb_device *dev;
- int mode;
- uint16_t vendor;
- uint16_t product;
-};
-
-static int switch_csr(struct device_info *devinfo)
+static int usb_switch_csr(struct usb_dev_handle *dev, enum mode mode)
{
- struct usb_dev_handle *udev;
int err;

- udev = usb_open(devinfo->dev);
- if (!udev)
- return -errno;
-
- err = usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, devinfo->mode, 0, NULL, 0, 10000);
-
+ err = usb_control_msg(dev,
+ USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, mode, 0, NULL, 0, 10000);
if (err == 0) {
err = -1;
errno = EALREADY;
@@ -112,13 +58,10 @@ static int switch_csr(struct device_info *devinfo)
if (errno == ETIMEDOUT)
err = 0;
}
-
- usb_close(udev);
-
return err;
}

-static int send_report(int fd, const char *buf, size_t size)
+static int hid_logitech_send_report(int fd, const char *buf, size_t size)
{
struct hiddev_report_info rinfo;
struct hiddev_usage_ref uref;
@@ -147,72 +90,42 @@ static int send_report(int fd, const char *buf, size_t size)
return err;
}

-static int switch_logitech(struct device_info *devinfo)
+static int hid_switch_logitech(const char *filename)
{
- char devname[PATH_MAX + 1];
- int i, fd, err = -1;
-
- for (i = 0; i < 16; i++) {
- struct hiddev_devinfo dinfo;
- char rep1[] = { 0xff, 0x80, 0x80, 0x01, 0x00, 0x00 };
- char rep2[] = { 0xff, 0x80, 0x00, 0x00, 0x30, 0x00 };
- char rep3[] = { 0xff, 0x81, 0x80, 0x00, 0x00, 0x00 };
-
- sprintf(devname, "%s/hiddev%d", devpath, i);
- fd = open(devname, O_RDWR);
- if (fd < 0) {
- sprintf(devname, "%s/usb/hiddev%d", devpath, i);
- fd = open(devname, O_RDWR);
- if (fd < 0) {
- sprintf(devname, "%s/usb/hid/hiddev%d", devpath, i);
- fd = open(devname, O_RDWR);
- if (fd < 0)
- continue;
- }
- }
-
- memset(&dinfo, 0, sizeof(dinfo));
- err = ioctl(fd, HIDIOCGDEVINFO, &dinfo);
- if (err < 0 || (int) dinfo.busnum != atoi(devinfo->dev->bus->dirname) ||
- (int) dinfo.devnum != atoi(devinfo->dev->filename)) {
- close(fd);
- continue;
- }
-
- err = ioctl(fd, HIDIOCINITREPORT, 0);
- if (err < 0) {
- close(fd);
- break;
- }
-
- err = send_report(fd, rep1, sizeof(rep1));
- if (err < 0) {
- close(fd);
- break;
- }
-
- err = send_report(fd, rep2, sizeof(rep2));
- if (err < 0) {
- close(fd);
- break;
- }
-
- err = send_report(fd, rep3, sizeof(rep3));
- close(fd);
- break;
- }
-
+ char rep1[] = { 0xff, 0x80, 0x80, 0x01, 0x00, 0x00 };
+ char rep2[] = { 0xff, 0x80, 0x00, 0x00, 0x30, 0x00 };
+ char rep3[] = { 0xff, 0x81, 0x80, 0x00, 0x00, 0x00 };
+ int fd;
+ int err = -1;
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0)
+ return err;
+
+ err = ioctl(fd, HIDIOCINITREPORT, 0);
+ if (err < 0)
+ goto out;
+
+ err = hid_logitech_send_report(fd, rep1, sizeof(rep1));
+ if (err < 0)
+ goto out;
+
+ err = hid_logitech_send_report(fd, rep2, sizeof(rep2));
+ if (err < 0)
+ goto out;
+
+ err = hid_logitech_send_report(fd, rep3, sizeof(rep3));
+out:
+ close(fd);
return err;
}

-static int switch_dell(struct device_info *devinfo)
+static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode)
{
char report[] = { 0x7f, 0x00, 0x00, 0x00 };
-
- struct usb_dev_handle *handle;
int err;

- switch (devinfo->mode) {
+ switch (mode) {
case HCI:
report[1] = 0x13;
break;
@@ -221,22 +134,16 @@ static int switch_dell(struct device_info *devinfo)
break;
}

- handle = usb_open(devinfo->dev);
- if (!handle)
- return -EIO;
-
/* Don't need to check return, as might not be in use */
- usb_detach_kernel_driver_np(handle, 0);
+ usb_detach_kernel_driver_np(dev, 0);

- if (usb_claim_interface(handle, 0) < 0) {
- usb_close(handle);
+ if (usb_claim_interface(dev, 0) < 0)
return -EIO;
- }

- err = usb_control_msg(handle,
- USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ 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);
+ report, sizeof(report), 5000);

if (err == 0) {
err = -1;
@@ -245,131 +152,200 @@ static int switch_dell(struct device_info *devinfo)
if (errno == ETIMEDOUT)
err = 0;
}
-
- usb_close(handle);
-
return err;
}

-static int find_device(struct device_info* devinfo)
+/*
+ * 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)
{
struct usb_bus *bus;
- struct usb_device *dev;
+ 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)
+ 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->descriptor.idVendor == devinfo->vendor &&
- dev->descriptor.idProduct == devinfo->product) {
- devinfo->dev=dev;
- return 1;
- }
+ if (dev->devnum == devnum)
+ return dev;
}
- return 0;
+ }
+
+ return NULL;
}

-static void usage(char* error)
+static struct usb_dev_handle *find_device(struct udev_device *udev_dev)
+{
+ struct usb_device *dev;
+
+ dev = usb_device_open_from_udev(udev_dev);
+ if (dev == NULL)
+ return NULL;
+ return usb_open(dev);
+}
+
+static void usage(const char *error)
{
if (error)
fprintf(stderr,"\n%s\n", error);
else
printf("hid2hci - Bluetooth HID to HCI mode switching utility\n\n");

- printf("Usage:\n"
- "\thid2hci [options]\n"
- "\n");
-
- printf("Options:\n"
- "\t-h, --help Display help\n"
- "\t-q, --quiet Don't display any messages\n"
- "\t-r, --mode= Mode to switch to [hid, hci]\n"
- "\t-v, --vendor= Vendor ID to act upon\n"
- "\t-p, --product= Product ID to act upon\n"
- "\t-m, --method= Method to use to switch [csr, logitech, dell]\n"
- "\n");
- if (error)
- exit(1);
+ 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"
+ " --help\n\n");
}

-static struct option main_options[] = {
- { "help", no_argument, 0, 'h' },
- { "quiet", no_argument, 0, 'q' },
- { "mode", required_argument, 0, 'r' },
- { "vendor", required_argument, 0, 'v' },
- { "product", required_argument, 0, 'p' },
- { "method", required_argument, 0, 'm' },
- { 0, 0, 0, 0 }
-};
-
int main(int argc, char *argv[])
{
- struct device_info dev = { NULL, HCI, 0, 0 };
- int opt, quiet = 0;
- int (*method)(struct device_info *dev) = NULL;
-
- while ((opt = getopt_long(argc, argv, "+r:v:p:m:qh", main_options, NULL)) != -1) {
- switch (opt) {
- case 'r':
- if (optarg && !strcmp(optarg, "hid"))
- dev.mode = HID;
- else if (optarg && !strcmp(optarg, "hci"))
- dev.mode = HCI;
- else
- usage("ERROR: Undefined radio mode\n");
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "mode", required_argument, NULL, 'm' },
+ { "devpath", required_argument, NULL, 'p' },
+ { "method", required_argument, NULL, 'M' },
+ { }
+ };
+ enum method {
+ METHOD_UNDEF,
+ METHOD_CSR,
+ METHOD_LOGITECH_HID,
+ METHOD_DELL,
+ } method = METHOD_UNDEF;
+ 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;
+ enum mode mode = HCI;
+ const char *devpath = NULL;
+ int err = -1;
+ int rc = 1;
+
+ for (;;) {
+ int option;
+
+ option = getopt_long(argc, argv, "m:p:M:h", options, NULL);
+ if (option == -1)
break;
- case 'v':
- sscanf(optarg, "%4hx", &dev.vendor);
+
+ switch (option) {
+ case 'm':
+ if (!strcmp(optarg, "hid")) {
+ mode = HID;
+ } else if (!strcmp(optarg, "hci")) {
+ mode = HCI;
+ } else {
+ usage("error: undefined radio mode\n");
+ exit(1);
+ }
break;
case 'p':
- sscanf(optarg, "%4hx", &dev.product);
+ devpath = optarg;
break;
- case 'm':
- if (optarg && !strcmp(optarg, "csr"))
- method = switch_csr;
- else if (optarg && !strcmp(optarg, "logitech"))
- method = switch_logitech;
- else if (optarg && !strcmp(optarg, "dell"))
- method = switch_dell;
- else
- usage("ERROR: Undefined switching method\n");
- break;
- case 'q':
- quiet = 1;
+ case 'M':
+ if (!strcmp(optarg, "csr")) {
+ method = METHOD_CSR;
+ usb_switch = usb_switch_csr;
+ } else if (!strcmp(optarg, "logitech-hid")) {
+ method = METHOD_LOGITECH_HID;
+ } else if (!strcmp(optarg, "dell")) {
+ method = METHOD_DELL;
+ usb_switch = usb_switch_dell;
+ } else {
+ usage("error: undefined switching method\n");
+ exit(1);
+ }
break;
case 'h':
usage(NULL);
- default:
- exit(0);
}
}

- if (!quiet && (!dev.vendor || !dev.product || !method))
- usage("ERROR: Vendor ID, Product ID, and Switching Method must all be defined.\n");
+ if (!devpath || method == METHOD_UNDEF) {
+ usage("error: --devpath= and --method= must be defined\n");
+ exit(1);
+ }

- argc -= optind;
- argv += optind;
- optind = 0;
+ udev = udev_new();
+ if (udev == NULL)
+ goto exit;

- usb_init();
-
- if (!find_device(&dev)) {
- if (!quiet)
- fprintf(stderr, "Device %04x:%04x not found on USB bus.\n",
- dev.vendor, dev.product);
- exit(1);
+ snprintf(syspath, sizeof(syspath), "%s/%s", udev_get_sys_path(udev), devpath);
+ udev_dev = udev_device_new_from_syspath(udev, syspath);
+ if (udev_dev == NULL) {
+ fprintf(stderr, "error: could not find '%s'\n", devpath);
+ goto exit;
}

- if (!quiet)
- printf("Attempting to switch device %04x:%04x to %s mode ",
- dev.vendor, dev.product, dev.mode ? "HID" : "HCI");
- fflush(stdout);
+ switch (method) {
+ case METHOD_CSR:
+ case METHOD_DELL: {
+ struct udev_device *dev;
+ struct usb_dev_handle *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");
+ if (dev == NULL) {
+ fprintf(stderr, "error: could not find usb_device for '%s'\n", devpath);
+ goto exit;
+ }
+ }
+
+ handle = find_device(dev);
+ if (handle == NULL) {
+ fprintf(stderr, "error: unable to handle '%s'\n",
+ udev_device_get_syspath(dev));
+ goto exit;
+ }
+ err = usb_switch(handle, mode);
+ break;
+ }
+ case METHOD_LOGITECH_HID: {
+ const char *device;

- if (method(&dev) < 0 && !quiet)
- printf("failed (%s)\n", strerror(errno));
- else if (!quiet)
- printf("was successful\n");
+ device = udev_device_get_devnode(udev_dev);
+ if (device == NULL) {
+ fprintf(stderr, "error: could not find hiddev device node\n");
+ goto exit;
+ }
+ err = hid_switch_logitech(device);
+ break;
+ }
+ default:
+ break;
+ }

- return errno;
+ if (err < 0)
+ fprintf(stderr, "error: switching device '%s' failed.\n",
+ udev_device_get_syspath(udev_dev));
+exit:
+ udev_device_unref(udev_dev);
+ udev_unref(udev);
+ return rc;
}




2011-04-28 19:59:49

by Johan Hedberg

[permalink] [raw]
Subject: Re: [Patch] Update hid2hci tool from udev codebase

Hi Kay,

On Thu, Apr 28, 2011, Kay Sievers wrote:
> commit 4a2b9643b6e81d12c3c5fb863d1cca353437e102
> Author: Kay Sievers <[email protected]>
> Date: Thu Apr 28 11:02:24 2011 +0200
>
> Update hid2hci tool from udev codebase

Pushed upstream. Thanks.

Johan