Hello

I made some progress on this issue. The problem is common to NFC readers
powered by the pn533 chip from NXP, which is quite common. It has at
least two bugs in its USB implementation:
- Large transfer can overwrite the chip USB configuration descriptors
- In some situation the chip fails to update the toggle bit in USB frame.

The second problem causes ack frames from the chip to be silently 
discarded by the host controler. As a result, requests timeout without
a reply. And when rebooting, the first problem causes NetBSD to reject
the device attachement, because its USB configuration descriptors do not 
contain usable data. The only way to recover with our current kernel is
to unplug/replug the device.

libnfc has workarounds for the two problems. It uses the chip overflow
on purpose to rewrite the correct USB descriptors, and it sends empty
frames in order to get an ack with appropriate toggle bit when that
problem happens. But that workarounds will only be of some help if
middleware does not come in their ways.

I found three situations where the NetBSD kernel USB implementation
would break the day. Here are the proposed patches to fix the situation:


1) Provide fake USB descriptors 
https://ftp.espci.fr/shadow/manu/desc_fake.patch

When we detect the USB descriptors are corrupted (type and size make
no sense), we provide hard-coded configuration, interface and endpoint
descriptors. We trigger that on appropriate USB product ID and vendor ID 
from the USB device descriptor, which fortunately is not corrupted. It 
works well for the pn533, because according to the chip documentation, 
the descriptors are immutable, hence our fake version is always right.

This lets NetBSD configure the device on reboot after it has corrupted
its USB descriptors, and libnfc can then actually use it. 


2) Use USB timeout for ugen write operations
https://ftp.espci.fr/shadow/manu/ugen_timeout.patch

The ioctl USB_SET_TIMEOUT was only used for read operations in ugen(4).
That patch makes sure it is also used for write operation, so that 
a user process will not wait forever for a missing ack frame.


3) Use USB timeout in usbd_transfer()
https://ftp.espci.fr/shadow/manu/usb_sync_xfer.patch

Make sure the USB timeout is used when doing synchronous USB transfers.
Here again the goal is to avoid getting stuck in the kernel forever
because the ack frame was rejected by the host controler.

-- 
Emmanuel Dreyfus
m...@netbsd.org

Reply via email to