Fix unused-but-set warnings in helper functions.
[maemo-rb.git] / firmware / usb.c
blob56f6fb7230bffc50c9c88be8e612cf97984bb597
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 #else /* !HAVE_USBSTACK */
275 static inline void usb_stack_enable(bool enable)
277 (void)enable;
280 #ifdef HAVE_HOTSWAP
281 static inline void usb_handle_hotswap(long id)
283 #if (CONFIG_STORAGE & STORAGE_MMC)
284 switch(id)
286 case SYS_HOTSWAP_INSERTED:
287 case SYS_HOTSWAP_EXTRACTED:
288 if(usb_state == USB_INSERTED)
290 usb_enable(false);
291 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
293 break;
294 case USB_REENABLE:
295 if(usb_state == USB_INSERTED)
296 usb_enable(true); /* reenable only if still inserted */
297 break;
299 #endif /* STORAGE_MMC */
300 (void)id;
302 #endif /* HAVE_HOTSWAP */
304 static inline bool usb_configure_drivers(int for_state)
306 switch(for_state)
308 case USB_POWERED:
309 exclusive_storage_access = false;
310 break;
311 case USB_INSERTED:
312 exclusive_storage_access = true;
313 return true;
314 case USB_EXTRACTED:
315 if(exclusive_storage_access)
316 usb_release_exclusive_storage();
317 break;
320 return false;
323 static inline void usb_slave_mode(bool on)
325 int rc;
327 if(on)
329 DEBUGF("Entering USB slave mode\n");
330 disk_unmount_all();
331 storage_soft_reset();
332 storage_init();
333 storage_enable(false);
334 usb_enable(true);
335 cpu_idle_mode(true);
337 else
339 DEBUGF("Leaving USB slave mode\n");
341 cpu_idle_mode(false);
343 /* Let the ISDx00 settle */
344 sleep(HZ*1);
346 usb_enable(false);
348 rc = storage_init();
349 if(rc)
350 panicf("storage: %d",rc);
352 sleep(HZ/10);
353 rc = disk_mount_all();
354 if(rc <= 0) /* no partition */
355 panicf("mount: %d",rc);
358 #endif /* HAVE_USBSTACK */
360 static void usb_set_host_present(bool present)
362 if(usb_host_present == present)
363 return;
365 usb_host_present = present;
367 if(!usb_host_present)
369 usb_configure_drivers(USB_EXTRACTED);
370 return;
373 if(usb_power_button())
375 /* Only charging is desired */
376 usb_configure_drivers(USB_POWERED);
377 return;
380 if(!usb_configure_drivers(USB_INSERTED))
381 return; /* Exclusive storage access not required */
383 /* Tell all threads that they have to back off the storage.
384 We subtract one for our own thread. Expect an ACK for every
385 listener for each broadcast they received. If it has been too
386 long, the user might have entered a screen that didn't ACK
387 when inserting the cable, such as a debugging screen. In that
388 case, reset the count or else USB would be locked out until
389 rebooting because it most likely won't ever come. Simply
390 resetting to the most recent broadcast count is racy. */
391 if(TIME_AFTER(current_tick, usb_last_broadcast_tick + HZ*5))
393 usb_num_acks_to_expect = 0;
394 usb_last_broadcast_tick = current_tick;
397 usb_num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
398 DEBUGF("usb: waiting for %d acks...\n", usb_num_acks_to_expect);
401 static bool usb_handle_connected_ack(void)
403 if(usb_num_acks_to_expect > 0 && --usb_num_acks_to_expect == 0)
405 DEBUGF("usb: all threads have acknowledged the connect.\n");
406 if(usb_host_present)
408 usb_slave_mode(true);
409 return true;
412 else
414 DEBUGF("usb: got ack, %d to go...\n", usb_num_acks_to_expect);
417 return false;
420 /*--- General driver code ---*/
421 static void NORETURN_ATTR usb_thread(void)
423 struct queue_event ev;
425 while(1)
427 queue_wait(&usb_queue, &ev);
429 switch(ev.id)
431 /*** Main USB thread duties ***/
433 #ifdef HAVE_USBSTACK
434 case USB_TRANSFER_COMPLETION:
435 if(usb_state <= USB_EXTRACTED)
436 break;
438 #ifdef USB_DETECT_BY_REQUEST
439 usb_set_host_present(true);
440 #endif
442 usb_core_handle_transfer_completion(
443 (struct usb_transfer_completion_event_data*)ev.data);
444 break;
445 #endif /* HAVE_USBSTACK */
447 case USB_INSERTED:
448 if(usb_state != USB_EXTRACTED)
449 break;
451 #ifdef HAVE_LCD_BITMAP
452 if(usb_do_screendump())
454 usb_state = USB_SCREENDUMP;
455 break;
457 #endif
459 usb_state = USB_POWERED;
460 usb_stack_enable(true);
462 #ifndef USB_DETECT_BY_REQUEST
463 usb_set_host_present(true);
464 #endif
465 break;
466 /* USB_INSERTED */
468 case SYS_USB_CONNECTED_ACK:
469 if(usb_handle_connected_ack())
470 usb_state = USB_INSERTED;
471 break;
472 /* SYS_USB_CONNECTED_ACK */
474 case USB_EXTRACTED:
475 if(usb_state == USB_EXTRACTED)
476 break;
478 if(usb_state == USB_POWERED || usb_state == USB_INSERTED)
479 usb_stack_enable(false);
481 /* Only disable the USB slave mode if we really have enabled
482 it. Some expected acks may not have been received. */
483 if(usb_state == USB_INSERTED)
484 usb_slave_mode(false);
486 usb_state = USB_EXTRACTED;
488 usb_set_host_present(false);
489 break;
490 /* USB_EXTRACTED: */
492 /*** Miscellaneous USB thread duties ***/
494 /* HOTSWAP */
495 #ifdef HAVE_HOTSWAP
496 case SYS_HOTSWAP_INSERTED:
497 case SYS_HOTSWAP_EXTRACTED:
498 #if (CONFIG_STORAGE & STORAGE_MMC)
499 case USB_REENABLE:
500 #endif
501 usb_handle_hotswap(ev.id);
502 break;
503 #endif
505 /* FIREWIRE */
506 #ifdef USB_FIREWIRE_HANDLING
507 case USB_REQUEST_REBOOT:
508 if(usb_reboot_button())
509 try_reboot();
510 break;
511 #endif
513 /* CHARGING */
514 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
515 case USB_CHARGER_UPDATE:
516 usb_charging_maxcurrent_change(usb_charging_maxcurrent());
517 break;
518 #endif
520 /* CLOSE */
521 #ifdef USB_DRIVER_CLOSE
522 case USB_QUIT:
523 thread_exit();
524 break;
525 #endif
526 } /* switch */
527 } /* while */
530 #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
531 void usb_charger_update(void)
533 queue_post(&usb_queue, USB_CHARGER_UPDATE, 0);
535 #endif
537 #ifdef USB_STATUS_BY_EVENT
538 void usb_status_event(int current_status)
540 /* Caller isn't expected to filter for changes in status.
541 * current_status:
542 * USB_INSERTED, USB_EXTRACTED
544 if(usb_monitor_enabled)
546 int oldstatus = disable_irq_save(); /* Dual-use function */
547 queue_remove_from_head(&usb_queue, current_status);
548 queue_post(&usb_queue, current_status, 0);
549 restore_irq(oldstatus);
553 void usb_start_monitoring(void)
555 int oldstatus = disable_irq_save(); /* Sync to event */
556 int status = usb_detect();
558 usb_monitor_enabled = true;
560 /* An event may have been missed because it was sent before monitoring
561 * was enabled due to the connector already having been inserted before
562 * before or during boot. */
563 usb_status_event(status);
565 #ifdef USB_FIREWIRE_HANDLING
566 if(firewire_detect())
567 usb_firewire_connect_event();
568 #endif
570 restore_irq(oldstatus);
573 #ifdef USB_FIREWIRE_HANDLING
574 void usb_firewire_connect_event(void)
576 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
578 #endif /* USB_FIREWIRE_HANDLING */
580 #else /* !USB_STATUS_BY_EVENT */
582 static void usb_tick(void)
584 #define NUM_POLL_READINGS (HZ/5)
585 static int usb_countdown = -1;
586 static int last_usb_status = USB_EXTRACTED;
587 #ifdef USB_FIREWIRE_HANDLING
588 static int firewire_countdown = -1;
589 static int last_firewire_status = false;
590 #endif
592 if(usb_monitor_enabled)
594 #ifdef USB_FIREWIRE_HANDLING
595 int current_firewire_status = firewire_detect();
596 if(current_firewire_status != last_firewire_status)
598 last_firewire_status = current_firewire_status;
599 firewire_countdown = NUM_POLL_READINGS;
601 else
603 /* Count down until it gets negative */
604 if(firewire_countdown >= 0)
605 firewire_countdown--;
607 /* Report to the thread if we have had 3 identical status
608 readings in a row */
609 if(firewire_countdown == 0)
611 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
614 #endif /* USB_FIREWIRE_HANDLING */
616 int current_status = usb_detect();
618 /* Only report when the status has changed */
619 if(current_status != last_usb_status)
621 last_usb_status = current_status;
622 usb_countdown = NUM_POLL_READINGS;
624 else
626 /* Count down until it gets negative */
627 if(usb_countdown >= 0)
628 usb_countdown--;
630 /* Report to the thread if we have had 3 identical status
631 readings in a row */
632 if(usb_countdown == 0)
634 queue_post(&usb_queue, current_status, 0);
638 #if (CONFIG_STORAGE & STORAGE_MMC)
639 if(usb_mmc_countdown > 0)
641 usb_mmc_countdown--;
642 if(usb_mmc_countdown == 0)
643 queue_post(&usb_queue, USB_REENABLE, 0);
645 #endif
648 void usb_start_monitoring(void)
650 usb_monitor_enabled = true;
652 #endif /* USB_STATUS_BY_EVENT */
653 #endif /* USB_FULL_INIT */
655 void usb_acknowledge(long id)
657 queue_post(&usb_queue, id, 0);
660 void usb_init(void)
662 #ifdef USB_FULL_INIT
663 usb_enable(false);
665 queue_init(&usb_queue, true);
667 usb_thread_entry = create_thread(usb_thread, usb_stack,
668 sizeof(usb_stack), 0, usb_thread_name
669 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
671 #ifndef USB_STATUS_BY_EVENT
672 tick_add_task(usb_tick);
673 #endif
674 #endif /* USB_FULL_INIT */
676 usb_init_device();
679 void usb_wait_for_disconnect(struct event_queue *q)
681 #ifdef USB_FULL_INIT
682 struct queue_event ev;
684 /* Don't return until we get SYS_USB_DISCONNECTED */
685 while(1)
687 queue_wait(q, &ev);
688 if(ev.id == SYS_USB_DISCONNECTED)
689 return;
691 #endif /* USB_FULL_INIT */
692 (void)q;
695 int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)
697 #ifdef USB_FULL_INIT
698 struct queue_event ev;
700 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
701 while(1)
703 queue_wait_w_tmo(q, &ev, ticks);
704 switch(ev.id)
706 case SYS_USB_DISCONNECTED:
707 return 0;
708 case SYS_TIMEOUT:
709 return 1;
712 #endif /* USB_FULL_INIT */
713 (void)q; (void)ticks;
714 return 0;
717 #ifdef USB_DRIVER_CLOSE
718 void usb_close(void)
720 unsigned int thread = usb_thread_entry;
721 usb_thread_entry = 0;
723 if(thread == 0)
724 return;
726 #ifndef USB_STATUS_BY_EVENT
727 tick_remove_task(usb_tick);
728 #endif
729 usb_monitor_enabled = false;
730 queue_post(&usb_queue, USB_QUIT, 0);
731 thread_wait(thread);
733 #endif /* USB_DRIVER_CLOSE */
735 bool usb_inserted(void)
737 return usb_state == USB_INSERTED || usb_state == USB_POWERED;
740 #ifdef HAVE_USBSTACK
741 bool usb_exclusive_storage(void)
743 /* Storage isn't actually exclusive until slave mode has been entered */
744 return exclusive_storage_access && usb_state == USB_INSERTED;
746 #endif /* HAVE_USBSTACK */
748 int usb_release_exclusive_storage(void)
750 int bccount;
751 exclusive_storage_access = false;
752 /* Tell all threads that we are back in business */
753 bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
754 DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount);
755 return bccount;
758 #ifdef HAVE_USB_POWER
759 bool usb_powered(void)
761 return usb_state == USB_POWERED;
763 #endif /* HAVE_USB_POWER */
765 #ifdef USB_ENABLE_HID
766 void usb_set_hid(bool enable)
768 usb_hid = enable;
769 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
771 #endif /* USB_ENABLE_HID */
773 #elif defined(USB_NONE)
774 /* Dummy functions for USB_NONE */
776 bool usb_inserted(void)
778 return false;
781 void usb_acknowledge(long id)
783 id = id;
786 void usb_init(void)
790 void usb_start_monitoring(void)
794 int usb_detect(void)
796 return USB_EXTRACTED;
799 void usb_wait_for_disconnect(struct event_queue *q)
801 (void)q;
803 #endif /* USB_NONE */