<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 打通linux的tty驅動(dòng)的數據鏈路

打通linux的tty驅動(dòng)的數據鏈路

作者: 時(shí)間:2016-10-08 來(lái)源:網(wǎng)絡(luò ) 收藏

………

}

就是根據cmd的值進(jìn)行相關(guān)操作,有對線(xiàn)路規程操作的,有直接通過(guò)tty_driver操作的。

三、TTY驅動(dòng)層分析

接下來(lái)看,TTY驅動(dòng)層是怎樣的:

TTY驅動(dòng)層是根據不同的硬件操作來(lái)完成相應的操作,這里我們以串口為例。

串口作為一個(gè)標準的設備,把共性的分離出來(lái),就成了uart層,特性成了serial層。

主要是serial層作為一個(gè)驅動(dòng)模塊加載。以8250.c為例:

static int __init serial8250_init(void)

{

………

serial8250_reg.nr= UART_NR;

ret= uart_register_driver(serial8250_reg);

………

serial8250_register_ports(serial8250_reg,serial8250_isa_devs->dev);

………

#define UART_NR CONFIG_SERIAL_8250_NR_UARTS

CONFIG_SERIAL_8250_NR_UARTS是在配置內核的時(shí)候定義的,表示支持串口的個(gè)數。

static struct uart_driver serial8250_reg = {

。owner =THIS_MODULE,

。driver_name =serial,

。dev_name =ttyS,

。major =TTY_MAJOR,

。minor =64,

。cons =SERIAL8250_CONSOLE,

};

在驅動(dòng)層里有幾個(gè)重要的數據結構:

structuart_driver;

structuart_state ;

structuart_port;

structtty_driver;

structtty_port;

實(shí)際上,理清了這幾個(gè)結構體的關(guān)系,也就理清了TTY驅動(dòng)層。

uart_register_driver:

這個(gè)函數主要是向TTY核心層注冊一個(gè)TTY驅動(dòng):

retval= tty_register_driver(normal);

其中normal是tty_driver.

另外,還會(huì )對tty_driver和uart_driver之間進(jìn)行某些賦值和指針連接。我們最關(guān)心的是,給tty_driver初始化了操作函數uart_ops,這樣,在tty核心層就可以通過(guò)uart_ops來(lái)對UART層進(jìn)行操作。

serial8250_register_ports:

最重要的兩個(gè)函數:serial8250_isa_init_ports和uart_add_one_port

serial8250_isa_init_ports主要的工作是初始化uart_8250_port:開(kāi)啟定時(shí)器和初始化uart_port.

uart_add_one_port顧名思議,就是為uart_driver增加一個(gè)端口,在uart_driver里的state指向NR個(gè)slot, 然后,這個(gè)函數的主要工作就是為slot增加一個(gè)port.這樣,uart_driver就可以通過(guò)port對ops操作函數集進(jìn)行最底層的操作。

現在來(lái)分析下連接部分,也就是tty_driver如何工作,如何連接tty核心層(或者ldisc層)和串口層uart_port.關(guān)于操作部分主要是uart_ops.

uart_open:

staticint uart_open(struct tty_struct *tty, struct file *filp)

{

………

retval= uart_startup(tty, state, 0);

……

}

staticint uart_startup(struct tty_struct *tty, struct uart_state *state,int init_hw)

{

……

retval= uport->ops->startup(uport);

………

調用了uart_port的操作函數ops的startup,在這個(gè)函數里作了一些串口初始化的工作,其中有申請接收數據中斷或建立超時(shí)輪詢(xún)處理。

在startup里面申請了接收數據中斷,那么這個(gè)中斷服務(wù)程序就跟讀操作密切相關(guān)了,從tty核心層的讀操作可知,接收到的數據一定是傳送到read_buf中的?,F在來(lái)看是中斷服務(wù)程序。

調用receive_chars來(lái)接收數據,在receive_chars中,出現了兩個(gè)傳輸數據的函數:

tty_insert_flip_char和tty_flip_buffer_push.

static inline int tty_insert_flip_char(struct tty_struct *tty,

unsigned char ch, char flag)

{

struct tty_buffer *tb = tty->buf.tail;

if(tb tb->used tb->size) {

tb->flag_buf_ptr[tb->used]= flag;

tb->char_buf_ptr[tb->used++]= ch;

return1;

}

return tty_insert_flip_string_flags(tty, ch, flag, 1);

}

當當前的tty_buffer空間不夠時(shí)調用tty_insert_flip_string_flags,在這個(gè)函數里會(huì )去查找下一個(gè)tty_buffer,并將數據放到下一個(gè)tty_buffer的char_buf_ptr里。

那么char_buf_ptr的數據怎樣與線(xiàn)路規程中的read_buf關(guān)聯(lián)的呢,我們看,在初始化tty_buffer的時(shí)候,也就是在tty_buffer_init函數中:

void tty_buffer_init(struct tty_struct *tty)

{

spin_lock_init(tty->buf.lock);

tty->buf.head= NULL;

tty->buf.tail= NULL;

tty->buf.free= NULL;

tty->buf.memory_used= 0;

INIT_DELAYED_WORK(tty->buf.work,flush_to_ldisc);

}

在函數的最后,初始化了一個(gè)工作隊列。

而這個(gè)隊列在什么時(shí)候調度呢,在驅動(dòng)層里receive_chars的最后調用了tty_flip_buffer_push這個(gè)函數。

void tty_flip_buffer_push(struct tty_struct *tty)

{

unsigned long flags;spin_lock_irqsave(tty->buf.lock, flags);if (tty->buf.tail != NULL)

tty->buf.tail->commit = tty->buf.tail->used;spin_unlock_irqrestore(tty->buf.lock, flags);

if (tty->low_latency)

flush_to_ldisc(tty->buf.work.work);else schedule_delayed_work(tty->buf.work, 1);

}

那么,在push數據到tty_buffer的時(shí)候有兩種方式,一種是flush_to_ldisc,另一種就是調度tty緩沖區的工作隊列。

flush_to_ldisc是隊列調用的函數:

static void flush_to_ldisc(struct work_struct *work)



關(guān)鍵詞:

評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>