Re: [PATCH] HID: usbhid: Add mechanism to blacklist based on device release

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

 



Seems a reasonable mechanism for everybody,
Thanks for working it Niels !
Adding my Acked-by and a couple of suggestions.

On Mon, Oct 2, 2017 at 11:04 AM,  <nolsen@xxxxxxxxx> wrote:
> From: Niels Skou Olsen <nolsen@xxxxxxxxx>
>
> Modify usbhid_exists_squirk() to consider the device release number
> (bcdDevice) of devices marked for HID_QUIRK_IGNORE. This allows for
> conditional blacklisting of devices older than a known good release.
>
> Also, use this mechanism to un-blacklist two Jabra speakerphone devices
> that were blacklisted in 2013, and now have fixed the firmware. These
> devices encode firmware version in bcdDevice.
>
> For reference, see the original blacklist commit:
> Commit 31b9779cb292 ("HID: ignore Jabra speakerphones HID interface")
>
> Signed-off-by: Niels Skou Olsen <nolsen@xxxxxxxxx>


Acked-by: Vincent Palatin <vpalatin@xxxxxxxxxxxx>


> ---
>  drivers/hid/hid-core.c          |  2 -
>  drivers/hid/usbhid/hid-core.c   |  7 +++-
>  drivers/hid/usbhid/hid-quirks.c | 86 +++++++++++++++++++++++++++++++++++++----
>  include/linux/hid.h             |  4 +-
>  4 files changed, 87 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 9bc9116..b49d7c4 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -2697,8 +2697,6 @@ static const struct hid_device_id hid_ignore_list[] = {
>         { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
> -       { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410) },
> -       { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_GN9350E) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
>         { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) },
> diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
> index 089bad8..2cde551 100644
> --- a/drivers/hid/usbhid/hid-core.c
> +++ b/drivers/hid/usbhid/hid-core.c
> @@ -977,7 +977,8 @@ static int usbhid_parse(struct hid_device *hid)
>         int ret, n;
>
>         quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
> -                       le16_to_cpu(dev->descriptor.idProduct));
> +                                    le16_to_cpu(dev->descriptor.idProduct),
> +                                    le16_to_cpu(dev->descriptor.bcdDevice));
>
>         if (quirks & HID_QUIRK_IGNORE)
>                 return -ENODEV;
> @@ -1289,6 +1290,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
>         unsigned int n, has_in = 0;
>         size_t len;
>         int ret;
> +       const u16 bcdDevice = le16_to_cpu(dev->descriptor.bcdDevice);
>
>         dbg_hid("HID probe called for ifnum %d\n",
>                         intf->altsetting->desc.bInterfaceNumber);
> @@ -1319,7 +1321,8 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
>         hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
>         hid->product = le16_to_cpu(dev->descriptor.idProduct);
>         hid->name[0] = 0;
> -       hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product);
> +       hid->quirks = usbhid_lookup_quirk(hid->vendor, hid->product, bcdDevice);
> +
>         if (intf->cur_altsetting->desc.bInterfaceProtocol ==
>                         USB_INTERFACE_PROTOCOL_MOUSE)
>                 hid->type = HID_TYPE_USBMOUSE;
> diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
> index a83fa76..c19b8a8 100644
> --- a/drivers/hid/usbhid/hid-quirks.c
> +++ b/drivers/hid/usbhid/hid-quirks.c
> @@ -99,6 +99,8 @@ static const struct hid_blacklist {
>         { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL },
>         { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
>         { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
> +       { USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410, HID_QUIRK_IGNORE },
> +       { USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510, HID_QUIRK_IGNORE },
>         { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007, HID_QUIRK_ALWAYS_POLL },
>         { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
>         { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET },
> @@ -173,6 +175,27 @@ static const struct hid_blacklist {
>         { 0, 0 }
>  };
>
> +/*
> + * Entries in hid_ignore_by_release[] specify a known good version of a
> + * device. Version is the bcdDevice field of the device descriptor, which
> + * according to the USB spec is defined as a 'device release number'. Some
> + * vendors encode firmware version in this field.
> + *
> + * A device with a HID_QUIRK_IGNORE entry in hid_blacklist[] _and_ an
> + * entry in hid_ignore_by_release[], will have its bcdDevice value checked


Is there really a value in putting it in both lists ? can we put it
only in the latter ?


> + * against the good_release value. If the bcdDevice value is less than
> + * good_release the device is ignored.
> + */
> +static const struct hid_ignore_by_release {
> +       __u16 idVendor;
> +       __u16 idProduct;
> +       __u16 good_release;
> +} hid_ignore_by_release[] = {
> +       { USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410, 0x111 },
> +       { USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510, 0x214 },
> +       { 0, 0 }
> +};


Maybe we should use here 'struct usb_device_id' as done in other drivers.
(and maybe put the flags in  .driver_info)
It conveniently  has a .bcdDevice_lo and .bcdDevice_hi fields.
Then we can use the more generic usb_match_id() function.

> +
>  /* Dynamic HID quirks list - specified at runtime */
>  struct quirks_list_struct {
>         struct hid_blacklist hid_bl_item;
> @@ -335,18 +358,62 @@ void usbhid_quirks_exit(void)
>  }
>
>  /**
> + * usbhid_ignore_based_on_device_release: conditionally ignore based
> + *                                        on bcdDevice
> + *
> + * Description:
> + *
> + *     Given a HID_QUIRK_IGNORE blacklist entry and a bcdDevice value,
> + *     check to see if the bcdDevice is less than a known good release.
> + *
> + * Returns: pointer if the device must be ignored, NULL otherwise
> + */
> +static const struct hid_blacklist *
> +usbhid_ignore_based_on_device_release(const struct hid_blacklist *bl_entry,
> +                                     const u16 bcdDevice)
> +{
> +       const struct hid_ignore_by_release *entry = NULL;
> +       int n = 0;
> +
> +       if (bl_entry == NULL || bl_entry->quirks != HID_QUIRK_IGNORE)
> +               return bl_entry;
> +
> +       for (; hid_ignore_by_release[n].idVendor; n++)
> +               if (hid_ignore_by_release[n].idVendor == bl_entry->idVendor &&
> +                   (hid_ignore_by_release[n].idProduct == (__u16) HID_ANY_ID ||
> +                    hid_ignore_by_release[n].idProduct == bl_entry->idProduct))
> +                       entry = &hid_ignore_by_release[n];
> +
> +       if (entry != NULL) {
> +               if (bcdDevice < entry->good_release)
> +                       /* Go on and let the ignore happen */
> +                       return bl_entry;
> +
> +               /* Override the passed blacklist entry, and allow the device */
> +               return NULL;
> +       }
> +
> +       /* We found no device release based ignore info, so the passed
> +        * HID_QUIRK_IGNORE blacklist entry must be used
> +        */
> +       return bl_entry;
> +}
> +
> +/**
>   * usbhid_exists_squirk: return any static quirks for a USB HID device
>   * @idVendor: the 16-bit USB vendor ID, in native byteorder
>   * @idProduct: the 16-bit USB product ID, in native byteorder
> + * @bcdDevice: the 16-bit USB device release number, in native byteorder
>   *
>   * Description:
> - *     Given a USB vendor ID and product ID, return a pointer to
> - *     the hid_blacklist entry associated with that device.
> + *     Given a USB vendor, product ID, and device release number return a
> + *     pointer to the hid_blacklist entry associated with that device.
>   *
>   * Returns: pointer if quirk found, or NULL if no quirks found.
>   */
>  static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
> -               const u16 idProduct)
> +                                                       const u16 idProduct,
> +                                                       const u16 bcdDevice)
>  {
>         const struct hid_blacklist *bl_entry = NULL;
>         int n = 0;
> @@ -357,6 +424,8 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
>                                 hid_blacklist[n].idProduct == idProduct))
>                         bl_entry = &hid_blacklist[n];
>
> +       bl_entry = usbhid_ignore_based_on_device_release(bl_entry, bcdDevice);
> +
>         if (bl_entry != NULL)
>                 dbg_hid("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n",
>                                 bl_entry->quirks, bl_entry->idVendor,
> @@ -368,14 +437,17 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
>   * usbhid_lookup_quirk: return any quirks associated with a USB HID device
>   * @idVendor: the 16-bit USB vendor ID, in native byteorder
>   * @idProduct: the 16-bit USB product ID, in native byteorder
> + * @bcdDevice: the 16-bit USB device release number, in native byteorder
>   *
>   * Description:
> - *     Given a USB vendor ID and product ID, return any quirks associated
> - *     with that device.
> + *     Given a USB vendor ID, product ID and device release number, return
> + *     any quirks associated with that device.
>   *
>   * Returns: a u32 quirks value.
>   */
> -u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
> +u32 usbhid_lookup_quirk(const u16 idVendor,
> +                       const u16 idProduct,
> +                       const u16 bcdDevice)
>  {
>         u32 quirks = 0;
>         const struct hid_blacklist *bl_entry = NULL;
> @@ -389,7 +461,7 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
>         down_read(&dquirks_rwsem);
>         bl_entry = usbhid_exists_dquirk(idVendor, idProduct);
>         if (!bl_entry)
> -               bl_entry = usbhid_exists_squirk(idVendor, idProduct);
> +               bl_entry = usbhid_exists_squirk(idVendor, idProduct, bcdDevice);
>         if (bl_entry)
>                 quirks = bl_entry->quirks;
>         up_read(&dquirks_rwsem);
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index ab05a86..273795a 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -1096,7 +1096,9 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
>                 int interrupt);
>
>  /* HID quirks API */
> -u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
> +u32 usbhid_lookup_quirk(const u16 idVendor,
> +                       const u16 idProduct,
> +                       const u16 bcdDevice);
>  int usbhid_quirks_init(char **quirks_param);
>  void usbhid_quirks_exit(void);
>
> --
> 2.7.4
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux