用中的linux驱动 platform_device

用中的linux驱动 platform_device原文出自:http://blog.csdn.net/ghostyu/article/details/6908805一个现实的linux设备和驱动通常要挂接在一种总线上,像pci,usb,iic,spi等都是总线结构,这当然不是问题,但是嵌入式系统中,Soc系统集成的独立外设控制器,挂接在soc内存空间的外设等却不依附于此类总线。基于这个背景,linux发明了一种虚拟总线:platfor

大家好,又见面了,我是你们的朋友全栈君。

原文出自:http://blog.csdn.net/ghostyu/article/details/6908805

一个现实的linux设备和驱动通常要挂接在一种总线上,像pci,usb,iic,spi等都是总线结构,这当然不是问题,但是嵌入式系统中,Soc系统集成的独立外设控制器,挂接在soc内存空间的外设等却不依附于此类总线。


基于这个背景,linux发明了一种虚拟总线:platform总线,相应的设备称为platform_device,而驱动成为platform_driver。
注意,platform_device并不是与自负设备,块设备等平行的概念,而是linux提供的一种附加手段,例如s3c2440处理器中,把内部集成的iic,rtc,spi,lcd,watchdog,等控制器归纳为platform_device,但是他们本身就是字符设备。

platform_device

  1. struct platform_device {
  2. const char * name;
  3. int id;
  4. struct device dev;
  5. u32 num_resources;
  6. struct resource * resource;
  7. const struct platform_device_id *id_entry;
  8. /* arch specific additions */
  9. struct pdev_archdata archdata;
  10. };

platform_device成员变量

