dts 修改:
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&uart2_pins_a>;
rts-gpio = <&pio 4 10 GPIO_ACTIVE_HIGH>; //PE10
rs485-rts-active-high;
rs485-rts-delay = <0 0>;
linux,rs485-enabled-at-boot-time;
status = "okay";
};
https://gist.github.com/amarburg/07564916d8d32e20e6ae375c1c83a995
测试代码:
/*
* Test program Linux RS485-mode ioctls.
*
* cc -o rs485_mode rs485_mode.c
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <linux/serial.h>
/* RS485 ioctls: */
#define TIOCGRS485 0x542E
#define TIOCSRS485 0x542F
int main( int argc, char **argv )
{
unsigned int i;
char buf[80];
if( argc < 3 ) {
printf("Usage: %s [port name] [0|1]\n", argv[0]);
exit(0);
}
int enable = atoi( argv[2] );
char *port = argv[1];
int fd = open(port, O_RDWR);
if (fd < 0) {
/* Error handling. See errno. */
fprintf( stderr, "Error opening port \"%s\" (%d): %s\n", port, errno, strerror( errno ));
exit(-1);
}
struct serial_rs485 rs485conf;
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
fprintf( stderr, "Error reading ioctl port (%d): %s\n", errno, strerror( errno ));
}
printf("Port currently RS485 mode is %s\n", (rs485conf.flags & SER_RS485_ENABLED) ? "set" : "NOT set");
if( enable ) {
printf("RS485 mode will be SET\n");
rs485conf.flags |= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND;
} else {
printf("RS485 mode will be UNSET\n");
rs485conf.flags &= ~SER_RS485_ENABLED;
}
if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
fprintf( stderr, "Error sending ioctl port (%d): %s\n", errno, strerror( errno ));
}
/* Use read() and write() syscalls here... */
if (ioctl (fd, TIOCGRS485, &rs485conf) < 0) {
fprintf( stderr, "Error reading ioctl port (%d): %s\n", errno, strerror( errno ));
}
printf("Confirm RS485 mode is %s\n", (rs485conf.flags & SER_RS485_ENABLED) ? "set" : "NOT set");
/* Do something on the serial port... */
for( i = 0; i < 100; ++i ) {
snprintf( buf,79, "%d\r\n", i );
write( fd, buf, strlen(buf));
sleep(1);
}
/* Close the device when finished: */
if (close (fd) < 0) {
fprintf( stderr, "Error closing port (%d): %s\n", errno, strerror( errno ));
}
exit(0);
}
测试命令:
# rs485test /dev/ttyS2 1
Port currently RS485 mode is NOT set
RS485 mode will be SET
Error sending ioctl port (25): Inappropriate ioctl for device
Confirm RS485 mode is NOT set
在线
serial_core.c 参与了编译, ioctl 命令实现了 TIOCGRS485, TIOCSRS485
https://github.com/torvalds/linux/blob/master/drivers/tty/serial/serial_core.c
/*
* Called via sys_ioctl. We can use spin_lock_irq() here.
*/
static int
uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
{
struct uart_state *state = tty->driver_data;
struct tty_port *port = &state->port;
struct uart_port *uport;
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
/*
* These ioctls don't rely on the hardware to be present.
*/
switch (cmd) {
case TIOCSERCONFIG:
down_write(&tty->termios_rwsem);
ret = uart_do_autoconfig(tty, state);
up_write(&tty->termios_rwsem);
break;
}
if (ret != -ENOIOCTLCMD)
goto out;
if (tty_io_error(tty)) {
ret = -EIO;
goto out;
}
/*
* The following should only be used when hardware is present.
*/
switch (cmd) {
case TIOCMIWAIT:
ret = uart_wait_modem_status(state, arg);
break;
}
if (ret != -ENOIOCTLCMD)
goto out;
mutex_lock(&port->mutex);
uport = uart_port_check(state);
if (!uport || tty_io_error(tty)) {
ret = -EIO;
goto out_up;
}
/*
* All these rely on hardware being present and need to be
* protected against the tty being hung up.
*/
switch (cmd) {
case TIOCSERGETLSR: /* Get line status register */
ret = uart_get_lsr_info(tty, state, uarg);
break;
case TIOCGRS485:
ret = uart_get_rs485_config(uport, uarg);
break;
case TIOCSRS485:
ret = uart_set_rs485_config(uport, uarg);
break;
case TIOCSISO7816:
ret = uart_set_iso7816_config(state->uart_port, uarg);
break;
case TIOCGISO7816:
ret = uart_get_iso7816_config(state->uart_port, uarg);
break;
default:
if (uport->ops->ioctl)
ret = uport->ops->ioctl(uport, cmd, arg);
break;
}
out_up:
mutex_unlock(&port->mutex);
out:
return ret;
}
接下来再跟踪一下
在线