栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

platform框架----Linux MISC杂项框架---Linux INPUT 子系统框架

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

platform框架----Linux MISC杂项框架---Linux INPUT 子系统框架

platform框架 platform框架简述

不同架构有不同指令集
不同的系统级芯片的若干控制器的使用方法不同
鼠标,打印机等设备的控制器使用方法一样

platform 总线- -匹配

platform总线就是使用 platform_match 函数来根据注册的设备来查找对应的驱动,或者根据注册的驱动来查找相应的设备
platform_match(设备,驱动) //platform总线匹配设备和驱动

platform 驱动- -驱动的分隔与分离

platform_driver 结构体描画platform驱动(Driver 驱动程序,司机,车手,驾驶员)

 struct platform_driver {
 int (*probe)(struct platform_device *);            //当驱动与设备匹配成功以后 probe 函数就会执行
 int (*remove)(struct platform_device *);
 void (*shutdown)(struct platform_device *);
 int (*suspend)(struct platform_device *, pm_message_t state);
 int (*resume)(struct platform_device *);
 struct device_driver driver;                      //device_driver 相当于基类,提供了最基础的驱动框架。plaform_driver 继承了这个基类,然后在此基础上又添加了一些特有的成员变量
 const struct platform_device_id *id_table;        //id_table 是个表(也就是数组)
 bool prevent_deferred_probe;
 };
platform 设备- -传感器,打印机,鼠标等等

platform_device 结构体中的resource 结构体resource 表示资源,也就是设备信息,比如外设寄存器等。

struct resource {
 resource_size_t start;  //资源的起始信息
 resource_size_t end;    //资源的终止信息
 const char *name;       //资源名字
 unsigned long flags;    //资源类型
 struct resource *parent, *sibling, *child;
 };

platform_device 结构体来段描述设备,现在早都改用设备树去描述了(Device 设备,装置)

 struct platform_device {
 const char *name;
 int id;
 bool id_auto;
 struct device dev;
 u32 num_resources;
 struct resource *resource;

 const struct platform_device_id *id_entry;
 char *driver_override; 

 
 struct mfd_cell *mfd_cell;

 struct pdev_archdata archdata;
 };
platform框架的API函数
int platform_driver_register (要注册的platform驱动)     //向Linux内核注册一个 platform 驱动
void platform_driver_unregister(要拆卸的platform驱动)   //向Linux内核拆卸一个 platform 驱动
int platform_match(设备,驱动)                     //platform总线匹配设备和驱动
int platform_device_register(要注册的platform设备)      //向Linux内核注册一个platform设备
void platform_device_unregister(要拆卸的platform设备)   //向Linux内核拆卸一个platform设备

传统过时的拆卸设备的过程如下:
 cdev_del(); 
 unregister_chrdev_region(); 
 device_destroy(); 
 class_destroy(); 
