Re: [PATCH] Explicitly disable BT radio using rfkill interface on suspend

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Alan:


Alan Stern wrote:
> On Wed, 20 May 2009, Mario Limonciello wrote:
>
>   
>
> 	echo 0 >/sys/bus/usb/devices/.../power/persist
>
> This will also prevent reset-resume after hibernation.
>
>   
Yes, as it turns out this works properly for a single resume if I apply
that to the bits of all the child devices.  I take it that bit is just
for debugging purposes, and any solution centered around it would not be
a good solution.
>
> You can't.  Instead you have to arrange things so that when the
> intentional change was made, it left behind a timestamp indicator.  If
> that timestamp if present and not more than a few seconds in the past,
> you know the change was intentional.
>
>
>   
So I took up your advice here and tried to assemble a new udev rule and
function that would get called out upon when coming out of S3. It takes
the Vendor and Product IDs of the parent device of the device we just
lost and passes them to the new function.  The new function then tries
to walk that USB bus again to find the child device that it is supposed
to operate upon.

There is "remove" event in the udev log for that BT radio child device. 
I tried to extract as many attributes as I could from that information
and put it in the rule.  The details from this are in attribute_walk.out
(attached).

Unfortunately, this rule isn't getting ran after S3 even though I see
the remove event.  I can run udevadm test PATH (where PATH is the one of
the BT device we lost) and see that it should be spawning the rule.

However, running udevadm test -a remove PATH, I just see that the rule
gets matched, but not executed.  I can't help but think this is all very
close to functional and there is either something silly i'm doing wrong
or a deficiency of udev that's preventing the attributes from being
matched on the removal event.  Would you mind taking a look and/or
commenting?

-- 
Mario Limonciello
*Dell | Linux Engineering*
mario_limonciello@xxxxxxxx
=== modified file 'extras/hid2hci/70-hid2hci.rules'
--- extras/hid2hci/70-hid2hci.rules	2009-06-26 06:17:23 +0000
+++ extras/hid2hci/70-hid2hci.rules	2009-06-30 21:49:54 +0000
@@ -1,7 +1,7 @@
 # do not edit this file, it will be overwritten on update
 
-ACTION!="add", GOTO="hid2hci_end"
 SUBSYSTEM!="usb", GOTO="hid2hci_end"
+ACTION!="add|change", GOTO="addchange_end"
 
 # 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
@@ -22,4 +22,17 @@
 ATTR{idVendor}=="0458", ATTR{idProduct}=="1000", RUN+="hid2hci --method csr -v $attr{idVendor} -p $attr{idProduct} --mode hci"
 ATTR{idVendor}=="05ac", ATTR{idProduct}=="1000", RUN+="hid2hci --method csr -v $attr{idVendor} -p $attr{idProduct} --mode hci"
 
+LABEL="addchange_end"
+
+# When a Dell device recovers from S3, the mouse child needs to be repoked
+# Well, unfortunately the only event we see is the BT device disappearing, so
+# we have to run with that and chase down the mouse device on USB bus as a child.
+ATTR{bDeviceClass}=="e0", \
+ATTR{bDeviceSubClass}=="01", \
+ATTR{bDeviceProtocol}=="01", \
+ATTR{idVendor}=="413c", \
+ATTR{bmAttributes}=="e0", \
+IMPORT{parent}="ID_*", \
+RUN+="hid2hci --method dell -v $env{ID_VENDOR_ID} -p $env{ID_MODEL_ID} --mode hci -s 02"
+
 LABEL="hid2hci_end"

=== modified file 'extras/hid2hci/hid2hci.c'
--- extras/hid2hci/hid2hci.c	2009-06-16 17:30:22 +0000
+++ extras/hid2hci/hid2hci.c	2009-06-30 21:49:27 +0000
@@ -271,6 +271,28 @@
 	return 0;
 }
 
