从devkit8000分析设备驱动程序工作过程

     去年想移植Android到omap3530,今年想移植DVSDK4.0到omap3530和DM368_ipnc,按照说明书移植总感觉很蒙,没搞明白没有把握。要是在上层开发,像是写windows程序一样,那么只要求会装操作系统就够了,但是要是想把没有板级支持的系统装上去,必须得搞清楚移植的原理和工作过程。感觉以前老是到处找怎么移植,一遍一遍的实验,浪费了不少时间,安心下来研究了一下代码,发现清晰多了。下面以2.6.28版本board_omap3devkit8000.c的lcd设备添加为例说明一下驱动程序的调用过程。

1。初始化与调用

     /arch/arm/mach-omap2/board-omap3devkit8000.c中,在文件最后,有如下宏定义:

    MACHINE_START(OMAP3_DEVKIT8000, "OMAP3 DevKit8000 Board")

         .phys_io = 0x48000000,

        .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,

     .boot_params = 0x80000100,

     .map_io = omap3_devkit8000_map_io,

     .init_irq = omap3_devkit8000_init_irq,

     .init_machine = omap3_devkit8000_init,

     .timer = &omap_timer,

  MACHINE_END


MACHINE_START和MACHINE_END宏定义在arch/arm/include/asm/mach/arch.h

MACHINE_START主要是定义了"struct machine_desc"的类型,放在 section(".arch.info.init"),是初始化数据,kernel boot 起来的时候期望 bootloader 传参数进来,其中包括 Machine Type,参考arch/arm/tools/mach-types 和MACHINE_START() 第一个参数对上号。因此,哪个MACHINE 是 run-time 的时候决定的,this way, you can pack as many machine as you want, and dynamically initialize the specific platforms.

各个成员函数在不同时期被调用:

   .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。

   .init_irq在start_kernel() --> init_IRQ() --> init_arch_irq() 被调用

   .map_io 在 setup_arch() --> paging_init() --> devicemaps_init()被调用

其他主要都在 setup_arch() 中用到。


添加设备在成员函数omap3_devkit8000_init()中,此函数初始化了很多项,I2C、SPI之类的,其中添加设备也在里面:

    platform_add_devices(omap3_devkit8000_devices,ARRAY_SIZE(omap3_devkit8000_devices));

    这个函数在platform_deveice.h中定义,添加一系列的设备

        其中的参数omap3_devkit8000_devices列表在下面定义

       static struct platform_device *omap3_devkit8000_devices[] __initdata = {

    #ifdef CONFIG_OMAP2_DSS

     &omap3_evm_dss_device,

     &omap3evm_vout_device,

    #else

     &omap3_devkit8000_lcd_device,

    #endif

     &leds_gpio,

     &keys_gpio,

     &w1_device,

     &omap_dm9000_dev,

    };

       platform_device数据结构类型也在platform_deveice.h中定义,

 

    struct platform_device {

     const char * name;

     int id;

     struct device dev;

     u32 num_resources;

     struct resource * resource;

    };


      添加的设备omap3_devkit8000_lcd_device的定义

    static struct platform_device omap3_devkit8000_lcd_device = {

     .name = "omap3_devkit8000_lcd",

     .id = -1,

    };

     添加LCD设备只是使用了name="omap3_devkit8000_lcd"和id这两个参数,omap3_devkit8000_lcd这个模块名称在drivers/video/omap/lcd_omap3devkit8000.c定义,id=-1应该是系统分配设备号的意思,id>0应该就是用户指定


2。添加设备列表

   platform_add_devices()函数在drivers/base/platform.c中,把一系列的设备注册

int platform_add_devices(struct platform_device **devs, int num)

{

int i, ret = 0;

for (i = 0; i < num; i++) {

ret = platform_device_register(devs[i]);

if (ret) {

while (--i >= 0)

platform_device_unregister(devs[i]);

break;

}

}

return ret;

}

其中注册函数

int platform_device_register(struct platform_device *pdev)

{

device_initialize(&pdev->dev);

return platform_device_add(pdev);

}

添加设备函数

int platform_device_add(struct platform_device *pdev)

{

int i, ret = 0;

if (!pdev)

return -EINVAL;

if (!pdev->dev.parent)

pdev->dev.parent = &platform_bus;

pdev->dev.bus = &platform_bus_type;

if (pdev->id != -1)

snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,

 pdev->id);

else

strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);

for (i = 0; i < pdev->num_resources; i++) {

struct resource *p, *r = &pdev->resource[i];

if (r->name == NULL)

r->name = pdev->dev.bus_id;

p = r->parent;

if (!p) {

if (resource_type(r) == IORESOURCE_MEM)

p = &iomem_resource;

else if (resource_type(r) == IORESOURCE_IO)

p = &ioport_resource;

}

if (p && insert_resource(p, r)) {

printk(KERN_ERR

       "%s: failed to claim resource %d/n",

       pdev->dev.bus_id, i);

ret = -EBUSY;

goto failed;

}

}

pr_debug("Registering platform device '%s'. Parent at %s/n",

 pdev->dev.bus_id, pdev->dev.parent->bus_id);

ret = device_add(&pdev->dev);

if (ret == 0)

return ret;

 failed:

while (--i >= 0) {

struct resource *r = &pdev->resource[i];

unsigned long type = resource_type(r);

if (type == IORESOURCE_MEM || type == IORESOURCE_IO)

release_resource(r);

}

return ret;

}


3。对应设备驱动

在drivers/video/omap/lcd_omap3devkit8000.c,包含omap3_devkit8000_lcd启动模块,名称与添加设备的名称一直

struct platform_driver omap3_devkit8000_panel_driver = {

.probe = omap3_devkit8000_panel_probe,

.remove = omap3_devkit8000_panel_remove,

.suspend = omap3_devkit8000_panel_suspend,

.resume = omap3_devkit8000_panel_resume,

.driver = {

.name = "omap3_devkit8000_lcd",

.owner = THIS_MODULE,

},

};

      用platform_driver_register 向系统注册驱动程序时,会在s3c2410sdi_driver的信息里提取name为搜索内容,搜索系统注册的device中有没有这个 platform_device。 如果有注册,那么接着会执行platform_driver 里probe函数用的最多和刚才platform_device有关的语句是platform_get_resource,这条语句用于获取 platform_device里的resource资料.例如映射的IO地址,中断等,剩下等得就是ioremap,和 request_irq等的事情了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值