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更多成员的解析,请看下回。

相关推荐
Strugglingler3 天前
【Linux PL011驱动支持RS485】
linux·uart·rs485·pl011
tzy2334 天前
Modbus:工业通信的“通用语言”
网络·串口·协议·modbus·rs-485·规约·iec 101
山木嵌入式4 天前
同步通信与异步通信(UART/USART):定义、原理、场景全解析
串口·嵌入式·uart·通信
小贺儿开发5 天前
Unity3D 串口通信上位机联调系统
unity·串口·协议·数据·通信·传输·互动
东成20225 天前
ch340驱动的串口可以寻址DMA吗
串口·dma·ch340
小灰灰搞电子6 天前
rt-thread UART串口使用详解
单片机·嵌入式硬件·串口
山木嵌入式8 天前
STM32 UART串口通信协议与3种底层驱动实现(寄存器/标准库/HAL库)
stm32·单片机·串口·uart
The_superstar610 天前
衡山派lvgl小练
串口·lvgl·衡山派·ds133ebs
小懒懒️17 天前
嵌入式常见通信协议——RS232,RS485
uart·rs232·rs485
星光202517 天前
APM学习(9):串口管理
串口·ardupilot