ARMLinux s3c2440 之UART分析二
Linux系統的串口驅動與一般字符設備并一樣,它采用層次化的架構,從而看做是一個串行系統來實現。
本文引用地址:http://www.104case.com/article/201611/318137.htm(1)關注UART或其他底層串行硬件特征的底層驅動程序。
(2)和底層驅動程序接口的TTY驅動程序。
(3)加工用于和TTY驅動程序交換數據的線路規程。
下圖描述了串行系統間的層次結構關系(s3c2440串口實現例),可以概括為:用戶應用層 --> 線路規劃層 -->TTY層 -->底層驅動層 -->物理硬件層
線路規程和TTY驅動程序是與硬件平臺無關的,Linux源碼中已經提供了實現,所以對于具體的平臺,我們只需實現底層驅動程序即可,這也是我們最關心的。在s3c2440a中,主要由dirivers/serial/下的s3c2440.c和samsung.c實現。
Uart驅動程序主要圍繞三個關鍵的數據結構展開(include/linux/serial_core.h中定義):
UART特定的驅動程序結構定義:struct uart_driver s3c24xx_uart_drv;
UART端口結構定義: struct uart_port s3c24xx_serial_ops;
UART相關操作函數結構定義: struct uart_ops s3c24xx_serial_ops;
基于以上三個結構體,來看看s3c2440是如何掛接到Linux中串口構架的:
S3c2440串口相關操作函數定義在s3c24xx_serial_ops中,這個是一個structuart_ops結構
static struct uart_ops s3c24xx_serial_ops ={.pm =s3c24xx_serial_pm, //電源管理函數.tx_empty = s3c24xx_serial_tx_empty, //檢車發送FIFO緩沖區是否空.get_mctrl = s3c24xx_serial_get_mctrl, //是否串口流控.set_mctrl = s3c24xx_serial_set_mctrl, //是否設置串口流控cts.stop_tx =s3c24xx_serial_stop_tx, //停止發送.start_tx =s3c24xx_serial_start_tx, //啟動發送.stop_rx =s3c24xx_serial_stop_rx, //停止接收.enable_ms = s3c24xx_serial_enable_ms, //空函數.break_ctl = s3c24xx_serial_break_ctl, //發送break信號.startup =s3c24xx_serial_startup, //串口發送/接收,以及中斷申請初始配置函數.shutdown = s3c24xx_serial_shutdown, //關閉串口.set_termios = s3c24xx_serial_set_termios,//串口clk,波特率,數據位等參數設置.type = s3c24xx_serial_type, // CPU類型關于串口.release_port =s3c24xx_serial_release_port, //釋放串口.request_port =s3c24xx_serial_request_port, //申請串口.config_port = s3c24xx_serial_config_port, //串口的一些配置信息info.verify_port = s3c24xx_serial_verify_port, //串口檢測};
驅動程序結構定義:
static struct uart_driver s3c24xx_uart_drv= {.owner =THIS_MODULE,.dev_name = "s3c2440_serial", //具體設備名稱.nr =CONFIG_SERIAL_SAMSUNG_UARTS, //定義有幾個端口.cons = S3C24XX_SERIAL_CONSOLE, //console接口.driver_name =S3C24XX_SERIAL_NAME, //串口名:ttySAC.major =S3C24XX_SERIAL_MAJOR, //主設備號.minor =S3C24XX_SERIAL_MINOR, //次設備號};
端口配置結構定義,其中包括了一個structuart_ports結構:
struct s3c24xx_uart_port {unsignedchar rx_claimed;unsignedchar tx_claimed;unsignedint pm_level;unsignedlong baudclk_rate;unsignedint rx_irq;unsignedint tx_irq;structs3c24xx_uart_info *info;structs3c24xx_uart_clksrc *clksrc;structclk *clk;structclk *baudclk;structuart_port port;#ifdef CONFIG_CPU_FREQstructnotifier_block freq_transition;#endif};static structs3c24xx_uart_ports3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {[0]= { //串口0.port= {.lock =__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),.iotype =UPIO_MEM, //.irq =IRQ_S3CUART_RX0, //中斷號.uartclk = 0, //時鐘值.fifosize = 16, //定義FIFO緩存區大小.ops = &s3c24xx_serial_ops, //串口相關操作函數.flags = UPF_BOOT_AUTOCONF,.line = 0, //線路1}},[1]= {//串口1.port= {.lock =__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),.iotype = UPIO_MEM,.irq = IRQ_S3CUART_RX1,.uartclk = 0,.fifosize = 16,.ops = &s3c24xx_serial_ops,.flags = UPF_BOOT_AUTOCONF,.line = 1,}},#if CONFIG_SERIAL_SAMSUNG_UARTS > 2[2]= {//串口2.port= {.lock =__SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),.iotype = UPIO_MEM,.irq = IRQ_S3CUART_RX2,.uartclk = 0,.fifosize = 16,.ops =&s3c24xx_serial_ops,.flags = UPF_BOOT_AUTOCONF,.line = 2,}},#endif};
綜上所述,s3c2440主要是實現這三個數據結構:
s3c24xx_serial_ops, s3c24xx_uart_drv, s3c24xx_uart_ports3c24xx_serial_ports
下篇將進一步結合源碼探討ARM-Linuxs3c2440 的實現。
評論