S3C6410 按键驱动(五) --- 驱动源代码(我采用自动分配设备号的方法,注册设备)

/**********wzk_key.c ************/
/******wzk*********/
#include "wzk_key.h"

int DOWN = 0;
/*
#define DEVICE_NAME	"keys"
#define KEY_MAJOR 232


static unsigned long key_table [] = {
       S3C64XX_GPN(0),
       S3C64XX_GPN(1),
       S3C64XX_GPN(2),
       S3C64XX_GPN(3),
       S3C64XX_GPN(4),
       S3C64XX_GPN(5),

};
*/

//timer
void my_timer_callback(unsigned long tmp)
{
	DOWN = 0;
	printk("timer\n");
}

void init_mytimer(void)
{

	init_timer(&mytimer);
	mytimer.data = 5;
	mytimer.expires = jiffies + 1;
	mytimer.function = my_timer_callback;
	add_timer(&mytimer);

	return;
}

void start_timer(int time_value)
{

	int ret;

	DOWN = 1;
	ret = mod_timer(&mytimer,jiffies + msecs_to_jiffies(time_value));
	if(ret)
	{
		printk("mod_timer error!\n");
		return;
	}

	return;
}


void clear_keys(void)
{
	int i;
	for(i = 0; i < 6; i++)
	{
		key_values[i] = '0';
	}

	return;
}

static irqreturn_t keys_interrupt(int irq,void *dev_id)
{
	struct key_irq *key_irqs = (struct key_irq *)dev_id;
	int number;

	clear_keys();

	number = key_irqs->number;
	printk("number = %d\n",number);
	if(DOWN == 0)
	{
	switch(number)
	{
		case 0:
//			key_values[number] = '1';
			start_timer(1000);	
			break;
		case 1:
//			key_values[number] = '1';	
			start_timer(1000);
			break;
		case 2:
//			key_values[number] = '1';	
			start_timer(1000);		
			break;

		case 3:
//			key_values[number] = '1';	
			start_timer(1000);	
			break;

		case 4:
//			key_values[number] = '1';	
			start_timer(1000);	
			break;

		case 5:
//			key_values[number] = '1';	
			start_timer(1000);	
			break;

/*
			tmp = readl(S3C64XX_GPNDAT);
			down = !(tmp & (1 << number));
			break;
*/
		default:
			key_values[number] = '0';
			return IRQ_RETVAL(IRQ_HANDLED);
	}

	key_values[number] = '1';
	ev_press = 1;
	wake_up_interruptible(&key_waitq);
/*
	if(down != (key_values[number] & 1))
	{
		key_values[number] = '0' + down;
		ev_press = 1;
		
		wake_up_interruptible(&key_waitq);
*/
	printk("interrupt\n");
	}
	return IRQ_RETVAL(IRQ_HANDLED);
}

int s3c6410_keys_open(struct inode *inode,struct file *file)
{

	int num;
	int ret;

	for(num = 0; num < KEYNUM; num++)
	{
		ret = request_irq(key_irqs[num].irq,keys_interrupt,key_irqs[num].flags,key_irqs[num].name,(void*)&key_irqs[num]);
	}

	init_mytimer();
	return 0;
}

int s3c6410_keys_close(struct inode *inode,struct file *file)
{
	int i;
	int ret;
	for(i = 0; i < KEYNUM; i++)
	{
		free_irq(key_irqs[i].irq,(void*)&key_irqs[i]);
	}

	ret = del_timer(&mytimer);
	if(ret)
	{
		printk("timer is using ...\n");
	}
	return 0;
}

static int s3c6410_keys_read(struct file *filp,char __user *buff,size_t count,loff_t *offp)
{
	unsigned long err;
	if(!ev_press)
	{
		wait_event_interruptible(key_waitq,ev_press);
		printk("ev_press = %d\n",ev_press);
	}

	ev_press = 0;

	err = copy_to_user((void *)buff,(const void*)(&key_values),min(sizeof(key_values),count));

	return min(sizeof(key_values),count);
}

static unsigned int s3c6410_keys_poll(struct file *file,struct poll_table_struct *wait)
{
	unsigned int mask = 0;
	poll_wait(file,&key_waitq,wait);
	if(ev_press)
		mask |= POLLIN | POLLRDNORM;
	return mask;
}

static long s3c6410_keys_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	return 0;
}


