Annotation of prex-old/dev/arm/gba/keypad.c, Revision 1.1.1.1.2.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>
1.1.1.1.2.1! nbrk 36: #include "keypad.h"
1.1 nbrk 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 */
1.1.1.1.2.1! nbrk 109: static irq_t keypad_irq; /* Handle for keyboard irq */
1.1 nbrk 110: static int nr_open; /* Open count */
1.1.1.1.2.1! nbrk 111: static struct event keypad_event;
1.1 nbrk 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 {
1.1.1.1.2.1! nbrk 137: sched_wakeup(&keypad_event);
1.1 nbrk 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: {
1.1.1.1.2.1! nbrk 231: int rc, c;
1.1 nbrk 232: size_t count;
233:
234: if (input_handler)
235: return EBUSY;
236: if (*nbyte == 0)
237: return 0;
238: if (keyq_empty()) {
1.1.1.1.2.1! nbrk 239: rc = sched_sleep(&keypad_event);
1.1 nbrk 240: if (rc == SLP_INTR)
241: return EINTR;
242: }
243: for (count = 0; count < *nbyte; count++) {
244: if (keyq_empty())
245: break;
1.1.1.1.2.1! nbrk 246: c = keyq_dequeue();
! 247: if (umem_copyout(&c, buf, 1))
! 248: return EFAULT;
1.1 nbrk 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:
1.1.1.1.2.1! nbrk 279: event_init(&keypad_event, "keypad");
! 280:
1.1 nbrk 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);
1.1.1.1.2.1! nbrk 286: ASSERT(keypad_irq != IRQ_NULL);
1.1 nbrk 287:
288: /* Enable interrupt for all key */
289: REG_KEYCNT = KEY_ALL | KEYIRQ_EN;
290: return 0;
291: }
292:
CVSweb