From: Kay Sievers <kay.sievers@vrfy.org>
To: linux-bluetooth@vger.kernel.org
Subject: [Patch] Update hid2hci tool from udev codebase
Date: Thu, 28 Apr 2011 11:08:47 +0200 [thread overview]
Message-ID: <1303981727.1065.11.camel@zag> (raw)
commit 4a2b9643b6e81d12c3c5fb863d1cca353437e102
Author: Kay Sievers <kay.sievers@vrfy.org>
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 <marcel@holtmann.org>.
.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 <marcel@holtmann.org>
- *
+ * Copyright (C) 2008-2009 Mario Limonciello <mario_limonciello@dell.com>
+ * Copyright (C) 2009-2011 Kay Sievers <kay.sievers@vrfy.org>
*
* 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;
}
next reply other threads:[~2011-04-28 9:08 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-04-28 9:08 Kay Sievers [this message]
2011-04-28 19:59 ` [Patch] Update hid2hci tool from udev codebase Johan Hedberg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1303981727.1065.11.camel@zag \
--to=kay.sievers@vrfy.org \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.