How do I open/write/read a uart device from a kernel module?

帅比萌擦擦* 提交于 2019-12-11 06:34:34

问题


The device is a scanner. I know uart5 is setup in the dtsi file and in userspace it is listed under /dev/ttymxc4. From userspace, I understand that I can manipulate the device by

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;
}

And use termios to set all the settings like baudrate, write data using the write call etc.

I am wanting to abstract a lot of the commands under sysfs. I've setup a "uart driver" like this:

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);

And I am using gpio lines to turn on the system and a few other things. However, in the schematic, I do not see the gpio lines for these things.

UART5_CTS_HOST_SCAN_3_3V
UART5_RTS_HOST_SCAN_3_3V
UART5_RxD_HOST_SCAN_3_3V
UART5_TxD_HOST_SCAN_3_3V

I am just not sure how to open/write/read data from the device. I know about sys_open and similar calls, however, I know they are not the "right" way to do this; I don't want to have to go through userspace.

So, in summary how do I

  1. "choose" the /dev/ttymxc4 device in my module and
  2. open, set baud rate, and read/write data to the device?

Thanks! Please help! New to everything uart, I've dealt with i2c in the past and it seemed less complicated.


回答1:


Here's what I did. I am accessing the uart file from the kernel instead of using any kernel native method. This is cheating, but it works. So,

#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;
    }

I then use Sysfs to provide functionality to the user. Is this the right way to do it? Probably not, but it is working for my purposes. It is essentially moving the user-space way of implementing to the kernel.



来源:https://stackoverflow.com/questions/51045615/how-do-i-open-write-read-a-uart-device-from-a-kernel-module

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!