接前一篇文章:RS485在Linux内核(驱动)及全志T113平台上的实现(6)
本文内容参考:
RS485 Serial Communications --- The Linux Kernel documentation
Linux环境下RS-485驱动程序开发与实现-CSDN博客
【imx6ul】linux下rs485的使用_linux rs485-CSDN博客
全志R40 串口485 控制操作_485发送控制脚-CSDN博客
Allwinner T113 UART转485_t113 485配置-CSDN博客
特此致谢!
二、RS485内核(驱动)核心结构
上一回由struct uart_port讲到了其中最为核心的struct uart_ops。上一回也讲到了,该结构是串口驱动三大核心数据结构之一。本回开始对struct uart_ops进行讲解。为了便于理解和回顾,再次贴出struct uart_ops定义,在kernel/linux-5.10-origin/include/linux/serial_core.h中,如下:
cpp
/*
* This structure describes all the operations that can be done on the
* physical hardware. See Documentation/driver-api/serial/driver.rst for details.
*/
struct uart_ops {
unsigned int (*tx_empty)(struct uart_port *);
void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
unsigned int (*get_mctrl)(struct uart_port *);
void (*stop_tx)(struct uart_port *);
void (*start_tx)(struct uart_port *);
void (*throttle)(struct uart_port *);
void (*unthrottle)(struct uart_port *);
void (*send_xchar)(struct uart_port *, char ch);
void (*stop_rx)(struct uart_port *);
void (*enable_ms)(struct uart_port *);
void (*break_ctl)(struct uart_port *, int ctl);
int (*startup)(struct uart_port *);
void (*shutdown)(struct uart_port *);
void (*flush_buffer)(struct uart_port *);
void (*set_termios)(struct uart_port *, struct ktermios *new,
struct ktermios *old);
void (*set_ldisc)(struct uart_port *, struct ktermios *);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);
/*
* Return a string describing the type of the port
*/
const char *(*type)(struct uart_port *);
/*
* Release IO and memory resources used by the port.
* This includes iounmap if necessary.
*/
void (*release_port)(struct uart_port *);
/*
* Request IO and memory resources used by the port.
* This includes iomapping the port if necessary.
*/
int (*request_port)(struct uart_port *);
void (*config_port)(struct uart_port *, int);
int (*verify_port)(struct uart_port *, struct serial_struct *);
int (*ioctl)(struct uart_port *, unsigned int, unsigned long);
#ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct uart_port *);
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
#endif
};
前文书曾提到过,struct uart_ops是串口端口操作函数集,也就是UART底层操作函数集。其指向一组硬件相关的操作函数(发送数据、接收数据、设置波特率、中断处理等)。驱动必须实现这些函数才能让串口工作。不同的UART控制器(如8250、ttySAC、pl011等)会实现自己的struct uart_ops实例,内核通过统一的接口调用这些硬件相关的操作,实现 "上层统一、底层差异化" 的串口驱动架构。
下边就来逐一解析相关成员回调函数。
- unsigned int (*tx_empty)(struct uart_port *);
检查发送缓冲区是否为空。
- void (*set_mctrl)(struct uart_port *, unsigned int mctrl);
设置调制解调器控制信号。
- unsigned int (*get_mctrl)(struct uart_port *);
获取调制解调器控制信号。
- void (*stop_tx)(struct uart_port *);
停止发送。
- void (*start_tx)(struct uart_port *);
启动(开始)发送。
- void (*throttle)(struct uart_port *);
暂停接收(限流)。
throttle(字面意为 "节流 / 限流")是struct uart_ops中用于暂停串口数据接收的操作接口,当上层串口缓冲区(tty 层)即将满时,内核会调用这个函数,通知底层驱动停止接收新的数据,防止数据溢出丢失。throttle由内核tty层自动触发,驱动开发者无需主动调用,只需实现底层硬件操作逻辑。
对于支持硬件流控(RTS/CTS)的 UART,throttle除了关闭接收中断,还需控制RTS引脚(拉低),让发送方主动停止发送。
- void (*unthrottle)(struct uart_port *);
恢复接收(解除限流)。
throttle通常需要和unthrottle成对实现 ------ 只实现throttle会导致串口接收被暂停后无法恢复,数据传输中断。
- void (*send_xchar)(struct uart_port *, char ch);
发送xChar。
- void (*stop_rx)(struct uart_port *);
停止接收。
struct uart_ops更多成员的解析,请看下回。