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中的相关部分。