嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型

简介: 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(三十)LED模板驱动程序的改造:总线设备驱动模型

1.1 原来的框架

1670922163672.jpg


1.2 要实现的框架

1670922178625.jpg


1.3 写代码


使用GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart\
05_嵌入式Linux驱动开发基础知识\source\
02_led_drv\04_led_drv_template_bus_dev_drv


1.3.1 注意事项


① 如果platform_device中不提供release函数,如下图所示不提供红框部分的函数:

1670922211555.jpg

1670922218840.jpg

你可以提供一个release函数,如果实在无事可做,把这函数写为空。


② EXPORT_SYMBOL

a.c编译为a.ko,里面定义了func_a;如果它想让b.ko使用该函数,那么a.c里需要导出此函数(如果a.c,b.c都编进内核,则无需导出): EXPORT_SYMBOL(led_device_create);

并且,使用时要先加载a.ko。 如果先加载b.ko,会有类似如下“Unknown symbol”的提示:

1670922228866.jpg


1.3.2 实现platform_device结构体


board_A.c作为一个可加载模块,里面也有入口函数、出口函数。在入口函数中注册platform_device结构体,在platform_device结构体中指定使用哪个GPIO引脚。


首先看入口函数,它调用platform_device_register函数,向内核注册

board_A_led_dev结构体:
50 static int __init led_dev_init(void)
51 {
52     int err;
53
54     err = platform_device_register(&board_A_led_dev);
55
56     return 0;
57 }
58


board_A_led_dev结构体定义如下。 在resouces数组中指定了2个引脚(第27~38行);


我们还提供了一个空函数led_dev_release(第23~25行),它被赋给board_A_led_dev结构体(第46行),这个函数在卸载platform_device时会被调用,如果不提供的话内核会打印警告信息。

23 static void led_dev_release(struct device *dev)
24 {
25 }
26
27 static struct resource resources[] = {
28         {
29                 .start = GROUP_PIN(3,1),
30                 .flags = IORESOURCE_IRQ,
31                 .name = "100ask_led_pin",
32         },
33         {
34                 .start = GROUP_PIN(5,8),
35                 .flags = IORESOURCE_IRQ,
36                 .name = "100ask_led_pin",
37         },
38 };
39
40
41 static struct platform_device board_A_led_dev = {
42         .name = "100ask_led",
43         .num_resources = ARRAY_SIZE(resources),
44         .resource = resources,
45         .dev = {
46                 .release = led_dev_release,
47          },
48 };
49


1.3.3 实现platform_driver结构体


chip_demo_gpio.c中注册platform_driver结构体,它使用Bus/Dev/Drv模型,当有匹配的platform_device时,它的probe函数就会被调用。

在probe函数中所做的事情跟之前的代码没有差别。 先看入口函数。 第150行向内核注册一个platform_driver结构体;

这个结构体的核心在于第140行的chip_demo_gpio_probe函数。

138 static struct platform_driver chip_demo_gpio_driver = {
139     .probe      = chip_demo_gpio_probe,
140     .remove     = chip_demo_gpio_remove,
141     .driver     = {
142         .name   = "100ask_led",
143     },
144 };
145
146 static int __init chip_demo_gpio_drv_init(void)
147 {
148     int err;
149
150     err = platform_driver_register(&chip_demo_gpio_driver);
151     register_led_operations(&board_demo_led_opr);
152
153     return 0;
154 }
155


chip_demo_gpio_probe函数代码如下。

第107行:从匹配的platform_device中获取资源,确定GPIO引脚。

第111行:把引脚记录下来,在操作硬件时要用。

第112行:新发现了一个GPIO引脚,就调用上层驱动的代码创建设备节点。

100 static int chip_demo_gpio_probe(struct platform_device *pdev)
101 {
102     struct resource *res;
103     int i = 0;
104
105     while (1)
106     {
107         res = platform_get_resource(pdev, IORESOURCE_IRQ, i++);
108         if (!res)
109             break;
110
111         g_ledpins[g_ledcnt] = res->start;
112         led_class_create_device(g_ledcnt);
113         g_ledcnt++;
114     }
115     return 0;
116
117 }
118


操作硬件的代码如下,第31、63行的代码里用到了数组g_ledpins,里面的值来自platform_device,在probe函数中根据platform_device的资源确定了引脚:

