IMX257 总线设备驱动模型编程之总线篇

发布时间:2024-08-15  

从现在开始,我们开始来实现 总线-设备-驱动模型中的总线。、

我们这个程序的目标是在 sysfs文件系统的/sys/bus/ 目录下面建立一个文件夹。

一、总线介绍

1. 总线数据结构bus_type

struct bus_type 结构体的定义如下:

struct bus_type {

const char *name; --总线名

struct bus_attribute *bus_attrs; --总线属性

struct device_attribute *dev_attrs; --总线设备属性

struct driver_attribute *drv_attrs; --总线驱动属性

以下的函数会在设备注册或驱动注册的时候调用。

 

int (*match)(struct device *dev, struct device_driver *drv);

--实现设备与驱动的匹配。不同的总线实现匹配的方法不同,如platform总线采用name匹配,而usb_bus采用id匹配

 

int (*uevent)(struct device *dev, struct kobj_uevent_env *env);

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

--在2.6的内核中实现一个设备与驱动的探测。主要是因为热插拔的设备的增多。

 

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

 

struct dev_pm_ops *pm; --电源管理

struct bus_type_private *p; --bus_type私有成员,

这个结构体中主要包括了kset以及klist,用于管理其挂载其总线下的设备和驱动

};

 

下面我们来看看bus_type_private结构体

struct bus_type_private {

struct kset subsys; /*代表该bus子系统,里面的kobj是该bus的主kobj,最顶层*/

struct kset *drivers_kset; /* 挂接到该总线上所有的驱动的集合 */

struct kset *devices_kset; /* 挂接到该总线上所有的设备的集合 */

struct klist klist_devices; /* 总线上所有设备的的列表 */

struct klist klist_drivers; /* 总线上所有驱动的的列表 */

struct blocking_notifier_head bus_notifier;

unsigned int drivers_autoprobe:1; /*设置是否在注册驱动时,自动探测(probe)设备*/

struct bus_type *bus; /*回指包含自己的总线*/

};

 

 

2. 注册总线

内核中采用bus_register来注册一个新的总线。

其使用如:ret = bus_register(&my_bus_type);

bus_register函数的源码如下(剔除一些错误处理):

int bus_register(struct bus_type *bus)

{

int retval;

struct bus_type_private *priv;

priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);

priv->bus = bus;

bus->p = priv;

BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);

retval = kobject_set_name(&priv->subsys.kobj, '%s', bus->name);

//设置kobject名称,有时会使用snprintf来设置,不过会出现bug,最好使用该函数。

 

priv->subsys.kobj.kset = bus_kset; //kobj中的kset指向父kset

priv->subsys.kobj.ktype = &bus_ktype; //kobj中的ktype指向父ktype

priv->drivers_autoprobe = 1; //设置总线下的设备和驱动自动探测

retval = kset_register(&priv->subsys);

//注册kset,关于kset,kobject,以及ktype的关系以后在学习

 

retval = bus_create_file(bus, &bus_attr_uevent); //创建bus的文件属性

priv->devices_kset = kset_create_and_add('devices', NULL,&priv->subsys.kobj);

//在父kset下创建和加入名为devices和drivers的kset

 

priv->drivers_kset = kset_create_and_add('drivers', NULL,&priv->subsys.kobj);

klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);

//初始化klist,这个函数主要是实现一些赋值及初始化的功能

 

klist_init(&priv->klist_drivers, NULL, NULL);

retval = add_probe_files(bus);

//主要是创建该bus下probe的属性文件,可以通过cat file 和cat x > file 向属性文件读出和写入数据。

 

retval = bus_add_attrs(bus); --添加bus自带的属性文件

return 0;

}

 

从上面的程序得知,总线注册主要工作如下

创建bus_type_ private,并申请相应的内存,通过赋值bus_type的一些属性,然后添加进入list

下面函数其实是实现一个从链表的节点,查询到该节点所属的设备,并且减少dev的计数。

static void klist_devices_get(struct klist_node *n)

{

struct device *dev = container_of(n, struct device, knode_bus);

get_device(dev);

}

 

其实bus的注册比较简单,说到底还是kset和kobject控制着这一切,抛开kset和kobject的具体实现,bus还是很好理解的。

 

3. 创建属性文件

 

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

通过BUS_ATTR宏定义定义一个属性文件,其参数依次是属性文件名,属性文件的mode,显示属性文件函数和存储属性文件函数。

显示属性文件的函数如下所示:

static ssize_t show_bus_version(struct bus_type *bus, char *buf){

return snprintf(buf, PAGE_SIZE, '%sn', Version);

}

 

创建属性文件:

bus_create_file(&my_bus_type, &bus_attr_version)

其实原理上,它就是调用sysfs_create_file函数来实现的。

 

4. bus的注销

