You should use Reply-To-All so that your messages get sent to the mailing list as well as to me. On Tue, 18 Oct 2011, Arno Augustin wrote: > Hi Alan, > > thank's for your answer :-) > Yes, I think without having detailed information about nvidia > controllers a sysfs attribute would be the best way to deal with the > problem. > But even if the kernel checks device IDs itself it would be more > flexible to have the ability to write the ohci flags via sysfs.... Well, here's a patch that adds both a blacklist and a sysfs file called shutdown_quirk in the directories for the OHCI controller devices. I can't test it very well because I don't have NVIDIA hardware. Alan Stern drivers/usb/host/ohci-pci.c | 67 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) Index: usb-3.1/drivers/usb/host/ohci-pci.c =================================================================== --- usb-3.1.orig/drivers/usb/host/ohci-pci.c +++ usb-3.1/drivers/usb/host/ohci-pci.c @@ -175,7 +175,46 @@ static int ohci_quirk_amd700(struct usb_ return 0; } -/* nVidia controllers continue to drive Reset signalling on the bus +/* Control the OHCI_QUIRK_SHUTDOWN setting */ +static ssize_t show_shutdown_quirk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ohci_hcd *ohci = hcd_to_ohci(bus_to_hcd(dev_get_drvdata(dev))); + + return sprintf(buf, "%d\n", !!(ohci->flags & OHCI_QUIRK_SHUTDOWN)); +} + +static ssize_t store_shutdown_quirk(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct ohci_hcd *ohci = hcd_to_ohci(bus_to_hcd(dev_get_drvdata(dev))); + int v, rc; + + rc = kstrtoint(buf, 0, &v); + if (rc) + return rc; + if (v == 1) + ohci->flags |= OHCI_QUIRK_SHUTDOWN; + else if (v == 0) + ohci->flags &= ~OHCI_QUIRK_SHUTDOWN; + else + return -ERANGE; + return count; +} +static DEVICE_ATTR(shutdown_quirk, 0644, show_shutdown_quirk, + store_shutdown_quirk); + +/* + * NVIDIA product IDs not identified correctly by the code below. + * Keep this list sorted in numeric order. + */ +static u16 nvidia_blacklist[] = { + 0x077b, 0x077d, /* MCP78S */ + 0 /* Terminating entry */ +}; + +/* + * Some NVIDIA controllers continue to drive Reset signalling on the bus * even after system shutdown, wasting power. This flag tells the * shutdown routine to leave the controller OPERATIONAL instead of RESET. */ @@ -183,18 +222,28 @@ static int ohci_quirk_nvidia_shutdown(st { struct pci_dev *pdev = to_pci_dev(hcd->self.controller); struct ohci_hcd *ohci = hcd_to_ohci(hcd); + u16 *p; - /* Evidently nVidia fixed their later hardware; this is a guess at + /* Evidently NVIDIA fixed their later hardware; this is a guess at * the changeover point. */ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d - if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) { + if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) ohci->flags |= OHCI_QUIRK_SHUTDOWN; - ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); + + /* Check against the blacklist */ + for (p = nvidia_blacklist; *p; ++p) { + if (*p == pdev->device) { + ohci->flags ^= OHCI_QUIRK_SHUTDOWN; + break; + } } + if (ohci->flags & OHCI_QUIRK_SHUTDOWN) + ohci_dbg(ohci, "enabled NVIDIA shutdown quirk\n"); - return 0; + return device_create_file(hcd->self.controller, + &dev_attr_shutdown_quirk); } static void sb800_prefetch(struct ohci_hcd *ohci, int on) @@ -322,6 +371,12 @@ static int __devinit ohci_pci_start (str return ret; } +static void ohci_pci_stop(struct usb_hcd *hcd) +{ + device_remove_file(hcd->self.controller, &dev_attr_shutdown_quirk); + ohci_stop(hcd); +} + #ifdef CONFIG_PM static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) @@ -387,7 +442,7 @@ static const struct hc_driver ohci_pci_h */ .reset = ohci_pci_reset, .start = ohci_pci_start, - .stop = ohci_stop, + .stop = ohci_pci_stop, .shutdown = ohci_shutdown, #ifdef CONFIG_PM -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html