本文介绍一种bus_drv_dev模型,这个模型其实就是一种通过bus总线,将分别位于左边的device和driver联系起来的机制。

声明:本文是学习韦东山老师后的学习感悟,如有雷同请勿见怪。

大致的意思是:在这个机制中,device通过device_register函数将自己放入bus的dev链表中,而driver通过driver_register函数将自己放入bus的drv链表中。而此时bus会使用他下面的match函数用来比较dev链中的设备和drv中的驱动是否匹配,如果匹配则建立联系,调用probe函数。

下面我们用代码分析:

首先 分析platform_device_register函数

int platform_device_register(struct platform_device * pdev)
{
device_initialize(&pdev->dev);               //此为前半部分
return platform_device_add(pdev);        //此为后半部分,将设备添加到dev中
}

而platform_device 的内容为

struct platform_device {
const char * name;                        //这个设备的名称
u32 id;     //他的ID
struct device dev;                             
u32 num_resources;              //这个设备有几个resource
struct resource * resource;        //这个设备的resource
};

接下来我们分析platform_driver_register函数

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;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver);
}

我们看到有介绍bus的&platform_bus_type;我们打开这个结构体会发现有他就是bus类的结构体

struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.suspend = platform_suspend,
.suspend_late = platform_suspend_late,
.resume_early = platform_resume_early,
.resume = platform_resume,
};

我们发现里面有一条.match = platform_match,语句,这个函数指针就是指向match函数的,通过match函数比较dev和drv来确定他们是否匹配,那么他们比较的是什么那??

我们打开这个函数指针:

static int platform_match(struct device * dev, struct device_driver * drv)
{
struct platform_device *pdev = container_of(dev, struct platform_device, dev);
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}

通过(strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0)可以知道比较的是dev和drv的name,因此在注册device和driver是他们的名字一定要一样。

下面我们用具体的点亮LED的程序来说明这个机制:

先写device端:

static struct resource led_resource[] = {
{
.start = 0x56000050,
.end =   0x56000050+8-1,
.flags = IORESOURCE_MEM,       //资源类别
},{
.start = 6,
.end = 6,
.flags = IORESOURCE_IRQ,       //资源类别
},
};

static void led_release(struct device *pdev)
{
}

static struct platform_device led_dev = {
.name = "myled",                   //此处的名字就是一定要与driver中一样的名字
.id = -1,
.num_resources = ARRAY_SIZE(led_resource),   
.resource = led_resource,
.dev      ={
.release = led_release,     //此处的release函数是一定要加的,不然rmmod 时会出现错误
},
};

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");

而driver中的程序为(程序中一些不必要的定义和代码我删了):

//probe函数,驱动和设备匹配成功后 就会调用这个函数
static int led_probe(struct platform_device *pdev)
{
printk("led_probe,fount device\n");
/* 根据platform_device  的资源进行ioremap */

ress = platform_get_resource(pdev,IORESOURCE_MEM,0);//从dev中获得resource的IORESOURCE_MEM类    //信息,从而获得端口物理地址
gpio_con = ioremap(ress->start, ress->end - ress->start);
goio_dat = gpio_con + 1;

ress = platform_get_resource(pdev,IORESOURCE_IRQ,0);//从dev中获得resource的IORESOURCE_IRQ类    //信息,从而获得按键值
pin = ress->start;

/* 注册字符设备驱动 */
auto_major = register_chrdev(0,"myled", &led_fops);
led_class = class_create(THIS_MODULE,"myled");
led_class_dev = class_device_create(led_class,NULL,MKDEV(auto_major,0),NULL,"myled");       //自动生成/dev/myled设备

return 0;
}

//remove函数,当设备或者驱动卸载时会调用这个函数
static int led_remove(struct platform_device *dev)
{
printk("led_remove,remove device\n");
class_device_unregister(led_class_dev);
class_destroy(led_class);
unregister_chrdev(auto_major,"myled");
iounmap(gpio_con);

return 0;
}

static struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.owner = THIS_MODULE,
.name = "myled",           //此处的名字就是一定要与device中一样的名字
},
};

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");

