summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/keymaps/keymap-e200.c10
-rw-r--r--firmware/export/pp5024.h6
-rw-r--r--firmware/target/arm/sandisk/sansa-e200/button-e200.c270
-rw-r--r--firmware/target/arm/system-pp502x.c30
4 files changed, 213 insertions, 103 deletions
diff --git a/apps/keymaps/keymap-e200.c b/apps/keymaps/keymap-e200.c
index 8e11cadb8b..c946b5feca 100644
--- a/apps/keymaps/keymap-e200.c
+++ b/apps/keymaps/keymap-e200.c
@@ -31,9 +31,9 @@
31 * Insert LAST_ITEM_IN_LIST at the end of each mapping 31 * Insert LAST_ITEM_IN_LIST at the end of each mapping
32 */ 32 */
33static const struct button_mapping button_context_standard[] = { 33static const struct button_mapping button_context_standard[] = {
34 { ACTION_STD_PREV, BUTTON_SCROLL_UP|BUTTON_REL, BUTTON_NONE }, 34 { ACTION_STD_PREV, BUTTON_SCROLL_UP, BUTTON_NONE },
35 { ACTION_STD_PREVREPEAT, BUTTON_SCROLL_UP|BUTTON_REPEAT, BUTTON_NONE }, 35 { ACTION_STD_PREVREPEAT, BUTTON_SCROLL_UP|BUTTON_REPEAT, BUTTON_NONE },
36 { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN|BUTTON_REL, BUTTON_NONE }, 36 { ACTION_STD_NEXT, BUTTON_SCROLL_DOWN, BUTTON_NONE },
37 { ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, 37 { ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
38 38
39 { ACTION_STD_MENU, BUTTON_POWER|BUTTON_REL, BUTTON_POWER }, 39 { ACTION_STD_MENU, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
@@ -159,9 +159,9 @@ static const struct button_mapping button_context_quickscreen[] = {
159}; /* button_context_quickscreen */ 159}; /* button_context_quickscreen */
160 160
161static const struct button_mapping button_context_settings_right_is_inc[] = { 161static const struct button_mapping button_context_settings_right_is_inc[] = {
162 { ACTION_SETTINGS_INC, BUTTON_SCROLL_DOWN|BUTTON_REL, BUTTON_NONE }, 162 { ACTION_SETTINGS_INC, BUTTON_SCROLL_DOWN, BUTTON_NONE },
163 { ACTION_SETTINGS_INCREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE }, 163 { ACTION_SETTINGS_INCREPEAT, BUTTON_SCROLL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
164 { ACTION_SETTINGS_DEC, BUTTON_SCROLL_UP|BUTTON_REL, BUTTON_NONE }, 164 { ACTION_SETTINGS_DEC, BUTTON_SCROLL_UP, BUTTON_NONE },
165 { ACTION_SETTINGS_DECREPEAT, BUTTON_SCROLL_UP|BUTTON_REPEAT,BUTTON_NONE }, 165 { ACTION_SETTINGS_DECREPEAT, BUTTON_SCROLL_UP|BUTTON_REPEAT,BUTTON_NONE },
166 166
167 { ACTION_STD_PREV, BUTTON_UP|BUTTON_REL, BUTTON_NONE }, 167 { ACTION_STD_PREV, BUTTON_UP|BUTTON_REL, BUTTON_NONE },
diff --git a/firmware/export/pp5024.h b/firmware/export/pp5024.h
index 3ed3d5dade..b9238ae98d 100644
--- a/firmware/export/pp5024.h
+++ b/firmware/export/pp5024.h
@@ -23,4 +23,10 @@
23 completely */ 23 completely */
24#include "pp5020.h" 24#include "pp5020.h"
25 25
26#undef GPIO_IRQ
27#define GPIO_IRQ (32+6)
28
29#undef GPIO_MASK
30#define GPIO_MASK (1 << (GPIO_IRQ-32))
31
26#endif 32#endif
diff --git a/firmware/target/arm/sandisk/sansa-e200/button-e200.c b/firmware/target/arm/sandisk/sansa-e200/button-e200.c
index 028a76f7a8..168332e3c1 100644
--- a/firmware/target/arm/sandisk/sansa-e200/button-e200.c
+++ b/firmware/target/arm/sandisk/sansa-e200/button-e200.c
@@ -23,26 +23,193 @@
23#include "button.h" 23#include "button.h"
24#include "backlight.h" 24#include "backlight.h"
25 25
26static unsigned int old_wheel_value = 0; 26#define WHEEL_REPEAT_INTERVAL 30
27static unsigned int wheel_repeat = BUTTON_NONE; 27#define WHEEL_FAST_ON_INTERVAL 2
28#define WHEEL_FAST_OFF_INTERVAL 6
29
30/* Clickwheel */
31static unsigned int old_wheel_value = 0;
32static unsigned int wheel_repeat = BUTTON_NONE;
33static unsigned int wheel_click_count = 0;
34static int wheel_fast_mode = 0;
35static unsigned long last_wheel_tick = 0;
36static unsigned long last_wheel_post = 0;
37#ifndef BOOTLOADER
38static unsigned long next_backlight_on = 0;
39#endif
40/* Buttons */
41static bool hold_button = false;
42static bool hold_button_old = false;
43static int int_btn = BUTTON_NONE;
28 44
29void button_init_device(void) 45void button_init_device(void)
30{ 46{
31 /* Enable all buttons */ 47 /* Enable all buttons */
48 GPIOF_OUTPUT_EN &= ~0xff;
32 GPIOF_ENABLE |= 0xff; 49 GPIOF_ENABLE |= 0xff;
33 GPIOH_ENABLE |= 0xc0;
34 50
35 /* Scrollwheel light - enable control through GPIOG pin 7 and set timeout */ 51 /* Scrollwheel light - enable control through GPIOG pin 7 and set timeout */
36 GPIOG_ENABLE = 0x80;
37 GPIOG_OUTPUT_EN |= 0x80; 52 GPIOG_OUTPUT_EN |= 0x80;
38 53 GPIOG_ENABLE = 0x80;
54
55 GPIOH_ENABLE |= 0xc0;
56 GPIOH_OUTPUT_EN &= ~0xc0;
57
58#if 0
59 CPU_INT_PRIORITY &= ~HI_MASK;
60 CPU_HI_INT_PRIORITY &= ~GPIO_MASK;
61
62 CPU_INT_CLR = HI_MASK;
63 CPU_HI_INT_CLR = GPIO_MASK;
64#endif
65 GPIOF_INT_CLR = 0xff;
66 GPIOH_INT_CLR = 0xc0;
67
68 /* Read initial buttons */
69 old_wheel_value = GPIOF_INPUT_VAL & 0xff;
70 GPIOF_INT_LEV = (GPIOF_INT_LEV & ~0xff) | (old_wheel_value ^ 0xff);
71 hold_button = (GPIOF_INPUT_VAL & 0x80) != 0;
72
39 /* Read initial wheel value (bit 6-7 of GPIOH) */ 73 /* Read initial wheel value (bit 6-7 of GPIOH) */
40 old_wheel_value = GPIOH_INPUT_VAL & 0xc0; 74 old_wheel_value = GPIOH_INPUT_VAL & 0xc0;
75 GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (old_wheel_value ^ 0xc0);
76
77 GPIOF_INT_EN = 0xff;
78 GPIOH_INT_EN = 0xc0;
79#if 0
80 CPU_HI_INT_EN = GPIO_MASK;
81 CPU_INT_EN = HI_MASK;
82#endif
83
84 last_wheel_tick = current_tick;
85 last_wheel_post = current_tick;
41} 86}
42 87
43bool button_hold(void) 88bool button_hold(void)
44{ 89{
45 return (GPIOF_INPUT_VAL & 0x80)?true:false; 90 return hold_button;
91}
92
93void clickwheel_int(void)
94{
95 /* Read wheel
96 * Bits 6 and 7 of GPIOH change as follows:
97 * Clockwise rotation 01 -> 00 -> 10 -> 11
98 * Counter-clockwise 11 -> 10 -> 00 -> 01
99 *
100 * This is equivalent to wheel_value of:
101 * Clockwise rotation 0x40 -> 0x00 -> 0x80 -> 0xc0
102 * Counter-clockwise 0xc0 -> 0x80 -> 0x00 -> 0x40
103 */
104 static const unsigned char wheel_tbl[2][4] =
105 {
106 /* 0x00 0x40 0x80 0xc0 */ /* Wheel value */
107 { 0x40, 0xc0, 0x00, 0x80 }, /* Clockwise rotation */
108 { 0x80, 0x00, 0xc0, 0x40 }, /* Counter-clockwise */
109 };
110
111 unsigned int wheel_value;
112
113 GPIOH_INT_CLR = GPIOH_INT_STAT & 0xc0;
114
115 wheel_value = GPIOH_INPUT_VAL & 0xc0;
116 GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (wheel_value ^ 0xc0);
117
118 if (!hold_button)
119 {
120 unsigned int btn = BUTTON_NONE;
121
122 if (old_wheel_value == wheel_tbl[0][wheel_value >> 6])
123 btn = BUTTON_SCROLL_DOWN;
124 else if (old_wheel_value == wheel_tbl[1][wheel_value >> 6])
125 btn = BUTTON_SCROLL_UP;
126
127 if (btn != BUTTON_NONE)
128 {
129 int repeat = 1;
130
131 if (btn != wheel_repeat)
132 {
133 wheel_repeat = btn;
134 repeat =
135 wheel_fast_mode =
136 wheel_click_count = 0;
137 }
138
139 if (wheel_fast_mode)
140 {
141 if (TIME_AFTER(current_tick,
142 last_wheel_tick + WHEEL_FAST_OFF_INTERVAL))
143 {
144 if (++wheel_click_count < 2)
145 btn = BUTTON_NONE;
146 wheel_fast_mode = 0;
147 }
148 }
149 else
150 {
151 if (repeat && TIME_BEFORE(current_tick,
152 last_wheel_tick + WHEEL_FAST_ON_INTERVAL))
153 wheel_fast_mode = 1;
154 else if (++wheel_click_count < 2)
155 btn = BUTTON_NONE;
156 }
157
158#ifndef BOOTLOADER
159 if (TIME_AFTER(current_tick, next_backlight_on))
160 {
161 next_backlight_on = current_tick + HZ/4;
162 backlight_on();
163 button_backlight_on();
164 }
165#endif
166 if (btn != BUTTON_NONE)
167 {
168 wheel_click_count = 0;
169
170 if (repeat && TIME_BEFORE(current_tick,
171 last_wheel_post + WHEEL_REPEAT_INTERVAL))
172 btn |= BUTTON_REPEAT;
173
174 last_wheel_post = current_tick;
175
176 if (queue_empty(&button_queue))
177 queue_post(&button_queue, btn, 0);
178 }
179
180 last_wheel_tick = current_tick;
181 }
182 }
183
184 old_wheel_value = wheel_value;
185}
186
187void button_int(void)
188{
189 unsigned char state;
190
191 GPIOF_INT_CLR = GPIOF_INT_STAT;
192
193 state = GPIOF_INPUT_VAL & 0xff;
194
195 GPIOF_INT_LEV = (GPIOF_INT_LEV & ~0xff) | (state ^ 0xff);
196
197 int_btn = BUTTON_NONE;
198
199 hold_button = (state & 0x80) != 0;
200
201 /* device buttons */
202 if (!hold_button)
203 {
204 /* Read normal buttons */
205 if ((state & 0x01) == 0) int_btn |= BUTTON_REC;
206 if ((state & 0x02) == 0) int_btn |= BUTTON_DOWN;
207 if ((state & 0x04) == 0) int_btn |= BUTTON_RIGHT;
208 if ((state & 0x08) == 0) int_btn |= BUTTON_LEFT;
209 if ((state & 0x10) == 0) int_btn |= BUTTON_SELECT; /* The centre button */
210 if ((state & 0x20) == 0) int_btn |= BUTTON_UP; /* The "play" button */
211 if ((state & 0x40) != 0) int_btn |= BUTTON_POWER;
212 }
46} 213}
47 214
48/* 215/*
@@ -50,101 +217,16 @@ bool button_hold(void)
50 */ 217 */
51int button_read_device(void) 218int button_read_device(void)
52{ 219{
53 int btn = BUTTON_NONE;
54 unsigned char state;
55 static bool hold_button = false;
56 bool hold_button_old;
57 unsigned int new_wheel_value = 0; /* read later, but this stops a warning */
58
59 /* Hold */ 220 /* Hold */
60 hold_button_old = hold_button;
61 hold_button = button_hold();
62
63#ifndef BOOTLOADER 221#ifndef BOOTLOADER
64 /* light handling */ 222 /* light handling */
65 if (hold_button != hold_button_old) 223 if (hold_button != hold_button_old)
66 { 224 {
225 hold_button_old = hold_button;
67 backlight_hold_changed(hold_button); 226 backlight_hold_changed(hold_button);
68 } 227 }
69#endif 228#endif
70 229
71 /* device buttons */ 230 /* The int_btn variable is set in the button interrupt handler */
72 if (!hold_button) 231 return int_btn;
73 {
74 /* Read normal buttons */
75 state = GPIOF_INPUT_VAL & 0xff;
76 if ((state & 0x1) == 0) btn |= BUTTON_REC;
77 if ((state & 0x2) == 0) btn |= BUTTON_DOWN;
78 if ((state & 0x4) == 0) btn |= BUTTON_RIGHT;
79 if ((state & 0x8) == 0) btn |= BUTTON_LEFT;
80 if ((state & 0x10) == 0) btn |= BUTTON_SELECT; /* The centre button */
81 if ((state & 0x20) == 0) btn |= BUTTON_UP; /* The "play" button */
82 if ((state & 0x40) != 0) btn |= BUTTON_POWER;
83
84 /* Read wheel
85 * Bits 6 and 7 of GPIOH change as follows:
86 * Clockwise rotation 01 -> 00 -> 10 -> 11
87 * Counter-clockwise 11 -> 10 -> 00 -> 01
88 *
89 * This is equivalent to wheel_value of:
90 * Clockwise rotation 0x40 -> 0x00 -> 0x80 -> 0xc0
91 * Counter-clockwise 0xc0 -> 0x80 -> 0x00 -> 0x40
92 */
93 new_wheel_value = GPIOH_INPUT_VAL & 0xc0;
94 switch(new_wheel_value){
95 case 0x00:
96 if(old_wheel_value==0x80)
97 btn |= BUTTON_SCROLL_UP;
98 else if (old_wheel_value==0x40)
99 btn |= BUTTON_SCROLL_DOWN;
100 break;
101 case 0x40:
102 if(old_wheel_value==0x00)
103 btn |= BUTTON_SCROLL_UP;
104 else if (old_wheel_value==0xc0)
105 btn |= BUTTON_SCROLL_DOWN;
106 break;
107 case 0x80:
108 if(old_wheel_value==0xc0)
109 btn |= BUTTON_SCROLL_UP;
110 else if (old_wheel_value==0x00)
111 btn |= BUTTON_SCROLL_DOWN;
112 break;
113 case 0xc0:
114 if(old_wheel_value==0x40)
115 btn |= BUTTON_SCROLL_UP;
116 else if (old_wheel_value==0x80)
117 btn |= BUTTON_SCROLL_DOWN;
118 break;
119 }
120
121 if(wheel_repeat == BUTTON_NONE){
122 if(btn & BUTTON_SCROLL_UP)
123 wheel_repeat = BUTTON_SCROLL_UP;
124
125 if(btn & BUTTON_SCROLL_DOWN)
126 wheel_repeat = BUTTON_SCROLL_DOWN;
127 } else if (wheel_repeat == BUTTON_SCROLL_UP) {
128 btn |= BUTTON_SCROLL_UP;
129 wheel_repeat = BUTTON_NONE;
130 } else if (wheel_repeat == BUTTON_SCROLL_DOWN) {
131 btn |= BUTTON_SCROLL_DOWN;
132 wheel_repeat = BUTTON_NONE;
133 }
134
135 old_wheel_value = new_wheel_value;
136 }
137
138 if( (btn & BUTTON_SCROLL_UP) || (btn & BUTTON_SCROLL_DOWN) ){
139 /* only trigger once per click */
140 if ((new_wheel_value == 0x00) || (new_wheel_value == 0xc0))
141 {
142 btn = btn&(~(BUTTON_SCROLL_UP|BUTTON_SCROLL_DOWN));
143 }
144#ifndef BOOTLOADER
145 button_backlight_on();
146#endif
147 }
148
149 return btn;
150} 232}
diff --git a/firmware/target/arm/system-pp502x.c b/firmware/target/arm/system-pp502x.c
index 1f1cdf47b6..72e3a9b361 100644
--- a/firmware/target/arm/system-pp502x.c
+++ b/firmware/target/arm/system-pp502x.c
@@ -56,12 +56,21 @@ void irq(void)
56/* TODO: this should really be in the target tree, but moving it there caused 56/* TODO: this should really be in the target tree, but moving it there caused
57 crt0.S not to find it while linking */ 57 crt0.S not to find it while linking */
58/* TODO: Even if it isn't in the target tree, this should be the default case */ 58/* TODO: Even if it isn't in the target tree, this should be the default case */
59extern void button_int(void);
60extern void clickwheel_int(void);
61
59void irq(void) 62void irq(void)
60{ 63{
61 if(CURRENT_CORE == CPU) 64 if(CURRENT_CORE == CPU) {
62 { 65 if (CPU_INT_STAT & TIMER1_MASK) {
63 if (CPU_INT_STAT & TIMER1_MASK) 66#ifdef SANSA_E200
67 if (GPIOF_INT_STAT & 0xff)
68 button_int();
69 if (GPIOH_INT_STAT & 0xc0)
70 clickwheel_int();
71#endif
64 TIMER1(); 72 TIMER1();
73 }
65 else if (CPU_INT_STAT & TIMER2_MASK) 74 else if (CPU_INT_STAT & TIMER2_MASK)
66 TIMER2(); 75 TIMER2();
67 } else { 76 } else {
@@ -222,7 +231,20 @@ void system_init(void)
222 COP_INT_CLR = -1; 231 COP_INT_CLR = -1;
223 CPU_INT_CLR = -1; 232 CPU_INT_CLR = -1;
224 INT_FORCED_CLR = -1; 233 INT_FORCED_CLR = -1;
225 234
235 GPIOA_INT_EN = 0;
236 GPIOB_INT_EN = 0;
237 GPIOC_INT_EN = 0;
238 GPIOD_INT_EN = 0;
239 GPIOE_INT_EN = 0;
240 GPIOF_INT_EN = 0;
241 GPIOG_INT_EN = 0;
242 GPIOH_INT_EN = 0;
243 GPIOI_INT_EN = 0;
244 GPIOJ_INT_EN = 0;
245 GPIOK_INT_EN = 0;
246 GPIOL_INT_EN = 0;
247
226# if NUM_CORES > 1 && defined(HAVE_ADJUSTABLE_CPU_FREQ) 248# if NUM_CORES > 1 && defined(HAVE_ADJUSTABLE_CPU_FREQ)
227 spinlock_init(&boostctrl_mtx); 249 spinlock_init(&boostctrl_mtx);
228# endif 250# endif