• 驱动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
    ", 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
    ");
     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
    ");
     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
    ");
     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
    ");
     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!
    ");
    17     }
    18     if (argc != 2)
    19     {
    20         printf("Usage :
    ");
    21         printf("%s <on|off>
    ", 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

  • 相关阅读:
    前端开发浏览器兼容问题
    pc端页面打包成安卓apk
    AJAX
    webpack
    【javascript】数据结构-集合
    【javascript】数据结构-队列
    【前端】display: box布局教程 [转]
    【前端】Flex 布局教程:语法篇 [转]
    【前端】几种实现水平垂直居中的方法总结
    【前端】jQuery选择器$()的实现原理
  • 原文地址:https://www.cnblogs.com/Lwd-linux/p/6265746.html
Copyright © 2020-2023  润新知