• 嵌入式Linux应用开发-第十章LED模板总线设备驱动模型


    第十章 LED模板驱动程序的改造:总线设备驱动模型

    在这里插入图片描述

    10.1 原来的框架

    在这里插入图片描述

    10.2 要实现的框架

    在这里插入图片描述

    10.3 写代码

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

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

    10.3.1 注意事项

    ① 如果 platform_device中不提供 release函数,如下图所示不提供红框部分的函数:
    在这里插入图片描述

    则在调用 platform_device_unregister时会出现警告,如下图所示:

    rootaroc-rk3399-pc;/mnti# insmod board_A_led.ko
    rootaroc-rk3399-pc:/mnt]# rmmod board_A_led.ko
    2412528005524125,29502724125.3051301
    Device 'xxxxxx led.0' does not have a release() function, it is broken and must be fixed
    ---- cut here -----------
    WARNING: at drivers/base/core.c:251
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

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

    EXPORT_SYMBOL(led_device_create); 
    
    • 1

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

    rootaroc-rk3399-pc:/mnt]# insmod chip_demo_gpio.ko
    24299,917448] chip_demo_gpio: Unknown symbo register led operations (err 0)
    24299.935714] chip_demo_gpio: Unknown symbol led class destroy device (err 0)
    24299.9508431 chip_demo_gpio: Unknown symbol led class create device (err 0)
    24299,9714821 chip_demo_gpio: Unknown symbol register led operations (err 0)
    24299.982958] chip_demo_gpio: Unknown symbol led class destroy device (err 0)
    24299,9948341 chip_demo_gpio: Unknown symbol led class create device (err 0)
    can't insert 'chip_demo_gpio.ko': unknown symbol in module, or unknown nsmoc: parameter
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    10.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 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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 = "xxxxxx_led_pin", 
    32         }, 
    33         { 
    34                 .start = GROUP_PIN(5,8), 
    35                 .flags = IORESOURCE_IRQ, 
    36                 .name = "xxxxxx_led_pin", 
    37         }, 
    38 }; 
    39 
    40 
    41 static struct platform_device board_A_led_dev = { 
    42         .name = "xxxxxx_led", 
    43         .num_resources = ARRAY_SIZE(resources), 
    44         .resource = resources, 
    45         .dev = { 
    46                 .release = led_dev_release, 
    47          }, 
    48 }; 
    49 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    10.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 = “xxxxxx_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 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    操作硬件的代码如下,第 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76

    10.4 课后作业

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

  • 相关阅读:
    协议-http协议-基础概念04-长短连接-重定向-cookie-缓存-代理
    <PLC><西门子><工控>西门子博图V18中使用SCL语言编写一个CRC16-modbus校验程序
    pycharm配置python3.8版本专门用于undecteded_chromedriver测试
    Spring——【第一章入门】:核心Aop与Ioc
    Python低溫半导体电子束量子波算法计算
    第2-3-7章 个人网盘服务接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss
    html旅游网站设计与实现——绿色古典旅游景区 HTML+CSS+JavaScript
    STM32项目 -- 选题分享(部分)
    qt使用mysql数据库
    分享一个java+springboot+vue校园电动车租赁系统(源码、调试、开题、lw)
  • 原文地址:https://blog.csdn.net/kingpower2018/article/details/133345250