Fix warning
[kugel-rb.git] / firmware / usb.c
blob2f277ac2007ee3a94b339c9294ff41fc4b9fa110
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 #if defined(USB_DETECT_BY_DRV) || defined(USB_DETECT_BY_CORE)
61 /* These aren't treated differently here */
62 #define USB_DELAYED_INSERT
63 #endif
65 #ifdef HAVE_LCD_BITMAP
66 bool do_screendump_instead_of_usb = false;
67 #endif
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;
76 #endif
78 /* Make sure there's enough stack space for screendump */
79 #ifdef USB_FULL_INIT
80 static long usb_stack[(DEFAULT_STACK_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 SHAREDBSS_ATTR;
86 static bool exclusive_storage_access = false;
87 #ifdef USB_ENABLE_HID
88 static bool usb_hid = true;
89 #endif
91 #ifdef USB_FULL_INIT
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. */
99 sleep(HZ*2);
100 #endif
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 */
110 #ifdef IPOD_NANO2G
111 memcpy((void *)0x0002bf00, "diskmodehotstuff\1\0\0\0", 20);
112 #endif
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;
125 screen_dump();
126 #ifdef HAVE_REMOTE_LCD
127 remote_screen_dump();
128 #endif
129 return true;
132 return false;
134 #else /* !HAVE_LCD_BITMAP */
135 static inline bool usb_do_screendump(void)
137 return false;
139 #endif /* HAVE_LCD_BITMAP */
142 #ifdef HAVE_USBSTACK
144 #ifdef HAVE_HOTSWAP
145 static inline void usb_handle_hotswap(long id)
147 switch(id)
149 case SYS_HOTSWAP_INSERTED:
150 case SYS_HOTSWAP_EXTRACTED:
151 usb_core_hotswap_event(1, id == SYS_HOTSWAP_INSERTED);
152 break;
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)
160 switch(for_state)
162 case USB_POWERED:
163 #ifdef USB_ENABLE_STORAGE
164 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false);
165 #endif
166 #ifdef USB_ENABLE_HID
167 #ifdef USB_ENABLE_CHARGING_ONLY
168 usb_core_enable_driver(USB_DRIVER_HID, false);
169 #else
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);
176 #endif
177 exclusive_storage_access = false;
179 usb_attach(); /* Powered only: attach now. */
180 break;
181 /* USB_POWERED: */
183 case USB_INSERTED:
184 #ifdef USB_ENABLE_STORAGE
185 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true);
186 #endif
187 #ifdef USB_ENABLE_HID
188 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
189 #endif
190 #ifdef USB_ENABLE_CHARGING_ONLY
191 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
192 #endif
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)
198 return true;
200 usb_attach(); /* Not exclusive: attach now. */
201 break;
202 /* USB_INSERTED: */
204 case USB_EXTRACTED:
205 if(exclusive_storage_access)
206 usb_release_exclusive_storage();
207 break;
208 /* USB_EXTRACTED: */
211 return false;
214 #ifdef USE_ROCKBOX_USB
215 static inline void usb_slave_mode(bool on)
217 int rc;
219 if(on)
221 trigger_cpu_boost();
222 #ifdef HAVE_PRIORITY_SCHEDULING
223 thread_set_priority(thread_self(), PRIORITY_REALTIME);
224 #endif
225 disk_unmount_all();
226 usb_attach();
228 else /* usb_state == USB_INSERTED (only!) */
230 usb_enable(false);
231 #ifdef HAVE_PRIORITY_SCHEDULING
232 thread_set_priority(thread_self(), PRIORITY_SYSTEM);
233 #endif
234 /* Entered exclusive mode */
235 rc = disk_mount_all();
236 if(rc <= 0) /* no partition */
237 panicf("mount: %d",rc);
239 cancel_cpu_boost();
242 #else /* !USB_ROCKBOX_USB */
243 static inline void usb_slave_mode(bool on)
245 if(on)
247 /* until we have native mass-storage mode, we want to reboot on
248 usb host connect */
249 try_reboot();
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 */
262 #ifdef HAVE_HOTSWAP
263 static inline void usb_handle_hotswap(long id)
265 #if (CONFIG_STORAGE & STORAGE_MMC)
266 switch(id)
268 case SYS_HOTSWAP_INSERTED:
269 case SYS_HOTSWAP_EXTRACTED:
270 if(usb_state == USB_INSERTED)
272 usb_enable(false);
273 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
275 break;
276 case USB_REENABLE:
277 if(usb_state == USB_INSERTED)
278 usb_enable(true); /* reenable only if still inserted */
279 break;
281 #endif /* STORAGE_MMC */
282 (void)id;
284 #endif /* HAVE_HOTSWAP */
286 static inline bool usb_configure_drivers(int for_state)
288 switch(for_state)
290 case USB_POWERED:
291 exclusive_storage_access = false;
292 break;
293 case USB_INSERTED:
294 exclusive_storage_access = true;
295 return true;
296 case USB_EXTRACTED:
297 if(exclusive_storage_access)
298 usb_release_exclusive_storage();
299 break;
302 return false;
305 static inline void usb_slave_mode(bool on)
307 int rc;
309 if(on)
311 DEBUGF("Entering USB slave mode\n");
312 disk_unmount_all();
313 storage_soft_reset();
314 storage_init();
315 storage_enable(false);
316 usb_enable(true);
317 cpu_idle_mode(true);
319 else
321 DEBUGF("Leaving USB slave mode\n");
323 cpu_idle_mode(false);
325 /* Let the ISDx00 settle */
326 sleep(HZ*1);
328 usb_enable(false);
330 rc = storage_init();
331 if(rc)
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 return (button_status() & ~USBPOWER_BTN_IGNORE);
347 #ifdef USB_FIREWIRE_HANDLING
348 static inline bool usb_reboot_button(void)
350 return (button_status() & ~USBPOWER_BTN_IGNORE);
352 #endif
353 #else /* !HAVE_USB_POWER */
354 static inline bool usb_power_button(void)
356 return false;
359 #ifdef USB_FIREWIRE_HANDLING
360 static inline bool usb_reboot_button(void)
362 return false;
364 #endif
365 #endif /* HAVE_USB_POWER */
367 #ifndef USB_DRIVER_CLOSE
368 static void usb_thread(void) NORETURN_ATTR;
369 #endif
370 static void usb_thread(void)
372 #ifdef USB_DELAYED_INSERT
373 bool host_detected = false;
374 #endif
375 int num_acks_to_expect = 0;
376 long last_broadcast_tick = current_tick;
377 struct queue_event ev;
379 while(1)
381 queue_wait(&usb_queue, &ev);
382 switch(ev.id)
384 /*** Main USB thread duties ***/
386 #ifdef HAVE_USBSTACK
387 case USB_TRANSFER_COMPLETION:
388 usb_core_handle_transfer_completion(
389 (struct usb_transfer_completion_event_data*)ev.data);
390 break;
391 #endif /* HAVE_USBSTACK */
393 case USB_INSERTED:
394 #ifdef USB_DELAYED_INSERT
395 if(usb_state != USB_POWERED)
396 break;
398 if (host_detected)
399 break; /* Drivers configured but we're still USB_POWERED */
401 host_detected = true;
402 #else /* !USB_DELAYED_INSERT */
403 if(usb_state != USB_EXTRACTED)
404 break;
406 if(usb_do_screendump())
407 break;
409 usb_state = USB_POWERED;
410 #endif /* USB_DELAYED_INSERT */
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 inserted. Waiting for %d acks...\n",
438 num_acks_to_expect);
440 /* Leave the state as USB_POWERED until the expected number of
441 ACKS are received. */
442 break;
443 /* USB_INSERTED: */
445 case SYS_USB_CONNECTED_ACK:
446 if(num_acks_to_expect > 0 && --num_acks_to_expect == 0)
448 DEBUGF("All threads have acknowledged the connect.\n");
449 if(usb_state == USB_POWERED)
451 usb_slave_mode(true);
452 usb_state = USB_INSERTED;
455 else
457 DEBUGF("usb: got ack, %d to go...\n",
458 num_acks_to_expect);
460 break;
461 /* SYS_USB_CONNECTED_ACK */
463 #ifdef USB_DELAYED_INSERT
464 /* In this case, these events handle cable insertion. USB driver or
465 core determines USB_INSERTED. */
466 case USB_POWERED:
467 if(usb_state != USB_EXTRACTED)
468 break;
470 if(usb_do_screendump())
471 break;
473 usb_state = USB_POWERED;
474 usb_enable(true);
475 break;
476 /* USB_POWERED: */
478 case USB_UNPOWERED:
479 if(usb_state == USB_POWERED)
480 usb_enable(false);
481 /* Fall-through - other legal states can be USB_INSERTED or
482 USB_SCREENDUMP */
483 #endif /* USB_DELAYED_INSERT */
484 case USB_EXTRACTED:
485 if(usb_state == USB_EXTRACTED)
486 break;
488 /* Only disable the USB slave mode if we really have enabled
489 it. Some expected acks may not have been received. */
490 if(usb_state == USB_INSERTED)
491 usb_slave_mode(false);
493 usb_state = USB_EXTRACTED;
495 /* Ok to broadcast disconnect now */
496 usb_configure_drivers(USB_EXTRACTED);
497 #ifdef USB_DELAYED_INSERT
498 host_detected = false;
499 #endif
500 break;
501 /* USB_UNPOWERED: 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 #endif
515 /* FIREWIRE */
516 #ifdef USB_FIREWIRE_HANDLING
517 case USB_REQUEST_REBOOT:
518 if(usb_reboot_button())
519 try_reboot();
520 break;
521 #endif
523 /* CHARGING */
524 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
525 case USB_CHARGER_UPDATE:
526 usb_charging_maxcurrent_change(usb_charging_maxcurrent());
527 break;
528 #endif
530 /* CLOSE */
531 #ifdef USB_DRIVER_CLOSE
532 case USB_QUIT:
533 return;
534 #endif
535 } /* switch */
536 } /* while */
539 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
540 void usb_charger_update(void)
542 queue_post(&usb_queue, USB_CHARGER_UPDATE, 0);
544 #endif
546 #ifdef USB_STATUS_BY_EVENT
547 void usb_status_event(int current_status)
549 /* Caller isn't expected to filter for changes in status.
550 * current_status:
551 * USB_DETECT_BY_DRV/CORE: USB_POWERED, USB_UNPOWERED,
552 USB_INSERTED (driver/core)
553 * else: 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 #ifdef USB_DELAYED_INSERT
575 /* Filter the status - USB_INSERTED may happen later */
576 status = (status == USB_EXTRACTED) ? USB_UNPOWERED : USB_POWERED;
577 #endif
578 usb_status_event(status);
580 #ifdef USB_FIREWIRE_HANDLING
581 if(firewire_detect())
582 usb_firewire_connect_event();
583 #endif
585 restore_irq(oldstatus);
588 #ifdef USB_FIREWIRE_HANDLING
589 void usb_firewire_connect_event(void)
591 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
593 #endif /* USB_FIREWIRE_HANDLING */
595 #else /* !USB_STATUS_BY_EVENT */
597 static void usb_tick(void)
599 #define NUM_POLL_READINGS (HZ/5)
600 static int usb_countdown = -1;
601 static int last_usb_status = USB_EXTRACTED;
602 #ifdef USB_FIREWIRE_HANDLING
603 static int firewire_countdown = -1;
604 static int last_firewire_status = false;
605 #endif
607 if(usb_monitor_enabled)
609 #ifdef USB_FIREWIRE_HANDLING
610 int current_firewire_status = firewire_detect();
611 if(current_firewire_status != last_firewire_status)
613 last_firewire_status = current_firewire_status;
614 firewire_countdown = NUM_POLL_READINGS;
616 else
618 /* Count down until it gets negative */
619 if(firewire_countdown >= 0)
620 firewire_countdown--;
622 /* Report to the thread if we have had 3 identical status
623 readings in a row */
624 if(firewire_countdown == 0)
626 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
629 #endif /* USB_FIREWIRE_HANDLING */
631 int current_status = usb_detect();
633 /* Only report when the status has changed */
634 if(current_status != last_usb_status)
636 last_usb_status = current_status;
637 usb_countdown = NUM_POLL_READINGS;
639 else
641 /* Count down until it gets negative */
642 if(usb_countdown >= 0)
643 usb_countdown--;
645 /* Report to the thread if we have had 3 identical status
646 readings in a row */
647 if(usb_countdown == 0)
649 queue_post(&usb_queue, current_status, 0);
653 #if (CONFIG_STORAGE & STORAGE_MMC)
654 if(usb_mmc_countdown > 0)
656 usb_mmc_countdown--;
657 if(usb_mmc_countdown == 0)
658 queue_post(&usb_queue, USB_REENABLE, 0);
660 #endif
663 void usb_start_monitoring(void)
665 usb_monitor_enabled = true;
667 #endif /* USB_STATUS_BY_EVENT */
668 #endif /* USB_FULL_INIT */
670 void usb_acknowledge(long id)
672 queue_post(&usb_queue, id, 0);
675 void usb_init(void)
677 usb_init_device();
679 #ifdef USB_FULL_INIT
680 usb_enable(false);
682 queue_init(&usb_queue, true);
684 usb_thread_entry = create_thread(usb_thread, usb_stack,
685 sizeof(usb_stack), 0, usb_thread_name
686 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
688 #ifndef USB_STATUS_BY_EVENT
689 tick_add_task(usb_tick);
690 #endif
691 #endif /* USB_FULL_INIT */
694 void usb_wait_for_disconnect(struct event_queue *q)
696 #ifdef USB_FULL_INIT
697 struct queue_event ev;
699 /* Don't return until we get SYS_USB_DISCONNECTED */
700 while(1)
702 queue_wait(q, &ev);
703 if(ev.id == SYS_USB_DISCONNECTED)
704 return;
706 #endif /* USB_FULL_INIT */
707 (void)q;
710 int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)
712 #ifdef USB_FULL_INIT
713 struct queue_event ev;
715 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
716 while(1)
718 queue_wait_w_tmo(q, &ev, ticks);
719 switch(ev.id)
721 case SYS_USB_DISCONNECTED:
722 return 0;
723 case SYS_TIMEOUT:
724 return 1;
727 #endif /* USB_FULL_INIT */
728 (void)q; (void)ticks;
729 return 0;
732 #ifdef USB_DRIVER_CLOSE
733 void usb_close(void)
735 unsigned int thread = usb_thread_entry;
736 usb_thread_entry = 0;
738 if(thread == 0)
739 return;
741 #ifndef USB_STATUS_BY_EVENT
742 tick_remove_task(usb_tick);
743 #endif
744 usb_monitor_enabled = false;
746 queue_post(&usb_queue, USB_QUIT, 0);
747 thread_wait(thread);
749 #endif /* USB_DRIVER_CLOSE */
751 bool usb_inserted(void)
753 return usb_state == USB_INSERTED || usb_state == USB_POWERED;
756 #ifdef HAVE_USBSTACK
757 bool usb_exclusive_storage(void)
759 /* Storage isn't actually exclusive until slave mode has been entered */
760 return exclusive_storage_access && usb_state == USB_INSERTED;
762 #endif /* HAVE_USBSTACK */
764 int usb_release_exclusive_storage(void)
766 int bccount;
767 exclusive_storage_access = false;
768 /* Tell all threads that we are back in business */
769 bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
770 DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount);
771 return bccount;
774 #ifdef HAVE_USB_POWER
775 bool usb_powered(void)
777 return usb_state == USB_POWERED;
779 #endif /* HAVE_USB_POWER */
781 #ifdef USB_ENABLE_HID
782 void usb_set_hid(bool enable)
784 usb_hid = enable;
785 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
787 #endif /* USB_ENABLE_HID */
789 #else /* SIMULATOR || USB_NONE */
791 #ifdef USB_NONE
792 bool usb_inserted(void)
794 return false;
796 #endif /* USB_NONE */
798 /* Dummy simulator functions */
799 void usb_acknowledge(long id)
801 id = id;
804 void usb_init(void)
808 void usb_start_monitoring(void)
812 int usb_detect(void)
814 return USB_EXTRACTED;
817 void usb_wait_for_disconnect(struct event_queue *q)
819 (void)q;
822 #endif /* !USB_NONE && !SIMULATOR */