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);
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 */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
unsigned long sysrq; /* sysrq timeout */
unsigned int sysrq_ch; /* char for sysrq */
#endif
/* 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_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 char hub6; /* this should be in the 8250 driver */
unsigned char suspended;
unsigned char unused[2];
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;
void *private_data; /* generic platform data pointer */
}
在 Linux 内核中,struct uart_port
是 UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)驱动的核心数据结构,用于表示一个 UART 端口的硬件和软件状态。以下是其常见成员变量及其用途的解析:
核心成员变量
-
iobase
(I/O 基地址)- 用途:表示 UART 端口的 I/O 地址(物理地址或虚拟地址),用于通过
inb
/outb
等函数直接访问寄存器。 - 示例:在 x86 平台,可能是
0x3F8
(COM1 的默认地址)。
- 用途:表示 UART 端口的 I/O 地址(物理地址或虚拟地址),用于通过
-
membase
(内存映射基地址)- 用途:如果 UART 寄存器通过内存映射访问(MMIO),此成员保存映射后的虚拟地址。
- 示例:在嵌入式 SoC 中,可能通过
ioremap()
映射物理地址到membase
。
-
mapbase
(物理地址基址)- 用途:UART 寄存器的物理基地址,用于内存映射或资源申请。
- 示例:
mapbase = 0xFE201000
(某 ARM SoC 的 UART 物理地址)。
-
irq
(中断号)- 用途:UART 使用的中断号,用于注册中断处理函数。
- 示例:
irq = 5
(某些平台的 COM2 中断号)。
-
fifosize
(FIFO 大小)- 用途:UART 硬件 FIFO 的深度,驱动根据此值优化数据传输。
- 示例:
fifosize = 16
表示 16 字节的发送/接收 FIFO。
-
uartclk
(UART 主时钟频率)- 用途:UART 的基准时钟频率(Hz),用于计算波特率分频系数。
- 示例:
uartclk = 24000000
(24MHz 时钟)。
操作函数集 (ops
)
-
const struct uart_ops *ops
- 用途:指向 UART 操作函数集的指针,定义了驱动与硬件交互的具体方法,例如:
startup()
:初始化 UART 硬件。shutdown()
:关闭 UART 硬件。set_mctrl()
:设置调制解调器控制线(如 RTS、DTR)。get_mctrl()
:读取调制解调器状态线(如 CTS、DSR)。set_termios()
:配置波特率、数据位、停止位等参数。start_tx()
:启动数据传输。stop_rx()
:停止接收数据。serial_in()
读写硬件寄存器的核心函数,抽象不同硬件的访问方式get_divisor)()
计算或设置波特率分频器throttle)()
流量控制:暂停/恢复数据接收handle_irq()
中断处理函数入口(如处理接收或发送中断)
- 关键性:驱动开发者必须实现这些函数以适配具体硬件。
- 用途:指向 UART 操作函数集的指针,定义了驱动与硬件交互的具体方法,例如:
状态与配置
-
flags
(标志位)- 用途:描述 UART 端口的特性或状态,例如:
UPF_FIXED_TYPE
:固定端口类型。UPF_SKIP_TEST
:跳过自检。UPF_HARD_FLOW
:支持硬件流控(RTS/CTS)。
- 示例:
port->flags = UPF_BOOT_AUTOCONF | UPF_HARD_FLOW;
- 用途:描述 UART 端口的特性或状态,例如:
-
type
(端口类型)- 用途:标识 UART 硬件类型(如
PORT_16550A
、PORT_XSCALE
),与驱动匹配。 - 示例:
type = PORT_16550A;
- 用途:标识 UART 硬件类型(如
-
icount
(中断计数器)- 用途:统计接收/发送中断次数、帧错误等,用于调试和状态监控。
- 成员:
struct { unsigned int rx; unsigned int tx; unsigned int frame; unsigned int parity; // ... } icount;
-
state
(端口状态)- 用途:指向
struct uart_state
,包含与 TTY 子系统相关的状态(如缓冲区和信号处理)。
- 用途:指向
其他重要成员
-
dev
(关联的设备)- 用途:指向关联的
struct device
,用于设备模型、电源管理和 sysfs 接口。 - 示例:
port->dev = &pdev->dev;
(与 Platform Device 绑定)。
- 用途:指向关联的
-
private_data
(私有数据)- 用途:驱动私有数据指针,可用于存储硬件特定配置或上下文。
- 示例:存储 DMA 通道或自定义结构体。
-
line
(串口线路号)- 用途:UART 的索引号(如 ttyS0、ttyS1),由内核分配。
- 示例:
line = 0
对应/dev/ttyS0
。
高级功能相关
-
pm
(电源管理)- 用途:电源管理操作(如休眠、唤醒),需实现
uart_pm_ops
中的方法。
- 用途:电源管理操作(如休眠、唤醒),需实现
-
handle_break
(Break 条件处理)- 用途:自定义处理 BREAK 信号的函数指针(可选)。