Annotation of prex-old/dev/arm/gba/swkbd.c, Revision 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