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

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

本文内容参考:

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_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中更多关键成员(字段)的说明如下:

  • unsigned int read_status_mask

关心的Rx错误状态。驱动(程序)专有。

  • unsigned int ignore_status_mask

忽略的Rx错误状态。驱动(程序)专有。

  • struct console *cons; /* struct console, if any */

如果有,指向struct console。

  • upf_t flags

端口标志:UPF_BOOT_AUTOCONF(自动配置)、UPF_SPD_HI(高速)等。当持有端口锁时,此标志必须被更新。

  • unsigned int mctrl

当前的modem设置。

  • unsigned int timeout

基于字符的超时时间。

  • unsigned int type

端口类型。

  • const struct uart_ops *ops

串口端口操作函数集,即UART底层操作函数集(读/写寄存器、初始化等)。这是最为核心的部分。

  • unsigned int custom_divisor

自定义波特率除数。

  • unsigned int line

端口索引。串口线号(如ttyS0对应line=0)。

  • resource_size_t mapbase

IO内存物理基地址,可用于ioremap。

  • struct device *dev

指向父设备的指针。

  • unsigned char hub6

这将用在8250驱动中。

  • void *private_data

端口私有数据,一般为platform数据指针。

更多内容请看下回。

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