s3c2410kbd.c~

来自「优龙2410linux2.6.8内核源代码」· C~ 代码 · 共 325 行

C~
325
字号
/* * 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;#define GPGCON	0x56000060//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_ESC,	KEY_4,         KEY_5,         KEY_6,         KEY_BACKSPACE,	KEY_7,         KEY_8,         KEY_9,         KEY_ENTER,	KEY_PAGEUP,    KEY_3,         KEY_PAGEDOWN,  KEY_PRINT};*///由于历史问题,仍用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_EINT13, S3C2410_GPG5,   S3C2410_GPG5_EINT13,  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_GPB6,   S3C2410_GPB6_OUTP,   3 },	{  0,  S3C2410_GPB7,   S3C2410_GPB7_OUTP,   2 },	{  0,  S3C2410_GPB5,   S3C2410_GPB5_OUTP,   1 },	{  0,  S3C2410_GPB10,  S3C2410_GPB10_OUTP,  0 },};struct s3c2410kbd {	struct input_dev  dev;	spinlock_t        lock;	int               count;	int               shift;		char              phys[32];};static struct s3c2410kbd kbd;//qsm2007-06-29#if 0unsigned int s3c2410_gpio_getcfg(unsigned int pin){        unsigned long base = S3C2410_GPIO_BASE(pin);        unsigned long offs = S3C2410_GPIO_OFFSET(pin);        return __raw_readl(base + 0x04) & (1<< offs);}#endifstatic  irqreturn_t s3c2410kbd_keyevent(int irq, void *dev_id, struct pt_regs *regs){	struct s3c2410kbd_button *button = (struct s3c2410kbd_button *)dev_id; 	unsigned int down,tmp;//	static void *gpfcon,*gpfdata,*gpgcon,*gpgdata;	unsigned int gpfcon,gpfdata,gpgcon,gpgdata,gpbcon,gpbdata;	int last_key = button->keycode;//	gpgcon = ioremap_nocache(S3C2410_GPGCON,0x0000004);//	gpgcon = ioremap_nocache(GPGCON,0x0000004)//	printk("!button\n");	mdelay(30);	if (!button)		return IRQ_HANDLED;	mdelay(10);	tmp = s3c2410_gpio_getpin(button->pin);//	printk("frist getpin button->pin:%x  == %x\n",button->pin,tmp);	mdelay(1);	down = !(tmp);//	printk("frist down= %d ,last_key = %d \n",down,last_key);	//printk(KERN_DEBUG "%d %02x %x\n",down,button->index,button->keycode);	if(last_key != KEY_CODE_INVALID)	{		input_report_key(&kbd.dev, last_key, 0);	//	mdelay(10);		input_sync(&kbd.dev);		mdelay(100);		button->keycode = KEY_CODE_INVALID;		//printk(KERN_DEBUG "%x button %s\n",last_key, "force up");	}	else 	{		input_report_key(&kbd.dev, last_key, 1);                //      mdelay(10);                        input_sync(&kbd.dev);                        mdelay(100);	}	if(down)	{	//printk("In down \n");		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_setpin(s3c2410kbd_x[i].pin,0);		//	mdelay(10);		}		mdelay(1);//qsm_start#if 0		gpfcon = readl(S3C2410_GPFCON);		gpfdata = readl(S3C2410_GPFDAT);		gpgcon = readl(S3C2410_GPGCON);		gpgdata = readl(S3C2410_GPGDAT);		printk("set Xdata gpfcon==%x , gpfdata=%x\n",gpfcon,gpfdata);		printk("set Xdata gpgcon==%x , gpgdata=%x\n",gpgcon,gpgdata);#endif//qsm-end		for (i = 0; button->keycode == KEY_CODE_INVALID && i < ARRAY_SIZE (s3c2410kbd_y); i++) 		{			s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,1);			mdelay(10);			if(s3c2410_gpio_getpin(button->pin))			{								button->keycode = s3c2410kbd_buttons[button->index + s3c2410kbd_y[i].index];			}						s3c2410_gpio_setpin(s3c2410kbd_y[i].pin,0);		//	mdelay(10);		}		mdelay(1);		if(button->keycode != KEY_CODE_INVALID && button->keycode != last_key)		{						input_report_key(&kbd.dev, button->keycode, down);		//	mdelay(10);			input_sync(&kbd.dev);			mdelay(100);//			button->keycode = KEY_CODE_INVALID;			//printk(KERN_DEBUG "%x button %s\n",button->keycode, down ? "pressed" : "released");		}		else 		{			input_report_key(&kbd.dev, button->keycode, !down);                        input_sync(&kbd.dev);                        mdelay(100);		}		mdelay(1);		for (i = 0; i < ARRAY_SIZE (s3c2410kbd_x); i++) 		{			s3c2410_gpio_cfgpin(s3c2410kbd_x[i].pin,s3c2410kbd_x[i].pin_setting);		//	mdelay(10);		}//qsm-start#if 0		gpfcon = readl(S3C2410_GPFCON);                gpfdata = readl(S3C2410_GPFDAT);                gpgcon = readl(S3C2410_GPGCON);                gpgdata = readl(S3C2410_GPGDAT);                printk("set Xcon gpfcon==%x , gpfdata=%x\n",gpfcon,gpfdata);                printk("set Xcon gpgcon==%x , gpfdata=%x\n",gpgcon,gpgdata);#endif//qsm-end			}	return IRQ_HANDLED;}int __init s3c2410kbd_init(void){	int i;	unsigned int gpbcon,gpbdata;	printk(KERN_INFO "s3c2410kbd_init\n");	/* Initialise input stuff */	memset(&kbd, 0, sizeof(struct s3c2410kbd));	init_input_dev(&kbd.dev);	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	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(S3C2410_GPFCON) & (~0x3),S3C2410_GPFCON);	writel(readl(S3C2410_GPFCON) | 0x2 ,S3C2410_GPFCON);//      printk("later GPGCON=%x\n",readl(gpgcon)); //qsmend	for (i = 0; i < ARRAY_SIZE (s3c2410kbd_x); i++) 	{//		s3c2410_gpio_cfgpin(s3c2410kbd_x[i].pin,s3c2410kbd_x[i].pin_setting);//		printk("GPGCON=%x\n",readl(gpgcon));//qsm2006-06-30				request_irq (s3c2410kbd_x[i].irq, s3c2410kbd_keyevent,\		             SA_INTERRUPT, DRV_NAME, &s3c2410kbd_x[i]);//		printk("request_irq[%d] successfully!\n",i);		set_irq_type(s3c2410kbd_x[i].irq, IRQT_BOTHEDGE);//		s3c2410_gpio_setpin(s3c2410kbd_x[i].pin,0);	}//		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);	}	writel(readl(S3C2410_GPBCON) & ~0x20fc00 , S3C2410_GPBCON);	writel(readl(S3C2410_GPBCON)| 0x105400 , S3C2410_GPBCON);	writew(readw(S3C2410_GPBDAT) & 0 ,S3C2410_GPBDAT);	writeb(readb(S3C2410_GPFDAT) & 0 ,S3C2410_GPFDAT);	writew(readw(S3C2410_GPGDAT) & 0 ,S3C2410_GPGDAT);//qsm-start#if 0	printk("gpbcon == %x\n",readl(S3C2410_GPBCON));	printk("gpbdata == %x\n",readw(S3C2410_GPBDAT));	printk("gpfcon == %x\n" , readl(S3C2410_GPFCON));	printk("gpfdata == %x\n",readb(S3C2410_GPFDAT));	printk("gpgcon == %x\n",readl(S3C2410_GPGCON));	printk("gpgdata == %x\n",readw(S3C2410_GPGDAT));#endif//qsm-end	printk(KERN_INFO "%s successfully loaded\n", DRV_NAME);	/* 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 + =
减小字号Ctrl + -
显示快捷键?