For those who don’t want to read a long post, here’s the summary : I’m trying to write a USB gadget driver to make my N900 act as a hub, I don’t know if I can get it to work because the kernel subsystem doesn’t seem to allow me to do it. If someone knows how to get a request’s destination address, or override the usb_gadget_ep0.c SET_ADDRESS, or knows of limitations that would prevent me from making it work, let me know. I also have ‘working code’ for the usb hub now, but it seems that when I simulate a device insertion, my computer’s (not the N900’s) kernel crashes, so I’m a bit stuck.
Read the rest if this article interests you.
Some of you already know about the PSJailbreak, for those who don’t, it’s a USB dongle that exploits the PS3 and allows you to run unsigned packages (homebrew).
Some people tried (and some succeeded) to create a ‘cheap’ clone of the dongle by reverse engineering what it does, and rewriting it into some ATMega microcontroller.
My idea was to use an existing programmable linux-based device (my N900) to act as the dongle. So I started looking inside the kernel’s source to understand how I can achieve that. I found that the kernel has a ‘usb gadget’ subsystem for writing gadget drivers (in other words, a driver to make your device act as a slave/peripheral) so I started writing a gadget driver.
I must say it wasn’t an easy task (for someone with ~zero kernel experience) especially considering that the only ‘real’ documentation I found was the undocumented source code of other gadget modules…
Anyways, the PSJailbreak dongle emulates a USB Hub with multiple devices getting connected/disconnected to it, so I tried to write a driver to emulate a USB Hub, I thought that it would be a great idea and useful, since it could be used in order to allow my N900 to be in PCSuite mode *and* mass storage mode at the same time, without having to make that annoying choice everytime I plug it into USB.
Anyways, I first realized that I can’t just insmod/rmmod drivers to emulate a device getting connected/disconnected, because the usb_gadget_register_driver doesn’t allow us to register more than one driver. Ok, makes sense, I can live with that, but this means that I’ll have to modify the kernel to make sure the usb_gadget_register_driver redirects to my hub’s code to simulate the insertion/removal and let my hub driver be the only one registered on the controller. Anyways, for my use case, I thought I can just write all the code for all these ‘virtual devices’ directly into my driver for now.
Second issue I came up with is that the drivers never get a SET_ADDRESS.. that’s handled internally by the kernel (drivers/usb/musb/msub_gadget_ep0.c) which means that even if I say “new device connected”, if the host sends me a SET_ADDRESS, I won’t get it, so I can’t map addresses to my virtual devices… but not only that, but I found no way whatsoever to find what is my current address, or to which address a message is being sent… I suppose it’s all being handled by the usb subsystem.. but I can’t find a “if (destination != self->address) return; anywhere in the code either.. which makes me think that it might be handled by the controller itself.. (since we do receive messages destined to other devices, if we’re connected to a hub, it has to drop those somewhere), but I don’t know, either the controllers don’t let me do what I want, or the kernel’s USB subsystem was never written to allow for USB hubs to be created. I figured that if I could at least simulate a device being connected, I should be able to find out how the kernel would handle the newly received SET_ADDRESS or the requests being received to the virtual device… then maybe I would understand a bit more how to do it and whether or not it’s even possible.
Call it bad luck, but now, whenever I plug my N900 (with my driver module loaded) into my laptop (linux debian, kernel 2.6.32-5), my laptop crashes.. it completely freezes up, the kernel panics, and then I’m forced to reboot it.. I’ve looked at what messages I’m sending/receiving from the N900’s dmesg (yes, the N900 is perfectly fine and doesn’t kernel panic), and I compare it with the USB dump of a generic hub being plugged into the computer, and I see no difference, I’m doing exactly the same! And yet, my kernel segfaults, and now, I’m stuck as I don’t know how to move forward.. I only got a partial stack trace, I know the khubd thread gets the segfault, and that it’s when it’s trying to build a URB… there also seems to be some error being reported by the power/battery manager or something, so maybe it has something to do with bad/wrong values of self-powered/power needs of the device.. but that’s it…
I went to the #kernel channel on freenode, asked about this issue, asked how to get proper debug/stacktrace, and asked how a usb gadget can know its own address, but noone seems to care/answer/be awake. So that’s why I’m posting this on my blog.. first, to let everyone know what I’m doing and how advanced (or not) I am in the project, but also to ask people for help, if they know of a solution to my problem, let me know in the comments. Please, do not post comments like “I have a PS3/N900/something if you need help testing”… I don’t.
Finally, I’d like to finish by saying that I do not condone piracy. The PSJailbreak is an exploit that jailbreaks the PS3 allowing you to run unsigned code, it opens the door to homebrew and yes, also to piracy, but it’s each individual’s choice to either use it for legal applications or not. It is fair use to be allowed to make backups of your expensive games (and I’ve got about 50+ disc-based games). I’m doing this project only because I like the challenge, I thought it would be a good experience for me to dive a bit into the kernel code, and I found it entertaining. I also wanted to showcase the power of the N900 even more by making it become any usb device I want.. even a PSJailbreak clone, I don’t think anyone has used it in this manner yet.
Thanks for reading!
Update : I got a stacktrace from the kernel crash!