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

发布时间:2024-08-15  

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

一、问题分析

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 的学习了。敬请期待。。


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

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

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

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

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

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

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

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