From 745133014e6161c4d8c7a7eab137b7d9b1174c55 Mon Sep 17 00:00:00 2001 From: Frank Gevaerts Date: Mon, 10 Mar 2008 20:55:24 +0000 Subject: make the usb storage driver handle hotswap correctly, and exit the usb screen once all drives are "ejected" (either as a command from the OS or physically) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16617 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/usb.h | 2 + firmware/export/usb_core.h | 5 ++- firmware/usb.c | 44 ++++++++++++++---- firmware/usbstack/usb_class_driver.h | 6 +++ firmware/usbstack/usb_core.c | 29 ++++++++++-- firmware/usbstack/usb_storage.c | 86 +++++++++++++++++++++++++++++------- firmware/usbstack/usb_storage.h | 5 +++ 7 files changed, 148 insertions(+), 29 deletions(-) diff --git a/firmware/export/usb.h b/firmware/export/usb.h index 4dae7c2e68..a80dd82667 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -30,6 +30,7 @@ enum { USB_POWERED, USB_TRANSFER_COMPLETION, USB_REQUEST_DISK, + USB_RELEASE_DISK, USB_REQUEST_REBOOT }; @@ -105,6 +106,7 @@ void usb_signal_transfer_completion(struct usb_transfer_completion_event_data* e bool usb_driver_enabled(int driver); bool usb_exclusive_ata(void); /* ata is available for usb */ void usb_request_exclusive_ata(void); +void usb_release_exclusive_ata(void); #endif #if defined(IPOD_COLOR) || defined(IPOD_4G) \ diff --git a/firmware/export/usb_core.h b/firmware/export/usb_core.h index a1701bc3f8..fd55ac8782 100644 --- a/firmware/export/usb_core.h +++ b/firmware/export/usb_core.h @@ -21,7 +21,7 @@ #ifndef BOOTLOADER -//#define USB_SERIAL +#define USB_SERIAL #define USB_STORAGE #define USB_CHARGING_ONLY #else /* BOOTLOADER */ @@ -47,5 +47,8 @@ void usb_core_enable_driver(int driver,bool enabled); bool usb_core_driver_enabled (int driver); void usb_core_handle_transfer_completion( struct usb_transfer_completion_event_data* event); +#ifdef HAVE_HOTSWAP +void usb_core_hotswap_event(int volume,bool inserted); +#endif #endif diff --git a/firmware/usb.c b/firmware/usb.c index d59cbc3d15..7c43a8ba90 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -227,6 +227,18 @@ static void usb_thread(void) num_acks_to_expect); } break; + case USB_RELEASE_DISK: + if(!waiting_for_ack) + { + /* Tell all threads that they have to back off the ATA. + We subtract one for our own thread. */ + num_acks_to_expect = + queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1; + waiting_for_ack = true; + DEBUGF("USB inserted. Waiting for ack from %d threads...\n", + num_acks_to_expect); + } + break; #endif case SYS_USB_CONNECTED_ACK: if(waiting_for_ack) @@ -264,7 +276,6 @@ static void usb_thread(void) case USB_EXTRACTED: #ifdef HAVE_USBSTACK usb_enable(false); - exclusive_ata_access = false; #ifdef HAVE_PRIORITY_SCHEDULING thread_set_priority(usb_thread_entry,PRIORITY_SYSTEM); #endif @@ -292,13 +303,16 @@ static void usb_thread(void) #endif usb_state = USB_EXTRACTED; - - /* Tell all threads that we are back in business */ - num_acks_to_expect = - queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1; - waiting_for_ack = true; - DEBUGF("USB extracted. Waiting for ack from %d threads...\n", - num_acks_to_expect); + if(exclusive_ata_access) + { + exclusive_ata_access = false; + /* Tell all threads that we are back in business */ + num_acks_to_expect = + queue_broadcast(SYS_USB_DISCONNECTED, 0) - 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: @@ -319,15 +333,19 @@ static void usb_thread(void) } break; -#ifdef HAVE_MMC +#ifdef HAVE_HOTSWAP case SYS_HOTSWAP_INSERTED: case SYS_HOTSWAP_EXTRACTED: +#ifdef HAVE_USBSTACK + usb_core_hotswap_event(1,ev.id == SYS_HOTSWAP_INSERTED); +#else if(usb_state == USB_INSERTED) { usb_enable(false); usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */ } break; +#endif case USB_REENABLE: if(usb_state == USB_INSERTED) @@ -512,6 +530,14 @@ void usb_request_exclusive_ata(void) } } +void usb_release_exclusive_ata(void) +{ + if(exclusive_ata_access) { + queue_post(&usb_queue, USB_RELEASE_DISK, 0); + exclusive_ata_access = false; + } +} + bool usb_exclusive_ata(void) { return exclusive_ata_access; diff --git a/firmware/usbstack/usb_class_driver.h b/firmware/usbstack/usb_class_driver.h index 631d5a3bc1..beeec86fb7 100644 --- a/firmware/usbstack/usb_class_driver.h +++ b/firmware/usbstack/usb_class_driver.h @@ -54,6 +54,12 @@ struct usb_class_driver { able to handle it, it should ack the request, and return true. Otherwise it should return false. */ bool (*control_request)(struct usb_ctrlrequest* req); + +#ifdef HAVE_HOTSWAP + /* Tells the driver that a hotswappable disk/card was inserted or + extracted */ + void (*notify_hotswap)(int volume, bool inserted); +#endif }; #endif diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index e0aaa9b2f4..aa4686500d 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -199,7 +199,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] = .init = usb_storage_init, .disconnect = NULL, .transfer_complete = usb_storage_transfer_complete, - .control_request = usb_storage_control_request + .control_request = usb_storage_control_request, +#ifdef HAVE_HOTSWAP + .notify_hotswap = usb_storage_notify_hotswap, +#endif }, #endif #ifdef USB_SERIAL @@ -213,7 +216,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] = .init = usb_serial_init, .disconnect = usb_serial_disconnect, .transfer_complete = usb_serial_transfer_complete, - .control_request = usb_serial_control_request + .control_request = usb_serial_control_request, +#ifdef HAVE_HOTSWAP + .notify_hotswap = NULL, +#endif }, #endif #ifdef USB_CHARGING_ONLY @@ -227,7 +233,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] = .init = NULL, .disconnect = NULL, .transfer_complete = NULL, - .control_request = NULL + .control_request = NULL, +#ifdef HAVE_HOTSWAP + .notify_hotswap = NULL, +#endif }, #endif }; @@ -386,6 +395,20 @@ bool usb_core_driver_enabled(int driver) return drivers[driver].enabled; } +#ifdef HAVE_HOTSWAP +void usb_core_hotswap_event(int volume,bool inserted) +{ + int i; + for(i=0;idata_transfer_length; - unsigned int block_size; - unsigned int block_count; + unsigned int block_size = 0; + unsigned int block_count = 0; bool lun_present=true; #ifdef ONLY_EXPOSE_CARD_SLOT unsigned char lun = cbw->lun+1; @@ -536,9 +586,8 @@ static void handle_scsi(struct command_block_wrapper* cbw) block_count = cinfo->numblocks; } else { - lun_present=false; - block_size = 0; - block_count = 0; + ejected[lun] = true; + try_release_ata(); } #else unsigned short* identify = ata_get_identify(); @@ -562,8 +611,8 @@ static void handle_scsi(struct command_block_wrapper* cbw) if(!usb_exclusive_ata()) { send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; - cur_sense_data.asc=ASC_NOT_READY; - cur_sense_data.ascq=ASCQ_BECOMING_READY; + cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; break; } if(lun_present) { @@ -732,12 +781,17 @@ static void handle_scsi(struct command_block_wrapper* cbw) case SCSI_START_STOP_UNIT: logf("scsi start_stop unit %d",lun); - if((cbw->command_block[4] & 0xf0) == 0) + if((cbw->command_block[4] & 0xf0) == 0) /*load/eject bit is valid*/ { /* Process start and eject bits */ - if((cbw->command_block[4] & 0x01) == 0 && - (cbw->command_block[4] & 0x02) != 0) /* Stop and eject */ + logf("scsi load/eject"); + if((cbw->command_block[4] & 0x01) == 0) /* Don't start */ { - ejected[lun]=true; + if((cbw->command_block[4] & 0x02) != 0) /* eject */ + { + logf("scsi eject"); + ejected[lun]=true; + try_release_ata(); + } } } send_csw(UMS_STATUS_GOOD); @@ -828,7 +882,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) cur_cmd.sector, MIN(BUFFER_SIZE/SECTOR_SIZE, - cur_cmd.count), + cur_cmd.count), cur_cmd.data[cur_cmd.data_select]); send_and_read_next(); } diff --git a/firmware/usbstack/usb_storage.h b/firmware/usbstack/usb_storage.h index 34bc0144dd..40f8ed9248 100644 --- a/firmware/usbstack/usb_storage.h +++ b/firmware/usbstack/usb_storage.h @@ -27,6 +27,11 @@ void usb_storage_init_connection(int interface,int endpoint); void usb_storage_init(void); void usb_storage_transfer_complete(bool in,int state,int length); bool usb_storage_control_request(struct usb_ctrlrequest* req); +#ifdef HAVE_HOTSWAP +void usb_storage_notify_hotswap(int volume,bool inserted); +#endif + +void usb_storage_reconnect(void); #endif -- cgit v1.2.3