Prex Home / Browse Source - Prex Version: 0.9.0

root/bsp/drv/arm/gba/swkbd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. swkbd_select_page
  2. swkbd_toggle_shift
  3. swkbd_timeout
  4. swkbd_move_cursor
  5. swkbd_key_press
  6. swkbd_input
  7. swkbd_init_image
  8. swkbd_init_cursor
  9. swkbd_init

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

/* [<][>][^][v][top][bottom][index][help] */