日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux配置串口驱动程序,[Linux 驱动] -- Linux 驱动之串口(UART)

發布時間:2024/8/1 linux 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux配置串口驱动程序,[Linux 驱动] -- Linux 驱动之串口(UART) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、UART 驅動程序概述

在嵌入式 Linux 系統中,串口被看成終端設備,終端設備(tty)的驅動程序分為三個部分:

tty_core

tty_disicipline

tty_driver

包括3個結構體:

uart_driver

uart_port

uart_ops( include/serial_core.h)

因此實現一個平臺的 UART 驅動程序只需要實現這3個結構體即可。

二、uart_drvier 與 tty_driver 之間的關系

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

...........................

struct uart_state *state;

struct tty_driver *tty_driver; //uart_driver 封裝了 tty_driver,使底層uart驅動不用關心tty_driver。

};

一個 tty 驅動程序必須注冊/注銷 tty_driver;

一個 uart 驅動則變為注冊/注銷 uart_driver;

使用如下接口:

int uart_register_driver(struct uart_driver *drv);

void uart_unregister_driver(struct uart_drvier *drv);

int tty_register_driver(struct tty_driver *drv);

void tty_unregister_driver(struct tty_driver *drv);

實際上,uart_register_driver() 和 uart_unregister_drvier() 中分別包含了 tty_register_driver() 和 tty_unregister () 的操作,詳情如下:

uart_port結構體:

uart_port 用于描述一個 UART 端口(直接對應于一個串口)的 I/O 端口或 I/O內存地址、FIFO大小、端口類型等信息。

struct uart_port

{

spinlock_t lock; //串口端口鎖

unsigned int iobase; //IO 端口基地址

unsigned char __iomem *membase; //IO 內存基地址,經映射(如ioremap)后的IO內存虛擬基地址

unsigned int irq; //中斷號

unsigend int uartlock; //串口時鐘

unsigend int fifosize; //串口FIFO緩沖大小

unsigned char x_char; //xon/xoff 字符

unsigned char regshift; //寄存器位移

unsigned char iotype; //IO訪問方式

unsigned char unused1;

#define UPIO_PORT (0) //IO端口

#deifne UPIO_HUB6 (1)

#define UPIO_MEM (2) //IO內存

#define UPIO_MEM32(3)

#define UPIO_AU (4) //Aulx00 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; //重要,見下面

struct uart_icount icount; //計數器 uart_icount 為串口信息計數器,包含了發送字符計數、接收字符計數等。在串口的發送中斷處理函數和接收處理函數中,我們需要管理這些計數。

struct console *cons; //console 結構體

#ifdef CONFIG_SERIAL_CORE_CONSOLE

unsigned long sysrq; //sysrq timeout

#endif

upf_t flags;

#define UPF_FOURPORT ((__forceupf_t)(1 << 1))

#define UPF_SAK ((__forceupf_t)(1 << 2))

#define UPF_SPD_MASK ((__forceupf_t)(0x1030))

#define UPF_SPD_HI ((__forceupf_t)(0x0010))

#define UPF_SPD_VHI ((__forceupf_t)(0x0020))

#define UPF_SPD_CUST ((__forceupf_t)(0x0030))

#define UPF_SPD_SHI ((__forceupf_t)(0x1000))

#define UPF_SPD_WARP ((__forceupf_t)(0x1010))

#define UPF_SKIP_TEST ((__forceupf_t)(1 << 6))

#define UPF_AUTO_IRQ ((__forceupf_t)(1 << 7))

#define UPF_HARDPPS_CD ((__forceupf_t)(1 << 11))

#define UPF_LOW_LATENCY ((__forceupf_t)(1 << 13))

#define UPF_BUGGY_UART ((__forceupf_t)(1 << 14))

#define UPF_MAGIC_MULTIPLIER((__force upf_t)(1 << 16))

#define UPF_CONS_FLOW ((__forceupf_t)(1 << 23))

#define UPF_SHARE_IRQ ((__forceupf_t)(1 << 24))

#define UPF_BOOT_AUTOCONF ((__forceupf_t)(1 << 28))

#define UPF_FIXED_PORT ((__forceupf_t)(1 << 29))

#define UPF_DEAD ((__forceupf_t)(1 << 30))

#define UPF_IOREMAP ((__forceupf_t)(1 << 31))

#define UPF_CHANGE_MASK((__forceupf_t)(0x17fff))

#define UPF_USR_MASK ((__forceupf_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;

unsigend char unused[2];

void *private_data; //端口私有數據,一般為platform數據指針

};

