Annotation of prex/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 <console.h>
! 71: #include "lcd.h"
! 72: #include "kbd_img.h"
! 73: #include "keymap.h"
! 74: #include "keypad.h"
! 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);
! 85: static int kbd_ioctl(device_t, u_long, void *);
! 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
! 168: kbd_timeout(void *arg)
! 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':
! 353: #ifdef DEBUG
! 354: debug_dump(DUMP_THREAD);
! 355: debug_dump(DUMP_TASK);
! 356: debug_dump(DUMP_VM);
! 357: #endif
! 358: break;
! 359: }
! 360: if (move) {
! 361: timeout = CURSOR_WAIT;
! 362: move_cursor();
! 363: }
! 364: out:
! 365: ignore_key = 1;
! 366: timer_callout(&kbd_tmr, timeout, &kbd_timeout, NULL);
! 367: return;
! 368: }
! 369:
! 370: /*
! 371: * I/O control
! 372: */
! 373: static int
! 374: kbd_ioctl(device_t dev, u_long cmd, void *arg)
! 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