aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2019-02-04 12:00:07 +0100
committerGerd Hoffmann <kraxel@redhat.com>2019-02-04 12:00:07 +0100
commitf33f5609a374ce8c80beecccc85fe49cae60e1ce (patch)
treee56aea1d2a04047d40b103933c9a6a2c7cac99ff
parent91856e84f0474fe64f95c5f3acc6981469e7ce46 (diff)
downloaddrminfo-f33f5609a374ce8c80beecccc85fe49cae60e1ce.tar.gz
add fbtest
-rw-r--r--drminfo.spec1
-rw-r--r--drmtest.c2
-rw-r--r--fbtest.c107
-rw-r--r--fbtools.c234
-rw-r--r--fbtools.h10
-rw-r--r--meson.build10
6 files changed, 363 insertions, 1 deletions
diff --git a/drminfo.spec b/drminfo.spec
index e3b84e3..ecef075 100644
--- a/drminfo.spec
+++ b/drminfo.spec
@@ -38,4 +38,5 @@ ninja-build -C build-rpm install
%{_bindir}/drm*
%{_bindir}/prime
%{_bindir}/virtiotest
+%{_bindir}/fbtest
%{_mandir}/man1/drm*.1*
diff --git a/drmtest.c b/drmtest.c
index b4ed929..18176b8 100644
--- a/drmtest.c
+++ b/drmtest.c
@@ -172,7 +172,7 @@ int main(int argc, char **argv)
int c,i;
for (;;) {
- c = getopt(argc, argv, "hgdc:s:o:i:f:m:");
+ c = getopt(argc, argv, "hc:s:o:i:f:m:");
if (c == -1)
break;
switch (c) {
diff --git a/fbtest.c b/fbtest.c
new file mode 100644
index 0000000..41afcd5
--- /dev/null
+++ b/fbtest.c
@@ -0,0 +1,107 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <cairo.h>
+#include <pixman.h>
+
+#include "fbtools.h"
+#include "ttytools.h"
+#include "render.h"
+#include "image.h"
+
+/* ------------------------------------------------------------------ */
+
+/* cairo */
+static cairo_surface_t *cs;
+
+/* user options */
+static cairo_surface_t *image;
+
+/* ------------------------------------------------------------------ */
+
+static void fb_draw(const char *text)
+{
+ char info[80];
+ cairo_t *cr;
+
+ snprintf(info, sizeof(info), "fbtest: %dx%d", fb_var.xres, fb_var.yres);
+ cr = cairo_create(cs);
+ if (image) {
+ render_image(cr, fb_var.xres, fb_var.yres, image);
+ } else {
+ render_test(cr, fb_var.xres, fb_var.yres, info, text);
+ }
+ cairo_destroy(cr);
+}
+
+/* ------------------------------------------------------------------ */
+
+static void usage(FILE *fp)
+{
+ fprintf(fp,
+ "\n"
+ "usage: fbtest [ options ]\n"
+ "\n"
+ "options:\n"
+ " -h print this\n"
+ " -f <nr> pick framebuffer\n"
+ " -s <secs> set sleep time\n"
+ " -i <file> load and display image <file>\n"
+ "\n");
+}
+
+int main(int argc, char **argv)
+{
+ int framebuffer = 0;
+ int secs = 60;
+ char buf[32];
+ int c;
+
+ for (;;) {
+ c = getopt(argc, argv, "hs:i:f:");
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'f':
+ framebuffer = atoi(optarg);
+ break;
+ case 's':
+ secs = atoi(optarg);
+ break;
+ case 'i':
+ image = load_image(optarg);
+ break;
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ fb_init(framebuffer);
+ cs = cairo_image_surface_create_for_data(fb_mem + fb_mem_offset,
+ fb_format,
+ fb_var.xres,
+ fb_var.yres,
+ fb_fix.line_length);
+ fb_draw("*");
+
+ tty_raw();
+ kbd_wait(secs);
+ read(0, buf, sizeof(buf));
+ tty_restore();
+
+ fb_fini();
+ return 0;
+}
diff --git a/fbtools.c b/fbtools.c
new file mode 100644
index 0000000..8fb86f3
--- /dev/null
+++ b/fbtools.c
@@ -0,0 +1,234 @@
+/*
+ * some generic framebuffer device stuff
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/fb.h>
+
+#include <cairo.h>
+
+#include "fbtools.h"
+
+/* -------------------------------------------------------------------- */
+/* internal variables */
+
+struct fb_fix_screeninfo fb_fix;
+struct fb_var_screeninfo fb_var;
+unsigned char *fb_mem;
+int fb_mem_offset = 0;
+cairo_format_t fb_format = CAIRO_FORMAT_INVALID;
+
+static int fb;
+static int kd_mode;
+static bool kd_mode_restore = false;
+
+static struct termios term;
+static struct fb_var_screeninfo fb_ovar;
+static unsigned short ored[256], ogreen[256], oblue[256];
+static struct fb_cmap ocmap = { 0, 256, ored, ogreen, oblue };
+
+static unsigned short p_red[256], p_green[256], p_blue[256];
+static struct fb_cmap p_cmap = { 0, 256, p_red, p_green, p_blue };
+
+/* -------------------------------------------------------------------- */
+/* palette handling */
+
+static unsigned short color_scale(int n, int max)
+{
+ int ret = 65535.0 * (float)n/(max);
+ if (ret > 65535) ret = 65535;
+ if (ret < 0) ret = 0;
+ return ret;
+}
+
+static void fb_linear_palette(int r, int g, int b)
+{
+ int i, size;
+
+ size = 256 >> (8 - r);
+ for (i = 0; i < size; i++)
+ p_red[i] = color_scale(i,size);
+ p_cmap.len = size;
+
+ size = 256 >> (8 - g);
+ for (i = 0; i < size; i++)
+ p_green[i] = color_scale(i,size);
+ if (p_cmap.len < size)
+ p_cmap.len = size;
+
+ size = 256 >> (8 - b);
+ for (i = 0; i < size; i++)
+ p_blue[i] = color_scale(i,size);
+ if (p_cmap.len < size)
+ p_cmap.len = size;
+}
+
+static void fb_set_palette(void)
+{
+ if (fb_fix.visual != FB_VISUAL_DIRECTCOLOR && fb_var.bits_per_pixel != 8)
+ return;
+ if (-1 == ioctl(fb,FBIOPUTCMAP,&p_cmap)) {
+ perror("ioctl FBIOPUTCMAP");
+ exit(1);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* initialisation & cleanup */
+
+static void
+fb_memset (void *addr, int c, size_t len)
+{
+#if 1 /* defined(__powerpc__) */
+ unsigned int i, *p;
+
+ i = (c & 0xff) << 8;
+ i |= i << 16;
+ len >>= 2;
+ for (p = addr; len--; p++)
+ *p = i;
+#else
+ memset(addr, c, len);
+#endif
+}
+
+void fb_fini(void)
+{
+ /* restore console */
+ if (-1 == ioctl(fb, FBIOPUT_VSCREENINFO, &fb_ovar))
+ perror("ioctl FBIOPUT_VSCREENINFO");
+ if (-1 == ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix))
+ perror("ioctl FBIOGET_FSCREENINFO");
+ if (fb_ovar.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fb, FBIOPUTCMAP, &ocmap))
+ perror("ioctl FBIOPUTCMAP");
+ }
+ close(fb);
+
+ if (kd_mode_restore) {
+ if (-1 == ioctl(STDIN_FILENO, KDSETMODE, kd_mode))
+ perror("ioctl KDSETMODE");
+ }
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+}
+
+/* -------------------------------------------------------------------- */
+
+void fb_init(int cardno)
+{
+ unsigned long page_mask;
+ char device[64];
+
+ snprintf(device, sizeof(device), "/dev/fb%d", cardno);
+ fprintf(stderr, "trying fbdev: %s ...\n", device);
+
+ if (-1 == ioctl(STDIN_FILENO, KDGETMODE, &kd_mode)) {
+ perror("ioctl KDGETMODE");
+ } else {
+ kd_mode_restore = true;
+ }
+
+ /* get current settings (which we have to restore) */
+ if (-1 == (fb = open(device,O_RDWR | O_CLOEXEC))) {
+ fprintf(stderr,"open %s: %s\n",device,strerror(errno));
+ exit(1);
+ }
+ if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_ovar)) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ exit(1);
+ }
+ if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) {
+ perror("ioctl FBIOGET_FSCREENINFO");
+ exit(1);
+ }
+ if (-1 == ioctl(fb,FBIOGET_VSCREENINFO,&fb_var)) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ exit(1);
+ }
+ if (fb_ovar.bits_per_pixel == 8 ||
+ fb_fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ if (-1 == ioctl(fb,FBIOGETCMAP,&ocmap)) {
+ perror("ioctl FBIOGETCMAP");
+ exit(1);
+ }
+ }
+ tcgetattr(STDIN_FILENO, &term);
+
+ /* checks & initialisation */
+ if (kd_mode_restore) {
+ if (-1 == ioctl(STDIN_FILENO, KDSETMODE, KD_GRAPHICS))
+ perror("ioctl KDSETMODE");
+ }
+ if (-1 == ioctl(fb,FBIOGET_FSCREENINFO,&fb_fix)) {
+ perror("ioctl FBIOGET_FSCREENINFO");
+ exit(1);
+ }
+ if (fb_fix.type != FB_TYPE_PACKED_PIXELS) {
+ fprintf(stderr,"can handle only packed pixel frame buffers\n");
+ goto err;
+ }
+ page_mask = getpagesize()-1;
+ fb_mem_offset = (unsigned long)(fb_fix.smem_start) & page_mask;
+ fb_mem = mmap(NULL,fb_fix.smem_len+fb_mem_offset,
+ PROT_READ|PROT_WRITE,MAP_SHARED,fb,0);
+ if (-1L == (long)fb_mem) {
+ perror("mmap");
+ goto err;
+ }
+ /* move viewport to upper left corner */
+ if (fb_var.xoffset != 0 || fb_var.yoffset != 0) {
+ fb_var.xoffset = 0;
+ fb_var.yoffset = 0;
+ if (-1 == ioctl(fb,FBIOPAN_DISPLAY,&fb_var)) {
+ perror("ioctl FBIOPAN_DISPLAY");
+ goto err;
+ }
+ }
+
+ /* cls */
+ fb_memset(fb_mem+fb_mem_offset, 0, fb_fix.line_length * fb_var.yres);
+
+ /* init palette */
+ switch (fb_var.bits_per_pixel) {
+ case 16:
+ fb_format = CAIRO_FORMAT_RGB16_565;
+ fb_linear_palette(5,6,5);
+ break;
+ case 32:
+ fb_format = CAIRO_FORMAT_RGB24;
+ fb_linear_palette(8,8,8);
+ break;
+ default:
+ fprintf(stderr, "unsupported framebuffer format (%d bpp)\n",
+ fb_var.bits_per_pixel);
+ goto err;
+
+ }
+ fb_set_palette();
+ return;
+
+ err:
+ fb_fini();
+ exit(1);
+}
diff --git a/fbtools.h b/fbtools.h
new file mode 100644
index 0000000..1dc6f17
--- /dev/null
+++ b/fbtools.h
@@ -0,0 +1,10 @@
+#include <linux/fb.h>
+
+extern struct fb_fix_screeninfo fb_fix;
+extern struct fb_var_screeninfo fb_var;
+extern unsigned char *fb_mem;
+extern int fb_mem_offset;
+extern cairo_format_t fb_format;
+
+void fb_init(int devnr);
+void fb_fini(void);
diff --git a/meson.build b/meson.build
index 9392108..02ad834 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,9 @@
project('drminfo', 'c', default_options : [ 'c_std=c99' ] )
+# tweak warnings
+add_global_arguments('-D_POSIX_SOURCE=1', language : 'c')
+add_global_arguments('-D_GNU_SOURCE=1', language : 'c')
+
# pkg-config deps
libdrm_dep = dependency('libdrm')
gbm_dep = dependency('gbm')
@@ -13,6 +17,7 @@ jpeg_dep = declare_dependency(link_args : '-ljpeg')
drminfo_srcs = [ 'drminfo.c', 'drmtools.c' ]
drmtest_srcs = [ 'drmtest.c', 'drmtools.c', 'ttytools.c', 'render.c', 'image.c' ]
+fbtest_srcs = [ 'fbtest.c', 'fbtools.c', 'ttytools.c', 'render.c', 'image.c' ]
prime_srcs = [ 'prime.c' ]
viotest_srcs = [ 'virtiotest.c', 'drmtools.c', 'ttytools.c', 'render.c' ]
gtktest_srcs = [ 'gtktest.c', 'render.c', 'image.c' ]
@@ -20,6 +25,7 @@ gtktest_srcs = [ 'gtktest.c', 'render.c', 'image.c' ]
drminfo_deps = [ libdrm_dep, cairo_dep, pixman_dep ]
drmtest_deps = [ libdrm_dep, gbm_dep, epoxy_dep,
cairo_dep, pixman_dep, jpeg_dep ]
+fbtest_deps = [ cairo_dep, pixman_dep, jpeg_dep ]
prime_deps = [ libdrm_dep, gbm_dep ]
viotest_deps = [ libdrm_dep, gbm_dep, epoxy_dep,
cairo_dep, pixman_dep, jpeg_dep ]
@@ -34,6 +40,10 @@ executable('drmtest',
sources : drmtest_srcs,
dependencies : drmtest_deps,
install : true)
+executable('fbtest',
+ sources : fbtest_srcs,
+ dependencies : fbtest_deps,
+ install : true)
executable('prime',
sources : prime_srcs,
dependencies : prime_deps,