Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Workaround PN533 USB descriptor corruption



details:   https://anonhg.NetBSD.org/src/rev/137cbd276509
branches:  trunk
changeset: 445655:137cbd276509
user:      manu <manu%NetBSD.org@localhost>
date:      Thu Nov 08 02:11:54 2018 +0000

description:
Workaround PN533 USB descriptor corruption

During normal operation, the PN533 chip may corrupt its USB configuration,
interface and endpoint descriptors. The device descriptor remains unaffected.

Since the descriptors are documented to be immutable, we can work around
the problem by providing hard-coded descriptors instead of pulling them
from the device.

Userland implementation such as NFC tools' libnfc use the same approach,
but this kernel quirk is still necessary so that the device can be
attached on reboot, after its USB descriptors got corrupted.

diffstat:

 sys/dev/usb/usb_quirks.c |  345 ++++++++++++++++++++++++++++++++++------------
 sys/dev/usb/usb_quirks.h |    5 +-
 sys/dev/usb/usbdi_util.c |   23 ++-
 sys/dev/usb/usbdi_util.h |    4 +-
 4 files changed, 283 insertions(+), 94 deletions(-)

diffs (truncated from 494 to 300 lines):

diff -r 513f0408c903 -r 137cbd276509 sys/dev/usb/usb_quirks.c
--- a/sys/dev/usb/usb_quirks.c  Thu Nov 08 02:08:35 2018 +0000
+++ b/sys/dev/usb/usb_quirks.c  Thu Nov 08 02:11:54 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: usb_quirks.c,v 1.87 2018/07/24 08:15:57 msaitoh Exp $  */
+/*     $NetBSD: usb_quirks.c,v 1.88 2018/11/08 02:11:54 manu Exp $     */
 /*     $FreeBSD: src/sys/dev/usb/usb_quirks.c,v 1.30 2003/01/02 04:15:55 imp Exp $     */
 
 /*
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb_quirks.c,v 1.87 2018/07/24 08:15:57 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_quirks.c,v 1.88 2018/11/08 02:11:54 manu Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -43,13 +43,137 @@
 
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdevs.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usbhist.h>
 #include <dev/usb/usb_quirks.h>
 
 #ifdef USB_DEBUG
 extern int usbdebug;
 #endif
 
+#define DPRINTF(FMT,A,B,C,D)    USBHIST_LOG(usbdebug,FMT,A,B,C,D)
+
 #define ANY 0xffff
+#define _USETW(w) { (w) & 0x00ff, ((w) & 0xff00) >> 8 }
+
+/*
+ * NXP PN533 NFC chip descriptors
+ */
+static const usb_endpoint_descriptor_t desc_ep_pn533_in = {
+       /* bLength */           sizeof(desc_ep_pn533_in),
+       /* bDescriptorType */   UDESC_ENDPOINT,
+       /* bEndpointAddress */  UE_DIR_IN | 0x04,
+       /* bmAttributes */      UE_BULK,
+       /* wMaxPacketSize */    _USETW(0x0040),
+       /* bInterval */         0x04, /* 255ms */
+};
+
+static const usb_endpoint_descriptor_t desc_ep_pn533_out = {
+       /* bLength */           sizeof(desc_ep_pn533_in),
+       /* bDescriptorType */   UDESC_ENDPOINT,
+       /* bEndpointAddress */  UE_DIR_OUT | 0x04,
+       /* bmAttributes */      UE_BULK,
+       /* wMaxPacketSize */    _USETW(0x0040),
+       /* bInterval */         0x04, /* 255ms */
+};
+
+static const usb_interface_descriptor_t desc_iface_pn533 = {
+       /* bLength */           sizeof(desc_iface_pn533),
+       /* bDescriptorType */    UDESC_INTERFACE,
+       /* bInterfaceNumber */   0,
+       /* bAlternateSetting */  0,
+       /* bNumEndpoints */      2,
+       /* bInterfaceClass */    0xff,
+       /* bInterfaceSubClass */ 0xff,
+       /* bInterfaceProtocol */ 0xff,
+       /* iInterface */         0,
+};
+
+static const usb_config_descriptor_t desc_conf_pn533 = {
+       /* bLength */            sizeof(desc_conf_pn533),
+       /* bDescriptorType */    UDESC_CONFIG,
+       /* wTotalLength  */      _USETW(sizeof(desc_conf_pn533) +
+                                       sizeof(desc_iface_pn533) +
+                                       sizeof(desc_ep_pn533_in) +
+                                       sizeof(desc_ep_pn533_out)
+                                ),
+       /* bNumInterfac */       1,
+       /* bConfigurationValue */1,
+       /* iConfiguration */     0,
+       /* bmAttributes */       UC_ATTR_MBO,
+       /* bMaxPower */          0x32, /* 100mA */
+};
+
+static const usb_descriptor_t *desc_pn533[] = {
+       (const usb_descriptor_t *)&desc_conf_pn533,
+       (const usb_descriptor_t *)&desc_iface_pn533,
+       (const usb_descriptor_t *)&desc_ep_pn533_out,
+       (const usb_descriptor_t *)&desc_ep_pn533_in,
+       NULL
+};
+
+
+usbd_status
+usbd_get_desc_fake(struct usbd_device *dev, int type, int index,
+                  int len, void *desc)
+{
+       USBHIST_FUNC(); USBHIST_CALLED(usbdebug);
+#ifdef USB_DEBUG
+       const usb_device_descriptor_t *dd = usbd_get_device_descriptor(dev);
+#endif
+       const usb_descriptor_t *ub;
+       int i = 0;
+       int j = 0;
+       usbd_status err = USBD_INVAL;
+
+       if (dev->ud_quirks == NULL || dev->ud_quirks->desc == NULL) {
+               DPRINTF("%04x/%04x: no fake descriptors",
+                       UGETW(dd->idVendor), UGETW(dd->idProduct), 0, 0);
+               goto out;
+       }
+
+       for (j = 0; dev->ud_quirks->desc[j]; j++) {
+               ub = dev->ud_quirks->desc[j];
+               if (ub->bDescriptorType == type && i++ == index)
+                       break;
+       }
+
+       if (dev->ud_quirks->desc[j] == NULL) {
+               DPRINTF("%04x/%04x: no fake descriptor type = %d, len = %d",
+                      UGETW(dd->idVendor), UGETW(dd->idProduct), type, len);
+               goto out;
+       }
+
+       do {
+               ub = dev->ud_quirks->desc[j];
+
+               if (ub->bLength > len) {
+                       DPRINTF("%04x/%04x: short buf len = %d, bLength = %d",
+                               UGETW(dd->idVendor), UGETW(dd->idProduct),
+                               type, ub->bLength);
+                       goto out;
+               }
+
+               memcpy(desc, ub, ub->bLength);
+               DPRINTF("%04x/%04x: Use fake descriptor type %d",
+                       UGETW(dd->idVendor), UGETW(dd->idProduct),
+                       type, 0);
+
+               desc = (char *)desc + ub->bLength;
+               len -= ub->bLength;
+               j++;
+       } while (len && dev->ud_quirks->desc[j] &&
+                dev->ud_quirks->desc[j]->bDescriptorType != type);
+
+       err = USBD_NORMAL_COMPLETION;
+
+       DPRINTF("%04x/%04x: Using fake USB descriptors\n",
+               UGETW(dd->idVendor), UGETW(dd->idProduct), 0, 0);
+out:
+       DPRINTF("return err = %d", err, 0, 0, 0);
+       return err;     
+}
 
 Static const struct usbd_quirk_entry {
        uint16_t idVendor;
@@ -58,99 +182,142 @@
        struct usbd_quirks quirks;
 } usb_quirks[] = {
  /* Devices which should be ignored by uhid */
- { USB_VENDOR_APC, USB_PRODUCT_APC_UPS,                    ANY,   { UQ_HID_IGNORE }},
- { USB_VENDOR_CYBERPOWER, USB_PRODUCT_CYBERPOWER_UPS, ANY, { UQ_HID_IGNORE }},
- { USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS1,           ANY,   { UQ_HID_IGNORE }},
- { USB_VENDOR_MGE, USB_PRODUCT_MGE_UPS2,           ANY,   { UQ_HID_IGNORE }},
- { USB_VENDOR_MICROCHIP,  USB_PRODUCT_MICROCHIP_PICKIT1,
-       ANY,    { UQ_HID_IGNORE }},
- { USB_VENDOR_TRIPPLITE2, ANY,                     ANY,   { UQ_HID_IGNORE }},
- { USB_VENDOR_MISC, USB_PRODUCT_MISC_WISPY_24X, ANY, { UQ_HID_IGNORE }},
- { USB_VENDOR_WELTREND, USB_PRODUCT_WELTREND_HID,   ANY,   { UQ_HID_IGNORE }},
- { USB_VENDOR_SILABS, USB_PRODUCT_SILABS_EC3,       ANY,   { UQ_HID_IGNORE }},
- { USB_VENDOR_TI, USB_PRODUCT_TI_MSP430,            ANY,   { UQ_HID_IGNORE }},
+ { USB_VENDOR_APC,             USB_PRODUCT_APC_UPS,                    ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_CYBERPOWER,      USB_PRODUCT_CYBERPOWER_UPS,             ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_MGE,             USB_PRODUCT_MGE_UPS1,                   ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_MGE,             USB_PRODUCT_MGE_UPS2,                   ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_MICROCHIP,       USB_PRODUCT_MICROCHIP_PICKIT1,          ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_TRIPPLITE2,      ANY,                                    ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_MISC,            USB_PRODUCT_MISC_WISPY_24X,             ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_WELTREND,        USB_PRODUCT_WELTREND_HID,               ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_SILABS,          USB_PRODUCT_SILABS_EC3,                 ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_TI,              USB_PRODUCT_TI_MSP430,                  ANY,
+       { UQ_HID_IGNORE, NULL }},
+ { USB_VENDOR_KYE,             USB_PRODUCT_KYE_NICHE,                  0x100,
+       { UQ_NO_SET_PROTO, NULL }},
+ { USB_VENDOR_INSIDEOUT,       USB_PRODUCT_INSIDEOUT_EDGEPORT4,        0x094,
+       { UQ_SWAP_UNICODE, NULL }},
+ { USB_VENDOR_DALLAS,          USB_PRODUCT_DALLAS_J6502,               0x0a2,
+       { UQ_BAD_ADC, NULL }},
+ { USB_VENDOR_DALLAS,          USB_PRODUCT_DALLAS_J6502,               0x0a2,
+       { UQ_AU_NO_XU, NULL }},
+ { USB_VENDOR_ALTEC,           USB_PRODUCT_ALTEC_ADA70,                0x103,
+       { UQ_BAD_ADC, NULL }},
+ { USB_VENDOR_ALTEC,           USB_PRODUCT_ALTEC_ASC495,               0x000,
+       { UQ_BAD_AUDIO, NULL }},
+ { USB_VENDOR_SONY,            USB_PRODUCT_SONY_PS2EYETOY4,            0x000,
+       { UQ_BAD_AUDIO, NULL }},
+ { USB_VENDOR_SONY,            USB_PRODUCT_SONY_PS2EYETOY5,            0x000,
+       { UQ_BAD_AUDIO, NULL }},
+ { USB_VENDOR_PHILIPS,         USB_PRODUCT_PHILIPS_PCVC740K,           ANY,
+       { UQ_BAD_AUDIO, NULL }},
+ { USB_VENDOR_LOGITECH,                USB_PRODUCT_LOGITECH_QUICKCAMPRONB,     0x000,
+       { UQ_BAD_AUDIO, NULL }},
+ { USB_VENDOR_LOGITECH,                USB_PRODUCT_LOGITECH_QUICKCAMPRO4K,     0x000,
+       { UQ_BAD_AUDIO, NULL }},
+ { USB_VENDOR_LOGITECH,                USB_PRODUCT_LOGITECH_QUICKCAMMESS,      0x100,
+       { UQ_BAD_ADC, NULL }},
+ { USB_VENDOR_QTRONIX,         USB_PRODUCT_QTRONIX_980N,               0x110,
+       { UQ_SPUR_BUT_UP, NULL }},
+ { USB_VENDOR_ALCOR2,          USB_PRODUCT_ALCOR2_KBD_HUB,             0x001,
+       { UQ_SPUR_BUT_UP, NULL }},
+ { USB_VENDOR_METRICOM,                USB_PRODUCT_METRICOM_RICOCHET_GS,       0x100,
+       { UQ_ASSUME_CM_OVER_DATA, NULL }},
+ { USB_VENDOR_SANYO,           USB_PRODUCT_SANYO_SCP4900,              0x000,
+       { UQ_ASSUME_CM_OVER_DATA, NULL }},
+ { USB_VENDOR_MOTOROLA2,       USB_PRODUCT_MOTOROLA2_T720C,            0x001,
+       { UQ_ASSUME_CM_OVER_DATA, NULL }},
+ { USB_VENDOR_EICON,           USB_PRODUCT_EICON_DIVA852,              0x100,
+       { UQ_ASSUME_CM_OVER_DATA, NULL }},
+ { USB_VENDOR_SIEMENS2,                USB_PRODUCT_SIEMENS2_MC75,              0x000,
+       { UQ_ASSUME_CM_OVER_DATA, NULL }},
+ { USB_VENDOR_TELEX,           USB_PRODUCT_TELEX_MIC1,                 0x009,
+       { UQ_AU_NO_FRAC, NULL }},
+ { USB_VENDOR_SILICONPORTALS,  USB_PRODUCT_SILICONPORTALS_YAPPHONE,    0x100,
+       { UQ_AU_INP_ASYNC, NULL }},
+ { USB_VENDOR_AVANCELOGIC,     USB_PRODUCT_AVANCELOGIC_USBAUDIO,       0x101,
+       { UQ_AU_INP_ASYNC, NULL }},
+ { USB_VENDOR_PLANTRONICS,     USB_PRODUCT_PLANTRONICS_HEADSET,        0x004,
+       { UQ_AU_INP_ASYNC, NULL }},
+ { USB_VENDOR_CMEDIA,          USB_PRODUCT_CMEDIA_USBAUDIO,            ANY,
+       { UQ_AU_INP_ASYNC, NULL }},
 
- { USB_VENDOR_KYE, USB_PRODUCT_KYE_NICHE,          0x100, { UQ_NO_SET_PROTO}},
- { USB_VENDOR_INSIDEOUT, USB_PRODUCT_INSIDEOUT_EDGEPORT4,
-                                                   0x094, { UQ_SWAP_UNICODE}},
- { USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_J6502,            0x0a2, { UQ_BAD_ADC }},
- { USB_VENDOR_DALLAS, USB_PRODUCT_DALLAS_J6502,            0x0a2, { UQ_AU_NO_XU }},
- { USB_VENDOR_ALTEC, USB_PRODUCT_ALTEC_ADA70,      0x103, { UQ_BAD_ADC }},
- { USB_VENDOR_ALTEC, USB_PRODUCT_ALTEC_ASC495,      0x000, { UQ_BAD_AUDIO }},
- { USB_VENDOR_SONY, USB_PRODUCT_SONY_PS2EYETOY4,    0x000, { UQ_BAD_AUDIO }},
- { USB_VENDOR_SONY, USB_PRODUCT_SONY_PS2EYETOY5,    0x000, { UQ_BAD_AUDIO }},
- { USB_VENDOR_PHILIPS, USB_PRODUCT_PHILIPS_PCVC740K,  ANY, { UQ_BAD_AUDIO }},
- { USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_QUICKCAMPRONB,
-       0x000, { UQ_BAD_AUDIO }},
- { USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_QUICKCAMPRO4K,
-       0x000, { UQ_BAD_AUDIO }},
- { USB_VENDOR_LOGITECH, USB_PRODUCT_LOGITECH_QUICKCAMMESS,
-       0x100, { UQ_BAD_ADC }},
- { USB_VENDOR_QTRONIX, USB_PRODUCT_QTRONIX_980N,    0x110, { UQ_SPUR_BUT_UP }},
- { USB_VENDOR_ALCOR2, USB_PRODUCT_ALCOR2_KBD_HUB,   0x001, { UQ_SPUR_BUT_UP }},
- { USB_VENDOR_METRICOM, USB_PRODUCT_METRICOM_RICOCHET_GS,
-       0x100, { UQ_ASSUME_CM_OVER_DATA }},
- { USB_VENDOR_SANYO, USB_PRODUCT_SANYO_SCP4900,
-       0x000, { UQ_ASSUME_CM_OVER_DATA }},
- { USB_VENDOR_MOTOROLA2, USB_PRODUCT_MOTOROLA2_T720C,
-       0x001, { UQ_ASSUME_CM_OVER_DATA }},
- { USB_VENDOR_EICON, USB_PRODUCT_EICON_DIVA852,
-       0x100, { UQ_ASSUME_CM_OVER_DATA }},
- { USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_MC75,
-       0x000, { UQ_ASSUME_CM_OVER_DATA }},
- { USB_VENDOR_TELEX, USB_PRODUCT_TELEX_MIC1,       0x009, { UQ_AU_NO_FRAC }},
- { USB_VENDOR_SILICONPORTALS, USB_PRODUCT_SILICONPORTALS_YAPPHONE,
-                                                   0x100, { UQ_AU_INP_ASYNC }},
- { USB_VENDOR_AVANCELOGIC, USB_PRODUCT_AVANCELOGIC_USBAUDIO,
-                                                   0x101, { UQ_AU_INP_ASYNC }},
- { USB_VENDOR_PLANTRONICS, USB_PRODUCT_PLANTRONICS_HEADSET,
-                                                   0x004, { UQ_AU_INP_ASYNC }},
- { USB_VENDOR_CMEDIA, USB_PRODUCT_CMEDIA_USBAUDIO,  ANY,   { UQ_AU_INP_ASYNC }},
  /* XXX These should have a revision number, but I don't know what they are. */
- { USB_VENDOR_HP, USB_PRODUCT_HP_895C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_880C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_815C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_810C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_830C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_885C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_840C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_816C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_HP, USB_PRODUCT_HP_959C,             ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_MTK, USB_PRODUCT_MTK_GPS_RECEIVER,    ANY,   { UQ_NO_UNION_NRM }},
- { USB_VENDOR_NEC, USB_PRODUCT_NEC_PICTY900,       ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_NEC, USB_PRODUCT_NEC_PICTY760,       ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_NEC, USB_PRODUCT_NEC_PICTY920,       ANY,   { UQ_BROKEN_BIDIR }},
- { USB_VENDOR_NEC, USB_PRODUCT_NEC_PICTY800,       ANY,   { UQ_BROKEN_BIDIR }},
-
- { USB_VENDOR_HP, USB_PRODUCT_HP_1220C,                    ANY,   { UQ_BROKEN_BIDIR }},
+ { USB_VENDOR_HP,              USB_PRODUCT_HP_895C,                    ANY,
+       { UQ_BROKEN_BIDIR, NULL }},
+ { USB_VENDOR_HP,              USB_PRODUCT_HP_880C,                    ANY,
+       { UQ_BROKEN_BIDIR, NULL }},
+ { USB_VENDOR_HP,              USB_PRODUCT_HP_815C,                    ANY,
+       { UQ_BROKEN_BIDIR, NULL }},
+ { USB_VENDOR_HP,              USB_PRODUCT_HP_810C,                    ANY,



Home | Main Index | Thread Index | Old Index