现在的位置: 首页 > 综合 > 正文

平台设备驱动

2018年01月10日 ⁄ 综合 ⁄ 共 3932字 ⁄ 字号 评论关闭

 

通常在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函数中完成的

【上篇】
【下篇】

抱歉!评论已关闭.