2.the linux device model

Linux中,分别使用bus_type,device_driver,device来描述总线,驱动和设备,在设备模型中,所有的设备都通过总线来连接。即使有些设备没有连接到一根物理总线上,Linux为其设置了一个内部的、虚拟的platform总线,来维持总线、驱动、设备的关系。

<device.h>

总线:

点击(此处)折叠或打开

    struct bus_type {const char* name;//总线名字struct module* owner;struct ksetsubsys;//子系统,连接到一个全局变量kset bus_subsys。这样每一根总线系统都会通过bus_subsys结构连接起来。struct ksetdrivers;//总线驱动struct ksetdevices;//插入总线的所有设备struct bus_attribute* bus_attrs;struct device_attribute* dev_attrs;struct driver_attribute* drv_attrs;int(*match)(struct device * dev, struct device_driver * drv);int(*uevent)(struct device *dev, char **envp,int num_envp, char *buffer, int buffer_size);//参数与kset里的uevent相同。int(*probe)(struct device * dev);int(*remove)(struct device * dev);void(*shutdown)(struct device * dev);….}

总线注册:bus_register(structbus_type*bus);

总线删除:bus_unregister(structbus_type*bus);

总线属性:

点击(此处)折叠或打开

    struct bus_attribute {struct attributeattr;ssize_t (*show)(struct bus_type *, char * buf);ssize_t (*store)(struct bus_type *, const char * buf, size_t count);}

创建和初始化bus_attribute结构:

#defineBUS_ATTR(_name,_mode,_show,_store)

创建总线属性:

intbus_create_file(structbus_type*,structbus_attribute*);

删除属性:

voidbus_remove_file(structbus_type*,structbus_attribute*);

点击(此处)折叠或打开

    Bus.c#include <linux/device.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/string.h>#include <linux/sysfs.h>#include <linux/stat.h>#include <linux/mm.h>static ssize_t show_bus_author(struct bus_type *bus,char *buf) {return snprintf(buf,PAGE_SIZE,”%s\n”,”show_bus_author”);}static int virtual_bus_match(struct device *dev,struct device_driver *drv) {Printk(KERN_DEBUG”\n!!!!!!match!!!!!!\n”); return !strcmp(dev_name(dev),drv->name);}void my_bus_release(struct device *dev) {printk(KERN_DEBUG”my bus release\n”);}struct bus_type virtual_bus={.name=”virtual_bus”,.match=virtual_bus_match,};struct device my_busdev={.init_name=”my_busdev”,.release=my_bus_release,};EXPORT_SYMBOL(virtual_bus);EXPORT_SYMBOL(my_busdev);static BUS_ATTR(c,S_IRUGO,show_bus_author,NULL);static int __init bus_init(void) {int ret;ret=bus_register(&virtual_bus);//register virtual_busif(ret){return ret;}if(bus_create_file(&virtual_bus,&bus_attr_c)) { //创建总线属性文件printk(KERN_NOTICE”unable to create bus attr\n”);}ret =device_register(&my_busdev);if(ret) {printk(KERN_NOTICE”unable to register device\n”);}printk(“bus register success!\n”);return 0;}static void __exit bus_exit(void) {bus_unregister(&virtual_bus);device_unregister(&my_busdev);}module_init(bus_init);module_exit(bus_exit);MODULE_AUTHOR(“MANGO”);MODULE_LICENSE(“Dual BSD/GPL”)

编译后,会在/sys/bus下建立virtual_bus文件夹。

执行catc,得到如下输出:

设备驱动程序:

点击(此处)折叠或打开

    struct device_driver {const char* name;struct bus_type* bus;struct kobjectkobj;struct klistklist_devices;struct klist_nodeknode_bus;struct module* owner;const char * mod_name;/* used for built-in modules */struct module_kobject* mkobj;int(*probe)(struct device * dev);int(*remove)(struct device * dev);void(*shutdown)(struct device * dev);int(*suspend)(struct device * dev, pm_message_t state);int(*resume)(struct device * dev);}

Driver.c

点击(此处)折叠或打开

    #include <linux/device.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/string.h>#include <linux/sysfs.h>#include <linux/stat.h>#include <linux/mm.h>extern struct device my_busdev;extern struct bus_type virtual_bus;extern struct device virtual_device;static ssize_t show_driver_author(struct device_driver *driver,char *buf) {return snprintf(buf,PAGE_SIZE,”%s\n”,”mango”);}int my_driver_remove(struct device *dev) {printk(“my_driver_remove\n”);return 0;}int my_driver_probe(struct device *dev) {printk(“my_driver_probe\n”);return 0;}struct device_driver virtual_driver={.name=”mytest”,.bus=&virtual_bus,.probe=my_driver_probe,.remove=my_driver_remove,};static DRIVER_ATTR(c,S_IRUGO,show_driver_author,NULL);static int __init my_driver_init(void) {int ret;ret=driver_register(&virtual_driver);if(ret)return ret;if(driver_create_file(&virtual_driver,&driver_attr_c))printk(KERN_NOTICE”unable to create author attr\n”);printk(“driver register success\n”);return ret;}static void __exit my_driver_exit(void) {driver_unregister(&virtual_driver);printk(“driver unregister success\n”);}module_init(my_driver_init);module_exit(my_driver_exit);MODULE_AUTHOR(“MANGO”);MODULE_LICENSE(“Dual BSD/GPL”)

编译后driver.ko

设备:

点击(此处)折叠或打开

    struct device {struct klistklist_children;struct klist_nodeknode_parent;/* node in sibling list */struct klist_nodeknode_driver;struct klist_nodeknode_bus;struct device*parent;//设备的父设备,大多数情况下,一个父设备是某种总线的宿主控制器。如果是NULL,则表示该设备是顶层设备。struct kobject kobj;//device->kobj->parent与&device->parent->kobj是相同的。charbus_id[BUS_ID_SIZE];/* position on parent bus */struct device_type*type;……struct bus_type* bus;/* type of bus device is on */struct device_driver *driver;/* which driver has allocated this device */void*driver_data;/* data private to the driver */……void(*release)(struct device * dev);//当指向设备的最后一个引用被删除时,内核调用该方法。}

设备注册:intdevice_register(structdevice*dev);

设备删除:intdevice_unregister(structdevice*dev);

设备属性:

点击(此处)折叠或打开

    struct device_attribute {struct attributeattr;ssize_t (*show)(struct device *dev, struct device_attribute *attr,char *buf);ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);};

宏:#defineDEVICE_ATTR(_name,_mode,_show,_store)

创建设备属性:

intdevice_create_file(structdevice*device,structdevice_attribute*entry);

删除设备属性:

voiddevice_remove_file(structdevice*dev,structdevice_attribute*attr);

设置设备的名字:

dev_set_name(&dev,”name”);

Device.c

点击(此处)折叠或打开

    #include <linux/device.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/string.h>#include <linux/sysfs.h>#include <linux/stat.h>#include <linux/mm.h>extern struct device my_bus;extern struct bus_type virtual_bus;extern struct device virtual_device;static ssize_t show_driver_author(struct device_driver *driver,char *buf) {return snprintf(buf,PAGE_SIZE,”%s\n”,”mango”);}int my_driver_remove(struct device *dev) {printk(“my_driver_remove\n”);return 0;}int my_driver_probe(struct device *dev) {printk(“my_driver_probe\n”);return 0;}struct device_driver virtual_driver={.name=”mytest”,.bus=&virtual_bus,.probe=my_driver_probe,.remove=my_driver_remove,};static char *c=”mango_attr”;static DRIVER_ATTR(c,S_IRUGO,show_driver_author,NULL);static int __init my_driver_init(void) {int ret;ret=driver_register(&virtual_driver);if(ret)return ret;if(driver_create_file(&virtual_driver,&driver_attr_c))printk(KERN_NOTICE”unable to create author attr\n”);printk(“driver register success\n”);return ret;}static void __exit my_driver_exit(void) {driver_unregister(&virtual_driver);printk(“driver unregister success\n”);}module_init(my_driver_init);module_exit(my_driver_exit);MODULE_AUTHOR(“MANGO”);MODULE_LICENSE(“Dual BSD/GPL”)

编译完后生成device.ko,加载后得到如下输出:

该device指定的父设备是my_busdev,则应该对应目录为:/sys/devices/my_busdev/mytest

执行catc,可以看到如下输出:

三个都加载,由于driver和device名字一样,会匹配上,如下图:

此时再看bus下,文件结构如下:

会发现依附于virtual_bus总线的device和driver通过总线match起来,且都建立了相应的连接文件。

device_driver和device分别表示驱动和设备,这两者必须依附于一条总线,因此都包含了structbus_type指针。在Linux内核中,设备和驱动程序是分开注册的。bus_type的match成员函数可以将两者捆绑在一起。

总线、驱动和设备最终会落实为sysfs中的1个目录,总线、设备和驱动中的各个attribute则直接落实为sysfs中的1个文件,attribute会伴随着show和store函数,分别用于读和写该attribute对应的sysfs文件结点。

事实上,udev规则中个信息的来源实际上就是bus_type,device_driver,device以及attribute等所对应的文件节点。

一个设备类描述了一种设备类型,类是一个设备的高层视图,几乎所有的类都显示在/sys/class目录中。一个例外是块设备。出于历史原因,它们出现在/sys/block下。

每个类都需要一个唯一的名字,它将显示在/sys/class中。

注册函数:intclass_register(structclass*cls);

删除函数:voidclass_unregister(structclass*cls);

你写PPT时,阿拉斯加的鳕鱼正跃出水面,

2.the linux device model

相关文章:

你感兴趣的文章:

标签云: