第 1 部分针对 Oracle Solaris 平台设计设备驱动程序
9. 直接内存访问 (Direct Memory Access, DMA)
14. 分层驱动程序接口 (Layered Driver Interface, LDI)
B. Oracle Solaris DDI/DKI 服务汇总
除了视频模式更改回调外,驱动程序与内核终端仿真器之间的所有活动都由 tem(terminal emulator module,终端仿真器模块)启动。这意味着,tem 将发出本文档中介绍的所有 ioctl 命令。以下各节提供了有关每个 ioctl 命令的实现详细信息。有关更多信息,请参见 visual_io(7I) 手册页和 /usr/include/sys/visual_io.h 头文件。有关视频模式更改回调函数的详细信息,请参见视频模式更改回调接口。
注 - 每个 ioctl 命令都应确定是否已在 ioctl 标志参数中设置 FKIOCTL,如果未设置该位,则返回 EPERM。
VIS_DEVINIT ioctl 命令将帧缓存器驱动程序初始化为系统控制台设备。该 ioctl 将传递 vis_devinit 结构的地址。
tem 首先将其视频模式更改回调函数的地址装入 vis_devinit 结构的 modechg_cb 字段,再将其软状态装入 modechg_arg 字段。然后,tem 发出 VIS_DEVINIT ioctl 命令。接下来,帧缓存器驱动程序初始化自身,并通过设置 vis_devinit 结构中的 version 、width、height、linebytes、depth、mode 和 polledio 字段将自身的配置摘要返回到 tem。以下代码中显示了 vis_devinit 结构。
struct vis_devinit { /* * This set of fields are used as parameters passed from the * layered frame buffer driver to the terminal emulator. */ int version; /* Console IO interface rev */ screen_size_t width; /* Width of the device */ screen_size_t height; /* Height of the device */ screen_size_t linebytes; /* Bytes per scan line */ int depth; /* Device depth */ short mode; /* Display mode Mode */ struct vis_polledio *polledio; /* Polled output routines */ /* * The following fields are used as parameters passed from the * terminal emulator to the underlying frame buffer driver. */ vis_modechg_cb_t modechg_cb; /* Video mode change callback */ struct vis_modechg_arg *modechg_arg; /* Mode change cb arg */ };
要在控制台帧缓存器驱动程序中实现 VIS_DEVINIT ioctl 命令,请按照以下通用步骤操作:
定义一个 struct 以包含特定于控制台的状态。该结构由控制台帧缓存器驱动程序专用。在本附录中,该结构称为 consinfo。consinfo 结构包含诸如以下的信息:
位块传输 (blit) 缓冲区的当前大小
指向位块传输 (blit) 缓冲区的指针
色彩表信息
呈现模式信息(如行间距)的驱动程序
背景色
视频内存地址
终端仿真器回调地址
分配内存:
分配足够大的位块传输 (blit) 缓冲区,以便以最高的视频深度存储像素的合理的、缺省大小的矩形区。如果传入的请求超出缓冲区的大小,可以分配额外的内存。帧缓存器驱动程序的最大字体大小为 12×22。假设 DEFAULT_HEIGHT 为 12,DEFAULT_WIDTH 为 22,最大视频深度为 32,那么,缓冲区大小应为 8448 个字节 (DEFAULT_HEIGHT × DEFAULT_WIDTH × 32)。
分配 vis_polledio 结构。
分配缓冲区以用于保持光标。该缓冲区的大小应相当于最大字符的大小。该缓冲区的大小将不会发生变化。
从 modechg_cb 和 modechg_ctx 获取 tem 的视频更改回调地址和回调上下文,并将这些信息存储在 consinfo 结构中。
使用轮询式显示、副本和光标函数的入口点地址填充 vis_polledio 结构。
在 tem 传递给驱动程序的 vis_devinit 结构的字段中提供相应信息:
将 version 字段设置为 VIS_CONS_REV,这是 /usr/include/sys/visual_io.h 头文件中定义的一个常量。
将 mode 字段设置为 VIS_PIXEL。
将 polledio 字段设置为 vis_polledio 结构的地址。
将 height 字段设置为视频模式高度(以像素为单位)。
将 width 字段设置为视频模式宽度(以像素为单位)。
将 depth 字段设置为帧缓存器像素深度,单位为字节(例如,32 位像素深度将为 4 个字节)。
将 linebytes 字段设置为 height × width × depth 的值。
将会使用 vis_devinit 结构将这些信息从驱动程序发送到 tem。通过这些信息,终端仿真器可知道如何呈现信息以及如何将信息传递给图形驱动程序。
只要控制台帧缓存器驱动程序更改了其视频模式(特别是 height、width 或 depth),驱动程序就必须调用 tem 的视频模式更改回调函数来更新 vis_devinit 结构并将其传递回终端仿真器。终端仿真器将其模式更改回调函数地址传入 vis_devinit 结构的 modechg_cb 字段。模式更改回调函数具有以下函数签名:
typedef void (*vis_modechg_cb_t) (struct vis_modechg_arg *, struct vis_devinit *);
如前面的 typedef 中所述,模式更改回调函数使用两个参数。第一个参数为 modechg_arg,第二个参数为 vis_devinit 结构。modechg_arg 会在 VIS_DEVINIT ioctl 命令初始化期间从 tem 发送到驱动程序。驱动程序必须通过每个视频模式更改回调将 modechg_arg 发送回给 tem。
初始化内核控制台的上下文。具体的要求会随图形设备的功能而异。例如,该初始化的步骤可能包括:设置绘制引擎状态、初始化调色板,或者定位和映射视频内存或呈现引擎,以便数据能够以位块传输到屏幕。
将 vis_devinit 结构返回给调用方。
VIS_DEFINI ioctl 命令可释放驱动程序的控制台资源,并完成会话。
要在控制台帧缓存器驱动程序中实现 VIS_DEVFINI ioctl 命令,请按照以下通用步骤操作:
重置控制台帧缓存器驱动程序状态。
清除轮询式 I/O 入口点和内核终端仿真器视频更改函数回调地址。
释放内存。
VIS_CONSDISPLAY ioctl 命令可在指定的位置显示像素矩形区。这种显示方式又称为以位块传输 (blitting) 矩形。vis_consdisplay 结构包含以驱动程序和 tem 使用的视频深度呈现矩形所必需的信息。以下代码中显示了 vis_consdisplay 结构。
struct vis_consdisplay { screen_pos_t row; /* Row (in pixels) to display data at */ screen_pos_t col; /* Col (in pixels) to display data at */ screen_size_t width; /* Width of data (in pixels) */ screen_size_t height; /* Height of data (in pixels) */ unsigned char *data; /* Address of pixels to display */ unsigned char fg_color; /* Foreground color */ unsigned char bg_color; /* Background color */ };
要在控制台帧缓存器驱动程序中实现 VIS_CONSDISPLAY ioctl 命令,请按照以下通用步骤操作:
复制 vis_consdisplay 结构。
验证显示参数。如果任一显示参数超出范围,则会返回错误。
计算要以位块传输到视频内存的矩形的大小。根据执行 VIS_DEVINIT 期间创建的位块传输 (blit) 缓冲区大小验证此大小。如果需要,为位块传输 (blit) 缓冲区分配额外的内存。
检索位块传输 (blit) 数据。内核终端仿真器已在议定的像素深度准备了此数据。该深度与执行 VIS_DEVINIT 期间 tem 传递的像素深度相同。每当设备驱动程序通过 tem 的回调更改视频模式时,都会更新像素深度。典型的像素深度为 8 位索引色彩表和 32 位真彩 (TrueColor)。
使所有用户上下文无效,以使用户应用程序不能通过用户内存映射同时访问帧缓存器硬件。在轮询式 I/O 模式下,既不允许也没有必要执行此步骤,因为用户应用程序并没有运行。请务必持有锁,以便在完成 VIS_CONSDISPLAY ioctl 之前,用户无法通过缺页恢复映射。
建立特定于驱动程序的控制台呈现上下文。
如果帧缓存器在 8 位索引色彩模式下运行,请恢复 tem 以前通过 VIS_PUTCMAP ioctl 设置的内核控制台色彩表。建议使用延迟 ( lazy) 色彩表装入方案,以优化性能。在延迟 (lazy) 方案中,控制台帧缓存器只恢复自发出 VIS_DEVINIT ioctl 以来实际使用的色彩。
在 tem 发送的像素坐标上显示 tem 传出的数据。您可能需要转换 RGB 像素数据字节顺序。
VIS_CONSCOPY ioctl 命令可将像素矩形区从一个位置复制到另一个位置。该 ioctl 的用途之一就是执行滚动。
要在控制台帧缓存器驱动程序中实现 VIS_CONSCOPY ioctl 命令,请按照下面的通用步骤操作:
复制 vis_conscopy 结构。vis_conscopy 结构描述源和目标矩形大小与位置。
验证显示参数。如果任一显示参数超出范围,则会返回错误。
使所有用户上下文无效,以使用户应用程序不能通过用户内存映射同时访问帧缓存器硬件。在轮询式 I/O 模式下,既不允许也没有必要执行此步骤,因为用户应用程序并没有运行。请务必持有锁,以便在完成 VIS_CONSDISPLAY ioctl 之前,用户无法通过缺页恢复映射。
调用函数以复制矩形。
注 - 为实现最佳性能,请使用图形设备的呈现引擎来实现复制功能。您需要确定如何执行驱动程序内的上下文管理以设置呈现引擎,从而实现最佳性能。
VIS_CONSCURSOR ioctl 命令可显示或隐藏光标。以下代码中显示了 vis_conscursor 结构。
struct vis_conscursor { screen_pos_t row; /* Row to display cursor (in pixels) */ screen_pos_t col; /* Col to display cursor (in pixels) */ screen_size_t width; /* Width of cursor (in pixels) */ screen_size_t height; /* Height of cursor (in pixels) */ color_t fg_color; /* Foreground color */ color_t bg_color; /* Background color */ short action; /* Show or Hide cursor */ };
要在控制台帧缓存器驱动程序中实现 VIS_CONSCOPY ioctl 命令,请按照下面的通用步骤操作:
从内核终端仿真器复制 vis_conscursor 结构。
验证显示参数。如果任一显示参数超出范围,则会返回错误。
使所有用户上下文无效,以使用户应用程序不能通过用户内存映射同时访问帧缓存器硬件。在轮询式 I/O 模式下,既不允许也没有必要执行此步骤,因为用户应用程序并没有运行。请务必持有锁,以便在完成 VIS_CONSDISPLAY ioctl 之前,用户无法通过缺页恢复映射。
终端仿真器可通过以下两个操作之一调用 VIS_CONSCOPY ioctl:SHOW_CURSOR 和 HIDE_CURSOR。以下步骤介绍如何通过读取和写入视频内存实现此功能。您可能也可使用呈现引擎来完成此工作。是否能够使用呈现引擎取决于帧缓存器硬件。
执行以下步骤可实现 SHOW_CURSOR 功能:
将像素保存到要在其中绘制光标的矩形内。隐藏光标时将需要使用这些保存的像素。
扫描要在其中绘制光标的矩形界定的屏幕上的所有像素。在此矩形中,将与指定光标前景色 (fg_color) 匹配的像素替换为白色像素。将与指定光标背景色 (bg_color) 匹配的像素替换为黑色像素。视觉效果为黑色光标悬停在白色文本上。此方法适用于文本的任何前景色和背景色。尝试根据色彩表位置进行反色是不切实际的。也没有必要使用更复杂的策略,例如使用 HSB(Hue, Saturation, Brightness,色调、饱和度和亮度)色彩模式进行反色。
要实现 HIDE_CURSOR 功能,请将光标矩形下方的像素替换为通过前面的 SHOW_CURSOR 操作保存的像素。
VIS_PUTCMAP ioctl 命令可建立控制台色彩表。终端仿真器调用此函数以设置内核的色彩表。以下代码中显示了 vis_cmap 结构。该结构只适用于 8 位索引色彩模式。
struct vis_cmap { int index; /* Index into colormap to start updating */ int count; /* Number of entries to update */ unsigned char *red; /* List of red values */ unsigned char *green; /* List of green values */ unsigned char *blue; /* List of blue values */ };
VIS_PUTCMAP ioctl 命令与 FBIOPUTCMAP 命令类似。VIS_PUTCMAP 命令特定于与帧缓存器终端仿真器兼容的控制台代码。
终端仿真器可调用 VIS_GETCMAP ioctl 命令来检索控制台色彩表。