Chinaunix首页 | 论坛 | 博客
  • 博客访问: 304379
  • 博文数量: 78
  • 博客积分: 3635
  • 博客等级: 中校
  • 技术积分: 1115
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-28 09:35
文章分类

全部博文(78)

文章存档

2011年(13)

2010年(65)

我的朋友

分类: LINUX

2010-10-28 16:00:55

 文章来自:%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中已被删除,这里不再研究。

阅读(1140) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

chinaunix网友2010-10-29 14:59:52

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com