static void NORETURN_ATTR pmu_thread(void) { struct queue_event ev; unsigned char ints[6]; while (true) { queue_wait_w_tmo(&pmu_queue, &ev, TIMEOUT_BLOCK); switch (ev.id) { case Q_EINT: /* read (clear) PMU interrupts, this will also raise the PMU IRQ pin */ pmu_read_multiple(PCF5063X_REG_INT1, 2, ints); ints[5] = pmu_read(PCF50635_REG_INT6); #if CONFIG_CHARGING if (ints[0] & ~ints_msk[0]) pmu_read_inputs_mbcs(); #endif if (ints[1] & ~ints_msk[1]) pmu_read_inputs_ooc(); if (ints[5] & ~ints_msk[5]) pmu_read_inputs_gpio(); eint_register(&pmu_eint); break; case SYS_TIMEOUT: break; } } }
static bool scroll_process_message(int delay) { struct queue_event ev; do { long tick = current_tick; queue_wait_w_tmo(&scroll_queue, &ev, delay); switch (ev.id) { case SYS_TIMEOUT: return false; case SYS_USB_CONNECTED: usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&scroll_queue); sync_display_ticks(); return true; #if (CONFIG_PLATFORM & PLATFORM_NATIVE) case SYS_REMOTE_PLUGGED: if (!remote_initialized) sync_display_ticks(); #endif } delay -= current_tick - tick; } while (delay > 0); return false; }
/* Return USB_HANDLED if session took place else return USB_EXTRACTED */ static int handle_usb(int connect_timeout) { static struct event_queue q SHAREDBSS_ATTR; struct queue_event ev; int usb = USB_EXTRACTED; long end_tick = 0; if (!usb_plugged()) return USB_EXTRACTED; queue_init(&q, true); usb_init(); usb_start_monitoring(); printf("USB: Connecting"); if (connect_timeout != TIMEOUT_BLOCK) end_tick = current_tick + connect_timeout; while (1) { /* Sleep no longer than 1/2s */ queue_wait_w_tmo(&q, &ev, HZ/2); if (ev.id == SYS_USB_CONNECTED) { /* Switch to verbose mode if not in it so that the status updates * are shown */ verbose = true; /* Got the message - wait for disconnect */ printf("Bootloader USB mode"); usb = USB_HANDLED; usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&q); break; } if (connect_timeout != TIMEOUT_BLOCK && TIME_AFTER(current_tick, end_tick)) { /* Timed out waiting for the connect - will happen when connected * to a charger instead of a host port and the charging pin is * the same as the USB pin */ printf("USB: Timed out"); break; } if (!usb_plugged()) break; /* Cable pulled */ } usb_close(); queue_delete(&q); return usb; }
static void codec_pcmbuf_insert_callback( const void *ch1, const void *ch2, int count) { const char *src[2] = { ch1, ch2 }; while (count > 0) { int out_count = dsp_output_count(ci.dsp, count); int inp_count; char *dest; while (1) { if ((dest = pcmbuf_request_buffer(&out_count)) != NULL) break; cancel_cpu_boost(); /* It will be awhile before space is available but we want "instant" response to any message */ queue_wait_w_tmo(&codec_queue, NULL, HZ/20); if (!queue_empty(&codec_queue) && codec_check_queue__have_msg() < 0) return; } /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ inp_count = dsp_input_count(ci.dsp, out_count); if (inp_count <= 0) return; /* Input size has grown, no error, just don't write more than length */ if (inp_count > count) inp_count = count; out_count = dsp_process(ci.dsp, dest, src, inp_count); if (out_count <= 0) return; pcmbuf_write_complete(out_count); count -= inp_count; } }
long button_get_w_tmo(int ticks) { struct queue_event ev; #ifdef HAVE_ADJUSTABLE_CPU_FREQ /* Be sure to keep boosted state. */ if (!queue_empty(&button_queue)) return button_get(true); button_boost(false); #endif queue_wait_w_tmo(&button_queue, &ev, ticks); if (ev.id == SYS_TIMEOUT) ev.id = BUTTON_NONE; else button_data = ev.data; return ev.id; }
int mmc_remove_request(void) { struct queue_event ev; FOR_NB_SCREENS(i) screens[i].clear_display(); splash(0, ID2P(LANG_REMOVE_MMC)); while (1) { queue_wait_w_tmo(&button_queue, &ev, HZ/2); switch (ev.id) { case SYS_HOTSWAP_EXTRACTED: return SYS_HOTSWAP_EXTRACTED; case SYS_USB_DISCONNECTED: return SYS_USB_DISCONNECTED; } } }
static void button_queue_wait(struct queue_event *evp, int timeout) { /* Loop once after wait time if boosted in order to unboost and wait the full remaining time */ do { int ticks = timeout; if (ticks == 0) /* TIMEOUT_NOBLOCK */ ; else if (ticks > 0) { if (button_boosted && ticks > BUTTON_UNBOOST_TMO) ticks = BUTTON_UNBOOST_TMO; timeout -= ticks; } else /* TIMEOUT_BLOCK (ticks < 0) */ { if (button_boosted) ticks = BUTTON_UNBOOST_TMO; } queue_wait_w_tmo(&button_queue, evp, ticks); if (evp->id != SYS_TIMEOUT) { /* GUI boost build gets immediate kick, otherwise at least 3 messages had to be there */ #ifndef HAVE_GUI_BOOST if (queue_count(&button_queue) >= 2) #endif button_boost(true); break; } if (button_boosted && TIME_AFTER(current_tick, button_unboost_tick)) button_boost(false); } while (timeout); }
int usb_wait_for_disconnect_w_tmo(struct event_queue *q, int ticks) { #ifdef USB_FULL_INIT struct queue_event ev; /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */ while(1) { queue_wait_w_tmo(q, &ev, ticks); switch(ev.id) { case SYS_USB_DISCONNECTED: usb_acknowledge(SYS_USB_DISCONNECTED_ACK); return 0; case SYS_TIMEOUT: return 1; } } #else (void)q; (void)ticks; return 0; #endif /* USB_FULL_INIT */ }
/* Voice thread message processing */ static enum voice_state voice_message(struct voice_thread_data *td) { if (quiet_counter > 0) queue_wait_w_tmo(&voice_queue, &td->ev, HZ/10); else queue_wait(&voice_queue, &td->ev); switch (td->ev.id) { case Q_VOICE_PLAY: LOGFQUEUE("voice < Q_VOICE_PLAY"); if (quiet_counter == 0) { /* Boost CPU now */ trigger_cpu_boost(); } else { /* Stop any clip still playing */ voice_stop_playback(); } quiet_counter = QUIET_COUNT; /* Copy the clip info */ td->vi = *(struct voice_info *)td->ev.data; /* Be sure audio buffer is initialized */ audio_restore_playback(AUDIO_WANT_VOICE); /* We need nothing more from the sending thread - let it run */ queue_reply(&voice_queue, 1); /* Make audio play more softly and set delay to return to normal playback level */ pcmbuf_soft_mode(true); /* Clean-start the decoder */ td->st = speex_decoder_init(&speex_wb_mode); /* Make bit buffer use our own buffer */ speex_bits_set_bit_buffer(&td->bits, td->vi.start, td->vi.size); speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); return VOICE_STATE_DECODE; case SYS_TIMEOUT: if (voice_unplayed_frames()) { /* Waiting for PCM to finish */ break; } /* Drop through and stop the first time after clip runs out */ if (quiet_counter-- != QUIET_COUNT) { if (quiet_counter <= 0) pcmbuf_soft_mode(false); break; } /* Fall-through */ case Q_VOICE_STOP: LOGFQUEUE("voice < Q_VOICE_STOP"); cancel_cpu_boost(); voice_stop_playback(); break; /* No default: no other message ids are sent */ } return VOICE_STATE_MESSAGE; }
void buffering_thread(void) { bool filling = false; struct queue_event ev; while (true) { if (!filling) { cancel_cpu_boost(); } queue_wait_w_tmo(&buffering_queue, &ev, filling ? 5 : HZ/2); switch (ev.id) { case Q_START_FILL: LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev.data); /* Call buffer callbacks here because this is one of two ways * to begin a full buffer fill */ send_event(BUFFER_EVENT_BUFFER_LOW, 0); shrink_buffer(); queue_reply(&buffering_queue, 1); filling |= buffer_handle((int)ev.data); break; case Q_BUFFER_HANDLE: LOGFQUEUE("buffering < Q_BUFFER_HANDLE %d", (int)ev.data); queue_reply(&buffering_queue, 1); buffer_handle((int)ev.data); break; case Q_RESET_HANDLE: LOGFQUEUE("buffering < Q_RESET_HANDLE %d", (int)ev.data); queue_reply(&buffering_queue, 1); reset_handle((int)ev.data); break; case Q_CLOSE_HANDLE: LOGFQUEUE("buffering < Q_CLOSE_HANDLE %d", (int)ev.data); queue_reply(&buffering_queue, close_handle((int)ev.data)); break; case Q_HANDLE_ADDED: LOGFQUEUE("buffering < Q_HANDLE_ADDED %d", (int)ev.data); /* A handle was added: the disk is spinning, so we can fill */ filling = true; break; case Q_BASE_HANDLE: LOGFQUEUE("buffering < Q_BASE_HANDLE %d", (int)ev.data); base_handle_id = (int)ev.data; break; #ifndef SIMULATOR case SYS_USB_CONNECTED: LOGFQUEUE("buffering < SYS_USB_CONNECTED"); usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&buffering_queue); break; #endif case SYS_TIMEOUT: LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT"); break; } update_data_counters(); /* If the buffer is low, call the callbacks to get new data */ if (num_handles > 0 && data_counters.useful <= conf_watermark) send_event(BUFFER_EVENT_BUFFER_LOW, 0); #if 0 /* TODO: This needs to be fixed to use the idle callback, disable it * for simplicity until its done right */ #if MEM > 8 /* If the disk is spinning, take advantage by filling the buffer */ else if (storage_disk_is_active() && queue_empty(&buffering_queue)) { if (num_handles > 0 && data_counters.useful <= high_watermark) send_event(BUFFER_EVENT_BUFFER_LOW, 0); if (data_counters.remaining > 0 && BUF_USED <= high_watermark) { /* This is a new fill, shrink the buffer up first */ if (!filling) shrink_buffer(); filling = fill_buffer(); update_data_counters(); } } #endif #endif if (queue_empty(&buffering_queue)) { if (filling) { if (data_counters.remaining > 0 && BUF_USED < buffer_len) filling = fill_buffer(); else if (data_counters.remaining == 0) filling = false; } else if (ev.id == SYS_TIMEOUT) { if (data_counters.remaining > 0 && data_counters.useful <= conf_watermark) { shrink_buffer(); filling = fill_buffer(); } } } } }
/* GUI boost build gets immediate kick, otherwise at least 3 messages had to be there */ #ifndef HAVE_GUI_BOOST if (queue_count(&button_queue) >= 2) #endif button_boost(true); break; } if (button_boosted && TIME_AFTER(current_tick, button_unboost_tick)) button_boost(false); } while (timeout); } #else /* ndef HAVE_ADJUSTABLE_CPU_FREQ */ static inline void button_queue_wait(struct queue_event *evp, int timeout) { queue_wait_w_tmo(&button_queue, evp, timeout); }
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; } } }