Data does not belong in .h files. Not even if it makes the .c file prettier.
[kugel-rb.git] / firmware / usb.c
blobe5c7565d39a4d193dbd0b4368f23eb45dce3c478
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 "ata.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 "sprintf.h"
40 #include "string.h"
41 #include "usb-target.h"
42 #ifdef HAVE_USBSTACK
43 #include "usb_core.h"
44 #endif
45 #ifdef IRIVER_H300_SERIES
46 #include "pcf50606.h" /* for pcf50606_usb_charging_... */
47 #endif
48 #include "logf.h"
50 /* Conditions under which we want the entire driver */
51 #if !defined(BOOTLOADER) || (CONFIG_CPU == SH7034) || \
52 (defined(TOSHIBA_GIGABEAT_S) && defined(USE_ROCKBOX_USB) && defined(USB_STORAGE)) || \
53 (defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx) || \
54 defined(CPU_TCC77X) || defined(CPU_TCC780X)))
55 #define USB_FULL_INIT
56 #endif
58 #ifdef HAVE_LCD_BITMAP
59 bool do_screendump_instead_of_usb = false;
60 #if defined(USB_FULL_INIT) && defined(BOOTLOADER)
61 static void screen_dump(void) {}
62 #else
63 void screen_dump(void); /* Nasty again. Defined in apps/ too */
64 #endif
65 #endif
67 #if !defined(SIMULATOR) && !defined(USB_NONE)
69 #define NUM_POLL_READINGS (HZ/5)
70 static int countdown;
72 static int usb_state;
74 #if defined(HAVE_MMC) && defined(USB_FULL_INIT)
75 static int usb_mmc_countdown = 0;
76 #endif
78 /* FIXME: The extra 0x800 is consumed by fat_mount() when the fsinfo
79 needs updating */
80 #ifdef USB_FULL_INIT
81 static long usb_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)];
82 static const char usb_thread_name[] = "usb";
83 static struct thread_entry *usb_thread_entry;
84 #endif
85 static struct event_queue usb_queue;
86 static int last_usb_status;
87 static bool usb_monitor_enabled;
88 #ifdef HAVE_USBSTACK
89 static bool exclusive_ata_access;
90 #endif
93 #if defined(IPOD_COLOR) || defined(IPOD_4G) \
94 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
95 static int firewire_countdown;
96 static bool last_firewire_status;
97 #endif
99 #ifdef USB_FULL_INIT
100 #ifndef HAVE_USBSTACK
101 static void usb_slave_mode(bool on)
103 int rc;
105 if(on)
107 DEBUGF("Entering USB slave mode\n");
108 ata_soft_reset();
109 ata_init();
110 ata_enable(false);
111 usb_enable(true);
113 else
115 DEBUGF("Leaving USB slave mode\n");
117 /* Let the ISDx00 settle */
118 sleep(HZ*1);
120 usb_enable(false);
122 rc = ata_init();
123 if(rc)
124 panicf("ata: %d",rc);
126 rc = disk_mount_all();
127 if (rc <= 0) /* no partition */
128 panicf("mount: %d",rc);
132 #endif
134 static void try_reboot(void)
136 #ifdef HAVE_DISK_STORAGE
137 ata_sleepnow(); /* Immediately spindown the disk. */
138 sleep(HZ*2);
139 #endif
141 #ifdef IPOD_ARCH /* The following code is based on ipodlinux */
142 #if CONFIG_CPU == PP5020
143 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
144 #elif CONFIG_CPU == PP5022
145 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
146 #endif /* CONFIG_CPU */
147 #endif /* IPOD_ARCH */
149 system_reboot(); /* Reboot */
152 static void usb_thread(void)
154 int num_acks_to_expect = -1;
155 bool waiting_for_ack;
156 struct queue_event ev;
158 waiting_for_ack = false;
160 while(1)
162 queue_wait(&usb_queue, &ev);
163 switch(ev.id)
165 #ifdef USB_DRIVER_CLOSE
166 case USB_QUIT:
167 return;
168 #endif
169 #ifdef HAVE_USBSTACK
170 case USB_TRANSFER_COMPLETION:
171 usb_core_handle_transfer_completion((struct usb_transfer_completion_event_data*)ev.data);
172 break;
173 #endif
174 #ifdef HAVE_USB_POWER
175 case USB_POWERED:
176 usb_state = USB_POWERED;
177 break;
178 #endif
179 case USB_INSERTED:
180 #ifdef HAVE_LCD_BITMAP
181 if(do_screendump_instead_of_usb)
183 screen_dump();
185 else
186 #endif
187 #ifdef HAVE_USB_POWER
188 #if defined(IRIVER_H10) || defined (IRIVER_H10_5GB)
189 if((button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON)
190 #else
191 if((button_status() & ~USBPOWER_BTN_IGNORE) == USBPOWER_BUTTON)
192 #endif
194 usb_state = USB_POWERED;
195 #ifdef HAVE_USBSTACK
196 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,false);
197 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,true);
198 usb_enable(true);
199 #endif
201 else
202 #endif
204 #ifdef HAVE_USBSTACK
205 /* Set the state to USB_POWERED for now. if a real
206 connection is detected it will switch to USB_INSERTED */
207 usb_state = USB_POWERED;
208 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE,true);
209 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY,false);
210 usb_enable(true);
211 #else
212 /* Tell all threads that they have to back off the ATA.
213 We subtract one for our own thread. */
214 num_acks_to_expect =
215 queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
216 waiting_for_ack = true;
217 DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
218 num_acks_to_expect);
219 #endif
221 break;
222 #ifdef HAVE_USBSTACK
223 case USB_REQUEST_DISK:
224 if(!waiting_for_ack)
226 /* Tell all threads that they have to back off the ATA.
227 We subtract one for our own thread. */
228 num_acks_to_expect =
229 queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
230 waiting_for_ack = true;
231 DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
232 num_acks_to_expect);
234 break;
235 case USB_RELEASE_DISK:
236 if(!waiting_for_ack)
238 /* Tell all threads that they have to back off the ATA.
239 We subtract one for our own thread. */
240 num_acks_to_expect =
241 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
242 waiting_for_ack = true;
243 DEBUGF("USB inserted. Waiting for ack from %d threads...\n",
244 num_acks_to_expect);
246 break;
247 #endif
248 case SYS_USB_CONNECTED_ACK:
249 if(waiting_for_ack)
251 num_acks_to_expect--;
252 if(num_acks_to_expect == 0)
254 DEBUGF("All threads have acknowledged the connect.\n");
255 #ifdef HAVE_USBSTACK
256 #ifndef USE_ROCKBOX_USB
257 /* until we have native mass-storage mode, we want to reboot on
258 usb host connect */
259 usb_enable(true);
260 try_reboot();
261 #endif /* USE_ROCKBOX_USB */
262 #ifdef HAVE_PRIORITY_SCHEDULING
263 thread_set_priority(usb_thread_entry,PRIORITY_REALTIME);
264 #endif
265 exclusive_ata_access = true;
267 #else
268 usb_slave_mode(true);
269 cpu_idle_mode(true);
270 #endif
271 usb_state = USB_INSERTED;
272 waiting_for_ack = false;
274 else
276 DEBUGF("usb: got ack, %d to go...\n",
277 num_acks_to_expect);
280 break;
282 case USB_EXTRACTED:
283 #ifdef HAVE_USBSTACK
284 usb_enable(false);
285 #ifdef HAVE_PRIORITY_SCHEDULING
286 thread_set_priority(usb_thread_entry,PRIORITY_SYSTEM);
287 #endif
288 #endif
289 #ifdef HAVE_LCD_BITMAP
290 if(do_screendump_instead_of_usb)
291 break;
292 #endif
293 #ifdef HAVE_USB_POWER
294 if(usb_state == USB_POWERED)
296 usb_state = USB_EXTRACTED;
297 break;
299 #endif
300 #ifndef HAVE_USBSTACK
301 if(usb_state == USB_INSERTED)
303 /* Only disable the USB mode if we really have enabled it
304 some threads might not have acknowledged the
305 insertion */
306 usb_slave_mode(false);
307 cpu_idle_mode(false);
309 #endif
311 usb_state = USB_EXTRACTED;
312 #ifdef HAVE_USBSTACK
313 if(exclusive_ata_access)
315 int rc = disk_mount_all();
316 if (rc <= 0) /* no partition */
317 panicf("mount: %d",rc);
318 exclusive_ata_access = false;
319 #endif
320 /* Tell all threads that we are back in business */
321 num_acks_to_expect =
322 queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
323 waiting_for_ack = true;
324 DEBUGF("USB extracted. Waiting for ack from %d threads...\n",
325 num_acks_to_expect);
326 #ifdef HAVE_USBSTACK
328 #endif
329 break;
331 case SYS_USB_DISCONNECTED_ACK:
332 if(waiting_for_ack)
334 num_acks_to_expect--;
335 if(num_acks_to_expect == 0)
337 DEBUGF("All threads have acknowledged. "
338 "We're in business.\n");
339 waiting_for_ack = false;
341 else
343 DEBUGF("usb: got ack, %d to go...\n",
344 num_acks_to_expect);
347 break;
349 #ifdef HAVE_HOTSWAP
350 case SYS_HOTSWAP_INSERTED:
351 case SYS_HOTSWAP_EXTRACTED:
352 #ifdef HAVE_USBSTACK
353 usb_core_hotswap_event(1,ev.id == SYS_HOTSWAP_INSERTED);
354 #else
355 if(usb_state == USB_INSERTED)
357 usb_enable(false);
358 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
360 #endif
361 break;
363 case USB_REENABLE:
364 if(usb_state == USB_INSERTED)
365 usb_enable(true); /* reenable only if still inserted */
366 break;
367 #endif /* HAVE_HOTSWAP */
368 case USB_REQUEST_REBOOT:
369 #ifdef HAVE_USB_POWER
370 if((button_status() & ~USBPOWER_BTN_IGNORE) != USBPOWER_BUTTON)
371 #endif
372 try_reboot();
373 break;
377 #endif
379 #ifdef HAVE_USBSTACK
380 void usb_signal_transfer_completion(struct usb_transfer_completion_event_data* event_data)
382 queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data);
384 #endif
386 #ifdef USB_FULL_INIT
387 static void usb_tick(void)
389 int current_status;
391 if(usb_monitor_enabled)
393 #if defined(IPOD_COLOR) || defined(IPOD_4G) \
394 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
395 int current_firewire_status = firewire_detect();
396 if(current_firewire_status != last_firewire_status)
398 last_firewire_status = current_firewire_status;
399 firewire_countdown = NUM_POLL_READINGS;
401 else
403 /* Count down until it gets negative */
404 if(firewire_countdown >= 0)
405 firewire_countdown--;
407 /* Report to the thread if we have had 3 identical status
408 readings in a row */
409 if(firewire_countdown == 0)
411 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
414 #endif
416 current_status = usb_detect();
418 /* Only report when the status has changed */
419 if(current_status != last_usb_status)
421 last_usb_status = current_status;
422 countdown = NUM_POLL_READINGS;
424 else
426 /* Count down until it gets negative */
427 if(countdown >= 0)
428 countdown--;
430 /* Report to the thread if we have had 3 identical status
431 readings in a row */
432 if(countdown == 0)
434 queue_post(&usb_queue, current_status, 0);
438 #ifdef HAVE_MMC
439 if(usb_mmc_countdown > 0)
441 usb_mmc_countdown--;
442 if (usb_mmc_countdown == 0)
443 queue_post(&usb_queue, USB_REENABLE, 0);
445 #endif
447 #endif
449 void usb_acknowledge(long id)
451 queue_post(&usb_queue, id, 0);
454 void usb_init(void)
456 usb_state = USB_EXTRACTED;
457 #ifdef HAVE_USBSTACK
458 exclusive_ata_access = false;
459 #endif
460 usb_monitor_enabled = false;
461 countdown = -1;
463 #if defined(IPOD_COLOR) || defined(IPOD_4G) \
464 || defined(IPOD_MINI) || defined(IPOD_MINI2G)
465 firewire_countdown = -1;
466 last_firewire_status = false;
467 #endif
469 usb_init_device();
470 #ifdef USB_FULL_INIT
471 usb_enable(false);
472 #endif
474 /* We assume that the USB cable is extracted */
475 last_usb_status = USB_EXTRACTED;
477 #ifdef USB_FULL_INIT
478 queue_init(&usb_queue, true);
480 usb_thread_entry = create_thread(usb_thread, usb_stack,
481 sizeof(usb_stack), 0, usb_thread_name
482 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
484 tick_add_task(usb_tick);
485 #endif
489 void usb_wait_for_disconnect(struct event_queue *q)
491 struct queue_event ev;
493 /* Don't return until we get SYS_USB_DISCONNECTED */
494 while(1)
496 queue_wait(q, &ev);
497 if(ev.id == SYS_USB_DISCONNECTED)
499 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
500 return;
505 int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)
507 struct queue_event ev;
509 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
510 while(1)
512 queue_wait_w_tmo(q, &ev, ticks);
513 switch(ev.id)
515 case SYS_USB_DISCONNECTED:
516 usb_acknowledge(SYS_USB_DISCONNECTED_ACK);
517 return 0;
518 break;
519 case SYS_TIMEOUT:
520 return 1;
521 break;
526 void usb_start_monitoring(void)
528 usb_monitor_enabled = true;
531 #ifdef USB_DRIVER_CLOSE
532 void usb_close(void)
534 struct thread_entry *thread = usb_thread_entry;
535 usb_thread_entry = NULL;
537 if (thread == NULL)
538 return;
540 tick_remove_task(usb_tick);
541 usb_monitor_enabled = false;
543 queue_post(&usb_queue, USB_QUIT, 0);
544 thread_wait(thread);
546 #endif /* USB_DRIVER_CLOSE */
548 bool usb_inserted(void)
550 #ifdef HAVE_USB_POWER
551 return usb_state == USB_INSERTED || usb_state == USB_POWERED;
552 #else
553 return usb_state == USB_INSERTED;
554 #endif
557 #ifdef HAVE_USBSTACK
558 void usb_request_exclusive_ata(void)
560 /* This is not really a clean place to start boosting the cpu. but it's
561 * currently the best one. We want to get rid of having to boost the cpu
562 * for usb anyway */
563 trigger_cpu_boost();
564 if(!exclusive_ata_access) {
565 queue_post(&usb_queue, USB_REQUEST_DISK, 0);
569 void usb_release_exclusive_ata(void)
571 cancel_cpu_boost();
572 if(exclusive_ata_access) {
573 queue_post(&usb_queue, USB_RELEASE_DISK, 0);
574 exclusive_ata_access = false;
578 bool usb_exclusive_ata(void)
580 return exclusive_ata_access;
582 #endif
584 #ifdef HAVE_USB_POWER
585 bool usb_powered(void)
587 return usb_state == USB_POWERED;
590 #if CONFIG_CHARGING
591 bool usb_charging_enable(bool on)
593 bool rc = false;
594 #ifdef IRIVER_H300_SERIES
595 int irqlevel;
596 logf("usb_charging_enable(%s)\n", on ? "on" : "off" );
597 irqlevel = disable_irq_save();
598 pcf50606_set_usb_charging(on);
599 rc = on;
600 restore_irq(irqlevel);
601 #else
602 /* TODO: implement it for other targets... */
603 (void)on;
604 #endif
605 return rc;
608 bool usb_charging_enabled(void)
610 bool rc = false;
611 #ifdef IRIVER_H300_SERIES
612 /* TODO: read the state of the GPOOD2 register...
613 * (this also means to set the irq level here) */
614 rc = pcf50606_usb_charging_enabled();
615 #else
616 /* TODO: implement it for other targets... */
617 #endif
619 logf("usb charging %s", rc ? "enabled" : "disabled" );
620 return rc;
622 #endif
623 #endif
625 #else
627 #ifdef USB_NONE
628 bool usb_inserted(void)
630 return false;
632 #endif
634 /* Dummy simulator functions */
635 void usb_acknowledge(long id)
637 id = id;
640 void usb_init(void)
644 void usb_start_monitoring(void)
648 int usb_detect(void)
650 return USB_EXTRACTED;
653 void usb_wait_for_disconnect(struct event_queue *q)
655 (void)q;
658 #endif /* USB_NONE or SIMULATOR */