📄 keybutton.c
字号:
/*-------------------------------------------------------------- 4X4键盘使用中断号IRQ_EINT4, IRQ_EINT5, IRQ_EINT6, IRQ_EINT7 4X4键盘行输入线:S3C2410_GPF4, S3C2410_GPF5,S3C2410_GPF6, S3C2410_GPF7(与中断号分别对应) 4X4键盘列扫描线:S3C2410_GPG0, S3C2410_GPG2, S3C2410_GPG8, S3C2410_GPG9--------------------------------------------------------------*/ #include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/miscdevice.h>#include <asm/uaccess.h> /*copy user*/#include <linux/sched.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <asm/io.h>#include <asm-arm/arch-s3c2410/irqs.h>#include <asm-arm/irq.h>#include <linux/interrupt.h>#include <linux/ioport.h>#include <linux/wait.h>//#include <linux/irq.h>#include <linux/cdev.h>#include <linux/delay.h>#include <linux/devfs_fs.h>#include <linux/devfs_fs_kernel.h>#include <asm/hardware.h>#include <asm/arch/regs-gpio.h>#define DEVICE_NAME "keybutton"#define BUTTON_MAJOR 234#define BUTTON_MINOR 0#define KBDSTATUS_UP 0#define KBDSTATUS_DOWN 1#define KBDSTATUS_DOWNX 2static int kbd_status; //按键状态static int irq_col_tab[] = { IRQ_EINT4, IRQ_EINT5, IRQ_EINT6, IRQ_EINT7};#define COL_NUM ( (sizeof irq_col_tab) / sizeof (irq_col_tab[0]) )static unsigned gpio_col_tab[] = {S3C2410_GPF4, S3C2410_GPF5,S3C2410_GPF6, S3C2410_GPF7};static unsigned gpio_row_tab[] = {S3C2410_GPG0, S3C2410_GPG2, S3C2410_GPG8, S3C2410_GPG9 };static unsigned gpio_row_out_tab[] = { S3C2410_GPG0_OUTP, S3C2410_GPG2_OUTP, S3C2410_GPG8_OUTP, S3C2410_GPG9_OUTP };static unsigned key_scan_value[] = {0x001,0x004,0x100,0x200};#define ROW_NUM ( sizeof gpio_row_tab / sizeof (gpio_row_tab[0]) )static int ready = 0;static int key_value = 0, last_value = 0;int col_no, row_no,r;unsigned int gpf_con,gpf_dat,gpf_up,gpg_con,gpg_dat,gpg_up,gpf_con1,gpg_con1,gpf_dat1,gpg_dat1;static DECLARE_WAIT_QUEUE_HEAD(buttons_wait);//static int waitting_down_tab[] = {1, 1, 1, 1,};static void __iomem *gpbase;//static void __iomem *addrpenda_map;//static void __iomem *addrpendb_map;static void scan_kbd(void);static void kbd_timer_handler(void);static int ISKBD_DOWN(void);static int ISKBD_DOWN(void){ int c1; gpf_con1=readl(gpbase+0x50) ; gpf_dat1=readl(gpbase+0x54); gpg_con1=readl(gpbase+0x60) ; gpg_dat1=readl(gpbase+0x64); //printk("ISKBD_DOWN col_no= %d\n",col_no); if(col_no==0){ writel(gpf_con1 & 0xfcff,gpbase+0x50); c1 = readl(gpbase+0x54) & 0x10; writel((gpf_con1 | (2<<8)),gpbase+0x50) ; } else if(col_no==1){ writel(gpf_con1 & 0xf3ff,gpbase+0x50); c1 = readl(gpbase+0x54) & 0x20; writel((gpf_con1 | (2<<10)),gpbase+0x50) ; } else if(col_no==2){ writel(gpf_con1 & 0xcfff,gpbase+0x50) ; c1 = readl(gpbase+0x54) & 0x40; writel((gpf_con1 |(2<<12)),gpbase+0x50) ; } else if(col_no==3){ writel(gpf_con1 & 0x3fff,gpbase+0x50) ; c1 = readl(gpbase+0x54) & 0x80; writel((gpf_con1 |(2<<14)),gpbase+0x50) ;//F端口中F7管脚设为中断模式 } else return 0; if(!c1) c1=1; else c1=0; return c1;} static void kbd_timer_handler(void){ if(ISKBD_DOWN()) { //printk("key socend test down\n"); if(kbd_status == KBDSTATUS_DOWNX) { kbd_status = KBDSTATUS_DOWN; scan_kbd(); } mdelay(100); kbd_timer_handler(); } else{ kbd_status = KBDSTATUS_UP; }}static void scan_kbd(void){ int i; //spin_lock_irq(&kbd); gpf_con=readl(gpbase+0x50) ; gpf_dat=readl(gpbase+0x54); gpf_up=readl(gpbase+0x58); gpg_con=readl(gpbase+0x60) ; gpg_dat=readl(gpbase+0x64); gpg_up=readl(gpbase+0x68); //printk("gpf_con=%x,gpf_up=%x,gpf_dat=%x.gpg_con+%x\n",gpf_con,gpf_up,gpf_dat,gpg_con); writel(gpf_con & 0x00ff,gpbase+0x50); writel(gpf_up | 0xf7,gpbase+0x58); //printk("gpf_con=%x,gpg_con=%x\n",readl(gpbase+0x50),readl(gpbase+0x60)); for (i = 0; i < 4; i++) { //unsigned char val = 0x10; //printk("scan row\n"); writel((gpg_dat | (key_scan_value[i])),gpbase+0x64); udelay(100); r= s3c2410_gpio_getpin(gpio_col_tab[col_no]); writel((gpg_dat & (~(key_scan_value[i]))),gpbase+0x64); udelay(100); if(r) { // found row_no = i; break; } } writel((gpf_con |(2<<2)|(2<<8)|(2<<10)|(2<<12)|(2<<14)),gpbase+0x50) ; udelay(100); set_irq_type(IRQ_EINT4,IRQT_LOW); set_irq_type(IRQ_EINT5,IRQT_LOW); set_irq_type(IRQ_EINT6,IRQT_LOW); set_irq_type(IRQ_EINT7,IRQT_LOW); //printk("gpf_con=%x,gpg_con=%x\n",readl(gpbase+0x50),readl(gpbase+0x60)); //spin_lock_irq(&kbd); if (col_no < 0 || row_no < 0) { mdelay(10); kbd_timer_handler(); } key_value = row_no * 4 + col_no + 1; //printk("kernel key_value=%d\n",key_value); ready = 1; wake_up_interruptible(&buttons_wait);}static irqreturn_t buttons_irq(int irq, void *dev_id, struct pt_regs *reg){ int i; unsigned long flags; col_no = -1; row_no = -1; //printk("interupt=%d\n",irq); for (i = 0; i < COL_NUM; i++) { if (irq_col_tab[i] == irq) { col_no = i; //printk("irq col= %d\n",i); break; } } if (col_no < 0) { goto EXIT; } //printk("kbd_status 0=%d\n",kbd_status); if(kbd_status == KBDSTATUS_UP) { //printk("key down\n"); local_irq_save(flags); //printk("ISKBD_DOWN=%d\n",ISKBD_DOWN()); if(ISKBD_DOWN()) { //printk("key first test down\n"); kbd_status = KBDSTATUS_DOWNX; mdelay(10); kbd_timer_handler(); } else local_irq_restore(flags); } EXIT: return IRQ_HANDLED;}static void free_irqs(void){ int i; for (i = 0; i < COL_NUM; i++) { int irq = irq_col_tab[i]; free_irq(irq, buttons_irq); }}static void buttons_io_port_init(void){ int i; for (i = 0; i < ROW_NUM; i ++) { unsigned gpio = gpio_row_tab[i]; s3c2410_gpio_cfgpin(gpio, gpio_row_out_tab[i]); s3c2410_gpio_pullup(gpio,1); s3c2410_gpio_setpin(gpio,0); }}static int buttons4x4_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos){ //static int key; //int repeat = key == key_value; // key == key_value; if (!ready) return -EAGAIN; if (count != sizeof key_value) return -EINVAL; // if (repeat) { // return -EAGAIN; // } copy_to_user(buffer, &key_value, sizeof key_value); last_value = key_value; ready = 0; return sizeof key_value;}static unsigned int buttons4x4_select( struct file *file, struct poll_table_struct *wait){ if (ready) return 1; poll_wait(file, &buttons_wait, wait); return 0;}static int buttons4x4_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ switch(cmd) { default: return -EINVAL; }}static int buttons4x4_open(struct inode *inode, struct file *file){ int i,ret; //int port_irq; for (i = 0; i < COL_NUM; i++) { int irq = irq_col_tab[i]; set_irq_type(irq,IRQT_LOW); s3c2410_gpio_pullup(gpio_col_tab[i],1); ret = request_irq(irq, buttons_irq, SA_INTERRUPT, DEVICE_NAME, NULL); if (ret) { unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME); printk(DEVICE_NAME " can't request irq %d\n", irq); return ret; } } printk("keybutton interrupt register!\n"); return 0;}static int buttons4x4_release(struct inode *inode, struct file *file){ free_irqs(); return 0;}static struct file_operations buttons4x4_fops = { .owner = THIS_MODULE, .open = buttons4x4_open, .ioctl = buttons4x4_ioctl, .poll = buttons4x4_select, .read = buttons4x4_read, .release = buttons4x4_release,};static int __init buttons4x4_init(void){ int ret; //int i; ready = 0; #ifdef CONFIG_DEVFS_FS devfs_mk_cdev(MKDEV(BUTTON_MAJOR,BUTTON_MINOR),S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME); #endif ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &buttons4x4_fops); if (ret < 0) { printk(DEVICE_NAME " can't register major number\n"); return ret; } printk(DEVICE_NAME " keybutton register \n"); buttons_io_port_init(); gpbase=ioremap_nocache(0x56000000,0x80); kbd_status = KBDSTATUS_UP; return 0;}static void __exit buttons4x4_exit(void){ iounmap(gpbase); #ifdef CONFIG_DEVFS_FS devfs_remove(DEVICE_NAME); #endif unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME); printk(DEVICE_NAME " keybutton unregister \n");}module_init(buttons4x4_init);module_exit(buttons4x4_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("guibaijun");MODULE_DESCRIPTION("s3c2410_kdb_4x4 driver--07-08-07");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -