串口驅動的源文件一般是使用drivers/serial/8250.c文件,或該文件的稍作修改。這是因為大多的串口接口的操作寄存器都是符合相關的定義,都是基本一樣的。那么在移植串口驅動時,一般是為該驅動添加我們的串口接口設備。一般來說,串口接口設備在board文件中添加或在板級目錄下添加專屬的serial文件。 設備的定義一般如下: struct plat_serial8250_port serial_std_platform_data[] = { { .membase = (void *) io_p2v(UART5_BASE), .mapbase = UART5_BASE, .irq = IRQ_UART_IIR5, .uartclk = MAIN_OSC_FREQ, .regshift = 2, .iotype = UPIO_MEM32, .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, }, { .membase = (void *) io_p2v(UART3_BASE), .mapbase = UART3_BASE, .irq = IRQ_UART_IIR3, .uartclk = MAIN_OSC_FREQ, .regshift = 2, .iotype = UPIO_MEM32, .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, }, { .membase = (void *) io_p2v(UART4_BASE), .mapbase = UART4_BASE, .irq = IRQ_UART_IIR4, .uartclk = MAIN_OSC_FREQ, .regshift = 2, .iotype = UPIO_MEM32, .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, } } struct platform_device serial_std_platform_device = { .name = "serial8250", .id = 0, .dev = { .platform_data = serial_std_platform_data, }, }; 這個platform_device對象的私有數據指成員向一個plat_serial8250_port類型的數組。在這里該數組描述了三個串口接口的基本信息。當8250驅動檢測到這個platform_device對象后,就分析該對象的私有數據成員指向的那個plat_serial8250_port類型的數組。然后根據該數組的每個成員描述的信息生成一個串口對象設備。 實現了這個platform_device結構體后,把這個對象注冊即可。但這個對象的name必須是serial8250。否則8250驅動檢測不到這個樣的設備。 如果注冊順利且工作正常,那么在驅動加載時會打印出串口接口探測信息: serial8250.0: ttyS0 at MMIO 0x40080000 (irq = 7) is a 16550A serial8250.0: ttyS1 at MMIO 0x40088000 (irq = 8) is a 16550A serial8250.0: ttyS2 at MMIO 0x40098000 (irq = 10) is a 16550A serial8250.0表示8250驅動檢測到的第一個platform_device對象。如果檢測到第二個platform對象,會打印成serial8250.1;如此類推。 0x40080000表示串口接口寄存器物理地址的基地址; irq描述串口接口所用的中斷; 16550A表示該串口接口的類型。有可能這個類型的名字不是我們所預期的,但是只要該類型的TX/RX FIFO長度和我們實際串口接口的一樣,就可以接受。 ttyS0/1/2表示串口設備的名字 如果注冊成功,則在/dev/目錄下生成: ttyS0,ttyS1,ttyS2的設備文件節點。同時在/sys/devices/platform/目錄下,生成serial8250,serial8250.0目錄。 這時即可對串口的各設備文件節點進行測試。 下面詳細介紹plat_serial8250_port這個對象。我們看一段上面的代碼: { .membase = (void *) io_p2v(UART5_BASE), .mapbase = UART5_BASE, .irq = IRQ_UART_IIR5, .uartclk = MAIN_OSC_FREQ, .regshift = 2, .iotype = UPIO_MEM32, .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST, }, membase: 該成員描述的該串口接口寄存器虛擬地址的基地址。在初始化該成員時,需要自己把該串口接口寄存器的物理地址映射到虛擬地址空間。并且該映射工作需要在內核的板級初始化階段完成。 mapbase: 該成員描述的該串口接口寄存器物理地址的基地址。其實只要初始化了mapbase成員,上面的membase成員就可以不必初始化了。因為8250驅動如果檢測到只初始化了mapbase成員而membase為NULL,則自動把該串口接口寄存器的物理地址空間映射到虛擬地址空間。 irq: 該成員描述的是該串口接口使用的中斷號。 uartclk: 該成員描述了該串口接口使用的時鐘頻率。 regshift: 該成員表示:在訪問該串口接口的某個寄存器時,需把該寄存器的號左移多少位然后加基地址(不管是物理或虛擬地址)才能得能到這個寄存器的址址。 iotype: 該成員表示該串口接口寄存器的地址類型,可以取值以下的其中一個: UPIO_PORT 端口地址,8位 UPIO_HUB6 UPIO_MEM 8位的內存地址 UPIO_MEM32 32位的內存地址 UPIO_AU UPIO_TSI UPIO_DWAPB UPIO_RM9000 一般來說,如果該成員初始化為UPIO_MEM或UPIO_PORT,那么regshift成員應該為0;如果該成員初始化為UPIO_MEM32,那么regshift成員應該為2. flags: UPF_BOOT_AUTOCONF 表示自動探測串口類型,這個一般是需要的 UPF_SKIP_TEST 表示在探測串口類型時,是否測試地址的可訪問性。這在調試階段是需要的。 除了flags,上面的各個成員都必須嚴格設置正確才能保證串口接口被正確探測和初始化。 如果串口接口類型沒有被探測出來,或者FIFO長度不對,這需要考慮寄存器的訪問是否正確,這包括:基地址是否正確,regshift和iotype是否正確,時鐘頻率是否正確。 如果探測信息也沒有,或者接口數量不對。那么請在mem menuconfig中,在 Device Drivers ---> Character devices ---> Serial drivers ---> (8) Maximum number of 8250/16550 serial ports (8) Number of 8250/16550 serial ports to register at runtime 這兩項的數字等于在8250注冊串口接口的總數。 以下課程可免費試聽C語言、電子、PCB、STM32、Linux、FPGA、JAVA、安卓等。 想學習的你和我聯系預約就可以免費聽課了。 宋工企鵝號:35--24-65--90-88 Tel/WX:173--17--95--19--08 |