📄 s3c2410-kbd-final.c
字号:
//============================================================================//// File Name: s3c2410-kbd.c//////// (c) Copyright 05.08.2008 minghe. All rights reserved//////// This source code is xxx. proprietary and confidential//// information//////// Description://// keyboard driver for s3c2410 base on kernel 2.6//////// Modification History:////============================================================================#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/devfs_fs_kernel.h>#include <asm/hardware.h>#include <asm/delay.h>#include <asm/uaccess.h>#include <asm/arch-s3c2410/regs-gpio.h>#include <linux/poll.h>#include <asm/io.h>#include <asm-arm/arch-s3c2410/irqs.h>#include <asm-arm/irq.h>#include <linux/interrupt.h>#include <linux/wait.h>#include <linux/timer.h>#define DEVICE_NAME "s3c2410-kbd"#define kbd_major 233#define KBDRAW_MINOR 0#define MAX_KBD_BUF 16#define BUF_HEAD (kbddev.buf[kbddev.head])#define BUF_TAIL (kbddev.buf[kbddev.tail])#define INCBUF(x, mod) ((++(x))&((mod) - 1))#define KBD_TIMER_DELAY (HZ/10)#define KBD_TIMER_DELAY1 (HZ/100)//#define key1_irq IRQ_EINT0//#define key2_irq IRQ_EINT13//#define key3_irq IRQ_EINT11//#define key4_irq IRQ_EINT19//#define key1 s3c2410_gpio_getpin(S3C2410_GPF0)//#define key2 s3c2410_gpio_getpin(S3C2410_GPG5)#define KEYSTATUS_DOWNX 1#define KEYSTATUS_DOWN 2#define KEYSTATUS_UP 3#define KEY_DOWN 128 #define rows 4#define columns 2//#define CONFIG_DEVFS_FS#undef DEBUG//#define DEBUG#ifdef DEBUG#define DPRINTK( fmt, args... ) printk(DEVICE_NAME ": %s() %d " fmt, __FUNCTION__, __LINE__, ## args)#else#define DPRINTK( x... )#endiftypedef unsigned char KBD_RET;typedef struct{ unsigned int kbdStatus; KBD_RET buf[MAX_KBD_BUF]; unsigned int head, tail; wait_queue_head_t wq;} KBD_DEV;static KBD_DEV kbddev;static struct timer_list kbd_timer;static int key;static int cs[] = {S3C2410_GPB6, S3C2410_GPB7};static int rs[] = {S3C2410_GPF0, S3C2410_GPG5, S3C2410_GPG3, S3C2410_GPG11};static int key_irq[] = {IRQ_EINT0, IRQ_EINT13, IRQ_EINT11, IRQ_EINT19};static int rp_mod[] = {S3C2410_GPF0_EINT0, S3C2410_GPG5_EINT13, S3C2410_GPG3_EINT11, S3C2410_GPG11_EINT19};static int cp_mod[] = {S3C2410_GPB6_OUTP, S3C2410_GPB7_OUTP};//static int kbd_major = 0;//static int key_irq;static void (*kbdEvent)(void);void kbdEvent_dummy(void){};static int ISKBD_DOWN(void){ int i, j, key_down_flag = 0; //int *cp, *rp; //cp = cs; //rp = rs; for (i = 0; i < columns; i++) { for (j = 0; j < columns; j++) { if (j == i) s3c2410_gpio_setpin(cs[j], 0); else s3c2410_gpio_setpin(cs[j], 1); } for (j = 0; j < rows; j++) { if (!s3c2410_gpio_getpin(rs[j])) { key_down_flag = 1; break; } } if (key_down_flag) break; } for (j = 0; j < columns; j++) s3c2410_gpio_setpin(cs[j], 0); return key_down_flag;}static void KBD_CLOSE_INT(void){ int i; for (i = 0; i < rows; i++) disable_irq(key_irq[i]);// disable_irq(key1_irq);// disable_irq(key2_irq);// disable_irq(key3_irq);// disable_irq(key4_irq);}static void KBD_OPEN_INT(void){ int i; for (i = 0; i < rows; i++) enable_irq(key_irq[i]);// enable_irq(key1_irq);// enable_irq(key2_irq);// enable_irq(key3_irq);// enable_irq(key4_irq);}static irqreturn_t s3c2410_isr_kbd(int irq, void *dev_id, struct pt_regs *reg){ DPRINTK("Occured key board Interrupt, irq = %d\n",irq); if ((kbddev.kbdStatus == KEYSTATUS_UP)) { KBD_CLOSE_INT(); DPRINTK("Interrupt have been closed\n"); if (ISKBD_DOWN()) { kbddev.kbdStatus = KEYSTATUS_DOWNX; DPRINTK("KEYSTATUS is KEYSTATUS_DOWNX\n"); kbd_timer.expires = jiffies + KBD_TIMER_DELAY1; add_timer(&kbd_timer); } else { KBD_OPEN_INT(); DPRINTK("Interrupt have been opened\n"); } } return irq;}static void kbdEvent_raw(void){ if (kbddev.kbdStatus == KEYSTATUS_DOWN) { BUF_HEAD = (key | KEY_DOWN); } else { BUF_HEAD = key; } DPRINTK("BUF_HEAD = %d\n", BUF_HEAD); kbddev.head = INCBUF(kbddev.head, MAX_KBD_BUF); wake_up_interruptible(&(kbddev.wq)); DPRINTK("BUF_HEAD = %d\n", BUF_HEAD);}static int Read_ExINT_Key(void){ int i, j; int key_down_flag = 0; int key_value; int row = 0, col = 0; //int *cp, *rp; //cp = cs; //rp = rs; for (i = 0; i < columns; i++) { for (j = 0; j < columns; j++) { if (j == i) s3c2410_gpio_setpin(cs[j], 0); else s3c2410_gpio_setpin(cs[j], 1); } for (j = 0; j < rows; j++) { if (!s3c2410_gpio_getpin(rs[j])) { row = j; key_down_flag = 1; break; } } if (key_down_flag) { col = i; break; } } key_value = row*columns + col + 1; for (j = 0; j < columns; j++) s3c2410_gpio_setpin(cs[j], 0); return key_value;}static void s3c2410_get_kbd(void){ key = Read_ExINT_Key(); DPRINTK("key = %d\n", key); //kbdEvent = kbdEvent_raw; kbdEvent();}static void kbd_timer_handler(unsigned long data){ if (ISKBD_DOWN()) { if (kbddev.kbdStatus == KEYSTATUS_DOWNX) { kbddev.kbdStatus = KEYSTATUS_DOWN; DPRINTK("KEYSTATUS is KEYSTATUS_DOWN\n"); kbd_timer.expires = jiffies + KBD_TIMER_DELAY; s3c2410_get_kbd(); } else { kbd_timer.expires = jiffies + KBD_TIMER_DELAY; } add_timer(&kbd_timer); } else { kbddev.kbdStatus = KEYSTATUS_UP; del_timer(&kbd_timer); DPRINTK("KEY UP, code = %d\n",key); kbdEvent(); KBD_OPEN_INT(); }}static KBD_RET kbdRead(void){ KBD_RET kbd_ret; kbd_ret = BUF_TAIL; kbddev.tail = INCBUF(kbddev.tail, MAX_KBD_BUF); return kbd_ret;} static ssize_t s3c2410_kbd_read(struct file *filp, char * buffer, size_t count, loff_t *ppos){ KBD_RET kbd_ret; retry: if (kbddev.head != kbddev.tail) { DPRINTK("BUF_TAIL = %d\n", BUF_TAIL); kbd_ret = kbdRead(); DPRINTK("BUF_TAIL = %d\n", BUF_TAIL); copy_to_user(buffer, (char *)&kbd_ret, sizeof(KBD_RET)); return sizeof(KBD_RET); } else { if (filp -> f_flags & O_NONBLOCK) { DPRINTK("mod is nonblock\n"); return -EAGAIN; } DPRINTK("wait_queue has slept\n"); wait_event_interruptible(kbddev.wq, (kbddev.head != kbddev.tail)); DPRINTK("wait_queue is waked\n"); if (signal_pending(current)) return -ERESTARTSYS; goto retry; } return sizeof(KBD_RET);}static int s3c2410_kbd_open(struct inode *inode, struct file *filp){ kbddev.head = kbddev.tail = 0; kbdEvent = kbdEvent_raw; DPRINTK("cdev is opened\n"); return 0;}static int s3c2410_kbd_release(struct inode *inode, struct file *filp){ kbdEvent =kbdEvent_dummy; return 0;}unsigned int s3c2410_kbd_poll(struct file *filp, struct poll_table_struct *wait){ unsigned int mask = 0; poll_wait(filp, &kbddev.wq, wait); if(kbddev.head != kbddev.tail) { mask |= POLLIN | POLLRDNORM; DPRINTK("poll: data ready\n"); } return mask;}static struct file_operations s3c2410_fops = { .owner = THIS_MODULE, .open = s3c2410_kbd_open, .read = s3c2410_kbd_read, .release = s3c2410_kbd_release, .poll = s3c2410_kbd_poll,};static int __init s3c2410_kbd_init(void){ int ret; int i; for (i = 0; i < rows; i++) { set_irq_type(key_irq[i], IRQT_FALLING); s3c2410_gpio_cfgpin(rs[i], rp_mod[i]); s3c2410_gpio_pullup(rs[i], 1); }// set_irq_type(key1_irq, IRQT_FALLING);// set_irq_type(key2_irq, IRQT_FALLING);// set_irq_type(key3_irq, IRQT_FALLING);// set_irq_type(key4_irq, IRQT_FALLING); // s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_EINT0);// s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_EINT13);// s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_EINT11);// s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_EINT19);// s3c2410_gpio_pullup(S3C2410_GPF0, 1);// s3c2410_gpio_pullup(S3C2410_GPG5, 1);// s3c2410_gpio_pullup(S3C2410_GPG3, 1);// s3c2410_gpio_pullup(S3C2410_GPG11, 1); kbdEvent = kbdEvent_dummy; ret = register_chrdev(kbd_major, DEVICE_NAME, &s3c2410_fops); if (ret < 0) { DPRINTK(DEVICE_NAME " can't get major number\n"); return ret; } //kbd_major = ret; //#ifdef CONFIG_DEVFS_FS ret = devfs_mk_cdev(MKDEV(kbd_major, KBDRAW_MINOR), S_IFCHR | S_IRUSR | S_IWUSR, "keyboard"); if (ret < 0) { DPRINTK(DEVICE_NAME " can't make char device"); return ret; } //#endif for (i = 0; i < rows; i++) { ret = request_irq(key_irq[i], s3c2410_isr_kbd, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_kbd); if (ret < 0) { DPRINTK(DEVICE_NAME " can't request key%d_irq\n", i + 1); return ret; } }// ret = request_irq(key1_irq, s3c2410_isr_kbd, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_kbd);// if (ret < 0) // {// DPRINTK(DEVICE_NAME " can't request key1_irq\n");// return ret;// }// // ret = request_irq(key2_irq, s3c2410_isr_kbd, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_kbd);// if (ret < 0) // {// DPRINTK(DEVICE_NAME " can't request key2_irq\n");// return ret;// }// // ret = request_irq(key3_irq, s3c2410_isr_kbd, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_kbd);// if (ret < 0) // {// DPRINTK(DEVICE_NAME " can't request key2_irq\n");// return ret;// }// // ret = request_irq(key4_irq, s3c2410_isr_kbd, SA_INTERRUPT, DEVICE_NAME, s3c2410_isr_kbd);// if (ret < 0) // {// DPRINTK(DEVICE_NAME " can't request key4_irq\n");// return ret;// } for (i = 0; i < columns; i++) { s3c2410_gpio_cfgpin(cs[i], cp_mod[i]); s3c2410_gpio_setpin(cs[i], 0); }// s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPB6_OUTP);// s3c2410_gpio_cfgpin(S3C2410_GPB7, S3C2410_GPB7_OUTP);// s3c2410_gpio_setpin(S3C2410_GPB6, 0);// s3c2410_gpio_setpin(S3C2410_GPB7, 0); kbddev.head = kbddev.tail = 0; kbddev.kbdStatus = KEYSTATUS_UP; init_waitqueue_head(&(kbddev.wq)); init_timer(&kbd_timer); kbd_timer.function = kbd_timer_handler;#ifdef DEBUG s3c2410_kbd_open(NULL, NULL);#endif printk(DEVICE_NAME " initialized\n"); return 0;}static void __exit s3c2410_kbd_exit(void){#ifdef CONFIG_DEVFS_FS int i; for (i = 0; i < rows; i++) free_irq(key_irq[i], s3c2410_isr_kbd);// free_irq(key1_irq, s3c2410_isr_kbd);// free_irq(key2_irq, s3c2410_isr_kbd);// free_irq(key3_irq, s3c2410_isr_kbd);// free_irq(key4_irq, s3c2410_isr_kbd); unregister_chrdev(kbd_major, "keyboard"); unregister_chrdev(kbd_major,DEVICE_NAME); devfs_remove( "keyboard" );#endif}module_init(s3c2410_kbd_init);module_exit(s3c2410_kbd_exit); MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -