Annotation of prex-old/dev/arm/gba/keypad.c, Revision 1.1.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