问题
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
- "choose" the /dev/ttymxc4 device in my module and
- 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