rockbox/firmware/target/arm/sandisk/sansa-e200/button-e200.c
Daniel Stenberg 2acc0ac542 Updated our source code header to explicitly mention that we are GPL v2 or
later. We still need to hunt down snippets used that are not. 1324 modified
files...
http://www.rockbox.org/mail/archive/rockbox-dev-archive-2008-06/0060.shtml


git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17847 a1c6a512-1295-4272-9138-f99709370657
2008-06-28 18:10:04 +00:00

286 lines
8.8 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 by Barry Wardell
*
* 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.
*
****************************************************************************/
/* Taken from button-h10.c by Barry Wardell and reverse engineering by MrH. */
#include "system.h"
#include "button.h"
#include "backlight.h"
#include "powermgmt.h"
#define WHEEL_REPEAT_INTERVAL 300000
#define WHEEL_FAST_ON_INTERVAL 20000
#define WHEEL_FAST_OFF_INTERVAL 60000
#define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */
/* Clickwheel */
#ifndef BOOTLOADER
static unsigned int old_wheel_value = 0;
static unsigned int wheel_repeat = BUTTON_NONE;
static unsigned int wheel_click_count = 0;
static unsigned int wheel_delta = 0;
static int wheel_fast_mode = 0;
static unsigned long last_wheel_usec = 0;
static unsigned long wheel_velocity = 0;
static long last_wheel_post = 0;
static long next_backlight_on = 0;
/* Buttons */
static bool hold_button = false;
static bool hold_button_old = false;
#define _button_hold() hold_button
#else
#define _button_hold() ((GPIOF_INPUT_VAL & 0x80) != 0)
#endif /* BOOTLOADER */
static int int_btn = BUTTON_NONE;
void button_int(void);
void button_init_device(void)
{
/* Enable all buttons */
GPIOF_OUTPUT_EN &= ~0xff;
GPIOF_ENABLE |= 0xff;
/* Scrollwheel light - enable control through GPIOG pin 7 and set timeout */
GPIOG_OUTPUT_EN |= 0x80;
GPIOG_ENABLE = 0x80;
#ifndef BOOTLOADER
/* Mask these before performing init ... because init has possibly
occurred before */
GPIOF_INT_EN &= ~0xff;
GPIOH_INT_EN &= ~0xc0;
/* Get current tick before enabling button interrupts */
last_wheel_usec = USEC_TIMER;
last_wheel_post = last_wheel_usec;
GPIOH_ENABLE |= 0xc0;
GPIOH_OUTPUT_EN &= ~0xc0;
/* Read initial buttons */
button_int();
GPIOF_INT_CLR = 0xff;
/* Read initial wheel value (bit 6-7 of GPIOH) */
old_wheel_value = GPIOH_INPUT_VAL & 0xc0;
GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (old_wheel_value ^ 0xc0);
GPIOH_INT_CLR = 0xc0;
/* Enable button interrupts */
GPIOF_INT_EN |= 0xff;
GPIOH_INT_EN |= 0xc0;
CPU_INT_EN = HI_MASK;
CPU_HI_INT_EN = GPIO1_MASK;
#endif /* BOOTLOADER */
}
bool button_hold(void)
{
return _button_hold();
}
/* clickwheel */
#ifndef BOOTLOADER
void clickwheel_int(void)
{
/* Read wheel
* Bits 6 and 7 of GPIOH change as follows:
* Clockwise rotation 01 -> 00 -> 10 -> 11
* Counter-clockwise 11 -> 10 -> 00 -> 01
*
* This is equivalent to wheel_value of:
* Clockwise rotation 0x40 -> 0x00 -> 0x80 -> 0xc0
* Counter-clockwise 0xc0 -> 0x80 -> 0x00 -> 0x40
*/
static const unsigned char wheel_tbl[2][4] =
{
/* 0x00 0x40 0x80 0xc0 */ /* Wheel value */
{ 0x40, 0xc0, 0x00, 0x80 }, /* Clockwise rotation */
{ 0x80, 0x00, 0xc0, 0x40 }, /* Counter-clockwise */
};
unsigned int wheel_value;
wheel_value = GPIOH_INPUT_VAL & 0xc0;
GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (wheel_value ^ 0xc0);
GPIOH_INT_CLR = GPIOH_INT_STAT & 0xc0;
if (!hold_button)
{
unsigned int btn = BUTTON_NONE;
if (old_wheel_value == wheel_tbl[0][wheel_value >> 6])
btn = BUTTON_SCROLL_FWD;
else if (old_wheel_value == wheel_tbl[1][wheel_value >> 6])
btn = BUTTON_SCROLL_BACK;
if (btn != BUTTON_NONE)
{
int repeat = 1; /* assume repeat */
unsigned long usec = USEC_TIMER;
unsigned v = (usec - last_wheel_usec) & 0x7fffffff;
v = (v>0) ? 1000000 / v : 0; /* clicks/sec = 1000000 * clicks/usec */
v = (v>0xffffff) ? 0xffffff : v; /* limit to 24 bit */
/* some velocity filtering to smooth things out */
wheel_velocity = (7*wheel_velocity + v) / 8;
if (btn != wheel_repeat)
{
/* direction reversals nullify all fast mode states */
wheel_repeat = btn;
repeat =
wheel_fast_mode =
wheel_velocity =
wheel_click_count = 0;
}
if (wheel_fast_mode != 0)
{
/* fast OFF happens immediately when velocity drops below
threshold */
if (TIME_AFTER(usec,
last_wheel_usec + WHEEL_FAST_OFF_INTERVAL))
{
/* moving out of fast mode */
wheel_fast_mode = 0;
/* reset velocity */
wheel_velocity = 0;
/* wheel_delta is always 1 in slow mode */
wheel_delta = 1;
}
}
else
{
/* fast ON gets filtered to avoid inadvertent jumps to fast mode */
if (repeat && wheel_velocity > 1000000/WHEEL_FAST_ON_INTERVAL)
{
/* moving into fast mode */
wheel_fast_mode = 1 << 31;
wheel_click_count = 0;
wheel_velocity = 1000000/WHEEL_FAST_OFF_INTERVAL;
}
else if (++wheel_click_count < 2)
{
btn = BUTTON_NONE;
}
/* wheel_delta is always 1 in slow mode */
wheel_delta = 1;
}
if (TIME_AFTER(current_tick, next_backlight_on) ||
v <= 4)
{
/* poke backlight to turn it on or maintain it no more often
than every 1/4 second*/
next_backlight_on = current_tick + HZ/4;
backlight_on();
buttonlight_on();
reset_poweroff_timer();
}
if (btn != BUTTON_NONE)
{
wheel_click_count = 0;
/* generate repeats if quick enough */
if (repeat && TIME_BEFORE(usec,
last_wheel_post + WHEEL_REPEAT_INTERVAL))
btn |= BUTTON_REPEAT;
last_wheel_post = usec;
if (queue_empty(&button_queue))
{
queue_post(&button_queue, btn, wheel_fast_mode |
(wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION);
/* message posted - reset delta */
wheel_delta = 1;
}
else
{
/* skipped post - increment delta */
if (++wheel_delta > 0x7f)
wheel_delta = 0x7f;
}
}
last_wheel_usec = usec;
}
}
old_wheel_value = wheel_value;
}
#endif /* BOOTLOADER */
/* device buttons */
void button_int(void)
{
unsigned char state;
int_btn = BUTTON_NONE;
state = GPIOF_INPUT_VAL & 0xff;
#ifndef BOOTLOADER
GPIOF_INT_LEV = (GPIOF_INT_LEV & ~0xff) | (state ^ 0xff);
GPIOF_INT_CLR = GPIOF_INT_STAT;
hold_button = (state & 0x80) != 0;
#endif
if (!_button_hold())
{
/* Read normal buttons */
if ((state & 0x01) == 0) int_btn |= BUTTON_REC;
if ((state & 0x02) == 0) int_btn |= BUTTON_DOWN;
if ((state & 0x04) == 0) int_btn |= BUTTON_RIGHT;
if ((state & 0x08) == 0) int_btn |= BUTTON_LEFT;
if ((state & 0x10) == 0) int_btn |= BUTTON_SELECT; /* The centre button */
if ((state & 0x20) == 0) int_btn |= BUTTON_UP; /* The "play" button */
if ((state & 0x40) != 0) int_btn |= BUTTON_POWER;
}
}
/*
* Get button pressed from hardware
*/
int button_read_device(void)
{
#ifdef BOOTLOADER
/* Read buttons directly in the bootloader */
button_int();
#else
/* light handling */
if (hold_button != hold_button_old)
{
hold_button_old = hold_button;
backlight_hold_changed(hold_button);
}
#endif /* BOOTLOADER */
/* The int_btn variable is set in the button interrupt handler */
return int_btn;
}