bus_dev_drv 模型相关推荐

  1. java中实现具有传递性吗_Java中volatile关键字详解,jvm内存模型,原子性、可见性、有序性...

    一.Java内存模型 想要理解volatile为什么能确保可见性,就要先理解Java中的内存模型是什么样的. Java内存模型规定了所有的变量都存储在主内存中.每条线程中还有自己的工作内存,线程的工作 ...

  2. 【软件工程】RUP与软件开发5大模型

    软件开发的5大模型 1.瀑布模型:按照人的思维一步一步的开发下去,如果需求分析得当,每个阶段顺利,结果还不错! 2.快速原型模型:后来人们发现,自己不可能一下子就把所有的需求搞清楚,总是在开发的过程中 ...

  3. 判别模型和生成模型的区别

    20210703 https://www.zhihu.com/question/20446337 机器学习"判定模型"和"生成模型"有什么区别? 重点 http ...

  4. 算法工程师落地_模型的更新升级能力

    20210728 https://mp.weixin.qq.com/s/lAJV1QPy_ZWJeQ1cIpUdEg 2021年,算法工程师必备的能力是什么? 数据分析和代码编写,java的能力 20 ...

  5. tensorflow 1.x Saver(保存与加载模型) 预测

    20201231 tensorflow 1.X 模型保存 https://blog.csdn.net/qq_35290785/article/details/89646248 保存模型 saver=t ...

  6. tensor和模型 保存与加载 PyTorch

    PyTorch教程-7:PyTorch中保存与加载tensor和模型详解 保存和读取Tensor PyTorch中的tensor可以保存成 .pt 或者 .pth 格式的文件,使用torch.save ...

  7. lightgbm保存模型参数

    20210205 params = {'task': 'train', # 执行的任务类型'boosting_type': 'gbrt', # 基学习器'objective': 'lambdarank ...

  8. 各bert 模型下载

    20210618 https://huggingface.co/bert-base-chinese/tree/main bert 官方 https://mirrors.tuna.tsinghua.ed ...

  9. ELECTRA 超过bert预训练NLP模型

    论文:ELECTRA: Pre-training Text Encoders As Discriminators Rather Then Generators 本文目前在ICLR 2020盲审中,前几 ...

最新文章

  1. javascript 面向对象编程(工厂模式、构造函数模式、原型模式)
  2. Jquery Mobile 百度地图 Demo
  3. ansible备份mysql_ansible做mysql备份和安全加固
  4. rman全备时,配置项如何设置?
  5. UkrGuru.SqlJson——你的SQL Server和.NET 5之间的链接
  6. Php AES加密、解密与Java互操作的问题
  7. php制作日历的代码,php日历制作代码分享_PHP教程
  8. UltraEdit 注册机使用激活方法 更新:暴力破解
  9. hash素数表(备用)
  10. OLED驱动芯片SSD1306解读
  11. MATLAB 符号运算
  12. 视频网站ts流媒体服务器,流媒体服务器支持HLS,RTMP,RTSP,HTTP-FLV,HTTP-TS,HTTP-AAC输出...
  13. 动态规划之钢条切割问题——Rod-cutting problem
  14. win10导入iphone手机中的照片和视频出错:发生了一些问题,文件可能未导入
  15. postman脚本批量请求
  16. 使用阿里图标库icon图标 ttf字体文件转化成base64格式
  17. 上海配眼镜(攻略) ,个人配镜经验总结,你不了解的这里都有!
  18. 田野调查手记·浮山篇(一)
  19. 一个屌丝程序猿的人生(一百一十五)
  20. java 读取串口数据

热门文章

  1. CSplitterWnd窗口分割之——动态静态嵌套分割(二)
  2. 按键精灵大漠插件使用基础练习入门代码
  3. 爱江山更爱美人自动刷小号请安膜拜
  4. Cypress系列(43)- visit() 命令详解
  5. 计算机看门狗的作用,关于看门狗的作用
  6. STM32之ADC实验
  7. html5 播放进度,获取并设置HTML5 Video的当前进度
  8. unity中3dUI或者模型始终面向摄像机,跟随摄像机视角旋转丨视角跟随丨固定视角
  9. sphinx全文检索之PHP使用教程
  10. Jasper 中文字体