void usb_core_exit(void) { int i; for(i = 0; i < USB_NUM_DRIVERS; i++) if(drivers[i].enabled && drivers[i].disconnect != NULL) { drivers[i].disconnect(); drivers[i].enabled = false; } if(initialized) { usb_drv_exit(); initialized = false; } usb_state = DEFAULT; #ifdef HAVE_USB_CHARGING_ENABLE usb_no_host = false; usb_charging_maxcurrent_change(usb_charging_maxcurrent()); #endif logf("usb_core_exit() finished"); }
static void usb_thread(void) { int num_acks_to_expect = 0; struct queue_event ev; while(1) { queue_wait(&usb_queue, &ev); switch(ev.id) { #ifdef USB_DRIVER_CLOSE case USB_QUIT: return; #endif #ifdef HAVE_USBSTACK case USB_TRANSFER_COMPLETION: usb_core_handle_transfer_completion( (struct usb_transfer_completion_event_data*)ev.data); break; #endif #ifdef USB_DETECT_BY_DRV /* In this case, these events the handle cable insertion USB * driver determines INSERTED/EXTRACTED state. */ case USB_POWERED: /* Set the state to USB_POWERED for now and enable the driver * to detect a bus reset only. If a bus reset is detected, * USB_INSERTED will be received. */ usb_state = USB_POWERED; usb_enable(true); break; case USB_UNPOWERED: usb_enable(false); /* This part shouldn't be obligatory for anything that can * reliably detect removal of the data lines. USB_EXTRACTED * could be posted on that event while bus power remains * available. */ queue_post(&usb_queue, USB_EXTRACTED, 0); break; #endif /* USB_DETECT_BY_DRV */ case USB_INSERTED: #ifdef HAVE_LCD_BITMAP if(do_screendump_instead_of_usb) { usb_state = USB_SCREENDUMP; screen_dump(); #ifdef HAVE_REMOTE_LCD remote_screen_dump(); #endif break; } #endif #ifdef HAVE_USB_POWER if(usb_power_button()) { /* Only charging is desired */ usb_state = USB_POWERED; #ifdef HAVE_USBSTACK #ifdef USB_ENABLE_STORAGE usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, false); #endif #ifdef USB_ENABLE_HID #ifdef USB_ENABLE_CHARGING_ONLY usb_core_enable_driver(USB_DRIVER_HID, false); #else usb_core_enable_driver(USB_DRIVER_HID, true); #endif /* USB_ENABLE_CHARGING_ONLY */ #endif /* USB_ENABLE_HID */ #ifdef USB_ENABLE_CHARGING_ONLY usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, true); #endif usb_attach(); #endif break; } #endif /* HAVE_USB_POWER */ #ifdef HAVE_USBSTACK #ifdef HAVE_USB_POWER /* Set the state to USB_POWERED for now. If permission to connect * by threads and storage is granted it will be changed to * USB_CONNECTED. */ usb_state = USB_POWERED; #endif #ifdef USB_ENABLE_STORAGE usb_core_enable_driver(USB_DRIVER_MASS_STORAGE, true); #endif #ifdef USB_ENABLE_HID usb_core_enable_driver(USB_DRIVER_HID, usb_hid); #endif #ifdef USB_ENABLE_CHARGING_ONLY usb_core_enable_driver(USB_DRIVER_CHARGING_ONLY, false); #endif /* Check any drivers enabled at this point for exclusive storage * access requirements. */ exclusive_storage_access = usb_core_any_exclusive_storage(); if(!exclusive_storage_access) { usb_attach(); break; } #endif /* HAVE_USBSTACK */ /* Tell all threads that they have to back off the storage. We subtract one for our own thread. */ num_acks_to_expect = queue_broadcast(SYS_USB_CONNECTED, 0) - 1; DEBUGF("USB inserted. Waiting for ack from %d threads...\n", num_acks_to_expect); break; case SYS_USB_CONNECTED_ACK: if(num_acks_to_expect > 0 && --num_acks_to_expect == 0) { DEBUGF("All threads have acknowledged the connect.\n"); usb_slave_mode(true); usb_state = USB_INSERTED; } else { DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); } break; case USB_EXTRACTED: #ifdef HAVE_LCD_BITMAP if(usb_state == USB_SCREENDUMP) { usb_state = USB_EXTRACTED; break; /* Connected for screendump only */ } #endif #ifndef HAVE_USBSTACK /* Stack must undo this if POWERED state was transitional */ #ifdef HAVE_USB_POWER if(usb_state == USB_POWERED) { usb_state = USB_EXTRACTED; break; } #endif #endif /* HAVE_USBSTACK */ if(usb_state == USB_INSERTED) { /* Only disable the USB mode if we really have enabled it some threads might not have acknowledged the insertion */ usb_slave_mode(false); } usb_state = USB_EXTRACTED; #ifdef HAVE_USBSTACK if(!exclusive_storage_access) { #ifndef USB_DETECT_BY_DRV /* Disabled handling USB_UNPOWERED */ usb_enable(false); #endif break; } #endif /* HAVE_USBSTACK */ num_acks_to_expect = usb_release_exclusive_storage(); break; case SYS_USB_DISCONNECTED_ACK: if(num_acks_to_expect > 0 && --num_acks_to_expect == 0) { DEBUGF("All threads have acknowledged. " "We're in business.\n"); } else { DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); } break; #ifdef HAVE_HOTSWAP case SYS_HOTSWAP_INSERTED: case SYS_HOTSWAP_EXTRACTED: #ifdef HAVE_USBSTACK usb_core_hotswap_event(1,ev.id == SYS_HOTSWAP_INSERTED); #else /* !HAVE_USBSTACK */ if(usb_state == USB_INSERTED) { #if (CONFIG_STORAGE & STORAGE_MMC) usb_enable(false); usb_mmc_countdown = HZ/2; /* re-enable after 0.5 sec */ #endif /* STORAGE_MMC */ } #endif /* HAVE_USBSTACK */ break; #if (CONFIG_STORAGE & STORAGE_MMC) case USB_REENABLE: if(usb_state == USB_INSERTED) usb_enable(true); /* reenable only if still inserted */ break; #endif /* STORAGE_MMC */ #endif /* HAVE_HOTSWAP */ #ifdef USB_FIREWIRE_HANDLING case USB_REQUEST_REBOOT: #ifdef HAVE_USB_POWER if (usb_reboot_button()) #endif try_reboot(); break; #endif /* USB_FIREWIRE_HANDLING */ #if defined(HAVE_USB_CHARGING_ENABLE) && defined(HAVE_USBSTACK) case USB_CHARGER_UPDATE: usb_charging_maxcurrent_change(usb_charging_maxcurrent()); break; #endif } } }