驱动设备模型之总线设备驱动

本文深入介绍了Linux设备模型的三大核心组成部分:总线、设备和驱动,并通过具体实例展示了它们之间的交互方式。

本文转自:驱动设备模型之总线设备驱动

为了适用要求越来越高的硬件设备需求,linux2.6内核提供了一种全新的内核设备模型。

设备模型三元素:总线、设备、驱动;

第一节:总线

总线是处理器与设备之间的通道,所有的设备通过总线相连;总线由bus_type定义(位于<linux/device.h>)

 1 struct bus_type {
 2     const char        *name;
 3     struct bus_attribute    *bus_attrs;
 4     struct device_attribute    *dev_attrs;
 5     struct driver_attribute    *drv_attrs;
 6 
 7     int (*match)(struct device *dev, struct device_driver *drv);
 8     int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
 9     int (*probe)(struct device *dev);
10     int (*remove)(struct device *dev);
11     void (*shutdown)(struct device *dev);
12 
13     int (*suspend)(struct device *dev, pm_message_t state);
14     int (*resume)(struct device *dev);
15 
16     const struct dev_pm_ops *pm;
17 device
18     struct subsys_private *p;
19 };


bus_type结构体中重要的方法:

match:当一个新设备或驱动被添加到这条总线时,该方法被调用。用来判断制定的驱动程序是否能够处理指定的设备。若可以,返回非零值。

uevent:为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量;

bus_attribute: 总线属性,这个结构体如下:

1 struct bus_attribute {
2     struct attribute    attr;
3     ssize_t (*show)(struct bus_type *bus, char *buf);
4     ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
5 };


总线属性的操作方法:

int bus_create_file(struct bus_type *bus,struct bus_attribute *attr) //创建属性

void bus_remove_file(struct bus_type*bus, struct bus_attribute *attr) //删除属性

总线的常用操作函数:

int bus_register(struct bus_type * bus) //总线的注册

void bus_unregister(struct bus_type *bus) //总线的删除

第二节:设备

linux每个设备又结构体devices来定义(位于linux/device.h),如下:

 1 struct device {
 2     struct device        *parent;
 3 
 4     struct device_private    *p;
 5 
 6     struct kobject kobj;
 7     const char        *init_name; /* initial name of the device */
 8     struct device_type    *type;
 9 
10     struct mutex        mutex;    /* mutex to synchronize calls to
11                      * its driver.
12                      */
13 
14     struct bus_type    *bus;        /* type of bus device is on */
15     struct device_driver *driver;    /* which driver has allocated this
16                        device */
17     void        *platform_data;    /* Platform specific data, device
18                        core doesn't touch it */
19     struct dev_pm_info    power;
20 
21 #ifdef CONFIG_NUMA
22     int        numa_node;    /* NUMA node this device is close to */
23 #endif
24     u64        *dma_mask;    /* dma mask (if dma'able device) */
25     u64        coherent_dma_mask;/* Like dma_mask, but for
26                          alloc_coherent mappings as
27                          not all hardware supports
28                          64 bit addresses for consistent
29                          allocations such descriptors. */
30 
31     struct device_dma_parameters *dma_parms;
32 
33     struct list_head    dma_pools;    /* dma pools (if dma'ble) */
34 
35     struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
36                          override */
37     /* arch specific additions */
38     struct dev_archdata    archdata;
39 #ifdef CONFIG_OF
40     struct device_node    *of_node;
41 #endif
42 
43     dev_t            devt;    /* dev_t, creates the sysfs "dev" */
44 
45     spinlock_t        devres_lock;
46     struct list_head    devres_head;
47 
48     struct klist_node    knode_class;
49     struct class        *class;
50     const struct attribute_group **groups;    /* optional groups */
51 
52     void    (*release)(struct device *dev);
53 };


设备属性由struct device_attribute描述:

1 struct device_attribute {
2     struct attribute    attr;
3     ssize_t (*show)(struct device *dev, struct device_attribute *attr,
4             char *buf);
5     ssize_t (*store)(struct device *dev, struct device_attribute *attr,
6              const char *buf, size_t count);
7 };


设备属性的常用操作方法:

int device_create_file(struct device *device, struct device_attribute * entry) //创建属性

void device_remove_file(struct device * dev, struct device_attribute * attr) //删除属性

设备的常用操作函数:

int device_register(struct device *dev) //注册一个设备;

void device_unregister(struct device *dev) //注销设备

注意:一条总线也是个设备,也必须按设备注册;

第三节:驱动

