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

📄 s3c2410kbd.c

📁 s3c2410驱动
💻 C
字号:
/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright (c) 2005 Arnaud Patard <arnaud.patard@rtp-net.org> * Samsung S3C2410 keyboard support * * Based on various pxa ipaq drivers. *  * ChangeLog * * 2005-06-21: Arnaud Patard <arnaud.patard@rtp-net.org> *      - Initial version * 2007-04-17: lqm@ucdragon.net *      - modified for 4x4 maxtrix keyboard */#include <linux/config.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/slab.h>#include <linux/input.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/interrupt.h>#include <linux/device.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/arch/hardware.h>#include <asm/arch/regs-gpio.h>//#include </arch/arm/mach-s3c2410/gpio.h>/* For id.version */#define S3C2410KBDVERSION   0x0001#define DRV_NAME            "s3c2410-maxtrixkb"MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");MODULE_DESCRIPTION("s3c2410 keyboard driver");MODULE_LICENSE("GPL");#define KEY_CODE_INVALID -1//qsmstart2007-06-30static void *gpgcon;static void *gpfcon;static void *test_reg;#define GPGCON	0x56000060#define GPFCON  0x56000050#define TESTCON  0x56000088//qsm_endstruct s3c2410kbd_button {	int irq;	int pin;	int pin_setting;	int index;	int keycode;};static int s3c2410kbd_buttons[] = {	KEY_1,         KEY_2,         KEY_3,         KEY_B,	KEY_4,         KEY_5,         KEY_6,         KEY_C,	KEY_7,         KEY_8,         KEY_9,         KEY_ENTER,	KEY_U,         KEY_0,         KEY_D,         KEY_P,};//由于历史问题,仍用U,P代替上下翻、C为更正,B为后退.../*static int s3c2410kbd_buttons[] = {	KEY_B,        KEY_3,          KEY_2,         KEY_1,	KEY_C,        KEY_6,          KEY_5,         KEY_4,	KEY_ENTER,    KEY_9,          KEY_8,         KEY_7,	KEY_P,        KEY_D,          KEY_0,         KEY_U,};*/static struct s3c2410kbd_button s3c2410kbd_x[] = {	{  IRQ_EINT0,  S3C2410_GPF0,   S3C2410_GPF0_EINT0,   3<<2 ,KEY_CODE_INVALID},	{  IRQ_EINT2,  S3C2410_GPF2,   S3C2410_GPF2_EINT2,   2<<2 ,KEY_CODE_INVALID},	{  IRQ_EINT11, S3C2410_GPG3,   S3C2410_GPG3_EINT11,  1<<2 ,KEY_CODE_INVALID},	{  IRQ_EINT19, S3C2410_GPG11,  S3C2410_GPG11_EINT19, 0<<2 ,KEY_CODE_INVALID},//	{  IRQ_EINT13, S3C2410_GPG5,   S3C2410_GPG5_EINT13,  2<<2 ,KEY_CODE_INVALID},};static struct s3c2410kbd_button s3c2410kbd_y[] = {	{  0,  S3C2410_GPE11,   S3C2410_GPE11_OUTP,   0 },	{  0,  S3C2410_GPG6,    S3C2410_GPG6_OUTP,    1 },	{  0,  S3C2410_GPE13,   S3C2410_GPE13_OUTP,   2 },	{  0,  S3C2410_GPG2,    S3C2410_GPG2_OUTP,    3 },};struct s3c2410kbd {	struct input_dev  dev;	spinlock_t        lock;	int               count;	int               shift;		char              phys[32];};static struct s3c2410kbd kbd;unsigned int get_state(void){		if(*(volatile unsigned *)S3C2410_GPFDAT & (1<<0))		return 0;	else if (*(volatile unsigned *)S3C2410_GPGDAT & (1<<3))		return 0;	else if (*(volatile unsigned *)S3C2410_GPGDAT & (1<<5))                return 0;	else if (*(volatile unsigned *)S3C2410_GPGDAT & (1<<11))                return 0;        else                 return 1;}static irqreturn_t s3c2410kbd_keyevent(int irq, void *dev_id, struct pt_regs *regs){		int i;	for (i = 0; i < 4; i++) {		disable_irq(s3c2410kbd_x[i].irq);	};	//printk( "  button222222222\n" );	//printk(KERN_INFO "s3c2410kbd_init222222222\n");	static struct s3c2410kbd_button *button; //= (struct s3c2410kbd_button *)dev_id; 	unsigned int down;	static int last_key; 	button = (struct s3c2410kbd_button *)dev_id;	last_key = button->keycode;	mdelay(10);	if (!button)		return IRQ_HANDLED;	mdelay(10);	down =!( s3c2410_gpio_getpin(button->pin));	//printk("down==%d, button->index==%02x, button->keycode==%x, last_key== %d\n",down,button->index,button->keycode,last_key);	if(last_key != KEY_CODE_INVALID)// || button->keycode == KEY_CODE_INVALID)	{		input_report_key_2440(&kbd.dev, last_key, 0);		input_sync_2440(&kbd.dev);		button->keycode = KEY_CODE_INVALID;		printk("test report 0\n");		//printk(KERN_DEBUG "%x button %s\n",last_key, "force up");	}//	if(down)//	{	//		printk("In down function(down==%d)\n",down);		//int i;		//lqm@ucdragon.net must set to input,or interrpt will trigger again		for (i = 0; i < ARRAY_SIZE (s3c2410kbd_x); i++) 		{			s3c2410_gpio_cfgpin(s3c2410kbd_x[i].pin,0);//配置 为 输入		}		for (i = 0; i < ARRAY_SIZE (s3c2410kbd_y); i++) 		{			s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,1);		}		for (i = 0; button->keycode == KEY_CODE_INVALID && i < ARRAY_SIZE (s3c2410kbd_y); i++) 		{			s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,0);//赋值			//mdelay(100);			if(!s3c2410_gpio_getpin(button->pin))//扫描			{				mdelay(5);				if(!s3c2410_gpio_getpin(button->pin))//扫描				{					mdelay(5);					if(!s3c2410_gpio_getpin(button->pin))//扫描					{						button->keycode = s3c2410kbd_buttons[button->index + s3c2410kbd_y[i].index];						printk("%d======================%d\n",irq,button->index + s3c2410kbd_y[i].index);						printk("later TESTCON=%x\n",readl(test_reg)); 						s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,1);						break;					}									}			}			s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,1);		}		for (i = 0; i < ARRAY_SIZE (s3c2410kbd_y); i++) 		{			s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,0);		}		if(button->keycode != KEY_CODE_INVALID)// && button->keycode != last_key)		{			input_report_key_2440(&kbd.dev, button->keycode, down);			input_sync_2440(&kbd.dev);			//printk("IN DOWN dwon==%d, button->index==%02x, button->keycode==%x, last_key==%d\n",down,button->index,button->keycode,last_key);			printk("%d--------------------%d\n",irq,button->keycode);			//printk("%x button %s\n\n\n",button->keycode, down ? "pressed" : "released");			mdelay(10);			input_report_key(&kbd.dev, button->keycode, 0);                        input_sync(&kbd.dev);			button->keycode = KEY_CODE_INVALID;		}		for (i = 0; i < ARRAY_SIZE (s3c2410kbd_x); i++) 		{			s3c2410_gpio_cfgpin(s3c2410kbd_x[i].pin,  s3c2410kbd_x[i].pin_setting);		}//	}	mdelay(10);		for (i = 0; i < 4; i++) {		enable_irq(s3c2410kbd_x[i].irq);	};	return IRQ_HANDLED;}int __init s3c2410kbd_init(void){		int i;	int ret;	printk(KERN_INFO "s3c2410kbd_init\n");	/* Initialise input stuff */	memset(&kbd, 0, sizeof(struct s3c2410kbd));	init_input_dev(&kbd.dev);//	set_bit(EV_KEY,kbd.dev.evbit[0]);	kbd.dev.evbit[0] = BIT(EV_KEY);	sprintf(kbd.phys, "input/s3c2410_kbd0");	kbd.dev.private = &kbd;	kbd.dev.name = DRV_NAME;	kbd.dev.phys = kbd.phys;	kbd.dev.id.bustype = BUS_HOST;	kbd.dev.id.vendor = 0xDEAD;	kbd.dev.id.product = 0xBEEF;	kbd.dev.id.version = S3C2410KBDVERSION;		gpgcon = ioremap_nocache(GPGCON,0x0000004);	//qsm2007-06-30	gpfcon = ioremap_nocache(GPFCON,0x0000004);	test_reg= ioremap_nocache(TESTCON,0x0000004);	for (i = 0; i < ARRAY_SIZE (s3c2410kbd_buttons); i++) 	{		set_bit(s3c2410kbd_buttons[i], kbd.dev.keybit);	}	s3c2410_gpio_cfgpin(s3c2410kbd_x[0].pin,s3c2410kbd_x[0].pin_setting);//qsmstat	printk("GPGCON=%x\n",readl(gpgcon));    //qsm2006-06-30	writel(readl(gpgcon)&(~(0x00c00cc0)),gpgcon);	writel(readl(gpgcon)|(0x00800880),gpgcon);	writel(readl(gpfcon) & (~0x3),gpfcon);        writel(readl(gpfcon) | 0x2   ,gpfcon);	*(volatile unsigned *)S3C2410_GPGUP = 0;	*(volatile unsigned *)S3C2410_GPFUP = 0;      printk("later GPGCON=%x\n",readl(gpgcon)); //qsmend	for (i = 0; i < ARRAY_SIZE (s3c2410kbd_x); i++) 	{//qsm2007-06-30		s3c2410_gpio_cfgpin(s3c2410kbd_x[i].pin,s3c2410kbd_x[i].pin_setting);		//		printk("GPGCON=%x\n",readl(gpgcon));//qsm2006-06-30			printk("befor TESTCON=%x\n",readl(test_reg)); 		set_irq_type(s3c2410kbd_x[i].irq, IRQT_BOTHEDGE);//ztl		ret = request_irq (s3c2410kbd_x[i].irq, s3c2410kbd_keyevent,\		             SA_INTERRUPT, DRV_NAME, &s3c2410kbd_x[i]);		printk("ret%d!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",ret);		printk("request_irq[%d] successfully!\n",s3c2410kbd_x[i].irq);		printk("later TESTCON=%x\n",readl(test_reg)); 		writel(readl(test_reg)&((0xfffff2f2)),test_reg);		printk("last  TESTCON=%x\n",readl(test_reg)); 		//disable_irq(s3c2410kbd_x[i].irq);				//set_irq_type(s3c2410kbd_x[i].irq, IRQT_BOTHEDGE);		//set_irq_type(s3c2410kbd_x[i].irq, IRQT_FALLING);		//set_irq_type(s3c2410kbd_x[i].irq, IRQT_RISING);		//set_irq_type(s3c2410kbd_x[i].irq, IRQT_LOW);		printk("====== !!!!%d!!!!!!!%d!!!!!!!!!%d!!!!!!!!!!!!!!\n",IRQT_BOTHEDGE, IRQT_FALLING,IRQT_RISING);	}		printk("last GPGCON=%x\n",readl(gpgcon));	//qsm2006-06-30	for (i = 0; i < ARRAY_SIZE (s3c2410kbd_y); i++) 	{		s3c2410_gpio_cfgpin(s3c2410kbd_y[i].pin,  s3c2410kbd_y[i].pin_setting);		s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,0);	}	*(volatile unsigned *)S3C2410_GPBCON &= (~0x20fc00);	*(volatile unsigned *)S3C2410_GPBCON |= 0x105400;	*(volatile unsigned *)S3C2410_GPBDAT = 0;	*(volatile unsigned *)S3C2410_GPBUP  = 0;			printk(KERN_INFO "%s successfully loaded\n", DRV_NAME);	//printk(KERN_INFO "%d successfully loaded\n", );	/* All went ok, so register to the input system */	input_register_device(&kbd.dev);	return 0;}void __exit s3c2410kbd_remove(void){	int i;	for (i = 0; i < ARRAY_SIZE (s3c2410kbd_x); i++)	{		disable_irq(s3c2410kbd_x[i].irq);		free_irq(s3c2410kbd_x[i].irq,&kbd.dev);	}	input_unregister_device(&kbd.dev);}module_init(s3c2410kbd_init);module_exit(s3c2410kbd_remove);

⌨️ 快捷键说明

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