You are not logged in.

#1 2021-01-07 22:05:13

kramosik
Member
Registered: 2021-01-07
Posts: 4

[x1 carbon gen 7] laptop screen does not pick up updates from fbdev

There is a very weird issue with the linux fbdev driver on my x1 carbon gen 7. When I write to the framebuffer device using the API in linux/fb.h, the laptop screen can only pick up the first frame. The screen freezes unless you type something onto the screen or use Ctrl-C to exit the program. Strangely, the issue only affects the laptop screen, HDMI output is not affected. When plugged into an external monitor, I can see the screen updating, but only on the monitor.

It affects programs using the /dev/fb0 device such as fbi, fbpdf, and mplayer, etc. (the drm backend of mpv, fbi, fbpdf doesn't seem to be affected), but the following program should demonstrate the problem,

/* compile with 
 *   $ cc fb.c -lm
 */
#include <stdint.h>
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <time.h>
#include <math.h>

enum {
  width = 256, height = 256
};

static float
t(void)
{
  struct timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts);
  return ts.tv_sec + ts.tv_nsec/1000000000.0;
}

/* draw anything that changes with time */
static void
draw(uint32_t *fb, int pitch)
{
  for (int y = 0; y < height; ++y)
  for (int x = 0; x < width;  ++x) {
    uint8_t s = 255*(0.5 + 0.5 * sin(x*x + y*y + 5*t()));
    fb[y*pitch + x] = 0xff<<24 | s<<16 | s<<8 | s;
  }
}

int 
main(void) {
  struct fb_fix_screeninfo finfo;
  struct fb_var_screeninfo vinfo;
  int fd;
  size_t size;
  uint32_t *fb;

  fd = open("/dev/fb0", O_RDWR);
  if (fd < 0)
    return 1;
  if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0)
    return 1;
  if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0)
    return 1;

  /* we will only work with 32 bit color for simplicity */
  assert(vinfo.bits_per_pixel == 32);

  /* set up our framebuffer */
  size = vinfo.yres_virtual * finfo.line_length;
  fb = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
  if (fb == MAP_FAILED)
    return 1;
  fb = (fb + vinfo.xoffset + vinfo.yoffset*finfo.line_length);

  while (1) {
    draw(fb, finfo.line_length/4);
  }

  munmap(fb, size);
  close(fd);
}

Can someone confirm the issue? I have also opened an issue on the linux kernel side.

Last edited by kramosik (2021-01-07 22:07:28)

Offline

Board footer

Powered by FluxBB