A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
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
16 *
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.
21 *
22 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
23 * KIND, either express or implied.
24 *
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 "disk.h"
34#include "panic.h"
35#include "lcd.h"
36#include "usb.h"
37#include "button.h"
38#include "string.h"
39#ifdef HAVE_USBSTACK
40#include "usb_core.h"
41#endif
42#include "logf.h"
43#include "screendump.h"
44#include "powermgmt.h"
45
46#ifndef BOOTLOADER
47#include "misc.h"
48#include "gui/yesno.h"
49#include "settings.h"
50#include "lang_enum.h"
51#include "gui/skin_engine/skin_engine.h"
52#endif
53
54#if defined(IPOD_ACCESSORY_PROTOCOL)
55#include "iap.h"
56#endif
57
58/* Conditions under which we want the entire driver */
59#if !defined(BOOTLOADER) || \
60 (defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) || \
61 (defined(HAVE_USBSTACK) && defined(IPOD_NANO2G)) || \
62 (defined(HAVE_USBSTACK) && (defined(CREATIVE_ZVx))) || \
63 (defined(HAVE_USBSTACK) && (defined(OLYMPUS_MROBE_500))) || \
64 defined(CPU_TCC780X) || \
65 (CONFIG_USBOTG == USBOTG_JZ4740) || \
66 (CONFIG_USBOTG == USBOTG_JZ4760)
67/* TODO: condition should be reset to be only the original
68 (defined(HAVE_USBSTACK) && defined(HAVE_BOOTLOADER_USB_MODE)) */
69#define USB_FULL_INIT
70#endif
71
72/* USB detect debouncing interval (200ms taken from the usb polling code) */
73#define USB_DEBOUNCE_POLL (200*HZ/1000)
74/* NOTE: "usb_dw_gonak_effective:failed!" *PANIC*s can be observed when
75 disconnecting the FiiO M3K from USB with the debounce interval
76 for USB_STATUS_BY_EVENT set to 200ms, as above (see e75a3fb).
77 Adjusting the interval to 10ms reduces likelihood of a panic. */
78#define USB_DEBOUNCE_TIME (10*HZ/1000)
79
80bool do_screendump_instead_of_usb = false;
81
82#if !defined(SIMULATOR) && !defined(USB_NONE)
83
84/* We assume that the USB cable is extracted */
85static int usb_state = USB_EXTRACTED;
86#if (CONFIG_STORAGE & STORAGE_MMC) && defined(USB_FULL_INIT) && !defined(HAVE_USBSTACK)
87static int usb_mmc_countdown = 0;
88#endif
89
90/* Make sure there's enough stack space for screendump */
91#ifdef USB_FULL_INIT
92#ifndef USB_EXTRA_STACK
93# define USB_EXTRA_STACK 0x0 /*Define in firmware/export/config/[target].h*/
94#endif
95static long usb_stack[(DEFAULT_STACK_SIZE*4 + DUMP_BMP_LINESIZE + USB_EXTRA_STACK)/sizeof(long)];
96static const char usb_thread_name[] = "usb";
97static unsigned int usb_thread_entry = 0;
98static bool usb_monitor_enabled = false;
99#endif /* USB_FULL_INIT */
100static struct event_queue usb_queue SHAREDBSS_ATTR;
101static bool exclusive_storage_access = false;
102#ifdef USB_ENABLE_HID
103static bool usb_hid = true;
104#endif
105#ifdef USB_ENABLE_AUDIO
106static int usb_audio = 0;
107#endif
108
109#ifdef USB_FULL_INIT
110static bool usb_host_present = false;
111static int usb_num_acks_to_expect = 0;
112static long usb_last_broadcast_tick = 0;
113#ifdef HAVE_USB_POWER
114static int usb_mode = USBMODE_DEFAULT;
115static int new_usbmode = USBMODE_DEFAULT;
116#endif
117
118static int usb_release_exclusive_storage(void);
119
120#if defined(USB_FIREWIRE_HANDLING)
121static void try_reboot(void)
122{
123#ifdef HAVE_DISK_STORAGE
124 storage_sleepnow(); /* Immediately spindown the disk. */
125 sleep(HZ*2);
126#endif
127
128#ifdef IPOD_ARCH /* The following code is based on ipodlinux */
129#if CONFIG_CPU == PP5020
130 memcpy((void *)0x40017f00, "diskmode\0\0hotstuff\0\0\1", 21);
131#elif CONFIG_CPU == PP5022
132 memcpy((void *)0x4001ff00, "diskmode\0\0hotstuff\0\0\1", 21);
133#endif /* CONFIG_CPU */
134#endif /* IPOD_ARCH */
135
136#ifdef IPOD_NANO2G
137 memcpy((void *)0x0002bf00, "diskmodehotstuff\1\0\0\0", 20);
138#endif
139
140 system_reboot(); /* Reboot */
141}
142#endif /* USB_FIRWIRE_HANDLING */
143
144/* Screen dump */
145static inline bool usb_do_screendump(void)
146{
147 if(do_screendump_instead_of_usb)
148 {
149 screen_dump();
150#ifdef HAVE_REMOTE_LCD
151 remote_screen_dump();
152#endif /* HAVE_REMOTE_LCD */
153 return true;
154 }
155 return false;
156}
157
158#ifdef HAVE_USB_POWER
159void usb_set_mode(int mode)
160{
161 usb_mode = mode;
162#if defined(DX50) || defined(DX90)
163 ibasso_set_usb_mode(mode);
164#endif
165}
166#endif
167
168#ifdef USB_FIREWIRE_HANDLING
169static inline bool usb_reboot_button(void)
170{
171#ifdef HAVE_USB_POWER
172 return (button_status() & ~USBPOWER_BTN_IGNORE);
173#else
174 return false;
175#endif
176}
177#endif /* USB_FIREWIRE_HANDLING */
178
179
180/*--- Routines that differ depending upon the presence of a USB stack ---*/
181
182#ifdef HAVE_USBSTACK
183/* Enable / disable USB when the stack is enabled - otherwise a noop */
184static inline void usb_stack_enable(bool enable)
185{
186 usb_enable(enable);
187}
188
189#ifdef HAVE_HOTSWAP
190static inline void usb_handle_hotswap(long id)
191{
192 switch(id)
193 {
194 case SYS_HOTSWAP_INSERTED:
195 case SYS_HOTSWAP_EXTRACTED:
196 usb_core_hotswap_event(1, id == SYS_HOTSWAP_INSERTED);
197 break;
198 }
199 /* Note: No MMC storage handling is needed with the stack atm. */
200}
201#endif /* HAVE_HOTSWAP */
202
203static inline bool usb_configure_drivers(int for_state)
204{
205#ifdef USB_ENABLE_AUDIO
206 // FIXME: doesn't seem to get set when loaded at boot...
207 usb_audio = global_settings.usb_audio;
208#endif
209 switch(for_state)
210 {
211 case USB_POWERED:
212#ifdef USB_ENABLE_STORAGE
213 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false);
214#endif
215#ifdef USB_ENABLE_HID
216#ifdef USB_ENABLE_CHARGING_ONLY
217 usb_core_enable_driver(USB_DRIVER_HID, false);
218#else
219 usb_core_enable_driver(USB_DRIVER_HID, true);
220#endif /* USB_ENABLE_CHARGING_ONLY */
221#endif /* USB_ENABLE_HID */
222#ifdef USB_ENABLE_AUDIO
223 usb_core_enable_driver(USB_DRIVER_AUDIO, (usb_audio == 1) || (usb_audio == 2)); // while "always" or "only in charge-only mode"
224#endif /* USB_ENABLE_AUDIO */
225
226#ifdef USB_ENABLE_CHARGING_ONLY
227 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true);
228#endif
229 exclusive_storage_access = false;
230
231 usb_attach(); /* Powered only: attach now. */
232 break;
233 /* USB_POWERED: */
234
235 case USB_INSERTED:
236#ifdef USB_ENABLE_STORAGE
237 usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true);
238#endif
239#ifdef USB_ENABLE_HID
240 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
241#endif
242#ifdef USB_ENABLE_AUDIO
243 usb_core_enable_driver(USB_DRIVER_AUDIO, (usb_audio == 1) || (usb_audio == 3)); // while "always" or "only in mass-storage mode"
244#endif /* USB_ENABLE_AUDIO */
245#ifdef USB_ENABLE_CHARGING_ONLY
246 usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false);
247#endif
248 /* Check any drivers enabled at this point for exclusive storage
249 * access requirements. */
250 exclusive_storage_access = usb_core_any_exclusive_storage();
251
252 if(exclusive_storage_access)
253 return true;
254
255 usb_attach(); /* Not exclusive: attach now. */
256 break;
257 /* USB_INSERTED: */
258
259 case USB_EXTRACTED:
260 if(exclusive_storage_access)
261 usb_release_exclusive_storage();
262 break;
263 /* USB_EXTRACTED: */
264 }
265
266 return false;
267}
268
269static inline void usb_slave_mode(bool on)
270{
271 int rc;
272
273 if(on)
274 {
275 trigger_cpu_boost();
276#ifdef HAVE_PRIORITY_SCHEDULING
277 thread_set_priority(thread_self(), PRIORITY_REALTIME);
278#endif
279 disk_unmount_all();
280 usb_attach();
281 }
282 else /* usb_state == USB_INSERTED (only!) */
283 {
284#ifdef HAVE_PRIORITY_SCHEDULING
285 thread_set_priority(thread_self(), PRIORITY_SYSTEM);
286#endif
287 /* Entered exclusive mode */
288 rc = disk_mount_all();
289 if(rc <= 0) /* no partition */
290 panicf("mount: %d",rc);
291
292 cancel_cpu_boost();
293 }
294}
295
296void usb_signal_transfer_completion(
297 struct usb_transfer_completion_event_data* event_data)
298{
299 queue_post(&usb_queue, USB_TRANSFER_COMPLETION, (intptr_t)event_data);
300}
301
302void usb_signal_notify(long id, intptr_t data)
303{
304 queue_post(&usb_queue, id, data);
305}
306
307#else /* !HAVE_USBSTACK */
308
309static inline void usb_stack_enable(bool enable)
310{
311 (void)enable;
312}
313
314#ifdef HAVE_HOTSWAP
315static inline void usb_handle_hotswap(long id)
316{
317#if (CONFIG_STORAGE & STORAGE_MMC)
318 switch(id)
319 {
320 case SYS_HOTSWAP_INSERTED:
321 case SYS_HOTSWAP_EXTRACTED:
322 if(usb_state == USB_INSERTED)
323 {
324 usb_enable(false);
325 usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */
326 }
327 break;
328 case USB_REENABLE:
329 if(usb_state == USB_INSERTED)
330 usb_enable(true); /* reenable only if still inserted */
331 break;
332 }
333#endif /* STORAGE_MMC */
334 (void)id;
335}
336#endif /* HAVE_HOTSWAP */
337
338static inline bool usb_configure_drivers(int for_state)
339{
340 switch(for_state)
341 {
342 case USB_POWERED:
343 exclusive_storage_access = false;
344 break;
345 case USB_INSERTED:
346 exclusive_storage_access = true;
347 return true;
348 case USB_EXTRACTED:
349 if(exclusive_storage_access)
350 usb_release_exclusive_storage();
351 break;
352 }
353
354 return false;
355}
356
357static inline void usb_slave_mode(bool on)
358{
359 int rc;
360
361 if(on)
362 {
363 DEBUGF("Entering USB slave mode\n");
364 disk_unmount_all();
365 storage_soft_reset();
366 storage_init();
367 storage_enable(false);
368 usb_enable(true);
369 cpu_idle_mode(true);
370 }
371 else
372 {
373 DEBUGF("Leaving USB slave mode\n");
374
375 cpu_idle_mode(false);
376
377 /* Let the ISDx00 settle */
378 sleep(HZ*1);
379
380 usb_enable(false);
381
382 rc = storage_init();
383 if(rc)
384 panicf("storage: %d",rc);
385
386 sleep(HZ/10);
387 rc = disk_mount_all();
388 if(rc <= 0) /* no partition */
389 panicf("mount: %d",rc);
390 }
391}
392#endif /* HAVE_USBSTACK */
393
394static void usb_set_host_present(bool present)
395{
396 if(usb_host_present == present)
397 return;
398
399 usb_host_present = present;
400
401 if(!usb_host_present)
402 {
403 usb_configure_drivers(USB_EXTRACTED);
404 return;
405 }
406
407#ifdef HAVE_USB_POWER
408 if (new_usbmode == USB_MODE_CHARGE || new_usbmode == USB_MODE_ADB)
409 {
410 /* Only charging is desired */
411 usb_configure_drivers(USB_POWERED);
412 return;
413 }
414#endif
415
416 if(!usb_configure_drivers(USB_INSERTED))
417 return; /* Exclusive storage access not required */
418
419 /* Tell all threads that they have to back off the storage.
420 We subtract one for our own thread. Expect an ACK for every
421 listener for each broadcast they received. If it has been too
422 long, the user might have entered a screen that didn't ACK
423 when inserting the cable, such as a debugging screen. In that
424 case, reset the count or else USB would be locked out until
425 rebooting because it most likely won't ever come. Simply
426 resetting to the most recent broadcast count is racy. */
427 if(TIME_AFTER(current_tick, usb_last_broadcast_tick + HZ*5))
428 {
429 usb_num_acks_to_expect = 0;
430 usb_last_broadcast_tick = current_tick;
431 }
432
433 usb_num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1;
434 DEBUGF("usb: waiting for %d acks...\n", usb_num_acks_to_expect);
435}
436
437static bool usb_handle_connected_ack(void)
438{
439 if(usb_num_acks_to_expect > 0 && --usb_num_acks_to_expect == 0)
440 {
441 DEBUGF("usb: all threads have acknowledged the connect.\n");
442 if(usb_host_present)
443 {
444 usb_slave_mode(true);
445 return true;
446 }
447 }
448 else
449 {
450 DEBUGF("usb: got ack, %d to go...\n", usb_num_acks_to_expect);
451 }
452
453 return false;
454}
455
456/*--- General driver code ---*/
457static void NORETURN_ATTR usb_thread(void)
458{
459 struct queue_event ev;
460
461 while(1)
462 {
463 queue_wait(&usb_queue, &ev);
464
465 reset_poweroff_timer(); /* Any USB event counts */
466
467 switch(ev.id)
468 {
469 /*** Main USB thread duties ***/
470
471#ifdef HAVE_USBSTACK
472 case USB_NOTIFY_SET_ADDR:
473 case USB_NOTIFY_SET_CONFIG:
474 if(usb_state <= USB_EXTRACTED)
475 break;
476 usb_core_handle_notify(ev.id, ev.data);
477 break;
478 case USB_TRANSFER_COMPLETION:
479 if(usb_state <= USB_EXTRACTED)
480 break;
481
482#ifdef USB_DETECT_BY_REQUEST
483 usb_set_host_present(true);
484#endif
485
486 usb_core_handle_transfer_completion(
487 (struct usb_transfer_completion_event_data*)ev.data);
488 break;
489#endif /* HAVE_USBSTACK */
490
491 case USB_INSERTED:
492 if(usb_state != USB_EXTRACTED)
493 break;
494
495 if(usb_do_screendump())
496 {
497 usb_state = USB_SCREENDUMP;
498 break;
499 }
500
501 usb_state = USB_POWERED;
502
503 usb_stack_enable(true);
504#ifndef BOOTLOADER
505#ifndef HAVE_USB_POWER
506 int usb_mode = -1;
507#endif
508 send_event(SYS_EVENT_USB_INSERTED, &usb_mode);
509#endif
510 /* Power (charging-only) button */
511#ifdef HAVE_USB_POWER
512 new_usbmode = usb_mode;
513 switch (usb_mode) {
514 case USB_MODE_CHARGE:
515 case USB_MODE_ADB:
516 if (button_status() & ~USBPOWER_BTN_IGNORE)
517 new_usbmode = USB_MODE_MASS_STORAGE;
518 break;
519 default:
520 case USB_MODE_MASS_STORAGE:
521 if (button_status() & ~USBPOWER_BTN_IGNORE)
522 new_usbmode = USB_MODE_CHARGE;
523 break;
524 }
525#endif
526
527#ifndef USB_DETECT_BY_REQUEST
528 usb_set_host_present(true);
529#endif
530 break;
531 /* USB_INSERTED */
532
533 case SYS_USB_CONNECTED_ACK:
534 if(usb_handle_connected_ack())
535 usb_state = USB_INSERTED;
536 break;
537 /* SYS_USB_CONNECTED_ACK */
538
539 case USB_EXTRACTED:
540 if(usb_state == USB_EXTRACTED)
541 break;
542
543 if(usb_state == USB_POWERED || usb_state == USB_INSERTED)
544 usb_stack_enable(false);
545
546#ifdef IPOD_ACCESSORY_PROTOCOL
547 iap_reset_state(IF_IAP_MP(0));
548#endif
549
550 /* Only disable the USB slave mode if we really have enabled
551 it. Some expected acks may not have been received. */
552 if(usb_state == USB_INSERTED)
553 usb_slave_mode(false);
554
555 usb_state = USB_EXTRACTED;
556#ifdef HAVE_USB_POWER
557 new_usbmode = usb_mode;
558#endif
559#ifndef BOOTLOADER
560 send_event(SYS_EVENT_USB_EXTRACTED, NULL);
561#endif
562 usb_set_host_present(false);
563 break;
564 /* USB_EXTRACTED: */
565
566 /*** Miscellaneous USB thread duties ***/
567
568 /* HOTSWAP */
569#ifdef HAVE_HOTSWAP
570 case SYS_HOTSWAP_INSERTED:
571 case SYS_HOTSWAP_EXTRACTED:
572#if (CONFIG_STORAGE & STORAGE_MMC)
573 case USB_REENABLE:
574#endif
575 usb_handle_hotswap(ev.id);
576 break;
577#endif
578
579 /* FIREWIRE */
580#ifdef USB_FIREWIRE_HANDLING
581 case USB_REQUEST_REBOOT:
582 if(usb_reboot_button())
583 try_reboot();
584 break;
585#endif
586
587 /* CHARGING */
588#if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
589 case USB_CHARGER_UPDATE:
590 usb_charging_maxcurrent_change(usb_charging_maxcurrent());
591 break;
592#endif
593
594 /* CLOSE */
595#ifdef USB_DRIVER_CLOSE
596 case USB_QUIT:
597 thread_exit();
598 break;
599#endif
600 } /* switch */
601 } /* while */
602}
603
604#if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK)
605void usb_charger_update(void)
606{
607 queue_post(&usb_queue, USB_CHARGER_UPDATE, 0);
608}
609#endif
610
611#ifdef USB_STATUS_BY_EVENT
612static int usb_status_tmo_callback(struct timeout* tmo)
613{
614 if(usb_monitor_enabled)
615 {
616 int current_status = usb_detect();
617 int* last_status = (int*)tmo->data;
618
619 if(current_status != *last_status)
620 {
621 /* Signal changed during the timeout; wait longer */
622 *last_status = current_status;
623 return USB_DEBOUNCE_TIME;
624 }
625
626 /* Signal is stable, post the event. The thread will deal with
627 * any spurious transitions (like inserted -> inserted). */
628 queue_post(&usb_queue, current_status, 0);
629 }
630
631 return 0;
632}
633
634void usb_status_event(int current_status)
635{
636 static struct timeout tmo;
637 static int last_status = USB_EXTRACTED;
638
639 /* Caller isn't expected to filter for changes in status.
640 * current_status:
641 * USB_INSERTED, USB_EXTRACTED
642 */
643 if(usb_monitor_enabled)
644 {
645 int oldstatus = disable_irq_save(); /* Dual-use function */
646 last_status = current_status;
647 timeout_register(&tmo, usb_status_tmo_callback, USB_DEBOUNCE_TIME,
648 (intptr_t)&last_status);
649 restore_irq(oldstatus);
650 }
651}
652
653void usb_start_monitoring(void)
654{
655 int oldstatus = disable_irq_save(); /* Sync to event */
656 int status = usb_detect();
657
658 usb_monitor_enabled = true;
659
660 /* An event may have been missed because it was sent before monitoring
661 * was enabled due to the connector already having been inserted before
662 * before or during boot. */
663 usb_status_event(status);
664
665#ifdef USB_FIREWIRE_HANDLING
666 if(firewire_detect())
667 usb_firewire_connect_event();
668#endif
669
670 restore_irq(oldstatus);
671}
672
673#ifdef USB_FIREWIRE_HANDLING
674void usb_firewire_connect_event(void)
675{
676 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
677}
678#endif /* USB_FIREWIRE_HANDLING */
679
680#else /* !USB_STATUS_BY_EVENT */
681
682static void usb_tick(void)
683{
684 static int usb_countdown = -1;
685 static int last_usb_status = USB_EXTRACTED;
686#ifdef USB_FIREWIRE_HANDLING
687 static int firewire_countdown = -1;
688 static int last_firewire_status = false;
689#endif
690
691 if(usb_monitor_enabled)
692 {
693#ifdef USB_FIREWIRE_HANDLING
694 int current_firewire_status = firewire_detect();
695 if(current_firewire_status != last_firewire_status)
696 {
697 last_firewire_status = current_firewire_status;
698 firewire_countdown = USB_DEBOUNCE_POLL;
699 }
700 else
701 {
702 /* Count down until it gets negative */
703 if(firewire_countdown >= 0)
704 firewire_countdown--;
705
706 /* Report status when the signal has been stable long enough */
707 if(firewire_countdown == 0)
708 {
709 queue_post(&usb_queue, USB_REQUEST_REBOOT, 0);
710 }
711 }
712#endif /* USB_FIREWIRE_HANDLING */
713
714 int current_status = usb_detect();
715
716 /* Only report when the status has changed */
717 if(current_status != last_usb_status)
718 {
719 last_usb_status = current_status;
720 usb_countdown = USB_DEBOUNCE_POLL;
721 }
722 else
723 {
724 /* Count down until it gets negative */
725 if(usb_countdown >= 0)
726 usb_countdown--;
727
728 /* Report status when the signal has been stable long enough */
729 if(usb_countdown == 0)
730 {
731 queue_post(&usb_queue, current_status, 0);
732 }
733 }
734 }
735#if (CONFIG_STORAGE & STORAGE_MMC)
736 if(usb_mmc_countdown > 0)
737 {
738 usb_mmc_countdown--;
739 if(usb_mmc_countdown == 0)
740 queue_post(&usb_queue, USB_REENABLE, 0);
741 }
742#endif
743}
744
745void usb_start_monitoring(void)
746{
747 usb_monitor_enabled = true;
748}
749#endif /* USB_STATUS_BY_EVENT */
750#endif /* USB_FULL_INIT */
751
752void usb_acknowledge(long id)
753{
754 queue_post(&usb_queue, id, 0);
755}
756
757void usb_init(void)
758{
759 /* Do required hardware inits first. For software USB the driver has
760 * to make sure this won't trigger a transfer completion before the
761 * queue and thread are created. */
762 usb_init_device();
763
764#ifdef USB_FULL_INIT
765 usb_enable(false);
766
767 queue_init(&usb_queue, true);
768
769 usb_thread_entry = create_thread(usb_thread, usb_stack,
770 sizeof(usb_stack), 0, usb_thread_name
771 IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
772
773#ifndef USB_STATUS_BY_EVENT
774 tick_add_task(usb_tick);
775#endif
776#endif /* USB_FULL_INIT */
777}
778
779void usb_wait_for_disconnect(struct event_queue *q)
780{
781#ifdef USB_FULL_INIT
782 struct queue_event ev;
783
784 /* Don't return until we get SYS_USB_DISCONNECTED */
785 while(1)
786 {
787 queue_wait(q, &ev);
788 if(ev.id == SYS_USB_DISCONNECTED)
789 return;
790 }
791#endif /* USB_FULL_INIT */
792 (void)q;
793}
794
795int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks)
796{
797#ifdef USB_FULL_INIT
798 struct queue_event ev;
799
800 /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */
801 while(1)
802 {
803 queue_wait_w_tmo(q, &ev, ticks);
804 switch(ev.id)
805 {
806 case SYS_USB_DISCONNECTED:
807 return 0;
808 case SYS_TIMEOUT:
809 return 1;
810 }
811 }
812#endif /* USB_FULL_INIT */
813 (void)q; (void)ticks;
814 return 0;
815}
816
817#ifdef USB_DRIVER_CLOSE
818void usb_close(void)
819{
820 unsigned int thread = usb_thread_entry;
821 usb_thread_entry = 0;
822
823 if(thread == 0)
824 return;
825
826#ifndef USB_STATUS_BY_EVENT
827 tick_remove_task(usb_tick);
828#endif
829 usb_monitor_enabled = false;
830 queue_post(&usb_queue, USB_QUIT, 0);
831 thread_wait(thread);
832}
833#endif /* USB_DRIVER_CLOSE */
834
835bool usb_inserted(void)
836{
837 return usb_state == USB_INSERTED || usb_state == USB_POWERED;
838}
839
840#ifdef HAVE_USBSTACK
841bool usb_exclusive_storage(void)
842{
843 /* Storage isn't actually exclusive until slave mode has been entered */
844 return exclusive_storage_access && usb_state == USB_INSERTED;
845}
846#endif /* HAVE_USBSTACK */
847
848int usb_release_exclusive_storage(void)
849{
850 int bccount;
851 exclusive_storage_access = false;
852 /* Tell all threads that we are back in business */
853 bccount = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1;
854 DEBUGF("USB extracted. Broadcast to %d threads...\n", bccount);
855 return bccount;
856}
857
858#ifdef USB_ENABLE_HID
859void usb_set_hid(bool enable)
860{
861 usb_hid = enable;
862 usb_core_enable_driver(USB_DRIVER_HID, usb_hid);
863}
864#endif /* USB_ENABLE_HID */
865
866#ifdef USB_ENABLE_AUDIO
867void usb_set_audio(int value)
868{
869 usb_audio = value;
870}
871#endif /* USB_ENABLE_AUDIO */
872
873#ifdef HAVE_USB_POWER
874bool usb_powered_only(void)
875{
876 return usb_state == USB_POWERED;
877}
878#endif /* HAVE_USB_POWER */
879
880#elif defined(USB_NONE)
881/* Dummy functions for USB_NONE */
882
883bool usb_inserted(void)
884{
885 return false;
886}
887
888void usb_acknowledge(long id)
889{
890 (void)id;
891}
892
893void usb_init(void)
894{
895}
896
897void usb_start_monitoring(void)
898{
899}
900
901int usb_detect(void)
902{
903 return USB_EXTRACTED;
904}
905
906void usb_wait_for_disconnect(struct event_queue *q)
907{
908 (void)q;
909}
910#endif /* USB_NONE */