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