UT4412BV03开发板学习Linux设备驱动模型二.docx
- 文档编号:7757992
- 上传时间:2023-01-26
- 格式:DOCX
- 页数:10
- 大小:103.26KB
UT4412BV03开发板学习Linux设备驱动模型二.docx
《UT4412BV03开发板学习Linux设备驱动模型二.docx》由会员分享,可在线阅读,更多相关《UT4412BV03开发板学习Linux设备驱动模型二.docx(10页珍藏版)》请在冰豆网上搜索。
UT4412BV03开发板学习Linux设备驱动模型二
UT4412BV03开发板学习Linux设备驱动模型
(二)
设备驱动模型有三个重要部分,分别是总线(bus_type),设备(device),驱动(driver)
下面对三个组件分别进行介绍。
1.总线
从硬件上来讲,物理总线有数据总线和地址总线,在设备驱动模型中所有设备都是通过总线相连接的,驱动程序依附在总线上,下面将表示总线,设备,驱动三者之间的关系。
了解了总线的结构之后,下面具体说明总线中用到的一些结构体及相关的函数。
#include
1.总线的数据结构bus_type
structbus_type {
constchar*name;//总线的名字
structbus_attribute*bus_attrs;//总线属性和导出到sysfs中的方法
structdevice_attribute*dev_attrs;//设备属性和导出到sysfs中的方法
structdriver_attribute*drv_attrs;//驱动程序属性和导出到sysfs中的方法
int(*match)(structdevice*dev,structdevice_driver*drv);//匹配函数,检验参数二的驱动是否支持参数一的设备
//当一条总线上新设备或新驱动被添加时,会一次或多次调用该函数,
//如果指定的驱动能适用于指定的设备,那么该函数返回非0,否则返回0
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);//恢复供电状态,是设备正常工作的方法
structdev_pm_ops*pm;//关于电源管理的操作符
structbus_type_private*p;//总线私有数据
};
2.总线属性数据结构
structbus_attribute {
structattributeattr;//总线属性的变量
ssize_t(*show)(structbus_type*bus,char*buf);//属性读函数
ssize_t(*store)(structbus_type*bus,constchar*buf,size_tcount);//属性写函数
};
structattribute{
constchar*name;//属性名字
structmodule*owner;
mode_tmode;//属性读写权限
};
3.初始化bus_attribute结构体用的宏
#defineBUS_ATTR(_name,_mode,_show,_store)\
structbus_attributebus_attr_##_name=__ATTR(_name,_mode,_show,_store)
例:
staticBUS_ATTR(config,0644,ap_config_time_show,ap_config_time_store);
对此宏进行扩展为
structbus_attributebus_attr_config_time={
.attr={.name=config_time,.mode=0644},
.show=ap_config_time_show,
.store=ap_config_time_store,
}
4.创建总线属性的函数
intbus_create_file(structbus_type*bus,structbus_attribute*attr)
{
interror;
if(bus_get(bus)){
error=sysfs_create_file(&bus->p->subsys.kobj,&attr->attr);
bus_put(bus);
}else
error=-EINVAL;
returnerror;
}
5.移除总线属性用到的函数
voidbus_remove_file(structbus_type*bus,structbus_attribute*attr)
{
if(bus_get(bus)){
sysfs_remove_file(&bus->p->subsys.kobj,&attr->attr);
bus_put(bus);
}
}
6.总线上用到的方法
int(*match)(structdevice*dev,structdevice_driver*drv);//匹配函数,检验参数二的驱动是否支持参数一的设备
//当一条总线上新设备或新驱动被添加时,会一次或多次调用该函数,
//如果指定的驱动能适用于指定的设备,那么该函数返回非0,否则返回0
当用户空间产生热插拔事件前,可能需要内核传递一些参数给用户空间,这里只能使用环境变量来传递,
传递环境变量用到的函数int(*uevent)(structdevice*dev,structkobj_uevent_env*env);
该函数只能在内核支持热插拔事件时才有用,否则该函数被定义为NULL。
举例:
staticintamba_uevent(structdevice*dev,structkobj_uevent_env*env)
{
structamba_device*pcdev=to_amba_device(dev);
intretval=0;
//向env中添加环境变量“AMBA_ID”
retval=add_uevent_var(env,"AMBA_ID=%08x",pcdev->periphid);
returnretval;
}
#else
#defineamba_ueventNULL//表示不支持热插拔事件
#endif
7.总线注册函数
intbus_register(structbus_type*bus)
为驱动程序定义一条新总线,调用此函数,这函数可能会调用失败,因此我们一般
要检查其返回值,如果调用成功将在/sys/bus目录下生成总线目录
8.总线注销函数
voidbus_unregister(structbus_type*bus)
{
pr_debug("bus:
'%s':
unregistering\n",bus->name);
bus_remove_attrs(bus);
remove_probe_files(bus);
kset_unregister(bus->p->drivers_kset);
kset_unregister(bus->p->devices_kset);
bus_remove_file(bus,&bus_attr_uevent);
kset_unregister(&bus->p->subsys);
kfree(bus->p);
bus->p=NULL;
}
二.设备
在linux驱动中,每一个设备都由一个device结构体来描述,对于驱动开发者来说,当遇到新设备时,
需要定义一个新的设备结构体,并将device这个结构体包含在新的设备结构体中
1.device结构体
structdevice{
structdevice*parent;
structdevice_private*p;
structkobjectkobj;
constchar *init_name; /*initialnameofthedevice*/
structdevice_type*type;
structsemaphoresem; /*semaphoretosynchronizecallsto *itsdriver*/
structbus_type*bus; /*typeofbusdeviceison*/
structdevice_driver *driver; /*whichdriverhasallocatedthis device
void*driver_data; /*dataprivatetothedriver*/
void*platform_data; /*Platformspecificdata,device coredoesn'ttouchit*/
structdev_pm_infopower;
#ifdefCONFIG_NUMA
intnuma_node; /*NUMAnodethisdeviceiscloseto*/
#endif
u64*dma_mask; /*dmamask(ifdma'abledevice)*/
u64coherent_dma_mask; /*Likedma_mask,butfor alloc_coherentmappingsas notallhardwaresupports
64bitaddressesforconsistentallocationssuchdescriptors.*/
structdevice_dma_parameters*dma_parms;
structlist_headdma_pools; /*dmapools(ifdma'ble)*/
structdma_coherent_mem*dma_mem; /*internalforcoherentmem override*/
structdev_archdataarchdata; /*archspecificadditions*/
dev_tdevt; /*dev_t,createsthesysfs"dev"*/
spinlock_tdevres_lock;
structlist_headdevres_head;
structklist_nodeknode_class;
structclass*class;
structattribute_group**groups; /*optionalgroups*/
void(*release)(structdevice*dev);
};
2.设备注册用到的函数
设备必须要向linux内核注册后才能使用,下面是设备的注册函数
intdevice_register(structdevice*dev)
{
device_initialize(dev);
returndevice_add(dev);
}
3.设备卸载用到的函数
voiddevice_unregister(structdevice*dev)
{
pr_debug("device:
'%s':
%s\n",dev_name(dev),__func__);
device_del(dev);
put_device(dev);
}
4.设备属性结构体
structdevice_attribute{
structattributeattr;//设备属性
ssize_t(*show)(structdevice*dev,structdevice_attribute*attr,
char*buf);//显示属性的方法
ssize_t(*store)(structdevice*dev,structdevice_attribute*attr,
constchar*buf,size_tcount);//设置属性的方法
};
写程序时,可以使用宏DEVICE_ATTR初始化attribute结构体
#defineDEVICE_ATTR(_name,_mode,_show,_store)\
structdevice_attributedev_attr_##_name=__ATTR(_name,_mode,_show,_store)
5.用device_create_file函数在device目录下创建一个属性文件
intdevice_create_file(structdevice*dev,structdevice_attribute*attr)
{
interror=0;
if(dev)
error=sysfs_create_file(&dev->kobj,&attr->attr);
returnerror;
}
6.用device_remove_file函数在device目录下删除一个属性文件
voiddevice_remove_file(structdevice*dev,structdevice_attribute*attr)
{
if(dev)
sysfs_remove_file(&dev->kobj,&attr->attr);
}
三.驱动
在设备驱动模型中,记录了注册到系统中的所有设备,并不是所有设备都能使用,本节重点介绍驱动和设备需要绑定在一起才能使用。
一个设备对应一个驱动,一个驱动可能对应多个设备驱动,设备驱动模型中的探测函数自动探测新设备,并为其分配一个合适的驱动,这样新设备就能够使用了,对于驱动都应该有下面的驱动结构体。
1.设备驱动device_driver结构体
structdevice_driver{
constchar*name;/*设备驱动程序的名字*/
structbus_type*bus;/*指向驱动属于的总线,总线上有很多设备*/
structmodule*owner;/*设备驱动自身的模块*/
constchar*mod_name;/*usedforbuilt-inmodules*//*驱动模块的名字*/
/*探测设备的方法,并检测设备驱动可以控制哪些装备*/
int(*probe)(structdevice*dev);
int(*remove)(structdevice*dev);/*移除设备时调用该方法*/
void(*shutdown)(structdevice*dev);/*设备关闭时调用的方法*/
int(*suspend)(structdevice*dev,pm_message_tstate);/*设备置于低功率状态时所调用的方法*/
int(*resume)(structdevice*dev);/*设备恢复正常状态时所调用的方法*/
structattribute_group**groups;/*属性组*/
structdev_pm_ops*pm;/*用于电源管理*/
structdriver_private*p;/*设备驱动的私有数据*/
};
structdriver_private {
structkobjectkobj;/*内嵌的kobject结构,用来构建设备驱动模型的结构*/
structklistklist_devices;/*该设备支持的所有设备链表*/
structklist_nodeknode_bus;/*该驱动所属总线*/
structmodule_kobject*mkobj;/*驱动的模块*/
structdevice_driver*driver;/*指向驱动本身*/
};
3.驱动的属性结构体
structdriver_attribute{
structattributeattr;
ssize_t(*show)(structdevice_driver*driver,char*buf);
ssize_t(*store)(structdevice_driver*driver,constchar*buf,
size_tcount);
};
4.在驱动所属目录中创建一个属性
intdriver_create_file(structdevice_driver*drv,
structdriver_attribute*attr)
{
interror;
if(drv)
error=sysfs_create_file(&drv->p->kobj,&attr->attr);
else
error=-EINVAL;
returnerror;
}
5.在驱动所属目录中删除一个属性
voiddriver_remove_file(structdevice_driver*drv,
structdriver_attribute*attr)
{
if(drv)
sysfs_remove_file(&drv->p->kobj,&attr->attr);
}
4.驱动程序的注册
此函数是向设备驱动模型中插入一个新的device_driver对象
intdriver_register(structdevice_driver*drv)
{
intret;
structdevice_driver*other;
BUG_ON(!
drv->bus->p);
if((drv->bus->probe&&drv->probe)||
(drv->bus->remove&&drv->remove)||
(drv->bus->shutdown&&drv->shutdown))
printk(KERN_WARNING"Driver'%s'needsupdating-pleaseuse"
"bus_typemethods\n",drv->name);
other=driver_find(drv->name,drv->bus);
if(other){
put_driver(other);
printk(KERN_ERR"Error:
Driver'%s'isalreadyregistered,"
"aborting...\n",drv->name);
return-EEXIST;
}
ret=bus_add_driver(drv);
if(ret)
returnret;
ret=driver_add_groups(drv,drv->groups);
if(ret)
bus_remove_driver(drv);
returnret;
}
4.设备驱动程序的注销
voiddriver_unregister(structdevice_driver*drv)
{
if(!
drv||!
drv->p){
WARN(1,"Unexpecteddriverunregister!
\n");
return;
}
driver_remove_groups(drv,drv->groups);//从组中移除该驱动
bus_remove_driver(drv);//从总线中移除驱动
}
以上内容简单的梳理了一下linux系统中设备驱动模型的相关知识,分析了linux设备驱动模型中设备,总线,驱动三者之间的关系,并将设备驱动模型中的总线,设备,驱动的重要结构体,及函数进行了相关分析,这样将有助于在以后用到设备驱动模型编程时,能够快速的理解和编写设备驱动程序。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- UT4412BV03 开发 学习 Linux 设备 驱动 模型