summaryrefslogtreecommitdiff
path: root/firmware/drivers/button.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/button.c')
-rw-r--r--firmware/drivers/button.c424
1 files changed, 1 insertions, 423 deletions
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index 599c22bc80..8acae01006 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -72,8 +72,7 @@ static bool remote_filter_first_keypress;
72#define REPEAT_INTERVAL_FINISH 5 72#define REPEAT_INTERVAL_FINISH 5
73 73
74/* the power-off button and number of repeated keys before shutting off */ 74/* the power-off button and number of repeated keys before shutting off */
75#if (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD) ||\ 75#if (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD)
76 (CONFIG_KEYPAD == IRIVER_IFP7XX_PAD)
77#define POWEROFF_BUTTON BUTTON_PLAY 76#define POWEROFF_BUTTON BUTTON_PLAY
78#define POWEROFF_COUNT 40 77#define POWEROFF_COUNT 40
79#elif !defined(TARGET_TREE) 78#elif !defined(TARGET_TREE)
@@ -87,344 +86,10 @@ static int button_read(void);
87static bool remote_button_hold_only(void); 86static bool remote_button_hold_only(void);
88#endif 87#endif
89 88
90#if CONFIG_KEYPAD == IPOD_4G_PAD
91/* Variable to use for setting button status in interrupt handler */
92int int_btn = BUTTON_NONE;
93#ifdef HAVE_WHEEL_POSITION
94static int wheel_position = -1;
95static bool send_events = true;
96#endif
97#endif
98
99#ifdef HAVE_HEADPHONE_DETECTION 89#ifdef HAVE_HEADPHONE_DETECTION
100bool phones_present = false; 90bool phones_present = false;
101#endif 91#endif
102 92
103#if (CONFIG_KEYPAD == IPOD_4G_PAD) && !defined(IPOD_MINI)
104static void opto_i2c_init(void)
105{
106 int i, curr_value;
107
108 /* wait for value to settle */
109 i = 1000;
110 curr_value = (inl(0x7000c104) << 16) >> 24;
111 while (i > 0)
112 {
113 int new_value = (inl(0x7000c104) << 16) >> 24;
114
115 if (new_value != curr_value) {
116 i = 10000;
117 curr_value = new_value;
118 }
119 else {
120 i--;
121 }
122 }
123
124 GPIOB_OUTPUT_VAL |= 0x10;
125 DEV_EN |= 0x10000;
126 DEV_RS |= 0x10000;
127 udelay(5);
128 DEV_RS &= ~0x10000; /* finish reset */
129
130 outl(0xffffffff, 0x7000c120);
131 outl(0xffffffff, 0x7000c124);
132 outl(0xc00a1f00, 0x7000c100);
133 outl(0x1000000, 0x7000c104);
134}
135
136static inline int ipod_4g_button_read(void)
137{
138 int whl = -1;
139
140 /* The ipodlinux source had a udelay(250) here, but testing has shown that
141 it is not needed - tested on Nano, Color/Photo and Video. */
142 /* udelay(250);*/
143
144 int btn = BUTTON_NONE;
145 unsigned reg = 0x7000c104;
146 if ((inl(0x7000c104) & 0x4000000) != 0) {
147 unsigned status = inl(0x7000c140);
148
149 reg = reg + 0x3C; /* 0x7000c140 */
150 outl(0x0, 0x7000c140); /* clear interrupt status? */
151
152 if ((status & 0x800000ff) == 0x8000001a) {
153 static int old_wheel_value IDATA_ATTR = -1;
154 static int wheel_repeat = 0;
155
156 if (status & 0x100)
157 btn |= BUTTON_SELECT;
158 if (status & 0x200)
159 btn |= BUTTON_RIGHT;
160 if (status & 0x400)
161 btn |= BUTTON_LEFT;
162 if (status & 0x800)
163 btn |= BUTTON_PLAY;
164 if (status & 0x1000)
165 btn |= BUTTON_MENU;
166 if (status & 0x40000000) {
167 /* NB: highest wheel = 0x5F, clockwise increases */
168 int new_wheel_value = (status << 9) >> 25;
169 whl = new_wheel_value;
170 backlight_on();
171 /* The queue should have no other events when scrolling */
172 if (queue_empty(&button_queue) && old_wheel_value >= 0) {
173
174 /* This is for later = BUTTON_SCROLL_TOUCH;*/
175 int wheel_delta = new_wheel_value - old_wheel_value;
176 unsigned long data;
177 int wheel_keycode;
178
179 if (wheel_delta < -48)
180 wheel_delta += 96; /* Forward wrapping case */
181 else if (wheel_delta > 48)
182 wheel_delta -= 96; /* Backward wrapping case */
183
184 if (wheel_delta > 4) {
185 wheel_keycode = BUTTON_SCROLL_FWD;
186 } else if (wheel_delta < -4) {
187 wheel_keycode = BUTTON_SCROLL_BACK;
188 } else goto wheel_end;
189
190#ifdef HAVE_WHEEL_POSITION
191 if (send_events)
192#endif
193 {
194 data = (wheel_delta << 16) | new_wheel_value;
195 queue_post(&button_queue, wheel_keycode | wheel_repeat,
196 (void *)data);
197 }
198
199 if (!wheel_repeat) wheel_repeat = BUTTON_REPEAT;
200 }
201
202 old_wheel_value = new_wheel_value;
203 } else if (old_wheel_value >= 0) {
204 /* scroll wheel up */
205 old_wheel_value = -1;
206 wheel_repeat = 0;
207 }
208
209 } else if (status == 0xffffffff) {
210 opto_i2c_init();
211 }
212 }
213
214wheel_end:
215
216 if ((inl(reg) & 0x8000000) != 0) {
217 outl(0xffffffff, 0x7000c120);
218 outl(0xffffffff, 0x7000c124);
219 }
220 /* Save the new absolute wheel position */
221 wheel_position = whl;
222 return btn;
223}
224
225void ipod_4g_button_int(void)
226{
227 CPU_HI_INT_CLR = I2C_MASK;
228 /* The following delay was 250 in the ipodlinux source, but 50 seems to
229 work fine - tested on Nano, Color/Photo and Video. */
230 udelay(50);
231 outl(0x0, 0x7000c140);
232 int_btn = ipod_4g_button_read();
233 outl(inl(0x7000c104) | 0xC000000, 0x7000c104);
234 outl(0x400a1f00, 0x7000c100);
235
236 GPIOB_OUTPUT_VAL |= 0x10;
237 CPU_INT_EN = 0x40000000;
238 CPU_HI_INT_EN = I2C_MASK;
239}
240#endif
241#if (CONFIG_KEYPAD == IPOD_3G_PAD) || defined(IPOD_MINI)
242/* iPod 3G and mini 1G, mini 2G uses iPod 4G code */
243void handle_scroll_wheel(int new_scroll, int was_hold, int reverse)
244{
245 int wheel_keycode = BUTTON_NONE;
246 static int prev_scroll = -1;
247 static int direction = 0;
248 static int count = 0;
249 static int scroll_state[4][4] = {
250 {0, 1, -1, 0},
251 {-1, 0, 0, 1},
252 {1, 0, 0, -1},
253 {0, -1, 1, 0}
254 };
255
256 if ( prev_scroll == -1 ) {
257 prev_scroll = new_scroll;
258 }
259 else if (direction != scroll_state[prev_scroll][new_scroll]) {
260 direction = scroll_state[prev_scroll][new_scroll];
261 count = 0;
262 }
263 else if (!was_hold) {
264 backlight_on();
265 if (++count == 6) { /* reduce sensitivity */
266 count = 0;
267 switch (direction) {
268 case 1:
269 if (reverse) {
270 /* 'r' keypress */
271 wheel_keycode = BUTTON_SCROLL_FWD;
272 }
273 else {
274 /* 'l' keypress */
275 wheel_keycode = BUTTON_SCROLL_BACK;
276 }
277 break;
278 case -1:
279 if (reverse) {
280 /* 'l' keypress */
281 wheel_keycode = BUTTON_SCROLL_BACK;
282 }
283 else {
284 /* 'r' keypress */
285 wheel_keycode = BUTTON_SCROLL_FWD;
286 }
287 break;
288 default:
289 /* only happens if we get out of sync */
290 break;
291 }
292 }
293 }
294 if (wheel_keycode != BUTTON_NONE && queue_empty(&button_queue))
295 queue_post(&button_queue, wheel_keycode, NULL);
296 prev_scroll = new_scroll;
297}
298#endif
299#if (CONFIG_KEYPAD == IPOD_4G_PAD) && defined(IPOD_MINI)
300/* mini 1 only, mini 2G uses iPod 4G code */
301static int ipod_mini_button_read(void)
302{
303 unsigned char source, wheel_source, state, wheel_state;
304 static bool was_hold = false;
305 int btn = BUTTON_NONE;
306
307 /* The ipodlinux source had a udelay(250) here, but testing has shown that
308 it is not needed - tested on mini 1g. */
309 /* udelay(250);*/
310
311 /* get source(s) of interupt */
312 source = GPIOA_INT_STAT & 0x3f;
313 wheel_source = GPIOB_INT_STAT & 0x30;
314
315 if (source == 0 && wheel_source == 0) {
316 return BUTTON_NONE; /* not for us */
317 }
318
319 /* get current keypad & wheel status */
320 state = GPIOA_INPUT_VAL & 0x3f;
321 wheel_state = GPIOB_INPUT_VAL & 0x30;
322
323 /* toggle interrupt level */
324 GPIOA_INT_LEV = ~state;
325 GPIOB_INT_LEV = ~wheel_state;
326
327 /* hold switch causes all outputs to go low */
328 /* we shouldn't interpret these as key presses */
329 if ((state & 0x20)) {
330 if (!(state & 0x1))
331 btn |= BUTTON_SELECT;
332 if (!(state & 0x2))
333 btn |= BUTTON_MENU;
334 if (!(state & 0x4))
335 btn |= BUTTON_PLAY;
336 if (!(state & 0x8))
337 btn |= BUTTON_RIGHT;
338 if (!(state & 0x10))
339 btn |= BUTTON_LEFT;
340
341 if (wheel_source & 0x30) {
342 handle_scroll_wheel((wheel_state & 0x30) >> 4, was_hold, 1);
343 }
344 }
345
346 was_hold = button_hold();
347
348 /* ack any active interrupts */
349 if (source)
350 GPIOA_INT_CLR = source;
351 if (wheel_source)
352 GPIOB_INT_CLR = wheel_source;
353
354 return btn;
355}
356
357void ipod_mini_button_int(void)
358{
359 CPU_HI_INT_CLR = GPIO_MASK;
360 int_btn = ipod_mini_button_read();
361 //CPU_INT_EN = 0x40000000;
362 CPU_HI_INT_EN = GPIO_MASK;
363}
364#endif
365#if CONFIG_KEYPAD == IPOD_3G_PAD
366static int ipod_3g_button_read(void)
367{
368 unsigned char source, state;
369 static int was_hold = 0;
370 int btn = BUTTON_NONE;
371 /*
372 * we need some delay for g3, cause hold generates several interrupts,
373 * some of them delayed
374 */
375 udelay(250);
376
377 /* get source of interupts */
378 source = GPIOA_INT_STAT;
379
380
381 /* get current keypad status */
382 state = GPIOA_INPUT_VAL;
383 GPIOA_INT_LEV = ~state;
384
385 if (was_hold && source == 0x40 && state == 0xbf) {
386 /* ack any active interrupts */
387 GPIOA_INT_CLR = source;
388 return BUTTON_NONE;
389 }
390 was_hold = 0;
391
392
393 if ((state & 0x20) == 0) {
394 /* 3g hold switch is active low */
395 was_hold = 1;
396 /* hold switch on 3g causes all outputs to go low */
397 /* we shouldn't interpret these as key presses */
398 GPIOA_INT_CLR = source;
399 return BUTTON_NONE;
400 }
401 if ((state & 0x1) == 0) {
402 btn |= BUTTON_RIGHT;
403 }
404 if ((state & 0x2) == 0) {
405 btn |= BUTTON_SELECT;
406 }
407 if ((state & 0x4) == 0) {
408 btn |= BUTTON_PLAY;
409 }
410 if ((state & 0x8) == 0) {
411 btn |= BUTTON_LEFT;
412 }
413 if ((state & 0x10) == 0) {
414 btn |= BUTTON_MENU;
415 }
416
417 if (source & 0xc0) {
418 handle_scroll_wheel((state & 0xc0) >> 6, was_hold, 0);
419 }
420
421 /* ack any active interrupts */
422 GPIOA_INT_CLR = source;
423
424 return btn;
425}
426#endif
427
428static void button_tick(void) 93static void button_tick(void)
429{ 94{
430 static int count = 0; 95 static int count = 0;
@@ -669,45 +334,6 @@ void button_init(void)
669 /* nothing to initialize here */ 334 /* nothing to initialize here */
670#elif CONFIG_KEYPAD == GMINI100_PAD 335#elif CONFIG_KEYPAD == GMINI100_PAD
671 /* nothing to initialize here */ 336 /* nothing to initialize here */
672#elif (CONFIG_KEYPAD == IPOD_4G_PAD) && !defined(IPOD_MINI)
673 opto_i2c_init();
674 /* hold button - enable as input */
675 GPIOA_ENABLE |= 0x20;
676 GPIOA_OUTPUT_EN &= ~0x20;
677 /* hold button - set interrupt levels */
678 GPIOA_INT_LEV = ~(GPIOA_INPUT_VAL & 0x20);
679 GPIOA_INT_CLR = GPIOA_INT_STAT & 0x20;
680 /* enable interrupts */
681 GPIOA_INT_EN = 0x20;
682 /* unmask interrupt */
683 CPU_INT_EN = 0x40000000;
684 CPU_HI_INT_EN = I2C_MASK;
685
686#elif (CONFIG_KEYPAD == IPOD_4G_PAD) && defined(IPOD_MINI)
687 /* iPod Mini G1 */
688 /* buttons - enable as input */
689 GPIOA_ENABLE |= 0x3f;
690 GPIOA_OUTPUT_EN &= ~0x3f;
691 /* scroll wheel- enable as input */
692 GPIOB_ENABLE |= 0x30; /* port b 4,5 */
693 GPIOB_OUTPUT_EN &= ~0x30; /* port b 4,5 */
694 /* buttons - set interrupt levels */
695 GPIOA_INT_LEV = ~(GPIOA_INPUT_VAL & 0x3f);
696 GPIOA_INT_CLR = GPIOA_INT_STAT & 0x3f;
697 /* scroll wheel - set interrupt levels */
698 GPIOB_INT_LEV = ~(GPIOB_INPUT_VAL & 0x30);
699 GPIOB_INT_CLR = GPIOB_INT_STAT & 0x30;
700 /* enable interrupts */
701 GPIOA_INT_EN = 0x3f;
702 GPIOB_INT_EN = 0x30;
703 /* unmask interrupt */
704 CPU_INT_EN = 0x40000000;
705 CPU_HI_INT_EN = GPIO_MASK;
706
707#elif CONFIG_KEYPAD == IPOD_3G_PAD
708 GPIOA_INT_LEV = ~GPIOA_INPUT_VAL;
709 GPIOA_INT_CLR = GPIOA_INT_STAT;
710 GPIOA_INT_EN = 0xff;
711#endif /* CONFIG_KEYPAD */ 337#endif /* CONFIG_KEYPAD */
712 queue_init(&button_queue, true); 338 queue_init(&button_queue, true);
713 button_read(); 339 button_read();
@@ -1266,35 +892,6 @@ static int button_read(void)
1266 if (data & 0x01) 892 if (data & 0x01)
1267 btn |= BUTTON_ON; 893 btn |= BUTTON_ON;
1268 894
1269#elif (CONFIG_KEYPAD == IPOD_4G_PAD)
1270 static bool hold_button = false;
1271 bool hold_button_old;
1272
1273 /* normal buttons */
1274 hold_button_old = hold_button;
1275 hold_button = button_hold();
1276
1277 if (hold_button != hold_button_old)
1278 backlight_hold_changed(hold_button);
1279
1280 (void)data;
1281 /* The int_btn variable is set in the button interrupt handler */
1282 btn = int_btn;
1283
1284#elif (CONFIG_KEYPAD == IPOD_3G_PAD)
1285 static bool hold_button = false;
1286 bool hold_button_old;
1287
1288 /* normal buttons */
1289 hold_button_old = hold_button;
1290 hold_button = button_hold();
1291
1292 if (hold_button != hold_button_old)
1293 backlight_hold_changed(hold_button);
1294
1295 (void)data;
1296 btn = ipod_3g_button_read();
1297
1298#endif /* CONFIG_KEYPAD */ 895#endif /* CONFIG_KEYPAD */
1299 896
1300#ifdef HAVE_LCD_BITMAP 897#ifdef HAVE_LCD_BITMAP
@@ -1313,13 +910,6 @@ static int button_read(void)
1313 return retval; 910 return retval;
1314} 911}
1315 912
1316#if (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD)
1317bool button_hold(void)
1318{
1319 return (GPIOA_INPUT_VAL & 0x20)?false:true;
1320}
1321#endif
1322
1323#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) 913#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1324bool button_hold(void) 914bool button_hold(void)
1325{ 915{
@@ -1357,18 +947,6 @@ int button_status(void)
1357 return lastbtn; 947 return lastbtn;
1358} 948}
1359 949
1360#ifdef HAVE_WHEEL_POSITION
1361int wheel_status(void)
1362{
1363 return wheel_position;
1364}
1365
1366void wheel_send_events(bool send)
1367{
1368 send_events = send;
1369}
1370#endif
1371
1372void button_clear_queue(void) 950void button_clear_queue(void)
1373{ 951{
1374 queue_clear(&button_queue); 952 queue_clear(&button_queue);