summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2008-03-10 20:55:24 +0000
committerFrank Gevaerts <frank@gevaerts.be>2008-03-10 20:55:24 +0000
commit745133014e6161c4d8c7a7eab137b7d9b1174c55 (patch)
tree0731cf8a30b17dae164e4240e48b28782cdf5a06
parent9d32b6aa1776db210d5c01589704a65238240df2 (diff)
downloadrockbox-745133014e6161c4d8c7a7eab137b7d9b1174c55.tar.gz
rockbox-745133014e6161c4d8c7a7eab137b7d9b1174c55.zip
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
-rw-r--r--firmware/export/usb.h2
-rw-r--r--firmware/export/usb_core.h5
-rw-r--r--firmware/usb.c44
-rw-r--r--firmware/usbstack/usb_class_driver.h6
-rw-r--r--firmware/usbstack/usb_core.c29
-rw-r--r--firmware/usbstack/usb_storage.c86
-rw-r--r--firmware/usbstack/usb_storage.h5
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 {
30 USB_POWERED, 30 USB_POWERED,
31 USB_TRANSFER_COMPLETION, 31 USB_TRANSFER_COMPLETION,
32 USB_REQUEST_DISK, 32 USB_REQUEST_DISK,
33 USB_RELEASE_DISK,
33 USB_REQUEST_REBOOT 34 USB_REQUEST_REBOOT
34}; 35};
35 36
@@ -105,6 +106,7 @@ void usb_signal_transfer_completion(struct usb_transfer_completion_event_data* e
105bool usb_driver_enabled(int driver); 106bool usb_driver_enabled(int driver);
106bool usb_exclusive_ata(void); /* ata is available for usb */ 107bool usb_exclusive_ata(void); /* ata is available for usb */
107void usb_request_exclusive_ata(void); 108void usb_request_exclusive_ata(void);
109void usb_release_exclusive_ata(void);
108#endif 110#endif
109 111
110#if defined(IPOD_COLOR) || defined(IPOD_4G) \ 112#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 @@
21 21
22#ifndef BOOTLOADER 22#ifndef BOOTLOADER
23 23
24//#define USB_SERIAL 24#define USB_SERIAL
25#define USB_STORAGE 25#define USB_STORAGE
26#define USB_CHARGING_ONLY 26#define USB_CHARGING_ONLY
27#else /* BOOTLOADER */ 27#else /* BOOTLOADER */
@@ -47,5 +47,8 @@ void usb_core_enable_driver(int driver,bool enabled);
47bool usb_core_driver_enabled (int driver); 47bool usb_core_driver_enabled (int driver);
48void usb_core_handle_transfer_completion( 48void usb_core_handle_transfer_completion(
49 struct usb_transfer_completion_event_data* event); 49 struct usb_transfer_completion_event_data* event);
50#ifdef HAVE_HOTSWAP
51void usb_core_hotswap_event(int volume,bool inserted);
52#endif
50#endif 53#endif
51 54
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)
227 num_acks_to_expect); 227 num_acks_to_expect);
228 } 228 }
229 break; 229 break;
230 case USB_RELEASE_DISK:
231 if(!waiting_for_ack)
232 {
233 /* Tell all threads that they have to back off the ATA.
234 We subtract one for our own thread. */
235 num_acks_to_expect =
236 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
237 waiting_for_ack = true;
238 DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
239 num_acks_to_expect);
240 }
241 break;
230#endif 242#endif
231 case SYS_USB_CONNECTED_ACK: 243 case SYS_USB_CONNECTED_ACK:
232 if(waiting_for_ack) 244 if(waiting_for_ack)
@@ -264,7 +276,6 @@ static void usb_thread(void)
264 case USB_EXTRACTED: 276 case USB_EXTRACTED:
265#ifdef HAVE_USBSTACK 277#ifdef HAVE_USBSTACK
266 usb_enable(false); 278 usb_enable(false);
267 exclusive_ata_access = false;
268#ifdef HAVE_PRIORITY_SCHEDULING 279#ifdef HAVE_PRIORITY_SCHEDULING
269 thread_set_priority(usb_thread_entry,PRIORITY_SYSTEM); 280 thread_set_priority(usb_thread_entry,PRIORITY_SYSTEM);
270#endif 281#endif
@@ -292,13 +303,16 @@ static void usb_thread(void)
292#endif 303#endif
293 304
294 usb_state = USB_EXTRACTED; 305 usb_state = USB_EXTRACTED;
295 306 if(exclusive_ata_access)
296 /* Tell all threads that we are back in business */ 307 {
297 num_acks_to_expect = 308 exclusive_ata_access = false;
298 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1; 309 /* Tell all threads that we are back in business */
299 waiting_for_ack = true; 310 num_acks_to_expect =
300 DEBUGF("USB extracted. Waiting for ack from %d threads...\n", 311 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
301 num_acks_to_expect); 312 waiting_for_ack = true;
313 DEBUGF("USB extracted. Waiting for ack from %d threads...\n",
314 num_acks_to_expect);
315 }
302 break; 316 break;
303 317
304 case SYS_USB_DISCONNECTED_ACK: 318 case SYS_USB_DISCONNECTED_ACK:
@@ -319,15 +333,19 @@ static void usb_thread(void)
319 } 333 }
320 break; 334 break;
321 335
322#ifdef HAVE_MMC 336#ifdef HAVE_HOTSWAP
323 case SYS_HOTSWAP_INSERTED: 337 case SYS_HOTSWAP_INSERTED:
324 case SYS_HOTSWAP_EXTRACTED: 338 case SYS_HOTSWAP_EXTRACTED:
339#ifdef HAVE_USBSTACK
340 usb_core_hotswap_event(1,ev.id == SYS_HOTSWAP_INSERTED);
341#else
325 if(usb_state == USB_INSERTED) 342 if(usb_state == USB_INSERTED)
326 { 343 {
327 usb_enable(false); 344 usb_enable(false);
328 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */ 345 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
329 } 346 }
330 break; 347 break;
348#endif
331 349
332 case USB_REENABLE: 350 case USB_REENABLE:
333 if(usb_state == USB_INSERTED) 351 if(usb_state == USB_INSERTED)
@@ -512,6 +530,14 @@ void usb_request_exclusive_ata(void)
512 } 530 }
513} 531}
514 532
533void usb_release_exclusive_ata(void)
534{
535 if(exclusive_ata_access) {
536 queue_post(&usb_queue, USB_RELEASE_DISK, 0);
537 exclusive_ata_access = false;
538 }
539}
540
515bool usb_exclusive_ata(void) 541bool usb_exclusive_ata(void)
516{ 542{
517 return exclusive_ata_access; 543 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 {
54 able to handle it, it should ack the request, and return true. Otherwise 54 able to handle it, it should ack the request, and return true. Otherwise
55 it should return false. */ 55 it should return false. */
56 bool (*control_request)(struct usb_ctrlrequest* req); 56 bool (*control_request)(struct usb_ctrlrequest* req);
57
58#ifdef HAVE_HOTSWAP
59 /* Tells the driver that a hotswappable disk/card was inserted or
60 extracted */
61 void (*notify_hotswap)(int volume, bool inserted);
62#endif
57}; 63};
58 64
59#endif 65#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] =
199 .init = usb_storage_init, 199 .init = usb_storage_init,
200 .disconnect = NULL, 200 .disconnect = NULL,
201 .transfer_complete = usb_storage_transfer_complete, 201 .transfer_complete = usb_storage_transfer_complete,
202 .control_request = usb_storage_control_request 202 .control_request = usb_storage_control_request,
203#ifdef HAVE_HOTSWAP
204 .notify_hotswap = usb_storage_notify_hotswap,
205#endif
203 }, 206 },
204#endif 207#endif
205#ifdef USB_SERIAL 208#ifdef USB_SERIAL
@@ -213,7 +216,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
213 .init = usb_serial_init, 216 .init = usb_serial_init,
214 .disconnect = usb_serial_disconnect, 217 .disconnect = usb_serial_disconnect,
215 .transfer_complete = usb_serial_transfer_complete, 218 .transfer_complete = usb_serial_transfer_complete,
216 .control_request = usb_serial_control_request 219 .control_request = usb_serial_control_request,
220#ifdef HAVE_HOTSWAP
221 .notify_hotswap = NULL,
222#endif
217 }, 223 },
218#endif 224#endif
219#ifdef USB_CHARGING_ONLY 225#ifdef USB_CHARGING_ONLY
@@ -227,7 +233,10 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
227 .init = NULL, 233 .init = NULL,
228 .disconnect = NULL, 234 .disconnect = NULL,
229 .transfer_complete = NULL, 235 .transfer_complete = NULL,
230 .control_request = NULL 236 .control_request = NULL,
237#ifdef HAVE_HOTSWAP
238 .notify_hotswap = NULL,
239#endif
231 }, 240 },
232#endif 241#endif
233}; 242};
@@ -386,6 +395,20 @@ bool usb_core_driver_enabled(int driver)
386 return drivers[driver].enabled; 395 return drivers[driver].enabled;
387} 396}
388 397
398#ifdef HAVE_HOTSWAP
399void usb_core_hotswap_event(int volume,bool inserted)
400{
401 int i;
402 for(i=0;i<USB_NUM_DRIVERS;i++) {
403 if(drivers[i].enabled &&
404 drivers[i].notify_hotswap!=NULL)
405 {
406 drivers[i].notify_hotswap(volume,inserted);
407 }
408 }
409}
410#endif
411
389static void usb_core_set_serial_function_id(void) 412static void usb_core_set_serial_function_id(void)
390{ 413{
391 int id = 0; 414 int id = 0;
diff --git a/firmware/usbstack/usb_storage.c b/firmware/usbstack/usb_storage.c
index 58578d958b..06d999d6de 100644
--- a/firmware/usbstack/usb_storage.c
+++ b/firmware/usbstack/usb_storage.c
@@ -262,15 +262,65 @@ static enum {
262 SENDING_CSW 262 SENDING_CSW
263} state = WAITING_FOR_COMMAND; 263} state = WAITING_FOR_COMMAND;
264 264
265static bool check_disk_present(int volume)
266{
267 unsigned char sector[512];
268 return ata_read_sectors(IF_MV2(volume,)0,1,sector) == 0;
269}
270
271static void try_release_ata(void)
272{
273 /* Check if there is a connected drive left. If not,
274 release excusive access */
275 bool canrelease=true;
276 int i;
277 for(i=0;i<NUM_VOLUMES;i++) {
278 if(ejected[i]==false){
279 canrelease=false;
280 break;
281 }
282 }
283 if(canrelease) {
284 logf("scsi release ata");
285 usb_release_exclusive_ata();
286 }
287}
288
289#ifdef HAVE_HOTSWAP
290void usb_storage_notify_hotswap(int volume,bool inserted)
291{
292 logf("notify %d",inserted);
293 if(inserted && check_disk_present(volume)) {
294 ejected[volume] = false;
295 }
296 else {
297 ejected[volume] = true;
298 try_release_ata();
299 }
300
301}
302#endif
303
304void usb_storage_reconnect(void)
305{
306 int i;
307 for(i=0;i<NUM_VOLUMES;i++)
308 ejected[i] = !check_disk_present(i);
309
310 usb_request_exclusive_ata();
311}
312
265/* called by usb_code_init() */ 313/* called by usb_code_init() */
266void usb_storage_init(void) 314void usb_storage_init(void)
267{ 315{
268 int i; 316 int i;
269 for(i=0;i<NUM_VOLUMES;i++) 317 for(i=0;i<NUM_VOLUMES;i++) {
270 ejected[i]=false; 318 ejected[i] = !check_disk_present(i);
319 }
271 logf("usb_storage_init done"); 320 logf("usb_storage_init done");
272} 321}
273 322
323
274int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size, 324int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size,
275 int interface_number,int endpoint) 325 int interface_number,int endpoint)
276{ 326{
@@ -348,7 +398,7 @@ void usb_storage_transfer_complete(bool in,int status,int length)
348 int result = ata_write_sectors(IF_MV2(cur_cmd.lun,) 398 int result = ata_write_sectors(IF_MV2(cur_cmd.lun,)
349 cur_cmd.sector, 399 cur_cmd.sector,
350 MIN(BUFFER_SIZE/SECTOR_SIZE, 400 MIN(BUFFER_SIZE/SECTOR_SIZE,
351 cur_cmd.count), 401 cur_cmd.count),
352 cur_cmd.data[cur_cmd.data_select]); 402 cur_cmd.data[cur_cmd.data_select]);
353 if(result != 0) { 403 if(result != 0) {
354 send_csw(UMS_STATUS_FAIL); 404 send_csw(UMS_STATUS_FAIL);
@@ -508,7 +558,7 @@ static void send_and_read_next(void)
508 cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) 558 cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,)
509 cur_cmd.sector, 559 cur_cmd.sector,
510 MIN(BUFFER_SIZE/SECTOR_SIZE, 560 MIN(BUFFER_SIZE/SECTOR_SIZE,
511 cur_cmd.count), 561 cur_cmd.count),
512 cur_cmd.data[cur_cmd.data_select]); 562 cur_cmd.data[cur_cmd.data_select]);
513 } 563 }
514} 564}
@@ -520,8 +570,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
520 TODO: support 48-bit LBA */ 570 TODO: support 48-bit LBA */
521 571
522 unsigned int length = cbw->data_transfer_length; 572 unsigned int length = cbw->data_transfer_length;
523 unsigned int block_size; 573 unsigned int block_size = 0;
524 unsigned int block_count; 574 unsigned int block_count = 0;
525 bool lun_present=true; 575 bool lun_present=true;
526#ifdef ONLY_EXPOSE_CARD_SLOT 576#ifdef ONLY_EXPOSE_CARD_SLOT
527 unsigned char lun = cbw->lun+1; 577 unsigned char lun = cbw->lun+1;
@@ -536,9 +586,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
536 block_count = cinfo->numblocks; 586 block_count = cinfo->numblocks;
537 } 587 }
538 else { 588 else {
539 lun_present=false; 589 ejected[lun] = true;
540 block_size = 0; 590 try_release_ata();
541 block_count = 0;
542 } 591 }
543#else 592#else
544 unsigned short* identify = ata_get_identify(); 593 unsigned short* identify = ata_get_identify();
@@ -562,8 +611,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
562 if(!usb_exclusive_ata()) { 611 if(!usb_exclusive_ata()) {
563 send_csw(UMS_STATUS_FAIL); 612 send_csw(UMS_STATUS_FAIL);
564 cur_sense_data.sense_key=SENSE_NOT_READY; 613 cur_sense_data.sense_key=SENSE_NOT_READY;
565 cur_sense_data.asc=ASC_NOT_READY; 614 cur_sense_data.asc=ASC_MEDIUM_NOT_PRESENT;
566 cur_sense_data.ascq=ASCQ_BECOMING_READY; 615 cur_sense_data.ascq=0;
567 break; 616 break;
568 } 617 }
569 if(lun_present) { 618 if(lun_present) {
@@ -732,12 +781,17 @@ static void handle_scsi(struct command_block_wrapper* cbw)
732 781
733 case SCSI_START_STOP_UNIT: 782 case SCSI_START_STOP_UNIT:
734 logf("scsi start_stop unit %d",lun); 783 logf("scsi start_stop unit %d",lun);
735 if((cbw->command_block[4] & 0xf0) == 0) 784 if((cbw->command_block[4] & 0xf0) == 0) /*load/eject bit is valid*/
736 { /* Process start and eject bits */ 785 { /* Process start and eject bits */
737 if((cbw->command_block[4] & 0x01) == 0 && 786 logf("scsi load/eject");
738 (cbw->command_block[4] & 0x02) != 0) /* Stop and eject */ 787 if((cbw->command_block[4] & 0x01) == 0) /* Don't start */
739 { 788 {
740 ejected[lun]=true; 789 if((cbw->command_block[4] & 0x02) != 0) /* eject */
790 {
791 logf("scsi eject");
792 ejected[lun]=true;
793 try_release_ata();
794 }
741 } 795 }
742 } 796 }
743 send_csw(UMS_STATUS_GOOD); 797 send_csw(UMS_STATUS_GOOD);
@@ -828,7 +882,7 @@ static void handle_scsi(struct command_block_wrapper* cbw)
828 cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,) 882 cur_cmd.last_result = ata_read_sectors(IF_MV2(cur_cmd.lun,)
829 cur_cmd.sector, 883 cur_cmd.sector,
830 MIN(BUFFER_SIZE/SECTOR_SIZE, 884 MIN(BUFFER_SIZE/SECTOR_SIZE,
831 cur_cmd.count), 885 cur_cmd.count),
832 cur_cmd.data[cur_cmd.data_select]); 886 cur_cmd.data[cur_cmd.data_select]);
833 send_and_read_next(); 887 send_and_read_next();
834 } 888 }
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);
27void usb_storage_init(void); 27void usb_storage_init(void);
28void usb_storage_transfer_complete(bool in,int state,int length); 28void usb_storage_transfer_complete(bool in,int state,int length);
29bool usb_storage_control_request(struct usb_ctrlrequest* req); 29bool usb_storage_control_request(struct usb_ctrlrequest* req);
30#ifdef HAVE_HOTSWAP
31void usb_storage_notify_hotswap(int volume,bool inserted);
32#endif
33
34void usb_storage_reconnect(void);
30 35
31#endif 36#endif
32 37