Notes about writing usb slave drivers I passionately hate USB. Maybe I'm just dumb, but I think USB is horribly complex. I once mentioned this to a friend, who's a hardware (chip) guy, and he was surprised me saying so. The thing is that the hardware side of usb is actually quite simple, and that's why it's cheap. The software layers on top of it however are simply horrible. A marvelous example of design-by-committee[1], where an overly complex spec leads to to misunderstanding by developers that design devices, which leads to bugs that stick because the existence of workarounds on the host side -- introduced by a first generation of buggy devices -- never encourages developers to actually follow the specs since "it works, anyway". (Postel's law gone bad [2]). The big irony of USB is that it contains a lot of device classes that are supposed to be universal: one host driver handles them all. However, if you look at the host driver in in Linux, it still needs to identify the devices by their vendor:device ID in order to perform workarounds, because in reality many of these devices contain bugs. The dream does does seem to work in general for printers, disks, keyboards and mice. And audio and midi devices. So I'm going to assume I'm just dumb and will now go out to slay that dragon. EDIT 8/2013: After getting my hands dirty on some more real world protocols, I'm inclined to think that getting *something* to work when a lot of people are involved in designing a protocol is a victory in itself. Elegance in procols seems to only work when they never have to be extended. The pain comes from not being able to design or maintain a minimal interface over time due to backwards compatibility issues or simply lack of overview or agreement. I tend to relate protocol elegance to the ease at wich parsing state machines can be built in a particular style (see some other post on protocol-oriented programming). More specifically: how much buffering is needed, and how many branch points does the code contain? EDIT 7/2014: I'll leave the social commentary in, but hey I got some things to work. USB is not that bad once it becomes clear that most of the horror can be ignored. It's just buffered streams, really. [1] http://en.wikipedia.org/wiki/Design_by_committee [2] http://en.wikipedia.org/wiki/Robustness_principle Entry: Setup Date: Sun Mar 6 10:00:18 EST 2011 * Host: linux. This makes it easier to see what's actually going on. I'm using a KVM instance with a modified kernel. * Slave: AT91SAM7 + eCos to serve as example, but my real target is the PIC18F with drivers implemented in Staapl. Entry: Linux KVM workbench Date: Sun Mar 6 10:01:43 EST 2011 My test host is called `kers', which is a KVM running a debian 2.6.32 kernel. The idea is modify only the modules that are necessary for debugging. Starting kvm with the option "-usb -usbdevice host:056a:00d4" allows you to attach a particular USB device to the vm. Then to make the usbserial generic driver work, changing the identifier in drivers/usb/seria/generic.c or choosing the predefined identifier 05f9:ffff. Entry: USB docs Date: Sun Mar 6 10:02:50 EST 2011 The general USB1.1 doc is a good starting point [2]. Any later versions are simply too complex. The goal is to implement some device classes. Docs are here[1]. I'm implementing a driver for the PIC18F2550[3]. [1] http://www.usb.org/developers/devclass_docs [2] http://esd.cs.ucr.edu/webres/usb11.pdf [3] http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010280 Entry: Staapl code on PIC18 Date: Mon Mar 7 12:44:55 EST 2011 Trivially compiling picstamp.fm, the file usb.f is missing. I have no idea where this went. Last code doing something[1] (It works "a bit"..). Todo: rewrite the whole .fm file into a Scheme module file. No Forth syntax for the driver. This is going to take a while as the `load' word is not supported in Scheme, and needs to be replaced with units. The 2 words that need to be plugged in are: - fosc - baud These are grabbed from the global context in monitor-serial-core.f and then passed on as parameters to the lower level modules. That seems to be a good idea: keep as much as possible in module form, using lexical parameters, and use "integration units" to pass parameters around. Is there a problem with p18f2550.f ? Currently it only includes p18f2550.f It's probably simplest to start at that file. Best would be something that can work directly from the header file. EDIT: added staapl/pic18/genheader.ss to compile an INC file to a scheme module. This triggers a problem with units: ROADMAP: - fix header file parsing DONE - fix low-level pic18 const dependenices (exercise for general unit problems) - fix p18f2550.f - fix monitor-serial-core.f [1] entry://../staapl/20090215-181941 [2] entry://../staapl/20110307-191827 Entry: libusb talk Date: Mon Mar 14 19:57:54 EDT 2011 Peter Stuge[1] Descriptors: Device (one per device) Configuration (mutually exclusive operation modes) Interface (independent behaviours) Endpoint (in/out channels per interface) [1] http://www.youtube.com/watch?v=SodMHKpykXw Entry: libusb, Racket FFI and PK2 Date: Tue Mar 29 12:14:36 EDT 2011 I've fixed some issues with the libusb FFI I'm using for the PK2 driver. Currently working on the PK2 ICSP/ICD protocol for use with the Staapl monitor, which I think is more important than the USB interface. Dev is going better than before now that I have a DSO to actually see what's going on. Entry: PK2 done Date: Fri Apr 8 14:32:08 EDT 2011 I've got the PK2 interface running reasonably reliably with asynch log display from PIC. Still some quirks that I expect to be either PK2 bugs, or improper PK2 init or error handling. So, time to tackle the USB. Let's stick to the previous organization: - Low level communications driver: handles all USB responses and transfers. - High level protocol: construction of per-device descriptors and endpoints. Entry: USB low-level Date: Fri Apr 8 14:35:32 EDT 2011 Following _usb.f : making sense of the different request dispatch levels. Each level is one decision down the tree, following only the first ones. level 0: dispatch UIR interrupts: error, soframe, idle, activity, stall, reset and transaction. level 1: transaction: - IN - OUT - SETUP level 2: SETUP - 0 GET_STATUS - 1 CLEAR_STATUS - 3 SET_FEATURE - 5 SET_ADDRESS - 6 GET_DESCRIPTOR - 7 SET_DESCRIPTOR - 8 GET_CONFIGURATION - 9 SET_CONFIGURATION - A GET_INTERFACE - B SET_INTERFACE level 3: GET_DESCRIPTOR - 1 DEVICE - 2 CONFIGURATION - 3 STRING - 4 INTERFACE - 5 ENDPOINT What about this: - generate macros for all code that simply returns a fixed reply packet. - use long names: SETUP.GET_DESCRIPTOR.DEVICE Entry: Got a USB sniffer Date: Wed May 23 18:28:21 EDT 2012 First thing I see with the beagle[1] is that there is traffic that is not just the device visible on the line. Does a HUB send stuff to all ports without being smart about where the devices are? From [2] it seems that hubs just forward to all ports: "During normal transmission, hubs are essentially transparent: data received from its upstream port is broadcast to all devices attached to its downstream ports; data received from a downstream port is generally forwarded to the upstream port only." and only for insertion there's a brief communication with host to perform the reset signalling: "Hubs are not transparent when dealing with changes in the status of downstream ports, such as insertion or removal of devices. In particular, if a downstream port of a hub changes status, this change is dealt with in an interaction between the host and this hub; the hubs between them act as transparent in this case." [1] http://www.totalphase.com/products/beagle_usb12/ [2] http://en.wikipedia.org/wiki/USB_hub Entry: USB on AT91SAM7 Date: Fri Aug 9 08:58:51 EDT 2013 Working on SIMtrace[1] firmware. [1] http://bb.osmocom.org/trac/wiki/SIMtrace Entry: USB: device / configuration / interface Date: Fri Aug 9 08:59:33 EDT 2013 A USB device can have multiple configurations. A configuration can have multiple interfaces. Only one configuration is active at one time. Multiple interfaces can be active at one time. Entry: Sending raw control transfers Date: Fri Aug 9 10:04:07 EDT 2013 Questions: - Is it possible to send control requests to a device while (of of) its interface(s) is claimed by another process? - Does it make sense to send control requests to an interface? Otherwise: how to send data over the default pipe to a second interface? First, let's have a look at bmRequestType (9.3.1 in usb11.pdf) D7: Data transfer direction 0 = Host-to-device 1 = Device-to-host D6...5: Type 0 = Standard 1 = Class 2 = Vendor 3 = Reserved D4...0: Recipient 0 = Device 1 = Interface 2 = Endpoint 3 = Other 4...31 = Reserved What I want to do is to poll for device data using a non-standard request, directed at a particular interface. D7 = 1 # Device-to-host D6-5 = 10 # Vendor D4-0 = 00001 # Interface 0xC1 for interface or 0xC0 for device wIndex = interface It does seem to work for VENDOR requests. In the at91lib code, requests are handled by the driver - in the CCID this is CCID_RequestHandler - which passes control back to the framework for standard requests using USBDDriver_RequestHandler() void USBVendorRequest(const USBGenericRequest *pRequest) ... #if 1 else if (USBGenericRequest_GetType(pRequest) == USBGenericRequest_VENDOR) { USBVendorRequest(pRequest); } #endif ... In the CCID driver, the following code overrides the main callback: //------------------------------------------------------------------------------ // Optional RequestReceived() callback re-implementation //------------------------------------------------------------------------------ #if !defined(NOAUTOCALLBACK) //------------------------------------------------------------------------------ /// Re-implemented callback, invoked when a new USB Request is received. //------------------------------------------------------------------------------ void USBDCallbacks_RequestReceived(const USBGenericRequest *request) { CDCDSerialDriver_RequestHandler(request); } #endif [1] http://libusb.sourceforge.net/api-1.0/group__syncio.html [2] http://msdn.microsoft.com/en-us/library/windows/hardware/ff539261%28v=vs.85%29.aspx Entry: USB linux Date: Fri Aug 9 12:50:33 EDT 2013 Makes little sense to me how topology is organized. What's the difference between: - bus - hub - port - the "usb b-x.y.z" in dmesg The x.y.z seems to be port numbers, i.e. physical topology. The b- seems to be bus number. How does a device get associated to a bus? Aha, I think I get it. - Busses are different host controllers, which in Linux have an associated "root hub" virtual hub. tom@zoo:/dev/bus/usb$ lspci |grep USB 00:12.0 USB controller: Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 USB OHCI0 Controller 00:12.2 USB controller: Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 USB EHCI Controller 00:13.0 USB controller: Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 USB OHCI0 Controller 00:13.2 USB controller: Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 USB EHCI Controller 00:14.5 USB controller: Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 USB OHCI2 Controller 00:16.0 USB controller: Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 USB OHCI0 Controller 00:16.2 USB controller: Advanced Micro Devices [AMD] nee ATI SB7x0/SB8x0/SB9x0 USB EHCI Controller tom@zoo:/dev/bus/usb$ lsusb |grep root Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Q: why are some 12M (OHCI, USB1.1) and others 480M (EHCI, USB2.0) ? It seems that a port is mapped either to an OHCI bus or a EHCI bus, depending on the kind of device it attaches to. Q: what's the difference between OHCI0 and OHCI2 - Not all root hubs have an equal amount of ports: lsusb -t |grep root_hub /: Bus 07.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/4p, 12M /: Bus 06.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/2p, 12M /: Bus 05.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/4p, 480M /: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/5p, 12M /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/5p, 480M /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/5p, 12M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/5p, 480M Pairing them 12M/480M, there is one that's special: 2p 12M Bus 06, which doesn't seem to have any devices attached. The other ones are 4+5+5, 14 physical ports? I count 12 physical ports. At least one internal one for the card reader, so there is probably a second internal one. - Some 7-port hubs are actually two 4-port hubs: 0409:005a "NEC Corp. HighSpeed Hub" x 2 = Tripp Lite 7-Port USB 2.0 Hub 05e3:0610 "Genesys Logic, Inc. 4-port hub x 2 = D-Link Hi-Speed USB 2.0 7-Port Powered Hub (DUB-H7) TOPOLOGY: tom@zoo:/dev/bus/usb$ lsusb -t 5-2.1:1.1: No such file or directory /: Bus 07.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/4p, 12M |__ Port 1: Dev 2, If 0, Class=vend., Driver=pl2303, 12M /: Bus 06.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/2p, 12M /: Bus 05.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/4p, 480M |__ Port 2: Dev 3, If 0, Class=hub, Driver=hub/4p, 480M |__ Port 1: Dev 5, If 0, Class=stor., Driver=usb-storage, 480M |__ Port 1: Dev 5, If 1, Class=vend., Driver=, 480M |__ Port 3: Dev 6, If 0, Class=vend., Driver=ftdi_sio, 12M |__ Port 4: Dev 7, If 0, Class=hub, Driver=hub/4p, 480M |__ Port 1: Dev 8, If 0, Class=vend., Driver=usbfs, 12M /: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/5p, 12M /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/5p, 480M |__ Port 1: Dev 2, If 0, Class=stor., Driver=usb-storage, 480M |__ Port 3: Dev 3, If 0, Class=stor., Driver=usb-storage, 480M /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ohci_hcd/5p, 12M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/5p, 480M |__ Port 2: Dev 2, If 0, Class=hub, Driver=hub/4p, 480M |__ Port 4: Dev 5, If 0, Class=hub, Driver=hub/4p, 480M |__ Port 2: Dev 15, If 0, Class=print, Driver=usbfs, 480M |__ Port 5: Dev 3, If 0, Class=hub, Driver=hub/4p, 480M |__ Port 1: Dev 6, If 0, Class=hub, Driver=hub/4p, 480M |__ Port 2: Dev 19, If 0, Class=>ifc, Driver=usbfs, 12M |__ Port 4: Dev 9, If 0, Class=hub, Driver=hub/4p, 480M |__ Port 3: Dev 10, If 0, Class=HID, Driver=usbhid, 1.5M |__ Port 4: Dev 11, If 0, Class=HID, Driver=usbhid, 1.5M DEVICES: tom@zoo:/dev/bus/usb$ lsusb Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 001 Device 002: ID 0409:005a NEC Corp. HighSpeed Hub Bus 001 Device 003: ID 05e3:0610 Genesys Logic, Inc. 4-port hub Bus 003 Device 002: ID 04e8:6014 Samsung Electronics Co., Ltd Bus 003 Device 003: ID 1307:0330 Transcend Information, Inc. 63-in-1 Multi-Card Reader/Writer Bus 005 Device 003: ID 0409:005a NEC Corp. HighSpeed Hub Bus 007 Device 002: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port Bus 001 Device 015: ID 04f9:0045 Brother Industries, Ltd Bus 001 Device 005: ID 0409:005a NEC Corp. HighSpeed Hub Bus 001 Device 006: ID 05e3:0610 Genesys Logic, Inc. 4-port hub Bus 005 Device 005: ID 18d1:4e12 Google Inc. Nexus One (debug) Bus 005 Device 006: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC Bus 005 Device 007: ID 0409:005a NEC Corp. HighSpeed Hub Bus 001 Device 019: ID 1a1e:9000 Bus 001 Device 009: ID 1a40:0101 Terminus Technology Inc. 4-Port HUB Bus 005 Device 008: ID 1366:0101 SEGGER J-Link ARM Bus 001 Device 010: ID 03f9:0100 KeyTronic Corp. KT-2001 Keyboard Bus 001 Device 011: ID 045e:0040 Microsoft Corp. Wheel Mouse Optical Entry: USB control OUT Date: Fri Aug 9 16:07:10 EDT 2013 host->device control request: H...D tok packet -> SETUP 8 bytes Table 9-2. Format of Setup Data -> IN <- OUT 0 size "short packet" to ack device->host control request: [1] http://www.beyondlogic.org/usbnutshell/usb6.shtml Entry: Staapl USB ACM serial driver Date: Sat Aug 31 12:24:06 EDT 2013 The Staapl descriptor language might be too abstract. Overall, when dealing with design-by-commitee specs, it seems best to just keep the structure definitions as close as possible to what is found in the documents. The ACM needs a couple of descriptors: - There are two interface descriptors - The descriptor list found in at91lib/usb/device/cdc-serial/CDCDSerialDriverDescriptors.c : - CDC Abstract Control Model - Call manageement - Abstract Control Management What I do not understand: - Where to add class-specific descriptors - How are these distinguished from USB standard descriptors? - Are all descriptors simply concatenated? It seems the host just does these: - Device - Configuration (which has all interfaces concatenated) - String It seems that GET_DESCRIPTOR isn't called for INTERFACE, at least in the Staapl USB firmware this isn't implemented. Found an answer[2]: Set Descriptor/Get Descriptor is used to return the specified descriptor in wValue. A request for the configuration descriptor will return the device descriptor and all interface and endpoint descriptors in the one request. Endpoint Descriptors cannot be accessed directly by a GetDescriptor/SetDescriptor Request. Interface Descriptors cannot be accessed directly by a GetDescriptor/SetDescriptor Request. String Descriptors include a Language ID in wIndex to allow for multiple language support. [1] http://www.lvr.com/usb_virtual_com_port.htm [2] http://www.beyondlogic.org/usbnutshell/usb6.shtml Entry: USB ACM Date: Sun Sep 1 11:05:59 EDT 2013 Reading the full spec seems like a waste of time as only the bare minimum of functionalit is necessary. Let's start from working code. In the at91lib code, the reply to GET_DESCRIPTOR CONFIGURATION is described by the type: typedef struct { USBConfigurationDescriptor configuration; USBInterfaceDescriptor communication; CDCHeaderDescriptor header; CDCCallManagementDescriptor callManagement; CDCAbstractControlManagementDescriptor abstractControlManagement; CDCUnionDescriptor union1; USBEndpointDescriptor notification; USBInterfaceDescriptor data; USBEndpointDescriptor dataOut; USBEndpointDescriptor dataIn; } __attribute__ ((packed)) CDCDSerialDriverConfigurationDescriptors; First, figure out the size of this to see if it fits in the Staapl stuff. -> 67 bytes, so we need to implement multiple IN packets first. This contains two interfaces. Entry: Distinguishing a bag of USB serial adapters Date: Sun Sep 8 15:31:06 EDT 2013 I have these PL2303-based SIM card readers that are identical. I've been using a script to uniquely identify tty USB adapters, which uses the device reported serial number string to identify the port, or else a concatenation of idVendor and idProduct. Let's change the latter to the bus/port hierarchy the device is plugged into. At least that is under physical control. Found some info here[2]. The tree address is actually in the device hierarchical name. See the following line in the updated [1]: DEVTREE=$(basename $(readlink -f ../../)) [1] http://zwizwa.be/darcs/pool/bin/ttyUSB_id [2] http://askubuntu.com/questions/49910/how-to-distinguish-between-identical-usb-to-serial-adapters Entry: ACM descriptor Date: Sat Sep 14 11:52:21 EDT 2013 Trying to get USB CDC ACM to work in staapl. Basic descriptor transfer seems to work ok, but it is not recognized: [master] tom@tx:~/staapl/staapl/app$ lsusb -v -d 05F9:FFF0 Bus 002 Device 021: ID 05f9:fff0 PSC Scanning, Inc. libusb couldn't open USB device /dev/bus/usb/002/021: Permission denied. libusb requires write access to USB device nodes. Couldn't open device, some information will be missing Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 1.10 bDeviceClass 0 (Defined at Interface level) bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 64 idVendor 0x05f9 PSC Scanning, Inc. idProduct 0xfff0 bcdDevice 0.00 iManufacturer 1 iProduct 2 iSerial 3 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 67 bNumInterfaces 2 bConfigurationValue 1 iConfiguration 0 bmAttributes 0xa0 (Bus Powered) Remote Wakeup MaxPower 100mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 Unused bInterfaceProtocol 0 iInterface 0 ** UNRECOGNIZED: 05 24 00 10 01 ** UNRECOGNIZED: 05 24 01 01 00 ** UNRECOGNIZED: 04 24 02 02 ** UNRECOGNIZED: 05 24 06 00 01 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 10 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 2 bInterfaceClass 10 CDC Data bInterfaceSubClass 0 Unused bInterfaceProtocol 0 iInterface 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x01 EP 1 OUT bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 2 Transfer Type Bulk Synch Type None Usage Type Data wMaxPacketSize 0x0040 1x 64 bytes bInterval 0 [master] tom@tx:~/staapl/staapl/app$ Entry: CDC SETUP requests Date: Sat Sep 14 13:02:21 EDT 2013 After getting all descriptors and receiving SET_CONFIGURATION, host sends a SETUP request with the following data: 21 22 00 00 00 00 00 00 which seems to be incorrectly handled. frome[1]: 21 = Class request to interface 0. 22 = Request type /// SetLineCoding request code. #define CDCGenericRequest_SETLINECODING 0x20 /// GetLineCoding request code. #define CDCGenericRequest_GETLINECODING 0x21 /// SetControlLineState request code. #define CDCGenericRequest_SETCONTROLLINESTATE 0x22 It seems best to just disable this in the capabilities: See [2] p36 D7..D4: RESERVED (Reset to zero) D3: 1 - Device supports the notification Network_Connection. D2: 1 - Device supports the request Send_Break D1: 1 - Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State. D0: 1 - Device supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature. Funny though, setting this byte to 0 still causes these requests to come in. Ignoring them seems fine, i.e. just sending a 0-size IN0. [1] http://www.beyondlogic.org/usbnutshell/usb6.shtml [2] http://www.usb.org/developers/devclass_docs/usbcdc11.pdf Entry: Staapl drivers Date: Wed Jul 9 20:33:01 EDT 2014 Got it to work reliably on Staapl PIC18. Basic ideas: - low priority interrupt - poll buffers from mainloop (UOWN bit) - ignore requests (for CDC serial and MIDI this wasn't necessary) - simple API for reading/writing to endpoint buffers