本文转自:驱动设备模型之总线设备驱动
为了适用要求越来越高的硬件设备需求,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盘,系统一样能够支持。
本文深入介绍了Linux设备模型的三大核心组成部分:总线、设备和驱动,并通过具体实例展示了它们之间的交互方式。
1703

被折叠的 条评论
为什么被折叠?



