Here's what I've discovered about some kinds of USB device:
- Keyboard and mouse: they support a simplified bootstrap
mode that's very simple to deal with. Here's a driver for the common
parts of bootstrap-mode keyboard and mouse:
USBHID : USBDevice ()
USBHID init: devicename
[
super init: (OFW open: devicename).
self setConfiguration: 1.
self setBootstrapProtocol.
]
USBHID setBootstrapProtocol
[
self controlSetIndex: 0 value: 0
requestType: (DR_HIDD bitOr: DR_OUT) request: SET_PROTOCOL
]
USBHID setIdle: ms
[
self controlSetIndex: 0 value: (ms // 4 << 8)
requestType: (DR_HIDD bitOr: DR_OUT) request: SET_IDLE
]
USBHID selftest
[
self init.
1000 timesRepeat: [ self readReport ifNotNilDo: [ :e | e println]. ]
]
and here's a subclass that knows how to turn the reports into mouse events:
USBMouse : USBHID ()
USBMouse init [ self init: '/mouse' ]
USBMouse init: device [ super init: device. self setIdle: 0 ]
USBMouse readReport [ ^MouseEvent fromUSB: (self intrIn: 1) ]
MouseEvent fromUSB: report
[
self := self new.
left := (report first bitAnd: 1) ~~ 0.
right := (report first bitAnd: 2) ~~ 0.
dx := report second.
dy := report third.
"Treat bit 8 as sign."
(dx bitAnd: 0x80) ~~ 0 ifTrue: [ dx := dx - 256 ].
(dy bitAnd: 0x80) ~~ 0 ifTrue: [ dy := dy - 256 ].
]
The keyboard is similar: it reports the set of keys (identified by scancode) that are currently pressed, and uses a fixed mapping from scancodes onto key identifiers.
I regret that I haven't come back to look at the full-blown USB Human Input Device protocol yet!
- Ethernet: In theory the USB
Communications Device Class specifies the high-level interface for
ethernet-like network adapters, but in practice most
USB-ethernet dongles seem to be built from an ASIX
USB-ethernet chip. For example, the Apple USB-ethernet dongle is
internally an ASIX 88772A.
ASIX chips aren't compatible with the
USB CDC standard, they use their own custom
protocol instead. The protocol is simple but it's lower-level
than CDC: you're sometimes peeking and poking registers instead of exchanging
messages.
- Display:
My previous posts ( first, second) describe the USB-VGA adapter I found. I'm unhappy with this device: taking a notoriously closed graphics chip and blindly bridging its PCI bus onto USB is really kludgy. The components don't even seem to be particularly cheap (Octopart suggests $15 for the USB-PCI bridge chip) so I suppose the intention was to save development money by not having to program the dongle. I'd be happier if they'd spent the same money on an ARM- or FPGA- based dongle and programmed it to do the job gracefully, but that's me being a naive software guy.
I'm finding driver writing frustratingly slow going. I'm used to a very experimental and exploratory programming style, but that's not very effective because when you make a mistake the devices won't tell you where! This reminds me of talking to
SIM cards and
web services. I'm looking for a smarter working style.