//set gpk is interrupt mode
void init_dev(void)
{
	unsigned int tmp;
	
	s3c_gpio_cfgpin(key_table[0],S3C_GPIO_SFN(2));
	s3c_gpio_cfgpin(key_table[1],S3C_GPIO_SFN(2));
	s3c_gpio_cfgpin(key_table[2],S3C_GPIO_SFN(2));
	s3c_gpio_cfgpin(key_table[3],S3C_GPIO_SFN(2));
	s3c_gpio_cfgpin(key_table[4],S3C_GPIO_SFN(2));
	s3c_gpio_cfgpin(key_table[5],S3C_GPIO_SFN(2));

	tmp = readl(S3C64XX_GPNCON);
	printk("%x\n",tmp);
}

static struct file_operations s3c6410_keys_fops = {
	.owner	= THIS_MODULE,
	.open = s3c6410_keys_open,
	.unlocked_ioctl	= s3c6410_keys_ioctl,
	.release = s3c6410_keys_close,
	.read = s3c6410_keys_read,
	.poll = s3c6410_keys_poll
};

static struct cdev cdev_keys;
struct class * my_class;
dev_t devno;

static int __init s3c6410_keys_init(void)
{
	int ret;
//	dev_t devno;
	printk(KERN_NOTICE "enter s3c6410_keys_init\n");


	devno = MKDEV(KEY_MAJOR,0);

	ret = alloc_chrdev_region(&devno,0,1,DEVICE_NAME);
	if(ret)
	{
		printk(KERN_NOTICE "can not register led device");
		return ret;
	}
	
	cdev_init(&cdev_keys,&s3c6410_keys_fops);
	cdev_keys.owner = THIS_MODULE;

	ret =cdev_add(&cdev_keys,devno,1);
	if(ret)
	{
		printk(KERN_NOTICE "can not add leds device");
		return ret;
	}

	my_class = class_create(THIS_MODULE,DEVICE_NAME);
	if(IS_ERR(my_class))
	{
		printk("Err: Failed in creating class\n");
		return -1;	
	}

	device_create(my_class,NULL,devno,NULL,DEVICE_NAME);

	init_dev();

	printk(DEVICE_NAME " initialized\n");

	return 0;
}

static void __exit s3c6410_keys_exit(void)
{

	
	device_destroy(my_class,devno);
	class_destroy(my_class);

	cdev_del(&cdev_keys);

	unregister_chrdev_region(devno,1);	

	printk(KERN_NOTICE "s3c6410_keys_exit\n");
}


module_init(s3c6410_keys_init);
module_exit(s3c6410_keys_exit);

MODULE_LICENSE("GPL");



/**********wzk_key.h***********/



#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/irq.h>
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-n.h>
#include <mach/map.h>                   //S3C64XX_VA_GPIO
#include <plat/gpio-cfg.h>
#include <mach/hardware.h>
#include <linux/io.h>
#include <asm/io.h>

#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/semaphore.h>
#include <linux/timer.h>

#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/irqs.h>

#include <linux/timer.h>
#include <linux/jiffies.h>

#define DEVICE_NAME     "keys"
#define KEY_MAJOR 189


static unsigned long key_table [] = {
       S3C64XX_GPN(0),
       S3C64XX_GPN(1),
       S3C64XX_GPN(2),
       S3C64XX_GPN(3),
       S3C64XX_GPN(4),
       S3C64XX_GPN(5),

};

struct key_irq{

	int irq;
	int number;
	unsigned long flags;
	char *name;
};

static struct key_irq key_irqs[] = {

	{IRQ_EINT(0),0,IRQF_TRIGGER_FALLING,"KEY1"}, 
	 //./include/linux/interrupt.h
	//./arch/arm/mach-s3c64xx/include/mach/irqs.h
	{IRQ_EINT(1),1,IRQF_TRIGGER_FALLING,"KEY2"}, 
	{IRQ_EINT(2),2,IRQF_TRIGGER_FALLING,"KEY3"}, 
	{IRQ_EINT(3),3,IRQF_TRIGGER_FALLING,"KEY4"}, 
	{IRQ_EINT(4),4,IRQF_TRIGGER_FALLING,"KEY5"}, 
	{IRQ_EINT(5),5,IRQF_TRIGGER_FALLING,"KEY6"}
};

static DECLARE_WAIT_QUEUE_HEAD(key_waitq);

#define KEYNUM 6

static volatile int ev_press = 0;
static volatile char key_values[] = {0,0,0,0,0,0};
//static volatile int press_cnt[KEYNUM] = {0,0,0,0,0,0};

static struct timer_list mytimer;


你可能感兴趣的:(S3C6410 按键驱动(五) --- 驱动源代码(我采用自动分配设备号的方法,注册设备))