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

📄 key_driver.c

📁 在linux2.6.8.1下的s3c2410的键盘驱动
💻 C
字号:
/********************************************
*  *GEC2410-BOX
*  *date : created at 2007-09-19 by baijb
********************************************/

#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/devfs_fs_kernel.h>

#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>

#define DEVICE_NAME	"key_driver"
#define LEDRAW_MINOR	1
#define KBD_TIMER_DELAY (HZ/50)

static int keyMajor = 0;

//--------------------------------------------
static struct key_info
{
	unsigned int 		irq_num;
	unsigned int 		gpio_port;
	unsigned int 		key_num;
} keys[2] = {
		{ IRQ_EINT10, S3C2410_GPG2, 1 },
		{ IRQ_EINT11, S3C2410_GPG3, 2 },	
	};

static int key_value = 0;
static int ready = 0;
static struct timer_list kbd_timer;
static DECLARE_WAIT_QUEUE_HEAD(key_wait);

/****************************************
*  *Pin function: EXINT
****************************************/
static void init_key_exint(void)
{
	__raw_writel(__raw_readl(S3C2410_GPGCON) & (~(0x0f<<4)) | (0x0a<<4), S3C2410_GPGCON);  //GPG2,3--EXINT10,11
	__raw_writel(__raw_readl(S3C2410_EXTINT1) & (~(0x77<<8)) | (0x22<<8), S3C2410_EXTINT1); //EXINT10,11--falling edge triger
}

/****************************************
*  * Pin funciton: input
****************************************/
static void init_key_input(void)
{
	__raw_writel(__raw_readl(S3C2410_GPGCON) & (~(0x0f<<4)), S3C2410_GPGCON);  //GPG2,3--EXINT10,11
}

//-------------------------------------------
static void kbd_timer_handler(unsigned long date)
{
	struct key_info *key=NULL;

	key_value = 0;
	if((__raw_readl(S3C2410_GPGDAT) &  (1<<2)) == 0 )  {		//GPG2--pressed
		key = &keys[0];
		key_value = key->key_num;
	}
	else if((__raw_readl(S3C2410_GPGDAT) &  (1<<3)) == 0 ) {	//GPG3--pressed
		key = &keys[1];
		key_value = key->key_num; 
	}

	ready = 1;
	del_timer(&kbd_timer);
	
	wake_up_interruptible(&key_wait);
	
	init_key_exint();
}

//--------------------------------------------
static irqreturn_t key_irq_handle(int irq, void *devid, struct pt_regs *regs){
	
	init_key_input();	//GPG2,3--input.delay 20 ms,then query which key is pressed.
	
	kbd_timer.expires = jiffies + KBD_TIMER_DELAY;		//delay 20 ms
	add_timer(&kbd_timer);
	
	return IRQ_HANDLED;
}

//---------------------------------------------
static int s3c2410_key_open(struct inode *inode, struct file *filp)
{
	int ret;
	struct key_info *key=NULL;
	
	printk(KERN_INFO DEVICE_NAME ": opened.\n");

	init_key_exint();
	
	ready = 0;
	key = &keys[0];
	
	ret = request_irq(key->irq_num, key_irq_handle, SA_INTERRUPT, DEVICE_NAME, NULL);
	if(ret) {
		printk(KERN_INFO DEVICE_NAME " Failed to request irq.\n");
		return ret;
	}

	key = &keys[1];
	ret = request_irq(key->irq_num, key_irq_handle, SA_INTERRUPT, DEVICE_NAME, NULL);
	if(ret) {
		printk(KERN_INFO DEVICE_NAME " Failed to request irq.\n");
		return ret;
	}

	init_timer(&kbd_timer);
	kbd_timer.function = kbd_timer_handler;
	
	return 0;
}

//-------------------------------------------------
static ssize_t s3c2410_key_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
	static int value;

	wait_event_interruptible(key_wait, ready == 1);
//	interruptible_sleep_on(&key_wait);

	if(count != sizeof(key_value)) {
		printk("there is no key pressed!\n");
		return -EINVAL;
	}

	value = key_value;
        copy_to_user(buffer, &value, sizeof(value));
	ready = 0;
	
        return sizeof(value);
}

//----------------------------------------------------------
static int s3c2410_key_release(struct inode *inode, struct file *filp)
{
	struct key_info *key=NULL;
	
	printk(KERN_INFO DEVICE_NAME ": released.\n");

	key = &keys[0];
	free_irq(key->irq_num, NULL);
	key = &keys[1];
	free_irq(key->irq_num, NULL);
	
	return 0;
}

//--------------------------------------------------------
static struct file_operations s3c2410_fops = {
	owner:	THIS_MODULE,
	open:	s3c2410_key_open,
	read:   	s3c2410_key_read,
	release:	s3c2410_key_release,
};

static int __init key_driver_init(void)
{
	int ret;

	printk("s3c2410 key_driver init\n");

	ret = register_chrdev(0, DEVICE_NAME, &s3c2410_fops);
	if (ret < 0) {
	  	printk(DEVICE_NAME " can't get major number\n");
	  	return ret;
	}
	keyMajor = ret;

	#ifdef CONFIG_DEVFS_FS
		devfs_mk_dir("key");
		devfs_mk_cdev(MKDEV(keyMajor, LEDRAW_MINOR), S_IFCHR|S_IRUGO|S_IWUSR, "key/%d", 0);
	#endif
	
	return ret;
}


static void __exit key_driver_exit(void)
{
	printk("key_driver exit!\n");
#ifdef CONFIG_DEVFS_FS	
	devfs_remove("key/%d", 0);	
	devfs_remove("key");			
#endif	

	unregister_chrdev(keyMajor, DEVICE_NAME);
}

module_init(key_driver_init);
module_exit(key_driver_exit);

⌨️ 快捷键说明

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