AMSv2: enable storage write in bootloader
[maemo-rb.git] / firmware / usb.c
blobec81ba6f58fe5aa1a4bff231b8da143d51a9a2f7
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
12 * iPod driver based on code from the ipodlinux project - http://ipodlinux.org
13 * Adapted for Rockbox in January 2006
14 * Original file: podzilla/usb.c
15 * Copyright (C) 2005 Adam Johnston
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
25 ****************************************************************************/
26 #include "config.h"
27 #include "cpu.h"
28 #include "kernel.h"
29 #include "thread.h"
30 #include "system.h"
31 #include "debug.h"
32 #include "storage.h"
33 #include "fat.h"
34 #include "disk.h"
35 #include "panic.h"
36 #include "lcd.h"
37 #include "usb-target.h"
38 #include "usb.h"
39 #include "button.h"
40 #include "string.h"
41 #ifdef HAVE_USBSTACK
42 #include "usb_core.h"
43 #endif
44 #include "logf.h"
45 #include "screendump.h"
47 /* Conditions under which we want the entire driver */
48 #if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \
49 (defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) || \
50 (defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx))) || \
51 (defined(HAVE_USBSTACK) && (defined(OLYMPUS_MROBE_500))) || \
52 (defined(HAVE_USBSTACK) && (defined(IPOD_NANO2G))) || \
53 defined(CPU_TCC77X) || defined(CPU_TCC780X) || \
54 (CONFIG_USBOTG == USBOTG_JZ4740) || \
55 (defined(USE_ROCKBOX_USB) && CONFIG_USBOTG == USBOTG_AS3525) || \
56 (defined(USE_ROCKBOX_USB) && CONFIG_USBOTG == USBOTG_AS3525v2)
57 #define USB_FULL_INIT
58 #endif
60 #ifdef HAVE_LCD_BITMAP
61 bool do_screendump_instead_of_usb = false;
62 #endif
64 #if !defined(SIMULATOR) && !defined(USB_NONE)
66 /* We assume that the USB cable is extracted */
67 static int usb_state = USB_EXTRACTED;
69 #if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) && !defined(HAVE_USBSTACK)
70 static int usb_mmc_countdown = 0;
71 #endif
73 /* Make sure there's enough stack space for screendump */
74 #ifdef USB_FULL_INIT
75 static long usb_stack[(DEFAULT_STACK_SIZE + DUMP_BMP_LINESIZE)/sizeof(long)];
76 static const char usb_thread_name[] = "usb";
77 static unsigned int usb_thread_entry = 0;
78 static bool usb_monitor_enabled = false;
79 #endif /* USB_FULL_INIT */
80 static struct event_queue usb_queue SHAREDBSS_ATTR;
81 static bool exclusive_storage_access = false;
82 #ifdef USB_ENABLE_HID
83 static bool usb_hid = true;
84 #endif
86 #ifdef USB_FULL_INIT
88 #if defined(USB_FIREWIRE_HANDLING) \
89 || (defined(HAVE_USBSTACK) && !defined(USE_ROCKBOX_USB))
90 static void try_reboot(void)
92 #ifdef HAVE_DISK_STORAGE
93 storage_sleepnow(); /* Immediately spindown the disk. */
94 sleep(HZ*2);
95 #endif
97 #ifdef IPOD_ARCH /* The following code is based on ipodlinux */
98 #if CONFIG_CPU == PP5020
99 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
100 #elif CONFIG_CPU == PP5022
101 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
102 #endif /* CONFIG_CPU */
103 #endif /* IPOD_ARCH */
105 #ifdef IPOD_NANO2G
106 memcpy((void *)0x0002bf00, "diskmodehotstuff\1\0\0\0", 20);
107 #endif
109 system_reboot(); /* Reboot */
111 #endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */
113 /* Screen dump */
114 static inline bool usb_do_screendump(void)
116 #ifdef HAVE_LCD_BITMAP
117 if(do_screendump_instead_of_usb)
119 usb_state = USB_SCREENDUMP;
120 screen_dump();
121 #ifdef HAVE_REMOTE_LCD
122 remote_screen_dump();
123 #endif /* HAVE_REMOTE_LCD */
124 return true;
126 #endif /* HAVE_LCD_BITMAP */
127 return false;
130 /* Power (charging-only) button */
131 static inline bool usb_power_button(void)
133 #ifdef HAVE_USB_POWER
134 return (button_status() & ~USBPOWER_BTN_IGNORE);
135 #else
136 return false;
137 #endif
140 #ifdef USB_FIREWIRE_HANDLING
141 static inline bool usb_reboot_button(void)
143 #ifdef HAVE_USB_POWER
144 return (button_status() & ~USBPOWER_BTN_IGNORE);
145 #else
146 return false;
147 #endif
149 #endif /* USB_FIREWIRE_HANDLING */
152 /*--- Routines that differ depending upon the presence of a USB stack ---*/
154 #ifdef HAVE_USBSTACK
155 /* Enable / disable USB when the stack is enabled - otherwise a noop */
156 static inline void usb_stack_enable(bool enable)
158 usb_enable(enable);
161 #ifdef HAVE_HOTSWAP
162 static inline void usb_handle_hotswap(long id)
164 switch(id)
166 case SYS_HOTSWAP_INSERTED:
167 case SYS_HOTSWAP_EXTRACTED:
168 usb_core_hotswap_event(1, id == SYS_HOTSWAP_INSERTED);
169 break;
171 /* Note: No MMC storage handling is needed with the stack atm. */
173 #endif /* HAVE_HOTSWAP */
175 static inline bool usb_configure_drivers(int for_state)
177 switch(for_state)
179 case USB_POWERED:
180 #ifdef USB_ENABLE_STORAGE
181 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false);
182 #endif
183 #ifdef USB_ENABLE_HID
184 #ifdef USB_ENABLE_CHARGING_ONLY
185 usb_core_enable_driver(USB_DRIVER_HID, false);
186 #else
187 usb_core_enable_driver(USB_DRIVER_HID, true);
188 #endif /* USB_ENABLE_CHARGING_ONLY */
189 #endif /* USB_ENABLE_HID */
191 #ifdef USB_ENABLE_CHARGING_ONLY
192 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
193 #endif
194 exclusive_storage_access = false;
196 usb_attach(); /* Powered only: attach now. */
197 break;
198 /* USB_POWERED: */
200 case USB_INSERTED:
201 #ifdef USB_ENABLE_STORAGE
202 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true);
203 #endif
204 #ifdef USB_ENABLE_HID
205 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
206 #endif
207 #ifdef USB_ENABLE_CHARGING_ONLY
208 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
209 #endif
210 /* Check any drivers enabled at this point for exclusive storage
211 * access requirements. */
212 exclusive_storage_access = usb_core_any_exclusive_storage();
214 if(exclusive_storage_access)
215 return true;
217 usb_attach(); /* Not exclusive: attach now. */
218 break;
219 /* USB_INSERTED: */
221 case USB_EXTRACTED:
222 if(exclusive_storage_access)
223 usb_release_exclusive_storage();
224 break;
225 /* USB_EXTRACTED: */
228 return false;
231 #ifdef USE_ROCKBOX_USB
232 static inline void usb_slave_mode(bool on)
234 int rc;
236 if(on)
238 trigger_cpu_boost();
239 #ifdef HAVE_PRIORITY_SCHEDULING
240 thread_set_priority(thread_self(), PRIORITY_REALTIME);
241 #endif
242 disk_unmount_all();
243 usb_attach();
245 else /* usb_state == USB_INSERTED (only!) */
247 #ifdef HAVE_PRIORITY_SCHEDULING
248 thread_set_priority(thread_self(), PRIORITY_SYSTEM);
249 #endif
250 /* Entered exclusive mode */
251 rc = disk_mount_all();
252 if(rc <= 0) /* no partition */
253 panicf("mount: %d",rc);
255 cancel_cpu_boost();
258 #else /* !USE_ROCKBOX_USB */
259 static inline void usb_slave_mode(bool on)
261 /* Until we have native mass-storage mode, we want to reboot on USB host
262 * connect */
263 if(on)
264 try_reboot();
266 #endif /* USE_ROCKBOX_USB */
268 void usb_signal_transfer_completion(
269 struct usb_transfer_completion_event_data* event_data)
271 queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data);
274 #else /* !HAVE_USBSTACK */
276 static inline void usb_stack_enable(bool enable)
278 (void)enable;
281 #ifdef HAVE_HOTSWAP
282 static inline void usb_handle_hotswap(long id)
284 #if (CONFIG_STORAGE & STORAGE_MMC)
285 switch(id)
287 case SYS_HOTSWAP_INSERTED:
288 case SYS_HOTSWAP_EXTRACTED:
289 if(usb_state == USB_INSERTED)
291 usb_enable(false);
292 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
294 break;
295 case USB_REENABLE:
296 if(usb_state == USB_INSERTED)
297 usb_enable(true); /* reenable only if still inserted */
298 break;
300 #endif /* STORAGE_MMC */
301 (void)id;
303 #endif /* HAVE_HOTSWAP */
305 static inline bool usb_configure_drivers(int for_state)
307 switch(for_state)
309 case USB_POWERED:
310 exclusive_storage_access = false;
311 break;
312 case USB_INSERTED:
313 exclusive_storage_access = true;
314 return true;
315 case USB_EXTRACTED:
316 if(exclusive_storage_access)
317 usb_release_exclusive_storage();
318 break;
321 return false;
324 static inline void usb_slave_mode(bool on)
326 int rc;
328 if(on)
330 DEBUGF("Entering USB slave mode\n");
331 disk_unmount_all();
332 storage_soft_reset();
333 storage_init();
334 storage_enable(false);
335 usb_enable(true);
336 cpu_idle_mode(true);
338 else
340 DEBUGF("Leaving USB slave mode\n");
342 cpu_idle_mode(false);
344 /* Let the ISDx00 settle */
345 sleep(HZ*1);
347 usb_enable(false);
349 rc = storage_init();
350 if(rc)
351 panicf("storage: %d",rc);
353 sleep(HZ/10);
354 rc = disk_mount_all();
355 if(rc <= 0) /* no partition */
356 panicf("mount: %d",rc);
359 #endif /* HAVE_USBSTACK */
362 /*--- General driver code ---*/
363 static void NORETURN_ATTR usb_thread(void)
365 int num_acks_to_expect = 0;
366 long last_broadcast_tick = current_tick;
367 bool host_detected = false;
368 struct queue_event ev;
370 while(1)
372 queue_wait(&usb_queue, &ev);
374 switch(ev.id)
376 /*** Main USB thread duties ***/
378 #ifdef HAVE_USBSTACK
379 case USB_TRANSFER_COMPLETION:
380 if(usb_state <= USB_EXTRACTED)
381 break;
383 usb_core_handle_transfer_completion(
384 (struct usb_transfer_completion_event_data*)ev.data);
385 break;
386 #endif /* HAVE_USBSTACK */
388 case USB_INSERTED:
389 if(usb_state != USB_EXTRACTED)
390 break;
392 if(usb_do_screendump())
393 break;
395 usb_state = USB_POWERED;
396 usb_stack_enable(true);
398 #ifdef USB_DETECT_BY_CORE
399 /* Wait for USB core to detect the host */
400 break;
402 case USB_HOSTED:
403 if(usb_state != USB_POWERED)
404 break;
405 #endif /* USB_DETECT_BY_CORE */
407 if(host_detected)
408 break;
410 host_detected = true;
412 if(usb_power_button())
414 /* Only charging is desired */
415 usb_configure_drivers(USB_POWERED);
416 break;
419 if(!usb_configure_drivers(USB_INSERTED))
420 break; /* Exclusive storage access not required */
422 /* Tell all threads that they have to back off the storage.
423 We subtract one for our own thread. Expect an ACK for every
424 listener for each broadcast they received. If it has been too
425 long, the user might have entered a screen that didn't ACK
426 when inserting the cable, such as a debugging screen. In that
427 case, reset the count or else USB would be locked out until
428 rebooting because it most likely won't ever come. Simply
429 resetting to the most recent broadcast count is racy. */
430 if(TIME_AFTER(current_tick, last_broadcast_tick + HZ*5))
432 num_acks_to_expect = 0;
433 last_broadcast_tick = current_tick;
436 num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
437 DEBUGF("usb: waiting for %d acks...\n", num_acks_to_expect);
439 /* Leave the state as USB_POWERED until the expected number of
440 ACKS are received. */
441 break;
442 /* USB_INSERTED: or USB_HOSTED: */
444 case SYS_USB_CONNECTED_ACK:
445 if(num_acks_to_expect > 0 && --num_acks_to_expect == 0)
447 DEBUGF("usb: all threads have acknowledged the connect.\n");
448 if(host_detected)
450 usb_slave_mode(true);
451 usb_state = USB_INSERTED;
454 else
456 DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect);
458 break;
459 /* SYS_USB_CONNECTED_ACK */
461 case USB_EXTRACTED:
462 if(usb_state == USB_EXTRACTED)
463 break;
465 if(usb_state == USB_POWERED || usb_state == USB_INSERTED)
466 usb_stack_enable(false);
468 /* Only disable the USB slave mode if we really have enabled
469 it. Some expected acks may not have been received. */
470 if(usb_state == USB_INSERTED)
471 usb_slave_mode(false);
473 usb_state = USB_EXTRACTED;
475 if(host_detected)
477 /* Ok to broadcast disconnect now */
478 usb_configure_drivers(USB_EXTRACTED);
479 host_detected = false;
482 break;
483 /* USB_EXTRACTED: */
485 /*** Miscellaneous USB thread duties ***/
487 /* HOTSWAP */
488 #ifdef HAVE_HOTSWAP
489 case SYS_HOTSWAP_INSERTED:
490 case SYS_HOTSWAP_EXTRACTED:
491 #if (CONFIG_STORAGE & STORAGE_MMC)
492 case USB_REENABLE:
493 #endif
494 usb_handle_hotswap(ev.id);
495 break;
496 #endif
498 /* FIREWIRE */
499 #ifdef USB_FIREWIRE_HANDLING
500 case USB_REQUEST_REBOOT:
501 if(usb_reboot_button())
502 try_reboot();
503 break;
504 #endif
506 /* CHARGING */
507 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
508 case USB_CHARGER_UPDATE:
509 usb_charging_maxcurrent_change(usb_charging_maxcurrent());
510 break;
511 #endif
513 /* CLOSE */
514 #ifdef USB_DRIVER_CLOSE
515 case USB_QUIT:
516 thread_exit();
517 break;
518 #endif
519 } /* switch */
520 } /* while */
523 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
524 void usb_charger_update(void)
526 queue_post(&usb_queue, USB_CHARGER_UPDATE, 0);
528 #endif
530 #ifdef USB_STATUS_BY_EVENT
531 void usb_status_event(int current_status)
533 /* Caller isn't expected to filter for changes in status.
534 * current_status:
535 * all: USB_INSERTED, USB_EXTRACTED
536 * USB_DETECT_BY_CORE: USB_HOSTED (from core)
538 if(usb_monitor_enabled)
540 int oldstatus = disable_irq_save(); /* Dual-use function */
541 queue_remove_from_head(&usb_queue, current_status);
542 queue_post(&usb_queue, current_status, 0);
543 restore_irq(oldstatus);
547 void usb_start_monitoring(void)
549 int oldstatus = disable_irq_save(); /* Sync to event */
550 int status = usb_detect();
552 usb_monitor_enabled = true;
554 /* An event may have been missed because it was sent before monitoring
555 * was enabled due to the connector already having been inserted before
556 * before or during boot. */
557 #ifdef USB_DETECT_BY_CORE
558 /* Filter the status - USB_HOSTED may happen later */
559 status = (status == USB_INSERTED) ? : USB_EXTRACTED;
560 #endif
561 usb_status_event(status);
563 #ifdef USB_FIREWIRE_HANDLING
564 if(firewire_detect())
565 usb_firewire_connect_event();
566 #endif
568 restore_irq(oldstatus);
571 #ifdef USB_FIREWIRE_HANDLING
572 void usb_firewire_connect_event(void)
574 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
576 #endif /* USB_FIREWIRE_HANDLING */
578 #else /* !USB_STATUS_BY_EVENT */
580 static void usb_tick(void)
582 #define NUM_POLL_READINGS (HZ/5)
583 static int usb_countdown = -1;
584 static int last_usb_status = USB_EXTRACTED;
585 #ifdef USB_FIREWIRE_HANDLING
586 static int firewire_countdown = -1;
587 static int last_firewire_status = false;
588 #endif
590 if(usb_monitor_enabled)
592 #ifdef USB_FIREWIRE_HANDLING
593 int current_firewire_status = firewire_detect();
594 if(current_firewire_status != last_firewire_status)
596 last_firewire_status = current_firewire_status;
597 firewire_countdown = NUM_POLL_READINGS;
599 else
601 /* Count down until it gets negative */
602 if(firewire_countdown >= 0)
603 firewire_countdown--;
605 /* Report to the thread if we have had 3 identical status
606 readings in a row */
607 if(firewire_countdown == 0)
609 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
612 #endif /* USB_FIREWIRE_HANDLING */
614 int current_status = usb_detect();
616 /* Only report when the status has changed */
617 if(current_status != last_usb_status)
619 last_usb_status = current_status;
620 usb_countdown = NUM_POLL_READINGS;
622 else
624 /* Count down until it gets negative */
625 if(usb_countdown >= 0)
626 usb_countdown--;
628 /* Report to the thread if we have had 3 identical status
629 readings in a row */
630 if(usb_countdown == 0)
632 queue_post(&usb_queue, current_status, 0);
636 #if (CONFIG_STORAGE & STORAGE_MMC)
637 if(usb_mmc_countdown > 0)
639 usb_mmc_countdown--;
640 if(usb_mmc_countdown == 0)
641 queue_post(&usb_queue, USB_REENABLE, 0);
643 #endif
646 void usb_start_monitoring(void)
648 usb_monitor_enabled = true;
650 #endif /* USB_STATUS_BY_EVENT */
651 #endif /* USB_FULL_INIT */
653 void usb_acknowledge(long id)
655 queue_post(&usb_queue, id, 0);
658 void usb_init(void)
660 #ifdef USB_FULL_INIT
661 usb_enable(false);
663 queue_init(&usb_queue, true);
665 usb_thread_entry = create_thread(usb_thread, usb_stack,
666 sizeof(usb_stack), 0, usb_thread_name
667 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
669 #ifndef USB_STATUS_BY_EVENT
670 tick_add_task(usb_tick);
671 #endif
672 #endif /* USB_FULL_INIT */
674 usb_init_device();
677 void usb_wait_for_disconnect(struct event_queue *q)
679 #ifdef USB_FULL_INIT
680 struct queue_event ev;
682 /* Don't return until we get SYS_USB_DISCONNECTED */
683 while(1)
685 queue_wait(q, &ev);
686 if(ev.id == SYS_USB_DISCONNECTED)
687 return;
689 #endif /* USB_FULL_INIT */
690 (void)q;
693 int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)
695 #ifdef USB_FULL_INIT
696 struct queue_event ev;
698 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
699 while(1)
701 queue_wait_w_tmo(q, &ev, ticks);
702 switch(ev.id)
704 case SYS_USB_DISCONNECTED:
705 return 0;
706 case SYS_TIMEOUT:
707 return 1;
710 #endif /* USB_FULL_INIT */
711 (void)q; (void)ticks;
712 return 0;
715 #ifdef USB_DRIVER_CLOSE
716 void usb_close(void)
718 unsigned int thread = usb_thread_entry;
719 usb_thread_entry = 0;
721 if(thread == 0)
722 return;
724 #ifndef USB_STATUS_BY_EVENT
725 tick_remove_task(usb_tick);
726 #endif
727 usb_monitor_enabled = false;
728 queue_post(&usb_queue, USB_QUIT, 0);
729 thread_wait(thread);
731 #endif /* USB_DRIVER_CLOSE */
733 bool usb_inserted(void)
735 return usb_state == USB_INSERTED || usb_state == USB_POWERED;
738 #ifdef HAVE_USBSTACK
739 bool usb_exclusive_storage(void)
741 /* Storage isn't actually exclusive until slave mode has been entered */
742 return exclusive_storage_access && usb_state == USB_INSERTED;
744 #endif /* HAVE_USBSTACK */
746 int usb_release_exclusive_storage(void)
748 int bccount;
749 exclusive_storage_access = false;
750 /* Tell all threads that we are back in business */
751 bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
752 DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount);
753 return bccount;
756 #ifdef HAVE_USB_POWER
757 bool usb_powered(void)
759 return usb_state == USB_POWERED;
761 #endif /* HAVE_USB_POWER */
763 #ifdef USB_ENABLE_HID
764 void usb_set_hid(bool enable)
766 usb_hid = enable;
767 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
769 #endif /* USB_ENABLE_HID */
771 #elif defined(USB_NONE)
772 /* Dummy functions for USB_NONE */
774 bool usb_inserted(void)
776 return false;
779 void usb_acknowledge(long id)
781 id = id;
784 void usb_init(void)
788 void usb_start_monitoring(void)
792 int usb_detect(void)
794 return USB_EXTRACTED;
797 void usb_wait_for_disconnect(struct event_queue *q)
799 (void)q;
801 #endif /* USB_NONE */