linux UART串口驅(qū)動(dòng)開發(fā)文檔
順帶介紹開關(guān)中斷接口:
static void w83697uart_start_tx(struct uart_port *port, unsigned int tty_start)
static void w83697uart_stop_tx(struct uart_port *port, unsigned int tty_stop)
函數(shù): static void w83697uart_int(int irq, void *dev_id, struct pt_regs *regs)
描述: 中斷處理函數(shù),為3個(gè)使用系統(tǒng)外部中斷的的串口的中斷入口,其中必須處理的中斷狀態(tài)分為如下幾種, 注意必須在處理中斷時(shí)根據(jù)手冊中的說明來清除中斷,通常是讀或?qū)懩承┘拇嫫骷纯伞?p>接收中斷.
傳送中斷.
FIFO超時(shí)中斷.
其它不具體處理的中斷,必須讀相應(yīng)寄存器清中斷.
函數(shù): static void w83697uart_int2(int irq, void *dev_id, struct pt_regs *regs)
描述: 中斷處理函數(shù),為另外幾個(gè)使用串口使用的GPIO中斷入口,GPIO中斷共享同一個(gè)系統(tǒng)中斷向量, 必須根據(jù)GPIO的中斷狀態(tài)寄存器的相應(yīng)位來判斷對應(yīng)的中斷是屬哪一個(gè)串口的,從而進(jìn)行相應(yīng)的處理,其實(shí)這個(gè)判斷也是無所謂的,因?yàn)橹袛喈a(chǎn)生時(shí)傳進(jìn)來的參數(shù)已經(jīng)含有了相應(yīng)串口的參數(shù), 在判斷完中斷產(chǎn)生的GPIO口后立即調(diào)用w83697uart_int2 完成具體的中斷處理.
函數(shù): static int w83697uart_startup(struct uart_port *port)
描述: 串口開啟后的初始化函數(shù),主要完成初始化配置,以及安裝中斷處理了函數(shù),初始化配置包括打開中斷使能標(biāo)志。
函數(shù): static void w83697uart_shutdown(struct uart_port *port)
描述: 串口關(guān)閉函數(shù),清除配置,半閉中斷.
函數(shù): static void w83697uart_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot)
描述: 配置函數(shù),經(jīng)由上次調(diào)用下來,主要配制串口的波特率比,以及各種容錯(cuò)處理,在串口打開初始化時(shí)會(huì)被調(diào)用,在必變串口波特率/校驗(yàn)方式/停止位/傳送位數(shù)等參數(shù)時(shí)會(huì)被調(diào)用.
5. 串口驅(qū)動(dòng)與上層的接口關(guān)聯(lián)
文件: linux-2.4.21/drivers/serial/core.c
這一層接口是串口驅(qū)動(dòng)中的共用部分代碼, 核心結(jié)構(gòu)為struct uart_driver. 這一層上承TTY終端,下啟串口底層,串口底層主要處理了與串口硬件相關(guān)的部分,并向上提供uart中間層向下的接口. Uart coar向下與底層驅(qū)動(dòng)的接口,通過一個(gè)static struct uart_ops amba_pops結(jié)構(gòu)完成? 這個(gè)結(jié)構(gòu)直接賦值給串口struct uart_amba_port amba_ports 的.ops成員,最后將串口的port加入到uart_driver當(dāng)中完成關(guān)聯(lián), 通過uart_add_one_port加入.
static int __init w83697uart_init(void)
{
int ret, i;
ret = uart_register_driver(amba_reg);
if (ret == 0) {
for (i = 0; i UART_NR; i++)
uart_add_one_port(amba_reg, amba_ports[i].port);
}
return ret;
}
二. Linux的中斷機(jī)制及中斷共享機(jī)制.
前面講到了有6個(gè)串口,除了w83697中的前三個(gè)串使用的是獨(dú)立的系統(tǒng)外部中斷之外,其它的在個(gè)串口是共享一個(gè)系統(tǒng)中斷向量的,現(xiàn)在我們來看看多個(gè)中斷是如何掛在一個(gè)系統(tǒng)中斷向量表當(dāng)中的,共享中斷到底是什么樣的一種機(jī)制?
進(jìn)行分析代碼可知,linux下的中斷采用的是中斷向量的方式,每一個(gè)中斷對應(yīng)一個(gè)中斷描述數(shù)組當(dāng)中的一項(xiàng), 結(jié)構(gòu)為struct irqdesc,其當(dāng)中對應(yīng)一成員結(jié)構(gòu)為struct irqactionr 的成員action, 這個(gè)即表示此中斷向量對應(yīng)的中斷處理動(dòng)作,這里引用從網(wǎng)上下載的一幅圖講明中斷向量表與中斷動(dòng)作之間的關(guān)系:
struct irqaction {
void (*handler)(int, void *, struct pt_regs *);
unsigned long flags;
unsigned long mask;
const char *name;
void *dev_id;
struct irqaction *next;
};
從上面的結(jié)構(gòu)體與圖當(dāng)中,我們就可以很清楚的看到,一個(gè)中斷向量表可以對應(yīng)一個(gè)irqaction,也可能對應(yīng)多個(gè)由鏈表鏈在一起的一個(gè)鏈表irqaction, 這當(dāng)中主要在安裝中斷的時(shí)候通過中斷的標(biāo)志位來決定:
安裝中斷處理,不可共享:
retval = request_irq(port->irq, w83697uart_int, 0, w83697_uart3, port);
安裝中斷處理,可共享:
retval = request_irq(port->irq, w83697uart_int2, SA_SHIRQ, w83977_uart5, port);
由上即可知,安裝共享中斷時(shí),只須指定安裝的中斷標(biāo)志位flag為SA_SHIRQ, 進(jìn)入分析安裝中斷的處理可知,在安裝時(shí),會(huì)檢測已經(jīng)安裝的中斷是否支持共享中斷,如果不支持,則新的中斷安裝動(dòng)作失敗;如果已經(jīng)安裝的中斷支持共享中斷,則還必須檢測將要安裝的新中斷是否支持中斷共享,如果不支持則安裝還是會(huì)失敗,如果支持則將此新的中斷處理鏈接到此中斷向量對應(yīng)的中斷動(dòng)作處理鏈表當(dāng)中.
在產(chǎn)生中斷時(shí),共享中斷向量中對應(yīng)的中斷處理程序鏈表中的每一個(gè)都會(huì)被調(diào)用,依據(jù)鏈表的次序來,這樣處理雖然會(huì)有影響到效率,但是一般情況下中斷傳到用戶的中斷處理服務(wù)程序中時(shí),由用戶根據(jù)硬件的狀態(tài)來決定是否處理中斷,所以能常情況下都是立即就返回了,效率的影響不會(huì)是大的問題.
三. Linux的軟中斷機(jī)制.
前面已經(jīng)簡單講過了LINUX下的硬中斷處理機(jī)制,其實(shí)硬中斷的處理都由LINUX底層代碼具體完成了,使用者一般在處理硬中斷時(shí)是相當(dāng)簡單的,只須要用request_irq()簡單的掛上中斷即可,這里我們進(jìn)一步介紹一下LINUX下的軟中斷機(jī)制,軟中斷機(jī)制相比起硬中斷機(jī)制稍微復(fù)雜一些,而且在LINUX內(nèi)核本身應(yīng)用非常的廣, 它作為一種軟性的異步執(zhí)行機(jī)制,只有深入理解了它才能靈活的運(yùn)用.
之所以提到內(nèi)核的softirq機(jī)制,主要是因?yàn)樵诖谥袛嘁彩褂昧诉@些機(jī)制,理解了這些機(jī)制就能更加明白串口驅(qū)動(dòng)一些問題, 現(xiàn)在先提出幾個(gè)問題如下:
前面提供到中斷接收后數(shù)據(jù),先放到flip緩沖區(qū)當(dāng)中,這樣讓人很容易進(jìn)一步想知道,中斷處理的緩沖區(qū)的數(shù)據(jù),用戶進(jìn)程讀取串口時(shí)如何讀到的?很明顯中斷處于內(nèi)核空間,用戶讀取串口輸入進(jìn)程是在用戶空間,中斷緩沖區(qū)中的數(shù)據(jù)如何被處理到終端緩沖區(qū)中,供用戶讀取的?
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)linux相關(guān)文章:linux教程
評論