linux framebuffer 例子 (2)

把前面一篇的例了加强一下。上一个例子打开了fbdev设备并一次性地向里面写了一屏的数据,把整个屏幕画成红色。但这个时候如果用Alt+Fi切换一下虚拟终端,画出的红色马上消失。这是因为切换终端之后,这个终端也要维护屏幕的输出,重绘的framebuffer。
  DirectFB和PicoGL在使用framebuffer的时候都避免了这种情况的发生,方法就是操作tty设备。原理很简单,就是打开一个新的终端tty设备,把它激活,并设为图形模式,让它独占framebuffer设备,然后再输出图形,这样,即使用户按Alt+Fi也无法切换终端,framebuffer就不会被重刷,从而实现了稳定的输出。
  那么打开哪一个新的tty设备呢?先用ioctl(ConsoleFD, VT_OPENQRY, &vtnumber)查一下当前打开的虚拟终端数量,一般的发行版都是打开6个,即tty1~tty6,这个可以在/etc/inittab里面控制。另外,tty0是系统自动打开的,但不用于用户登录,所以查询的结果是一共打开7个,vtnumber=7,这个数字也就是下一次可用的终端号,即tty7。

代码如下:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <fcntl.h>
  5. #include <linux/fb.h>
  6. #include <linux/vt.h>
  7. #include <linux/kd.h>
  8. #include <sys/mman.h>
  9. #include <asm/ioctls.h>
  10. static int OriginalVT = -1;
  11. struct fb_fix_screeninfo FixedInfo;
  12. struct fb_var_screeninfo OrigVarInfo;
  13. static int FrameBufferFD = -1;
  14. void *FrameBuffer = (void *) -1;
  15. static int ConsoleFD = -1;
  16. #define SIGUSR1 10
  17. void openFBDEV(void) {
  18.     int vtnumber, ttyfd;
  19.     char ttystr[1000];
  20.     /* open the framebuffer device */
  21.     FrameBufferFD = open("/dev/fb0", O_RDWR);
  22.     if (FrameBufferFD < 0) {
  23.         fprintf(stderr, "Error opening /dev/fb0/n");
  24.         exit(1);
  25.     }
  26.     /* Get the fixed screen info */
  27.     if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
  28.         fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed/n");
  29.         exit(1);
  30.     }
  31.     /* get the variable screen info */
  32.     if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
  33.         fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed/n");
  34.         exit(1);
  35.     }
  36.        
  37.     if (FixedInfo.visual != FB_VISUAL_TRUECOLOR && FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
  38.         fprintf(stderr, "non-TRUE/DIRECT-COLOR visuals (0x%x) not supported by this demo./n", FixedInfo.visual);
  39.         exit(1);
  40.     }

  41.     /*
  42.      * fbdev says the frame buffer is at offset zero, and the mmio region
  43.      * is immediately after.
  44.      */
  45.     /* mmap the framebuffer into our address space */
  46.     FrameBuffer = (void *) mmap(0, /* start */
  47.         FixedInfo.smem_len, /* bytes */
  48.         PROT_READ | PROT_WRITE, /* prot */
  49.         MAP_SHARED, /* flags */
  50.         FrameBufferFD, /* fd */
  51.         0 /* offset */);
  52.     if (FrameBuffer == (void *) - 1) {
  53.         fprintf(stderr, "error: unable to mmap framebuffer/n");
  54.         exit(1);
  55.     }
  56.     /* open /dev/tty0 and get the vt number */
  57.     if ((ConsoleFD = open("/dev/tty0", O_WRONLY, 0)) < 0) {
  58.         fprintf(stderr, "error opening /dev/tty0/n");
  59.         exit(1);
  60.     }
  61.     if (ioctl(ConsoleFD, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
  62.         fprintf(stderr, "error: couldn't get a free vt/n");
  63.         exit(1);
  64.     }
  65.     close(ConsoleFD);
  66.     ConsoleFD = -1;
  67.      /* open the console tty */
  68.      sprintf(ttystr, "/dev/tty%d", vtnumber);  /* /dev/tty1-64 */
  69.      ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0);
  70.      if (ConsoleFD < 0) {
  71.              fprintf(stderr, "error couldn't open console fd %d/n", vtnumber);
  72.          exit(1);
  73.      }
  74.      /* save current vt number */
  75.      {
  76.        struct vt_stat vts;
  77.        if (ioctl(ConsoleFD, VT_GETSTATE, &vts) == 0)
  78.              OriginalVT = vts.v_active;
  79.      }
  80.      /* disconnect from controlling tty */
  81.      ttyfd = open("/dev/tty", O_RDWR);
  82.      if (ttyfd >= 0) {
  83.                 ioctl(ttyfd, TIOCNOTTY, 0);
  84.         close(ttyfd);
  85.      }
  86.      /* some magic to restore the vt when we exit */
  87.      {
  88.        struct vt_mode vt;
  89.        if (ioctl(ConsoleFD, VT_ACTIVATE, vtnumber) != 0)
  90.               fprintf(stderr,"ioctl VT_ACTIVATE/n");
  91.        if (ioctl(ConsoleFD, VT_WAITACTIVE, vtnumber) != 0)
  92.               fprintf(stderr,"ioctl VT_WAITACTIVE/n");
  93.        
  94.        if (ioctl(ConsoleFD, VT_GETMODE, &vt) < 0) {
  95.               fprintf(stderr, "error: ioctl VT_GETMODE/n");
  96.           exit(1);
  97.        }
  98.        vt.mode = VT_PROCESS;
  99.        vt.relsig = SIGUSR1;
  100.        vt.acqsig = SIGUSR1;
  101.        if (ioctl(ConsoleFD, VT_SETMODE, &vt) < 0) {
  102.                fprintf(stderr, "error: ioctl(VT_SETMODE) failed/n");
  103.            exit(1);
  104.        }
  105.      }
  106.      /* go into graphics mode */
  107.      if (ioctl(ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) {
  108.              fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed/n");
  109.          exit(1);
  110.      }
  111. }

  112. void closeFBDEV(void) {
  113.         struct vt_mode VT;
  114.     /* restore original variable screen info */
  115.     if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo)) {
  116.             fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed)/n");
  117.         exit(1);
  118.     }
  119.     munmap(FrameBuffer, FixedInfo.smem_len);
  120.     close(FrameBufferFD);
  121.     /* restore text mode */
  122.     ioctl(ConsoleFD, KDSETMODE, KD_TEXT);
  123.     /* set vt */
  124.     if (ioctl(ConsoleFD, VT_GETMODE, &VT) != -1) {
  125.             VT.mode = VT_AUTO;
  126.         ioctl(ConsoleFD, VT_SETMODE, &VT);
  127.     }
  128.     /* restore original vt */
  129.     if (OriginalVT >= 0) {
  130.             ioctl(ConsoleFD, VT_ACTIVATE, OriginalVT);
  131.         OriginalVT = -1;
  132.     }
  133.     close(ConsoleFD);
  134. }

  135. int main() {
  136.     openFBDEV();
  137.     fprintf(stderr, "openFBDEV finish/n");
  138.     memset(FrameBuffer, 128, FixedInfo.smem_len);
  139.     sleep(5);
  140.     closeFBDEV();
  141.     fprintf(stderr, "closeFBDEV finish/n");
  142.     return 0;
  143. }


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值