release
dev builds
extras
themes manual
wiki
device status forums
mailing lists
IRC bugs
patches
dev guide



Wiki > Main > RockboxUsbHandling (compare)

Difference: RockboxUsbHandling (r9 vs. r8)

USB handling in Rockbox

How Rockbox handles USB slave mode

General

Rockbox is designed for devices with a Universal Mass Storage USB connection. When the user inserts the USB cable, Rockbox should stop accessing the hard drive and enter USB Mode. When the user extracts the cable, Rockbox should continue as normal.

The USB thread

There is a dedicated thread that monitors the USB connector and waits for a connection. When it happens, it tells the other threads to stop the disk activity and report back when they are ready. When all threads have responded, the USB thread grants the USB chip control of the hard drive, and waits until the USB connector is extracted. It then tells all threads that it is permitted to access the HD again.

The signalling mechanism

The USB thread uses the queue_broadcast() function to signal the other threads. This means that threads that don't have an event queue will not be notified.

The USB thread will not enter USB mode until all threads are ready.

digraph G { graph [bgcolor="#b6c6e5"]; usb -> t1 [label="SYS_USB_CONNECTED" fontsize=6]; usb -> t2 [label="SYS_USB_CONNECTED" fontsize=6]; usb -> t3 [label="SYS_USB_CONNECTED" fontsize=6]; }

Step 1: The USB thread sends SYS_USB_CONNECTED to all threads

digraph G { graph [bgcolor="#b6c6e5"]; usb -> t1 [dir="back" label="SYS_USB_CONNECTED_ACK" fontsize=6]; usb -> t2 [dir="back" label="SYS_USB_CONNECTED_ACK" fontsize=6]; usb -> t3 [dir="back" label="SYS_USB_CONNECTED_ACK" fontsize=6]; }

Step 2: All threads reply with SYS_USB_CONNECTED_ACK

The SYS_USB events

EventDescription
SYS_USB_CONNECTED This is sent to all threads when the USB cable is connected
SYS_USB_CONNECTED_ACK This is sent by a thread as a reply to SYS_USB_CONNECTED when the thread is ready to enter USB mode
SYS_USB_DISCONNECTED This is sent to all threads when the USB cable is disconnected
SYS_USB_DISCONNECTED_ACK This is sent by a thread as a reply to SYS_USB_DISCONNECTED when the thread is ready to leave USB mode

Helper functions

There are two functions that can handle this for you. Use them.

void usb_acknowledge(long id)

Call this to send an acknowledge to a USB event. Example:

usb_acknowledge(SYS_USB_CONNECTED_ACK);

void usb_wait_for_disconnect(struct event_queue *q)

Call this to wait until the USB thread sends the SYS_USB_DISCONNECTED event. This function also sends the SYS_USB_DISCONNECTED_ACK event for you. Pass a pointer to your event queue.

usb_wait_for_disconnect(&my_queue);

int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)

Same as above, but you can specify a timeout where the function returns even if the USB connection is still active. The return value is 1 if there was a timeout, and 0 if the USB was disconnected.

Example

If you decide that your thread should respond to USB events, do like this:

static struct event_queue my_queue;

void my_thread(void)
{
    struct event ev;

   while(1) {
      queue_wait_w_tmo(&my_queue, &ev, 0);

      switch(ev.id) {
      case SYS_USB_CONNECTED:
         /* Do cleanup, like closing open files */
         usb_acknowledge(SYS_USB_CONNECTED_ACK);

         /* Wait until the USB cable is extracted again */
         usb_wait_for_disconnect(&my_queue);
         break;
      }
   }
}

Special case: the main thread

The main thread is responsible for displaying the "USB Connected" screen while in USB mode. Therefore, the main thread should do it differently. The SYS_USB_CONNECTED event is received in the button queue (which is a regular event queue), so you have to handle it in your button event handler. For your convenience, there is a function that handles all this for you, the default event handler.

Just call the default event handler in the default case of your switch. It returns the event that was handled if you need to know, for example if you want to quit the function if it has been in USB mode.

Example

while (!exit) {
        key = button_get();
        switch( key ) {
        case BUTTON_STOP:
            exit = true;
            break;

        default:
            if(default_event_handler(key) == SYS_USB_CONNECTED) {
                return MYFUNC_ATTACHED_USB;
            }
            break;
        }
    }

r10 - 14 Nov 2010 - 01:02:36 - FredBauer

Revision r9 - 13 Oct 2009 - 15:09 - RafaelCarre
Revision r8 - 13 Oct 2009 - 14:47 - PhilipBarton
Copyright by the contributing authors.