Как использовать драйвер одной платформы для нескольких экземпляров одного и того же платформенного устройства?

Как отделить alloc_chrdev_region и cdev_add от функции проверки драйвера платформы, чтобы инициировать несколько экземпляров одного и того же устройства? И где я могу получить доступ к образцу кода соответствующего драйвера платформы с аналогичными возможностями?

У меня есть 4 экземпляра устройства, которые работают одинаково. Обычно я использую драйвер платформы для управления своим устройством, но имеющийся у меня код может инициировать только одно созданное устройство с помощью команд .ko и insmod, а не несколько экземпляров одного и того же устройства.

Я пытался переписать свой код. Я обнаружил, что функция проверки platform_driver включает alloc_chrdev_region и cdev_add. Я не знаю, как отделить функцию alloc_chrdev_region и cdev_add от функции проверки platform_driver.

Следующий код - это дерево устройств моего устройства:

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 основных устройства с разными основными идентификаторами, чего я не ожидал (мне нужен 1 основной идентификатор с 4 разными второстепенными идентификаторами).

Следующее сообщение - это журнал моего устройства, он показывает, что функции зонда вызываются 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

person vollerain    schedule 22.08.2019    source источник
comment
Похоже, вы применяете отклоняющийся подход к устройствам / конвейерам CSI-2. Вы искали примеры в папке drivers / media /?   -  person 0andriy    schedule 22.08.2019
comment
Вы можете вызвать alloc_chrdev_region в функции инициализации вашего модуля, чтобы зарезервировать диапазон номеров устройств, а затем назначить неиспользуемый номер устройства из вашего зарезервированного диапазона в функции проверки.   -  person Ian Abbott    schedule 22.08.2019
comment
@ 0andriy Да, но я обнаружил, что большая часть примеров кода в этом каталоге связана с драйвером v4l2, который для меня слишком тяжел.   -  person vollerain    schedule 01.09.2019
comment
@ Ян Эбботт: Да, я попробовал ваше предложение. Теперь я получаю основной идентификатор в static int __init fstream_init (void) {..} и добавляю / init cdev в функцию fstream_probe platform_driver. И с 4 экземплярами одного и того же устройства в DTS я могу успешно найти 4 устройства с одинаковым основным идентификатором, но с другим второстепенным идентификатором. Однако я обнаружил, что на самом деле эти cdev одинаковы ... То есть, если я открою / dev / st_fstream0 или / dev / st_fstream3, драйвер просто откроет тот же экземпляр ... Я не знаю, что не так с этим.   -  person vollerain    schedule 01.09.2019
comment
Обработчик операции с открытым файлом драйвера (например, int mydriver_fop_open(struct inode *inode, struct file *file)) получает объединенные старший и младший номер устройства в inode->i_rdev. Вы должны иметь возможность использовать это, чтобы проверить, какое устройство открывается (например, MINOR(inode->i_rdev) сообщает вам младший номер). Установите file->private_data, чтобы он указывал на личные данные вашего устройства для использования другими обработчиками файловых операций драйвера.   -  person Ian Abbott    schedule 02.09.2019
comment
@Ian Abbott Действительно спасибо! Ваше предложение, наконец, позволило моему коду нормально работать. Ты такой профессионал!   -  person vollerain    schedule 05.09.2019


Ответы (1)


Как предлагает @Ian Abbott, с cdev и pdev в моем коде драйвера мне нужно сделать следующее:

  1. Получите основной идентификатор в static int __init fstream_init (void) {..} и добавьте / init cdev в функции platform_driver fstream_probe. И с 4 экземплярами того же устройства в DTS я могу успешно найти 4 устройства с тем же основным идентификатором, но другой младший ID.

  2. Убедитесь, что каждое устройство занимает свою собственную глобальную структуру данных, используя статический массив и вспомогательный идентификатор, чтобы различать друг друга.

  3. Также используйте file-> private_data и container_of, чтобы открыть и выпустить cdev.

И это наконец-то работает! Спасибо всем!

person vollerain    schedule 05.09.2019