platform驱动分离
---恢复内容开始---
---
title: platform驱动分离
tags: linux
date: 2018/11/30 09:24:37
toc: true
platform驱动分离
框架结构
platform的bus总线结构将一个硬件驱动分为device设备与driver驱动两个部分,使用platform设备将两个联系到一起.
简单来说,就是将以前所写的驱动,将数据与算法分离,左边dev表示可变的数据,右边的driver表示稳定的算法.比如I2C/USB等总线协议可以理解为稳定的算法,具体的不同的EEPROM/led等可以理解为数据,包含了特殊的自身信息,比如io信息等.

与输入子系统联系
输入子系统是内核定义了一套统一的标准接口,而platform是将左侧的设备层分割为数据与算法


设备描述
这里的设备文件使用platform_device来描述,结构如下,总体来说可以称之为设备描述
platform_device_register注册设备文件,匹配后会调用驱动算法的probeplatform_device_unregister卸载设备- 具体数据描述如下
驱动算法
这里将其称为驱动算法,其实也是一个正常的驱动程序,区别在于可以获取到上面注册的设备文件信息.当注册设备文件或者注册驱动文件的时候,都会调用驱动算法的probe.
platform_driver_register用来注册驱动,当注册设备文件或者注册驱动文件的时候,都会调用驱动算法的probe.platform_driver_unregister用来卸载驱动platform框架中的管理结构如下:
//driver
struct platform_driver {
//函数
(*probe) //匹配到设备文件的name与driver中的name一致将会在注册时执行
(*remove) //卸载驱动出口,卸载驱动设备的时候应该也会调用
(*shutdown)
(*suspend)
(*suspend_late)
(*resume_early)
(*resume)
//结构体
struct device_driver driver
{
.name //用作匹配
}
};
probe,当有设备文件和驱动算法匹配的时候自动执行,一般用来获取资源文件信息等,注册驱动,ioremap等,可以理解为执行驱动的第一个程序了
注意:
- 这里的
platform_driver也是一个普通的驱动,可以用最原始的方式来注册驱动,创建class类,再在下面添加具体的设备文件来使用mdev机制自动创建所需要的文件. - 也可以使用输入子系统的 框架,输入子系统所需要的驱动程序需要一套约定的接口,我们可以将输入子系统中的左侧的设备驱动再分割成设备描述与驱动算法.

注册机制
驱动算法使用platform_driver_register来注册,如下:
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type; //(1)挂接到虚拟总线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;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver); //(2) 注册到driver目录下
}
从代码上看,
platform只是只是bus中的一种,挂载到platform_bus_typestruct bus_type platform_bus_type = {
.nam = "platform", //设备名称
.dev_attrs = platform_dev_attrs, //设备属性、含获取sys文件名,该总线会放在/sys/bus下
.match = platform_match, //匹配函数,成功调用driver的.probe函数
.uevent = platform_uevent, //消息传递,比如热插拔操作
.suspend = platform_suspend, //电源管理的低功耗挂起
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume, //恢复
};
可以看到匹配函数
match=platform_match,是匹配dev和driver的namestatic int platform_match(struct device * dev, struct device_driver * drv)
{
/*找到所有的device设备*/
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
driver_register()函数就是用来创建/sys/bus/platform/driver的
程序
设备文件
#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 = 0x56000050,
.end = 0x56000050 + 8 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 5,
.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");
驱动算法
/* 分配/设置/注册一个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 */
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");
测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/* led_test on
* led_test off
*/
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/led", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
if (argc != 2)
{
printf("Usage :\n");
printf("%s <on|off>\n", argv[0]);
return 0;
}
if (strcmp(argv[1], "on") == 0)
{
val = 1;
}
else
{
val = 0;
}
write(fd, &val, 4);
return 0;
}
测试
- 注册两个驱动,会自动生成文件
/sys/bus/platform/下的devices和drives生成驱动 - 测试使用
./test on点灯---恢复内容结束---
---
title: platform驱动分离
tags: linux
date: 2018/11/30 09:24:37
toc: true
platform驱动分离
框架结构
platform的bus总线结构将一个硬件驱动分为device设备与driver驱动两个部分,使用platform设备将两个联系到一起.
简单来说,就是将以前所写的驱动,将数据与算法分离,左边dev表示可变的数据,右边的driver表示稳定的算法.比如I2C/USB等总线协议可以理解为稳定的算法,具体的不同的EEPROM/led等可以理解为数据,包含了特殊的自身信息,比如io信息等.

