/************************************************************************/

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");            // 描述模块的别名信息
device

相关文章: