RS485在Linux内核(驱动)及全志T113平台上的实现(7)

接前一篇文章: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自动方向切换模式-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更多成员的解析,请看下回。

相关推荐
蓝天居士20 小时前
RS485在Linux内核(驱动)及全志T113平台上的实现(4)
串口·rs485·设备驱动
蓝天居士2 天前
RS485在Linux内核(驱动)及全志T113平台上的实现(5)
串口·rs485·设备驱动
蓝天居士15 天前
Linux网络驱动之Fixed-Link(7)
网卡·设备驱动
蓝天居士15 天前
Linux网络驱动之Fixed-Link(8)
网卡·设备驱动
Industio_触觉智能15 天前
触觉智能RV1126B核心板配置USB复合设备(下)
串口·acm·开发板·usb·rv1126b·ums·usb存储
蓝天居士19 天前
RTL8367RB芯片介绍(17)
网卡·设备驱动·芯片资料
同志啊为人民服务!1 个月前
RS485通信,无法进入中断处理程序,问题分析过程
单片机·编译器·rs485·中断处理程序
蓝天居士1 个月前
RTL8367RB芯片介绍(8)
网卡·设备驱动·芯片资料
ccut 第一混1 个月前
C# 基于 RS485 与设备通讯(以照度计为例子)
c#·rs485