/************************************************************************/
Linux内核版本:2.6.35.7
运行平台:三星s5pv210
/************************************************************************/
1、本例中通过使用Linux驱动模型中的platform总线和led驱动框架编写出来的led驱动代码来分析platform总线的工作原理,本代码是我自己将近快一天的时间编写出来的,
已经通过运行验证代码是能够正常运行的。对此对代码做如下分析:
在platform总线(任意总线)下的驱动代码都是要分为两部分:设备和驱动,在platform总线下是platform_device和platform_driver。
关于这个问题,我在我的上一篇博客中已经做了很好的说明。对于设备部分的注册:
(1)一般是内核的移植工程师在做移植的时候添加的,在我的这个移植好的内核中是放在arch/arm/mach-s5pv210/mach-x210.c文件中,
所以如果移植工程师没有添加你需要编写的驱动对应的设备,那么就需要你自己添加,你可以直接在这个文件中添加,系统启动的时候就会
直接加载这个文件的代码,所以设备就会被注册到我们的platform总线下,那么就会添加到platform总线管理下的device设备管理相关的数
据结构中去(链表),此时platform总线下的match函数就会自动进行匹配(每注册一个设备或者驱动match函数都会被调用),因为此时还
相应的驱动被注册,所以匹配肯定是失败的;当我们把驱动也注册之后,也会把驱动添加到platform总线管理下的drive驱动管理相关的数据
结构中去(也是一个链表),platform总线将会再次执行match函数,此时match函数就会匹配成功,platform总线下的设备和驱动就建立了对应
关系了,那么设备就能够工作了。
(2)设备注册部分也可以单独编写, 我们下驱动的时候提供 xxxxx_device.c(用来编写设备部分)和xxx_driver(用来编写驱动部分),将他们
编译成模块,系统启动之后分别使用insmod装载设备和驱动(顺序无所谓)。这种情况一般使用在调试阶段,如果确定我们的驱动是没有bug的情况下
,最好还是把驱动编译进内核,把他们放在他们应该在的位置。
2、led驱动代码
本例子采用的是单独编写编译的方式,代码分析如下:
(1)设备部分:leds-x210-device.c
1 #include <linux/module.h> // module_init module_exit 2 #include <linux/init.h> // __init __exit 3 #include <linux/fs.h> 4 #include <linux/leds.h> 5 #include <mach/regs-gpio.h> 6 #include <mach/gpio-bank.h> 7 #include <linux/io.h> 8 #include <linux/ioport.h> 9 #include <mach/gpio.h> 10 #include <linux/platform_device.h> 11 12 // 定义一个结构体用于放置本设备的私有数据 13 struct x210_led_platdata { 14 unsigned int gpio; // led设备用到的GPIO 15 char *device_name; // led设备在/sys/class/leds/目录下的名字 16 char *gpio_name; // 使用gpiolob申请gpio资源时分配的名字 17 }; 18 19 20 // 定义x210_led_platdata类型的变量,分别对应板子上的4颗led小灯 21 static struct x210_led_platdata x210_led1_pdata = { 22 .gpio = S5PV210_GPJ0(3), 23 .device_name = "led1", 24 .gpio_name = "led1-gpj0_3", 25 }; 26 27 static struct x210_led_platdata x210_led2_pdata = { 28 .gpio = S5PV210_GPJ0(4), 29 .device_name = "led2", 30 .gpio_name = "led2-gpj0_4", 31 }; 32 33 static struct x210_led_platdata x210_led3_pdata = { 34 .gpio = S5PV210_GPJ0(5), 35 .device_name = "led3", 36 .gpio_name = "led3-gpj0_5", 37 }; 38 39 static struct x210_led_platdata x210_led4_pdata = { 40 .gpio = S5PV210_GPD0(1), 41 .device_name = "led4", 42 .gpio_name = "led4-gpd0_1", 43 }; 44 45 46 // 定义4个release函数,当我们卸载设备时会调用platform_device结构体中的device结构体下的release函数 47 void x210_led1_release(struct device *dev) 48 { 49 printk(KERN_INFO "x210_led1_release\n"); 50 } 51 52 void x210_led2_release(struct device *dev) 53 { 54 printk(KERN_INFO "x210_led1_release\n"); 55 } 56 57 void x210_led3_release(struct device *dev) 58 { 59 printk(KERN_INFO "x210_led1_release\n"); 60 } 61 62 void x210_led4_release(struct device *dev) 63 { 64 printk(KERN_INFO "x210_led1_release\n"); 65 } 66 67 68 // 定义4个platform_device结构体 69 static struct platform_device x210_led1 = { 70 .name = "x210_led", 71 .id = 0, 72 .dev = { 73 .platform_data = &x210_led1_pdata, 74 .release = x210_led1_release, 75 }, 76 }; 77 78 static struct platform_device x210_led2 = { 79 .name = "x210_led", 80 .id = 1, 81 .dev = { 82 .platform_data = &x210_led2_pdata, 83 .release = x210_led2_release, 84 }, 85 }; 86 87 static struct platform_device x210_led3 = { 88 .name = "x210_led", 89 .id = 2, 90 .dev = { 91 .platform_data = &x210_led3_pdata, 92 .release = x210_led3_release, 93 }, 94 }; 95 96 static struct platform_device x210_led4 = { 97 .name = "x210_led", 98 .id = 3, 99 .dev = { 100 .platform_data = &x210_led4_pdata, 101 .release = x210_led4_release, 102 }, 103 }; 104 105 106 // 将4个platform_device结构体地址放入一个数组中 107 static struct platform_device *x210_devices[] = { 108 &x210_led1, 109 &x210_led2, 110 &x210_led3, 111 &x210_led4, 112 }; 113 114 // 入口函数 115 static int __init leds_x210_init(void) 116 { 117 if (platform_add_devices(x210_devices, ARRAY_SIZE(x210_devices))) // 循环注册platform平台设备 118 { 119 printk(KERN_ERR "platform_add_devices failed.\n"); 120 return -1; 121 } 122 123 return 0; 124 } 125 126 // 出口函数(卸载) 127 static void __exit leds_x210_exit(void) 128 { 129 int i = 0; 130 for (i = 0; i < 4; i++) 131 platform_device_unregister(x210_devices[i]); // 当执行到这个函数的时候就会去执行platform_device结构体中的device结构体下的release函数 132 } 133 134 /*函数入口和出口修饰*/ 135 module_init(leds_x210_init); 136 module_exit(leds_x210_exit); 137 138 /*描述模块信息*/ 139 MODULE_LICENSE("GPL"); // 描述模块的许可证 140 MODULE_AUTHOR("Tao Deng <> 773904075@qq.com"); // 描述模块的作者 141 MODULE_DESCRIPTION("led device for x210."); // 描述模块的介绍信息 142 MODULE_ALIAS("alias DT"); // 描述模块的别名信息