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

接前一篇文章:RS485在Linux内核(驱动)及全志T113平台上的实现(3)

本文内容参考:

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内核(驱动)核心结构

上一回结合官方文档(RS485 Serial Communications --- The Linux Kernel documentation)讲完了核心数据结构struct rs485_serial。本回对其它相关结构进行讲解。

前文书已经讲过:

之前将重点放在了struct rs485_serial上,现在重点关注struct uart_port以及其中的rs485_config。

先来看struct uart_port。其在kernel/linux-5.10-origin/include/linux/serial_core.h中定义,如下:

cpp 复制代码
struct uart_port {
	spinlock_t		lock;			/* port lock */
	unsigned long		iobase;			/* in/out[bwl] */
	unsigned char __iomem	*membase;		/* read/write[bwl] */
	unsigned int		(*serial_in)(struct uart_port *, int);
	void			(*serial_out)(struct uart_port *, int, int);
	void			(*set_termios)(struct uart_port *,
				               struct ktermios *new,
				               struct ktermios *old);
	void			(*set_ldisc)(struct uart_port *,
					     struct ktermios *);
	unsigned int		(*get_mctrl)(struct uart_port *);
	void			(*set_mctrl)(struct uart_port *, unsigned int);
	unsigned int		(*get_divisor)(struct uart_port *,
					       unsigned int baud,
					       unsigned int *frac);
	void			(*set_divisor)(struct uart_port *,
					       unsigned int baud,
					       unsigned int quot,
					       unsigned int quot_frac);
	int			(*startup)(struct uart_port *port);
	void			(*shutdown)(struct uart_port *port);
	void			(*throttle)(struct uart_port *port);
	void			(*unthrottle)(struct uart_port *port);
	int			(*handle_irq)(struct uart_port *);
	void			(*pm)(struct uart_port *, unsigned int state,
				      unsigned int old);
	void			(*handle_break)(struct uart_port *);
	int			(*rs485_config)(struct uart_port *,
						struct serial_rs485 *rs485);
	int			(*iso7816_config)(struct uart_port *,
						  struct serial_iso7816 *iso7816);
	unsigned int		irq;			/* irq number */
	unsigned long		irqflags;		/* irq flags  */
	unsigned int		uartclk;		/* base uart clock */
	unsigned int		fifosize;		/* tx fifo size */
	unsigned char		x_char;			/* xon/xoff char */
	unsigned char		regshift;		/* reg offset shift */
	unsigned char		iotype;			/* io access style */
	unsigned char		quirks;			/* internal quirks */

#define UPIO_PORT		(SERIAL_IO_PORT)	/* 8b I/O port access */
#define UPIO_HUB6		(SERIAL_IO_HUB6)	/* Hub6 ISA card */
#define UPIO_MEM		(SERIAL_IO_MEM)		/* driver-specific */
#define UPIO_MEM32		(SERIAL_IO_MEM32)	/* 32b little endian */
#define UPIO_AU			(SERIAL_IO_AU)		/* Au1x00 and RT288x type IO */
#define UPIO_TSI		(SERIAL_IO_TSI)		/* Tsi108/109 type IO */
#define UPIO_MEM32BE		(SERIAL_IO_MEM32BE)	/* 32b big endian */
#define UPIO_MEM16		(SERIAL_IO_MEM16)	/* 16b little endian */

	/* quirks must be updated while holding port mutex */
#define UPQ_NO_TXEN_TEST	BIT(0)

	unsigned int		read_status_mask;	/* driver specific */
	unsigned int		ignore_status_mask;	/* driver specific */
	struct uart_state	*state;			/* pointer to parent state */
	struct uart_icount	icount;			/* statistics */

	struct console		*cons;			/* struct console, if any */
	/* flags must be updated while holding port mutex */
	upf_t			flags;

