• 驱动_Platform平台总线


    platform

    作用:实现硬件的操作方法和设备信息的分离,便于SOC控制器驱动的升级

    <结构体>

    platform_driver {

      struct platform_driver {

      int (*probe)(struct platform_device *); //实现初级驱动中加载函数中的代码

      (1.实例化全局对象-----kzalloc)

      (2.申请设备号 --- register_chrdev)

      (3.自动创建设备节点 ---- class_create,device_create)

      (4.拿到pdev中的资源)

      (5.初始化硬件------ ioremap)

      (6.实现file_opretions)

      int (*remove)(struct platform_device *); //实现初级驱动中卸载函数中的代码

      void (*shutdown)(struct platform_device *);   // 电源管理

      int (*suspend)(struct platform_device *, pm_message_t state);    // 电源管理

      int (*resume)(struct platform_device *);      // 电源管理

      struct device_driver driver;

      const struct platform_device_id *id_table; //与pdev中的名称匹配

    }

    platform_bus_type {

      const char *name;

      struct bus_attribute *bus_attrs;

      struct device_attribute *dev_attrs;

      struct driver_attribute *drv_attrs;

      int (*uevent)(struct device *dev, struct kobj_uevent_env *env);

      int (*probe)(struct device *dev);

      int (*remove)(struct device *dev);

      void (*shutdown)(struct device *dev);

      int (*suspend)(struct device *dev, pm_message_t state);

      int (*resume)(struct device *dev);

      const struct dev_pm_ops *pm;

      struct subsys_private *p;

      int (*match)(struct device *dev, struct device_driver *drv); // 匹配方法-------------↓

    }                                                              ↓            

    static int platform_match (struct device *dev, struct device_driver *drv){
        struct platform_device *pdev = to_platform_device(dev);
        struct platform_driver *pdrv = to_platform_driver(drv);

        /* Attempt an OF style match first */
        if (of_driver_match_device(dev, drv))
        return 1;

        /* Then try to match against the id table */
        if (pdrv->id_table)
        return platform_match_id(pdrv->id_table, pdev) != NULL;

        /* fall-back to driver name match */
        return (strcmp(pdev->name, drv->name) == 0);
      }

    platform_device {

      const char * name; //名字,用于与pdrv匹配

      int id; //表示不同寄存器组的编号,一般可以填:-1

      struct device dev; //父类    ——————>  void *platform_data;    /指向自定义数据的指针

      const struct platform_device_id *id_entry;/* MFD cell pointer */

      struct mfd_cell *mfd_cell;/* arch specific additions */

      struct pdev_archdata archdata;

      u32 num_resources; //资源的个数

      struct resource * resource; //资源的详细信息----描述中断或者内存地址————↓

    }                                      ↓

    struct  resource {
      resource_size_t start; //如果资源为地址,则为起始地址,如果是中断,则表示中断号
      resource_size_t end; //如果资源为地址,则为最后一个字节的地址,如果是中断,则表示中断号
      const char *name;
      unsigned long flags;
      struct resource *parent, *sibling, *child;

    };

    <函数>

      注册:
       int platform_driver_register(struct platform_driver *);
       void platform_driver_unregister(struct platform_driver *);

       代码示例:https://www.cnblogs.com/panda-w/p/10991957.html

    <笔记>

    1. 总线匹配成功自动调用pdrv中的probe方法;

    2. pdrv可以一对多,只要名字相同均可匹配

    3. 什么时候用平台总线:------将操作和数据(资源,自定义数据)分离

      1,只要有设备地址和中断都可以用
      2,如果驱动需要咋多个平台总升级使用  

    4. 查看平台总线:ls /sys/bus/platform/devices/  (内核启动自动调用,开机批量注册pdev)

    5. 因为probe 和 remove都在pdrv实现,卸载驱动时,要先卸载pdev,然后再卸载pdrv

    6. gpio口的寄存器初始化操作方式:   

        看原理图 ----> 看芯片手册 ------> 寄存器地址 --------> ioremap(地址映射)
        *gpc0_conf &= ~(0xff<<12);
        *gpco_conf |= 0x11<<12;

        

      1, 直接地址操作
        volatile unsigned long *gpc0conf;
        volatile unsigned long *gpc0data;

        gpc0conf = ioremap(地址, 长度);
        gpc0conf = gpc0data + 1; 

      2, 内核提供的库函数操作
        __raw_readl(地址)       __raw_writel(value, 地址);

        unsigned long value = __raw_readl(led_reg_base);
        value &= ~(0xff<<12);
        value |= (0x11<<12); //配置成输出功能
        __raw_writel(value, led_reg_base);

    7. 内核提供的接口: readl/writel ------ __raw_readl       __raw_writel   

        static unsigned int __raw_readl(unsigned int ptr) //参数: ptr ----- 地址:address
        {
          return *((volatile unsigned int *)ptr);
        }

        

        static void __raw_writel(unsigned int value, unsigned int ptr) //参数: value--写入的数据,ptr---地址:address
        {
          *((volatile unsigned int *)ptr) = value;
        }

    8. 编程思想:      

    第一步:设计自定义数据类型:                        
      struct led_platdata{      //设计一个平台总线的自定义数据类型
       char *name;
       int shift; //移位数
       int conf_reg_data; //配置寄存器的值
       int conf_reg_clear; //配置寄存器的值清空
       int data_reg; //数据寄存器的值
      };
    第二步:在pdev中初始化自定义数据
      struct led_platdata led_pdata = {
       .name = "gpc0_3/4",
       .shift = 3,
       .conf_reg_data = 0x11,
       .conf_reg_clear = 0xff,
       .data_reg = 0x3,

      };
    第三步:
      struct platform_device led_pdev = {
       .name = "s5pv210_led",
       .id = -1,
       .num_resources = ARRAY_SIZE(led_resource),
       .resource = led_resource,
       .dev = {
       .platform_data = &led_pdata, //将自定义数据赋给pdev的父类中的:platform_data
       .release = led_dev_release,
      },

    9. 平台总线默认内核就自动帮我们创建,使用平台总线编写驱动,将一个驱动分成两个模块:pdev,pdrv

    10.  杂项设备的注册: 默认的主设备号是10  

      struct miscdevice {
       int minor; //次设备--自由定义--0-255之间
       const char *name; //设备节点的名字
       const struct file_operations *fops; //文件操作接口
       struct list_head list; //链表
      };

    Stay hungry, stay foolish 待续。。。
  • 相关阅读:
    C#多线程操作界面控件的解决方案
    InvokeHelper,让跨线程访问/修改主界面控件不再麻烦
    .netCF中后台多线程与UI界面交互的冻结问题
    c#设计模式第一天
    C#代理
    界面
    第一章面向对象涉及原则
    C# 为webBrowser设置代理
    设计模式等
    下载: Intel® 64 and IA32 Architectures Software Developer Manuals
  • 原文地址:https://www.cnblogs.com/panda-w/p/10922753.html
Copyright © 2020-2023  润新知