AM335X 串列埠驅動學習(1)-基於linux3.8核心
學習串列埠驅動,先從資料結構入手吧。串列埠驅動有3個核心資料結構:
(/drivers/tty/serial/omap-serial.c)
- UART特定的驅動程式結構定義:struct uart_driver serial_omap_reg;
- UART埠結構定義: struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
- UART相關操作函式結構定義: struct uart_ops serial_omap_pops;
重要資料結構
1. uart_driver
uart_driver 封裝了tty_driver,使得底層的UART驅動無需關心tty_driver。
#include <linux/serial_core.h>
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;
};
其中的uart_state是裝置私有資訊結構體,
在uart_open()中:
tty->driver_data = state;
在其他uart_xxx()中:
struct uart_state *state = tty->driver_data;
就可以獲取裝置私有資訊結構體。
#include<linux/serial_core.h>
static struct uart_driver serial_omap_reg = {
.owner = THIS_MODULE,
.driver_name = "OMAP-SERIAL",
.dev_name = OMAP_SERIAL_NAME,
.nr = OMAP_MAX_HSUART_PORTS,
.cons = OMAP_CONSOLE,
};
一個tty驅動必須註冊/登出tty_driver,而一個UART驅動則變為註冊/登出uart_driver,使用如下介面:
int uart_register_driver(struct uart_driver *drv);
void uart_unregister_driver(struct uart_driver *drv);
2. uart_port
用於描述一個UART的I/O埠或者IO記憶體地址等資訊;實際上,一個uart_port例項對應一個串列埠裝置。
#include<linux/serial_core.h>
struct uart_port {
spinlock_t lock; /* port lock 串列埠埠鎖 */
unsigned long iobase; /* in/out[bwl] io埠基地 */
unsigned char __iomem *membase;/* read/write[bwl] IO記憶體基地址,經對映(如ioremap)後的IO記憶體虛擬基地址 */
unsigned int (*serial_in)(struct uart_port *, int);
void (*serial_out)(struct uart_port *, int, int);
void (*set_termios)(struct uart_port *,
struct ktermios *new,
struct ktermios *old);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int old);
unsigned int irq; /* irq number */
unsigned long irqflags; /* irq flags */
unsigned int uartclk; /* base uart clock */
unsigned int fifosize; /* tx fifo size */
unsigned char x_char; /* xon/xoff char */
unsigned char regshift; /* reg offset shift */
unsigned char iotype; /* io access style */
unsigned char unused1;
#define UPIO_PORT (0)
#define UPIO_HUB6 (1)
#define UPIO_MEM (2)
#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 */
#define UPIO_DWAPB32 (8) /* DesignWare APB UART (32 bit accesses) */
unsigned int read_status_mask; /* driver specific */
unsigned int ignore_status_mask; /* driver specific */
struct uart_state *state; /* pointer to parent state */
struct uart_icount icount; /* statistics */
struct console *cons; /* struct console, if any */
#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
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_NO_TXEN_TEST ((__force upf_t) (1 << 15))
#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))
/* The exact UART type is known and should not be probed. */
#define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
#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; /* current modem ctrl settings */
unsigned int timeout; /* character-based timeout */
unsigned int type; /* port type */
const struct uart_ops *ops; /*UART操作集*/
unsigned int custom_divisor;
unsigned int line; /* port index */
resource_size_t mapbase; /* for ioremap */
struct device *dev; /* parent device */
unsigned char hub6; /* this should be in the 8250 driver */
unsigned char suspended;
unsigned char irq_wake;
unsigned char unused[2];
void *private_data; /* generic platform data pointer */
};
uart_omap_port 封裝了uart_port:
#inclide<linux/serial_core.h>
struct uart_omap_port {
struct uart_port port;
struct uart_omap_dma uart_dma;
struct device *dev;
unsigned char ier;
unsigned char lcr;
unsigned char mcr;
unsigned char fcr;
unsigned char efr;
unsigned char dll;
unsigned char dlh;
unsigned char mdr1;
unsigned char scr;
int use_dma;
/*
* Some bits in registers are cleared on a read, so they must
* be saved whenever the register is read but the bits will not
* be immediately processed.
*/
unsigned int lsr_break_flag;
unsigned char msr_saved_flags;
char name[20];
unsigned long port_activity;
int context_loss_cnt;
u32 errata;
u8 wakeups_enabled;
int DTR_gpio;
int DTR_inverted;
int DTR_active;
struct pm_qos_request pm_qos_request;
u32 latency;
u32 calc_latency;
struct work_struct qos_work;
struct pinctrl *pins;
struct serial_rs485 rs485;
};
static struct uart_omap_port *ui[OMAP_MAX_HSUART_PORTS];
由此可見,對串列埠的一系列初始化,實際上落到了對ui結構體的填充上。
在serial_omap_probe(struct platform_device *pdev)中:
struct uart_omap_port up; /*uart_omap_port 封裝了uart_port /
ui[up->port.line] = up;
serial_omap_add_console_port(up);
uart_add_one_port(&serial_omap_reg, &up->port);
- 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_stat有兩個成員在底層串列埠驅動會用到:xmit和port。使用者空間程式通過串列埠傳送資料時,上層驅動將使用者資料儲存在xmit;而串列埠傳送中斷處理函式就是通過xmit獲取到使用者資料並將它們傳送出去。串列埠接收中斷處理函式需要通過port將接收到的資料傳遞給行規則層。
/*
* This is the state information which is persistent across opens.
*/
struct uart_state {
struct tty_port port;
int pm_state;
struct circ_buf xmit;
struct tasklet_struct tlet;
struct uart_port *uart_port;
};
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 (*flush_buffer)(struct uart_port *);
void (*set_termios)(struct uart_port *, struct ktermios *new,
struct ktermios *old);/* 設定串列埠引數 */
void (*set_ldisc)(struct uart_port *, int new);
void (*pm)(struct uart_port *, unsigned int state,
unsigned int oldstate);/* 串列埠電源管理 */
int (*set_wake)(struct uart_port *, unsigned int state);
void (*wake_peer)(struct uart_port *);
/*
* Return a string describing the type of the port
*/
const char *(*type)(struct uart_port *);/* 返回一描述串列埠型別的字串 */
/*
* Release IO and memory resources used by the port.
* This includes iounmap if necessary.
*/
void (*release_port)(struct uart_port *);/* 釋放串列埠已申請的IO埠/IO記憶體資源,必要時還需iounmap */
/*
* Request IO and memory resources used by the port.
* This includes iomapping the port if necessary.
*/
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);
#ifdef CONFIG_CONSOLE_POLL
void (*poll_put_char)(struct uart_port *, unsigned char);
int (*poll_get_char)(struct uart_port *);
#endif
};
UART驅動的主體工作通過下列函式來實現:
#include<>
static struct uart_ops serial_omap_pops = {
.tx_empty = serial_omap_tx_empty,/*檢車傳送FIFO緩衝區是否空*/
.set_mctrl = serial_omap_set_mctrl,/*是否設定串列埠流控cts*/
.get_mctrl = serial_omap_get_mctrl,/*是否串列埠流控*/
.stop_tx = serial_omap_stop_tx,/*停止傳送*/
.start_tx = serial_omap_start_tx,/*啟動傳送*/
.throttle = serial_omap_throttle,/**/
.unthrottle = serial_omap_unthrottle,/**/
.stop_rx = serial_omap_stop_rx,/*停止接收*/
.enable_ms = serial_omap_enable_ms,/**/
.break_ctl = serial_omap_break_ctl,/*傳送break訊號*/
.startup = serial_omap_startup,/*串列埠傳送/接收,以及中斷申請初始配置函式*/
.shutdown = serial_omap_shutdown,/*關閉串列埠*/
.set_termios = serial_omap_set_termios,/*串列埠clk,波特率,資料位等引數設定*/
.pm = serial_omap_pm,/*電源管理函式*/
.set_wake = serial_omap_set_wake,/**/
.type = serial_omap_type,/*CPU型別關於串列埠*/
.release_port = serial_omap_release_port,/*釋放串列埠*/
.request_port = serial_omap_request_port,/*申請串列埠*/
.config_port = serial_omap_config_port,/*串列埠的一些配置資訊info*/
.verify_port = serial_omap_verify_port,/*串列埠檢測*/
.ioctl = serial_omap_ioctl,/**/
#ifdef CONFIG_CONSOLE_POLL
.poll_put_char = serial_omap_poll_put_char,/**/
.poll_get_char = serial_omap_poll_get_char,/**/
#endif
};
而在serial_core.c中定義了tty_operations的例項,包含uart_open();uart_close();uart_send_xchar()等成員函式,這些函數借助uart_ops結構體中的成員函式來完成具體的操作。
static const struct tty_operations uart_ops = {
.open = uart_open,
.close = uart_close,
.write = uart_write,
.put_char = uart_put_char,
.flush_chars = uart_flush_chars,
.write_room = uart_write_room,
.chars_in_buffer= uart_chars_in_buffer,
.flush_buffer = uart_flush_buffer,
.ioctl = uart_ioctl,
.throttle = uart_throttle,
.unthrottle = uart_unthrottle,
.send_xchar = uart_send_xchar,
.set_termios = uart_set_termios,
.set_ldisc = uart_set_ldisc,
.stop = uart_stop,
.start = uart_start,
.hangup = uart_hangup,
.break_ctl = uart_break_ctl,
.wait_until_sent= uart_wait_until_sent,
#ifdef CONFIG_PROC_FS
.proc_fops = &uart_proc_fops,
#endif
.tiocmget = uart_tiocmget,
.tiocmset = uart_tiocmset,
#ifdef CONFIG_CONSOLE_POLL
.poll_init = uart_poll_init,
.poll_get_char = uart_poll_get_char,
.poll_put_char = uart_poll_put_char,
#endif
};
從下面的例子中可以看出串列埠核心層的tty_operations與uart_ops的關係:
/*
* This function is used to send a high-priority XON/XOFF character to
* the device
*/
static void uart_send_xchar(struct tty_struct *tty, char ch)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
unsigned long flags;
if (port->ops->send_xchar)/*如果uart_ops中實現了send_xchar成員函式*/
port->ops->send_xchar(port, ch);
else {
port->x_char = ch;
if (ch) {
spin_lock_irqsave(&port->lock, flags);
port->ops->start_tx(port);
spin_unlock_irqrestore(&port->lock, flags);
}
}
}
(待續)
相關推薦
AM335X 串列埠驅動學習(1)-基於linux3.8核心
學習串列埠驅動,先從資料結構入手吧。串列埠驅動有3個核心資料結構: (/drivers/tty/serial/omap-serial.c) - UART特定的驅動程式結構定義:struct uart_driver serial_omap_reg; - U
busybox檔案系統與簡單驅動學習(1)-busybox檔案系統搭建與nfs掛載配置
一、busybox編譯安裝 2、參考資料:訊為4412精英版開發手冊9.5章節 3、實際操作環境:Ubuntu14.04、交叉編譯環境 arm-none-linux-gnueabi-(直接用訊為提供的,也可以網上用其他的)、busybox版本
Air202學習(1)認識Air202 S6 核心板
1、外設分佈圖 上圖可以看出,當我們想讓模組開機自啟動時,只需把【上電自動開機焊點】用焊錫點上即可。 2、排針管腳 模組可以採用4V/5V直流供電,可以用USB-TTL供電。 HOST_TX,HOST_RX為下載、除錯串列埠。連線方式如下: 3、關於板載L
串列埠驅動程式設計詳解---串列埠初始化(上)
TTY驅動程式架構: 1. TTY概念解析 1.1 /dev/ttySCA0 1.2 /dev/tty1-n 1.3 /dev/console 在linux系統中,終端是一類字元型裝置,它包括多種型別,通常使用tty來簡稱各種型別的終端裝
Linux 網卡驅動學習(二)(網絡驅動接口小結)
-a key 頻率 網絡 上網 ren 網絡設備 ews 入口 【摘要】前文我們分析了一個虛擬硬件的網絡驅動樣例。從中我們看到了網絡設備的一些接口。事實上網絡設備驅動和塊設備驅動的功能比較相似,都是發送和接收數據包(數據請求)。當然它們實際是有非常多不同
redis學習(1)--- NoSQL介紹
redis學習 模型 width 快速查詢 init 文件 borde 處理 only 一、NoSQL介紹 1、什麽是NoSQL NoSQL = Not Only SQL 非關系型數據庫 2、為什麽用NoSQL High performance - 高
Linux 網卡驅動學習(六)(應用層、tcp 層、ip 層、設備層和驅動層作用解析)
local acc 每次 letter auto sizeof style article inode 本文將介紹網絡連接建立的過程、收發包流程,以及當中應用層、tcp層、ip層、設備層和驅動層各層發揮的作用。 1、應用層 對於使用socket進行網絡連接的serv
ArcGIS API for JavaScript學習(1):第一個地圖
樣式表 參數 資源 charset 底層 arcgis 順序 api navi 1.簡介 ArcGIS API for JavaScript跟隨ArcGIS 9.3同時發布,是ESRI根據JavaScript技術實現的調用ArcGIS Server REST API接口的一
Linux學習(1)
linux開始學習Linux了,希望能學有所成————測試中本文出自 “Linux學習” 博客,請務必保留此出處http://mmchy.blog.51cto.com/13044974/1941714Linux學習(1)
facets學習(1):什麽是facets
遺失 air 不同的 無縫切換 over 快速 後來 樣式 觀察 ML 數據集可以包含數億個數據點,每個數據點由數百(甚至數千)的特征組成,幾乎不可能以直觀的方式了解整個數據集。為幫助理解、分析和調試 ML 數據集,谷歌開源了 Facets,一款可視化工具。 Facets
C++學習(1):最大子段和(多種解法)
多少 問題: code namespace 數據 組成 amp using () 問題:給定由n個數(可能為負數)組成的序列a1,a2,a3,...,an,求該序列子段和的最大值。 第一種解法:(最容易考慮的方法,將所有的子段一一相加,然後比較) 1 #include&
嵌入式開發學習(1)<ARM體系結構>
特點 如何 現在 訪問 任務 物聯網 嵌入 專用 arm1 SoC : 在cpu 裏內嵌了很多外設,現在所說的cpu 實際上都是SoC。 32位cpu指的是數據總線是32位的。 32位的地址總線尋址範圍是4G。2的32次方。 CISC complex instruction
IDEA 學習筆記之 Java項目開發深入學習(1)
java項目 bsp 重構 str 代碼提示 log pan ora tro Java項目開發深入學習(1): 定義編譯輸出路徑: 繼承以上工程配置 重新定義新的項目編譯路徑 添加source目錄:點擊添加,再點擊移除: 編譯項目: 常用快捷鍵總結: Ctr
nodejs學習(1)
管理工具 cti 分享 環境 scrip alt world 命令提示符 true 1.安裝:可以在http://nodejs.org/dist/下載nodejs的所有版本,我在裏面下載了node-v8.9.0-x64.msi,安裝完成,在命令提示符中輸入“node --v
Win10下Docker學習(1)安裝
ner table 組成 高效率 down 提高 打開 cpu 其他人 Docker簡介 Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發布到任何流行的 Linux 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,
bartender鏈接數據庫提示:無法鏈接到數據庫 外部數據驅動程序(1)中的意外錯誤#6670
bartender 6670 外部數據驅動程序bartender鏈接數據庫提示:無法鏈接到數據庫 外部數據驅動程序(1)中的意外錯誤#6670是 微軟 10月份更新的補丁導致。解決:1.關閉自動更新2.卸載補丁:win7 KB4041678 KB404168
Vue深度學習(1)
msg 第一個 數據綁定 vue.js 這就是 one round 本質 dex Hello World 現在就讓我們來寫第一個vue.js的實例。如下代碼: html代碼: <div id="demo"> {{ message }}
腳本學習(1)列出一組IP內所有活動主機
cat -c spa ash 活動 pin null status amp 1、用ping命令編寫腳本來查詢一組IP地址同時檢查他們是否處於活動狀態 1 [zhi@centos7 ~]$ vi CheckHostStatus.sh 2 [zhi@centos7 ~]$
Python爬蟲學習(1)
數據 bin des fin load 寫入 all pytho urlopen 接觸python不久,也在慕課網學習了一些python相關基礎,對於爬蟲初步認為是依靠一系列正則獲取目標內容數據 於是參照著慕課網上的教學視頻,完成了我的第一個python爬蟲,雞凍 >
Docker學習(1)安裝
www. ati https 機制 生產環境 開機啟動 works tab 流行 1. Docker簡介 Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的容器中,然後發布到任何流行的 Linux 機器上,也可以實現虛擬化。容器是完全