应用中的linux驱动 platform_device

来源:互联网 发布:unity3d 刚体不受重力 编辑:程序博客网 时间:2024/06/07 10:41

linux驱动学习(六) 应用中的linux驱动 platform_device

标签: linuxstructresourcesmodule嵌入式table
8237人阅读 评论(2)收藏举报
本文章已收录于:
分类:
作者同类文章X
  • linux驱动学习(九) usb设备驱动的初步认知
  • linux驱动学习(八) i2c驱动架构(史上最全) davinc dm368 i2c驱动分析
  • linux驱动学习(七) ioctl中的cmd和_IO() , _IOR() , IOW() ,_IOWR() 以及_IOC_NR()的关系
  • /proc/devices awk
  • 《Linux内核修炼之道》 之 高效学习Linux驱动开发
  • 更多

一个现实的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

[cpp] view plain copy
print?
  1. struct platform_device {  
  2.     const char  * name;  
  3.     int     id;  
  4.     struct device   dev;  
  5.     u32     num_resources;  
  6.     struct resource * resource;  
  7.   
  8.     const struct platform_device_id *id_entry;  
  9.   
  10.     /* arch specific additions */  
  11.     struct pdev_archdata    archdata;  
  12. };  

platform_device成员变量

1、struct device(部分),include<linux/device.h>
[cpp] view plain copy
print?
  1. struct device {  
  2.     struct device       *parent;  
  3.   
  4.     struct device_private   *p;  
  5.   
  6.     struct kobject kobj;  
  7.     const char      *init_name; /* initial name of the device */  
  8.     struct device_type  *type;  
  9.   
  10.     struct mutex        mutex;  /* mutex to synchronize calls to 
  11.                      * its driver. 
  12.                      */  
  13.   
  14.     struct bus_type *bus;       /* type of bus device is on */  
  15.     struct device_driver *driver;   /* which driver has allocated this 
  16.                        device */  
  17.     void        *platform_data; /* Platform specific data, device 
  18.                        core doesn't touch it */  



2、struct resource

[cpp] view plain copy
print?
  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

[cpp] view plain copy
print?
  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

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


用于向内核注册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,简略的如下形式

[cpp] view plain copy
print?
  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,代码如下

[cpp] view plain copy
print?
  1. static struct platform_device mychar_device = {   
  2.     .name = "mychar",  
  3.     .id = -1,  
  4. };  
这样就表示,开发板上有一个devie,名字叫mychar,因为mychar是内存中虚拟出来的,所以这里并不需要设置别的,只要设置一下与driver相匹配的name:mychar就可以了

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

[cpp] view plain copy
print?
  1. static struct platform_device *mini2440_devices[] __initdata = {  
  2.     &mychar_device,  
  3.     &s3c_rtc,  
  4.     &s3c_device_fb,  
  5.     ...  
  6. }  


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

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

[cpp] view plain copy
print?
  1.     resource_size_t start;  
  2.     resource_size_t end;  
  3.     const char *name;  
  4.     unsigned long flags;  
  5. 通常只关心struct resource中的以上四个成员变量  
  6. start 与end两个字段的值随着flags的改变而改变,当flags 为 IORESOURCE_MEM 时,start,end分别表示该platform_device 占据的内存的开始地址和结束地址,若flags为IORESOURCE_IRQ 时,start end 则表示该platform_device 使用的中断号的开始值和结束值,假如只使用了1个中断号,那么start与end相同。  
  7. 例如dm9000的resource部分:  
  8. /* DM9000AEP 10/100 ethernet controller */  
  9.   
  10. static struct resource mini2440_dm9k_resource[] = {  
  11.     [0] = {  
  12.         .start = MACH_MINI2440_DM9K_BASE,  
  13.         .end   = MACH_MINI2440_DM9K_BASE + 3,  
  14.         .flags = IORESOURCE_MEM  
  15.     },  
  16.     [1] = {  
  17.         .start = MACH_MINI2440_DM9K_BASE + 4,  
  18.         .end   = MACH_MINI2440_DM9K_BASE + 7,  
  19.         .flags = IORESOURCE_MEM  
  20.     },  
  21.     [2] = {  
  22.         .start = IRQ_EINT7,  
  23.         .end   = IRQ_EINT7,  
  24.         .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,  
  25.     }  
  26. };  
  27. 所谓的resource,具体来时是与板级硬件密切相关的,比如控制器映射到soc内存的地址范围,外部中断引脚等,  
  28. 当然,要把定义的这个resources[]赋值给platform_device的.resource 字段,同时要设置.num_resources资源个数。  
  29. 设备除了可以再bsp中定义资源以外,还可以附加一些数据信息,因为对设备的硬件描述除了中断,内存,DMA通道以外,可能还会有一些配置信息,而这些配置信息也依赖于板,不宜直接放置在设备驱动本身,因此platform也提供了platform_data的支持,platform_data的形式是自定义的,比如对于dm9000网卡来说,platform_data中可以存放mac地址,总线宽度,板上有误eeprom等信息。  
  30.  * The DM9000 has no eeprom, and it's MAC address is set by  
  31.  * the bootloader before starting the kernel.  
  32.  */  
  33. static struct dm9000_plat_data mini2440_dm9k_pdata = {  
  34.     .flags      = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),  
  35. };  
  36. 然后将这个data赋值给platform_device中.dev的.platform_data数据项,如下:  
  37. static struct platform_device mini2440_device_eth = {  
  38.     .name       = "dm9000",  
  39.     .id     = -1,  
  40.     .num_resources  = ARRAY_SIZE(mini2440_dm9k_resource),  
  41.     .resource   = mini2440_dm9k_resource,  
  42.     .dev        = {  
  43.         .platform_data  = &mini2440_dm9k_pdata,  
  44.     },  
  45. };  
  46.   
  47. 所以在抑制linux到具体的开发板时,基本都是这么移植的是不是?回答是肯定的,这里注意了,以上与板级硬件密切相关的代码部分,均在bsp板级支持文件中,例如mach-s3c2440.c中,但是你看到了真正的驱动了吗比如字符设备的read write等函数的实现了吗。  
  48. 真正的驱动代码在内核的driver文件夹下,比如dm9000的驱动在 drviver/net/文件夹下的dm9000.c中,而且这部分的代码是与具体的板级硬件无关的,再比如nandflash的驱动,配置也是在mach-s3c2440.c中,但关键的驱动源码在 drvier/mtd/nand/文件夹下  
  49. 这样的结构就是linux驱动的分层思想,设备驱动的核心层与例化。  


