dtcms文档 Zookeeper使用 ssm vuejs2 Zeptojs Plupload vue表单提交 后台系统模板 sql server 视频教程 jquery循环 jquery解析json mac虚拟打印机 mysql错误代码1064 java微服务架构 mysql教程 destoon python最大值 python字符串匹配 python命令大全 stringjava java数据类型 java写入txt java架构 flash相册制作 qq飞车剧情辅助 整站系统 位置不可用 pmbok第六版 ABViewer 数组求和 windowsjs延时函数 正当防卫4存档 神魔辅助 winsxs可以删除吗 appsync补丁 hedit 中文微信小程序API 女圣骑 a1474 轮播图代码
当前位置: 首页 > 学习教程  > 编程语言

Linux驱动注册轮询设备

2020/7/24 10:30:28 文章标签:

一般情况下很少需要使用注册轮询设备的,
因为轮询设备需要高频率调用获取外设的状态,增加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)二次封装

本文链接: http://www.dtmao.cc/news_show_50293.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?