ARM Linux S3C2440 之UART分析
在分析ARM-Linux s3c2440中UART的時有必要先了解 s3c2440A中串口的硬件知識。
硬件篇:
S3c2440A串口提供三個獨(dú)立的異步串行通信I/O端口(asynchronousserial I/O ports)。每一個串口均可以以普通中斷方式或者DMA方式進(jìn)行數(shù)據(jù)收發(fā)。采用系統(tǒng)時鐘時,最大速率為115.2kbps.如果采用外部時鐘(UEXTCLK),UART速度可以更快。每個串口包含有2個64-byte的FIFO緩存區(qū)用來發(fā)送或傳輸數(shù)據(jù)。S3c2440A 串口具有可編程波特率,紅外(IR)收發(fā)數(shù)據(jù),1或者2 位的停止位(stop),5/6/7/8 位數(shù)據(jù)寬度和奇偶校驗(yàn)功能(parity checking)。
每個串口由波特率產(chǎn)生單元,發(fā)送單元,接收單元和控制單元組成。如下圖所示,波特產(chǎn)生單元的時鐘可以是PCLK,FCLK/n,或者UEXTCLK(外部輸入的時鐘)。發(fā)送和接收單元包含有一個64-byte的FIFOs(先入先出隊(duì)列)和數(shù)據(jù)移位器。
發(fā)送數(shù)據(jù)時,數(shù)據(jù)先被寫進(jìn)FIFO,然后拷貝到數(shù)據(jù)移位器后發(fā)送數(shù)據(jù),最后數(shù)據(jù)被一位一位由數(shù)據(jù)發(fā)送腳(TxDn)送出。類似的,數(shù)據(jù)在接收時,數(shù)據(jù)一位一位的由數(shù)據(jù)接收腳(RxDn)接收,然后拷貝到FIFO緩存區(qū)。
寄存器:
串口的控制寄存器有兩種,一種是UCONx,一種是ULCONx,它們各有三個:UCON0(ULCON0) ~ UCON2(ULCON2)分別對應(yīng)于每一個串口,用于設(shè)置UART的工作模式,波特率,中斷類型等
狀態(tài)寄存器:UTRSTAT0 ~UTRSTAT2, 用于串口工作時,接收/發(fā)送的狀態(tài)指示:
FIFO控制寄存器: UFCON0 ~ UFCON2, 用于對FIFO的設(shè)置,假如使用的是中斷觸發(fā),當(dāng)緩沖區(qū)的字節(jié)達(dá)到FIFO設(shè)置的觸發(fā)值,就會觸發(fā)中斷產(chǎn)生.
FIFO狀態(tài)寄存器: UFSTAT0 ~ UFSTAT2, 用于表示FIFO緩存中的狀態(tài)
對于Arm-linux s3c2440串口的使用,主要是對以上寄存器的操作。
下面將結(jié)合源碼分析arm-linux s3c2440串口驅(qū)動的實(shí)現(xiàn)(軟件篇)
軟件篇(linux-2.6.22.6):
Linux系統(tǒng)的串口驅(qū)動與一般字符設(shè)備并一樣,它采用層次化的架構(gòu),從而看做是一個串行系統(tǒng)來實(shí)現(xiàn)。
(1)關(guān)注UART或其他底層串行硬件特征的底層驅(qū)動程序。
(2)和底層驅(qū)動程序接口的TTY驅(qū)動程序。
(3)加工用于和TTY驅(qū)動程序交換數(shù)據(jù)的線路規(guī)程。
下圖描述了串行系統(tǒng)間的層次結(jié)構(gòu)關(guān)系(s3c2440串口實(shí)現(xiàn)例),可以概括為:用戶應(yīng)用層 --> 線路規(guī)劃層 -->TTY層 -->底層驅(qū)動層 -->物理硬件層
線路規(guī)程和TTY驅(qū)動程序是與硬件平臺無關(guān)的,Linux源碼中已經(jīng)提供了實(shí)現(xiàn),所以對于具體的平臺,我們只需實(shí)現(xiàn)底層驅(qū)動程序即可,這也是我們最關(guān)心的。在s3c2440a中,主要由dirivers/serial/下的s3c2410.c和samsung.c實(shí)現(xiàn)。
Uart驅(qū)動程序主要圍繞三個關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)展開(include/linux/serial_core.h中定義):
UART特定的驅(qū)動程序結(jié)構(gòu)定義:struct uart_driver s3c24xx_uart_drv;
UART端口結(jié)構(gòu)定義: struct uart_port s3c24xx_serial_ops;
UART相關(guān)操作函數(shù)結(jié)構(gòu)定義: struct uart_ops s3c24xx_serial_ops;
基于以上三個結(jié)構(gòu)體,來看看s3c2440是如何掛接到Linux中串口構(gòu)架的:
S3c2440串口相關(guān)操作函數(shù)定義在s3c24xx_serial_ops(路徑:driversserialS3c2410.c)中,這個是一個struct uart_ops結(jié)構(gòu)
staticstructuart_opss3c24xx_serial_ops={
.pm=s3c24xx_serial_pm,//電源管理相關(guān)的函數(shù)
.tx_empty=s3c24xx_serial_tx_empty,//檢查發(fā)送的fifo是為空
.get_mctrl=s3c24xx_serial_get_mctrl,//是否串口流控
.set_mctrl=s3c24xx_serial_set_mctrl,//是否設(shè)置串口流控cts
.stop_tx=s3c24xx_serial_stop_tx,//停止發(fā)送
.start_tx=s3c24xx_serial_start_tx,//啟動發(fā)送
.stop_rx=s3c24xx_serial_stop_rx,//停止接受
.enable_ms=s3c24xx_serial_enable_ms,//空函數(shù)
.break_ctl=s3c24xx_serial_break_ctl,//發(fā)送break信號
.startup=s3c24xx_serial_startup,//串口發(fā)送接受以及中斷申請的初始化設(shè)置函數(shù)
.shutdown=s3c24xx_serial_shutdown,//關(guān)閉串口
.set_termios=s3c24xx_serial_set_termios,//串口時鐘,波特率,數(shù)據(jù)位等的參數(shù)設(shè)置
.type=s3c24xx_serial_type,//???
.release_port=s3c24xx_serial_release_port,//釋放串口
.request_port=s3c24xx_serial_request_port,//申請串口
.config_port=s3c24xx_serial_config_port,//串口的一些配置信息
.verify_port=s3c24xx_serial_verify_port,//串口檢測
};
驅(qū)動程序結(jié)構(gòu)定義:
staticstructuart_drivers3c24xx_uart_drv={
.owner=THIS_MODULE,
.dev_name="s3c2410_serial",//具體設(shè)備的名稱
.nr=3,//定義幾個端口
.cons=S3C24XX_SERIAL_CONSOLE,//console端口號
.driver_name=S3C24XX_SERIAL_NAME,//串口名
.major=S3C24XX_SERIAL_MAJOR,//主設(shè)備號
.minor=S3C24XX_SERIAL_MINOR,//次設(shè)備號
};
端口配置結(jié)構(gòu)定義,其中包括了一個struct uart_ports結(jié)構(gòu)(下面的賦值都是對uart_port的填充):
staticstructs3c24xx_uart_ports3c24xx_serial_ports[NR_PORTS]={
[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,//串口的操作函數(shù)
.flags=UPF_BOOT_AUTOCONF,
.line=0,
}
},
[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,
}
},
#ifNR_PORTS>2
[2]={
.port={
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),