diff --git a/apps/SOURCES b/apps/SOURCES index 1aa4955205..6118438b40 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -100,7 +100,7 @@ gui/statusbar.c #ifdef HAVE_LCD_BITMAP gui/statusbar-skinned.c #endif -#if (CONFIG_PLATFORM&PLATFORM_ANDROID) +#if (CONFIG_PLATFORM&PLATFORM_ANDROID) && !defined (DX50) && !defined(DX90) hosted/android/yesno.c hosted/android/notification.c #else @@ -129,7 +129,7 @@ player/keyboard.c #ifdef HAVE_LCD_BITMAP recorder/bmp.c recorder/icons.c -#if (CONFIG_PLATFORM&PLATFORM_ANDROID) +#if (CONFIG_PLATFORM&PLATFORM_ANDROID) && !defined (DX50) && !defined(DX90) hosted/android/keyboard.c #else recorder/keyboard.c @@ -305,4 +305,6 @@ keymaps/keymap-ypz5.c keymaps/keymap-ihifi.c #elif CONFIG_KEYPAD == SAMSUNG_YPR1_PAD keymaps/keymap-ypr1.c +#elif CONFIG_KEYPAD == DX50_PAD +keymaps/keymap-dx50.c #endif diff --git a/apps/keymaps/keymap-dx50.c b/apps/keymaps/keymap-dx50.c new file mode 100644 index 0000000000..ee3b32005a --- /dev/null +++ b/apps/keymaps/keymap-dx50.c @@ -0,0 +1,219 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* Button Code Definitions for iBasso DX50 & DX90 */ + +#include +#include +#include + +#include "config.h" +#include "action.h" +#include "button.h" +#include "settings.h" + +/* + * The format of the list is as follows + * { Action Code, Button code, Prereq button code } + * if there's no need to check the previous button's value, use BUTTON_NONE + * Insert LAST_ITEM_IN_LIST at the end of each mapping + */ + +static const struct button_mapping button_context_standard[] = { + { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE }, + { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE }, + { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_STD_OK, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY }, + { ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE }, + { ACTION_STD_CONTEXT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE }, + + LAST_ITEM_IN_LIST +}; /* button_context_standard */ + +static const struct button_mapping button_context_wps[] = { + { ACTION_WPS_MENU, BUTTON_POWER, BUTTON_NONE }, + { ACTION_WPS_CONTEXT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_WPS_PLAY, BUTTON_PLAY|BUTTON_REL, BUTTON_NONE }, + { ACTION_WPS_SKIPNEXT, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE }, + { ACTION_WPS_SKIPPREV, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE }, + { ACTION_WPS_SEEKBACK, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_WPS_SEEKFWD, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_WPS_STOPSEEK, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT|BUTTON_REPEAT }, + { ACTION_WPS_STOPSEEK, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT|BUTTON_REPEAT }, + { ACTION_WPS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE }, + { ACTION_WPS_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE }, + { ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, + LAST_ITEM_IN_LIST +}; /* button_context_wps */ + +static const struct button_mapping button_context_list[] = { +#ifdef HAVE_VOLUME_IN_LIST + { ACTION_LIST_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_LIST_VOLUP, BUTTON_VOL_UP, BUTTON_NONE }, + { ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE }, + { ACTION_LIST_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, +#endif + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), +}; /* button_context_list */ + +static const struct button_mapping button_context_tree[] = { + + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST), +}; /* button_context_tree */ + +static const struct button_mapping button_context_listtree_scroll_with_combo[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_TREE), +}; + +static const struct button_mapping button_context_listtree_scroll_without_combo[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_TREE), +}; + +static const struct button_mapping button_context_settings[] = { + { ACTION_SETTINGS_INC, BUTTON_VOL_UP|BUTTON_REL, BUTTON_NONE }, + { ACTION_SETTINGS_INCREPEAT, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_SETTINGS_DEC, BUTTON_VOL_DOWN|BUTTON_REL, BUTTON_NONE }, + { ACTION_SETTINGS_DECREPEAT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), +}; /* button_context_settings */ + +static const struct button_mapping button_context_settings_right_is_inc[] = { + + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), +}; /* button_context_settingsgraphical */ + +static const struct button_mapping button_context_mainmenu[] = { + + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_TREE), +}; /* button_context_mainmenu */ + +static const struct button_mapping button_context_yesno[] = { + { ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE }, + + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD), +}; /* button_context_settings_yesno */ + +static const struct button_mapping button_context_colorchooser[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS), +}; /* button_context_colorchooser */ + +static const struct button_mapping button_context_eq[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS), +}; /* button_context_eq */ + +static const struct button_mapping button_context_keyboard[] = { + { ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE }, + { ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_RIGHT, BUTTON_RIGHT, BUTTON_NONE }, + { ACTION_KBD_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, + + { ACTION_KBD_CURSOR_LEFT, BUTTON_PLAY|BUTTON_LEFT, BUTTON_NONE }, + { ACTION_KBD_CURSOR_LEFT, BUTTON_PLAY|BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_CURSOR_RIGHT, BUTTON_PLAY|BUTTON_RIGHT, BUTTON_NONE }, + { ACTION_KBD_CURSOR_RIGHT, BUTTON_PLAY|BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_SELECT, BUTTON_PLAY, BUTTON_NONE }, + + { ACTION_KBD_UP, BUTTON_VOL_UP, BUTTON_NONE }, + { ACTION_KBD_UP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE }, + { ACTION_KBD_DOWN, BUTTON_VOL_DOWN, BUTTON_NONE }, + { ACTION_KBD_DOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, + + LAST_ITEM_IN_LIST +}; /* button_context_keyboard */ + +/** Bookmark Screen **/ +static const struct button_mapping button_context_bmark[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST), +}; /* button_context_bmark */ + +static const struct button_mapping button_context_time[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS), +}; /* button_context_time */ + +static const struct button_mapping button_context_quickscreen[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) +}; /* button_context_quickscreen */ + +static const struct button_mapping button_context_pitchscreen[] = { + + { ACTION_PS_INC_SMALL, BUTTON_VOL_UP|BUTTON_REL, BUTTON_NONE }, + { ACTION_PS_DEC_SMALL, BUTTON_VOL_DOWN|BUTTON_REL, BUTTON_NONE }, + { ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE }, + + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) +}; /* button_context_pitchcreen */ + + +static const struct button_mapping button_context_radio[] = { + LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS) +}; /* button_context_radio */ + +const struct button_mapping* target_get_context_mapping(int context) +{ + switch (context) + { + case CONTEXT_STD: + return button_context_standard; + case CONTEXT_WPS: + return button_context_wps; + + case CONTEXT_LIST: + return button_context_list; + case CONTEXT_MAINMENU: + return button_context_mainmenu; + case CONTEXT_TREE: + if (global_settings.hold_lr_for_scroll_in_list) + return button_context_listtree_scroll_without_combo; + else + return button_context_listtree_scroll_with_combo; + case CONTEXT_CUSTOM|CONTEXT_TREE: + return button_context_tree; + + case CONTEXT_SETTINGS: + return button_context_settings; + case CONTEXT_CUSTOM|CONTEXT_SETTINGS: + case CONTEXT_SETTINGS_RECTRIGGER: + return button_context_settings_right_is_inc; + + case CONTEXT_SETTINGS_COLOURCHOOSER: + return button_context_colorchooser; + case CONTEXT_SETTINGS_EQ: + return button_context_eq; + + case CONTEXT_SETTINGS_TIME: + return button_context_time; + + case CONTEXT_KEYBOARD: + return button_context_keyboard; + + case CONTEXT_FM: + return button_context_radio; + case CONTEXT_BOOKMARKSCREEN: + return button_context_bmark; + case CONTEXT_QUICKSCREEN: + return button_context_quickscreen; + case CONTEXT_PITCHSCREEN: + return button_context_pitchscreen; + } + return button_context_standard; +} diff --git a/apps/main.c b/apps/main.c index 9098180fb8..60164515fa 100644 --- a/apps/main.c +++ b/apps/main.c @@ -340,7 +340,7 @@ static void init(void) #ifdef SIMULATOR sim_tasks_init(); #endif -#if (CONFIG_PLATFORM & PLATFORM_ANDROID) +#if (CONFIG_PLATFORM & PLATFORM_ANDROID) && !defined(DX50) && !defined(DX90) notification_init(); #endif lang_init(core_language_builtin, language_strings, diff --git a/apps/plugins/battery_bench.c b/apps/plugins/battery_bench.c index 930d56f29a..b0976d5e10 100644 --- a/apps/plugins/battery_bench.c +++ b/apps/plugins/battery_bench.c @@ -261,6 +261,12 @@ #define BATTERY_ON_TXT "PLAY - start" #define BATTERY_OFF_TXT "Power" +#elif CONFIG_KEYPAD == DX50_PAD +#define BATTERY_ON BUTTON_PLAY +#define BATTERY_OFF BUTTON_POWER +#define BATTERY_OFF_TXT "POWER" +#define BATTERY_ON_TXT "PLAY - start" + #else #error No keymap defined! #endif diff --git a/apps/plugins/blackjack.c b/apps/plugins/blackjack.c index 2211f88620..4022696a1f 100644 --- a/apps/plugins/blackjack.c +++ b/apps/plugins/blackjack.c @@ -541,6 +541,20 @@ enum { #define BJACK_QUIT_NAME "Back" #define BJACK_DOUBLE_NAME "Shortcut" +#elif CONFIG_KEYPAD == DX50_PAD +#define BJACK_QUIT BUTTON_POWER +#define BJACK_DOUBLEDOWN BUTTON_RIGHT +#define BJACK_SELECT BUTTON_PLAY +#define BJACK_QUIT BUTTON_POWER +#define BJACK_STAY BUTTON_LEFT +#define BJACK_UP BUTTON_VOL_UP +#define BJACK_DOWN BUTTON_VOL_DOWN +#define BJACK_LEFT BUTTON_LEFT +#define BJACK_SELECT_NAME "Play" +#define BJACK_STAY_NAME "Left" +#define BJACK_QUIT_NAME "Power" +#define BJACK_DOUBLE_NAME "Right" + #else #error No keymap defined! #endif diff --git a/apps/plugins/brickmania.c b/apps/plugins/brickmania.c index ee72e0bf37..0c9223d398 100644 --- a/apps/plugins/brickmania.c +++ b/apps/plugins/brickmania.c @@ -311,6 +311,13 @@ CONFIG_KEYPAD == SANSA_CONNECT_PAD #define UP BUTTON_UP #define DOWN BUTTON_DOWN +#elif CONFIG_KEYPAD == DX50_PAD +#define QUIT BUTTON_POWER +#define LEFT BUTTON_LEFT +#define RIGHT BUTTON_RIGHT +#define SELECT BUTTON_PLAY +#define UP BUTTON_VOL_UP +#define DOWN BUTTON_VOL_DOWN #else #error No keymap defined! diff --git a/apps/plugins/calculator.c b/apps/plugins/calculator.c index 6c75595f9e..c378ecbb81 100644 --- a/apps/plugins/calculator.c +++ b/apps/plugins/calculator.c @@ -497,6 +497,9 @@ F3: equal to "=" #define CALCULATOR_CALC BUTTON_PLAYPAUSE #define CALCULATOR_CLEAR BUTTON_SHORTCUT +#elif CONFIG_KEYPAD == DX50_PAD +#define CALCULATOR_QUIT BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/calendar.c b/apps/plugins/calendar.c index 2e0577fc73..91613fcf88 100644 --- a/apps/plugins/calendar.c +++ b/apps/plugins/calendar.c @@ -369,6 +369,16 @@ #define CALENDAR_NEXT_MONTH BUTTON_SHORTCUT #define CALENDAR_PREV_MONTH BUTTON_MENU +#elif CONFIG_KEYPAD == DX50_PAD +#define CALENDAR_QUIT (BUTTON_POWER|BUTTON_REL) +#define CALENDAR_SELECT BUTTON_PLAY +#define CALENDAR_NEXT_WEEK BUTTON_VOL_DOWN +#define CALENDAR_PREV_WEEK BUTTON_VOL_UP +#define CALENDAR_NEXT_DAY BUTTON_RIGHT +#define CALENDAR_PREV_DAY BUTTON_LEFT +#define CALENDAR_NEXT_MONTH BUTTON_BOTTOMRIGHT +#define CALENDAR_PREV_MONTH BUTTON_BOTTOMLEFT + #else #error "No keypad setting." #endif diff --git a/apps/plugins/chessbox/chessbox_pgn.h b/apps/plugins/chessbox/chessbox_pgn.h index c7aca0f939..df6a01c891 100644 --- a/apps/plugins/chessbox/chessbox_pgn.h +++ b/apps/plugins/chessbox/chessbox_pgn.h @@ -485,6 +485,19 @@ #define CB_MENU BUTTON_MENU #define CB_LEVEL BUTTON_BACK +#elif CONFIG_KEYPAD == DX50_PAD +#define CB_SELECT BUTTON_PLAY +#define CB_UP BUTTON_VOL_UP +#define CB_DOWN BUTTON_VOL_DOWN +#define CB_LEFT BUTTON_LEFT +#define CB_RIGHT BUTTON_RIGHT +#define CB_PLAY (BUTTON_PLAY|BUTTON_REPEAT) +#define CB_MENU BUTTON_POWER +#define CB_SCROLL_UP (BUTTON_VOL_UP|BUTTON_REPEAT) +#define CB_SCROLL_DOWN (BUTTON_VOL_DOWN|BUTTON_REPEAT) +#define CB_SCROLL_LEFT (BUTTON_LEFT|BUTTON_REPEAT) +#define CB_SCROLL_RIGHT (BUTTON_RIGHT|BUTTON_REPEAT) + #else #error No keymap defined! #endif diff --git a/apps/plugins/chessclock.c b/apps/plugins/chessclock.c index cacfbbe939..01895d20f8 100644 --- a/apps/plugins/chessclock.c +++ b/apps/plugins/chessclock.c @@ -387,6 +387,15 @@ #define CHC_SETTINGS_OK BUTTON_SELECT #define CHC_SETTINGS_CANCEL BUTTON_BACK +#elif CONFIG_KEYPAD == DX50_PAD +#define CHC_QUIT (BUTTON_POWER|BUTTON_REPEAT) +#define CHC_RESET (BUTTON_PLAY|BUTTON_REPEAT) +#define CHC_MENU BUTTON_RIGHT +#define CHC_STARTSTOP BUTTON_PLAY +#define CHC_SETTINGS_INC BUTTON_VOL_UP +#define CHC_SETTINGS_DEC BUTTON_VOL_DOWN +#define CHC_SETTINGS_CANCEL BUTTON_RIGHT + #else #error No keymap defined! #endif diff --git a/apps/plugins/chip8.c b/apps/plugins/chip8.c index d1a8285ace..efb62eb27e 100644 --- a/apps/plugins/chip8.c +++ b/apps/plugins/chip8.c @@ -1259,6 +1259,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define CHIP8_KEY8 BUTTON_PLAY #define CHIP8_KEY9 BUTTON_POWER +#elif (CONFIG_KEYPAD == DX50_PAD) +#define CHIP8_OFF BUTTON_POWER + #else #error No keymap defined! #endif diff --git a/apps/plugins/clix.c b/apps/plugins/clix.c index c204663cf5..ffbb01abb8 100644 --- a/apps/plugins/clix.c +++ b/apps/plugins/clix.c @@ -253,6 +253,9 @@ #elif (CONFIG_KEYPAD == SAMSUNG_YPR1_PAD) #define CLIX_BUTTON_QUIT BUTTON_POWER +#elif (CONFIG_KEYPAD == DX50_PAD) +#define CLIX_BUTTON_QUIT BUTTON_POWER + #else #error "no keymap" #endif diff --git a/apps/plugins/cube.c b/apps/plugins/cube.c index 5331d531db..09993204cd 100644 --- a/apps/plugins/cube.c +++ b/apps/plugins/cube.c @@ -390,6 +390,14 @@ #define CUBE_PAUSE BUTTON_PLAYPAUSE #define CUBE_HIGHSPEED BUTTON_SHORTCUT +#elif (CONFIG_KEYPAD == DX50_PAD) +#define CUBE_QUIT (BUTTON_POWER|BUTTON_REL) +#define CUBE_NEXT BUTTON_RIGHT +#define CUBE_PREV BUTTON_LEFT +#define CUBE_INC BUTTON_VOL_UP +#define CUBE_DEC BUTTON_VOL_DOWN +#define CUBE_MODE BUTTON_PLAY + #else #error No keymap defined! #endif diff --git a/apps/plugins/doom/i_video.c b/apps/plugins/doom/i_video.c index c285215e50..11aa712d33 100644 --- a/apps/plugins/doom/i_video.c +++ b/apps/plugins/doom/i_video.c @@ -523,6 +523,12 @@ void I_ShutdownGraphics(void) #define DOOMBUTTON_WEAPON BUTTON_SHORTCUT #define DOOMBUTTON_MAP BUTTON_MENU +#elif CONFIG_KEYPAD == DX50_PAD +#define DOOMBUTTON_ESC BUTTON_POWER +#define DOOMBUTTON_SHOOT BUTTON_VOL_UP +#define DOOMBUTTON_WEAPON BUTTON_VOL_DOWN +#define DOOMBUTTON_MAP BUTTON_PLAY + #else #error Keymap not defined! #endif diff --git a/apps/plugins/fft/fft.c b/apps/plugins/fft/fft.c index d4b79b2ea7..9871c31eb9 100644 --- a/apps/plugins/fft/fft.c +++ b/apps/plugins/fft/fft.c @@ -320,6 +320,11 @@ GREY_INFO_STRUCT # define FFT_ORIENTATION BUTTON_SELECT # define FFT_WINDOW BUTTON_MENU +#elif (CONFIG_KEYPAD == DX50_PAD) +# define FFT_QUIT (BUTTON_POWER|BUTTON_REL) +# define FFT_PREV_GRAPH BUTTON_VOL_UP +# define FFT_NEXT_GRAPH BUTTON_VOL_DOWN + #elif !defined(HAVE_TOUCHSCREEN) #error No keymap defined! #endif diff --git a/apps/plugins/flipit.c b/apps/plugins/flipit.c index 6274af4f1d..d3dc98aa54 100644 --- a/apps/plugins/flipit.c +++ b/apps/plugins/flipit.c @@ -453,6 +453,18 @@ #define FLIPIT_STEP_BY_STEP BUTTON_PLAY #define FLIPIT_TOGGLE BUTTON_SELECT +#elif CONFIG_KEYPAD == DX50_PAD + +#define FLIPIT_LEFT BUTTON_LEFT +#define FLIPIT_RIGHT BUTTON_RIGHT +#define FLIPIT_UP BUTTON_VOL_UP +#define FLIPIT_DOWN BUTTON_VOL_DOWN +#define FLIPIT_QUIT (BUTTON_POWER|BUTTON_REL) +#define FLIPIT_SHUFFLE (BUTTON_VOL_UP|BUTTON_POWER) +#define FLIPIT_SOLVE (BUTTON_VOL_DOWN|BUTTON_POWER) +#define FLIPIT_STEP_BY_STEP (BUTTON_LEFT|BUTTON_POWER) +#define FLIPIT_TOGGLE BUTTON_PLAY + #else #error No keymap defined! #endif diff --git a/apps/plugins/fractals/fractal.h b/apps/plugins/fractals/fractal.h index b5ab0d31c9..7e13657595 100644 --- a/apps/plugins/fractals/fractal.h +++ b/apps/plugins/fractals/fractal.h @@ -451,6 +451,9 @@ #define FRACTAL_PRECISION_DEC (BUTTON_POWER|BUTTON_MENU) #define FRACTAL_RESET BUTTON_SHORTCUT +#elif CONFIG_KEYPAD == DX50_PAD +#define FRACTAL_QUIT (BUTTON_POWER|BUTTON_REL) + #else #error No keymap defined! #endif diff --git a/apps/plugins/goban/goban.h b/apps/plugins/goban/goban.h index c709df3281..531b137556 100644 --- a/apps/plugins/goban/goban.h +++ b/apps/plugins/goban/goban.h @@ -432,6 +432,9 @@ #define GBN_BUTTON_CONTEXT BUTTON_PLAY #define GBN_BUTTON_NEXT_VAR BUTTON_NEXT +#elif (CONFIG_KEYPAD == DX50_PAD) +#define GBN_BUTTON_MENU (BUTTON_POWER|BUTTON_REL) + #else #error Unsupported keypad #endif diff --git a/apps/plugins/imageviewer/imageviewer_button.h b/apps/plugins/imageviewer/imageviewer_button.h index dd3b35041f..c5fb9730c1 100644 --- a/apps/plugins/imageviewer/imageviewer_button.h +++ b/apps/plugins/imageviewer/imageviewer_button.h @@ -452,6 +452,14 @@ #define IMGVIEW_PREVIOUS BUTTON_BACK #define IMGVIEW_MENU BUTTON_MENU +#elif CONFIG_KEYPAD == DX50_PAD +#define IMGVIEW_ZOOM_IN BUTTON_VOL_UP +#define IMGVIEW_ZOOM_OUT BUTTON_VOL_DOWN +#define IMGVIEW_NEXT BUTTON_RIGHT +#define IMGVIEW_PREVIOUS BUTTON_LEFT +#define IMGVIEW_QUIT (BUTTON_POWER|BUTTON_REL) +#define IMGVIEW_MENU (BUTTON_PLAY|BUTTON_REL) + #else #error No keymap defined! #endif diff --git a/apps/plugins/invadrox.c b/apps/plugins/invadrox.c index e77fe1e4a6..c1da3a6338 100644 --- a/apps/plugins/invadrox.c +++ b/apps/plugins/invadrox.c @@ -259,6 +259,13 @@ CONFIG_KEYPAD == MROBE500_PAD #define RIGHT BUTTON_RIGHT #define FIRE BUTTON_SELECT +#elif CONFIG_KEYPAD == DX50_PAD + +#define QUIT (BUTTON_POWER|BUTTON_REL) +#define LEFT BUTTON_LEFT +#define RIGHT BUTTON_PLAY +#define FIRE BUTTON_RIGHT + #else #error INVADROX: Unsupported keypad #endif diff --git a/apps/plugins/jewels.c b/apps/plugins/jewels.c index b4c53a96c4..d8a3cc39b5 100644 --- a/apps/plugins/jewels.c +++ b/apps/plugins/jewels.c @@ -359,6 +359,10 @@ CONFIG_KEYPAD == MROBE500_PAD #define HK_SELECT "SELECT" #define HK_CANCEL "POWER" +#elif CONFIG_KEYPAD == DX50_PAD +#define JEWELS_CANCEL BUTTON_POWER +#define HK_CANCEL "Power" + #else #error No keymap defined! #endif diff --git a/apps/plugins/lib/pluginlib_actions.c b/apps/plugins/lib/pluginlib_actions.c index 97dde57fbe..3113f64667 100644 --- a/apps/plugins/lib/pluginlib_actions.c +++ b/apps/plugins/lib/pluginlib_actions.c @@ -434,6 +434,13 @@ const struct button_mapping pla_main_ctx[] = {PLA_SELECT, BUTTON_PLAY, BUTTON_NONE}, {PLA_SELECT_REL, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY}, {PLA_SELECT_REPEAT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE}, +#elif (CONFIG_KEYPAD == DX50_PAD) + {PLA_CANCEL, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE}, + {PLA_EXIT, BUTTON_POWER|BUTTON_REL, BUTTON_NONE}, + {PLA_SELECT, BUTTON_PLAY, BUTTON_NONE}, + {PLA_SELECT_REL, BUTTON_PLAY|BUTTON_REL, BUTTON_NONE}, + {PLA_SELECT_REPEAT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE}, + #else # ifndef HAVE_TOUCHSCREEN # error pluginlib_actions: No actions defined diff --git a/apps/plugins/midi/midiplay.c b/apps/plugins/midi/midiplay.c index f5edc83f9a..2f4a698fad 100644 --- a/apps/plugins/midi/midiplay.c +++ b/apps/plugins/midi/midiplay.c @@ -275,6 +275,13 @@ #define BTN_DOWN BUTTON_DOWN #define BTN_PLAY BUTTON_PLAYPAUSE +#elif CONFIG_KEYPAD == DX50_PAD +#define BTN_QUIT BUTTON_POWER +#define BTN_RIGHT BUTTON_RIGHT +#define BTN_LEFT BUTTON_LEFT +#define BTN_UP BUTTON_VOL_UP +#define BTN_DOWN BUTTON_VOL_DOWN + #else #error No keymap defined! #endif diff --git a/apps/plugins/minesweeper.c b/apps/plugins/minesweeper.c index 4758a1f911..982bb8b67c 100644 --- a/apps/plugins/minesweeper.c +++ b/apps/plugins/minesweeper.c @@ -377,6 +377,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define MINESWP_DISCOVER BUTTON_SELECT #define MINESWP_INFO BUTTON_MENU +#elif (CONFIG_KEYPAD == DX50_PAD) +# define MINESWP_QUIT (BUTTON_POWER|BUTTON_REL) + #else #error No keymap defined! #endif diff --git a/apps/plugins/mp3_encoder.c b/apps/plugins/mp3_encoder.c index 7b3c18bea2..7da00ad23b 100644 --- a/apps/plugins/mp3_encoder.c +++ b/apps/plugins/mp3_encoder.c @@ -2540,6 +2540,11 @@ CONFIG_KEYPAD == MROBE500_PAD #define MP3ENC_DONE BUTTON_PLAYPAUSE #define MP3ENC_SELECT BUTTON_SELECT +#elif (CONFIG_KEYPAD == DX50_PAD) +#define MP3ENC_PREV BUTTON_LEFT +#define MP3ENC_NEXT BUTTON_RIGHT +#define MP3ENC_DONE BUTTON_POWER +#define MP3ENC_SELECT BUTTON_PLAY #else #error No keymap defined! diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index 7b259395b9..1a9636e8d8 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -289,6 +289,14 @@ struct mpeg_settings settings; #define MPEG_START_TIME_DOWN BUTTON_DOWN #define MPEG_START_TIME_EXIT BUTTON_BACK +#elif CONFIG_KEYPAD == DX50_PAD +#define MPEG_START_TIME_EXIT BUTTON_POWER +#define MPEG_START_TIME_SELECT BUTTON_PLAY +#define MPEG_START_TIME_LEFT BUTTON_LEFT +#define MPEG_START_TIME_RIGHT BUTTON_RIGHT +#define MPEG_START_TIME_UP BUTTON_VOL_UP +#define MPEG_START_TIME_DOWN BUTTON_VOL_DOWN + #else #error No keymap defined! #endif diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index b041094e25..945d906d8b 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c @@ -417,6 +417,15 @@ CONFIG_KEYPAD == SANSA_M200_PAD #define MPEG_RW BUTTON_LEFT #define MPEG_FF BUTTON_RIGHT +#elif CONFIG_KEYPAD == DX50_PAD +#define MPEG_MENU BUTTON_POWER +#define MPEG_VOLDOWN BUTTON_VOL_DOWN +#define MPEG_VOLUP BUTTON_VOL_UP +#define MPEG_RW BUTTON_LEFT +#define MPEG_FF BUTTON_RIGHT +#define MPEG_PAUSE BUTTON_PLAY +#define MPEG_STOP (BUTTON_PLAY|BUTTON_REPEAT) + #else #error No keymap defined! #endif diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c index 559d52ea06..a0b976f466 100644 --- a/apps/plugins/oscilloscope.c +++ b/apps/plugins/oscilloscope.c @@ -486,6 +486,11 @@ #define OSCILLOSCOPE_VOL_UP BUTTON_UP #define OSCILLOSCOPE_VOL_DOWN BUTTON_DOWN +#elif CONFIG_KEYPAD == DX50_PAD +#define OSCILLOSCOPE_QUIT (BUTTON_POWER|BUTTON_REL) +#define OSCILLOSCOPE_VOL_UP BUTTON_VOL_UP +#define OSCILLOSCOPE_VOL_DOWN BUTTON_VOL_DOWN + #else #error No keymap defined! #endif diff --git a/apps/plugins/pacbox/pacbox.h b/apps/plugins/pacbox/pacbox.h index 1854006a91..5da7a8b099 100644 --- a/apps/plugins/pacbox/pacbox.h +++ b/apps/plugins/pacbox/pacbox.h @@ -328,6 +328,9 @@ #define PACMAN_1UP BUTTON_SELECT #define PACMAN_COIN BUTTON_PLAYPAUSE +#elif CONFIG_KEYPAD == DX50_PAD +#define PACMAN_MENU BUTTON_POWER + #else #error Keymap not defined! diff --git a/apps/plugins/pegbox.c b/apps/plugins/pegbox.c index fc0019fc26..1048138136 100644 --- a/apps/plugins/pegbox.c +++ b/apps/plugins/pegbox.c @@ -616,6 +616,11 @@ CONFIG_KEYPAD == MROBE500_PAD #define LVL_DOWN_TEXT "PLAY/PAUSE" #define SELECT_TEXT "SELECT" +#elif CONFIG_KEYPAD == DX50_PAD +#define PEGBOX_QUIT BUTTON_POWER + +#define QUIT_TEXT "Power" + #else #error Unsupported keymap! #endif diff --git a/apps/plugins/plugins.make b/apps/plugins/plugins.make index 92769d770a..1edbd37306 100644 --- a/apps/plugins/plugins.make +++ b/apps/plugins/plugins.make @@ -11,7 +11,9 @@ is_app_build = ifdef APP_TYPE ifneq ($(APP_TYPE),sdl-sim) - is_app_build = yes +ifeq (,$(findstring standalone, $(APP_TYPE))) + is_app_build = yes +endif endif endif diff --git a/apps/plugins/pong.c b/apps/plugins/pong.c index eb5adb3351..4ec62e01be 100644 --- a/apps/plugins/pong.c +++ b/apps/plugins/pong.c @@ -287,6 +287,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define PONG_RIGHT_UP BUTTON_RIGHT #define PONG_RIGHT_DOWN BUTTON_LEFT +#elif (CONFIG_KEYPAD == DX50_PAD) +#define PONG_QUIT (BUTTON_POWER|BUTTON_REL) + #else #error No keymap defined! #endif diff --git a/apps/plugins/reversi/reversi-gui.h b/apps/plugins/reversi/reversi-gui.h index 5c43ce2373..3932b688ef 100644 --- a/apps/plugins/reversi/reversi-gui.h +++ b/apps/plugins/reversi/reversi-gui.h @@ -312,6 +312,10 @@ #define REVERSI_BUTTON_MAKE_MOVE BUTTON_SELECT #define REVERSI_BUTTON_MENU BUTTON_MENU +#elif CONFIG_KEYPAD == DX50_PAD +#define REVERSI_BUTTON_QUIT BUTTON_POWER +#define REVERSI_BUTTON_MENU BUTTON_PLAY + #else #error No keymap defined! #endif diff --git a/apps/plugins/rockblox.c b/apps/plugins/rockblox.c index 5647b0a719..cde542a1c0 100644 --- a/apps/plugins/rockblox.c +++ b/apps/plugins/rockblox.c @@ -449,6 +449,14 @@ #define ROCKBLOX_DROP BUTTON_SELECT #define ROCKBLOX_RESTART BUTTON_SHORTCUT +#elif CONFIG_KEYPAD == DX50_PAD +#define ROCKBLOX_OFF BUTTON_POWER +#define ROCKBLOX_ROTATE BUTTON_RIGHT +#define ROCKBLOX_LEFT BUTTON_LEFT +#define ROCKBLOX_RIGHT BUTTON_PLAY +#define ROCKBLOX_DROP BUTTON_VOL_DOWN +#define ROCKBLOX_RESTART BUTTON_VOL_UP + #else #error No keymap defined! #endif diff --git a/apps/plugins/rockboy/rockboy.c b/apps/plugins/rockboy/rockboy.c index c12df07140..12feabb8e1 100644 --- a/apps/plugins/rockboy/rockboy.c +++ b/apps/plugins/rockboy/rockboy.c @@ -402,6 +402,13 @@ static void setoptions (void) options.A = BUTTON_SHORTCUT; options.B = BUTTON_PLAYPAUSE; +#elif CONFIG_KEYPAD == DX50_PAD + options.A = BUTTON_VOL_UP; + options.B = BUTTON_VOL_DOWN; + options.MENU = BUTTON_POWER; + options.START = BUTTON_LEFT; + options.SELECT = BUTTON_RIGHT; + #else #error No Keymap Defined! #endif @@ -414,7 +421,7 @@ static void setoptions (void) #if CONFIG_KEYPAD == MROBE500_PAD options.A = BUTTON_BOTTOMLEFT; options.B = BUTTON_BOTTOMRIGHT; -#elif CONFIG_KEYPAD != COWON_D2_PAD +#elif (CONFIG_KEYPAD != COWON_D2_PAD ) || (CONFIG_KEYPAD != DX50_PAD ) options.A = BUTTON_BOTTOMLEFT; options.B = BUTTON_BOTTOMRIGHT; options.MENU = BUTTON_TOPLEFT; diff --git a/apps/plugins/rockpaint.c b/apps/plugins/rockpaint.c index af6ce20eec..f3647c6024 100644 --- a/apps/plugins/rockpaint.c +++ b/apps/plugins/rockpaint.c @@ -310,6 +310,9 @@ #define ROCKPAINT_TOOLBAR BUTTON_SHORTCUT #define ROCKPAINT_TOOLBAR2 BUTTON_PLAYPAUSE +#elif ( CONFIG_KEYPAD == DX50_PAD ) +#define ROCKPAINT_QUIT (BUTTON_POWER|BUTTON_REL) + #else #error "Please define keys for this keypad" #endif diff --git a/apps/plugins/sliding_puzzle.c b/apps/plugins/sliding_puzzle.c index 39c60628c7..d4dd01f948 100644 --- a/apps/plugins/sliding_puzzle.c +++ b/apps/plugins/sliding_puzzle.c @@ -310,6 +310,12 @@ CONFIG_KEYPAD == MROBE500_PAD #define PUZZLE_SHUFFLE BUTTON_SHORTCUT #define PUZZLE_PICTURE BUTTON_PLAYPAUSE +#elif (CONFIG_KEYPAD == DX50_PAD) +#define PUZZLE_QUIT (BUTTON_POWER|BUTTON_REL) +#define PUZZLE_SHUFFLE BUTTON_PLAY +#define PUZZLE_PICTURE BUTTON_RIGHT +#define PUZZLE_QUIT_TEXT "[Power]" + #else #error No keymap defined! #endif diff --git a/apps/plugins/snake.c b/apps/plugins/snake.c index 55d91cb5f9..a22ecf4c70 100644 --- a/apps/plugins/snake.c +++ b/apps/plugins/snake.c @@ -269,6 +269,14 @@ dir is the current direction of the snake - 0=up, 1=right, 2=down, 3=left; #define SNAKE_DOWN BUTTON_DOWN #define SNAKE_PLAYPAUSE BUTTON_PLAYPAUSE +#elif CONFIG_KEYPAD == DX50_PAD +#define SNAKE_QUIT BUTTON_POWER +#define SNAKE_LEFT BUTTON_LEFT +#define SNAKE_RIGHT BUTTON_PLAY +#define SNAKE_UP BUTTON_VOL_UP +#define SNAKE_DOWN BUTTON_VOL_DOWN +#define SNAKE_PLAYPAUSE BUTTON_RIGHT + #else #error No keymap defined! #endif diff --git a/apps/plugins/snake2.c b/apps/plugins/snake2.c index 2fb5521a79..b695dc9abd 100644 --- a/apps/plugins/snake2.c +++ b/apps/plugins/snake2.c @@ -383,6 +383,15 @@ CONFIG_KEYPAD == MROBE500_PAD #define SNAKE2_PLAYPAUSE BUTTON_PLAYPAUSE #define SNAKE2_PLAYPAUSE_TEXT "Play/Pause" +#elif (CONFIG_KEYPAD == DX50_PAD) +#define SNAKE2_QUIT (BUTTON_POWER|BUTTON_REL) +#define SNAKE2_LEFT BUTTON_LEFT +#define SNAKE2_RIGHT BUTTON_PLAY +#define SNAKE2_UP BUTTON_VOL_UP +#define SNAKE2_DOWN BUTTON_VOL_DOWN +#define SNAKE2_PLAYPAUSE BUTTON_RIGHT +#define SNAKE2_PLAYPAUSE_TEXT "Right" + #else #error No keymap defined! #endif diff --git a/apps/plugins/sokoban.c b/apps/plugins/sokoban.c index 07b5856240..f3c4f9c8f6 100644 --- a/apps/plugins/sokoban.c +++ b/apps/plugins/sokoban.c @@ -611,6 +611,14 @@ #define BUTTON_SAVE (BUTTON_POWER | BUTTON_PLAY) #define BUTTON_SAVE_NAME "POWER + PLAY" +#elif CONFIG_KEYPAD == DX50_PAD +#define SOKOBAN_MENU (BUTTON_POWER|BUTTON_REL) +#define SOKOBAN_PAUSE BUTTON_PLAY +#define SOKOBAN_LEVEL_DOWN BUTTON_LEFT +#define SOKOBAN_LEVEL_UP BUTTON_RIGHT +#define SOKOBAN_MENU_NAME "Power" +#define SOKOBAN_PAUSE_NAME "Play" + #else #error No keymap defined! #endif diff --git a/apps/plugins/solitaire.c b/apps/plugins/solitaire.c index 04e3c15d56..541b42de42 100644 --- a/apps/plugins/solitaire.c +++ b/apps/plugins/solitaire.c @@ -651,6 +651,9 @@ CONFIG_KEYPAD == MROBE500_PAD #define HK_CUR2STACK "Menu" #define HK_REM2STACK "Shortcut" +#elif (CONFIG_KEYPAD == DX50_PAD) +# define SOL_QUIT (BUTTON_POWER | BUTTON_REL) + #else #error No keymap defined! #endif diff --git a/apps/plugins/spacerocks.c b/apps/plugins/spacerocks.c index 68f47caa4a..a7e9912cf4 100644 --- a/apps/plugins/spacerocks.c +++ b/apps/plugins/spacerocks.c @@ -333,6 +333,14 @@ #define AST_RIGHT BUTTON_RIGHT #define AST_FIRE BUTTON_SELECT +#elif (CONFIG_KEYPAD == DX50_PAD) +#define AST_QUIT BUTTON_POWER +#define AST_THRUST BUTTON_VOL_UP +#define AST_HYPERSPACE BUTTON_VOL_DOWN +#define AST_LEFT BUTTON_LEFT +#define AST_RIGHT BUTTON_PLAY +#define AST_FIRE BUTTON_RIGHT + #else #error No keymap defined! #endif diff --git a/apps/plugins/star.c b/apps/plugins/star.c index b43c05ebf5..a1367e9044 100644 --- a/apps/plugins/star.c +++ b/apps/plugins/star.c @@ -581,6 +581,10 @@ #define STAR_TOGGLE_CONTROL_NAME "Select" #define STAR_QUIT_NAME "Back" +#elif (CONFIG_KEYPAD == DX50_PAD) +#define STAR_QUIT BUTTON_POWER +#define STAR_QUIT_NAME "Power" + #else #error No keymap defined! #endif diff --git a/apps/plugins/sudoku/sudoku.h b/apps/plugins/sudoku/sudoku.h index 2bc65eeaa7..2caa75fbbe 100644 --- a/apps/plugins/sudoku/sudoku.h +++ b/apps/plugins/sudoku/sudoku.h @@ -398,6 +398,9 @@ #define SUDOKU_BUTTON_TOGGLE BUTTON_SELECT #define SUDOKU_BUTTON_POSSIBLE BUTTON_SHORTCUT +#elif CONFIG_KEYPAD == DX50_PAD +#define SUDOKU_BUTTON_QUIT (BUTTON_POWER|BUTTON_REL) + #else #error No keymap defined! #endif diff --git a/apps/plugins/text_viewer/tv_button.h b/apps/plugins/text_viewer/tv_button.h index bcaa593cea..7c0cfab519 100644 --- a/apps/plugins/text_viewer/tv_button.h +++ b/apps/plugins/text_viewer/tv_button.h @@ -506,6 +506,16 @@ #define TV_AUTOSCROLL BUTTON_PLAYPAUSE #define TV_BOOKMARK BUTTON_SHORTCUT +#elif CONFIG_KEYPAD == DX50_PAD +#define TV_QUIT (BUTTON_POWER | BUTTON_REL) +#define TV_SCROLL_UP BUTTON_VOL_UP +#define TV_SCROLL_DOWN BUTTON_VOL_DOWN +#define TV_SCREEN_LEFT BUTTON_LEFT +#define TV_SCREEN_RIGHT BUTTON_RIGHT +#define TV_MENU (BUTTON_PLAY | BUTTON_REL) +#define TV_AUTOSCROLL (BUTTON_POWER | BUTTON_PLAY) +#define TV_BOOKMARK (BUTTON_POWER | BUTTON_VOL_UP) + #else #error No keymap defined! #endif diff --git a/apps/plugins/vu_meter.c b/apps/plugins/vu_meter.c index 6d8922cd4b..43a7b917a9 100644 --- a/apps/plugins/vu_meter.c +++ b/apps/plugins/vu_meter.c @@ -395,6 +395,14 @@ #define LABEL_MENU "Menu" #define LABEL_VOLUME "Up/Down" +#elif CONFIG_KEYPAD == DX50_PAD +#define VUMETER_QUIT (BUTTON_POWER|BUTTON_REL) +#define VUMETER_MENU BUTTON_PLAY +#define VUMETER_UP BUTTON_RIGHT +#define VUMETER_DOWN BUTTON_LEFT +#define LABEL_QUIT "Power" +#define LABEL_MENU "Play" + #else #error No keymap defined! #endif diff --git a/apps/plugins/wormlet.c b/apps/plugins/wormlet.c index 51021dfac4..26b97c7748 100644 --- a/apps/plugins/wormlet.c +++ b/apps/plugins/wormlet.c @@ -370,6 +370,15 @@ CONFIG_KEYPAD == MROBE500_PAD #define BTN_QUIT BUTTON_BACK #define BTN_STOPRESET BUTTON_SHORTCUT +#elif CONFIG_KEYPAD == DX50_PAD +#define BTN_DIR_UP BUTTON_VOL_UP +#define BTN_DIR_DOWN BUTTON_VOL_DOWN +#define BTN_DIR_LEFT BUTTON_LEFT +#define BTN_DIR_RIGHT BUTTON_RIGHT +#define BTN_STARTPAUSE BUTTON_PLAY +#define BTN_QUIT BUTTON_POWER +#define BTN_STOPRESET (BUTTON_PLAY|BUTTON_REPEAT) + #else #error No keymap defined! #endif diff --git a/apps/plugins/xobox.c b/apps/plugins/xobox.c index 3cf3b2a434..f3ed96f282 100644 --- a/apps/plugins/xobox.c +++ b/apps/plugins/xobox.c @@ -322,6 +322,14 @@ CONFIG_KEYPAD == MROBE500_PAD #define DOWN BUTTON_DOWN #define PAUSE BUTTON_PLAYPAUSE +#elif CONFIG_KEYPAD == DX50_PAD +#define QUIT BUTTON_POWER +#define LEFT BUTTON_LEFT +#define RIGHT BUTTON_RIGHT +#define UP BUTTON_VOL_UP +#define DOWN BUTTON_VOL_DOWN +#define PAUSE BUTTON_PLAY + #else #error No keymap defined! #endif diff --git a/apps/plugins/zxbox/keymaps.h b/apps/plugins/zxbox/keymaps.h index d8be7f832b..bdbe4f93ad 100644 --- a/apps/plugins/zxbox/keymaps.h +++ b/apps/plugins/zxbox/keymaps.h @@ -262,6 +262,14 @@ #define ZX_RIGHT BUTTON_RIGHT #define ZX_SELECT BUTTON_SELECT +#elif CONFIG_KEYPAD == DX50_PAD +#define ZX_MENU BUTTON_POWER +#define ZX_UP BUTTON_VOL_UP +#define ZX_DOWN BUTTON_VOL_DOWN +#define ZX_SELECT BUTTON_PLAY +#define ZX_LEFT BUTTON_LEFT +#define ZX_RIGHT BUTTON_RIGHT + #else #error Keymap not defined! diff --git a/apps/root_menu.c b/apps/root_menu.c index 7ec803f585..f1b5017751 100644 --- a/apps/root_menu.c +++ b/apps/root_menu.c @@ -792,13 +792,13 @@ void root_menu(void) case GO_TO_ROOT: if (last_screen != GO_TO_ROOT) selected = get_selection(last_screen); -#if (CONFIG_PLATFORM&PLATFORM_ANDROID) +#if (CONFIG_PLATFORM&PLATFORM_ANDROID) && !defined(DX50) && !defined(DX90) /* When we are in the main menu we want the hardware BACK * button to be handled by Android instead of rockbox */ android_ignore_back_button(true); #endif next_screen = do_menu(&root_menu_, &selected, NULL, false); -#if (CONFIG_PLATFORM&PLATFORM_ANDROID) +#if (CONFIG_PLATFORM&PLATFORM_ANDROID) && !defined(DX50) && !defined(DX90) android_ignore_back_button(false); #endif if (next_screen != GO_TO_PREVIOUS) diff --git a/firmware/SOURCES b/firmware/SOURCES index 070f0d4a62..950e4f2bcf 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1811,18 +1811,28 @@ target/arm/rk27xx/ihifi/powermgmt-ihifi960.c target/hosted/kernel-unix.c target/hosted/filesystem-unix.c target/hosted/lc-unix.c +#if !defined(DX50) && !defined(DX90) target/hosted/android/lcd-android.c target/hosted/android/button-android.c -#ifdef DEBUG -target/hosted/android/debug-android.c -#endif target/hosted/android/pcm-android.c target/hosted/android/powermgmt-android.c -target/hosted/android/system-android.c target/hosted/android/telephony-android.c #ifdef APPLICATION target/hosted/android/app/button-application.c #endif +#else +drivers/lcd-memframe.c +target/hosted/android/dx50/pcm-dx50.c +target/hosted/android/dx50/tinyalsa/pcm.c +target/hosted/android/dx50/powermgmt-dx50.c +target/hosted/android/dx50/backlight-dx50.c +target/hosted/android/dx50/button-dx50.c +target/hosted/android/dx50/lcd-dx50.c +#endif +#ifdef DEBUG +target/hosted/android/debug-android.c +#endif +target/hosted/android/system-android.c drivers/audio/android.c #endif diff --git a/firmware/asm/SOURCES b/firmware/asm/SOURCES index ebb6951071..f16285e623 100644 --- a/firmware/asm/SOURCES +++ b/firmware/asm/SOURCES @@ -14,7 +14,7 @@ mempcpy.c #if (defined(SANSA_E200) || defined(GIGABEAT_F) || defined(GIGABEAT_S) || \ defined(CREATIVE_ZVx) || defined(SANSA_CONNECT) || defined(SANSA_FUZEPLUS) || \ defined(COWON_D2) || defined(MINI2440) || defined(SAMSUNG_YPR0) || \ - defined(SAMSUNG_YPR1) || (defined(MROBE_500) && !defined(LCD_USE_DMA)) || \ + defined(SAMSUNG_YPR1) || defined(DX50) || defined(DX90) || (defined(MROBE_500) && !defined(LCD_USE_DMA)) || \ defined(CREATIVE_ZEN) || defined(CREATIVE_ZENXFI)) && \ !defined(SIMULATOR) #if LCD_DEPTH == 24 diff --git a/firmware/asm/arm/thread.h b/firmware/asm/arm/thread.h index 7b8ebc2041..533a088979 100644 --- a/firmware/asm/arm/thread.h +++ b/firmware/asm/arm/thread.h @@ -31,7 +31,11 @@ struct regs #if (CONFIG_PLATFORM & PLATFORM_HOSTED) #include +#if defined(DX50) || defined (DX90) + #define DEFAULT_STACK_SIZE 0x2000 /* Bytes */ +#else #define DEFAULT_STACK_SIZE 0x1000 /* Bytes */ +#endif #else #define DEFAULT_STACK_SIZE 0x400 /* Bytes */ #endif diff --git a/firmware/drivers/audio/android.c b/firmware/drivers/audio/android.c index 7a5f34ea48..f26087470b 100644 --- a/firmware/drivers/audio/android.c +++ b/firmware/drivers/audio/android.c @@ -22,12 +22,34 @@ #include "config.h" #include "audiohw.h" +#if defined(DX50) || defined(DX90) +#include "system.h" +#include "pcm_sw_volume.h" +#endif +#if defined(DX50) || defined(DX90) +void audiohw_set_volume(int vol_l, int vol_r) +{ + int hw_volume; + hw_volume = MAX(vol_l, vol_r); + +#ifdef HAVE_SW_VOLUME_CONTROL + vol_l-=hw_volume; + vol_r-=hw_volume; + pcm_set_master_volume(vol_l, vol_r); +#endif + + extern void pcm_set_mixer_volume(int); + pcm_set_mixer_volume(hw_volume); + +} +#else void audiohw_set_volume(int volume) { extern void pcm_set_mixer_volume(int); pcm_set_mixer_volume(volume); } +#endif void audiohw_set_balance(int balance) { @@ -36,6 +58,8 @@ void audiohw_set_balance(int balance) void audiohw_close(void) { +#if !defined(DX50) && !defined(DX90) extern void pcm_shutdown(void); pcm_shutdown(); +#endif } diff --git a/firmware/drivers/touchscreen.c b/firmware/drivers/touchscreen.c index 42ddf7ec47..572f05ab7f 100644 --- a/firmware/drivers/touchscreen.c +++ b/firmware/drivers/touchscreen.c @@ -188,7 +188,7 @@ bool touchscreen_is_enabled(void) } #endif -#if ((CONFIG_PLATFORM & PLATFORM_ANDROID) == 0) +#if ((CONFIG_PLATFORM & PLATFORM_ANDROID) == 0) || defined(DX50) || defined(DX90) /* android has an API for this */ #define TOUCH_SLOP 16u diff --git a/firmware/export/config.h b/firmware/export/config.h index a56dd32303..bf95dc4c09 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -164,6 +164,7 @@ #define IHIFI_PAD 60 #define SAMSUNG_YPR1_PAD 61 #define SAMSUNG_YH920_PAD 62 +#define DX50_PAD 63 /* CONFIG_REMOTE_KEYPAD */ #define H100_REMOTE 1 @@ -575,6 +576,10 @@ Lyre prototype 1 */ #include "config/creativezenxfistyle.h" #elif defined(SAMSUNG_YPR1) #include "config/samsungypr1.h" +#elif defined(DX50) +#include "config/ibassodx50.h" +#elif defined(DX90) +#include "config/ibassodx90.h" #else /* no known platform */ #endif diff --git a/firmware/export/config/ibassodx50.h b/firmware/export/config/ibassodx50.h new file mode 100644 index 0000000000..652377cc6c --- /dev/null +++ b/firmware/export/config/ibassodx50.h @@ -0,0 +1,136 @@ +/* + * This config file is for Rockbox as an application on Android + */ + +/* We don't run on hardware directly */ +#define CONFIG_PLATFORM (PLATFORM_HOSTED|PLATFORM_ANDROID) + +/* For Rolo and boot loader */ +#define MODEL_NUMBER 94 + +#define MODEL_NAME "iBasso DX50" + +#define USB_NONE + +/* define this if you have a bitmap LCD display */ +#define HAVE_LCD_BITMAP + +/* define this if you have a colour LCD */ +#define HAVE_LCD_COLOR + +/* define this if you want album art for this target */ +#define HAVE_ALBUMART + +/* define this to enable bitmap scaling */ +#define HAVE_BMP_SCALING + +/* define this to enable JPEG decoding */ +#define HAVE_JPEG + +/* define this if you have access to the quickscreen */ +#define HAVE_QUICKSCREEN + +/* define this if you would like tagcache to build on this target */ +#define HAVE_TAGCACHE + +/* LCD dimensions */ +#define LCD_WIDTH 320 +#define LCD_HEIGHT 240 +#define LCD_DPI 166 +#define LCD_DEPTH 16 +#define LCD_PIXELFORMAT RGB565 + +#define HAVE_LCD_ENABLE + +/* define this to indicate your device's keypad */ +#define HAVE_TOUCHSCREEN +#define HAVE_BUTTON_DATA + +/* define this if you have RTC RAM available for settings */ +//#define HAVE_RTC_RAM + +/* define this if you have a real-time clock */ +//#define CONFIG_RTC APPLICATION + +/* Define this if you have a software controlled poweroff */ +#define HAVE_SW_POWEROFF + +/* The number of bytes reserved for loadable codecs */ +#define CODEC_SIZE 0x100000 + +/* The number of bytes reserved for loadable plugins */ +#define PLUGIN_BUFFER_SIZE 0x160000 + +#define AB_REPEAT_ENABLE + +/* Define this for LCD backlight available */ +#define HAVE_BACKLIGHT +#define HAVE_BACKLIGHT_BRIGHTNESS + +/* Main LCD backlight brightness range and defaults */ +#define MIN_BRIGHTNESS_SETTING 4 +#define MAX_BRIGHTNESS_SETTING 255 +#define DEFAULT_BRIGHTNESS_SETTING 255 + +/* Which backlight fading type? */ +#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING + +/* Define this if you do software codec */ +#define CONFIG_CODEC SWCODEC + +//#define HAVE_MULTIMEDIA_KEYS +#define CONFIG_KEYPAD DX50_PAD + +/* define this if the target has volume keys which can be used in the lists */ +#define HAVE_VOLUME_IN_LIST + +/* define this if the host platform can change volume outside of rockbox */ +//#define PLATFORM_HAS_VOLUME_CHANGE + +#define HAVE_SW_TONE_CONTROLS + +#define HAVE_SW_VOLUME_CONTROL + +#define BATTERY_CAPACITY_DEFAULT 2100 /* default battery capacity */ +#define BATTERY_CAPACITY_MIN 1700 /* min. capacity selectable */ +#define BATTERY_CAPACITY_MAX 3200 /* max. capacity selectable */ +#define BATTERY_CAPACITY_INC 50 /* capacity increment */ +#define BATTERY_TYPES_COUNT 1 /* only one type */ + +#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE + +#define CONFIG_CHARGING CHARGING_SIMPLE + +#define NO_LOW_BATTERY_SHUTDOWN + +/* Define current usage levels. */ +#define CURRENT_NORMAL 210 /* 10 hours from a 2100 mAh battery */ +#define CURRENT_BACKLIGHT 30 /* TBD */ +#define CURRENT_RECORD 0 /* no recording */ + +/* Define this to the CPU frequency */ +/* +#define CPU_FREQ 48000000 +*/ + +/* define this if the hardware can be powered off while charging */ +#define HAVE_POWEROFF_WHILE_CHARGING + + +/* Offset ( in the firmware file's header ) to the file CRC */ +#define FIRMWARE_OFFSET_FILE_CRC 0 + +/* Offset ( in the firmware file's header ) to the real data */ +#define FIRMWARE_OFFSET_FILE_DATA 8 + +#define CONFIG_LCD LCD_COWOND2 + +/* Define this if a programmable hotkey is mapped */ +#define HAVE_HOTKEY + +#define BOOTDIR "/.rockbox" + +/* No special storage */ +#define CONFIG_STORAGE STORAGE_HOSTFS +#define HAVE_STORAGE_FLUSH + diff --git a/firmware/export/config/ibassodx90.h b/firmware/export/config/ibassodx90.h new file mode 100644 index 0000000000..d560f3e10b --- /dev/null +++ b/firmware/export/config/ibassodx90.h @@ -0,0 +1,136 @@ +/* + * This config file is for Rockbox as an application on Android + */ + +/* We don't run on hardware directly */ +#define CONFIG_PLATFORM (PLATFORM_HOSTED|PLATFORM_ANDROID) + +/* For Rolo and boot loader */ +#define MODEL_NUMBER 95 + +#define MODEL_NAME "iBasso DX90" + +#define USB_NONE + +/* define this if you have a bitmap LCD display */ +#define HAVE_LCD_BITMAP + +/* define this if you have a colour LCD */ +#define HAVE_LCD_COLOR + +/* define this if you want album art for this target */ +#define HAVE_ALBUMART + +/* define this to enable bitmap scaling */ +#define HAVE_BMP_SCALING + +/* define this to enable JPEG decoding */ +#define HAVE_JPEG + +/* define this if you have access to the quickscreen */ +#define HAVE_QUICKSCREEN + +/* define this if you would like tagcache to build on this target */ +#define HAVE_TAGCACHE + +/* LCD dimensions */ +#define LCD_WIDTH 320 +#define LCD_HEIGHT 240 +#define LCD_DPI 166 +#define LCD_DEPTH 16 +#define LCD_PIXELFORMAT RGB565 + +#define HAVE_LCD_ENABLE + +/* define this to indicate your device's keypad */ +#define HAVE_TOUCHSCREEN +#define HAVE_BUTTON_DATA + +/* define this if you have RTC RAM available for settings */ +//#define HAVE_RTC_RAM + +/* define this if you have a real-time clock */ +//#define CONFIG_RTC APPLICATION + +/* Define this if you have a software controlled poweroff */ +#define HAVE_SW_POWEROFF + +/* The number of bytes reserved for loadable codecs */ +#define CODEC_SIZE 0x100000 + +/* The number of bytes reserved for loadable plugins */ +#define PLUGIN_BUFFER_SIZE 0x160000 + +#define AB_REPEAT_ENABLE + +/* Define this for LCD backlight available */ +#define HAVE_BACKLIGHT +#define HAVE_BACKLIGHT_BRIGHTNESS + +/* Main LCD backlight brightness range and defaults */ +#define MIN_BRIGHTNESS_SETTING 4 +#define MAX_BRIGHTNESS_SETTING 255 +#define DEFAULT_BRIGHTNESS_SETTING 255 + +/* Which backlight fading type? */ +#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING + +/* Define this if you do software codec */ +#define CONFIG_CODEC SWCODEC + +//#define HAVE_MULTIMEDIA_KEYS +#define CONFIG_KEYPAD DX50_PAD + +/* define this if the target has volume keys which can be used in the lists */ +#define HAVE_VOLUME_IN_LIST + +/* define this if the host platform can change volume outside of rockbox */ +//#define PLATFORM_HAS_VOLUME_CHANGE + +#define HAVE_SW_TONE_CONTROLS + +#define HAVE_SW_VOLUME_CONTROL + +#define BATTERY_CAPACITY_DEFAULT 2100 /* default battery capacity */ +#define BATTERY_CAPACITY_MIN 1700 /* min. capacity selectable */ +#define BATTERY_CAPACITY_MAX 3200 /* max. capacity selectable */ +#define BATTERY_CAPACITY_INC 50 /* capacity increment */ +#define BATTERY_TYPES_COUNT 1 /* only one type */ + +#define CONFIG_BATTERY_MEASURE VOLTAGE_MEASURE + +#define CONFIG_CHARGING CHARGING_SIMPLE + +#define NO_LOW_BATTERY_SHUTDOWN + +/* Define current usage levels. */ +#define CURRENT_NORMAL 210 /* 10 hours from a 2100 mAh battery */ +#define CURRENT_BACKLIGHT 30 /* TBD */ +#define CURRENT_RECORD 0 /* no recording */ + +/* Define this to the CPU frequency */ +/* +#define CPU_FREQ 48000000 +*/ + +/* define this if the hardware can be powered off while charging */ +#define HAVE_POWEROFF_WHILE_CHARGING + + +/* Offset ( in the firmware file's header ) to the file CRC */ +#define FIRMWARE_OFFSET_FILE_CRC 0 + +/* Offset ( in the firmware file's header ) to the real data */ +#define FIRMWARE_OFFSET_FILE_DATA 8 + +#define CONFIG_LCD LCD_COWOND2 + +/* Define this if a programmable hotkey is mapped */ +#define HAVE_HOTKEY + +#define BOOTDIR "/.rockbox" + +/* No special storage */ +#define CONFIG_STORAGE STORAGE_HOSTFS +#define HAVE_STORAGE_FLUSH + diff --git a/firmware/export/hosted_codec.h b/firmware/export/hosted_codec.h index f5e92ed297..00ab099772 100644 --- a/firmware/export/hosted_codec.h +++ b/firmware/export/hosted_codec.h @@ -25,7 +25,9 @@ && !(CONFIG_PLATFORM & PLATFORM_MAEMO5) AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -80, 0, 0) #else +#if !defined(DX50) && !defined(DX90) #define AUDIOHW_CAPS (MONO_VOL_CAP) +#endif AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -99, 0, 0) #endif /* CONFIG_PLATFORM & PLATFORM_SDL */ @@ -50,4 +52,4 @@ AUDIOHW_SETTING(TREBLE_CUTOFF, "", 0, 1, 1, 4, 1) #endif #endif /* CONFIG_PLATFORM & PLATFORM_ANDROID */ -#endif /* HOSTED_CODEC_H */ \ No newline at end of file +#endif /* HOSTED_CODEC_H */ diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index b6d4b9f66e..a4b260b315 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c @@ -679,6 +679,8 @@ static void power_thread(void) /* Delay reading the first battery level */ #ifdef MROBE_100 while (_battery_voltage() > 4200) /* gives false readings initially */ +#elif defined(DX50) || defined(DX90) + while (_battery_voltage() < 1) /* can give false readings initially */ #endif { sleep(HZ/100); diff --git a/firmware/target/hosted/android/dx50/adc-target.h b/firmware/target/hosted/android/dx50/adc-target.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/firmware/target/hosted/android/dx50/backlight-dx50.c b/firmware/target/hosted/android/dx50/backlight-dx50.c new file mode 100644 index 0000000000..98dbcb8abe --- /dev/null +++ b/firmware/target/hosted/android/dx50/backlight-dx50.c @@ -0,0 +1,76 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * + * Copyright (C) 2011 by Lorenzo Miori + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "backlight.h" +#include "backlight-target.h" +#include "lcd.h" +#include "lcd-target.h" +#include +#include +#include "unistd.h" + +bool _backlight_init(void) +{ + /* We have nothing to do */ + return true; +} + +void _backlight_on(void) +{ + FILE *f = fopen("/sys/power/state", "w"); + fputs("on", f); + fclose(f); + lcd_enable(true); +} + +void _backlight_off(void) +{ + FILE * f; + + /* deny the player to sleep deep */ + f = fopen("/sys/power/wake_lock", "w"); + fputs("player", f); + fclose(f); + + /* deny the player to mute */ + f = fopen("/sys/class/codec/wm8740_mute", "w"); + fputc(0, f); + fclose(f); + + /* turn off backlight */ + f = fopen("/sys/power/state", "w"); + fputs("mem", f); + fclose(f); + +} + +void _backlight_set_brightness(int brightness) +{ + /* Just another check... */ + if (brightness > MAX_BRIGHTNESS_SETTING) + brightness = MAX_BRIGHTNESS_SETTING; + if (brightness < MIN_BRIGHTNESS_SETTING) + brightness = MIN_BRIGHTNESS_SETTING; + + FILE *f = fopen("/sys/devices/platform/rk29_backlight/backlight/rk28_bl/brightness", "w"); + fprintf(f, "%d", brightness); + fclose(f); +} diff --git a/firmware/target/hosted/android/dx50/backlight-target.h b/firmware/target/hosted/android/dx50/backlight-target.h new file mode 100644 index 0000000000..67836aa790 --- /dev/null +++ b/firmware/target/hosted/android/dx50/backlight-target.h @@ -0,0 +1,31 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Maurus Cuelenaere + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef BACKLIGHT_TARGET_H +#define BACKLIGHT_TARGET_H + +#include + +bool _backlight_init(void); +void _backlight_on(void); +void _backlight_off(void); +void _backlight_set_brightness(int brightness); + +#endif /* BACKLIGHT_TARGET_H */ diff --git a/firmware/target/hosted/android/dx50/button-dx50.c b/firmware/target/hosted/android/dx50/button-dx50.c new file mode 100644 index 0000000000..5ab58ce420 --- /dev/null +++ b/firmware/target/hosted/android/dx50/button-dx50.c @@ -0,0 +1,314 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (c) 2010 Thomas Martitz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + + +#include +#include "button.h" +#include "buttonmap.h" +#include "config.h" +#include "kernel.h" +#include "system.h" +#include "touchscreen.h" +#include "powermgmt.h" +#include "backlight.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +static struct pollfd *ufds; +static char **device_names; +static int nfds; + +enum { + PRINT_DEVICE_ERRORS = 1U << 0, + PRINT_DEVICE = 1U << 1, + PRINT_DEVICE_NAME = 1U << 2, + PRINT_DEVICE_INFO = 1U << 3, + PRINT_VERSION = 1U << 4, + PRINT_POSSIBLE_EVENTS = 1U << 5, + PRINT_INPUT_PROPS = 1U << 6, + PRINT_HID_DESCRIPTOR = 1U << 7, + + PRINT_ALL_INFO = (1U << 8) - 1, + + PRINT_LABELS = 1U << 16, +}; + +static int last_y, last_x; +static int last_btns; + +static enum { + STATE_UNKNOWN, + STATE_UP, + STATE_DOWN +} last_touch_state = STATE_UNKNOWN; + + +static int open_device(const char *device, int print_flags) +{ + int fd; + struct pollfd *new_ufds; + char **new_device_names; + + fd = open(device, O_RDWR); + if(fd < 0) { + if(print_flags & PRINT_DEVICE_ERRORS) + fprintf(stderr, "could not open %s, %s\n", device, strerror(errno)); + return -1; + } + + new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); + if(new_ufds == NULL) { + fprintf(stderr, "out of memory\n"); + return -1; + } + ufds = new_ufds; + new_device_names = realloc(device_names, sizeof(device_names[0]) * (nfds + 1)); + if(new_device_names == NULL) { + fprintf(stderr, "out of memory\n"); + return -1; + } + device_names = new_device_names; + + ufds[nfds].fd = fd; + ufds[nfds].events = POLLIN; + device_names[nfds] = strdup(device); + nfds++; + + return 0; +} + + + +static int scan_dir(const char *dirname, int print_flags) +{ + char devname[PATH_MAX]; + char *filename; + DIR *dir; + struct dirent *de; + dir = opendir(dirname); + if(dir == NULL) + return -1; + strcpy(devname, dirname); + filename = devname + strlen(devname); + *filename++ = '/'; + while((de = readdir(dir))) { + if(de->d_name[0] == '.' && + (de->d_name[1] == '\0' || + (de->d_name[1] == '.' && de->d_name[2] == '\0'))) + continue; + strcpy(filename, de->d_name); + open_device(devname, print_flags); + } + closedir(dir); + return 0; +} + +bool _hold; + +bool button_hold() +{ + FILE *f = fopen("/sys/class/axppower/holdkey", "r"); + char x; + fscanf(f, "%c", &x); + fclose(f); + _hold = !(x&STATE_UNLOCKED); + return _hold; +} + + +void button_init_device(void) +{ + int res; + int print_flags = 0; + const char *device = NULL; + const char *device_path = "/dev/input"; + + nfds = 1; + ufds = calloc(1, sizeof(ufds[0])); + ufds[0].fd = inotify_init(); + ufds[0].events = POLLIN; + if(device) { + res = open_device(device, print_flags); + if(res < 0) { + // return 1; + } + } else { + res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE); + if(res < 0) { + fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno)); + // return 1; + } + res = scan_dir(device_path, print_flags); + if(res < 0) { + fprintf(stderr, "scan dir failed for %s\n", device_path); + // return 1; + } + } + + button_hold(); //store state + + set_rockbox_ready(); +} + +void touchscreen_enable_device(bool en) +{ + (void)en; /* FIXME: do something smart */ +} + + +int keycode_to_button(int keyboard_key) +{ + switch(keyboard_key){ + case KEYCODE_PWR: + return BUTTON_POWER; + + case KEYCODE_PWR_LONG: + return BUTTON_POWER_LONG; + + case KEYCODE_VOLPLUS: + return BUTTON_VOL_UP; + + case KEYCODE_VOLMINUS: + return BUTTON_VOL_DOWN; + + case KEYCODE_PREV: + return BUTTON_LEFT; + + case KEYCODE_NEXT: + return BUTTON_RIGHT; + + case KEYCODE_PLAY: + return BUTTON_PLAY; + + case KEYCODE_HOLD: + button_hold(); /* store state */ + backlight_hold_changed(_hold); + return BUTTON_NONE; + + default: + return BUTTON_NONE; + } +} + + +int button_read_device(int *data) +{ + int i; + int res; + struct input_event event; + int read_more; + unsigned button = 0; + + if(last_btns & BUTTON_POWER_LONG) + { + return last_btns; /* simulate repeat */ + } + + do { + read_more = 0; + poll(ufds, nfds, 10); + for(i = 1; i < nfds; i++) { + if(ufds[i].revents & POLLIN) { + res = read(ufds[i].fd, &event, sizeof(event)); + if(res < (int)sizeof(event)) { + fprintf(stderr, "could not get event\n"); + } + + switch(event.type) + { + case 1: /* HW-Button */ + button = keycode_to_button(event.code); + if (_hold) /* we have to wait for keycode_to_button() first to maybe clear hold state */ + break; + if (button == BUTTON_NONE) + { + last_btns = button; + break; + } +/* workaround for a wrong feedback, only present with DX90 */ +#if defined(DX90) + if (button == BUTTON_RIGHT && (last_btns & BUTTON_LEFT == BUTTON_LEFT) && !event.value) + { + button = BUTTON_LEFT; + } +#endif + if (event.value) + last_btns |= button; + else + last_btns &= (~button); + + break; + + case 3: /* Touchscreen */ + if(_hold) + break; + + switch(event.code) + { + case 53: /* x -> next will be y */ + last_x = event.value; + read_more = 1; + break; + case 54: /* y */ + last_y = event.value; + break; + case 57: /* press -> next will be x */ + if(event.value==1) + { + last_touch_state = STATE_DOWN; + read_more = 1; + } + else + last_touch_state = STATE_UP; + break; + } + break; + } + } + } + } while(read_more); + + + /* Get grid button/coordinates based on the current touchscreen mode + * + * Caveat: the caller seemingly depends on *data always being filled with + * the last known touchscreen position, so always call + * touchscreen_to_pixels() */ + int touch = touchscreen_to_pixels(last_x, last_y, data); + + if (last_touch_state == STATE_DOWN) + return last_btns | touch; + + return last_btns; +} + diff --git a/firmware/target/hosted/android/dx50/button-target.h b/firmware/target/hosted/android/dx50/button-target.h new file mode 100644 index 0000000000..adc9cf6bfd --- /dev/null +++ b/firmware/target/hosted/android/dx50/button-target.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 by Rob Purchase + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version.r + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef _BUTTON_TARGET_H_ +#define _BUTTON_TARGET_H_ + +#include + +#define HAS_BUTTON_HOLD + +/* Main unit's buttons */ +#define BUTTON_LEFT 0x00000001 +#define BUTTON_RIGHT 0x00000002 +#define BUTTON_PLAY 0x00000004 +#define BUTTON_POWER 0x00000008 +#define BUTTON_VOL_UP 0x00000010 +#define BUTTON_VOL_DOWN 0x00000020 +#define BUTTON_POWER_LONG 0x00000040 + +#define BUTTON_MAIN (BUTTON_LEFT|BUTTON_VOL_UP|BUTTON_VOL_DOWN\ + |BUTTON_RIGHT|BUTTON_PLAY|BUTTON_POWER|BUTTON_POWER_LONG) + +#define KEYCODE_LINEOUT 113 +#define KEYCODE_SPDIF 114 +#define KEYCODE_HOLD 115 +#define KEYCODE_PWR 116 +#define KEYCODE_PWR_LONG 117 +#define KEYCODE_SD 143 +#define KEYCODE_VOLPLUS 158 +#define KEYCODE_VOLMINUS 159 +#define KEYCODE_PREV 160 +#define KEYCODE_NEXT 162 +#define KEYCODE_PLAY 161 +#define STATE_UNLOCKED 16 +#define STATE_SPDIF_UNPLUGGED 32 +#define STATE_LINEOUT_UNPLUGGED 64 + +/* Touch Screen Area Buttons */ +#define BUTTON_TOPLEFT 0x00001000 +#define BUTTON_TOPMIDDLE 0x00002000 +#define BUTTON_TOPRIGHT 0x00004000 +#define BUTTON_MIDLEFT 0x00008000 +#define BUTTON_CENTER 0x00010000 +#define BUTTON_MIDRIGHT 0x00020000 +#define BUTTON_BOTTOMLEFT 0x00040000 +#define BUTTON_BOTTOMMIDDLE 0x00080000 +#define BUTTON_BOTTOMRIGHT 0x00100000 + + +/* Software power-off */ +#define POWEROFF_BUTTON BUTTON_POWER_LONG +#define POWEROFF_COUNT 0 + +#endif /* _BUTTON_TARGET_H_ */ diff --git a/firmware/target/hosted/android/dx50/lcd-dx50.c b/firmware/target/hosted/android/dx50/lcd-dx50.c new file mode 100644 index 0000000000..4d78baaf00 --- /dev/null +++ b/firmware/target/hosted/android/dx50/lcd-dx50.c @@ -0,0 +1,120 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: lcd-bitmap.c 29248 2011-02-08 20:05:25Z thomasjfox $ + * + * Copyright (C) 2011 Lorenzo Miori, Thomas Martitz + * Copyright (C) 2013 Lorenzo Miori + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "file.h" +#include "debug.h" +#include "system.h" +#include "screendump.h" +#include "lcd.h" +#include "lcd-target.h" + +static int dev_fd = 0; +fb_data *dev_fb = 0; + +#ifdef HAVE_LCD_SHUTDOWN +void lcd_shutdown(void) +{ + printf("FB closed."); + munmap(dev_fb, FRAMEBUFFER_SIZE); + close(dev_fd); +} +#endif + +void lcd_init_device(void) +{ + size_t screensize; + struct fb_var_screeninfo vinfo; + struct fb_fix_screeninfo finfo; + + /* Open the framebuffer device */ + dev_fd = open("/dev/graphics/fb0", O_RDWR); + if (dev_fd == -1) { + perror("Error: cannot open framebuffer device"); + exit(1); + } + + /* Get the fixed properties */ + if (ioctl(dev_fd, FBIOGET_FSCREENINFO, &finfo) == -1) { + perror("Error reading fixed information"); + exit(2); + } + + + /* Now we get the settable settings, and we set 16 bit bpp */ + if (ioctl(dev_fd, FBIOGET_VSCREENINFO, &vinfo) == -1) { + perror("Error reading variable information"); + exit(3); + } + /* framebuffer does not fit the screen, a bug of iBassos Firmware, not rockbox. + cannot be solved with parameters */ + vinfo.bits_per_pixel = LCD_DEPTH; + vinfo.xres = vinfo.xres_virtual = vinfo.width = LCD_WIDTH; + vinfo.yres = vinfo.yres_virtual = vinfo.height = LCD_HEIGHT; + + if (ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo)) { + perror("fbset(ioctl)"); + exit(4); + } + + /* Figure out the size of the screen in bytes */ + screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; + if (screensize != FRAMEBUFFER_SIZE) { + exit(4); + perror("Display and framebuffer mismatch!\n"); + } + + /* Map the device to memory */ + dev_fb = mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, dev_fd, 0); + if ((int)dev_fb == -1) { + perror("Error: failed to map framebuffer device to memory"); + exit(4); + } + + /* Be sure to turn on display at startup */ + ioctl(dev_fd, FBIOBLANK, VESA_NO_BLANKING); +#ifdef HAVE_LCD_ENABLE + lcd_set_active(true); +#endif +} + +#ifdef HAVE_LCD_ENABLE +void lcd_enable(bool enable) + { + if (lcd_active() == enable) + return; + + lcd_set_active(enable); + + /* Turn on or off the display using Linux interface */ + ioctl(dev_fd, FBIOBLANK, enable ? VESA_NO_BLANKING : VESA_POWERDOWN); + + if (enable) + send_event(LCD_EVENT_ACTIVATION, NULL); +} +#endif diff --git a/firmware/target/hosted/android/dx50/lcd-target.h b/firmware/target/hosted/android/dx50/lcd-target.h new file mode 100644 index 0000000000..900350eca2 --- /dev/null +++ b/firmware/target/hosted/android/dx50/lcd-target.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __LCD_TARGET_H__ +#define __LCD_TARGET_H__ + +extern fb_data *dev_fb; +#define LCD_FRAMEBUF_ADDR(col, row) (dev_fb + row*LCD_WIDTH + col) +#ifdef HAVE_LCD_ENABLE +extern void lcd_set_active(bool active); +extern void lcd_enable(bool enable); +#endif +#endif diff --git a/firmware/target/hosted/android/dx50/pcm-dx50.c b/firmware/target/hosted/android/dx50/pcm-dx50.c new file mode 100644 index 0000000000..e7695873a0 --- /dev/null +++ b/firmware/target/hosted/android/dx50/pcm-dx50.c @@ -0,0 +1,364 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Thomas Martitz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + + +/* + * Based, but heavily modified, on the example given at + * http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html + * + * This driver uses the so-called unsafe async callback method and hardcoded device + * names. It fails when the audio device is busy by other apps. + * + * To make the async callback safer, an alternative stack is installed, since + * it's run from a signal hanlder (which otherwise uses the user stack). If + * tick tasks are run from a signal handler too, please install + * an alternative stack for it too. + * + * TODO: Rewrite this to do it properly with multithreading + * + * Alternatively, a version using polling in a tick task is provided. While + * supposedly safer, it appears to use more CPU (however I didn't measure it + * accurately, only looked at htop). At least, in this mode the "default" + * device works which doesnt break with other apps running. + */ + + +#include "autoconf.h" + +#include +#include +#include +#include +#include "tinyalsa/asoundlib.h" +#include "tinyalsa/asound.h" +#include "system.h" +#include "debug.h" +#include "kernel.h" + +#include "pcm.h" +#include "pcm-internal.h" +#include "pcm_mixer.h" +#include "pcm_sampr.h" +#include "audiohw.h" + +#include +#include + +static const snd_pcm_format_t format = PCM_FORMAT_S16_LE; /* sample format */ +static const int channels = 2; /* count of channels */ +static unsigned int rate = 44100; /* stream rate */ + +typedef struct pcm snd_pcm_t; +static snd_pcm_t *handle; +struct pcm_config config; + +static snd_pcm_sframes_t period_size = 512; /* if set to >= 1024, all timers become even slower */ +static char *frames; + +static const void *pcm_data = 0; +static size_t pcm_size = 0; + +static int recursion; + +static int set_hwparams(snd_pcm_t *handle) +{ + int err; + if (!frames) + frames = malloc(pcm_frames_to_bytes(handle, pcm_get_buffer_size(handle))); + err = 0; /* success */ + return err; +} + + +/* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ +static bool fill_frames(void) +{ + size_t copy_n, frames_left = period_size; + bool new_buffer = false; + + while (frames_left > 0) + { + if (!pcm_size) + { + new_buffer = true; + if (!pcm_play_dma_complete_callback(PCM_DMAST_OK, &pcm_data, + &pcm_size)) + { + return false; + } + } + copy_n = MIN((size_t)pcm_size, pcm_frames_to_bytes(handle, frames_left)); + memcpy(&frames[pcm_frames_to_bytes(handle, period_size-frames_left)], pcm_data, copy_n); + + pcm_data += copy_n; + pcm_size -= copy_n; + frames_left -= pcm_bytes_to_frames(handle, copy_n); + + if (new_buffer) + { + new_buffer = false; + pcm_play_dma_status_callback(PCM_DMAST_STARTED); + } + } + return true; +} + + +static void pcm_tick(void) +{ + if (fill_frames()) + { + if (pcm_write(handle, frames, pcm_frames_to_bytes(handle, period_size))) { + printf("Error playing sample\n"); + return;//break; + } + + } + else + { + DEBUGF("%s: No Data.\n", __func__); + return;//break; + } +} + +static int async_rw(snd_pcm_t *handle) +{ + int err; + snd_pcm_sframes_t sample_size; + char *samples; + + /* fill buffer with silence to initiate playback without noisy click */ + sample_size = pcm_frames_to_bytes(handle, pcm_get_buffer_size(handle)); + samples = malloc(sample_size); + + memset(samples, 0, sample_size); + + err = pcm_write(handle, samples, sample_size); + free(samples); + + if (err != 0) + { + DEBUGF("Initial write error: %d\n", err); + return err; + } + if (pcm_state(handle) == PCM_STATE_PREPARED) + { + err = pcm_start(handle); + if (err < 0) + { + DEBUGF("Start error: %d\n", err); + return err; + } + } + return 0; +} + +void cleanup(void) +{ + free(frames); + frames = NULL; + pcm_close(handle); +} + +void pcm_play_dma_init(void) +{ + config.channels = channels; + config.rate = rate; + config.period_size = period_size; + config.period_count = 4; + config.format = format; + config.start_threshold = 0; + config.stop_threshold = 0; + config.silence_threshold = 0; + + + handle = pcm_open(0, 0, PCM_OUT, &config); + if (!handle || !pcm_is_ready(handle)) { + printf("Unable to open PCM device: %s\n", pcm_get_error(handle)); + return; + } + + pcm_dma_apply_settings(); + + tick_add_task(pcm_tick); + + atexit(cleanup); + return; +} + + +void pcm_play_lock(void) +{ + if (recursion++ == 0) + tick_remove_task(pcm_tick); +} + +void pcm_play_unlock(void) +{ + if (--recursion == 0) + tick_add_task(pcm_tick); +} + +static void pcm_dma_apply_settings_nolock(void) +{ + set_hwparams(handle); +} + +void pcm_dma_apply_settings(void) +{ + pcm_play_lock(); + pcm_dma_apply_settings_nolock(); + pcm_play_unlock(); +} + + +void pcm_play_dma_pause(bool pause) +{ + (void)pause; +} + + +void pcm_play_dma_stop(void) +{ + pcm_stop(handle); +} + +void pcm_play_dma_start(const void *addr, size_t size) +{ +#if defined(DX50) || defined(DX90) + /* headphone output relay: if this is done at startup already, a loud click is audible on headphones. Here, some time later, + the output caps are charged a bit and the click is much softer */ + system("/system/bin/muteopen"); +#endif + pcm_dma_apply_settings_nolock(); + + pcm_data = addr; + pcm_size = size; + + while (1) + { + snd_pcm_state_t state = pcm_state(handle); + switch (state) + { + case PCM_STATE_RUNNING: + return; + case PCM_STATE_XRUN: + { + printf("No handler for STATE_XRUN!\n"); + continue; + } + case PCM_STATE_PREPARED: + { /* prepared state, we need to fill the buffer with silence before + * starting */ + int err = async_rw(handle); + if (err < 0) + printf("Start error: %d\n", err); + return; + } + case PCM_STATE_PAUSED: + { /* paused, simply resume */ + pcm_play_dma_pause(0); + return; + } + case PCM_STATE_DRAINING: + /* run until drained */ + continue; + default: + DEBUGF("Unhandled state: %d\n", state); + return; + } + } +} + +size_t pcm_get_bytes_waiting(void) +{ + return pcm_size; +} + +const void * pcm_play_dma_get_peak_buffer(int *count) +{ + uintptr_t addr = (uintptr_t)pcm_data; + *count = pcm_size / 4; + return (void *)((addr + 3) & ~3); +} + +void pcm_play_dma_postinit(void) +{ + return; +} + +void pcm_set_mixer_volume(int volume) +{ +#if defined(DX50) || defined(DX90) + /* -990 to 0 -> 0 to 255 */ + int val = (volume+990)*255/990; +#if defined(DX50) + FILE *f = fopen("/dev/codec_volume", "w"); +#else /* DX90 */ + FILE *f = fopen("/sys/class/codec/es9018_volume", "w"); +#endif /* DX50 */ + fprintf(f, "%d", val); + fclose(f); +#else + (void)volume; +#endif /* DX50 || DX90 */ +} + +#ifdef HAVE_RECORDING +void pcm_rec_lock(void) +{ +} + +void pcm_rec_unlock(void) +{ +} + +void pcm_rec_dma_init(void) +{ +} + +void pcm_rec_dma_close(void) +{ +} + +void pcm_rec_dma_start(void *start, size_t size) +{ + (void)start; + (void)size; +} + +void pcm_rec_dma_stop(void) +{ +} + +const void * pcm_rec_dma_get_peak_buffer(void) +{ + return NULL; +} + +void audiohw_set_recvol(int left, int right, int type) +{ + (void)left; + (void)right; + (void)type; +} + +#endif /* HAVE_RECORDING */ diff --git a/firmware/target/hosted/android/dx50/powermgmt-dx50.c b/firmware/target/hosted/android/dx50/powermgmt-dx50.c new file mode 100644 index 0000000000..45756cb8e8 --- /dev/null +++ b/firmware/target/hosted/android/dx50/powermgmt-dx50.c @@ -0,0 +1,72 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 by Thomas Martitz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include "config.h" +#include "power.h" +#include "powermgmt.h" + +unsigned int power_input_status(void) +{ + int val; + FILE *f = fopen("/sys/class/power_supply/ac/present", "r"); + fscanf(f, "%d", &val); + fclose(f); + return val?POWER_INPUT_MAIN_CHARGER:POWER_INPUT_NONE; +} + +/* Values for stock PISEN battery. TODO: Needs optimization */ + +const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = +{ + 3380 +}; + +const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = +{ + 3100 +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ +const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = +{ + { 3370, 3650, 3700, 3740, 3780, 3820, 3870, 3930, 4000, 4090, 4190 } +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ +const unsigned short percent_to_volt_charge[11] = +{ + 3540, 3860, 3930, 3980, 4000, 4020, 4040, 4080, 4130, 4180, 4220 /* LiPo */ +}; + + +/* Returns battery voltage from android measurement [millivolts] */ +int _battery_voltage(void) +{ + int val; + FILE *f = fopen("/sys/class/power_supply/battery/voltage_now", "r"); + fscanf(f, "%d", &val); + fclose(f); + return (val/1000); +} + + diff --git a/firmware/target/hosted/android/dx50/tinyalsa/asound.h b/firmware/target/hosted/android/dx50/tinyalsa/asound.h new file mode 100644 index 0000000000..fc1e4f6d67 --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/asound.h @@ -0,0 +1,821 @@ +/**************************************************************************** + **************************************************************************** + *** + *** This header was automatically generated from a Linux kernel header + *** of the same name, to make information necessary for userspace to + *** call into the kernel available to libc. It contains only constants, + *** structures, and macros generated from the original header, and thus, + *** contains no copyrightable information. + *** + **************************************************************************** + ****************************************************************************/ +#ifndef __SOUND_ASOUND_H +#define __SOUND_ASOUND_H + +#include + +#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor)) +#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff) +#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff) +#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff) +#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion))) + +struct snd_aes_iec958 { + unsigned char status[24]; + unsigned char subcode[147]; + unsigned char pad; + unsigned char dig_subframe[4]; +}; + +#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1) + +enum { + SNDRV_HWDEP_IFACE_OPL2 = 0, + SNDRV_HWDEP_IFACE_OPL3, + SNDRV_HWDEP_IFACE_OPL4, + SNDRV_HWDEP_IFACE_SB16CSP, + SNDRV_HWDEP_IFACE_EMU10K1, + SNDRV_HWDEP_IFACE_YSS225, + SNDRV_HWDEP_IFACE_ICS2115, + SNDRV_HWDEP_IFACE_SSCAPE, + SNDRV_HWDEP_IFACE_VX, + SNDRV_HWDEP_IFACE_MIXART, + SNDRV_HWDEP_IFACE_USX2Y, + SNDRV_HWDEP_IFACE_EMUX_WAVETABLE, + SNDRV_HWDEP_IFACE_BLUETOOTH, + SNDRV_HWDEP_IFACE_USX2Y_PCM, + SNDRV_HWDEP_IFACE_PCXHR, + SNDRV_HWDEP_IFACE_SB_RC, + SNDRV_HWDEP_IFACE_HDA, + SNDRV_HWDEP_IFACE_USB_STREAM, + + SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM +}; + +struct snd_hwdep_info { + unsigned int device; + int card; + unsigned char id[64]; + unsigned char name[80]; + int iface; + unsigned char reserved[64]; +}; + +struct snd_hwdep_dsp_status { + unsigned int version; + unsigned char id[32]; + unsigned int num_dsps; + unsigned int dsp_loaded; + unsigned int chip_ready; + unsigned char reserved[16]; +}; + +struct snd_hwdep_dsp_image { + unsigned int index; + unsigned char name[64]; + unsigned char __user *image; + size_t length; + unsigned long driver_data; +}; + +#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int) +#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info) +#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status) +#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image) + +#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10) + +typedef unsigned long snd_pcm_uframes_t; +typedef signed long snd_pcm_sframes_t; + +enum { + SNDRV_PCM_CLASS_GENERIC = 0, + SNDRV_PCM_CLASS_MULTI, + SNDRV_PCM_CLASS_MODEM, + SNDRV_PCM_CLASS_DIGITIZER, + + SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER, +}; + +enum { + SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0, + SNDRV_PCM_SUBCLASS_MULTI_MIX, + + SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX, +}; + +enum { + SNDRV_PCM_STREAM_PLAYBACK = 0, + SNDRV_PCM_STREAM_CAPTURE, + SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE, +}; + +typedef int __bitwise snd_pcm_access_t; +#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0) +#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1) +#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2) +#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3) +#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4) +#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED + +typedef int __bitwise snd_pcm_format_t; +#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0) +#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1) +#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2) +#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3) +#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4) +#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5) +#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6) +#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7) +#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8) +#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9) +#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10) +#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11) +#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12) +#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13) +#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14) +#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15) +#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16) +#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17) +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18) +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19) +#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20) +#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21) +#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22) +#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23) +#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24) +#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31) +#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32) +#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33) +#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34) +#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35) +#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36) +#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37) +#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38) +#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39) +#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40) +#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) +#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) +#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) +#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) +#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) +#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) +#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) +#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B + +#ifdef SNDRV_LITTLE_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE +#endif +#ifdef SNDRV_BIG_ENDIAN +#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE +#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE +#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE +#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE +#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE +#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE +#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE +#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE +#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE +#endif + +typedef int __bitwise snd_pcm_subformat_t; +#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0) +#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD + +#define SNDRV_PCM_INFO_MMAP 0x00000001 +#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002 +#define SNDRV_PCM_INFO_DOUBLE 0x00000004 +#define SNDRV_PCM_INFO_BATCH 0x00000010 +#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100 +#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200 +#define SNDRV_PCM_INFO_COMPLEX 0x00000400 +#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000 +#define SNDRV_PCM_INFO_OVERRANGE 0x00020000 +#define SNDRV_PCM_INFO_RESUME 0x00040000 +#define SNDRV_PCM_INFO_PAUSE 0x00080000 +#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000 +#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000 +#define SNDRV_PCM_INFO_SYNC_START 0x00400000 +#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000 +#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000 + +typedef int __bitwise snd_pcm_state_t; +#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0) +#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1) +#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2) +#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3) +#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4) +#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5) +#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6) +#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7) +#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8) +#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED + +enum { + SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000, + SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000, + SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000, +}; + +union snd_pcm_sync_id { + unsigned char id[16]; + unsigned short id16[8]; + unsigned int id32[4]; +}; + +struct snd_pcm_info { + unsigned int device; + unsigned int subdevice; + int stream; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned char subname[32]; + int dev_class; + int dev_subclass; + unsigned int subdevices_count; + unsigned int subdevices_avail; + union snd_pcm_sync_id sync; + unsigned char reserved[64]; +}; + +typedef int snd_pcm_hw_param_t; +#define SNDRV_PCM_HW_PARAM_ACCESS 0 +#define SNDRV_PCM_HW_PARAM_FORMAT 1 +#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2 +#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS +#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT + +#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8 +#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9 +#define SNDRV_PCM_HW_PARAM_CHANNELS 10 +#define SNDRV_PCM_HW_PARAM_RATE 11 +#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12 +#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13 +#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14 +#define SNDRV_PCM_HW_PARAM_PERIODS 15 +#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16 +#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17 +#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18 +#define SNDRV_PCM_HW_PARAM_TICK_TIME 19 +#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS +#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME + +#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0) +#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1) +#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) + +struct snd_interval { + unsigned int min, max; + unsigned int openmin:1, + openmax:1, + integer:1, + empty:1; +}; + +#define SNDRV_MASK_MAX 256 + +struct snd_mask { + __u32 bits[(SNDRV_MASK_MAX+31)/32]; +}; + +struct snd_pcm_hw_params { + unsigned int flags; + struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - + SNDRV_PCM_HW_PARAM_FIRST_MASK + 1]; + struct snd_mask mres[5]; + struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL - + SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1]; + struct snd_interval ires[9]; + unsigned int rmask; + unsigned int cmask; + unsigned int info; + unsigned int msbits; + unsigned int rate_num; + unsigned int rate_den; + snd_pcm_uframes_t fifo_size; + unsigned char reserved[64]; +}; + +enum { + SNDRV_PCM_TSTAMP_NONE = 0, + SNDRV_PCM_TSTAMP_ENABLE, + SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE, +}; + +struct snd_pcm_sw_params { + int tstamp_mode; + unsigned int period_step; + unsigned int sleep_min; + snd_pcm_uframes_t avail_min; + snd_pcm_uframes_t xfer_align; + snd_pcm_uframes_t start_threshold; + snd_pcm_uframes_t stop_threshold; + snd_pcm_uframes_t silence_threshold; + snd_pcm_uframes_t silence_size; + snd_pcm_uframes_t boundary; + unsigned char reserved[64]; +}; + +struct snd_pcm_channel_info { + unsigned int channel; + __kernel_off_t offset; + unsigned int first; + unsigned int step; +}; + +struct snd_pcm_status { + snd_pcm_state_t state; + struct timespec trigger_tstamp; + struct timespec tstamp; + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t hw_ptr; + snd_pcm_sframes_t delay; + snd_pcm_uframes_t avail; + snd_pcm_uframes_t avail_max; + snd_pcm_uframes_t overrange; + snd_pcm_state_t suspended_state; + unsigned char reserved[60]; +}; + +struct snd_pcm_mmap_status { + snd_pcm_state_t state; + int pad1; + snd_pcm_uframes_t hw_ptr; + struct timespec tstamp; + snd_pcm_state_t suspended_state; +}; + +struct snd_pcm_mmap_control { + snd_pcm_uframes_t appl_ptr; + snd_pcm_uframes_t avail_min; +}; + +#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0) +#define SNDRV_PCM_SYNC_PTR_APPL (1<<1) +#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2) + +struct snd_pcm_sync_ptr { + unsigned int flags; + union { + struct snd_pcm_mmap_status status; + unsigned char reserved[64]; + } s; + union { + struct snd_pcm_mmap_control control; + unsigned char reserved[64]; + } c; +}; + +struct snd_xferi { + snd_pcm_sframes_t result; + void __user *buf; + snd_pcm_uframes_t frames; +}; + +struct snd_xfern { + snd_pcm_sframes_t result; + void __user * __user *bufs; + snd_pcm_uframes_t frames; +}; + +enum { + SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0, + SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, + SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC, +}; + +#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int) +#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info) +#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int) +#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int) +#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params) +#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12) +#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params) +#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status) +#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t) +#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22) +#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr) +#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info) +#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40) +#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41) +#define SNDRV_PCM_IOCTL_START _IO('A', 0x42) +#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43) +#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44) +#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int) +#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47) +#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48) +#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t) +#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi) +#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi) +#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern) +#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern) +#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int) +#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61) + +#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0) + +enum { + SNDRV_RAWMIDI_STREAM_OUTPUT = 0, + SNDRV_RAWMIDI_STREAM_INPUT, + SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT, +}; + +#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001 +#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002 +#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004 + +struct snd_rawmidi_info { + unsigned int device; + unsigned int subdevice; + int stream; + int card; + unsigned int flags; + unsigned char id[64]; + unsigned char name[80]; + unsigned char subname[32]; + unsigned int subdevices_count; + unsigned int subdevices_avail; + unsigned char reserved[64]; +}; + +struct snd_rawmidi_params { + int stream; + size_t buffer_size; + size_t avail_min; + unsigned int no_active_sensing: 1; + unsigned char reserved[16]; +}; + +struct snd_rawmidi_status { + int stream; + struct timespec tstamp; + size_t avail; + size_t xruns; + unsigned char reserved[16]; +}; + +#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int) +#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info) +#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params) +#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status) +#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int) +#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int) + +#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +enum { + SNDRV_TIMER_CLASS_NONE = -1, + SNDRV_TIMER_CLASS_SLAVE = 0, + SNDRV_TIMER_CLASS_GLOBAL, + SNDRV_TIMER_CLASS_CARD, + SNDRV_TIMER_CLASS_PCM, + SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM, +}; + +enum { + SNDRV_TIMER_SCLASS_NONE = 0, + SNDRV_TIMER_SCLASS_APPLICATION, + SNDRV_TIMER_SCLASS_SEQUENCER, + SNDRV_TIMER_SCLASS_OSS_SEQUENCER, + SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER, +}; + +#define SNDRV_TIMER_GLOBAL_SYSTEM 0 +#define SNDRV_TIMER_GLOBAL_RTC 1 +#define SNDRV_TIMER_GLOBAL_HPET 2 +#define SNDRV_TIMER_GLOBAL_HRTIMER 3 + +#define SNDRV_TIMER_FLG_SLAVE (1<<0) + +struct snd_timer_id { + int dev_class; + int dev_sclass; + int card; + int device; + int subdevice; +}; + +struct snd_timer_ginfo { + struct snd_timer_id tid; + unsigned int flags; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned long reserved0; + unsigned long resolution; + unsigned long resolution_min; + unsigned long resolution_max; + unsigned int clients; + unsigned char reserved[32]; +}; + +struct snd_timer_gparams { + struct snd_timer_id tid; + unsigned long period_num; + unsigned long period_den; + unsigned char reserved[32]; +}; + +struct snd_timer_gstatus { + struct snd_timer_id tid; + unsigned long resolution; + unsigned long resolution_num; + unsigned long resolution_den; + unsigned char reserved[32]; +}; + +struct snd_timer_select { + struct snd_timer_id id; + unsigned char reserved[32]; +}; + +struct snd_timer_info { + unsigned int flags; + int card; + unsigned char id[64]; + unsigned char name[80]; + unsigned long reserved0; + unsigned long resolution; + unsigned char reserved[64]; +}; + +#define SNDRV_TIMER_PSFLG_AUTO (1<<0) +#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1) +#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2) + +struct snd_timer_params { + unsigned int flags; + unsigned int ticks; + unsigned int queue_size; + unsigned int reserved0; + unsigned int filter; + unsigned char reserved[60]; +}; + +struct snd_timer_status { + struct timespec tstamp; + unsigned int resolution; + unsigned int lost; + unsigned int overrun; + unsigned int queue; + unsigned char reserved[64]; +}; + +#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) +#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) +#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int) +#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo) +#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams) +#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus) +#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select) +#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info) +#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params) +#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status) + +#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0) +#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1) +#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) +#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) + +struct snd_timer_read { + unsigned int resolution; + unsigned int ticks; +}; + +enum { + SNDRV_TIMER_EVENT_RESOLUTION = 0, + SNDRV_TIMER_EVENT_TICK, + SNDRV_TIMER_EVENT_START, + SNDRV_TIMER_EVENT_STOP, + SNDRV_TIMER_EVENT_CONTINUE, + SNDRV_TIMER_EVENT_PAUSE, + SNDRV_TIMER_EVENT_EARLY, + SNDRV_TIMER_EVENT_SUSPEND, + SNDRV_TIMER_EVENT_RESUME, + + SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10, + SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10, + SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10, + SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10, + SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10, + SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10, +}; + +struct snd_timer_tread { + int event; + struct timespec tstamp; + unsigned int val; +}; + +#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6) + +struct snd_ctl_card_info { + int card; + int pad; + unsigned char id[16]; + unsigned char driver[16]; + unsigned char name[32]; + unsigned char longname[80]; + unsigned char reserved_[16]; + unsigned char mixername[80]; + unsigned char components[128]; +}; + +typedef int __bitwise snd_ctl_elem_type_t; +#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0) +#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1) +#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2) +#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3) +#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4) +#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5) +#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6) +#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64 + +typedef int __bitwise snd_ctl_elem_iface_t; +#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0) +#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1) +#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2) +#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3) +#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4) +#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5) +#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6) +#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER + +#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0) +#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1) +#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2) +#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3) +#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4) +#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5) +#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) +#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6) +#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8) +#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9) +#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10) +#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28) +#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29) + +#define SNDRV_CTL_POWER_D0 0x0000 +#define SNDRV_CTL_POWER_D1 0x0100 +#define SNDRV_CTL_POWER_D2 0x0200 +#define SNDRV_CTL_POWER_D3 0x0300 +#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000) +#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001) + +struct snd_ctl_elem_id { + unsigned int numid; + snd_ctl_elem_iface_t iface; + unsigned int device; + unsigned int subdevice; + unsigned char name[44]; + unsigned int index; +}; + +struct snd_ctl_elem_list { + unsigned int offset; + unsigned int space; + unsigned int used; + unsigned int count; + struct snd_ctl_elem_id __user *pids; + unsigned char reserved[50]; +}; + +struct snd_ctl_elem_info { + struct snd_ctl_elem_id id; + snd_ctl_elem_type_t type; + unsigned int access; + unsigned int count; + __kernel_pid_t owner; + union { + struct { + long min; + long max; + long step; + } integer; + struct { + long long min; + long long max; + long long step; + } integer64; + struct { + unsigned int items; + unsigned int item; + char name[64]; + } enumerated; + unsigned char reserved[128]; + } value; + union { + unsigned short d[4]; + unsigned short *d_ptr; + } dimen; + unsigned char reserved[64-4*sizeof(unsigned short)]; +}; + +struct snd_ctl_elem_value { + struct snd_ctl_elem_id id; + unsigned int indirect: 1; + union { + union { + long value[128]; + long *value_ptr; + } integer; + union { + long long value[64]; + long long *value_ptr; + } integer64; + union { + unsigned int item[128]; + unsigned int *item_ptr; + } enumerated; + union { + unsigned char data[512]; + unsigned char *data_ptr; + } bytes; + struct snd_aes_iec958 iec958; + } value; + struct timespec tstamp; + unsigned char reserved[128-sizeof(struct timespec)]; +}; + +struct snd_ctl_tlv { + unsigned int numid; + unsigned int length; + unsigned int tlv[0]; +}; + +#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int) +#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info) +#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list) +#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value) +#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int) +#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info) +#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id) +#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv) +#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int) +#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info) +#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int) +#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info) +#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int) +#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info) +#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int) +#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int) +#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int) + +enum sndrv_ctl_event_type { + SNDRV_CTL_EVENT_ELEM = 0, + SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM, +}; + +#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0) +#define SNDRV_CTL_EVENT_MASK_INFO (1<<1) +#define SNDRV_CTL_EVENT_MASK_ADD (1<<2) +#define SNDRV_CTL_EVENT_MASK_TLV (1<<3) +#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U) + +struct snd_ctl_event { + int type; + union { + struct { + unsigned int mask; + struct snd_ctl_elem_id id; + } elem; + unsigned char data8[60]; + } data; +}; + +#define SNDRV_CTL_NAME_NONE "" +#define SNDRV_CTL_NAME_PLAYBACK "Playback " +#define SNDRV_CTL_NAME_CAPTURE "Capture " + +#define SNDRV_CTL_NAME_IEC958_NONE "" +#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch" +#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume" +#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default" +#define SNDRV_CTL_NAME_IEC958_MASK "Mask" +#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask" +#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask" +#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream" +#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what + +#endif + diff --git a/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h b/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h new file mode 100644 index 0000000000..6aacae46d6 --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/asoundlib.h @@ -0,0 +1,257 @@ +/* asoundlib.h +** +** Copyright 2011, The Android Open Source Project +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of The Android Open Source Project nor the names of +** its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +*/ + +#ifndef ASOUNDLIB_H +#define ASOUNDLIB_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* + * PCM API + */ + +struct pcm; + +#define PCM_OUT 0x00000000 +#define PCM_IN 0x10000000 +#define PCM_MMAP 0x00000001 +#define PCM_NOIRQ 0x00000002 +#define PCM_NORESTART 0x00000004 /* PCM_NORESTART - when set, calls to + * pcm_write for a playback stream will not + * attempt to restart the stream in the case + * of an underflow, but will return -EPIPE + * instead. After the first -EPIPE error, the + * stream is considered to be stopped, and a + * second call to pcm_write will attempt to + * restart the stream. + */ + +/* PCM runtime states */ +#define PCM_STATE_OPEN 0 +#define PCM_STATE_SETUP 1 +#define PCM_STATE_PREPARED 2 +#define PCM_STATE_RUNNING 3 +#define PCM_STATE_XRUN 4 +#define PCM_STATE_DRAINING 5 +#define PCM_STATE_PAUSED 6 +#define PCM_STATE_SUSPENDED 7 +#define PCM_STATE_DISCONNECTED 8 + +/* Bit formats */ +enum pcm_format { + PCM_FORMAT_S16_LE = 0, + PCM_FORMAT_S32_LE, + PCM_FORMAT_S8, + PCM_FORMAT_S24_LE, + + PCM_FORMAT_MAX, +}; + +/* Configuration for a stream */ +struct pcm_config { + unsigned int channels; + unsigned int rate; + unsigned int period_size; + unsigned int period_count; + enum pcm_format format; + + /* Values to use for the ALSA start, stop and silence thresholds. Setting + * any one of these values to 0 will cause the default tinyalsa values to be + * used instead. Tinyalsa defaults are as follows. + * + * start_threshold : period_count * period_size + * stop_threshold : period_count * period_size + * silence_threshold : 0 + */ + unsigned int start_threshold; + unsigned int stop_threshold; + unsigned int silence_threshold; +}; + +/* PCM parameters */ +enum pcm_param +{ + PCM_PARAM_SAMPLE_BITS, + PCM_PARAM_FRAME_BITS, + PCM_PARAM_CHANNELS, + PCM_PARAM_RATE, + PCM_PARAM_PERIOD_TIME, + PCM_PARAM_PERIOD_SIZE, + PCM_PARAM_PERIOD_BYTES, + PCM_PARAM_PERIODS, + PCM_PARAM_BUFFER_TIME, + PCM_PARAM_BUFFER_SIZE, + PCM_PARAM_BUFFER_BYTES, + PCM_PARAM_TICK_TIME, +}; + +/* Mixer control types */ +enum mixer_ctl_type { + MIXER_CTL_TYPE_BOOL, + MIXER_CTL_TYPE_INT, + MIXER_CTL_TYPE_ENUM, + MIXER_CTL_TYPE_BYTE, + MIXER_CTL_TYPE_IEC958, + MIXER_CTL_TYPE_INT64, + MIXER_CTL_TYPE_UNKNOWN, + + MIXER_CTL_TYPE_MAX, +}; + +/* Open and close a stream */ +struct pcm *pcm_open(unsigned int card, unsigned int device, + unsigned int flags, struct pcm_config *config); +int pcm_close(struct pcm *pcm); +int pcm_is_ready(struct pcm *pcm); + +/* Obtain the parameters for a PCM */ +struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, + unsigned int flags); +void pcm_params_free(struct pcm_params *pcm_params); +unsigned int pcm_params_get_min(struct pcm_params *pcm_params, + enum pcm_param param); +unsigned int pcm_params_get_max(struct pcm_params *pcm_params, + enum pcm_param param); + +/* Set and get config */ +int pcm_get_config(struct pcm *pcm, struct pcm_config *config); +int pcm_set_config(struct pcm *pcm, struct pcm_config *config); + +/* Returns a human readable reason for the last error */ +const char *pcm_get_error(struct pcm *pcm); + +/* Returns the sample size in bits for a PCM format. + * As with ALSA formats, this is the storage size for the format, whereas the + * format represents the number of significant bits. For example, + * PCM_FORMAT_S24_LE uses 32 bits of storage. + */ +unsigned int pcm_format_to_bits(enum pcm_format format); + +/* Returns the buffer size (int frames) that should be used for pcm_write. */ +unsigned int pcm_get_buffer_size(struct pcm *pcm); +unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames); +unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes); + +/* Returns the pcm latency in ms */ +unsigned int pcm_get_latency(struct pcm *pcm); + +/* Returns available frames in pcm buffer and corresponding time stamp. + * For an input stream, frames available are frames ready for the + * application to read. + * For an output stream, frames available are the number of empty frames available + * for the application to write. + */ +int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, + struct timespec *tstamp); + +/* Write data to the fifo. + * Will start playback on the first write or on a write that + * occurs after a fifo underrun. + */ +int pcm_write(struct pcm *pcm, const void *data, unsigned int count); +int pcm_read(struct pcm *pcm, void *data, unsigned int count); + +/* + * mmap() support. + */ +int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count); +int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, + unsigned int *frames); +int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); + + +/* Start and stop a PCM channel that doesn't transfer data */ +int pcm_start(struct pcm *pcm); +int pcm_stop(struct pcm *pcm); + +/* Interrupt driven API */ +int pcm_wait(struct pcm *pcm, int timeout); + +int pcm_avail_update(struct pcm *pcm); + +int pcm_state(struct pcm *pcm); + + +/* + * MIXER API + */ + +struct mixer; +struct mixer_ctl; + +/* Open and close a mixer */ +struct mixer *mixer_open(unsigned int card); +void mixer_close(struct mixer *mixer); + +/* Get info about a mixer */ +const char *mixer_get_name(struct mixer *mixer); + +/* Obtain mixer controls */ +unsigned int mixer_get_num_ctls(struct mixer *mixer); +struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id); +struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name); + +/* Get info about mixer controls */ +const char *mixer_ctl_get_name(struct mixer_ctl *ctl); +enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl); +const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl); +unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl); +unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl); +const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, + unsigned int enum_id); + +/* Some sound cards update their controls due to external events, + * such as HDMI EDID byte data changing when an HDMI cable is + * connected. This API allows the count of elements to be updated. + */ +void mixer_ctl_update(struct mixer_ctl *ctl); + +/* Set and get mixer controls */ +int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id); +int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent); + +int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id); +int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count); +int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value); +int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count); +int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string); + +/* Determe range of integer mixer controls */ +int mixer_ctl_get_range_min(struct mixer_ctl *ctl); +int mixer_ctl_get_range_max(struct mixer_ctl *ctl); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +#endif diff --git a/firmware/target/hosted/android/dx50/tinyalsa/mixer.c b/firmware/target/hosted/android/dx50/tinyalsa/mixer.c new file mode 100644 index 0000000000..f75dec488a --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/mixer.c @@ -0,0 +1,497 @@ +/* mixer.c +** +** Copyright 2011, The Android Open Source Project +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of The Android Open Source Project nor the names of +** its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#define __force +#define __bitwise +#define __user +#include + +#include + +struct mixer_ctl { + struct mixer *mixer; + struct snd_ctl_elem_info *info; + char **ename; +}; + +struct mixer { + int fd; + struct snd_ctl_card_info card_info; + struct snd_ctl_elem_info *elem_info; + struct mixer_ctl *ctl; + unsigned int count; +}; + +void mixer_close(struct mixer *mixer) +{ + unsigned int n,m; + + if (!mixer) + return; + + if (mixer->fd >= 0) + close(mixer->fd); + + if (mixer->ctl) { + for (n = 0; n < mixer->count; n++) { + if (mixer->ctl[n].ename) { + unsigned int max = mixer->ctl[n].info->value.enumerated.items; + for (m = 0; m < max; m++) + free(mixer->ctl[n].ename[m]); + free(mixer->ctl[n].ename); + } + } + free(mixer->ctl); + } + + if (mixer->elem_info) + free(mixer->elem_info); + + free(mixer); + + /* TODO: verify frees */ +} + +struct mixer *mixer_open(unsigned int card) +{ + struct snd_ctl_elem_list elist; + struct snd_ctl_elem_info tmp; + struct snd_ctl_elem_id *eid = NULL; + struct mixer *mixer = NULL; + unsigned int n, m; + int fd; + char fn[256]; + + snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card); + fd = open(fn, O_RDWR); + if (fd < 0) + return 0; + + memset(&elist, 0, sizeof(elist)); + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) + goto fail; + + mixer = calloc(1, sizeof(*mixer)); + if (!mixer) + goto fail; + + mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl)); + mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info)); + if (!mixer->ctl || !mixer->elem_info) + goto fail; + + if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0) + goto fail; + + eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id)); + if (!eid) + goto fail; + + mixer->count = elist.count; + mixer->fd = fd; + elist.space = mixer->count; + elist.pids = eid; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0) + goto fail; + + for (n = 0; n < mixer->count; n++) { + struct snd_ctl_elem_info *ei = mixer->elem_info + n; + ei->id.numid = eid[n].numid; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0) + goto fail; + mixer->ctl[n].info = ei; + mixer->ctl[n].mixer = mixer; + if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) { + char **enames = calloc(ei->value.enumerated.items, sizeof(char*)); + if (!enames) + goto fail; + mixer->ctl[n].ename = enames; + for (m = 0; m < ei->value.enumerated.items; m++) { + memset(&tmp, 0, sizeof(tmp)); + tmp.id.numid = ei->id.numid; + tmp.value.enumerated.item = m; + if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0) + goto fail; + enames[m] = strdup(tmp.value.enumerated.name); + if (!enames[m]) + goto fail; + } + } + } + + free(eid); + return mixer; + +fail: + /* TODO: verify frees in failure case */ + if (eid) + free(eid); + if (mixer) + mixer_close(mixer); + else if (fd >= 0) + close(fd); + return 0; +} + +const char *mixer_get_name(struct mixer *mixer) +{ + return (const char *)mixer->card_info.name; +} + +unsigned int mixer_get_num_ctls(struct mixer *mixer) +{ + if (!mixer) + return 0; + + return mixer->count; +} + +struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id) +{ + if (mixer && (id < mixer->count)) + return mixer->ctl + id; + + return NULL; +} + +struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name) +{ + unsigned int n; + + if (!mixer) + return NULL; + + for (n = 0; n < mixer->count; n++) + if (!strcmp(name, (char*) mixer->elem_info[n].id.name)) + return mixer->ctl + n; + + return NULL; +} + +void mixer_ctl_update(struct mixer_ctl *ctl) +{ + ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info); +} + +const char *mixer_ctl_get_name(struct mixer_ctl *ctl) +{ + if (!ctl) + return NULL; + + return (const char *)ctl->info->id.name; +} + +enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl) +{ + if (!ctl) + return MIXER_CTL_TYPE_UNKNOWN; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL; + case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM; + case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE; + case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64; + default: return MIXER_CTL_TYPE_UNKNOWN; + }; +} + +const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl) +{ + if (!ctl) + return ""; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL"; + case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT"; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM"; + case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE"; + case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958"; + case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64"; + default: return "Unknown"; + }; +} + +unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl) +{ + if (!ctl) + return 0; + + return ctl->info->count; +} + +static int percent_to_int(struct snd_ctl_elem_info *ei, int percent) +{ + int range; + + if (percent > 100) + percent = 100; + else if (percent < 0) + percent = 0; + + range = (ei->value.integer.max - ei->value.integer.min); + + return ei->value.integer.min + (range * percent) / 100; +} + +static int int_to_percent(struct snd_ctl_elem_info *ei, int value) +{ + int range = (ei->value.integer.max - ei->value.integer.min); + + if (range == 0) + return 0; + + return ((value - ei->value.integer.min) / range) * 100; +} + +int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id)); +} + +int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent)); +} + +int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id) +{ + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (id >= ctl->info->count)) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + return !!ev.value.integer.value[id]; + + case SNDRV_CTL_ELEM_TYPE_INTEGER: + return ev.value.integer.value[id]; + + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + return ev.value.enumerated.item[id]; + + case SNDRV_CTL_ELEM_TYPE_BYTES: + return ev.value.bytes.data[id]; + + default: + return -EINVAL; + } + + return 0; +} + +int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count) +{ + struct snd_ctl_elem_value ev; + int ret; + size_t size; + void *source; + + if (!ctl || (count > ctl->info->count) || !count || !array) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + size = sizeof(ev.value.integer.value[0]); + source = ev.value.integer.value; + break; + + case SNDRV_CTL_ELEM_TYPE_BYTES: + size = sizeof(ev.value.bytes.data[0]); + source = ev.value.bytes.data; + break; + + default: + return -EINVAL; + } + + memcpy(array, source, size * count); + + return 0; +} + +int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value) +{ + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (id >= ctl->info->count)) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev); + if (ret < 0) + return ret; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + ev.value.integer.value[id] = !!value; + break; + + case SNDRV_CTL_ELEM_TYPE_INTEGER: + ev.value.integer.value[id] = value; + break; + + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + ev.value.enumerated.item[id] = value; + break; + + default: + return -EINVAL; + } + + return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); +} + +int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count) +{ + struct snd_ctl_elem_value ev; + size_t size; + void *dest; + + if (!ctl || (count > ctl->info->count) || !count || !array) + return -EINVAL; + + memset(&ev, 0, sizeof(ev)); + ev.id.numid = ctl->info->id.numid; + + switch (ctl->info->type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + case SNDRV_CTL_ELEM_TYPE_INTEGER: + size = sizeof(ev.value.integer.value[0]); + dest = ev.value.integer.value; + break; + + case SNDRV_CTL_ELEM_TYPE_BYTES: + size = sizeof(ev.value.bytes.data[0]); + dest = ev.value.bytes.data; + break; + + default: + return -EINVAL; + } + + memcpy(dest, array, size * count); + + return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); +} + +int mixer_ctl_get_range_min(struct mixer_ctl *ctl) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return ctl->info->value.integer.min; +} + +int mixer_ctl_get_range_max(struct mixer_ctl *ctl) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER)) + return -EINVAL; + + return ctl->info->value.integer.max; +} + +unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl) +{ + if (!ctl) + return 0; + + return ctl->info->value.enumerated.items; +} + +const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl, + unsigned int enum_id) +{ + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) || + (enum_id >= ctl->info->value.enumerated.items)) + return NULL; + + return (const char *)ctl->ename[enum_id]; +} + +int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string) +{ + unsigned int i, num_enums; + struct snd_ctl_elem_value ev; + int ret; + + if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED)) + return -EINVAL; + + num_enums = ctl->info->value.enumerated.items; + for (i = 0; i < num_enums; i++) { + if (!strcmp(string, ctl->ename[i])) { + memset(&ev, 0, sizeof(ev)); + ev.value.enumerated.item[0] = i; + ev.id.numid = ctl->info->id.numid; + ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev); + if (ret < 0) + return ret; + return 0; + } + } + + return -EINVAL; +} + diff --git a/firmware/target/hosted/android/dx50/tinyalsa/pcm.c b/firmware/target/hosted/android/dx50/tinyalsa/pcm.c new file mode 100644 index 0000000000..bd44dce52f --- /dev/null +++ b/firmware/target/hosted/android/dx50/tinyalsa/pcm.c @@ -0,0 +1,973 @@ +/* pcm.c +** +** Copyright 2011, The Android Open Source Project +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** * Neither the name of The Android Open Source Project nor the names of +** its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +** DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#define __force +#define __bitwise +#define __user +#include + +#include + +#define PARAM_MAX SNDRV_PCM_HW_PARAM_LAST_INTERVAL +#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2) + +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline int param_is_interval(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_INTERVAL) && + (p <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL); +} + +static inline struct snd_interval *param_to_interval(struct snd_pcm_hw_params *p, int n) +{ + return &(p->intervals[n - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, unsigned int bit) +{ + if (bit >= SNDRV_MASK_MAX) + return; + if (param_is_mask(n)) { + struct snd_mask *m = param_to_mask(p, n); + m->bits[0] = 0; + m->bits[1] = 0; + m->bits[bit >> 5] |= (1 << (bit & 31)); + } +} + +static void param_set_min(struct snd_pcm_hw_params *p, int n, unsigned int val) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + i->min = val; + } +} + +static unsigned int param_get_min(struct snd_pcm_hw_params *p, int n) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + return i->min; + } + return 0; +} + +static unsigned int param_get_max(struct snd_pcm_hw_params *p, int n) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + return i->max; + } + return 0; +} + +static void param_set_int(struct snd_pcm_hw_params *p, int n, unsigned int val) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + i->min = val; + i->max = val; + i->integer = 1; + } +} + +static unsigned int param_get_int(struct snd_pcm_hw_params *p, int n) +{ + if (param_is_interval(n)) { + struct snd_interval *i = param_to_interval(p, n); + if (i->integer) + return i->max; + } + return 0; +} + +static void param_init(struct snd_pcm_hw_params *p) +{ + int n; + + memset(p, 0, sizeof(*p)); + for (n = SNDRV_PCM_HW_PARAM_FIRST_MASK; + n <= SNDRV_PCM_HW_PARAM_LAST_MASK; n++) { + struct snd_mask *m = param_to_mask(p, n); + m->bits[0] = ~0; + m->bits[1] = ~0; + } + for (n = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; + n <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; n++) { + struct snd_interval *i = param_to_interval(p, n); + i->min = 0; + i->max = ~0; + } + p->rmask = ~0U; + p->cmask = 0; + p->info = ~0U; +} + +#define PCM_ERROR_MAX 128 + +struct pcm { + int fd; + unsigned int flags; + int running:1; + int underruns; + unsigned int buffer_size; + unsigned int boundary; + char error[PCM_ERROR_MAX]; + struct pcm_config config; + struct snd_pcm_mmap_status *mmap_status; + struct snd_pcm_mmap_control *mmap_control; + struct snd_pcm_sync_ptr *sync_ptr; + void *mmap_buffer; + unsigned int noirq_frames_per_msec; +}; + +unsigned int pcm_get_buffer_size(struct pcm *pcm) +{ + return pcm->buffer_size; +} + +const char* pcm_get_error(struct pcm *pcm) +{ + return pcm->error; +} + +static int oops(struct pcm *pcm, int e, const char *fmt, ...) +{ + va_list ap; + int sz; + + va_start(ap, fmt); + vsnprintf(pcm->error, PCM_ERROR_MAX, fmt, ap); + va_end(ap); + sz = strlen(pcm->error); + + if (errno) + snprintf(pcm->error + sz, PCM_ERROR_MAX - sz, + ": %s", strerror(e)); + return -1; +} + +static unsigned int pcm_format_to_alsa(enum pcm_format format) +{ + switch (format) { + case PCM_FORMAT_S32_LE: + return SNDRV_PCM_FORMAT_S32_LE; + case PCM_FORMAT_S8: + return SNDRV_PCM_FORMAT_S8; + case PCM_FORMAT_S24_LE: + return SNDRV_PCM_FORMAT_S24_LE; + default: + case PCM_FORMAT_S16_LE: + return SNDRV_PCM_FORMAT_S16_LE; + }; +} + +unsigned int pcm_format_to_bits(enum pcm_format format) +{ + switch (format) { + case PCM_FORMAT_S32_LE: + case PCM_FORMAT_S24_LE: + return 32; + default: + case PCM_FORMAT_S16_LE: + return 16; + }; +} + +unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes) +{ + return bytes / (pcm->config.channels * + (pcm_format_to_bits(pcm->config.format) >> 3)); +} + +unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames) +{ + return frames * pcm->config.channels * + (pcm_format_to_bits(pcm->config.format) >> 3); +} + +static int pcm_sync_ptr(struct pcm *pcm, int flags) { + if (pcm->sync_ptr) { + pcm->sync_ptr->flags = flags; + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SYNC_PTR, pcm->sync_ptr) < 0) + return -1; + } + return 0; +} + +static int pcm_hw_mmap_status(struct pcm *pcm) { + + if (pcm->sync_ptr) + return 0; + + int page_size = sysconf(_SC_PAGE_SIZE); + pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED, + pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS); + if (pcm->mmap_status == MAP_FAILED) + pcm->mmap_status = NULL; + if (!pcm->mmap_status) + goto mmap_error; + + pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL); + if (pcm->mmap_control == MAP_FAILED) + pcm->mmap_control = NULL; + if (!pcm->mmap_control) { + munmap(pcm->mmap_status, page_size); + pcm->mmap_status = NULL; + goto mmap_error; + } + pcm->mmap_control->avail_min = 1; + + return 0; + +mmap_error: + + pcm->sync_ptr = calloc(1, sizeof(*pcm->sync_ptr)); + if (!pcm->sync_ptr) + return -ENOMEM; + pcm->mmap_status = &pcm->sync_ptr->s.status; + pcm->mmap_control = &pcm->sync_ptr->c.control; + pcm->mmap_control->avail_min = 1; + pcm_sync_ptr(pcm, 0); + + return 0; +} + +static void pcm_hw_munmap_status(struct pcm *pcm) { + if (pcm->sync_ptr) { + free(pcm->sync_ptr); + pcm->sync_ptr = NULL; + } else { + int page_size = sysconf(_SC_PAGE_SIZE); + if (pcm->mmap_status) + munmap(pcm->mmap_status, page_size); + if (pcm->mmap_control) + munmap(pcm->mmap_control, page_size); + } + pcm->mmap_status = NULL; + pcm->mmap_control = NULL; +} + +static int pcm_areas_copy(struct pcm *pcm, unsigned int pcm_offset, + const char *src, unsigned int src_offset, + unsigned int frames) +{ + int size_bytes = pcm_frames_to_bytes(pcm, frames); + int pcm_offset_bytes = pcm_frames_to_bytes(pcm, pcm_offset); + int src_offset_bytes = pcm_frames_to_bytes(pcm, src_offset); + + /* interleaved only atm */ + memcpy((char*)pcm->mmap_buffer + pcm_offset_bytes, + src + src_offset_bytes, size_bytes); + return 0; +} + +static int pcm_mmap_write_areas(struct pcm *pcm, const char *src, + unsigned int offset, unsigned int size) +{ + void *pcm_areas; + int commit; + unsigned int pcm_offset, frames, count = 0; + + while (size > 0) { + frames = size; + pcm_mmap_begin(pcm, &pcm_areas, &pcm_offset, &frames); + pcm_areas_copy(pcm, pcm_offset, src, offset, frames); + commit = pcm_mmap_commit(pcm, pcm_offset, frames); + if (commit < 0) { + oops(pcm, commit, "failed to commit %d frames\n", frames); + return commit; + } + + offset += commit; + count += commit; + size -= commit; + } + return count; +} + +int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail, + struct timespec *tstamp) +{ + int frames; + int rc; + snd_pcm_uframes_t hw_ptr; + + if (!pcm_is_ready(pcm)) + return -1; + + rc = pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_APPL|SNDRV_PCM_SYNC_PTR_HWSYNC); + if (rc < 0) + return -1; + + if ((pcm->mmap_status->state != PCM_STATE_RUNNING) && + (pcm->mmap_status->state != PCM_STATE_DRAINING)) + return -1; + + *tstamp = pcm->mmap_status->tstamp; + if (tstamp->tv_sec == 0 && tstamp->tv_nsec == 0) + return -1; + + hw_ptr = pcm->mmap_status->hw_ptr; + if (pcm->flags & PCM_IN) + frames = hw_ptr - pcm->mmap_control->appl_ptr; + else + frames = hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; + + if (frames < 0) + return -1; + + *avail = (unsigned int)frames; + + return 0; +} + +int pcm_write(struct pcm *pcm, const void *data, unsigned int count) +{ + struct snd_xferi x; + + if (pcm->flags & PCM_IN) + return -EINVAL; + + x.buf = (void*)data; + x.frames = count / (pcm->config.channels * + pcm_format_to_bits(pcm->config.format) / 8); + + for (;;) { + if (!pcm->running) { + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE)) + return oops(pcm, errno, "cannot prepare channel"); + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) + return oops(pcm, errno, "cannot write initial data"); + pcm->running = 1; + return 0; + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) { + pcm->running = 0; + if (errno == EPIPE) { + /* we failed to make our window -- try to restart if we are + * allowed to do so. Otherwise, simply allow the EPIPE error to + * propagate up to the app level */ + pcm->underruns++; + if (pcm->flags & PCM_NORESTART) + return -EPIPE; + continue; + } + return oops(pcm, errno, "cannot write stream data"); + } + return 0; + } +} + +int pcm_read(struct pcm *pcm, void *data, unsigned int count) +{ + struct snd_xferi x; + + if (!(pcm->flags & PCM_IN)) + return -EINVAL; + + x.buf = data; + x.frames = count / (pcm->config.channels * + pcm_format_to_bits(pcm->config.format) / 8); + + for (;;) { + if (!pcm->running) { + if (pcm_start(pcm) < 0) { + fprintf(stderr, "start error"); + return -errno; + } + } + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) { + pcm->running = 0; + if (errno == EPIPE) { + /* we failed to make our window -- try to restart */ + pcm->underruns++; + continue; + } + return oops(pcm, errno, "cannot read stream data"); + } + return 0; + } +} + +static struct pcm bad_pcm = { + .fd = -1, +}; + +struct pcm_params *pcm_params_get(unsigned int card, unsigned int device, + unsigned int flags) +{ + struct snd_pcm_hw_params *params; + char fn[256]; + int fd; + + snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, + flags & PCM_IN ? 'c' : 'p'); + + fd = open(fn, O_RDWR); + if (fd < 0) { + fprintf(stderr, "cannot open device '%s'\n", fn); + goto err_open; + } + + params = calloc(1, sizeof(struct snd_pcm_hw_params)); + if (!params) + goto err_calloc; + + param_init(params); + if (ioctl(fd, SNDRV_PCM_IOCTL_HW_REFINE, params)) { + fprintf(stderr, "SNDRV_PCM_IOCTL_HW_REFINE error (%d)\n", errno); + goto err_hw_refine; + } + + close(fd); + + return (struct pcm_params *)params; + +err_hw_refine: + free(params); +err_calloc: + close(fd); +err_open: + return NULL; +} + +void pcm_params_free(struct pcm_params *pcm_params) +{ + struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; + + if (params) + free(params); +} + +static int pcm_param_to_alsa(enum pcm_param param) +{ + switch (param) { + case PCM_PARAM_SAMPLE_BITS: + return SNDRV_PCM_HW_PARAM_SAMPLE_BITS; + break; + case PCM_PARAM_FRAME_BITS: + return SNDRV_PCM_HW_PARAM_FRAME_BITS; + break; + case PCM_PARAM_CHANNELS: + return SNDRV_PCM_HW_PARAM_CHANNELS; + break; + case PCM_PARAM_RATE: + return SNDRV_PCM_HW_PARAM_RATE; + break; + case PCM_PARAM_PERIOD_TIME: + return SNDRV_PCM_HW_PARAM_PERIOD_TIME; + break; + case PCM_PARAM_PERIOD_SIZE: + return SNDRV_PCM_HW_PARAM_PERIOD_SIZE; + break; + case PCM_PARAM_PERIOD_BYTES: + return SNDRV_PCM_HW_PARAM_PERIOD_BYTES; + break; + case PCM_PARAM_PERIODS: + return SNDRV_PCM_HW_PARAM_PERIODS; + break; + case PCM_PARAM_BUFFER_TIME: + return SNDRV_PCM_HW_PARAM_BUFFER_TIME; + break; + case PCM_PARAM_BUFFER_SIZE: + return SNDRV_PCM_HW_PARAM_BUFFER_SIZE; + break; + case PCM_PARAM_BUFFER_BYTES: + return SNDRV_PCM_HW_PARAM_BUFFER_BYTES; + break; + case PCM_PARAM_TICK_TIME: + return SNDRV_PCM_HW_PARAM_TICK_TIME; + break; + + default: + return -1; + } +} + +unsigned int pcm_params_get_min(struct pcm_params *pcm_params, + enum pcm_param param) +{ + struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; + int p; + + if (!params) + return 0; + + p = pcm_param_to_alsa(param); + if (p < 0) + return 0; + + return param_get_min(params, p); +} + +unsigned int pcm_params_get_max(struct pcm_params *pcm_params, + enum pcm_param param) +{ + struct snd_pcm_hw_params *params = (struct snd_pcm_hw_params *)pcm_params; + int p; + + if (!params) + return 0; + + p = pcm_param_to_alsa(param); + if (p < 0) + return 0; + + return param_get_max(params, p); +} + +int pcm_close(struct pcm *pcm) +{ + if (pcm == &bad_pcm) + return 0; + + pcm_hw_munmap_status(pcm); + + if (pcm->flags & PCM_MMAP) { + pcm_stop(pcm); + munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); + } + + if (pcm->fd >= 0) + close(pcm->fd); + pcm->running = 0; + pcm->buffer_size = 0; + pcm->fd = -1; + free(pcm); + return 0; +} + +struct pcm *pcm_open(unsigned int card, unsigned int device, + unsigned int flags, struct pcm_config *config) +{ + struct pcm *pcm; + struct snd_pcm_info info; + struct snd_pcm_hw_params params; + struct snd_pcm_sw_params sparams; + char fn[256]; + int rc; + + pcm = calloc(1, sizeof(struct pcm)); + if (!pcm || !config) + return &bad_pcm; /* TODO: could support default config here */ + + pcm->config = *config; + + snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, + flags & PCM_IN ? 'c' : 'p'); + + pcm->flags = flags; + pcm->fd = open(fn, O_RDWR); + if (pcm->fd < 0) { + oops(pcm, errno, "cannot open device '%s'", fn); + return pcm; + } + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { + oops(pcm, errno, "cannot get info"); + goto fail_close; + } + + param_init(¶ms); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_FORMAT, + pcm_format_to_alsa(config->format)); + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_SUBFORMAT, + SNDRV_PCM_SUBFORMAT_STD); + param_set_min(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, + pcm_format_to_bits(config->format)); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_FRAME_BITS, + pcm_format_to_bits(config->format) * config->channels); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_CHANNELS, + config->channels); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); + param_set_int(¶ms, SNDRV_PCM_HW_PARAM_RATE, config->rate); + + if (flags & PCM_NOIRQ) { + + if (!(flags & PCM_MMAP)) { + oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); + goto fail; + } + + params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; + pcm->noirq_frames_per_msec = config->rate / 1000; + } + + if (flags & PCM_MMAP) + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); + else + param_set_mask(¶ms, SNDRV_PCM_HW_PARAM_ACCESS, + SNDRV_PCM_ACCESS_RW_INTERLEAVED); + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, ¶ms)) { + oops(pcm, errno, "cannot set hw params"); + goto fail_close; + } + + /* get our refined hw_params */ + config->period_size = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); + config->period_count = param_get_int(¶ms, SNDRV_PCM_HW_PARAM_PERIODS); + pcm->buffer_size = config->period_count * config->period_size; + + if (flags & PCM_MMAP) { + pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), + PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); + if (pcm->mmap_buffer == MAP_FAILED) { + oops(pcm, -errno, "failed to mmap buffer %d bytes\n", + pcm_frames_to_bytes(pcm, pcm->buffer_size)); + goto fail_close; + } + } + + + memset(&sparams, 0, sizeof(sparams)); + sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; + sparams.period_step = 1; + sparams.avail_min = 1; + + if (!config->start_threshold) { + if (pcm->flags & PCM_IN) + pcm->config.start_threshold = sparams.start_threshold = 1; + else + pcm->config.start_threshold = sparams.start_threshold = + config->period_count * config->period_size / 2; + } else + sparams.start_threshold = config->start_threshold; + + /* pick a high stop threshold - todo: does this need further tuning */ + if (!config->stop_threshold) { + if (pcm->flags & PCM_IN) + pcm->config.stop_threshold = sparams.stop_threshold = + config->period_count * config->period_size * 10; + else + pcm->config.stop_threshold = sparams.stop_threshold = + config->period_count * config->period_size; + } + else + sparams.stop_threshold = config->stop_threshold; + + sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ + sparams.silence_size = 0; + sparams.silence_threshold = config->silence_threshold; + pcm->boundary = sparams.boundary = pcm->buffer_size; + + while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) + pcm->boundary *= 2; + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { + oops(pcm, errno, "cannot set sw params"); + goto fail; + } + + rc = pcm_hw_mmap_status(pcm); + if (rc < 0) { + oops(pcm, rc, "mmap status failed"); + goto fail; + } + + pcm->underruns = 0; + return pcm; + +fail: + if (flags & PCM_MMAP) + munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); +fail_close: + close(pcm->fd); + pcm->fd = -1; + return pcm; +} + +int pcm_is_ready(struct pcm *pcm) +{ + return pcm->fd >= 0; +} + +int pcm_start(struct pcm *pcm) +{ + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0) + return oops(pcm, errno, "cannot prepare channel"); + + if (pcm->flags & PCM_MMAP) + pcm_sync_ptr(pcm, 0); + + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START) < 0) + return oops(pcm, errno, "cannot start channel"); + + pcm->running = 1; + return 0; +} + +int pcm_stop(struct pcm *pcm) +{ + if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0) + return oops(pcm, errno, "cannot stop channel"); + + pcm->running = 0; + return 0; +} + +static inline int pcm_mmap_playback_avail(struct pcm *pcm) +{ + int avail; + + avail = pcm->mmap_status->hw_ptr + pcm->buffer_size - pcm->mmap_control->appl_ptr; + + if (avail < 0) + avail += pcm->boundary; + else if (avail > (int)pcm->boundary) + avail -= pcm->boundary; + + return avail; +} + +static inline int pcm_mmap_capture_avail(struct pcm *pcm) +{ + int avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr; + if (avail < 0) + avail += pcm->boundary; + return avail; +} + +static inline int pcm_mmap_avail(struct pcm *pcm) +{ + pcm_sync_ptr(pcm, SNDRV_PCM_SYNC_PTR_HWSYNC); + if (pcm->flags & PCM_IN) + return pcm_mmap_capture_avail(pcm); + else + return pcm_mmap_playback_avail(pcm); +} + +static void pcm_mmap_appl_forward(struct pcm *pcm, int frames) +{ + unsigned int appl_ptr = pcm->mmap_control->appl_ptr; + appl_ptr += frames; + + /* check for boundary wrap */ + if (appl_ptr > pcm->boundary) + appl_ptr -= pcm->boundary; + pcm->mmap_control->appl_ptr = appl_ptr; +} + +int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, + unsigned int *frames) +{ + unsigned int continuous, copy_frames, avail; + + /* return the mmap buffer */ + *areas = pcm->mmap_buffer; + + /* and the application offset in frames */ + *offset = pcm->mmap_control->appl_ptr % pcm->buffer_size; + + avail = pcm_mmap_avail(pcm); + if (avail > pcm->buffer_size) + avail = pcm->buffer_size; + continuous = pcm->buffer_size - *offset; + + /* we can only copy frames if the are availabale and continuos */ + copy_frames = *frames; + if (copy_frames > avail) + copy_frames = avail; + if (copy_frames > continuous) + copy_frames = continuous; + *frames = copy_frames; + + return 0; +} + +int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames) +{ + (void)offset; + /* update the application pointer in userspace and kernel */ + pcm_mmap_appl_forward(pcm, frames); + pcm_sync_ptr(pcm, 0); + + return frames; +} + +int pcm_avail_update(struct pcm *pcm) +{ + pcm_sync_ptr(pcm, 0); + return pcm_mmap_avail(pcm); +} + +int pcm_state(struct pcm *pcm) +{ + int err = pcm_sync_ptr(pcm, 0); + if (err < 0) + return err; + + return pcm->mmap_status->state; +} + +int pcm_wait(struct pcm *pcm, int timeout) +{ + struct pollfd pfd; + int err; + + pfd.fd = pcm->fd; + pfd.events = POLLOUT | POLLERR | POLLNVAL; + + do { + /* let's wait for avail or timeout */ + err = poll(&pfd, 1, timeout); + if (err < 0) + return -errno; + + /* timeout ? */ + if (err == 0) + return 0; + + /* have we been interrupted ? */ + if (errno == -EINTR) + continue; + + /* check for any errors */ + if (pfd.revents & (POLLERR | POLLNVAL)) { + switch (pcm_state(pcm)) { + case PCM_STATE_XRUN: + return -EPIPE; + case PCM_STATE_SUSPENDED: + return -ESTRPIPE; + case PCM_STATE_DISCONNECTED: + return -ENODEV; + default: + return -EIO; + } + } + /* poll again if fd not ready for IO */ + } while (!(pfd.revents & (POLLIN | POLLOUT))); + + return 1; +} + +int pcm_mmap_write(struct pcm *pcm, const void *buffer, unsigned int bytes) +{ + int err = 0, frames, avail; + unsigned int offset = 0, count; + + if (bytes == 0) + return 0; + + count = pcm_bytes_to_frames(pcm, bytes); + + while (count > 0) { + + /* get the available space for writing new frames */ + avail = pcm_avail_update(pcm); + if (avail < 0) { + fprintf(stderr, "cannot determine available mmap frames"); + return err; + } + + /* start the audio if we reach the threshold */ + if (!pcm->running && + (pcm->buffer_size - avail) >= pcm->config.start_threshold) { + if (pcm_start(pcm) < 0) { + fprintf(stderr, "start error: hw 0x%x app 0x%x avail 0x%x\n", + (unsigned int)pcm->mmap_status->hw_ptr, + (unsigned int)pcm->mmap_control->appl_ptr, + avail); + return -errno; + } + } + + /* sleep until we have space to write new frames */ + if (pcm->running && + (unsigned int)avail < pcm->mmap_control->avail_min) { + int time = -1; + + if (pcm->flags & PCM_NOIRQ) + time = (pcm->buffer_size - avail - pcm->mmap_control->avail_min) + / pcm->noirq_frames_per_msec; + + err = pcm_wait(pcm, time); + if (err < 0) { + pcm->running = 0; + fprintf(stderr, "wait error: hw 0x%x app 0x%x avail 0x%x\n", + (unsigned int)pcm->mmap_status->hw_ptr, + (unsigned int)pcm->mmap_control->appl_ptr, + avail); + pcm->mmap_control->appl_ptr = 0; + return err; + } + continue; + } + + frames = count; + if (frames > avail) + frames = avail; + + if (!frames) + break; + + /* copy frames from buffer */ + frames = pcm_mmap_write_areas(pcm, buffer, offset, frames); + if (frames < 0) { + fprintf(stderr, "write error: hw 0x%x app 0x%x avail 0x%x\n", + (unsigned int)pcm->mmap_status->hw_ptr, + (unsigned int)pcm->mmap_control->appl_ptr, + avail); + return frames; + } + + offset += frames; + count -= frames; + } + + return 0; +} diff --git a/firmware/target/hosted/android/system-android.c b/firmware/target/hosted/android/system-android.c index d13b8d6462..6279504e48 100644 --- a/firmware/target/hosted/android/system-android.c +++ b/firmware/target/hosted/android/system-android.c @@ -23,6 +23,12 @@ #include #include #include +#if defined(DX50) || defined(DX90) +#include +#include +#include +#include +#endif /* DX50 || DX90 */ #include #include "config.h" #include "system.h" @@ -31,40 +37,83 @@ +#if !defined(DX50) && !defined(DX90) /* global fields for use with various JNI calls */ static JavaVM *vm_ptr; JNIEnv *env_ptr; jobject RockboxService_instance; jclass RockboxService_class; +#endif /* !DX50 && !DX90 */ uintptr_t *stackbegin; uintptr_t *stackend; extern int main(void); +#if !defined(DX50) && !defined(DX90) extern void telephony_init_device(void); - +#endif void system_exception_wait(void) { +#if defined(DX50) || defined(DX90) + while(1); +#else intptr_t dummy = 0; while(button_read_device(&dummy) != BUTTON_BACK); +#endif /* DX50 || DX90 */ } void system_reboot(void) { +#if defined(DX50) || defined(DX90) + reboot(RB_AUTOBOOT); +#else power_off(); +#endif /* DX50 || DX90 */ } +#if !defined(DX50) && !defined(DX90) /* this is used to return from the entry point of the native library. */ static jmp_buf poweroff_buf; +#endif + void power_off(void) { +#if defined(DX50) || defined(DX90) + reboot(RB_POWER_OFF); +#else longjmp(poweroff_buf, 1); +#endif /* DX50 || DX90 */ } void system_init(void) { +#if defined(DX50) || defined(DX90) + volatile uintptr_t stack = 0; + stackbegin = stackend = (uintptr_t*) &stack; + + struct stat m1, m2; + stat("/mnt/", &m1); + do + { + /* waiting for storage to get mounted */ + stat("/sdcard/", &m2); + usleep(100000); + } + while(m1.st_dev == m2.st_dev); +/* here would be the correct place for 'system("/system/bin/muteopen");' (headphone-out relay) but in pcm-dx50.c, pcm_play_dma_start() + the output capacitors are charged already a bit and the click of the headphone-connection-relay is softer */ + +#if defined(DX90) + /* DAC needs to be unmuted on DX90 */ + FILE * f = fopen("/sys/class/codec/wm8740_mute", "w"); + fputc(0, f); + fclose(f); +#endif /* DX90 */ + +#else /* no better place yet */ telephony_init_device(); +#endif /* DX50 || DX90 */ } int hostfs_init(void) @@ -79,6 +128,7 @@ int hostfs_flush(void) return 0; } +#if !defined(DX50) && !defined(DX90) JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void* reserved) { @@ -119,7 +169,7 @@ Java_org_rockbox_RockboxService_main(JNIEnv *env, jobject this) /* simply return here. this will allow the VM to clean up objects and do * garbage collection */ } - +#endif /* !DX50 && !DX90 */ /* below is the facility for external (from other java threads) to safely call * into our snative code. When extracting rockbox.zip the main function is diff --git a/firmware/target/hosted/filesystem-app.c b/firmware/target/hosted/filesystem-app.c index a4730a07d9..93fadc6d6e 100644 --- a/firmware/target/hosted/filesystem-app.c +++ b/firmware/target/hosted/filesystem-app.c @@ -104,6 +104,7 @@ void paths_init(void) #if (CONFIG_PLATFORM & PLATFORM_ANDROID) os_mkdir("/sdcard/rockbox" __MKDIR_MODE_ARG); os_mkdir("/sdcard/rockbox/rocks.data" __MKDIR_MODE_ARG); + os_mkdir("/sdcard/rockbox/eqs" __MKDIR_MODE_ARG); #else char config_dir[MAX_PATH]; diff --git a/manual/rockbox_interface/images/ibassodx50-front.pdf b/manual/rockbox_interface/images/ibassodx50-front.pdf new file mode 100644 index 0000000000..ab35104b47 Binary files /dev/null and b/manual/rockbox_interface/images/ibassodx50-front.pdf differ diff --git a/manual/rockbox_interface/images/ibassodx50-front.png b/manual/rockbox_interface/images/ibassodx50-front.png new file mode 100644 index 0000000000..cb81b0dab1 Binary files /dev/null and b/manual/rockbox_interface/images/ibassodx50-front.png differ diff --git a/manual/rockbox_interface/images/ibassodx50-front.svg b/manual/rockbox_interface/images/ibassodx50-front.svg new file mode 100644 index 0000000000..81f9c8ee8c --- /dev/null +++ b/manual/rockbox_interface/images/ibassodx50-front.svg @@ -0,0 +1,1966 @@ + + + + + iBasso DX50 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + iBasso DX50 + + 2014-05-01 + + + Simon Rothen + + + + + + + + + + + + + + + Volume down + Volume up + + Power + Hold + Prev + Play + Next + Gain + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rbutil/ibassoboot/jni/Android.mk b/rbutil/ibassoboot/jni/Android.mk new file mode 100644 index 0000000000..1d1566d8c0 --- /dev/null +++ b/rbutil/ibassoboot/jni/Android.mk @@ -0,0 +1,6 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE := MangoPlayer +LOCAL_SRC_FILES := ibassodualboot.c qdbmp.c +include $(BUILD_EXECUTABLE) diff --git a/rbutil/ibassoboot/jni/chooser.bmp b/rbutil/ibassoboot/jni/chooser.bmp new file mode 100644 index 0000000000..3e6742d600 Binary files /dev/null and b/rbutil/ibassoboot/jni/chooser.bmp differ diff --git a/rbutil/ibassoboot/jni/ibassodualboot.c b/rbutil/ibassoboot/jni/ibassodualboot.c new file mode 100644 index 0000000000..3f20bbeecf --- /dev/null +++ b/rbutil/ibassoboot/jni/ibassodualboot.c @@ -0,0 +1,439 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2014 by Ilia Sergachev + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "qdbmp.h" + + +#define MIN_TIME 1395606821 +#define TIME_FILE "/data/time_store" +#define TIME_CHECK_PERIOD 60 /* seconds */ +#define VOLD_LINK "/data/vold" +#define PLAYER_FILE "/data/chosen_player" +#define NOASK_FLAG "/data/no_ask_once" +#define POLL_MS 10 + + +#define KEYCODE_HEADPHONES 114 +#define KEYCODE_HOLD 115 +#define KEYCODE_PWR 116 +#define KEYCODE_PWR_LONG 117 +#define KEYCODE_SD 143 +#define KEYCODE_VOLPLUS 158 +#define KEYCODE_VOLMINUS 159 +#define KEYCODE_PREV 160 +#define KEYCODE_NEXT 162 +#define KEYCODE_PLAY 161 + +#define KEY_HOLD_OFF 16 + +void checktime() +{ + time_t t_stored=0, t_current=time(NULL); + + FILE *f = fopen(TIME_FILE, "r"); + if(f!=NULL) + { + fscanf(f, "%ld", &t_stored); + fclose(f); + } + + printf("stored time: %ld, current time: %ld\n", t_stored, t_current); + + if(t_storedd_name[0] == '.' && + (de->d_name[1] == '\0' || + (de->d_name[1] == '.' && de->d_name[2] == '\0'))) + continue; + strcpy(filename, de->d_name); + open_device(devname, print_flags); + } + closedir(dir); + return 0; +} + + + +void button_init_device(void) +{ + int res; + int print_flags = 0; + const char *device = NULL; + const char *device_path = "/dev/input"; + + nfds = 1; + ufds = calloc(1, sizeof(ufds[0])); + ufds[0].fd = inotify_init(); + ufds[0].events = POLLIN; + if(device) + { + res = open_device(device, print_flags); + if(res < 0) { + fprintf(stderr, "open device failed\n"); + } + } + else + { + res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE); + if(res < 0) + { + fprintf(stderr, "could not add watch for %s, %s\n", device_path, strerror(errno)); + } + res = scan_dir(device_path, print_flags); + if(res < 0) + { + fprintf(stderr, "scan dir failed for %s\n", device_path); + } + } +} + + +int draw() +{ + int fbfd = 0; + struct fb_var_screeninfo vinfo; + struct fb_fix_screeninfo finfo; + long int screensize = 0; + char *fbp = 0; + int x = 0, y = 0; + long int location = 0; + + /* Open the file for reading and writing */ + fbfd = open("/dev/graphics/fb0", O_RDWR); + if (fbfd == -1) + { + perror("Error: cannot open framebuffer device"); + exit(1); + } + /* Get fixed screen information */ + if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo) == -1) + { + perror("Error reading fixed information"); + exit(2); + } + + /* Get variable screen information */ + if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) == -1) + { + perror("Error reading variable information"); + exit(3); + } + + /* Figure out the size of the screen in bytes */ + screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; + + vinfo.xres = vinfo.xres_virtual = vinfo.width = 320; + vinfo.yres = vinfo.yres_virtual = vinfo.height = 240; + vinfo.xoffset = vinfo.yoffset = vinfo.sync = vinfo.vmode = 0; + vinfo.pixclock = 104377; + vinfo.left_margin = 20; + vinfo.right_margin = 50; + vinfo.upper_margin = 2; + vinfo.lower_margin = 4; + vinfo.hsync_len = 10; + vinfo.vsync_len = 2; + vinfo.red.offset = 11; + vinfo.red.length = 5; + vinfo.red.msb_right = 0; + vinfo.green.offset = 5; + vinfo.green.length = 6; + vinfo.green.msb_right = 0; + vinfo.blue.offset = 0; + vinfo.blue.length = 5; + vinfo.blue.msb_right = 0; + vinfo.transp.offset = vinfo.transp.length = vinfo.transp.msb_right = 0; + vinfo.nonstd = 4; + + if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo)) + { + perror("fbset(ioctl)"); + exit(4); + } + + + /* Map the device to memory */ + fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, + fbfd, 0); + if ((int)fbp == -1) + { + perror("Error: failed to map framebuffer device to memory"); + exit(4); + } + + BMP* bmp = BMP_ReadFile("/system/rockbox/chooser.bmp"); + BMP_CHECK_ERROR( stderr, -1 ); + + UCHAR r, g, b; + unsigned short int t; + + for (y = 0; y < 240; y++) + for (x = 0; x < 320; x++) + { + location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8) + + (y+vinfo.yoffset) * finfo.line_length; + + BMP_GetPixelRGB(bmp, x, y, &r, &g, &b); + t = (r>>3)<<11 | (g>>2) << 5 | (b>>3); + *((unsigned short int*)(fbp + location)) = t; + } + + BMP_Free( bmp ); + + munmap(fbp, screensize); + close(fbfd); + return 0; +} + + +int choose_player() +{ + int i; + int res; + struct input_event event; + + while(true) + { + poll(ufds, nfds, POLL_MS); + for(i = 1; i < nfds; i++) + { + if(ufds[i].revents & POLLIN) + { + res = read(ufds[i].fd, &event, sizeof(event)); + if(res < (int)sizeof(event)) + { + fprintf(stderr, "could not get event\n"); + } + if(event.type==1) + { + if(event.code==KEYCODE_NEXT) + { + puts("rockbox!"); + return 1; + } + else if(event.code==KEYCODE_PREV) + { + puts("mango!"); + return 0; + } + else if(event.code==KEYCODE_PWR || event.code==KEYCODE_PWR_LONG) + { + reboot(LINUX_REBOOT_CMD_POWER_OFF); + } + } + else if(event.type==3) + { + if(event.code==53) //x coord + { + if(event.value<160) + { + puts("mango!"); + return 0; + } + else + { + puts("rockbox!"); + return 1; + } + } + } + } + } + } + return true; +} + +bool check_for_hold() +{ + FILE *f = fopen("/sys/class/axppower/holdkey", "r"); + char x; + fscanf(f, "%c", &x); + fclose(f); + + if(x & KEY_HOLD_OFF) + return false; + else + return true; +} + +int main(int argc, char **argv) +{ + FILE *f; + int last_chosen_player = -1; + + f = fopen(PLAYER_FILE, "r"); + if(f!=NULL) + { + fscanf(f, "%d", &last_chosen_player); + fclose(f); + } + bool ask = (access(VOLD_LINK, F_OK) == -1) || ((access(NOASK_FLAG, F_OK) == -1) && check_for_hold()) || (last_chosen_player==-1); + + if(ask) + { + draw(); + button_init_device(); + int player_chosen_now = choose_player(); + + if(last_chosen_player!=player_chosen_now) + { + f = fopen(PLAYER_FILE, "w"); + fprintf(f, "%d", player_chosen_now); + fclose(f); + } + + if(last_chosen_player!=player_chosen_now || (access(VOLD_LINK, F_OK) == -1)) + { + system("rm "VOLD_LINK); + + if(player_chosen_now) + system("ln -s /system/bin/vold_rockbox "VOLD_LINK); + else + system("ln -s /system/bin/vold_original "VOLD_LINK); + + system("touch "NOASK_FLAG); + system("reboot"); + } + last_chosen_player = player_chosen_now; + } + + system("rm "NOASK_FLAG); + + while(1) + { + if(last_chosen_player) + { +// system("/system/bin/openadb"); + system("/system/rockbox/lib/rockbox"); + } + else +// system("/system/bin/closeadb"); + system("/system/bin/MangoPlayer_original"); + + sleep(1); + } + + return 0; +} + + + diff --git a/rbutil/ibassoboot/jni/qdbmp.c b/rbutil/ibassoboot/jni/qdbmp.c new file mode 100644 index 0000000000..fd1337277d --- /dev/null +++ b/rbutil/ibassoboot/jni/qdbmp.c @@ -0,0 +1,798 @@ +#include "qdbmp.h" +#include +#include + + +/* Bitmap header */ +typedef struct _BMP_Header +{ + USHORT Magic; /* Magic identifier: "BM" */ + UINT FileSize; /* Size of the BMP file in bytes */ + USHORT Reserved1; /* Reserved */ + USHORT Reserved2; /* Reserved */ + UINT DataOffset; /* Offset of image data relative to the file's start */ + UINT HeaderSize; /* Size of the header in bytes */ + UINT Width; /* Bitmap's width */ + UINT Height; /* Bitmap's height */ + USHORT Planes; /* Number of color planes in the bitmap */ + USHORT BitsPerPixel; /* Number of bits per pixel */ + UINT CompressionType; /* Compression type */ + UINT ImageDataSize; /* Size of uncompressed image's data */ + UINT HPixelsPerMeter; /* Horizontal resolution (pixels per meter) */ + UINT VPixelsPerMeter; /* Vertical resolution (pixels per meter) */ + UINT ColorsUsed; /* Number of color indexes in the color table that are actually used by the bitmap */ + UINT ColorsRequired; /* Number of color indexes that are required for displaying the bitmap */ +} BMP_Header; + + +/* Private data structure */ +struct _BMP +{ + BMP_Header Header; + UCHAR* Palette; + UCHAR* Data; +}; + + +/* Holds the last error code */ +static BMP_STATUS BMP_LAST_ERROR_CODE = 0; + + +/* Error description strings */ +static const char* BMP_ERROR_STRING[] = +{ + "", + "General error", + "Could not allocate enough memory to complete the operation", + "File input/output error", + "File not found", + "File is not a supported BMP variant (must be uncompressed 8, 24 or 32 BPP)", + "File is not a valid BMP image", + "An argument is invalid or out of range", + "The requested action is not compatible with the BMP's type" +}; + + +/* Size of the palette data for 8 BPP bitmaps */ +#define BMP_PALETTE_SIZE ( 256 * 4 ) + + + +/*********************************** Forward declarations **********************************/ +int ReadHeader ( BMP* bmp, FILE* f ); +int WriteHeader ( BMP* bmp, FILE* f ); + +int ReadUINT ( UINT* x, FILE* f ); +int ReadUSHORT ( USHORT *x, FILE* f ); + +int WriteUINT ( UINT x, FILE* f ); +int WriteUSHORT ( USHORT x, FILE* f ); + + + + + + +/*********************************** Public methods **********************************/ + + +/************************************************************** + Creates a blank BMP image with the specified dimensions + and bit depth. +**************************************************************/ +BMP* BMP_Create( UINT width, UINT height, USHORT depth ) +{ + BMP* bmp; + int bytes_per_pixel = depth >> 3; + UINT bytes_per_row; + + if ( height <= 0 || width <= 0 ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return NULL; + } + + if ( depth != 8 && depth != 24 && depth != 32 ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED; + return NULL; + } + + + /* Allocate the bitmap data structure */ + bmp = calloc( 1, sizeof( BMP ) ); + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + return NULL; + } + + + /* Set header' default values */ + bmp->Header.Magic = 0x4D42; + bmp->Header.Reserved1 = 0; + bmp->Header.Reserved2 = 0; + bmp->Header.HeaderSize = 40; + bmp->Header.Planes = 1; + bmp->Header.CompressionType = 0; + bmp->Header.HPixelsPerMeter = 0; + bmp->Header.VPixelsPerMeter = 0; + bmp->Header.ColorsUsed = 0; + bmp->Header.ColorsRequired = 0; + + + /* Calculate the number of bytes used to store a single image row. This is always + rounded up to the next multiple of 4. */ + bytes_per_row = width * bytes_per_pixel; + bytes_per_row += ( bytes_per_row % 4 ? 4 - bytes_per_row % 4 : 0 ); + + + /* Set header's image specific values */ + bmp->Header.Width = width; + bmp->Header.Height = height; + bmp->Header.BitsPerPixel = depth; + bmp->Header.ImageDataSize = bytes_per_row * height; + bmp->Header.FileSize = bmp->Header.ImageDataSize + 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 ); + bmp->Header.DataOffset = 54 + ( depth == 8 ? BMP_PALETTE_SIZE : 0 ); + + + /* Allocate palette */ + if ( bmp->Header.BitsPerPixel == 8 ) + { + bmp->Palette = (UCHAR*) calloc( BMP_PALETTE_SIZE, sizeof( UCHAR ) ); + if ( bmp->Palette == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + free( bmp ); + return NULL; + } + } + else + { + bmp->Palette = NULL; + } + + + /* Allocate pixels */ + bmp->Data = (UCHAR*) calloc( bmp->Header.ImageDataSize, sizeof( UCHAR ) ); + if ( bmp->Data == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + free( bmp->Palette ); + free( bmp ); + return NULL; + } + + + BMP_LAST_ERROR_CODE = BMP_OK; + + return bmp; +} + + +/************************************************************** + Frees all the memory used by the specified BMP image. +**************************************************************/ +void BMP_Free( BMP* bmp ) +{ + if ( bmp == NULL ) + { + return; + } + + if ( bmp->Palette != NULL ) + { + free( bmp->Palette ); + } + + if ( bmp->Data != NULL ) + { + free( bmp->Data ); + } + + free( bmp ); + + BMP_LAST_ERROR_CODE = BMP_OK; +} + + +/************************************************************** + Reads the specified BMP image file. +**************************************************************/ +BMP* BMP_ReadFile( const char* filename ) +{ + BMP* bmp; + FILE* f; + + if ( filename == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return NULL; + } + + + /* Allocate */ + bmp = calloc( 1, sizeof( BMP ) ); + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + return NULL; + } + + + /* Open file */ + f = fopen( filename, "rb" ); + if ( f == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND; + free( bmp ); + return NULL; + } + + + /* Read header */ + if ( ReadHeader( bmp, f ) != BMP_OK || bmp->Header.Magic != 0x4D42 ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; + fclose( f ); + free( bmp ); + return NULL; + } + + + /* Verify that the bitmap variant is supported */ + if ( ( bmp->Header.BitsPerPixel != 32 && bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 8 ) + || bmp->Header.CompressionType != 0 || bmp->Header.HeaderSize != 40 ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_SUPPORTED; + fclose( f ); + free( bmp ); + return NULL; + } + + + /* Allocate and read palette */ + if ( bmp->Header.BitsPerPixel == 8 ) + { + bmp->Palette = (UCHAR*) malloc( BMP_PALETTE_SIZE * sizeof( UCHAR ) ); + if ( bmp->Palette == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + fclose( f ); + free( bmp ); + return NULL; + } + + if ( fread( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; + fclose( f ); + free( bmp->Palette ); + free( bmp ); + return NULL; + } + } + else /* Not an indexed image */ + { + bmp->Palette = NULL; + } + + + /* Allocate memory for image data */ + bmp->Data = (UCHAR*) malloc( bmp->Header.ImageDataSize ); + if ( bmp->Data == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_OUT_OF_MEMORY; + fclose( f ); + free( bmp->Palette ); + free( bmp ); + return NULL; + } + + + /* Read image data */ + if ( fread( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_INVALID; + fclose( f ); + free( bmp->Data ); + free( bmp->Palette ); + free( bmp ); + return NULL; + } + + + fclose( f ); + + BMP_LAST_ERROR_CODE = BMP_OK; + + return bmp; +} + + +/************************************************************** + Writes the BMP image to the specified file. +**************************************************************/ +void BMP_WriteFile( BMP* bmp, const char* filename ) +{ + FILE* f; + + if ( filename == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return; + } + + + /* Open file */ + f = fopen( filename, "wb" ); + if ( f == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_FILE_NOT_FOUND; + return; + } + + + /* Write header */ + if ( WriteHeader( bmp, f ) != BMP_OK ) + { + BMP_LAST_ERROR_CODE = BMP_IO_ERROR; + fclose( f ); + return; + } + + + /* Write palette */ + if ( bmp->Palette ) + { + if ( fwrite( bmp->Palette, sizeof( UCHAR ), BMP_PALETTE_SIZE, f ) != BMP_PALETTE_SIZE ) + { + BMP_LAST_ERROR_CODE = BMP_IO_ERROR; + fclose( f ); + return; + } + } + + + /* Write data */ + if ( fwrite( bmp->Data, sizeof( UCHAR ), bmp->Header.ImageDataSize, f ) != bmp->Header.ImageDataSize ) + { + BMP_LAST_ERROR_CODE = BMP_IO_ERROR; + fclose( f ); + return; + } + + + BMP_LAST_ERROR_CODE = BMP_OK; + fclose( f ); +} + + +/************************************************************** + Returns the image's width. +**************************************************************/ +UINT BMP_GetWidth( BMP* bmp ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return -1; + } + + BMP_LAST_ERROR_CODE = BMP_OK; + + return ( bmp->Header.Width ); +} + + +/************************************************************** + Returns the image's height. +**************************************************************/ +UINT BMP_GetHeight( BMP* bmp ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return -1; + } + + BMP_LAST_ERROR_CODE = BMP_OK; + + return ( bmp->Header.Height ); +} + + +/************************************************************** + Returns the image's color depth (bits per pixel). +**************************************************************/ +USHORT BMP_GetDepth( BMP* bmp ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + return -1; + } + + BMP_LAST_ERROR_CODE = BMP_OK; + + return ( bmp->Header.BitsPerPixel ); +} + + +/************************************************************** + Populates the arguments with the specified pixel's RGB + values. +**************************************************************/ +void BMP_GetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b ) +{ + UCHAR* pixel; + UINT bytes_per_row; + UCHAR bytes_per_pixel; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + bytes_per_pixel = bmp->Header.BitsPerPixel >> 3; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel (rows are flipped) */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel ); + + + /* In indexed color mode the pixel's value is an index within the palette */ + if ( bmp->Header.BitsPerPixel == 8 ) + { + pixel = bmp->Palette + *pixel * 4; + } + + /* Note: colors are stored in BGR order */ + if ( r ) *r = *( pixel + 2 ); + if ( g ) *g = *( pixel + 1 ); + if ( b ) *b = *( pixel + 0 ); + } +} + + +/************************************************************** + Sets the specified pixel's RGB values. +**************************************************************/ +void BMP_SetPixelRGB( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b ) +{ + UCHAR* pixel; + UINT bytes_per_row; + UCHAR bytes_per_pixel; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 24 && bmp->Header.BitsPerPixel != 32 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + bytes_per_pixel = bmp->Header.BitsPerPixel >> 3; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel (rows are flipped) */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x * bytes_per_pixel ); + + /* Note: colors are stored in BGR order */ + *( pixel + 2 ) = r; + *( pixel + 1 ) = g; + *( pixel + 0 ) = b; + } +} + + +/************************************************************** + Gets the specified pixel's color index. +**************************************************************/ +void BMP_GetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR* val ) +{ + UCHAR* pixel; + UINT bytes_per_row; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x ); + + + if ( val ) *val = *pixel; + } +} + + +/************************************************************** + Sets the specified pixel's color index. +**************************************************************/ +void BMP_SetPixelIndex( BMP* bmp, UINT x, UINT y, UCHAR val ) +{ + UCHAR* pixel; + UINT bytes_per_row; + + if ( bmp == NULL || x < 0 || x >= bmp->Header.Width || y < 0 || y >= bmp->Header.Height ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + BMP_LAST_ERROR_CODE = BMP_OK; + + /* Row's size is rounded up to the next multiple of 4 bytes */ + bytes_per_row = bmp->Header.ImageDataSize / bmp->Header.Height; + + /* Calculate the location of the relevant pixel */ + pixel = bmp->Data + ( ( bmp->Header.Height - y - 1 ) * bytes_per_row + x ); + + *pixel = val; + } +} + + +/************************************************************** + Gets the color value for the specified palette index. +**************************************************************/ +void BMP_GetPaletteColor( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + if ( r ) *r = *( bmp->Palette + index * 4 + 2 ); + if ( g ) *g = *( bmp->Palette + index * 4 + 1 ); + if ( b ) *b = *( bmp->Palette + index * 4 + 0 ); + + BMP_LAST_ERROR_CODE = BMP_OK; + } +} + + +/************************************************************** + Sets the color value for the specified palette index. +**************************************************************/ +void BMP_SetPaletteColor( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b ) +{ + if ( bmp == NULL ) + { + BMP_LAST_ERROR_CODE = BMP_INVALID_ARGUMENT; + } + + else if ( bmp->Header.BitsPerPixel != 8 ) + { + BMP_LAST_ERROR_CODE = BMP_TYPE_MISMATCH; + } + + else + { + *( bmp->Palette + index * 4 + 2 ) = r; + *( bmp->Palette + index * 4 + 1 ) = g; + *( bmp->Palette + index * 4 + 0 ) = b; + + BMP_LAST_ERROR_CODE = BMP_OK; + } +} + + +/************************************************************** + Returns the last error code. +**************************************************************/ +BMP_STATUS BMP_GetError() +{ + return BMP_LAST_ERROR_CODE; +} + + +/************************************************************** + Returns a description of the last error code. +**************************************************************/ +const char* BMP_GetErrorDescription() +{ + if ( BMP_LAST_ERROR_CODE > 0 && BMP_LAST_ERROR_CODE < BMP_ERROR_NUM ) + { + return BMP_ERROR_STRING[ BMP_LAST_ERROR_CODE ]; + } + else + { + return NULL; + } +} + + + + + +/*********************************** Private methods **********************************/ + + +/************************************************************** + Reads the BMP file's header into the data structure. + Returns BMP_OK on success. +**************************************************************/ +int ReadHeader( BMP* bmp, FILE* f ) +{ + if ( bmp == NULL || f == NULL ) + { + return BMP_INVALID_ARGUMENT; + } + + /* The header's fields are read one by one, and converted from the format's + little endian to the system's native representation. */ + if ( !ReadUSHORT( &( bmp->Header.Magic ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.FileSize ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.Reserved1 ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.Reserved2 ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.DataOffset ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.HeaderSize ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.Width ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.Height ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.Planes ), f ) ) return BMP_IO_ERROR; + if ( !ReadUSHORT( &( bmp->Header.BitsPerPixel ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.CompressionType ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.ImageDataSize ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.HPixelsPerMeter ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.VPixelsPerMeter ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.ColorsUsed ), f ) ) return BMP_IO_ERROR; + if ( !ReadUINT( &( bmp->Header.ColorsRequired ), f ) ) return BMP_IO_ERROR; + + return BMP_OK; +} + + +/************************************************************** + Writes the BMP file's header into the data structure. + Returns BMP_OK on success. +**************************************************************/ +int WriteHeader( BMP* bmp, FILE* f ) +{ + if ( bmp == NULL || f == NULL ) + { + return BMP_INVALID_ARGUMENT; + } + + /* The header's fields are written one by one, and converted to the format's + little endian representation. */ + if ( !WriteUSHORT( bmp->Header.Magic, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.FileSize, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.Reserved1, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.Reserved2, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.DataOffset, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.HeaderSize, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.Width, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.Height, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.Planes, f ) ) return BMP_IO_ERROR; + if ( !WriteUSHORT( bmp->Header.BitsPerPixel, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.CompressionType, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.ImageDataSize, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.HPixelsPerMeter, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.VPixelsPerMeter, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.ColorsUsed, f ) ) return BMP_IO_ERROR; + if ( !WriteUINT( bmp->Header.ColorsRequired, f ) ) return BMP_IO_ERROR; + + return BMP_OK; +} + + +/************************************************************** + Reads a little-endian unsigned int from the file. + Returns non-zero on success. +**************************************************************/ +int ReadUINT( UINT* x, FILE* f ) +{ + UCHAR little[ 4 ]; /* BMPs use 32 bit ints */ + + if ( x == NULL || f == NULL ) + { + return 0; + } + + if ( fread( little, 4, 1, f ) != 1 ) + { + return 0; + } + + *x = ( little[ 3 ] << 24 | little[ 2 ] << 16 | little[ 1 ] << 8 | little[ 0 ] ); + + return 1; +} + + +/************************************************************** + Reads a little-endian unsigned short int from the file. + Returns non-zero on success. +**************************************************************/ +int ReadUSHORT( USHORT *x, FILE* f ) +{ + UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */ + + if ( x == NULL || f == NULL ) + { + return 0; + } + + if ( fread( little, 2, 1, f ) != 1 ) + { + return 0; + } + + *x = ( little[ 1 ] << 8 | little[ 0 ] ); + + return 1; +} + + +/************************************************************** + Writes a little-endian unsigned int to the file. + Returns non-zero on success. +**************************************************************/ +int WriteUINT( UINT x, FILE* f ) +{ + UCHAR little[ 4 ]; /* BMPs use 32 bit ints */ + + little[ 3 ] = (UCHAR)( ( x & 0xff000000 ) >> 24 ); + little[ 2 ] = (UCHAR)( ( x & 0x00ff0000 ) >> 16 ); + little[ 1 ] = (UCHAR)( ( x & 0x0000ff00 ) >> 8 ); + little[ 0 ] = (UCHAR)( ( x & 0x000000ff ) >> 0 ); + + return ( f && fwrite( little, 4, 1, f ) == 1 ); +} + + +/************************************************************** + Writes a little-endian unsigned short int to the file. + Returns non-zero on success. +**************************************************************/ +int WriteUSHORT( USHORT x, FILE* f ) +{ + UCHAR little[ 2 ]; /* BMPs use 16 bit shorts */ + + little[ 1 ] = (UCHAR)( ( x & 0xff00 ) >> 8 ); + little[ 0 ] = (UCHAR)( ( x & 0x00ff ) >> 0 ); + + return ( f && fwrite( little, 2, 1, f ) == 1 ); +} + diff --git a/rbutil/ibassoboot/jni/qdbmp.h b/rbutil/ibassoboot/jni/qdbmp.h new file mode 100644 index 0000000000..d6c0e6c452 --- /dev/null +++ b/rbutil/ibassoboot/jni/qdbmp.h @@ -0,0 +1,133 @@ +#ifndef _BMP_H_ +#define _BMP_H_ + + +/************************************************************** + + QDBMP - Quick n' Dirty BMP + + v1.0.0 - 2007-04-07 + http://qdbmp.sourceforge.net + + + The library supports the following BMP variants: + 1. Uncompressed 32 BPP (alpha values are ignored) + 2. Uncompressed 24 BPP + 3. Uncompressed 8 BPP (indexed color) + + QDBMP is free and open source software, distributed + under the MIT licence. + + Copyright (c) 2007 Chai Braudo (braudo@users.sourceforge.net) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + +**************************************************************/ + +#include + + + +/* Type definitions */ +#ifndef UINT + #define UINT unsigned long int +#endif + +#ifndef USHORT + #define USHORT unsigned short +#endif + +#ifndef UCHAR + #define UCHAR unsigned char +#endif + + +/* Version */ +#define QDBMP_VERSION_MAJOR 1 +#define QDBMP_VERSION_MINOR 0 +#define QDBMP_VERSION_PATCH 1 + + +/* Error codes */ +typedef enum +{ + BMP_OK = 0, /* No error */ + BMP_ERROR, /* General error */ + BMP_OUT_OF_MEMORY, /* Could not allocate enough memory to complete the operation */ + BMP_IO_ERROR, /* General input/output error */ + BMP_FILE_NOT_FOUND, /* File not found */ + BMP_FILE_NOT_SUPPORTED, /* File is not a supported BMP variant */ + BMP_FILE_INVALID, /* File is not a BMP image or is an invalid BMP */ + BMP_INVALID_ARGUMENT, /* An argument is invalid or out of range */ + BMP_TYPE_MISMATCH, /* The requested action is not compatible with the BMP's type */ + BMP_ERROR_NUM +} BMP_STATUS; + + +/* Bitmap image */ +typedef struct _BMP BMP; + + + + +/*********************************** Public methods **********************************/ + + +/* Construction/destruction */ +BMP* BMP_Create ( UINT width, UINT height, USHORT depth ); +void BMP_Free ( BMP* bmp ); + + +/* I/O */ +BMP* BMP_ReadFile ( const char* filename ); +void BMP_WriteFile ( BMP* bmp, const char* filename ); + + +/* Meta info */ +UINT BMP_GetWidth ( BMP* bmp ); +UINT BMP_GetHeight ( BMP* bmp ); +USHORT BMP_GetDepth ( BMP* bmp ); + + +/* Pixel access */ +void BMP_GetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR* r, UCHAR* g, UCHAR* b ); +void BMP_SetPixelRGB ( BMP* bmp, UINT x, UINT y, UCHAR r, UCHAR g, UCHAR b ); +void BMP_GetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR* val ); +void BMP_SetPixelIndex ( BMP* bmp, UINT x, UINT y, UCHAR val ); + + +/* Palette handling */ +void BMP_GetPaletteColor ( BMP* bmp, UCHAR index, UCHAR* r, UCHAR* g, UCHAR* b ); +void BMP_SetPaletteColor ( BMP* bmp, UCHAR index, UCHAR r, UCHAR g, UCHAR b ); + + +/* Error handling */ +BMP_STATUS BMP_GetError (); +const char* BMP_GetErrorDescription (); + + +/* Useful macro that may be used after each BMP operation to check for an error */ +#define BMP_CHECK_ERROR( output_file, return_value ) \ + if ( BMP_GetError() != BMP_OK ) \ + { \ + fprintf( ( output_file ), "BMP error: %s\n", BMP_GetErrorDescription() ); \ + return( return_value ); \ + } \ + +#endif diff --git a/tools/configure b/tools/configure index 12025ba942..20b9095f73 100755 --- a/tools/configure +++ b/tools/configure @@ -664,14 +664,19 @@ androidcc () { exit fi if [ -z "$ANDROID_NDK_PATH" ]; then - echo "ERROR: You need the Android NDK installed (r5 or higher) and have the ANDROID_NDK_PATH" + echo "ERROR: You need the Android NDK installed (r16 or higher) and have the ANDROID_NDK_PATH" echo "environment variable point to the root directory of the Android NDK." exit fi buildhost=$(uname | tr "[:upper:]" "[:lower:]") GCCOPTS=`echo $CCOPTS | sed -e s/-ffreestanding// -e s/-nostdlib// -e s/-Wundef//` - LDOPTS="$LDOPTS -Wl,-soname,librockbox.so -shared -ldl -llog" - GLOBAL_LDOPTS="-Wl,-z,defs -Wl,-z,noexecstack -shared" + LDOPTS="$LDOPTS -ldl -llog" + if [ "$modelname" != "ibassodx50" ] && [ "$modelname" != "ibassodx90" ]; then + LDOPTS="$LDOPTS -Wl,-soname,librockbox.so -shared" + fi + SHARED_LDFLAG="-shared" + SHARED_CFLAGS='' + GLOBAL_LDOPTS="-Wl,-z,defs -Wl,-z,noexecstack" ANDROID_ARCH=$1 # for android.make too gccchoice="4.6" # arch dependant stuff @@ -683,8 +688,8 @@ androidcc () { # threads work fine so far thread_support="ASSEMBLER_THREADS" GCCOPTS="$GCCOPTS -march=armv5te -mtune=xscale -msoft-float -fomit-frame-pointer \ - --sysroot=$ANDROID_NDK_PATH/platforms/android-5/arch-arm" - LDOPTS="$LDOPTS --sysroot=$ANDROID_NDK_PATH/platforms/android-5/arch-arm" + --sysroot=$ANDROID_NDK_PATH/platforms/android-16/arch-arm" + LDOPTS="$LDOPTS --sysroot=$ANDROID_NDK_PATH/platforms/android-16/arch-arm" ;; mips) endian="little" @@ -1336,13 +1341,10 @@ cat <