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 }