驱动04.平台总线驱动模型——点亮LED灯

Posted wade_linux

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了驱动04.平台总线驱动模型——点亮LED灯相关的知识,希望对你有一定的参考价值。

1 平台总线的简介

  平台总线是一种虚拟的总线,相应的设备则为platform_device,而驱动则为platform_driver。总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与之匹配的驱动;相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配由总线完成。

  我们可以把一个驱动程序抽出来分为两部分,一部分是硬件相关的dev,另一部分则是稳定的纯软件部分driver。而总线只是一种机制,把dev和driver这两部分建立“联系”的机制。

eg:

①dev部分

  a.把device放入bus的dev链表

  b.从bus的drv链表取出每一个drv,用bus的match函数判断drv是否支持dev

  c.如果支持,将调用drv的probe函数

 

②drv部分

  a.把driver放入bus的drv链表

  b.从bus的dev链表取出每一个dev,用bus的match函数判断dev是否支持drv

  c.如果支持,将调用drv的probe函数

2 linux平台总线的代码分析

struct bus_type platform_bus_type = {
    .name        = "platform",
    .dev_attrs    = platform_dev_attrs,
    .match        = platform_match,  //dev和drv匹配时调用的函数
    .uevent        = platform_uevent,
    .suspend    = platform_suspend,
    .suspend_late    = platform_suspend_late,
    .resume_early    = platform_resume_early,
    .resume        = platform_resume,
};
static int platform_match(struct device * dev, struct device_driver * drv)
{
    struct platform_device *pdev = container_of(dev, struct platform_device, dev);

    return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);//当dev的设备名与drv的名字相同时,则匹配成功
}

platform_device
结构体的定义
struct platform_device {
    const char    * name;
    u32        id;
    struct device    dev;
    u32        num_resources;//资源数目
    struct resource    * resource;//设备信息,使用platform_get_resource函数来获取资源信息
};

注册平台设备platform_device_register,实际上是加入到bus的dev链表中

1 int platform_device_register(struct platform_device * pdev)
2 {
3     device_initialize(&pdev->dev);//初始化platform_device的device成员
4     return platform_device_add(pdev);//实际上是调用device_add函数
5 }

 同样的,也有platform_driver结构体的定义

 1 struct platform_driver {
 2     int (*probe)(struct platform_device *);
 3     int (*remove)(struct platform_device *);
 4     void (*shutdown)(struct platform_device *);
 5     int (*suspend)(struct platform_device *, pm_message_t state);
 6     int (*suspend_late)(struct platform_device *, pm_message_t state);
 7     int (*resume_early)(struct platform_device *);
 8     int (*resume)(struct platform_device *);
 9     struct device_driver driver;
10 }
//device_driver的定义:
 1 struct device_driver {
 2     const char        * name;
 3     struct bus_type        * bus;
 4 
 5     struct kobject        kobj;
 6     struct klist        klist_devices;
 7     struct klist_node    knode_bus;
 8 
 9     struct module        * owner;
10     const char         * mod_name;    /* used for built-in modules */
11     struct module_kobject    * mkobj;
12 
13     int    (*probe)    (struct device * dev);
14     int    (*remove)    (struct device * dev);
15     void    (*shutdown)    (struct device * dev);
16     int    (*suspend)    (struct device * dev, pm_message_t state);
17     int    (*resume)    (struct device * dev);
18 };
注册device_driver结构体:
 1 int driver_register(struct device_driver * drv)
 2 {
 3     if ((drv->bus->probe && drv->probe) ||
 4         (drv->bus->remove && drv->remove) ||
 5         (drv->bus->shutdown && drv->shutdown)) {
 6         printk(KERN_WARNING "Driver \'%s\' needs updating - please use bus_type methods\\n", drv->name);
 7     }
 8     klist_init(&drv->klist_devices, NULL, NULL);
 9     return bus_add_driver(drv);
10 }
 

3 写代码

3.1框架

(1)分配、设置、注册一个platform_device/platform_driver结构体

(2)按照led.c的框架来构建

3.2 源代码

 1 #include <linux/module.h>
 2 #include <linux/version.h>
 3 
 4 #include <linux/init.h>
 5 
 6 #include <linux/kernel.h>
 7 #include <linux/types.h>
 8 #include <linux/interrupt.h>
 9 #include <linux/list.h>
