您的位置:首页 > 运维架构 > Linux

平台设备驱动总结

2011-07-03 00:55 218 查看
 
通常在Linux中,把SOC系统中集成的独立外设单元(如:I2C、IIS、RTC、看门狗等)都被当作平台设备来处理。在Linux中用platform_device结构体来描述一个平台设备,在2.6.32内核中定义在:include/linux/platform_device.h中,如下:
 

                                                                   
在Linux中是用这个结构体来定义一些平台设备的。
在arch/arm/plat-s3c24xx/devs.c中就定义了很多平台设备。
平台设备驱动是指具体的某种平台设备的驱动,比如RTC平台设备驱动。在Linux中,系统还为平台设备定义了平台驱动结构体platform_driver,就好比系统为字符设备定义了file_operations一样,但不要把平台设备跟字符设备、块设备、网络设备搞成了并列的概念,因平台设备也可以是字符设备等其他设备。注意:在被定义为平台设备的字符设备的驱动中,除了要实现字符设备驱动中file_operations的open、release、read、write等接口函数外,还要实现平台设备驱动中platform_driver的probe、remove、suspend、resume等接口函数。
 
以S3c2440开发板为例,在linux-2.6.30.4/arch/arm/plat-s3c24xx/common-smdk.c中定义了如下设备:
staticstruct platform_device __initdata *smdk_devs[] = {
//
平台设备列表
1
,也就是说我们要使用一个新的平台设备要先在上面定义,然后加到这个列表中,最后到驱动层去实现该设备的驱动

       &s3c_device_nand,
       &s3c_device_sdi,
       &smdk_led4,
       &smdk_led5,
       &smdk_led6,
       &smdk_led7,
};
在linux-2.6.30.4/arch/arm/mach-s3c2440/mach-smdk2440.c中定义了如下设备:
static struct platform_device*smdk2440_devices[] __initdata = {
//
平台设备列表
2

       &s3c_device_usb,
       &s3c_device_lcd,
       &s3c_device_wdt,
       &s3c_device_i2c0,
       &s3c_device_iis,
       &s3c_device_rtc,
       &s3c_device_dm9000,
       &s3c_device_uda134x,
};
这些设备在smdk2440_machine_init函数中,通过platform_add_device函数注册进内核。
linux-2.6.30.4/arch/arm/mach-s3c2440/mach-smdk2440.c
static void __initsmdk2440_machine_init(void)
{
       s3c24xx_fb_set_platdata(&smdk2440_fb_info);
       s3c_i2c0_set_platdata(NULL);
 
       platform_add_devices(smdk2440_devices,ARRAY_SIZE(smdk2440_devices));
//
将上面列表中的平台设备添加到系统总线中

       smdk_machine_init();
}
linux-2.6.30.4/arch/arm/plat-s3c24xx/common-smdk.c
void __init smdk_machine_init(void)
{
       ……
       s3c_device_nand.dev.platform_data =&smdk_nand_info;
       platform_add_devices(smdk_devs,ARRAY_SIZE(smdk_devs));
//
将上面列表中的平台设备添加到系统总线中

       s3c_pm_init();
}
以实时时钟RTC 驱动为例
linux/arch/arm/plat-s3c24xx/devs.c中:
struct platform_device s3c_device_rtc = {
       .name              = "s3c2410-rtc",
       .id           = -1,
       .num_resources        =ARRAY_SIZE(s3c_rtc_resource),
       .resource   = s3c_rtc_resource,
};
drivers/rtc/rtc-s3c.c中:
static struct platform_driver s3c2410_rtc_driver = {
       .probe            = s3c_rtc_probe,// RTC探测函数, 探测就意味着在系统总线中去检测设备的存在,然后获取设备有用的相关资源信息,以便我们使用这些信息
       .remove          = __devexit_p(s3c_rtc_remove),// RTC移除函数
       .suspend  = s3c_rtc_suspend,// RTC挂起函数
       .resume          = s3c_rtc_resume,// RTC恢复函数
       .driver            = {
              .name      = "s3c2410-rtc",
              .owner    = THIS_MODULE,
       },
};
在linux/arch/arm/plat-s3c24xx/devs.c中
static struct resource s3c_rtc_resource[] = {//定义了RTC平台设备使用的资源,这些资源在驱动中都会用到
       [0]= {//IO端口资源范围
              .start= S3C24XX_PA_RTC,
              .end   = S3C24XX_PA_RTC+ 0xff,
              .flags= IORESOURCE_MEM,
       },
       [1]= {//RTC报警中断资源
              .start= IRQ_RTC,
              .end   = IRQ_RTC,
              .flags= IORESOURCE_IRQ,
       },
       [2]= {//TICK节拍时间中断资源
              .start= IRQ_TICK,
              .end   = IRQ_TICK,
              .flags= IORESOURCE_IRQ
       }
};
static int __init s3c_rtc_init(void)
{
    /*将RTC注册成平台设备驱动*/
return platform_driver_register(&s3c2410_rtc_driver);
}
 
static void __exit s3c_rtc_exit(void)
{
    /*注销RTC平台设备驱动*/
platform_driver_unregister(&s3c2410_rtc_driver);
}
 
module_init(s3c_rtc_init);
module_exit(s3c_rtc_exit);
RTC设备类的操作,是对RTC硬件的各种寄存器进行操作,rtc_class_ops是RTC设备类在RTC驱动核心部分中定义的对RTC设备类进行操作的结构体,类似字符设备在驱动中的file_operations对字符设备进行操作的意思。对RTC的操作主要有打开、关闭、设置或获取时间、设置或获取报警、设置节拍时间计数值等等,该结构体内接口函数的实现都在下面
static const struct rtc_class_ops s3c_rtcops = {
.open = s3c_rtc_open,
.release = s3c_rtc_release,
.irq_set_freq = s3c_rtc_setfreq, /*在第②步中已实现*/
.irq_set_state = s3c_rtc_setpie,
.read_time = s3c_rtc_gettime,
.set_time = s3c_rtc_settime,
.read_alarm = s3c_rtc_getalarm,
.set_alarm = s3c_rtc_setalarm,
};
机理:内核启动后,首先够造链表将描述设备的platform_device结构组织起来,得到一个设备的列表;当加载到某个驱动程序的platform_driver结构时(start_kernelàrest_init()àinit àdo_basic_setup();//初始化设备驱动程序),使用一些匹配函数来检查驱动程序是否支持这些设备,常用的检查方法很简单:比较驱动程序和设备的名称。
当注册成功时会调用platform_driver结构元素probe函数指针,这里就是s3c_rtc_probe。驱动的初始化等都是在prob函数中完成的。
 
 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息