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 #if defined(USB_DETECT_BY_DRV) || defined(USB_DETECT_BY_CORE)
61 /* These aren't treated differently here */
62 #define USB_DELAYED_INSERT
65 #ifdef HAVE_LCD_BITMAP
66 bool do_screendump_instead_of_usb
= false;
69 #if !defined(SIMULATOR) && !defined(USB_NONE)
71 /* We assume that the USB cable is extracted */
72 static int usb_state
= USB_EXTRACTED
;
74 #if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT)
75 static int usb_mmc_countdown
= 0;
78 /* Make sure there's enough stack space for screendump */
80 static long usb_stack
[(DEFAULT_STACK_SIZE
+ SECTOR_SIZE
+ DUMP_BMP_LINESIZE
)/sizeof(long)];
81 static const char usb_thread_name
[] = "usb";
82 static unsigned int usb_thread_entry
= 0;
83 static bool usb_monitor_enabled
= false;
84 #endif /* USB_FULL_INIT */
85 static struct event_queue usb_queue
;
86 static bool exclusive_storage_access
= false;
88 static bool usb_hid
= true;
93 #if defined(USB_FIREWIRE_HANDLING) \
94 || (defined(HAVE_USBSTACK) && !defined(USE_ROCKBOX_USB))
95 static void try_reboot(void)
97 #ifdef HAVE_DISK_STORAGE
98 storage_sleepnow(); /* Immediately spindown the disk. */
102 #ifdef IPOD_ARCH /* The following code is based on ipodlinux */
103 #if CONFIG_CPU == PP5020
104 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
105 #elif CONFIG_CPU == PP5022
106 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
107 #endif /* CONFIG_CPU */
108 #endif /* IPOD_ARCH */
111 memcpy((void *)0x0002bf00, "diskmodehotstuff\1\0\0\0", 20);
114 system_reboot(); /* Reboot */
116 #endif /* USB_FIRWIRE_HANDLING || (HAVE_USBSTACK && !USE_ROCKBOX_USB) */
119 #ifdef HAVE_LCD_BITMAP
120 static inline bool usb_do_screendump(void)
122 if(do_screendump_instead_of_usb
)
124 usb_state
= USB_SCREENDUMP
;
126 #ifdef HAVE_REMOTE_LCD
127 remote_screen_dump();
134 #else /* !HAVE_LCD_BITMAP */
135 static inline bool usb_do_screendump(void)
139 #endif /* HAVE_LCD_BITMAP */
145 static inline void usb_handle_hotswap(long id
)
149 case SYS_HOTSWAP_INSERTED
:
150 case SYS_HOTSWAP_EXTRACTED
:
151 usb_core_hotswap_event(1, id
== SYS_HOTSWAP_INSERTED
);
154 /* Note: No MMC storage handling is needed with the stack atm. */
156 #endif /* HAVE_HOTSWAP */
158 static inline bool usb_configure_drivers(int for_state
)
163 #ifdef USB_ENABLE_STORAGE
164 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE
, false);
166 #ifdef USB_ENABLE_HID
167 #ifdef USB_ENABLE_CHARGING_ONLY
168 usb_core_enable_driver(USB_DRIVER_HID
, false);
170 usb_core_enable_driver(USB_DRIVER_HID
, true);
171 #endif /* USB_ENABLE_CHARGING_ONLY */
172 #endif /* USB_ENABLE_HID */
174 #ifdef USB_ENABLE_CHARGING_ONLY
175 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY
, true);
177 exclusive_storage_access
= false;
179 usb_attach(); /* Powered only: attach now. */
184 #ifdef USB_ENABLE_STORAGE
185 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE
, true);
187 #ifdef USB_ENABLE_HID
188 usb_core_enable_driver(USB_DRIVER_HID
, usb_hid
);
190 #ifdef USB_ENABLE_CHARGING_ONLY
191 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY
, false);
193 /* Check any drivers enabled at this point for exclusive storage
194 * access requirements. */
195 exclusive_storage_access
= usb_core_any_exclusive_storage();
197 if(exclusive_storage_access
)
200 usb_attach(); /* Not exclusive: attach now. */
205 if(exclusive_storage_access
)
206 usb_release_exclusive_storage();
214 #ifdef USE_ROCKBOX_USB
215 static inline void usb_slave_mode(bool on
)
222 #ifdef HAVE_PRIORITY_SCHEDULING
223 thread_set_priority(THREAD_ID_CURRENT
, PRIORITY_REALTIME
);
228 else /* usb_state == USB_INSERTED (only!) */
231 #ifdef HAVE_PRIORITY_SCHEDULING
232 thread_set_priority(THREAD_ID_CURRENT
, PRIORITY_SYSTEM
);
234 /* Entered exclusive mode */
235 rc
= disk_mount_all();
236 if(rc
<= 0) /* no partition */
237 panicf("mount: %d",rc
);
242 #else /* !USB_ROCKBOX_USB */
243 static inline void usb_slave_mode(bool on
)
247 /* until we have native mass-storage mode, we want to reboot on
252 #endif /* USE_ROCKBOX_USB */
254 void usb_signal_transfer_completion(
255 struct usb_transfer_completion_event_data
* event_data
)
257 queue_post(&usb_queue
, USB_TRANSFER_COMPLETION
, (intptr_t)event_data
);
260 #else /* !HAVE_USBSTACK */
263 static inline void usb_handle_hotswap(long id
)
265 #if (CONFIG_STORAGE & STORAGE_MMC)
268 case SYS_HOTSWAP_INSERTED
:
269 case SYS_HOTSWAP_EXTRACTED
:
270 if(usb_state
== USB_INSERTED
)
273 usb_mmc_countdown
= HZ
/2; /* re-enable after 0.5 sec */
277 if(usb_state
== USB_INSERTED
)
278 usb_enable(true); /* reenable only if still inserted */
281 #endif /* STORAGE_MMC */
284 #endif /* HAVE_HOTSWAP */
286 static inline bool usb_configure_drivers(int for_state
)
291 exclusive_storage_access
= false;
294 exclusive_storage_access
= true;
297 if(exclusive_storage_access
)
298 usb_release_exclusive_storage();
305 static inline void usb_slave_mode(bool on
)
311 DEBUGF("Entering USB slave mode\n");
313 storage_soft_reset();
315 storage_enable(false);
321 DEBUGF("Leaving USB slave mode\n");
323 cpu_idle_mode(false);
325 /* Let the ISDx00 settle */
332 panicf("storage: %d",rc
);
334 rc
= disk_mount_all();
335 if(rc
<= 0) /* no partition */
336 panicf("mount: %d",rc
);
339 #endif /* HAVE_USBSTACK */
341 #ifdef HAVE_USB_POWER
342 static inline bool usb_power_button(void)
344 #if (defined(IRIVER_H10) || defined (IRIVER_H10_5GB)) && !defined(USE_ROCKBOX_USB)
345 return (button_status() & ~USBPOWER_BTN_IGNORE
) != USBPOWER_BUTTON
;
347 return (button_status() & ~USBPOWER_BTN_IGNORE
) == USBPOWER_BUTTON
;
351 #ifdef USB_FIREWIRE_HANDLING
352 static inline bool usb_reboot_button(void)
354 return (button_status() & ~USBPOWER_BTN_IGNORE
) != USBPOWER_BUTTON
;
357 #else /* !HAVE_USB_POWER */
358 static inline bool usb_power_button(void)
363 #ifdef USB_FIREWIRE_HANDLING
364 static inline bool usb_reboot_button(void)
369 #endif /* HAVE_USB_POWER */
371 #ifndef USB_DRIVER_CLOSE
372 static void usb_thread(void) NORETURN_ATTR
;
374 static void usb_thread(void)
376 int num_acks_to_expect
= 0;
377 long last_broadcast_tick
= current_tick
;
378 struct queue_event ev
;
382 queue_wait(&usb_queue
, &ev
);
385 /*** Main USB thread duties ***/
388 case USB_TRANSFER_COMPLETION
:
389 usb_core_handle_transfer_completion(
390 (struct usb_transfer_completion_event_data
*)ev
.data
);
392 #endif /* HAVE_USBSTACK */
395 #ifdef USB_DELAYED_INSERT
396 if(usb_state
!= USB_POWERED
)
398 #else /* !USB_DELAYED_INSERT */
399 if(usb_state
!= USB_EXTRACTED
)
402 if(usb_do_screendump())
405 usb_state
= USB_POWERED
;
406 #endif /* USB_DELAYED_INSERT */
408 if(usb_power_button())
410 /* Only charging is desired */
411 usb_configure_drivers(USB_POWERED
);
415 if(!usb_configure_drivers(USB_INSERTED
))
416 break; /* Exclusive storage access not required */
418 /* Tell all threads that they have to back off the storage.
419 We subtract one for our own thread. Expect an ACK for every
420 listener for each broadcast they received. If it has been too
421 long, the user might have entered a screen that didn't ACK
422 when inserting the cable, such as a debugging screen. In that
423 case, reset the count or else USB would be locked out until
424 rebooting because it most likely won't ever come. Simply
425 resetting to the most recent broadcast count is racy. */
426 if(TIME_AFTER(current_tick
, last_broadcast_tick
+ HZ
*5))
428 num_acks_to_expect
= 0;
429 last_broadcast_tick
= current_tick
;
432 num_acks_to_expect
+= queue_broadcast(SYS_USB_CONNECTED
, 0) - 1;
433 DEBUGF("USB inserted. Waiting for %d acks...\n",
436 /* Leave the state as USB_POWERED until the expected number of
437 ACKS are received. */
441 case SYS_USB_CONNECTED_ACK
:
442 if(num_acks_to_expect
> 0 && --num_acks_to_expect
== 0)
444 DEBUGF("All threads have acknowledged the connect.\n");
445 if(usb_state
== USB_POWERED
)
447 usb_slave_mode(true);
448 usb_state
= USB_INSERTED
;
453 DEBUGF("usb: got ack, %d to go...\n",
457 /* SYS_USB_CONNECTED_ACK */
459 #ifdef USB_DELAYED_INSERT
460 /* In this case, these events handle cable insertion. USB driver or
461 core determines USB_INSERTED. */
463 if(usb_state
!= USB_EXTRACTED
)
466 if(usb_do_screendump())
469 usb_state
= USB_POWERED
;
475 if(usb_state
== USB_POWERED
)
477 /* Fall-through - other legal states can be USB_INSERTED or
479 #endif /* USB_DELAYED_INSERT */
481 if(usb_state
== USB_EXTRACTED
)
484 /* Only disable the USB slave mode if we really have enabled
485 it. Some expected acks may not have been received. */
486 if(usb_state
== USB_INSERTED
)
487 usb_slave_mode(false);
489 usb_state
= USB_EXTRACTED
;
491 /* Ok to broadcast disconnect now */
492 usb_configure_drivers(USB_EXTRACTED
);
494 /* USB_UNPOWERED: USB_EXTRACTED: */
496 /*** Miscellaneous USB thread duties ***/
500 case SYS_HOTSWAP_INSERTED
:
501 case SYS_HOTSWAP_EXTRACTED
:
502 #if (CONFIG_STORAGE & STORAGE_MMC)
505 usb_handle_hotswap(ev
.id
);
509 #ifdef USB_FIREWIRE_HANDLING
510 case USB_REQUEST_REBOOT
:
511 if(usb_reboot_button())
517 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
518 case USB_CHARGER_UPDATE
:
519 usb_charging_maxcurrent_change(usb_charging_maxcurrent());
524 #ifdef USB_DRIVER_CLOSE
532 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
533 void usb_charger_update(void)
535 queue_post(&usb_queue
, USB_CHARGER_UPDATE
, 0);
539 #ifdef USB_STATUS_BY_EVENT
540 void usb_status_event(int current_status
)
542 /* Caller isn't expected to filter for changes in status.
544 * USB_DETECT_BY_DRV/CORE: USB_POWERED, USB_UNPOWERED,
545 USB_INSERTED (driver/core)
546 * else: USB_INSERTED, USB_EXTRACTED
548 if(usb_monitor_enabled
)
550 int oldstatus
= disable_irq_save(); /* Dual-use function */
551 queue_remove_from_head(&usb_queue
, current_status
);
552 queue_post(&usb_queue
, current_status
, 0);
553 restore_irq(oldstatus
);
557 void usb_start_monitoring(void)
559 int oldstatus
= disable_irq_save(); /* Sync to event */
560 int status
= usb_detect();
562 usb_monitor_enabled
= true;
564 /* An event may have been missed because it was sent before monitoring
565 * was enabled due to the connector already having been inserted before
566 * before or during boot. */
567 #ifdef USB_DELAYED_INSERT
568 /* Filter the status - USB_INSERTED may happen later */
569 status
= (status
== USB_INSERTED
) ? USB_POWERED
: USB_UNPOWERED
;
571 usb_status_event(status
);
573 #ifdef USB_FIREWIRE_HANDLING
574 if(firewire_detect())
575 usb_firewire_connect_event();
578 restore_irq(oldstatus
);
581 #ifdef USB_FIREWIRE_HANDLING
582 void usb_firewire_connect_event(void)
584 queue_post(&usb_queue
, USB_REQUEST_REBOOT
, 0);
586 #endif /* USB_FIREWIRE_HANDLING */
588 #else /* !USB_STATUS_BY_EVENT */
590 static void usb_tick(void)
592 #define NUM_POLL_READINGS (HZ/5)
593 static int usb_countdown
= -1;
594 static int last_usb_status
= USB_EXTRACTED
;
595 #ifdef USB_FIREWIRE_HANDLING
596 static int firewire_countdown
= -1;
597 static int last_firewire_status
= false;
600 if(usb_monitor_enabled
)
602 #ifdef USB_FIREWIRE_HANDLING
603 int current_firewire_status
= firewire_detect();
604 if(current_firewire_status
!= last_firewire_status
)
606 last_firewire_status
= current_firewire_status
;
607 firewire_countdown
= NUM_POLL_READINGS
;
611 /* Count down until it gets negative */
612 if(firewire_countdown
>= 0)
613 firewire_countdown
--;
615 /* Report to the thread if we have had 3 identical status
617 if(firewire_countdown
== 0)
619 queue_post(&usb_queue
, USB_REQUEST_REBOOT
, 0);
622 #endif /* USB_FIREWIRE_HANDLING */
624 int current_status
= usb_detect();
626 /* Only report when the status has changed */
627 if(current_status
!= last_usb_status
)
629 last_usb_status
= current_status
;
630 usb_countdown
= NUM_POLL_READINGS
;
634 /* Count down until it gets negative */
635 if(usb_countdown
>= 0)
638 /* Report to the thread if we have had 3 identical status
640 if(usb_countdown
== 0)
642 queue_post(&usb_queue
, current_status
, 0);
646 #if (CONFIG_STORAGE & STORAGE_MMC)
647 if(usb_mmc_countdown
> 0)
650 if(usb_mmc_countdown
== 0)
651 queue_post(&usb_queue
, USB_REENABLE
, 0);
656 void usb_start_monitoring(void)
658 usb_monitor_enabled
= true;
660 #endif /* USB_STATUS_BY_EVENT */
661 #endif /* USB_FULL_INIT */
663 void usb_acknowledge(long id
)
665 queue_post(&usb_queue
, id
, 0);
675 queue_init(&usb_queue
, true);
677 usb_thread_entry
= create_thread(usb_thread
, usb_stack
,
678 sizeof(usb_stack
), 0, usb_thread_name
679 IF_PRIO(, PRIORITY_SYSTEM
) IF_COP(, CPU
));
681 #ifndef USB_STATUS_BY_EVENT
682 tick_add_task(usb_tick
);
684 #endif /* USB_FULL_INIT */
687 void usb_wait_for_disconnect(struct event_queue
*q
)
690 struct queue_event ev
;
692 /* Don't return until we get SYS_USB_DISCONNECTED */
696 if(ev
.id
== SYS_USB_DISCONNECTED
)
699 #endif /* USB_FULL_INIT */
703 int usb_wait_for_disconnect_w_tmo(struct event_queue
*q
, int ticks
)
706 struct queue_event ev
;
708 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
711 queue_wait_w_tmo(q
, &ev
, ticks
);
714 case SYS_USB_DISCONNECTED
:
720 #endif /* USB_FULL_INIT */
721 (void)q
; (void)ticks
;
725 #ifdef USB_DRIVER_CLOSE
728 unsigned int thread
= usb_thread_entry
;
729 usb_thread_entry
= 0;
734 #ifndef USB_STATUS_BY_EVENT
735 tick_remove_task(usb_tick
);
737 usb_monitor_enabled
= false;
739 queue_post(&usb_queue
, USB_QUIT
, 0);
742 #endif /* USB_DRIVER_CLOSE */
744 bool usb_inserted(void)
746 return usb_state
== USB_INSERTED
|| usb_state
== USB_POWERED
;
750 bool usb_exclusive_storage(void)
752 return exclusive_storage_access
;
754 #endif /* HAVE_USBSTACK */
756 int usb_release_exclusive_storage(void)
759 exclusive_storage_access
= false;
760 /* Tell all threads that we are back in business */
761 bccount
= queue_broadcast(SYS_USB_DISCONNECTED
, 0) - 1;
762 DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount
);
766 #ifdef HAVE_USB_POWER
767 bool usb_powered(void)
769 return usb_state
== USB_POWERED
;
771 #endif /* HAVE_USB_POWER */
773 #ifdef USB_ENABLE_HID
774 void usb_set_hid(bool enable
)
777 usb_core_enable_driver(USB_DRIVER_HID
, usb_hid
);
779 #endif /* USB_ENABLE_HID */
781 #else /* SIMULATOR || USB_NONE */
784 bool usb_inserted(void)
788 #endif /* USB_NONE */
790 /* Dummy simulator functions */
791 void usb_acknowledge(long id
)
800 void usb_start_monitoring(void)
806 return USB_EXTRACTED
;
809 void usb_wait_for_disconnect(struct event_queue
*q
)
814 #endif /* !USB_NONE && !SIMULATOR */