Annotation of prex-old/dev/arm/gba/swkbd.c, Revision 1.1.1.1.2.1
1.1 nbrk 1: /*-
2: * Copyright (c) 2005, Kohsuke Ohtani
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. Neither the name of the author nor the names of any co-contributors
14: * may be used to endorse or promote products derived from this software
15: * without specific prior written permission.
16: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27: * SUCH DAMAGE.
28: */
29:
30: /*
31: * swkbd.c - GBA software keyboard driver
32: */
33:
34: /**
35: * This driver emulates a generic keyboard by using GBA keypad.
36: *
37: * <Key assign>
38: *
39: * On-screen keyboard:
40: *
41: * A : Select pointed key
42: * B : Enter key
43: * Select : Hide keyboard
44: * Start :
45: * Right : Move keyboard cursor right
46: * Left : Move keyboard cursor left
47: * Up : Move keyboard cursor up
48: * Down : Move keyboard cursor down
49: * Button R : Toggle shift state
50: * Button L : Toggle shift state
51: *
52: * No on-screen keyboard:
53: *
54: * A : A key
55: * B : B key
56: * Select : Show keyboard
57: * Start : Enter key
58: * Right : Right key
59: * Left : Left key
60: * Up : Up key
61: * Down : Down key
62: * Button R : R key
63: * Button L : L Key
64: *
65: */
66:
67: #include <driver.h>
68: #include <prex/keycode.h>
69: #include <sys/tty.h>
1.1.1.1.2.1! nbrk 70: #include <console.h>
1.1 nbrk 71: #include "lcd.h"
72: #include "kbd_img.h"
73: #include "keymap.h"
1.1.1.1.2.1! nbrk 74: #include "keypad.h"
1.1 nbrk 75:
76: /*
77: * Since GBA does not kick interrupt for the button release, we have
78: * to wait for a while after button is pressed. Otherwise, many key
79: * events are queued by one button press.
80: */
81: #define CURSOR_WAIT 100 /* 100 msec */
82: #define BUTTON_WAIT 200 /* 200 msec */
83:
84: static int kbd_init(void);
1.1.1.1.2.1! nbrk 85: static int kbd_ioctl(device_t, u_long, void *);
1.1 nbrk 86:
87: static void move_cursor(void);
88:
89: /*
90: * Driver structure
91: */
92: struct driver kbd_drv = {
93: /* name */ "GBA S/W Keyboard",
94: /* order */ 11,
95: /* init */ kbd_init,
96: };
97:
98: static struct devio kbd_io = {
99: /* open */ NULL,
100: /* close */ NULL,
101: /* read */ NULL,
102: /* write */ NULL,
103: /* ioctl */ kbd_ioctl,
104: /* event */ NULL,
105: };
106:
107: static device_t kbd_dev; /* Device object */
108: static struct tty *tty;
109: static struct timer kbd_tmr;
110:
111: /* Meta key status */
112: static int shift;
113: static int alt;
114: static int ctrl;
115: static int capslk;
116:
117: static int kbd_on;
118: static int kbd_page;
119: static volatile int ignore_key;
120: static u_int pos_x, pos_y;
121: static int cur_obj; /* Current object for cursor */
122:
123: /*
124: * Select keyboard page.
125: *
126: * Page0 ... Text only
127: * Page1 ... Text & Normal keyboard
128: * Page2 ... Text & Shifted keyboard
129: */
130: static void
131: kbd_select(int page)
132: {
133:
134: if (page == 0)
135: REG_DISPCNT = 0x0840; /* only BG3 */
136: else if (page == 1) {
137: REG_DISPCNT = 0x1A40; /* use BG1&3 */
138: move_cursor();
139: } else {
140: REG_DISPCNT = 0x1C40; /* use BG2&3 */
141: move_cursor();
142: }
143: kbd_page = page;
144: }
145:
146: /*
147: * Toggle keyboard type: normal or shift.
148: */
149: static void
150: kbd_toggle(void)
151: {
152: int page;
153:
154: if (kbd_page == 0)
155: return;
156: if (capslk)
157: page = shift ? 1 : 2;
158: else
159: page = shift ? 2 : 1;
160: kbd_select(page);
161: }
162:
163: /*
164: * Timer call back handler.
165: * Just clear ignoring flag.
166: */
167: static void
1.1.1.1.2.1! nbrk 168: kbd_timeout(void *arg)
1.1 nbrk 169: {
170:
171: ignore_key = 0;
172: }
173:
174: /*
175: * Move cursor to point key.
176: */
177: static void
178: move_cursor(void)
179: {
180: uint16_t *oam = OAM;
181: struct _key_info *ki;
182: int i, x, y;
183:
184: ki = (struct _key_info *)&key_info[pos_y][pos_x];
185: x = ki->pos_x + 108;
186: y = pos_y * 8 + 11;
187: i = 0;
188: switch (ki->width) {
189: case 9: i = 0; break;
190: case 11: i = 1; break;
191: case 12: i = 2; break;
192: case 13: i = 3; break;
193: case 15: i = 4; break;
194: case 17: i = 5; break;
195: case 19: i = 6; break;
196: case 53: i = 7; break;
197: }
198: if (i != cur_obj) {
199: oam[cur_obj * 4] = (uint16_t)((oam[cur_obj * 4] & 0xff00) | 160);
200: oam[cur_obj * 4 + 1] = (uint16_t)((oam[cur_obj * 4 + 1] & 0xfe00) | 240);
201: cur_obj = i;
202: }
203: oam[i * 4] = (uint16_t)((oam[i * 4] & 0xff00) | y);
204: oam[i * 4 + 1] = (uint16_t)((oam[i * 4 + 1] & 0xfe00) | x);
205: }
206:
207: /*
208: * Process key press
209: */
210: static void
211: key_press(void)
212: {
213: struct _key_info *ki;
214: u_char ac;
215:
216: ki = (struct _key_info *)&key_info[pos_y][pos_x];
217: ac = ki->normal;
218:
219: /* Check meta key */
220: switch (ac) {
221: case K_SHFT:
222: shift = !shift;
223: kbd_toggle();
224: return;
225: case K_CTRL:
226: ctrl = !ctrl;
227: return;
228: case K_ALT:
229: alt = !alt;
230: return;
231: case K_CAPS:
232: capslk = !capslk;
233: kbd_toggle();
234: return;
235: }
236: /* Check ctrl & shift state */
237: if (ctrl) {
238: if (ac >= 'a' && ac <= 'z')
239: ac = ac - 'a' + 0x01;
240: else if (ac == '\\')
241: ac = 0x1c;
242: else
243: ac = 0;
244: } else if (kbd_page == 2)
245: ac = ki->shifted;
246:
247: if (ac == 0)
248: return;
249:
250: /* Check caps lock state */
251: if (capslk) {
252: if (ac >= 'A' && ac <= 'Z')
253: ac += 'a' - 'A';
254: else if (ac >= 'a' && ac <= 'z')
255: ac -= 'a' - 'A';
256: }
257:
258: /* Check alt key */
259: if (alt)
260: ac |= 0x80;
261:
262: /* Insert key to queue */
263: tty_input(ac, tty);
264:
265: /* Reset meta status */
266: if (shift) {
267: shift = 0;
268: kbd_toggle();
269: }
270: if (ctrl)
271: ctrl = 0;
272: if (alt)
273: alt = 0;
274: }
275:
276: /*
277: * Input handler
278: * This routine will be called by keypad ISR.
279: */
280: static void
281: kbd_isr(u_char c)
282: {
283: int move = 0;
284: int timeout = BUTTON_WAIT;
285:
286: if (ignore_key)
287: return;
288:
289: /* Select key */
290: if (c == '\t') {
291: kbd_on = !kbd_on;
292: kbd_select(kbd_on);
293:
294: /* Reset meta status */
295: shift = 0;
296: alt = 0;
297: ctrl = 0;
298: capslk = 0;
299: goto out;
300: }
301:
302: /* Direct input */
303: if (!kbd_on) {
304: tty_input(c, tty);
305: goto out;
306: }
307:
308: switch (c) {
309: case K_LEFT:
310: if (pos_x > 0) {
311: if (pos_y == 4 && pos_x >=4 && pos_x <= 8) /* Space */
312: pos_x = 3;
313: pos_x--;
314: move = 1;
315: }
316: break;
317: case K_RGHT:
318: if (pos_x < max_x[pos_y]) {
319: if (pos_y == 4 && pos_x > 3 && pos_x <= 7) /* Space */
320: pos_x = 8;
321: pos_x++;
322: move = 1;
323: }
324: break;
325: case K_UP:
326: if (pos_y > 0 ) {
327: pos_y--;
328: move = 1;
329: if (pos_x > max_x[pos_y])
330: pos_x = max_x[pos_y];
331: }
332: break;
333: case K_DOWN:
334: if (pos_y < 4) {
335: pos_y++;
336: move = 1;
337: if (pos_x > max_x[pos_y])
338: pos_x = max_x[pos_y];
339: }
340: break;
341: case 'A':
342: key_press();
343: break;
344: case 'B':
345: tty_input('\n', tty);
346: break;
347: case 'R':
348: case 'L':
349: shift = shift ? 0 : 1;
350: kbd_toggle();
351: break;
352: case '\n':
1.1.1.1.2.1! nbrk 353: #ifdef DEBUG
! 354: debug_dump(DUMP_THREAD);
! 355: debug_dump(DUMP_TASK);
! 356: debug_dump(DUMP_VM);
1.1 nbrk 357: #endif
358: break;
359: }
360: if (move) {
361: timeout = CURSOR_WAIT;
362: move_cursor();
363: }
364: out:
365: ignore_key = 1;
1.1.1.1.2.1! nbrk 366: timer_callout(&kbd_tmr, timeout, &kbd_timeout, NULL);
1.1 nbrk 367: return;
368: }
369:
370: /*
371: * I/O control
372: */
373: static int
1.1.1.1.2.1! nbrk 374: kbd_ioctl(device_t dev, u_long cmd, void *arg)
1.1 nbrk 375: {
376:
377: return 0;
378: }
379:
380: /*
381: * Init font
382: */
383: static void
384: init_kbd_image(void)
385: {
386: uint8_t bit;
387: uint16_t val1, val2;
388: uint16_t *pal = BG_PALETTE;
389: uint16_t *tile1 = KBD1_TILE;
390: uint16_t *tile2 = KBD2_TILE;
391: uint16_t *map1 = KBD1_MAP;
392: uint16_t *map2 = KBD2_MAP;
393: int i, j, row, col;
394:
395: /* Load tiles for keyboard image */
396: for (i = 0; i < 32; i++)
397: tile1[i] = 0;
398:
399: for (i = 0; i < 64 * 12; i++) {
400: bit = 0x01;
401: for (j = 0; j < 4; j++) {
402: val1 = kbd1_bitmap[i] & bit ? 0xff : 0x03;
403: val2 = kbd2_bitmap[i] & bit ? 0xff : 0x03;
404: bit = bit << 1;
405: val1 |= kbd1_bitmap[i] & bit ? 0xff00 : 0x0300;
406: val2 |= kbd2_bitmap[i] & bit ? 0xff00 : 0x0300;
407: bit = bit << 1;
408: tile1[i * 4 + 32 + j] = val1;
409: tile2[i * 4 + j] = val2;
410: }
411: }
412:
413:
414: /* Setup map */
415: i = 1;
416: for (row = 1; row < 7; row++) {
417: for (col = 13; col < 29; col++) {
418: map1[row * 32 + col] = (uint16_t)i;
419: map2[row * 32 + col] = (uint16_t)(i + 127);
420: i++;
421: }
422: }
423:
424: pal[3] = RGB(0,0,31); /* Kbd bg color */
425: pal[255] = RGB(28,28,28); /* Kbd color */
426:
427: /* Setup video */
428: REG_BG1CNT = 0x1284; /* Size0, 256color, priority0 */
429: REG_BG2CNT = 0x1484; /* Size0, 256color, priority0 */
430: kbd_select(1);
431: }
432:
433: /*
434: * Initialize keyboard cursor
435: */
436: static void
437: init_cursor(void)
438: {
439: int i, j;
440: uint8_t bit;
441: uint16_t val;
442: uint16_t *oam = OAM;
443: uint16_t *cur = CURSOR_DATA;
444: uint16_t *pal = SPL_PALETTE;
445:
446: /* Move out all objects */
447: for (i = 0; i < 128; i++) {
448: oam[0] = 160;
449: oam[1] = 240;
450: oam += 4;
451: }
452: /* Load cursor splite */
453: for (i = 0; i < 64 * 7 + 64 * 8; i++) {
454: bit = 0x01;
455: for (j = 0; j < 4; j++) {
456: val = cursor_bitmap[i] & bit ? 0xff : 0;
457: bit = bit << 1;
458: val |= cursor_bitmap[i] & bit ? 0xff00 : 0;
459: bit = bit << 1;
460: cur[i * 4 + j] = val;
461: }
462: }
463:
464: /* Setup cursors */
465: oam = OAM;
466: for (i = 0; i < 7; i++) {
467: oam[0] = (uint16_t)(0x6000 + 160); /* 256 color, Horizontal */
468: oam[1] = (uint16_t)(0x8000 + 240); /* 32x16 */
469: oam[2] = (uint16_t)(i * 16); /* Tile number */
470: oam += 4;
471: }
472: /* for space key */
473: oam[0] = 0x6000 + 160; /* 256 color, Horizontal */
474: oam[1] = 0xC000 + 240; /* 64x32 */
475: oam[2] = 112;
476:
477: pal[255] = RGB(31,0,0); /* cursor color */
478: }
479:
480: /*
481: * Initialize
482: */
483: static int
484: kbd_init(void)
485: {
486:
487: kbd_dev = device_create(&kbd_io, "kbd", DF_CHR);
488: ASSERT(kbd_dev);
489:
490: ignore_key = 0;
491: cur_obj = 0;
492: kbd_on = 1;
493: kbd_page = 0;
494: pos_x = 0;
495: pos_y = 0;
496:
497: timer_init(&kbd_tmr);
498: init_cursor();
499: init_kbd_image();
500: move_cursor();
501:
502: /* Hook keypad isr */
503: keypad_attach(kbd_isr);
504:
505: /* Attach to console */
506: console_attach(&tty);
507: return 0;
508: }
509:
CVSweb