linux驱动实践(五)--linux下的按键驱动之查询方式

         虽然好几个月之前就对linux下的阻塞,非阻塞,select poll的实现,工作队列,tasklet等等做了较为深入的分析,但是在遇到实际的硬件驱动中,才真正去思考怎么将这些用到实际中,构建一个稳定高效的驱动。

        板子上有四个按键,linux内核中有input子系统来很好的完成这个事情。先按照自己的思路一步步来,最后看下人家input子系统是如何实现的,肯定有不少值得借鉴的。

        其实按键驱动的查询方式没什么实际价值,因为一直处于查询过程中,进程没有睡眠,占用cpu非常高,让其他应用程序没法很好的利用cpu。先看看驱动使用后的cpu状况:

        top -d  5


        看到这个cpu利用率,就可以明白这个驱动没什么用了,但是没关系,后面一步步用开头提到的方式来打造一个可以用的驱动程序。代码比较糟糕,还是贴一下,与将来的好代码做个对比:

        驱动代码:

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>

#include <linux/kernel.h>	/* printk() */
#include <linux/slab.h>		/* kmalloc() */
#include <linux/fs.h>		/* everything... */
#include <linux/errno.h>	/* error codes */
#include <linux/types.h>	/* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h>	/* O_ACCMODE */
#include <linux/seq_file.h>
#include <linux/cdev.h>
#include <linux/ioport.h>

#include <asm/system.h>		/* cli(), *_flags */
#include <asm/uaccess.h>	/* copy_*_user */
#include <asm/io.h>

#define KEY_NUM			4

#define GPFCON	 0x56000050 
#define GPFDAT	 0x56000054 
#define GPFUP 	 0x56000058


struct key_dev
{
	struct cdev dev;
	void __iomem *base;
	unsigned long offset;
};

struct key_dev Key[4];
dev_t dev = 0;

void __iomem *con;


int key_open(struct inode *inode, struct file *filp)
{
	struct key_dev *key; /* device information */

	key = container_of(inode->i_cdev, struct key_dev, dev);
	filp->private_data = key; /* for other methods */

	return 0;          /* success */
}

int key_release(struct inode *inode, struct file *filp)
{
	return 0;
}

ssize_t key_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	char data;
	struct key_dev *key;
	u32 value;
	//printk(KERN_INFO "debug by baikal: key dev read\n");

	key = (struct key_dev *)filp->private_data;
	value = ioread32(key->base);
	if(value & 1<<key->offset)
		data = '0';
	else
		data = '1';
	copy_to_user(buf,&data,count);
	return 0;
}

ssize_t key_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	return 0;	
}

struct file_operations key_fops = {
	.owner =    THIS_MODULE,
	.read =     key_read,
	.write =    key_write,
	//.ioctl =    key_ioctl,
	.open =     key_open,
	.release =  key_release,
};

static int key_init(void)
{	
	int result, i;
	u32 value;
	
	request_mem_region(GPFCON,0x4,"key");
	con = ioremap(GPFCON,0x4);
	value = ioread32(con);
	iowrite32(value & 0xfcc0 ,con);      //配置GPF0,1,2,4为input

	result = alloc_chrdev_region(&dev, 0, KEY_NUM,"key");
	if (result < 0) {
		printk(KERN_WARNING "key: can't get major %d\n", MAJOR(dev));
		return result;
	}
	
	for(i = 0; i < KEY_NUM; i++)
	{
		cdev_init( &Key[i].dev, &key_fops);
		request_mem_region(GPFDAT,0x4,"key");
		Key[i].base = ioremap(GPFDAT,0x4);
		if(i < 3)
			Key[i].offset = i;
		else
		    	Key[i].offset = i+1;
			     
		Key[i].dev.owner = THIS_MODULE;
		Key[i].dev.ops = &key_fops;
		result = cdev_add(&Key[i].dev,MKDEV(MAJOR(dev),i),1);
		if(result < 0)
		{
			printk(KERN_ERR "KEY: can't add key%d\n",i);
			return result;
		}
	}

	return 0;
}

static void key_exit(void)
{
	int i;		
	release_mem_region(GPFCON,0x4);
	iounmap(con);
	release_mem_region(GPFDAT,0x4);
	for( i = 0; i < KEY_NUM; i++)
	{
		iounmap(Key[i].base);

		cdev_del(&Key[i].dev);	
	}
	unregister_chrdev_region(dev, KEY_NUM);

}


module_init(key_init);
module_exit(key_exit);

MODULE_AUTHOR("Baikal");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Simple Keyboard Driver");

        测试代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>

int main(int argc, char **argv)
{
    	int fd[4];
	char data;
	if(argc != 1)
	{
		printf("usage : ./key\n");

		return -1;
	}

	fd[0] = open("/dev/key0",O_RDWR);
	fd[1] = open("/dev/key1",O_RDWR);
	fd[2] = open("/dev/key2",O_RDWR);
	fd[3] = open("/dev/key4",O_RDWR);

	if(fd[0] < 0)
	{
		perror("open key[0]");
		return -1;    
	}

	if(fd[1] < 0)
	{
		perror("open key[1]");
		return -1;    
	}

	if(fd[2] < 0)
	{
		perror("open key[2]");
		return -1;    
	}

	if(fd[3] < 0)
	{
		perror("open key[4]");
		return -1;    
	}


	while(1)
	{
	    
		read(fd[0], &data, 1);
		//printf("data:%d\n",data);
		if(data == '1')
			printf("key 0 pressed\n");
		else
		    	;
		    	//printf("key 0 not pressed\n");

		read(fd[1], &data, 1);
		if(data == '1')
		    	printf("key 1 pressed\n");

		read(fd[2], &data, 1);
		if(data == '1')
		    	printf("key 2 pressed\n");

		read(fd[3], &data, 1);
		if(data == '1')
		    	printf("key 4 pressed\n");

	
	    
	    
	}
	return 0;


}


        

你可能感兴趣的:(linux驱动实践(五)--linux下的按键驱动之查询方式)