From f18d20ee36f8a23e0f37fd342cf186e3b6a91408 Mon Sep 17 00:00:00 2001 From: Frank Gevaerts Date: Sun, 2 Mar 2008 00:15:02 +0000 Subject: Only show the usb screen once a real usb connection is established. In case other threads are slow in acknowledging the SYS_USB_CONNECTED message, tell the OS that the disk is not ready yet (the OS interprets this as "spinning up") git-svn-id: svn://svn.rockbox.org/rockbox/trunk@16471 a1c6a512-1295-4272-9138-f99709370657 --- firmware/export/usb.h | 3 +++ firmware/usb.c | 59 ++++++++++++++++++++++++++++++++++------- firmware/usbstack/usb_core.c | 4 +++ firmware/usbstack/usb_storage.c | 42 ++++++++++++++++++++++++----- 4 files changed, 92 insertions(+), 16 deletions(-) diff --git a/firmware/export/usb.h b/firmware/export/usb.h index 4bfbfd4b75..833d2ab35e 100644 --- a/firmware/export/usb.h +++ b/firmware/export/usb.h @@ -29,6 +29,7 @@ enum { USB_REENABLE, USB_POWERED, USB_TRANSFER_COMPLETION, + USB_REQUEST_DISK, USB_REQUEST_REBOOT }; @@ -102,6 +103,8 @@ bool usb_charging_enabled(void); #ifdef HAVE_USBSTACK void usb_signal_transfer_completion(struct usb_transfer_completion_event_data* event_data); bool usb_driver_enabled(int driver); +bool usb_exclusive_ata(void); /* ata is available for usb */ +void usb_request_exclusive_ata(void); #endif #if defined(IPOD_COLOR) || defined(IPOD_4G) \ diff --git a/firmware/usb.c b/firmware/usb.c index 07d2c5890c..d9c13dffdf 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -73,6 +73,7 @@ static struct thread_entry *usb_thread_entry; static struct event_queue usb_queue; static int last_usb_status; static bool usb_monitor_enabled; +static bool exclusive_disk; #if defined(IPOD_COLOR) || defined(IPOD_4G) \ @@ -197,6 +198,16 @@ static void usb_thread(void) else #endif { +#ifdef HAVE_USBSTACK +#ifdef USE_ROCKBOX_USB + usb_core_enable_protocol(USB_DRIVER_MASS_STORAGE,true); + usb_core_enable_protocol(USB_DRIVER_SERIAL,false);/* TODO: add debug setting */ + usb_core_enable_protocol(USB_DRIVER_CHARGING_ONLY,false); + usb_enable(true); +#else + usb_request_exclusive_ata(); +#endif /* USE_ROCKBOX_USB */ +#else /* Tell all threads that they have to back off the ATA. We subtract one for our own thread. */ num_acks_to_expect = @@ -204,9 +215,23 @@ static void usb_thread(void) waiting_for_ack = true; DEBUGF("USB inserted. Waiting for ack from %d threads...\n", num_acks_to_expect); +#endif } break; - +#ifdef HAVE_USBSTACK + case USB_REQUEST_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_CONNECTED, 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) { @@ -215,25 +240,22 @@ static void usb_thread(void) { DEBUGF("All threads have acknowledged the connect.\n"); #ifdef HAVE_USBSTACK -#ifdef HAVE_PRIORITY_SCHEDULING - thread_set_priority(usb_thread_entry,PRIORITY_REALTIME); -#endif -#ifdef USE_ROCKBOX_USB - usb_core_enable_protocol(USB_DRIVER_MASS_STORAGE,true); - usb_core_enable_protocol(USB_DRIVER_SERIAL,false);/* TODO: add debug setting */ - usb_core_enable_protocol(USB_DRIVER_CHARGING_ONLY,false); - usb_enable(true); -#else /* USE_ROCKBOX_USB */ +#ifndef USE_ROCKBOX_USB /* until we have native mass-storage mode, we want to reboot on usb host connect */ try_reboot(); #endif /* USE_ROCKBOX_USB */ +#ifdef HAVE_PRIORITY_SCHEDULING + thread_set_priority(usb_thread_entry,PRIORITY_REALTIME); + exclusive_disk = true; +#endif #else usb_slave_mode(true); cpu_idle_mode(true); #endif usb_state = USB_INSERTED; + waiting_for_ack = false; } else { @@ -246,6 +268,7 @@ static void usb_thread(void) case USB_EXTRACTED: #ifdef HAVE_USBSTACK usb_enable(false); + exclusive_disk = false; #ifdef HAVE_PRIORITY_SCHEDULING thread_set_priority(usb_thread_entry,PRIORITY_SYSTEM); #endif @@ -290,6 +313,7 @@ static void usb_thread(void) { DEBUGF("All threads have acknowledged. " "We're in business.\n"); + waiting_for_ack = false; } else { @@ -403,6 +427,7 @@ void usb_acknowledge(long id) void usb_init(void) { usb_state = USB_EXTRACTED; + exclusive_disk = false; usb_monitor_enabled = false; countdown = -1; @@ -481,6 +506,20 @@ bool usb_inserted(void) #endif } +#ifdef HAVE_USBSTACK +void usb_request_exclusive_ata(void) +{ + if(!exclusive_disk) { + queue_post(&usb_queue, USB_REQUEST_DISK, 0); + } +} + +bool usb_exclusive_ata(void) +{ + return exclusive_disk; +} +#endif + #ifdef HAVE_USB_POWER bool usb_powered(void) { diff --git a/firmware/usbstack/usb_core.c b/firmware/usbstack/usb_core.c index aa0f06e4f6..f40d76bee0 100644 --- a/firmware/usbstack/usb_core.c +++ b/firmware/usbstack/usb_core.c @@ -460,6 +460,10 @@ static void usb_core_control_request_handler(struct usb_ctrlrequest* req) { if(usb_state == DEFAULT) { set_serial_descriptor(); +#ifdef USB_STORAGE + if(usb_core_storage_enabled) + usb_request_exclusive_ata(); +#endif } #ifdef USB_BENCHMARK diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c index 73464cf608..bde774e5f0 100644 --- a/firmware/usbstack/usb_storage.c +++ b/firmware/usbstack/usb_storage.c @@ -80,6 +80,8 @@ #define ASC_LBA_OUT_OF_RANGE 0x21 #define ASC_WRITE_ERROR 0x0C #define ASC_READ_ERROR 0x11 +#define ASC_NOT_READY 0x04 +#define ASCQ_BECOMING_READY 0x01 #define SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA 0x02000000 @@ -207,6 +209,7 @@ static struct { unsigned char sense_key; unsigned char information; unsigned char asc; + unsigned char ascq; } cur_sense_data; static void handle_scsi(struct command_block_wrapper* cbw); @@ -228,10 +231,6 @@ static enum { /* called by usb_code_init() */ void usb_storage_init(void) { - size_t bufsize; - unsigned char * audio_buffer = audio_get_buffer(false,&bufsize); - /* TODO : check if bufsize is at least 32K ? */ - tb.transfer_buffer = (void *)UNCACHED_ADDR((unsigned int)(audio_buffer + 31) & 0xffffffe0); logf("usb_storage_init done"); } @@ -270,6 +269,7 @@ void usb_storage_transfer_complete(bool in,int status,int length) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_MEDIUM_ERROR; cur_sense_data.asc=ASC_WRITE_ERROR; + cur_sense_data.ascq=0; break; } @@ -291,6 +291,7 @@ void usb_storage_transfer_complete(bool in,int status,int length) cur_sense_data.sense_key=0; cur_sense_data.information=0; cur_sense_data.asc=0; + cur_sense_data.ascq=0; } break; case WAITING_FOR_COMMAND: @@ -329,6 +330,7 @@ void usb_storage_transfer_complete(bool in,int status,int length) cur_sense_data.sense_key=0; cur_sense_data.information=0; cur_sense_data.asc=0; + cur_sense_data.ascq=0; } break; case SENDING_BLOCKS: @@ -351,6 +353,7 @@ void usb_storage_transfer_complete(bool in,int status,int length) cur_sense_data.sense_key=0; cur_sense_data.information=0; cur_sense_data.asc=0; + cur_sense_data.ascq=0; } break; } @@ -390,13 +393,20 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req) handled = true; break; - case USB_REQ_SET_CONFIGURATION: + case USB_REQ_SET_CONFIGURATION: { + size_t bufsize; + unsigned char * audio_buffer; logf("ums: set config"); /* prime rx endpoint. We only need room for commands */ state = WAITING_FOR_COMMAND; + + /* TODO : check if bufsize is at least 32K ? */ + audio_buffer = audio_get_buffer(false,&bufsize); + tb.transfer_buffer = (void *)UNCACHED_ADDR((unsigned int)(audio_buffer + 31) & 0xffffffe0); usb_drv_recv(EP_MASS_STORAGE, tb.transfer_buffer, 1024); handled = true; break; + } } return handled; @@ -409,6 +419,7 @@ static void send_and_read_next(void) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_MEDIUM_ERROR; cur_sense_data.asc=ASC_READ_ERROR; + cur_sense_data.ascq=0; return; } send_block_data(current_cmd.data[current_cmd.data_select], @@ -472,6 +483,13 @@ static void handle_scsi(struct command_block_wrapper* cbw) switch (cbw->command_block[0]) { case SCSI_TEST_UNIT_READY: logf("scsi test_unit_ready %d",lun); + 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; + break; + } if(lun_present) { send_csw(UMS_STATUS_GOOD); } @@ -479,6 +497,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; } break; @@ -516,7 +535,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) tb.sense_data->AdditionalSenseLength=10; tb.sense_data->CommandSpecificInformation=0; tb.sense_data->AdditionalSenseCode=cur_sense_data.asc; - tb.sense_data->AdditionalSenseCodeQualifier=0; + tb.sense_data->AdditionalSenseCodeQualifier=cur_sense_data.ascq; tb.sense_data->FieldReplaceableUnitCode=0; tb.sense_data->SKSV=0; tb.sense_data->SenseKeySpecific=0; @@ -531,6 +550,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; break; } /*unsigned char pc = (cbw->command_block[2] & 0xc0) >>6;*/ @@ -563,6 +583,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD; + cur_sense_data.ascq=0; break; } break; @@ -573,6 +594,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; break; } /*unsigned char pc = (cbw->command_block[2] & 0xc0) >>6;*/ @@ -608,6 +630,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; cur_sense_data.asc=ASC_INVALID_FIELD_IN_CBD; + cur_sense_data.ascq=0; break; } break; @@ -641,6 +664,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; } break; } @@ -660,6 +684,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; } break; } @@ -671,6 +696,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; break; } current_cmd.data[0] = tb.transfer_buffer; @@ -692,6 +718,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; + cur_sense_data.ascq=0; } else { current_cmd.last_result = ata_read_sectors(IF_MV2(current_cmd.lun,) current_cmd.sector, @@ -708,6 +735,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_NOT_READY; cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT; + cur_sense_data.ascq=0; break; } current_cmd.data[0] = tb.transfer_buffer; @@ -727,6 +755,7 @@ static void handle_scsi(struct command_block_wrapper* cbw) send_csw(UMS_STATUS_FAIL); cur_sense_data.sense_key=SENSE_ILLEGAL_REQUEST; cur_sense_data.asc=ASC_LBA_OUT_OF_RANGE; + cur_sense_data.ascq=0; } else { receive_block_data(current_cmd.data[0], @@ -776,6 +805,7 @@ static void send_csw(int status) cur_sense_data.sense_key=0; cur_sense_data.information=0; cur_sense_data.asc=0; + cur_sense_data.ascq=0; } } -- cgit v1.2.3