From 249bba03f1051f4984538f66b9e7d36674c61e5c Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Sat, 24 Dec 2011 11:56:46 +0000 Subject: Initial commit of the Samsung YP-R0 port. This port is a hybrid native/RaaA port. It runs on a embedded linux system, but is the only application. It therefore can implement lots of stuff that native targets also implement, while leveraging the underlying linux kernel. The port is quite advanced. User interface, audio playback, plugins work mostly fine. Missing is e.g. power mangement and USB (see SamsungYPR0 wiki page). Included in utils/ypr0tools are scripts and programs required to generate a patched firmware. The patched firmware has the rootfs modified to load Rockbox. It includes a early/safe USB mode. This port needs a new toolchain, one that includes glibc headers and libraries. rockboxdev.sh can generate it, but e.g. codesourcey and distro packages may also work. Most of the initial effort is done by Lorenzo Miori and others (on ABI), including reverse engineering and patching of the original firmware, initial drivers, and more. Big thanks to you. Flyspray: FS#12348 Author: Lorenzo Miori, myself Merry christmas to ypr0 owners! :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31415 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 29 +- firmware/common/rbpaths.c | 34 ++ firmware/drivers/audio/as3514.c | 42 +- firmware/drivers/rtc/rtc_as3514.c | 4 +- firmware/export/as3514.h | 5 + firmware/export/ascodec.h | 4 + firmware/export/audiohw.h | 2 +- firmware/export/config.h | 16 + firmware/export/config/ypr0.h | 168 ++++++++ firmware/export/rbpaths.h | 5 +- firmware/include/dir_uncached.h | 2 +- firmware/pcm_mixer.c | 5 + firmware/sound.c | 5 +- firmware/system.c | 2 +- firmware/target/hosted/pcm-alsa.c | 518 +++++++++++++++++++++++++ firmware/target/hosted/ypr0/adc-target.h | 25 ++ firmware/target/hosted/ypr0/ascodec-target.h | 92 +++++ firmware/target/hosted/ypr0/ascodec-ypr0.c | 206 ++++++++++ firmware/target/hosted/ypr0/backlight-target.h | 29 ++ firmware/target/hosted/ypr0/backlight-ypr0.c | 89 +++++ firmware/target/hosted/ypr0/button-target.h | 53 +++ firmware/target/hosted/ypr0/button-ypr0.c | 103 +++++ firmware/target/hosted/ypr0/dir-target.h | 56 +++ firmware/target/hosted/ypr0/fs-ypr0.c | 141 +++++++ firmware/target/hosted/ypr0/i2c-target.h | 25 ++ firmware/target/hosted/ypr0/kernel-ypr0.c | 163 ++++++++ firmware/target/hosted/ypr0/lc-ypr0.c | 40 ++ firmware/target/hosted/ypr0/lcd-ypr0.c | 147 +++++++ firmware/target/hosted/ypr0/powermgmt-ypr0.c | 133 +++++++ firmware/target/hosted/ypr0/system-target.h | 37 ++ firmware/target/hosted/ypr0/system-ypr0.c | 106 +++++ firmware/target/hosted/ypr0/usb-target.h | 25 ++ firmware/target/hosted/ypr0/ypr0.make | 25 ++ 33 files changed, 2325 insertions(+), 11 deletions(-) create mode 100644 firmware/export/config/ypr0.h create mode 100644 firmware/target/hosted/pcm-alsa.c create mode 100644 firmware/target/hosted/ypr0/adc-target.h create mode 100644 firmware/target/hosted/ypr0/ascodec-target.h create mode 100644 firmware/target/hosted/ypr0/ascodec-ypr0.c create mode 100644 firmware/target/hosted/ypr0/backlight-target.h create mode 100644 firmware/target/hosted/ypr0/backlight-ypr0.c create mode 100644 firmware/target/hosted/ypr0/button-target.h create mode 100644 firmware/target/hosted/ypr0/button-ypr0.c create mode 100644 firmware/target/hosted/ypr0/dir-target.h create mode 100644 firmware/target/hosted/ypr0/fs-ypr0.c create mode 100644 firmware/target/hosted/ypr0/i2c-target.h create mode 100644 firmware/target/hosted/ypr0/kernel-ypr0.c create mode 100644 firmware/target/hosted/ypr0/lc-ypr0.c create mode 100644 firmware/target/hosted/ypr0/lcd-ypr0.c create mode 100644 firmware/target/hosted/ypr0/powermgmt-ypr0.c create mode 100644 firmware/target/hosted/ypr0/system-target.h create mode 100644 firmware/target/hosted/ypr0/system-ypr0.c create mode 100644 firmware/target/hosted/ypr0/usb-target.h create mode 100644 firmware/target/hosted/ypr0/ypr0.make (limited to 'firmware') diff --git a/firmware/SOURCES b/firmware/SOURCES index 7053358bee..f59475e27a 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -14,8 +14,10 @@ target/hosted/cpuinfo-linux.c #endif target/hosted/powermgmt.c +#ifndef SAMSUNG_YPR0 /* uses as3514 rtc */ target/hosted/rtc.c #endif +#endif system.c usb.c #ifdef ROCKBOX_HAS_LOGF @@ -62,6 +64,26 @@ target/hosted/sdl/app/button-application.c #endif #endif +#ifdef SAMSUNG_YPR0 +#if (CONFIG_RTC == RTC_AS3514) +drivers/rtc/rtc_as3514.c +#else +target/hosted/rtc.c +#endif +target/hosted/ypr0/button-ypr0.c +target/hosted/ypr0/kernel-ypr0.c +target/hosted/ypr0/lcd-ypr0.c +target/hosted/ypr0/system-ypr0.c +target/hosted/ypr0/fs-ypr0.c +target/hosted/ypr0/lc-ypr0.c +thread.c +#ifdef HAVE_BACKLIGHT +target/hosted/ypr0/backlight-ypr0.c +#endif +target/hosted/ypr0/ascodec-ypr0.c +target/hosted/ypr0/powermgmt-ypr0.c +#endif + /* Maemo specific files */ #if (CONFIG_PLATFORM & PLATFORM_MAEMO) target/hosted/maemo/maemo-thread.c @@ -368,6 +390,10 @@ drivers/audio/aic3x.c #elif defined (HAVE_DUMMY_CODEC) drivers/audio/dummy_codec.c #endif /* defined(HAVE_*) */ +#else /* PLATFORM_HOSTED */ +#if defined(SAMSUNG_YPR0) && defined(HAVE_AS3514) +drivers/audio/as3514.c +target/hosted/pcm-alsa.c #elif defined(HAVE_SDL_AUDIO) drivers/audio/sdl.c #if CONFIG_CODEC == SWCODEC @@ -377,6 +403,7 @@ target/hosted/maemo/pcm-gstreamer.c target/hosted/sdl/pcm-sdl.c #endif /* (CONFIG_PLATFORM & PLATFORM_MAEMO) */ #endif /* CONFIG_CODEC == SWCODEC */ +#endif #endif /* (CONFIG_PLATFORM & PLATFORM_NATIVE) && !defined(BOOTLOADER) */ /* CPU Specific - By class then particular chip if applicable */ @@ -722,7 +749,7 @@ target/arm/ascodec-pp.c # endif # if !defined(BOOTLOADER) || defined(CPU_PP) target/arm/adc-as3514.c -# ifndef SANSA_M200V4 +# if !defined(SANSA_M200V4) && !defined(SAMSUNG_YPR0) target/arm/powermgmt-ascodec.c # endif # endif diff --git a/firmware/common/rbpaths.c b/firmware/common/rbpaths.c index ed413eb03e..95bff3341f 100644 --- a/firmware/common/rbpaths.c +++ b/firmware/common/rbpaths.c @@ -23,6 +23,7 @@ #include /* snprintf */ #include #include +#include "config.h" #include "rbpaths.h" #include "file.h" /* MAX_PATH */ #include "logf.h" @@ -38,11 +39,17 @@ #undef mkdir #undef rmdir + #if (CONFIG_PLATFORM & PLATFORM_ANDROID) #include "dir-target.h" #define opendir opendir_android #define mkdir mkdir_android #define rmdir rmdir_android +#elif defined(SAMSUNG_YPR0) +#include "dir-target.h" +#define opendir opendir_ypr0 +#define mkdir mkdir_ypr0 +#define rmdir rmdir_ypr0 #elif (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) #define open sim_open #define remove sim_remove @@ -59,6 +66,8 @@ extern int sim_rmdir(const char* name); const char *rbhome; #endif +#if !defined(SAMSUNG_YPR0) + /* flags for get_user_file_path() */ /* whether you need write access to that file/dir, especially true * for runtime generated files (config.cfg) */ @@ -238,3 +247,28 @@ int app_rmdir(const char* name) } return rmdir(fname); } + +#else + +int app_open(const char *name, int o, ...) +{ + if (o & O_CREAT) + { + int ret; + va_list ap; + va_start(ap, o); + ret = open(name, o, va_arg(ap, mode_t)); + va_end(ap); + return ret; + } + return open(name, o); +} + +int app_creat(const char* name, mode_t mode) { return creat(name, mode); } +int app_remove(const char *name) { return remove(name); } +int app_rename(const char *old, const char *new) { return rename(old,new); } +DIR *app_opendir(const char *name) { return opendir(name); } +int app_mkdir(const char* name) { return mkdir(name); } +int app_rmdir(const char* name) { return rmdir(name); } + +#endif diff --git a/firmware/drivers/audio/as3514.c b/firmware/drivers/audio/as3514.c index 64531cfc2b..0fe3070c19 100644 --- a/firmware/drivers/audio/as3514.c +++ b/firmware/drivers/audio/as3514.c @@ -78,6 +78,7 @@ const struct sound_settings_info audiohw_settings[] = { #endif }; +#ifndef SAMSUNG_YPR0 /* Shadow registers */ static uint8_t as3514_regs[AS3514_NUM_AUDIO_REGS]; /* 8-bit registers */ @@ -110,7 +111,29 @@ static void as3514_write_masked(unsigned int reg, unsigned int bits, { as3514_write(reg, (as3514_regs[reg] & ~mask) | (bits & mask)); } +#else +static void as3514_write(unsigned int reg, unsigned int value) +{ + ascodec_write(reg, value); +} + +/* Helpers to set/clear bits */ +static void as3514_set(unsigned int reg, unsigned int bits) +{ + ascodec_write(reg, ascodec_read(reg) | bits); +} + +static void as3514_clear(unsigned int reg, unsigned int bits) +{ + ascodec_write(reg, ascodec_read(reg) & ~bits); +} +static void as3514_write_masked(unsigned int reg, unsigned int bits, + unsigned int mask) +{ + ascodec_write(reg, (ascodec_read(reg) & ~mask) | (bits & mask)); +} +#endif /* convert tenth of dB volume to master volume register value */ int tenthdb2master(int db) { @@ -145,8 +168,11 @@ int sound_val2phys(int setting, int value) */ void audiohw_preinit(void) { + +#ifndef SAMSUNG_YPR0 /* read all reg values */ ascodec_readbytes(0x0, AS3514_NUM_AUDIO_REGS, as3514_regs); +#endif #ifdef HAVE_AS3543 @@ -284,9 +310,14 @@ void audiohw_set_master_vol(int vol_l, int vol_r) #if CONFIG_CPU == AS3525v2 #define MIXER_MAX_VOLUME 0x1b #else /* lets leave the AS3514 alone until its better tested*/ +#ifdef SAMSUNG_YPR0 +#define MIXER_MAX_VOLUME 0x1a +#else #define MIXER_MAX_VOLUME 0x16 #endif +#endif +#ifndef SAMSUNG_YPR0 if (vol_r <= MIXER_MAX_VOLUME) { mix_r = vol_r; hph_r = 0; @@ -302,7 +333,16 @@ void audiohw_set_master_vol(int vol_l, int vol_r) mix_l = MIXER_MAX_VOLUME; hph_l = vol_l - MIXER_MAX_VOLUME; } - +#else +/* Okay. This is shit coded indeed. It is just a test. + Some considerations: Samsung keeps DAC constantly to 0x1a volume. It modifies only the headphone amp volume +*/ + + mix_r = 0x1a; + mix_l = 0x1a; + hph_l = vol_l; + hph_r = vol_r; +#endif as3514_write_masked(AS3514_DAC_R, mix_r, AS3514_VOL_MASK); as3514_write_masked(AS3514_DAC_L, mix_l, AS3514_VOL_MASK); diff --git a/firmware/drivers/rtc/rtc_as3514.c b/firmware/drivers/rtc/rtc_as3514.c index 44ef3cc4a1..868fa9753b 100644 --- a/firmware/drivers/rtc/rtc_as3514.c +++ b/firmware/drivers/rtc/rtc_as3514.c @@ -141,11 +141,11 @@ void rtc_alarm_poweroff(void) seconds = 24*3600; seconds -= tm.tm_sec; - +#ifndef SAMSUNG_YPR0 /* disable MCLK, it is a wakeup source and prevents proper shutdown */ CGU_AUDIO = (2 << 0) | (1 << 11); CGU_PLLBSUP = (1 << 2) | (1 << 3); - +#endif /* write wakeup register */ alarm.seconds = seconds; alarm.enabled = true; diff --git a/firmware/export/as3514.h b/firmware/export/as3514.h index acf13444fa..bcdb1a78c6 100644 --- a/firmware/export/as3514.h +++ b/firmware/export/as3514.h @@ -131,9 +131,14 @@ extern void audiohw_set_sampr_dividers(int fsel); /* Headphone volume goes from -81.0 ... +6dB */ #define VOLUME_MIN -810 #else +#ifdef SAMSUNG_YPR0 +/* Headphone volume goes from -40.5 ... +6dB */ +#define VOLUME_MIN -405 +#else /* Headphone volume goes from -73.5 ... +6dB */ #define VOLUME_MIN -735 #endif +#endif #define VOLUME_MAX 60 /*** Audio Registers ***/ diff --git a/firmware/export/ascodec.h b/firmware/export/ascodec.h index 93cd767608..658153e420 100644 --- a/firmware/export/ascodec.h +++ b/firmware/export/ascodec.h @@ -28,4 +28,8 @@ #include "ascodec-target.h" #endif +#ifdef SAMSUNG_YPR0 +#include "ascodec-target.h" +#endif + #endif diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index 102d107d8a..304c5aa460 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h @@ -79,7 +79,7 @@ #elif defined(HAVE_DUMMY_CODEC) #include "dummy_codec.h" #endif -#if (CONFIG_PLATFORM & PLATFORM_HOSTED) +#if (CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO|PLATFORM_PANDORA|PLATFORM_SDL)) /* #include gives errors in other code areas, * we don't really need it here, so don't. but it should maybe be fixed */ #ifndef SIMULATOR /* simulator gets values from the target .h files */ diff --git a/firmware/export/config.h b/firmware/export/config.h index 039b48a759..542587fc9d 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -143,6 +143,7 @@ #define HM60X_PAD 50 #define HM801_PAD 51 #define SANSA_CONNECT_PAD 52 +#define SAMSUNG_YPR0_PAD 53 /* CONFIG_REMOTE_KEYPAD */ #define H100_REMOTE 1 @@ -232,6 +233,7 @@ #define LCD_HX8340B 44 /* as used by the HiFiMAN HM-601/HM-602/HM-801 */ #define LCD_CONNECT 45 /* as used by the Sandisk Sansa Connect */ #define LCD_GIGABEATS 46 +#define LCD_YPR0 47 /* LCD_PIXELFORMAT */ #define HORIZONTAL_PACKING 1 @@ -483,6 +485,8 @@ Lyre prototype 1 */ #include "config/nokian900.h" #elif defined(PANDORA) #include "config/pandora.h" +#elif defined(SAMSUNG_YPR0) +#include "config/ypr0.h" #else /* no known platform */ #endif @@ -580,6 +584,10 @@ Lyre prototype 1 */ #define CONFIG_BACKLIGHT_FADING BACKLIGHT_NO_FADING #endif +#ifndef CONFIG_I2C +#define CONFIG_I2C I2C_NONE +#endif + #ifndef CONFIG_TUNER #define CONFIG_TUNER 0 #endif @@ -600,6 +608,14 @@ Lyre prototype 1 */ #define CONFIG_RTC 0 #endif +#ifndef BATTERY_TYPES_COUNT +#define BATTERY_TYPES_COUNT 0 +#endif + +#ifndef BATTERY_CAPACITY_INC +#define BATTERY_CAPACITY_INC 0 +#endif + #ifndef CONFIG_ORIENTATION #if LCD_HEIGHT > LCD_WIDTH #define CONFIG_ORIENTATION SCREEN_PORTRAIT diff --git a/firmware/export/config/ypr0.h b/firmware/export/config/ypr0.h new file mode 100644 index 0000000000..25e1906a80 --- /dev/null +++ b/firmware/export/config/ypr0.h @@ -0,0 +1,168 @@ +/* + * This config file is for the RockBox as application on the Samsung YP-R0 player. + * The target name for ifdefs is: SAMSUNG_YPR0; or CONFIG_PLATFORM & PLAFTORM_YPR0 + */ + +#define TARGET_TREE /* this target is using the target tree system */ + +/* We don't run on hardware directly */ +/* YP-R0 need it too of course */ +#define CONFIG_PLATFORM (PLATFORM_HOSTED) + +/* For Rolo and boot loader */ +#define MODEL_NUMBER 100 + +#define MODEL_NAME "Samsung YP-R0" + +/* Indeed to check that */ +/*TODO: R0 should charge battery automatically, no software stuff to manage that. Just to know about some as3543 registers, that should be set after loading samsung's afe.ko module + */ +/*TODO: implement USB data transfer management -> see safe mode script and think a way to implemtent it in the code */ +#define USB_NONE + +/* Hardware controlled charging with monitoring */ +//#define CONFIG_CHARGING CHARGING_MONITOR + +/* There is only USB charging */ +//#define HAVE_USB_POWER + +/* 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 the LCD needs to be shutdown */ +/* TODO: Our framebuffer must be closed... */ +#define HAVE_LCD_SHUTDOWN + +/* 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 have access to the pitchscreen */ +#define HAVE_PITCHSCREEN + +/* define this if you would like tagcache to build on this target */ +#define HAVE_TAGCACHE + +/* LCD dimensions + * + * overriden by configure for application builds */ +#ifndef LCD_WIDTH +#define LCD_WIDTH 240 +#endif + +#ifndef LCD_HEIGHT +#define LCD_HEIGHT 320 +#endif + +#define LCD_DEPTH 16 +/* Check that but should not matter */ +#define LCD_PIXELFORMAT 565 + +/* YP-R0 has the backlight */ +#define HAVE_BACKLIGHT + +/* Define this for LCD backlight brightness available */ +#define HAVE_BACKLIGHT_BRIGHTNESS + +/* Main LCD backlight brightness range and defaults */ +/* 0 is turned off. 31 is the real maximum for the ASCODEC DCDC but samsung doesn't use any value over 15, so it safer to don't go up too much */ +#define MIN_BRIGHTNESS_SETTING 1 +#define MAX_BRIGHTNESS_SETTING 15 +#define DEFAULT_BRIGHTNESS_SETTING 4 + +/* Which backlight fading type? */ +/* TODO: ASCODEC has an auto dim feature, so disabling the supply to leds should do the trick. But for now I tested SW fading only */ +#define CONFIG_BACKLIGHT_FADING BACKLIGHT_FADING_SW_SETTING + +/* define this if you have RTC RAM available for settings */ +/* TODO: in theory we could use that, ascodec offers us such a ram. we have also a small device, part of the nand of 1 MB size, that Samsung uses to store region code etc and it's almost unused space */ +//#define HAVE_RTC_RAM + +/* define this if you have a real-time clock */ +//#define CONFIG_RTC APPLICATION +#define CONFIG_RTC RTC_AS3514 +#define HAVE_RTC_ALARM + +/* The number of bytes reserved for loadable codecs */ +#define CODEC_SIZE 0x80000 + +/* The number of bytes reserved for loadable plugins */ +#define PLUGIN_BUFFER_SIZE 0x100000 + +/* We can do AB-repeat -> we use User key, our hotkey */ +#define AB_REPEAT_ENABLE +#define ACTION_WPSAB_SINGLE ACTION_WPS_HOTKEY + +/* Define this if you do software codec */ +#define CONFIG_CODEC SWCODEC + +/* R0 KeyPad configuration for plugins */ +#define CONFIG_KEYPAD SAMSUNG_YPR0_PAD +/* It's better to close /dev/r0Btn at shutdown */ +#define BUTTON_DRIVER_CLOSE + +/* The YPR0 has a as3534 codec and we use that to control the volume */ +#define HAVE_AS3514 +#define HAVE_AS3543 + +#define HAVE_SW_TONE_CONTROLS + +/* TODO: Make use of the si4703 tuner hardware */ +/* #define CONFIG_TUNER SI4700 */ +/* #define HAVE_TUNER_PWR_CTRL*/ + +/*TODO: In R0 there is an interrupt for this (figure out ioctls)*/ +/* #define HAVE_HEADPHONE_DETECTION */ + +/* Define current usage levels. */ +/* TODO: to be filled with correct values after implementing power management */ +#define CURRENT_NORMAL 88 /* 18 hours from a 1600 mAh battery */ +#define CURRENT_BACKLIGHT 30 /* TBD */ +#define CURRENT_RECORD 0 /* no recording yet */ + +/* TODO: We need to do battery handling */ +//#define BATTERY_CAPACITY_DEFAULT 600 /* default battery capacity */ +//#define BATTERY_CAPACITY_MIN 600 /* min. capacity selectable */ +//#define BATTERY_CAPACITY_MAX 700 /* max. capacity selectable */ +//#define BATTERY_CAPACITY_INC 50 /* capacity increment */ +//#define BATTERY_TYPES_COUNT 1 /* only one type */ + +/* TODO: We possibly can only watch linux charging */ +//#define CONFIG_CHARGING CHARGING_TARGET +//#define HAVE_RESET_BATTERY_FILTER + +/* same dimensions as gigabeats */ +#define CONFIG_LCD LCD_YPR0 + +/* Define this if a programmable hotkey is mapped */ +#define HAVE_HOTKEY + +/* Define this if you have a software controlled poweroff */ +#define HAVE_SW_POWEROFF + +/* Define this if you have adjustable CPU frequency + * NOTE: We could do that on this device, but it's probably better + * to let linux do it (we set ondemand governor before loading Rockbox) */ +/* #define HAVE_ADJUSTABLE_CPU_FREQ */ +/* Define this to the CPU frequency */ +#define CPU_FREQ 532000000 +/* 0.8Vcore using 200 MHz */ +/* #define CPUFREQ_DEFAULT 200000000 */ +/* This is 400 MHz -> not so powersaving-ful */ +/* #define CPUFREQ_NORMAL 400000000 */ +/* Max IMX37 Cpu Frequency */ +/* #define CPUFREQ_MAX CPU_FREQ */ + +/* TODO: my idea is to create a folder in the cramfs [/.rockbox], mounting it by the starter script as the current working directory, so no issues of any type keeping the rockbox folder as in all other players */ +#define BOOTDIR "/.rockbox" diff --git a/firmware/export/rbpaths.h b/firmware/export/rbpaths.h index 74d26f93d3..8f554c25f4 100644 --- a/firmware/export/rbpaths.h +++ b/firmware/export/rbpaths.h @@ -44,7 +44,7 @@ #define ROCKBOX_DIR_LEN (sizeof(ROCKBOX_DIR)-1) #endif /* def __PCTOOL__ */ -#ifndef APPLICATION +#if !defined(APPLICATION) || defined(SAMSUNG_YPR0) /* make sure both are the same for native builds */ #undef ROCKBOX_LIBRARY_PATH @@ -57,6 +57,7 @@ #define PLAYLIST_CATALOG_DEFAULT_DIR "/Playlists" #define paths_init() + #else /* application */ #define PLUGIN_DIR ROCKBOX_LIBRARY_PATH "/rockbox/rocks" @@ -80,7 +81,7 @@ extern void paths_init(void); #define PLUGIN_DEMOS_DIR PLUGIN_DIR "/demos" #define VIEWERS_DIR PLUGIN_DIR "/viewers" -#ifdef APPLICATION +#if defined(APPLICATION) && !defined(SAMSUNG_YPR0) #define PLUGIN_DATA_DIR "/.rockbox/rocks.data" #define PLUGIN_GAMES_DATA_DIR PLUGIN_DATA_DIR #define PLUGIN_APPS_DATA_DIR PLUGIN_DATA_DIR diff --git a/firmware/include/dir_uncached.h b/firmware/include/dir_uncached.h index d9a29fbada..e0fea13c14 100644 --- a/firmware/include/dir_uncached.h +++ b/firmware/include/dir_uncached.h @@ -74,7 +74,7 @@ typedef struct { #if defined(APPLICATION) -#if (CONFIG_PLATFORM & PLATFORM_ANDROID) +#if (CONFIG_PLATFORM & PLATFORM_ANDROID) || defined(SAMSUNG_YPR0) #include "dir-target.h" #endif # undef opendir_uncached diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c index 25c41c2586..3194f76e04 100644 --- a/firmware/pcm_mixer.c +++ b/firmware/pcm_mixer.c @@ -70,6 +70,11 @@ static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATT #define MAX_IDLE_FRAMES (NATIVE_FREQUENCY*3 / MIX_FRAME_SAMPLES) static unsigned int idle_counter = 0; +/* Cheapo buffer align macro to align to the 16-16 PCM size */ +#define ALIGN_CHANNEL(start, size) \ + ({ start = (void *)(((uintptr_t)start + 3) & ~3); \ + size &= ~3; }) + #if (CONFIG_PLATFORM & PLATFORM_NATIVE) /* Include any implemented CPU-optimized mixdown routines */ diff --git a/firmware/sound.c b/firmware/sound.c index c97ccc243f..99db7896ab 100644 --- a/firmware/sound.c +++ b/firmware/sound.c @@ -235,7 +235,8 @@ static void set_prescaled_volume(void) dsp_callback(DSP_CALLBACK_SET_SW_VOLUME, 0); #endif -#ifndef HAVE_SDL_AUDIO +/* ypr0 with sdl has separate volume controls */ +#if !defined(HAVE_SDL_AUDIO) || defined(SAMSUNG_YPR0) #if CONFIG_CODEC == MAS3507D dac_volume(tenthdb2reg(l), tenthdb2reg(r), false); #elif defined(HAVE_UDA1380) || defined(HAVE_WM8975) || defined(HAVE_WM8758) \ @@ -670,7 +671,7 @@ void sound_set(int setting, int value) && !defined (HAVE_WM8711) && !defined (HAVE_WM8721) \ && !defined (HAVE_WM8731) && !defined (HAVE_WM8978) \ && !defined (HAVE_WM8750) && !defined (HAVE_WM8751) \ - && !defined(HAVE_AK4537)) || (CONFIG_PLATFORM & PLATFORM_HOSTED) + && !defined(HAVE_AK4537)) || defined(SIMULATOR) int sound_val2phys(int setting, int value) { #if CONFIG_CODEC == MAS3587F diff --git a/firmware/system.c b/firmware/system.c index 7e269ee119..111a94f80e 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -26,7 +26,7 @@ #include "string.h" #include "file.h" -#if (CONFIG_PLATFORM & PLATFORM_NATIVE) +#ifdef HAVE_ADJUSTABLE_CPU_FREQ long cpu_frequency SHAREDBSS_ATTR = CPU_FREQ; #endif diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c new file mode 100644 index 0000000000..928187993e --- /dev/null +++ b/firmware/target/hosted/pcm-alsa.c @@ -0,0 +1,518 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + * 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. + * device works which doesnt break with other apps running. + */ + + +#include "autoconf.h" + +#include +#include +#include +#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 +#include + +#define USE_ASYNC_CALLBACK +/* plughw:0,0 works with both, however "default" is recommended. + * default doesnt seem to work with async callback but doesn't break + * with multple applications running */ +static char device[] = "plughw:0,0"; /* playback device */ +static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */ +static const snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format */ +static const int channels = 2; /* count of channels */ +static unsigned int rate = 44100; /* stream rate */ + +static snd_pcm_t *handle; +static snd_pcm_sframes_t buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */ +static snd_pcm_sframes_t period_size = MIX_FRAME_SAMPLES * 4; /* ~4k */ +static short *frames; + +static const char *pcm_data = 0; +static size_t pcm_size = 0; + +#ifdef USE_ASYNC_CALLBACK +static snd_async_handler_t *ahandler; +static pthread_mutex_t pcm_mtx; +#else +static int recursion; +#endif + +static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate) +{ + unsigned int rrate; + int err; + snd_pcm_hw_params_t *params; + snd_pcm_hw_params_alloca(¶ms); + + + /* choose all parameters */ + err = snd_pcm_hw_params_any(handle, params); + if (err < 0) + { + printf("Broken configuration for playback: no configurations available: %s\n", snd_strerror(err)); + return err; + } + /* set the interleaved read/write format */ + err = snd_pcm_hw_params_set_access(handle, params, access_); + if (err < 0) + { + printf("Access type not available for playback: %s\n", snd_strerror(err)); + return err; + } + /* set the sample format */ + err = snd_pcm_hw_params_set_format(handle, params, format); + if (err < 0) + { + printf("Sample format not available for playback: %s\n", snd_strerror(err)); + return err; + } + /* set the count of channels */ + err = snd_pcm_hw_params_set_channels(handle, params, channels); + if (err < 0) + { + printf("Channels count (%i) not available for playbacks: %s\n", channels, snd_strerror(err)); + return err; + } + /* set the stream rate */ + rrate = sample_rate; + err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); + if (err < 0) + { + printf("Rate %iHz not available for playback: %s\n", rate, snd_strerror(err)); + return err; + } + if (rrate != sample_rate) + { + printf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, err); + return -EINVAL; + } + + /* set the buffer size */ + err = snd_pcm_hw_params_set_buffer_size_near(handle, params, &buffer_size); + if (err < 0) + { + printf("Unable to set buffer size %i for playback: %s\n", buffer_size, snd_strerror(err)); + return err; + } + + /* set the period size */ + err = snd_pcm_hw_params_set_period_size_near (handle, params, &period_size, NULL); + if (err < 0) + { + printf("Unable to set period size %i for playback: %s\n", period_size, snd_strerror(err)); + return err; + } + if (!frames) + frames = malloc(period_size * channels * sizeof(short)); + + /* write the parameters to device */ + err = snd_pcm_hw_params(handle, params); + if (err < 0) + { + printf("Unable to set hw params for playback: %s\n", snd_strerror(err)); + return err; + } + return 0; +} + +/* Set sw params: playback start threshold and low buffer watermark */ +static int set_swparams(snd_pcm_t *handle) +{ + int err; + + snd_pcm_sw_params_t *swparams; + snd_pcm_sw_params_alloca(&swparams); + + /* get the current swparams */ + err = snd_pcm_sw_params_current(handle, swparams); + if (err < 0) + { + printf("Unable to determine current swparams for playback: %s\n", snd_strerror(err)); + return err; + } + /* start the transfer when the buffer is haalmost full */ + err = snd_pcm_sw_params_set_start_threshold(handle, swparams, buffer_size / 2); + if (err < 0) + { + printf("Unable to set start threshold mode for playback: %s\n", snd_strerror(err)); + return err; + } + /* allow the transfer when at least period_size samples can be processed */ + err = snd_pcm_sw_params_set_avail_min(handle, swparams, period_size); + if (err < 0) + { + printf("Unable to set avail min for playback: %s\n", snd_strerror(err)); + return err; + } + /* write the parameters to the playback device */ + err = snd_pcm_sw_params(handle, swparams); + if (err < 0) + { + printf("Unable to set sw params for playback: %s\n", snd_strerror(err)); + return err; + } + return 0; +} + +/* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ +static bool fill_frames(void) +{ + ssize_t copy_n, frames_left = period_size; + bool new_buffer = false; + + while (frames_left > 0) + { + if (!pcm_size) + { + new_buffer = true; + pcm_play_get_more_callback((void **)&pcm_data, &pcm_size); + if (!pcm_size || !pcm_data) + return false; + } + copy_n = MIN((ssize_t)pcm_size, frames_left*4); + memcpy(&frames[2*(period_size-frames_left)], pcm_data, copy_n); + + pcm_data += copy_n; + pcm_size -= copy_n; + frames_left -= copy_n/4; + + if (new_buffer) + { + new_buffer = false; + pcm_play_dma_started_callback(); + } + } + return true; +} + +#ifdef USE_ASYNC_CALLBACK +static void async_callback(snd_async_handler_t *ahandler) +{ + snd_pcm_t *handle = snd_async_handler_get_pcm(ahandler); + + if (pthread_mutex_trylock(&pcm_mtx) != 0) + return; +#else +static void pcm_tick(void) +{ + if (snd_pcm_state(handle) != SND_PCM_STATE_RUNNING) + return; +#endif + + while (snd_pcm_avail_update(handle) >= period_size) + { + if (fill_frames()) + { + int err = snd_pcm_writei(handle, frames, period_size); + if (err < 0 && err != period_size && err != -EAGAIN) + { + printf("Write error: written %i expected %li\n", err, period_size); + break; + } + } + else + { + DEBUGF("%s: No Data.\n", __func__); + break; + } + } +#ifdef USE_ASYNC_CALLBACK + pthread_mutex_unlock(&pcm_mtx); +#endif +} + +static int async_rw(snd_pcm_t *handle) +{ + int err; + snd_pcm_sframes_t sample_size; + short *samples; + +#ifdef USE_ASYNC_CALLBACK + err = snd_async_add_pcm_handler(&ahandler, handle, async_callback, NULL); + if (err < 0) + { + DEBUGF("Unable to register async handler: %s\n", snd_strerror(err)); + return err; + } +#endif + + /* fill buffer with silence to initiate playback without noisy click */ + sample_size = buffer_size; + samples = malloc(sample_size * channels * sizeof(short)); + + snd_pcm_format_set_silence(format, samples, sample_size); + err = snd_pcm_writei(handle, samples, sample_size); + free(samples); + + if (err < 0) + { + DEBUGF("Initial write error: %s\n", snd_strerror(err)); + return err; + } + if (err != (ssize_t)sample_size) + { + DEBUGF("Initial write error: written %i expected %li\n", err, sample_size); + return err; + } + if (snd_pcm_state(handle) == SND_PCM_STATE_PREPARED) + { + err = snd_pcm_start(handle); + if (err < 0) + { + DEBUGF("Start error: %s\n", snd_strerror(err)); + return err; + } + } + return 0; +} + + +void cleanup(void) +{ + free(frames); + frames = NULL; + snd_pcm_close(handle); +} + + +void pcm_play_dma_init(void) +{ + int err; + + + if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) + { + printf("%s(): Cannot open device %s: %s\n", __func__, device, snd_strerror(err)); + exit(EXIT_FAILURE); + return; + } + + if ((err = snd_pcm_nonblock(handle, 1))) + printf("Could not set non-block mode: %s\n", snd_strerror(err)); + + if ((err = set_hwparams(handle, rate)) < 0) + { + printf("Setting of hwparams failed: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + if ((err = set_swparams(handle)) < 0) + { + printf("Setting of swparams failed: %s\n", snd_strerror(err)); + exit(EXIT_FAILURE); + } + +#ifdef USE_ASYNC_CALLBACK + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&pcm_mtx, &attr); +#else + tick_add_task(pcm_tick); +#endif + + + atexit(cleanup); + return; +} + + +void pcm_play_lock(void) +{ +#ifdef USE_ASYNC_CALLBACK + pthread_mutex_lock(&pcm_mtx); +#else + if (recursion++ == 0) + tick_remove_task(pcm_tick); +#endif +} + +void pcm_play_unlock(void) +{ +#ifdef USE_ASYNC_CALLBACK + pthread_mutex_unlock(&pcm_mtx); +#else + if (--recursion == 0) + tick_add_task(pcm_tick); +#endif +} + +static void pcm_dma_apply_settings_nolock(void) +{ + snd_pcm_drop(handle); + set_hwparams(handle, pcm_sampr); +} + +void pcm_dma_apply_settings(void) +{ + pcm_play_lock(); + pcm_dma_apply_settings_nolock(); + pcm_play_unlock(); +} + + +void pcm_play_dma_pause(bool pause) +{ + snd_pcm_pause(handle, pause); +} + + +void pcm_play_dma_stop(void) +{ + snd_pcm_drain(handle); +} + +void pcm_play_dma_start(const void *addr, size_t size) +{ + pcm_dma_apply_settings_nolock(); + + pcm_data = addr; + pcm_size = size; + + while (1) + { + snd_pcm_state_t state = snd_pcm_state(handle); + switch (state) + { + case SND_PCM_STATE_RUNNING: + return; + case SND_PCM_STATE_XRUN: + { + DEBUGF("Trying to recover from error\n"); + int err = snd_pcm_recover(handle, -EPIPE, 0); + if (err < 0) + DEBUGF("Recovery failed: %s\n", snd_strerror(err)); + continue; + } + case SND_PCM_STATE_SETUP: + { + int err = snd_pcm_prepare(handle); + if (err < 0) + printf("Prepare error: %s\n", snd_strerror(err)); + /* fall through */ + } + case SND_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: %s\n", snd_strerror(err)); + return; + } + case SND_PCM_STATE_PAUSED: + { /* paused, simply resume */ + pcm_play_dma_pause(0); + return; + } + case SND_PCM_STATE_DRAINING: + /* run until drained */ + continue; + default: + DEBUGF("Unhandled state: %s\n", snd_pcm_state_name(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) +{ +} + + +void pcm_set_mixer_volume(int volume) +{ + (void)volume; +} +#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/ypr0/adc-target.h b/firmware/target/hosted/ypr0/adc-target.h new file mode 100644 index 0000000000..bdbc4cfabd --- /dev/null +++ b/firmware/target/hosted/ypr0/adc-target.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: adc-target.h 29516 2011-03-05 15:31:52Z thomasjfox $ + * + * 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. + * + ****************************************************************************/ + +#ifndef __ADC_TARGET_H__ +#define __ADC_TARGET_H__ + +#endif /* __ADC_TARGET_H__ */ diff --git a/firmware/target/hosted/ypr0/ascodec-target.h b/firmware/target/hosted/ypr0/ascodec-target.h new file mode 100644 index 0000000000..f4ecf20a1b --- /dev/null +++ b/firmware/target/hosted/ypr0/ascodec-target.h @@ -0,0 +1,92 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: ascodec-target.h 26116 2010-05-17 20:53:25Z funman $ + * + * Module wrapper for AS3543 audio codec, using /dev/afe (afe.ko) of Samsung YP-R0 + * + * Copyright (c) 2011 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. + * + ****************************************************************************/ + +#ifndef _ASCODEC_TARGET_H +#define _ASCODEC_TARGET_H + +#include "as3514.h" +#include "kernel.h" +#include "adc.h" +#include "ascodec.h" + +/* ioctl parameter struct */ + +struct codec_req_struct { +/* This works for every kind of afe.ko module requests */ + unsigned char reg; /* Main register address */ + unsigned char subreg; /* Set this only if you are reading/writing a PMU register*/ + unsigned char value; /* To be read if reading a register; to be set if writing to a register */ +}; + +int ascodec_init(void); +void ascodec_close(void); +int ascodec_write(unsigned int reg, unsigned int value); +int ascodec_read(unsigned int reg); +void ascodec_write_pmu(unsigned int index, unsigned int subreg, unsigned int value); +int ascodec_read_pmu(unsigned int index, unsigned int subreg); +void ascodec_set(unsigned int reg, unsigned int bits); +void ascodec_clear(unsigned int reg, unsigned int bits); +void ascodec_write_masked(unsigned int reg, unsigned int bits, unsigned int mask); +int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data); +unsigned short adc_read(int channel); +void ascodec_lock(void); +void ascodec_unlock(void); + +static inline bool ascodec_chg_status(void) +{ + return ascodec_read(AS3514_IRQ_ENRD0) & CHG_STATUS; +} + +static inline bool ascodec_endofch(void) +{ + return ascodec_read(AS3514_IRQ_ENRD0) & CHG_ENDOFCH; +} + +static inline void ascodec_monitor_endofch(void) +{ + ascodec_write(AS3514_IRQ_ENRD0, IRQ_ENDOFCH); +} + +static inline void ascodec_wait_adc_finished(void) +{ + /* + * FIXME: not implemented + * + * If irqs are not available on the target platform, + * this should be most likely implemented by polling + * AS3514_IRQ_ENRD2 in the same way powermgmt-ascodec.c + * is polling IRQ_ENDOFCH. + */ +} + +static inline void ascodec_write_charger(int value) +{ + ascodec_write_pmu(AS3543_CHARGER, 1, value); +} + +static inline int ascodec_read_charger(void) +{ + return ascodec_read_pmu(AS3543_CHARGER, 1); +} + +#endif /* !_ASCODEC_TARGET_H */ diff --git a/firmware/target/hosted/ypr0/ascodec-ypr0.c b/firmware/target/hosted/ypr0/ascodec-ypr0.c new file mode 100644 index 0000000000..a4e92e6f6b --- /dev/null +++ b/firmware/target/hosted/ypr0/ascodec-ypr0.c @@ -0,0 +1,206 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: ascodec-target.h 26116 2010-05-17 20:53:25Z funman $ + * + * Module wrapper for AS3543 audio codec, using /dev/afe (afe.ko) of Samsung YP-R0 + * + * Copyright (c) 2011 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 "fcntl.h" +#include "unistd.h" +#include "stdio.h" +#include "string.h" +#include "sys/ioctl.h" +#include "stdlib.h" + +#include "ascodec-target.h" + +int afe_dev = -1; + +/* Write to a normal register */ +#define IOCTL_REG_WRITE 0x40034101 +/* Write to a PMU register */ +#define IOCTL_SUBREG_WRITE 0x40034103 +/* Read from a normal register */ +#define IOCTL_REG_READ 0x80034102 +/* Read from a PMU register */ +#define IOCTL_SUBREG_READ 0x80034103 + +static struct mutex as_mtx; + +int ascodec_init(void) { + + afe_dev = open("/dev/afe", O_RDWR); + + mutex_init(&as_mtx); + + return afe_dev; + +} + +void ascodec_close(void) { + + if (afe_dev >= 0) { + close(afe_dev); + } + +} + +/* Read functions returns -1 if fail, otherwise the register's value if success */ +/* Write functions return >= 0 if success, otherwise -1 if fail */ + +int ascodec_write(unsigned int reg, unsigned int value) +{ + struct codec_req_struct y; + struct codec_req_struct *p; + p = &y; + p->reg = reg; + p->value = value; + return ioctl(afe_dev, IOCTL_REG_WRITE, p); +} + +int ascodec_read(unsigned int reg) +{ + int retval = -1; + struct codec_req_struct y; + struct codec_req_struct *p; + p = &y; + p->reg = reg; + retval = ioctl(afe_dev, IOCTL_REG_READ, p); + if (retval >= 0) + return p->value; + else + return retval; +} + +void ascodec_write_pmu(unsigned int index, unsigned int subreg, + unsigned int value) +{ + struct codec_req_struct y; + struct codec_req_struct *p; + p = &y; + p->reg = index; + p->subreg = subreg; + p->value = value; + ioctl(afe_dev, IOCTL_SUBREG_WRITE, p); +} + +int ascodec_read_pmu(unsigned int index, unsigned int subreg) +{ + int retval = -1; + struct codec_req_struct y; + struct codec_req_struct *p; + p = &y; + p->reg = index; + p->subreg = subreg; + retval = ioctl(afe_dev, IOCTL_SUBREG_READ, p); + if (retval >= 0) + return p->value; + else + return retval; +} + +/* Helpers to set/clear bits */ +void ascodec_set(unsigned int reg, unsigned int bits) +{ + ascodec_write(reg, ascodec_read(reg) | bits); +} + +void ascodec_clear(unsigned int reg, unsigned int bits) +{ + ascodec_write(reg, ascodec_read(reg) & ~bits); +} + +void ascodec_write_masked(unsigned int reg, unsigned int bits, + unsigned int mask) +{ + ascodec_write(reg, (ascodec_read(reg) & ~mask) | (bits & mask)); +} + +/*FIXME: doesn't work */ +int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data) +{ + unsigned int i; + + for (i=index; i= NUM_ADC_CHANNELS) + return 0; + + ascodec_lock(); + + /* Select channel */ + ascodec_write(AS3514_ADC_0, (channel << 4)); + unsigned char buf[2]; + + /* + * The AS3514 ADC will trigger an interrupt when the conversion + * is finished, if the corresponding enable bit in IRQ_ENRD2 + * is set. + * Previously the code did not wait and this apparently did + * not pose any problems, but this should be more correct. + * Without the wait the data read back may be completely or + * partially (first one of the two bytes) stale. + */ + /*FIXME: not implemented*/ + ascodec_wait_adc_finished(); + + /* Read data */ + ascodec_readbytes(AS3514_ADC_0, 2, buf); + data = (((buf[0] & 0x3) << 8) | buf[1]); + + ascodec_unlock(); + return data; +} + +void adc_init(void) +{ +} diff --git a/firmware/target/hosted/ypr0/backlight-target.h b/firmware/target/hosted/ypr0/backlight-target.h new file mode 100644 index 0000000000..561e159e8c --- /dev/null +++ b/firmware/target/hosted/ypr0/backlight-target.h @@ -0,0 +1,29 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: backlight-target.h 19322 2008-12-04 04:16:53Z jethead71 $ + * + * 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. + * + ****************************************************************************/ +#ifndef BACKLIGHT_TARGET_H +#define BACKLIGHT_TARGET_H + +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/ypr0/backlight-ypr0.c b/firmware/target/hosted/ypr0/backlight-ypr0.c new file mode 100644 index 0000000000..930b56be2e --- /dev/null +++ b/firmware/target/hosted/ypr0/backlight-ypr0.c @@ -0,0 +1,89 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: backlight-gigabeat-s.c 25800 2010-05-04 10:07:53Z jethead71 $ + * + * 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 "as3514.h" +#include "ascodec-target.h" +#include +#include "unistd.h" + +static bool backlight_on_status = true; /* Is on or off? */ + +/*TODO: see if LCD sleep could be implemented in a better way -> ie using a rockbox feature */ +/* Turn off LCD power supply */ +static void _backlight_lcd_sleep(void) +{ + int fp = open("/sys/class/graphics/fb0/blank", O_RDWR); + write(fp, "1", 1); + close(fp); +} +/* Turn on LCD screen */ +static void _backlight_lcd_power(void) +{ + int fp = open("/sys/class/graphics/fb0/blank", O_RDWR); + write(fp, "0", 1); + close(fp); +} + +bool _backlight_init(void) +{ + /* We have nothing to do */ + return true; +} + +void _backlight_on(void) +{ + if (!backlight_on_status) + { + /* Turn on lcd power before backlight */ + _backlight_lcd_power(); + /* Original app sets this to 0xb1 when backlight is on... */ + ascodec_write_pmu(AS3543_BACKLIGHT, 0x1, 0xb1); + } + + backlight_on_status = true; + +} + +void _backlight_off(void) +{ + if (backlight_on_status) { + /* Disabling the DCDC15 completely, keeps brightness register value */ + ascodec_write_pmu(AS3543_BACKLIGHT, 0x1, 0x00); + /* Turn off lcd power then */ + _backlight_lcd_sleep(); + } + + backlight_on_status = false; +} + +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; + ascodec_write_pmu(AS3543_BACKLIGHT, 0x3, brightness << 3 & 0xf8); +} diff --git a/firmware/target/hosted/ypr0/button-target.h b/firmware/target/hosted/ypr0/button-target.h new file mode 100644 index 0000000000..5d65d97607 --- /dev/null +++ b/firmware/target/hosted/ypr0/button-target.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: button-target.h 29248 2011-02-08 20:05:25Z thomasjfox $ + * + * 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. + * + ****************************************************************************/ + +#ifndef _BUTTON_TARGET_H_ +#define _BUTTON_TARGET_H_ + +#include +#include "config.h" + +void button_init_device(void); +void button_close_device(void); +int button_read_device(void); + +/* Logical buttons key codes */ +#define BUTTON_UP 0x00000001 +#define BUTTON_DOWN 0x00000002 +#define BUTTON_LEFT 0x00000004 +#define BUTTON_RIGHT 0x00000008 +#define BUTTON_USER 0x00000010 +#define BUTTON_MENU 0x00000020 +#define BUTTON_BACK 0x00000040 +#define BUTTON_POWER 0x00000080 +#define BUTTON_SELECT 0x00000100 + +#define BUTTON_MAIN 0x1FF /* all buttons */ + +/* No remote */ +#define BUTTON_REMOTE 0 + +/* Software power-off */ +#define POWEROFF_BUTTON BUTTON_POWER +/* About 3 seconds */ +#define POWEROFF_COUNT 10 + +#endif /* _BUTTON_TARGET_H_ */ diff --git a/firmware/target/hosted/ypr0/button-ypr0.c b/firmware/target/hosted/ypr0/button-ypr0.c new file mode 100644 index 0000000000..4298410161 --- /dev/null +++ b/firmware/target/hosted/ypr0/button-ypr0.c @@ -0,0 +1,103 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: button-sdl.c 30482 2011-09-08 14:53:28Z kugel $ + * + * Copyright (C) 2011 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 /* EXIT_SUCCESS */ +#include "config.h" +#include "button.h" +#include "kernel.h" +#include "system.h" +#include "button-target.h" + +/* R0 physical key codes */ +enum ypr0_buttons { + R0BTN_NONE = BUTTON_NONE, + R0BTN_POWER = 1, + R0BTN_UP, + R0BTN_DOWN, + R0BTN_RIGHT, + R0BTN_LEFT, + R0BTN_CENTRAL, + R0BTN_MENU, + R0BTN_BACK, + R0BTN_3DOTS = 11, +}; + + +static int r0_btn_fd = 0; +/* Samsung keypad driver doesn't allow multiple key combinations :( */ +static enum ypr0_buttons r0_read_key(void) +{ + unsigned char keys; + + if (r0_btn_fd < 0) + return 0; + + if (read(r0_btn_fd, &keys, 1)) + return keys; + + return 0; +} + +/* Conversion from physical keypress code to logic key code */ +static int key_to_button(enum ypr0_buttons keyboard_button) +{ + switch (keyboard_button) + { + default: return BUTTON_NONE; + case R0BTN_POWER: return BUTTON_POWER; + case R0BTN_UP: return BUTTON_UP; + case R0BTN_DOWN: return BUTTON_DOWN; + case R0BTN_RIGHT: return BUTTON_RIGHT; + case R0BTN_LEFT: return BUTTON_LEFT; + case R0BTN_CENTRAL: return BUTTON_SELECT; + case R0BTN_MENU: return BUTTON_MENU; + case R0BTN_BACK: return BUTTON_BACK; + case R0BTN_3DOTS: return BUTTON_USER; + } +} + +int button_read_device(void) +{ + return key_to_button(r0_read_key()); +} + + +/* Open the keypad device: it is offered by r0Btn.ko module */ +void button_init_device(void) +{ + r0_btn_fd = open("/dev/r0Btn", O_RDONLY); + if (r0_btn_fd < 0) + printf("/dev/r0Btn open error!"); +} + +#ifdef BUTTON_DRIVER_CLOSE +/* I'm not sure it's called at shutdown...give a check! */ +void button_close_device(void) +{ + if (r0_btn_fd >= 0) { + close(r0_btn_fd); + printf("/dev/r0Btn closed!"); + } +} +#endif /* BUTTON_DRIVER_CLOSE */ diff --git a/firmware/target/hosted/ypr0/dir-target.h b/firmware/target/hosted/ypr0/dir-target.h new file mode 100644 index 0000000000..48859526df --- /dev/null +++ b/firmware/target/hosted/ypr0/dir-target.h @@ -0,0 +1,56 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ + +#ifndef __DIR_TARGET_H__ +#define __DIR_TARGET_H__ + +#include +/* including unistd.h is too noisy */ +extern int rmdir(const char* name); + + +#define dirent_uncached dirent +#define DIR_UNCACHED DIR +#define opendir_uncached _opendir +#define readdir_uncached _readdir +#define closedir_uncached _closedir +#define mkdir_uncached _mkdir +#define rmdir_uncached rmdir + +#define dirent_ypr0 dirent +#define DIR_ypr0 DIR +#define opendir_ypr0 _opendir +#define readdir_ypr0 _readdir +#define closedir_ypr0 _closedir +#define mkdir_ypr0 _mkdir +#define rmdir_ypr0 rmdir + +extern DIR* _opendir(const char* name); +extern int _mkdir(const char* name); +extern int _closedir(DIR* dir); +extern struct dirent *_readdir(DIR* dir); +extern void fat_size(unsigned long *size, unsigned long *free); + +#define DIRFUNCTIONS_DEFINED +#define DIRENT_DEFINED +#define DIR_DEFINED + +#endif /* __DIR_TARGET_H__ */ diff --git a/firmware/target/hosted/ypr0/fs-ypr0.c b/firmware/target/hosted/ypr0/fs-ypr0.c new file mode 100644 index 0000000000..7f49a5f91a --- /dev/null +++ b/firmware/target/hosted/ypr0/fs-ypr0.c @@ -0,0 +1,141 @@ +/*************************************************************************** + * __________ __ ___. + * 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 /* stat() */ +#include /* snprintf */ +#include /* size_t */ +#include +#include /* localtime() */ +#include "system-target.h" +#include "dir-target.h" +#include "file.h" +#include "dir.h" +#include "rbpaths.h" + + +long filesize(int fd) +{ + struct stat buf; + + if (!fstat(fd, &buf)) + return buf.st_size; + else + return -1; +} + +/* do we really need this in the app? */ +void fat_size(unsigned long* size, unsigned long* free) +{ + *size = *free = 0; +} + +#undef opendir +#undef closedir +#undef mkdir +#undef readdir + +/* need to wrap around DIR* because we need to save the parent's + * directory path in order to determine dirinfo */ +struct __dir { + DIR *dir; + char *path; +}; + +DIR* _opendir(const char *name) +{ + char *buf = malloc(sizeof(struct __dir) + strlen(name)+1); + if (!buf) + return NULL; + + struct __dir *this = (struct __dir*)buf; + + this->path = buf+sizeof(struct __dir); + /* definitely fits due to strlen() */ + strcpy(this->path, name); + + this->dir = opendir(name); + + if (!this->dir) + { + free(buf); + return NULL; + } + return (DIR*)this; +} + +int _mkdir(const char *name) +{ + return mkdir(name, 0777); +} + +int _closedir(DIR *dir) +{ + struct __dir *this = (struct __dir*)dir; + int ret = closedir(this->dir); + free(this); + return ret; +} + +struct dirent* _readdir(DIR* dir) +{ + struct __dir *d = (struct __dir*)dir; + return readdir(d->dir); +} + +struct dirinfo dir_get_info(DIR* _parent, struct dirent *dir) +{ + struct __dir *parent = (struct __dir*)_parent; + struct stat s; + struct tm *tm = NULL; + struct dirinfo ret; + char path[MAX_PATH]; + + snprintf(path, sizeof(path), "%s/%s", parent->path, dir->d_name); + memset(&ret, 0, sizeof(ret)); + + if (!stat(path, &s)) + { + if (S_ISDIR(s.st_mode)) + { + ret.attribute = ATTR_DIRECTORY; + } + ret.size = s.st_size; + tm = localtime(&(s.st_mtime)); + } + + if (!lstat(path, &s) && S_ISLNK(s.st_mode)) + { + ret.attribute |= ATTR_LINK; + } + + if (tm) + { + ret.wrtdate = ((tm->tm_year - 80) << 9) | + ((tm->tm_mon + 1) << 5) | + tm->tm_mday; + ret.wrttime = (tm->tm_hour << 11) | + (tm->tm_min << 5) | + (tm->tm_sec >> 1); + } + + return ret; +} diff --git a/firmware/target/hosted/ypr0/i2c-target.h b/firmware/target/hosted/ypr0/i2c-target.h new file mode 100644 index 0000000000..3b046bba96 --- /dev/null +++ b/firmware/target/hosted/ypr0/i2c-target.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: i2c-target.h 29516 2011-03-05 15:31:52Z thomasjfox $ + * + * 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. + * + ****************************************************************************/ + +#ifndef __I2C_TARGET_H__ +#define __I2C_TARGET_H__ + +#endif /* __I2C_TARGET_H__ */ diff --git a/firmware/target/hosted/ypr0/kernel-ypr0.c b/firmware/target/hosted/ypr0/kernel-ypr0.c new file mode 100644 index 0000000000..bcf2cee583 --- /dev/null +++ b/firmware/target/hosted/ypr0/kernel-ypr0.c @@ -0,0 +1,163 @@ +/*************************************************************************** + * __________ __ ___. + * 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 +#include +#include +#include +#include "config.h" +#include "system.h" +#include "button.h" +#include "audio.h" +#include "panic.h" +#include "timer.h" + + +static pthread_cond_t wfi_cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t wfi_mtx = PTHREAD_MUTEX_INITIALIZER; +/* + * call tick tasks and wake the scheduler up */ +void timer_signal(union sigval arg) +{ + (void)arg; + call_tick_tasks(); + interrupt(); +} + +/* + * wait on the sem which the signal handler posts to save cpu time (aka sleep) + * + * other mechanisms could use them as well */ +void wait_for_interrupt(void) +{ + pthread_cond_wait(&wfi_cond, &wfi_mtx); +} + +/* + * Wakeup the kernel, if sleeping (shall not be called from a signal handler) */ +void interrupt(void) +{ + pthread_cond_signal(&wfi_cond); +} + + +/* + * setup a hrtimer to send a signal to our process every tick + */ +union sigval tick_arg = { + .sival_int = 0, +}; + +void tick_start(unsigned int interval_in_ms) +{ + int ret = 0; + timer_t timerid; + struct itimerspec ts; + sigevent_t sigev; + + /* initializing in the declaration causes some weird warnings */ + memset(&sigev, 0, sizeof(sigevent_t)); + sigev.sigev_notify = SIGEV_THREAD, + sigev.sigev_notify_function = timer_signal; + + ts.it_value.tv_sec = ts.it_interval.tv_sec = 0; + ts.it_value.tv_nsec = ts.it_interval.tv_nsec = interval_in_ms*1000*1000; + + /* add the timer */ + ret |= timer_create(CLOCK_REALTIME, &sigev, &timerid); + ret |= timer_settime(timerid, 0, &ts, NULL); + + /* Grab the mutex already now and leave it to this thread. We don't + * care about race conditions when signaling the condition (because + * they are not critical), but a mutex is necessary due to the API */ + pthread_mutex_lock(&wfi_mtx); + + if (ret != 0) + panicf("%s(): %s\n", __func__, strerror(errno)); +} + +#define cycles_to_microseconds(cycles) \ + ((int)((1000000*cycles)/TIMER_FREQ)) + + +static timer_t timer_tid; +static int timer_prio = -1; +void (*global_unreg_callback)(void); +void (*global_timer_callback)(void); + +static void timer_cb(union sigval arg) +{ + (void)arg; + if (global_timer_callback) + global_timer_callback(); +} + +bool timer_register(int reg_prio, void (*unregister_callback)(void), + long cycles, void (*timer_callback)(void)) +{ + int ret = 0; + struct itimerspec ts; + sigevent_t sigev; + long in_us = cycles_to_microseconds(cycles); + + if (reg_prio <= timer_prio || in_us <= 0) + return false; + + if (timer_prio >= 0 && global_unreg_callback) + global_unreg_callback(); + + /* initializing in the declaration causes some weird warnings */ + memset(&sigev, 0, sizeof(sigevent_t)); + sigev.sigev_notify = SIGEV_THREAD, + sigev.sigev_notify_function = timer_cb; + + ts.it_value.tv_sec = ts.it_interval.tv_sec = in_us / 1000000; + ts.it_value.tv_nsec = ts.it_interval.tv_nsec = (in_us%1000000)*1000; + + /* add the timer */ + ret |= timer_create(CLOCK_REALTIME, &sigev, &timer_tid); + ret |= timer_settime(timer_tid, 0, &ts, NULL); + + global_timer_callback = timer_callback; + global_unreg_callback = unregister_callback; + timer_prio = reg_prio; + + return ret == 0; +} + +bool timer_set_period(long cycles) +{ + struct itimerspec ts; + long in_us = cycles_to_microseconds(cycles); + ts.it_value.tv_sec = ts.it_interval.tv_sec = in_us / 1000000; + ts.it_value.tv_nsec = ts.it_interval.tv_nsec = (in_us%1000000)*1000; + + return timer_settime(timer_tid, 0, &ts, NULL) == 0; +} + +void timer_unregister(void) +{ + timer_delete(timer_tid); + timer_prio = -1; +} + diff --git a/firmware/target/hosted/ypr0/lc-ypr0.c b/firmware/target/hosted/ypr0/lc-ypr0.c new file mode 100644 index 0000000000..434e901a56 --- /dev/null +++ b/firmware/target/hosted/ypr0/lc-ypr0.c @@ -0,0 +1,40 @@ +/*************************************************************************** + * __________ __ ___. + * 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 /* size_t */ +#include "load_code.h" + +/* the load_code wrappers simply wrap, nothing to do */ +void *lc_open(const char *filename, unsigned char *buf, size_t buf_size) +{ + return _lc_open(filename, buf, buf_size); +} + +void *lc_get_header(void *handle) +{ + return _lc_get_header(handle); +} + +void lc_close(void *handle) +{ + _lc_close(handle); +} + diff --git a/firmware/target/hosted/ypr0/lcd-ypr0.c b/firmware/target/hosted/ypr0/lcd-ypr0.c new file mode 100644 index 0000000000..f0565ae2d4 --- /dev/null +++ b/firmware/target/hosted/ypr0/lcd-ypr0.c @@ -0,0 +1,147 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: lcd-bitmap.c 29248 2011-02-08 20:05:25Z thomasjfox $ + * + * Copyright (C) 2011 Lorenzo Miori, 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 +#include "string.h" +#include +#include +#include + +#include "file.h" +#include "debug.h" +#include "system.h" +#include "screendump.h" +#include "lcd.h" + +/* eqivalent to fb + y*width + x */ +#define LCDADDR(x, y) (&lcd_framebuffer[(y)][(x)]) + +static int dev_fd = 0; +static fb_data *dev_fb = 0; + +void lcd_update(void) +{ + /* update the entire display */ + memcpy(dev_fb, lcd_framebuffer, sizeof(lcd_framebuffer)); +} + +/* Copy Rockbox frame buffer to the mmapped lcd device */ +void lcd_update_rect(int x, int y, int width, int height) +{ + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || + (y >= LCD_HEIGHT) || (x + width <= 0) || (y + height <= 0)) + return; + + /* do the necessary clipping */ + if (x < 0) + { /* clip left */ + width += x; + x = 0; + } + if (y < 0) + { /* clip top */ + height += y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; /* clip right */ + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; /* clip bottom */ + + fb_data* src = LCDADDR(x, y); + fb_data* dst = dev_fb + y*LCD_WIDTH + x; + + if (LCD_WIDTH == width) + { /* optimized full-width update */ + memcpy(dst, src, width * height * sizeof(fb_data)); + } + else + { /* row by row */ + do + { + memcpy(dst, src, width * sizeof(fb_data)); + src += LCD_WIDTH; + dst += LCD_WIDTH; + } while(--height > 0); + } +} + +void lcd_shutdown(void) +{ + printf("FB closed."); + munmap(dev_fb, sizeof(lcd_framebuffer)); + close(dev_fd); +} + +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/fb0", O_RDWR); + if (dev_fd == -1) { + perror("Error: cannot open framebuffer device"); + exit(1); + } + printf("The framebuffer device was opened successfully.\n"); + + /* 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); + } + + vinfo.bits_per_pixel = 16; + + if (ioctl(dev_fd, FBIOPUT_VSCREENINFO, &vinfo)) { + perror("fbset(ioctl)"); + exit(4); + } + + printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel); + + /* Figure out the size of the screen in bytes */ + screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; + if (screensize != sizeof(lcd_framebuffer)) + { + 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); + } + printf("The framebuffer device was mapped to memory successfully.\n"); +} diff --git a/firmware/target/hosted/ypr0/powermgmt-ypr0.c b/firmware/target/hosted/ypr0/powermgmt-ypr0.c new file mode 100644 index 0000000000..5701e9f02f --- /dev/null +++ b/firmware/target/hosted/ypr0/powermgmt-ypr0.c @@ -0,0 +1,133 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: powermgmt-sim.c 29543 2011-03-08 19:33:30Z thomasjfox $ + * + * 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 +#include "kernel.h" +#include "powermgmt.h" +#include "ascodec-target.h" +#include "stdio.h" + +#if 0 /*still unused*/ +/* The battery manufacturer's website shows discharge curves down to 3.0V, + so 'dangerous' and 'shutoff' levels of 3.4V and 3.3V should be safe. + */ +const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] = +{ + 3550 +}; + +const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] = +{ + 3450 +}; + +/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */ +const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] = +{ + { 3300, 3692, 3740, 3772, 3798, 3828, 3876, 3943, 4013, 4094, 4194 } +}; + +#if CONFIG_CHARGING +/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */ +const unsigned short percent_to_volt_charge[11] = +{ + 3417, 3802, 3856, 3888, 3905, 3931, 3973, 4025, 4084, 4161, 4219 +}; +#endif /* CONFIG_CHARGING */ +#endif + +#define BATT_MINMVOLT 3450 /* minimum millivolts of battery */ +#define BATT_MAXMVOLT 4150 /* maximum millivolts of battery */ +#define BATT_MAXRUNTIME (10 * 60) /* maximum runtime with full battery in + minutes */ + +extern void send_battery_level_event(void); +extern int last_sent_battery_level; +extern int battery_percent; + +static unsigned int battery_millivolts = BATT_MAXMVOLT; +/* estimated remaining time in minutes */ +static int powermgmt_est_runningtime_min = BATT_MAXRUNTIME; + +static void battery_status_update(void) +{ + static time_t last_change = 0; + time_t now; + + time(&now); + + if (last_change < now) { + last_change = now; + + battery_percent = 100 * (battery_millivolts - BATT_MINMVOLT) / + (BATT_MAXMVOLT - BATT_MINMVOLT); + + powermgmt_est_runningtime_min = + battery_percent * BATT_MAXRUNTIME / 100; + } + + send_battery_level_event(); +} + +void battery_read_info(int *voltage, int *level) +{ + battery_status_update(); + + if (voltage) + *voltage = battery_millivolts; + + if (level) + *level = battery_percent; +} + +unsigned int battery_voltage(void) +{ + battery_status_update(); + return battery_millivolts; +} + +int battery_level(void) +{ + battery_status_update(); + return battery_percent; +} + +int battery_time(void) +{ + battery_status_update(); + return powermgmt_est_runningtime_min; +} + +bool battery_level_safe(void) +{ + return battery_level() >= 10; +} + +void set_battery_capacity(int capacity) +{ + (void)capacity; +} + +#if BATTERY_TYPES_COUNT > 1 +void set_battery_type(int type) +{ + (void)type; +} +#endif diff --git a/firmware/target/hosted/ypr0/system-target.h b/firmware/target/hosted/ypr0/system-target.h new file mode 100644 index 0000000000..07a3163ea9 --- /dev/null +++ b/firmware/target/hosted/ypr0/system-target.h @@ -0,0 +1,37 @@ +/*************************************************************************** + * __________ __ ___. + * 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. + * + ****************************************************************************/ +#ifndef __SYSTEM_TARGET_H__ +#define __SYSTEM_TARGET_H__ + +#define disable_irq() +#define enable_irq() +#define disable_irq_save() 0 +#define restore_irq(level) (void)level + +void wait_for_interrupt(void); +void interrupt(void); + +static inline void commit_dcache(void) {} +static inline void commit_discard_dcache(void) {} +static inline void commit_discard_idcache(void) {} + +#define NEED_GENERIC_BYTESWAPS +#endif /* __SYSTEM_TARGET_H__ */ diff --git a/firmware/target/hosted/ypr0/system-ypr0.c b/firmware/target/hosted/ypr0/system-ypr0.c new file mode 100644 index 0000000000..3a2b30339f --- /dev/null +++ b/firmware/target/hosted/ypr0/system-ypr0.c @@ -0,0 +1,106 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: system-sdl.c 29925 2011-05-25 20:11:03Z thomasjfox $ + * + * Copyright (C) 2006 by Daniel Everton + * + * 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 "system.h" +#include "panic.h" +#include "debug.h" + +#if defined(HAVE_SDL_AUDIO) || defined(HAVE_SDL_THREADS) || defined(HAVE_SDL) +#include +#endif + +#include "ascodec-target.h" + +void sim_do_exit(void) +{ + exit(EXIT_SUCCESS); +} + +void shutdown_hw(void) +{ + /* Something that we need to do before exit on our platform YPR0 */ + ascodec_close(); + sim_do_exit(); +} + +uintptr_t *stackbegin; +uintptr_t *stackend; +void system_init(void) +{ + int *s; + /* fake stack, OS manages size (and growth) */ + stackbegin = stackend = (uintptr_t*)&s; + +#if defined(HAVE_SDL_AUDIO) || defined(HAVE_SDL_THREADS) || defined(HAVE_SDL) + SDL_Init(0); /* need this if using any SDL subsystem */ +#endif + /* Here begins our platform specific initilization for various things */ + ascodec_init(); +} + + +void system_reboot(void) +{ + sim_do_exit(); +} + +void system_exception_wait(void) +{ + system_reboot(); +} + +#ifdef HAVE_ADJUSTABLE_CPU_FREQ +#include +#include "file.h" +/* This is the Linux Kernel CPU governor... */ +static void set_cpu_freq(int speed) +{ + char temp[10]; + int cpu_dev; + cpu_dev = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed", O_WRONLY); + if (cpu_dev < 0) + return; + write(cpu_dev, temp, sprintf(temp, "%d", speed) + 1); + close(cpu_dev); +} + +void set_cpu_frequency(long frequency) +{ + switch (frequency) + { + case CPUFREQ_MAX: + set_cpu_freq(532000); + cpu_frequency = CPUFREQ_MAX; + break; + case CPUFREQ_NORMAL: + set_cpu_freq(400000); + cpu_frequency = CPUFREQ_NORMAL; + break; + default: + set_cpu_freq(200000); + cpu_frequency = CPUFREQ_DEFAULT; + break; + } +} +#endif diff --git a/firmware/target/hosted/ypr0/usb-target.h b/firmware/target/hosted/ypr0/usb-target.h new file mode 100644 index 0000000000..237d179775 --- /dev/null +++ b/firmware/target/hosted/ypr0/usb-target.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id: usb-target.h 29516 2011-03-05 15:31:52Z thomasjfox $ + * + * 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. + * + ****************************************************************************/ + +#ifndef __USB_TARGET_H__ +#define __USB_TARGET_H__ + +#endif /* __USB_TARGET_H__ */ diff --git a/firmware/target/hosted/ypr0/ypr0.make b/firmware/target/hosted/ypr0/ypr0.make new file mode 100644 index 0000000000..c2114878db --- /dev/null +++ b/firmware/target/hosted/ypr0/ypr0.make @@ -0,0 +1,25 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +INCLUDES += -I$(FIRMDIR)/include -I$(FIRMDIR)/export $(TARGET_INC) -I$(BUILDDIR) -I$(APPSDIR) + +SIMFLAGS += $(INCLUDES) $(DEFINES) -DHAVE_CONFIG_H $(GCCOPTS) + +.SECONDEXPANSION: # $$(OBJ) is not populated until after this + + +$(BUILDDIR)/rockbox.elf : $$(OBJ) $$(FIRMLIB) $$(VOICESPEEXLIB) $$(SKINLIB) + $(call PRINTS,LD $(@F))$(CC) $(GCCOPTS) -Os -o $@ $(OBJ) \ + -L$(BUILDDIR)/firmware -lfirmware \ + -L$(BUILDDIR)/apps/codecs $(VOICESPEEXLIB:lib%.a=-l%) \ + -L$(BUILDDIR)/lib -lskin_parser \ + $(LDOPTS) $(GLOBAL_LDOPTS) -Wl,-Map,$(BUILDDIR)/rockbox.map + +$(BUILDDIR)/rockbox : $(BUILDDIR)/rockbox.elf + $(call PRINTS,OC $(@F))$(OC) -S -x $< $@ -- cgit v1.2.3