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 NBP PN533 USB toggle bit bugs



details:   https://anonhg.NetBSD.org/src/rev/83acb18b26e5
branches:  trunk
changeset: 445843:83acb18b26e5
user:      manu <manu%NetBSD.org@localhost>
date:      Thu Nov 15 02:35:23 2018 +0000

description:
Workaround NBP PN533 USB toggle bit bugs

The PN533 is known to mishandle the USB toggle bit, causing replies to
be filtered out by the host controller. As a result, the kernel sees
a timed out operation.

Vendor errata suggests that userland applications should detect the
situation on read timeout, and write a dumy frame to resync the toggle bit.
NFC Tools's libnfc does just that, but in order to succeed, the dummy
frame write must not be reported as timed out.

We therefore introduce a new USB quirk for devices known to miss output
acks. When that occur, we pretend that the operation succeeded, leaving
userland the duty to check that everything went okay.

This workaround lets libnfc recover from interrupted communications
without the need te reboot the system.

diffstat:

 sys/dev/usb/usb_quirks.c |  23 +++++++++++++++++------
 sys/dev/usb/usb_quirks.h |   3 ++-
 sys/dev/usb/usbdi.c      |  29 ++++++++++++++++++++++++-----
 3 files changed, 43 insertions(+), 12 deletions(-)

diffs (121 lines):

diff -r e43551b25ecf -r 83acb18b26e5 sys/dev/usb/usb_quirks.c
--- a/sys/dev/usb/usb_quirks.c  Thu Nov 15 00:01:38 2018 +0000
+++ b/sys/dev/usb/usb_quirks.c  Thu Nov 15 02:35:23 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: usb_quirks.c,v 1.89 2018/11/08 09:00:24 martin Exp $   */
+/*     $NetBSD: usb_quirks.c,v 1.90 2018/11/15 02:35:23 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.89 2018/11/08 09:00:24 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb_quirks.c,v 1.90 2018/11/15 02:35:23 manu Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -310,13 +310,24 @@
  { USB_VENDOR_ZOOM,            USB_PRODUCT_ZOOM_3095,                  ANY,
        { UQ_LOST_CS_DESC, NULL }},
 
- /* NXP PN533 corrupts its USB configuration descriptors */
+ /*
+  * NXP PN533 bugs
+  * 
+  * 1. It corrupts its USB descriptors. The quirk is to provide hardcoded
+  *    descriptors instead of getting them from the device.
+  * 2. It mishandles the USB toggle bit. This causes some replies to be
+  *    filered out by the USB host controller and be reported as timed out.
+  *    NFC tool's libnfc workaround this bug by sending a dummy frame to
+  *    resync the toggle bit, but in order to succeed, that operation must
+  *    not be reported as failed. The quirk is therefore to pretend to 
+  *    userland that output timeouts are successes.
+  */
  { USB_VENDOR_PHILIPSSEMI,     USB_PRODUCT_PHILIPSSEMI_PN533,          ANY,
-       { UQ_DESC_CORRUPT, desc_pn533 }},
+       { UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
  { USB_VENDOR_SHUTTLE,         USB_PRODUCT_SHUTTLE_SCL3711,            ANY,
-       { UQ_DESC_CORRUPT, desc_pn533 }},
+       { UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
  { USB_VENDOR_SHUTTLE,         USB_PRODUCT_SHUTTLE_SCL3712,            ANY,
-       { UQ_DESC_CORRUPT, desc_pn533 }},
+       { UQ_DESC_CORRUPT | UQ_MISS_OUT_ACK, desc_pn533 }},
  { 0, 0, 0, { 0, NULL } }
 };
 
diff -r e43551b25ecf -r 83acb18b26e5 sys/dev/usb/usb_quirks.h
--- a/sys/dev/usb/usb_quirks.h  Thu Nov 15 00:01:38 2018 +0000
+++ b/sys/dev/usb/usb_quirks.h  Thu Nov 15 02:35:23 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: usb_quirks.h,v 1.28 2018/11/08 02:11:54 manu Exp $     */
+/*     $NetBSD: usb_quirks.h,v 1.29 2018/11/15 02:35:23 manu Exp $     */
 /*     $FreeBSD: src/sys/dev/usb/usb_quirks.h,v 1.9 1999/11/12 23:31:03 n_hibma Exp $  */
 
 /*
@@ -50,6 +50,7 @@
 #define UQ_LOST_CS_DESC 0x10000 /* look everywhere for the CS descriptors */
 #define UQ_APPLE_ISO   0x20000 /* force ISO layout on Apple keyboards */
 #define UQ_DESC_CORRUPT        0x40000 /* may corrupt its config descriptors */
+#define UQ_MISS_OUT_ACK        0x80000 /* may fail to ack output */
        const usb_descriptor_t **desc;  /* Replacement for UQ_DESC_CORRUPT */
 };
 
diff -r e43551b25ecf -r 83acb18b26e5 sys/dev/usb/usbdi.c
--- a/sys/dev/usb/usbdi.c       Thu Nov 15 00:01:38 2018 +0000
+++ b/sys/dev/usb/usbdi.c       Thu Nov 15 02:35:23 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: usbdi.c,v 1.178 2018/09/16 20:21:56 mrg Exp $  */
+/*     $NetBSD: usbdi.c,v 1.179 2018/11/15 02:35:23 manu Exp $ */
 
 /*
  * Copyright (c) 1998, 2012, 2015 The NetBSD Foundation, Inc.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.178 2018/09/16 20:21:56 mrg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usbdi.c,v 1.179 2018/11/15 02:35:23 manu Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -898,9 +898,7 @@
        struct usbd_pipe *pipe = xfer->ux_pipe;
        struct usbd_bus *bus = pipe->up_dev->ud_bus;
        int sync = xfer->ux_flags & USBD_SYNCHRONOUS;
-       int erred =
-           xfer->ux_status == USBD_CANCELLED ||
-           xfer->ux_status == USBD_TIMEOUT;
+       int erred;
        int polling = bus->ub_usepolling;
        int repeat = pipe->up_repeat;
 
@@ -915,6 +913,27 @@
            xfer->ux_state);
        KASSERT(pipe != NULL);
 
+       /*
+        * If device is known to miss out ack, then pretend that
+        * output timeout is a success. Userland should handle
+        * the logic to verify that the operation succeeded.
+        */
+       if (pipe->up_dev->ud_quirks &&
+           pipe->up_dev->ud_quirks->uq_flags & UQ_MISS_OUT_ACK &&
+           xfer->ux_status == USBD_TIMEOUT &&
+           !usbd_xfer_isread(xfer)) {
+               USBHIST_LOG(usbdebug, "Possible output ack miss for xfer %#jx: "
+                   "hiding write timeout to %d.%s for %d bytes written",
+                   xfer, curlwp->l_proc->p_pid, curlwp->l_lid,
+                   xfer->ux_length);
+
+               xfer->ux_status = USBD_NORMAL_COMPLETION;
+               xfer->ux_actlen = xfer->ux_length;
+       }
+
+       erred = xfer->ux_status == USBD_CANCELLED ||
+               xfer->ux_status == USBD_TIMEOUT;
+
        if (!repeat) {
                /* Remove request from queue. */
 



Home | Main Index | Thread Index | Old Index