Platform机制
来源:互联网 发布:python exit status 2 编辑:程序博客网 时间:2024/06/04 14:50
Platform机制
Platform总线Linux中一种虚拟总线。platform机制的本身使用并不复杂,由两部分组成:platform_device和platform_driver
Platform 驱动与传统的设备驱动模型相比,优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时使用统一的接口,这样提高了程序的可移植性。
通过platform机制开发底层设备驱动的流程:
定义platform_device->注册platform_device->定义platform_driver->注册platform_driver
Platform机制使用了bus driver device模型,device是硬件相关代码,driver是比较稳定的代码,类似输入子系统里面,input.c是提供给上层的统一接口,buttons.c是硬件相关代码<-分离->evdev.c是纯软件比较稳定的代码。
1 分析drivers\base\platform.c
platform总线的注册在drivers\base\init.c中调用
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();}
int __init platform_bus_init(void){int error;early_platform_cleanup();error = device_register(&platform_bus); // 总线也是一个设备if (error)return error;error = bus_register(&platform_bus_type); // 注册platform总线if (error)device_unregister(&platform_bus);return error;}
platform机制是基于Linux总线设备驱动模型实现的
struct bus_type platform_bus_type = {.name= "platform",.dev_attrs= platform_dev_attrs, // 总线属性.match= platform_match, // 用于匹配platform device和platform driver.uevent= platform_uevent,.pm= &platform_dev_pm_ops, // 电源管理相关};
struct device platform_bus = {.init_name= "platform",};
static struct device_attribute platform_dev_attrs[] = {__ATTR_RO(modalias),__ATTR_NULL,};#define __ATTR_RO(_name) { \.attr= { .name = __stringify(_name), .mode = 0444 },\.show= _name##_show,\}static ssize_t modalias_show(struct device *dev, struct device_attribute *a, char *buf){struct platform_device*pdev = to_platform_device(dev);int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;}
根据name来匹配
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);}
当环境变化时调用(设备拔插等)
static int platform_uevent(struct device *dev, struct kobj_uevent_env *env){struct platform_device*pdev = to_platform_device(dev);int rc;/* Some devices have extra OF data and an OF-style MODALIAS */rc = of_device_uevent(dev,env);if (rc != -ENODEV)return rc;// 添加值到环境buffer中add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX,(pdev->id_entry) ? pdev->id_entry->name : pdev->name);return 0;}
2. Platform平台设备
平台设备使用Struct Platform_device来描述:
struct platform_device { const char *name; /*设备名*/ int id; /*设备编号,配合设备名使用*/ struct device dev; u32 num_resources; struct resource *resource; /*设备资源*/}
2.1 Platform_device的分配使用
struct platform_device *platform_device_alloc(const char *name, int id)
参数:
name: 设备名
id: 设备id,一般为-1
2.2 注册平台设备
int platform_device_register(struct platform_device *pdev)
会调用device_add,主要操作有:
1. 把device放入bus的dev链表
2. 从bus的drv链表中取出每一个drv,用bus的match函数判断drv是否支持该dev
3. 若可以支持,调用drv的probe函数
详细可以参考:device_add流程
int platform_device_register(struct platform_device *pdev){device_initialize(&pdev->dev);return platform_device_add(pdev); // 里面会调用device_add}
2.3 平台设备资源
使用struct resource来描述:
struct resource { resource_size_t start; //资源的起始物理地址 resource_size_t end; //资源的结束物理地址 const char *name; //资源的名称 unsigned long flags; //资源的类型,比如MEM,IO,IRQ类型 struct resource *parent, *sibling, *child; //资源链表指针}
2.4 获取资源
struct resource *platform_get_resource(struct platform_device*dev, unsigned int type, unsigned int num)
参数:
dev: 资源所属的设备
type: 获取的资源类型
num: 获取的资源数
3 Platform平台驱动
使用struct platform_driver 描述:
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 (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver;}
3.1 平台驱动注册
int platform_driver_register(struct platform_driver *)
1. 把drv放入bus的drv链表
2. 从bus的dev链表中取出每一个dev,用bus的match函数判断该drv是否支持dev
3. 若可以支持,调用drv的probe函数
int platform_driver_register(struct platform_driver *drv){drv->driver.bus = &platform_bus_type;if (drv->probe)drv->driver.probe = platform_drv_probe;if (drv->remove)drv->driver.remove = platform_drv_remove;if (drv->shutdown)drv->driver.shutdown = platform_drv_shutdown;return driver_register(&drv->driver); // 里面会调用driver_find(drv->name, drv->bus);遍历设备}
什么时候驱动回去遍历设备,看能否处理?
注册驱动时或注册设备时都会去相互遍历匹配
驱动和设备怎么匹配呢?
根据name来匹配滴
通常会在probe函数里面创建设备节点,方便上层调用
4 实例
led_drv.c
/* 分配/设置/注册一个platform_driver */#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/sched.h>#include <linux/pm.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <linux/platform_device.h>#include <linux/input.h>#include <linux/irq.h>#include <asm/uaccess.h>#include <asm/io.h>static int major;static struct class *cls;static volatile unsigned long *gpio_con;static volatile unsigned long *gpio_dat;static int pin;static int led_open(struct inode *inode, struct file *file){//printk("first_drv_open\n");/* 配置为输出 */*gpio_con &= ~(0x3<<(pin*2));*gpio_con |= (0x1<<(pin*2));return 0;}static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){int val;//printk("first_drv_write\n");copy_from_user(&val, buf, count); //copy_to_user();if (val == 1){// 点灯*gpio_dat &= ~(1<<pin);}else{// 灭灯*gpio_dat |= (1<<pin);}return 0;}static struct file_operations led_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = led_open, .write=led_write, };static int led_probe(struct platform_device *pdev){struct resource*res;/* 根据platform_device的资源进行ioremap */res = platform_get_resource(pdev, IORESOURCE_MEM, 0);gpio_con = ioremap(res->start, res->end - res->start + 1);gpio_dat = gpio_con + 1;res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);pin = res->start;/* 注册字符设备驱动程序 */printk("led_probe, found led\n");major = register_chrdev(0, "myled", &led_fops);cls = class_create(THIS_MODULE, "myled");class_device_create(cls, NULL, MKDEV(major, 0), NULL, "led"); /* /dev/led */// 后续新的内核版本使用的是class_create()和device_create()return 0;}static int led_remove(struct platform_device *pdev){/* 卸载字符设备驱动程序 *//* iounmap */printk("led_remove, remove led\n");class_device_destroy(cls, MKDEV(major, 0));class_destroy(cls);unregister_chrdev(major, "myled");iounmap(gpio_con);return 0;}struct platform_driver led_drv = {.probe= led_probe,.remove= led_remove,.driver= {.name= "myled",}};static int led_drv_init(void){platform_driver_register(&led_drv);return 0;}static void led_drv_exit(void){platform_driver_unregister(&led_drv);}module_init(led_drv_init);module_exit(led_drv_exit);MODULE_LICENSE("GPL");led_dev.c
#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/interrupt.h>#include <linux/list.h>#include <linux/timer.h>#include <linux/init.h>#include <linux/serial_core.h>#include <linux/platform_device.h>/* 分配/设置/注册一个platform_device */static struct resource led_resource[] = { [0] = { .start = 0x56000010, /* TQ2440的LED是GPB5,6,7,8, GPBCON地址是0x56000010 */ .end = 0x56000010 + 8 - 1, .flags = IORESOURCE_MEM, }, [1] = { .start = 5, /* LED1 */ .end = 5, .flags = IORESOURCE_IRQ, }};static void led_release(struct device * dev){}static struct platform_device led_dev = { .name = "myled", .id = -1, .num_resources = ARRAY_SIZE(led_resource), .resource = led_resource, .dev = { .release = led_release, },};static int led_dev_init(void){platform_device_register(&led_dev);return 0;}static void led_dev_exit(void){platform_device_unregister(&led_dev);}module_init(led_dev_init);module_exit(led_dev_exit);MODULE_LICENSE("GPL");
阅读全文
0 0
- platform机制
- Platform机制
- Linux platform 机制探讨
- platform内核机制
- Linux platform机制
- Linux内核中的platform机制
- Linux内核中的platform机制
- Linux驱动的platform机制
- Linux内核中的platform机制
- Linux内核中的platform机制
- Linux内核中的platform机制
- Linux驱动的platform机制
- Linux驱动的platform机制
- Linux驱动的platform机制 .
- Linux驱动的platform机制
- Linux驱动的platform机制
- Linux驱动的platform机制
- Linux驱动的platform机制
- Windows下使用命令安装Python的scipy库出错的解决
- Flask的路由和视图函数
- 八大排序算法之直接插入排序和希尔排序
- 一个关于Booth算法的文章
- Win10下Free Pascal IDE的BUG
- Platform机制
- Eclipse中导入项目前有红叉提示但是项目内容不报错解决办法
- 项目报错:Non-resolvable parent POM for com.taotao
- matlab学习笔记——视频处理
- 链表面试题:判断两个链表是否相交
- java SAX解析XML
- TensotFlow 应用实例:03-在TensotFlow中使用Variable变量
- C++类的默认继承方式为保护继承
- 欧拉函数的简单应用