|
|||
Prex Home / Browse Source - Prex Version: 0.9.0 |
|||
root/bsp/drv/arm/gba/swkbd.c/* [<][>][^][v][top][bottom][index][help] */DEFINITIONSThis source file includes following definitions.
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] */ | |||
Copyright© 2005-2009 Kohsuke Ohtani |