From 8d82ddfcaf5a3e941106800eefeea1b9ebce4ec8 Mon Sep 17 00:00:00 2001 From: Linus Nielsen Feltzing Date: Sun, 30 Jun 2002 13:13:13 +0000 Subject: Even better USB support git-svn-id: svn://svn.rockbox.org/rockbox/trunk@1262 a1c6a512-1295-4272-9138-f99709370657 --- firmware/usb.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- firmware/usb.h | 2 + 2 files changed, 136 insertions(+), 12 deletions(-) diff --git a/firmware/usb.c b/firmware/usb.c index a3421c7d47..c6ae306218 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -22,6 +22,14 @@ #include "thread.h" #include "system.h" #include "debug.h" +#include "ata.h" +#include "fat.h" +#include "disk.h" +#include "panic.h" + + +#define USB_REALLY_BRAVE + #ifndef SIMULATOR @@ -30,7 +38,55 @@ static char usb_stack[0x100]; static struct event_queue usb_queue; -static bool usb_connected; +static bool last_usb_status; +static bool usb_monitor_enabled; + +static void usb_enable(bool on) +{ +#ifdef ARCHOS_RECORDER + if(!on) /* The pin is inverted on the Recorder */ +#else + if(on) +#endif + PADR &= ~0x400; /* enable USB */ + else + PADR |= 0x400; + PAIOR |= 0x400; +} + +static void usb_slave_mode(bool on) +{ + int rc; + struct partinfo* pinfo; + + if(on) + { + DEBUGF("Entering USB slave mode\n"); + ata_enable(false); + usb_enable(true); + } + else + { + DEBUGF("Leaving USB slave mode\n"); + + /* Let the ISDx00 settle */ + sleep(HZ*1); + + usb_enable(false); + + rc = ata_init(); + if(rc) + panicf("ata: %d",rc); + + pinfo = disk_init(); + if (!pinfo) + panicf("disk: NULL"); + + rc = fat_mount(pinfo[0].start); + if(rc) + panicf("mount: %d",rc); + } +} static void usb_thread(void) { @@ -50,7 +106,8 @@ static void usb_thread(void) We subtract one for our own thread. */ num_acks_to_expect = queue_broadcast(SYS_USB_CONNECTED, NULL) - 1; waiting_for_ack = true; - DEBUGF("USB inserted. Waiting for ack from %d threads...\n"); + DEBUGF("USB inserted. Waiting for ack from %d threads...\n", + num_acks_to_expect); break; case SYS_USB_CONNECTED_ACK: @@ -65,13 +122,43 @@ static void usb_thread(void) current firmware isn't quite ready for this yet. Let's just chicken out and reboot. */ DEBUGF("All threads have acknowledged. Rebooting...\n"); +#ifdef USB_REALLY_BRAVE + usb_slave_mode(true); +#else system_reboot(); +#endif } else { DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); } } + break; + + case USB_EXTRACTED: + /* Tell all threads that we are back in business */ + num_acks_to_expect = + queue_broadcast(SYS_USB_DISCONNECTED, NULL) - 1; + waiting_for_ack = true; + DEBUGF("USB extracted. Waiting for ack from %d threads...\n", + num_acks_to_expect); + break; + + case SYS_USB_DISCONNECTED_ACK: + if(waiting_for_ack) + { + num_acks_to_expect--; + if(num_acks_to_expect == 0) + { + DEBUGF("All threads have acknowledged. We're in business.\n"); + usb_slave_mode(false); + } + else + { + DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); + } + } + break; } } } @@ -80,16 +167,23 @@ static void usb_tick(void) { bool current_status; + if(usb_monitor_enabled) + { #ifdef ARCHOS_RECORDER - current_status = (PCDR & 0x04)?true:false; + current_status = (PCDR & 0x04)?true:false; #else - current_status = (PADR & 0x8000)?false:true; + current_status = (PADR & 0x8000)?false:true; #endif - - if(current_status && !usb_connected) - { - usb_connected = true; - queue_post(&usb_queue, USB_INSERTED, NULL); + + /* Only report when the status has changed */ + if(current_status != last_usb_status) + { + last_usb_status = current_status; + if(current_status) + queue_post(&usb_queue, USB_INSERTED, NULL); + else + queue_post(&usb_queue, USB_EXTRACTED, NULL); + } } } @@ -100,14 +194,38 @@ void usb_acknowledge(int id) void usb_init(void) { - int rc; + usb_monitor_enabled = false; - usb_connected = false; + usb_enable(false); + + /* We assume that the USB cable is extracted */ + last_usb_status = false; queue_init(&usb_queue); create_thread(usb_thread, usb_stack, sizeof(usb_stack)); - rc = tick_add_task(usb_tick); + tick_add_task(usb_tick); +} + +void usb_wait_for_disconnect(struct event_queue *q) +{ + struct event ev; + + /* Don't return until we get SYS_USB_DISCONNECTED */ + while(1) + { + queue_wait(q, &ev); + if(ev.id == SYS_USB_DISCONNECTED) + { + usb_acknowledge(SYS_USB_DISCONNECTED_ACK); + return; + } + } +} + +void usb_start_monitoring(void) +{ + usb_monitor_enabled = true; } #else @@ -122,4 +240,8 @@ void usb_init(void) { } +void usb_start_monitoring(void) +{ +} + #endif diff --git a/firmware/usb.h b/firmware/usb.h index de13f829c1..8775e672a4 100644 --- a/firmware/usb.h +++ b/firmware/usb.h @@ -20,6 +20,8 @@ #define _USB_H_ void usb_init(void); +void usb_start_monitoring(void); void usb_acknowledge(int id); +void usb_wait_for_disconnect(struct event_queue *q); #endif -- cgit v1.2.3