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/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 ++ 19 files changed, 2013 insertions(+) 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/target/hosted') 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