[cpp] view plain copy
print?
  1. <pre></pre>  
  2. <pre></pre>  
  3. <pre></pre>  
9
0
 
 

  相关文章推荐
  • Linux驱动学习——platform平台总线
  • Linux驱动中的platform
  • Linux驱动---------platform总线设备
  • Linux驱动的platform机制
  • Linux驱动之设备模型(9)-platform
  • Linux驱动程序中的platform总线详…
  • Linux驱动的platform机制
  • Linux驱动之Platform Driver
  • Linux驱动中的platform
  • Linux驱动程序中的platform总线详解
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 护照在国外掉了怎么办 上海动迁房户口怎么办 政府强制拆房怎么办 农村无证宅基地怎么办 身份证没磁怎么办护照 买安置房怎么办产权 安置房房东违约怎么办 安置房产权到期怎么办 安置房怎么办房产证吗 美甲后指甲长了怎么办 在菲律宾怎么办持枪证? 绝地求生打不准怎么办 身份证号码变更后社保怎么办 社保与身份不符怎么办 年龄改了学籍怎么办 结婚证信息错误怎么办 六级身份证过期怎么办 身份号泄露了怎么办 身体证信息泄露怎么办 手机号被泄漏了怎么办 姓名和电话泄露怎么办 个人身份证信息泄露怎么办 身份号码泄露了怎么办 我身份证泄露了怎么办 身份证信息泄漏了怎么办 无锡身份证丢了怎么办 人在外地怎么办身份证 欠空放公司不还怎么办 兼职要身份证照片怎么办 身份证刷不了磁怎么办 身份证不能刷了怎么办 身份证指纹错了怎么办 指纹手机丢了怎么办 异地办理临时身份证怎么办 杭州办理外地身份证怎么办 办理身份证没有户口本怎么办 2018身份证掉了怎么办 双户口注销社保怎么办 常用户口被注销怎么办 刚到厦门怎么办身份证 新疆身份证丢了怎么办