Linux下的串口總線驅動(一)
PC機南橋的LPC總線(Low Pin Count并行總線,代替以前的ISA總線)上掛接了一個超級I/O模塊,而UART是這個超級模塊芯片組的一部分,這個UART通過RS232線程轉換與串行端口相連。與RS232不同,RS485并不是標準的PC接口,但在嵌入式領域,會為了可靠通信而使用RS485,RS485使用差分信號,因此其傳輸距離可以達到數百米,而RS232傳輸距離僅數幾米,在處理器一端,RS485接口是半雙工的UART操作。
Linux包含如下幾種終端設備:串行端口終端(/dev/ttySn)、偽終端(/dev/pty)、控制終端(/dev/tty)、控制臺終端(/dev/ttyn,/dev/conslole)。串行端口終端使用的設備名為/dev/ttyS0,/dev/ttyS1等,對應的設備號為(4,0),(4,1)。通過查看/proc/tty/drivers文件可以知道什么類型的tty設備存在以及什么驅動被加載到內核,這個文件包括一個當前存在的不同tty驅動的列表,包括驅動名,缺省的節點名,驅動的主編號,驅動的次編號范圍,以及tty驅動的類型。
I/O系統調用是從帶有線路規程的TTY I/O核心開始,然后通過TTY層,最后到達UART驅動層。主要涉及串口內核配置、UART層內核代碼、TTY層內核代碼、線路規程內核代碼、串口測試代碼五個部分。
二.串口內核配置
對于Mini2440串口驅動,我想從配置開始講起。在內核中Kconfig必須完成一層層調用,如果沒有在上一個Kconfig中調用該層Kconfig,那么該層Kconfig中的內容不會在此出現。這種情況下,只有當該層的Kconfig被其他層調用,該層Kconfig中的內容才會被顯示。所以我們找找drivers/serial/Kconfig在哪里被調用的呢?
在/drivers/char/kconfig中可以看到一行代碼source "drivers/serial/Kconfig",那我們就到drivers/serial/Kconfig下看看
Samsung SoC serial support對應于samsung.o
config SERIAL_SAMSUNG
Support for console on Samsung SoC serial port對應于控制臺驅動
Samsung S3C2440/S3C2442 Serial port support對應于s3c2440.o
在/drivers/char/Makefile中可以看到
obj-y
我們知道tty_io.o
自此,我們知道關于串口驅動,我們內核中被編譯了s3c2440.o
我們對此進行分類,屬于UART層的是s3c2440.o
好了,對于串口的地圖我們已經分析好了,那我們就按照UART層,TTY層,線路規程一個個的逛逛吧。
三.UART層內核代碼
我們先看看samsung.o的init代碼吧,這里面完成了uart_driver的注冊
static int __init s3c24xx_serial_modinit(void)
{
}
static struct uart_driver s3c24xx_uart_drv = {
};
我們關注下上面這個結構體中一個成員S3C24XX_SERIAL_CONSOLE
#define S3C24XX_SERIAL_CONSOLE &s3c24xx_serial_console
static struct console s3c24xx_serial_console = {
};
上面是控制臺的結構體成員。
對于UART驅動,我們除了需要注冊uart_driver外,還需要注冊端口,我們看看s3c2440.o。
這個文件里面注冊了一個平臺設備,其中平臺設備的探測函數最終調用了samsung.o中的s3c24xx_serial_probe函數。
int s3c24xx_serial_probe(struct platform_device *dev,
{
}
通過上面的函數,我們發現在UART層,我們調用了uart_add_one_port函數完成端口的添加,我們來看看添加了什么端口呢?
static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
#if CONFIG_SERIAL_SAMSUNG_UARTS >2
#endif
#if CONFIG_SERIAL_SAMSUNG_UARTS >3
#endif
};
在端口的定義中,我們知道s3c24xx_uart_port中定義了一個uart_port結構體,繼續跟蹤對UART的操作函數
static struct uart_ops s3c24xx_serial_ops = {
};
對于上述uart_ops函數,我們需要自己去實現uart層的具體操作。
我們在UART層主要涉及uart_driver,uart_port,uart_ops三個結構體,并調用tty層的uart_register_driver和uart_add_one_port完成驅動和端口的注冊,UART層具體操作函數需要用戶自己設計。
好了,總結下UART驅動層需要完成的任務:
其一,定義uart_driver、uart_ops、uart_port等結構體的實例并在適當的地方根據具體硬件和驅動的情況初始化它們,當然具體設備XXX的驅動可以將這些結構套在新定義的XXX_uart_driver、XXX_uart_ops、XXX_uart_port之內。
其二,在模塊初始化時調用uart_register_driver()和uart_add_one_port()以注冊UART驅動并添加端口,在模塊卸載時調用uart_unregister_driver()和uart_remove_one_port()以注銷UART驅動并移除端口。
其三,根據具體硬件的datasheet實現uart_ops中的成員函數,這些函數的實現成為UART驅動的主體工作。
關鍵詞: Linux串口總線驅
2022-01-17 10:59:35
2022-01-17 10:55:22
2022-01-17 09:21:35
2022-01-17 08:41:04
2022-01-17 08:38:24
2022-01-17 08:33:04
2022-01-17 08:31:18
2022-01-17 08:28:59
2022-01-17 08:27:51
2022-01-17 08:26:14
2022-01-17 08:24:11
2022-01-17 08:22:23
2022-01-17 08:18:40
營業執照公示信息
相關新聞