串口驅動程序學習linux
本文主要實現對串口驅動程序初始化的分析ios
1、串口驅動中的數據結構數據結構
儘管一個特定的UART設備驅動徹底能夠按照tty驅動的設計方法來設計,即定義tty_driver並實現tty_operations其中的成員函數,可是Linux已經在文件serial_core.c中實現了UART設備的通用tty驅動層,稱爲串口核心層,這樣,UART驅動的主要任務變成了實現serial_core.c中定義的一組uart_xxx接口而非tty_xxx接口。app
1.1下圖描述了串行系統間的層次結構關係,能夠歸納爲:函數
用戶應用層 --> 線路規劃層 --> TTY層 --> 底層驅動層 --> 物理硬件層學習
1.2下圖是串口核心層在整個tty源文件關係及數據流向中的位置:this
其中的xxx_uart.c在此處就是drivers/tty/serial/samsung.c和s3c6400.cspa
2、串口驅動中的數據結構設計
1.4使用到的數據結構3d
Uart驅動程序主要圍繞三個關鍵的數據結構展開(include/linux/serial_core.h中定義):
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、串口初始化分析
分析過程:
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 }