[BACK]Return to keypad.c CVS log [TXT][DIR] Up to [local] / prex / dev / arm / gba

Annotation of prex/dev/arm/gba/keypad.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:  * keypad.c - GBA keypad driver
        !            32:  */
        !            33:
        !            34: #include <driver.h>
        !            35: #include <prex/keycode.h>
        !            36: #include "keypad.h"
        !            37:
        !            38: /* Parameters */
        !            39: #define KEYQ_SIZE      32
        !            40: #define KEYPAD_IRQ     12
        !            41:
        !            42: /* Registers for keypad control */
        !            43: #define REG_KEYSTS     (*(volatile uint16_t *)0x4000130)
        !            44: #define REG_KEYCNT     (*(volatile uint16_t *)0x4000132)
        !            45:
        !            46: /* KEY_STS/KEY_CNT */
        !            47: #define KEY_A          0x0001
        !            48: #define KEY_B          0x0002
        !            49: #define KEY_SELECT     0x0004
        !            50: #define KEY_START      0x0008
        !            51: #define KEY_RIGHT      0x0010
        !            52: #define KEY_LEFT       0x0020
        !            53: #define KEY_UP         0x0040
        !            54: #define KEY_DOWN       0x0080
        !            55: #define KEY_R          0x0100
        !            56: #define KEY_L          0x0200
        !            57:
        !            58: #define KEY_ALL                0x03ff
        !            59:
        !            60: /* KEY_CNT value */
        !            61: #define KEYIRQ_EN      0x4000  /* 0=Disable, 1=Enable */
        !            62: #define KEYIRQ_COND    0x8000  /* 0=Logical OR, 1=Logical AND */
        !            63:
        !            64: typedef void (*input_func)(u_char);
        !            65:
        !            66: static int keypad_init(void);
        !            67: static int keypad_open(device_t, int);
        !            68: static int keypad_close(device_t);
        !            69: static int keypad_read(device_t, char *, size_t *, int);
        !            70:
        !            71: /*
        !            72:  * Driver structure
        !            73:  */
        !            74: struct driver keypad_drv = {
        !            75:        /* name */      "GBA Keypad",
        !            76:        /* order */     4,
        !            77:        /* init */      keypad_init,
        !            78: };
        !            79:
        !            80: static struct devio keypad_io = {
        !            81:        /* open */      keypad_open,
        !            82:        /* close */     keypad_close,
        !            83:        /* read */      keypad_read,
        !            84:        /* write */     NULL,
        !            85:        /* ioctl */     NULL,
        !            86:        /* event */     NULL,
        !            87: };
        !            88:
        !            89: /*
        !            90:  * Key map
        !            91:  */
        !            92: static const u_char key_map[] = {
        !            93:        0,
        !            94:        'A',            /* A */
        !            95:        'B',            /* B */
        !            96:        '\t',           /* Select */
        !            97:        '\n',           /* Start */
        !            98:        K_RGHT,         /* Right */
        !            99:        K_LEFT,         /* Left */
        !           100:        K_UP,           /* Up */
        !           101:        K_DOWN,         /* Down */
        !           102:        'R',            /* R */
        !           103:        'L',            /* L */
        !           104: };
        !           105:
        !           106: #define KEY_MAX (sizeof(key_map) / sizeof(u_char))
        !           107:
        !           108: static device_t keypad_dev;    /* Device object */
        !           109: static irq_t keypad_irq;       /* Handle for keyboard irq */
        !           110: static int nr_open;            /* Open count */
        !           111: static struct event keypad_event;
        !           112:
        !           113: static u_char keyq[KEYQ_SIZE]; /* Queue for ascii character */
        !           114: static int q_tail;
        !           115: static int q_head;
        !           116:
        !           117: static input_func input_handler;
        !           118:
        !           119: /*
        !           120:  * Keyboard queue operation
        !           121:  */
        !           122: #define keyq_next(i)    (((i) + 1) & (KEYQ_SIZE - 1))
        !           123: #define keyq_empty()    (q_tail == q_head)
        !           124: #define keyq_full()     (keyq_next(q_tail) == q_head)
        !           125:
        !           126: /*
        !           127:  * Put one charcter on key queue
        !           128:  */
        !           129: static void
        !           130: keyq_enqueue(u_char c)
        !           131: {
        !           132:
        !           133:        /* Forward key to input handker */
        !           134:        if (input_handler)
        !           135:                input_handler(c);
        !           136:        else {
        !           137:                sched_wakeup(&keypad_event);
        !           138:                if (keyq_full())
        !           139:                        return;
        !           140:                keyq[q_tail] = c;
        !           141:                q_tail = keyq_next(q_tail);
        !           142:        }
        !           143: }
        !           144:
        !           145: /*
        !           146:  * Get one character from key queue
        !           147:  */
        !           148: static u_char
        !           149: keyq_dequeue(void)
        !           150: {
        !           151:        u_char c;
        !           152:
        !           153:        c = keyq[q_head];
        !           154:        q_head = keyq_next(q_head);
        !           155:        return c;
        !           156: }
        !           157:
        !           158: /*
        !           159:  * Interrupt service routine
        !           160:  */
        !           161: static int
        !           162: keypad_isr(int irq)
        !           163: {
        !           164:        uint16_t sts;
        !           165:
        !           166:        sts = ~REG_KEYSTS & KEY_ALL;
        !           167:
        !           168:        if (sts == (KEY_SELECT|KEY_START))
        !           169:                machine_reset();
        !           170:
        !           171:        if (sts & KEY_A)
        !           172:                keyq_enqueue('A');
        !           173:        if (sts & KEY_B)
        !           174:                keyq_enqueue('B');
        !           175:        if (sts & KEY_SELECT)
        !           176:                keyq_enqueue('\t');
        !           177:        if (sts & KEY_START)
        !           178:                keyq_enqueue('\n');
        !           179:        if (sts & KEY_RIGHT)
        !           180:                keyq_enqueue(K_RGHT);
        !           181:        if (sts & KEY_LEFT)
        !           182:                keyq_enqueue(K_LEFT);
        !           183:        if (sts & KEY_UP)
        !           184:                keyq_enqueue(K_UP);
        !           185:        if (sts & KEY_DOWN)
        !           186:                keyq_enqueue(K_DOWN);
        !           187:        if (sts & KEY_R)
        !           188:                keyq_enqueue('R');
        !           189:        if (sts & KEY_L)
        !           190:                keyq_enqueue('L');
        !           191:
        !           192:        return 0;
        !           193: }
        !           194:
        !           195: /*
        !           196:  * Open
        !           197:  */
        !           198: static int
        !           199: keypad_open(device_t dev, int mode)
        !           200: {
        !           201:
        !           202:        if (input_handler)
        !           203:                return EBUSY;
        !           204:        if (nr_open > 0)
        !           205:                return EBUSY;
        !           206:        nr_open++;
        !           207:        return 0;
        !           208: }
        !           209:
        !           210: /*
        !           211:  * Close
        !           212:  */
        !           213: static int
        !           214: keypad_close(device_t dev)
        !           215: {
        !           216:
        !           217:        if (input_handler)
        !           218:                return EBUSY;
        !           219:        if (nr_open != 1)
        !           220:                return EINVAL;
        !           221:        nr_open--;
        !           222:        return 0;
        !           223: }
        !           224:
        !           225: /*
        !           226:  * Read
        !           227:  */
        !           228: static int
        !           229: keypad_read(device_t dev, char *buf, size_t *nbyte, int blkno)
        !           230: {
        !           231:        int rc, c;
        !           232:        size_t count;
        !           233:
        !           234:        if (input_handler)
        !           235:                return EBUSY;
        !           236:        if (*nbyte == 0)
        !           237:                return 0;
        !           238:        if (keyq_empty()) {
        !           239:                rc = sched_sleep(&keypad_event);
        !           240:                if (rc == SLP_INTR)
        !           241:                        return EINTR;
        !           242:        }
        !           243:        for (count = 0; count < *nbyte; count++) {
        !           244:                if (keyq_empty())
        !           245:                        break;
        !           246:                c = keyq_dequeue();
        !           247:                if (umem_copyout(&c, buf, 1))
        !           248:                        return EFAULT;
        !           249:                buf++;
        !           250:        }
        !           251:        *nbyte = count;
        !           252:        return 0;
        !           253: }
        !           254:
        !           255: /*
        !           256:  * Attach input handler for another driver.
        !           257:  *
        !           258:  * After an input handler is attached, all key event is forwarded
        !           259:  * to that handler.
        !           260:  */
        !           261: void
        !           262: keypad_attach(void (*handler)(u_char))
        !           263: {
        !           264:
        !           265:        input_handler = handler;
        !           266: }
        !           267:
        !           268: /*
        !           269:  * Initialize
        !           270:  */
        !           271: int
        !           272: keypad_init(void)
        !           273: {
        !           274:        input_handler = NULL;
        !           275:
        !           276:        keypad_dev = device_create(&keypad_io, "keypad", DF_CHR);
        !           277:        ASSERT(keypad_dev);
        !           278:
        !           279:        event_init(&keypad_event, "keypad");
        !           280:
        !           281:        /* Disable keypad interrupt */
        !           282:        REG_KEYCNT = 0;
        !           283:
        !           284:        /* Setup isr */
        !           285:        keypad_irq = irq_attach(KEYPAD_IRQ, IPL_INPUT, 0, keypad_isr, NULL);
        !           286:        ASSERT(keypad_irq != IRQ_NULL);
        !           287:
        !           288:        /* Enable interrupt for all key */
        !           289:        REG_KEYCNT = KEY_ALL | KEYIRQ_EN;
        !           290:        return 0;
        !           291: }
        !           292:

CVSweb