quot;《 Serial Drivers 》by Alessandro Rubiniquot; 学习笔记
Introduction to "serial device driver" ? ? (My study note)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?膜拜大神的作品.?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Standing on the shoulder of the gaints.
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ——題記
用什么眼光去看待串口設(shè)備
?
?? ? ? ? ? ?當談到軟件對于串口的抽象實現(xiàn)的時候,人們第一反應(yīng)可能是設(shè)備/dev/ttyS0,這個眾所周知的串行設(shè)備通信的接口文件(至少在PC端是這種). 因為/dev/ttyS0?是一個char類型的文件,于是一個串口設(shè)備通常被覺得是一個char driver 驅(qū)動著. 非常傻非常天真。不是這樣滴~
? ? ? ? ? ? ? 其實“char driver”的抽象并不能全然正確的對設(shè)備進行抽象描寫敘述, ? ?
because there is not specific major number associated to each of them. (這句話不是非常懂~)
? ? ? ? ? ? ? ? 你能夠?qū)懶碌膁river。不要嘗試為串口設(shè)備加入新的major number (主設(shè)備號)
??
? ? ? ? ? ? ?當我們查看串口設(shè)備ttyS* ? ( ' * ' ?通配符) ,我們會發(fā)現(xiàn)。這廝的major number都是4 有木有!
問題來了----什么讓串口設(shè)備驅(qū)動和普通的字符設(shè)備驅(qū)動不同捏?
?
? ? ? ? ? ?Since a serial communication channel can be used to plug an alphanumeric terminal, a serial device driver must be integrated in the terminal emulator layer, called the ``tty'' abstraction, from the name of ancient tele-type devices (still in wide use when Unix was being written)
俯瞰 tty 設(shè)備管理
? ? ? ? ? ? ? 靈活有力的 tty handling 由幾個模塊組成。畢竟tty設(shè)備太多了,并且都非常重要。
?
上圖給出了tty core 和 tty driver之間的關(guān)系
?
?大多數(shù)文件都是放置在 drivers/char 以下。假設(shè)不是。這里的文件夾就放在相關(guān)的根文件夾下咯? ?
下圖給出了和串行設(shè)備管理的相關(guān)文件拓撲圖
?? ? ? ? ? ? ?文件?fs/devices.c 導出接口用于大多數(shù)系統(tǒng)資源的注冊,每一個device driver 由 major number 唯一確定。
??
這就是 為何當我們須要支持新的tty driver的時候, ?tty_register_driver() 函數(shù)須要獲得major number?number. 這個函數(shù)在tty_io.c 里面定義。而且該文件還定義了和tty 設(shè)備相關(guān)的文件操作.
? ? ? ? ? ? ? ?設(shè)備相關(guān)driver 來實現(xiàn)對于設(shè)備操作的支持。這些操作就涉及數(shù)據(jù)的輸入輸出。數(shù)據(jù)流的控制以及和更上一層的交互. 這些文件操作和中斷一起。實際操控著數(shù)據(jù)的IO.
?
? ? ? ? ? ? ? ?數(shù)據(jù)在用戶空間和串口設(shè)備驅(qū)動之間隔著一個tty 層(tty line discipline),用于實現(xiàn)數(shù)據(jù)的轉(zhuǎn)換. 這點在LDD3里就有講~
并非全部的tty 管理操作都在 tty_io.c 里面定義,大多數(shù)策略(policy) 是在 ??line discipline定義的。這是一個軟件模塊,控制物理的tty I/O 怎樣使用.
? ? ? ? ? ? ? ?默認的 ?line discipline for 叫?N_TTY. ?假設(shè)?n_tty?處于active 狀態(tài),輸入數(shù)據(jù)通過通常的/dev/ 接口和標準的terminal I/O 函數(shù)來達到 用戶空間.
?
圖中的紅線顯示出對數(shù)據(jù)流動的邏輯控制,從硬件通道上至用戶空間能夠涉及的設(shè)備相關(guān)文件(/dev/文件夾下的文件)
而鏈接這一切的是 stryct tty ,在這個結(jié)構(gòu)體里面包括了一個指針,這個指針指向全部相關(guān)的模塊:?
- file_operations(用于和用戶空間通信交互)
- struct tty_driver則實際掌控著控制硬件操作的部分,
- ?struct?tty_ldisc?則列出全部當前 line discipline 的入口指針
為啥這么麻煩?
? ? ? ? ? ? ? ?這類組織管理方式看似麻煩復雜,然而這樣的額外付出的復雜性能夠獲得更加好的靈活性。使得模塊更加強大。
? ? ? ? ? ? 便于對于不同的tty設(shè)備更改 line discipline.
? ? ? ? ? ? 普通的設(shè)備驅(qū)動就是在硬件和用戶空間之間的通信橋梁。和普通的設(shè)備驅(qū)動不同, a serial driver 和用戶空間沒啥關(guān)系。a serial driver ?接受到來自硬件的設(shè)備都不是直接傳給用戶空間的。它傳給 ?line discipline, 而且 也差點兒不直接接受用戶空間數(shù)據(jù),它的數(shù)據(jù)來源于 一個 line discipline method.
一個單獨的serial driver不是用戶空間和硬件之間的數(shù)據(jù)轉(zhuǎn)換者.?
? ? ? ? ? ? The task is left to the line discipline, together with all the hairy?termios?handling. This makes it possible for serial data to be steered to a different user-space access facility than its associated?ttyS?device special file.
一些相關(guān)的數(shù)據(jù)結(jié)構(gòu)
這里有三種和tty 管理相關(guān)的基本的數(shù)據(jù)結(jié)構(gòu)?
- struct tty_struct?
- struct tty_driver: this is the low level hardware handling. At open time, the function?get_tty_driver?retrieves the driver for the current tty an places it into the?driver?field of?tty_struct, where it is further accessed.
- struct tty_driver {/* the driver states which range of devices it supports */short major; /* major device number */short minor_start; /* start of minor device number*/short num; /* number of devices *//* and has its own operations */int (*open)();void (*close)();int (*write)();int (*ioctl)(); /* device-specific control *//* return information on buffer state */int (*write_room)(); /* how much can be written */int (*chars_in_buffer)(); /* how much is there to read *//* flow control, input and output */void (*throttle)();void (*unthrottle)();void (*stop)();void (*start)();/* and callbacks for /proc/tty/driver/ */int (*read_proc)();int (*write_proc)();};
- struct tty_ldisc: the structure is referenced by the?ldisc?field of?tty_struct. At open time the field is initialized to reference?n_tty, and user programs can change the current line discipline via?ioctl, as explained in a while.
- struct tty_ldisc {/* routines called from above */int (*open)();void (*close)();ssize_t (*read)();ssize_t (*write)();int (*ioctl)();/* routines called from below */void (*receive_buf)();int (*receive_room)();void (*write_wakeup)();};
? ? ? ? ? ? ? ? 這些數(shù)據(jù)結(jié)構(gòu)在三個不同的文件中面定義。 ?tty_struct 這個復雜的大家伙在?include/linux/tty.h?里面,相比另外兩個結(jié)構(gòu)體,事實上這個東東用的少~.
? ? ? ? ? ? ? ? ?include/linux/tty_driver.h?and?include/linux/tty_ldisc.h?定義了另外兩個結(jié)構(gòu)體. ? 不像tty_struct, ??tty_driver 和?tty_ldisc?都是module 作者經(jīng)常使用的東東~
對于數(shù)據(jù)流的讀寫
?
? ? ? ? ? ?向串口寫數(shù)據(jù)的時候。是非常直接的,中間沒有buffer。可是從串口讀數(shù)據(jù)就麻煩點了,并且這個時候中間是有buffer的。 ?數(shù)據(jù)被儲存在buffer里面,知道用戶空間的程序需求他們的時候,這個buffer里的數(shù)據(jù)就會傳遞到用戶空間.
?
無論什么時候,當用戶程序要從串口讀數(shù)據(jù)的時候,這個時候buffer是空的,那么此時用戶程序陷入休眠,直到buffer被填充。?
? ? ? ? ? ?注意到,write buffer 實際上也是存在的。僅僅是實現(xiàn)的非常直接, ?由于write操作的每一步都由上一級驅(qū)動(注意圖中的箭頭是左邊write操作是單向的。而右邊read操作是雙向的)。
?
? ? ? ? ? ?read buffer 是放在struct tty 里面的。因為是動態(tài)分配的。所以不存在內(nèi)存的浪費. ??
? ? ? ? ? ? ? 實際上,tty相關(guān)的buffer被分做兩級管理: kernel developers chose to provide both a ``conventional'' buffer, where data is waiting to be eaten by the line discipline (i.e., in the default case, being transferred to user space), and a ``flip'' buffer, used by hardware routines to store incoming data as quickly as possible, without the need to synchronize for concurrent access: flip buffers are exclusive ownership of the hardware device, which eventually calls?tty_flip_buffer_push?to deliver data to the tty buffer, where the line discipline pulls it from.
It's interesting to note that the flip buffer is laid out as two physical buffers that are alternatively written to. This allows more reliable operation, as the interrupt handler will always have a whole buffer available for writing. The function?flush_to_ldisc, called by the low-level driver and part of the tty layer (i.e.,?tty_io.c), arranges for the flip buffer to be flipped, before the interrupt handler returns. This layout, by the way, is why the flip buffer is called so.
register_serial ?扮演的角色
假設(shè)你注意到 drivers/char/serial.c? 導出了一個叫?register_serial 的函數(shù),你會琢磨這家伙在 tty 構(gòu)架中扮演什么角色呢??
?其實,這個功能不過為了更便利easy的在執(zhí)行時去加入標準的串口設(shè)備tty 驅(qū)動。 ?
?
轉(zhuǎn)載于:https://www.cnblogs.com/claireyuancy/p/6752130.html
總結(jié)
以上是生活随笔為你收集整理的quot;《 Serial Drivers 》by Alessandro Rubiniquot; 学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 业务订单号生成算法,每秒50W左右,不同
- 下一篇: CentOS安装Chrome