void sim_thread(void) { struct queue_event ev; long last_broadcast_tick = current_tick; int num_acks_to_expect; while (1) { queue_wait(&sim_queue, &ev); switch(ev.id) { case SIM_SCREENDUMP: screen_dump(); #ifdef HAVE_REMOTE_LCD remote_screen_dump(); #endif break; case SIM_USB_INSERTED: /* from firmware/usb.c: */ /* Tell all threads that they have to back off the storage. We subtract one for our own thread. Expect an ACK for every listener for each broadcast they received. If it has been too long, the user might have entered a screen that didn't ACK when inserting the cable, such as a debugging screen. In that case, reset the count or else USB would be locked out until rebooting because it most likely won't ever come. Simply resetting to the most recent broadcast count is racy. */ if(TIME_AFTER(current_tick, last_broadcast_tick + HZ*5)) { num_acks_to_expect = 0; last_broadcast_tick = current_tick; } num_acks_to_expect += queue_broadcast(SYS_USB_CONNECTED, 0) - 1; DEBUGF("USB inserted. Waiting for %d acks...\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"); } else { DEBUGF("usb: got ack, %d to go...\n", num_acks_to_expect); } break; case SIM_USB_EXTRACTED: /* in usb.c, this is only done for exclusive storage * do it here anyway but don't depend on the acks */ queue_broadcast(SYS_USB_DISCONNECTED, 0); break; default: DEBUGF("sim_tasks: unhandled event: %ld\n", ev.id); break; } } }
static void sd_detect_callback(int ssp) { (void)ssp; /* This is called only if the state was stable for 300ms - check state * and post appropriate event. */ if(imx233_ssp_sdmmc_detect(SD_SSP)) queue_broadcast(SYS_HOTSWAP_INSERTED, 0); else queue_broadcast(SYS_HOTSWAP_EXTRACTED, 0); imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback); }
/* * Detect charger inserted. Return true if the state is transistional. */ static inline bool detect_charger(unsigned int pwr) { /* * Detect charger plugged/unplugged transitions. On a plugged or * unplugged event, we return immediately, run once through the main * loop (including the subroutines), and end up back here where we * transition to the appropriate steady state charger on/off state. */ if (pwr & POWER_INPUT_CHARGER) { switch (charger_input_state) { case NO_CHARGER: case CHARGER_UNPLUGGED: charger_input_state = CHARGER_PLUGGED; break; case CHARGER_PLUGGED: queue_broadcast(SYS_CHARGER_CONNECTED, 0); last_sent_battery_level = 0; charger_input_state = CHARGER; break; case CHARGER: /* Steady state */ return false; } } else { /* charger not inserted */ switch (charger_input_state) { case NO_CHARGER: /* Steady state */ return false; case CHARGER_UNPLUGGED: queue_broadcast(SYS_CHARGER_DISCONNECTED, 0); last_sent_battery_level = 100; charger_input_state = NO_CHARGER; break; case CHARGER_PLUGGED: case CHARGER: charger_input_state = CHARGER_UNPLUGGED; break; } } /* Transitional state */ return true; }
/** * Gets called by the policy framework if an important * event arrives: Incoming calls etc. */ void maemo_tell_rockbox_to_stop_audio(void) { sim_enter_irq_handler(); queue_broadcast(SYS_CALL_INCOMING, 0); sim_exit_irq_handler(); osso_system_note_infoprint(maemo_osso_ctx, "Stopping rockbox playback", NULL); }
int usb_release_exclusive_storage(void) { int num_acks_to_expect; #ifdef HAVE_USBSTACK exclusive_storage_access = false; #endif /* HAVE_USBSTACK */ /* Tell all threads that we are back in business */ num_acks_to_expect = queue_broadcast(SYS_USB_DISCONNECTED, 0) - 1; DEBUGF("USB extracted. Waiting for ack from %d threads...\n", num_acks_to_expect); return num_acks_to_expect; }
int sd_init(void) { mutex_init(&sd_mutex); queue_init(&sd_queue, true); create_thread(sd_thread, sd_stack, sizeof(sd_stack), 0, sd_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) IF_COP(, CPU)); #ifdef SANSA_FUZEPLUS imx233_ssp_setup_ssp1_sd_mmc_pins(true, 4, PINCTRL_DRIVE_8mA, false); #endif imx233_ssp_sdmmc_setup_detect(SD_SSP, true, sd_detect_callback); if(imx233_ssp_sdmmc_detect(SD_SSP)) queue_broadcast(SYS_HOTSWAP_INSERTED, 0); return 0; }
void usb_storage_init_connection(void) { logf("ums: set config"); /* prime rx endpoint. We only need room for commands */ state = WAITING_FOR_COMMAND; #if (CONFIG_CPU == IMX31L || defined(CPU_TCC77X) || defined(CPU_TCC780X) || \ defined(BOOTLOADER) || CONFIG_CPU == DM320) && !defined(CPU_PP502x) static unsigned char _cbw_buffer[MAX_CBW_SIZE] USB_DEVBSS_ATTR __attribute__((aligned(32))); cbw_buffer = (void *)_cbw_buffer; static unsigned char _transfer_buffer[ALLOCATE_BUFFER_SIZE] USB_DEVBSS_ATTR __attribute__((aligned(32))); tb.transfer_buffer = (void *)_transfer_buffer; #ifdef USB_USE_RAMDISK static unsigned char _ramdisk_buffer[RAMDISK_SIZE*SECTOR_SIZE]; ramdisk_buffer = _ramdisk_buffer; #endif #else /* TODO : check if bufsize is at least 32K ? */ size_t bufsize; unsigned char * audio_buffer; audio_buffer = audio_get_buffer(false,&bufsize); #if defined(UNCACHED_ADDR) && CONFIG_CPU != AS3525 cbw_buffer = (void *)UNCACHED_ADDR((unsigned int)(audio_buffer+31) & 0xffffffe0); #else cbw_buffer = (void *)((unsigned int)(audio_buffer+31) & 0xffffffe0); #endif tb.transfer_buffer = cbw_buffer + MAX_CBW_SIZE; commit_discard_dcache(); #ifdef USB_USE_RAMDISK ramdisk_buffer = tb.transfer_buffer + ALLOCATE_BUFFER_SIZE; #endif #endif usb_drv_recv(ep_out, cbw_buffer, MAX_CBW_SIZE); int i; for(i=0;i<storage_num_drives();i++) { locked[i] = false; ejected[i] = !check_disk_present(IF_MD(i)); queue_broadcast(SYS_USB_LUN_LOCKED, (i<<16)+0); } }
/* Monitor remote hotswap */ static void remote_tick(void) { static bool last_status = false; static int countdown = 0; static int init_delay = 0; bool current_status; int val; int level; current_status = remote_detect(); /* Only report when the status has changed */ if (current_status != last_status) { last_status = current_status; countdown = current_status ? 20*HZ : 1; } else { /* Count down until it gets negative */ if (countdown >= 0) countdown--; if (current_status) { if (!(countdown % 8)) { /* Determine which type of remote it is */ level = disable_irq_save(); val = adc_scan(ADC_REMOTEDETECT); restore_irq(level); if (val < ADCVAL_H100_LCD_REMOTE_HOLD) { if (val < ADCVAL_H100_LCD_REMOTE) if (val < ADCVAL_H300_LCD_REMOTE) _remote_type = REMOTETYPE_H300_LCD; /* hold off */ else _remote_type = REMOTETYPE_H100_LCD; /* hold off */ else if (val < ADCVAL_H300_LCD_REMOTE_HOLD) _remote_type = REMOTETYPE_H300_LCD; /* hold on */ else _remote_type = REMOTETYPE_H100_LCD; /* hold on */ if (--init_delay <= 0) { queue_broadcast(SYS_REMOTE_PLUGGED, 0); init_delay = 6; } } else { _remote_type = REMOTETYPE_H300_NONLCD; /* hold on or off */ } } } else { if (countdown == 0) { _remote_type = REMOTETYPE_UNPLUGGED; queue_broadcast(SYS_REMOTE_UNPLUGGED, 0); } } } /* handle chip select timeout */ if (remote_cs_countdown >= 0) remote_cs_countdown--; if (remote_cs_countdown == 0) CS_HI; }
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 } } }
static void sd_thread(void) { struct queue_event ev; while (1) { queue_wait_w_tmo(&sd_queue, &ev, HZ); switch(ev.id) { case SYS_HOTSWAP_INSERTED: case SYS_HOTSWAP_EXTRACTED: { fat_lock(); /* lock-out FAT activity first - prevent deadlocking via disk_mount that would cause a reverse-order attempt with another thread */ mutex_lock(&sd_mutex); /* lock-out card activity - direct calls into driver that bypass the fat cache */ /* We now have exclusive control of fat cache and sd */ disk_unmount(sd_first_drive); /* release "by force", ensure file descriptors aren't leaked and any busy ones are invalid if mounting */ /* Force card init for new card, re-init for re-inserted one or * clear if the last attempt to init failed with an error. */ card_info.initialized = 0; if(ev.id == SYS_HOTSWAP_INSERTED) { int ret = sd_init_card(); if(ret == 0) { ret = disk_mount(sd_first_drive); /* 0 if fail */ if(ret < 0) DEBUGF("disk_mount failed: %d", ret); } else DEBUGF("sd_init_card failed: %d", ret); } /* * Mount succeeded, or this was an EXTRACTED event, * in both cases notify the system about the changed filesystems */ if(card_info.initialized) queue_broadcast(SYS_FS_CHANGED, 0); /* Access is now safe */ mutex_unlock(&sd_mutex); fat_unlock(); } break; case SYS_TIMEOUT: if(!TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) sd_enable(false); break; case SYS_USB_CONNECTED: usb_acknowledge(SYS_USB_CONNECTED_ACK); /* Wait until the USB cable is extracted again */ usb_wait_for_disconnect(&sd_queue); break; } } }