【问题标题】:How to use single platform driver for multiple instances of the same platform device?如何为同一平台设备的多个实例使用单一平台驱动程序?
【发布时间】:2019-08-22 02:51:55
【问题描述】:

如何将 alloc_chrdev_region 和 cdev_add 与平台驱动程序的探测功能分开,以便启动同一设备的多个实例?在哪里可以访问具有类似功能的相关平台驱动示例代码?

我有 4 个以相同方式工作的实例化设备。 通常我使用平台驱动来操作我的设备,但我的代码只能用.ko和insmod命令启动1个实例化设备,而不是同一设备的多个实例。

我试图重写我的代码。发现platform_driver的probe函数包括alloc_chrdev_region和cdev_add。我不知道如何将alloc_chrdev_region和cdev_add函数与platform_driver的probe函数分开。

以下代码是我设备的设备树:

mipi_csi2_rx_v_cap_pipeline_0: v_cap_pipeline@a0030000 {
compatible = "xlnx,v-cap-pipeline-1.0";
interrupt-names = "interrupt";
interrupt-parent = <&gic>;
interrupts = <0 104 4>;
reg = <0x0 0xa0030000 0x0 0x4000>;
xlnx,s-axi-chn-mst-num = <0x2>;
};
mipi_csi2_rx_v_cap_pipeline_1: v_cap_pipeline@a0034000 {
compatible = "xlnx,v-cap-pipeline-1.0";
interrupt-names = "interrupt";
interrupt-parent = <&gic>;
interrupts = <0 105 4>;
reg = <0x0 0xa0034000 0x0 0x4000>;
xlnx,s-axi-chn-mst-num = <0x2>;
};
mipi_csi2_rx_v_cap_pipeline_2: v_cap_pipeline@a0038000 {
compatible = "xlnx,v-cap-pipeline-1.0";
interrupt-names = "interrupt";
interrupt-parent = <&gic>;
interrupts = <0 106 4>;
reg = <0x0 0xa0038000 0x0 0x4000>;
xlnx,s-axi-chn-mst-num = <0x2>;
};
mipi_csi2_rx_v_cap_pipeline_3: v_cap_pipeline@a003c000 {
compatible = "xlnx,v-cap-pipeline-1.0";
interrupt-names = "interrupt";
interrupt-parent = <&gic>;
interrupts = <0 107 4>;
reg = <0x0 0xa003c000 0x0 0x4000>;
xlnx,s-axi-chn-mst-num = <0x2>;
};

以下示例代码是我的平台驱动程序的探测功能:

static int fstream_probe(struct platform_device *pdev) {
    struct device *dev = &pdev->dev;

    dev_t devno = MKDEV(fstream_major, 0);
    ret = alloc_chrdev_region(&devno, 0, DEV_NUM, DRIVER_NAME);
    fstream_major = MAJOR(devno);      
    cdevp = (struct fstream_cdev *) kzalloc(sizeof(struct fstream_cdev)*DEV_NUM, GFP_KERNEL);
    fstream_setup_cdev(cdevp);  

    ...
    /* others ignored */
    PDEBUG(" init success\n");;
}    

static struct of_device_id fstream_of_match[] = {
    {.compatible = "xlnx,v-cap-pipeline-1.0", },
    { /* end of list */ },
};
MODULE_DEVICE_TABLE(of, fstream_of_match);

static struct platform_driver fstream_driver = {
    .driver = {
        .name = DRIVER_NAME,
        .owner = THIS_MODULE,
        .of_match_table = fstream_of_match,
    },
    .probe      = fstream_probe,
    .remove     = fstream_remove,
};

static int __init fstream_init(void) {
    return platform_driver_register(&fstream_driver);
}

module_init(fstream_init);

当我的代码中的探测函数被调用 4 次时,在 /proc/devices 下创建了 4 个具有不同主要 id 的主要设备,这不是我所期望的(我想要 1 个主要 id 和 4 个不同的次要 id)。

以下消息是我设备的日志,它显示探测函数被调用了 4 次:

zynqmp#dmesg |grep fstream
[  111.769297] st_fstream: loading out-of-tree module taints kernel.
[  111.775514] st_fstream: unknown parameter 'st_fstream' ignored
[  111.781314] st_fstream: unknown parameter 'st_fstream' ignored
[  111.787429] [fstream]cdev Device number reg/allocation successed. cdev->major=243, cdev->minor=0.
[  111.787511] [fstream]@0xa0030000 mapped to 0xffffff800bbe0000, irq=46
[  111.787512] [fstream] init success
[  111.787572] [fstream]cdev Device number reg/allocation successed. cdev->major=242, cdev->minor=0.
[  111.787631] [fstream]@0xa0034000 mapped to 0xffffff800bbf0000, irq=47
[  111.787634] [fstream] init success
[  111.787671] [fstream]cdev Device number reg/allocation successed. cdev->major=241, cdev->minor=0.
[  111.787730] [fstream]@0xa0038000 mapped to 0xffffff800bc00000, irq=48
[  111.787732] [fstream] init success
[  111.787767] [fstream]cdev Device number reg/allocation successed. cdev->major=240, cdev->minor=0.
[  111.787826] [fstream]@0xa003c000 mapped to 0xffffff800bc10000, irq=49
[  111.787827] [fstream] init success

【问题讨论】:

  • 看起来你正在为 CSI-2 设备/管道做一个不正常的方法。您是否查看过 drivers/media/ 文件夹中的示例?
  • 你可以在你的模块初始化函数中调用alloc_chrdev_region来保留一个设备号范围,然后在你的探测函数中从你保留的范围内分配一个未使用的设备号。
  • @0andriy 是的,但是我发现这个目录中的大多数示例代码都与 v4l2 驱动程序相关联,这对我来说太重了。
  • @Ian Abbott 是的,我尝试了您的建议。现在我在 static int __init fstream_init(void){..} 中获得主 ID,并在 platform_driver 的 fstream_probe 函数中添加/初始化 cdev。在 DTS 中通过 4 个相同设备的实例化,我可以成功找到 4 个具有相同主要 ID 但不同次要 ID 的设备。但是,我发现其实这些cdev都是一样的……也就是说,如果我打开/dev/st_fstream0,或者/dev/st_fstream3,驱动只是打开同一个实例化……不知道怎么回事有了这个。
  • 驱动程序的“打开”文件操作处理程序(例如int mydriver_fop_open(struct inode *inode, struct file *file))在inode-&gt;i_rdev 中获取设备的主次编号组合。您应该能够使用它来检查正在打开的设备(例如,MINOR(inode-&gt;i_rdev) 告诉您次要编号)。将file-&gt;private_data 设置为指向您设备的私有数据,以供驱动程序的其他文件操作处理程序使用。

标签: linux-device-driver device-tree


【解决方案1】:

正如@Ian Abbott 建议的那样,在我的驱动程序代码中使用 cdev 和 pdev 时,我需要执行以下操作:

  1. 在static int __init fstream_init(void){..}中获取major id,并在platform_driver的fstream_probe函数中添加/初始化cdev。并且在DTS中同一个设备的4个实例化,我可以成功找到4个设备具有相同的主要 ID 但不同的次要 ID。

  2. 确保每个设备占用自己的全局数据结构,通过静态数组和次要ID来区分。

  3. 另外,使用file->private_data和container_of来打开和释放cdev。

它终于奏效了!谢谢大家!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多