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

发布者:omicron25最新更新时间:2024-08-15 来源: cnblogs关键字:总线设备 手机看文章 扫描二维码
随时随地手机看文章

在实现驱动程序之前,我们来想两个问题:

一、问题分析

1.什么时候驱动程序会在总线上找它可以处理的设备?

在driver_register(&my_driver),驱动注册时,驱动程序会在总线上找它可以处理的设备。

2.为什么说这个驱动可以处理相应的设备?

总线来判断这个驱动是否可以处理相应的设备,在总线中有.match = my_match ,当驱动在总线上找到了设备时,.match 函数就是用来判断这个驱动是否可以处理设备,判断的原则就是,判断设备的dev->bus_id和驱动的driver->name 是否相等,如果相等,则表明这个驱动是可以处理这个设备的。    此时就说明驱动找到了设备,接着,驱动程序就会调用probe这个函数,这就是我们所说的总线设备驱动模型,三者工作作用。

 

加载总线之后,不管是先加载驱动或者先加载设备都可以,如果先加载驱动的话,在注册设备时就会在总线上寻找驱动,如果先加载设备时,当注册驱动程序时,驱动程序会在总线中寻找有没有相应的设备。

二、程序分析

1.包含总线

和前面的设备程序一样,先包含总线

2.定义驱动结构体

注意 struct 的成员 .name ,因为探测驱动与设备是否匹配就是看这个名字

my_probe 和my_remove 就是分别当驱动程序 和 设备 关联 或者 不关联时会调用的函数

 

3.定义属性文件的结构体

关于 static DRIVER_ATTR(drv,S_IRUGO,mydriver_show,NULL);这种宏,此处就不再废话了,不懂的可以看linux源码或者前面我们bus篇中的讲解

 

4.在init函数中 注册驱动 创建属性文件

可以发现又是和前面的一样,不再废话了。

 

5. 在exit函数中移除驱动

 

三、编译测试

编译,成功生成 mybus.ko mydev.o mydrv.ko:

加载

方案一 先加载驱动后加载设备 加载顺序 mybus.ko mydrv.ko mydev.ko

可以发现,一旦我们加载设备,便打印出 驱动中的my_probe的代码:告诉我们驱动找到了设备

移除时,发现打印出了驱动中my_remove函数的代码Driver found device unpluged ! 如图所示:

同样我们还发现,mybus已经有俩个使用了 分别是 mydev 和 mydrv

 

下面我们来试试方案二,看看结果怎么样

方案二 先加载设备后加载驱动 加载顺序 mybus.ko mydev.ko mydrv.ko

可以发现,结果一样,一旦我们加载驱动,便打印出 驱动中的my_probe的代码:告诉我们驱动找到了设备

这里更加证实了我们前面问题二中的答案

 

下面我们进入 /sys/bus/my_bus/drivers/my_dev 看看下面有什么文件

附上mybus.c 驱动程序


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 

 7 

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

 9 

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

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

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

13 }

14 

15 static void my_bus_release(struct device *dev){

16     printk('

17 }

18   

19 //设置设备的名字  dev_set_name(&dev,'name');

20 struct device my_bus = {

21     .init_name = 'my_bus0',

22     .release = my_bus_release,

23 };

24 

25 struct bus_type my_bus_type = {

26     .name = 'my_bus',

27     .match = my_match,

28 };

29 EXPORT_SYMBOL(my_bus);  //导出符号

30 EXPORT_SYMBOL(my_bus_type);

31 

32 //显示总线版本号

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

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

35 }

36 

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

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

39 

