(1)帧缓冲设备跟TTY的关系。需要关注tty跟帧缓冲设备的关系,一般情况下帧缓冲设备是可以独立操作的,但是如果为了保证单独占用不被抢占,似乎还要关联一个tty终端。这里用的是虚终端VT。
虚终端,也叫虚屏,它的英文名字为virtual terminal,缩写为VT或vt。在Unix系统用户中,虚终端有着广泛的应用。它解决了主控台单一交互界面的限制,使用户可在保护当前界面的情况下启用另一界面去做另一工作。我们可利用Unix系统提供的系统调用来编制虚终端程序,并可把它加入到我们的应用程序中去。
我们可利用ioctl函数操纵虚终端设备文件,实现与Unix系统内核的交互,得到我们所需要的服务。使用ioctl的具体形式如下:
int ioct1(int filedes,int request,…/*参数*/。request为请求的服务,随后的参数可为各种数据类型,视具体情况而定。
VT_OPENQRY 查找一个可利用的虚终端。
VT_SETMODE 设置虚终端模式(自动或进程控制)。
VT_GETSTATE 获取全部虚终端的状态信息。
VT_ACTIVATE 使在参数中指定的虚终端号为活动虚终端。如果指定的虚终端不处于打开状态或者不存在,调用将失败。
VT_WAITACTIVE 等待虚终端被激活,不需要参数。
有了上面的介绍,现在我们就可以实现虚终端了:
1,查找是否有可利用的虚终端,如没有,则结束。
2,打开可利用虚终端设备文件,以便进行。
3,利用ioctl的TCSETSW功能设置虚终端参数。
4,利用ioctl的VT_ACTIVATE功能激活虚终端,并利用VT_WAITACTIVE功能等待其可用。
5,用putenv函数设置环境变量。
至此,一个虚终端程序就实现了。
(2)open_framebuffer
static int con_fd, fb_fd, last_vt = -1;
static struct fb_fix_screeninfo fix;
static struct fb_var_screeninfo var;
static unsigned char *fbuffer;
static unsigned char **line_addr;
static int fb_fd=0;
static int bytes_per_pixel;
static unsigned colormap [256];
__u32 xres, yres;
#define TSLIB_FBDEVICE "/dev/graphics/fb0"
static char *defaultfbdevice = "/dev/graphics/fb0";
static char *defaultconsoledevice = "/dev/tty";
static char *fbdevice = NULL;
static char *consoledevice = NULL;
int open_framebuffer(void)
{
struct vt_stat vts; char vtname[128]; int fd, nr; unsigned y, addr;
if ((fbdevice = getenv ("TSLIB_FBDEVICE")) == NULL)
fbdevice = defaultfbdevice; //帧设备
if ((consoledevice = getenv ("TSLIB_CONSOLEDEVICE")) == NULL)
consoledevice = defaultconsoledevice; //控制台设备
if (strcmp (consoledevice, "none") != 0)
{
sprintf (vtname,"%s%d", consoledevice, 1); //组合成dev/tty1
fd = open (vtname, O_WRONLY);
if (ioctl(fd, VT_OPENQRY, &nr) < 0) { //查找可用的虚终端
return -1;
}
close(fd);
sprintf(vtname, "%s%d", consoledevice, nr); //获得可以的虚终端名字
con_fd = open(vtname, O_RDWR | O_SYNC);
if (ioctl(con_fd, VT_GETSTATE, &vts) == 0) //获取虚终端设备状态信息
{
last_vt = vts.v_active;
}
if (ioctl(con_fd, VT_ACTIVATE, nr) < 0) //如果激活失败
{
close(con_fd);return -1;
}
if (ioctl(con_fd, VT_WAITACTIVE, nr) < 0) //是否可用
{
close(con_fd);return -1;
}
if (ioctl(con_fd, KDSETMODE, KD_GRAPHICS) < 0) //设置中断工作在图像模式
{
close(con_fd);return -1;
}
}
fb_fd = open(fbdevice, O_RDWR); //在打开帧缓冲设备
ioctl(fb_fd, FBIOGET_FSCREENINFO, &fix);
ioctl(fb_fd, FBIOGET_VSCREENINFO, &var); //获得设备的配置参数
xres = var.xres;
yres = var.yres; //获得屏幕分辨率
fbuffer = mmap(NULL, fix.smem_len, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fb_fd, 0);
memset(fbuffer,0,fix.smem_len);
bytes_per_pixel = (var.bits_per_pixel + 7) / 8;
line_addr = malloc (sizeof (__u32) * var.yres_virtual);
addr = 0;
for (y = 0; y < var.yres_virtual; y++, addr += fix.line_length)
line_addr [y] = fbuffer + addr; //得到后面画点画线的基础地址
}
(3)close_framebuffer
void close_framebuffer(void)
{
munmap(fbuffer, fix.smem_len);
close(fb_fd); //关闭映射和帧缓冲
if(strcmp(consoledevice,"none")!=0)
{
if (ioctl(con_fd, KDSETMODE, KD_TEXT) < 0)
LOGE("KDSETMODE");
if (last_vt >= 0)
if (ioctl(con_fd, VT_ACTIVATE, last_vt))
LOGE("VT_ACTIVATE");
close(con_fd);
}
free (line_addr);
}