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