diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/sandisk/sansa-e200/button-e200.c | 321 |
1 files changed, 180 insertions, 141 deletions
diff --git a/firmware/target/arm/sandisk/sansa-e200/button-e200.c b/firmware/target/arm/sandisk/sansa-e200/button-e200.c index 21c0c376e1..be4a34d49f 100644 --- a/firmware/target/arm/sandisk/sansa-e200/button-e200.c +++ b/firmware/target/arm/sandisk/sansa-e200/button-e200.c | |||
@@ -26,22 +26,16 @@ | |||
26 | #include "backlight.h" | 26 | #include "backlight.h" |
27 | #include "powermgmt.h" | 27 | #include "powermgmt.h" |
28 | 28 | ||
29 | #define WHEEL_REPEAT_INTERVAL 300000 | 29 | #define WHEEL_REPEAT_VELOCITY 35 /* deg/s */ |
30 | #define WHEEL_FAST_ON_INTERVAL 20000 | 30 | #define WHEEL_SMOOTHING_VELOCITY 50 /* deg/s */ |
31 | #define WHEEL_FAST_OFF_INTERVAL 60000 | 31 | #define WHEEL_FAST_ON_VELOCITY 350 /* deg/s */ |
32 | #define WHEEL_FAST_OFF_VELOCITY 150 /* deg/s */ | ||
33 | #define WHEEL_BASE_SENSITIVITY 2 | ||
32 | #define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */ | 34 | #define WHEELCLICKS_PER_ROTATION 48 /* wheelclicks per full rotation */ |
33 | 35 | ||
34 | /* Clickwheel */ | ||
35 | #ifndef BOOTLOADER | 36 | #ifndef BOOTLOADER |
36 | static unsigned int old_wheel_value = 0; | 37 | /* Wheel */ |
37 | static unsigned int wheel_repeat = BUTTON_NONE; | 38 | static int read_wheel_keycode(void); |
38 | static unsigned int wheel_click_count = 0; | ||
39 | static unsigned int wheel_delta = 0; | ||
40 | static int wheel_fast_mode = 0; | ||
41 | static unsigned long last_wheel_usec = 0; | ||
42 | static unsigned long wheel_velocity = 0; | ||
43 | static long last_wheel_post = 0; | ||
44 | static long next_backlight_on = 0; | ||
45 | /* Buttons */ | 39 | /* Buttons */ |
46 | static bool hold_button = false; | 40 | static bool hold_button = false; |
47 | static bool hold_button_old = false; | 41 | static bool hold_button_old = false; |
@@ -54,38 +48,31 @@ static int int_btn = BUTTON_NONE; | |||
54 | void button_init_device(void) | 48 | void button_init_device(void) |
55 | { | 49 | { |
56 | /* Enable all buttons */ | 50 | /* Enable all buttons */ |
57 | GPIOF_OUTPUT_EN &= ~0xff; | 51 | GPIO_CLEAR_BITWISE(GPIOF_OUTPUT_EN, 0xff); |
58 | GPIOF_ENABLE |= 0xff; | 52 | GPIO_SET_BITWISE(GPIOF_ENABLE, 0xff); |
59 | 53 | ||
60 | /* Scrollwheel light - enable control through GPIOG pin 7 and set timeout */ | 54 | /* Scrollwheel light - enable control through GPIOG pin 7 and set timeout */ |
61 | GPIOG_OUTPUT_EN |= 0x80; | 55 | GPIO_SET_BITWISE(GPIOG_OUTPUT_EN, 0x80); |
62 | GPIOG_ENABLE = 0x80; | 56 | GPIO_SET_BITWISE(GPIOG_ENABLE, 0x80); |
63 | 57 | ||
64 | #ifndef BOOTLOADER | 58 | #ifndef BOOTLOADER |
65 | /* Mask these before performing init ... because init has possibly | 59 | /* Mask these before performing init ... because init has possibly |
66 | occurred before */ | 60 | occurred before */ |
67 | GPIOF_INT_EN &= ~0xff; | 61 | GPIO_CLEAR_BITWISE(GPIOF_INT_EN, 0xff); |
68 | GPIOH_INT_EN &= ~0xc0; | 62 | GPIO_CLEAR_BITWISE(GPIOH_INT_EN, 0xc0); |
69 | 63 | ||
70 | /* Get current tick before enabling button interrupts */ | 64 | GPIO_CLEAR_BITWISE(GPIOH_OUTPUT_EN, 0xc0); |
71 | last_wheel_usec = USEC_TIMER; | 65 | GPIO_SET_BITWISE(GPIOH_ENABLE, 0xc0); |
72 | last_wheel_post = last_wheel_usec; | ||
73 | |||
74 | GPIOH_ENABLE |= 0xc0; | ||
75 | GPIOH_OUTPUT_EN &= ~0xc0; | ||
76 | 66 | ||
77 | /* Read initial buttons */ | 67 | /* Read initial buttons */ |
78 | button_int(); | 68 | button_int(); |
79 | GPIOF_INT_CLR = 0xff; | ||
80 | 69 | ||
81 | /* Read initial wheel value (bit 6-7 of GPIOH) */ | 70 | /* Read initial wheel value (bit 6-7 of GPIOH) */ |
82 | old_wheel_value = GPIOH_INPUT_VAL & 0xc0; | 71 | read_wheel_keycode(); |
83 | GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (old_wheel_value ^ 0xc0); | ||
84 | GPIOH_INT_CLR = 0xc0; | ||
85 | 72 | ||
86 | /* Enable button interrupts */ | 73 | /* Enable button interrupts */ |
87 | GPIOF_INT_EN |= 0xff; | 74 | GPIO_SET_BITWISE(GPIOF_INT_EN, 0xff); |
88 | GPIOH_INT_EN |= 0xc0; | 75 | GPIO_SET_BITWISE(GPIOH_INT_EN, 0xc0); |
89 | 76 | ||
90 | CPU_INT_EN = HI_MASK; | 77 | CPU_INT_EN = HI_MASK; |
91 | CPU_HI_INT_EN = GPIO1_MASK; | 78 | CPU_HI_INT_EN = GPIO1_MASK; |
@@ -99,7 +86,7 @@ bool button_hold(void) | |||
99 | 86 | ||
100 | /* clickwheel */ | 87 | /* clickwheel */ |
101 | #ifndef BOOTLOADER | 88 | #ifndef BOOTLOADER |
102 | void clickwheel_int(void) | 89 | static int read_wheel_keycode(void) |
103 | { | 90 | { |
104 | /* Read wheel | 91 | /* Read wheel |
105 | * Bits 6 and 7 of GPIOH change as follows: | 92 | * Bits 6 and 7 of GPIOH change as follows: |
@@ -117,138 +104,190 @@ void clickwheel_int(void) | |||
117 | { 0x80, 0x00, 0xc0, 0x40 }, /* Counter-clockwise */ | 104 | { 0x80, 0x00, 0xc0, 0x40 }, /* Counter-clockwise */ |
118 | }; | 105 | }; |
119 | 106 | ||
120 | unsigned int wheel_value; | 107 | static unsigned long prev_value; |
121 | 108 | ||
122 | wheel_value = GPIOH_INPUT_VAL & 0xc0; | 109 | int keycode = BUTTON_NONE; |
123 | GPIOH_INT_LEV = (GPIOH_INT_LEV & ~0xc0) | (wheel_value ^ 0xc0); | 110 | |
111 | unsigned long value = GPIOH_INPUT_VAL & 0xc0; | ||
112 | GPIO_WRITE_BITWISE(GPIOH_INT_LEV, value ^ 0xc0, 0xc0); | ||
124 | GPIOH_INT_CLR = GPIOH_INT_STAT & 0xc0; | 113 | GPIOH_INT_CLR = GPIOH_INT_STAT & 0xc0; |
125 | 114 | ||
126 | if (!hold_button) | 115 | if (!hold_button) |
127 | { | 116 | { |
128 | unsigned int btn = BUTTON_NONE; | 117 | unsigned long prev = prev_value; |
118 | int scroll = value >> 6; | ||
119 | |||
120 | if (prev == wheel_tbl[0][scroll]) | ||
121 | keycode = BUTTON_SCROLL_FWD; | ||
122 | else if (prev == wheel_tbl[1][scroll]) | ||
123 | keycode = BUTTON_SCROLL_BACK; | ||
124 | } | ||
125 | |||
126 | prev_value = value; | ||
127 | |||
128 | return keycode; | ||
129 | } | ||
130 | |||
131 | void clickwheel_int(void) | ||
132 | { | ||
133 | static int prev_keycode = BUTTON_NONE; | ||
134 | static int prev_keypost = BUTTON_NONE; | ||
135 | static int count = 0; | ||
136 | static int fast_mode = 0; | ||
137 | static long next_backlight_on = 0; | ||
138 | |||
139 | static unsigned long prev_usec[WHEEL_BASE_SENSITIVITY] = { 0 }; | ||
140 | static unsigned long delta = 1ul << 24; | ||
141 | static unsigned long velocity = 0; /* Velocity smoothed or unsmoothed */ | ||
142 | |||
143 | unsigned long usec = USEC_TIMER; | ||
144 | unsigned long v; /* Raw velocity */ | ||
145 | |||
146 | int keycode = read_wheel_keycode(); | ||
147 | |||
148 | if (keycode == BUTTON_NONE) | ||
149 | return; | ||
150 | |||
151 | /* Spurious wheel "reversals" are not uncommon. Resetting also helps | ||
152 | * cover them up. As such, prev_keypost is also not reset or else false | ||
153 | * non-repeats are generated when it happens. */ | ||
154 | if (keycode != prev_keycode) | ||
155 | { | ||
156 | /* Direction reversals reset state */ | ||
157 | unsigned long usec_back = 360000000ul / | ||
158 | (WHEEL_REPEAT_VELOCITY*WHEELCLICKS_PER_ROTATION); | ||
159 | prev_keycode = keycode; | ||
160 | count = 0; | ||
161 | fast_mode = 0; | ||
162 | prev_usec[0] = usec - usec_back; | ||
163 | prev_usec[1] = prev_usec[0] - usec_back; | ||
164 | delta = 1ul << 24; | ||
165 | velocity = 0; | ||
166 | } | ||
167 | |||
168 | if (TIME_AFTER(current_tick, next_backlight_on)) | ||
169 | { | ||
170 | /* Poke backlight to turn it on or maintain it no more often | ||
171 | * than every 1/4 second */ | ||
172 | next_backlight_on = current_tick + HZ/4; | ||
173 | backlight_on(); | ||
174 | buttonlight_on(); | ||
175 | reset_poweroff_timer(); | ||
176 | } | ||
177 | |||
178 | /* Calculate deg/s based upon interval and number of clicks in that | ||
179 | * interval - FIR moving average */ | ||
180 | v = usec - prev_usec[1]; | ||
181 | |||
182 | if ((long)v <= 0) | ||
183 | { | ||
184 | /* timer wrapped (no activity for awhile), skip acceleration */ | ||
185 | v = 0; | ||
186 | delta = 1ul << 24; | ||
187 | } | ||
188 | else | ||
189 | { | ||
190 | /* Check overflow below */ | ||
191 | if (v > 0xfffffffful / WHEELCLICKS_PER_ROTATION) | ||
192 | v = 0xfffffffful / WHEELCLICKS_PER_ROTATION; | ||
193 | |||
194 | v = 360000000ul*WHEEL_BASE_SENSITIVITY / (v*WHEELCLICKS_PER_ROTATION); | ||
195 | |||
196 | if (v > 0xfffffful) | ||
197 | v = 0xfffffful; /* limit to 24 bits */ | ||
198 | } | ||
129 | 199 | ||
130 | if (old_wheel_value == wheel_tbl[0][wheel_value >> 6]) | 200 | prev_usec[1] = prev_usec[0]; |
131 | btn = BUTTON_SCROLL_FWD; | 201 | prev_usec[0] = usec; |
132 | else if (old_wheel_value == wheel_tbl[1][wheel_value >> 6]) | ||
133 | btn = BUTTON_SCROLL_BACK; | ||
134 | 202 | ||
135 | if (btn != BUTTON_NONE) | 203 | if (v < WHEEL_SMOOTHING_VELOCITY) |
204 | { | ||
205 | /* Very slow - no smoothing */ | ||
206 | velocity = v; | ||
207 | /* Ensure backlight never gets stuck for an extended period if tick | ||
208 | * wrapped such that next poke is very far ahead */ | ||
209 | next_backlight_on = current_tick - 1; | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | /* Some velocity filtering to smooth things out */ | ||
214 | velocity = (7*velocity + v) / 8; | ||
215 | } | ||
216 | |||
217 | if (fast_mode != 0) | ||
218 | { | ||
219 | /* Fast OFF happens immediately when velocity drops below | ||
220 | threshold */ | ||
221 | if (v < WHEEL_FAST_OFF_VELOCITY) | ||
222 | { | ||
223 | fast_mode = 0; /* moving out of fast mode */ | ||
224 | velocity = v; | ||
225 | |||
226 | /* delta is always 1 in slow mode */ | ||
227 | delta = 1ul << 24; | ||
228 | } | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | /* Fast ON gets filtered to avoid inadvertent jumps to fast mode */ | ||
233 | if (velocity >= WHEEL_FAST_ON_VELOCITY) | ||
234 | fast_mode = 1; /* moving into fast mode */ | ||
235 | |||
236 | /* delta is always 1 in slow mode */ | ||
237 | delta = 1ul << 24; | ||
238 | } | ||
239 | |||
240 | count += fast_mode + 1; | ||
241 | if (count < WHEEL_BASE_SENSITIVITY) | ||
242 | return; | ||
243 | |||
244 | count = 0; | ||
245 | |||
246 | if (queue_empty(&button_queue)) | ||
247 | { | ||
248 | /* Post wheel keycode with wheel data */ | ||
249 | int key = keycode; | ||
250 | |||
251 | if (v >= WHEEL_REPEAT_VELOCITY && prev_keypost == key) | ||
136 | { | 252 | { |
137 | int repeat = 1; /* assume repeat */ | 253 | /* Quick enough and same key is being posted more than once in a |
138 | unsigned long usec = USEC_TIMER; | 254 | * row - generate repeats - use unsmoothed v */ |
139 | unsigned v = (usec - last_wheel_usec) & 0x7fffffff; | 255 | key |= BUTTON_REPEAT; |
140 | |||
141 | v = (v>0) ? 1000000 / v : 0; /* clicks/sec = 1000000 * clicks/usec */ | ||
142 | v = (v>0xffffff) ? 0xffffff : v; /* limit to 24 bit */ | ||
143 | |||
144 | /* some velocity filtering to smooth things out */ | ||
145 | wheel_velocity = (7*wheel_velocity + v) / 8; | ||
146 | |||
147 | if (btn != wheel_repeat) | ||
148 | { | ||
149 | /* direction reversals nullify all fast mode states */ | ||
150 | wheel_repeat = btn; | ||
151 | repeat = | ||
152 | wheel_fast_mode = | ||
153 | wheel_velocity = | ||
154 | wheel_click_count = 0; | ||
155 | } | ||
156 | |||
157 | if (wheel_fast_mode != 0) | ||
158 | { | ||
159 | /* fast OFF happens immediately when velocity drops below | ||
160 | threshold */ | ||
161 | if (TIME_AFTER(usec, | ||
162 | last_wheel_usec + WHEEL_FAST_OFF_INTERVAL)) | ||
163 | { | ||
164 | /* moving out of fast mode */ | ||
165 | wheel_fast_mode = 0; | ||
166 | /* reset velocity */ | ||
167 | wheel_velocity = 0; | ||
168 | /* wheel_delta is always 1 in slow mode */ | ||
169 | wheel_delta = 1; | ||
170 | } | ||
171 | } | ||
172 | else | ||
173 | { | ||
174 | /* fast ON gets filtered to avoid inadvertent jumps to fast mode */ | ||
175 | if (repeat && wheel_velocity > 1000000/WHEEL_FAST_ON_INTERVAL) | ||
176 | { | ||
177 | /* moving into fast mode */ | ||
178 | wheel_fast_mode = 1 << 31; | ||
179 | wheel_click_count = 0; | ||
180 | wheel_velocity = 1000000/WHEEL_FAST_OFF_INTERVAL; | ||
181 | } | ||
182 | else if (++wheel_click_count < 2) | ||
183 | { | ||
184 | btn = BUTTON_NONE; | ||
185 | } | ||
186 | |||
187 | /* wheel_delta is always 1 in slow mode */ | ||
188 | wheel_delta = 1; | ||
189 | } | ||
190 | |||
191 | if (TIME_AFTER(current_tick, next_backlight_on) || | ||
192 | v <= 4) | ||
193 | { | ||
194 | /* poke backlight to turn it on or maintain it no more often | ||
195 | than every 1/4 second*/ | ||
196 | next_backlight_on = current_tick + HZ/4; | ||
197 | backlight_on(); | ||
198 | buttonlight_on(); | ||
199 | reset_poweroff_timer(); | ||
200 | } | ||
201 | |||
202 | if (btn != BUTTON_NONE) | ||
203 | { | ||
204 | wheel_click_count = 0; | ||
205 | |||
206 | /* generate repeats if quick enough */ | ||
207 | if (repeat && TIME_BEFORE(usec, | ||
208 | last_wheel_post + WHEEL_REPEAT_INTERVAL)) | ||
209 | btn |= BUTTON_REPEAT; | ||
210 | |||
211 | last_wheel_post = usec; | ||
212 | |||
213 | if (queue_empty(&button_queue)) | ||
214 | { | ||
215 | queue_post(&button_queue, btn, wheel_fast_mode | | ||
216 | (wheel_delta << 24) | wheel_velocity*360/WHEELCLICKS_PER_ROTATION); | ||
217 | /* message posted - reset delta */ | ||
218 | wheel_delta = 1; | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | /* skipped post - increment delta */ | ||
223 | if (++wheel_delta > 0x7f) | ||
224 | wheel_delta = 0x7f; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | last_wheel_usec = usec; | ||
229 | } | 256 | } |
257 | |||
258 | prev_keypost = keycode; | ||
259 | |||
260 | queue_post(&button_queue, key, (fast_mode << 31) | delta | velocity); | ||
261 | /* Message posted - reset delta */ | ||
262 | delta = 1ul << 24; | ||
230 | } | 263 | } |
264 | else | ||
265 | { | ||
266 | /* Skipped post - increment delta and limit to 7 bits */ | ||
267 | delta += 1ul << 24; | ||
231 | 268 | ||
232 | old_wheel_value = wheel_value; | 269 | if (delta > (0x7ful << 24)) |
270 | delta = 0x7ful << 24; | ||
271 | } | ||
233 | } | 272 | } |
234 | #endif /* BOOTLOADER */ | 273 | #endif /* BOOTLOADER */ |
235 | 274 | ||
236 | /* device buttons */ | 275 | /* device buttons */ |
237 | void button_int(void) | 276 | void button_int(void) |
238 | { | 277 | { |
239 | unsigned char state; | 278 | unsigned long state = GPIOF_INPUT_VAL & 0xff; |
240 | |||
241 | int_btn = BUTTON_NONE; | ||
242 | |||
243 | state = GPIOF_INPUT_VAL & 0xff; | ||
244 | 279 | ||
245 | #ifndef BOOTLOADER | 280 | #ifndef BOOTLOADER |
246 | GPIOF_INT_LEV = (GPIOF_INT_LEV & ~0xff) | (state ^ 0xff); | 281 | unsigned long status = GPIOF_INT_STAT; |
247 | GPIOF_INT_CLR = GPIOF_INT_STAT; | 282 | |
283 | GPIO_WRITE_BITWISE(GPIOF_INT_LEV, state ^ 0xff, 0xff); | ||
284 | GPIOF_INT_CLR = status; | ||
248 | 285 | ||
249 | hold_button = (state & 0x80) != 0; | 286 | hold_button = (state & 0x80) != 0; |
250 | #endif | 287 | #endif |
251 | 288 | ||
289 | int_btn = BUTTON_NONE; | ||
290 | |||
252 | if (!_button_hold()) | 291 | if (!_button_hold()) |
253 | { | 292 | { |
254 | /* Read normal buttons */ | 293 | /* Read normal buttons */ |