驱动程序由struct device_driver描述,代码如下:

 1 struct device_driver {
 2     const char        *name;
 3     struct bus_type        *bus;
 4 
 5     struct module        *owner;
 6     const char        *mod_name;    /* used for built-in modules */
 7 
 8     bool suppress_bind_attrs;    /* disables bind/unbind via sysfs */
 9 
10 #if defined(CONFIG_OF)
11     const struct of_device_id    *of_match_table;
12 #endif
13 
14     int (*probe) (struct device *dev);
15     int (*remove) (struct device *dev);
16     void (*shutdown) (struct device *dev);
17     int (*suspend) (struct device *dev, pm_message_t state);
18     int (*resume) (struct device *dev);
19     const struct attribute_group **groups;
20 
21     const struct dev_pm_ops *pm;
22 
23     struct driver_private *p;
24 };


驱动属性使用struct driver_attribute来描述,如下:

1 struct driver_attribute {
2     struct attribute attr;
3     ssize_t (*show)(struct device_driver *driver, char *buf);
4     ssize_t (*store)(struct device_driver *driver, const char *buf,
5              size_t count);
6 };


驱动属性的常用操作方法:

int driver_create_file(struct device_driver * drv,struct driver_attribute * attr) //创建属性

void driver_remove_file(struct device_driver * drv,struct driver_attribute * attr) /删除属性

驱动常用的操作函数:

int driver_register(struct device_driver *drv) //注册驱动

void driver_unregister(struct device_driver *drv) //注销驱动

实例分析:

至此,已经介绍完设备模型的基本结构,下面以一个实例分析三者之间的关系:

bus.c 在sysfs/bus下创建一个总线目录my_bus

1 #include <linux/device.h>
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 #include <linux/init.h>
 5 #include <linux/string.h>
 6 
 7 MODULE_AUTHOR("David Xie");
 8 MODULE_LICENSE("Dual BSD/GPL");
 9 
10 static char *Version = "$Revision: 1.9 $";
11 
12 /*比较设备的bus_id与驱动的名字是否匹配,匹配一致则在insmod驱动 时候调用probe函数*/
13 
14 static int my_match(struct device *dev, struct device_driver *driver)
15 {
16     return !strncmp(dev->bus_id, driver->name, strlen(driver->name));
17 }
18 
19 static void my_bus_release(struct device *dev)
20 {
21     printk(KERN_DEBUG "my bus release\n");
22 }
23 
24 struct bus_type my_bus_type = {
25     .name = "my_bus",
26     .match = my_match,
27 };
28     
29 struct device my_bus = {
30     .bus_id   = "my_bus0",
31     .release  = my_bus_release
32 };
33 
34 
35 /*符号导出
36  * Export a simple attribute.
37  */
38 EXPORT_SYMBOL(my_bus);
39 EXPORT_SYMBOL(my_bus_type);
40 
41 static ssize_t show_bus_version(struct bus_type *bus, char *buf)
42 {
43     return snprintf(buf, PAGE_SIZE, "%s\n", Version);
44 }
45 
46 static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);
47 
48 
49 static int __init my_bus_init(void)
50 {
51     int ret;
52         
53         /*注册总线*/
54     ret = bus_register(&my_bus_type);
55     if (ret)
56         return ret;
57         
58     /*创建属性文件*/    
59     if (bus_create_file(&my_bus_type, &bus_attr_version))
60         printk(KERN_NOTICE "Fail to create version attribute!\n");
61     
62     /*注册总线设备,设备是挂在my_bus总线上的,怎么做的呢?看device.c*/
63     ret = device_register(&my_bus);
64     if (ret)
65         printk(KERN_NOTICE "Fail to register device:my_bus!\n");
66         
67     return ret;
68 }
69 
70 static void my_bus_exit(void)
71 {
72     device_unregister(&my_bus);
73     bus_unregister(&my_bus_type);
74 }
75 
76 module_init(my_bus_init);
77 module_exit(my_bus_exit);


device.c 在sysfs/bus/my_bus/devices目录下创建一个设备my_dev

这里my_dev是一个连接文件,它连接到sysfs/devices/my_bus0/my_dev

 1 #include <linux/device.h>
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 #include <linux/init.h>
 5 #include <linux/string.h>
 6 
 7 MODULE_AUTHOR("David Xie");
 8 MODULE_LICENSE("Dual BSD/GPL");
 9 