10 #include <linux/timer.h>
11 #include <linux/init.h>
12 #include <linux/serial_core.h>
13 #include <linux/platform_device.h>
14 
15 static struct resource myled_dev_resource[] = {
16     [0] = {
17         .start = 0x56000050,
18         .end   = 0x56000050 + 8 - 1,
19         .flags = IORESOURCE_MEM,
20     },
21     [1] = {
22         .start = 6,
23         .end   = 6,
24         .flags = IORESOURCE_IRQ,
25     }
26 };
27 
28 
29 static void myled_dev_release(struct device * dev)
30 {
31 }
32 
33 
34 static struct platform_device myled_dev = {
35     .name          = "myled",
36     .id       = -1,
37     .num_resources      = ARRAY_SIZE(myled_dev_resource),
38     .resource      = myled_dev_resource,
39     .dev              = {
40         .release   = myled_dev_release,
41     }
42 };
43 
44 static int myled_dev_init(void)
45 {
46     platform_device_register(&myled_dev);
47     return 0;
48 }
49 
50 static void myled_dev_exit(void)
51 {
52     platform_device_unregister(&myled_dev);
53 }
54 
55 module_init(myled_dev_init);
56 module_exit(myled_dev_exit);
57 
58 MODULE_LICENSE("GPL");
myled_dev.c
  1 #include <linux/module.h>
  2 #include <linux/version.h>
  3 
  4 #include <linux/init.h>
  5 #include <linux/fs.h>
  6 #include <linux/interrupt.h>
  7 #include <linux/irq.h>
  8 #include <linux/sched.h>
  9 #include <linux/pm.h>
 10 #include <linux/sysctl.h>
 11 #include <linux/proc_fs.h>
 12 #include <linux/delay.h>
 13 #include <linux/platform_device.h>
 14 #include <linux/input.h>
 15 #include <linux/irq.h>
 16 #include <asm/uaccess.h>
 17 #include <asm/io.h>
 18 
 19 
 20 
 21 static struct class *g_ptMyledCls;
 22 static struct class_device    *g_ptMyledClsDev;
 23 static int g_iPin;
 24 
 25 volatile unsigned long *gpiocon = NULL;
 26 volatile unsigned long *gpiodat = NULL;
 27 
 28 
 29 static int myled_open(struct inode *inode, struct file *file)
 30 {
 31     //printk("first_drv_open\\n");
 32     /* 配置GPF4,5,6为输出 */
 33     *gpiocon &= ~(0x3<<(g_iPin*2)) ;
 34     *gpiodat |= (0x1<<(g_iPin*2)) ;
 35     return 0;
 36 }
 37 
 38 static ssize_t myled_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
 39 {
 40     int val;
 41 
 42     //printk("first_drv_write\\n");
 43 
 44     copy_from_user(&val, buf, count); //    copy_to_user();
 45 
 46     if (val == 1)
 47     {
 48         // 点灯
 49         *gpiodat &= ~(1<<g_iPin);
 50     }
 51     else
 52     {
 53         // 灭灯
 54         *gpiodat |= (1<<g_iPin);
 55     }
 56     
 57     return 0;
 58 }
 59 
 60 
 61 static struct file_operations myled_fops = {
 62     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
 63     .open    =  myled_open,     
 64     .write      =    myled_write,       
 65 };
 66 
 67 
 68 static int g_iMajor;
 69 
 70 static int myled_probe(struct platform_device *dev)
 71 {    
 72     struct resource *tRes;
 73     tRes = platform_get_resource(dev, IORESOURCE_MEM, 0);
 74     gpiocon = ioremap(tRes->start, tRes->end - tRes->start +1);
 75     gpiodat = gpiocon + 1;
 76 
 77     tRes    = platform_get_resource(dev, IORESOURCE_IRQ, 0);
 78     g_iPin = tRes->start;
 79 
 80     printk("myled_probe, found led\\n");
 81     
 82     g_iMajor = register_chrdev(0, "myled", &myled_fops); // 注册, 告诉内核
 83     g_ptMyledCls = class_create(THIS_MODULE, "myled");
 84 
 85     g_ptMyledClsDev = class_device_create(g_ptMyledCls, NULL, MKDEV(g_iMajor, 0), NULL, "myled"); /* /dev/xyz */
 86     return 0;
 87 }
 88 
 89 static int myled_remove(struct platform_device *dev)
 90 {
 91     printk("led_remove, remove led\\n");
 92 
 93     class_device_destroy(g_ptMyledCls, MKDEV(g_iMajor, 0));
 94     class_destroy(g_ptMyledCls);
 95     unregister_chrdev(g_iMajor, "myled");
 96     iounmap(gpiocon);
 97     
 98     return 0;
 99 }
100 
101 static struct platform_driver myled_driver = {
102     .probe        = myled_probe,
103     .remove        = myled_remove,
104     .driver        = {
105         .name        = "myled",
106     },
107 };
108 
109 static int myled_drv_init(void)
110 {
111     platform_driver_register(&myled_driver);
112     return 0;
113 }
114 
115 static void myled_drv_exit(void)
116 {
117     platform_driver_unregister(&myled_driver);
118 }
119 
120 
121 module_init(myled_drv_init);
122 module_exit(myled_drv_exit);
123 
124 MODULE_LICENSE("GPL");
myled_drv.c
 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <stdio.h>
 5 
 6 /* firstdrvtest on
 7   * firstdrvtest off
 8   */
 9 int main(int argc, char **argv)
10 {
11     int fd;
12     int val = 1;
13     fd = open("/dev/myled", O_RDWR);
14     if (fd < 0)
15     {
16         printf("can\'t open!\\n");
17     }
18     if (argc != 2)
19     {
20         printf("Usage :\\n");
21         printf("%s <on|off>\\n", argv[0]);
22         return 0;
23     }
24 
25     if (strcmp(argv[1], "on") == 0)
26     {
27         val  = 1;
28     }
29     else
30     {
31         val = 0;
32     }
33     
34     write(fd, &val, 4);
35     return 0;
36 }
测试程序

编辑于2017-01-09 16:36:01

 

以上是关于驱动04.平台总线驱动模型——点亮LED灯的主要内容,如果未能解决你的问题,请参考以下文章

实现点亮LED灯

i.MX6ULL驱动开发 | 24 - 基于platform平台驱动模型点亮LED

Linux 内核自带的 LED 灯驱动

单片机的IO驱动LED灯电路,需要用到三极管,求原理图,并说明

linux设备驱动模型之平台总线实践环节

点亮指路灯led