文章来自:%C0%EE%C7I/blog/item/80426edf51a0f468d0164e9d.html
sculld 驱动添加一个自己的属性到它的设备入口,称为 dev, 仅包含关联的设备号,源码如下:
de>static ssize_t sculld_show_dev(struct device *ddev,de>de>struct device_attribute *attr,de>de> char *buf) { struct sculld_dev *dev = ddev->driver_data; return print_dev_t(buf, dev->cdev.dev); }
static DEVICE_ATTR(dev, S_IRUGO, sculld_show_dev, NULL);
/*接着, 在初始化时间, 设备被注册, 并且 dev 属性通过下面的函数被创建:*/ static void sculld_register_dev(struct sculld_dev *dev, int index) { sprintf(dev->devname, "sculld%d", index); dev->ldev.name = dev->devname; dev->ldev.driver = &sculld_driver; dev->ldev.dev.driver_data = dev; register_ldd_device(&dev->ldev); if (device_create_file(&dev->ldev.dev, &dev_attr_dev)) printk( "Unable to create dev attribute ! \n"); } /*注意:程序使用 driver_data 成员来存储指向我们自己的内部的设备结构的指针。请检查de>de>device_create_filede>de>的返回值,否则编译时会有警告。*/de> |
设备驱动程序
设备模型跟踪所有系统已知的驱动,主要目的是使驱动程序核心能协调驱动和新设备之间的关系。一旦驱动在系统中是已知的对象就可能完成大量的工作。驱动程序的结构体 device_driver 定义如下:
de>/*定义在*/ struct device_driver { const char * name;/*驱动程序的名字( 在 sysfs 中出现 )*/ struct bus_type * bus;/*驱动程序所操作的总线类型*/
struct kobject kobj;/*内嵌的kobject对象*/ struct klist klist_devices;/*当前驱动程序能操作的设备链表*/ struct klist_node knode_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); };
/*注册device_driver 结构的函数是:*/ int driver_register(struct device_driver *drv); void driver_unregister(struct device_driver *drv);
/*driver的属性结构在:*/ struct driver_attribute { struct attribute attr; ssize_t (*show)(struct device_driver *drv, char *buf); ssize_t (*store)(struct device_driver *drv, const char *buf, size_t count); }; DRIVER_ATTR(_name,_mode,_show,_store)
/*属性文件创建的方法:*/ int driver_create_file(struct device_driver * drv, struct driver_attribute * attr); void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr);
/*bus_type 结构含有一个成员( drv_attrs ) 指向一组为属于该总线的所有设备创建的默认属性*/de> |
在更新的内核里,这个结构体变得更简洁了,隐藏了无需驱动编程人员知道的一些成员:
/*in Linux 2.6.26.5*/
de>struct device_driver { const char *name; struct bus_type *bus;
struct module *owner; const char *mod_name; /* used for built-in modules */
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); struct attribute_group **groups;
struct driver_private *p; };
struct driver_private { struct kobject kobj; struct klist klist_devices; struct klist_node knode_bus; struct module_kobject *mkobj; struct device_driver *driver; }; #define to_driver(obj) container_of(obj, struct driver_private, kobj)de> |
驱动程序结构的嵌入
对大多数驱动程序核心结构, device_driver 结构通常被嵌入到一个更高层的、总线相关的结构中。
以lddbus 子系统为例,它定义了ldd_driver 结构:
de>struct ldd_driver { char *version; struct module *module; struct device_driver driver; struct driver_attribute version_attr; }; #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver); de> |
lddbus总线中相关的驱动注册和注销函数是:
de>/* * Crude driver interface. */ static ssize_t show_version(struct device_driver *driver, char *buf) { struct ldd_driver *ldriver = to_ldd_driver(driver); sprintf(buf, "%s\n", ldriver->version); return strlen(buf); }
int register_ldd_driver(struct ldd_driver *driver) { int ret; driver->driver.bus = &ldd_bus_type; ret = driver_register(&driver->driver);/*注册底层的 device_driver 结构到核心*/ if (ret) return ret; driver->version_attr.attr.name = "version";/* driver_attribute 结构必须手工填充*/ driver->version_attr.attr.owner = driver->module;/* 注意:设定 version 属性的拥有者为驱动模块, 不是 lddbus 模块!因为 show_version 函数是使用驱动模块所创建的 ldd_driver 结构,若 ldd_driver 结构在一个用户空间进程试图读取版本号时已经注销,就会出错*/ driver->version_attr.attr.mode = S_IRUGO; driver->version_attr.show = show_version; driver->version_attr.store = NULL; return driver_create_file(&driver->driver, &driver->version_attr);/*建立版本属性,因为这个属性在运行时被创建,所以不能使用 DRIVER_ATTR 宏*/ }
void unregister_ldd_driver(struct ldd_driver *driver) { driver_unregister(&driver->driver); } EXPORT_SYMBOL(register_ldd_driver); EXPORT_SYMBOL(unregister_ldd_driver);de> |
在sculld 中创建的 ldd_driver 结构如下:
de>/* Device model stuff */ static struct ldd_driver sculld_driver = { .version = "$Revision: 1.21 $", .module = THIS_MODULE, .driver = { .name = "sculld", }, };/*只要一个简单的 register_ldd_driver 调用就可添加它到系统中。一旦完成初始化, 驱动信息可在 sysfs 中显示*/de> |
类 子系统
类是一个设备的高层视图, 它抽象出了底层的实现细节,从而允许用户空间使用设备所提供的功能, 而不用关心设备是如何连接和工作的。类成员通常由上层代码所控制, 而无需驱动的明确支持。但有些情况下驱动也需要直接处理类。
几乎所有的类都显示在 /sys/class 目录中。出于历史的原因,有一个例外:块设备显示在 /sys/block目录中。在许多情况, 类子系统是向用户空间导出信息的最好方法。当类子系统创建一个类时, 它将完全拥有这个类,根本不用担心哪个模块拥有那些属性,而且信息的表示也比较友好。
为了管理类,驱动程序核心导出了一些接口,其目的之一是提供包含设备号的属性以便自动创建设备节点,所以udev的使用离不开类。 类函数和结构与设备模型的其他部分遵循相同的模式,所以真正崭新的概念是很少的。
注意:class_simple 是老接口,在2.6.13中已被删除,这里不再研究。
阅读(1168) | 评论(1) | 转发(1) |