Camera 驱动加载

来源:互联网 发布:手机网络共享怎么设置 编辑:程序博客网 时间:2024/06/04 19:37

一、概述

  一般在 Linux 设备驱动模型中,我们只需要关心总线、设备、驱动这三个实体。总线会充当红娘对加载于其上的设备与驱动进行配对,对于 Camera 模块也不例外,下面从总线、设备、驱动的角度来分析 Camera 模块驱动的注册、匹配与加载过程。本文以MTK平台为例。

二、驱动加载过程

  驱动加载都是以module_init(XXX)开始,如下所示:

module_init(CAMERA_HW_i2C_init);

1、入口函数

/*=======================================================  * CAMERA_HW_i2C_init()  *======================================================*/static int __init CAMERA_HW_i2C_init(void){    PK_DBG("[camerahw_probe] start\n");#ifndef CONFIG_OF    int ret = 0;    //注册平台总线的设备    ret = platform_device_register(&camerahw_platform_device);    if (ret) {        PK_ERR("[camerahw_probe] platform_device_register fail\n");        return ret;    }    ret = platform_device_register(&camerahw2_platform_device);    if (ret) {        PK_ERR("[camerahw2_probe] platform_device_register fail\n");        return ret;    }#endif    //注册平台总线的驱动    if (platform_driver_register(&g_stCAMERA_HW_Driver)) {        PK_ERR("failed to register CAMERA_HW driver\n");        return -ENODEV;    }    if (platform_driver_register(&g_stCAMERA_HW_Driver2)) {        PK_ERR("failed to register CAMERA_HW driver\n");        return -ENODEV;    }    /* FIX-ME: linux-3.10 procfs API changed *///在proc下创建driver/camsensor这个节点,用于前置摄像头进行adb效果调试    proc_create("driver/camsensor", 0, NULL, &fcamera_proc_fops);//在proc下创建driver/camsensor2这个节点,用于后置摄像头进行adb效果调试    proc_create("driver/camsensor2", 0, NULL, &fcamera_proc_fops2);    proc_create("driver/camsensor3", 0, NULL, &fcamera_proc_fops3);    /* Camera information */    memset(mtk_ccm_name, 0, camera_info_size);    proc_create(PROC_CAMERA_INFO, 0, NULL, &fcamera_proc_fops1);    …………    return 0;}

  CAMERA_HW_i2C_init函数主要做的是首先要进行I2C总线板极设备的注册及初始化工作,然后注册platform总线的driver,通过g_stCAMERA_HW_Driver结构体里面的name来与device进行匹配。同时,在函数里面还在proc目录下创建了driver/camsensor和driver/camsensor2两个节点,这样做主要是方便sensor的IC原厂FAE利用adb进行效果调试的。

2、g_stCAMERA_HW_Driver结构体

static struct platform_driver g_stCAMERA_HW_Driver = {    .probe      = CAMERA_HW_probe,//匹配成功则调用    .remove     = CAMERA_HW_remove,    .suspend    = CAMERA_HW_suspend,//休眠时调用    .resume     = CAMERA_HW_resume,//唤醒时调用    .driver     = {        .name   = "image_sensor",        .owner  = THIS_MODULE,#ifdef CONFIG_OF        .of_match_table = CAMERA_HW_of_ids,#endif    }};

  g_stCAMERA_HW_Driver结构体中主要有probe、remove、suspend等接口的实现,尤其是probe接口为设备注册的匹配函数,在driver与device匹配后就会调用 .probe = CAMERA_HW_probe进入CAMERA_HW_probe函数。

3、探测函数CAMERA_HW_probe

static int CAMERA_HW_probe(struct platform_device *pdev){#if !defined(CONFIG_MTK_CLKMGR)    Get_ccf_clk(pdev);#endif#if !defined(CONFIG_MTK_LEGACY)/*GPIO Pin control*/    mtkcam_gpio_init(pdev);//GPIO管脚通过pinctl进行初始化#endif    //注册I2C驱动    return i2c_add_driver(&CAMERA_HW_i2c_driver);}

4、CAMERA_HW_i2c_driver结构体

struct i2c_driver CAMERA_HW_i2c_driver = {    .probe = CAMERA_HW_i2c_probe,    .remove = CAMERA_HW_i2c_remove,    .driver = {        .name = CAMERA_HW_DRVNAME1,        .owner = THIS_MODULE,#ifdef CONFIG_OF        .of_match_table = CAMERA_HW_i2c_of_ids,#endif    },    .id_table = CAMERA_HW_i2c_id,};

  sensor驱动最终还是会注册I2C设备,I2C总线的注册其实跟platform总线的注册大致相同,注册完I2C driver后就会进行匹配,匹配成功后系统就会调用CAMERA_HW_i2c_driver 结构体里面的 .probe = CAMERA_HW_i2c_probe。

5、探测函数CAMERA_HW_probe

static int CAMERA_HW_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id){    int i4RetValue = 0;    PK_DBG("[CAMERA_HW] Attach I2C\n");    /* get sensor i2c client */    spin_lock(&kdsensor_drv_lock);    g_pstI2Cclient = client;    /* set I2C clock rate */    g_pstI2Cclient->timing = 100;/* 100k */    g_pstI2Cclient->ext_flag &= ~I2C_POLLING_FLAG; /* No I2C polling busy waiting */    spin_unlock(&kdsensor_drv_lock);    /* Register char driver */    i4RetValue = RegisterCAMERA_HWCharDrv();//注册一个字符设备    if (i4RetValue) {        PK_ERR("[CAMERA_HW] register char device failed!\n");        return i4RetValue;    }    /* spin_lock_init(&g_CamHWLock); */#if !defined(CONFIG_MTK_LEGACY)    Get_Cam_Regulator();//获取电源#endif    PK_DBG("[CAMERA_HW] Attached!!\n");    return 0;}

6、字符设备注册

static inline int RegisterCAMERA_HWCharDrv(void){#if CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO    // 动态分配一个字符设备    if (alloc_chrdev_region(&g_CAMERA_HWdevno, 0, 1, CAMERA_HW_DRVNAME1)) {        PK_DBG("[CAMERA SENSOR] Allocate device no failed\n");        return -EAGAIN;    }#else    // 静态分配一个字符设备    if (register_chrdev_region(g_CAMERA_HWdevno , 1 , CAMERA_HW_DRVNAME1)) {        PK_DBG("[CAMERA SENSOR] Register device no failed\n");        return -EAGAIN;    }#endif    /* Allocate driver */    g_pCAMERA_HW_CharDrv = cdev_alloc(); // 申请一个cdev结构体    if (NULL == g_pCAMERA_HW_CharDrv) {        unregister_chrdev_region(g_CAMERA_HWdevno, 1);        PK_DBG("[CAMERA SENSOR] Allocate mem for kobject failed\n");        return -ENOMEM;    }    /* Attatch file operation. */    //关联到file_operation进入字符设备    cdev_init(g_pCAMERA_HW_CharDrv, &g_stCAMERA_HW_fops);    g_pCAMERA_HW_CharDrv->owner = THIS_MODULE;    /* Add to system */    //将我们分配的字符设备,attach上file_operation添加到system    if (cdev_add(g_pCAMERA_HW_CharDrv, g_CAMERA_HWdevno, 1)) {        PK_DBG("[mt6516_IDP] Attatch file operation failed\n");        unregister_chrdev_region(g_CAMERA_HWdevno, 1);        return -EAGAIN;    }    //创建一个sensordrv类    sensor_class = class_create(THIS_MODULE, "sensordrv");    if (IS_ERR(sensor_class)) {        int ret = PTR_ERR(sensor_class);        PK_DBG("Unable to create class, err = %d\n", ret);        return ret;    }    sensor_device = device_create(sensor_class, NULL, g_CAMERA_HWdevno, NULL, CAMERA_HW_DRVNAME1);    return 0;}

  camera的模块驱动为字符驱动,所以RegisterCAMERA_HWCharDrv函数主要是对camera_image进行字符驱动注册,代码开始先判断是否定义了CAMERA_HW_DYNAMIC_ALLOCATE_DEVNO变量来判断动态还是静态分配一个字符设备,然后通过cdev_alloc申请了一个cdev结构体后,通过cdev_init将g_stCAMERA_HW_fops关联到字符设备,g_stCAMERA_HW_fops是HAL层与内核驱动进行交互的渠道。然后就是将我们分配的字符设备,attach上file_operation添加到system,最后在sys/class目录下创建一个sensordrv类。

三、总结

  到目前为止,我们大致了解camera驱动模块大致的加载过程,值得注意的是注册字符设备时,关联着结构体g_stCAMERA_HW_fops;下一篇将围绕这个结构体,一起分析HAL层与驱动的交互过程

0 0
原创粉丝点击