static void mpr121_thread(void) { struct queue_event ev; while(1) { queue_wait(&mpr121_queue, &ev); /* handle usb connect and ignore all messages except rmi interrupts */ if(ev.id == SYS_USB_CONNECTED) { usb_acknowledge(SYS_USB_CONNECTED_ACK); continue; } else if(ev.id != MPR121_INTERRUPT) continue; /* clear interrupt and get status */ unsigned status; touchpad_btns = 0; if(!mpr121_get_touch_status(&status)) { /* ELE3: up * ELE4: back * ELE5: menu * ELE6: down * ELE7: play */ if(status & 0x8) touchpad_btns |= BUTTON_UP; if(status & 0x10) touchpad_btns |= BUTTON_BACK; if(status & 0x20) touchpad_btns |= BUTTON_MENU; if(status & 0x40) touchpad_btns |= BUTTON_DOWN; if(status & 0x80) touchpad_btns |= BUTTON_PLAY; } /* enable interrupt */ imx233_pinctrl_setup_irq(0, 18, true, true, false, &mpr121_irq_cb, 0); } }
static void usb_mode(void) { int button; /* Init USB */ usb_init(); usb_start_monitoring(); /* Wait for threads to connect */ show_splash(HZ/2, "Waiting for USB"); while (1) { button = button_get_w_tmo(HZ/2); if (button == SYS_USB_CONNECTED) break; /* Hit */ } if (button == SYS_USB_CONNECTED) { /* Got the message - wait for disconnect */ show_splash(0, "Bootloader USB mode"); usb_acknowledge(SYS_USB_CONNECTED_ACK); while (1) { button = button_get(true); if (button == SYS_USB_DISCONNECTED) 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 int handle_usb_events(void) { #if (CONFIG_STORAGE & STORAGE_MMC) int next_update=0; #endif /* STORAGE_MMC */ /* Don't return until we get SYS_USB_DISCONNECTED or SYS_TIMEOUT */ while(1) { int button; #ifdef USB_ENABLE_HID if (usb_hid) { button = get_hid_usb_action(); /* On mode change, we need to refresh the screen */ if (button == ACTION_USB_HID_MODE_SWITCH_NEXT || button == ACTION_USB_HID_MODE_SWITCH_PREV) { break; } } else #endif { button = button_get_w_tmo(HZ/2); /* hid emits the event in get_action */ send_event(GUI_EVENT_ACTIONUPDATE, NULL); } switch(button) { case SYS_USB_DISCONNECTED: usb_acknowledge(SYS_USB_DISCONNECTED_ACK); return 1; case SYS_CHARGER_DISCONNECTED: /*reset rockbox battery runtime*/ global_status.runtime = 0; break; case SYS_TIMEOUT: break; } #if (CONFIG_STORAGE & STORAGE_MMC) /* USB-MMC bridge can report activity */ if(TIME_AFTER(current_tick,next_update)) { if(usb_inserted()) { led(mmc_usb_active(HZ)); } next_update=current_tick+HZ/2; } #endif /* STORAGE_MMC */ } return 0; }
static void usb_screen(void) { lcd_clear_display(); lcd_puts(0, 0, "USB mode"); lcd_update(); usb_acknowledge(SYS_USB_CONNECTED_ACK); while(usb_wait_for_disconnect_w_tmo(&button_queue, HZ)) { } }
static void usb_mode(int connect_timeout) { int button; usb_init(); usb_start_monitoring(); /* Wait for threads to connect or cable is pulled */ printf("USB: Connecting"); long end_tick = current_tick + connect_timeout; while(1) { button = button_get_w_tmo(HZ/10); if(button == SYS_USB_CONNECTED) break; /* Hit */ if(TIME_AFTER(current_tick, end_tick)) { /* Timed out waiting for the connect - will happen when connected * to a charger through the USB port */ printf("USB: Timed out"); break; } if(usb_detect() == USB_EXTRACTED) break; /* Cable pulled */ } if(button == SYS_USB_CONNECTED) { /* Got the message - wait for disconnect */ printf("Bootloader USB mode"); usb_acknowledge(SYS_USB_CONNECTED_ACK); while(1) { button = button_get_w_tmo(HZ/2); if(button == SYS_USB_DISCONNECTED) break; } } /* Put drivers initialized for USB connection into a known state */ usb_close(); }
static void NORETURN_ATTR audio_thread(void) { struct queue_event ev; ev.id = Q_NULL; /* something not in switch below */ pcm_postinit(); while (1) { switch (ev.id) { /* Starts the playback engine branch */ case Q_AUDIO_PLAY: LOGFQUEUE("audio < Q_AUDIO_PLAY"); audio_playback_handler(&ev); continue; /* Playback has to handle these, even if not playing */ case Q_AUDIO_REMAKE_AUDIO_BUFFER: #ifdef HAVE_DISK_STORAGE case Q_AUDIO_UPDATE_WATERMARK: #endif audio_playback_handler(&ev); break; #ifdef AUDIO_HAVE_RECORDING /* Starts the recording engine branch */ case Q_AUDIO_INIT_RECORDING: LOGFQUEUE("audio < Q_AUDIO_INIT_RECORDING"); audio_recording_handler(&ev); continue; #endif /* All return upon USB */ case SYS_USB_CONNECTED: LOGFQUEUE("audio < SYS_USB_CONNECTED"); voice_stop(); usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&audio_queue); break; } queue_wait(&audio_queue, &ev); } }
void usb_wait_for_disconnect(struct event_queue *q) { #ifdef USB_FULL_INIT struct queue_event ev; /* Don't return until we get SYS_USB_DISCONNECTED */ while(1) { queue_wait(q, &ev); if(ev.id == SYS_USB_DISCONNECTED) { usb_acknowledge(SYS_USB_DISCONNECTED_ACK); return; } } #else (void)q; #endif /* USB_FULL_INIT */ }
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 */ }
void display_logf(void) /* Doesn't return! */ { int i, index, button, user_index=0; #ifdef HAVE_TOUCHSCREEN int touch, prev_y=0; #endif char buffer[COLUMNS+1]; while(1) { index = logfindex + user_index; lcd_clear_display(); for(i = LINES-1; i>=0; i--) { if(--index < 0) { if(logfwrap) index = MAX_LOGF_LINES-1; else break; /* done */ } memcpy(buffer, logfbuffer[index], COLUMNS); if (logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_CONTINUE_LINE) buffer[MAX_LOGF_ENTRY-1] = '>'; else if (logfbuffer[index][MAX_LOGF_ENTRY] == LOGF_TERMINATE_MULTI_LINE) buffer[MAX_LOGF_ENTRY-1] = '\0'; buffer[COLUMNS] = '\0'; lcd_puts(0, i, buffer); } button = button_get(false); if(button == SYS_USB_CONNECTED) usb_acknowledge(SYS_USB_CONNECTED_ACK); else if(button == SYS_USB_DISCONNECTED) ; else if(button & LOGF_UP) user_index++; else if(button & LOGF_DOWN) user_index--; else if(button & LOGF_CLEAR) user_index = 0; #ifdef HAVE_TOUCHSCREEN else if(button & BUTTON_TOUCHSCREEN) { touch = button_get_data(); if(button & BUTTON_REL) prev_y = 0; if(prev_y != 0) user_index += (prev_y - (touch & 0xFFFF)) / SYSFONT_HEIGHT; prev_y = touch & 0xFFFF; } #endif lcd_update(); sleep(HZ/16); } }
void gui_usb_screen_run(bool early_usb) { (void) early_usb; struct usb_screen_vps_t usb_screen_vps_ar[NB_SCREENS]; #if defined HAVE_TOUCHSCREEN enum touchscreen_mode old_mode = touchscreen_get_mode(); /* TODO: Paint buttons on screens OR switch to point mode and use * touchscreen as a touchpad to move the host's mouse cursor */ touchscreen_set_mode(TOUCHSCREEN_BUTTON); #endif push_current_activity(ACTIVITY_USBSCREEN); #ifdef USB_ENABLE_HID usb_hid = global_settings.usb_hid; usb_keypad_mode = global_settings.usb_keypad_mode; #endif FOR_NB_SCREENS(i) { struct screen *screen = &screens[i]; screen->set_viewport(NULL); #ifdef HAVE_LCD_CHARCELLS /* Quick fix. Viewports should really be enabled proper for charcell */ viewport_set_defaults(&usb_screen_vps_ar[i].parent, i); #else usb_screen_fix_viewports(screen, &usb_screen_vps_ar[i]); #endif } /* update the UI before disabling fonts, this maximizes the propability * that font cache lookups succeed during USB */ send_event(GUI_EVENT_ACTIONUPDATE, NULL); #ifdef HAVE_LCD_BITMAP if(!early_usb) { /* The font system leaves the .fnt fd's open, so we need for force close them all */ font_disable_all(); } #endif usb_acknowledge(SYS_USB_CONNECTED_ACK); while (1) { usb_screens_draw(usb_screen_vps_ar); #ifdef SIMULATOR if (button_get_w_tmo(HZ/2)) break; send_event(GUI_EVENT_ACTIONUPDATE, NULL); #else if (handle_usb_events()) break; #endif /* SIMULATOR */ } FOR_NB_SCREENS(i) { const struct viewport* vp = NULL; #if defined(HAVE_LCD_BITMAP) && defined(USB_ENABLE_HID) vp = usb_hid ? &usb_screen_vps_ar[i].title : NULL; #elif !defined(HAVE_LCD_BITMAP) vp = &usb_screen_vps_ar[i].parent; #endif if (vp) screens[i].scroll_stop_viewport(vp); } #ifdef USB_ENABLE_HID if (global_settings.usb_keypad_mode != usb_keypad_mode) { global_settings.usb_keypad_mode = usb_keypad_mode; settings_save(); } #endif #ifdef HAVE_TOUCHSCREEN touchscreen_set_mode(old_mode); #endif #ifdef HAVE_LCD_CHARCELLS status_set_usb(false); #endif /* HAVE_LCD_CHARCELLS */ #ifdef HAVE_LCD_BITMAP if(!early_usb) { font_enable_all(); /* Not pretty, reload all settings so fonts are loaded again correctly */ settings_apply(true); /* Reload playlist */ playlist_resume(); } #endif FOR_NB_SCREENS(i) { screens[i].backlight_on(); viewportmanager_theme_undo(i, false); } pop_current_activity(); }
void gui_usb_screen_run(void) { int i; struct usb_screen_vps_t usb_screen_vps_ar[NB_SCREENS]; #if defined HAVE_TOUCHSCREEN enum touchscreen_mode old_mode = touchscreen_get_mode(); /* TODO: Paint buttons on screens OR switch to point mode and use * touchscreen as a touchpad to move the host's mouse cursor */ touchscreen_set_mode(TOUCHSCREEN_BUTTON); #endif #ifndef SIMULATOR usb_acknowledge(SYS_USB_CONNECTED_ACK); #endif #ifdef USB_ENABLE_HID usb_hid = global_settings.usb_hid; usb_keypad_mode = global_settings.usb_keypad_mode; #endif FOR_NB_SCREENS(i) { struct screen *screen = &screens[i]; screen->set_viewport(NULL); #ifdef HAVE_LCD_BITMAP usb_screen_fix_viewports(screen, &usb_screen_vps_ar[i]); #endif } while (1) { usb_screens_draw(usb_screen_vps_ar); #ifdef SIMULATOR if (button_get_w_tmo(HZ/2)) break; send_event(GUI_EVENT_ACTIONUPDATE, NULL); #else if (handle_usb_events()) break; #endif /* SIMULATOR */ } FOR_NB_SCREENS(i) { const struct viewport* vp = NULL; #if defined(HAVE_LCD_BITMAP) && defined(USB_ENABLE_HID) vp = usb_hid ? &usb_screen_vps_ar[i].title : NULL; #elif !defined(HAVE_LCD_BITMAP) vp = &usb_screen_vps_ar[i].parent; #endif if (vp) screens[i].scroll_stop(vp); } #ifdef USB_ENABLE_HID if (global_settings.usb_keypad_mode != usb_keypad_mode) { global_settings.usb_keypad_mode = usb_keypad_mode; settings_save(); } #endif #ifdef HAVE_TOUCHSCREEN touchscreen_set_mode(old_mode); #endif #ifdef HAVE_LCD_CHARCELLS status_set_usb(false); #endif /* HAVE_LCD_CHARCELLS */ FOR_NB_SCREENS(i) { screens[i].backlight_on(); viewportmanager_theme_undo(i, false); } }
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(); } } } } }
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; } } }