40 static int __init my_bus_init(void){

41     int ret;

42     /* 注册总线 */

43     ret = bus_register(&my_bus_type);

44     if(ret)

45         return ret;

46     /*  创建属性文件 */

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

48         printk('

49 

50     /* 注册总线设备 */

51     ret = device_register(&my_bus);

52     if(ret)

53         printk('

54     return ret;

55 }

56 

57 static void my_bus_exit(void){

58     bus_unregister(&my_bus_type);

59     device_unregister(&my_bus);

60 }

61 

62 module_init(my_bus_init);

63 module_exit(my_bus_exit);

64 

65 

66 MODULE_AUTHOR('Lover雪儿');

67 MODULE_LICENSE('GPL');


附上mydev.c 驱动程序


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 

 7 //包含总线

 8 extern struct device my_bus;

 9 extern struct bus_type my_bus_type;

10 

11 static void my_dev_release(struct device *dev){

12     printk('

13 }

14   

15 //设置设备的名字  dev_set_name(&dev,'name');

16 struct device my_dev = {

17     .bus = &my_bus_type,

18     .parent = &my_bus,        //父目录为my_bus

19     .release = my_dev_release,

20 };

21 

22 ssize_t mydev_show(struct device *dev,struct device_attribute *attr,char *buf){

23     return sprintf(buf, '%sn', 'This is my device');

24 }

25 

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

27 static DEVICE_ATTR(dev,S_IRUGO,mydev_show,NULL);

28 

29 static int __init my_dev_init(void){

30     int ret = 0;

31 

32     /* 初始化设备 以后看驱动与设备是否匹配就看这个名字 */

33       dev_set_name(&my_dev,'my_dev');

34 

35     /* 注册设备 */

36     ret = device_register(&my_dev);

37     if(ret)

38         printk('

39     /* 创建属性文件 */

40     if(device_create_file(&my_dev, &dev_attr_dev))

41         printk('

42 

43     return ret;

44 }

45 

46 static void my_dev_exit(void){

47     device_remove_file(&my_dev, &dev_attr_dev);

48     device_unregister(&my_dev);

49 }

50 

51 module_init(my_dev_init);

52 module_exit(my_dev_exit);

53 

54 

55 MODULE_AUTHOR('Lover雪儿');

56 MODULE_LICENSE('GPL');


附上mydrv.c 驱动程序


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 

 7 //包含总线

 8 extern struct device my_bus;

 9 extern struct bus_type my_bus_type;

10 

11 static int my_probe(struct device *dev){

12     printk('

13     return 0;

14 }

15 

16 static int my_remove(struct device *dev){

17     printk('

18     return 0;

19 }

20 // 驱动结构体 

21 struct device_driver my_driver = {

22     .name = 'my_dev',        //此处声明了 本驱动程序可以处理的设备 名字

23     .bus = &my_bus_type,

24     .probe = my_probe,

25     .remove = my_remove,

26 };

27 

28 ssize_t mydriver_show(struct device_driver *driver,char *buf){

29     return sprintf(buf, '%sn', 'This is my driver');

30 }

31 

32 //产生后面的 driver_attr_drv 结构体

33 static DRIVER_ATTR(drv,S_IRUGO,mydriver_show,NULL);

34 

35 static int __init my_driver_init(void){

36     int ret = 0;

37 

38     /* 注册驱动 */

39     ret = driver_register(&my_driver);

40     if(ret)

41         printk('

42     /* 创建属性文件 */

43     if(driver_create_file(&my_driver, &driver_attr_drv))

44         printk('

45 

46     return ret;

47 }

48 

49 static void my_driver_exit(void){

50     driver_remove_file(&my_driver, &driver_attr_drv);

51     driver_unregister(&my_driver);

52 }

53 

54 module_init(my_driver_init);

55 module_exit(my_driver_exit);

56 

57 

58 MODULE_AUTHOR('Lover雪儿');

59 MODULE_LICENSE('GPL');


附上makefile程序


 1 ifeq ($(KERNELRELEASE),)

 2     KERNELDIR ?= /home/study/system/linux-2.6.31

 3     PWD := $(shell pwd)

 4 modules:

 5     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

 6 modules_install:

 7     $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install

 8 clean:

 9     rm -rf *.o *~ core .depend  *.cmd *.ko *.mod.c .tmp_versions *.markers *.order *.symvers

10 

11 else

12     obj-m := mybus.o mydev.o mydrv.o

13 endif


好啦,至此,我们的总线-设备-驱动 模型已经实现了,但是并不能说我们已经懂了,这里再次废话一下,很多原理知识虽然乏味,还是要看,光会写程序是没用的,还需要懂为什么。


我也是处于学习阶段,这些都是我的一些简单的经验,能帮助大家快速入门,剩下的还是。。。入门了就会相对跟简单了。


很多人说学习linux驱动很难,那是因为对未知的恐惧,说简单点,就是那么几个结构体,算法和API的使用罢了,不说了,说多了就是欠揍的下场,


任重而道远,加油吧!!!


下面我们的任务就是实现 平台设备驱动程序 platform 的学习了。敬请期待。。


关键字:总线设备 引用地址:IMX257 总线设备驱动模型编程之驱动篇

上一篇:IMX257 总线设备驱动模型编程之平台总线设备platform
下一篇:IMX257 总线设备驱动模型编程之设备篇

推荐阅读最新更新时间:2026-03-20 20:00

IMX257 LED驱动程序实现
由于昨天对IMX257的地址分配不了解,所以前面只能用s3c24xx的驱动程序来了解ioremap等对IO端口的工作原理。 但是经过昨晚对IMX257芯片的细细梳理,今天早上起来又把IMX257的芯片资料看了一遍,终于成功看懂了,下面意义给大家道来。 我们此处使用ERR_LED 也就是GPIO3_23引脚 一、IMX257 芯片资料分析 1.确定相关寄存器基址 确定IOMUX地址 GPIO3的地址 2.确定相关寄存器的偏移地址 IOMUX的相关的模式配置寄存器,配置为ALT5模式 偏移地址: 寄存器描述: 接下来就是配置GPIO的相关信息,上拉,CMOS输入输出,等信息 偏移地址: 寄存器描述:
[单片机]
<font color='red'>IMX257</font> LED<font color='red'>驱动</font>程序实现
IMX257 设备驱动模型之sysfs文件系统知识点整合(二)
前天我们实现了一个简单的sysfs的kobject的驱动程序,可是有没有发现很多东西都不懂,原因就是在我们对sysfs和kobject的工作原理不懂,虽然我一直不提倡整天接触那些乏味的知识点,也一直不喜欢谈论太多的知识点,但是有的时候,理论知识是实践的基础,有些基础的知识点还是不得不提,下面进入正题。 一、sysfs介绍 在linux2.6内核以后,引入了一个新的文件系统sysfs,它挂载于/sys目录下,跟devfs一样它也是一个虚拟文 件系统,也是用来对系统的设备进行管理的,它把实际连接到系统上的设备和总线组织成一个分级的文件,用户空间的程序同样可以利用这些信息以实现和内核的交 互,该文件系统是当前系统上实际设备树的一个直观反
[单片机]
<font color='red'>IMX257</font> <font color='red'>设备</font><font color='red'>驱动</font><font color='red'>模型</font>之sysfs文件系统知识点整合(二)
IMX257 输入子系统
一、输入子系统 1.输入子系统结构体定义 struct input_dev{ const char *name; 设备名 const char *phys; 设备在系统中路径 const char *uniq; struct input_id id; 用于匹配input hander参数 unsigned long propbit ; unsigned long evbit ; //设备所支持事件类型,主要有EV_SYNC,EV_KEY,EV_REL,EV_ABS等 unsigned long keybit ; //按键所对应的位图 unsigned long relbit ; //相对坐标对应位图 u
[单片机]
<font color='red'>IMX257</font> 输入子系统
iMX257引脚配置函数/内存读写函数
要包含的三个头文件: #include mx257_gpio.h #include mx25_pins.h #include iomux.h 一、GPIO引脚使用 选择引脚模式- 引脚配置- 申请GPIO- 设置引脚输入/输出- 读取GPIO- 释放引脚模式- 释放GPIO 1.选择引脚的模式(ALT0-ALT7) int mxc_request_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t cfg) void mxc_free_iomux(iomux_pin_name_t pin, iomux_pin_cfg_t cfg) 示例: mxc_request_iomux(GPIO
[单片机]
Tiny210按键分层分离(总线-驱动-设备模型)
led_dev.c驱动源码: #include linux/module.h #include linux/version.h #include linux/init.h #include linux/kernel.h #include linux/types.h #include linux/interrupt.h #include linux/list.h #include linux/timer.h #include linux/init.h #include linux/serial_core.h #include linux/platform_device.h // 分配/设置/注册一个platfo
[单片机]
OK6410分层分离(总线-驱动-设备模型)
led_dev.c源码: #include linux/module.h #include linux/moduleparam.h #include linux/ioport.h #include linux/init.h #include linux/delay.h #include linux/platform_device.h // 1. 分配一个platform_device // 2. 设置 static struct resource led_resoures = { = { .start = 0x7F008820, // GPMCON .end = 0x7F008827,
[单片机]
USB的便携式ARINC429总线通信设备设计
在航空电子综合化系统中,快速、有效的数据传输对整个航空电子系统的性能有很大影响,因此数据总线被称为现代航空电子系统的“骨架”。ARINC429是航空电子系统之间最常用的通信总线之一。要在计算机上实现与机载设备的ARINC429总线数据通信,必须实现429总线与计算机总线之间的数据传输。本文设计了基于USB总线的便携式ARINC429总线通信设备,并通过实际运行测试,对该设备的可靠性和稳定性进行了验证。 1 系统总体设计 1.1 系统功能分析 该系统主要分为3大功能单元:中央控制单元、429数据收发单元、429电平转换单元。系统的功能结构框图如图1所示。中央控制单元与PC机进行USB通信,将USB总线转换为自定义总线,并根据PC机发
[测试测量]
USB的便携式ARINC429<font color='red'>总线</font>通信<font color='red'>设备</font>设计
基于单片机设计的总线通信设备
在航空电子综合化系统中,快速、有效的数据传输对整个航空电子系统的性能有很大影响,因此数据总线被称为现代航空电子系统的“骨架”。ARINC429是航空电子系统之间最常用的通信总线之一。要在计算机上实现与机载设备的ARINC429总线数据通信,必须实现429总线与计算机总线之间的数据传输。本文设计了基于USB总线的便携式ARINC429总线通信设备,并通过实际运行测试,对该设备的可靠性和稳定性进行了验证。 1 系统总体设计 1.1 系统功能分析 该系统主要分为3大功能单元:中央控制单元、429数据收发单元、429电平转换单元。系统的功能结构框图如图1所示。中央控制单元与PC机进行USB通信,将USB总线转换为自定义总线,并根据PC机发来
[单片机]
基于单片机设计的<font color='red'>总线</font>通信<font color='red'>设备</font>
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved