MTK UART驅動程式碼分析
首先參考網上的一些資料,給出UART驅動的整體描述與框架,
在 linux 系統中,tty 表示各種終端。終端通常都跟硬體相對應。比如對應於輸入裝置鍵盤 滑鼠,輸出裝置顯示器的控制終端和串列埠終端。
最上面的使用者空間會有很多對底層硬體的操作,像 read,write 等。使用者空間主要是通過設 備檔案同 tty_core 互動,tty_core 根據用空間操作的型別再選擇跟 line discipline 和 tty_driver 也就是 serial_core 互動,例如設定硬體的 ioctl 指令就直接交給 serial_core 處理。 Read 和 write 操作就會交給 line discipline 處理。Line discipline 是線路規程 的意思。正如它的名字一樣,它表示的是這條終端”執行緒”的輸入與輸出規範設定,主要用 來進行輸入/輸出資料的預處理。處理之後,就會將資料交給 serial_core。
一個 uart_driver 通常會註冊一段裝置號.即在使用者空間會看到 uart_driver 對應有多個設 備節點。例如:/dev/ttyMT0 /dev/ttyMT1 每個裝置節點是對應一個具體硬體的,這樣就可 做到對多個硬體裝置的統一管理,而每個裝置檔案應該對應一個 uart_port,也就是 說:uart_device 要和多個 uart_port 關係起來。並且每個 uart_port 對應一個 circ_buf(用來接收資料),所以 uart_port 必須要和這個快取區關係起來。
MTK uart 驅動,原始檔路徑 Mediatek/kernel/drivers/uart/uart.c
第 2238 行,呼叫 mtk_uart_sysfs 函式,其定義如下:
該函式初始化 mtk_uart_sysobj 結構體,主要呼叫 kobject_init_and_add 函式完成對 kobject 的初始化,建立 kobject 的層次結構,並將 kobject 新增到 sysfs 檔案系統中。具 體實現請參考 http://blog.csdn.net/liuhaoyutz/article/details/12993931。
回到 mtk_uart_init 函式,第 2241 行呼叫 uart_register_driver 函式註冊 mtk_uart_drv。mtk_uart_drv 結構如下:
uart_register_driver 函式定義在 kernel/drivers/tty/serial/serial_core.c 檔案中,
第 2244行,uart驅動與tty_driver關聯起來。
第 2254 行,設定 uart 的初始波特率。
第 2257 行,將 tty_driver 的操作集統一設為了 uart_ops.這樣就使得從使用者空間下來的操作可以找到正確的 serial_core 的操作函式。Uart_ops 如下:
第 2267 行,uart_port_ops 結構體如下:
第 2272 行,呼叫 tty_register_driver 函式,其所在檔案為 kernel/drivers/tty/tty_io.c。
第 3154 行,MKDEV 巨集定義在 include/linux/kdev_t.h 標頭檔案,#define MKDEV(ma,mi) (((ma)<< MINORBITS) | (mi)) 作用是將主裝置號和次裝置號轉換成 dev_t 型別。
第 3155 行,register_chrdev_region 為一個字元驅動獲取一個或多個裝置編號。
第 3170行,cdev_init函式initialize a cdev structure,tty_fops結構體如下:
第 3172行,呼叫 cdev_add() 函式,將cdev新增到系統中去。
第 3185行至3193行,因normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 故沒有呼叫tty_register_device來建立ttyMT0~ttyMT3裝置。
第 3194行,呼叫proc_tty_register_driver建立/proc/tty/driver/mtk-uart檔案。其driver->ops->proc_fops 為uart_ops結構體中的uart_proc_fops函式。
回到 uart_register_driver函式,第2276 行呼叫 put_tty_driver 函式,當註冊失敗時,判斷引用計數登出驅動。
回到 mtk_uart_init 函式,第 2245 行呼叫 platform_driver_register 函式註冊 mtk_uart_dev_drv。
第2223行,mtk_uart_probe函式如下:
第2356行,呼叫uart_configure_port函式進行埠配置。
第2362行,呼叫tty_register_device建立ttyMT0~ttyMT3裝置。
Mtk-uart平臺裝置:
Mediatek/platform/mt8127/kernel/core/include/mach/Devs.h
mediatek/platform/mt8127/kernel/core/Mt_devs.c
回到 mtk_uart_init 函式,第 2275 行呼叫 mtk_uart_init_ops 函式。
回到 mtk_uart_init 函式,第 2277 行呼叫 mtk_uart_init_debug_spinlock 函式。
整個驅動載入完成後,驅動資料之間的總體關係如下:
kernel/drivers/tty/tty_io.c
tty_open函式:
第1920行retval = tty_alloc_file(filp);//動態分配tty_file_private記憶體
第1931行tty_open_current_tty(device, filp);//獲取當前程序的控制終端
詳細檢視http://blog.csdn.net/mirkerson/article/details/38107927
第1936行tty_lookup_driver(device, filp, &noctty, &index);//根據device名字,查詢驅動並且返回device index。
第1943行tty_driver_lookup_tty(driver, inode, index);//查詢tty指標,從uart驅動流程程式碼看,僅僅是分配指標空間,並沒有賦值,即返回的tty為空指標。具體見tty_register_driver函式的3162行。
第1955行,呼叫tty_init_dev函式初始tty裝置
第1409行,分配tty_struct。
第1414行,呼叫initialize_tty_struct函式對tty_struct進行初始化。
第2946行,呼叫tty_ldisc_init函式,
第977行呼叫tty_ldisc_get函式,獲取tty_ldisc_N_TTY(n_tty.c).
具體流程如下 :kernel/init/main.c: start_kernel ----> tty_io.c: console_init ----> tty_ldisc.c: tty_ldisc_begin
回到tty_ldisc_init函式,第980行呼叫tty_ldisc_assign將ld賦值給tty->ldisc。
回到tty_init_dev函式,第1416行呼叫tty_driver_install_tty函式。
因driver->ops->install為空,即呼叫tty_standard_install函式。
第1289行將新建立的tty賦值給driver->ttys[tty->index]。
第1283行呼叫tty_init_termios,
第1267行將init_termios賦值給tp,
第1275、1276行,呼叫tty_termios_input_baud_rate及tty_termios_baud_rate函式賦值輸入輸出波特率。
回到tty_init_dev函式,第1425行,呼叫tty_ldisc_setup函式開啟線路規程。具體會呼叫到tty_ldisc_N_TTY.open函式。
回到tty_open函式。第1966行呼叫tty_add_file將tty與file關聯。
第1976行,呼叫tty->ops->open(tty, filp);即uart_ops.open
uart_port的初始化(uart.c):
對mtk_uarts結構體成員變數進行初始化。
執行tty_open後,結構圖如下:
使用者層操作入口為cdev->ops = tty_fops, 在執行tty_open後,會呼叫mtk_uart_startup函式建立中斷機制,
request_irq(port->irq, (irq_handler_t)mtk_uart_irq, IRQF_LEVEL_TRIGGER_POLARITY, DRV_NAME, uart);
與硬體中直接打交道的介面為mtk_uart_ops.