PlatformBus总线驱动

一、什么是platformBUS

  platform总线是一种虚拟的总线,并不存在物理实物,其设计原因是为了保证Linux设备和驱动模型的统一性(部分设备挂载在对应总线下与cpu通信,部分设备不依附总线模型)

  把不依附总线模型的设备统一挂载到platform总线之下

  模型如下图

  

 

 

 二、总线框架原理

   在总线设备、驱动模型中,需要关心总线、设备和驱动这三个实体,总线将设备和驱动绑定

   在系统设备注册时,寻找与之匹配的驱动,匹配由总线完成。

   在系统注册驱动时,寻找与之匹配的设备,匹配由总线完成。

  总线模型的驱动由两个部分组成,描述设备相关的结构体和描述驱动相关的结构体

  与传统驱动代码比较,总线型交由内核统一管理,提高了代码的可移植性和安全性

三、platform总线和设备树

  当向系统注册设备时,我们可以通过调用platform_device_register函数,也可以通过修改设备树文件,因为总线类型由内核管理,内核会解析Dtb文件,完成platform device的创建

 

四、程序框架

  三个对象 Bus、driver、device

  其中Bus 对象一般不需要我们创建,由系统创建,driver对象和device对象分别用两个结构体来描述

  kernel在初始化阶段会创建platform框架,其调用路径为

  

/*
*start_kernel -> reset_init -> do_basic_setup -> driver_init 
*在driver_init中完成paltform总线的初始化
*/

void __init driver_init(void)
{
    /* These are the core pieces */
    devtmpfs_init();
    devices_init();
    buses_init();
    classes_init();
    firmware_init();
    hypervisor_init();

    /* These are also core pieces, but must come after the
     * core core pieces.
     */
    platform_bus_init();
    system_bus_init();
    cpu_dev_init();
    memory_dev_init();
}

 

  驱动框架

  1. 注册一个paltform_driver  
  2. 注册设备号, 并注册file_operations结构体  -----》 为用户提供一个设备标识,同时提供系统调用的接口
  3. 创建设备节点 ----- 》 class_create

  代码示例:

struct cdev * led_cdev = NULL;
dev_t devno;
static
struct file_operations fops = { .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write }
static int led_probe(struct platform_device* pdev)
{
  //申请设备号,创建设备节点
  alloc_chrdev_region(&devno, 0, 1, "led")
  led_cdev = cdev_alloc();
  cdev_init(led_cdev, &fops);
  cdev_add(led_cdev, devno, dev_count);
  
  //创建设备节点
  led_class = class_create(THIS_MODULE, "led");
  class_device_create(led_class, NULL, devno, NULL, "led");
  
}
static struct platform_driver led_driver = { .probe = led_proble, .remove = led_remov, .driver = { .owner = THIS_MODULE, .name = "led", } } static int __init platform_led_init(void) { return platform_driver_register(&led_driver); } static void __exit platform_led_exit(void) { platform_driver_unregister(&mvb_driver); } module_init(platform_led_init); module_exit(platform_led_exit); MODULE_LICENSE("GPL");

 

    4.初始化硬件  -------》 ioremap(地址)   地址从设备类型结构体获取

    5.实现系统调用

  ioremap映射内存地址,以及对系统调用的实现,和cdev实现的驱动程序其实都相同的

 

设备程序编写流程

  对于设备程序,我们要主要关心的时platform_device 结构,该结构描述了设备相关的信息,根据查询用户手册,得到设备的一些硬件资源信息

  然后通过platform_device_register 函数注册进内核

  platform_device 结构体

struct platform_device {
     const char* name;                 //设备名称   
     int id;                //设备编号
     struct device dev;
     u32 num_resources;               //设备使用各类资源的数量    
     struct resource* resource;      //设备使用的资源
     struct platform_device_id *id_entry;
    
}    

resource结构体

struct resource {
 const char *name;
 unsigned long start, end;
 unsigned long flags;
 struct resource *parent, *sibling, *child;
};

 

代码示例

#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/string.h>

struct resource    mvb_resource[] = {

    [0] = {
        .start    = 0x44E07000,
        .end    = 0x44E08000,
        .flags    = IORESOURCE_MEM,
    },

    [1] = {
        .start    = 0x4804C000,
        .end    = 0x4804D000,
        .flags     = IORESOURCE_MEM,
    },

    [2] = {
        .start    = 0x481AC000,
        .end     = 0x481AD000,
        .flags    = IORESOURCE_MEM,
    },

    [3] = {
        .start    = 0x481AE000,
        .end    = 0x481AF000,
        .flags    = IORESOURCE_MEM,
    }

};

static void platform_device_mvb_release(struct device *dev)
{

}

struct platform_device     mvb_device = {
    .name             = "mvb",
    .id             = -1,
    .num_resources     = ARRAY_SIZE(mvb_resource),
    .resource        = mvb_resource,
    .dev = {
        .release = platform_device_mvb_release,
    }
};

static int __init mvb_device_init(void)
{
    int ret;
    ret = platform_device_register(&mvb_device);
    if(ret){
        printk("platform_device_region err\n");
        return -EBUSY;
    }
    return 0;
}

static void __exit mvb_device_exit(void)
{
    platform_device_unregister(&mvb_device);
}

module_init(mvb_device_init);
module_exit(mvb_device_exit);
MODULE_AUTHOR("from Chen Xin");
MODULE_LICENSE("GPL");

 

posted @ 2020-12-31 15:54  是小陈同学呀  阅读(377)  评论(0)    收藏  举报