一般情况下很少需要使用注册轮询设备的,
因为轮询设备需要高频率调用获取外设的状态,增加CPU的负担.
但是碰到过2次需要使用注册轮询的情况:
1 外设IO口非常紧张的情况下,没有空出多余的IO口作为中断脚.
2 所使用的IO口没有带有中断功能.芯片中没有设计其对应的中断号
#include <linux/input-polldev.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
struct pollgpio_key_data {
int m_id;
struct input_polled_dev *poll_dev;
};
static void adgpiokeys_poll(struct input_polled_dev *dev){
struct timex txc;
struct rtc_time tm;
do_gettimeofday(&(txc.time));
rtc_time_to_tm(txc.time.tv_sec,&tm);
printk("[%d-%02d-%02d %02d:%02d:%02d][%s,pid=%d]\n",
tm.tm_year+1900,tm.tm_mon+1, tm.tm_mday,
tm.tm_hour,tm.tm_min,tm.tm_sec,
__FUNCTION__, current->pid);
}
static int adgpiokeys_probe(struct platform_device *pdev){
struct pollgpio_key_data *adkey;
struct input_polled_dev *poll_dev;
int err;
printk("%s, pid=%d\n", __func__, current->pid);
adkey = kzalloc(sizeof(struct pollgpio_key_data), GFP_KERNEL);
if (!adkey){
return -ENOMEM;
}
poll_dev = input_allocate_polled_device();
if (!poll_dev) {
err = -ENOMEM;
goto fail;
}
platform_set_drvdata(pdev, adkey);
// 不设置名字会警告 input: Unspecified device as /devices/virtual/input/input10
poll_dev->input->name = "demo-name01";
poll_dev->input->phys = "demopoll-key/input0";
poll_dev->poll = adgpiokeys_poll;
poll_dev->poll_interval = 200; // 设置轮询的频率为200毫秒, default = 500
adkey->poll_dev = poll_dev; // for set_drvdata and get_drvdata
adkey->m_id = 0x8008;
err = input_register_polled_device(poll_dev);
if (err)
goto fail;
return 0;
fail:
printk(KERN_ERR "Adkey: failed to register driver, error: %d\n", err);
platform_set_drvdata(pdev, NULL);
input_free_polled_device(poll_dev);
kfree(adkey);
return err;
}
static int adgpiokeys_remove(struct platform_device *pdev){
struct pollgpio_key_data *adkey = platform_get_drvdata(pdev);
printk("%s,m_id=0x%x\n", __func__, adkey->m_id);
input_unregister_polled_device(adkey->poll_dev);
input_free_polled_device(adkey->poll_dev);
kfree(adkey);
return 0;
}
static struct platform_driver analog_ops = {
.probe = adgpiokeys_probe,
.remove = __devexit_p(adgpiokeys_remove),
.suspend = NULL,
.resume = NULL,
.driver = {
.owner = THIS_MODULE,
.name = "analog-key",
},
};
static int __init ad_gpio_key_init(void){
return platform_driver_register(&analog_ops);
}
static void __exit ad_gpio_key_exit(void){
printk("analog_gpio_key_exit\n");
platform_driver_unregister(&analog_ops);
}
//late_initcall(ad_gpio_key_init);
module_init(ad_gpio_key_init);
module_exit(ad_gpio_key_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mr.linux.debug");
MODULE_DESCRIPTION("Demo ad gpio poll for kernel module");
相关函数接口的原型分析
/// 向内核申请一个轮询设备
struct input_polled_dev *input_allocate_polled_device(void)
{
struct input_polled_dev *dev;
dev = kzalloc(sizeof(struct input_polled_dev), GFP_KERNEL);
if (!dev)
return NULL;
dev->input = input_allocate_device();
if (!dev->input) {
kfree(dev);
return NULL;
}
return dev;
}
向输入子系统注册一个轮询设备
int input_register_polled_device(struct input_polled_dev *dev)
{
struct input_dev *input = dev->input;
input_set_drvdata(input, dev);
INIT_DELAYED_WORK(&dev->work, input_polled_device_work);
if (!dev->poll_interval)
dev->poll_interval = 500;
input->open = input_open_polled_device;
input->close = input_close_polled_device;
return input_register_device(input);
}
/// 轮询设备的结构体
struct input_polled_dev {
void *private; // 私有的驱动数据
void (*flush)(struct input_polled_dev *dev); // 驱动程序提供的方法,刷新设备的状态(可选)
void (*poll)(struct input_polled_dev *dev); // 轮询调用的处理函数
unsigned int poll_interval; /* msec */ // 轮询的间隔时间, 以毫秒为单位
struct input_dev *input; // 普通的输入子设备
struct delayed_work work; // 包含一个延时工作队列
};
可以看出来两个接口的处理原理
input_allocate_polled_device | 向内核申请一个轮询设备 就是对申请输入子系统设备(input_allocate_device)二次封装 |
input_register_polled_device | 向输入子系统注册一个轮询设备 就是对注册输入子系统设备(input_register_device)二次封装 |