Project

General

Profile

Statistics
| Branch: | Revision:

root / 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
}