Chinaunix首页 | 论坛 | 博客
  • 博客访问: 352550
  • 博文数量: 41
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 784
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-21 20:58
文章分类

全部博文(41)

文章存档

2017年(1)

2010年(1)

2009年(18)

2008年(21)

分类: LINUX

2009-06-07 19:30:57

在前面一篇linux设备模型深探(1)我们详细了解了底层元素kset,kobject,ktype之间的关系后,本节讲解下驱动模型中另外几个概念(busdriverdevice)为后面具体分析特定驱动(platform,pci)模型打个基础。

 

BUS

在设备模型中,所有的device都是通过总线bus 连接,这里的bus包括通常意义的总线如usbpci,也包括虚拟的platform总线。

[root@wangp bus]# pwd

/sys/bus

[root@wangp bus]# ls

ac97  acpi  bluetooth  gameport  i2c  ide  pci  pci_express  pcmcia  platform  pnp  scsi  serio  usb

[root@wangp platform]# pwd

/sys/bus/platform

[root@wangp platform]# ls

devices  drivers

 

struct bus_type {

       const char              * name;

       struct module         * owner;

 

       struct kset             subsys;

       struct kset             drivers;

       struct kset             devices;

       struct klist              klist_devices;

       struct klist              klist_drivers;

 

       struct blocking_notifier_head bus_notifier;

 

       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, struct kobj_uevent_env *env);

       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 (*suspend_late)(struct device * dev, pm_message_t state);

       int (*resume_early)(struct device * dev);

       int (*resume)(struct device * dev);

 

       unsigned int drivers_autoprobe:1;

};

 

name是总线的名字,每个总线下都有自己的子系统,其中包含2ksetdeviecedriver,分别代表已知总线的驱动和插入总线的设备

platform总线的声明如下:

 

struct bus_type platform_bus_type = {

       .name             = "platform",

       .dev_attrs       = platform_dev_attrs,

       .match            = platform_match,

       .uevent          = platform_uevent,

       .suspend  = platform_suspend,

       .suspend_late  = platform_suspend_late,

       .resume_early  = platform_resume_early,

       .resume          = platform_resume,

};

 

只有很少的bus_type成员需要初始化,大部分交给kernel来处理

 

 

关于总线的操作常用的如下:

int  bus_register(struct bus_type * bus);

void bus_unregister(struct bus_type * bus);

/* iterator helpers for buses */

 

列举总线上从start之后的每个设备,并进行fn操作,通常用途是对bus上的设备和驱动进行绑定

int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*fn)(struct device *, void *));

 

int driver_attach(struct device_driver * drv)

{

       return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

}

 

static int __driver_attach(struct device * dev, void * data)

{

       struct device_driver * drv = data;

 

       /*

        * Lock device and try to bind to it. We drop the error

        * here and always return 0, because we need to keep trying

        * to bind to devices and some drivers will return an error

        * simply if it didn't support the device.

        *

        * driver_probe_device() will spit a warning if there

        * is an error.

        */

 

       if (dev->parent)      /* Needed for USB */

              down(&dev->parent->sem);

       down(&dev->sem);

       if (!dev->driver)

              driver_probe_device(drv, dev);

       up(&dev->sem);

       if (dev->parent)

              up(&dev->parent->sem);

 

       return 0;

}

 

几乎linux设备模型的每一层都提供了添加属性的函数,总线也不例外

struct bus_attribute {

       struct attribute       attr;

       ssize_t (*show)(struct bus_type *, char * buf); //显示属性

       ssize_t (*store)(struct bus_type *, const char * buf, size_t count); //设置属性

};

创建属于一个总线的属性使用(在模块的加载时间完成)

int  bus_create_file(struct bus_type *,struct bus_attribute *);

void bus_remove_file(struct bus_type *, struct bus_attribute *);

 

在说明下bussysfs里面的结构,刚才已经讲过,bus_type中有2kset结构对应于devicedriver,也就是说每个bus下面都会有devicedriver2个文件夹。

 

首先在总线上注册的驱动会得到一个文件夹driver,如platform驱动

[root@wangp platform]# pwd

/sys/bus/platform

[root@wangp platform]# ls

devices  drivers

[root@wangp drivers]# pwd

/sys/bus/platform/drivers

[root@wangp drivers]# ls

i8042  pcspkr  serial8250  vesafb

 

而任何在总线/sys/bus/xxx/上发现的设备会得到一个symlink(符号链接)即/sys/bus/xxx/device指向/sys/device/xxx下面的文件夹

[root@wangp devices]# pwd

/sys/bus/platform/devices

[root@wangp devices]# ls -l

total 0

lrwxrwxrwx 1 root root 0 Jun  6 10:37 bluetooth -> ../../../devices/platform/bluetooth

lrwxrwxrwx 1 root root 0 Jun  6 10:37 floppy.0 -> ../../../devices/platform/floppy.0

lrwxrwxrwx 1 root root 0 Jun  6 10:37 i8042 -> ../../../devices/platform/i8042

lrwxrwxrwx 1 root root 0 Jun  6 10:37 pcspkr -> ../../../devices/platform/pcspkr

lrwxrwxrwx 1 root root 0 Jun  6 10:37 serial8250 -> ../../../devices/platform/serial8250

lrwxrwxrwx 1 root root 0 Jun  6 10:37 vesafb.0 -> ../../../devices/platform/vesafb.0

 

 

DEVICE

struct device {

       struct klist              klist_children;

       struct klist_node     knode_parent;        /* node in sibling list */

       struct klist_node     knode_driver;

       struct klist_node     knode_bus;

       struct device          *parent;  //该设备所属的设备

 

       struct kobject kobj;

       char bus_id[BUS_ID_SIZE];     /* position on parent bus */

       struct device_type  *type;