bus的卸载函数如下所示:

bus_unregister(&my_bus_type);

 

二、总线实例介绍

1. 定义bus_type结构体

 

以及实现.match的my_match函数,用于检测驱动与设备是否匹配

2. 定义bus属性文件结构体

上面的version是我们前面定义的一个字符串

 

3. 在init函数中注册总线

如图所示,

bus_register(&my_bus_type); 用于注册我们的总线,加入总线列表list,具体功能看前面

bus_create_file(&my_bus_type, &bus_attr_version); 创建我们my_bus_type 的属性文件

&bus_attr_version 这个结构体就是前面我们

static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL); 得到的。

查看linux源码如下:

 

4. 在exit函数中卸载总线

 

至止,我们已经实现了 总线-驱动-设备 模型中的总线了

5. 编译测试

 

附上源代码:


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 

 7 static char *Version = '$LoverXueEr : 1.0 $';

 8 

 9 //检测驱动是否匹配设备,dev->bus_id 和 driver->name相等的

10 static int my_match(struct device *dev ,struct device_driver *driver){

11     return !strncmp(dev_name(dev),driver->name,strlen(driver->name));

12 }

13 

14 struct bus_type my_bus_type = {

15     .name = 'my_bus',

16     .match = my_match,

17 };

18 //显示总线版本号

19 static ssize_t show_bus_version(struct bus_type *bus,char *buf){

20     return snprintf(buf,PAGE_SIZE,'%sn',Version);

21 }

22 

23 //产生后面的 bus_attr_version 结构体

24 static BUS_ATTR(version,S_IRUGO, show_bus_version, NULL);

25 

26 static int __init my_bus_init(void){

27     int ret;

28     /* 注册总线 */

29     ret = bus_register(&my_bus_type);

30     if(ret)

31         return ret;

32     /*  创建属性文件 */

33     if(bus_create_file(&my_bus_type, &bus_attr_version))

34         printk('<0>Fail to create version attribute! n');

35     return ret;

36 }

37 

38 static void my_bus_exit(void){

39     bus_unregister(&my_bus_type);

40 }

41 

42 module_init(my_bus_init);

43 module_exit(my_bus_exit);

44 

45 

46 MODULE_AUTHOR('Lover雪儿');

47 MODULE_LICENSE('GPL');


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    总线舵机是什么?基于STM32的单线串口通信;1 总线舵机的介绍 总线伺服舵机即串行总线智能舵机,实际上可以理解为数字舵机的衍生品,数字舵机与模拟舵机相比而言是控制系统设计上的颠覆,而总线伺服舵机对于舵机......
    机。六自由度机械臂共包含6个舵机,分别为1号总线舵机、5号LX-225舵机、2号3号4号6号LX-15D舵机舵机均具有堵转保护和过温保护,支持回读,具有温度、电压和位置反馈。供电后通过编程接口将控制......
    组成结构如图1所示。 2 系统的硬件设计 2.1 89C51 单片机 采用51单片机作为控制系统,以 89C51 为主控芯片,拥有 6 路接口的 PWM 舵机和四个独立接口的总线舵机,实现按键控制、采集......
    总线、SPI 总线和串口总线等。 (1) I2C 总线 I2C(Inter-Integrated Circuit)总线是 Philips 公司提出的一种双向的串行总线,采用两根信号线SCL(时钟线)和......
    电机旋转一周。   3、运动控制系统软件设计   下位机控制程序由串口收发程序,限位开关检测程序,舵机驱动程序、步进电机驱动等部分组成。下面将对舵机驱动和串口收发部分做详细的介绍。   3.1、舵机驱动程序   根据......
    775电机如何控制转速 775电机和795电机的区别;  775电机如何控制转速   775电机是一种常见的直流无刷电机,通常可以通过以下方式进行转速控制:   电压调节:775电机......
    ,温度和湿度控制,空气质量测量,家用电器定时和自动窗帘等功能的控制 主控是STM32F103RCT6单片机,连接到每个传感器。通过LD3320语音芯片生成语音信号到MCU的串口,在串口......
    电机转动固定的角度,图5.21为工业常用步进电机参考测试电路,有条件的读者朋友可以结合本节内容实现下如何控制步进电机转动固定步数。另外读者朋友还可以结合前面小节学到的A/D采集知识或I/O输入......
    把它们整理了一下。本文引用地址:UART通用异步收发器 UART口指的是一种物理形式(硬件)。 UART是异步,全双工串口总线,它比同步串口复杂很多。有两根线,一根TXD用于发送,一根RXD用于接收。 UART的串......
    中断:USART1,USART2串口初始化函数(以USART1为例): 串口中断处理函数: 字符串接收与处理(从openMV接收到的数据): 字符串转化为两位小数浮点数(用于后续PID控制): 2.3......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>