📄 buttons.c
字号:
#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/miscdevice.h>#include <linux/sched.h>#include <linux/delay.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/irq.h>#include <linux/delay.h>#include <asm/hardware.h>#include <asm/irq.h>#define DEVICE_NAME "buttons"#define BUTTON_MAJOR 232/********************************************************* 4X4 矩阵键盘四个输入引脚: EINT0 -----( GPF0 )----INPUT EINT2 -----( GPF2 )----INPUT EINT11-----( GPG3 )----INPUT EINT19-----( GPG11 )----INPUT 四个输出引脚: KEYSCAN0---( GPE11 )----OUTPUT KEYSCAN1---( GPG6 )----OUTPUT KEYSCAN2---( GPE13 )----OUTPUT KEYSCAN3---( GPG2 )----OUTPUT**********************************************************//*int Key_Scan( void ){ int returnvalue;//delay// unsigned long j = jiffies +5;// while(jiffies<j);//上锁spin_lock_irq (&my_lock); GPGCON = GPGCON & (~((3<<22)|(3<<6))) | ((0<<22)|(0<<6)) ; //GPG11,13 set input GPFCON = GPFCON & (~((3<<4)|(3<<0))) | ((0<<4)|(0<<0)) ; //GPF2,0 set input //扫描键盘第4列 K16、K15、K14、K13 GPGDAT = GPGDAT & (~((1<<6)|(1<<2))) | (1<<6) | (0<<2) ; //GPG6 output 1;GPG2 output 0 GPEDAT = GPEDAT & (~((1<<13)|(1<<11))) | (1<<13) | (1<<11) ; //GPE13 output 1;GPE11 output 1 if( (GPFDAT&(1<< 0)) == 0 ) { returnvalue= 16 ;goto out;} else if( (GPFDAT&(1<< 2)) == 0 ) { returnvalue= 15 ;goto out;} else if( (GPGDAT&(1<< 3)) == 0 ) { returnvalue= 14 ;goto out;} else if( (GPGDAT&(1<<11)) == 0 ) { returnvalue= 13 ;goto out;} //扫描键盘第2列 K11、K8、K5、K2 GPGDAT = GPGDAT & (~((1<<6)|(1<<2))) | (0<<6) | (1<<2) ; //GPG6 output 0;GPG2 output 1 GPEDAT = GPEDAT & (~((1<<13)|(1<<11))) | (1<<13) | (1<<11) ; //GPE13 output 1;GPE11 output 1 if( (GPFDAT&(1<< 0)) == 0 ) { returnvalue= 11;goto out;} else if( (GPFDAT&(1<< 2)) == 0 ) { returnvalue= 8 ;goto out;} else if( (GPGDAT&(1<< 3)) == 0 ) { returnvalue= 5 ;goto out;} else if( (GPGDAT&(1<<11)) == 0 ) { returnvalue= 2 ;goto out;} //扫描键盘第1列 K10、K7、K4、K1 GPGDAT = GPGDAT & (~((1<<6)|(1<<2))) | (1<<6) | (1<<2) ; //GPG6 output 1;GPG2 output 1 GPEDAT = GPEDAT & (~((1<<13)|(1<<11))) | (1<<13) | (0<<11) ; //GPE13 output 1;GPE11 output 0 if( (GPFDAT&(1<< 0)) == 0 ) { returnvalue= 10;goto out;} else if( (GPFDAT&(1<< 2)) == 0 ) { returnvalue= 7; goto out;} else if( (GPGDAT&(1<< 3)) == 0 ) { returnvalue= 4; goto out;} else if( (GPGDAT&(1<<11)) == 0 ) { returnvalue= 1; goto out;} //扫描键盘第3列 K12、K9、K6、K3 GPGDAT = GPGDAT & (~((1<<6)|(1<<2))) | (1<<6) | (1<<2) ; //GPG6 output 1;GPG2 output 1 GPEDAT = GPEDAT & (~((1<<13)|(1<<11))) | (0<<13) | (1<<11) ; //GPE13 output 0;GPE11 output 1 if( (GPFDAT&(1<< 0)) == 0 ) returnvalue= 12 ; else if( (GPFDAT&(1<< 2)) == 0 ) returnvalue= 9 ; else if( (GPGDAT&(1<< 3)) == 0 ) returnvalue= 6 ; else if( (GPGDAT&(1<<11)) == 0 ) returnvalue= 3 ; else returnvalue= 0xff ;out: //重新初始化IO口 GPGCON = GPGCON & (~((3<<12)|(3<<4))) | ((1<<12)|(1<<4)) ; //GPG6,2 set output GPGDAT = GPGDAT & (~((1<<6)|(1<<2))); //GPG6,2 output 0 GPECON = GPECON & (~((3<<26)|(3<<22))) | ((1<<26)|(1<<22)); //GPE13,11 set output GPEDAT = GPEDAT & (~((1<<13)|(1<<11))); //GPE13,11 output 0 GPGCON = GPGCON & (~((3<<22)|(3<<6))) | ((2<<22)|(2<<6)) ; //GPG11,3 set EINT GPFCON = GPFCON & (~((3<<4)|(3<<0))) | ((2<<4)|(2<<0)) ; //GPF2,0 set EINTspin_lock_irq (&my_lock);//解锁 return returnvalue;}*/static struct key_info { int irq_no; unsigned int gpio_port; unsigned int gpio_port_kscan; int key_no;} key_info_tab[16] = { /*键盘第1列 k10 k7 k4 k1*/ { IRQ_EINT19, GPIO_G11, GPIO_E11, 1 }, { IRQ_EINT11, GPIO_G3, GPIO_E11, 4 }, { IRQ_EINT2, GPIO_F2, GPIO_E11, 7 }, { IRQ_EINT0, GPIO_F0, GPIO_E11, 10 }, /*键盘第2列 k11 k8 k5 k2*/ { IRQ_EINT19, GPIO_G11, GPIO_G6, 2 }, { IRQ_EINT11, GPIO_G3, GPIO_G6, 5 }, { IRQ_EINT2, GPIO_F2, GPIO_G6, 8 }, { IRQ_EINT0, GPIO_F0, GPIO_G6, 11 }, /*键盘第3列 k12 k9 k5 k3*/ { IRQ_EINT19, GPIO_G11, GPIO_E13, 3 }, { IRQ_EINT11, GPIO_G3, GPIO_E13, 6 }, { IRQ_EINT2, GPIO_F2, GPIO_E13, 9 }, { IRQ_EINT0, GPIO_F0, GPIO_E13, 12 }, /*键盘第4列 k16 k15 k14 k13*/ { IRQ_EINT19, GPIO_G11, GPIO_G2, 13 }, { IRQ_EINT11, GPIO_G3, GPIO_G2, 14 }, { IRQ_EINT2, GPIO_F2, GPIO_G2, 15 }, { IRQ_EINT0, GPIO_F0, GPIO_G2, 16 },};static int eint[4] = {IRQ_EINT19, IRQ_EINT11, IRQ_EINT2, IRQ_EINT0};static unsigned int ioport[4] = {GPIO_G11, GPIO_G3, GPIO_F2, GPIO_F0};static unsigned int kscan[4] = {GPIO_E11, GPIO_G6, GPIO_E13, GPIO_G2};static int ready = 0;static int key_value = 0;/*初始化按键的等待队列*/static DECLARE_WAIT_QUEUE_HEAD(buttons_wait);/* 初始化kscan口为输出0 */static void buttons_io_port_init(void){ int i; for(i=0; i < sizeof kscan / sizeof kscan[1]; i++) { set_gpio_ctrl(kscan[i] | GPIO_PULLUP_DIS | GPIO_MODE_OUT); write_gpio_bit(kscan[i], 0); }}/* 设置单个kscan口为输出0 */static void buttons_kscan_reset(int column){ int i; for(i=0; i < sizeof kscan / sizeof kscan[1]; i++) { if(i == column) write_gpio_bit(kscan[i], 0); else write_gpio_bit(kscan[i], 1); }}/* 设置GPIO口为输入状态 */static void buttons_port_reset(void){ int i; for(i=0; i < sizeof ioport / sizeof ioport[1]; i++) { set_gpio_ctrl(ioport[i] | GPIO_PULLUP_DIS | GPIO_MODE_IN); }}/* 重新设置中断 */static void buttons_int_reset(void){ int i; for(i=0; i < sizeof eint / sizeof eint[1]; i++) { set_external_irq(eint[i], EXT_FALLING_EDGE, GPIO_PULLUP_DIS); }}static void buttons_irq(int irq, void *dev_id, struct pt_regs *reg){ struct key_info *k; int i, j; int found = 0; int up = -1; int column = 0; int row = 0; buttons_port_reset(); /* 设置GPIO为输入状态 */ udelay(10000); /*延时10000us*/ /* 键盘扫描 */ for ( j = 0; j < sizeof kscan / sizeof kscan[1]; j++) { buttons_kscan_reset(j); column = j; for ( i = 0; i < sizeof eint / sizeof eint[1]; i++) { if(eint[i] == irq) { row = i; up = read_gpio_bit(ioport[i]); break; } } if(up == 0) { found = 1; break; } } udelay(10000); /* 延时去抖 */ if (found) { k = key_info_tab + column * 4 + row; if (up) { key_value = k->key_no + 0x80;// } else { key_value = k->key_no; } } ready = 1; wake_up_interruptible(&buttons_wait); buttons_io_port_init(); /* 重新设置GPIO为输出 */ buttons_int_reset(); /* 重新设置中断 */}static int request_irqs(void){ int i; for (i = 0; i < sizeof eint / sizeof eint[1]; i++) { set_external_irq(eint[i], EXT_FALLING_EDGE, GPIO_PULLUP_DIS); //设置与外部中断号相对应的GPIO端口,下降沿触发,上拉寄存器是禁止的 if (request_irq(eint[i], &buttons_irq, SA_INTERRUPT, DEVICE_NAME, &buttons_irq)) { return -1; } /*请求中断,所有的按键都使用同一个中断处理程序。中断处理程序根据中断号确定按下的是哪一个按键。*/ } return 0;}static void free_irqs(void){ int i; for (i = 0; i < sizeof eint / sizeof eint[1]; i++) free_irq(eint[i], buttons_irq);}static int matrix4_buttons_read(struct file * file, char * buffer, size_t count, loff_t *ppos){ static int key; int flags; int repeat; if (!ready) return -EAGAIN; if (count != sizeof key_value) return -EINVAL; save_flags(flags); //没有必要 if (key != key_value) { key = key_value; repeat = 0; } else { repeat = 1; } restore_flags(flags); /*if (repeat) { return -EAGAIN; }*/ copy_to_user(buffer, &key, sizeof key); ready = 0; return sizeof key_value;}static unsigned int matrix4_buttons_select(struct file *file, struct poll_table_struct *wait){ if (ready) return 1; poll_wait(file, &buttons_wait, wait); //通过调用函数 poll_wait,增加buttons_wait等待队列到poll_table 结构。 //poll 方法是 3 个系统调用的后端: poll, epoll, 和 select.(from ldd) // 用作查询对一个或多个文件描述符的 return 0;}static int matrix4_buttons_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ switch(cmd) { default: return -EINVAL; }}static struct file_operations matrix4_buttons_fops = { owner: THIS_MODULE, ioctl: matrix4_buttons_ioctl, poll: matrix4_buttons_select, read: matrix4_buttons_read,};static devfs_handle_t devfs_handle;static int __init matrix4_buttons_init(void){ int ret; ready = 0; ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &matrix4_buttons_fops); if (ret < 0) { printk(DEVICE_NAME " can't register major number\n"); return ret; } buttons_io_port_init(); ret = request_irqs(); if (ret) { unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME); printk(DEVICE_NAME " can't request irqs\n"); return ret; } devfs_handle = devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, BUTTON_MAJOR, 0, S_IFCHR | S_IRUSR | S_IWUSR, &matrix4_buttons_fops, NULL); return 0;}static void __exit matrix4_buttons_exit(void){ devfs_unregister(devfs_handle); free_irqs(); unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME);}module_init(matrix4_buttons_init);module_exit(matrix4_buttons_exit);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -