w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

fb.c (14393B)


      1 /* $Id$ */
      2 /**************************************************************************
      3                 fb.c 0.3 Copyright (C) 2002, hito
      4  **************************************************************************/
      5 
      6 #include <stdio.h>
      7 #include <stdlib.h>
      8 #include <string.h>
      9 #include <unistd.h>
     10 #include <fcntl.h>
     11 #include <limits.h>
     12 #include <errno.h>
     13 #include <sys/ioctl.h>
     14 #include <sys/mman.h>
     15 #include <linux/fb.h>
     16 
     17 #include "fb.h"
     18 
     19 #define FB_ENV		"FRAMEBUFFER"
     20 #define	FB_DEFDEV	"/dev/fb0"
     21 
     22 #define MONO_OFFSET_8BIT  0x40
     23 #define COLORS_MONO_8BIT  0x40
     24 #define MONO_MASK_8BIT    0xFC
     25 #define MONO_SHIFT_8BIT   2
     26 
     27 #define COLOR_OFFSET_8BIT 0x80
     28 #define COLORS_8BIT       0x80
     29 #define RED_MASK_8BIT     0xC0
     30 #define GREEN_MASK_8BIT   0xE0
     31 #define BLUE_MASK_8BIT    0xC0
     32 #define RED_SHIFT_8BIT    1
     33 #define GREEN_SHIFT_8BIT  3
     34 #define BLUE_SHIFT_8BIT   6
     35 
     36 #define FALSE 0
     37 #define TRUE  1
     38 
     39 #define IMAGE_SIZE_MAX 10000
     40 
     41 static struct fb_cmap *fb_cmap_create(struct fb_fix_screeninfo *,
     42 				      struct fb_var_screeninfo *);
     43 static void fb_cmap_destroy(struct fb_cmap *cmap);
     44 static int fb_fscrn_get(int fbfp, struct fb_fix_screeninfo *scinfo);
     45 static void *fb_mmap(int fbfp, struct fb_fix_screeninfo *scinfo);
     46 static int fb_munmap(void *buf, struct fb_fix_screeninfo *scinfo);
     47 static int fb_vscrn_get(int fbfp, struct fb_var_screeninfo *scinfo);
     48 static int fb_cmap_set(int fbfp, struct fb_cmap *cmap);
     49 static int fb_cmap_get(int fbfp, struct fb_cmap *cmap);
     50 static int fb_cmap_init(void);
     51 static int fb_get_cmap_index(int r, int g, int b);
     52 static unsigned long fb_get_packed_color(int r, int g, int b);
     53 
     54 static struct fb_fix_screeninfo fscinfo;
     55 static struct fb_var_screeninfo vscinfo;
     56 static struct fb_cmap *cmap = NULL, *cmap_org = NULL;
     57 static int is_open = FALSE;
     58 static int fbfp = -1;
     59 static size_t pixel_size = 0;
     60 static unsigned char *buf = NULL;
     61 
     62 int
     63 fb_open(void)
     64 {
     65     char *fbdev = { FB_DEFDEV };
     66 
     67     if (is_open == TRUE)
     68 	return 1;
     69 
     70     if (getenv(FB_ENV)) {
     71 	fbdev = getenv(FB_ENV);
     72     }
     73 
     74     if ((fbfp = open(fbdev, O_RDWR)) == -1) {
     75 	fprintf(stderr, "open %s error\n", fbdev);
     76 	goto ERR_END;
     77     }
     78 
     79     if (fb_fscrn_get(fbfp, &fscinfo)) {
     80 	goto ERR_END;
     81     }
     82 
     83     if (fb_vscrn_get(fbfp, &vscinfo)) {
     84 	goto ERR_END;
     85     }
     86 
     87     if ((cmap = fb_cmap_create(&fscinfo, &vscinfo)) == (struct fb_cmap *)-1) {
     88 	goto ERR_END;
     89     }
     90 
     91     if (!(buf = fb_mmap(fbfp, &fscinfo))) {
     92 	fprintf(stderr, "Can't allocate memory.\n");
     93 	goto ERR_END;
     94     }
     95 
     96     if (fscinfo.type != FB_TYPE_PACKED_PIXELS) {
     97 	fprintf(stderr, "This type of framebuffer is not supported.\n");
     98 	goto ERR_END;
     99     }
    100 
    101     if (fscinfo.visual == FB_VISUAL_PSEUDOCOLOR && vscinfo.bits_per_pixel == 8) {
    102 	if (fb_cmap_get(fbfp, cmap)) {
    103 	    fprintf(stderr, "Can't get color map.\n");
    104 	    fb_cmap_destroy(cmap);
    105 	    cmap = NULL;
    106 	    goto ERR_END;
    107 	}
    108 
    109 	if (fb_cmap_init())
    110 	    goto ERR_END;
    111 
    112 	pixel_size = 1;
    113     }
    114     else if ((fscinfo.visual == FB_VISUAL_TRUECOLOR ||
    115 	      fscinfo.visual == FB_VISUAL_DIRECTCOLOR) &&
    116 	     (vscinfo.bits_per_pixel == 15 ||
    117 	      vscinfo.bits_per_pixel == 16 ||
    118 	      vscinfo.bits_per_pixel == 24 || vscinfo.bits_per_pixel == 32)) {
    119 	pixel_size = (vscinfo.bits_per_pixel + 7) / CHAR_BIT;
    120     }
    121     else {
    122 	fprintf(stderr, "This type of framebuffer is not supported.\n");
    123 	goto ERR_END;
    124     }
    125 
    126     is_open = TRUE;
    127     return 0;
    128 
    129   ERR_END:
    130     fb_close();
    131     return 1;
    132 }
    133 
    134 void
    135 fb_close(void)
    136 {
    137     if (is_open != TRUE)
    138 	return;
    139 
    140     if (cmap != NULL) {
    141 	fb_cmap_destroy(cmap);
    142 	cmap = NULL;
    143     }
    144     if (cmap_org != NULL) {
    145 	fb_cmap_set(fbfp, cmap_org);
    146 	fb_cmap_destroy(cmap_org);
    147 	cmap = NULL;
    148     }
    149     if (buf != NULL) {
    150 	fb_munmap(buf, &fscinfo);
    151 	buf = NULL;
    152     }
    153 
    154     if (fbfp >= 0) {
    155 	close(fbfp);
    156     }
    157 
    158     is_open = FALSE;
    159 }
    160 
    161 /***********   fb_image_*  ***********/
    162 
    163 FB_IMAGE *
    164 fb_image_new(int width, int height)
    165 {
    166     FB_IMAGE *image;
    167 
    168     if (is_open != TRUE)
    169 	return NULL;
    170 
    171     if (width > IMAGE_SIZE_MAX || height > IMAGE_SIZE_MAX || width < 1
    172 	|| height < 1)
    173 	return NULL;
    174 
    175     image = malloc(sizeof(*image));
    176     if (image == NULL)
    177 	return NULL;
    178 
    179     image->data = calloc(sizeof(*(image->data)), width * height * pixel_size);
    180     if (image->data == NULL) {
    181 	free(image);
    182 	return NULL;
    183     }
    184 
    185     image->num = 1;
    186     image->id = 0;
    187     image->delay = 0;
    188 
    189     image->width = width;
    190     image->height = height;
    191     image->rowstride = width * pixel_size;
    192     image->len = width * height * pixel_size;
    193 
    194     return image;
    195 }
    196 
    197 void
    198 fb_image_free(FB_IMAGE * image)
    199 {
    200     if (image == NULL)
    201 	return;
    202 
    203     if (image->data != NULL)
    204 	free(image->data);
    205 
    206     free(image);
    207 }
    208 
    209 void
    210 fb_image_pset(FB_IMAGE * image, int x, int y, int r, int g, int b)
    211 {
    212     unsigned long work;
    213 
    214     if (image == NULL || is_open != TRUE || x >= image->width
    215 	|| y >= image->height)
    216 	return;
    217 
    218     work = fb_get_packed_color(r, g, b);
    219     memcpy(image->data + image->rowstride * y + pixel_size * x, &work,
    220 	   pixel_size);
    221 }
    222 
    223 void
    224 fb_image_fill(FB_IMAGE * image, int r, int g, int b)
    225 {
    226     unsigned long work;
    227     int offset;
    228 
    229     if (image == NULL || is_open != TRUE)
    230 	return;
    231 
    232     work = fb_get_packed_color(r, g, b);
    233 
    234     for (offset = 0; offset < image->len; offset += pixel_size) {
    235 	memcpy(image->data + offset, &work, pixel_size);
    236     }
    237 }
    238 
    239 int
    240 fb_image_draw(FB_IMAGE * image, int x, int y, int sx, int sy, int width,
    241 	      int height)
    242 {
    243     int i, offset_fb, offset_img;
    244 
    245     if (image == NULL || is_open != TRUE ||
    246 	sx > image->width || sy > image->height ||
    247 	x > fb_width() || y > fb_height())
    248 	return 1;
    249 
    250     if (sx + width > image->width)
    251 	width = image->width - sx;
    252 
    253     if (sy + height > image->height)
    254 	height = image->height - sy;
    255 
    256     if (x + width > fb_width())
    257 	width = fb_width() - x;
    258 
    259     if (y + height > fb_height())
    260 	height = fb_height() - y;
    261 
    262     offset_fb = fscinfo.line_length * y + pixel_size * x;
    263     offset_img = image->rowstride * sy + pixel_size * sx;
    264     for (i = 0; i < height; i++) {
    265 	memcpy(buf + offset_fb, image->data + offset_img, pixel_size * width);
    266 	offset_fb += fscinfo.line_length;
    267 	offset_img += image->rowstride;
    268     }
    269 
    270     return 0;
    271 }
    272 
    273 void
    274 fb_image_copy(FB_IMAGE * dest, FB_IMAGE * src)
    275 {
    276     if (dest == NULL || src == NULL)
    277 	return;
    278 
    279     if (dest->len != src->len)
    280 	return;
    281 
    282     memcpy(dest->data, src->data, src->len);
    283 }
    284 
    285 /***********   fb_frame_*  ***********/
    286 
    287 FB_IMAGE **
    288 fb_frame_new(int w, int h, int n)
    289 {
    290     FB_IMAGE **frame;
    291     int i, error = 0;
    292 
    293     if (w > IMAGE_SIZE_MAX || h > IMAGE_SIZE_MAX || w < 1 || h < 1 || n < 1)
    294 	return NULL;
    295 
    296     frame = malloc(sizeof(*frame) * n);
    297     if (frame == NULL)
    298 	return NULL;
    299 
    300     for (i = 0; i < n; i++) {
    301 	frame[i] = fb_image_new(w, h);
    302 	frame[i]->num = n;
    303 	frame[i]->id = i;
    304 	frame[i]->delay = 1000;
    305 	if (frame[i] == NULL)
    306 	    error = 1;
    307     }
    308 
    309     if (error) {
    310 	fb_frame_free(frame);
    311 	return NULL;
    312     }
    313 
    314     return frame;
    315 }
    316 
    317 
    318 void
    319 fb_frame_free(FB_IMAGE ** frame)
    320 {
    321     int i, n;
    322 
    323     if (frame == NULL)
    324 	return;
    325 
    326     n = frame[0]->num;
    327     for (i = 0; i < n; i++) {
    328 	fb_image_free(frame[i]);
    329     }
    330     free(frame);
    331 }
    332 
    333 int
    334 fb_width(void)
    335 {
    336     if (is_open != TRUE)
    337 	return 0;
    338 
    339     return vscinfo.xres;
    340 }
    341 
    342 int
    343 fb_height(void)
    344 {
    345     if (is_open != TRUE)
    346 	return 0;
    347 
    348     return vscinfo.yres;
    349 }
    350 
    351 int
    352 fb_clear(int x, int y, int w, int h, int r, int g, int b)
    353 {
    354     int i, offset_fb;
    355     static int rr = -1, gg = -1, bb = -1;
    356     static char *tmp = NULL;
    357 
    358     if (is_open != TRUE || x > fb_width() || y > fb_height())
    359 	return 1;
    360 
    361     if (x < 0)
    362 	x = 0;
    363     if (y < 0)
    364 	y = 0;
    365 
    366     if (x + w > fb_width())
    367 	w = fb_width() - x;
    368     if (y + h > fb_height())
    369 	h = fb_height() - y;
    370 
    371     if (tmp == NULL) {
    372 	tmp = malloc(fscinfo.line_length);
    373 	if (tmp == NULL)
    374 	    return 1;
    375     }
    376     if (rr != r || gg != g || bb != b) {
    377 	unsigned long work;
    378 	int ww = fb_width();
    379 
    380 	work = fb_get_packed_color(r, g, b);
    381 	for (i = 0; i < ww; i++)
    382 	    memcpy(tmp + pixel_size * i, &work, pixel_size);
    383 	rr = r;
    384 	gg = g;
    385 	bb = b;
    386     }
    387     offset_fb = fscinfo.line_length * y + pixel_size * x;
    388     for (i = 0; i < h; i++) {
    389 	memcpy(buf + offset_fb, tmp, pixel_size * w);
    390 	offset_fb += fscinfo.line_length;
    391     }
    392     return 0;
    393 }
    394 
    395 /********* static functions **************/
    396 static unsigned long
    397 fb_get_packed_color(int r, int g, int b)
    398 {
    399     if (pixel_size == 1) {
    400 	return fb_get_cmap_index(r, g, b);
    401     }
    402     else {
    403 	return
    404 	    ((r >> (CHAR_BIT - vscinfo.red.length)) << vscinfo.red.offset) +
    405 	    ((g >> (CHAR_BIT - vscinfo.green.length)) << vscinfo.green.
    406 	     offset) +
    407 	    ((b >> (CHAR_BIT - vscinfo.blue.length)) << vscinfo.blue.offset);
    408     }
    409 }
    410 
    411 static int
    412 fb_get_cmap_index(int r, int g, int b)
    413 {
    414     int work;
    415     if ((r & GREEN_MASK_8BIT) == (g & GREEN_MASK_8BIT)
    416 	&& (g & GREEN_MASK_8BIT) == (b & GREEN_MASK_8BIT)) {
    417 	work = (r >> MONO_SHIFT_8BIT) + MONO_OFFSET_8BIT;
    418     }
    419     else {
    420 	work = ((r & RED_MASK_8BIT) >> RED_SHIFT_8BIT)
    421 	    + ((g & GREEN_MASK_8BIT) >> GREEN_SHIFT_8BIT)
    422 	    + ((b & BLUE_MASK_8BIT) >> BLUE_SHIFT_8BIT)
    423 	    + COLOR_OFFSET_8BIT;
    424     }
    425     return work;
    426 }
    427 
    428 static int
    429 fb_cmap_init(void)
    430 {
    431     int lp;
    432 
    433     if (cmap == NULL)
    434 	return 1;
    435 
    436     if (cmap->len < COLOR_OFFSET_8BIT + COLORS_8BIT) {
    437 	fprintf(stderr, "Can't allocate enough color.\n");
    438 	return 1;
    439     }
    440 
    441     if (cmap_org == NULL) {
    442 	if ((cmap_org =
    443 	     fb_cmap_create(&fscinfo, &vscinfo)) == (struct fb_cmap *)-1) {
    444 	    return 1;
    445 	}
    446 
    447 	if (fb_cmap_get(fbfp, cmap_org)) {
    448 	    fprintf(stderr, "Can't get color map.\n");
    449 	    fb_cmap_destroy(cmap_org);
    450 	    cmap_org = NULL;
    451 	    return 1;
    452 	}
    453     }
    454 
    455     cmap->start = MONO_OFFSET_8BIT;
    456     cmap->len = COLORS_8BIT + COLORS_MONO_8BIT;
    457 
    458     for (lp = 0; lp < COLORS_MONO_8BIT; lp++) {
    459 	int c;
    460 	c = (lp << (MONO_SHIFT_8BIT + 8)) +
    461 	    (lp ? (0xFFFF - (MONO_MASK_8BIT << 8)) : 0);
    462 	if (cmap->red)
    463 	    *(cmap->red + lp) = c;
    464 	if (cmap->green)
    465 	    *(cmap->green + lp) = c;
    466 	if (cmap->blue)
    467 	    *(cmap->blue + lp) = c;
    468     }
    469 
    470     for (lp = 0; lp < COLORS_8BIT; lp++) {
    471 	int r, g, b;
    472 	r = lp & (RED_MASK_8BIT >> RED_SHIFT_8BIT);
    473 	g = lp & (GREEN_MASK_8BIT >> GREEN_SHIFT_8BIT);
    474 	b = lp & (BLUE_MASK_8BIT >> BLUE_SHIFT_8BIT);
    475 	if (cmap->red)
    476 	    *(cmap->red + lp + COLORS_MONO_8BIT)
    477 		= (r << (RED_SHIFT_8BIT + 8)) +
    478 		(r ? (0xFFFF - (RED_MASK_8BIT << 8)) : 0);
    479 	if (cmap->green)
    480 	    *(cmap->green + lp + COLORS_MONO_8BIT)
    481 		= (g << (GREEN_SHIFT_8BIT + 8)) +
    482 		(g ? (0xFFFF - (GREEN_MASK_8BIT << 8)) : 0);
    483 	if (cmap->blue)
    484 	    *(cmap->blue + lp + COLORS_MONO_8BIT)
    485 		= (b << (BLUE_SHIFT_8BIT + 8)) +
    486 		(b ? (0xFFFF - (BLUE_MASK_8BIT << 8)) : 0);
    487     }
    488 
    489     if (fb_cmap_set(fbfp, cmap)) {
    490 	fb_cmap_destroy(cmap);
    491 	cmap = NULL;
    492 	fprintf(stderr, "Can't set color map.\n");
    493 	return 1;
    494     }
    495     return 0;
    496 }
    497 
    498 /*
    499  * (struct fb_cmap) Device independent colormap information.
    500  * 
    501  * fb_cmap_create()     create colormap information
    502  * fb_cmap_destroy()    destroy colormap information
    503  * fb_cmap_get()        get information
    504  * fb_cmap_set()        set information
    505  */
    506 
    507 #define	LUT_MAX		(256)
    508 
    509 static struct fb_cmap *
    510 fb_cmap_create(struct fb_fix_screeninfo *fscinfo,
    511 	       struct fb_var_screeninfo *vscinfo)
    512 {
    513     struct fb_cmap *cmap;
    514     int cmaplen = LUT_MAX;
    515 
    516     /* check the existence of colormap */
    517     if (fscinfo->visual == FB_VISUAL_MONO01 ||
    518 	fscinfo->visual == FB_VISUAL_MONO10 ||
    519 	fscinfo->visual == FB_VISUAL_TRUECOLOR)
    520 	return NULL;
    521 
    522     cmap = (struct fb_cmap *)malloc(sizeof(struct fb_cmap));
    523     if (!cmap) {
    524 	perror("cmap malloc error\n");
    525 	return (struct fb_cmap *)-1;
    526     }
    527     memset(cmap, 0, sizeof(struct fb_cmap));
    528 
    529     /* Allocates memory for a colormap */
    530     if (vscinfo->red.length) {
    531 	cmap->red = (__u16 *) malloc(sizeof(__u16) * cmaplen);
    532 	if (!cmap->red) {
    533 	    perror("red lut malloc error\n");
    534 	    return (struct fb_cmap *)-1;
    535 	}
    536     }
    537     if (vscinfo->green.length) {
    538 	cmap->green = (__u16 *) malloc(sizeof(__u16) * cmaplen);
    539 	if (!cmap->green) {
    540 	    if (vscinfo->red.length)
    541 		free(cmap->red);
    542 	    perror("green lut malloc error\n");
    543 	    return (struct fb_cmap *)-1;
    544 	}
    545     }
    546     if (vscinfo->blue.length) {
    547 	cmap->blue = (__u16 *) malloc(sizeof(__u16) * cmaplen);
    548 	if (!cmap->blue) {
    549 	    if (vscinfo->red.length)
    550 		free(cmap->red);
    551 	    if (vscinfo->green.length)
    552 		free(cmap->green);
    553 	    perror("blue lut malloc error\n");
    554 	    return (struct fb_cmap *)-1;
    555 	}
    556     }
    557     if (vscinfo->transp.length) {
    558 	cmap->transp = (__u16 *) malloc(sizeof(__u16) * cmaplen);
    559 	if (!cmap->transp) {
    560 	    if (vscinfo->red.length)
    561 		free(cmap->red);
    562 	    if (vscinfo->green.length)
    563 		free(cmap->green);
    564 	    if (vscinfo->blue.length)
    565 		free(cmap->blue);
    566 	    perror("transp lut malloc error\n");
    567 	    return (struct fb_cmap *)-1;
    568 	}
    569     }
    570     cmap->len = cmaplen;
    571     return cmap;
    572 }
    573 
    574 static void
    575 fb_cmap_destroy(struct fb_cmap *cmap)
    576 {
    577     if (cmap->red)
    578 	free(cmap->red);
    579     if (cmap->green)
    580 	free(cmap->green);
    581     if (cmap->blue)
    582 	free(cmap->blue);
    583     if (cmap->transp)
    584 	free(cmap->transp);
    585     free(cmap);
    586 }
    587 
    588 static int
    589 fb_cmap_get(int fbfp, struct fb_cmap *cmap)
    590 {
    591     if (ioctl(fbfp, FBIOGETCMAP, cmap)) {
    592 	perror("ioctl FBIOGETCMAP error\n");
    593 	return -1;
    594     }
    595     return 0;
    596 }
    597 
    598 static int
    599 fb_cmap_set(int fbfp, struct fb_cmap *cmap)
    600 {
    601     if (ioctl(fbfp, FBIOPUTCMAP, cmap)) {
    602 	perror("ioctl FBIOPUTCMAP error\n");
    603 	return -1;
    604     }
    605     return 0;
    606 }
    607 
    608 /*
    609  * access to framebuffer
    610  * 
    611  * fb_mmap()            map from framebuffer into memory
    612  * fb_munmap()          deletes the mappings
    613  */
    614 
    615 static void *
    616 fb_mmap(int fbfp, struct fb_fix_screeninfo *scinfo)
    617 {
    618     void *buf;
    619     if ((buf = (unsigned char *)
    620 	 mmap(NULL, scinfo->smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfp,
    621 	      (off_t) 0))
    622 	== MAP_FAILED) {
    623 	perror("mmap error");
    624 	return NULL;
    625     }
    626     return buf;
    627 }
    628 
    629 static int
    630 fb_munmap(void *buf, struct fb_fix_screeninfo *scinfo)
    631 {
    632     return munmap(buf, scinfo->smem_len);
    633 }
    634 
    635 /*
    636  * (struct fb_fix_screeninfo) device independent fixed information
    637  * 
    638  * fb_fscrn_get()               get information
    639  */
    640 static int
    641 fb_fscrn_get(int fbfp, struct fb_fix_screeninfo *scinfo)
    642 {
    643     if (ioctl(fbfp, FBIOGET_FSCREENINFO, scinfo)) {
    644 	perror("ioctl FBIOGET_FSCREENINFO error\n");
    645 	return -1;
    646     }
    647     return 0;
    648 }
    649 
    650 /*
    651  * (struct fb_var_screeninfo) device independent variable information
    652  * 
    653  * fb_vscrn_get()               get information
    654  */
    655 static int
    656 fb_vscrn_get(int fbfp, struct fb_var_screeninfo *scinfo)
    657 {
    658     if (ioctl(fbfp, FBIOGET_VSCREENINFO, scinfo)) {
    659 	perror("ioctl FBIOGET_VSCREENINFO error\n");
    660 	return -1;
    661     }
    662     return 0;
    663 }