本文描述查询法。 所谓查询法,就是在应用程序里面执行
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("Flinn682@foxmail.com");
MODULE_DESCRIPTION("buttons driver for mini2440");