/*
       * cdc_ncm.c
       *
       * Copyright (C) ST-Ericsson 2010-2012
       * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
       * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
       *
       * USB Host Driver for Network Control Model (NCM)
       * http://www.usb.org/developers/docs/devclass_docs/NCM10_012011.zip
       *
       * The NCM encoding, decoding and initialization logic
       * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
       *
       * This software is available to you under a choice of one of two
       * licenses. You may choose this file to be licensed under the terms
       * of the GNU General Public License (GPL) Version 2 or the 2-clause
       * BSD license listed below:
       *
       * Redistribution and use in source and binary forms, with or without
       * modification, are permitted provided that the following conditions
       * are met:
       * 1. Redistributions of source code must retain the above copyright
       *    notice, this list of conditions and the following disclaimer.
       * 2. Redistributions in binary form must reproduce the above copyright
       *    notice, this list of conditions and the following disclaimer in the
       *    documentation and/or other materials provided with the distribution.
       *
       * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
       * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
       * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
       * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
       * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
       * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
       * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
       * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
       * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
       * SUCH DAMAGE.
       */
      
      #include <linux/module.h>
      #include <linux/netdevice.h>
      #include <linux/ctype.h>
      #include <linux/etherdevice.h>
      #include <linux/ethtool.h>
      #include <linux/workqueue.h>
      #include <linux/mii.h>
      #include <linux/crc32.h>
      #include <linux/usb.h>
      #include <linux/hrtimer.h>
      #include <linux/atomic.h>
      #include <linux/usb/usbnet.h>
      #include <linux/usb/cdc.h>
      #include <linux/usb/cdc_ncm.h>
      
      #if IS_ENABLED(CONFIG_USB_NET_CDC_MBIM)
      static bool prefer_mbim = true;
      #else
      static bool prefer_mbim;
      #endif
      module_param(prefer_mbim, bool, 0644);
      MODULE_PARM_DESC(prefer_mbim, "Prefer MBIM setting on dual NCM/MBIM functions");
      
      static void cdc_ncm_txpath_bh(unsigned long param);
      static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx);
      static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *hr_timer);
      static struct usb_driver cdc_ncm_driver;
      
      struct cdc_ncm_stats {
              char stat_string[ETH_GSTRING_LEN];
              int sizeof_stat;
              int stat_offset;
      };
      
      #define CDC_NCM_STAT(str, m) { \
                      .stat_string = str, \
                      .sizeof_stat = sizeof(((struct cdc_ncm_ctx *)0)->m), \
                      .stat_offset = offsetof(struct cdc_ncm_ctx, m) }
      #define CDC_NCM_SIMPLE_STAT(m)        CDC_NCM_STAT(__stringify(m), m)
      
      static const struct cdc_ncm_stats cdc_ncm_gstrings_stats[] = {
              CDC_NCM_SIMPLE_STAT(tx_reason_ntb_full),
              CDC_NCM_SIMPLE_STAT(tx_reason_ndp_full),
              CDC_NCM_SIMPLE_STAT(tx_reason_timeout),
              CDC_NCM_SIMPLE_STAT(tx_reason_max_datagram),
              CDC_NCM_SIMPLE_STAT(tx_overhead),
              CDC_NCM_SIMPLE_STAT(tx_ntbs),
              CDC_NCM_SIMPLE_STAT(rx_overhead),
              CDC_NCM_SIMPLE_STAT(rx_ntbs),
      };
      
      #define CDC_NCM_LOW_MEM_MAX_CNT 10
      
      static int cdc_ncm_get_sset_count(struct net_device __always_unused *netdev, int sset)
      {
              switch (sset) {
              case ETH_SS_STATS:
                      return ARRAY_SIZE(cdc_ncm_gstrings_stats);
              default:
                      return -EOPNOTSUPP;
              }
      }
      
      static void cdc_ncm_get_ethtool_stats(struct net_device *netdev,
                                          struct ethtool_stats __always_unused *stats,
                                          u64 *data)
      {
              struct usbnet *dev = netdev_priv(netdev);
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              int i;
              char *p = NULL;
      
              for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
                      p = (char *)ctx + cdc_ncm_gstrings_stats[i].stat_offset;
                      data[i] = (cdc_ncm_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
              }
      }
      
      static void cdc_ncm_get_strings(struct net_device __always_unused *netdev, u32 stringset, u8 *data)
      {
              u8 *p = data;
              int i;
      
              switch (stringset) {
              case ETH_SS_STATS:
                      for (i = 0; i < ARRAY_SIZE(cdc_ncm_gstrings_stats); i++) {
                              memcpy(p, cdc_ncm_gstrings_stats[i].stat_string, ETH_GSTRING_LEN);
                              p += ETH_GSTRING_LEN;
                      }
              }
      }
      
      static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx);
      
      static const struct ethtool_ops cdc_ncm_ethtool_ops = {
              .get_link          = usbnet_get_link,
              .nway_reset        = usbnet_nway_reset,
              .get_drvinfo       = usbnet_get_drvinfo,
              .get_msglevel      = usbnet_get_msglevel,
              .set_msglevel      = usbnet_set_msglevel,
              .get_ts_info       = ethtool_op_get_ts_info,
              .get_sset_count    = cdc_ncm_get_sset_count,
              .get_strings       = cdc_ncm_get_strings,
              .get_ethtool_stats = cdc_ncm_get_ethtool_stats,
              .get_link_ksettings      = usbnet_get_link_ksettings,
              .set_link_ksettings      = usbnet_set_link_ksettings,
      };
      
      static u32 cdc_ncm_check_rx_max(struct usbnet *dev, u32 new_rx)
      {
    8         struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              u32 val, max, min;
      
              /* clamp new_rx to sane values */
              min = USB_CDC_NCM_NTB_MIN_IN_SIZE;
              max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_RX, le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize));
      
              /* dwNtbInMaxSize spec violation? Use MIN size for both limits */
              if (max < min) {
    5                 dev_warn(&dev->intf->dev, "dwNtbInMaxSize=%u is too small. Using %u\n",
                               le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize), min);
                      max = min;
              }
      
    8         val = clamp_t(u32, new_rx, min, max);
              if (val != new_rx)
    5                 dev_dbg(&dev->intf->dev, "rx_max must be in the [%u, %u] range\n", min, max);
      
    8         return val;
      }
      
      static u32 cdc_ncm_check_tx_max(struct usbnet *dev, u32 new_tx)
      {
    8         struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              u32 val, max, min;
      
              /* clamp new_tx to sane values */
              if (ctx->is_ndp16)
    8                 min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth16);
              else
                      min = ctx->max_datagram_size + ctx->max_ndp_size + sizeof(struct usb_cdc_ncm_nth32);
      
    8         max = min_t(u32, CDC_NCM_NTB_MAX_SIZE_TX, le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
      
              /* some devices set dwNtbOutMaxSize too low for the above default */
              min = min(min, max);
      
              val = clamp_t(u32, new_tx, min, max);
              if (val != new_tx)
                      dev_dbg(&dev->intf->dev, "tx_max must be in the [%u, %u] range\n", min, max);
      
    8         return val;
      }
      
      static ssize_t cdc_ncm_show_min_tx_pkt(struct device *d, struct device_attribute *attr, char *buf)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              return sprintf(buf, "%u\n", ctx->min_tx_pkt);
      }
      
      static ssize_t cdc_ncm_show_rx_max(struct device *d, struct device_attribute *attr, char *buf)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              return sprintf(buf, "%u\n", ctx->rx_max);
      }
      
      static ssize_t cdc_ncm_show_tx_max(struct device *d, struct device_attribute *attr, char *buf)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              return sprintf(buf, "%u\n", ctx->tx_max);
      }
      
      static ssize_t cdc_ncm_show_tx_timer_usecs(struct device *d, struct device_attribute *attr, char *buf)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              return sprintf(buf, "%u\n", ctx->timer_interval / (u32)NSEC_PER_USEC);
      }
      
      static ssize_t cdc_ncm_store_min_tx_pkt(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              unsigned long val;
      
              /* no need to restrict values - anything from 0 to infinity is OK */
              if (kstrtoul(buf, 0, &val))
                      return -EINVAL;
      
              ctx->min_tx_pkt = val;
              return len;
      }
      
      static ssize_t cdc_ncm_store_rx_max(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              unsigned long val;
      
              if (kstrtoul(buf, 0, &val) || cdc_ncm_check_rx_max(dev, val) != val)
                      return -EINVAL;
      
              cdc_ncm_update_rxtx_max(dev, val, ctx->tx_max);
              return len;
      }
      
      static ssize_t cdc_ncm_store_tx_max(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              unsigned long val;
      
              if (kstrtoul(buf, 0, &val) || cdc_ncm_check_tx_max(dev, val) != val)
                      return -EINVAL;
      
              cdc_ncm_update_rxtx_max(dev, ctx->rx_max, val);
              return len;
      }
      
      static ssize_t cdc_ncm_store_tx_timer_usecs(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              ssize_t ret;
              unsigned long val;
      
              ret = kstrtoul(buf, 0, &val);
              if (ret)
                      return ret;
              if (val && (val < CDC_NCM_TIMER_INTERVAL_MIN || val > CDC_NCM_TIMER_INTERVAL_MAX))
                      return -EINVAL;
      
              spin_lock_bh(&ctx->mtx);
              ctx->timer_interval = val * NSEC_PER_USEC;
              if (!ctx->timer_interval)
                      ctx->tx_timer_pending = 0;
              spin_unlock_bh(&ctx->mtx);
              return len;
      }
      
      static DEVICE_ATTR(min_tx_pkt, 0644, cdc_ncm_show_min_tx_pkt, cdc_ncm_store_min_tx_pkt);
      static DEVICE_ATTR(rx_max, 0644, cdc_ncm_show_rx_max, cdc_ncm_store_rx_max);
      static DEVICE_ATTR(tx_max, 0644, cdc_ncm_show_tx_max, cdc_ncm_store_tx_max);
      static DEVICE_ATTR(tx_timer_usecs, 0644, cdc_ncm_show_tx_timer_usecs, cdc_ncm_store_tx_timer_usecs);
      
      static ssize_t ndp_to_end_show(struct device *d, struct device_attribute *attr, char *buf)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              return sprintf(buf, "%c\n", ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END ? 'Y' : 'N');
      }
      
      static ssize_t ndp_to_end_store(struct device *d,  struct device_attribute *attr, const char *buf, size_t len)
      {
              struct usbnet *dev = netdev_priv(to_net_dev(d));
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              bool enable;
      
              if (strtobool(buf, &enable))
                      return -EINVAL;
      
              /* no change? */
              if (enable == (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
                      return len;
      
              if (enable) {
                      if (ctx->is_ndp16 && !ctx->delayed_ndp16) {
                              ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
                              if (!ctx->delayed_ndp16)
                                      return -ENOMEM;
                      }
                      if (!ctx->is_ndp16 && !ctx->delayed_ndp32) {
                              ctx->delayed_ndp32 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
                              if (!ctx->delayed_ndp32)
                                      return -ENOMEM;
                      }
              }
      
              /* flush pending data before changing flag */
              netif_tx_lock_bh(dev->net);
              usbnet_start_xmit(NULL, dev->net);
              spin_lock_bh(&ctx->mtx);
              if (enable)
                      ctx->drvflags |= CDC_NCM_FLAG_NDP_TO_END;
              else
                      ctx->drvflags &= ~CDC_NCM_FLAG_NDP_TO_END;
              spin_unlock_bh(&ctx->mtx);
              netif_tx_unlock_bh(dev->net);
      
              return len;
      }
      static DEVICE_ATTR_RW(ndp_to_end);
      
      #define NCM_PARM_ATTR(name, format, tocpu)                                \
      static ssize_t cdc_ncm_show_##name(struct device *d, struct device_attribute *attr, char *buf) \
      { \
              struct usbnet *dev = netdev_priv(to_net_dev(d)); \
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0]; \
              return sprintf(buf, format "\n", tocpu(ctx->ncm_parm.name));        \
      } \
      static DEVICE_ATTR(name, 0444, cdc_ncm_show_##name, NULL)
      
      NCM_PARM_ATTR(bmNtbFormatsSupported, "0x%04x", le16_to_cpu);
      NCM_PARM_ATTR(dwNtbInMaxSize, "%u", le32_to_cpu);
      NCM_PARM_ATTR(wNdpInDivisor, "%u", le16_to_cpu);
      NCM_PARM_ATTR(wNdpInPayloadRemainder, "%u", le16_to_cpu);
      NCM_PARM_ATTR(wNdpInAlignment, "%u", le16_to_cpu);
      NCM_PARM_ATTR(dwNtbOutMaxSize, "%u", le32_to_cpu);
      NCM_PARM_ATTR(wNdpOutDivisor, "%u", le16_to_cpu);
      NCM_PARM_ATTR(wNdpOutPayloadRemainder, "%u", le16_to_cpu);
      NCM_PARM_ATTR(wNdpOutAlignment, "%u", le16_to_cpu);
      NCM_PARM_ATTR(wNtbOutMaxDatagrams, "%u", le16_to_cpu);
      
      static struct attribute *cdc_ncm_sysfs_attrs[] = {
              &dev_attr_min_tx_pkt.attr,
              &dev_attr_ndp_to_end.attr,
              &dev_attr_rx_max.attr,
              &dev_attr_tx_max.attr,
              &dev_attr_tx_timer_usecs.attr,
              &dev_attr_bmNtbFormatsSupported.attr,
              &dev_attr_dwNtbInMaxSize.attr,
              &dev_attr_wNdpInDivisor.attr,
              &dev_attr_wNdpInPayloadRemainder.attr,
              &dev_attr_wNdpInAlignment.attr,
              &dev_attr_dwNtbOutMaxSize.attr,
              &dev_attr_wNdpOutDivisor.attr,
              &dev_attr_wNdpOutPayloadRemainder.attr,
              &dev_attr_wNdpOutAlignment.attr,
              &dev_attr_wNtbOutMaxDatagrams.attr,
              NULL,
      };
      
      static const struct attribute_group cdc_ncm_sysfs_attr_group = {
              .name = "cdc_ncm",
              .attrs = cdc_ncm_sysfs_attrs,
      };
      
      /* handle rx_max and tx_max changes */
      static void cdc_ncm_update_rxtx_max(struct usbnet *dev, u32 new_rx, u32 new_tx)
      {
    8         struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
              u32 val;
      
              val = cdc_ncm_check_rx_max(dev, new_rx);
      
              /* inform device about NTB input size changes */
              if (val != ctx->rx_max) {
    5                 __le32 dwNtbInMaxSize = cpu_to_le32(val);
      
                      dev_info(&dev->intf->dev, "setting rx_max = %u\n", val);
      
                      /* tell device to use new size */
                      if (usbnet_write_cmd(dev, USB_CDC_SET_NTB_INPUT_SIZE,
                                           USB_TYPE_CLASS | USB_DIR_OUT
                                           | USB_RECIP_INTERFACE,
                                           0, iface_no, &dwNtbInMaxSize, 4) < 0)
    5                         dev_dbg(&dev->intf->dev, "Setting NTB Input Size failed\n");
                      else
    2                         ctx->rx_max = val;
              }
      
              /* usbnet use these values for sizing rx queues */
    8         if (dev->rx_urb_size != ctx->rx_max) {
    5                 dev->rx_urb_size = ctx->rx_max;
                      if (netif_running(dev->net))
                              usbnet_unlink_rx_urbs(dev);
              }
      
    8         val = cdc_ncm_check_tx_max(dev, new_tx);
              if (val != ctx->tx_max)
                      dev_info(&dev->intf->dev, "setting tx_max = %u\n", val);
      
              /* Adding a pad byte here if necessary simplifies the handling
               * in cdc_ncm_fill_tx_frame, making tx_max always represent
               * the real skb max size.
               *
               * We cannot use dev->maxpacket here because this is called from
               * .bind which is called before usbnet sets up dev->maxpacket
               */
    8         if (val != le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize) &&
                  val % usb_maxpacket(dev->udev, dev->out, 1) == 0)
                      val++;
      
              /* we might need to flush any pending tx buffers if running */
    8         if (netif_running(dev->net) && val > ctx->tx_max) {
                      netif_tx_lock_bh(dev->net);
                      usbnet_start_xmit(NULL, dev->net);
                      /* make sure tx_curr_skb is reallocated if it was empty */
                      if (ctx->tx_curr_skb) {
                              dev_kfree_skb_any(ctx->tx_curr_skb);
                              ctx->tx_curr_skb = NULL;
                      }
                      ctx->tx_max = val;
                      netif_tx_unlock_bh(dev->net);
              } else {
    8                 ctx->tx_max = val;
              }
      
    8         dev->hard_mtu = ctx->tx_max;
      
              /* max qlen depend on hard_mtu and rx_urb_size */
              usbnet_update_max_qlen(dev);
      
              /* never pad more than 3 full USB packets per transfer */
    8         ctx->min_tx_pkt = clamp_t(u16, ctx->tx_max - 3 * usb_maxpacket(dev->udev, dev->out, 1),
                                        CDC_NCM_MIN_TX_PKT, ctx->tx_max);
      }
      
      /* helpers for NCM and MBIM differences */
      static u8 cdc_ncm_flags(struct usbnet *dev)
      {
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
                      return ctx->mbim_desc->bmNetworkCapabilities;
   10         if (ctx->func_desc)
   10                 return ctx->func_desc->bmNetworkCapabilities;
              return 0;
      }
      
      static int cdc_ncm_eth_hlen(struct usbnet *dev)
      {
    8         if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
                      return 0;
              return ETH_HLEN;
      }
      
      static u32 cdc_ncm_min_dgram_size(struct usbnet *dev)
      {
              if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting))
                      return CDC_MBIM_MIN_DATAGRAM_SIZE;
              return CDC_NCM_MIN_DATAGRAM_SIZE;
      }
      
      static u32 cdc_ncm_max_dgram_size(struct usbnet *dev)
      {
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              if (cdc_ncm_comm_intf_is_mbim(dev->intf->cur_altsetting) && ctx->mbim_desc)
                      return le16_to_cpu(ctx->mbim_desc->wMaxSegmentSize);
   10         if (ctx->ether_desc)
    8                 return le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
              return CDC_NCM_MAX_DATAGRAM_SIZE;
      }
      
      /* initial one-time device setup.  MUST be called with the data interface
       * in altsetting 0
       */
      static int cdc_ncm_init(struct usbnet *dev)
      {
   10         struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
              int err;
      
              err = usbnet_read_cmd(dev, USB_CDC_GET_NTB_PARAMETERS,
                                    USB_TYPE_CLASS | USB_DIR_IN
                                    |USB_RECIP_INTERFACE,
                                    0, iface_no, &ctx->ncm_parm,
                                    sizeof(ctx->ncm_parm));
              if (err < 0) {
                      dev_err(&dev->intf->dev, "failed GET_NTB_PARAMETERS\n");
                      return err; /* GET_NTB_PARAMETERS is required */
              }
      
              /* set CRC Mode */
   10         if (cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_CRC_MODE) {
                      dev_dbg(&dev->intf->dev, "Setting CRC mode off\n");
                      err = usbnet_write_cmd(dev, USB_CDC_SET_CRC_MODE,
                                             USB_TYPE_CLASS | USB_DIR_OUT
                                             | USB_RECIP_INTERFACE,
                                             USB_CDC_NCM_CRC_NOT_APPENDED,
                                             iface_no, NULL, 0);
                      if (err < 0)
                              dev_err(&dev->intf->dev, "SET_CRC_MODE failed\n");
              }
      
              /* use ndp16 by default */
   10         ctx->is_ndp16 = 1;
      
              /* set NTB format, if both formats are supported.
               *
               * "The host shall only send this command while the NCM Data
               *  Interface is in alternate setting 0."
               */
              if (le16_to_cpu(ctx->ncm_parm.bmNtbFormatsSupported) &
                                                      USB_CDC_NCM_NTB32_SUPPORTED) {
                      if (ctx->drvflags & CDC_NCM_FLAG_PREFER_NTB32) {
                              ctx->is_ndp16 = 0;
                              dev_dbg(&dev->intf->dev, "Setting NTB format to 32-bit\n");
                              err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
                                                     USB_TYPE_CLASS | USB_DIR_OUT
                                                     | USB_RECIP_INTERFACE,
                                                     USB_CDC_NCM_NTB32_FORMAT,
                                                     iface_no, NULL, 0);
                      } else {
                              ctx->is_ndp16 = 1;
                              dev_dbg(&dev->intf->dev, "Setting NTB format to 16-bit\n");
                              err = usbnet_write_cmd(dev, USB_CDC_SET_NTB_FORMAT,
                                                     USB_TYPE_CLASS | USB_DIR_OUT
                                                     | USB_RECIP_INTERFACE,
                                                     USB_CDC_NCM_NTB16_FORMAT,
                                                     iface_no, NULL, 0);
                      }
                      if (err < 0) {
                              ctx->is_ndp16 = 1;
                              dev_err(&dev->intf->dev, "SET_NTB_FORMAT failed\n");
                      }
              }
      
              /* set initial device values */
   10         ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
              ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
              ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
              ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
              ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
              /* devices prior to NCM Errata shall set this field to zero */
              ctx->tx_max_datagrams = le16_to_cpu(ctx->ncm_parm.wNtbOutMaxDatagrams);
      
   10         dev_dbg(&dev->intf->dev,
                      "dwNtbInMaxSize=%u dwNtbOutMaxSize=%u wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u wNdpOutAlignment=%u wNtbOutMaxDatagrams=%u flags=0x%x\n",
                      ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
                      ctx->tx_ndp_modulus, ctx->tx_max_datagrams, cdc_ncm_flags(dev));
      
              /* max count of tx datagrams */
   10         if ((ctx->tx_max_datagrams == 0) ||
                              (ctx->tx_max_datagrams > CDC_NCM_DPT_DATAGRAMS_MAX))
   10                 ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
      
              /* set up maximum NDP size */
   10         if (ctx->is_ndp16)
   10                 ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp16) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe16);
              else
                      ctx->max_ndp_size = sizeof(struct usb_cdc_ncm_ndp32) + (ctx->tx_max_datagrams + 1) * sizeof(struct usb_cdc_ncm_dpe32);
      
              /* initial coalescing timer interval */
              ctx->timer_interval = CDC_NCM_TIMER_INTERVAL_USEC * NSEC_PER_USEC;
      
              return 0;
      }
      
      /* set a new max datagram size */
      static void cdc_ncm_set_dgram_size(struct usbnet *dev, int new_size)
      {
    8         struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              u8 iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
              __le16 max_datagram_size;
              u16 mbim_mtu;
              int err;
      
              /* set default based on descriptors */
    8         ctx->max_datagram_size = clamp_t(u32, new_size,
                                               cdc_ncm_min_dgram_size(dev),
                                               CDC_NCM_MAX_DATAGRAM_SIZE);
      
              /* inform the device about the selected Max Datagram Size? */
    8         if (!(cdc_ncm_flags(dev) & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE))
                      goto out;
      
              /* read current mtu value from device */
              err = usbnet_read_cmd(dev, USB_CDC_GET_MAX_DATAGRAM_SIZE,
                                    USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
                                    0, iface_no, &max_datagram_size, sizeof(max_datagram_size));
              if (err != sizeof(max_datagram_size)) {
                      dev_dbg(&dev->intf->dev, "GET_MAX_DATAGRAM_SIZE failed\n");
                      goto out;
              }
      
              if (le16_to_cpu(max_datagram_size) == ctx->max_datagram_size)
                      goto out;
      
              max_datagram_size = cpu_to_le16(ctx->max_datagram_size);
              err = usbnet_write_cmd(dev, USB_CDC_SET_MAX_DATAGRAM_SIZE,
                                     USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
                                     0, iface_no, &max_datagram_size, sizeof(max_datagram_size));
              if (err < 0)
                      dev_dbg(&dev->intf->dev, "SET_MAX_DATAGRAM_SIZE failed\n");
      
      out:
              /* set MTU to max supported by the device if necessary */
    8         dev->net->mtu = min_t(int, dev->net->mtu, ctx->max_datagram_size - cdc_ncm_eth_hlen(dev));
      
              /* do not exceed operater preferred MTU */
              if (ctx->mbim_extended_desc) {
    1                 mbim_mtu = le16_to_cpu(ctx->mbim_extended_desc->wMTU);
    8                 if (mbim_mtu != 0 && mbim_mtu < dev->net->mtu)
    1                         dev->net->mtu = mbim_mtu;
              }
      }
      
      static void cdc_ncm_fix_modulus(struct usbnet *dev)
      {
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              u32 val;
      
              /*
               * verify that the structure alignment is:
               * - power of two
               * - not greater than the maximum transmit length
               * - not less than four bytes
               */
              val = ctx->tx_ndp_modulus;
      
              if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
                  (val != ((-val) & val)) || (val >= ctx->tx_max)) {
    8                 dev_dbg(&dev->intf->dev, "Using default alignment: 4 bytes\n");
    8                 ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
              }
      
              /*
               * verify that the payload alignment is:
               * - power of two
               * - not greater than the maximum transmit length
               * - not less than four bytes
               */
    8         val = ctx->tx_modulus;
      
              if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
    1             (val != ((-val) & val)) || (val >= ctx->tx_max)) {
    8                 dev_dbg(&dev->intf->dev, "Using default transmit modulus: 4 bytes\n");
    8                 ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
              }
      
              /* verify the payload remainder */
    8         if (ctx->tx_remainder >= ctx->tx_modulus) {
                      dev_dbg(&dev->intf->dev, "Using default transmit remainder: 0 bytes\n");
                      ctx->tx_remainder = 0;
              }
      
              /* adjust TX-remainder according to NCM specification. */
    8         ctx->tx_remainder = ((ctx->tx_remainder - cdc_ncm_eth_hlen(dev)) &
    8                              (ctx->tx_modulus - 1));
      }
      
      static int cdc_ncm_setup(struct usbnet *dev)
      {
    8         struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              u32 def_rx, def_tx;
      
              /* be conservative when selecting intial buffer size to
               * increase the number of hosts this will work for
               */
              def_rx = min_t(u32, CDC_NCM_NTB_DEF_SIZE_RX,
                             le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize));
              def_tx = min_t(u32, CDC_NCM_NTB_DEF_SIZE_TX,
                             le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize));
      
              /* clamp rx_max and tx_max and inform device */
              cdc_ncm_update_rxtx_max(dev, def_rx, def_tx);
      
              /* sanitize the modulus and remainder values */
    8         cdc_ncm_fix_modulus(dev);
      
              /* set max datagram size */
    8         cdc_ncm_set_dgram_size(dev, cdc_ncm_max_dgram_size(dev));
              return 0;
      }
      
      static void
      cdc_ncm_find_endpoints(struct usbnet *dev, struct usb_interface *intf)
      {
              struct usb_host_endpoint *e, *in = NULL, *out = NULL;
              u8 ep;
      
   10         for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
   10                 e = intf->cur_altsetting->endpoint + ep;
      
                      /* ignore endpoints which cannot transfer data */
                      if (!usb_endpoint_maxp(&e->desc))
                              continue;
      
   10                 switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
                      case USB_ENDPOINT_XFER_INT:
    9                         if (usb_endpoint_dir_in(&e->desc)) {
    9                                 if (!dev->status)
    9                                         dev->status = e;
                              }
                              break;
      
                      case USB_ENDPOINT_XFER_BULK:
   10                         if (usb_endpoint_dir_in(&e->desc)) {
   10                                 if (!in)
                                              in = e;
                              } else {
   10                                 if (!out)
                                              out = e;
                              }
                              break;
      
                      default:
                              break;
                      }
              }
   10         if (in && !dev->in)
   10                 dev->in = usb_rcvbulkpipe(dev->udev,
                                                in->desc.bEndpointAddress &
                                                USB_ENDPOINT_NUMBER_MASK);
   10         if (out && !dev->out)
   10                 dev->out = usb_sndbulkpipe(dev->udev,
                                                 out->desc.bEndpointAddress &
                                                 USB_ENDPOINT_NUMBER_MASK);
      }
      
      static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
      {
   14         if (ctx == NULL)
                      return;
      
   14         if (ctx->tx_rem_skb != NULL) {
                      dev_kfree_skb_any(ctx->tx_rem_skb);
                      ctx->tx_rem_skb = NULL;
              }
      
   14         if (ctx->tx_curr_skb != NULL) {
                      dev_kfree_skb_any(ctx->tx_curr_skb);
                      ctx->tx_curr_skb = NULL;
              }
      
   14         if (ctx->is_ndp16)
                      kfree(ctx->delayed_ndp16);
              else
                      kfree(ctx->delayed_ndp32);
      
              kfree(ctx);
      }
      
      /* we need to override the usbnet change_mtu ndo for two reasons:
       *  - respect the negotiated maximum datagram size
       *  - avoid unwanted changes to rx and tx buffers
       */
      int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
      {
              struct usbnet *dev = netdev_priv(net);
      
              net->mtu = new_mtu;
              cdc_ncm_set_dgram_size(dev, new_mtu + cdc_ncm_eth_hlen(dev));
      
              return 0;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu);
      
      static const struct net_device_ops cdc_ncm_netdev_ops = {
              .ndo_open             = usbnet_open,
              .ndo_stop             = usbnet_stop,
              .ndo_start_xmit             = usbnet_start_xmit,
              .ndo_tx_timeout             = usbnet_tx_timeout,
              .ndo_get_stats64     = usbnet_get_stats64,
              .ndo_change_mtu             = cdc_ncm_change_mtu,
              .ndo_set_mac_address = eth_mac_addr,
              .ndo_validate_addr   = eth_validate_addr,
      };
      
      int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
      {
              struct cdc_ncm_ctx *ctx;
              struct usb_driver *driver;
              u8 *buf;
              int len;
              int temp;
              u8 iface_no;
              struct usb_cdc_parsed_header hdr;
      
   14         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
              if (!ctx)
                      return -ENOMEM;
      
   14         hrtimer_init(&ctx->tx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
              ctx->tx_timer.function = &cdc_ncm_tx_timer_cb;
              tasklet_init(&ctx->bh, cdc_ncm_txpath_bh, (unsigned long)dev);
              atomic_set(&ctx->stop, 0);
              spin_lock_init(&ctx->mtx);
      
              /* store ctx pointer in device data field */
              dev->data[0] = (unsigned long)ctx;
      
              /* only the control interface can be successfully probed */
              ctx->control = intf;
      
              /* get some pointers */
              driver = driver_of(intf);
              buf = intf->cur_altsetting->extra;
              len = intf->cur_altsetting->extralen;
      
              /* parse through descriptors associated with control interface */
              cdc_parse_cdc_header(&hdr, intf, buf, len);
      
              if (hdr.usb_cdc_union_desc)
                      ctx->data = usb_ifnum_to_if(dev->udev,
   12                                             hdr.usb_cdc_union_desc->bSlaveInterface0);
   14         ctx->ether_desc = hdr.usb_cdc_ether_desc;
              ctx->func_desc = hdr.usb_cdc_ncm_desc;
              ctx->mbim_desc = hdr.usb_cdc_mbim_desc;
              ctx->mbim_extended_desc = hdr.usb_cdc_mbim_extended_desc;
      
              /* some buggy devices have an IAD but no CDC Union */
   14         if (!hdr.usb_cdc_union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
                      ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1);
                      dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n");
              }
      
              /* check if we got everything */
   14         if (!ctx->data) {
    3                 dev_dbg(&intf->dev, "CDC Union missing and no IAD found\n");
                      goto error;
              }
   11         if (cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting)) {
    1                 if (!ctx->mbim_desc) {
    1                         dev_dbg(&intf->dev, "MBIM functional descriptor missing\n");
                              goto error;
                      }
              } else {
   10                 if (!ctx->ether_desc || !ctx->func_desc) {
                              dev_dbg(&intf->dev, "NCM or ECM functional descriptors missing\n");
                              goto error;
                      }
              }
      
              /* claim data interface, if different from control */
   10         if (ctx->data != ctx->control) {
   10                 temp = usb_driver_claim_interface(driver, ctx->data, dev);
   10                 if (temp) {
    4                         dev_dbg(&intf->dev, "failed to claim data intf\n");
                              goto error;
                      }
              }
      
   10         iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
      
              /* Device-specific flags */
              ctx->drvflags = drvflags;
      
              /* Reset data interface. Some devices will not reset properly
               * unless they are configured first.  Toggle the altsetting to
               * force a reset.
               * Some other devices do not work properly with this procedure
               * that can be avoided using quirk CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
               */
              if (!(ctx->drvflags & CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE))
   10                 usb_set_interface(dev->udev, iface_no, data_altsetting);
      
   10         temp = usb_set_interface(dev->udev, iface_no, 0);
              if (temp) {
    7                 dev_dbg(&intf->dev, "set interface failed\n");
                      goto error2;
              }
      
              /* initialize basic device settings */
   10         if (cdc_ncm_init(dev))
                      goto error2;
      
              /* Some firmwares need a pause here or they will silently fail
               * to set up the interface properly.  This value was decided
               * empirically on a Sierra Wireless MC7455 running 02.08.02.00
               * firmware.
               */
              usleep_range(10000, 20000);
      
              /* configure data interface */
              temp = usb_set_interface(dev->udev, iface_no, data_altsetting);
              if (temp) {
                      dev_dbg(&intf->dev, "set interface failed\n");
                      goto error2;
              }
      
   10         cdc_ncm_find_endpoints(dev, ctx->data);
              cdc_ncm_find_endpoints(dev, ctx->control);
   10         if (!dev->in || !dev->out || !dev->status) {
    1                 dev_dbg(&intf->dev, "failed to collect endpoints\n");
                      goto error2;
              }
      
    9         usb_set_intfdata(ctx->data, dev);
              usb_set_intfdata(ctx->control, dev);
      
              if (ctx->ether_desc) {
    9                 temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
                      if (temp) {
    1                         dev_dbg(&intf->dev, "failed to get mac address\n");
                              goto error2;
                      }
    8                 dev_info(&intf->dev, "MAC-Address: %pM\n", dev->net->dev_addr);
              }
      
              /* finish setting up the device specific data */
    8         cdc_ncm_setup(dev);
      
              /* Allocate the delayed NDP if needed. */
              if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                      if (ctx->is_ndp16) {
                              ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
                              if (!ctx->delayed_ndp16)
                                      goto error2;
                      } else {
                              ctx->delayed_ndp32 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
                              if (!ctx->delayed_ndp32)
                                      goto error2;
                      }
                      dev_info(&intf->dev, "NDP will be placed at end of frame for this device.");
              }
      
              /* override ethtool_ops */
    8         dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
      
              /* add our sysfs attrs */
              dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group;
      
              /* must handle MTU changes */
              dev->net->netdev_ops = &cdc_ncm_netdev_ops;
   10         dev->net->max_mtu = cdc_ncm_max_dgram_size(dev) - cdc_ncm_eth_hlen(dev);
      
              return 0;
      
      error2:
    8         usb_set_intfdata(ctx->control, NULL);
              usb_set_intfdata(ctx->data, NULL);
              if (ctx->data != ctx->control)
    8                 usb_driver_release_interface(driver, ctx->data);
      error:
   12         cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
              dev->data[0] = 0;
              dev_info(&intf->dev, "bind() failure\n");
   14         return -ENODEV;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_bind_common);
      
      void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
      {
    8         struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
    8         struct usb_driver *driver = driver_of(intf);
      
              if (ctx == NULL)
                      return;                /* no setup */
      
              atomic_set(&ctx->stop, 1);
      
              hrtimer_cancel(&ctx->tx_timer);
      
              tasklet_kill(&ctx->bh);
      
              /* handle devices with combined control and data interface */
              if (ctx->control == ctx->data)
                      ctx->data = NULL;
      
              /* disconnect master --> disconnect slave */
    8         if (intf == ctx->control && ctx->data) {
    8                 usb_set_intfdata(ctx->data, NULL);
                      usb_driver_release_interface(driver, ctx->data);
                      ctx->data = NULL;
      
              } else if (intf == ctx->data && ctx->control) {
                      usb_set_intfdata(ctx->control, NULL);
                      usb_driver_release_interface(driver, ctx->control);
                      ctx->control = NULL;
              }
      
    8         usb_set_intfdata(intf, NULL);
              cdc_ncm_free(ctx);
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_unbind);
      
      /* Return the number of the MBIM control interface altsetting iff it
       * is preferred and available,
       */
    1 u8 cdc_ncm_select_altsetting(struct usb_interface *intf)
      {
              struct usb_host_interface *alt;
      
              /* The MBIM spec defines a NCM compatible default altsetting,
               * which we may have matched:
               *
               *  "Functions that implement both NCM 1.0 and MBIM (an
               *   “NCM/MBIM function”) according to this recommendation
               *   shall provide two alternate settings for the
               *   Communication Interface.  Alternate setting 0, and the
               *   associated class and endpoint descriptors, shall be
               *   constructed according to the rules given for the
               *   Communication Interface in section 5 of [USBNCM10].
               *   Alternate setting 1, and the associated class and
               *   endpoint descriptors, shall be constructed according to
               *   the rules given in section 6 (USB Device Model) of this
               *   specification."
               */
   15         if (intf->num_altsetting < 2)
   14                 return intf->cur_altsetting->desc.bAlternateSetting;
      
    1         if (prefer_mbim) {
    1                 alt = usb_altnum_to_altsetting(intf, CDC_NCM_COMM_ALTSETTING_MBIM);
    1                 if (alt && cdc_ncm_comm_intf_is_mbim(alt))
                              return CDC_NCM_COMM_ALTSETTING_MBIM;
              }
              return CDC_NCM_COMM_ALTSETTING_NCM;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_select_altsetting);
      
      static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
      {
              /* MBIM backwards compatible function? */
   14         if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
                      return -ENODEV;
      
              /* The NCM data altsetting is fixed, so we hard-coded it.
               * Additionally, generic NCM devices are assumed to accept arbitrarily
               * placed NDP.
               */
   14         return cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
      }
      
      static void cdc_ncm_align_tail(struct sk_buff *skb, size_t modulus, size_t remainder, size_t max)
      {
              size_t align = ALIGN(skb->len, modulus) - skb->len + remainder;
      
              if (skb->len + align > max)
                      align = max - skb->len;
              if (align && skb_tailroom(skb) >= align)
                      skb_put_zero(skb, align);
      }
      
      /* return a pointer to a valid struct usb_cdc_ncm_ndp16 of type sign, possibly
       * allocating a new one within skb
       */
      static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
      {
              struct usb_cdc_ncm_ndp16 *ndp16 = NULL;
              struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
              size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex);
      
              /* If NDP should be moved to the end of the NCM package, we can't follow the
              * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
              * the wNdpIndex field in the header is actually not consistent with reality. It will be later.
              */
              if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                      if (ctx->delayed_ndp16->dwSignature == sign)
                              return ctx->delayed_ndp16;
      
                      /* We can only push a single NDP to the end. Return
                       * NULL to send what we've already got and queue this
                       * skb for later.
                       */
                      else if (ctx->delayed_ndp16->dwSignature)
                              return NULL;
              }
      
              /* follow the chain of NDPs, looking for a match */
              while (ndpoffset) {
                      ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
                      if  (ndp16->dwSignature == sign)
                              return ndp16;
                      ndpoffset = le16_to_cpu(ndp16->wNextNdpIndex);
              }
      
              /* align new NDP */
              if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
                      cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size);
      
              /* verify that there is room for the NDP and the datagram (reserve) */
              if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
                      return NULL;
      
              /* link to it */
              if (ndp16)
                      ndp16->wNextNdpIndex = cpu_to_le16(skb->len);
              else
                      nth16->wNdpIndex = cpu_to_le16(skb->len);
      
              /* push a new empty NDP */
              if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
                      ndp16 = skb_put_zero(skb, ctx->max_ndp_size);
              else
                      ndp16 = ctx->delayed_ndp16;
      
              ndp16->dwSignature = sign;
              ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
              return ndp16;
      }
      
      static struct usb_cdc_ncm_ndp32 *cdc_ncm_ndp32(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign, size_t reserve)
      {
              struct usb_cdc_ncm_ndp32 *ndp32 = NULL;
              struct usb_cdc_ncm_nth32 *nth32 = (void *)skb->data;
              size_t ndpoffset = le32_to_cpu(nth32->dwNdpIndex);
      
              /* If NDP should be moved to the end of the NCM package, we can't follow the
               * NTH32 header as we would normally do. NDP isn't written to the SKB yet, and
               * the wNdpIndex field in the header is actually not consistent with reality. It will be later.
               */
              if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                      if (ctx->delayed_ndp32->dwSignature == sign)
                              return ctx->delayed_ndp32;
      
                      /* We can only push a single NDP to the end. Return
                       * NULL to send what we've already got and queue this
                       * skb for later.
                       */
                      else if (ctx->delayed_ndp32->dwSignature)
                              return NULL;
              }
      
              /* follow the chain of NDPs, looking for a match */
              while (ndpoffset) {
                      ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb->data + ndpoffset);
                      if  (ndp32->dwSignature == sign)
                              return ndp32;
                      ndpoffset = le32_to_cpu(ndp32->dwNextNdpIndex);
              }
      
              /* align new NDP */
              if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
                      cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size);
      
              /* verify that there is room for the NDP and the datagram (reserve) */
              if ((ctx->tx_curr_size - skb->len - reserve) < ctx->max_ndp_size)
                      return NULL;
      
              /* link to it */
              if (ndp32)
                      ndp32->dwNextNdpIndex = cpu_to_le32(skb->len);
              else
                      nth32->dwNdpIndex = cpu_to_le32(skb->len);
      
              /* push a new empty NDP */
              if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
                      ndp32 = skb_put_zero(skb, ctx->max_ndp_size);
              else
                      ndp32 = ctx->delayed_ndp32;
      
              ndp32->dwSignature = sign;
              ndp32->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp32) + sizeof(struct usb_cdc_ncm_dpe32));
              return ndp32;
      }
      
      struct sk_buff *
      cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign)
      {
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              union {
                      struct usb_cdc_ncm_nth16 *nth16;
                      struct usb_cdc_ncm_nth32 *nth32;
              } nth;
              union {
                      struct usb_cdc_ncm_ndp16 *ndp16;
                      struct usb_cdc_ncm_ndp32 *ndp32;
              } ndp;
              struct sk_buff *skb_out;
              u16 n = 0, index, ndplen;
              u8 ready2send = 0;
              u32 delayed_ndp_size;
              size_t padding_count;
      
              /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
               * accordingly. Otherwise, we should check here.
               */
              if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
                      delayed_ndp_size = ALIGN(ctx->max_ndp_size, ctx->tx_ndp_modulus);
              else
                      delayed_ndp_size = 0;
      
              /* if there is a remaining skb, it gets priority */
              if (skb != NULL) {
                      swap(skb, ctx->tx_rem_skb);
                      swap(sign, ctx->tx_rem_sign);
              } else {
                      ready2send = 1;
              }
      
              /* check if we are resuming an OUT skb */
              skb_out = ctx->tx_curr_skb;
      
              /* allocate a new OUT skb */
              if (!skb_out) {
                      if (ctx->tx_low_mem_val == 0) {
                              ctx->tx_curr_size = ctx->tx_max;
                              skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC);
                              /* If the memory allocation fails we will wait longer
                               * each time before attempting another full size
                               * allocation again to not overload the system
                               * further.
                               */
                              if (skb_out == NULL) {
                                      ctx->tx_low_mem_max_cnt = min(ctx->tx_low_mem_max_cnt + 1,
                                                                    (unsigned)CDC_NCM_LOW_MEM_MAX_CNT);
                                      ctx->tx_low_mem_val = ctx->tx_low_mem_max_cnt;
                              }
                      }
                      if (skb_out == NULL) {
                              /* See if a very small allocation is possible.
                               * We will send this packet immediately and hope
                               * that there is more memory available later.
                               */
                              if (skb)
                                      ctx->tx_curr_size = max(skb->len,
                                              (u32)USB_CDC_NCM_NTB_MIN_OUT_SIZE);
                              else
                                      ctx->tx_curr_size = USB_CDC_NCM_NTB_MIN_OUT_SIZE;
                              skb_out = alloc_skb(ctx->tx_curr_size, GFP_ATOMIC);
      
                              /* No allocation possible so we will abort */
                              if (skb_out == NULL) {
                                      if (skb != NULL) {
                                              dev_kfree_skb_any(skb);
                                              dev->net->stats.tx_dropped++;
                                      }
                                      goto exit_no_skb;
                              }
                              ctx->tx_low_mem_val--;
                      }
                      if (ctx->is_ndp16) {
                              /* fill out the initial 16-bit NTB header */
                              nth.nth16 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth16));
                              nth.nth16->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
                              nth.nth16->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth16));
                              nth.nth16->wSequence = cpu_to_le16(ctx->tx_seq++);
                      } else {
                              /* fill out the initial 32-bit NTB header */
                              nth.nth32 = skb_put_zero(skb_out, sizeof(struct usb_cdc_ncm_nth32));
                              nth.nth32->dwSignature = cpu_to_le32(USB_CDC_NCM_NTH32_SIGN);
                              nth.nth32->wHeaderLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_nth32));
                              nth.nth32->wSequence = cpu_to_le16(ctx->tx_seq++);
                      }
      
                      /* count total number of frames in this NTB */
                      ctx->tx_curr_frame_num = 0;
      
                      /* recent payload counter for this skb_out */
                      ctx->tx_curr_frame_payload = 0;
              }
      
              for (n = ctx->tx_curr_frame_num; n < ctx->tx_max_datagrams; n++) {
                      /* send any remaining skb first */
                      if (skb == NULL) {
                              skb = ctx->tx_rem_skb;
                              sign = ctx->tx_rem_sign;
                              ctx->tx_rem_skb = NULL;
      
                              /* check for end of skb */
                              if (skb == NULL)
                                      break;
                      }
      
                      /* get the appropriate NDP for this skb */
                      if (ctx->is_ndp16)
                              ndp.ndp16 = cdc_ncm_ndp16(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
                      else
                              ndp.ndp32 = cdc_ncm_ndp32(ctx, skb_out, sign, skb->len + ctx->tx_modulus + ctx->tx_remainder);
      
                      /* align beginning of next frame */
                      cdc_ncm_align_tail(skb_out,  ctx->tx_modulus, ctx->tx_remainder, ctx->tx_curr_size);
      
                      /* check if we had enough room left for both NDP and frame */
                      if ((ctx->is_ndp16 && !ndp.ndp16) || (!ctx->is_ndp16 && !ndp.ndp32) ||
                          skb_out->len + skb->len + delayed_ndp_size > ctx->tx_curr_size) {
                              if (n == 0) {
                                      /* won't fit, MTU problem? */
                                      dev_kfree_skb_any(skb);
                                      skb = NULL;
                                      dev->net->stats.tx_dropped++;
                              } else {
                                      /* no room for skb - store for later */
                                      if (ctx->tx_rem_skb != NULL) {
                                              dev_kfree_skb_any(ctx->tx_rem_skb);
                                              dev->net->stats.tx_dropped++;
                                      }
                                      ctx->tx_rem_skb = skb;
                                      ctx->tx_rem_sign = sign;
                                      skb = NULL;
                                      ready2send = 1;
                                      ctx->tx_reason_ntb_full++;        /* count reason for transmitting */
                              }
                              break;
                      }
      
                      /* calculate frame number withing this NDP */
                      if (ctx->is_ndp16) {
                              ndplen = le16_to_cpu(ndp.ndp16->wLength);
                              index = (ndplen - sizeof(struct usb_cdc_ncm_ndp16)) / sizeof(struct usb_cdc_ncm_dpe16) - 1;
      
                              /* OK, add this skb */
                              ndp.ndp16->dpe16[index].wDatagramLength = cpu_to_le16(skb->len);
                              ndp.ndp16->dpe16[index].wDatagramIndex = cpu_to_le16(skb_out->len);
                              ndp.ndp16->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe16));
                      } else {
                              ndplen = le16_to_cpu(ndp.ndp32->wLength);
                              index = (ndplen - sizeof(struct usb_cdc_ncm_ndp32)) / sizeof(struct usb_cdc_ncm_dpe32) - 1;
      
                              ndp.ndp32->dpe32[index].dwDatagramLength = cpu_to_le32(skb->len);
                              ndp.ndp32->dpe32[index].dwDatagramIndex = cpu_to_le32(skb_out->len);
                              ndp.ndp32->wLength = cpu_to_le16(ndplen + sizeof(struct usb_cdc_ncm_dpe32));
                      }
                      skb_put_data(skb_out, skb->data, skb->len);
                      ctx->tx_curr_frame_payload += skb->len;        /* count real tx payload data */
                      dev_kfree_skb_any(skb);
                      skb = NULL;
      
                      /* send now if this NDP is full */
                      if (index >= CDC_NCM_DPT_DATAGRAMS_MAX) {
                              ready2send = 1;
                              ctx->tx_reason_ndp_full++;        /* count reason for transmitting */
                              break;
                      }
              }
      
              /* free up any dangling skb */
              if (skb != NULL) {
                      dev_kfree_skb_any(skb);
                      skb = NULL;
                      dev->net->stats.tx_dropped++;
              }
      
              ctx->tx_curr_frame_num = n;
      
              if (n == 0) {
                      /* wait for more frames */
                      /* push variables */
                      ctx->tx_curr_skb = skb_out;
                      goto exit_no_skb;
      
              } else if ((n < ctx->tx_max_datagrams) && (ready2send == 0) && (ctx->timer_interval > 0)) {
                      /* wait for more frames */
                      /* push variables */
                      ctx->tx_curr_skb = skb_out;
                      /* set the pending count */
                      if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
                              ctx->tx_timer_pending = CDC_NCM_TIMER_PENDING_CNT;
                      goto exit_no_skb;
      
              } else {
                      if (n == ctx->tx_max_datagrams)
                              ctx->tx_reason_max_datagram++;        /* count reason for transmitting */
                      /* frame goes out */
                      /* variables will be reset at next call */
              }
      
              /* If requested, put NDP at end of frame. */
              if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                      if (ctx->is_ndp16) {
                              nth.nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
                              cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size - ctx->max_ndp_size);
                              nth.nth16->wNdpIndex = cpu_to_le16(skb_out->len);
                              skb_put_data(skb_out, ctx->delayed_ndp16, ctx->max_ndp_size);
      
                              /* Zero out delayed NDP - signature checking will naturally fail. */
                              ndp.ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
                      } else {
                              nth.nth32 = (struct usb_cdc_ncm_nth32 *)skb_out->data;
                              cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_curr_size - ctx->max_ndp_size);
                              nth.nth32->dwNdpIndex = cpu_to_le32(skb_out->len);
                              skb_put_data(skb_out, ctx->delayed_ndp32, ctx->max_ndp_size);
      
                              ndp.ndp32 = memset(ctx->delayed_ndp32, 0, ctx->max_ndp_size);
                      }
              }
      
              /* If collected data size is less or equal ctx->min_tx_pkt
               * bytes, we send buffers as it is. If we get more data, it
               * would be more efficient for USB HS mobile device with DMA
               * engine to receive a full size NTB, than canceling DMA
               * transfer and receiving a short packet.
               *
               * This optimization support is pointless if we end up sending
               * a ZLP after full sized NTBs.
               */
              if (!(dev->driver_info->flags & FLAG_SEND_ZLP) &&
                  skb_out->len > ctx->min_tx_pkt) {
                      padding_count = ctx->tx_curr_size - skb_out->len;
                      skb_put_zero(skb_out, padding_count);
              } else if (skb_out->len < ctx->tx_curr_size &&
                         (skb_out->len % dev->maxpacket) == 0) {
                      skb_put_u8(skb_out, 0);        /* force short packet */
              }
      
              /* set final frame length */
              if (ctx->is_ndp16) {
                      nth.nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
                      nth.nth16->wBlockLength = cpu_to_le16(skb_out->len);
              } else {
                      nth.nth32 = (struct usb_cdc_ncm_nth32 *)skb_out->data;
                      nth.nth32->dwBlockLength = cpu_to_le32(skb_out->len);
              }
      
              /* return skb */
              ctx->tx_curr_skb = NULL;
      
              /* keep private stats: framing overhead and number of NTBs */
              ctx->tx_overhead += skb_out->len - ctx->tx_curr_frame_payload;
              ctx->tx_ntbs++;
      
              /* usbnet will count all the framing overhead by default.
               * Adjust the stats so that the tx_bytes counter show real
               * payload data instead.
               */
              usbnet_set_skb_tx_stats(skb_out, n,
                                      (long)ctx->tx_curr_frame_payload - skb_out->len);
      
              return skb_out;
      
      exit_no_skb:
              /* Start timer, if there is a remaining non-empty skb */
              if (ctx->tx_curr_skb != NULL && n > 0)
                      cdc_ncm_tx_timeout_start(ctx);
              return NULL;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_fill_tx_frame);
      
      static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
      {
              /* start timer, if not already started */
              if (!(hrtimer_active(&ctx->tx_timer) || atomic_read(&ctx->stop)))
                      hrtimer_start(&ctx->tx_timer,
                                      ctx->timer_interval,
                                      HRTIMER_MODE_REL);
      }
      
      static enum hrtimer_restart cdc_ncm_tx_timer_cb(struct hrtimer *timer)
      {
              struct cdc_ncm_ctx *ctx =
                              container_of(timer, struct cdc_ncm_ctx, tx_timer);
      
              if (!atomic_read(&ctx->stop))
                      tasklet_schedule(&ctx->bh);
              return HRTIMER_NORESTART;
      }
      
      static void cdc_ncm_txpath_bh(unsigned long param)
      {
              struct usbnet *dev = (struct usbnet *)param;
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              spin_lock_bh(&ctx->mtx);
              if (ctx->tx_timer_pending != 0) {
                      ctx->tx_timer_pending--;
                      cdc_ncm_tx_timeout_start(ctx);
                      spin_unlock_bh(&ctx->mtx);
              } else if (dev->net != NULL) {
                      ctx->tx_reason_timeout++;        /* count reason for transmitting */
                      spin_unlock_bh(&ctx->mtx);
                      netif_tx_lock_bh(dev->net);
                      usbnet_start_xmit(NULL, dev->net);
                      netif_tx_unlock_bh(dev->net);
              } else {
                      spin_unlock_bh(&ctx->mtx);
              }
      }
      
      struct sk_buff *
      cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
      {
              struct sk_buff *skb_out;
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
      
              /*
               * The Ethernet API we are using does not support transmitting
               * multiple Ethernet frames in a single call. This driver will
               * accumulate multiple Ethernet frames and send out a larger
               * USB frame when the USB buffer is full or when a single jiffies
               * timeout happens.
               */
              if (ctx == NULL)
                      goto error;
      
              spin_lock_bh(&ctx->mtx);
      
              if (ctx->is_ndp16)
                      skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN));
              else
                      skb_out = cdc_ncm_fill_tx_frame(dev, skb, cpu_to_le32(USB_CDC_NCM_NDP32_NOCRC_SIGN));
      
              spin_unlock_bh(&ctx->mtx);
              return skb_out;
      
      error:
              if (skb != NULL)
                      dev_kfree_skb_any(skb);
      
              return NULL;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_tx_fixup);
      
      /* verify NTB header and return offset of first NDP, or negative error */
      int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
      {
              struct usbnet *dev = netdev_priv(skb_in->dev);
              struct usb_cdc_ncm_nth16 *nth16;
              int len;
              int ret = -EINVAL;
      
              if (ctx == NULL)
                      goto error;
      
              if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth16) +
                                              sizeof(struct usb_cdc_ncm_ndp16))) {
                      netif_dbg(dev, rx_err, dev->net, "frame too short\n");
                      goto error;
              }
      
              nth16 = (struct usb_cdc_ncm_nth16 *)skb_in->data;
      
              if (nth16->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH16_SIGN)) {
                      netif_dbg(dev, rx_err, dev->net,
                                "invalid NTH16 signature <%#010x>\n",
                                le32_to_cpu(nth16->dwSignature));
                      goto error;
              }
      
              len = le16_to_cpu(nth16->wBlockLength);
              if (len > ctx->rx_max) {
                      netif_dbg(dev, rx_err, dev->net,
                                "unsupported NTB block length %u/%u\n", len,
                                ctx->rx_max);
                      goto error;
              }
      
              if ((ctx->rx_seq + 1) != le16_to_cpu(nth16->wSequence) &&
                  (ctx->rx_seq || le16_to_cpu(nth16->wSequence)) &&
                  !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth16->wSequence))) {
                      netif_dbg(dev, rx_err, dev->net,
                                "sequence number glitch prev=%d curr=%d\n",
                                ctx->rx_seq, le16_to_cpu(nth16->wSequence));
              }
              ctx->rx_seq = le16_to_cpu(nth16->wSequence);
      
              ret = le16_to_cpu(nth16->wNdpIndex);
      error:
              return ret;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth16);
      
      int cdc_ncm_rx_verify_nth32(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
      {
              struct usbnet *dev = netdev_priv(skb_in->dev);
              struct usb_cdc_ncm_nth32 *nth32;
              int len;
              int ret = -EINVAL;
      
              if (ctx == NULL)
                      goto error;
      
              if (skb_in->len < (sizeof(struct usb_cdc_ncm_nth32) +
                                              sizeof(struct usb_cdc_ncm_ndp32))) {
                      netif_dbg(dev, rx_err, dev->net, "frame too short\n");
                      goto error;
              }
      
              nth32 = (struct usb_cdc_ncm_nth32 *)skb_in->data;
      
              if (nth32->dwSignature != cpu_to_le32(USB_CDC_NCM_NTH32_SIGN)) {
                      netif_dbg(dev, rx_err, dev->net,
                                "invalid NTH32 signature <%#010x>\n",
                                le32_to_cpu(nth32->dwSignature));
                      goto error;
              }
      
              len = le32_to_cpu(nth32->dwBlockLength);
              if (len > ctx->rx_max) {
                      netif_dbg(dev, rx_err, dev->net,
                                "unsupported NTB block length %u/%u\n", len,
                                ctx->rx_max);
                      goto error;
              }
      
              if ((ctx->rx_seq + 1) != le16_to_cpu(nth32->wSequence) &&
                  (ctx->rx_seq || le16_to_cpu(nth32->wSequence)) &&
                  !((ctx->rx_seq == 0xffff) && !le16_to_cpu(nth32->wSequence))) {
                      netif_dbg(dev, rx_err, dev->net,
                                "sequence number glitch prev=%d curr=%d\n",
                                ctx->rx_seq, le16_to_cpu(nth32->wSequence));
              }
              ctx->rx_seq = le16_to_cpu(nth32->wSequence);
      
              ret = le32_to_cpu(nth32->dwNdpIndex);
      error:
              return ret;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_nth32);
      
      /* verify NDP header and return number of datagrams, or negative error */
      int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset)
      {
              struct usbnet *dev = netdev_priv(skb_in->dev);
              struct usb_cdc_ncm_ndp16 *ndp16;
              int ret = -EINVAL;
      
              if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp16)) > skb_in->len) {
                      netif_dbg(dev, rx_err, dev->net, "invalid NDP offset  <%u>\n",
                                ndpoffset);
                      goto error;
              }
              ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
      
              if (le16_to_cpu(ndp16->wLength) < USB_CDC_NCM_NDP16_LENGTH_MIN) {
                      netif_dbg(dev, rx_err, dev->net, "invalid DPT16 length <%u>\n",
                                le16_to_cpu(ndp16->wLength));
                      goto error;
              }
      
              ret = ((le16_to_cpu(ndp16->wLength) -
                                              sizeof(struct usb_cdc_ncm_ndp16)) /
                                              sizeof(struct usb_cdc_ncm_dpe16));
              ret--; /* we process NDP entries except for the last one */
      
              if ((sizeof(struct usb_cdc_ncm_ndp16) +
                   ret * (sizeof(struct usb_cdc_ncm_dpe16))) > skb_in->len) {
                      netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
                      ret = -EINVAL;
              }
      
      error:
              return ret;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp16);
      
      /* verify NDP header and return number of datagrams, or negative error */
      int cdc_ncm_rx_verify_ndp32(struct sk_buff *skb_in, int ndpoffset)
      {
              struct usbnet *dev = netdev_priv(skb_in->dev);
              struct usb_cdc_ncm_ndp32 *ndp32;
              int ret = -EINVAL;
      
              if ((ndpoffset + sizeof(struct usb_cdc_ncm_ndp32)) > skb_in->len) {
                      netif_dbg(dev, rx_err, dev->net, "invalid NDP offset  <%u>\n",
                                ndpoffset);
                      goto error;
              }
              ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb_in->data + ndpoffset);
      
              if (le16_to_cpu(ndp32->wLength) < USB_CDC_NCM_NDP32_LENGTH_MIN) {
                      netif_dbg(dev, rx_err, dev->net, "invalid DPT32 length <%u>\n",
                                le16_to_cpu(ndp32->wLength));
                      goto error;
              }
      
              ret = ((le16_to_cpu(ndp32->wLength) -
                                              sizeof(struct usb_cdc_ncm_ndp32)) /
                                              sizeof(struct usb_cdc_ncm_dpe32));
              ret--; /* we process NDP entries except for the last one */
      
              if ((sizeof(struct usb_cdc_ncm_ndp32) +
                   ret * (sizeof(struct usb_cdc_ncm_dpe32))) > skb_in->len) {
                      netif_dbg(dev, rx_err, dev->net, "Invalid nframes = %d\n", ret);
                      ret = -EINVAL;
              }
      
      error:
              return ret;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp32);
      
      int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
      {
              struct sk_buff *skb;
              struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
              int len;
              int nframes;
              int x;
              int offset;
              union {
                      struct usb_cdc_ncm_ndp16 *ndp16;
                      struct usb_cdc_ncm_ndp32 *ndp32;
              } ndp;
              union {
                      struct usb_cdc_ncm_dpe16 *dpe16;
                      struct usb_cdc_ncm_dpe32 *dpe32;
              } dpe;
      
              int ndpoffset;
              int loopcount = 50; /* arbitrary max preventing infinite loop */
              u32 payload = 0;
      
              if (ctx->is_ndp16)
                      ndpoffset = cdc_ncm_rx_verify_nth16(ctx, skb_in);
              else
                      ndpoffset = cdc_ncm_rx_verify_nth32(ctx, skb_in);
      
              if (ndpoffset < 0)
                      goto error;
      
      next_ndp:
              if (ctx->is_ndp16) {
                      nframes = cdc_ncm_rx_verify_ndp16(skb_in, ndpoffset);
                      if (nframes < 0)
                              goto error;
      
                      ndp.ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb_in->data + ndpoffset);
      
                      if (ndp.ndp16->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN)) {
                              netif_dbg(dev, rx_err, dev->net,
                                        "invalid DPT16 signature <%#010x>\n",
                                        le32_to_cpu(ndp.ndp16->dwSignature));
                              goto err_ndp;
                      }
                      dpe.dpe16 = ndp.ndp16->dpe16;
              } else {
                      nframes = cdc_ncm_rx_verify_ndp32(skb_in, ndpoffset);
                      if (nframes < 0)
                              goto error;
      
                      ndp.ndp32 = (struct usb_cdc_ncm_ndp32 *)(skb_in->data + ndpoffset);
      
                      if (ndp.ndp32->dwSignature != cpu_to_le32(USB_CDC_NCM_NDP32_NOCRC_SIGN)) {
                              netif_dbg(dev, rx_err, dev->net,
                                        "invalid DPT32 signature <%#010x>\n",
                                        le32_to_cpu(ndp.ndp32->dwSignature));
                              goto err_ndp;
                      }
                      dpe.dpe32 = ndp.ndp32->dpe32;
              }
      
              for (x = 0; x < nframes; x++) {
                      if (ctx->is_ndp16) {
                              offset = le16_to_cpu(dpe.dpe16->wDatagramIndex);
                              len = le16_to_cpu(dpe.dpe16->wDatagramLength);
                      } else {
                              offset = le32_to_cpu(dpe.dpe32->dwDatagramIndex);
                              len = le32_to_cpu(dpe.dpe32->dwDatagramLength);
                      }
      
                      /*
                       * CDC NCM ch. 3.7
                       * All entries after first NULL entry are to be ignored
                       */
                      if ((offset == 0) || (len == 0)) {
                              if (!x)
                                      goto err_ndp; /* empty NTB */
                              break;
                      }
      
                      /* sanity checking */
                      if (((offset + len) > skb_in->len) ||
                                      (len > ctx->rx_max) || (len < ETH_HLEN)) {
                              netif_dbg(dev, rx_err, dev->net,
                                        "invalid frame detected (ignored) offset[%u]=%u, length=%u, skb=%p\n",
                                        x, offset, len, skb_in);
                              if (!x)
                                      goto err_ndp;
                              break;
      
                      } else {
                              /* create a fresh copy to reduce truesize */
                              skb = netdev_alloc_skb_ip_align(dev->net,  len);
                              if (!skb)
                                      goto error;
                              skb_put_data(skb, skb_in->data + offset, len);
                              usbnet_skb_return(dev, skb);
                              payload += len;        /* count payload bytes in this NTB */
                      }
      
                      if (ctx->is_ndp16)
                              dpe.dpe16++;
                      else
                              dpe.dpe32++;
              }
      err_ndp:
              /* are there more NDPs to process? */
              if (ctx->is_ndp16)
                      ndpoffset = le16_to_cpu(ndp.ndp16->wNextNdpIndex);
              else
                      ndpoffset = le32_to_cpu(ndp.ndp32->dwNextNdpIndex);
      
              if (ndpoffset && loopcount--)
                      goto next_ndp;
      
              /* update stats */
              ctx->rx_overhead += skb_in->len - payload;
              ctx->rx_ntbs++;
      
              return 1;
      error:
              return 0;
      }
      EXPORT_SYMBOL_GPL(cdc_ncm_rx_fixup);
      
      static void
      cdc_ncm_speed_change(struct usbnet *dev,
                           struct usb_cdc_speed_change *data)
      {
              uint32_t rx_speed = le32_to_cpu(data->DLBitRRate);
              uint32_t tx_speed = le32_to_cpu(data->ULBitRate);
      
              /*
               * Currently the USB-NET API does not support reporting the actual
               * device speed. Do print it instead.
               */
              if ((tx_speed > 1000000) && (rx_speed > 1000000)) {
                      netif_info(dev, link, dev->net,
                                 "%u mbit/s downlink %u mbit/s uplink\n",
                                 (unsigned int)(rx_speed / 1000000U),
                                 (unsigned int)(tx_speed / 1000000U));
              } else {
                      netif_info(dev, link, dev->net,
                                 "%u kbit/s downlink %u kbit/s uplink\n",
                                 (unsigned int)(rx_speed / 1000U),
                                 (unsigned int)(tx_speed / 1000U));
              }
      }
      
      static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
      {
              struct usb_cdc_notification *event;
      
              if (urb->actual_length < sizeof(*event))
                      return;
      
              /* test for split data in 8-byte chunks */
              if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
                      cdc_ncm_speed_change(dev,
                            (struct usb_cdc_speed_change *)urb->transfer_buffer);
                      return;
              }
      
              event = urb->transfer_buffer;
      
              switch (event->bNotificationType) {
              case USB_CDC_NOTIFY_NETWORK_CONNECTION:
                      /*
                       * According to the CDC NCM specification ch.7.1
                       * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
                       * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
                       */
                      netif_info(dev, link, dev->net,
                                 "network connection: %sconnected\n",
                                 !!event->wValue ? "" : "dis");
                      usbnet_link_change(dev, !!event->wValue, 0);
                      break;
      
              case USB_CDC_NOTIFY_SPEED_CHANGE:
                      if (urb->actual_length < (sizeof(*event) +
                                              sizeof(struct usb_cdc_speed_change)))
                              set_bit(EVENT_STS_SPLIT, &dev->flags);
                      else
                              cdc_ncm_speed_change(dev,
                                                   (struct usb_cdc_speed_change *)&event[1]);
                      break;
      
              default:
                      dev_dbg(&dev->udev->dev,
                              "NCM: unexpected notification 0x%02x!\n",
                              event->bNotificationType);
                      break;
              }
      }
      
      static const struct driver_info cdc_ncm_info = {
              .description = "CDC NCM",
              .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
                              | FLAG_LINK_INTR,
              .bind = cdc_ncm_bind,
              .unbind = cdc_ncm_unbind,
              .manage_power = usbnet_manage_power,
              .status = cdc_ncm_status,
              .rx_fixup = cdc_ncm_rx_fixup,
              .tx_fixup = cdc_ncm_tx_fixup,
      };
      
      /* Same as cdc_ncm_info, but with FLAG_WWAN */
      static const struct driver_info wwan_info = {
              .description = "Mobile Broadband Network Device",
              .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
                              | FLAG_LINK_INTR | FLAG_WWAN,
              .bind = cdc_ncm_bind,
              .unbind = cdc_ncm_unbind,
              .manage_power = usbnet_manage_power,
              .status = cdc_ncm_status,
              .rx_fixup = cdc_ncm_rx_fixup,
              .tx_fixup = cdc_ncm_tx_fixup,
      };
      
      /* Same as wwan_info, but with FLAG_NOARP  */
      static const struct driver_info wwan_noarp_info = {
              .description = "Mobile Broadband Network Device (NO ARP)",
              .flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT | FLAG_MULTI_PACKET
                              | FLAG_LINK_INTR | FLAG_WWAN | FLAG_NOARP,
              .bind = cdc_ncm_bind,
              .unbind = cdc_ncm_unbind,
              .manage_power = usbnet_manage_power,
              .status = cdc_ncm_status,
              .rx_fixup = cdc_ncm_rx_fixup,
              .tx_fixup = cdc_ncm_tx_fixup,
      };
      
      static const struct usb_device_id cdc_devs[] = {
              /* Ericsson MBM devices like F5521gw */
              { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
                      | USB_DEVICE_ID_MATCH_VENDOR,
                .idVendor = 0x0bdb,
                .bInterfaceClass = USB_CLASS_COMM,
                .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
                .bInterfaceProtocol = USB_CDC_PROTO_NONE,
                .driver_info = (unsigned long) &wwan_info,
              },
      
              /* Telit LE910 V2 */
              { USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x0036,
                      USB_CLASS_COMM,
                      USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
                .driver_info = (unsigned long)&wwan_noarp_info,
              },
      
              /* DW5812 LTE Verizon Mobile Broadband Card
               * Unlike DW5550 this device requires FLAG_NOARP
               */
              { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bb,
                      USB_CLASS_COMM,
                      USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
                .driver_info = (unsigned long)&wwan_noarp_info,
              },
      
              /* DW5813 LTE AT&T Mobile Broadband Card
               * Unlike DW5550 this device requires FLAG_NOARP
               */
              { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bc,
                      USB_CLASS_COMM,
                      USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
                .driver_info = (unsigned long)&wwan_noarp_info,
              },
      
              /* Dell branded MBM devices like DW5550 */
              { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
                      | USB_DEVICE_ID_MATCH_VENDOR,
                .idVendor = 0x413c,
                .bInterfaceClass = USB_CLASS_COMM,
                .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
                .bInterfaceProtocol = USB_CDC_PROTO_NONE,
                .driver_info = (unsigned long) &wwan_info,
              },
      
              /* Toshiba branded MBM devices */
              { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
                      | USB_DEVICE_ID_MATCH_VENDOR,
                .idVendor = 0x0930,
                .bInterfaceClass = USB_CLASS_COMM,
                .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
                .bInterfaceProtocol = USB_CDC_PROTO_NONE,
                .driver_info = (unsigned long) &wwan_info,
              },
      
              /* tag Huawei devices as wwan */
              { USB_VENDOR_AND_INTERFACE_INFO(0x12d1,
                                              USB_CLASS_COMM,
                                              USB_CDC_SUBCLASS_NCM,
                                              USB_CDC_PROTO_NONE),
                .driver_info = (unsigned long)&wwan_info,
              },
      
              /* Infineon(now Intel) HSPA Modem platform */
              { USB_DEVICE_AND_INTERFACE_INFO(0x1519, 0x0443,
                      USB_CLASS_COMM,
                      USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
                .driver_info = (unsigned long)&wwan_noarp_info,
              },
      
              /* u-blox TOBY-L4 */
              { USB_DEVICE_AND_INTERFACE_INFO(0x1546, 0x1010,
                      USB_CLASS_COMM,
                      USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
                .driver_info = (unsigned long)&wwan_info,
              },
      
              /* Generic CDC-NCM devices */
              { USB_INTERFACE_INFO(USB_CLASS_COMM,
                      USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
                      .driver_info = (unsigned long)&cdc_ncm_info,
              },
              {
              },
      };
      MODULE_DEVICE_TABLE(usb, cdc_devs);
      
      static struct usb_driver cdc_ncm_driver = {
              .name = "cdc_ncm",
              .id_table = cdc_devs,
              .probe = usbnet_probe,
              .disconnect = usbnet_disconnect,
              .suspend = usbnet_suspend,
              .resume = usbnet_resume,
              .reset_resume =        usbnet_resume,
              .supports_autosuspend = 1,
              .disable_hub_initiated_lpm = 1,
      };
      
      module_usb_driver(cdc_ncm_driver);
      
      MODULE_AUTHOR("Hans Petter Selasky");
      MODULE_DESCRIPTION("USB CDC NCM host driver");
      MODULE_LICENSE("Dual BSD/GPL");
      // SPDX-License-Identifier: GPL-2.0
      /*
       *  linux/lib/kasprintf.c
       *
       *  Copyright (C) 1991, 1992  Linus Torvalds
       */
      
      #include <stdarg.h>
      #include <linux/export.h>
      #include <linux/slab.h>
      #include <linux/types.h>
      #include <linux/string.h>
      
      /* Simplified asprintf. */
      char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap)
      {
              unsigned int first, second;
              char *p;
              va_list aq;
      
 1576         va_copy(aq, ap);
              first = vsnprintf(NULL, 0, fmt, aq);
              va_end(aq);
      
              p = kmalloc_track_caller(first+1, gfp);
              if (!p)
                      return NULL;
      
 1576         second = vsnprintf(p, first+1, fmt, ap);
 1576         WARN(first != second, "different return values (%u and %u) from vsnprintf(\"%s\", ...)",
                   first, second, fmt);
      
              return p;
      }
      EXPORT_SYMBOL(kvasprintf);
      
      /*
       * If fmt contains no % (or is exactly %s), use kstrdup_const. If fmt
       * (or the sole vararg) points to rodata, we will then save a memory
       * allocation and string copy. In any case, the return value should be
       * freed using kfree_const().
       */
      const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list ap)
      {
 1575         if (!strchr(fmt, '%'))
                      return kstrdup_const(fmt, gfp);
 1575         if (!strcmp(fmt, "%s"))
  378                 return kstrdup_const(va_arg(ap, const char*), gfp);
 1575         return kvasprintf(gfp, fmt, ap);
      }
      EXPORT_SYMBOL(kvasprintf_const);
      
      char *kasprintf(gfp_t gfp, const char *fmt, ...)
      {
              va_list ap;
              char *p;
      
 1576         va_start(ap, fmt);
              p = kvasprintf(gfp, fmt, ap);
              va_end(ap);
      
              return p;
      }
      EXPORT_SYMBOL(kasprintf);
      // SPDX-License-Identifier: GPL-2.0-or-later
      /*
       *  HID quirks support for Linux
       *
       *  Copyright (c) 1999 Andreas Gal
       *  Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
       *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
       *  Copyright (c) 2006-2007 Jiri Kosina
       *  Copyright (c) 2007 Paul Walmsley
       */
      
      /*
       */
      
      #include <linux/hid.h>
      #include <linux/export.h>
      #include <linux/slab.h>
      #include <linux/mutex.h>
      #include <linux/input/elan-i2c-ids.h>
      
      #include "hid-ids.h"
      
      /*
       * Alphabetically sorted by vendor then product.
       */
      
      static const struct hid_device_id hid_quirks[] = {
              { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016), HID_QUIRK_FULLSPEED_INTERVAL },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS1758), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS682), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS692), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE2), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_COMBATSTICK), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FIGHTERSTICK), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_THROTTLE), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K65RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70RGB_RAPIDFIRE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K70R), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K95RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_M65RGB), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_STRAFE), HID_QUIRK_NO_INIT_REPORTS | HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, HID_ANY_ID), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH_2968), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING), HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_1f4a), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PIXART_MOUSE), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_NATSU, USB_DEVICE_ID_NATSU_GAMEPAD), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_NEC, USB_DEVICE_ID_NEC_USB_GAME_PAD), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_NEXTWINDOW, USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN), HID_QUIRK_MULTI_INPUT},
              { HID_USB_DEVICE(USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK), HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1610), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_1640), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL), HID_QUIRK_HIDINPUT_FORCE },
              { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_MOUSE_4D22), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D0F), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4D65), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_PIXART_MOUSE_4E22), HID_QUIRK_ALWAYS_POLL },
              { HID_USB_DEVICE(USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_REALTEK, USB_DEVICE_ID_REALTEK_READER), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPAD), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
              { HID_USB_DEVICE(USB_VENDOR_ID_RETROUSB, USB_DEVICE_ID_RETROUSB_SNES_RETROPORT), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
              { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_X52), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE },
              { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD2), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SENNHEISER, USB_DEVICE_ID_SENNHEISER_BTD500USB), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SIGMATEL, USB_DEVICE_ID_SIGMATEL_STMP3780), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS1030_TOUCH), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS817_TOUCH), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS9200_TOUCH), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, USB_DEVICE_ID_SIS_TS), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DELL_K12A), HID_QUIRK_NO_INIT_REPORTS },
              { HID_USB_DEVICE(USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD), HID_QUIRK_BADPAD },
              { HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET },
              { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET), HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD), HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
              { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE), HID_QUIRK_MULTI_INPUT },
      
              { 0 }
      };
      
      /*
       * A list of devices for which there is a specialized driver on HID bus.
       *
       * Please note that for multitouch devices (driven by hid-multitouch driver),
       * there is a proper autodetection and autoloading in place (based on presence
       * of HID_DG_CONTACTID), so those devices don't need to be added to this list,
       * as we are doing the right thing in hid_scan_usage().
       *
       * Autodetection for (USB) HID sensor hubs exists too. If a collection of type
       * physical is found inside a usage page of type sensor, hid-sensor-hub will be
       * used as a driver. See hid_scan_report().
       */
      static const struct hid_device_id hid_have_special_driver[] = {
      #if IS_ENABLED(CONFIG_HID_A4TECH)
              { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
              { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
              { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ACCUTOUCH)
              { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_ACCUTOUCH_2216) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ACRUX)
              { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ALPS)
              { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
      #endif
      #if IS_ENABLED(CONFIG_HID_APPLE)
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
      #endif
      #if IS_ENABLED(CONFIG_HID_APPLEIR)
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ASUS)
              { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD) },
              { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3) },
              { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
              { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD) },
      #endif
      #if IS_ENABLED(CONFIG_HID_AUREAL)
              { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
      #endif
      #if IS_ENABLED(CONFIG_HID_BELKIN)
              { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
      #endif
      #if IS_ENABLED(CONFIG_HID_BETOP_FF)
              { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
              { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
              { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
              { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
      #endif
      #if IS_ENABLED(CONFIG_HID_CHERRY)
              { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
      #endif
      #if IS_ENABLED(CONFIG_HID_CHICONY)
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) },
      #endif
      #if IS_ENABLED(CONFIG_HID_CMEDIA)
              { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM6533) },
      #endif
      #if IS_ENABLED(CONFIG_HID_CORSAIR)
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_GLAIVE_RGB) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_SCIMITAR_PRO_RGB) },
      #endif
      #if IS_ENABLED(CONFIG_HID_CP2112)
              { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) },
      #endif
      #if IS_ENABLED(CONFIG_HID_CYPRESS)
              { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_DRAGONRISE)
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ELAN)
              { HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2_10_COVER) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ELECOM)
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1URBK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_DT1DRBK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1URBK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_HT1DRBK) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ELO)
              { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) },
      #endif
      #if IS_ENABLED(CONFIG_HID_EMS_FF)
              { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
      #endif
      #if IS_ENABLED(CONFIG_HID_EZKEY)
              { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
      #endif
      #if IS_ENABLED(CONFIG_HID_GEMBIRD)
              { HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD, USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) },
      #endif
      #if IS_ENABLED(CONFIG_HID_GFRM)
              { HID_BLUETOOTH_DEVICE(0x58, 0x2000) },
              { HID_BLUETOOTH_DEVICE(0x471, 0x2210) },
      #endif
      #if IS_ENABLED(CONFIG_HID_GREENASIA)
              { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
      #endif
      #if IS_ENABLED(CONFIG_HID_GT683R)
              { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
      #endif
      #if IS_ENABLED(CONFIG_HID_GYRATION)
              { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
      #endif
      #if IS_ENABLED(CONFIG_HID_HOLTEK)
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070) },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) },
              { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ICADE)
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_JABRA)
              { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, HID_ANY_ID) },
      #endif
      #if IS_ENABLED(CONFIG_HID_KENSINGTON)
              { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_KEYTOUCH)
              { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
      #endif
      #if IS_ENABLED(CONFIG_HID_KYE)
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_MANTICORE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
      #endif
      #if IS_ENABLED(CONFIG_HID_LCPOWER)
              { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) },
      #endif
      #if IS_ENABLED(CONFIG_HID_LENOVO)
              { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) },
      #endif
      #if IS_ENABLED(CONFIG_HID_LOGITECH)
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FG) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
      #endif
      #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP)
              { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
      #endif
      #if IS_ENABLED(CONFIG_HID_MAGICMOUSE)
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
      #endif
      #if IS_ENABLED(CONFIG_HID_MAYFLASH)
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3) },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) },
              { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) },
      #endif
      #if IS_ENABLED(CONFIG_HID_MICROSOFT)
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
      #endif
      #if IS_ENABLED(CONFIG_HID_MONTEREY)
              { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
      #endif
      #if IS_ENABLED(CONFIG_HID_MULTITOUCH)
              { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MELFAS_MT) },
      #endif
      #if IS_ENABLED(CONFIG_HID_WIIMOTE)
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
      #endif
      #if IS_ENABLED(CONFIG_HID_NTI)
              { HID_USB_DEVICE(USB_VENDOR_ID_NTI, USB_DEVICE_ID_USB_SUN) },
      #endif
      #if IS_ENABLED(CONFIG_HID_NTRIG)
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_10) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_11) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_12) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_13) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_14) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_15) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ORTEK)
              { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_IHOME_IMAC_A210S) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
      #endif
      #if IS_ENABLED(CONFIG_HID_PANTHERLORD)
              { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
              { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) },
      #endif
      #if IS_ENABLED(CONFIG_HID_PENMOUNT)
              { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) },
      #endif
      #if IS_ENABLED(CONFIG_HID_PETALYNX)
              { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_PICOLCD)
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
      #endif
      #if IS_ENABLED(CONFIG_HID_PLANTRONICS)
              { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
      #endif
      #if IS_ENABLED(CONFIG_HID_PRIMAX)
              { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) },
      #endif
      #if IS_ENABLED(CONFIG_HID_PRODIKEYS)
              { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
      #endif
      #if IS_ENABLED(CONFIG_HID_RETRODE)
              { HID_USB_DEVICE(USB_VENDOR_ID_FUTURE_TECHNOLOGY, USB_DEVICE_ID_RETRODE2) },
      #endif
      #if IS_ENABLED(CONFIG_HID_RMI)
              { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) },
              { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ROCCAT)
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEXTD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
      #endif
      #if IS_ENABLED(CONFIG_HID_SAITEK)
              { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT9) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
      #endif
      #if IS_ENABLED(CONFIG_HID_SAMSUNG)
              { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_SMARTJOYPLUS)
              { HID_USB_DEVICE(USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII) },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) },
      #endif
      #if IS_ENABLED(CONFIG_HID_SONY)
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_PS3_BDREMOTE) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR5U_REMOTE) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER) },
      #endif
      #if IS_ENABLED(CONFIG_HID_SPEEDLINK)
              { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_STEELSERIES)
              { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) },
      #endif
      #if IS_ENABLED(CONFIG_HID_SUNPLUS)
              { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
      #endif
      #if IS_ENABLED(CONFIG_HID_THRUSTMASTER)
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb605) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
              { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
      #endif
      #if IS_ENABLED(CONFIG_HID_TIVO)
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) },
              { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) },
      #endif
      #if IS_ENABLED(CONFIG_HID_TOPSEED)
              { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
      #endif
      #if IS_ENABLED(CONFIG_HID_TWINHAN)
              { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_UDRAW_PS3)
              { HID_USB_DEVICE(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW) },
      #endif
      #if IS_ENABLED(CONFIG_HID_XINMO)
              { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_THT_2P_ARCADE) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ZEROPLUS)
              { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
      #endif
      #if IS_ENABLED(CONFIG_HID_ZYDACRON)
              { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
      #endif
              { }
      };
      
      /* a list of devices that shouldn't be handled by HID core at all */
      static const struct hid_device_id hid_ignore_list[] = {
              { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)},
              { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)},
              { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
              { HID_USB_DEVICE(USB_VENDOR_ID_AXENTIA, USB_DEVICE_ID_AXENTIA_FM_RADIO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
              { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
              { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_RADIOSHARK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004) },
              { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005) },
              { 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_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) },
              { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
              { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYVOLTAGE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYCURRENT) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIC) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIB) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOTOR) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_ABSESP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_AUTODATABUS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
              { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) },
              { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454_V2) },
              { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400) },
              { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500) },
              { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0001) },
              { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
              { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
              { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
              { HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
              { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
      #if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB)
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) },
              { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) },
      #endif
              { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
              { }
      };
      
      /*
       * hid_mouse_ignore_list - mouse devices which should not be handled by the hid layer
       *
       * There are composite devices for which we want to ignore only a certain
       * interface. This is a list of devices for which only the mouse interface will
       * be ignored. This allows a dedicated driver to take care of the interface.
       */
      static const struct hid_device_id hid_mouse_ignore_list[] = {
              /* appletouch driver */
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
              { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI