Annotation of prex-old/dev/arm/gba/swkbd.c, Revision 1.1.1.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>
70: #include "lcd.h"
71: #include "kbd_img.h"
72: #include "keymap.h"
73:
74: extern void console_attach(struct tty **tpp);
75: extern void keypad_attach(void (*handler)(u_char));
76:
77: /*
78: * Since GBA does not kick interrupt for the button release, we have
79: * to wait for a while after button is pressed. Otherwise, many key
80: * events are queued by one button press.
81: */
82: #define CURSOR_WAIT 100 /* 100 msec */
83: #define BUTTON_WAIT 200 /* 200 msec */
84:
85: static int kbd_init(void);
86: static int kbd_ioctl(device_t, int, u_long);
87:
88: static void move_cursor(void);
89:
90: /*
91: * Driver structure
92: */
93: struct driver kbd_drv = {
94: /* name */ "GBA S/W Keyboard",
95: /* order */ 11,
96: /* init */ kbd_init,
97: };
98:
99: static struct devio kbd_io = {
100: /* open */ NULL,
101: /* close */ NULL,
102: /* read */ NULL,
103: /* write */ NULL,
104: /* ioctl */ kbd_ioctl,
105: /* event */ NULL,
106: };
107:
108: static device_t kbd_dev; /* Device object */
109: static struct tty *tty;
110: static struct timer kbd_tmr;
111:
112: /* Meta key status */
113: static int shift;
114: static int alt;
115: static int ctrl;
116: static int capslk;
117:
118: static int kbd_on;
119: static int kbd_page;
120: static volatile int ignore_key;
121: static u_int pos_x, pos_y;
122: static int cur_obj; /* Current object for cursor */
123:
124: /*
125: * Select keyboard page.
126: *
127: * Page0 ... Text only
128: * Page1 ... Text & Normal keyboard
129: * Page2 ... Text & Shifted keyboard
130: */
131: static void
132: kbd_select(int page)
133: {
134:
135: if (page == 0)
136: REG_DISPCNT = 0x0840; /* only BG3 */
137: else if (page == 1) {
138: REG_DISPCNT = 0x1A40; /* use BG1&3 */
139: move_cursor();
140: } else {
141: REG_DISPCNT = 0x1C40; /* use BG2&3 */
142: move_cursor();
143: }
144: kbd_page = page;
145: }
146:
147: /*
148: * Toggle keyboard type: normal or shift.
149: */
150: static void
151: kbd_toggle(void)
152: {
153: int page;
154:
155: if (kbd_page == 0)
156: return;
157: if (capslk)
158: page = shift ? 1 : 2;
159: else
160: page = shift ? 2 : 1;
161: kbd_select(page);
162: }
163:
164: /*
165: * Timer call back handler.
166: * Just clear ignoring flag.
167: */
168: static void
169: kbd_timeout(u_long tmp)
170: {
171:
172: ignore_key = 0;
173: }
174:
175: /*
176: * Move cursor to point key.
177: */
178: static void
179: move_cursor(void)
180: {
181: uint16_t *oam = OAM;
182: struct _key_info *ki;
183: int i, x, y;
184:
185: ki = (struct _key_info *)&key_info[pos_y][pos_x];
186: x = ki->pos_x + 108;
187: y = pos_y * 8 + 11;
188: i = 0;
189: switch (ki->width) {
190: case 9: i = 0; break;
191: case 11: i = 1; break;
192: case 12: i = 2; break;
193: case 13: i = 3; break;
194: case 15: i = 4; break;
195: case 17: i = 5; break;
196: case 19: i = 6; break;
197: case 53: i = 7; break;
198: }
199: if (i != cur_obj) {
200: oam[cur_obj * 4] = (uint16_t)((oam[cur_obj * 4] & 0xff00) | 160);
201: oam[cur_obj * 4 + 1] = (uint16_t)((oam[cur_obj * 4 + 1] & 0xfe00) | 240);
202: cur_obj = i;
203: }
204: oam[i * 4] = (uint16_t)((oam[i * 4] & 0xff00) | y);
205: oam[i * 4 + 1] = (uint16_t)((oam[i * 4 + 1] & 0xfe00) | x);
206: }
207:
208: /*
209: * Process key press
210: */
211: static void
212: key_press(void)
213: {
214: struct _key_info *ki;
215: u_char ac;
216:
217: ki = (struct _key_info *)&key_info[pos_y][pos_x];
218: ac = ki->normal;
219:
220: /* Check meta key */
221: switch (ac) {
222: case K_SHFT:
223: shift = !shift;
224: kbd_toggle();
225: return;
226: case K_CTRL:
227: ctrl = !ctrl;
228: return;
229: case K_ALT:
230: alt = !alt;
231: return;
232: case K_CAPS:
233: capslk = !capslk;
234: kbd_toggle();
235: return;
236: }
237: /* Check ctrl & shift state */
238: if (ctrl) {
239: if (ac >= 'a' && ac <= 'z')
240: ac = ac - 'a' + 0x01;
241: else if (ac == '\\')
242: ac = 0x1c;
243: else
244: ac = 0;
245: } else if (kbd_page == 2)
246: ac = ki->shifted;
247:
248: if (ac == 0)
249: return;
250:
251: /* Check caps lock state */
252: if (capslk) {
253: if (ac >= 'A' && ac <= 'Z')
254: ac += 'a' - 'A';
255: else if (ac >= 'a' && ac <= 'z')
256: ac -= 'a' - 'A';
257: }
258:
259: /* Check alt key */
260: if (alt)
261: ac |= 0x80;
262:
263: /* Insert key to queue */
264: tty_input(ac, tty);
265:
266: /* Reset meta status */
267: if (shift) {
268: shift = 0;
269: kbd_toggle();
270: }
271: if (ctrl)
272: ctrl = 0;
273: if (alt)
274: alt = 0;
275: }
276:
277: /*
278: * Input handler
279: * This routine will be called by keypad ISR.
280: */
281: static void
282: kbd_isr(u_char c)
283: {
284: int move = 0;
285: int timeout = BUTTON_WAIT;
286:
287: if (ignore_key)
288: return;
289:
290: /* Select key */
291: if (c == '\t') {
292: kbd_on = !kbd_on;
293: kbd_select(kbd_on);
294:
295: /* Reset meta status */
296: shift = 0;
297: alt = 0;
298: ctrl = 0;
299: capslk = 0;
300: goto out;
301: }
302:
303: /* Direct input */
304: if (!kbd_on) {
305: tty_input(c, tty);
306: goto out;
307: }
308:
309: switch (c) {
310: case K_LEFT:
311: if (pos_x > 0) {
312: if (pos_y == 4 && pos_x >=4 && pos_x <= 8) /* Space */
313: pos_x = 3;
314: pos_x--;
315: move = 1;
316: }
317: break;
318: case K_RGHT:
319: if (pos_x < max_x[pos_y]) {
320: if (pos_y == 4 && pos_x > 3 && pos_x <= 7) /* Space */
321: pos_x = 8;
322: pos_x++;
323: move = 1;
324: }
325: break;
326: case K_UP:
327: if (pos_y > 0 ) {
328: pos_y--;
329: move = 1;
330: if (pos_x > max_x[pos_y])
331: pos_x = max_x[pos_y];
332: }
333: break;
334: case K_DOWN:
335: if (pos_y < 4) {
336: pos_y++;
337: move = 1;
338: if (pos_x > max_x[pos_y])
339: pos_x = max_x[pos_y];
340: }
341: break;
342: case 'A':
343: key_press();
344: break;
345: case 'B':
346: tty_input('\n', tty);
347: break;
348: case 'R':
349: case 'L':
350: shift = shift ? 0 : 1;
351: kbd_toggle();
352: break;
353: case '\n':
354: #ifdef CONFIG_KDUMP
355: debug_dump(1); /* Thread dump */
356: debug_dump(2); /* Thread dump */
357: debug_dump(7); /* VM dump */
358: #endif
359: break;
360: }
361: if (move) {
362: timeout = CURSOR_WAIT;
363: move_cursor();
364: }
365: out:
366: ignore_key = 1;
367: timer_callout(&kbd_tmr, kbd_timeout, 0, timeout);
368: return;
369: }
370:
371: /*
372: * I/O control
373: */
374: static int
375: kbd_ioctl(device_t dev, int cmd, u_long arg)
376: {
377:
378: return 0;
379: }
380:
381: /*
382: * Init font
383: */
384: static void
385: init_kbd_image(void)
386: {
387: uint8_t bit;
388: uint16_t val1, val2;
389: uint16_t *pal = BG_PALETTE;
390: uint16_t *tile1 = KBD1_TILE;
391: uint16_t *tile2 = KBD2_TILE;
392: uint16_t *map1 = KBD1_MAP;
393: uint16_t *map2 = KBD2_MAP;
394: int i, j, row, col;
395:
396: /* Load tiles for keyboard image */
397: for (i = 0; i < 32; i++)
398: tile1[i] = 0;
399:
400: for (i = 0; i < 64 * 12; i++) {
401: bit = 0x01;
402: for (j = 0; j < 4; j++) {
403: val1 = kbd1_bitmap[i] & bit ? 0xff : 0x03;
404: val2 = kbd2_bitmap[i] & bit ? 0xff : 0x03;
405: bit = bit << 1;
406: val1 |= kbd1_bitmap[i] & bit ? 0xff00 : 0x0300;
407: val2 |= kbd2_bitmap[i] & bit ? 0xff00 : 0x0300;
408: bit = bit << 1;
409: tile1[i * 4 + 32 + j] = val1;
410: tile2[i * 4 + j] = val2;
411: }
412: }
413:
414:
415: /* Setup map */
416: i = 1;
417: for (row = 1; row < 7; row++) {
418: for (col = 13; col < 29; col++) {
419: map1[row * 32 + col] = (uint16_t)i;
420: map2[row * 32 + col] = (uint16_t)(i + 127);
421: i++;
422: }
423: }
424:
425: pal[3] = RGB(0,0,31); /* Kbd bg color */
426: pal[255] = RGB(28,28,28); /* Kbd color */
427:
428: /* Setup video */
429: REG_BG1CNT = 0x1284; /* Size0, 256color, priority0 */
430: REG_BG2CNT = 0x1484; /* Size0, 256color, priority0 */
431: kbd_select(1);
432: }
433:
434: /*
435: * Initialize keyboard cursor
436: */
437: static void
438: init_cursor(void)
439: {
440: int i, j;
441: uint8_t bit;
442: uint16_t val;
443: uint16_t *oam = OAM;
444: uint16_t *cur = CURSOR_DATA;
445: uint16_t *pal = SPL_PALETTE;
446:
447: /* Move out all objects */
448: for (i = 0; i < 128; i++) {
449: oam[0] = 160;
450: oam[1] = 240;
451: oam += 4;
452: }
453: /* Load cursor splite */
454: for (i = 0; i < 64 * 7 + 64 * 8; i++) {
455: bit = 0x01;
456: for (j = 0; j < 4; j++) {
457: val = cursor_bitmap[i] & bit ? 0xff : 0;
458: bit = bit << 1;
459: val |= cursor_bitmap[i] & bit ? 0xff00 : 0;
460: bit = bit << 1;
461: cur[i * 4 + j] = val;
462: }
463: }
464:
465: /* Setup cursors */
466: oam = OAM;
467: for (i = 0; i < 7; i++) {
468: oam[0] = (uint16_t)(0x6000 + 160); /* 256 color, Horizontal */
469: oam[1] = (uint16_t)(0x8000 + 240); /* 32x16 */
470: oam[2] = (uint16_t)(i * 16); /* Tile number */
471: oam += 4;
472: }
473: /* for space key */
474: oam[0] = 0x6000 + 160; /* 256 color, Horizontal */
475: oam[1] = 0xC000 + 240; /* 64x32 */
476: oam[2] = 112;
477:
478: pal[255] = RGB(31,0,0); /* cursor color */
479: }
480:
481: /*
482: * Initialize
483: */
484: static int
485: kbd_init(void)
486: {
487:
488: kbd_dev = device_create(&kbd_io, "kbd", DF_CHR);
489: ASSERT(kbd_dev);
490:
491: ignore_key = 0;
492: cur_obj = 0;
493: kbd_on = 1;
494: kbd_page = 0;
495: pos_x = 0;
496: pos_y = 0;
497:
498: timer_init(&kbd_tmr);
499: init_cursor();
500: init_kbd_image();
501: move_cursor();
502:
503: /* Hook keypad isr */
504: keypad_attach(kbd_isr);
505:
506: /* Attach to console */
507: console_attach(&tty);
508: return 0;
509: }
510:
CVSweb