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

📄 utu2440_buttons.w

📁 2440 扫描键盘驱动,验证过
💻 W
字号:
/* * * A button  driver for UTU2410 a board based on s3c2440 * * The source code in this file can be freely used, adapted, * and redistributed in source or binary form, so long as an * acknowledgment appears in derived source files.No warranty * is attached;we cannot take responsibility for errors or * fitness for use. * *  */#include <linux/autoconf.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/kernel.h>       /* printk() */#include <linux/fs.h>           /* everything... */#include <linux/cdev.h>#include <linux/interrupt.h>    /* request_irq() */#include <asm/arch/regs-gpio.h>#include <asm/arch/regs-irq.h>#include <asm/io.h>#include <asm/uaccess.h>        /* copy_to_user() */#include <linux/delay.h>	/* mdelay() */#include <linux/irq.h>#include <linux/input.h>#ifdef CONFIG_DEVFS_FS//#include <linux/devfs_fs_kernel.h>#endif#define VERSION_STRING  "Button driver for utu2440"#define DEVICE_NAME "utu2440-buttons"#define EXTINT_OFF (IRQ_EINT4 - 4)#define S3C2410_GND 5MODULE_AUTHOR("lili <bit.lili@gmail.com>");MODULE_LICENSE("Dual BSD/GPL");MODULE_DESCRIPTION(VERSION_STRING);unsigned int type=IRQT_BOTHEDGE;unsigned int buttons_major_number=0;struct cdev buttons_dev;static int ready = 0;static int key_value = 0;static struct key_info {	unsigned int irq_no;	unsigned int gpio_port;	int key_no;	unsigned int IN;	unsigned int EINT;} key_info_tab[6] = {	{ IRQ_EINT0, S3C2410_GPF0, 1 ,S3C2410_GPF0_INP,S3C2410_GPF0_EINT0},	{ IRQ_EINT1, S3C2410_GPF1, 2 ,S3C2410_GPF1_INP,S3C2410_GPF1_EINT1},	{ IRQ_EINT2, S3C2410_GPF2, 3 ,S3C2410_GPF2_INP,S3C2410_GPF2_EINT2},	{ IRQ_EINT3, S3C2410_GPF3, 4 ,S3C2410_GPF3_INP,S3C2410_GPF3_EINT3},	{ IRQ_EINT11, S3C2410_GPG3, 5 ,S3C2410_GPG3_INP,S3C2410_GPG3_EINT11},	{ IRQ_EINT19, S3C2410_GPG11, 6 ,S3C2410_GPG11_INP,S3C2410_GPG11_EINT19},};static struct scan_gpio {	unsigned int gpio_scan;		unsigned int IN;	unsigned int OUT;} scan_tab[4] = {	{ S3C2410_GPD13, S3C2410_GPD13_INP,S3C2410_GPD13_OUTP},	{ S3C2410_GPD14, S3C2410_GPD14_INP,S3C2410_GPD14_OUTP},	{ S3C2410_GPD15, S3C2410_GPD15_INP,S3C2410_GPD15_OUTP},	{ S3C2410_GPG12, S3C2410_GPG12_INP,S3C2410_GPG12_OUTP},};static struct key_code {	unsigned int key_no;		unsigned int key_code;} code_tab[22] = {	{ 1, KEY_ENTER},	{ 2, KEY_ENTER},	{ 3, KEY_ENTER},	{ 4, KEY_ENTER},	{ 5, KEY_ENTER},	{ 6, KEY_ENTER},	{ 7, KEY_ENTER},	{ 8, KEY_ENTER},	{ 9, KEY_ENTER},	{ 10, KEY_ENTER},	{ 11, KEY_ENTER},	{ 12, KEY_ENTER},	{ 13, KEY_ENTER},	{ 14, KEY_ENTER},	{ 15, KEY_ENTER},	{ 16, KEY_ENTER},	{ 17, KEY_ENTER},	{ 18, KEY_ENTER},	{ 19, KEY_ENTER},	{ 20, KEY_ENTER},	{ 21, KEY_ENTER},	{ 22, KEY_ENTER},};DECLARE_WAIT_QUEUE_HEAD(buttons_wait);static inline void s3c_irq_ack(unsigned int irqno){	unsigned long bitval = 1UL << (irqno - IRQ_EINT0);	__raw_writel(bitval, S3C2410_SRCPND);	__raw_writel(bitval, S3C2410_INTPND);} static void s3c_irqext_ack(unsigned int irqno){	unsigned long req;	unsigned long bit;	unsigned long mask;	bit = 1UL << (irqno - EXTINT_OFF);	mask = __raw_readl(S3C2410_EINTMASK);	__raw_writel(bit, S3C2410_EINTPEND);         req = __raw_readl(S3C2410_EINTPEND); 	req &= ~mask;	/* not sure if we should be acking the parent irq... */	if (irqno <= IRQ_EINT7 ) {		if ((req & 0xf0) == 0)			s3c_irq_ack(IRQ_EINT4t7);	} else {		if ((req >> 8) == 0)			s3c_irq_ack(IRQ_EINT8t23);	}}static int s3c_irqext_type(unsigned int irq, unsigned int type){	unsigned long extint_reg;	unsigned long gpcon_reg;	unsigned long gpcon_offset, extint_offset;	unsigned long newvalue = 0, value;	if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))	{		gpcon_reg = (unsigned long)S3C2410_GPFCON;		extint_reg = (unsigned long)S3C2410_EXTINT0;		gpcon_offset = (irq - IRQ_EINT0) * 2;		extint_offset = (irq - IRQ_EINT0) * 4;	}	else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))	{		gpcon_reg = (unsigned long)S3C2410_GPFCON;		extint_reg = (unsigned long)S3C2410_EXTINT0;		gpcon_offset = (irq - (EXTINT_OFF)) * 2;		extint_offset = (irq - (EXTINT_OFF)) * 4;	}	else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15))	{		gpcon_reg = (unsigned long)S3C2410_GPGCON;		extint_reg = (unsigned long)S3C2410_EXTINT1;		gpcon_offset = (irq - IRQ_EINT8) * 2;		extint_offset = (irq - IRQ_EINT8) * 4;	}	else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23))	{		gpcon_reg = (unsigned long)S3C2410_GPGCON;		extint_reg = (unsigned long)S3C2410_EXTINT2;		gpcon_offset = (irq - IRQ_EINT8) * 2;		extint_offset = (irq - IRQ_EINT16) * 4;	} else		return -1;	/* Set the GPIO to external interrupt mode */	value = __raw_readl(gpcon_reg);	value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);	__raw_writel(value, gpcon_reg);	/* Set the external interrupt to pointed trigger type */	switch (type)	{		case IRQT_NOEDGE:			printk(KERN_WARNING "No edge setting!\n");			break;		case IRQT_RISING:			newvalue = S3C2410_EXTINT_RISEEDGE;			break;		case IRQT_FALLING:			newvalue = S3C2410_EXTINT_FALLEDGE;			break;		case IRQT_BOTHEDGE:			newvalue = S3C2410_EXTINT_BOTHEDGE;			break;		case IRQT_LOW:			newvalue = S3C2410_EXTINT_LOWLEV;			break;		case IRQT_HIGH:			newvalue = S3C2410_EXTINT_HILEV;			break;		default:			printk(KERN_ERR "No such irq type %d", type);			return -1;	}	value = __raw_readl(extint_reg);	value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);	__raw_writel(value, extint_reg);	return 0;}static irqreturn_t buttons_irq(int irq,void *dev_id,struct pt_regs *req){	struct key_info *k;//	struct scan_gpio *scan;	int i,j;	int found = 0;	int up ;	unsigned long  flags;	for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[1]; i++) {		k = key_info_tab + i;		if (k->irq_no == irq) {			found = 1;			break;		}	}	if (!found) {		printk("bad irq %d in button\n", irq);		return IRQ_NONE;	}	local_irq_save(flags);	mdelay(1);//为ebook 项目修改, 2009.03 cywang				s3c2410_gpio_cfgpin(k->gpio_port, k->IN);	for(j=0;j<4;j++)		s3c2410_gpio_setpin(scan_tab[j].gpio_scan, 1);	if(!s3c2410_gpio_getpin(k->gpio_port))		key_value = code_tab[i*5+4].key_no;	else						for(j=0;j<4;j++)		{			s3c2410_gpio_setpin(scan_tab[j].gpio_scan, 0);			s3c2410_gpio_setpin(scan_tab[(j+1)%4].gpio_scan, 1);					s3c2410_gpio_setpin(scan_tab[(j+2)%4].gpio_scan, 1);			s3c2410_gpio_setpin(scan_tab[(j+3)%4].gpio_scan, 1);			up = s3c2410_gpio_getpin(k->gpio_port);			if(!up)			{				key_value = code_tab[i*5+j].key_no;				break;}		}	for(j=0;j<4;j++)		s3c2410_gpio_setpin(scan_tab[j].gpio_scan, 0);			//	up = s3c2410_gpio_getpin(k->gpio_port);	local_irq_restore(flags);        s3c_irqext_type(irq,  type);	if(irq<IRQ_EINT7)		s3c_irq_ack(irq);	else		s3c_irqext_ack(irq);/*	if (!up) {		key_value = k->key_no;		ready=1;	}*/	wake_up_interruptible(&buttons_wait);//	printk("buttons_irq");	if((key_value == 1))	{		s3c2410_gpio_setpin(S3C2410_GPF4, 0);		printk(KERN_INFO "Buttons Value 1\n");	}	if((key_value == 2))	{		s3c2410_gpio_setpin(S3C2410_GPF5, 0);		printk(KERN_INFO "Buttons Value 2\n");	}	if((key_value == 3))	{		s3c2410_gpio_setpin(S3C2410_GPF6, 0);		printk(KERN_INFO "Buttons Value 3\n");	}	if((key_value == 4))	{		s3c2410_gpio_setpin(S3C2410_GPF7, 0);		printk(KERN_INFO "Buttons Value 4\n");	}	if((key_value == 5))	{		s3c2410_gpio_setpin(S3C2410_GPF4, 0);		s3c2410_gpio_setpin(S3C2410_GPF5, 0);		s3c2410_gpio_setpin(S3C2410_GPF6, 0);		s3c2410_gpio_setpin(S3C2410_GPF7, 0);		printk(KERN_INFO "Buttons Value 5\n");	}	if((key_value == 6))	{		s3c2410_gpio_setpin(S3C2410_GPF4, 1);		s3c2410_gpio_setpin(S3C2410_GPF5, 1);		s3c2410_gpio_setpin(S3C2410_GPF6, 1);		s3c2410_gpio_setpin(S3C2410_GPF7, 1);		printk(KERN_INFO "Buttons Value 6\n");	}	return IRQ_HANDLED;}static int request_irqs(void){	struct key_info *k;	int i,request;	unsigned int irq;      	for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[1]; i++) {      		k = key_info_tab + i;      		irq=k->irq_no;      		s3c_irqext_type(irq,  type);      		if(irq<IRQ_EINT7)      			s3c_irq_ack(irq);      		else      			s3c_irqext_ack(irq);		request =request_irq(k->irq_no,&buttons_irq,SA_INTERRUPT,DEVICE_NAME,NULL);      		if (request) {      			printk(KERN_WARNING "buttons:can't get irq no.\n");			return -1;		}	}	return 0;}static void free_irqs(void){	struct key_info *k;	int i;	for (i = 0; i < sizeof key_info_tab / sizeof key_info_tab[1]; i++) {		k = key_info_tab + i;		free_irq(k->irq_no, NULL);	}}static ssize_t buttons_read(struct file *filp,char __user *buffer,size_t count,loff_t *ppos){       	static int key;	unsigned long  flags;	if (!ready) { 		return -EAGAIN;	}        if (count != sizeof key_value)        	return -EINVAL;	local_irq_save(flags);	key = key_value;	local_irq_restore(flags);        copy_to_user(buffer, &key, sizeof key);	ready = 0;	return sizeof key_value;}static struct file_operations buttons_fops = {	.owner	=	THIS_MODULE,	.read	=	buttons_read,};static int __init buttons_init(void){        int ret,devno;        dev_t dev;// 初始化GPIO	printk(KERN_INFO "Buttons key gpio init!\n");	s3c2410_gpio_cfgpin(S3C2410_GPD13,S3C2410_GPD13_OUTP);	s3c2410_gpio_setpin(S3C2410_GPD13, 0);	s3c2410_gpio_cfgpin(S3C2410_GPD14,S3C2410_GPD14_OUTP);	s3c2410_gpio_setpin(S3C2410_GPD14, 0);	s3c2410_gpio_cfgpin(S3C2410_GPD15,S3C2410_GPD15_OUTP);	s3c2410_gpio_setpin(S3C2410_GPD15, 0);	s3c2410_gpio_cfgpin(S3C2410_GPG12,S3C2410_GPG12_OUTP);	s3c2410_gpio_setpin(S3C2410_GPG12, 1);	s3c2410_gpio_cfgpin(S3C2410_GPG5,S3C2410_GPG5_OUTP);	s3c2410_gpio_setpin(S3C2410_GPG5, 1);        ret = alloc_chrdev_region(&dev,0,1,DEVICE_NAME);        buttons_major_number = MAJOR(dev);	printk(KERN_INFO "Initial utulinux 2440 Buttons driver!\n");        if (ret<0) {                printk(KERN_WARNING "button:can't get major number %d\n",buttons_major_number);                return ret;        }        ret = request_irqs();        if (ret) {                unregister_chrdev_region(dev,1);                printk(KERN_WARNING "button:can't request irqs\n");                return ret;        }        devno = MKDEV(buttons_major_number,0);        cdev_init(&buttons_dev,&buttons_fops);        buttons_dev.owner = THIS_MODULE;        buttons_dev.ops   = &buttons_fops;        ret = cdev_add(&buttons_dev,devno,1);        if (ret) {                free_irqs();                unregister_chrdev_region(dev,1);                printk(KERN_NOTICE "Error %d adding buttons device\n",ret);                return ret;        }        printk(KERN_INFO "Todo: mknod c /dev/%s %d 0\n",DEVICE_NAME,buttons_major_number);        return 0;}static void __exit buttons_cleanup(void){        dev_t dev=MKDEV(buttons_major_number,0);        free_irqs();        cdev_del(&buttons_dev);        unregister_chrdev_region(dev,1);        printk(KERN_INFO "unregistered the %s\n",DEVICE_NAME);}module_init(buttons_init);module_exit(buttons_cleanup);                             

⌨️ 快捷键说明

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