chiark / gitweb /
hid2hci: support to hid2hci for recovering Dell BT devices after S3
authorMario Limonciello <mario_limonciello@dell.com>
Tue, 21 Jul 2009 22:33:27 +0000 (00:33 +0200)
committerKay Sievers <kay.sievers@vrfy.org>
Tue, 21 Jul 2009 22:33:27 +0000 (00:33 +0200)
extras/hid2hci/70-hid2hci.rules
extras/hid2hci/hid2hci.c

index caf9120f535dd30894941f1ac3f16d56e4bc4762..47eec00abeddfbd52007a0308146f25ac2eda666 100644 (file)
@@ -11,6 +11,11 @@ SUBSYSTEM!="usb", GOTO="hid2hci_end"
 ATTR{bInterfaceClass}=="03", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="02", ATTRS{bDeviceClass}=="00", ATTRS{idVendor}=="413c", ATTRS{bmAttributes}=="e0", \
     RUN+="hid2hci --method dell -v $attr{idVendor} -p $attr{idProduct} --mode hci"
 
+# 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", ATTR{bmAttributes}=="e0", IMPORT{parent}="ID_*", ENV{REMOVE_CMD}="hid2hci --method dell -v $env{ID_VENDOR_ID} -p $env{ID_MODEL_ID} --mode hci -s 02"
+
 ENV{DEVTYPE}!="usb_device", GOTO="hid2hci_end"
 
 # Logitech devices
index aa44790f2baa9e59fd5991ad8f2277af23fefcd2..469f8709ea903da24ff8376220195427a529c447 100644 (file)
@@ -271,6 +271,36 @@ static int find_device(struct device_info* devinfo)
        return 0;
 }
 
+static int find_resuscitated_device(struct device_info* devinfo, uint8_t bInterfaceProtocol)
+{
+       int i,j,k,l;
+       struct usb_device *dev, *child;
+       struct usb_config_descriptor config;
+       struct usb_interface interface;
+       struct usb_interface_descriptor altsetting;
+
+       /* Using the base device, attempt to find the child with the
+        * matching bInterfaceProtocol */
+       dev = devinfo->dev;
+       for (i = 0; i < dev->num_children; i++) {
+               child = dev->children[i];
+               for (j = 0; j < child->descriptor.bNumConfigurations; j++) {
+                       config = child->config[j];
+                       for (k = 0; k < config.bNumInterfaces; k++) {
+                               interface = config.interface[k];
+                               for (l = 0; l < interface.num_altsetting; l++) {
+                                       altsetting = interface.altsetting[l];
+                                       if (altsetting.bInterfaceProtocol == bInterfaceProtocol) {
+                                               devinfo->dev = child;
+                                               return 1;
+                                       }
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
 static void usage(char* error)
 {
        if (error)
@@ -289,6 +319,7 @@ static void usage(char* error)
                "\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"
+               "\t-s, --resuscitate=   Find the child device with this bInterfaceProtocol to run on \n"
                "\n");
        if (error)
                exit(1);
@@ -301,6 +332,7 @@ static const struct option main_options[] = {
        { "vendor",     required_argument, 0, 'v' },
        { "product",    required_argument, 0, 'p' },
        { "method",     required_argument, 0, 'm' },
+       { "resuscitate",required_argument, 0, 's' },
        { 0, 0, 0, 0 }
 };
 
@@ -309,8 +341,9 @@ 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;
+       uint8_t resuscitate = 0;
 
-       while ((opt = getopt_long(argc, argv, "+r:v:p:m:qh", main_options, NULL)) != -1) {
+       while ((opt = getopt_long(argc, argv, "+s:r:v:p:m:qh", main_options, NULL)) != -1) {
                switch (opt) {
                case 'r':
                        if (optarg && !strcmp(optarg, "hid"))
@@ -339,6 +372,9 @@ int main(int argc, char *argv[])
                case 'q':
                        quiet = 1;
                        break;
+               case 's':
+                       sscanf(optarg, "%2hx", (short unsigned int*) &resuscitate);
+                       break;
                case 'h':
                        usage(NULL);
                default:
@@ -362,6 +398,13 @@ int main(int argc, char *argv[])
                exit(1);
        }
 
+       if (resuscitate && !find_resuscitated_device(&dev, resuscitate)) {
+               if (!quiet)
+                       fprintf(stderr, "Device %04x:%04x was unable to resucitate any child devices.\n",
+                               dev.vendor,dev.product);
+               exit(1);
+       }
+
        if (!quiet)
                printf("Attempting to switch device %04x:%04x to %s mode ",
                        dev.vendor, dev.product, dev.mode ? "HID" : "HCI");