免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1004 | 回复: 0
打印 上一主题 下一主题

linux设备模型深探(2) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-06-07 19:30 |只看该作者 |倒序浏览

                               
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}

  Normal
  0
  
  7.8 磅
  0
  2
  
  false
  false
  false
  
   
   
   
   
   
   
   
   
   
   
   
   
  
  MicrosoftInternetExplorer4



/* Style Definitions */
table.MsoNormalTable
        {mso-style-name:普通表格;
        mso-tstyle-rowband-size:0;
        mso-tstyle-colband-size:0;
        mso-style-noshow:yes;
        mso-style-parent:"";
        mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
        mso-para-margin:0cm;
        mso-para-margin-bottom:.0001pt;
        mso-pagination:widow-orphan;
        font-size:10.0pt;
        font-family:"Times New Roman";
        mso-fareast-font-family:"Times New Roman";
        mso-ansi-language:#0400;
        mso-fareast-language:#0400;
        mso-bidi-language:#0400;}
在前面一篇
linux设备模型深探(1)
我们详细了解了底层元素kset,kobject,ktype之间的关系后,本节讲解下驱动模型中另外几个概念(bus、driver、device)为后面具体分析特定驱动(platform,pci)模型打个基础。

BUS
在设备模型中,所有的device都是通过总线bus 连接,这里的bus包括通常意义的总线如usb,pci,也包括虚拟的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是总线的名字,每个总线下都有自己的子系统,其中包含2个kset,deviece和driver,分别代表已知总线的驱动和插入总线的设备
如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 *);

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

首先在总线上注册的驱动会得到一个文件夹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来跟踪所用的特定类型设备,platform、pci、i2c等,kset起到连接作用将设备模型和sysfs联系在一起。每个kset自身都包含一个kobject,这个kobject将作为很多其他的kobject的父类,从sys上看,某个kobject的父类是某个目录,那么它就是那个目录的子目录,parent指针可以代表目录层次,这样典型的设备模型层次就建立起来了,从面向对象的观点看,kset是顶层的容器类,kset继承他自己的kobject,并且可以当做kobject来处理


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

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



               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/72003/showart_1958091.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP