Linux设备模型.docx

上传人:b****1 文档编号:1071154 上传时间:2023-04-30 格式:DOCX 页数:16 大小:21.21KB
下载 相关 举报
Linux设备模型.docx_第1页
第1页 / 共16页
Linux设备模型.docx_第2页
第2页 / 共16页
Linux设备模型.docx_第3页
第3页 / 共16页
Linux设备模型.docx_第4页
第4页 / 共16页
Linux设备模型.docx_第5页
第5页 / 共16页
Linux设备模型.docx_第6页
第6页 / 共16页
Linux设备模型.docx_第7页
第7页 / 共16页
Linux设备模型.docx_第8页
第8页 / 共16页
Linux设备模型.docx_第9页
第9页 / 共16页
Linux设备模型.docx_第10页
第10页 / 共16页
Linux设备模型.docx_第11页
第11页 / 共16页
Linux设备模型.docx_第12页
第12页 / 共16页
Linux设备模型.docx_第13页
第13页 / 共16页
Linux设备模型.docx_第14页
第14页 / 共16页
Linux设备模型.docx_第15页
第15页 / 共16页
Linux设备模型.docx_第16页
第16页 / 共16页
亲,该文档总共16页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Linux设备模型.docx

《Linux设备模型.docx》由会员分享,可在线阅读,更多相关《Linux设备模型.docx(16页珍藏版)》请在冰点文库上搜索。

Linux设备模型.docx

Linux设备模型

Linux的sysfs文件系统一般mount在/sys目录。

本文主要介绍sysfs文件系统中设备驱动模型的建立过程,内核版本2.6.29。

设备驱动信息主要用来表示设备以及驱动的层次关系,以及处理热插拔等。

/sys中与之相关的数据有:

class代表一类设备,比如mtd、net、tty等等

bus总线,比如PCI、USB、I2C等

device代表一个设备

driver代表一个驱动

 

以下是一些sysfs中的全局变量:

///sys/class

structkset*class_kset=kset_create_and_add("class",NULL,NULL);

///sys/bus

structkset*bus_kset=kset_create_and_add("bus",&bus_uevent_ops,NULL);

///sys/devices

structkset*devices_kset=kset_create_and_add("devices",&device_uevent_ops,NULL);

 

1.    Class

1.1          class的基本结构

structclass{

constchar*name;

structmodule*owner;

structclass_attribute*class_attrs;

structdevice_attribute*dev_attrs;

structkobject*dev_kobj;

int(*dev_uevent)(structdevice*dev,structkobj_uevent_env*env);

void(*class_release)(structclass*class);

void(*dev_release)(structdevice*dev);

int(*suspend)(structdevice*dev,pm_message_tstate);

int(*resume)(structdevice*dev);

structpm_ops*pm;

structclass_private*p;

};

structclass_private{

structksetclass_subsys;

structlist_headclass_devices;

structlist_headclass_interfaces;

structksetclass_dirs;

structmutexclass_mutex;

structclass*class;

};

class在sysfs中的层次由structclass_private决定。

structclass只是class_private的封装。

structclass_private:

:

class_subsys.kobj.kset=class_kset;//父目录为/sys/class

structclass_private:

:

class_subsys.kobj->name代表这个class在/sys/class中显示的名字

structclass:

:

dev_attrs为设备属性,往class中添加设备的时候,这些属性会自动添加到设备目录下。

1.2          新建class

新建class有两种方法:

静态创建和动态创建。

●        静态创建

staticstructclassi2c_adapter_class={

.owner=THIS_MODULE,

.name="i2c-adapter",

.dev_attrs=i2c_adapter_attrs,

.class_attrs=...

};

intretval=class_register(&i2c_adapter_class);

 

●        动态创建

i2c_dev_class=class_create(THIS_MODULE,"i2c-dev");

class_create分配申请一块空间给class,然后对name、owner和class_release函数赋值,并最终调用class_register。

class_register

根据structclass的值,设置structclass_private

调用add_class_attrs在class中添加属性。

●        classattrs

class的属性最终是在/sys/class//目录下以文件的形式存在。

用户程序可以直接对这些属性进行读写。

如果要静态创建属性,可以在定义class时对.class_attrs域赋值,使其指向要添加的attr数组。

如果要动态创建。

可以通过函数class_create_file添加。

intclass_create_file(structclass*cls,conststructclass_attribute*attr);

 

如果是动态创建的属性,需要在模块卸载时调用class_remove_file释放。

如果是静态创建的属性,在调用class_unregister时会自动释放。

2.    Bus

2.1bus的基本结构

structbus_type{

constchar*name;

structbus_attribute*bus_attrs;

structdevice_attribute*dev_attrs;

structdriver_attribute*drv_attrs;

int(*match)(structdevice*dev,structdevice_driver*drv);

int(*uevent)(structdevice*dev,structkobj_uevent_env*env);

int(*probe)(structdevice*dev);

int(*remove)(structdevice*dev);

void(*shutdown)(structdevice*dev);

int(*suspend)(structdevice*dev,pm_message_tstate);

int(*suspend_late)(structdevice*dev,pm_message_tstate);

int(*resume_early)(structdevice*dev);

int(*resume)(structdevice*dev);

structpm_ext_ops*pm;

structbus_type_private*p;

};

structbus_type_private{

structksetsubsys;

structkset*drivers_kset;

structkset*devices_kset;

structklistklist_devices;

structklistklist_drivers;

structblocking_notifier_headbus_notifier;

unsignedintdrivers_autoprobe:

1;

structbus_type*bus;

};

与class类似,bus在sysfs中的显示由structbus_type_private决定,structbus_type只是一个封装。

structbus_type_private:

:

subsys.kobj代表/sys/bus/目录。

structbus_type_private:

:

subsys.kobj.kset=bus_kset;//默认父目录为/sys/bus/

structbus_type_private:

:

subsys.kobj.ktype=&bus_ktype;//bus的属性操作

structbus_type_private:

:

subsys.kobj.name=;

在/sys/bus/目录,每创建成功一个,都会自动创建两个子目录drivers和devices,分别代表连到此的设备和驱动。

在drivers和devices子目录下,每新建一个driver,会把structbus_type中的drv_attrs属性赋给那个driver;每创建一个device,会把structbus_type中dev_attrs赋给那个device。

2.2新建bus

structbus_typei2c_bus_type={

.name="i2c",

.dev_attrs=i2c_dev_attrs,

.match=i2c_device_match,

.uevent=i2c_device_uevent,

.probe=i2c_device_probe,

.remove=i2c_device_remove,

.shutdown=i2c_device_shutdown,

.suspend=i2c_device_suspend,

.resume=i2c_device_resume,

.bus_attr=…

};

intret=bus_register(&i2c_bus_type);

 

intbus_register(structbus_type*bus);

分配内存给structbus_type_private;

根据structbus_type的域设置bus_type_private;

根据.bus_attr设置bus的属性,这些属性在bus_unregister时会被自动释放。

