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