A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 910 lines 23 kB view raw
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 */