Chinaunix首页 | 论坛 | 博客
  • 博客访问: 70586
  • 博文数量: 26
  • 博客积分: 2825
  • 博客等级: 少校
  • 技术积分: 302
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-19 13:27
文章分类

全部博文(26)

文章存档

2009年(26)

我的朋友

分类: LINUX

2009-07-01 10:32:06

在探讨以独占方式操作FrameBuffer之前,先简单的回顾下,基本的读写FrameBuffer的步骤:

1 打开framebuffer设备;

2 通过ioctl取得fixed screen information;

3 通过ioctl取得variable screen information;

4 通过mmap映射设备内存到进程空间;

5 写framebuffer;


int open_screen(void)
{
    char vtname[128];
    int fd, nr;
    unsigned y, addr;
    struct fb_fix_screeninfo fix;
    sb = (screen_buffer*)malloc(sizeof (screen_buffer));
    if ((sb->dev_fd = open(FB_DEV_PATH, O_RDWR)) == -1) {
    perror("open");
    return -1;
    }

    int ret = ioctl(sb->dev_fd, FBIOGET_VSCREENINFO, &fb_vinfo);

    if (ret) {
    sb->width = FB_WIDTH;
    sb->height = FB_HEIGHT;
    sb->bytes_per_pixel = FB_BYTES_PER_PIXEL;
    fprintf(stderr,"in %s line %d",__FUNCTION__,__LINE__);
    } else {
    sb->width = fb_vinfo.xres;
    sb->height = fb_vinfo.yres;
    sb->bytes_per_pixel = fb_vinfo.bits_per_pixel / 8;
    }
    if(sb->bytes_per_pixel == 3)
    sb->bytes_per_pixel = 4;

    if (ioctl(sb->dev_fd, FBIOGET_FSCREENINFO, &fix) < 0) {
    close(sb->dev_fd);
    return -1;
    }

    fbmemlen = sb->width * sb->height * sb->bytes_per_pixel;

    if ((sb->buffer = (uint8_t *) mmap(NULL, fbmemlen, PROT_READ | PROT_WRITE,MAP_FILE | MAP_SHARED, sb->dev_fd, 0)) == (uint8_t *) -1)
    {
    fprintf (stderr, "rw_sd_inand.c: Can't mmap frame buffer ++\n");
    exit (1);
    }
    memset(sb->buffer, 0, fbmemlen);
    return 0;
}


6 关闭framebuffer设备;


void close_screen(screen_buffer *sb)
{
    if(!sb)
    return;
    // Unmap the framebuffer
    munmap(sb->buffer, fbmemlen);
    // Close framebuffer device
    close(sb->dev_fd);
    free(sb);



     依照上面的步骤,已经打开了framebuffer,你可以在其上画图,写字。屏幕上就及时能显示你往framebuffer里填充的内容。但是在多进程操作framebuffer的环境下,比如在一个拥有窗口管理环境下,操作framebuffer显示了全屏的一幅图片,此时窗口管理器有个进程在不断的更新系统当前时间,这样就存在当前图片显示不完整的情况。此时实际上只需要当前进程显示完整的一幅图片,改图片的显示区域不希望被其他操作framebuffer的进程所干扰。

   如何避免这种情况的发生?方法就是操作tty设备。原理很简单,就是打开一个新的终端tty设备,并把该设备激活,设为图形模式,让改终端独占 framebuffer设备,然后再输出图形,这样,即使有其他进程在操作framebuffer,当前终端的framebuffer就不会被重刷,从而实现了稳定的输 出。
  一般来说linux系统中会存在7个tty设备,tty0则是当前所使用虚拟终端的一个别名,系统所产生的信息会发送到该终端上.
tty1--tty6都称为虚拟终端设备,那么打开哪一个新的tty设备呢?先用ioctl(ConsoleFD, VT_OPENQRY, &vtnumber)查询一下当前打开的虚拟终端数量,一般的发行版都是打开6个,即tty1~tty6,这个可以在/etc/inittab里面 控制。另外,tty0是系统自动打开的,但不用于用户登录,所以查询的结果是一共打开7个,vtnumber=7,这个数字也就是下一次可用的终端号,即 tty7。代码如下:

struct vt_stat vts;
    char vtname[128];
    int fd, nr;
    unsigned y, addr;

    char *consoledevice = "/dev/tty";

    if (strcmp (consoledevice, "none") != 0) {
    sprintf (vtname,"%s%d", consoledevice, 1);
    printf("line %d : vtname is:%s\n",__LINE__,vtname);
    fd = open (vtname, O_WRONLY);
    if (fd < 0) {
     perror("open consoledevice");
     return -1;
    }

    if (ioctl(fd, VT_OPENQRY, &nr) < 0) {
     perror("ioctl VT_OPENQRY");
     return -1;
    }
    close(fd);

    sprintf(vtname, "%s%d", consoledevice, nr);

    printf("line %d : vtname is:%s\n",__LINE__,vtname);
    con_fd = open(vtname, O_RDWR | O_NDELAY);
    if (con_fd < 0) {
     perror("open tty");
     return -1;
    }

    if (ioctl(con_fd, VT_GETSTATE, &vts) == 0)
     last_vt = vts.v_active;

    if (ioctl(con_fd, VT_ACTIVATE, nr) < 0) {
     perror("VT_ACTIVATE");
     close(con_fd);
     return -1;
    }

    if (ioctl(con_fd, VT_WAITACTIVE, nr) < 0) {
     perror("VT_WAITACTIVE");
     close(con_fd);
     return -1;
    }

    if (ioctl(con_fd, KDSETMODE, KD_GRAPHICS) < 0) {
     perror("KDSETMODE");
     close(con_fd);
     return -1;
    }

    }


本文参考了tslib中的代码,参考 http://blog.csdn.net/fyzhao/archive/2008/12/11/3501099.aspx
阅读(1578) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~