(bus属性也可通过bus_create_file动态添加,但所有动态添加的属性都要在卸载时通过bus_remove_file释放。

 

3.Device

3.1Device的基本结构

structdevice{

structklistklist_children;

structklist_nodeknode_parent;/*nodeinsiblinglist*/

structklist_nodeknode_driver;

structklist_nodeknode_bus;

structdevice*parent;

structkobjectkobj;

charbus_id[BUS_ID_SIZE];/*positiononparentbus*/

constchar*init_name;/*initialnameofthedevice*/

structdevice_type*type;

unsigneduevent_suppress:

1;

structsemaphoresem;/*semaphoretosynchronizecallstoitsdriver.*/

structbus_type*bus;/*typeofbusdeviceison*/

structdevice_driver*driver;/*whichdriverhasallocatedthisdevice*/

void*driver_data;/*dataprivatetothedriver*/

void*platform_data;/*Platformspecificdata,devicecoredoesn'ttouchit*/

structdev_pm_infopower;

u64*dma_mask;/*dmamask(ifdma'abledevice)*/

u64coherent_dma_mask;/*Likedma_mask,butforalloc_coherentmappingsasnotallhardwaresupports64bitaddressesforconsistentallocationssuchdescriptors.*/

structdevice_dma_parameters*dma_parms;

structlist_headdma_pools;/*dmapools(ifdma'ble)*/

structdma_coherent_mem*dma_mem;/*internalforcoherentmem

override*/

/*archspecificadditions*/

structdev_archdataarchdata;

spinlock_tdevres_lock;

structlist_headdevres_head;

structlist_headnode;

structclass*class;

dev_tdevt;/*dev_t,createsthesysfs"dev"*/

structattribute_group**groups;/*optionalgroups*/

void(*release)(structdevice*dev);

};

3.2device_register

intdevice_register(structdevice*dev) ;

此函数将device登记到sysfs中。

在调用之前,需对structdevice进行初始化。

structdevicedev ;

dev.parent= ;//父设备

dev.release= ;//登记释放dev时调用的回调函数

dev.class= ;//structclass

dev.bus= ;//所属总线

然后调用device_register(&dev) ;

intdevice_register(structdevice*dev)

{

device_initialize(dev);

returndevice_add(dev);

}

device_initialize

做一些初始化工作,dev->kobj.kset=devices_kset ;//代表/sys/device目录

device_add

//设置dev->kobj.parent,即确定这个dev的父目录,详情见下节

setup_parent(dev,dev->parent);

//将dev挂到dev->kobj.parent代表的目录,如果没有parent,父目录默认被设置成dev->kobj.kset代表的目录

kobject_add(&dev->kobj,dev->kobj.parent,"%s",dev->bus_id);

device_create_file(dev,&uevent_attr);//给设备添加uevent属性

if(MAJOR(dev->devt))

device_create_file(dev,&devt_attr);//给设备添加dev属性(打印主从设备号)

device_create_sys_dev_entry(dev);//在设备的class下创建设备链接,比如/sys/char和/sys/block,链接名字为major:

minor;如果设备没有class,默认为/sys/char目录

device_add_class_symlinks(dev);

//在设备目录下建立subsystem链接,指向其所属的class

sysfs_create_link(&dev->kobj,&dev->class->p->class_subsys.kobj,"subsystem");

//在设备所属class目录下建立指向设备的链接,以设备名命名

sysfs_create_link(&dev->class->p->class_subsys.kobj,&dev->kobj,dev->bus_id);

//如果父设备存在,在设备目录下建立指向父设备的链接,以device命名

sysfs_create_link(&dev->kobj,&dev->parent->kobj,"device");

device_add_attrs(dev);

//如果有class,把class中dev_attrs属性都加上

device_add_attributes(dev,class->dev_attrs);

//如果有type,把type中dev_attrs属性都加上

device_add_groups(dev,type->groups);

//把device中groups指向的属性都加上

device_add_groups(dev,dev->groups);

bus_add_device(dev);//在设备有bus时有效

//如果有bus,将bus中dev_attrs都加上

device_add_attrs(bus_get(dev->bus),dev);

//在bus中建立指向设备的链接,以设备名命名

sysfs_create_link(&bus->p->devices_kset->kobj,&dev->kobj,dev->bus_id);

//在设备中建立指向总线的链接,以”subsystem”命名

sysfs_create_link(&dev->kobj,&dev->bus->p->subsys.kobj,"subsystem");

dpm_sysfs_add(dev);//建立power属性

device_pm_add(dev);

kobject_uevent(&dev->kobj,KOBJ_ADD);

bus_attach_device(dev);

/*如果总线支持自动检测设备(drivers_autoprobe==1;默认都支持),调用device_attach(dev);device_attach中,如果发现dev已经有driver与之关联,作一些sysfs的操作;如果没有,对总线中每一个驱动调用__device_attach。

__device_attachdriver_probe_device

driver_probe_device先调用bus的match函数,如果返回的是match,再调用really_probe。

(bus的match函数在这里调用)

really_probe先看bus有没有probe函数,如果有,调用bus的probe。

如果没有,调用driver的probe函数(这里就是我们驱动程序的probe函数被调用的地方)。

*/

if(bus->p->drivers_autoprobe)

ret=device_attach(dev);

klist_add_tail(&dev->knode_parent,&parent->klist_children);

list_add_tail(&dev->node,&dev->class->p->class_devices);

list_for_each_entry(class_intf,&dev->class->p->class_interfaces,node)

if(class_intf->add_dev)

class_intf->add_dev(dev,class_intf);

 

3.3device的四种类型

在sysfs的设备模型中,有四种设备类型:

物理设备有parent设备,没有class

直接虚拟设备有parent设备和class,parent没有class

间接虚拟设备有parent设备和class,parent有class

纯虚拟设备没有parent,有class(网络环回设备等)

 

以挂在PCI总线上的I2C适配器为例,首先需要创建一个设备,使其bus域指向PCIbus,这是一个物理设备;然后,以这个物理设备为父设备,创建一个class为I2C_adapter_class的子设备,这个设备是直接虚拟设备,描述I2Cadapter的功能。

I2C子系统对每一个I2Cadapter,又进一步创建了一个字符设备,I2Cdev,这个字符设备的class被设置为I2C_device_class,这里I2Cdev就是一个间接虚拟设备。

除非是纯虚设备,否则任何一个虚拟设备向父设备追溯,一定能找到一个物理设备。

 

structdevice中有两个域,bus和class,这两个域不能同时有值。

如果bus域非空,说明这个structdevice是挂在某个总线上,那么它必须是一个物理设备,class域必须是NULL;如果class域非空,说明这是一个属于某个类的虚拟设备,那么它的bus域就必须是NULL。

所以,在上节提到的两个函数,device_add_class_symlinks(dev)与bus_add_device(dev)中,虽然都创建了subsystem链接,但它们只有一个会起作用,否则系统会崩溃。

 

setup_parent函数

voidsetup_parent(structdevice*dev,structdevice*parent) ;

这个函数用来决定dev被加到sysfs的哪个目录下。

代码逻辑为:

kobj=get_device_parent(dev,parent);

if(kobj)

dev->kobj.parent=kobj;

 

staticstructkobject*get_device_parent(structdevice*dev,structdevice*parent) ;

这个函数会按照设备类型决定设备的父目录 :

●        如果是物理设备且有父设备(dev->class==NULL&&dev->parent)

父目录就是父设备代表的目录

●        如果是直接虚拟设备(dev->class&&dev->parent&&dev->parent->class!

=NULL)

在父设备代表的目录下新建一个子目录,名字为dev->class->name。

然后把这个新建的目

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2