platform框架使用示例 platform 设备框架
 
 #define PERIPH1_REGISTER_BASE (0x20000000) 
 #define PERIPH2_REGISTER_BASE (0x020E0068) 
 #define REGISTER_LENGTH 4                  //寄存器长度
 

 static struct resource xxx_resources[] = {  //一共有两个资源
 [0] = {
 .start = PERIPH1_REGISTER_BASE,             //资源的起始信息为外设1寄存器首地址
 .end = (PERIPH1_REGISTER_BASE + REGISTER_LENGTH - 1),//资源的终止信息为外设1寄存器首地址+寄存器长度-1
 .flags = IORESOURCE_MEM,                    //资源为内存类型的
 },
 [1] = {
 .start = PERIPH2_REGISTER_BASE,             //资源的起始信息为外设2寄存器首地址
 .end = (PERIPH2_REGISTER_BASE + REGISTER_LENGTH - 1),//资源的终止信息为外设2寄存器首地址+寄存器长度-1
 .flags = IORESOURCE_MEM,                    //资源为内存类型的
 },
 
 };
 
 static struct platform_device xxxdevice = {
 .name = "xxx-gpio",                      //注意 name 字段要和所使用的驱动中的 name 字段一致,否则驱动和设备无法匹配成功
 .id = -1,
 .num_resources = ARRAY_SIZE(xxx_resources),//num_resources 表示资源大小,其实就是数组 xxx_resources的元素数量
 .resource = xxx_resources,
 };

 
 static int __init xxxdevice_init(void)
 {
     return platform_device_register(&xxxdevice);  //向 Linux 内核注册一个 platform 驱动,Register 注册帐户,寄存器,登记
 }

 
 static void __exit xxx_resourcesdevice_exit(void)
 {
    platform_device_unregister(&xxxdevice);      //向 Linux 内核拆卸一个 platform 驱动,Register 注册帐户,寄存器,登记
 }

 module_init(xxxdevice_init);
 module_exit(xxxdevice_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("zuozhongkai");
platform 驱动框架
 struct xxx_dev{
 struct cdev cdev;
 
 };

struct xxx_dev xxxdev; 

static int xxx_open(struct inode *inode, struct file *filp)  //字符设备驱动open操作函数
 {
 
 return 0;
 }

 static ssize_t xxx_write(struct file *filp, const char __user *buf,size_t cnt, loff_t *offt)//字符设备驱动write操作函数
 {
 
 return 0;
 }

 static struct file_operations xxx_fops = {       //字符设备驱动操作集,注册字符设备驱动要指针xxx_fops
 .owner = THIS_MODULE,
 .open = xxx_open,
 .write = xxx_write,
 };

 static int xxx_probe(struct platform_device *dev) // platform驱动的probe函数,驱动与设备匹配成功以后此函数就会执行
 {
  ......
 cdev_init(&xxxdev.cdev, &xxx_fops); 

 return 0;
 }

 static int xxx_remove(struct platform_device *dev)  //当关闭 platform备驱动的时候此函数就会执行,使用 iounmap 释放内存、删除 cdev,注销设备号等等
 {
......
 cdev_del(&xxxdev.cdev);
 
 return 0;
 }

 
 static const struct of_device_id xxx_of_match[] = {
 { .compatible = "xxx-gpio" },   //匹配项的 compatible 值为“xxx-gpio”,因此当设备树中设备节点的 compatible 属性值为“xxx-gpio”的时候此设备就会与此驱动匹配
 {  }              //of_device_id 表最后一个匹配项必须是空的
 };

 
static struct platform_driver xxx_driver = {
 .driver = {
 .name = "xxx",                    //name 属性用于传统的驱动与设备匹配,也就是检查驱动和设备的 name 字段是不是相同
 .of_match_table = xxx_of_match,   //of_match_table 属性就是用于设备树下的驱动与设备检查
 },
 .probe = xxx_probe,               // platform驱动的probe函数,驱动与设备匹配成功以后此函数就会执行
 .remove = xxx_remove,              //当关闭 platform备驱动的时候此函数就会执行,使用 iounmap 释放内存、删除
 };


static int __init xxxdriver_init(void)
{
 return platform_driver_register(&xxx_driver); //向 Linux 内核注册一个 platform 驱动,Register 注册帐户,寄存器,登记
}

 
 static void __exit xxxdriver_exit(void)
 {
 platform_driver_unregister(&xxx_driver);    //向 Linux 内核拆卸一个 platform 驱动,Register 注册帐户,寄存器,登记
 }

 module_init(xxxdriver_init);   //指定为驱动的入口函数xxxdriver_init
 module_exit(xxxdriver_exit);   //指定为驱动的出口函数xxxdriver_exit
 MODULE_LICENSE("GPL");         // 指定LICENSE许可为GPL
 MODULE_AUTHOR("zuozhongkai");  // 指定作者信息为zuozhongkai
设备树下的 platform

当 Linux 内核支持了设备树以后就不需要用户手动去注册 platform 设备了。因为设备信息都放到了设备树中去描述,Linux 内核启动的时候会从设备树中读取设备信息,然后将其组织成 platform_device 形式于内核某空间,至于设备树到 platform_device 的具体过程就不去详细的追究了。
总之Linux内核织成的platform_device,和我们写最终结果一样

不使用设备树就自己定义初始化platform_device并加载此设备模块到linux内核某空间 (Device 设备,装置):
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 




#define CCM_CCGR1_BASE				(0x020C406C)	
#define SW_MUX_GPIO1_IO03_BASE		(0x020E0068)
#define SW_PAD_GPIO1_IO03_BASE		(0x020E02F4)
#define GPIO1_DR_BASE				(0x0209C000)
#define GPIO1_GDIR_BASE				(0x0209C004)
#define REGISTER_LENGTH				4


static void	led_release(struct device *dev)
{
	printk("led device released!rn");	
}


static struct resource led_resources[] = {
	[0] = {
		.start 	= CCM_CCGR1_BASE,
		.end 	= (CCM_CCGR1_BASE + REGISTER_LENGTH - 1),
		.flags 	= IORESOURCE_MEM,
	},	
	[1] = {
		.start	= SW_MUX_GPIO1_IO03_BASE,
		.end	= (SW_MUX_GPIO1_IO03_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[2] = {
		.start	= SW_PAD_GPIO1_IO03_BASE,
		.end	= (SW_PAD_GPIO1_IO03_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[3] = {
		.start	= GPIO1_DR_BASE,
		.end	= (GPIO1_DR_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
	[4] = {
		.start	= GPIO1_GDIR_BASE,
		.end	= (GPIO1_GDIR_BASE + REGISTER_LENGTH - 1),
		.flags	= IORESOURCE_MEM,
	},
};



static struct platform_device leddevice = {
	.name = "imx6ul-led",
	.id = -1,
	.dev = {
		.release = &led_release,
	},
	.num_resources = ARRAY_SIZE(led_resources),
	.resource = led_resources,
};
		

static int __init leddevice_init(void)
{
	return platform_device_register(&leddevice);
}


static void __exit leddevice_exit(void)
{
	platform_device_unregister(&leddevice);
}

 module_init(xxxdriver_init);   //指定为驱动的入口函数xxxdriver_init
 module_exit(xxxdriver_exit);   //指定为驱动的出口函数xxxdriver_exit
 MODULE_LICENSE("GPL");         // 指定LICENSE许可为GPL
 MODULE_AUTHOR("zuozhongkai");  // 指定作者信息为zuozhongkai
MISC杂项驱动,即驱动开发方式的杂项框架

当我们板子上的某些外设无法进行分类的时候就可以使用 MISC 驱动。
所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号

杂项设备画像
 struct miscdevice {
 int minor; 
 const char *name; 
 const struct file_operations *fops; 
 struct list_head list;
 struct device *parent;
 struct device *this_device;
 const struct attribute_group **groups;
 const char *nodename;
 umode_t mode;
 };
杂项框架的API函数
int misc_register(要注册的 MISC 设备)  //注册一个 MISC 设备
int misc_deregister(要注销的 MISC 设备) //注销掉 MISC 设备

传统过时的删除设备的过程如下
cdev_del(); 
unregister_chrdev_region(); 
device_destroy(); 
class_destroy(); 
Linux INPUT 子系统框架

input、 pinctrl、 gpio 子系统都是 Linux 内核针对某一类设备而创建的框架

驱动层:输入设备的具体驱动程序,比如按键驱动程序,向内核层报告输入内容。
核心层:承上启下,为驱动层提供输入设备注册和操作接口。通知事件层对输入事件进行处理。
事件层:主要和用户空间进行交互。

input 设备画像
struct input_dev {
 const char *name;
 const char *phys;
 const char *uniq;
 struct input_id id;

 unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];

 unsigned long evbit[BITS_TO_LONGS(EV_CNT)];   
 unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; 
 unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; 
 unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; 
 unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; 
 unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; 
 unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; 
 unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];   
 unsigned long swbit[BITS_TO_LONGS(SW_CNT)];   
  ......
  ......
 bool devres_managed;
 };
input框架的API函数
struct input_dev *input_allocate_device(void)        //申请一个input设备结构体变量
int input_register_device(要注册的input_dev)          //初始化要注册的input设备结构体变量

void input_free_device(需要释放的input_dev)           //注销input设备
void input_unregister_device(struct input_dev *dev)  //注销掉前面注册的input设备结构体变量

//input_event 函数可以上报所有的事件类型和事件值, Linux 内核也提供了其他的针对具体事件的上报函数
void input_event(需要上报的input_dev,上报的事件类型,我们要注册的按键值,事件值)    //上报指定的事件以及对应的值
void input_report_rel(struct input_dev *dev, unsigned int code, int value)
void input_report_abs(struct input_dev *dev, unsigned int code, int value)
void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
void input_report_switch(struct input_dev *dev, unsigned int code, int value)
void input_mt_sync(struct input_dev *dev)

void input_sync(需要上报同步事件的 input_dev)         //告诉 Linux 内核 input 子系统上报结束
input 驱动编写流程=注册input_dev+上报输入事件 注册input_dev
 struct input_dev *inputdev; 


 static int __init xxx_init(void)
 {
 ......
 inputdev = input_allocate_device(); 
 inputdev->name = "test_inputdev"; 

 
 __set_bit(EV_KEY, inputdev->evbit); 
__set_bit(EV_REP, inputdev->evbit); 
__set_bit(KEY_0, inputdev->keybit); 


 
 keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) |
 BIT_MASK(EV_REP);
 keyinputdev.inputdev->keybit[BIT_WORd(KEY_0)] |=
 BIT_MASK(KEY_0);
 

 
 keyinputdev.inputdev->evbit[0] = BIT_MASK(EV_KEY) |
 BIT_MASK(EV_REP);
 input_set_capability(keyinputdev.inputdev, EV_KEY, KEY_0);


 
 input_register_device(inputdev);
 ......
 return 0;
 }

 
 static void __exit xxx_exit(void)
{
 input_unregister_device(inputdev); 
 input_free_device(inputdev); 
 }
上报输入事件

事件上报参考代码:消抖定时器中断函数中将按键值上报给 Linux 内核,即按键抖动时过一段定时执行中断,中断调用上报函数

 
 void timer_function(unsigned long arg)
 {
 unsigned char value;

value = gpio_get_value(keydesc->gpio); 
if(value == 0){ 
 
 input_report_key(inputdev, KEY_0, 1); 
 input_sync(inputdev); 
 } else { 
 input_report_key(inputdev, KEY_0, 0); 
 input_sync(inputdev); 
 }
 }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/831695.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号