![](http://pics.livejournal.com/lukego/pic/0002k969/s320x240)
So the USB2VGA dongle isn't much fun to program -- especially since I haven't found a spec for the SiS315 graphics chip. I started out by porting very tedious Linux code like this:
ret |= SETIREGAND(SISCR, 0x5b, 0xdf);
ret |= SETIREG(SISSR, 0x05, 0x86);
ret |= SETIREGOR(SISSR, 0x20, 0x01);
ret |= SETREG(SISMISCW, 0x67);
for (i = 0x06; i <= 0x1f; i++) {
ret |= SETIREG(SISSR, i, 0x00);
}
for (i = 0x21; i <= 0x27; i++) {
ret |= SETIREG(SISSR, i, 0x00);
}
and after a while I reached the important realisation that these hundreds of numbers that you need to send the dongle in order to boot it are completely boring.
There's no sense in filling up source files with boring numbers, so I changed strategy. I recorded what Linux sends over USB to make the dongle boot and checked whether I could just blindly replay exactly the same traffic. This turned out to be easy and fun!
- Capture USB traffic while plugging in the dongle:
tcpdump -w trace.pcap -ni usb0
- Open the trace in wireshark and Print as ascii like this:
Frame 3 (14 bytes on wire, 14 bytes captured)
USB URB
URB id: 0x00000000de478380
URB type: URB_SUBMIT ('S')
URB transfer type: URB_BULK (3)
Endpoint: 0x0e
Device: 3
URB bus id: 1
Device setup request: not present ('-')
Data: present (0)
URB status: Operation now in progress (-EINPROGRESS) (-115)
URB length [bytes]: 6
Data length [bytes]: 6
[Response in: 4]
[bInterfaceClass: Unknown (0xffff)]
Application Data: 420044D00000
- Filter and massage the printed trace:
#!/usr/bin/env awk -f
/Endpoint:/ { ep = "" }
/Endpoint: 0x0[de]/ { ep = strtonum($2) }
/Application Data:/ && ep != "" { printf("SND %.2x %s\n", ep, $3); }
to resemble a script:
SND 0d 1F002403000004000000
SND 0d 1F006403000004000000
SND 0d 1F008403000004000000
SND 0d 1F000001000000070000
SND 0d 0F0004000000
...
- Write a traffic-replaying interpreter for the trace in (for example) Forth:
d# 128 constant /buffer
/buffer dma-alloc value buffer \ buffer in DMA-friendly memory.
0 value line
: SND ( "endpoint" "data" -- )
line 1+ to line
get-hex# ( endpoint )
safe-parse-word decode-hex ( endpoint adr len )
dup >r ( r: len )
buffer swap ( endpoint adr buffer len )
cmove ( endpoint )
buffer r> rot ( adr len endpoint )
bulk-out ?dup if
." usb error on write = " . ." line " line . abort
then
;
- Then plug the dongle into my OLPC XO and execute the Forth code in Openfirmware and -- drumroll -- the dongle boots! I see the contents of the framebuffer appear on my monitor. Cool!
Poking around a little more at the Forth prompt reveals that the screen is initialized to 800x600 in 16bpp RGB-565 mode. I can either settle for that or make a new trace of Xorg initializing some specific display mode of my liking.
Beats writing it by hand :-)