Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

serial: Support for RS-485 multipoint addresses

Add support for RS-485 multipoint addressing using 9th bit [*]. The
addressing mode is configured through ->rs485_config().

ADDRB in termios indicates 9th bit addressing mode is enabled. In this
mode, 9th bit is used to indicate an address (byte) within the
communication line. ADDRB can only be enabled/disabled through
->rs485_config() that is also responsible for setting the destination and
receiver (filter) addresses.

Add traps to detect unwanted changes to struct serial_rs485 layout using
static_assert().

[*] Technically, RS485 is just an electronic spec and does not itself
specify the 9th bit addressing mode but 9th bit seems at least
"semi-standard" way to do addressing with RS485.

Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://lore.kernel.org/r/20220624204210.11112-6-ilpo.jarvinen@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Ilpo Järvinen and committed by
Greg Kroah-Hartman
4f768e94 ae50bb27

+71 -4
+2
Documentation/driver-api/serial/driver.rst
··· 261 261 - parity enable 262 262 PARODD 263 263 - odd parity (when PARENB is in force) 264 + ADDRB 265 + - address bit (changed through .rs485_config()). 264 266 CREAD 265 267 - enable reception of characters (if not set, 266 268 still receive characters from the port, but
+25 -1
Documentation/driver-api/serial/serial-rs485.rst
··· 99 99 /* Error handling. See errno. */ 100 100 } 101 101 102 - 5. References 102 + 5. Multipoint Addressing 103 + ======================== 104 + 105 + The Linux kernel provides addressing mode for multipoint RS-485 serial 106 + communications line. The addressing mode is enabled with SER_RS485_ADDRB 107 + flag in serial_rs485. Struct serial_rs485 has two additional flags and 108 + fields for enabling receive and destination addresses. 109 + 110 + Address mode flags: 111 + - SER_RS485_ADDRB: Enabled addressing mode (sets also ADDRB in termios). 112 + - SER_RS485_ADDR_RECV: Receive (filter) address enabled. 113 + - SER_RS485_ADDR_DEST: Set destination address. 114 + 115 + Address fields (enabled with corresponding SER_RS485_ADDR_* flag): 116 + - addr_recv: Receive address. 117 + - addr_dest: Destination address. 118 + 119 + Once a receive address is set, the communication can occur only with the 120 + particular device and other peers are filtered out. It is left up to the 121 + receiver side to enforce the filtering. Receive address will be cleared 122 + if SER_RS485_ADDR_RECV is not set. 123 + 124 + Note: not all devices supporting RS485 support multipoint addressing. 125 + 126 + 6. References 103 127 ============= 104 128 105 129 [1] include/uapi/linux/serial.h
+21 -1
drivers/tty/serial/serial_core.c
··· 1288 1288 if (flags & ~port->rs485_supported->flags) 1289 1289 return -EINVAL; 1290 1290 1291 + /* Asking for address w/o addressing mode? */ 1292 + if (!(rs485->flags & SER_RS485_ADDRB) && 1293 + (rs485->flags & (SER_RS485_ADDR_RECV|SER_RS485_ADDR_DEST))) 1294 + return -EINVAL; 1295 + 1296 + /* Address given but not enabled? */ 1297 + if (!(rs485->flags & SER_RS485_ADDR_RECV) && rs485->addr_recv) 1298 + return -EINVAL; 1299 + if (!(rs485->flags & SER_RS485_ADDR_DEST) && rs485->addr_dest) 1300 + return -EINVAL; 1301 + 1291 1302 return 0; 1292 1303 } 1293 1304 ··· 1354 1343 rs485->flags &= supported_flags; 1355 1344 1356 1345 /* Return clean padding area to userspace */ 1357 - memset(rs485->padding, 0, sizeof(rs485->padding)); 1346 + memset(rs485->padding0, 0, sizeof(rs485->padding0)); 1347 + memset(rs485->padding1, 0, sizeof(rs485->padding1)); 1358 1348 } 1359 1349 1360 1350 int uart_rs485_config(struct uart_port *port) ··· 3413 3401 return 0; 3414 3402 } 3415 3403 EXPORT_SYMBOL_GPL(uart_get_rs485_mode); 3404 + 3405 + /* Compile-time assertions for serial_rs485 layout */ 3406 + static_assert(offsetof(struct serial_rs485, padding) == 3407 + (offsetof(struct serial_rs485, delay_rts_after_send) + sizeof(__u32))); 3408 + static_assert(offsetof(struct serial_rs485, padding1) == 3409 + offsetof(struct serial_rs485, padding[1])); 3410 + static_assert((offsetof(struct serial_rs485, padding[4]) + sizeof(__u32)) == 3411 + sizeof(struct serial_rs485)); 3416 3412 3417 3413 MODULE_DESCRIPTION("Serial driver core"); 3418 3414 MODULE_LICENSE("GPL");
+4
drivers/tty/tty_ioctl.c
··· 319 319 bits++; 320 320 if (cflag & PARENB) 321 321 bits++; 322 + if (cflag & ADDRB) 323 + bits++; 322 324 323 325 return bits; 324 326 } ··· 355 353 old_termios = tty->termios; 356 354 tty->termios = *new_termios; 357 355 unset_locked_termios(tty, &old_termios); 356 + /* Reset any ADDRB changes, ADDRB is changed through ->rs485_config() */ 357 + tty->termios.c_cflag ^= (tty->termios.c_cflag ^ old_termios.c_cflag) & ADDRB; 358 358 359 359 if (tty->ops->set_termios) 360 360 tty->ops->set_termios(tty, &old_termios);
+1
include/uapi/asm-generic/termbits-common.h
··· 46 46 #define EXTA B19200 47 47 #define EXTB B38400 48 48 49 + #define ADDRB 0x20000000 /* address bit */ 49 50 #define CMSPAR 0x40000000 /* mark or space (stick) parity */ 50 51 #define CRTSCTS 0x80000000 /* flow control */ 51 52
+18 -2
include/uapi/linux/serial.h
··· 126 126 #define SER_RS485_TERMINATE_BUS (1 << 5) /* Enable bus 127 127 termination 128 128 (if supported) */ 129 + 130 + /* RS-485 addressing mode */ 131 + #define SER_RS485_ADDRB (1 << 6) /* Enable addressing mode */ 132 + #define SER_RS485_ADDR_RECV (1 << 7) /* Receive address filter */ 133 + #define SER_RS485_ADDR_DEST (1 << 8) /* Destination address */ 134 + 129 135 __u32 delay_rts_before_send; /* Delay before send (milliseconds) */ 130 136 __u32 delay_rts_after_send; /* Delay after send (milliseconds) */ 131 - __u32 padding[5]; /* Memory is cheap, new structs 132 - are a royal PITA .. */ 137 + 138 + /* The fields below are defined by flags */ 139 + union { 140 + __u32 padding[5]; /* Memory is cheap, new structs are a pain */ 141 + 142 + struct { 143 + __u8 addr_recv; 144 + __u8 addr_dest; 145 + __u8 padding0[2]; 146 + __u32 padding1[4]; 147 + }; 148 + }; 133 149 }; 134 150 135 151 /*