匿名
未登录
登录
百问网嵌入式Linux wiki
搜索
查看“ELADCMSecondEditionChapterFivePartⅩ”的源代码
来自百问网嵌入式Linux wiki
名字空间
页面
讨论
更多
更多
页面选项
Read
查看源代码
历史
←
ELADCMSecondEditionChapterFivePartⅩ
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看与复制此页面的源代码。
__NOTITLE__ ==LED模板驱动程序的改造:总线设备驱动模型== ===原来的框架=== : [[File:EmbeddedLinuxApplicationDevelopmentCompleteManualSecondEditionChapterFive_092.png|800px]] ===要实现的框架=== : [[File:EmbeddedLinuxApplicationDevelopmentCompleteManualSecondEditionChapterFive_093.png|800px]] ===写代码=== : 使用GIT下载所有源码后,本节源码位于如下目录: 01_all_series_quickstart\04_快速入门(正式开始)\ 02_嵌入式Linux驱动开发基础知识\source\ 02_led_drv\04_led_drv_template_bus_dev_drv ====注意事项==== : ① 如果platform_device中不提供release函数,如下图所示不提供红框部分的函数: :: [[File:EmbeddedLinuxApplicationDevelopmentCompleteManualSecondEditionChapterFive_094.png|600px]] :: 则在调用platform_device_unregister时会出现警告,如下图所示: ::: [[File:EmbeddedLinuxApplicationDevelopmentCompleteManualSecondEditionChapterFive_095.png|600px]] :: 你可以提供一个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”的提示: ::: [[File:EmbeddedLinuxApplicationDevelopmentCompleteManualSecondEditionChapterFive_096.png|600px]] ====实现platform_device结构体==== : board_A.c作为一个可加载模块,里面也有入口函数、出口函数。在入口函数中注册platform_device结构体,在platform_device结构体中指定使用哪个GPIO引脚。 : 首先看入口函数,它调用platform_device_register函数,向内核注册board_A_led_dev结构体: <syntaxhighlight lang="C"> 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 </syntaxhighlight> : board_A_led_dev结构体定义如下。 : 在resouces数组中指定了2个引脚(第27~38行); : 我们还提供了一个空函数led_dev_release(第23~25行),它被赋给board_A_led_dev结构体(第46行),这个函数在卸载platform_device时会被调用,如果不提供的话内核会打印警告信息。 <syntaxhighlight lang="C"> 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 </syntaxhighlight> ====实现platform_driver结构体==== : chip_demo_gpio.c中注册platform_driver结构体,它使用Bus/Dev/Drv模型,当有匹配的platform_device时,它的probe函数就会被调用。 : 在probe函数中所做的事情跟之前的代码没有差别。 : 先看入口函数。 : 第150行向内核注册一个platform_driver结构体; : 这个结构体的核心在于第140行的chip_demo_gpio_probe函数。 <syntaxhighlight lang="C"> 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 </syntaxhighlight> : chip_demo_gpio_probe函数代码如下。 : 第107行:从匹配的platform_device中获取资源,确定GPIO引脚。 : 第111行:把引脚记录下来,在操作硬件时要用。 : 第112行:新发现了一个GPIO引脚,就调用上层驱动的代码创建设备节点。 <syntaxhighlight lang="C"> 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 </syntaxhighlight> : 操作硬件的代码如下,第31、63行的代码里用到了数组g_ledpins,里面的值来自platform_device,在probe函数中根据platform_device的资源确定了引脚: <syntaxhighlight lang="C"> 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 </syntaxhighlight> ===课后作业=== : 完善半成品程序:04_led_drv_template_bus_dev_drv_unfinished。 : 请仿照本节提供的程序(位于04_led_drv_template_bus_dev_drv目录),改造你所用的单板的LED驱动程序。 [[Category:嵌入式Linux应用开发完全手册第2版]]
返回至
ELADCMSecondEditionChapterFivePartⅩ
。
导航
导航
WIKI首页
官方店铺
资料下载
交流社区
所有页面
所有产品
MPU-Linux开发板
MCU-单片机开发板
Linux开发系列视频
单片机开发系列视频
所有模块配件
Wiki工具
Wiki工具
特殊页面
页面工具
页面工具
用户页面工具
更多
链入页面
相关更改
页面信息
页面日志