lcd probe函数 赏析

本文深入解析s3c24xxfb_probe函数的内部结构及工作流程,重点介绍了s3c2410fb_info结构体的作用,并详细解释了s3c2410fb_mach_info如何在smdk2440_machine_init函数中被初始化并传递给pdev->dev.platform_data的过程。
static int __init s3c24xxfb_probe(struct platform_device *pdev,enum s3c_drv_type drv_type)
{
    /**
        s3c2410fb_info这个结构体主要将一些零散的全局变量,打包成一个结构体
        他的成员有:
                struct clk      *clk;         //时钟结构体
                struct resource *mem;         //保存设备资源
                void __iomem        *io;      //保存虚拟地址
                void __iomem        *irq_base;//保存中断号
                ......
    */
    struct s3c2410fb_info * info;
    struct s3c2410fb_display *display;
    /**
        很重要的结构体,每一个framebuffer驱动对应一个fb_info
        是lcd驱动的核心。后面会详细说
    */
    struct fb_info *fbinfo;
    struct s3c2410fb_mach_info *mach_info;
    struct resource *res;
    int ret;
    int irq;
    int i;
    int size;
    u32 lcdcon1;
    /**
        看,如果mach_info 为空了,那么程序就会出错退出了,
        那么,s3c2410fb_mach_info 是再什么时候 放到pdev->dev.platform_data中的呢?
        在/arch/arm/mach_s3c2440/mach_smdk2440.c文件中有一个函数smdk2440_machine_init()
        static void __init smdk2440_machine_init(void)
        {
            在这个函数中,将s3c2410fb_mach_info 放入到了s3c_device_lcd.dev.platform_data中。
            看看它的源码是怎么样实现的,下面还有附有一张图

            s3c24xx_fb_set_platdata(&smdk2440_fb_info)
            {
                struct s3c2410fb_mach_info *npd;
                npd = kmalloc(sizeof(*npd), GFP_KERNEL);为s3c2410fb_mach_info分配内存空间
                if (npd) {
                    memcpy(npd, pd, sizeof(*npd));
                        将传入的s3c2410fb_mach_info结构放入到 s3c_device_lcd.dev.platform_data中,
                        后面的probe函数会取出这个s3c2410fb_mach_info
                    s3c_device_lcd.dev.platform_data = npd;
                } else {
                    printk(KERN_ERR "no memory for LCD platform data\n");
                }
            }
            s3c_i2c0_set_platdata(NULL);
            platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));
            smdk_machine_init();
        }
    */
    mach_info = pdev->dev.platform_data;
    if (mach_info == NULL) {
        dev_err(&pdev->dev,"no platform data for lcd, cannot attach\n");
        return -EINVAL;
    }


}
probe函数是Linux设备驱动模型中的关键部分,它在设备与驱动匹配成功后被调用,用于完成设备的初始化工作。probe函数的执行次数和触发条件与设备和驱动的匹配机制密切相关。 ### probe函数的执行次数 probe函数的执行次数通常取决于设备和驱动的匹配情况。在大多数情况下,**probe函数只会执行一次**,即在设备和驱动第一次成功匹配时调用。然而,在某些特定场景下,probe函数可能会被多次执行: - **热插拔设备**:对于支持热插拔的设备(如USB设备),当设备被拔出后重新插入,系统会重新检测到设备并再次调用probe函数。 - **驱动模块卸载后重新加载**:如果驱动是以模块形式加载的,卸载模块后重新加载,probe函数也会再次执行。 - **多实例设备**:某些设备可能有多个独立的实例(如多个相同型号的硬件模块),每个实例都会触发一次probe函数的执行。 ### probe函数的执行条件 probe函数的执行依赖于设备与驱动的匹配机制,具体触发条件如下: - **设备与驱动匹配成功**:当内核检测到设备树中的设备节点与驱动程序中定义的`of_match_table`或`id_table`中的条目匹配时,会调用驱动的probe函数[^2]。 - **设备资源可用**:probe函数执行时会尝试申请设备所需的硬件资源(如内存、中断号等),如果这些资源当前不可用,probe函数可能会失败或延迟执行[^1]。 - **设备树配置正确**:设备树中必须正确配置设备的属性,如`compatible`字段必须与驱动支持的设备类型匹配。否则,probe函数不会被调用[^4]。 - **驱动模块加载成功**:probe函数的执行前提是驱动模块已经被成功加载到内核中。如果驱动以模块形式存在,必须先执行`insmod`或`modprobe`命令加载模块[^2]。 ### probe函数执行失败的可能原因 如果probe函数未能执行或执行失败,常见的原因包括: - **设备树配置错误**:设备树中的`compatible`字段与驱动不匹配,导致驱动无法识别设备[^4]。 - **硬件资源冲突**:设备所需的硬件资源(如GPIO、中断号)被其他设备占用,导致probe函数无法正常申请资源[^4]。 - **驱动模块未正确加载**:如果驱动模块未能成功加载到内核,probe函数自然不会执行。 ### 示例代码:probe函数的基本结构 以下是一个典型的probe函数实现示例,展示了如何初始化设备并申请资源: ```c static int my_device_probe(struct platform_device *pdev) { struct resource *res; void __iomem *regs; /* 获取设备资源 */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Failed to get memory resource\n"); return -ENODEV; } /* 映射寄存器地址 */ regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!regs) { dev_err(&pdev->dev, "Failed to ioremap registers\n"); return -ENOMEM; } /* 初始化设备 */ writel(0x1, regs + REG_OFFSET); dev_info(&pdev->dev, "Device initialized successfully\n"); return 0; } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值