Блочное устройство - Получить устройство struct без использования функции зонда - PullRequest
0 голосов
/ 15 мая 2018

В настоящее время я изучаю программирование драйвера устройства linux и хотел бы управлять аппаратным устройством с помощью драйвера блочного устройства.

Мое аппаратное устройство использует три контакта для связи с окружающей средой

  • Часы - Выход -> Данные часы
  • Данные - двунаправленный -> Строка, которая передает данные в / из устройства
  • Мощность - выход -> Блок питания устройства

Это устройство использует собственный протокол. Он хранит данные, которые можно разделить на несколько файлов.

Что я сделал

В настоящее время я разработал символьное устройство, которое экспортируется в пользовательское пространство и реализует несколько ioctl. Затем я читаю / записываю данные с устройства на приложение пользователя, которое абстрагирует разделенную память устройства как одну зону памяти.

Реализованы следующие ioctl:

  • POWER_ON
  • power_off
  • СБРОС
  • SEND_COMMAND

Эта реализация полностью функциональна, и я хотел бы перейти к программированию драйвера устройства, преобразовав пару {char_driver, userspace_app} в драйвер устройства с одним блоком, который был бы доступен для чтения / записи напрямую.

Что я хочу сделать

Для драйвера char я заполнил дерево устройств соответствующей информацией, чтобы использовать его как platform_device . Информация о выводах ввода / вывода была загружена с него, и я использовал подсистемы gpio и regulator для определения ввода / вывода.

Я хотел бы реализовать драйвер блока по-другому, предоставив соответствующие контакты драйверу при вставке. Затем я буду использовать его как platform_device , но моя главная цель - понять основные механизмы, поэтому я хочу попробовать несколько решений.

Вот что я уже сделал

#define EMERG(fmt, ...)                printk(KERN_EMERG fmt, ##__VA_ARGS__)
#define ALERT(fmt, ...)                printk(KERN_ALERT fmt, ##__VA_ARGS__)
#define CRIT(fmt, ...)                 printk(KERN_CRIT fmt, ##__VA_ARGS__)
#define ERROR(fmt, ...)                printk(KERN_ERR fmt, ##__VA_ARGS__)
#define WARNING(fmt, ...)              printk(KERN_WARNING fmt, ##__VA_ARGS__)
#define NOTICE(fmt, ...)               printk(KERN_NOTICE fmt, ##__VA_ARGS__)
#define INFO(fmt, ...)                 printk(KERN_INFO fmt, ##__VA_ARGS__)
#define DEBUG(fmt, ...)                printk(KERN_DEBUG fmt, ##__VA_ARGS__)

/* Driver name */
#define DRIVER_NAME     "devtest"

#define GPIO_CLK_NAME       DRIVER_NAME"-clk"
#define GPIO_CLK_PIN        85
#define GPIO_IO_NAME        DRIVER_NAME"-io"
#define GPIO_IO_PIN         98
#define GPIO_RST_NAME       DRIVER_NAME"-rst"
#define GPIO_RST_PIN        73

static unsigned int device_counter = 0;

typedef struct {
    const char *name;
    int major;
    int minor;
    struct device *dev;
    struct regulator *power_reg;
}devtest_dev_t;

static int devtest_io_init(devtest_dev_t* devtest, unsigned int io_pin, unsigned int clk_pin, unsigned int rst_pin)
{
    int ret = 0;

    if(0 > devm_gpio_request(devtest->dev, io_pin, GPIO_IO_NAME))
    {
        ERROR("%s : Unable to allocate IO pin (%d)\n", DRIVER_NAME, clk_pin);
        ret = -EIO;
    }
    else if(0 > gpio_direction_input(io_pin))
    {
        ERROR("%s : Unable to set IO pin direction (%d)\n", DRIVER_NAME, io_pin);
        ret = -EIO;
    }
    else if(0 > devm_gpio_request(devtest->dev, clk_pin, GPIO_CLK_NAME))
    {
        ERROR("%s : Unable to allocate CLK pin (%d)\n", DRIVER_NAME, clk_pin);
        ret = -EIO;
    }
    else if(0 > gpio_direction_output(clk_pin, 0))
    {
        ERROR("%s : Unable to set CLK pin direction (%d)\n", DRIVER_NAME, clk_pin);
        ret = -EIO;
    }
    else if(0 > devm_gpio_request(devtest->dev, rst_pin, GPIO_RST_NAME))
    {
        ERROR("%s : Unable to allocate RST pin (%d)\n", DRIVER_NAME, rst_pin);
        ret = -EIO;
    }
    else if(0 > gpio_direction_output(rst_pin, 0))
    {
        ERROR("%s : Unable to set RST pin direction (%d)\n", DRIVER_NAME, rst_pin);
        ret = -EIO;
    }

    return ret;
}

static int __init devtest_init(void)
{
    struct regulator *pwr_reg = NULL;
    nf4tag_dev_t* self = NULL;

    if(NULL == (self = vmalloc(sizeof(devtest_dev_t))))
    {
        ERROR("%s : Unable to allocate memory for device\n", DRIVER_NAME);
        return -1;
    }
    memset(self, 0, sizeof(devtest_dev_t));
    DEBUG("%s : Device allocated and initialized\n", DRIVER_NAME);

    if(NULL == (self->dev = vmalloc(sizeof(struct device))))
    {
        ERROR("%s : Unable to allocate memory for device structure\n", DRIVER_NAME);
        return -2;
    }
    DEBUG("%s : Device struct allocated (%p)\n", DRIVER_NAME, self->dev);

    if(NULL == (pwr_reg = devm_regulator_get(self->dev, "power_regulator")))
    {
        ERROR("%s : Unable to allocate power regulator\n", DRIVER_NAME);
        return -EIO;
    }
    self->power_reg = pwr_reg;
    DEBUG("%s : Power regulator initialized\n", DRIVER_NAME);

    if(0 > devtest_io_init(self, GPIO_IO_PIN, GPIO_CLK_PIN, GPIO_RST_PIN))
    {
        ERROR("%s : Unable to allocate gpios\n", DRIVER_NAME);
        return -EIO;
    }
    DEBUG("%s : gpios allocated\n", DRIVER_NAME);

    device_counter += 1;

    return 0;
}
module_init(devtest_init);

С помощью этой реализации я могу выделить gpios, но у меня возникли проблемы с подсистемой регулятора, так как у меня есть ядро ​​Ой при его вставке.

