串口驱动程序学习
本文主要实现对串口驱动程序初始化的分析
一、串口驱动中的数据结构
尽管一个特定的UART设备驱动完全可以按照tty驱动的设计方法来设计,即定义tty_driver并实现tty_operations其中的成员函数,但是Linux已经在文件serial_core.c中实现了UART设备的通用tty驱动层,称为串口核心层,这样,UART驱动的主要任务变成了实现serial_core.c中定义的一组uart_xxx接口而非tty_xxx接口。
1.1下图描述了串行系统间的层次结构关系,可以概括为:
用户应用层 --> 线路规划层 --> TTY层 --> 底层驱动层 --> 物理硬件层
1.2下图是串口核心层在整个tty源文件关系及数据流向中的位置:
其中的xxx_uart.c在此处就是drivers/tty/serial/samsung.c和s3c6400.c
二、串口驱动中的数据结构
1.4使用到的数据结构
Uart驱动程序主要围绕三个关键的数据结构展开(include/linux/serial_core.h中定义):
- UART驱动程序结构:struct uart_driver
- UART端口结构: struct uart_port
- UART相关操作函数结构: struct uart_ops
1.4.1其中一个串口驱动对应一个struct uart_driver当然一个驱动是可以对应多个设备的:
1 struct uart_driver { 2 struct module *owner; 3 const char *driver_name; 4 const char *dev_name; 5 int major; 6 int minor; 7 int nr; //端口个数 8 struct console *cons; 9 10 /* 11 * these are private; the low level driver should not 12 * touch these; they should be initialised to NULL 13 */ 14 struct uart_state *state; 15 struct tty_driver *tty_driver; 16 };
其中的uart_state是设备状态结构结构体:
1 struct uart_state { 2 struct tty_port port; 3 int pm_state; 4 struct circ_buf xmit; 5 struct tasklet_struct tlet; 6 struct uart_port *uart_port; 7 };
在uart_open()中:
tty->driver_data = state;
在其他uart_xxx()中:
struct uart_state *state = tty->driver_data;
就可以获取设备私有信息结构体。
1.4.2uart_port用于描述一个UART端口(直接对应于一个串口)的I/O端口或者IO内存地址等信息--->即一个uart_port对应一个端口
1 struct uart_port { 2 spinlock_t lock; /* port lock */ 3 unsigned long iobase; /* in/out[bwl] */ 4 unsigned char __iomem *membase; /* read/write[bwl] */ 5 unsigned int (*serial_in)(struct uart_port *, int); 6 void (*serial_out)(struct uart_port *, int, int); 7 void (*set_termios)(struct uart_port *, 8 struct ktermios *new, 9 struct ktermios *old); 10 void (*pm)(struct uart_port *, unsigned int state, 11 unsigned int old); 12 unsigned int irq; /* irq number */ 13 unsigned long irqflags; /* irq flags */ 14 unsigned int uartclk; /* base uart clock */ 15 unsigned int fifosize; /* tx fifo size */ 16 unsigned char x_char; /* xon/xoff char */ 17 unsigned char regshift; /* reg offset shift */ 18 unsigned char iotype; /* io access style */ 19 unsigned char unused1; 20 21 #define UPIO_PORT (0) 22 #define UPIO_HUB6 (1) 23 #define UPIO_MEM (2) 24 #define UPIO_MEM32 (3) 25 #define UPIO_AU (4) /* Au1x00 type IO */ 26 #define UPIO_TSI (5) /* Tsi108/109 type IO */ 27 #define UPIO_DWAPB (6) /* DesignWare APB UART */ 28 #define UPIO_RM9000 (7) /* RM9000 type IO */ 29 #define UPIO_DWAPB32 (8) /* DesignWare APB UART (32 bit accesses) */ 30 31 unsigned int read_status_mask; /* driver specific */ 32 unsigned int ignore_status_mask; /* driver specific */ 33 struct uart_state *state; /* pointer to parent state */ 34 struct uart_icount icount; /* statistics */ 35 36 struct console *cons; /* struct console, if any */ 37 #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ) 38 unsigned long sysrq; /* sysrq timeout */ 39 #endif 40 41 upf_t flags; 42 43 #define UPF_FOURPORT ((__force upf_t) (1 << 1)) 44 #define UPF_SAK ((__force upf_t) (1 << 2)) 45 #define UPF_SPD_MASK ((__force upf_t) (0x1030)) 46 #define UPF_SPD_HI ((__force upf_t) (0x0010)) 47 #define UPF_SPD_VHI ((__force upf_t) (0x0020)) 48 #define UPF_SPD_CUST ((__force upf_t) (0x0030)) 49 #define UPF_SPD_SHI ((__force upf_t) (0x1000)) 50 #define UPF_SPD_WARP ((__force upf_t) (0x1010)) 51 #define UPF_SKIP_TEST ((__force upf_t) (1 << 6)) 52 #define UPF_AUTO_IRQ ((__force upf_t) (1 << 7)) 53 #define UPF_HARDPPS_CD ((__force upf_t) (1 << 11)) 54 #define UPF_LOW_LATENCY ((__force upf_t) (1 << 13)) 55 #define UPF_BUGGY_UART ((__force upf_t) (1 << 14)) 56 #define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15)) 57 #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16)) 58 #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) 59 #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) 60 /* The exact UART type is known and should not be probed. */ 61 #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27)) 62 #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) 63 #define UPF_FIXED_PORT ((__force upf_t) (1 << 29)) 64 #define UPF_DEAD ((__force upf_t) (1 << 30)) 65 #define UPF_IOREMAP ((__force upf_t) (1 << 31)) 66 67 #define UPF_CHANGE_MASK ((__force upf_t) (0x17fff)) 68 #define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY)) 69 70 unsigned int mctrl; /* current modem ctrl settings */ 71 unsigned int timeout; /* character-based timeout */ 72 unsigned int type; /* port type */ 73 const struct uart_ops *ops; 74 unsigned int custom_divisor; 75 unsigned int line; /* port index */ 76 resource_size_t mapbase; /* for ioremap */ 77 struct device *dev; /* parent device */ 78 unsigned char hub6; /* this should be in the 8250 driver */ 79 unsigned char suspended; 80 unsigned char irq_wake; 81 unsigned char unused[2]; 82 void *private_data; /* generic platform data pointer */ 83 };
1.4.3uart_ops定义了针对UART的一系列操作
1 struct uart_ops { 2 unsigned int (*tx_empty)(struct uart_port *); 3 void (*set_mctrl)(struct uart_port *, unsigned int mctrl); 4 unsigned int (*get_mctrl)(struct uart_port *); 5 void (*stop_tx)(struct uart_port *); 6 void (*start_tx)(struct uart_port *); 7 void (*send_xchar)(struct uart_port *, char ch); 8 void (*stop_rx)(struct uart_port *); 9 void (*enable_ms)(struct uart_port *); 10 void (*break_ctl)(struct uart_port *, int ctl); 11 int (*startup)(struct uart_port *); 12 void (*shutdown)(struct uart_port *); 13 void (*flush_buffer)(struct uart_port *); 14 void (*set_termios)(struct uart_port *, struct ktermios *new, 15 struct ktermios *old); 16 void (*set_ldisc)(struct uart_port *, int new); 17 void (*pm)(struct uart_port *, unsigned int state, 18 unsigned int oldstate); 19 int (*set_wake)(struct uart_port *, unsigned int state); 20 21 /* 22 * Return a string describing the type of the port 23 */ 24 const char *(*type)(struct uart_port *); 25 26 /* 27 * Release IO and memory resources used by the port. 28 * This includes iounmap if necessary. 29 */ 30 void (*release_port)(struct uart_port *); 31 32 /* 33 * Request IO and memory resources used by the port. 34 * This includes iomapping the port if necessary. 35 */ 36 int (*request_port)(struct uart_port *); 37 void (*config_port)(struct uart_port *, int); 38 int (*verify_port)(struct uart_port *, struct serial_struct *); 39 int (*ioctl)(struct uart_port *, unsigned int, unsigned long); 40 #ifdef CONFIG_CONSOLE_POLL 41 void (*poll_put_char)(struct uart_port *, unsigned char); 42 int (*poll_get_char)(struct uart_port *); 43 #endif 44 };
UART信息结构: struct uart_info
二、串口初始化分析
分析过程:
2.1进入到内核的Samsung.c文件中
找到内核模块加载函数:module_init(s3c24xx_serial_modinit);
可以看到加载模块直接调用platform_driver_register,注册了 开发板串口这个平台驱动。
因为把uart驱动注册为platform驱动,当平台驱动与平台设备进行匹配的时候会调用平台总线的match函数,匹配成功后就会调用平台驱动的xxx_probe()函数来进行一系列的初始化工作。
1 int s3c24xx_serial_probe(struct platform_device *dev, 2 struct s3c24xx_uart_info *info) 3 { 4 struct s3c24xx_uart_port *ourport; 5 int ret; 6 7 dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index); 8 9 ourport = &s3c24xx_serial_ports[probe_index]; 10 probe_index++; 11 12 dbg("%s: initialising port %p...\n", __func__, ourport); 13 14 ret = s3c24xx_serial_init_port(ourport, info, dev); 15 if (ret < 0) 16 goto probe_err; 17 18 dbg("%s: adding port\n", __func__); 19 uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); 20 platform_set_drvdata(dev, &ourport->port); 21 22 ret = device_create_file(&dev->dev, &dev_attr_clock_source); 23 if (ret < 0) 24 printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__); 25 26 ret = s3c24xx_serial_cpufreq_register(ourport); 27 if (ret < 0) 28 dev_err(&dev->dev, "failed to add cpufreq notifier\n"); 29 30 return 0; 31 32 probe_err: 33 return ret; 34 }