From 4d53b8012f1f01ddb3f24db2031b042bb4cbd0d0 Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Mon, 23 Apr 2012 12:07:02 +0200 Subject: HID: Add device group to modalias HID devices are only partially presented to userland. Hotplugged devices emit events containing a modalias based on the basic bus, vendor and product entities. However, in practise a hid device can depend on details such as a single usb interface or a particular item in a report descriptor. This patch adds a device group to the hid device id, and broadcasts it using uevent and the device modalias. The module alias generation is modified to match. As a consequence, a device with a non-zero group will be processed by the corresponding group driver instead of by the generic hid driver. Signed-off-by: Henrik Rydberg Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- scripts/mod/file2alias.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'scripts/mod') diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 8e730ccc3f2b..fe967cee7371 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -336,10 +336,12 @@ static int do_hid_entry(const char *filename, struct hid_device_id *id, char *alias) { id->bus = TO_NATIVE(id->bus); + id->group = TO_NATIVE(id->group); id->vendor = TO_NATIVE(id->vendor); id->product = TO_NATIVE(id->product); sprintf(alias, "hid:b%04X", id->bus); + ADD(alias, "g", id->group != HID_GROUP_ANY, id->group); ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); ADD(alias, "p", id->product != HID_ANY_ID, id->product); -- cgit v1.2.3 From 7431fb767d896b7f0048039f2e17707ea057d35a Mon Sep 17 00:00:00 2001 From: Henrik Rydberg Date: Mon, 23 Apr 2012 12:07:04 +0200 Subject: HID: Allow bus wildcard matching Most HID drivers do not need to know what bus driver is in use. A generic group driver can drive any hid device, and the device list should not need to be duplicated for each new bus. This patch adds wildcard matching to the HID bus, simplifying device list handling for group drivers. Signed-off-by: Henrik Rydberg Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- include/linux/mod_devicetable.h | 1 + scripts/mod/file2alias.c | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'scripts/mod') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f932cd533d49..20daee56d325 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1273,7 +1273,7 @@ EXPORT_SYMBOL_GPL(hid_input_report); static bool hid_match_one_id(struct hid_device *hdev, const struct hid_device_id *id) { - return id->bus == hdev->bus && + return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) && (id->group == HID_GROUP_ANY || id->group == hdev->group) && (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) && (id->product == HID_ANY_ID || id->product == hdev->product); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 55ed0b0dc610..5db93821f9c7 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -132,6 +132,7 @@ struct usb_device_id { #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 #define HID_ANY_ID (~0) +#define HID_BUS_ANY 0xffff #define HID_GROUP_ANY 0x0000 struct hid_device_id { diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index fe967cee7371..056de3104e75 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -340,7 +340,8 @@ static int do_hid_entry(const char *filename, id->vendor = TO_NATIVE(id->vendor); id->product = TO_NATIVE(id->product); - sprintf(alias, "hid:b%04X", id->bus); + sprintf(alias, "hid:"); + ADD(alias, "b", id->bus != HID_BUS_ANY, id->bus); ADD(alias, "g", id->group != HID_GROUP_ANY, id->group); ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor); ADD(alias, "p", id->product != HID_ANY_ID, id->product); -- cgit v1.2.3 From eb3d5cc67a525df5115c1dc1c0ff8a111bda70e4 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Wed, 23 May 2012 22:28:49 +0930 Subject: modpost: Stop grab_file() from leaking filedescriptors if fstat() fails In case the open() call succeeds but the subsequent fstat() call fails, then we'll return without close()'ing the filedescriptor. Signed-off-by: Jesper Juhl Signed-off-by: Rusty Russell --- scripts/mod/modpost.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'scripts/mod') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index c4e7d1510f9d..ea0eaca597b9 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -337,17 +337,20 @@ static void sym_update_crc(const char *name, struct module *mod, void *grab_file(const char *filename, unsigned long *size) { struct stat st; - void *map; + void *map = MAP_FAILED; int fd; fd = open(filename, O_RDONLY); - if (fd < 0 || fstat(fd, &st) != 0) + if (fd < 0) return NULL; + if (fstat(fd, &st)) + goto failed; *size = st.st_size; map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); - close(fd); +failed: + close(fd); if (map == MAP_FAILED) return NULL; return map; -- cgit v1.2.3 From 3c7ec94d2c4a67d9663a080aa5080134308261c4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Apr 2012 11:10:15 -0700 Subject: modpost: use proper kernel style for autogenerated files If the kernel build process is creating files automatically, the least it can do is create them in a properly formatted manner. Sure, it's a minor issue, but being consistent is nice. Cc: Rusty Russell Cc: Alessio Igor Bogani Cc: Tony Lindgren Cc: Ben Hutchings Cc: Russell King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Rusty Russell --- scripts/mod/modpost.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'scripts/mod') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index ea0eaca597b9..0f84bb38eb0d 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -1853,14 +1853,14 @@ static void add_header(struct buffer *b, struct module *mod) buf_printf(b, "\n"); buf_printf(b, "struct module __this_module\n"); buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); - buf_printf(b, " .name = KBUILD_MODNAME,\n"); + buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); if (mod->has_init) - buf_printf(b, " .init = init_module,\n"); + buf_printf(b, "\t.init = init_module,\n"); if (mod->has_cleanup) buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" - " .exit = cleanup_module,\n" + "\t.exit = cleanup_module,\n" "#endif\n"); - buf_printf(b, " .arch = MODULE_ARCH_INIT,\n"); + buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); buf_printf(b, "};\n"); } -- cgit v1.2.3 From 81df2d594340dcb6d1a02191976be88a1ca8120c Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 18 May 2012 21:27:43 +0200 Subject: USB: allow match on bInterfaceNumber MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some composite USB devices provide multiple interfaces with different functions, all using "vendor-specific" for class/subclass/protocol. Another OS use interface numbers to match the driver and interface. It seems these devices are designed with that in mind - using static interface numbers for the different functions. This adds support for matching against the bInterfaceNumber, allowing such devices to be supported without having to resort to testing against interface number whitelists and/or blacklists in the probe. Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 9 +++++++-- drivers/usb/core/message.c | 5 +++-- drivers/usb/core/sysfs.c | 5 +++-- include/linux/mod_devicetable.h | 7 +++++++ include/linux/usb.h | 16 ++++++++++++++++ scripts/mod/file2alias.c | 5 ++++- 6 files changed, 40 insertions(+), 7 deletions(-) (limited to 'scripts/mod') diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index f536aebc958e..23d7bbd199a5 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -622,14 +622,15 @@ int usb_match_one_id(struct usb_interface *interface, if (!usb_match_device(dev, id)) return 0; - /* The interface class, subclass, and protocol should never be + /* The interface class, subclass, protocol and number should never be * checked for a match if the device class is Vendor Specific, * unless the match record specifies the Vendor ID. */ if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC && !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | - USB_DEVICE_ID_MATCH_INT_PROTOCOL))) + USB_DEVICE_ID_MATCH_INT_PROTOCOL | + USB_DEVICE_ID_MATCH_INT_NUMBER))) return 0; if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && @@ -644,6 +645,10 @@ int usb_match_one_id(struct usb_interface *interface, (id->bInterfaceProtocol != intf->desc.bInterfaceProtocol)) return 0; + if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) && + (id->bInterfaceNumber != intf->desc.bInterfaceNumber)) + return 0; + return 1; } EXPORT_SYMBOL_GPL(usb_match_one_id); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index b548cf1dbc62..ca7fc392fd9e 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1559,7 +1559,7 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) if (add_uevent_var(env, "MODALIAS=usb:" - "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X", + "v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02Xin%02X", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), le16_to_cpu(usb_dev->descriptor.bcdDevice), @@ -1568,7 +1568,8 @@ static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env) usb_dev->descriptor.bDeviceProtocol, alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol)) + alt->desc.bInterfaceProtocol, + alt->desc.bInterfaceNumber)) return -ENOMEM; return 0; diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 9a56e3adf476..777f03c37725 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -840,7 +840,7 @@ static ssize_t show_modalias(struct device *dev, alt = intf->cur_altsetting; return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X" - "ic%02Xisc%02Xip%02X\n", + "ic%02Xisc%02Xip%02Xin%02X\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), le16_to_cpu(udev->descriptor.bcdDevice), @@ -849,7 +849,8 @@ static ssize_t show_modalias(struct device *dev, udev->descriptor.bDeviceProtocol, alt->desc.bInterfaceClass, alt->desc.bInterfaceSubClass, - alt->desc.bInterfaceProtocol); + alt->desc.bInterfaceProtocol, + alt->desc.bInterfaceNumber); } static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 5db93821f9c7..7771d453e5f3 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -78,6 +78,9 @@ struct ieee1394_device_id { * of a given interface; other interfaces may support other classes. * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass. * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass. + * @bInterfaceNumber: Number of interface; composite devices may use + * fixed interface numbers to differentiate between vendor-specific + * interfaces. * @driver_info: Holds information used by the driver. Usually it holds * a pointer to a descriptor understood by the driver, or perhaps * device flags. @@ -115,6 +118,9 @@ struct usb_device_id { __u8 bInterfaceSubClass; __u8 bInterfaceProtocol; + /* Used for vendor-specific interface matches */ + __u8 bInterfaceNumber; + /* not matched against */ kernel_ulong_t driver_info; }; @@ -130,6 +136,7 @@ struct usb_device_id { #define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 #define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 #define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 +#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400 #define HID_ANY_ID (~0) #define HID_BUS_ANY 0xffff diff --git a/include/linux/usb.h b/include/linux/usb.h index dea39dc551d4..f717fbdaee8e 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -776,6 +776,22 @@ static inline int usb_make_path(struct usb_device *dev, char *buf, size_t size) .idProduct = (prod), \ .bInterfaceProtocol = (pr) +/** + * USB_DEVICE_INTERFACE_NUMBER - describe a usb device with a specific interface number + * @vend: the 16 bit USB Vendor ID + * @prod: the 16 bit USB Product ID + * @num: bInterfaceNumber value + * + * This macro is used to create a struct usb_device_id that matches a + * specific interface number of devices. + */ +#define USB_DEVICE_INTERFACE_NUMBER(vend, prod, num) \ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_NUMBER, \ + .idVendor = (vend), \ + .idProduct = (prod), \ + .bInterfaceNumber = (num) + /** * USB_DEVICE_INFO - macro used to describe a class of usb devices * @cl: bDeviceClass value diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 5759751a1f61..7ed6864ef65b 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -156,7 +156,7 @@ static void device_id_check(const char *modname, const char *device_id, } /* USB is special because the bcdDevice can be matched against a numeric range */ -/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipN" */ +/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ static void do_usb_entry(struct usb_device_id *id, unsigned int bcdDevice_initial, int bcdDevice_initial_digits, unsigned char range_lo, unsigned char range_hi, @@ -210,6 +210,9 @@ static void do_usb_entry(struct usb_device_id *id, ADD(alias, "ip", id->match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, id->bInterfaceProtocol); + ADD(alias, "in", + id->match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, + id->bInterfaceNumber); add_wildcard(alias); buf_printf(&mod->dev_table_buf, -- cgit v1.2.3 From bb15d8db7cce766b62cab624120916d25e94ac7a Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sun, 3 Jun 2012 20:48:17 +0200 Subject: scripts/modpost: check for bad references in .pci.fixups area Functions used for PCI fixups (like DECLARE_PCI_FIXUP_HEADER) are often marked __init. This is okay as long as nobody is using PCI hotplug. However if one does execute | echo 1 > /sys/bus/pci/rescan and we hit a module which is marked __init istead of __devinit then we go boom because the code is removed after the kernel booted. This patch help to see those section mismatches. Cc: Michal Marek Cc: linux-kbuild@vger.kernel.org Cc: Rusty Russell Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Bjorn Helgaas --- scripts/mod/modpost.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'scripts/mod') diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 0f84bb38eb0d..68e9f5ed0a6f 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -865,6 +865,11 @@ static void check_section(const char *modname, struct elf_info *elf, #define ALL_EXIT_TEXT_SECTIONS \ ".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$" +#define ALL_PCI_INIT_SECTIONS \ + ".pci_fixup_early$", ".pci_fixup_header$", ".pci_fixup_final$", \ + ".pci_fixup_enable$", ".pci_fixup_resume$", \ + ".pci_fixup_resume_early$", ".pci_fixup_suspend$" + #define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \ MEM_INIT_SECTIONS #define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \ @@ -1027,6 +1032,12 @@ const struct sectioncheck sectioncheck[] = { .mismatch = ANY_EXIT_TO_ANY_INIT, .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, }, +{ + .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, + .tosec = { INIT_SECTIONS, NULL }, + .mismatch = ANY_INIT_TO_ANY_EXIT, + .symbol_white_list = { NULL }, +}, /* Do not export init/exit functions or data */ { .fromsec = { "__ksymtab*", NULL }, -- cgit v1.2.3