+static struct usb_device* find_resuscitated_device(uint16_t base_vendor, uint16_t base_product, uint8_t bInterfaceProtocol)
+{
+	struct usb_bus *bus;
+	struct usb_device *dev;
+	int i,j,k,l;
+
+	usb_find_busses();
+	usb_find_devices();
+
+	for (bus = usb_get_busses(); bus; bus = bus->next)
+		for (dev = bus->devices; dev; dev = dev->next)
+			if (dev->descriptor.idVendor == base_vendor &&
+			    dev->descriptor.idProduct == base_product)
+				for (i = 0; i < dev->num_children; i++)
+					for (j = 0; j < dev->children[i]->descriptor.bNumConfigurations; j++)
+						for (k = 0; k < dev->children[i]->config[j].bNumInterfaces; k++)
+							for (l = 0; l < dev->children[i]->config[j].interface[k].num_altsetting; l++)
+								if (dev->children[i]->config[j].interface[k].altsetting[l].bInterfaceProtocol == bInterfaceProtocol)
+									return dev->children[i];
+	return NULL;
+}
+
 static void usage(char* error)
 {
 	if (error)
@@ -289,6 +311,7 @@
 		"\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 +324,7 @@
 	{ "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 +333,9 @@
 	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"))
@@ -341,6 +366,9 @@
 			break;
 		case 'h':
 			usage(NULL);
+        case 's':
+            sscanf(optarg, "%2hx", (short unsigned int*) &resuscitate);
+            break;
 		default:
 			exit(0);
 		}
@@ -355,7 +383,16 @@
 
 	usb_init();
 
-	if (!find_device(&dev)) {
+	if (resuscitate) {
+		dev.dev = find_resuscitated_device(dev.vendor, dev.product, resuscitate);
+		if (!quiet && !dev.dev) {
+			fprintf(stderr, "Device %04x:%04x was unable to resucitate any child devices.\n",dev.vendor,dev.product);
+			exit(1);
+		}
+		dev.vendor = dev.dev->descriptor.idVendor;
+		dev.product = dev.dev->descriptor.idProduct;
+	}
+	else if (!find_device(&dev)) {
 		if (!quiet)
 			fprintf(stderr, "Device %04x:%04x not found on USB bus.\n",
 				dev.vendor, dev.product);

Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:04.0/usb3/3-4/3-4.3':
    KERNEL=="3-4.3"
    SUBSYSTEM=="usb"
    DRIVER=="usb"
    ATTR{configuration}==""
    ATTR{bNumInterfaces}==" 4"
    ATTR{bConfigurationValue}=="1"
    ATTR{bmAttributes}=="e0"
    ATTR{bMaxPower}=="100mA"
    ATTR{urbnum}=="186"
    ATTR{idVendor}=="413c"
    ATTR{idProduct}=="8156"
    ATTR{bcdDevice}=="0172"
    ATTR{bDeviceClass}=="e0"
    ATTR{bDeviceSubClass}=="01"
    ATTR{bDeviceProtocol}=="01"
    ATTR{bNumConfigurations}=="1"
    ATTR{bMaxPacketSize0}=="64"
    ATTR{speed}=="12"
    ATTR{busnum}=="3"
    ATTR{devnum}=="7"
    ATTR{version}==" 2.00"
    ATTR{maxchild}=="0"
    ATTR{quirks}=="0x0"
    ATTR{authorized}=="1"
    ATTR{manufacturer}=="Dell Computer Corp"
    ATTR{product}=="Dell Wireless 370 Bluetooth Mini-card"

  looking at parent device '/devices/pci0000:00/0000:00:04.0/usb3/3-4':
    KERNELS=="3-4"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bMaxPower}==" 94mA"
    ATTRS{urbnum}=="195"
    ATTRS{idVendor}=="0a5c"
    ATTRS{idProduct}=="4500"
    ATTRS{bcdDevice}=="0100"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="8"
    ATTRS{speed}=="12"
    ATTRS{busnum}=="3"
    ATTRS{devnum}=="2"
    ATTRS{version}==" 2.00"
    ATTRS{maxchild}=="3"
    ATTRS{quirks}=="0x0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="Broadcom"
    ATTRS{product}=="BCM2046B1"

  looking at parent device '/devices/pci0000:00/0000:00:04.0/usb3':
    KERNELS=="usb3"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{configuration}==""
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bmAttributes}=="e0"
    ATTRS{bMaxPower}=="  0mA"
    ATTRS{urbnum}=="75"
    ATTRS{idVendor}=="1d6b"
    ATTRS{idProduct}=="0001"
    ATTRS{bcdDevice}=="0206"
    ATTRS{bDeviceClass}=="09"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{bMaxPacketSize0}=="64"
    ATTRS{speed}=="12"
    ATTRS{busnum}=="3"
    ATTRS{devnum}=="1"
    ATTRS{version}==" 1.10"
    ATTRS{maxchild}=="4"
    ATTRS{quirks}=="0x0"
    ATTRS{authorized}=="1"
    ATTRS{manufacturer}=="Linux 2.6.30-10-generic ohci_hcd"
    ATTRS{product}=="OHCI Host Controller"
    ATTRS{serial}=="0000:00:04.0"
    ATTRS{authorized_default}=="1"

  looking at parent device '/devices/pci0000:00/0000:00:04.0':
    KERNELS=="0000:00:04.0"
    SUBSYSTEMS=="pci"
    DRIVERS=="ohci_hcd"
    ATTRS{vendor}=="0x10de"
    ATTRS{device}=="0x0aa5"
    ATTRS{subsystem_vendor}=="0x1028"
    ATTRS{subsystem_device}=="0x0271"
    ATTRS{class}=="0x0c0310"
    ATTRS{irq}=="21"
    ATTRS{local_cpus}=="ff"
    ATTRS{local_cpulist}=="0-7"
    ATTRS{modalias}=="pci:v000010DEd00000AA5sv00001028sd00000271bc0Csc03i10"
    ATTRS{broken_parity_status}=="0"
    ATTRS{msi_bus}==""

  looking at parent device '/devices/pci0000:00':
    KERNELS=="pci0000:00"
    SUBSYSTEMS==""
    DRIVERS==""

Attachment: signature.asc
Description: OpenPGP digital signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux