linux裝置驅動(3)字元驅動 -按鍵(查詢法)
阿新 • • 發佈:2018-12-19
本文描述查詢法。 所謂查詢法,就是在應用程式裡面執行
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");