       unsigned         is_registered:1;

       unsigned         uevent_suppress:1;

 

       struct semaphore    sem; /* semaphore to synchronize calls to

                                    * its driver.

                                    */

 

       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         *platform_data;      /* Platform specific data, device  core doesn't touch it */

       struct dev_pm_info power;

 

#ifdef CONFIG_NUMA

       int           numa_node;    /* NUMA node this device is close to */

#endif

       u64         *dma_mask;    /* dma mask (if dma'able device) */

       u64         coherent_dma_mask;/* Like dma_mask, but for

                                        alloc_coherent mappings as

                                        not all hardware supports

                                        64 bit addresses for consistent

                                        allocations such descriptors. */

 

       struct list_head       dma_pools;      /* dma pools (if dma'ble) */

 

       struct dma_coherent_mem     *dma_mem; /* internal for coherent mem   override */

       /* arch specific additions */

       struct dev_archdata archdata;

 

       spinlock_t        devres_lock;

       struct list_head       devres_head;

 

       /* class_device migration path */

       struct list_head       node;

       struct class             *class;

       dev_t                    devt;              /* dev_t, creates the sysfs "dev" */

       struct attribute_group    **groups;       /* optional groups */

 

       void  (*release)(struct device * dev);

};

这个结构相当于一个基类,对于基于特定总线的设备,会派生出特定的device结构(linux的驱动模型有很多结构都可以基于类来看待)

 

struct platform_device {

       const char       * name;

       int           id;

       struct device   dev;

       u32         num_resources;

       struct resource       * resource;

};

 

一个总线设备用如下函数注册(注册总线类型)

int device_register(struct device *dev)

{

       device_initialize(dev);

       return device_add(dev);

}

以完成parent name bus_id bus几个成员的初始化,注册后可以在/sys/devices下面看到

void device_unregister(struct device *dev);

 

同时和其相关的属性为

struct device_attribute {

       struct attribute       attr;

       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);

};

int device_create_file(struct device *device,struct device_attribute * entry);

device_remove_file(struct device * dev, struct device_attribute * attr);

以下完成一个总线设备的注册:

static void simple_bus_release(struct device *dev)

{

       printk("simple bus release\n");

}

struct device simple_bus = {

       .bus_id ="simple_bus",

       .release = simple_bus_release

}

 

ret = device_register(&simple_bus);

if(ret)

pritnk("unable to register simple_bus\n");

完成注册后,simple_bus就可以再sysfs/sys/devices下面看见,任何挂载这个bus上的device都会在/sys/devices/simple_bus下看到

 

DEVICE_DRIVER

 

struct device_driver {

       const char              * name;//sysfs下显示

       struct bus_type             * bus;

 

       struct kobject         kobj;

       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来派生出自己

特有的驱动,如

struct platform_driver {

       int (*probe)(struct platform_device *);

       int (*remove)(struct platform_device *);

       void (*shutdown)(struct platform_device *);

       int (*suspend)(struct platform_device *, pm_message_t state);

       int (*suspend_late)(struct platform_device *, pm_message_t state);

       int (*resume_early)(struct platform_device *);

       int (*resume)(struct platform_device *);

       struct device_driver driver;

};

比较xxx_driver device_driver我们可以发现,结构体所带的方法基本相同,在具体应该用的时候是可以转换的。

 

驱动的注册

int driver_register(struct device_driver * drv);

void driver_unregister(struct device_driver * drv);

而大多数驱动会调用针对特定总线的诸如platform_driver_register,pci_driver_register之类的函数去注册

 

总线(bus)可以挂接一类设备(device)

驱动(driver)可以驱动一类设备(device

因此和bus一样,device_driver也有一个函数为某个驱动来遍历所有设备

int driver_for_each_dev(struct device_driver *drv, void *data,int (*callback)(struct device *dev,void *data);

所有device_driver完成注册后,会在/sys/bus/xxx/driver目录下看到驱动信息

 

同时相应的属性内容

struct driver_attribute {

       struct attribute       attr;

       ssize_t (*show)(struct device_driver *, char * buf);

       ssize_t (*store)(struct device_driver *, const char * buf, size_t count);

};

int  driver_create_file(struct device_driver *,struct driver_attribute *);

void driver_remove_file(struct device_driver *, struct driver_attribute *);

 

说了这么多,现在来理一理kobject kset,subsys,sysfs,bus之间的关系

 


上图反映了继承体系的一个基本结构,kset是一组相同的kobject的集合,kernel可以通过跟踪kset来跟踪所用的特定类型设备,platformpcii2c等,kset起到连接作用将设备模型和sysfs联系在一起。每个kset自身都包含一个kobject,这个kobject将作为很多其他的kobject的父类,从sys上看,某个kobject的父类是某个目录,那么它就是那个目录的子目录,parent指针可以代表目录层次,这样典型的设备模型层次就建立起来了,从面向对象的观点看,kset是顶层的容器类,kset继承他自己的kobject,并且可以当做kobject来处理

 

如图:kset把它的子类kobject放在链表里面,kset子类链表里面那些kobjectkset指针指向上面的ksetparent指向父类。

 

struct kobject {

       const char              * k_name;

       struct kref              kref;

       struct list_head       entry;

       struct kobject         * parent;

       struct kset             * kset;

       struct kobj_type     * ktype;

       struct sysfs_dirent   * sd;

};

 

struct kset {

       struct kobj_type     *ktype;

       struct list_head       list;

       spinlock_t        list_lock;

       struct kobject         kobj;

       struct kset_uevent_ops  *uevent_ops;

};

 


 

                




有了这些基本单元,就可以派生出许多其他的新类别



了解了驱动模型的构架后,我们就可以分析具体的驱动(platform,pci)。


 

 

 

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