与输入子系统联系
输入子系统是内核定义了一套统一的标准接口,而platform是将左侧的设备层分割为数据与算法


设备描述
这里的设备文件使用platform_device来描述,结构如下,总体来说可以称之为设备描述
platform_device_register注册设备文件,匹配后会调用驱动算法的probeplatform_device_unregister卸载设备- 具体数据描述如下
驱动算法
这里将其称为驱动算法,其实也是一个正常的驱动程序,区别在于可以获取到上面注册的设备文件信息.当注册设备文件或者注册驱动文件的时候,都会调用驱动算法的probe.
platform_driver_register用来注册驱动,当注册设备文件或者注册驱动文件的时候,都会调用驱动算法的probe.platform_driver_unregister用来卸载驱动platform框架中的管理结构如下://driver
struct platform_driver {
//函数
(*probe) //匹配到设备文件的name与driver中的name一致将会在注册时执行
(*remove) //卸载驱动出口,卸载驱动设备的时候应该也会调用
(*shutdown)
(*suspend)
(*suspend_late)
(*resume_early)
(*resume)
//结构体
struct device_driver driver
{
.name //用作匹配
}
};
probe,当有设备文件和驱动算法匹配的时候自动执行,一般用来获取资源文件信息等,注册驱动,ioremap等,可以理解为执行驱动的第一个程序了
注意:
- 这里的
platform_driver也是一个普通的驱动,可以用最原始的方式来注册驱动,创建class类,再在下面添加具体的设备文件来使用mdev机制自动创建所需要的文件. - 也可以使用输入子系统的 框架,输入子系统所需要的驱动程序需要一套约定的接口,我们可以将输入子系统中的左侧的设备驱动再分割成设备描述与驱动算法.

