1. 程式人生 > >linux裝置驅動(3)字元驅動 -按鍵(查詢法)

linux裝置驅動(3)字元驅動 -按鍵(查詢法)

本文描述查詢法。 所謂查詢法,就是在應用程式裡面執行

while (1)
	{
		read(fd, key_vals, sizeof(key_vals));
        ...
	}

載入驅動並在後臺執行應用程式時, 通過top可以看到CPU利用率,該應用程序佔用99%。

先看應用程式

int main(int argc, char **argv)
{
	int fd;
	unsigned char key_vals[6];
	int cnt = 0;
	
	fd = open("/dev/buttons", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
	}

	while (1)
	{
		read(fd, key_vals, sizeof(key_vals));
		if (!key_vals[0] || !key_vals[1] || !key_vals[2] || !key_vals[3] || !key_vals[4] || !key_vals[5])
		{
			printf("%04d key pressed: %d %d %d %d %d %d\n", cnt++, key_vals[0], key_vals[1], key_vals[2], 
				key_vals[3], key_vals[4], key_vals[5]);
		}
	}
	
	return 0;
}

對於應用程式, 其框架如下

①實現file_operation裡面的open, read等函式

static struct file_operations buttons_fops = 
{
	.owner        = THIS_MODULE,
	.open         = buttons_open,
	.read         = buttons_read,
};

②註冊(register_chrdev)

major = register_chrdev(0, "buttons_drv", &buttons_fops);

③入口(module_init)

static int buttons_init(void)
{
	major = register_chrdev(0, "buttons_drv", &buttons_fops);

	buttons_class = class_create(THIS_MODULE, "buttons_drv");
	buttons_class_dev = class_device_create(buttons_class, NULL, MKDEV(major, 0),
		            NULL, "buttons");

	gpgcon = (volatile unsigned int*)ioremap(GPG_BASE, 4);
	gpgdat = gpgcon + 1;
	
	return 0;
}

④出口(module_exit)

static void buttons_exit(void)
{
	iounmap(gpgcon);
	
	class_device_unregister(buttons_class_dev);
	class_destroy(buttons_class);

	unregister_chrdev(major, "buttons_drv");
}

⑤硬體相關設定(地址對映)

static int buttons_open (struct inode *inode, struct file *file)
{
	// 設定引腳位輸入引腳
	*gpgcon &= ~((0x3 << (0 * 2)) | (0x3 << (3 * 2)) | (0x3 << (5 * 2)) | (0x3 << (6 * 2)) |\
				(0x3 << (7 * 2))| (0x3 << (11 * 2)));
	return 0;
}

完整程式如下:

/*
*  kernel : linux-2.6.22.6
*  gcc     : arm-linux-gcc -3.4.5
*
*   desc   : 這裡使用輪詢的方式,缺點很明顯, 佔CPU資源
*/

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

#include <linux/device.h>    /* class_device ... */


/**
*  buttons of mini2440, 低電平觸發
*    K1     GPG0    EINT8
*    K2     GPG3    EINT11
*    K3     GPG5    EINT13
*    K4     GPG6    EINT14
*    K5     GPG7    EINT15
*    K6     GPG11   EINT19
*/

static int major ;

static struct class *buttons_class;
static struct class_device *buttons_class_dev;

#define GPG_BASE 			0x56000060
static volatile unsigned int *gpgcon = NULL;
static volatile unsigned int *gpgdat = NULL;


static int buttons_open (struct inode *inode, struct file *file)
{
	// 設定引腳位輸入引腳
	*gpgcon &= ~((0x3 << (0 * 2)) | (0x3 << (3 * 2)) | (0x3 << (5 * 2)) | (0x3 << (6 * 2)) |\
				(0x3 << (7 * 2))| (0x3 << (11 * 2)));
	return 0;
}

static int buttons_read (struct file *file, char __user *usrbuf, size_t len , loff_t *offset)
{
	unsigned char val[6] = {0};
	int regval = 0;

	regval = *gpgdat;
	val[0] = (regval & (1 << 0)) ? 1: 0;
	val[1] = (regval & (1 << 3)) ? 1: 0;
	val[2] = (regval & (1 << 5)) ? 1: 0;
	val[3] = (regval & (1 << 6)) ? 1: 0;
	val[4] = (regval & (1 << 7)) ? 1: 0;
	val[5] = (regval & (1 << 11)) ? 1: 0;

	if(copy_to_user(usrbuf, val, sizeof(val)))
		return -EFAULT;
	return sizeof(val);
}


static struct file_operations buttons_fops = 
{
	.owner        = THIS_MODULE,
	.open         = buttons_open,
	.read         = buttons_read,
};

static int buttons_init(void)
{
	major = register_chrdev(0, "buttons_drv", &buttons_fops);

	buttons_class = class_create(THIS_MODULE, "buttons_drv");
	buttons_class_dev = class_device_create(buttons_class, NULL, MKDEV(major, 0),
		            NULL, "buttons");

	gpgcon = (volatile unsigned int*)ioremap(GPG_BASE, 4);
	gpgdat = gpgcon + 1;
	
	return 0;
}

static void buttons_exit(void)
{
	iounmap(gpgcon);
	
	class_device_unregister(buttons_class_dev);
	class_destroy(buttons_class);

	unregister_chrdev(major, "buttons_drv");
}

module_init(buttons_init);
module_exit(buttons_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("buttons driver for mini2440");