	/*
	 * These flags must be equivalent to the flags defined in
	 * include/uapi/linux/tty_flags.h which are the userspace definitions
	 * assigned from the serial_struct flags in uart_set_info()
	 * [for bit definitions in the UPF_CHANGE_MASK]
	 *
	 * Bits [0..UPF_LAST_USER] are userspace defined/visible/changeable
	 * The remaining bits are serial-core specific and not modifiable by
	 * userspace.
	 */
#define UPF_FOURPORT		((__force upf_t) ASYNC_FOURPORT       /* 1  */ )
#define UPF_SAK			((__force upf_t) ASYNC_SAK            /* 2  */ )
#define UPF_SPD_HI		((__force upf_t) ASYNC_SPD_HI         /* 4  */ )
#define UPF_SPD_VHI		((__force upf_t) ASYNC_SPD_VHI        /* 5  */ )
#define UPF_SPD_CUST		((__force upf_t) ASYNC_SPD_CUST   /* 0x0030 */ )
#define UPF_SPD_WARP		((__force upf_t) ASYNC_SPD_WARP   /* 0x1010 */ )
#define UPF_SPD_MASK		((__force upf_t) ASYNC_SPD_MASK   /* 0x1030 */ )
#define UPF_SKIP_TEST		((__force upf_t) ASYNC_SKIP_TEST      /* 6  */ )
#define UPF_AUTO_IRQ		((__force upf_t) ASYNC_AUTO_IRQ       /* 7  */ )
#define UPF_HARDPPS_CD		((__force upf_t) ASYNC_HARDPPS_CD     /* 11 */ )
#define UPF_SPD_SHI		((__force upf_t) ASYNC_SPD_SHI        /* 12 */ )
#define UPF_LOW_LATENCY		((__force upf_t) ASYNC_LOW_LATENCY    /* 13 */ )
#define UPF_BUGGY_UART		((__force upf_t) ASYNC_BUGGY_UART     /* 14 */ )
#define UPF_MAGIC_MULTIPLIER	((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ )

#define UPF_NO_THRE_TEST	((__force upf_t) (1 << 19))
/* Port has hardware-assisted h/w flow control */
#define UPF_AUTO_CTS		((__force upf_t) (1 << 20))
#define UPF_AUTO_RTS		((__force upf_t) (1 << 21))
#define UPF_HARD_FLOW		((__force upf_t) (UPF_AUTO_CTS | UPF_AUTO_RTS))
/* Port has hardware-assisted s/w flow control */
#define UPF_SOFT_FLOW		((__force upf_t) (1 << 22))
#define UPF_CONS_FLOW		((__force upf_t) (1 << 23))
#define UPF_SHARE_IRQ		((__force upf_t) (1 << 24))
#define UPF_EXAR_EFR		((__force upf_t) (1 << 25))
#define UPF_BUG_THRE		((__force upf_t) (1 << 26))
/* The exact UART type is known and should not be probed.  */
#define UPF_FIXED_TYPE		((__force upf_t) (1 << 27))
#define UPF_BOOT_AUTOCONF	((__force upf_t) (1 << 28))
#define UPF_FIXED_PORT		((__force upf_t) (1 << 29))
#define UPF_DEAD		((__force upf_t) (1 << 30))
#define UPF_IOREMAP		((__force upf_t) (1 << 31))
#define UPF_FULL_PROBE		((__force upf_t) (1ULL << 32))

#define __UPF_CHANGE_MASK	0x17fff
#define UPF_CHANGE_MASK		((__force upf_t) __UPF_CHANGE_MASK)
#define UPF_USR_MASK		((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))

#if __UPF_CHANGE_MASK > ASYNC_FLAGS
#error Change mask not equivalent to userspace-visible bit defines
#endif

	/*
	 * Must hold termios_rwsem, port mutex and port lock to change;
	 * can hold any one lock to read.
	 */
	upstat_t		status;

#define UPSTAT_CTS_ENABLE	((__force upstat_t) (1 << 0))
#define UPSTAT_DCD_ENABLE	((__force upstat_t) (1 << 1))
#define UPSTAT_AUTORTS		((__force upstat_t) (1 << 2))
#define UPSTAT_AUTOCTS		((__force upstat_t) (1 << 3))
#define UPSTAT_AUTOXOFF		((__force upstat_t) (1 << 4))
#define UPSTAT_SYNC_FIFO	((__force upstat_t) (1 << 5))

	int			hw_stopped;		/* sw-assisted CTS flow state */
	unsigned int		mctrl;			/* current modem ctrl settings */
	unsigned int		timeout;		/* character-based timeout */
	unsigned int		type;			/* port type */
	const struct uart_ops	*ops;
	unsigned int		custom_divisor;
	unsigned int		line;			/* port index */
	unsigned int		minor;
	resource_size_t		mapbase;		/* for ioremap */
	resource_size_t		mapsize;
	struct device		*dev;			/* parent device */

	unsigned long		sysrq;			/* sysrq timeout */
	unsigned int		sysrq_ch;		/* char for sysrq */
	unsigned char		has_sysrq;
	unsigned char		sysrq_seq;		/* index in sysrq_toggle_seq */

	unsigned char		hub6;			/* this should be in the 8250 driver */
	unsigned char		suspended;
	unsigned char		console_reinit;
	const char		*name;			/* port name */
	struct attribute_group	*attr_group;		/* port specific attributes */
	const struct attribute_group **tty_groups;	/* all attributes (serial core use only) */
	struct serial_rs485     rs485;
	struct gpio_desc	*rs485_term_gpio;	/* enable RS485 bus termination */
	struct serial_iso7816   iso7816;
	void			*private_data;		/* generic platform data pointer */
};

struct uart_port是Linux内核串口子系统中对物理UART硬件的抽象,其整合了UART端口的硬件参数、寄存器地址、中断信息、底层操作函数等所有关键信息,是连接串口驱动和硬件的桥梁。所有串口驱动(如8250、ttySAC等)都会基于此结构来实现具体的硬件适配。

struct uart_port中关键成员(字段)的说明如下:

  • spinlock_t lock

自旋锁,保护串口(端口)操作的原子性。

  • unsigned long iobase

IO端口基地址(IO映射方式)。

  • unsigned char __iomem *membase

IO内存映射基地址,经映射(如ioremap、MMIO等)后的IO内存虚拟基地址。

  • unsigned int irq

串口对应的中断号。

  • unsigned long irqflags

串口中断相关标志(上升沿/下降沿触发、高电平/低电平触发等)。

  • unsigned int uartclk

串口时钟(频率)。用于计算计算波特率。

  • unsigned int fifosize

串口发送缓冲区大小。

  • unsigned char x_char

XON/XOFF字符。XON/XOFF是一种基于软件实现的异步串行通信流控制协议,用于解决数据传输速率不匹配问题。其通过发送XOFF(ASCII字符DC3/Ctrl+S)暂停发送方传输,发送XON(ASCII字符DC1/Ctrl+Q)恢复传输,动态调节数据流以防止接收方缓冲区溢出。

  • unsigned char regshift

寄存器地址偏移量。

  • unsigned char iotype

IO访问方式。如UPIO_PORT(IO)、UPIO_MEM(MMIO)、UPIO_MEM32等。

struct uart_port更多关键成员的说明请看下回。

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