C 如何从内核模块打开/写入/读取uart设备?
这个设备是扫描仪。我知道uart5是在dtsi文件中设置的,在用户空间中它列在/dev/ttymxc4下。从用户空间,我知道我可以通过C 如何从内核模块打开/写入/读取uart设备?,c,linux,module,kernel,uart,C,Linux,Module,Kernel,Uart,这个设备是扫描仪。我知道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; } 我用gpio线路打
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;
}
我用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和类似的调用,但是,我知道它们不是这样做的“正确”方式;我不想通过用户空间
总之,我该怎么做
谢谢!请帮忙!对于uart来说,一切都是新事物,我在过去处理过i2c,它似乎不那么复杂。以下是我所做的。我从内核访问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;
}
#定义扫描器UART”/dev/ttymxc4
...
静态整型扫描程序\u打开(结构索引节点*索引节点,结构文件*文件)
结构术语;
...
scanner_file=filp_open(scanner_UART,O_RDWR | O_NOCTTY | O_NONBLOCK,0);
...
if(串行扫描文件、TCGETS(无符号长期)和长期)小于0
{
pr_err(“%s:无法获取termios\n”,_函数);
返回-1;
}
term.c|cflag=B9600 | CLOCAL | CREAD;//115200如果更改,必须配置扫描仪
/*无奇偶校验(8N1)*/
term.c_cflag&=~PARENB;
term.c_cflag&=~CSTOPB;
term.c_cflag&=~CSIZE;
术语c|cflag |=CS8;
术语c|lflag&=~(ICANON | ECHO | ECHO | ISIG);
术语c_of lag&=~OPOST;
术语c|u iflag&=~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
term.c_cc[VTIME]=5;//0.5秒读取超时
term.c_cc[VMIN]=0;//读不阻塞
if(串行扫描文件、TCSETS(无符号长期)和长期)小于0
{
pr_err(“%s:设置termios\n失败”,函数);
返回-1;
}
...
静态常量结构文件\u操作扫描程序\u fops={
.owner=此_模块,
.write=扫描器\写入,
.read=扫描仪读取,
.open=扫描仪\u打开,
.release=scanner\u close,
.llseek=nollseek,
};
结构MISC设备扫描仪\u设备={
.minor=杂项动力minor,
.name=“扫描仪”,
.fops=&scanner\u fops,
};
...
ret=杂项寄存器(和扫描仪设备);
如果(ret){
pr_err(“无法杂项注册:(\n”);
返回ret;
}
然后,我使用Sysfs向用户提供功能。这是正确的方法吗?可能不是,但它符合我的目的。它本质上是将实现的用户空间方式移动到内核。正确的方法是通过“serdev”设备接口(
#include
),特别是对于基于设备树的系统。DT绑定记录在文档/devicetree/bindings/serial/slave device.txt
中。示例驱动程序包括驱动程序/mfd/rave-sp.c
,驱动程序/net/ethernet/qualcomm/qca_uart.c
和一些蓝牙驱动程序(grep用于serdevu设备
)。该产品是Motorala(Zebra)SE4500。想通过sysfs将其添加到Android中。内核是4.9,似乎不包括serdev。但是我正在尝试添加它,因为它是非常模块化的(到目前为止,构建正在编译)。你认为这是最好的解决方案还是有4.9“正确”的解决方案?谢谢。我不知道是否有其他解决方案4.9的“正确”解决方案,因为serdev接口自4.11以来是新的,之前没有任何等效的接口。后端口似乎是一个合理的选择。它是相当独立的,但不是完全独立的,因为需要更改“tty_port”代码来处理端口客户机功能和挂接“serdev”"内容。请参阅提交c3485ee0d560、c1c98dadb2de、cd6484e1830b、BED3C6DFA6A、8ee3fde04758作为初学者。后端口是否需要更改tty_port.c?tty
似乎内置于我的4.4-127 El Repo LT内核中。有没有更简单的方法?我只需要控制RTS pin…我尝试将serdev
编译为4.4.127下的模块。Unfo当然,它很快就变得复杂,并且触及了内置驱动程序的源代码。因此,看起来不像serdev
将是一个从内核模块控制UART RTS引脚的解决方案……您不应该从内核空间打开字符设备。相反,您可以使用类似于serdev的东西。有一些蓝牙驱动程序作为示例e、 请参阅对原始问题的评论。Serdev是声明的答案,但所使用的内核没有Serdev。这不是一个选项。
#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;
}