You are viewing lukego

Luke's Weblog - Cheating [entries|archive|friends|userinfo]
Luke Gorrie

[ website | My Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Cheating [Mar. 26th, 2009|02:43 pm]
Previous Entry Share Next Entry
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!

  1. Capture USB traffic while plugging in the dongle:
    tcpdump -w trace.pcap -ni usb0
    
  2. 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
    
  3. 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
    ...
    
  4. 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
    ;
    
  5. 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 :-)

LinkReply

Comments:
[User Picture]From: darius
2009-03-26 05:18 am (UTC)

(Link)

Nice work! I wonder how many other drivers you could do that sort of thing to.
[User Picture]From: funos
2009-03-26 12:21 pm (UTC)

(Link)

Seconded. Nice work!

There's something wrong when modern code contains the equivalents of Commodore Basic POKE commands to load code. It's just punchcards in another form.
[User Picture]From: lukego
2009-03-26 09:47 pm (UTC)

(Link)

Now we see if this whole approach unravels. I need to support BITBLT i.e. rectangle-copy within the framebuffer without having to move the data over USB. I'd really like to find a spec (register description) for the SiS315 so please tell me if you know where to find one.
[User Picture]From: lukego
2009-03-26 09:51 pm (UTC)

(Link)

I think it's quite common for modern drivers to boot devices by uploading a firmware for them to execute. The PC treats the firmware as opaque binary data but in reality it's a complete software image for a microprocessor on the device and handles all init and communication. This seems a lot like what I'm doing except that I'm deriving the 'firmware' by nefarious means.

Edited at 2009-03-26 10:03 pm (UTC)
From: (Anonymous)
2009-03-27 03:14 pm (UTC)

(Link)

I have a Minolta scanner that does exactly that, too. I guess it's cheaper to produce, but it takes forever to start up and it doesn't work on Linux and probably never will.

If I'd known, I never would have bought it. There was a short time when "USB" really meant "universal".
From: (Anonymous)
2009-03-26 11:11 am (UTC)

Nice approach!

(Link)

Good stuff. Did you cast an eye over the trace to see if there was any resemblance to the boring linux code? i.e. was it somewhat decodable without extreme effort?
[User Picture]From: lukego
2009-03-26 09:58 pm (UTC)

Re: Nice approach!

(Link)

The trace is a series of 32-bit PEEK and POKE operations being sent to an 8051 microprocessor that's embedded in the NET2280 PCI-USB bridge. Each 6-byte USB request is a PEEK and each 10-byte request is a POKE. Details in http://www.digchip.com/datasheets/parts/datasheet/324/NET2280.php section 7.6.5 Dedicated (USB) endpoints. The basic format is 2 byte header, 4 byte address, optional 4 byte data (all little-endian).

I don't understand what the POKEs to SIS registers mean because I don't have a spec for that chip. I'd love to make the driver do everything I need without ever having to learn the gory details of the SIS.
From: (Anonymous)
2009-03-26 03:12 pm (UTC)

That sure looks fun

(Link)

Do you get paid for this?
[User Picture]From: lukego
2009-03-26 09:43 pm (UTC)

Re: That sure looks fun

(Link)

None of your business my dear stranger :-)
[User Picture]From: kragen
2009-03-26 06:08 pm (UTC)

(Link)

Good idea. Too bad I don't have a tcpdumpable usb0.
[User Picture]From: lukego
2009-03-26 09:36 pm (UTC)

(Link)

You need: Linux, libpcap 1.0, tcpdump 4.0, modprobe usbmon.

Don't forget the -w argument to tcpdump: it doesn't know how to ascii-print USB traffic and will print an obscure error message unless you ask it to write to a trace file.
From: (Anonymous)
2009-03-27 02:13 pm (UTC)

(Link)

Does the SiS chip have open source drivers (for a video card / onboard video connected by agp/pci/pcie) from which you can learn about programming it? Or if the linux/bsd drivers are too hard to understand maybe their docs have a maintainer listed and they know whether any docs are available not under nda?
[User Picture]From: lukego
2009-03-27 10:45 pm (UTC)

Re: Does this help?

(Link)

Thank you!
From: (Anonymous)
2009-03-27 08:30 pm (UTC)

SiS315

(Link)

Luke,

I wish I could explain how much the SiS315 chipset has been a pain in the ass to the Linux world. We've begged SiS (now called XGI) to release the register specs so we can make a 3D driver for their crappy hardware.

At this point in time here's your best option...

http://www.winischhofer.eu/linuxsisusbvga.shtml
From: (Anonymous)
2009-03-27 08:37 pm (UTC)

Re: SiS315

(Link)

wut
[User Picture]From: lukego
2009-03-27 10:48 pm (UTC)

Re: SiS315

(Link)

This is lamentable.

If there's another USB-based graphics adapter that's nicer to work with, e.g. that uses a driver interface based on USB abstractions, I'd love to hear about it.
From: node
2009-03-28 07:24 am (UTC)

fame!

(Link)

Or something like that.
From: (Anonymous)
2010-05-31 10:43 am (UTC)

mp5 players ,usb flash memory

(Link)

mp5 players ,usb flash memory ,電腦 http://www.egoingspot.com