⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fs2410_key_matrix .c

📁 这个源码相信对很多用arm开发板开发的人会有用的
💻 C
字号:
/* * s3c2410_gpio_button.c * * genric routine for S3C2410-base machine's button * * Based on sa1100_gpio_button.c * * Author: Janghoon Lyu <nandy@mizi.com> * Date  : $Date: 2003/03/27 06:28:13 $ * * $Revision: 1.1.2.12 $ * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive * for more details. * * 2002-09-03  Initial code by nandy */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/irq.h>#include <linux/poll.h>#include <linux/spinlock.h>#include <linux/delay.h>#include <asm/hardware.h>#define	DEVICE_NAME	"key_matrix"#define	KEY_MATRIX_6#ifdef	KEY_MATRIX_6#define	KEY_MATRIX_COL	6#define	KEY_MATRIX_RAW	6#else#define	KEY_MATRIX_COL	4#define	KEY_MATRIX_RAW	4#endif#define	BUFFER_MAX	32static u8  key_buffer[BUFFER_MAX];static int buffer_head, buffer_tail;static wait_queue_head_t buffer_wq;static spinlock_t buffer_lock;static volatile int DeviceOpened;static int DevMajor;/*************************************************************************************/static __inline void set_io1(void){#ifdef	KEY_MATRIX_6	// GPF0,GPF2,GPF3 input with pull-up	GPFCON &= ~(3 | (3<<4) | (3<<6));	GPFUP  &= ~(1 | (1<<2) | (1<<3));	// CPG0,GPG3,GPG11 input, GPG2,GPG6,GPG8,GPG10 output	GPGCON = (GPGCON & ~(3 | (3<<6) | (3<<22) | (3<<4) | (3<<12) | (3<<16) | (3<<20))) | (1<<4) | (1<<12) | (1<<16) | (1<<20);	GPGUP  = (GPGUP & ~(1 | (1<<3) | (1<<11))) | (1<<2) | (1<<6) | (1<<8) | (1<<10);	//GPE11,GPE13 output	GPECON = (GPECON & ~((3<<22) | (3<<26))) | (1<<22) | (1<<26);	GPEUP |= (1<<11) | (1<<13);		GPGDAT &= ~((1<<2)  | (1<<6) | (1<<8) | (1<<10));	//output 0	GPEDAT &= ~((1<<11) | (1<<13));						//output 0#else	// GPF0,GPF2 input with pull-up	GPFCON &= ~(3 | (3<<4));	GPFUP  &= ~(1 | (1<<2));	// GPG3,GPG11 input, GPG2,GPG6 output	GPGCON = (GPGCON & ~((3<<6) | (3<<22) | (3<<4) | (3<<12))) | (1<<4) | (1<<12);	GPGUP  = (GPGUP & ~((1<<3) | (1<<11))) | (1<<2) | (1<<6);//	set_gpio_ctrl(GPIO_F0  | GPIO_PULLUP_EN | GPIO_MODE_IN);//	set_gpio_ctrl(GPIO_F2  | GPIO_PULLUP_EN | GPIO_MODE_IN);//	set_gpio_ctrl(GPIO_G3  | GPIO_PULLUP_EN | GPIO_MODE_IN);//	set_gpio_ctrl(GPIO_G11 | GPIO_PULLUP_EN | GPIO_MODE_IN);		GPECON = (GPECON & ~((3<<22) | (3<<26))) | (1<<22) | (1<<26);	GPEUP |= (1<<11) | (1<<13);//	set_gpio_ctrl(GPIO_E11 | GPIO_PULLUP_DIS | GPIO_MODE_OUT);//	set_gpio_ctrl(GPIO_E13 | GPIO_PULLUP_DIS | GPIO_MODE_OUT);//	set_gpio_ctrl(GPIO_G2  | GPIO_PULLUP_DIS | GPIO_MODE_OUT);//	set_gpio_ctrl(GPIO_G6  | GPIO_PULLUP_DIS | GPIO_MODE_OUT);	GPGDAT &= ~((1<<2)  | (1<<6));	//output 0	GPEDAT &= ~((1<<11) | (1<<13));	//output 0#endif}static __inline void set_io2(void){#ifdef	KEY_MATRIX_6	// GPF0,GPF2,GPF3 output	GPFCON = (GPFCON & ~(3 | (3<<4) | (3<<6))) | 1 | (1<<4) | (1<<6);	GPFUP |= 1 | (1<<2) | (1<<3);	// GPG0,GPG3,GPG11 output, GPG2,GPG6,GPG8,GPG10 input	GPGCON = (GPGCON & ~(3 | (3<<6) | (3<<22) | (3<<4) | (3<<12) | (3<<16) | (3<<20))) | 1 | (1<<6) | (1<<22);	GPGUP  = (GPGUP & ~((1<<2) | (1<<6) | (1<<8) | (1<<10))) | 1 | (1<<3) | (1<<11);	// GPE11,GPE13 input with pull-up	GPECON &= ~((3<<22) | (3<<26));	GPEUP  &= ~((1<<11) | (1<<13));		GPFDAT &= ~(1 | (1<<2) | (1<<3));	//output 0	GPGDAT &= ~(1 | (1<<3) | (1<<11));	//output 0#else	// GPF0,GPF2 output	GPFCON = (GPFCON & ~(3 | (3<<4))) | 1 | (1<<4);	GPFUP |= 1 | (1<<2);	// GPG3,GPG11 output, GPG2,GPG6 input	GPGCON = (GPGCON & ~((3<<6) | (3<<22) | (3<<4) | (3<<12))) | (1<<6) | (1<<22);	GPGUP  = (GPGUP & ~((1<<2) | (1<<6))) | (1<<3) | (1<<11);	// GPE11,GPE13 input with pull-up	GPECON &= ~((3<<22) | (3<<26));	GPEUP  &= ~((1<<11) | (1<<13));	GPFDAT &= ~(1 | (1<<2));		//output 0	GPGDAT &= ~((1<<3) | (1<<11));	//output 0#endif}static __inline u32 get_io1(void){	u32 val = -1;	if(!(GPFDAT&1))		val &= ~1;	if(!(GPFDAT&(1<<2)))		val &= ~2;	if(!(GPGDAT&(1<<3)))		val &= ~4;	if(!(GPGDAT&(1<<11)))		val &= ~8;#ifdef	KEY_MATRIX_6	if(!(GPFDAT&(1<<3)))		val &= ~0x10;	if(!(GPGDAT&1))		val &= ~0x20;#endif	return val;}static __inline u32 get_io2(void){	u32 val = -1;	if(!(GPEDAT&(1<<11)))		val &= ~1;	if(!(GPEDAT&(1<<13)))		val &= ~2;	if(!(GPGDAT&(1<<2)))		val &= ~4;	if(!(GPGDAT&(1<<6)))		val &= ~8;#ifdef	KEY_MATRIX_6	if(!(GPGDAT&(1<<8)))		val &= ~0x10;	if(!(GPGDAT&(1<<10)))		val &= ~0x20;#endif	return val;}static __inline void init_io(int init){	set_gpio_ctrl(GPIO_E11 | GPIO_PULLUP_DIS | GPIO_MODE_OUT);	set_gpio_ctrl(GPIO_E13 | GPIO_PULLUP_DIS | GPIO_MODE_OUT);	set_gpio_ctrl(GPIO_G2  | GPIO_PULLUP_DIS | GPIO_MODE_OUT);	set_gpio_ctrl(GPIO_G6  | GPIO_PULLUP_DIS | GPIO_MODE_OUT);#ifdef	KEY_MATRIX_6	set_gpio_ctrl(GPIO_G8  | GPIO_PULLUP_DIS | GPIO_MODE_OUT);	set_gpio_ctrl(GPIO_G10 | GPIO_PULLUP_DIS | GPIO_MODE_OUT);#endif	if(1) {//init) {		set_external_irq(IRQ_EINT0,  EXT_LOWLEVEL, GPIO_PULLUP_EN);		set_external_irq(IRQ_EINT2,  EXT_LOWLEVEL, GPIO_PULLUP_EN);		set_external_irq(IRQ_EINT11, EXT_LOWLEVEL, GPIO_PULLUP_EN);		set_external_irq(IRQ_EINT19, EXT_LOWLEVEL, GPIO_PULLUP_EN);#ifdef	KEY_MATRIX_6		set_external_irq(IRQ_EINT3,  EXT_LOWLEVEL, GPIO_PULLUP_EN);		set_external_irq(IRQ_EINT8,  EXT_LOWLEVEL, GPIO_PULLUP_EN);#endif	} else {		set_gpio_ctrl(GPIO_F0  | GPIO_PULLUP_EN | GPIO_MODE_EINT);		set_gpio_ctrl(GPIO_F2  | GPIO_PULLUP_EN | GPIO_MODE_EINT);		set_gpio_ctrl(GPIO_G3  | GPIO_PULLUP_EN | GPIO_MODE_EINT);		set_gpio_ctrl(GPIO_G11 | GPIO_PULLUP_EN | GPIO_MODE_EINT);#ifdef	KEY_MATRIX_6		set_gpio_ctrl(GPIO_F3  | GPIO_PULLUP_EN | GPIO_MODE_EINT);		set_gpio_ctrl(GPIO_G0  | GPIO_PULLUP_EN | GPIO_MODE_EINT);#endif	}	write_gpio_bit(GPIO_E11, 0);	write_gpio_bit(GPIO_E13, 0);	write_gpio_bit(GPIO_G2, 0);	write_gpio_bit(GPIO_G6, 0);#ifdef	KEY_MATRIX_6	write_gpio_bit(GPIO_G8, 0);	write_gpio_bit(GPIO_G10, 0);#endif}static __inline int request_irqs(void (*handler)(int, void *, struct pt_regs *)){	int ret;	//printk("request_irq : IRQ_EINT0\n");	ret = request_irq(IRQ_EINT0, handler, SA_INTERRUPT, 			  DEVICE_NAME, DEVICE_NAME);	if(ret)		goto fail;	//printk("request_irq : IRQ_EINT2\n");	ret = request_irq(IRQ_EINT2, handler, SA_INTERRUPT, 			  DEVICE_NAME, DEVICE_NAME);	if(ret)		goto fail1;		//printk("request_irq : IRQ_EINT11\n");	ret = request_irq(IRQ_EINT11, handler, SA_INTERRUPT, 			  DEVICE_NAME, DEVICE_NAME);	if(ret)		goto fail2;	//printk("request_irq : IRQ_EINT19\n");	ret = request_irq(IRQ_EINT19, handler, SA_INTERRUPT, 			  DEVICE_NAME, DEVICE_NAME);	if(ret)		goto fail3;		#ifdef	KEY_MATRIX_6	//printk("request_irq : IRQ_EINT3\n");	ret = request_irq(IRQ_EINT3, handler, SA_INTERRUPT, 			  DEVICE_NAME, DEVICE_NAME);	if(ret)		goto fail4;	//printk("request_irq : IRQ_EINT8\n");	ret = request_irq(IRQ_EINT8, handler, SA_INTERRUPT, 			  DEVICE_NAME, DEVICE_NAME);	if(ret)		goto fail5;#endif		return 0;#ifdef	KEY_MATRIX_6fail5:	free_irq(IRQ_EINT3, DEVICE_NAME);fail4:	free_irq(IRQ_EINT19, DEVICE_NAME);#endiffail3:	free_irq(IRQ_EINT11, DEVICE_NAME);fail2:	free_irq(IRQ_EINT2, DEVICE_NAME);fail1:	free_irq(IRQ_EINT0, DEVICE_NAME);fail:	return ret;}static __inline void free_irqs(void){#ifdef	KEY_MATRIX_6	free_irq(IRQ_EINT8, DEVICE_NAME);	free_irq(IRQ_EINT3, DEVICE_NAME);#endif	free_irq(IRQ_EINT19, DEVICE_NAME);	free_irq(IRQ_EINT11, DEVICE_NAME);	free_irq(IRQ_EINT2,  DEVICE_NAME);	free_irq(IRQ_EINT0,  DEVICE_NAME);}static __inline void enable_irqs(void){	enable_irq(IRQ_EINT0);	enable_irq(IRQ_EINT2);	enable_irq(IRQ_EINT11);	enable_irq(IRQ_EINT19);#ifdef	KEY_MATRIX_6	enable_irq(IRQ_EINT3);	enable_irq(IRQ_EINT8);#endif}static __inline void disable_irqs(void){	disable_irq(IRQ_EINT0);	disable_irq(IRQ_EINT2);	disable_irq(IRQ_EINT11);	disable_irq(IRQ_EINT19);#ifdef	KEY_MATRIX_6	disable_irq(IRQ_EINT3);	disable_irq(IRQ_EINT8);#endif}/*************************************************************************************/static volatile int thread_leave;static struct completion thread_dead;static wait_queue_head_t thread_wq;static void key_matrix_isr(int irq, void *dev_id, struct pt_regs *regs){//	printk("%d\n", irq);	disable_irqs();	wake_up(&thread_wq);}static __inline void buffer_key(u32 no, u32 pressure){	if(!DeviceOpened)		return;	spin_lock_irq(&buffer_lock);	key_buffer[buffer_tail] = no | (pressure ? 0x80 : 0);	//printk("buffer key 0x%x\n", key_buffer[buffer_tail]);	buffer_tail = (buffer_tail+1) & (BUFFER_MAX-1);	if(buffer_tail==buffer_head)		buffer_head = (buffer_head+1) & (BUFFER_MAX-1);	spin_unlock_irq(&buffer_lock);	wake_up_interruptible(&buffer_wq);}static int key_matrix_scan_thread(void *arg){	u16 key_matrix_r0[KEY_MATRIX_COL];	u16 key_matrix_r1[KEY_MATRIX_COL];	for(buffer_head=0; buffer_head<KEY_MATRIX_COL; buffer_head++)		key_matrix_r0[buffer_head] = 0xffff;	buffer_head = 0;	/* we might get involved when memory gets low, so use PF_MEMALLOC */	current->flags |= PF_MEMALLOC;	snprintf(current->comm, sizeof(current->comm), "keyscand");#ifndef __rh_config_h__ /* HAVE_NPTL */	spin_lock_irq(&current->sigmask_lock);	sigfillset(&current->blocked);	recalc_sigpending(current);	spin_unlock_irq(&current->sigmask_lock);#else	spin_lock_irq(&current->sighand->siglock);	sigfillset(&current->blocked);	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);#endif	daemonize();	while(!thread_leave) {		u32 val, val1, key_r, times, stable = 0;		DECLARE_WAITQUEUE(wait, current);				add_wait_queue(&thread_wq, &wait);		set_current_state(TASK_INTERRUPTIBLE);		cli();		//must disable irq before enable all external interrupt		enable_irqs();		sti();		schedule();		remove_wait_queue(&thread_wq, &wait);				//if(thread_leave)		//	break;	//	printk("start key matrix scan...\n");		key_r = -1;		while(!thread_leave) {			times = 4;			val1  = -1;			while(times) {				set_io1();				udelay(10);				val = get_io1()&0xffff;				set_io2();				udelay(10);				val |= get_io2()<<16;				if(times!=4)					if(val!=val1) {						stable = 0;						break;					}				val1 = val;				times--;			}			if(!times) {				if(val==key_r)					stable += (stable < 10) ? 1 : 0;				else					stable = 0;				key_r = val;			}			if(stable==3) {				int i, j, vary, multi=0, act_cols=0, act_raws=0;				for(i=0; i<KEY_MATRIX_COL; i++)					if(!(key_r&(1<<i)))						act_cols++;				if(act_cols>=2) {					for(j=0; j<KEY_MATRIX_RAW; j++)						if(!(key_r&(1<<(16+j))))							act_raws++;					if(act_raws>=2) {						printk(KERN_WARNING "multi keys!\n");						multi = 1;					}				}				//printk("%x\n", key_r);				for(i=0; i<KEY_MATRIX_COL; i++) {					key_matrix_r1[i] = 0xffff;					for(j=0; j<KEY_MATRIX_RAW; j++)						if(!(((key_r>>(16+j))|(key_r>>i))&1))							key_matrix_r1[i] &= ~(1<<j);					vary = key_matrix_r0[i]^key_matrix_r1[i];					if(vary) {						//printk("%x,%x\n", key_matrix_r0[i], key_matrix_r1[i]);						for(j=0; j<KEY_MATRIX_RAW; j++)							if(vary&(1<<j)&&!multi)								buffer_key(i*KEY_MATRIX_RAW+j, 							key_matrix_r1[i]&(1<<j));						key_matrix_r0[i] = key_matrix_r1[i];					}				}								if(val==-1) {	//				printk("end key matrix scan...\n");					init_io(0);					break;	//wait for interrupt				}						}			set_current_state(TASK_INTERRUPTIBLE);			schedule_timeout(HZ/100);		}	}	complete_and_exit(&thread_dead, 0);}static int key_matrix_open(struct inode *inode, struct file *filp){	buffer_head = buffer_tail = 0;	init_waitqueue_head(&buffer_wq);	DeviceOpened++;	MOD_INC_USE_COUNT;	return 0;}static int key_matrix_release(struct inode *inode, struct file *filp){	DeviceOpened--;	MOD_DEC_USE_COUNT;	return 0;}static ssize_t key_matrix_read(struct file *filp, char *buffer, size_t count, loff_t *ppos){retry:	if (buffer_head != buffer_tail) {		spin_lock_irq(&buffer_lock);		copy_to_user(buffer, (char *)key_buffer + buffer_head, 1);		buffer_head = (buffer_head+1) & (BUFFER_MAX-1);		spin_unlock_irq(&buffer_lock);		return 1;	} else {		if (filp->f_flags & O_NONBLOCK)			return -EAGAIN;		interruptible_sleep_on(&buffer_wq);		if (signal_pending(current))			return -ERESTARTSYS;		goto retry;	}	return 1;}static unsigned int key_matrix_poll(struct file *filp, struct poll_table_struct *wait){	poll_wait(filp, &buffer_wq, wait);	return (buffer_head == buffer_tail) ? 0 : (POLLIN | POLLRDNORM); }static struct file_operations key_matrix_fops = {	owner:		THIS_MODULE,	open:		key_matrix_open,	read:		key_matrix_read,	release:	key_matrix_release,#ifdef USE_ASYNC	fasync:		key_matrix_fasync,#endif	poll:		key_matrix_poll,};#ifdef CONFIG_DEVFS_FSstatic devfs_handle_t devfs_dir, devfs_dev;#endifstatic int __init init_key_matrix(void){	int ret;	printk("FS2410 key matrix (GPIO) driver\n");	ret = register_chrdev(0, DEVICE_NAME, &key_matrix_fops);	if (ret < 0) {		 printk(DEVICE_NAME "can't get major number!\n");		 return ret;	}	DevMajor = ret;	init_io(1);	//initialize external irq before request_irq	cli();		//disable irq before request all external interrupts	ret = request_irqs(key_matrix_isr);	if(ret) {		sti();		printk("fail to request irq for device!\n");		unregister_chrdev(DevMajor, DEVICE_NAME);		return ret;	}	disable_irqs();	//all irqs are disabled, enable them in key_matrix_scan_thread	//	printk("0x%x, 0x%x, 0x%x\n", INTMSK, INTPND, SRCPND);	init_io(1);	//if low-level interrupt present, must clear INTPND!!!	//	printk("0x%x, 0x%x, 0x%x\n", INTMSK, INTPND, SRCPND);	sti();	//	printk("HaHa\n");	init_completion(&thread_dead);	init_waitqueue_head(&thread_wq);	ret = kernel_thread(key_matrix_scan_thread, NULL, 			  CLONE_FS|CLONE_FILES|CLONE_SIGHAND);	if (ret < 0) {		printk("fail to create kernel thread for device!\n");		free_irqs();	//now all irqs are disabled, so needn't cli()		return ret;	}#ifdef CONFIG_DEVFS_FS	devfs_dir = devfs_mk_dir(NULL, "keypad", NULL);	devfs_dev = devfs_register(devfs_dir, "0", DEVFS_FL_DEFAULT,			DevMajor, 0, S_IFCHR | S_IRUSR | S_IWUSR,			&key_matrix_fops, NULL);#endif	return 0;}static void __exit exit_key_matrix(void){	thread_leave = 1;	wake_up(&thread_wq);	wait_for_completion(&thread_dead);#ifdef CONFIG_DEVFS_FS		devfs_unregister(devfs_dev);	devfs_unregister(devfs_dir);#endif		//cli();	//if a interrupt happened, this irq will be disabled in handler,	free_irqs();	//so cli() is not required	//sti();	unregister_chrdev(DevMajor, DEVICE_NAME);}module_init(init_key_matrix);module_exit(exit_key_matrix);MODULE_LICENSE("GPL");MODULE_AUTHOR("antiscle <hzh12@tom.com>");MODULE_DESCRIPTION("key matrix (GPIO) driver for S3C2410");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -