[linux kernel] Linux uart driver framework analysis

Article directory

    • 1. Low-level serial hardware driver
    • 2. Console support
    • 3. Lock support
    • 4. Core data structure
      • 1. struct uart_driver
      • 2.struct uart_port
      • 3. struct uart_ops
    • 4. Summary of commonly used APIs
    • 5. Analysis of uart driver examples
      • 1. Original factory designed uart driver
      • 2. 8250 standard uart driver
    • 6. Summary

【linux kernel series articles】

The content of some articles has been corrected. This series of articles will be updated from time to time for a long time. I hope to share high-quality articles!

  • 1. “Hash table analysis of Linux kernel data structure”
  • 2. “One article summarizes the Linux kernel notification chain”
  • 3. “debugfs in linux kernel”
  • 4. “Linked List Analysis of Linux Kernel Data Structure”
  • 5. “Linux media subsystem analysis of media controller device”
  • 6. “V4L2-PCI driver sample analysis (Part 1)”
  • 7. “v4l2 Framework Analysis – v4l2_fh”
  • 8. “v4l2 Framework Analysis – v4l2_subdev”
  • 9. “v4l2 Framework Analysis – v4l2_device”
  • 10. “V4L2 Framework Analysis Video_device”
  • 11. “Important functions of linux kernel | do_initcalls”
  • 12. “Linux Device Driver Model | bus”
  • 13. “Thoughts on Linux Kernel Clipping”
  • 14. “Analysis of the link script vmlinux.lds.S of the Linux kernel based on ARM64”
  • 15. “Early Operations of Linux Kernel Start_kernel Function”
  • 16. “start_kernel function detailed explanation series – proc_caches_init”
  • 17. “start_kernel function detailed explanation series – fork_init”
  • 18. “Start_kernel function detailed explanation series – rcu_init”
  • 19. “start_kernel function detailed explanation series – proc_root_init”
  • 20. “start_kernel detailed explanation series [setup_arch]”
  • 21. “How does the Linux kernel start user space processes (Part 1)”
  • 22. “How does the Linux kernel start user space processes (Part 2)”
  • 23. “One article summarizes the completion mechanism of the Linux kernel”
  • 24. “One article summarizes the registration and uninstallation of Linux kernel device drivers”
  • 25. “Summary of the Linux kernel boot loader”
  • 26. “Linux kernel entry: head.o”
  • 27. “Mounting root file system rootfs”
  • 28. “Analysis of mount system call”
  • 29. “devtmpfs file system analysis”
  • 30. “Kthreadd thread of Linux kernel”
  • 31. “Process Scheduling of Linux Kernel-Scheduling Strategy”
  • 32. “Linux System Call Practice (Arm Architecture)”
  • 33. “Practice of __init mechanism of Linux kernel”
  • 34. “Analysis and Practice of EXPORT_SYMBOL() in Linux Kernel”
  • 35. “How to mount the root file system in the Linux kernel”
  • 36. “How does the Linux kernel wake up threads”
  • 37. “The init thread of the Linux kernel”
  • 38. “Linux kernel pseudo file system-sysfs analysis”
  • 39. “Initialization of Linux Kernel Device Model (Part 1)”
  • 40. “Initialization of Linux Kernel Device Model (Part 2)”
  • 41. “Linux kernel pseudo file system-proc analysis”
  • 42. “Linux interrupt management-workqueue work queue”
  • 43. “Linux Interrupt Management-Soft Interrupt”
  • 44. “linux interrupt management | tasklet”
  • 45. “Linux Interrupt Management | Interrupt Management Framework (01)”
  • 46. “Linux Memory Management | Allocate Physical Memory Pages”
  • 47. “Linux Memory Management | Release Memory Pages”
  • 48. “Analysis of the Registration Mechanism and Search Mechanism of Linux Kernel Devices”
  • 49. “Registration Mechanism of Linux Kernel Device Driver”

Linux source code related files:

  • serial-core.c
  • include/linux/serial_core.h

1. Low-level serial hardware driver

The driver of the underlying serial hardware is responsible for providing the port information defined by struct uart_port and a set of control methods defined by struct uart_ops to the serial core driver. The underlying driver also Responsible for handling port interrupts and providing support for the console.

2. Console support

The serial core provides some helper functions:

  • uart_get_console() identifies the correct port structure.
  • uart_parse_options()Parse command line parameters.
  • uart_console_write() is used to perform character-by-character writing, converting newlines into CRLF sequences. It is recommended to use this function when writing drivers instead of implementing a new write interface.

3. Lock support

The low-level hardware driver is responsible for performing the necessary locking using port->lock. Two locks are supported: one is the port spin lock, and the other is the overall semaphore. From the perspective of the uart core driver, port->lock is used to lock the following data:

port->mctrl
port->icount
port->state->xmit.head (circ_buf->head)
port->state->xmit.tail (circ_buf->tail)

The underlying driver is free to use this lock to implement additional locking. The port_mutex mutex is used to prevent ports from being added, removed, or reconfigured at inappropriate times.

4. Core data structure

1. struct uart_driver

The struct uart_driver structure represents the specific UART driver. The structure is defined as follows (/include/linux/serial_core.h):

struct uart_driver {
   <!-- -->
struct module *owner; //The owner of the driver module
const char *driver_name; //Driver name
const char *dev_name; //Device name
int major; //major device number
int minor; //Slave device number
int nr;
struct console *cons; //console

/*
* these are private; the low level driver should not
* touch these; they should be initialised to NULL
*/
struct uart_state *state; //uart state
struct tty_driver *tty_driver; //Describe ttydriver
};

2. struct uart_port

struct uart_port represents a specific port. The structure is defined as follows (include/linux/serial_core.h):

struct uart_port {
   <!-- -->
spinlock_t lock; /* port lock */
unsigned long iobase; /* input/output address */
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_mctrl)(struct uart_port *, unsigned int);
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 unused1;

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; /* Communication information */

struct console *cons; /* struct console, if any */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
unsigned long sysrq; /* sysrq timeout */
#endif

/* flags must be updated while holding port mutex */
upf_t flags;

#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;

int hw_stopped; /* sw-assisted CTS flow state */
unsigned