Fix FS#12824 : Malfunctioning FFT plugin in Sansa Clip Zip
[maemo-rb.git] / firmware / usb.c
blobb8c9822ff60d401ffb6f6d0f828538baeb7823d8
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.h"
38 #include "button.h"
39 #include "string.h"
40 #ifdef HAVE_USBSTACK
41 #include "usb_core.h"
42 #endif
43 #include "logf.h"
44 #include "screendump.h"
46 /* Conditions under which we want the entire driver */
47 #if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \
48 (defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) || \
49 (defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx))) || \
50 (defined(HAVE_USBSTACK) && (defined(OLYMPUS_MROBE_500))) || \
51 (defined(HAVE_USBSTACK) && defined(USE_ROCKBOX_USB) && CONFIG_USBOTG == USBOTG_S3C6400X) || \
52 defined(CPU_TCC77X) || defined(CPU_TCC780X) || \
53 (CONFIG_USBOTG == USBOTG_JZ4740) || \
54 (defined(USE_ROCKBOX_USB) && CONFIG_USBOTG == USBOTG_AS3525)
55 #define USB_FULL_INIT
56 #endif
58 #ifdef HAVE_LCD_BITMAP
59 bool do_screendump_instead_of_usb = false;
60 #endif
62 #if !defined(SIMULATOR) && !defined(USB_NONE)
64 /* We assume that the USB cable is extracted */
65 static int usb_state = USB_EXTRACTED;
66 #if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) && !defined(HAVE_USBSTACK)
67 static int usb_mmc_countdown = 0;
68 #endif
70 /* Make sure there's enough stack space for screendump */
71 #ifdef USB_FULL_INIT
72 static long usb_stack[(DEFAULT_STACK_SIZE + DUMP_BMP_LINESIZE)/sizeof(long)];
73 static const char usb_thread_name[] = "usb";
74 static unsigned int usb_thread_entry = 0;
75 static bool usb_monitor_enabled = false;
76 #endif /* USB_FULL_INIT */
77 static struct event_queue usb_queue SHAREDBSS_ATTR;
78 static bool exclusive_storage_access = false;
79 #ifdef USB_ENABLE_HID
80 static bool usb_hid = true;
81 #endif
83 #ifdef USB_FULL_INIT
84 static bool usb_host_present = false;
85 static int usb_num_acks_to_expect = 0;
86 static long usb_last_broadcast_tick = 0;
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 #ifdef HAVE_LCD_BITMAP
115 static inline bool usb_do_screendump(void)
117 if(do_screendump_instead_of_usb)
119 screen_dump();
120 #ifdef HAVE_REMOTE_LCD
121 remote_screen_dump();
122 #endif /* HAVE_REMOTE_LCD */
123 return true;
125 return false;
127 #endif /* HAVE_LCD_BITMAP */
129 /* Power (charging-only) button */
130 static inline bool usb_power_button(void)
132 #ifdef HAVE_USB_POWER
133 return (button_status() & ~USBPOWER_BTN_IGNORE);
134 #else
135 return false;
136 #endif
139 #ifdef USB_FIREWIRE_HANDLING
140 static inline bool usb_reboot_button(void)
142 #ifdef HAVE_USB_POWER
143 return (button_status() & ~USBPOWER_BTN_IGNORE);
144 #else
145 return false;
146 #endif
148 #endif /* USB_FIREWIRE_HANDLING */
151 /*--- Routines that differ depending upon the presence of a USB stack ---*/
153 #ifdef HAVE_USBSTACK
154 /* Enable / disable USB when the stack is enabled - otherwise a noop */
155 static inline void usb_stack_enable(bool enable)
157 usb_enable(enable);
160 #ifdef HAVE_HOTSWAP
161 static inline void usb_handle_hotswap(long id)
163 switch(id)
165 case SYS_HOTSWAP_INSERTED:
166 case SYS_HOTSWAP_EXTRACTED:
167 usb_core_hotswap_event(1, id == SYS_HOTSWAP_INSERTED);
168 break;
170 /* Note: No MMC storage handling is needed with the stack atm. */
172 #endif /* HAVE_HOTSWAP */
174 static inline bool usb_configure_drivers(int for_state)
176 switch(for_state)
178 case USB_POWERED:
179 #ifdef USB_ENABLE_STORAGE
180 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false);
181 #endif
182 #ifdef USB_ENABLE_HID
183 #ifdef USB_ENABLE_CHARGING_ONLY
184 usb_core_enable_driver(USB_DRIVER_HID, false);
185 #else
186 usb_core_enable_driver(USB_DRIVER_HID, true);
187 #endif /* USB_ENABLE_CHARGING_ONLY */
188 #endif /* USB_ENABLE_HID */
190 #ifdef USB_ENABLE_CHARGING_ONLY
191 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
192 #endif
193 exclusive_storage_access = false;
195 usb_attach(); /* Powered only: attach now. */
196 break;
197 /* USB_POWERED: */
199 case USB_INSERTED:
200 #ifdef USB_ENABLE_STORAGE
201 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true);
202 #endif
203 #ifdef USB_ENABLE_HID
204 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
205 #endif
206 #ifdef USB_ENABLE_CHARGING_ONLY
207 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
208 #endif
209 /* Check any drivers enabled at this point for exclusive storage
210 * access requirements. */
211 exclusive_storage_access = usb_core_any_exclusive_storage();
213 if(exclusive_storage_access)
214 return true;
216 usb_attach(); /* Not exclusive: attach now. */
217 break;
218 /* USB_INSERTED: */
220 case USB_EXTRACTED:
221 if(exclusive_storage_access)
222 usb_release_exclusive_storage();
223 break;
224 /* USB_EXTRACTED: */
227 return false;
230 #ifdef USE_ROCKBOX_USB
231 static inline void usb_slave_mode(bool on)
233 int rc;
235 if(on)
237 trigger_cpu_boost();
238 #ifdef HAVE_PRIORITY_SCHEDULING
239 thread_set_priority(thread_self(), PRIORITY_REALTIME);
240 #endif
241 disk_unmount_all();
242 usb_attach();
244 else /* usb_state == USB_INSERTED (only!) */
246 #ifdef HAVE_PRIORITY_SCHEDULING
247 thread_set_priority(thread_self(), PRIORITY_SYSTEM);
248 #endif
249 /* Entered exclusive mode */
250 rc = disk_mount_all();
251 if(rc <= 0) /* no partition */
252 panicf("mount: %d",rc);
254 cancel_cpu_boost();
257 #else /* !USE_ROCKBOX_USB */
258 static inline void usb_slave_mode(bool on)
260 /* Until we have native mass-storage mode, we want to reboot on USB host
261 * connect */
262 if(on)
263 try_reboot();
265 #endif /* USE_ROCKBOX_USB */
267 void usb_signal_transfer_completion(
268 struct usb_transfer_completion_event_data* event_data)
270 queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data);
273 void usb_signal_notify(long id, intptr_t data)
275 queue_post(&usb_queue, id, data);
278 #else /* !HAVE_USBSTACK */
280 static inline void usb_stack_enable(bool enable)
282 (void)enable;
285 #ifdef HAVE_HOTSWAP
286 static inline void usb_handle_hotswap(long id)
288 #if (CONFIG_STORAGE & STORAGE_MMC)
289 switch(id)
291 case SYS_HOTSWAP_INSERTED:
292 case SYS_HOTSWAP_EXTRACTED:
293 if(usb_state == USB_INSERTED)
295 usb_enable(false);
296 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
298 break;
299 case USB_REENABLE:
300 if(usb_state == USB_INSERTED)
301 usb_enable(true); /* reenable only if still inserted */
302 break;
304 #endif /* STORAGE_MMC */
305 (void)id;
307 #endif /* HAVE_HOTSWAP */
309 static inline bool usb_configure_drivers(int for_state)
311 switch(for_state)
313 case USB_POWERED:
314 exclusive_storage_access = false;
315 break;
316 case USB_INSERTED:
317 exclusive_storage_access = true;
318 return true;
319 case USB_EXTRACTED:
320 if(exclusive_storage_access)
321 usb_release_exclusive_storage();
322 break;
325 return false;
328 static inline void usb_slave_mode(bool on)
330 int rc;
332 if(on)
334 DEBUGF("Entering USB slave mode\n");
335 disk_unmount_all();
336 storage_soft_reset();
337 storage_init();
338 storage_enable(false);
339 usb_enable(true);
340 cpu_idle_mode(true);
342 else
344 DEBUGF("Leaving USB slave mode\n");
346 cpu_idle_mode(false);
348 /* Let the ISDx00 settle */
349 sleep(HZ*1);
351 usb_enable(false);
353 rc = storage_init();
354 if(rc)
355 panicf("storage: %d",rc);
357 sleep(HZ/10);
358 rc = disk_mount_all();
359 if(rc <= 0) /* no partition */
360 panicf("mount: %d",rc);
363 #endif /* HAVE_USBSTACK */
365 static void usb_set_host_present(bool present)
367 if(usb_host_present == present)
368 return;
370 usb_host_present = present;
372 if(!usb_host_present)
374 usb_configure_drivers(USB_EXTRACTED);
375 return;
378 if(usb_power_button())
380 /* Only charging is desired */
381 usb_configure_drivers(USB_POWERED);
382 return;
385 if(!usb_configure_drivers(USB_INSERTED))
386 return; /* Exclusive storage access not required */
388 /* Tell all threads that they have to back off the storage.
389 We subtract one for our own thread. Expect an ACK for every
390 listener for each broadcast they received. If it has been too
391 long, the user might have entered a screen that didn't ACK
392 when inserting the cable, such as a debugging screen. In that
393 case, reset the count or else USB would be locked out until
394 rebooting because it most likely won't ever come. Simply
395 resetting to the most recent broadcast count is racy. */
396 if(TIME_AFTER(current_tick, usb_last_broadcast_tick + HZ*5))
398 usb_num_acks_to_expect = 0;
399 usb_last_broadcast_tick = current_tick;
402 usb_num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
403 DEBUGF("usb: waiting for %d acks...\n", usb_num_acks_to_expect);
406 static bool usb_handle_connected_ack(void)
408 if(usb_num_acks_to_expect > 0 && --usb_num_acks_to_expect == 0)
410 DEBUGF("usb: all threads have acknowledged the connect.\n");
411 if(usb_host_present)
413 usb_slave_mode(true);
414 return true;
417 else
419 DEBUGF("usb: got ack, %d to go...\n", usb_num_acks_to_expect);
422 return false;
425 /*--- General driver code ---*/
426 static void NORETURN_ATTR usb_thread(void)
428 struct queue_event ev;
430 while(1)
432 queue_wait(&usb_queue, &ev);
434 switch(ev.id)
436 /*** Main USB thread duties ***/
438 #ifdef HAVE_USBSTACK
439 case USB_NOTIFY_SET_ADDR:
440 case USB_NOTIFY_SET_CONFIG:
441 if(usb_state <= USB_EXTRACTED)
442 break;
443 usb_core_handle_notify(ev.id, ev.data);
444 break;
445 case USB_TRANSFER_COMPLETION:
446 if(usb_state <= USB_EXTRACTED)
447 break;
449 #ifdef USB_DETECT_BY_REQUEST
450 usb_set_host_present(true);
451 #endif
453 usb_core_handle_transfer_completion(
454 (struct usb_transfer_completion_event_data*)ev.data);
455 break;
456 #endif /* HAVE_USBSTACK */
458 case USB_INSERTED:
459 if(usb_state != USB_EXTRACTED)
460 break;
462 #ifdef HAVE_LCD_BITMAP
463 if(usb_do_screendump())
465 usb_state = USB_SCREENDUMP;
466 break;
468 #endif
470 usb_state = USB_POWERED;
471 usb_stack_enable(true);
473 #ifndef USB_DETECT_BY_REQUEST
474 usb_set_host_present(true);
475 #endif
476 break;
477 /* USB_INSERTED */
479 case SYS_USB_CONNECTED_ACK:
480 if(usb_handle_connected_ack())
481 usb_state = USB_INSERTED;
482 break;
483 /* SYS_USB_CONNECTED_ACK */
485 case USB_EXTRACTED:
486 if(usb_state == USB_EXTRACTED)
487 break;
489 if(usb_state == USB_POWERED || usb_state == USB_INSERTED)
490 usb_stack_enable(false);
492 /* Only disable the USB slave mode if we really have enabled
493 it. Some expected acks may not have been received. */
494 if(usb_state == USB_INSERTED)
495 usb_slave_mode(false);
497 usb_state = USB_EXTRACTED;
499 usb_set_host_present(false);
500 break;
501 /* USB_EXTRACTED: */
503 /*** Miscellaneous USB thread duties ***/
505 /* HOTSWAP */
506 #ifdef HAVE_HOTSWAP
507 case SYS_HOTSWAP_INSERTED:
508 case SYS_HOTSWAP_EXTRACTED:
509 #if (CONFIG_STORAGE & STORAGE_MMC)
510 case USB_REENABLE:
511 #endif
512 usb_handle_hotswap(ev.id);
513 break;
514 #endif
516 /* FIREWIRE */
517 #ifdef USB_FIREWIRE_HANDLING
518 case USB_REQUEST_REBOOT:
519 if(usb_reboot_button())
520 try_reboot();
521 break;
522 #endif
524 /* CHARGING */
525 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
526 case USB_CHARGER_UPDATE:
527 usb_charging_maxcurrent_change(usb_charging_maxcurrent());
528 break;
529 #endif
531 /* CLOSE */
532 #ifdef USB_DRIVER_CLOSE
533 case USB_QUIT:
534 thread_exit();
535 break;
536 #endif
537 } /* switch */
538 } /* while */
541 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
542 void usb_charger_update(void)
544 queue_post(&usb_queue, USB_CHARGER_UPDATE, 0);
546 #endif
548 #ifdef USB_STATUS_BY_EVENT
549 void usb_status_event(int current_status)
551 /* Caller isn't expected to filter for changes in status.
552 * current_status:
553 * USB_INSERTED, USB_EXTRACTED
555 if(usb_monitor_enabled)
557 int oldstatus = disable_irq_save(); /* Dual-use function */
558 queue_remove_from_head(&usb_queue, current_status);
559 queue_post(&usb_queue, current_status, 0);
560 restore_irq(oldstatus);
564 void usb_start_monitoring(void)
566 int oldstatus = disable_irq_save(); /* Sync to event */
567 int status = usb_detect();
569 usb_monitor_enabled = true;
571 /* An event may have been missed because it was sent before monitoring
572 * was enabled due to the connector already having been inserted before
573 * before or during boot. */
574 usb_status_event(status);
576 #ifdef USB_FIREWIRE_HANDLING
577 if(firewire_detect())
578 usb_firewire_connect_event();
579 #endif
581 restore_irq(oldstatus);
584 #ifdef USB_FIREWIRE_HANDLING
585 void usb_firewire_connect_event(void)
587 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
589 #endif /* USB_FIREWIRE_HANDLING */
591 #else /* !USB_STATUS_BY_EVENT */
593 static void usb_tick(void)
595 #define NUM_POLL_READINGS (HZ/5)
596 static int usb_countdown = -1;
597 static int last_usb_status = USB_EXTRACTED;
598 #ifdef USB_FIREWIRE_HANDLING
599 static int firewire_countdown = -1;
600 static int last_firewire_status = false;
601 #endif
603 if(usb_monitor_enabled)
605 #ifdef USB_FIREWIRE_HANDLING
606 int current_firewire_status = firewire_detect();
607 if(current_firewire_status != last_firewire_status)
609 last_firewire_status = current_firewire_status;
610 firewire_countdown = NUM_POLL_READINGS;
612 else
614 /* Count down until it gets negative */
615 if(firewire_countdown >= 0)
616 firewire_countdown--;
618 /* Report to the thread if we have had 3 identical status
619 readings in a row */
620 if(firewire_countdown == 0)
622 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
625 #endif /* USB_FIREWIRE_HANDLING */
627 int current_status = usb_detect();
629 /* Only report when the status has changed */
630 if(current_status != last_usb_status)
632 last_usb_status = current_status;
633 usb_countdown = NUM_POLL_READINGS;
635 else
637 /* Count down until it gets negative */
638 if(usb_countdown >= 0)
639 usb_countdown--;
641 /* Report to the thread if we have had 3 identical status
642 readings in a row */
643 if(usb_countdown == 0)
645 queue_post(&usb_queue, current_status, 0);
649 #if (CONFIG_STORAGE & STORAGE_MMC)
650 if(usb_mmc_countdown > 0)
652 usb_mmc_countdown--;
653 if(usb_mmc_countdown == 0)
654 queue_post(&usb_queue, USB_REENABLE, 0);
656 #endif
659 void usb_start_monitoring(void)
661 usb_monitor_enabled = true;
663 #endif /* USB_STATUS_BY_EVENT */
664 #endif /* USB_FULL_INIT */
666 void usb_acknowledge(long id)
668 queue_post(&usb_queue, id, 0);
671 void usb_init(void)
673 /* Do required hardware inits first. For software USB the driver has
674 * to make sure this won't trigger a transfer completion before the
675 * queue and thread are created. */
676 usb_init_device();
678 #ifdef USB_FULL_INIT
679 usb_enable(false);
681 queue_init(&usb_queue, true);
683 usb_thread_entry = create_thread(usb_thread, usb_stack,
684 sizeof(usb_stack), 0, usb_thread_name
685 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
687 #ifndef USB_STATUS_BY_EVENT
688 tick_add_task(usb_tick);
689 #endif
690 #endif /* USB_FULL_INIT */
693 void usb_wait_for_disconnect(struct event_queue *q)
695 #ifdef USB_FULL_INIT
696 struct queue_event ev;
698 /* Don't return until we get SYS_USB_DISCONNECTED */
699 while(1)
701 queue_wait(q, &ev);
702 if(ev.id == SYS_USB_DISCONNECTED)
703 return;
705 #endif /* USB_FULL_INIT */
706 (void)q;
709 int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)
711 #ifdef USB_FULL_INIT
712 struct queue_event ev;
714 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
715 while(1)
717 queue_wait_w_tmo(q, &ev, ticks);
718 switch(ev.id)
720 case SYS_USB_DISCONNECTED:
721 return 0;
722 case SYS_TIMEOUT:
723 return 1;
726 #endif /* USB_FULL_INIT */
727 (void)q; (void)ticks;
728 return 0;
731 #ifdef USB_DRIVER_CLOSE
732 void usb_close(void)
734 unsigned int thread = usb_thread_entry;
735 usb_thread_entry = 0;
737 if(thread == 0)
738 return;
740 #ifndef USB_STATUS_BY_EVENT
741 tick_remove_task(usb_tick);
742 #endif
743 usb_monitor_enabled = false;
744 queue_post(&usb_queue, USB_QUIT, 0);
745 thread_wait(thread);
747 #endif /* USB_DRIVER_CLOSE */
749 bool usb_inserted(void)
751 return usb_state == USB_INSERTED || usb_state == USB_POWERED;
754 #ifdef HAVE_USBSTACK
755 bool usb_exclusive_storage(void)
757 /* Storage isn't actually exclusive until slave mode has been entered */
758 return exclusive_storage_access && usb_state == USB_INSERTED;
760 #endif /* HAVE_USBSTACK */
762 int usb_release_exclusive_storage(void)
764 int bccount;
765 exclusive_storage_access = false;
766 /* Tell all threads that we are back in business */
767 bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
768 DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount);
769 return bccount;
772 #ifdef HAVE_USB_POWER
773 bool usb_powered(void)
775 return usb_state == USB_POWERED;
777 #endif /* HAVE_USB_POWER */
779 #ifdef USB_ENABLE_HID
780 void usb_set_hid(bool enable)
782 usb_hid = enable;
783 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
785 #endif /* USB_ENABLE_HID */
787 #elif defined(USB_NONE)
788 /* Dummy functions for USB_NONE */
790 bool usb_inserted(void)
792 return false;
795 void usb_acknowledge(long id)
797 id = id;
800 void usb_init(void)
804 void usb_start_monitoring(void)
808 int usb_detect(void)
810 return USB_EXTRACTED;
813 void usb_wait_for_disconnect(struct event_queue *q)
815 (void)q;
817 #endif /* USB_NONE */