Using the Palm Pre as Xbox 360 Storage (part 2)
Posted by error454 on 09/12/2010
In my last post, I incorrectly theorized that the reason my Xbox 360 could not see my Palm Pre was because the mass storage driver was implemented as BOT instead of CBI. BOT or Bulk Only Transfer has only 2 endpoints, bulk-in & bulk-out. CBI or Control Bulk Interrupt has 3 endpoints, bulk-in, bulk-out and interrupt.
After spending some time in the code, I finished my cosmetic CBI driver hack, essentially making the Pre look identical to my working USB thumb drive in every single way. This was not the solution! I now have a working solution and it happens to be BOT, so we can safely say that the CBI vs BOT theory is moot.
Lab notes below.
Finishing the Cosmetic Hack
Although the cosmetic hack ended up being a complete waste of time, it was a good learning experience. I found the spec for mass storage devices which demystified setting the interface descriptor along with the Interrupt Endpoint.
Because US_PR_CB (0x01h) does not define the use of the Interrupt Endpoint, I thought it would be ideal to use for the cosmetic hack – since the EP is undefined, we can be sure that we won’t be impeding any functionality due to lack of interrupt handling. To set the EP Address, we use the following from the spec:
bEndpointAddress 8?h
The address of this endpoint on the USB device. This address is an Endpoint number between 1 and 15.
Bit 0..3 – Endpoint number
Bit 4..6 – Reserved, must be 0
Bit 7 – 0 = Out, 1 = In
Leading to these scribbles:
Bit 0..3 – Endpoint number
Bit 4..6 – Reserved, must be 0
Bit 7 – 0 = Out, 1 = In
10000010 = 130 decimal = 0x82h
After modifying fsg_function_bind() and do_set_interface() to include initialization of the Interrupt EP, the visibility hack was fully realized. However, the results were no different than before.
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 4
bmAttributes 0xc0
Self Powered
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 8 Mass Storage
bInterfaceSubClass 6 SCSI
bInterfaceProtocol 0 Control/Bulk/Interrupt
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 1
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 8
Digging Deeper
I figured that snooping USB traffic might lend an insight into what’s happening. To this end I used usbmon, luckily the required module was already built-in to the stock Pre kernel. Taking traces of both the stock driver and the modified working driver, I was very disappointed to find that the traffic for the USB detection phase was identical for both drivers?!? How could this be? Just a note, if you are ever looking to understand the raw text output that usbmon produces, the official readme and the cheat sheet are essential.
For reference, this is the repeating pattern I see in all of the usbmon traces, my decoding notes included.
//Not sure what this is but guessing that it is normal for BOT aebf8a80 14.472869 S Ii:1:001:1 -:-606348325 2 < //Get Port 1 Status ad8f4580 14.472930 S Ci:1:001:0 s a3 00 0000 0001 0004 4 < ad8f4580 14.472930 C Ci:1:001:0 0 4 = 07010000 //Clear Port 1 Feature 2 (over current) ad8f4580 14.472961 S Co:1:001:0 s 23 01 0002 0001 0000 0 ad8f4580 14.472961 C Co:1:001:0 0 0 //Get Port 2 Status ad8f4580 14.473419 S Ci:1:001:0 s a3 00 0000 0002 0004 4 < ad8f4580 14.473449 C Ci:1:001:0 0 4 = 00010000 //Get Port 3 Status ad8f4580 14.473480 S Ci:1:001:0 s a3 00 0000 0003 0004 4 < ad8f4580 14.473480 C Ci:1:001:0 0 4 = 00010000 //Get Port 1 Status ad8f4580 14.512908 S Ci:1:001:0 s a3 00 0000 0001 0004 4 < ad8f4580 14.512939 C Ci:1:001:0 0 4 = 03010400 //Clear Port 1 Feature 12 (ch suspend) ad8f4580 14.512939 S Co:1:001:0 s 23 01 0012 0001 0000 0 ad8f4580 14.512939 C Co:1:001:0 0 0 //Get Device Status ad8f4580 14.533111 S Ci:1:002:0 s 80 00 0000 0000 0002 2 < ad8f4580 14.534149 C Ci:1:002:0 0 2 = 0000 //Set Port 1 Feature 2 (over current) ad8f4580 14.833068 S Co:1:001:0 s 23 03 0002 0001 0000 0 ad8f4580 14.833099 C Co:1:001:0 0 0 aebf8a80 14.853027 C Ii:1:001:1 -2:-606348325 0
I feel like I’m on the wrong side of the usbmon trace! I was hoping to find that one of the Ci requests resulted in an error code, no such luck. Apart from errors produced from the requests bound for the Interrupt EP (Ii), things look clean. I should note that not only is the request structure identical between the 2 drivers, but the return codes for device and port status as well.
A Simple Working Solution
From pouring over the source for f_mass_storage.c, I knew that this work was based on file_storage.c by Alan Stern. This well-documented piece of code is essentially a file-backed USB Mass Storage Device (MSD). Meaning, when you load the module, you specify a file or device which is then presented as if it were a MSD.
I figured I may as well compile this simple module (file_storage.c) and give it a try. Due to the way the Palm USB solution is setup, I had to do just a bit more. It helps to understand the Palm USB ecosystem which I have painted below.

Palm USB Ecosystem
The rockhopper module wraps around 5 separate USB modules, handling the loading of the desired module. Because of this, rockhopper is always loaded in the background which means the USB ports will always be in-use. Because rockhopper is built into the kernel by default, a recompile was necessary to compile rockhopper as a loadable module. This allows loading my own file_storage module in place of it.
After loading the file_storage module and specifying my spare ext3fs partition (thanks to Meta-Doctor), I plugged into my Xbox 360 and was pleasantly surprised to be able to see and use my Pre as mass storage!
file_storage.c vs f_mass_storage.c
Why does one module work where the other does not? I began to look for some new tools to help me find out. The first tool I used was Intel’s USB Command Verifier, this utility lets you run a gamut of tests against your USB device, from the ones listed in Chapter 9 of the USB Spec to ones specific for MSDs. USB CV was incredibly frustrating to get going on my 64-bit system, the process looked like this:
- Install USB CV
- Reboot to disable driver-signing
- Manually install Intel EHCI debug driver due to bug in 64-bit version of USB CV
- Go find an AT keyboard/mouse because USB device signals are being hijacked
4 reboots later and I was in business. I ran the chapter 9 tests and the mass storage tests against both drivers. The chapter 9 test results were identical, the mass storage results were close to identical with the following discrepencies:
f_mass_storage
- Serial Number Test
- Invalid characters in Serial Number
- Test Case 4,8
- No stall after zero-length data
- Command Set Test
- No stall after zero-length data
- Power-Up Test
- Could not find device after enumeration
I should note that I also ran the Chapter 9 and mass storage tests against every USB mass storage device I own. 2 of the devices that work with my Xbox 360 failed the Serial Number Test. Also, I believe the Power-Up Test warning was triggered due to the amount of time it takes to plug-in the Pre and initiate mass storage mode. All-in-all, I didn’t find the smoking gun I was hoping for in these tests.
A New Goal
I have a working solution, but I don’t know why it works. My new goal is to provide a patch for f_mass_storage.c that will allow it to work with the Xbox 360. This means analyzing and understanding the changes between file_stoage.c and f_mass_storage.c.
Read all the answers in the finale.
Using the Palm Pre as Xbox 360 storage | Coding for Mobile Platforms said
[...] Continued in Part 2. [...]