平台总线、平台设备、平台驱动

随着soc的升级,S3C2440->S3C6410->S5PV210->4412,以前的程序就得重新写一遍,做着大量的重复工作,
人们为了提高效率,发现控制器的操作逻辑(方法)是一样的,只有寄存器地址不一样,如果将与硬件有关的
代码(platform_device)和驱动代码(platform_driver)分开,升级soc后,因为驱动方式一样,
只需要修改与硬件有关的代码就可以,实现一个驱动控制多个设备。

分离:

将设备信息封装成 platform_device,将驱动信息封装成 platform_driver,并为各自起名称,
然后将 platform_device 中的 struct device 和 platform_driver 中的 struct device_driver 分别注册到设备链表和驱动链表中。

int platform_device_register(struct platform_device *pdev)

  return platform_device_add(pdev);

    ret = device_add(&pdev->dev);

int platform_driver_register(struct platform_driver *drv)

  return driver_register(&drv->driver);

    ret = bus_add_driver(drv);

合并:

在系统每注册一个设备(驱动)时,平台总线会找与之匹配的驱动(设备),匹配原则是名称相同。

装载(insmod)时设备和驱动没有顺序,卸载(rmmod)时必须先卸载设备文件,因为卸载设备会调用驱动中的 remove 函数。

// 下面的“|”表示包含于上一个之中
// 描述设备的信息
struct platform_device {const char    * name;                    // 用于和platform_driver进行匹配的名字--自定义int        id;                      // 一般直接填-1,区分不同的控制组struct device    dev;                    // 父类|void    (*release)(struct device *dev);        // 设备卸载时调用的函数void    *platform_data;                // 匹配后传递的自定义数据... ...u32        num_resources;                // 资源的个数struct resource    * resource;                 // 描述资源信息|    resource_size_t start;                // 起始位置resource_size_t end;                // 结束位置const char *name;                 // 自定义unsigned long flags;                 // 区分不同的资源,一般是 内存或者中断资源... ...};
// 描述设备的操作方法
struct platform_driver {int (*probe)(struct platform_device *);                // 设备和驱动匹配后调用的函数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 char        *name;                // 该名字可以用于匹配,但比id_table中的name优先级低// 此名称在 /sys/bus/platform/drivers/xxx... ...const struct platform_device_id *id_table;|char name[PLATFORM_NAME_SIZE];                // 用于和platform_device的名字进行匹配,优先级高
};
// 平台总线
struct bus_type platform_bus_type = {.name        = "platform",.dev_attrs    = platform_dev_attrs,.match        = platform_match,                // 用于匹配,此函数可以看出匹配名称的优先级.uevent        = platform_uevent,.pm        = &platform_dev_pm_ops,
};

// 注册 platform_devive

int platform_device_register(struct platform_device *pdev);

// 注销 platform_devive

void platform_device_unregister(struct platform_device *pdev);

// 注册 platform_driver

int platform_driver_register(struct platform_driver *drv);

// 注销 platform_driver

void platform_driver_unregister(struct platform_driver *drv);

// 批量注册pdev

int platform_add_devices(struct platform_device **devs, int num);

获取资源的接口:

// 通过类型和编号获取资源

// 参数1:pdev

// 参数2:获取的资源类型

// 参数3:获取的资源编号

struct resource *platform_get_resource(struct platform_device *dev,unsigned int type, unsigned int num);

// 通过类型和名称获取资源

// 参数3:获取资源的名称

struct resource * platform_get_resource_byname(struct platform_device * dev,unsigned int type,const char * name);

// 通过编号获取中断资源

int platform_get_irq(struct platform_device * dev,unsigned int num);

// 通过名称获取中断资源

int platform_get_irq_byname(struct platform_device * dev,const char * name);

plat_led_dev.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>#include "plat_led.h"#define GPL2_0        0x11000100
#define GP_SIZE        8// 平台自定义数据,与硬件相关
struct regled led_reg = {.ctl_clr = 0x0f,.ctl_set = 0x01,.dat_clr = 0x01,.dat_set = 0x01,
}; static struct resource led_res[] = {[0] = {.start = GPL2_0,.end = GPL2_0 + GP_SIZE - 1,.name = "led0",.flags = IORESOURCE_MEM,},[1] = {.start = 888,.end = 888,.name = "virt_irq",.flags = IORESOURCE_IRQ,},
};void plat_led_release(struct device *dev)
{// 为了卸载模块时不报错误
}struct platform_device led_pdev = {.name = "plat_led",.id = -1,.dev = {.platform_data = &led_reg,.release = plat_led_release,},.num_resources = ARRAY_SIZE(led_res),.resource = led_res,
};static int __init plat_led_dev_init(void)
{platform_device_register(&led_pdev);return 0;
}static void __exit plat_led_dev_exit(void)
{platform_device_unregister(&led_pdev);
}module_init(plat_led_dev_init);
module_exit(plat_led_dev_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Aaron Lee");

plat_led_drv.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/platform_device.h>#include <asm/io.h>
#include <asm/uaccess.h>#include "plat_led.h"struct samsung *platled;static int platled_open(struct inode *inode, struct file *fops)
{writeb(readb(platled->reg_base+4) & (~platled->reg->dat_clr), platled->reg_base+4);return 0;
}static int platled_close(struct inode *inode, struct file *fops)
{return 0;
}static ssize_t platled_write(struct file *fops, const char __user *buf, size_t size, loff_t *fpos)
{int value;
//暂时忽略返回值copy_from_user(&value, buf, size);if (value)writeb((readb(platled->reg_base+4) & (~platled->reg->dat_clr)) | platled->reg->dat_set, platled->reg_base+4);elsewriteb(readb(platled->reg_base+4) & (~platled->reg->dat_clr), platled->reg_base+4);return 0;
}const struct file_operations platled_fops = {.open = platled_open,.release = platled_close,.write = platled_write,
};static int led_register(void)
{int ret;platled = kmalloc(sizeof(struct samsung), GFP_KERNEL);if (platled == NULL){printk("kmalloc fail!\n");return -ENOMEM;}platled->major = register_chrdev(0, "plat_led", &platled_fops);if (platled->major < 0){printk("register_chrdev fail!\n");ret = -EFAULT;goto chrdev_err;}platled->cls = class_create(THIS_MODULE, "plat_led");if (platled->cls < 0){printk("class_create fail!\n");ret = -EFAULT;goto class_err;}platled->dev = device_create(platled->cls, NULL, MKDEV(platled->major, 0), NULL, "plat_led");if (platled->dev < 0){printk("device_create fail!\n");ret = -EFAULT;goto device_err;}return 0;device_err:class_destroy(platled->cls);class_err:unregister_chrdev(platled->major, "plat_led");chrdev_err:kfree(platled);return ret;
}static void led_unregister(void)
{device_destroy(platled->cls, MKDEV(platled->major, 0));class_destroy(platled->cls);unregister_chrdev(platled->major, "plat_led");kfree(platled);
}int plat_led_probe(struct platform_device *pdev)
{int ret;struct resource *res;ret = led_register();if (ret < 0){printk("plat_led_probe fail\n");return -EFAULT;}res = platform_get_resource(pdev, IORESOURCE_MEM, 0);if (res == NULL){printk("platform_get_resource fail\n");return -ENODEV;}
// 获取平台自定义数据platled->reg = pdev->dev.platform_data;platled->reg_base = ioremap(res->start, resource_size(res));writel((readl(platled->reg_base) & (~platled->reg->ctl_clr)) | platled->reg->ctl_set, platled->reg_base);return 0;
}int plat_led_remove(struct platform_device *pdev)
{iounmap(platled->reg_base);led_unregister();return 0;
}const struct platform_device_id led_id_table[]  = {{"plat_led", 0x1234}, //第二个整数是自定义
};struct platform_driver led_pdrv = {.probe = plat_led_probe,.remove = plat_led_remove,.driver = {.name    = "red_led",},.id_table = led_id_table,// name用于匹配
};static int __init plat_led_drv_init(void)
{platform_driver_register(&led_pdrv);return 0;
}static void __exit plat_led_drv_exit(void)
{platform_driver_unregister(&led_pdrv);
}module_init(plat_led_drv_init);
module_exit(plat_led_drv_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Aaron Lee");

 plat_led.h

#ifndef __PLAT_LED_H_
#define __PLAT_LED_H_struct regled {unsigned long ctl_clr;unsigned long ctl_set;unsigned long dat_clr;unsigned long dat_set;
};struct samsung {int major;struct class *cls;struct device *dev;struct regled *reg;void *reg_base;
};#endif

Linux platform相关推荐

  1. linux驱动模型开发——linux platform总线机制讲解与实例开发

    1.概述: 通常在Linux中,把SoC系统中集成的独立外设单元(如:I2C.IIS.RTC.看门狗等)都被当作平台设备来处理. 从Linux2.6起,引入了一套新的驱动管理和注册机制:Platfor ...

  2. Linux Platform Device and Driver

    从 Linux 2.6 起引入了一套新的驱动管理和注册机制 :Platform_device 和 Platform_driver . Linux 中大部分的设备驱动,都可以使用这套机制 , 设备用 P ...

  3. [linux]platform总线机制与wtd驱动开发

    Linux之platform总线机制与wtd驱动开发 1.概述: 通常在Linux中,把SoC系统中集成的独立外设单元(如:I2C.IIS.RTC.看门狗等)都被当作平台设备来处理. 从Linux2. ...

  4. linux platform匹配机制,Linux驱动中的platform总线详解

    platform总线是学习linux驱动必须要掌握的一个知识点. 一.概念 嵌入式系统中有很多的物理总线:I2c.SPI.USB.uart.PCIE.APB.AHB linux从2.6起就加入了一套新 ...

  5. Linux platform总线(1):总体框架

    PlatForm设备驱动: 一.platform总线.设备与驱动 1.一个现实的Linux设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI.USB.I2 C.SPI等的设备而言,这自然不是问 ...

  6. [platform]linux platform device/driver(三)--Platform Device和Platform_driver注册过程之代码对比...

    转自:http://blog.csdn.net/thl789/article/details/6723350 Linux 2.6的设备驱动模型中,所有的device都是通过Bus相连.device_r ...

  7. Linux platform驱动模型

    /************************************************************************************ *本文为个人学习记录,如有错 ...

  8. linux platform 驱动模型分析

    一. 概述     platform设备和驱动与linux设备模型密切相关.platform在linux设备模型中,其实就是一种虚拟总线没有对应的硬件结构.它的主要作用就是管理系统的外设资源,比如io ...

  9. 嵌入式linux platform设备驱动

    对于linux这样一个成熟,庞大,复杂的操作系统,代码的重用性非常重要,否则的话会在linux内核中存在大量无意义的重复代码.尤其是驱动程序,因为驱动程序占用了 Linux内核代码量的大头,如果不对驱 ...

  10. Linux platform 设备驱动实验-基于正点原子IMX6ULL开发板

    我们以前的设备驱动都非常的简单,都是对IO进行最简单的读写操作.像I2C. SPI.LCD 这些复杂外设的驱动就不能这么去写了,Linux 系统要考虑到驱动的可重用性,因此提出了驱动的分离与分层这样的 ...

最新文章

  1. shell批量增删改查百库百表(mysql)
  2. 2016年定制维护组总结-历程回溯
  3. matlab子函数调用变量,matlab中,怎么样用function自定义函数调用另一个函数名为输入?...
  4. 字符串GZIP压缩解压
  5. r语言简介_R语言简介
  6. php大数除法保留精度问题
  7. 【拾贝】hive unoin all map数爆增
  8. 大庆油田真正解决了吃饭问题
  9. 阿里云Centos6数据盘扩容的问题处理
  10. Android音视频全面介绍与代码实践之音效(四)
  11. 【微机原理与接口 7】—— 常用指令分析4 (串操作指令剖析)
  12. 【中兴交换机MC-LAG配置】
  13. 中国塔格糖行业市场供需与战略研究报告
  14. R柱状图,叠图(排序)
  15. hdu6097—Mindis(计算几何)
  16. 4.操作卡片和OBU的指令以及流程
  17. 实战与分享更换域名的SEO情况
  18. 设计模式 | 装饰模式
  19. 软件智能:aaas系统 度量衡及文法规则
  20. 大专计算机办公应用,计算机办公软件应用: 高级

热门文章

  1. Ajax请求session超时解决办法
  2. 自动驾驶(三十二)---------车辆行人识别
  3. Window API ShowWindow
  4. 【C++】编程实现复数运算
  5. 根据年份和月份来计算天数
  6. jQuery使用ajaxSubmit()提交表单以及AjaxSubmit的一些用法
  7. 祝贺!中国战队EDG夺冠
  8. js取得当前url,javascript获取当前页面url值,js获取域名
  9. 可达性分析算法-针对的对象
  10. DAX 第八篇:【翻译】数据沿袭(Data Lineage )