如何分析linux内核的驱动

思路:

  1. 在linux内核中,自带的驱动都以platform模型的形式设计的。
  2. 一般情况下,所有的platform device在一起定义,并且在一起注册。
  3. driver是设计成了不同的源文件。
  4. 因为device放在一起定义,比较好找,我们可以现在找到device,再找driver

步骤:

  1. 找到针对一个硬件平台的主初始化源文件(arch/arm/mach-XXXX/mach-XXXX.c
    如:rkpx3平台/arch/arm/mach-mach-rkpx3/board-rkpx3-sdk.c

2. 找主初始化源文件中的机器宏
这里写图片描述


3. 找到主初始化函数(kernel启动过程中,会调用的一个函数,做嵌入式平台的初始化)

static void __init machine_rk30_board_init(void)
{
...
platform_add_devices(devices, ARRAY_SIZE(devices));
...
}

分析platform_add_devices()

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]); //注册platform device
        if (ret) {
            while (--i >= 0) //while(i--)
                platform_device_unregister(devs[i]);
            break;
        }
    }

    return ret;
}

4. 找到platform device的总表–>devices

static struct platform_device *devices[] __initdata = {
#ifdef CONFIG_ION
    &device_ion,
#endif
#if defined(CONFIG_GPIO_DET)
    &hq_gpio_device,
#endif

#ifdef CONFIG_ANDROID_TIMED_GPIO
    &rk29_device_vibrator,
#endif
#ifdef CONFIG_LEDS_GPIO_PLATFORM
    &rk29_device_gpio_leds,
#endif
...
}

—->条件编译选项,条件编译选项在Kconfig中定义,通过make menuconfig给其赋值,赋值后保存在.config中,由Makefile来使用该值,以确定如何编译驱动程序。
.config—->在make过程中,会生成一个头文件/include/generated/autoconf.h
—>Makefile使用autoconf.h

这里写图片描述

5. 在总表中,找到platform device —>

 #ifdef CONFIG_VIDEO_REVERSE_IMAGE
    &device_vehicle,
#endif

这里写图片描述

6. 根据platform device找到platform driver

依据:二者是同名的

static struct platform_driver radio_tea6851a_pdriver = {
    .driver     = {
        .name   = "radio-si4713",
    },
    .probe      = radio_si4713_pdriver_probe,
    .remove         = __exit_p(radio_tea6851a_pdriver_remove),
};
  1. 分析probe函数
/* Platform driver interface */
/* radio_tea6851a_pdriver_probe - probe for the device */
static int radio_tea6851a_pdriver_probe(struct platform_device *pdev)
{
    printk("radio si probe\n");
    struct radio_tea6851a_platform_data *pdata = pdev->dev.platform_data;
    struct radio_tea6851_device *rsdev;
    struct i2c_adapter *adapter;
    struct v4l2_subdev *sd;
    int rval = 0;

    if (!pdata) {
        dev_err(&pdev->dev, "Cannot proceed without platform data.\n");
        rval = -EINVAL;
        goto exit;
    }

    rsdev = kzalloc(sizeof *rsdev, GFP_KERNEL);
    if (!rsdev) {
        dev_err(&pdev->dev, "Failed to alloc video device.\n");
        rval = -ENOMEM;
        goto exit;
    }
    printk("V4l2_device_register\n");
    rval = v4l2_device_register(&pdev->dev, &rsdev->v4l2_dev);
    if (rval) {
        dev_err(&pdev->dev, "Failed to register v4l2 device.\n");
        goto free_rsdev;
    }

    printk("i2c_get_adapter\n");
    adapter = i2c_get_adapter(pdata->i2c_bus);
    if (!adapter) {
        dev_err(&pdev->dev, "Cannot get i2c adapter %d\n",
                            pdata->i2c_bus);
        rval = -ENODEV;
        goto unregister_v4l2_dev;
    }

    printk("v4l2_i2c_new_subdev_board\n");
    sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
                    pdata->subdev_board_info, NULL);
    if (!sd) {
        dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
        rval = -ENODEV;
        goto put_adapter;
    }

    printk("video_device_alloc\n");
    rsdev->radio_dev = video_device_alloc();
    if (!rsdev->radio_dev) {
        dev_err(&pdev->dev, "Failed to alloc video device.\n");
        rval = -ENOMEM;
        goto put_adapter;
    }

    memcpy(rsdev->radio_dev, &radio_tea6851a_vdev_template,
            sizeof(radio_tea6851a_vdev_template));
    video_set_drvdata(rsdev->radio_dev, rsdev);
    printk("video_register_device\n");
    if (video_register_device(rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) {
        dev_err(&pdev->dev, "Could not register video device.\n");
        rval = -EIO;
        goto free_vdev;
    }
    dev_info(&pdev->dev, "New device successfully probed\n");

    goto exit;

free_vdev:
    video_device_release(rsdev->radio_dev);
put_adapter:
    i2c_put_adapter(adapter);
unregister_v4l2_dev:
    v4l2_device_unregister(&rsdev->v4l2_dev);
free_rsdev:
    kfree(rsdev);
exit:
    return rval;
}

prob分析待续。

猜你喜欢

转载自blog.csdn.net/qq_33487044/article/details/81459453