📄 keypad.c
字号:
/*- * Copyright (c) 2005, Kohsuke Ohtani * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * keypad.c - GBA keypad driver */#include <driver.h>#include <keycode.h>/* Parameters */#define KEYQ_SIZE 32#define KEYPAD_IRQ 12/* Registers for keypad control */#define REG_KEYSTS (*(volatile uint16_t *)0x4000130)#define REG_KEYCNT (*(volatile uint16_t *)0x4000132)/* KEY_STS/KEY_CNT */#define KEY_A 0x0001#define KEY_B 0x0002#define KEY_SELECT 0x0004#define KEY_START 0x0008#define KEY_RIGHT 0x0010#define KEY_LEFT 0x0020#define KEY_UP 0x0040#define KEY_DOWN 0x0080#define KEY_R 0x0100#define KEY_L 0x0200#define KEY_ALL 0x03ff/* KEY_CNT value */#define KEYIRQ_EN 0x4000 /* 0=Disable, 1=Enable */#define KEYIRQ_COND 0x8000 /* 0=Logical OR, 1=Logical AND */typedef void (*input_func)(u_char);static int keypad_init();static int keypad_open();static int keypad_close();static int keypad_read();/* * Driver structure */struct driver keypad_drv __driver_entry = { /* name */ "GBA Keypad", /* order */ 4, /* init */ keypad_init,};static struct devio keypad_io = { /* open */ keypad_open, /* close */ keypad_close, /* read */ keypad_read, /* write */ NULL, /* ioctl */ NULL, /* event */ NULL,};/* * Key map */static const u_char key_map[] = { 0, 'A', /* A */ 'B', /* B */ K_TAB, /* Select */ K_ENTR, /* Start */ K_RGHT, /* Right */ K_LEFT, /* Left */ K_UP, /* Up */ K_DOWN, /* Down */ 'R', /* R */ 'L', /* L */};#define KEY_MAX (sizeof(key_map) / sizeof(u_char))static device_t keypad_dev; /* Device object */static int keypad_irq; /* Handle for keyboard irq */static int nr_open; /* Open count */static struct event io_event = EVENT_INIT(io_event, "keypad");static u_char keyq[KEYQ_SIZE]; /* Queue for ascii character */static int q_tail;static int q_head;static input_func input_handler;/* * Keyboard queue operation */#define keyq_next(i) (((i) + 1) & (KEYQ_SIZE - 1))#define keyq_empty() (q_tail == q_head)#define keyq_full() (keyq_next(q_tail) == q_head)/* * Put one charcter on key queue */static void keyq_enqueue(u_char c){ /* Forward key to input handker */ if (input_handler) input_handler(c); else { sched_wakeup(&io_event); if (keyq_full()) return; keyq[q_tail] = c; q_tail = keyq_next(q_tail); }}/* * Get one character from key queue */static u_char keyq_dequeue(void){ u_char c; c = keyq[q_head]; q_head = keyq_next(q_head); return c;}/* * Interrupt service routine */static int keypad_isr(int irq){ uint16_t sts; sts = ~REG_KEYSTS & KEY_ALL; if (sts == (KEY_SELECT|KEY_START)) system_reset(); if (sts & KEY_A) keyq_enqueue('A'); if (sts & KEY_B) keyq_enqueue('B'); if (sts & KEY_SELECT) keyq_enqueue(K_TAB); if (sts & KEY_START) keyq_enqueue(K_ENTR); if (sts & KEY_RIGHT) keyq_enqueue(K_RGHT); if (sts & KEY_LEFT) keyq_enqueue(K_LEFT); if (sts & KEY_UP) keyq_enqueue(K_UP); if (sts & KEY_DOWN) keyq_enqueue(K_DOWN); if (sts & KEY_R) keyq_enqueue('R'); if (sts & KEY_L) keyq_enqueue('L'); return 0;}/* * Open */static int keypad_open(device_t dev, int mode){ if (input_handler) return EBUSY; if (nr_open > 0) return EBUSY; nr_open++; return 0;}/* * Close */static int keypad_close(device_t dev){ if (input_handler) return EBUSY; if (nr_open != 1) return EINVAL; nr_open--; return 0;}/* * Read */static int keypad_read(device_t dev, char *buf, size_t *nbyte, int blkno){ int rc; size_t count; if (input_handler) return EBUSY; if (*nbyte == 0) return 0; if (keyq_empty()) { rc = sched_sleep(&io_event); if (rc == SLP_INTR) return EINTR; } for (count = 0; count < *nbyte; count++) { if (keyq_empty()) break; *buf = keyq_dequeue(); buf++; } *nbyte = count; return 0;}/* * Attach input handler for another driver. * * After an input handler is attached, all key event is forwarded * to that handler. */void keypad_attach(void (*handler)(u_char)) { input_handler = handler;}/* * Initialize */int keypad_init(void){ input_handler = NULL; keypad_dev = device_create(&keypad_io, "keypad"); ASSERT(keypad_dev); /* Disable keypad interrupt */ REG_KEYCNT = 0; /* Setup isr */ keypad_irq = irq_attach(KEYPAD_IRQ, IPL_INPUT, 0, keypad_isr, NULL); ASSERT(keypad_irq != -1); /* Enable interrupt for all key */ REG_KEYCNT = KEY_ALL | KEYIRQ_EN; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -