Как мне открыть / записать / прочитать устройство uart из модуля ядра? - PullRequest
0 голосов
/ 26 июня 2018

Устройство является сканером. Я знаю, что uart5 настроен в файле dtsi, а в пользовательском пространстве он указан в / dev / ttymxc4. Из пользовательского пространства я понимаю, что могу манипулировать устройством с помощью

fd = open("/dev/ttymxc5", O_RDWR|O_NOCTTY|O_NONBLOCK);
if (fd < 0)
{
    fprintf (stderr,"Open error on %s: %s\n", SCANNER_UART, strerror(errno));
    return nullptr;
}

И используйте termios для установки всех настроек, таких как скорость передачи данных, запись данных с помощью вызова записи и т. Д.

Я хочу абстрагироваться от многих команд в sysfs. Я настроил «драйвер UART», как это:

result = uart_register_driver(&scanner_reg);
if (result)
    return result;

result = uart_add_one_port(&scanner_reg, &scanner_port);
if (result)
    uart_unregister_driver(&scanner_reg);

И я использую линии gpio для включения системы и некоторых других вещей. Однако на схеме я не вижу линий gpio для этих вещей.

UART5_CTS_HOST_SCAN_3_3V
UART5_RTS_HOST_SCAN_3_3V
UART5_RxD_HOST_SCAN_3_3V
UART5_TxD_HOST_SCAN_3_3V

Я просто не уверен, как открыть / записать / прочитать данные с устройства. Я знаю о sys_open и подобных вызовах, однако я знаю, что это не "правильный" способ сделать это; Я не хочу проходить через пространство пользователя.

Итак, в целом, как мне

  1. «выбрать» устройство / dev / ttymxc4 в моем модуле и
  2. открыть, установить скорость передачи и считывать / записывать данные на устройство?

Спасибо! Пожалуйста помоги! Впервые в жизни, UART, я имел дело с i2c в прошлом, и он казался менее сложным.

1 Ответ

0 голосов
/ 16 июля 2019

Вот что я сделал. Я получаю доступ к файлу uart из ядра, а не использую какой-либо собственный метод ядра Это обман, но это работает. Таким образом,

#define SCANNER_UART "/dev/ttymxc4"
...
static int scanner_open(struct inode *inode, struct file *file)
    struct termios term;
...
    scanner_file = filp_open(SCANNER_UART, O_RDWR|O_NOCTTY|O_NONBLOCK, 0);
...
    if (serial_tty_ioctl(scanner_file, TCGETS, (unsigned long)&term) < 0)
    {
        pr_err("%s: Failed to get termios\n", __FUNCTION__);
        return -1;
    }

    term.c_cflag  = B9600 | CLOCAL | CREAD; // 115200 if change, must configure scanner

    /* No parity (8N1) */
    term.c_cflag &= ~PARENB;
    term.c_cflag &= ~CSTOPB;
    term.c_cflag &= ~CSIZE;
    term.c_cflag |= CS8;

    term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    term.c_oflag &= ~OPOST;

    term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);

    term.c_cc[VTIME] = 5; // 0.5 seconds read timeout
    term.c_cc[VMIN] = 0;  // read does not block

    if (serial_tty_ioctl(scanner_file, TCSETS, (unsigned long)&term) < 0)
    {
        pr_err("%s: Failed to set termios\n", __FUNCTION__);
        return -1;
    }
...
static const struct file_operations scanner_fops = {
    .owner          = THIS_MODULE,
    .write          = scanner_write,
    .read           = scanner_read,
    .open           = scanner_open,
    .release        = scanner_close,
    .llseek         = no_llseek,
};

struct miscdevice scanner_device = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "scanner",
    .fops = &scanner_fops,
};

...
    ret = misc_register(&scanner_device);
    if (ret) {
        pr_err("can't misc_register :(\n");
        return ret;
    }

Затем я использую Sysfs для предоставления функциональности пользователю. Это правильный способ сделать это? Наверное, нет, но это работает для моих целей. По сути, это перемещает способ реализации в пользовательском пространстве в ядро.

...