Gigabeat S: Add remote control reading and proper headphone insert detection. We need keymaps! A few were copied straight from Gigabeat F/X just to get things worked out.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19830 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
34314b1993
commit
753b7a90e1
6 changed files with 290 additions and 23 deletions
|
@ -309,8 +309,72 @@ static const struct button_mapping button_context_radio[] = {
|
|||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* Remote control mappings
|
||||
*****************************************************************************/
|
||||
static const struct button_mapping remote_button_context_standard[] = {
|
||||
{ ACTION_STD_PREV, BUTTON_RC_VOL_UP, BUTTON_NONE },
|
||||
{ ACTION_STD_PREVREPEAT, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ ACTION_STD_NEXT, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
|
||||
{ ACTION_STD_NEXTREPEAT, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ ACTION_STD_CANCEL, BUTTON_RC_REW, BUTTON_NONE },
|
||||
{ ACTION_STD_OK, BUTTON_RC_FF|BUTTON_REL, BUTTON_RC_FF },
|
||||
{ ACTION_STD_CONTEXT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_RC_FF },
|
||||
{ ACTION_STD_MENU, BUTTON_RC_DSP, BUTTON_NONE },
|
||||
|
||||
LAST_ITEM_IN_LIST
|
||||
};
|
||||
|
||||
static const struct button_mapping remote_button_context_wps[] = {
|
||||
{ ACTION_WPS_PLAY, BUTTON_RC_PLAY, BUTTON_NONE },
|
||||
|
||||
{ ACTION_WPS_SKIPNEXT, BUTTON_RC_FF|BUTTON_REL, BUTTON_RC_FF },
|
||||
{ ACTION_WPS_SKIPPREV, BUTTON_RC_REW|BUTTON_REL, BUTTON_RC_REW },
|
||||
|
||||
{ ACTION_WPS_SEEKBACK, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ ACTION_WPS_SEEKFWD, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ ACTION_WPS_STOPSEEK, BUTTON_RC_REW|BUTTON_REL, BUTTON_RC_REW|BUTTON_REPEAT },
|
||||
{ ACTION_WPS_STOPSEEK, BUTTON_RC_FF|BUTTON_REL, BUTTON_RC_FF|BUTTON_REPEAT },
|
||||
|
||||
{ ACTION_WPS_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_RC_PLAY },
|
||||
{ ACTION_WPS_MENU, BUTTON_RC_DSP, BUTTON_NONE },
|
||||
|
||||
{ ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
|
||||
{ ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
|
||||
{ ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP, BUTTON_NONE },
|
||||
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
};
|
||||
|
||||
static const struct button_mapping remote_button_context_tree[] = {
|
||||
{ ACTION_TREE_WPS, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY },
|
||||
{ ACTION_TREE_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_RC_PLAY },
|
||||
{ ACTION_STD_CANCEL, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE },
|
||||
|
||||
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
|
||||
};
|
||||
|
||||
static const struct button_mapping* get_context_mapping_remote( int context )
|
||||
{
|
||||
context ^= CONTEXT_REMOTE;
|
||||
|
||||
switch (context)
|
||||
{
|
||||
case CONTEXT_WPS:
|
||||
return remote_button_context_wps;
|
||||
case CONTEXT_MAINMENU:
|
||||
case CONTEXT_TREE:
|
||||
return remote_button_context_tree;
|
||||
}
|
||||
return remote_button_context_standard;
|
||||
}
|
||||
|
||||
const struct button_mapping* get_context_mapping(int context)
|
||||
{
|
||||
if (context&CONTEXT_REMOTE)
|
||||
return get_context_mapping_remote(context);
|
||||
|
||||
switch (context)
|
||||
{
|
||||
case CONTEXT_STD:
|
||||
|
|
|
@ -774,6 +774,7 @@ target/arm/imx31/gigabeat-s/wmcodec-imx31.c
|
|||
#ifndef BOOTLOADER
|
||||
target/arm/imx31/gigabeat-s/audio-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/fmradio-i2c-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
|
||||
target/arm/imx31/gigabeat-s/pcm-imx31.c
|
||||
target/arm/imx31/gigabeat-s/timer-imx31.c
|
||||
#endif
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
#define GPIO_EVENT_MASK (USE_GPIO1_EVENTS)
|
||||
|
||||
/* Define this if target has an additional number of threads specific to it */
|
||||
#define TARGET_EXTRA_THREADS 1
|
||||
#define TARGET_EXTRA_THREADS 2
|
||||
|
||||
/* Type of mobile power - check this out */
|
||||
#define BATTERY_CAPACITY_DEFAULT 700 /* default battery capacity */
|
||||
|
|
|
@ -32,9 +32,6 @@
|
|||
|
||||
/* Most code in here is taken from the Linux BSP provided by Freescale
|
||||
* Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
static bool headphones_detect = false;
|
||||
#endif
|
||||
static uint32_t int_btn = BUTTON_NONE;
|
||||
static bool hold_button = false;
|
||||
#ifdef BOOTLOADER
|
||||
|
@ -123,6 +120,16 @@ bool button_hold(void)
|
|||
return _button_hold();
|
||||
}
|
||||
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
/* Headphone driver pushes the data here */
|
||||
void button_headphone_set(int button)
|
||||
{
|
||||
int oldstatus = disable_irq_save();
|
||||
int_btn = (int_btn & ~BUTTON_REMOTE) | button;
|
||||
restore_irq(oldstatus);
|
||||
}
|
||||
#endif
|
||||
|
||||
int button_read_device(void)
|
||||
{
|
||||
/* Simple poll of GPIO status */
|
||||
|
@ -168,21 +175,6 @@ void button_power_event(void)
|
|||
restore_irq(oldlevel);
|
||||
}
|
||||
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
void headphone_detect_event(void)
|
||||
{
|
||||
/* FIXME: Not really the correct method */
|
||||
headphones_detect =
|
||||
(mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD2S) == 0;
|
||||
}
|
||||
|
||||
bool headphones_inserted(void)
|
||||
{
|
||||
return headphones_detect;
|
||||
}
|
||||
#endif /* HAVE_HEADPHONE_DETECTION */
|
||||
|
||||
void button_init_device(void)
|
||||
{
|
||||
#ifdef BOOTLOADER
|
||||
|
@ -223,8 +215,7 @@ void button_init_device(void)
|
|||
mc13783_enable_event(MC13783_ONOFD1_EVENT);
|
||||
|
||||
#ifdef HAVE_HEADPHONE_DETECTION
|
||||
headphone_detect_event();
|
||||
mc13783_enable_event(MC13783_ONOFD2_EVENT);
|
||||
headphone_init();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,8 @@ int button_read_device(void);
|
|||
void button_power_event(void);
|
||||
void headphone_detect_event(void);
|
||||
bool headphones_inserted(void);
|
||||
void headphone_init(void);
|
||||
void button_headphone_set(int button);
|
||||
|
||||
/* Toshiba Gigabeat S-specific button codes */
|
||||
|
||||
|
@ -55,9 +57,17 @@ bool headphones_inserted(void);
|
|||
#define BUTTON_NEXT (1 << 11)
|
||||
#define BUTTON_POWER (1 << 12) /* Read from PMIC */
|
||||
|
||||
#define BUTTON_MAIN (0x1fff)
|
||||
#define BUTTON_MAIN (0x00001fff)
|
||||
|
||||
#define BUTTON_REMOTE 0
|
||||
/* Remote control buttons */
|
||||
#define BUTTON_RC_VOL_UP (1 << 13)
|
||||
#define BUTTON_RC_VOL_DOWN (1 << 14)
|
||||
#define BUTTON_RC_FF (1 << 15)
|
||||
#define BUTTON_RC_REW (1 << 16)
|
||||
#define BUTTON_RC_PLAY (1 << 17)
|
||||
#define BUTTON_RC_DSP (1 << 18)
|
||||
|
||||
#define BUTTON_REMOTE (0x0007e000)
|
||||
|
||||
#define POWEROFF_BUTTON BUTTON_POWER
|
||||
#define POWEROFF_COUNT 10
|
||||
|
|
201
firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
Normal file
201
firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c
Normal file
|
@ -0,0 +1,201 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (c) 2009 by Michael Sevakis
|
||||
*
|
||||
* Driver to handle headphone jack events
|
||||
*
|
||||
* 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 "kernel.h"
|
||||
#include "thread.h"
|
||||
#include "mc13783.h"
|
||||
#include "mc13783-target.h"
|
||||
#include "adc.h"
|
||||
#include "button.h"
|
||||
|
||||
static struct wakeup headphone_wakeup;
|
||||
static unsigned int headphone_thread_id;
|
||||
static int headphone_stack[160/sizeof(int)]; /* Not much stack needed */
|
||||
static const char * const headphone_thread_name = "headphone";
|
||||
static bool headphones_detect = false;
|
||||
|
||||
/* Convert ADC reading into a button value. */
|
||||
static int adc_data_to_button(unsigned int data)
|
||||
{
|
||||
int btn = BUTTON_NONE;
|
||||
|
||||
if (data < 505)
|
||||
{
|
||||
if (data < 252)
|
||||
{
|
||||
if (data < 149)
|
||||
{
|
||||
if (data >= 64)
|
||||
{
|
||||
/* Play/Pause */
|
||||
btn = BUTTON_RC_PLAY;
|
||||
}
|
||||
/* else headphone direct */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* DSP */
|
||||
btn = BUTTON_RC_DSP;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data < 370)
|
||||
{
|
||||
/* RW */
|
||||
btn = BUTTON_RC_REW;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FF */
|
||||
btn = BUTTON_RC_FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data < 870)
|
||||
{
|
||||
if (data < 675)
|
||||
{
|
||||
/* Vol + */
|
||||
btn = BUTTON_RC_VOL_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Vol - */
|
||||
btn = BUTTON_RC_VOL_DOWN;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
|
||||
if (data < 951)
|
||||
{
|
||||
/* No buttons */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Not inserted */
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
static void headphone_thread(void)
|
||||
{
|
||||
int headphone_sleep_countdown = 0;
|
||||
int headphone_wait_timeout = TIMEOUT_BLOCK;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int rc = wakeup_wait(&headphone_wakeup, headphone_wait_timeout);
|
||||
unsigned int data = adc_read(ADC_HPREMOTE);
|
||||
|
||||
if (rc == OBJ_WAIT_TIMEDOUT)
|
||||
{
|
||||
if (headphone_sleep_countdown <= 0)
|
||||
{
|
||||
/* Polling ADC */
|
||||
int btn, btn2;
|
||||
|
||||
btn = adc_data_to_button(data);
|
||||
sleep(HZ/50);
|
||||
data = adc_read(ADC_HPREMOTE);
|
||||
btn2 = adc_data_to_button(data);
|
||||
|
||||
if (btn != btn2)
|
||||
{
|
||||
/* If the buttons dont agree twice in a row, then it's
|
||||
* none (from meg-fx remote reader). */
|
||||
btn = BUTTON_NONE;
|
||||
}
|
||||
|
||||
button_headphone_set(btn);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (--headphone_sleep_countdown == 0)
|
||||
{
|
||||
/* Nothing has changed and remote is not present -
|
||||
* go to sleep. */
|
||||
headphone_wait_timeout = TIMEOUT_BLOCK;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
headphones_detect = data <= 951; /* Max remote value */
|
||||
|
||||
/* Cancel any buttons if jack readings are unstable. */
|
||||
button_headphone_set(BUTTON_NONE);
|
||||
|
||||
if (data >= 64 && data <= 951)
|
||||
{
|
||||
/* Should be a remote control - accelerate */
|
||||
headphone_wait_timeout = HZ/20-HZ/50;
|
||||
headphone_sleep_countdown = 0;
|
||||
}
|
||||
else if (rc == OBJ_WAIT_SUCCEEDED)
|
||||
{
|
||||
/* Got signaled - something is being plugged/unplugged. Set
|
||||
* countdown until we just give up and go to sleep (~10s). */
|
||||
headphone_wait_timeout = HZ/2;
|
||||
headphone_sleep_countdown = 10*2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* This is called from the mc13783 interrupt thread */
|
||||
void headphone_detect_event(void)
|
||||
{
|
||||
/* Trigger the thread immediately. */
|
||||
wakeup_signal(&headphone_wakeup);
|
||||
}
|
||||
|
||||
/* Tell if anything is in the jack. */
|
||||
bool headphones_inserted(void)
|
||||
{
|
||||
return headphones_detect;
|
||||
}
|
||||
|
||||
void headphone_init(void)
|
||||
{
|
||||
/* A thread is required to monitor the remote ADC and jack state. */
|
||||
wakeup_init(&headphone_wakeup);
|
||||
headphone_thread_id = create_thread(headphone_thread,
|
||||
headphone_stack,
|
||||
sizeof(headphone_stack),
|
||||
0, headphone_thread_name
|
||||
IF_PRIO(, PRIORITY_REALTIME)
|
||||
IF_COP(, CPU));
|
||||
|
||||
/* Initially poll and then enable PMIC event */
|
||||
headphone_detect_event();
|
||||
mc13783_enable_event(MC13783_ONOFD2_EVENT);
|
||||
}
|
Loading…
Reference in a new issue