linux下的串列埠驅動程式
串列埠驅動確實不簡單,不過多花費心思整體思路還是容易理清的。
原文如下:
一、核心資料結構 串列埠驅動有3個核心資料結構,它們都定義在<#include linux/serial_core.h> 1、uart_driver uart_driver包含了串列埠裝置名、串列埠驅動名、主次裝置號、串列埠控制檯(可選)等資訊,還封裝了tty_driver(底層串列埠驅動無需關心tty_driver)。 struct uart_driver { struct module *owner; /* 擁有該uart_driver的模組,一般為THIS_MODULE */ const char *driver_name; /* 串列埠驅動名,串列埠裝置檔名以驅動名為基礎 */ const char *dev_name; /* 串列埠裝置名 */ int major; /* 主裝置號 */ int minor; /* 次裝置號 */ int nr; /* 該uart_driver支援的串列埠個數(最大) */ struct console *cons; /* 其對應的console.若該uart_driver支援serial console,否則為NULL */ /* * these are private; the low level driver should not * touch these; they should be initialised to NULL */ struct uart_state *state; struct tty_driver *tty_driver; }; 2、uart_port uart_port用於描述串列埠埠的I/O埠或I/O記憶體地址、FIFO大小、埠型別、串列埠時鐘等資訊。實際上,一個uart_port例項對應一個串列埠裝置 struct uart_port { spinlock_t lock; /* 串列埠埠鎖 */ unsigned int iobase; /* IO埠基地址 */ unsigned char __iomem *membase; /* IO記憶體基地址,經對映(如ioremap)後的IO記憶體虛擬基地址 */ unsigned int irq; /* 中斷號 */ unsigned int uartclk; /* 串列埠時鐘 */ unsigned int fifosize; /* 串列埠FIFO緩衝大小 */ unsigned char x_char; /* xon/xoff字元 */ unsigned char regshift; /* 暫存器位移 */ unsigned char iotype; /* IO訪問方式 */ unsigned char unused1; #define UPIO_PORT (0) /* IO埠 */ #define UPIO_HUB6 (1) #define UPIO_MEM (2) /* IO記憶體 */ #define UPIO_MEM32 (3) #define UPIO_AU (4) /* Au1x00 type IO */ #define UPIO_TSI (5) /* Tsi108/109 type IO */ #define UPIO_DWAPB (6) /* DesignWare APB UART */ #define UPIO_RM9000 (7) /* RM9000 type IO */ unsigned int read_status_mask; /* 關心的Rx error status */ unsigned int ignore_status_mask;/* 忽略的Rx error status */ struct uart_info *info; /* pointer to parent info */ struct uart_icount icount; /* 計數器 */ struct console *cons; /* console結構體 */ #ifdef CONFIG_SERIAL_CORE_CONSOLE unsigned long sysrq; /* sysrq timeout */ #endif upf_t flags; #define UPF_FOURPORT ((__force upf_t) (1 << 1)) #define UPF_SAK ((__force upf_t) (1 << 2)) #define UPF_SPD_MASK ((__force upf_t) (0x1030)) #define UPF_SPD_HI ((__force upf_t) (0x0010)) #define UPF_SPD_VHI ((__force upf_t) (0x0020)) #define UPF_SPD_CUST ((__force upf_t) (0x0030)) #define UPF_SPD_SHI ((__force upf_t) (0x1000)) #define UPF_SPD_WARP ((__force upf_t) (0x1010)) #define UPF_SKIP_TEST ((__force upf_t) (1 << 6)) #define UPF_AUTO_IRQ ((__force upf_t) (1 << 7)) #define UPF_HARDPPS_CD ((__force upf_t) (1 << 11)) #define UPF_LOW_LATENCY ((__force upf_t) (1 << 13)) #define UPF_BUGGY_UART ((__force upf_t) (1 << 14)) #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16)) #define UPF_CONS_FLOW ((__force upf_t) (1 << 23)) #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24)) #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28)) #define UPF_FIXED_PORT ((__force upf_t) (1 << 29)) #define UPF_DEAD ((__force upf_t) (1 << 30)) #define UPF_IOREMAP ((__force upf_t) (1 << 31)) #define UPF_CHANGE_MASK ((__force upf_t) (0x17fff)) #define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY)) unsigned int mctrl; /* 當前的moden設定 */ unsigned int timeout; /* character-based timeout */ unsigned int type; /* 埠型別 */ const struct uart_ops *ops; /* 串列埠埠操作函式集 */ unsigned int custom_divisor; unsigned int line; /* 埠索引 */ resource_size_t mapbase; /* IO記憶體物理基地址,可用於ioremap */ struct device *dev; /* 父裝置 */ unsigned char hub6; /* this should be in the 8250 driver */ unsigned char suspended; unsigned char unused[2]; void *private_data; /* 埠私有資料,一般為platform資料指標 */ }; uart_iconut為串列埠資訊計數器,包含了傳送字元計數、接收字元計數等。在串列埠的傳送中斷處理函式和接收中斷處理函式中,我們需要管理這些計數。 struct uart_icount { __u32 cts; __u32 dsr; __u32 rng; __u32 dcd; __u32 rx; /* 傳送字元計數 */ __u32 tx; /* 接受字元計數 */ __u32 frame; /* 幀錯誤計數 */ __u32 overrun; /* Rx FIFO溢位計數 */ __u32 parity; /* 幀校驗錯誤計數 */ __u32 brk; /* break計數 */ __u32 buf_overrun; }; uart_info有兩個成員在底層串列埠驅動會用到:xmit和tty。使用者空間程式通過串列埠傳送資料時,上層驅動將使用者資料儲存在xmit;而串列埠傳送中斷處理函式就是通過xmit獲取到使用者資料並將它們傳送出去。串列埠接收中斷處理函式需要通過tty將接收到的資料傳遞給行規則層。 /* uart_info例項僅在串列埠埠開啟時有效,它可能在串列埠關閉時被串列埠核心層釋放。因此,在使用uart_port的uart_info成員時必須保證串列埠已開啟。底層驅動和核心層驅動都可以修改uart_info例項。 * This is the state information which is only valid when the port * is open; it may be freed by the core driver once the device has * been closed. Either the low level driver or the core can modify * stuff here. */ struct uart_info { struct tty_struct *tty; struct circ_buf xmit; uif_t flags; /* * Definitions for info->flags. These are _private_ to serial_core, and * are specific to this structure. They may be queried by low level drivers. */ #define UIF_CHECK_CD ((__force uif_t) (1 << 25)) #define UIF_CTS_FLOW ((__force uif_t) (1 << 26)) #define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29)) #define UIF_INITIALIZED ((__force uif_t) (1 << 31)) #define UIF_SUSPENDED ((__force uif_t) (1 << 30)) int blocked_open; struct tasklet_struct tlet; wait_queue_head_t open_wait; wait_queue_head_t delta_msr_wait; }; 3、uart_ops uart_ops涵蓋了串列埠驅動可對串列埠裝置進行的所有操作。 /* * This structure describes all the operations that can be * done on the physical hardware. */ struct uart_ops { unsigned int (*tx_empty)(struct uart_port *); /* 串列埠的Tx FIFO快取是否為空 */ void (*set_mctrl)(struct uart_port *, unsigned int mctrl); /* 設定串列埠modem控制 */ unsigned int (*get_mctrl)(struct uart_port *); /* 獲取串列埠modem控制 */ void (*stop_tx)(struct uart_port *); /* 禁止串列埠傳送資料 */ void (*start_tx)(struct uart_port *); /* 使能串列埠傳送資料 */ void (*send_xchar)(struct uart_port *, char ch);/* 傳送xChar */ void (*stop_rx)(struct uart_port *); /* 禁止串列埠接收資料 */ void (*enable_ms)(struct uart_port *); /* 使能modem的狀態訊號 */ void (*break_ctl)(struct uart_port *, int ctl); /* 設定break訊號 */ int (*startup)(struct uart_port *); /* 啟動串列埠,應用程式開啟串列埠裝置檔案時,該函式會被呼叫 */ void (*shutdown)(struct uart_port *); /* 關閉串列埠,應用程式關閉串列埠裝置檔案時,該函式會被呼叫 */ void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios*old); /* 設定串列埠引數 */ void (*pm)(struct uart_port *, unsigned int state, unsigned int oldstate); /* 串列埠電源管理 */ int (*set_wake)(struct uart_port *, unsigned int state); /* */ const char *(*type)(struct uart_port *); /* 返回一描述串列埠型別的字串 */ void (*release_port)(struct uart_port *); /* 釋放串列埠已申請的IO埠/IO記憶體資源,必要時還需iounmap */ int (*request_port)(struct uart_port *); /* 申請必要的IO埠/IO記憶體資源,必要時還可以重新對映串列埠埠 */ void (*config_port)(struct uart_port *, int); /* 執行串列埠所需的自動配置 */ int (*verify_port)(struct uart_port *, struct serial_struct *); /* 核實新串列埠的資訊 */ int (*ioctl)(struct uart_port *, unsigned int, unsigned long); /* IO控制 */ }; 二、串列埠驅動API 1、uart_register_driver /* 功能: uart_register_driver用於將串列埠驅動uart_driver註冊到核心(串列埠核心層)中,通常在模組初始化函式呼叫該函式。 * 引數 drv:要註冊的uart_driver * 返回值: 成功,返回0;否則返回錯誤碼 */ int uart_register_driver(struct uart_driver *drv) 2、uart_unregister_driver /* 功能: uart_unregister_driver用於登出我們已註冊的uart_driver,通常在模組解除安裝函式呼叫該函式 * 引數 drv:要登出的uart_driver * 返回值: 成功,返回0;否則返回錯誤碼 */ void uart_unregister_driver(struct uart_driver *drv) 3、uart_add_one_port /* 功能: uart_add_one_port用於為串列埠驅動新增一個串列埠埠,通常在探測到裝置後(驅動的裝置probe方法)呼叫該函式 * 引數 drv:串列埠驅動 * port:要新增的串列埠埠 * 返回值: 成功,返回0;否則返回錯誤碼 */ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) 4、uart_remove_one_port /* 功能: uart_remove_one_port用於刪除一個已新增到串列埠驅動中的串列埠埠,通常在驅動解除安裝時呼叫該函式 * 引數 drv: 串列埠驅動 * port: 要刪除的串列埠埠 * 返回值: 成功,返回0;否則返回錯誤碼 */ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) 5、uart_write_wakeup /* 功能: uart_write_wakeup喚醒上層因向串列埠埠寫資料而阻塞的程序,通常在串列埠傳送中斷處理函式中呼叫該函式 * 引數 port:需要喚醒寫阻塞程序的串列埠埠 */ void uart_write_wakeup(struct uart_port *port) 6、uart_suspend_port /* 功能: uart_suspend_port用於掛起特定的串列埠埠 * 引數 drv: 要掛起的串列埠埠所屬的串列埠驅動 * port:要掛起的串列埠埠 * 返回值: 成功返回0;否則返回錯誤碼 */ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) 7、uart_resume_port /* 功能: uart_resume_port用於恢復某一已掛起的串列埠 * 引數 drv: 要恢復的串列埠埠所屬的串列埠驅動 * port:要恢復的串列埠埠 * 返回值: 成功返回0;否則返回錯誤碼 */ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) 8、uart_get_baud_rate /* 功能: uart_get_baud_rate通過解碼termios結構體來獲取指定串列埠的波特率 * 引數 port: 要獲取波特率的串列埠埠 * termios:當前期望的termios配置(包含串列埠波特率) * old: 以前的termios配置,可以為NULL * min: 可接受的最小波特率 * max: 可接受的最大波特率 * 返回值: 串列埠的波特率 */ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, struct ktermios *old, unsigned int min, unsigned int max) 9、uart_get_divisor /* 功能: uart_get_divisor用於計算某一波特率的串列埠時鐘分頻數(串列埠波特率除數) * 引數 port:要計算時鐘分頻數的串列埠埠 * baud:期望的波特率 *返回值: 串列埠時鐘分頻數 */ unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud) 10、uart_update_timeout /* 功能: uart_update_timeout用於更新(設定)串列埠FIFO超時時間 * 引數 port: 要更新超時時間的串列埠埠 * cflag:termios結構體的cflag值 * baud: 串列埠的波特率 */ void uart_update_timeout(struct uart_port *port, unsigned int cflag, unsigned int baud) 11、uart_match_port /* 功能:uart_match_port用於判斷兩串列埠埠是否為同一埠 * 引數 port1、port2:要判斷的串列埠埠 * 返回值:不同返回0;否則返回非0 */ int uart_match_port(struct uart_port *port1, struct uart_port *port2) 12、uart_console_write /* 功能: uart_console_write用於向串列埠埠寫一控制檯資訊 * 引數 port: 要寫資訊的串列埠埠 * s: 要寫的資訊 * count: 資訊的大小 * putchar: 用於向串列埠埠寫字元的函式,該函式函式有兩個引數:串列埠埠和要寫的字元 */ void uart_console_write(struct uart_port *port, const char *s, unsigned int count, void (*putchar)(struct uart_port *, int)) 三、串列埠驅動例子 該串列埠驅動例子是我針對s3c2410處理器的串列埠2(uart2)獨立開發的。因為我通過博創2410s開發板的GRPS擴充套件板來測試該驅動(已通過測試),所以我叫該串列埠為gprs_uart。 該驅動將串列埠看作平臺(platform)裝置。platform可以看作一偽匯流排,用於將集成於片上系統的輕量級裝置與Linux裝置驅動模型聯絡到一起,它包含以下兩部分(有關platform的宣告都在#include <linux/platform_device.h>,具體實現在drivers/base/platform.c): 1、platform裝置。我們需要為每個裝置定義一個platform_device例項 struct platform_device { const char *name; /* 裝置名 */ int id; /* 裝置的id號 */ struct device dev; /* 其對應的device */ u32 num_resources;/* 該裝置用有的資源數 */ struct resource *resource; /* 資源陣列 */ }; 為我們的裝置建立platform_device例項有兩種方法:填充一個platform_device結構體後用platform_device_register(一次註冊一個)或platform_add_devices(一次可以註冊多個platform裝置)將platform_device註冊到核心;更簡單的是使用platform_device_register_simple來建立並註冊我們的platform_device。 2、platform驅動。platform裝置由platform驅動進行管理。當裝置加入到系統中時,platform_driver的probe方法會被呼叫來見對應的裝置新增或者註冊到核心;當裝置從系統中移除時,platform_driver的remove方法會被呼叫來做一些清理工作,如移除該裝置的一些例項、登出一些已註冊到系統中去的東西。 struct platform_driver { int (*probe)(struct platform_device *); int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*suspend_late)(struct platform_device *, pm_message_t state); int (*resume_early)(struct platform_device *); int (*resume)(struct platform_device *); struct device_driver driver; }; 更詳細platform資料可參考網上相關文章。 例子驅動中申請和釋放IO記憶體區的整個過程如下: insmod gprs_uart.ko→gprs_init_module()→uart_register_driver()→gprs_uart_probe()→ uart_add_one_port()→gprs_uart_config_port()→gprs_uart_request_port()→request_mem_region() rmmod gprs_uart.ko→gprs_exit_module()→uart_unregister_driver()→gprs_uart_remove()→uart_remove_one_port()→gprs_uart_release_port()→release_mem_region() 例子驅動中申請和釋放IRQ資源的整個過程如下: open /dev/gprs_uart→gprs_uart_startup()→request_irq() close /dev/gprs_uart→gprs_uart_shutdown()→free_irq()
相關推薦
linux下的串列埠驅動程式
串列埠驅動確實不簡單,不過多花費心思整體思路還是容易理清的。原文如下:一、核心資料結構 串列埠驅動有3個核心資料結構,它們都定義在<#include linux/serial_core.h> 1、uart_driver uart_driver包含了串列埠裝置名、
Linux串列埠驅動程式(2)-串列埠驅動程式初始化分析
1、串列埠驅動程式結構分析 對使用者來講,能夠正常使用串列埠肯定是需要實現如下函式的: 1、串列埠裝置檔案的開啟 2、串列埠裝置檔案的初始化 3、串列埠裝置檔案的讀寫 4、串列埠裝置檔案的控制 2、串列埠驅動中重要的資料結構 首先分析一下串列埠讀寫的流程 當用戶讀寫串列埠
linux裝置驅動,tty串列埠程式設計 如何檢視linux下串列埠是否可用?串列埠名稱等
如何檢視linux下串列埠是否可用?串列埠名稱等? 檢視串列埠是否可用,可以對串列埠傳送資料比如對com1口,echo lyjie126 > /dev/ttyS0 檢視串列埠名稱使用 ls -l /dev/ttyS* 一般情況下串列埠的名稱全部在dev下面,如果你沒
解決Linux下串列埠資料接收不全的異常問題
1、引言 最近在Linux下除錯串列埠程式,遇到了串列埠資料接收不全的異常問題,經過將近一上午的努力終於找到問題根源,特此分享給大家,此次除錯過程中用到了主要用到了minicom工具,至於minicom的使用大家可以自行查詢相關資料。 2、正文
STM32 UART串列埠驅動程式
文章原始地址: http://feotech.com/?p=56 示例1.通過UART1進行資料傳送 UART 1 的初始化 /** * @brief UART1 Initialise. * @param None. * @retval None. */ void UART
記一次linux下串列埠資料丟包解決過程
專案中兩個晶片之間用串列埠進行通訊,由於傳輸格式中有校驗位,在資料量很大的時候總是校驗失敗。於是花了很長的時間最終解決了這個問題。 首先串列埠丟資料有兩種情況(明顯排除傳送端傳送的資料不對),第一種是通道也就是串列埠線或者連線口不行,無法承受很高的波特率(我使用的波特率是9
linux 下串列埠工具minicom的使用
為了在ubuntu 12.04下能夠看到正常串列埠輸出,使用Minicom. 1、安裝 sudo apt-get install minicom 2、配置 (1)首先在命令列下執行sudo minicom啟動程式 (2)進入主介面後按 Ctrl+A 然後再按Z 進入配
linux UART串列埠驅動開發
內容簡介: 介紹了Linux下的串列埠驅動的設計層次及介面, 並指出串列埠與TTY終端之間的關聯層次(串列埠可作TTY終端使用), 以及Linux下的中斷處理機制/中斷共享機制, 還有串列埠緩衝機制當中涉及的軟中斷機制; 其中有關w83697/w83977 IC方面的知識, 具體參考相關手冊, 對串列埠的配
Linux下PCI裝置驅動程式開發基本框架
PCI是一種廣泛採用的匯流排標準,它提供了許多優於其它匯流排標準(如EISA)的新特性,目前已經成為計算機系統中應用最為廣泛,並且最為通用的匯流排標準。Linux的核心能較好地支援PCI匯流排,本文以Intel 386體系結構為主,探討了在Linux下開發PCI裝置驅動程式的基本框架。 一、PCI匯流排
linux下串列埠除錯工具/串列埠終端推薦: picocom
對於picocom, kermit, minicom, picocom 最簡單易用,也完全符合我的使用需求。 安裝(mint / ubuntu):$ sudo apt-get install picocom使用:$ picocom -b 115200 /dev/ttyUSB
嵌入式Linux下串列埠除錯
By Toradex秦海 1). 簡介 UART串列埠是嵌入式裝置最為常用的除錯和通訊介面之一,無論是RS232還是RS422/485都有著非常廣泛的應用,因此本文就基於嵌入式Linux演示在User Space進行串列埠除錯。 本文所演示的平臺來自於Toradex Co
linux下串列埠非標準波特率的實現
最近要在linux下使用電腦的串列埠,而使用的波特率不是諸如9600,19200之類的標準波特率,從網上查詢非標準波特率的設定方法,都是說對termios結構體進行設定。按照網上的程式碼進行設定卻不成功。費了很大力氣終於找到了原因:原來我的linux版本支援一部分非標準的
LINUX下ADC按鍵驅動程式
ADC按鍵驅動 Adc鍵盤原理圖如下,將串聯電阻之間分別用按鍵引出來與地相連,當按鍵按下時端電壓會發生改變。基本思想是在ADC驅動基礎上,對取樣電壓進行判斷,檢測是哪一個按鍵按下。 1. ADC驅動分析 在init()函式中,首先獲取adc的時鐘,並用clk_e
8250 driver Linux多串列埠驅動解析 xr16v554
一:前言 前一段時間自己實踐了一下8250晶片串列埠驅動的編寫。今天就在此基礎上分析一下 linux kernel 自帶的串列埠驅動。畢竟只有對比專業的驅動程式碼才能更好的進步, 同以往一樣,基於linux kernel2.6.25. 相應驅動程式碼位於
Cutecom--Linux下串列埠除錯工具
Cutecom是一款在Linux環境下,非常好用的串列埠除錯工具,使用方法幾乎跟Windows下的串列埠除錯工具一樣,非常方便。 Cutecom的安裝:直接在終端輸入:sudo apt-get install cutecom。 安裝完後,使用命令:sudo cutecom開
Linux下串列埠程式設計總結
1.串列埠操作需要的標頭檔案 #include <stdio.h> //標準輸入輸出定義 #include <stdlib.h> //標準函式庫定義 #include <unistd.h> //Unix標準函式定義 #include <
linux下串列埠工具minicom使用
系統環境:ubuntu destop 11.10 我當時的需要主要是兩個,能夠看到正常串列埠輸出,並且把串列埠內容實時輸出到檔案中 那接下來工作主要是兩個:1、安裝 2、配置 相信各位也都是至少會操作一些全令行的,我們在這裡用apt-get安裝(不會的同學請google一
linux下串列埠轉TCP網路通訊
“` include”test.h” include”modbus.h” define BUFFER_SIZE 29 int ret; modbus_t *mb; int16_t tab_reg[32]={0}; //初始化串列
linux下串列埠控制
/* 本程式符合GPL條約 * Beneboy 2003-5-16 */ #include <stdio.h> // printf #include <fcntl.h> // open #in
Linux下串列埠通訊詳解(上)開啟串列埠和串列埠初始化詳解
linux下串列埠通訊主要有下面幾個步驟 串列埠通訊流程圖 下面我會一一介紹這幾個步驟。 1.開啟串列埠 程式碼(串列埠為ttyUSB0) //開啟串列埠 int open_port(void) { int fd; fd=open("/dev/ttyUSB0