注册机制
驱动算法使用platform_driver_register来注册,如下:
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type; //(1)挂接到虚拟总线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;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver); //(2) 注册到driver目录下
}
从代码上看,
platform只是只是bus中的一种,挂载到platform_bus_typestruct bus_type platform_bus_type = {
.nam = "platform", //设备名称
.dev_attrs = platform_dev_attrs, //设备属性、含获取sys文件名,该总线会放在/sys/bus下
.match = platform_match, //匹配函数,成功调用driver的.probe函数
.uevent = platform_uevent, //消息传递,比如热插拔操作
.suspend = platform_suspend, //电源管理的低功耗挂起
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume, //恢复
};
可以看到匹配函数
match=platform_match,是匹配dev和driver的namestatic int platform_match(struct device * dev, struct device_driver * drv)
{
/*找到所有的device设备*/
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
driver_register()函数就是用来创建/sys/bus/platform/driver的
程序
设备文件
#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 = 0x56000050,
.end = 0x56000050 + 8 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 5,
.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");
驱动算法
/* 分配/设置/注册一个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 */
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");
测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
/* led_test on
* led_test off
*/
int main(int argc, char **argv)
{
int fd;
int val = 1;
fd = open("/dev/led", O_RDWR);
if (fd < 0)
{
printf("can't open!\n");
}
if (argc != 2)
{
printf("Usage :\n");
printf("%s <on|off>\n", argv[0]);
return 0;
}
if (strcmp(argv[1], "on") == 0)
{
val = 1;
}
else
{
val = 0;
}
write(fd, &val, 4);
return 0;
}
测试
- 注册两个驱动,会自动生成文件
/sys/bus/platform/下的devices和drives生成驱动 - 测试使用
./test on点灯
platform驱动分离的更多相关文章
- 四、分离分层的 platform驱动
学习目标: 学习实现platform机制的分层分离,并基于platform机制,编写led设备和驱动程序: 一.分离分层 输入子系统.usb设备比驱动以及platform类型的驱动等都体现出分离分层机 ...
- Linux Platform驱动模型(二) _驱动方法
在Linux设备树语法详解和Linux Platform驱动模型(一) _设备信息中我们讨论了设备信息的写法,本文主要讨论平台总线中另外一部分-驱动方法,将试图回答下面几个问题: 如何填充platfo ...
- Linux Platform驱动模型(二) _驱动方法【转】
转自:http://www.cnblogs.com/xiaojiang1025/archive/2017/02/06/6367910.html 在Linux设备树语法详解和Linux Platform ...
- Linux 驱动框架---platform驱动框架
Linux系统的驱动框架主要就是三个主要部分组成,驱动.总线.设备.现在常见的嵌入式SOC已经不是单纯的CPU的概念了,它们都会在片上集成很多外设电路,这些外设都挂接在SOC内部的总线上,不同与IIC ...
- platform驱动之probe函数
驱动注册的probe函数 probe函数在设备驱动注册最后收尾工作,当设备的device 和其对应的driver 在总线上完成配对之后,系统就调用platform设备的probe函数完成驱动注册最后工 ...
- platform怎么实现数据数据和驱动分离
一些重要的结构体: struct platform_device { const char * name; int id; struct device dev; u32 num_resources; ...
- Linux Platform驱动模型(一)-设备信息
我在Linux字符设备驱动框架一文中简单介绍了Linux字符设备编程模型,在那个模型中,只要应用程序open()了相应的设备文件,就可以使用ioctl通过驱动程序来控制我们的硬件,这种模型直观,但是从 ...
- Linux驱动之平台设备驱动模型简析(驱动分离分层概念的建立)
Linux设备模型的目的:为内核建立一个统一的设备模型,从而有一个对系统结构的一般性抽象描述.换句话说,Linux设备模型提取了设备操作的共同属性,进行抽象,并将这部分共同的属性在内核中实现,而为需要 ...
- Linux Platform驱动模型(一) _设备信息
我在Linux字符设备驱动框架一文中简单介绍了Linux字符设备编程模型,在那个模型中,只要应用程序open()了相应的设备文件,就可以使用ioctl通过驱动程序来控制我们的硬件,这种模型直观,但是从 ...
随机推荐
- linux 网络套接字
在内核分析网络分组时,底层协议的数据将传输到跟高的层.而发送数据的时候顺序是相反的.每一层都是通过加(首部+净荷)传向跟底层,直至最终发送. 这些操作决定了网络的的性能. 就如下图所示 linux因此 ...
- c/c++ 重载运算符 类型转换运算符
重载运算符 类型转换运算符 问题:能不能把一个类型A的对象a,转换成另一个类型B的对象b呢?? 是可以的.这就必须要用类型A的类型转换运算符(conversion operator) 下面的opera ...
- java实现简单的solr查询
SolrQuery类是实现solr查询的类. @Test public void testSelect() { String url = "http://localhost:8081/sol ...
- 4.13Python数据处理篇之Matplotlib系列(十三)---轴的设置
目录 目录 前言 (一)设置轴的范围 1.同时对于x,y轴设置 2.分别对与x,y轴的设置 (二)设置刻度的大小 1.普通的刻度设置 2.添加文本的刻度设置 3.主副刻度的设置 (三)设置轴的数据 1 ...
- 2星|《IT真相》:日本咨询师面对美国云服务的发展,对日本IT业哀其不争
IT真相-打通IT与商务的通路 I 作者是日本管理咨询师,对日本的IT和金融业了解比较多.书的内容是:作者看到美国的云服务发展壮大,日本IT业没能抓住机会,对日本IT业做了一些批评,比如不思进取,不了 ...
- 一个Web项目中实现多个数据库存储数据并相互切换用过吗?
最近公司一个项目需要连接多个数据库(A和B)操作,根据不同的业务模块查询不同的数据库,因此需要改造下之前的spring-mybatis.xml配置文件以及jdbc.properties配置文件,项目后 ...
- Python开发【内置模块篇】日志模块
logging配置 import logging logging.basicConfig(level=logging.WARNING, format='%(asctime)s %(filename)s ...
- Python开发【内置模块篇】
动态导入模块 动态导入模块 导入一个库名为字符串的 module_t = __import__('m1.t') print (module_t) #m1 import importlib m=impo ...
- Linux-基础学习(五)-mariadb主从复制以及redis学习
开始今日份整理 1.mariadb的主从复制 主从复制大致图示: 1.1 mysql基本命令复习 linux下的操作 .启动mysql systemctl start mariadb .linux客户 ...
- git 命令积累
git status # 查看仓库的状态 git add . # 监控工作区的状态树,使用它会把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的 ...