串口核心層提供如下函數來添加一個端口:

int uart_add_one_port(struct uart_driver *drv, struct uart_port *port);

對上述函數的調用應該發生在 uart_register_driver() 之后, uart_add_one_port() 的一個最重要的作用是封裝了 tty_register_device()。

uart_add_one_port() 的“反函數”是 uart_remove_one_port(),其中會調用 tty_unregister_device(), 原型為:

int uart_remove_one_port(struct driver *drv, struct uart_port *port);

uart_info結構體:

uart_info 有兩個成員在底層串口驅動會用到: xmit 和 tty。用戶空間程序通過串口發送數據時,上層驅動將用戶數據保存在xmit;而串口發送中斷處理函數就是通過xmit獲取到用戶數據并將它們發送出去。串口接收中斷處理函數需要通過tty將接收到的數據傳遞給行規則層。

在使用串口核心層這個通用串口tty驅動層的接口后,一個串口驅動要完成的主要工作將包括:

定義uart_drvier、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驅動的主體工作。

串口驅動之tty

概念介紹:

在Linux中,終端是一類字符設備,他包括多種類型,通常使用tty來簡稱各種中斷設備串口終端(/dev/ttyS*):串口終端是使用串口連接的終端設備,Linux中將每一個串口設備都看作一個字符設備,這些串行端口對應的設備名稱是/dev/ttySAC0 和 /dev/ttySAC1。

控制臺終端(/dev/console):

在Linux中,計算中的輸出設備通常被稱為控制臺終端(console)。這里特指printk()信息輸出的。注意:/dev/console 是一個虛擬的設備,它需要映射到真正的tty上。比如通過內核啟動參數“console=ttySAC0”就是把console映射到串口0,經常被內核所使用。

注意:這里的終端是一個虛擬設備,虛擬設備必須和實際的設備聯系起來,console=ttySAC0系統啟動的時候就關聯起來了。

虛擬終端(/dev/tty*):

當用戶登錄的使用使用的是虛擬終端,使用快捷鍵組合:ctrl+alt+[F1-F6]組合鍵就可以切換到tty1,tty2,tty3等上面去。tty1-tty6等成為虛擬終端,而tty0是當前使用的終端的一個別名。主要是提供給應用程序使用。

tty架構

tty核心:

tty核心是對整個tty設備的抽象,并提供單一的接口。

tty線路規劃:

tty線路規程是對數據的傳輸的格式化,比如需要實現某種協議,就需要將協議的實現代碼放在該位置。

tty驅動:

是面向tty設備的硬件驅動

注意:Linux中的獲取回溯信息使用函數dump_stack()用來顯示各種函數的調用信息。

串口驅動程序的結構

分析:串口驅動程序需要提供給用戶讀數據的功能,寫數據,打開串口和關閉串口的功能。打開之前需要對肯定需要對串口進行初始化的工作。

重要數據結構:

struct uart_driver :一個串口對應一個串口驅動,用于描述串口結構

struct uart_port:??? 有幾個串口就對應幾個port

struct uart_ops:? UART相關操作函數結構體,對應相關串口所支持的操作函數集

struct uart_state:UART狀態結構

struct uart_info: UART信息結構

串口初始化:

定義并描述串口:struct uart_driver;

注冊串口驅動程序:uart_register_driver;

取出相應的串口,并初始化該取出的串口。

串口驅動之打開驅動:

系統調用過程:用戶使用open()函數打開設備文件

注意:

打開設備文件肯定有對應的設備驅動文件打開函數:file_operations;

在使用uart_register_driver()注冊串口驅動的時候,該函數里面會調用函數tty_register_driver(),該函數會調用 cdev_init()函數和cdev_add()。

從這里可以看出tty設備是屬于字符設備。

總結

以上是生活随笔為你收集整理的linux配置串口驱动程序,[Linux 驱动] -- Linux 驱动之串口(UART)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。