10 extern struct device my_bus; 
11 extern struct bus_type my_bus_type;
12 
13 /* Why need this ?*/
14 static void my_dev_release(struct device *dev)
15 { 
16     
17 }
18 
19 struct device my_dev = {
20     .bus = &my_bus_type,
21     .parent = &my_bus,
22     .release = my_dev_release,
23 };
24 
25 /*
26  * Export a simple attribute.
27  */
28 static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf)
29 {
30     return sprintf(buf, "%s\n", "This is my device!");
31 }
32 
33 static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);
34 
35 static int __init my_device_init(void)
36 {
37     int ret = 0;
38         
39         /* 初始化设备 */
40     strncpy(my_dev.bus_id, "my_dev", BUS_ID_SIZE);
41         
42         /*注册设备*/
43     device_register(&my_dev);
44         
45     /*创建属性文件*/
46     device_create_file(&my_dev, &dev_attr_dev);
47     
48     return ret;    
49 
50 }
51 
52 static void my_device_exit(void)
53 {
54     device_unregister(&my_dev);
55 }
56 
57 module_init(my_device_init);
58 module_exit(my_device_exit);

driver.c当加载驱动时候,会在总线上找到它能够处理的设备

 1 #include <linux/device.h>
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 #include <linux/init.h>
 5 #include <linux/string.h>
 6 
 7 MODULE_AUTHOR("David Xie");
 8 MODULE_LICENSE("Dual BSD/GPL");
 9 
10 extern struct bus_type my_bus_type;
11 
12 static int my_probe(struct device *dev)
13 {
14     printk("Driver found device which my driver can handle!\n");
15     return 0;
16 }
17 
18 static int my_remove(struct device *dev)
19 {
20     printk("Driver found device unpluged!\n");
21     return 0;
22 }
23 
24 struct device_driver my_driver = {
25     .name = "my_dev",
26     .bus = &my_bus_type, /*指明这个驱动程序是属于my_bus_type这条总线上的设备*/
27     .probe = my_probe,  /*在my_bus_type总线上找到它能够处理的设备,就调用my_probe;删除设备调用my_remove*/
28   .remove    = my_remove,  
29   /*能够处理的设备? 
30      1、什么时候驱动程序从总线找能够处理的设备;答:驱动注册时候
31   2、凭什么说能够处理呢?(或者说标准是什么);答:驱动与设备都是属于总线上的,利用总线的结构bus_type中match函数
32   */
33 };
34 
35 /*
36  * Export a simple attribute.
37  */
38 static ssize_t mydriver_show(struct device_driver *driver, char *buf)
39 {
40     return sprintf(buf, "%s\n", "This is my driver!");
41 }
42 
43 static DRIVER_ATTR(drv, S_IRUGO, mydriver_show, NULL);
44 
45 static int __init my_driver_init(void)
46 {
47     int ret = 0;
48         
49   /*注册驱动*/
50     driver_register(&my_driver);
51         
52     /*创建属性文件*/
53     driver_create_file(&my_driver, &driver_attr_drv);
54     
55     return ret;    
56 
57 }
58 
59 static void my_driver_exit(void)
60 {
61     driver_unregister(&my_driver);
62 }
63 
64 module_init(my_driver_init);
65 module_exit(my_driver_exit);


注意:无论是先加载驱动还是设备,都会调用probe这个函数。好比先插u盘,在启动系统 与启动系统后再插u盘,系统一样能够支持。

内容概要:本文档介绍了基于3D FDTD(时域有限差分)方法在MATLAB平台上对微带线馈电的矩形天线进行仿真分析的技术方案,重点在于模拟超MATLAB基于3D FDTD的微带线馈矩形天线分析[用于模拟超宽带脉冲通过线馈矩形天线的传播,以计算微带结构的回波损耗参数]宽带脉冲信号通过天线结构的传播过程,并计算微带结构的回波损耗参数(S11),以评估天线的匹配性能和辐射特性。该方法通过建立三维电磁场模型,精确求解麦克斯韦方程组,适用于高频电磁仿真,能够有效分析天线在宽频带内的响应特性。文档还提及该资源属于一个涵盖多个科研方向的综合性MATLAB仿真资源包,涉及通信、信号处理、电力系统、机器学习等多个领域。; 适合人群:具备电磁场与微波技术基础知识,熟悉MATLAB编程及数值仿真的高校研究生、科研人员及通信工程领域技术人员。; 使用场景及目标:① 掌握3D FDTD方法在天线仿真中的具体实现流程;② 分析微带天线的回波损耗特性,优化天线设计参数以提升宽带匹配性能;③ 学习复杂电磁问题的数值建模与仿真技巧,拓展在射频与无线通信领域的研究能力。; 阅读建议:建议读者结合电磁理论基础,仔细理解FDTD算法的离散化过程和边界条件设置,运行并调试提供的MATLAB代码,通过调整天线几何尺寸和材料参数观察回波损耗曲线的变化,从而深入掌握仿真原理与工程应用方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值