diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/target/arm/as3525/button-e200v2-fuze.c (renamed from firmware/target/arm/as3525/sansa-fuze/button-fuze.c) | 121 | ||||
-rw-r--r-- | firmware/target/arm/as3525/sansa-e200v2/button-e200v2.c | 248 |
2 files changed, 86 insertions, 283 deletions
diff --git a/firmware/target/arm/as3525/sansa-fuze/button-fuze.c b/firmware/target/arm/as3525/button-e200v2-fuze.c index 266ca79deb..6a9f02959c 100644 --- a/firmware/target/arm/as3525/sansa-fuze/button-fuze.c +++ b/firmware/target/arm/as3525/button-e200v2-fuze.c | |||
@@ -20,19 +20,34 @@ | |||
20 | * | 20 | * |
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | 22 | ||
23 | |||
24 | /* Basic button driver for the Fuze | ||
25 | * | ||
26 | * TODO: - Get the wheel working with interrupts (seems to be impossible | ||
27 | * so far) | ||
28 | */ | ||
29 | |||
30 | #include "system.h" | 23 | #include "system.h" |
31 | #include "button.h" | 24 | #include "button.h" |
32 | #include "button-target.h" | 25 | #include "button-target.h" |
33 | #include "backlight.h" | 26 | #include "backlight.h" |
34 | 27 | ||
28 | |||
29 | #ifdef SANSA_FUZE | ||
30 | #define DBOP_BIT15_BUTTON BUTTON_HOME | ||
31 | #define WHEEL_REPEAT_INTERVAL (HZ/5) | ||
32 | #define WHEEL_COUNTER_DIV 4 | ||
33 | #define ACCEL_INCREMENT 2 | ||
34 | #define ACCEL_SHIFT 2 | ||
35 | #define BUTTON_DELAY 45 | ||
36 | #endif | ||
37 | |||
38 | #ifdef SANSA_E200V2 | ||
39 | #define DBOP_BIT15_BUTTON BUTTON_REC | ||
35 | #define WHEEL_REPEAT_INTERVAL (HZ/5) | 40 | #define WHEEL_REPEAT_INTERVAL (HZ/5) |
41 | #define WHEEL_COUNTER_DIV 2 | ||
42 | #define ACCEL_INCREMENT 3 | ||
43 | #define ACCEL_SHIFT 1 | ||
44 | #define BUTTON_DELAY 10 | ||
45 | |||
46 | /* read_missed is true if buttons could not | ||
47 | * be read (see lcd_button_support) */ | ||
48 | static bool read_missed = false; | ||
49 | |||
50 | #endif | ||
36 | 51 | ||
37 | /* Buttons */ | 52 | /* Buttons */ |
38 | static bool hold_button = false; | 53 | static bool hold_button = false; |
@@ -118,15 +133,15 @@ static void scrollwheel(unsigned short dbop_din) | |||
118 | if (TIME_BEFORE(current_tick, last_wheel_post + WHEEL_REPEAT_INTERVAL)) | 133 | if (TIME_BEFORE(current_tick, last_wheel_post + WHEEL_REPEAT_INTERVAL)) |
119 | { | 134 | { |
120 | btn |= BUTTON_REPEAT; | 135 | btn |= BUTTON_REPEAT; |
121 | wheel_delta = accel>>2; | 136 | wheel_delta = accel>>ACCEL_SHIFT; |
122 | } | 137 | } |
123 | 138 | ||
124 | accel += 2; | 139 | accel += ACCEL_INCREMENT; |
125 | 140 | ||
126 | /* the wheel is more reliable if we don't send every change, | 141 | /* the wheel is more reliable if we don't send every change, |
127 | * every 4th is basically one "physical click" which should | 142 | * every WHEEL_COUNTER_DIVth is basically one "physical click" |
128 | * make up 1 item in lists */ | 143 | * which should make up 1 item in lists */ |
129 | if (++counter >= 4 && queue_empty(&button_queue)) | 144 | if (++counter >= WHEEL_COUNTER_DIV && queue_empty(&button_queue)) |
130 | { | 145 | { |
131 | buttonlight_on(); | 146 | buttonlight_on(); |
132 | backlight_on(); | 147 | backlight_on(); |
@@ -136,7 +151,11 @@ static void scrollwheel(unsigned short dbop_din) | |||
136 | last_wheel_post = current_tick; | 151 | last_wheel_post = current_tick; |
137 | } | 152 | } |
138 | } | 153 | } |
139 | if (accel > 0) | 154 | if (accel > 0 |
155 | #ifdef SANSA_E200V2 | ||
156 | && !read_missed /* decrement only if reading buttons was successful */ | ||
157 | #endif | ||
158 | ) | ||
140 | accel--; | 159 | accel--; |
141 | 160 | ||
142 | old_wheel_value = wheel_value; | 161 | old_wheel_value = wheel_value; |
@@ -150,49 +169,69 @@ bool button_hold(void) | |||
150 | 169 | ||
151 | static void button_delay(void) | 170 | static void button_delay(void) |
152 | { | 171 | { |
153 | int i = 50; | 172 | int i = BUTTON_DELAY; |
154 | while(i--) asm volatile ("nop\n"); | 173 | while(i--) asm volatile ("nop\n"); |
155 | } | 174 | } |
156 | 175 | ||
157 | unsigned short button_read_dbop(void) | 176 | unsigned short button_read_dbop(void) |
158 | { | 177 | { |
178 | #ifdef SANSA_FUZE | ||
159 | /* skip home and power reading if lcd_button_support was blocked, | 179 | /* skip home and power reading if lcd_button_support was blocked, |
160 | * since the dbop bit 15 is invalid then, and use the old value instead */ | 180 | * since the dbop bit 15 is invalid then, and use the old value instead |
161 | /* -20 (arbitary value) indicates valid home&power button read */ | 181 | * -20 (arbitary value) indicates valid home&power button read |
182 | * (fuze only) */ | ||
162 | int old_home_power = -20; | 183 | int old_home_power = -20; |
184 | #endif | ||
163 | if(!lcd_button_support()) | 185 | if(!lcd_button_support()) |
164 | { | 186 | { |
187 | #if defined(SANSA_FUZE) | ||
165 | old_home_power = (_dbop_din & (1<<15|1<<8)); | 188 | old_home_power = (_dbop_din & (1<<15|1<<8)); |
189 | #elif defined(SANSA_E200V2) | ||
190 | read_missed = true; | ||
191 | #endif | ||
166 | } | 192 | } |
167 | 193 | ||
168 | /* Set up dbop for input */ | 194 | #ifdef SANSA_E200V2 |
169 | DBOP_CTRL |= (1<<19); /* Tri-state DBOP on read cycle */ | 195 | if (!read_missed) /* read buttons only if lcd_button_support was not blocked */ |
170 | DBOP_CTRL &= ~(1<<16); /* disable output (1:write enabled) */ | 196 | #endif |
171 | DBOP_TIMPOL_01 = 0xe167e167; /* Set Timing & Polarity regs 0 & 1 */ | 197 | { |
172 | DBOP_TIMPOL_23 = 0xe167006e; /* Set Timing & Polarity regs 2 & 3 */ | 198 | /* Set up dbop for input */ |
173 | 199 | DBOP_CTRL |= (1<<19); /* Tri-state DBOP on read cycle */ | |
174 | button_delay(); | 200 | DBOP_CTRL &= ~(1<<16); /* disable output (1:write enabled) */ |
175 | DBOP_CTRL |= (1<<15); /* start read */ | 201 | DBOP_TIMPOL_01 = 0xe167e167; /* Set Timing & Polarity regs 0 & 1 */ |
176 | while (!(DBOP_STAT & (1<<16))); /* wait for valid data */ | 202 | DBOP_TIMPOL_23 = 0xe167006e; /* Set Timing & Polarity regs 2 & 3 */ |
177 | 203 | ||
178 | _dbop_din = DBOP_DIN; /* Read dbop data*/ | 204 | button_delay(); |
179 | 205 | DBOP_CTRL |= (1<<15); /* start read */ | |
180 | /* Reset dbop for output */ | 206 | while (!(DBOP_STAT & (1<<16))); /* wait for valid data */ |
181 | DBOP_TIMPOL_01 = 0x6e167; /* Set Timing & Polarity regs 0 & 1 */ | 207 | |
182 | DBOP_TIMPOL_23 = 0xa167e06f; /* Set Timing & Polarity regs 2 & 3 */ | 208 | _dbop_din = DBOP_DIN; /* Read dbop data*/ |
183 | DBOP_CTRL |= (1<<16); /* Enable output (0:write disable) */ | 209 | |
184 | DBOP_CTRL &= ~(1<<19); /* Tri-state when no active write */ | 210 | /* Reset dbop for output */ |
211 | DBOP_TIMPOL_01 = 0x6e167; /* Set Timing & Polarity regs 0 & 1 */ | ||
212 | DBOP_TIMPOL_23 = 0xa167e06f; /* Set Timing & Polarity regs 2 & 3 */ | ||
213 | DBOP_CTRL |= (1<<16); /* Enable output (0:write disable) */ | ||
214 | DBOP_CTRL &= ~(1<<19); /* Tri-state when no active write */ | ||
215 | } | ||
185 | 216 | ||
217 | #ifdef SANSA_FUZE | ||
186 | /* write back old values if blocked */ | 218 | /* write back old values if blocked */ |
187 | if (old_home_power != -20) | 219 | if (old_home_power != -20) |
188 | { | 220 | { |
189 | _dbop_din |= old_home_power & 1<<15; | 221 | _dbop_din |= old_home_power & 1<<15; |
190 | _dbop_din &= 0xfeff|(old_home_power & 1<<8); | 222 | _dbop_din &= 0xfeff|(old_home_power & 1<<8); |
191 | } | 223 | } |
224 | #endif | ||
225 | |||
192 | #if defined(HAVE_SCROLLWHEEL) && !defined(BOOTLOADER) | 226 | #if defined(HAVE_SCROLLWHEEL) && !defined(BOOTLOADER) |
193 | /* read wheel on bit 13 & 14, but sent to the button queue seperately */ | 227 | /* read wheel on bit 13 & 14, but sent to the button queue seperately */ |
194 | scrollwheel(_dbop_din); | 228 | scrollwheel(_dbop_din); |
195 | #endif | 229 | #endif |
230 | |||
231 | #ifdef SANSA_E200V2 | ||
232 | read_missed = false; | ||
233 | #endif | ||
234 | |||
196 | return _dbop_din; | 235 | return _dbop_din; |
197 | } | 236 | } |
198 | 237 | ||
@@ -248,26 +287,38 @@ int button_read_device(void) | |||
248 | { | 287 | { |
249 | int btn = BUTTON_NONE; | 288 | int btn = BUTTON_NONE; |
250 | unsigned short dbop = button_read_dbop(); | 289 | unsigned short dbop = button_read_dbop(); |
290 | #ifdef SANSA_FUZE | ||
251 | static unsigned power_counter = 0; | 291 | static unsigned power_counter = 0; |
292 | #endif | ||
252 | /* hold button */ | 293 | /* hold button */ |
253 | if(dbop & (1<<12)) | 294 | if(dbop & (1<<12)) |
254 | { | 295 | { |
296 | #ifdef SANSA_FUZE | ||
255 | power_counter = HZ; | 297 | power_counter = HZ; |
298 | #endif | ||
256 | hold_button = true; | 299 | hold_button = true; |
257 | } | 300 | } |
258 | else | 301 | else |
259 | { | 302 | { |
260 | hold_button = false; | 303 | hold_button = false; |
304 | #ifdef SANSA_FUZE | ||
261 | /* read power on bit 8, but not if hold button was just released, since | 305 | /* read power on bit 8, but not if hold button was just released, since |
262 | * you basically always hit power due to the slider mechanism after releasing | 306 | * you basically always hit power due to the slider mechanism after releasing |
307 | * (fuze only) | ||
263 | * hold (wait 1 sec) */ | 308 | * hold (wait 1 sec) */ |
264 | if (power_counter) | 309 | if (power_counter) |
265 | power_counter--; | 310 | power_counter--; |
266 | if (!power_counter && dbop & (1<<8)) | 311 | #endif |
312 | if (dbop & (1<<8) | ||
313 | #ifdef SANSA_FUZE | ||
314 | && !power_counter | ||
315 | #endif | ||
316 | ) | ||
267 | btn |= BUTTON_POWER; | 317 | btn |= BUTTON_POWER; |
268 | /* read home on bit 15 */ | 318 | /* read home on bit 15 */ |
269 | if (!(dbop & (1<<15))) | 319 | if (!(dbop & (1<<15))) |
270 | btn |= BUTTON_HOME; | 320 | btn |= DBOP_BIT15_BUTTON; |
321 | |||
271 | btn |= button_gpio(); | 322 | btn |= button_gpio(); |
272 | } | 323 | } |
273 | 324 | ||
diff --git a/firmware/target/arm/as3525/sansa-e200v2/button-e200v2.c b/firmware/target/arm/as3525/sansa-e200v2/button-e200v2.c deleted file mode 100644 index 8170c1b895..0000000000 --- a/firmware/target/arm/as3525/sansa-e200v2/button-e200v2.c +++ /dev/null | |||
@@ -1,248 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Barry Wardell | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* Taken from button-h10.c by Barry Wardell and reverse engineering by MrH. */ | ||
23 | |||
24 | #include "system.h" | ||
25 | #include "button.h" | ||
26 | #include "backlight.h" | ||
27 | #include "powermgmt.h" | ||
28 | |||
29 | |||
30 | static bool hold_button = false; | ||
31 | #ifndef BOOTLOADER | ||
32 | static bool hold_button_old = false; | ||
33 | #endif | ||
34 | static unsigned short _dbop_din = 0; | ||
35 | /* read_missed is true if buttons could not | ||
36 | * be read (see lcd_button_support) */ | ||
37 | static bool read_missed = false; | ||
38 | |||
39 | #define WHEEL_REPEAT_INTERVAL (HZ/4) | ||
40 | /* in the lcd driver */ | ||
41 | extern bool lcd_button_support(void); | ||
42 | |||
43 | void button_init_device(void) | ||
44 | { | ||
45 | |||
46 | } | ||
47 | |||
48 | bool button_hold(void) | ||
49 | { | ||
50 | return hold_button; | ||
51 | } | ||
52 | |||
53 | #if !defined(BOOTLOADER) && defined(HAVE_SCROLLWHEEL) | ||
54 | static void scrollwheel(unsigned short dbop_din) | ||
55 | { | ||
56 | /* current wheel values, parsed from dbop and the resulting button */ | ||
57 | unsigned wheel_value = 0; | ||
58 | unsigned btn = BUTTON_NONE; | ||
59 | /* old wheel values */ | ||
60 | static unsigned old_wheel_value = 0; | ||
61 | static unsigned old_btn = BUTTON_NONE; | ||
62 | |||
63 | /* getting BUTTON_REPEAT works like this: Remember when the btn value was | ||
64 | * posted to the button_queue last, and if it was recent enough, generate | ||
65 | * BUTTON_REPEAT | ||
66 | */ | ||
67 | static long last_wheel_post = 0; | ||
68 | /* Repeat is used for the scrollwheel acceleration. If high enough then | ||
69 | * jump over some items */ | ||
70 | static unsigned repeat = 0; | ||
71 | /* we omit 1 of 2 posts to the button_queue, that works better, so count */ | ||
72 | static int counter = 0; | ||
73 | /* Read wheel | ||
74 | * Bits 13 and 14 of DBOP_DIN change as follows: | ||
75 | * Clockwise rotation 00 -> 01 -> 11 -> 10 -> 00 | ||
76 | * Counter-clockwise 00 -> 10 -> 11 -> 01 -> 00 | ||
77 | */ | ||
78 | static const unsigned char wheel_tbl[2][4] = | ||
79 | { | ||
80 | { 2, 0, 3, 1 }, /* Clockwise rotation */ | ||
81 | { 1, 3, 0, 2 }, /* Counter-clockwise */ | ||
82 | }; | ||
83 | |||
84 | if(hold_button) | ||
85 | { | ||
86 | repeat = counter = 0; | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | wheel_value = dbop_din & (1<<13|1<<14); | ||
91 | wheel_value >>= 13; | ||
92 | |||
93 | if (old_wheel_value == wheel_tbl[0][wheel_value]) | ||
94 | btn = BUTTON_SCROLL_FWD; | ||
95 | else if (old_wheel_value == wheel_tbl[1][wheel_value]) | ||
96 | btn = BUTTON_SCROLL_BACK; | ||
97 | |||
98 | if (btn != BUTTON_NONE) | ||
99 | { | ||
100 | if (btn != old_btn) | ||
101 | { | ||
102 | /* direction reversals nullify repeats */ | ||
103 | old_btn = btn; | ||
104 | repeat = counter = 0; | ||
105 | } | ||
106 | /* wheel_delta will cause lists to jump over items, | ||
107 | * we want this for fast scrolling, but we must keep it accurate | ||
108 | * for slow scrolling */ | ||
109 | int wheel_delta = 0; | ||
110 | /* generate repeats if quick enough, scroll slightly too */ | ||
111 | if (TIME_BEFORE(current_tick, last_wheel_post + WHEEL_REPEAT_INTERVAL)) | ||
112 | { | ||
113 | btn |= BUTTON_REPEAT; | ||
114 | wheel_delta = repeat>>1; | ||
115 | } | ||
116 | |||
117 | repeat += 3; | ||
118 | /* the wheel is more reliable if we don't send ever change, | ||
119 | * every 2th is basically one "physical click" is | ||
120 | * 1 item in the rockbox menus */ | ||
121 | if (++counter >= 2 && queue_empty(&button_queue)) | ||
122 | { | ||
123 | buttonlight_on(); | ||
124 | backlight_on(); | ||
125 | queue_post(&button_queue, btn, ((wheel_delta+1)<<24)); | ||
126 | /* message posted - reset count & last post to the queue */ | ||
127 | counter = 0; | ||
128 | last_wheel_post = current_tick; | ||
129 | } | ||
130 | } | ||
131 | if (repeat > 0 && !read_missed) | ||
132 | repeat--; | ||
133 | |||
134 | old_wheel_value = wheel_value; | ||
135 | } | ||
136 | #endif /* !defined(BOOTLOADER) && defined(HAVE_SCROLLWHEEL) */ | ||
137 | |||
138 | unsigned short button_read_dbop(void) | ||
139 | { | ||
140 | /*write a red pixel */ | ||
141 | if (!lcd_button_support()) | ||
142 | { | ||
143 | read_missed = true; | ||
144 | } | ||
145 | if (!read_missed) | ||
146 | { | ||
147 | /* Set up dbop for input */ | ||
148 | while (!(DBOP_STAT & (1<<10))); /* Wait for fifo to empty */ | ||
149 | DBOP_CTRL |= (1<<19); /* Tri-state DBOP on read cycle */ | ||
150 | DBOP_CTRL &= ~(1<<16); /* disable output (1:write enabled) */ | ||
151 | DBOP_TIMPOL_01 = 0xe167e167; /* Set Timing & Polarity regs 0 & 1 */ | ||
152 | DBOP_TIMPOL_23 = 0xe167006e; /* Set Timing & Polarity regs 2 & 3 */ | ||
153 | |||
154 | DBOP_CTRL |= (1<<15); /* start read */ | ||
155 | while (!(DBOP_STAT & (1<<16))); /* wait for valid data */ | ||
156 | |||
157 | int delay=10; | ||
158 | while(delay--); /* short delay before reading */ | ||
159 | |||
160 | _dbop_din = DBOP_DIN; /* Read dbop data*/ | ||
161 | |||
162 | /* Reset dbop for output */ | ||
163 | DBOP_TIMPOL_01 = 0x6e167; /* Set Timing & Polarity regs 0 & 1 */ | ||
164 | DBOP_TIMPOL_23 = 0xa167e06f; /* Set Timing & Polarity regs 2 & 3 */ | ||
165 | DBOP_CTRL |= (1<<16); /* Enable output (0:write disable) */ | ||
166 | DBOP_CTRL &= ~(1<<19); /* Tri-state when no active write */ | ||
167 | } | ||
168 | #if !defined(BOOTLOADER) && defined(HAVE_SCROLLWHEEL) | ||
169 | scrollwheel(_dbop_din); | ||
170 | #endif | ||
171 | read_missed = false; | ||
172 | return _dbop_din; | ||
173 | } | ||
174 | |||
175 | unsigned short button_dbop_data(void) | ||
176 | { | ||
177 | return _dbop_din; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Get button pressed from hardware | ||
182 | */ | ||
183 | int button_read_device(void) | ||
184 | { | ||
185 | int btn = BUTTON_NONE; | ||
186 | /* read buttons from dbop */ | ||
187 | unsigned short dbop = button_read_dbop(); | ||
188 | |||
189 | /* hold button */ | ||
190 | if(dbop & (1<<12)) | ||
191 | { | ||
192 | hold_button = true; | ||
193 | return btn; | ||
194 | } | ||
195 | else | ||
196 | { | ||
197 | hold_button = false; | ||
198 | } | ||
199 | |||
200 | if (dbop & (1<<8)) | ||
201 | btn |= BUTTON_POWER; | ||
202 | |||
203 | if (!(dbop & (1<<15))) | ||
204 | btn |= BUTTON_REC; | ||
205 | |||
206 | /* Set afsel, so that we can read our buttons */ | ||
207 | GPIOC_AFSEL &= ~(1<<2|1<<3|1<<4|1<<5|1<<6); | ||
208 | /* set dir so we can read our buttons (but reset the C pins first) */ | ||
209 | GPIOB_DIR &= ~(1<<4); | ||
210 | GPIOC_DIR |= (1<<2|1<<3|1<<4|1<<5|1<<6); | ||
211 | GPIOC_PIN(2) = (1<<2); | ||
212 | GPIOC_PIN(3) = (1<<3); | ||
213 | GPIOC_PIN(4) = (1<<4); | ||
214 | GPIOC_PIN(5) = (1<<5); | ||
215 | GPIOC_PIN(6) = (1<<6); | ||
216 | |||
217 | GPIOC_DIR &= ~(1<<2|1<<3|1<<4|1<<5|1<<6); | ||
218 | |||
219 | int delay = 8; /* small delay needed to read buttons correctly */ | ||
220 | while(delay--); | ||
221 | |||
222 | /* direct GPIO connections */ | ||
223 | if (!GPIOC_PIN(2)) | ||
224 | btn |= BUTTON_UP; | ||
225 | if (!GPIOC_PIN(3)) | ||
226 | btn |= BUTTON_LEFT; | ||
227 | if (!GPIOC_PIN(4)) | ||
228 | btn |= BUTTON_SELECT; | ||
229 | if (!GPIOC_PIN(5)) | ||
230 | btn |= BUTTON_RIGHT; | ||
231 | if (!GPIOC_PIN(6)) | ||
232 | btn |= BUTTON_DOWN; | ||
233 | |||
234 | /* return to settings needed for lcd */ | ||
235 | GPIOC_DIR |= (1<<2|1<<3|1<<4|1<<5|1<<6); | ||
236 | GPIOC_AFSEL |= (1<<2|1<<3|1<<4|1<<5|1<<6); | ||
237 | |||
238 | #ifndef BOOTLOADER | ||
239 | /* light handling */ | ||
240 | if (hold_button != hold_button_old) | ||
241 | { | ||
242 | hold_button_old = hold_button; | ||
243 | backlight_hold_changed(hold_button); | ||
244 | } | ||
245 | #endif /* BOOTLOADER */ | ||
246 | /* The int_btn variable is set in the button interrupt handler */ | ||
247 | return btn; | ||
248 | } | ||