23 static int g_ledpins[100];
24 static int g_ledcnt = 0;
25
26 static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */
27 {
28     //printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
29
30   printk("init gpio: group %d, pin %d\n", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
31     switch(GROUP(g_ledpins[which]))
32     {
33         case 0:
34         {
35             printk("init pin of group 0 ...\n");
36             break;
37         }
38         case 1:
39         {
40             printk("init pin of group 1 ...\n");
41             break;
42         }
43         case 2:
44         {
45             printk("init pin of group 2 ...\n");
46             break;
47         }
48         case 3:
49         {
50             printk("init pin of group 3 ...\n");
51             break;
52         }
53     }
54
55     return 0;
56 }
57
58 static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
59 {
60     //printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
61    printk("set led %s: group %d, pin %d\n", status ? "on" : "off", GROUP(g_ledpins[which]), PIN(g_ledpins[which]));
62
63     switch(GROUP(g_ledpins[which]))
64     {
65         case 0:
66         {
67             printk("set pin of group 0 ...\n");
68             break;
69         }
70         case 1:
71         {
72             printk("set pin of group 1 ...\n");
73             break;
74         }
75         case 2:
76         {
77             printk("set pin of group 2 ...\n");
78             break;
79         }
80         case 3:
81         {
82             printk("set pin of group 3 ...\n");
83             break;
84         }
85     }
86
87     return 0;
88 }
89
90 static struct led_operations board_demo_led_opr = {
91     .init = board_demo_led_init,
92     .ctl  = board_demo_led_ctl,
93 };
94
95 struct led_operations *get_board_led_opr(void)
96 {
97     return &board_demo_led_opr;
98 }
99


1.4 课后作业


完善半成品程序:04_led_drv_template_bus_dev_drv_unfinished。

请仿照本节提供的程序(位于04_led_drv_template_bus_dev_drv目录),改造你所用的单板的LED驱动程序。

相关文章
|
3天前
|
Android开发
鸿蒙开发:自定义一个简单的标题栏
本身就是一个很简单的标题栏组件,没有什么过多的技术含量,有一点需要注意,当使用沉浸式的时候,注意标题栏的位置,需要避让状态栏。
鸿蒙开发:自定义一个简单的标题栏
|
3天前
|
API
鸿蒙开发:切换至基于rcp的网络请求
本文的内容主要是把之前基于http封装的库,修改为当前的Remote Communication Kit(远场通信服务),无非就是通信的方式变了,其他都大差不差。
鸿蒙开发:切换至基于rcp的网络请求
|
8天前
|
UED
鸿蒙next版开发:相机开发-适配不同折叠状态的摄像头变更(ArkTS)
在HarmonyOS 5.0中,ArkTS提供了强大的相机开发能力,特别是针对折叠屏设备的摄像头适配。本文详细介绍了如何在ArkTS中检测和适配不同折叠状态下的摄像头变更,确保相机应用在不同设备状态下的稳定性和用户体验。通过代码示例展示了具体的实现步骤。
35 8
|
8天前
|
API 内存技术
鸿蒙next版开发:相机开发-拍照(ArkTS)
在HarmonyOS 5.0中,ArkTS提供了一套完整的API来管理相机功能,特别是拍照功能。本文详细介绍如何在ArkTS中实现拍照功能,包括导入接口、创建会话、配置会话、触发拍照及监听拍照输出流状态,并提供代码示例进行详细解读。通过本文,你将掌握如何在HarmonyOS 5.0中使用ArkTS实现高效的拍照功能。
27 7
|
8天前
|
前端开发 API
鸿蒙next版开发:相机开发-预览(ArkTS)
在HarmonyOS 5.0中,使用ArkTS进行相机预览是核心功能之一。本文详细介绍了如何使用ArkTS实现相机预览,包括导入相机接口、创建Surface、获取相机输出能力、创建会话并开始预览,以及监听预览输出状态等步骤,并提供了代码示例。通过本文,读者可以掌握在HarmonyOS 5.0中使用ArkTS进行相机预览的基本方法。
26 6
|
8天前
|
编解码 开发工具 计算机视觉
鸿蒙5.0版开发:命令行工具(mediatool工具)
在HarmonyOS 5.0的开发中,命令行工具mediatool基于FFmpeg库,提供了丰富的媒体处理功能,如视频和音频的转码、封装格式转换、提取媒体信息等。本文详细介绍mediatool的功能和使用方法,并提供代码示例。
27 6
|
8天前
|
前端开发 开发者
鸿蒙next版开发:相机开发-元数据(ArkTS)
在HarmonyOS 5.0中,ArkTS新增了对相机元数据的访问能力,帮助开发者获取图像的详细信息。本文介绍了如何在ArkTS中获取和使用相机元数据,包括导入接口、创建元数据输出流、开启和停止元数据输出、监听元数据对象可用事件等步骤,并提供了详细的代码示例。
25 5
|
8天前
|
前端开发 API 开发者
鸿蒙next版开发:相机开发-录像(ArkTS)
在HarmonyOS 5.0中,ArkTS提供了一套完整的API来管理相机录像功能。本文详细介绍了如何在ArkTS中实现录像功能,包括导入接口、创建Surface、获取相机输出能力、创建会话并开始录像以及监听录像输出流状态,并提供了代码示例进行解读。希望本文能帮助开发者更好地利用ArkTS的相机录像功能。
24 5
|
8天前
|
API 开发者 内存技术
鸿蒙next版开发:相机开发-会话管理(ArkTS)
在HarmonyOS 5.0中,ArkTS提供了完整的API来管理相机会话,包括创建相机输入流、预览输出流、拍照输出流,配置和管理会话。本文详细介绍了相机会话管理的基础步骤和代码示例,涵盖会话创建、闪光灯和焦距配置及错误处理等内容,帮助开发者更好地利用ArkTS开发相机应用。
26 4
|
8天前
|
UED
鸿蒙next版开发:音频并发策略扩展(ArkTS)
在HarmonyOS 5.0中,音频并发策略通过ArkTS的AudioSessionManager接口管理多个音频流的交互和优先级。本文介绍了如何自定义音频焦点策略,包括激活、停用音频会话及注册回调函数,并提供了示例代码。适用于多媒体、通信和游戏应用。
32 4