1、struct device(部分),include<linux/device.h>

  1. struct device {
  2. struct device *parent;
  3. struct device_private *p;
  4. struct kobject kobj;
  5. const char *init_name; /* initial name of the device */
  6. struct device_type *type;
  7. struct mutex mutex; /* mutex to synchronize calls to
  8. * its driver.
  9. */
  10. struct bus_type *bus; /* type of bus device is on */
  11. struct device_driver *driver; /* which driver has allocated this
  12. device */
  13. void *platform_data; /* Platform specific data, device
  14. core doesn’t touch it */


2、struct resource

  1. struct resource {
  2. resource_size_t start;
  3. resource_size_t end;
  4. const char *name;
  5. unsigned long flags;
  6. struct resource *parent, *sibling, *child;
  7. };



platform_device对应的platform_driver

  1. struct platform_driver {
  2. int (*probe)(struct platform_device *);
  3. int (*remove)(struct platform_device *);
  4. void (*shutdown)(struct platform_device *);
  5. int (*suspend)(struct platform_device *, pm_message_t state);
  6. int (*resume)(struct platform_device *);
  7. struct device_driver driver;
  8. const struct platform_device_id *id_table;
  9. };



支持电源管理时,需要实现 shutdown,suspend,resume这三个函数,若不支持,将他们设为null。

platform_driver结构体中的重要成员变量 device_driver

  1. struct device_driver {
  2. const char *name;
  3. struct bus_type *bus;
  4. struct module *owner;
  5. const char *mod_name; /* used for built-in modules */
  6. bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
  7. #if defined(CONFIG_OF)
  8. const struct of_device_id *of_match_table;
  9. #endif
  10. int (*probe) (struct device *dev);
  11. int (*remove) (struct device *dev);
  12. void (*shutdown) (struct device *dev);
  13. int (*suspend) (struct device *dev, pm_message_t state);
  14. int (*resume) (struct device *dev);
  15. const struct attribute_group **groups;
  16. const struct dev_pm_ops *pm;
  17. struct driver_private *p;
  18. };

用于向内核注册platform_driver的函数platform_driver_register(platform_driver *)

反之,注销platform_driver的函数platform_drvier_unregister(platform*)

一般实现platform_driver时,除了实现file_operations中的read、write等函数外,还要实现platform_driver中的probe与remove等函数,其余均按正常的linux设备驱动的编写方法编写驱动程序。

例如将mychar移植成platform_driver,简略的如下形式

  1. static int __devinit mychar_probe(struct platform_device *pdev)
  2. {
  3. //申请设备号
  4. //申请设备结构体的内存
  5. //注册cdev
  6. //其实probe 函数里就是实现之前在mychar_init中实现的功能
  7. }
  8. static int __devexit mychar_remove(struct platform_device *pdev)
  9. {
  10. //实现之前在mychar_exit()中的释放内存的功能
  11. }
  12. static struct platform_driver mychar_device_driver = {
  13. .probe = mychar_probe,
  14. .remove = __devexit_p(mychar_remove),
  15. .driver = {
  16. .name = “mychar”,
  17. .owner = THIS_MODULE,
  18. }
  19. };
  20. //在mychar_init中注册platform_driver
  21. static int __init mychar_init(void)
  22. {
  23. return platform_driver_register(&mychar_device_driver);
  24. }
  25. //在mychar_exit 中注销platform
  26. static void __exit mychar_exit(void)
  27. {
  28. platform_driver_unregister(mychar_device_driver);
  29. }
  30. //驱动余下部分与之前实现的mychar相同
  31. module_init(mychar_init);
  32. module_exit(mychar_exit);

注意,如果要让这个驱动在开发板上能工作,需要在板文件中添加相应的代码,在板文件例如 arch/arm/mach-s3c2440/mach-mini2440.c,代码如下

  1. static struct platform_device mychar_device = {
  2. .name = “mychar”,
  3. .id = -1,
  4. };

这样就表示,开发板上有一个devie,名字叫mychar,因为mychar是内存中虚拟出来的,所以这里并不需要设置别的,只要设置一下与driver相匹配的name:mychar就可以了

通常开发板不会只有这一个设备,所以在platform_device数组中,将上面的mychar_device添加进来,如下:

  1. static struct platform_device *mini2440_devices[] __initdata = {
  2. &mychar_device,
  3. &s3c_rtc,
  4. &s3c_device_fb,
  5. }

platform_devece的资源与数据(resource 与platform_data)

还记的在platform_device 中的struct resource *resource吗,

  1. <pre name=“code” class=“cpp”> resource_size_t start;
  2. resource_size_t end;
  3. const char *name;
  4. unsigned long flags;


通常只关心struct resource中的以上四个成员变量

start 与end两个字段的值随着flags的改变而改变,当flags 为 IORESOURCE_MEM 时,start,end分别表示该platform_device 占据的内存的开始地址和结束地址,若flags为IORESOURCE_IRQ 时,start end 则表示该platform_device 使用的中断号的开始值和结束值,假如只使用了1个中断号,那么start与end相同。

例如dm9000的resource部分:

  1. /* DM9000AEP 10/100 ethernet controller */
  2. static struct resource mini2440_dm9k_resource[] = {
  3. [0] = {
  4. .start = MACH_MINI2440_DM9K_BASE,
  5. .end = MACH_MINI2440_DM9K_BASE + 3,
  6. .flags = IORESOURCE_MEM
  7. },
  8. [1] = {
  9. .start = MACH_MINI2440_DM9K_BASE + 4,
  10. .end = MACH_MINI2440_DM9K_BASE + 7,
  11. .flags = IORESOURCE_MEM
  12. },
  13. [2] = {
  14. .start = IRQ_EINT7,
  15. .end = IRQ_EINT7,
  16. .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
  17. }
  18. };

所谓的resource,具体来时是与板级硬件密切相关的,比如控制器映射到soc内存的地址范围,外部中断引脚等,

当然,要把定义的这个resources[]赋值给platform_device的.resource 字段,同时要设置.num_resources资源个数。

设备除了可以再bsp中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断,内存,DMA通道以外,可能还会有一些配置信息,而这些配置信息也依赖于板,不宜直接放置在设备驱动本身,因此platform也提供了platform_data的支持,platform_data的形式是自定义的,比如对于dm9000网卡来说,platform_data中可以存放mac地址,总线宽度,板上有误eeprom等信息。

  1. * The DM9000 has no eeprom, and it’s MAC address is set by
  2. * the bootloader before starting the kernel.
  3. */
  4. tatic struct dm9000_plat_data mini2440_dm9k_pdata = {
  5. .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
  6. ;

然后将这个data赋值给platform_device中.dev的.platform_data数据项,如下:

  1. static struct platform_device mini2440_device_eth = {
  2. .name = “dm9000”,
  3. .id = -1,
  4. .num_resources = ARRAY_SIZE(mini2440_dm9k_resource),
  5. .resource = mini2440_dm9k_resource,
  6. .dev = {
  7. .platform_data = &mini2440_dm9k_pdata,
  8. },
  9. };



所以在抑制linux到具体的开发板时,基本都是这么移植的是不是?回答是肯定的,这里注意了,以上与板级硬件密切相关的代码部分,均在bsp板级支持文件中,例如mach-s3c2440.c中,但是你看到了真正的驱动了吗比如字符设备的read write等函数的实现了吗。

真正的驱动代码在内核的driver文件夹下,比如dm9000的驱动在 drviver/net/文件夹下的dm9000.c中,而且这部分的代码是与具体的板级硬件无关的,再比如nandflash的驱动,配置也是在mach-s3c2440.c中,但关键的驱动源码在 drvier/mtd/nand/文件夹下

这样的结构就是linux驱动的分层思想,设备驱动的核心层与例化。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/163826.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • android r文件丢失_读取文件

    android r文件丢失_读取文件在用Eclipse做开发的时候,总是无缘无故缺少R文件,让整个项目报废,在网上查了资料后现在做一下整理。1、右击你的Android项目——>AndroidTools——>FixProjectProperties即可。2、清理下项目:使用菜单Project——>clean——>选中需要clean的项目这个最简单的方法,但是我觉得这并没有什么卵用。。。。。

  • Java面试题总结:微服务、SpringBoot、SpringCloud

    Java面试题总结:微服务、SpringBoot、SpringCloud

  • idea Mac 破解2021激活码[免费获取]

    (idea Mac 破解2021激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlMLZPB5EL5Q-eyJsaWNlbnNlSWQi…

  • Cordova App 打包全揭秘

    本文作者:大师兄(高武军)现就职于某公司移动端架构师兼产品开发。主要开发产品:mdn(适配app和微信的移动端解决方案),pageui(移动端ui组件库),formBuilder(可以让前端建表和操作表的表单设计器)。课程介绍点击查看原文Cordova是一个开源的移动开发框架。允许你用标准的Web技术——HTML5,CSS3和JavaScript做跨平台开发。应用在每个平台的

  • 使用Chrome Frame插件解决IE浏览器兼容问题

    使用Chrome Frame插件解决IE浏览器兼容问题时不时碰到客户的浏览器为IE7,IE8,甚至IE6的,他们不能升级浏览器,因为升级后,机器中其它的重要系统无法访问。而新系统的前端又需要浏览器的支持,比如H5,SVG等等,换框架结构,成本无疑是巨大的,而且风险不可控。针对此种情况,安装GoogleFrame是相对非常完美的解决方案,不要求升级浏览器,只安装一个插件,且对原系统无任何干扰,新系统也可根据情况对是否使用GoogleFrame插件进…

  • matplotlib.pyplot.plot()参数详解「建议收藏」

    matplotlib.pyplot.plot()参数详解「建议收藏」https://matplotlib.org/api/pyplot_summary.html在交互环境中查看帮助文档:importmatplotlib.pyplotasplthelp(plt.plot)以下是对帮助文档重要部分的翻译:plot函数的一般的调用形式:#单条线:plot([x],y,[fmt],data=None,**kwargs)#多条线一…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号