scoutos / prex-0.9.0 / bsp / drv / arm / gba / swkbd.c @ 03e9c04a
History | View | Annotate | Download (10.5 KB)
1 | 03e9c04a | Brad Neuman | /*-
|
---|---|---|---|
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 | } |