1. 簡介和基本設計思路
1.1 簡介
在操作系統的開發過程中,為外圍設備設計驅動程序是一個繁重的任務。隨著Linux、BSD等開放源代碼的操作系統的發展,這些系統已經支持越來越多的外圍設備,那麼是否有一種方法能夠將這些系統中已經存在的驅動程序直接在新的操作系統中使用呢?OS Environment則提供了這樣一種方法。
OS Environment在最初被稱為"device driver framework"即驅動程序框架,它實際上是一個驅動程序的設計規范,通過這個規范,就可以將大量已經存在的被用於實際系統中的驅動程序,以源碼的方式利用到新設計的操作系統,或其它需要驅動程序的應用中。
在驅動程序方面有一些標准如DDI/DKI和UDI等,這些接口和OSKit的OS Environment接口有什麼差別呢?UDI等接口是為了那些從頭寫的驅動程序而設計的,它對於驅動程序有著特殊的要求,比如UDI要求所有驅動程序在非阻塞的中斷模式下工作,從理論上講,通過這個限制UDI驅動程序就可以在進程模型或者中斷模型中運行,但這同時也使得很多已經存在的驅動程序無法在UDI接口中工作。OS Environment的設計目的就是為了要使用已經存在的驅動程序,因此OS Environment使用了折中的方案。
由於已經存在的驅動程序非常的多,很多驅動程序對其運行環境作出了假設,比如假定所有實存是直接映射到系統核心的虛存空間上的。然而新的系統並不一定就提供了這樣的環境,因此,在OS Environment中有兩種驅動,一種是完全兼容的,還有一種是部分兼容的。
1.2 組織
下面我們給出OSKit中OS Environment中驅動程序部分的結構圖,從這個結構圖中,我們可以更清楚的看出OSKit的這一部分是如何組織的。
在上圖中的兩條比較粗的線,就是OS Environment中的兩類接口,上面的是驅動程序界面,下面的是驅動-內核界面或簡稱內核界面。驅動程序界面為操作系統提供使用驅動程序的方法,而內核界面是操作系統為驅動程序提供一些支持,使得驅動程序可以合法的使用硬件資源。也可以說內核使用驅動程序界面而提供內核界面,驅動程序使用內核界面提供驅動程序界面。
通常,由操作系統內核提供,由驅動程序使用的代碼對於不同的目標系統來說是要重新寫的,至少目標系統要提供一些包裝,以使得驅動程序可以正常的工作。
Linux驅動程序和FreeBSD驅動程序是直接以源碼的方式包含進來的,為了讓這些源碼可以正常的工作,OSKit為它們提供了"glue"代碼,實際上是讓這些驅動程序可以通過內核界面和驅動程序界面正常的工作。
2. 驅動-內核界面(device-kernel interface)
驅動程序是要和系統中的硬件打交道的,它們要直接訪問系統中的硬件資源,如DMA、I/O端口,有些還要通過IRQ的驅動才能工作。此外,由於驅動程序的運行也需要內存,因此驅動程序還需要操作系統來為它提供內存。在不同的系統中,管理硬件資源的方法是不同的,管理內存等系統資源的方法也是不同的,為了讓各種驅動程序能夠在OSKit中協調工作,就必須要有一個統一的內核與驅動程序之間的接口,由系統內核去分配管理操作系統中的資源供驅動程序使用。驅動-內核界面就是被定義用來完成這個工作的。
下面,我們按照驅動-內核界面中的不同模塊來闡述OS Environment中系統內核為驅動程序提供的接口。
2.1 驅動程序申請內存的管理
2.1.1 概述
驅動程序在工作時是需要申請一些系統中的內存供它們自己使用的,比如將這些內存作為緩沖區等等。在OS Environment中有一組函數用來完成為驅動程序分配內存的工作。
為驅動程序分配內存是一項復雜的工作,隨著設備總線接口的不同和設備使用資源的不同,驅動程序需要使用的內存也是不同的。比如,如果一塊內存是用於DMA傳輸的,那麼這塊內存在物理地址上就必須是連續的,有一些設備還要求這部分內存是必須在低16M中的。為了區分驅動程序申請內存的目的的不同,OS Environment為這些函數指定了一組標志,用來指出申請的內存的要求或者內存應當如何被分配。
在OS Environment中,這些函數的缺省實現是在libdev庫中的,實際上,由於這組函數對於目標系統進行了很多不現實的假設,因此,在多數的目標系統中,都需要重新實現這組函數以取代OSKit所提供缺省函數。上面提到的假設包括以下這些:
通過使用malloc_lmm來分配內存
內存的申請和釋放永遠都不會被阻塞住
所有的內存分配函數在中斷時可以被調用
所申請的內存如果它們在邏輯上是相鄰的,則它們在物理上也是
虛存地址和實存地址空間是一樣的
不支持分頁
OS Environment中為什麼要有這些假設呢?了解這一點對於為目標系統重新設計這些函數是非常必要的。
在OSKit中,有一個缺省的內存管理模塊lmm(Linear Memory Management),即線性內存管理。lmm是一種不支持虛存的內存管理方法。Lmm庫是OSKit中核心的內存管理模塊,這個OSKit在缺省的情況下都是通過它來工作的。因此,libdev模塊也是不例外的,如果要替換掉lmm庫,則也必須要對libdev模塊進行相應的修改。通常,如果我們不引入虛存管理,則是沒有必要去替換掉lmm的。
為了簡單,在lmm中,沒有提供申請或釋放內存失敗的處理,因此,也就無法提供一種在申請或釋放內存時進行阻塞的機制。如果希望將這種機制引入,則目標系統必須對lmm和線程庫進行修改或重寫。
在Linux、FreeBSD等系統中都是使用了虛存管理的,然而lmm並不提供虛存的管理,所以當把各種驅動程序引入的時候,自然就存在一個使這些驅動程序在實存環境中能夠工作的問題。而這個問題最簡單的解決方法就是使實存與虛存在地址空間上一致,這樣就不會出現問題。
在DMA傳送的過程中,可能會用到多於一個的內存塊,硬件進行DMA傳送時是不會自動進行虛地址的轉換的,因此,就要求用於一次DMA傳送的實際內存地址必須是相鄰的,否則,DMA傳送將無法正常的工作。
2.1.2 內存分配標志
在OS Environment中,為了正確分配內存,每一個函數都有一個標志參數,其數據類型為osenv_memflags_t。該類型在oskit/dev/dev.h中定義,同時在該文件定義了每一個標志。這些標志有:
OSENV_AUTO_SIZE:使用這個標志告訴內存的管理者必須要記住分配的內存塊的大小,在這種情況下,當釋放相應的內存時傳遞給osenv_memory_free函數的關於內存大小的參數就是無效的。如果沒有使用這個標志,則內存的申請者必須要記住自己申請的內存塊的大小,到釋放內存時就要將這個數值作為參數傳遞給osenv_mem_free函數。
OSENV_NONBLOCKING:這個標志說明分配內存的工作不能被阻塞。在中斷處理程序中申請內存時,必須有這個參數。
OSENV_PHYS_WIRED:必須是非頁式的,對內存的訪問不能無效。
OSENV_PHYS_CONTIG:內存必須連續。
OSENV_VIRT_EQ_PHYS:虛存地址必須與實存地址相同。
OSENV_ISADMA_MEM:指出系統的DMA控制器將會訪問此內存區,實際上就是規定此段內存區必須連續,並且在系統的低16M之中,並且不能超過64K的界限。
OSENV_X861MB_MEM:因為有可能某些驅動程序會需要使用1MB以下的內存區,進行實模式的操作,因此設定此項。
2.1.3 內存分配函數
我們大概介紹一下內存分配函數,這些函數在dev/mem.c中定義:
osenv_mem_alloc:驅動程序用來申請內存的函數。
osenv_mem_free:釋放內存的函數。
osenv_mem_get_phys:返回一塊內存區的實地址。
osenv_mem_get_virt:返回一塊內存區的虛地址。
osenv_mem_phys_max:返回內存地址的最大值。
osenv_mem_map_phys:分配內核虛地址並將調用者的實地址映射到這個虛地址。
2.2 DMA的管理
如果系統希望使用DMA控制器,那麼就必須提供允許訪問DMA控制器的基本函數。目前在OS Environment中,是通過oskit_osenv_isa接口來對DMA進行管理的,在該接口中提供了兩個對DMA進行申請和釋放的工作,它們是isadma_alloc和isadma_free。這個接口中還有一些處理ISA設備注冊、注銷的方法,將在後面介紹。這個接口在dev/osenv_isa.c中定義。
由於Linux的驅動程序是通過宏及內嵌的匯編直接訪問DMA的,因此在OSKit中使用的所有驅動程序集中,只能有一個使用DMA控制器,因為OSKit無法去判斷究竟誰占用了資源。
2.3 I/O端口的管理
在很多的系統中,都有輸入輸出端口的概念,通常的情況下不同的硬件,要使用不同的輸入輸出端口,當然這也有一點例外。
輸入輸出的管理,是通過COM對象完成的,對象的類型是oskit_osenv_ioport。此對象提供了三個用於輸入、輸出的方法,它們是osenv_io_avail、osenv_io_alloc和osenv_io_free,這三個函數分別用於查詢一個端口是否被占用、申請端口及釋放端口。
2.4 硬件中斷
2.4.1 中斷支持概述
設備利用中斷來通知軟件可以對它進行操作,因此管理硬件的一個很重要的任務就是管理中斷資源。在OSKit中提供了一套常用的中斷管理方法,以支持包裝Linux、FreeBSD等系統的驅動程序。此外,OSKit還提供了一個支持實時應用的庫,在裡面提供了另外一種功能更強的處理中斷的方法。
OS Environment支持不同設備之間共享一個中斷,當然,要求這些設備本身支持共享中斷。由於OSKit處理中斷的方法,要求每一個硬件的驅動程序都提供一種檢測是否是該硬件發出的中斷信號,如果是,就進行處理,如果不是則要立即返回以便讓下一個設備的驅動程序繼續處理。
一般情況下,如果不同的驅動程序集都被鏈接到了一個內核文件之中,如果在一個驅動程序集中如果屏蔽了中斷信號,那麼對於所有的驅動程序集來說中斷信號就都被屏蔽了。
2.4.2 OS Environment中處理中斷的方法
為了更好的理解在OS Environment中應當如何去注冊中斷處理程序,這裡我們大概介紹一下OS Environment中處理中斷的方法。
在OS Envrionment中,使用了一個數組來存儲每一個中斷處理函數隊列中第一個元素的指針,當申請一個中斷時,實際上是將一個中斷處理函數加入到相應的隊列中,當釋放一個中斷時,就是將該處理函數的指針從處理隊列中刪除。在OS Environment中,有一個缺省的適用於所有中斷的處理程序,這個程序寫得非常短小,它負責在中斷來時,順序調用該中斷相應的中斷處理函數隊列中的所有的處理函數。
當然還有幾個數組用來進行一些輔助工作,如一個中斷號是否可以被共享等。
2.4.3 OS Environment中與中斷相關的函數
在OS Environment中是通過COM對象來管理中斷及中斷處理函數的。這兩個對象分別是oskit_osenv_intr和oskit_osenv_irq。
COM對象oskit_osenv_intr是在dev/x86/osenv_intr.c中定義的,實際的處理函數是在dev/x86/synth.c中定義的。oskit_osenv_intr中提供的用來操作中斷控制器的方法是:
intr_enable: 開中斷。
intr_disable: 關中斷。
intr_enabled: 返回當前中斷標志。
intr_savedisable:關中斷並返回關中斷之前的中斷標志。
COM對象oskit_osenv_irq是在dev/x86/osenv_irq.c中定義的,實際的處理函數在dev/x86/irq.c、kern/x86/pc/pic.c和dev/x86/pic.c中定義,它提供了以下的用於中斷的方法:
int osenv_irq_alloc ( int irqnum, void (*handler)(void *),
void *data, int flags )
分配中斷。此函數有四個參數,分別是中斷號、處理程序、一個數據和標志。當發生中斷時,CPU要把這裡給出的數據data傳遞給中斷處理程序。這裡的標志flags目前只有OSENV_IRQ_SHAREABLE。
void osenv_irq_free ( int irqnum, void (*handler)(void *),
void *data )
釋放中斷。這裡的三個參數應當與分配中斷時使用的前三個參數相同。
irq_disable: 關閉一個中斷號。
irq_enable: 激活一個中斷號。
irq_pending: 查看一個中斷號。
2.5 睡眠與喚醒
在當前的OS Environment模型中,只允許一個線程或請求進入驅動程序集。當驅動程序在等待一個外部事件發生時,可以睡眠以允許其它的請求運行。
當前睡眠與喚醒的操作由COM對象oskit_osenv_sleep提供,它提供了三個方法,分別是:
osenv_sleep_init: 初始化一個睡眠對象。
osenv_sleep: 讓一個進程進入睡眠。
osenv_wakeup: 喚醒一個睡眠的進程。
2.6 定時器
在OSKit中,通過COM接口oskit_osenv_timer來提供,這個接口為我們提供了以下的方法來操作定時器。
timer_init: 初始化定時器
timer_shutdown: 關閉定時器
timer_spin: 以非阻塞的方式等待一段時間。
timer_register: 注冊一個定時調用的函數。
timer_unregister: 取消注冊。
2.7 ISA設備的注冊
要將設備加入系統使其能夠使用,就要為設備注冊。在OS Environment中通過oskit_osenv_isa接口進行對設備的注冊。在OSKit中,注冊的設備的地址及驅動程序以一個鏈表來表示。首先要將設備的驅動程序加入這個鏈表然後,OS Environment可以統一的對注冊過的設備進行初始化。
oskit_osenv_isa中對設備進行注冊和注銷的方法是:
isa_bus_init:對ISA總線進行初始化。
isa_bus_getbus:得到系統總線數據接口的地址。
isa_bus_addchild:添加一個子設備。
isa_bus_remchild:刪除一個子設備。
2.8 驅動程序的注冊
為了對驅動程序進行注冊,OS Environment中提供了一個COM接口oskit_osenv_driver,這個接口提供了三個方法,分別是:
driver_register:用於注冊一個驅動程序。
driver_unregister:用於注銷一個驅動程序。
driver_lookup:查找驅動程序,這個方法可以用來查找一類驅動程序,如設備ISA設備的驅動。
3. 驅動程序界面(device driver interface)
3.1 塊設備驅動程序界面
OS Environment所提供的塊輸入/輸出對象的接口是和POSIX兼容的。這裡給出的只是最基本的幾個,為了提高性能,對象也可以提供更多的接口。
通過這個接口對塊輸入/輸出對象進行訪問時,要知道改對象所使用的最小的塊的大小,所有的讀寫操作都必須以這個大小的單元進行。
3.1.1 getblocksize
函數原型:
OSKIT_COMDECL_U (*getblocksize)(oskit_blkio_t *io);
用途:
得到這個塊輸入/輸出對象的最小的塊的大小,這個大小必須是2的冪,並且它將用於這個對象存在的整個生命期之中,所有讀、寫操作所使用的緩沖區的大小必須是此對象的整數倍。
3.1.2 read
函數原型:
OSKIT_COMDECl (*read)(oskit_blkio_t *io, void *buf,
oskit_off_t offset, oskit_size_t amount,
oskit_size_t *out_actual);
用途:
從某個絕對的位移處開始讀取指定數量的內容,實際讀取的字節數將被存放於out_actual所指向的地址之中。
3.1.3 write
函數原型:
OSKIT_COMDECl (*write)(oskit_blkio_t *io, const void *buf,
oskit_off_t offset, oskit_size_t amount,
oskit_size_t *out_actual);
用途:
從一個絕對的位移處開始寫一個塊輸入/輸出對象,如果在寫的過程中超出了該對象原有的大小,並且對象的大小無法被擴展的話,則實際寫入的字節數會比要求寫入的少。實際寫入的字節數放在 out_actual所指向的內存單元中。
3.1.4 getsize
函數原型:
OSKIT_COMDECl (*getsize)(oskit_blkio_t *io,
oskit_off_t *out_size);
用途:
得到一個塊設備當前的以字節計的大小。通常情況下塊設備都是固定大小的,但也其大小也可以是可變化的,因此在不同的時候得到的值有可能不同。
3.1.5 setsize
函數原型:
OSKIT_COMDECl (*setsize)(oskit_blkio_t *io,
oskit_off_t new_size);
設定一個塊輸入/輸出對象的大小,如果設定的值比原有的值小,則超出的部分將被丟棄,如果設定的值比原有的大,則不足的部分將以0值填充。如果此對象的大小是不可變的,則失敗。
3.2 TTY設備驅動程序界面
TTY設備的COM接口為oskit_ttydev,它提供下面這些方法,在oskit/dev/tty.h中定義。這個接口可以用來實現傳統的POSIX/Unix TTY式的設備如終端或串口。這是一個比較高級的接口並且繼承了很多UNIX系統中的較為復雜的東西,因此它並不是一個非常理想的接口。這個接口的功能實際上是需要由驅動程序提供,由於我們使用的驅動程序取自FreeBSD、Linux等系統,而這些系統都采用了POSIX/UNIX TTY式的設備接口,因此這些驅動程序可以直接支持oskit_ttydev接口。
oskit_ttydev,從oskit_device_t繼承而來。這個接口僅僅可以訪問TTY設備的一些信息,要真正對TTY設備進行讀寫,就必需要調用open( )方法獲得一個ttystream對象(參考下一節)。對一個oskit_ttydev對象進行open操作,就表示要對這個對象進行讀寫,這通常會使驅動程序為訪問設備而申請更多的內存。實際上,驅動程序沒有職責去做任何的事情,它可以僅僅提供將原本就屬於設備節點的ttystream接口,並將對此接口的引用作為open( )操作的結果返回。
以下詳細敘述接口中每一個方法的用途和用法。
3.2.1 getinfo(oskit_ttydev_getinfo)
函數原型:
OSKIT_COMDECl (*getinfo)(oskit_ttydev_t *fdev,
oskit_devinfo_t *out_info);
用途:通過此函數可以取得TTY設備的描述信息。
參數:
fdev - 這是要取得信息的TTY 設備。
out_info - 將取得的信息放於此參數所指向的oskit_devinfo_t結構中。
3.2.2 getdriver(oskit_ttydev_getdriver)
函數原型:
OSKIT_COMDECl (*getdriver)(oskit_ttydev_t *fdev,
oskit_driver_t **out_driver);
用途:獲得某個設備的驅動程序接口的引用。
參數:
fdev - 要取得驅動的TTY設備。
out_driver - 驅動接口的內存地址。
3.2.3 open(oskit_ttydev_open)
函數原型:
OSKIT_COMDECl (*open)(oskit_ttydev_t *dev, oskit_u32_t flags,
struct oskit_ttystream **out_ttystream);
用途:打開設備並使其工作在標准的"呼叫"方式,如果設備沒有被使用,則open操作通常會迅速結束,否則,將返回OSKIT_EBUSY錯誤。
參數:
dev:要讀取的設備
flags:讀取時使用的標志。
out_ttystream:將返回的ttystream接口的地址放在這個參數所指向地址的指針變量中。
3.2.4 listen(oskit_ttydev_listen)
函數原型:
OSKIT_COMDECl (*listen)(oskit_ttydev_t *dev,
oskit_u32_t flags,
struct oskit_ttystream **out_ttystream);
用途:將此設備以被動的等待方式打開。打開之後,進程將會暫停,直到有一個設備來調用它。如果設備不支持這種被動的callin的方式,則會返回錯誤碼OSKIT_E_NOTIMPL。
參數:
dev:要讀取的設備。
flags:讀取時使用的標記。
out_ttystream:將返回的ttystream接口的地址放在這個參數所指向地址的指針變量中。
3.3 TTY流界面
TTY流的COM接口為oskit_ttystream。這個接口實現了POSIX.1規定的終端流規范。下面詳細敘述接口中的每一個方法。
3.3.1 read(oskit_ttystream_read)
函數原型:
OSKIT_COMDECl (*read)(oskit_ttystream_t *s,
void *buf,
oskit_u32_t len,
oskit_u32_t *out_actual);
說明:
此函數從TTY流中讀入指定的字節,並放入一個緩沖區中。
參數:
s:要操作的ttystream接口。
buf:存放輸入的緩沖區。
len:最多讀入的字節數。
out_actual:將實際讀入的字節數存放到此指針所指向的單元。
3.3.2 write(oskit_ttystream_write)
函數原型:
OSKIT_COMDECl (*write)(oskit_ttystream_t *s,
const void *buf,
oskit_u32_t len,
oskit_u32_t *out_actual);
說明:
向一個TTY流中寫入指定的字節。
參數:
s:要操作的ttystream接口。
buf:存放輸出的緩沖區。
len:希望輸出的字節數。
out_actual:將實際輸出的字節數存入此指針所指向的地址。
3.3.3 seek(oskit_ttystream_seek)
函數原型:
OSKIT_COMDECl (*seek)(oskit_ttystream_t *s,
oskit_s64_t ofs,
oskit_seek_t whence,
oskit_u64_t *out_newpos);
說明:
將流指針定位到一個指定的位置。
參數:
s:要操作的流對象。
ofs:定位所采用的參考位置。
where:定位的目的位置。
out_newpos:將定位的最終位置存入此指針所指向的內存單元。
3.3.4 copyto(oskit_ttystream_copyto)
函數原型:
OSKIT_COMDECl (*copyto)(oskit_ttystream_t *s,
oskit_ttystream_t *dst,
oskit_u64_t size,
oskit_u64_t *out_read,
oskit_u64_t *out_written);
說明:
從一個流中讀出指定的字節並寫入另一個流中。
參數:
s:要操作的源TTY流。
dst:要操作的目的TTY流。
size:要復制的字節數。
out_read:將實際讀出的字節數寫入此指針指向的內存單元。
out_written:將實際輸出的字節數寫入此指針所指向的內存單元。
3.3.5 clone(oskit_ttystream_clone)
函數原型:
OSKIT_COMDECl (*clone)(oskit_ttystream_t *s,
oskit_ttystream_t **out_stream);
說明:
復制一個TTY流。
參數:
s:要被復制的TTY流
out_stream:將新的TTY流的地址寫入此指針所指向的內存單元。
3.3.6 getattr(oskit_ttystream_getattr)
函數原型:
OSKIT_COMDECl (*getattr)(oskit_ttystream_t *s,
struct oskit_termios *out_attr);
說明:
得到一個TTY流的termios屬性。
參數:
s:要操作的TTY流。
out_attr:將此TTY流的屬性放入此指針所指向的內存單元。termios是在POSIX中定義的輸入輸出參數的結構,該結構定義如下。
struct oskit_termios {
oskit_tcflag_t iflag;
oskit_tcflag_t oflag;
oskit_tcflag_t cflag;
oskit_tcflag_t lflag;
oskit_cc_t cc[OSKIT_NCCS];
oskit_speed_t ispeed;
oskit_speed_t ospeed;
};
下面將大概介紹一下termios結構中各個字段的用法。
Iflag:這個字段的值描述基本的中斷輸入控制。他們由該表中所示的屏蔽碼的按位"或"構成,這些屏蔽碼是按位不同的。下表中給出屏蔽碼的符號和簡單的含義:
屏蔽碼符號 屏蔽碼值 含義
OSKIT_IGNBRK 0x00000001 忽略中止信號
OSKIT_BRKINT 0x00000002 中止時的中斷信號
OSKIT_IGNPAR 0x00000004 忽略有奇偶錯的字符
OSKIT_PARMRK 0x00000008 標記奇偶錯
OSKIT_INPCK 0x00000010 啟用輸入奇偶校驗
OSKIT_ISTRIP 0x00000020 剝取字符
OSKIT_INLCR 0x00000040 輸入時將NL映射為CR
OSKIT_IGNCR 0x00000080 忽略CR
OSKIT_ICRNl 0x00000100 輸入時將CR映射為NL
OSKIT_IXON 0x00000200 啟用啟動/暫停輸出控制
OSKIT_IXOFF 0x00000400 啟用啟動/暫停輸入控制
OSKIT_IXANY 0x00000800 中止後任意字符可重新開始
oflag字段的值描述基本的終端輸出控制,它由下表中的屏蔽碼按位"或"構成。
屏蔽碼符號 屏蔽碼值 含義
OSKIT_OPOST 0x00000001 執行輸出控制
OSKIT_ONLCR 0x00000002 將NL映射為CR-NL
cflag字段的值描述基本的中斷硬件控制,它的值由下面給出的屏蔽碼按位"或"構成。
屏蔽碼符號 屏蔽碼值 含義
OSKIT_CSIZE 0x00000300 字節位數掩碼
OSKIT_CS5 0x00000000 5位
OSKIT_CS6 0x00000100 6位
OSKIT_CS7 0x00000200 7位
OSKIT_CS8 0x00000300 8位
OSKIT_CSTOPB 0x00000400 發送兩個停止位,無此碼時發送一個
OSKIT_CREAD 0x00000800 啟用接收器
OSKIT_PARENB 0x00001000 啟用奇偶校驗
OSKIT_PARODD 0x00002000 奇校驗,無此位時是偶校驗
OSKIT_HUPCl 0x00004000 最後一次關閉時掛斷
OSKIT_CLOCAl 0x00008000 忽略調制解調器的狀態線
lflag字段的值描述對局部方式的控制,它由一下的屏蔽碼按位"或"構成。
屏蔽碼符號 屏蔽碼值 含義
OSKIT_ECHOE 0x00000002 回顯刪除字符(erase char)
OSKIT_ECHOK 0x00000004 回顯KILL
OSKIT_ECHO 0x00000008 啟用回顯
OSKIT_ECHONl 0x00000010 回顯"\n"
OSKIT_ISIG 0x00000080 啟用信號
OSKIT_ICANON 0x00000100 加工方式輸入
OSKIT_IEXTEN 0x00000400 啟用擴展的功能(DISCARD和LNEXT)
OSKIT_TOSTOP 0x00400000 停止後台作業的輸出
OSKIT_NOFLSH 0x80000000 中斷、退出或中止後不清除
3.3.7 setattr(oskit_ttystream_setattr)
函數原型:
OSKIT_COMDECl (*setattr)(oskit_ttystream_t *s,
int actions,
const struct oskit_termios *attr);
說明:
設定一個TTY流的termios屬性。
參數:
s;要操作的TTY流。
actions:要進行的操作,可以是以下值:OSKIT_TCSANOW,使改變立即生效;OSKIT_TCSADRAIN,全部輸出後使改變生效;OSKIT_TCSAFLUSH,將輸出、輸出全部完成後使改變生效。
attr:一個termios結構,此結構中存放希望為此TTY流設定的屬性,關於termios結構可以參考getattr方法的說明。
3.3.8 sendbreak(oskit_ttystream_sendbreak)
函數原型:
OSKIT_COMDECl (*sendbreak)(oskit_ttystream_t *f,
oskit_u32_t duration);
說明:
在一段規定的時間內連續輸出0值位。
參數:
f:要進行操作的TTY流。
Duration:輸出0值位的時間,如果是0,則0值位的傳輸時間至少持續0.25秒,但不超過0.5秒。
3.3.9 drain(oskit_ttystream_drain)
函數原型:
OSKIT_COMDECl (*drain)(oskit_ttystream_t *s);
說明:
此函數將等待,直到所有寫到TTY流s上的輸出都已經完成為止。
參數:
s:要進行操作的TTY流。
3.3.10 flush(oskit_ttystream_flush)
函數原型:
OSKIT_COMDECl (*flush)(oskit_ttystream_t *s,
int queue_selector);
說明:
將一個TTY流中的緩沖區中的數據清空,即將已經接受但尚未讀入的數據讀入或者是將已經輸出但尚未發送的數據發送,或者兩者都有。
參數:
s:要操作的TTY流。
queue_selector:用來指定是對輸入還是對輸出進行操作。可以是OSKIT_TCIFLUSH,對輸入進行操作;OSKIT_TCOFLUSH對輸出進行操作;或者OSKIT_TCIOFLUSH,對輸入和輸出都進行操作。
3.3.11 flow(oskit_ttystream_flow)
函數原型:
OSKIT_COMDECl (*flow)(oskit_ttystream_t *s, int action);
說明:
這個函數使在TTY流s上的輸出暫停或開始。
參數:
s:要操作的TTY流。
action: 要進行的操作。可以是OSKIT_TCOOFF,暫停輸出;OSKIT_TCOON,重新開始輸出;OSKIT_TCIOFF,發送一個停止字符;OSKIT_TCION,發送一個開始字符。
3.3.12 ttyname(oskit_ttystream_ttyname)
函數原型:
OSKIT_COMDECl (*ttyname)(oskit_ttystream_t *s,
char **out_name);
說明:得到TTY終端的名稱。
參數:
s:要操作的TTY流對象。
out_name:將名稱字符串的地址放在這個內存單元中。
關於以上講述的OSKit的TTY流的接口的更多信息,可以參考POSIX中的相關部分。