1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
37 #include "usb-target.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)
60 #ifdef HAVE_LCD_BITMAP
61 bool do_screendump_instead_of_usb
= false;
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;
73 /* Make sure there's enough stack space for screendump */
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;
83 static bool usb_hid
= true;
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. */
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 */
106 memcpy((void *)0x0002bf00, "diskmodehotstuff\1\0\0\0", 20);
109 system_reboot(); /* Reboot */
111 #endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */
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
;
121 #ifdef HAVE_REMOTE_LCD
122 remote_screen_dump();
123 #endif /* HAVE_REMOTE_LCD */
126 #endif /* HAVE_LCD_BITMAP */
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
);
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
);
149 #endif /* USB_FIREWIRE_HANDLING */
152 /*--- Routines that differ depending upon the presence of a USB stack ---*/
155 /* Enable / disable USB when the stack is enabled - otherwise a noop */
156 static inline void usb_stack_enable(bool enable
)
162 static inline void usb_handle_hotswap(long id
)
166 case SYS_HOTSWAP_INSERTED
:
167 case SYS_HOTSWAP_EXTRACTED
:
168 usb_core_hotswap_event(1, id
== SYS_HOTSWAP_INSERTED
);
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
)
180 #ifdef USB_ENABLE_STORAGE
181 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE
, false);
183 #ifdef USB_ENABLE_HID
184 #ifdef USB_ENABLE_CHARGING_ONLY
185 usb_core_enable_driver(USB_DRIVER_HID
, false);
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);
194 exclusive_storage_access
= false;
196 usb_attach(); /* Powered only: attach now. */
201 #ifdef USB_ENABLE_STORAGE
202 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE
, true);
204 #ifdef USB_ENABLE_HID
205 usb_core_enable_driver(USB_DRIVER_HID
, usb_hid
);
207 #ifdef USB_ENABLE_CHARGING_ONLY
208 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY
, false);
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
)
217 usb_attach(); /* Not exclusive: attach now. */
222 if(exclusive_storage_access
)
223 usb_release_exclusive_storage();
231 #ifdef USE_ROCKBOX_USB
232 static inline void usb_slave_mode(bool on
)
239 #ifdef HAVE_PRIORITY_SCHEDULING
240 thread_set_priority(thread_self(), PRIORITY_REALTIME
);
245 else /* usb_state == USB_INSERTED (only!) */
247 #ifdef HAVE_PRIORITY_SCHEDULING
248 thread_set_priority(thread_self(), PRIORITY_SYSTEM
);
250 /* Entered exclusive mode */
251 rc
= disk_mount_all();
252 if(rc
<= 0) /* no partition */
253 panicf("mount: %d",rc
);
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
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
)
282 static inline void usb_handle_hotswap(long id
)
284 #if (CONFIG_STORAGE & STORAGE_MMC)
287 case SYS_HOTSWAP_INSERTED
:
288 case SYS_HOTSWAP_EXTRACTED
:
289 if(usb_state
== USB_INSERTED
)
292 usb_mmc_countdown
= HZ
/2; /* re-enable after 0.5 sec */
296 if(usb_state
== USB_INSERTED
)
297 usb_enable(true); /* reenable only if still inserted */
300 #endif /* STORAGE_MMC */
303 #endif /* HAVE_HOTSWAP */
305 static inline bool usb_configure_drivers(int for_state
)
310 exclusive_storage_access
= false;
313 exclusive_storage_access
= true;
316 if(exclusive_storage_access
)
317 usb_release_exclusive_storage();
324 static inline void usb_slave_mode(bool on
)
330 DEBUGF("Entering USB slave mode\n");
332 storage_soft_reset();
334 storage_enable(false);
340 DEBUGF("Leaving USB slave mode\n");
342 cpu_idle_mode(false);
344 /* Let the ISDx00 settle */
351 panicf("storage: %d",rc
);
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
;
372 queue_wait(&usb_queue
, &ev
);
376 /*** Main USB thread duties ***/
379 case USB_TRANSFER_COMPLETION
:
380 if(usb_state
<= USB_EXTRACTED
)
383 usb_core_handle_transfer_completion(
384 (struct usb_transfer_completion_event_data
*)ev
.data
);
386 #endif /* HAVE_USBSTACK */
389 if(usb_state
!= USB_EXTRACTED
)
392 if(usb_do_screendump())
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 */
403 if(usb_state
!= USB_POWERED
)
405 #endif /* USB_DETECT_BY_CORE */
410 host_detected
= true;
412 if(usb_power_button())
414 /* Only charging is desired */
415 usb_configure_drivers(USB_POWERED
);
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. */
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");
450 usb_slave_mode(true);
451 usb_state
= USB_INSERTED
;
456 DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect
);
459 /* SYS_USB_CONNECTED_ACK */
462 if(usb_state
== USB_EXTRACTED
)
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
;
477 /* Ok to broadcast disconnect now */
478 usb_configure_drivers(USB_EXTRACTED
);
479 host_detected
= false;
485 /*** Miscellaneous USB thread duties ***/
489 case SYS_HOTSWAP_INSERTED
:
490 case SYS_HOTSWAP_EXTRACTED
:
491 #if (CONFIG_STORAGE & STORAGE_MMC)
494 usb_handle_hotswap(ev
.id
);
499 #ifdef USB_FIREWIRE_HANDLING
500 case USB_REQUEST_REBOOT
:
501 if(usb_reboot_button())
507 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
508 case USB_CHARGER_UPDATE
:
509 usb_charging_maxcurrent_change(usb_charging_maxcurrent());
514 #ifdef USB_DRIVER_CLOSE
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);
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.
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
;
561 usb_status_event(status
);
563 #ifdef USB_FIREWIRE_HANDLING
564 if(firewire_detect())
565 usb_firewire_connect_event();
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;
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
;
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
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
;
624 /* Count down until it gets negative */
625 if(usb_countdown
>= 0)
628 /* Report to the thread if we have had 3 identical status
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)
640 if(usb_mmc_countdown
== 0)
641 queue_post(&usb_queue
, USB_REENABLE
, 0);
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);
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
);
672 #endif /* USB_FULL_INIT */
677 void usb_wait_for_disconnect(struct event_queue
*q
)
680 struct queue_event ev
;
682 /* Don't return until we get SYS_USB_DISCONNECTED */
686 if(ev
.id
== SYS_USB_DISCONNECTED
)
689 #endif /* USB_FULL_INIT */
693 int usb_wait_for_disconnect_w_tmo(struct event_queue
*q
, int ticks
)
696 struct queue_event ev
;
698 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
701 queue_wait_w_tmo(q
, &ev
, ticks
);
704 case SYS_USB_DISCONNECTED
:
710 #endif /* USB_FULL_INIT */
711 (void)q
; (void)ticks
;
715 #ifdef USB_DRIVER_CLOSE
718 unsigned int thread
= usb_thread_entry
;
719 usb_thread_entry
= 0;
724 #ifndef USB_STATUS_BY_EVENT
725 tick_remove_task(usb_tick
);
727 usb_monitor_enabled
= false;
728 queue_post(&usb_queue
, USB_QUIT
, 0);
731 #endif /* USB_DRIVER_CLOSE */
733 bool usb_inserted(void)
735 return usb_state
== USB_INSERTED
|| usb_state
== USB_POWERED
;
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)
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
);
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
)
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)
779 void usb_acknowledge(long id
)
788 void usb_start_monitoring(void)
794 return USB_EXTRACTED
;
797 void usb_wait_for_disconnect(struct event_queue
*q
)
801 #endif /* USB_NONE */