# insmod devtest.ko 
devtest: loading out-of-tree module taints kernel.
devtest : Device allocated and initialized
devtest : Device struct allocated (e089d000)
Unable to handle kernel paging request at virtual address e8bd8028
pgd = d4574000
[e8bd8028] *pgd=00000000
Internal error: Oops: 5 [#1] ARM
Modules linked in: nf4(O+)
CPU: 0 PID: 217 Comm: insmod Tainted: G           O    4.9.30 #1
Hardware name: Atmel SAMA5
task: d457b400 task.stack: d44f4000
PC is at __of_find_property+0x10/0x64
LR is at of_phandle_iterator_init+0x38/0x8c
pc : [<c03f4e98>]    lr : [<c03f69b4>]    psr: a00d0093
sp : d44f5cb8  ip : 00000000  fp : 00000001
r10: 00000000  r9 : 00280000  r8 : 00000000
r7 : d44f5d80  r6 : d44f5ccc  r5 : e8bd8010  r4 : d44f5cf4
r3 : 00000000  r2 : d44f5ccc  r1 : d44f5d80  r0 : e8bd8010
Flags: NzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment none
Control: 10c53c7d  Table: 34574059  DAC: 00000051
Process insmod (pid: 217, stack limit = 0xd44f4208)
Stack: (0xd44f5cb8 to 0xd44f6000)
5ca0:                                                       d44f5cf4 e8bd8010
5cc0: 400d0013 c03f69b4 ffffffff d44f5d0c e089d000 00000000 d44f5dbc c084af48
5ce0: bf000110 c03f6c38 00000000 00000000 bf00010f 00000000 00000000 00000000
5d00: 00000000 00000000 00000000 00000000 00000000 00000000 c05a702c e089d000
5d20: bf000110 c03f6d00 00000000 d44f5d30 00000020 d44f5d80 ffffff00 ffff0a00
5d40: c083b7a0 e089d000 bf000110 d44f5dbc c084af48 bf000110 00280000 00000000
5d60: 00000001 c02c3fcc e089d000 d44f5d7c d44f5dbc c0305648 c05a702c c0305658
5d80: 65776f70 65725f72 616c7567 2d726f74 70707573 0000796c 00000000 600d0013
5da0: 00000000 00000000 e089d000 e089d000 c084af48 c0308e58 bf000348 ffffffed
5dc0: 00000000 00000000 d4518050 e089d000 bf000110 00000000 00000001 2bae759c
5de0: bf000300 c030b080 e089b000 bf002000 d4516240 bf000348 00000000 bf0020a0
5e00: bf000300 c01016e0 d45b3c00 c084e7cc 00000001 a00e0013 d4851000 c05a23c4
5e20: 00000000 d45b3c00 d40bb800 c0812f98 c0812f98 c01a1088 00000012 d4516280
5e40: 00000001 a00e0013 d4516240 e0898000 00000001 d4518a80 bf000300 00000001
5e60: d4516240 bf000348 d4518a80 c016b5bc 00000001 2bae759c d44f5f54 00000001
5e80: d4518a88 c0160720 bf00030c 00007fff bf000300 c015e0e4 bf00030c 000003e8
5ea0: bf000450 e0899610 c05015f0 bf00030c 00000000 00000000 d44f5f48 d44f5f44
5ec0: 00001688 c01ac6f4 00001688 00000000 00000000 00000000 00000000 00000000
5ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
5f00: 00000000 00000000 7fffffff 00000000 00000003 00093008 0000017b c0107664
5f20: d44f4000 00000000 00000000 c0160d40 7fffffff 00000000 00000003 a00e0013
5f40: d45506c0 e0898000 00001688 00000000 00000020 e0898000 00001688 e08992a0
5f60: e089918c e0898c84 00000484 000004c4 00000000 00000000 00000000 000008a0
5f80: 00000016 00000017 00000010 00000000 0000000d 00000000 00093008 bef79f3e
5fa0: 00000002 c01074a0 00093008 bef79f3e 00000003 00093008 00000000 bef79f3e
5fc0: 00093008 bef79f3e 00000002 0000017b bef79f3e 00000000 b6fc5000 00000000
5fe0: bef79ca0 bef79c90 0001f899 b6f43972 800e0030 00000003 00000000 00000000
[<c03f4e98>] (__of_find_property) from [<c03f69b4>] (of_phandle_iterator_init+0x38/0x8c)
[<c03f69b4>] (of_phandle_iterator_init) from [<c03f6c38>] (__of_parse_phandle_with_args+0x24/0xc4)
[<c03f6c38>] (__of_parse_phandle_with_args) from [<c03f6d00>] (of_parse_phandle+0x28/0x4c)
[<c03f6d00>] (of_parse_phandle) from [<c0305658>] (regulator_dev_lookup+0x60/0x190)
[<c0305658>] (regulator_dev_lookup) from [<c0308e58>] (_regulator_get+0x60/0x264)
[<c0308e58>] (_regulator_get) from [<c030b080>] (_devm_regulator_get+0x9c/0xc0)
[<c030b080>] (_devm_regulator_get) from [<bf0020a0>] (nf4tag_init+0xa0/0x260 [nf4])
[<bf0020a0>] (devtest_init [nf4]) from [<c01016e0>] (do_one_initcall+0x40/0x170)
[<c01016e0>] (do_one_initcall) from [<c016b5bc>] (do_init_module+0x60/0x1b0)
[<c016b5bc>] (do_init_module) from [<c0160720>] (load_module+0x1b74/0x1f80)
[<c0160720>] (load_module) from [<c0160d40>] (SyS_finit_module+0xa8/0xb8)
[<c0160d40>] (SyS_finit_module) from [<c01074a0>] (ret_fast_syscall+0x0/0x3c)
Code: e3500000 012fff1e e92d4070 e1a06002 (e5904018) 
---[ end trace 39a2cd9292b80271 ]---

Очевидно, что я чего-то не понимаю. Я думаю, что проблема в том, что используемый struct device выделен, но никогда не инициализирован, поэтому функция devm_regulator_get не может найти регулятор с именем 'power_regulator'.

Итак, мои вопросы:

  • Правильно ли мое предположение?
  • Можно ли использовать struct regulator, когда драйвер устройства не проверяется?
  • Если да, то как это сделать?
  • Если нет, то какая лучшая альтернатива?
...