📄 fb.c
字号:
/* $Id: fb.c,v 1.16 2003/07/13 16:19:10 ukai Exp $ *//************************************************************************** fb.c 0.3 Copyright (C) 2002, hito **************************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <limits.h>#include <errno.h>#include <sys/ioctl.h>#include <sys/mman.h>#include <linux/fb.h>#include "fb.h"#define FB_ENV "FRAMEBUFFER"#define FB_DEFDEV "/dev/fb0"#define MONO_OFFSET_8BIT 0x40#define COLORS_MONO_8BIT 0x40#define MONO_MASK_8BIT 0xFC#define MONO_SHIFT_8BIT 2#define COLOR_OFFSET_8BIT 0x80#define COLORS_8BIT 0x80#define RED_MASK_8BIT 0xC0#define GREEN_MASK_8BIT 0xE0#define BLUE_MASK_8BIT 0xC0#define RED_SHIFT_8BIT 1#define GREEN_SHIFT_8BIT 3#define BLUE_SHIFT_8BIT 6#define FALSE 0#define TRUE 1#define IMAGE_SIZE_MAX 10000static struct fb_cmap *fb_cmap_create(struct fb_fix_screeninfo *, struct fb_var_screeninfo *);static void fb_cmap_destroy(struct fb_cmap *cmap);static int fb_fscrn_get(int fbfp, struct fb_fix_screeninfo *scinfo);static void *fb_mmap(int fbfp, struct fb_fix_screeninfo *scinfo);static int fb_munmap(void *buf, struct fb_fix_screeninfo *scinfo);static int fb_vscrn_get(int fbfp, struct fb_var_screeninfo *scinfo);static int fb_cmap_set(int fbfp, struct fb_cmap *cmap);static int fb_cmap_get(int fbfp, struct fb_cmap *cmap);static int fb_cmap_init(void);static int fb_get_cmap_index(int r, int g, int b);static unsigned long fb_get_packed_color(int r, int g, int b);static struct fb_fix_screeninfo fscinfo;static struct fb_var_screeninfo vscinfo;static struct fb_cmap *cmap = NULL, *cmap_org = NULL;static int is_open = FALSE;static int fbfp = -1;static size_t pixel_size = 0;static unsigned char *buf = NULL;intfb_open(void){ char *fbdev = { FB_DEFDEV }; if (is_open == TRUE) return 1; if (getenv(FB_ENV)) { fbdev = getenv(FB_ENV); } if ((fbfp = open(fbdev, O_RDWR)) == -1) { fprintf(stderr, "open %s error\n", fbdev); goto ERR_END; } if (fb_fscrn_get(fbfp, &fscinfo)) { goto ERR_END; } if (fb_vscrn_get(fbfp, &vscinfo)) { goto ERR_END; } if ((cmap = fb_cmap_create(&fscinfo, &vscinfo)) == (struct fb_cmap *)-1) { goto ERR_END; } if (!(buf = fb_mmap(fbfp, &fscinfo))) { fprintf(stderr, "Can't allocate memory.\n"); goto ERR_END; } if (fscinfo.type != FB_TYPE_PACKED_PIXELS) { fprintf(stderr, "This type of framebuffer is not supported.\n"); goto ERR_END; } if (fscinfo.visual == FB_VISUAL_PSEUDOCOLOR && vscinfo.bits_per_pixel == 8) { if (fb_cmap_get(fbfp, cmap)) { fprintf(stderr, "Can't get color map.\n"); fb_cmap_destroy(cmap); cmap = NULL; goto ERR_END; } if (fb_cmap_init()) goto ERR_END; pixel_size = 1; } else if ((fscinfo.visual == FB_VISUAL_TRUECOLOR || fscinfo.visual == FB_VISUAL_DIRECTCOLOR) && (vscinfo.bits_per_pixel == 15 || vscinfo.bits_per_pixel == 16 || vscinfo.bits_per_pixel == 24 || vscinfo.bits_per_pixel == 32)) { pixel_size = (vscinfo.bits_per_pixel + 7) / CHAR_BIT; } else { fprintf(stderr, "This type of framebuffer is not supported.\n"); goto ERR_END; } is_open = TRUE; return 0; ERR_END: fb_close(); return 1;}voidfb_close(void){ if (is_open != TRUE) return; if (cmap != NULL) { fb_cmap_destroy(cmap); cmap = NULL; } if (cmap_org != NULL) { fb_cmap_set(fbfp, cmap_org); fb_cmap_destroy(cmap_org); cmap = NULL; } if (buf != NULL) { fb_munmap(buf, &fscinfo); buf = NULL; } if (fbfp >= 0) { close(fbfp); } is_open = FALSE;}/*********** fb_image_* ***********/FB_IMAGE *fb_image_new(int width, int height){ FB_IMAGE *image; if (is_open != TRUE) return NULL; if (width > IMAGE_SIZE_MAX || height > IMAGE_SIZE_MAX || width < 1 || height < 1) return NULL; image = malloc(sizeof(*image)); if (image == NULL) return NULL; image->data = calloc(sizeof(*(image->data)), width * height * pixel_size); if (image->data == NULL) { free(image); return NULL; } image->num = 1; image->id = 0; image->delay = 0; image->width = width; image->height = height; image->rowstride = width * pixel_size; image->len = width * height * pixel_size; return image;}voidfb_image_free(FB_IMAGE * image){ if (image == NULL) return; if (image->data != NULL) free(image->data); free(image);}voidfb_image_pset(FB_IMAGE * image, int x, int y, int r, int g, int b){ unsigned long work; if (image == NULL || is_open != TRUE || x >= image->width || y >= image->height) return; work = fb_get_packed_color(r, g, b); memcpy(image->data + image->rowstride * y + pixel_size * x, &work, pixel_size);}voidfb_image_fill(FB_IMAGE * image, int r, int g, int b){ unsigned long work; int offset; if (image == NULL || is_open != TRUE) return; work = fb_get_packed_color(r, g, b); for (offset = 0; offset < image->len; offset += pixel_size) { memcpy(image->data + offset, &work, pixel_size); }}intfb_image_draw(FB_IMAGE * image, int x, int y, int sx, int sy, int width, int height){ int i, offset_fb, offset_img; if (image == NULL || is_open != TRUE || sx > image->width || sy > image->height || x > fb_width() || y > fb_height()) return 1; if (sx + width > image->width) width = image->width - sx; if (sy + height > image->height) height = image->height - sy; if (x + width > fb_width()) width = fb_width() - x; if (y + height > fb_height()) height = fb_height() - y; offset_fb = fscinfo.line_length * y + pixel_size * x; offset_img = image->rowstride * sy + pixel_size * sx; for (i = 0; i < height; i++) { memcpy(buf + offset_fb, image->data + offset_img, pixel_size * width); offset_fb += fscinfo.line_length; offset_img += image->rowstride; } return 0;}voidfb_image_copy(FB_IMAGE * dest, FB_IMAGE * src){ if (dest == NULL || src == NULL) return; if (dest->len != src->len) return; memcpy(dest->data, src->data, src->len);}/*********** fb_frame_* ***********/FB_IMAGE **fb_frame_new(int w, int h, int n){ FB_IMAGE **frame; int i, error = 0; if (w > IMAGE_SIZE_MAX || h > IMAGE_SIZE_MAX || w < 1 || h < 1 || n < 1) return NULL; frame = malloc(sizeof(*frame) * n); if (frame == NULL) return NULL; for (i = 0; i < n; i++) { frame[i] = fb_image_new(w, h); frame[i]->num = n; frame[i]->id = i; frame[i]->delay = 1000; if (frame[i] == NULL) error = 1; } if (error) { fb_frame_free(frame); return NULL; } return frame;}voidfb_frame_free(FB_IMAGE ** frame){ int i, n; if (frame == NULL) return; n = frame[0]->num; for (i = 0; i < n; i++) { fb_image_free(frame[i]); } free(frame);}intfb_width(void){ if (is_open != TRUE) return 0; return vscinfo.xres;}intfb_height(void){ if (is_open != TRUE) return 0; return vscinfo.yres;}intfb_clear(int x, int y, int w, int h, int r, int g, int b){ int i, offset_fb; static int rr = -1, gg = -1, bb = -1; static char *tmp = NULL; if (is_open != TRUE || x > fb_width() || y > fb_height()) return 1; if (x < 0) x = 0; if (y < 0) y = 0; if (x + w > fb_width()) w = fb_width() - x; if (y + h > fb_height()) h = fb_height() - y; if (tmp == NULL) { tmp = malloc(fscinfo.line_length); if (tmp == NULL) return 1; } if (rr != r || gg != g || bb != b) { unsigned long work; int ww = fb_width(); work = fb_get_packed_color(r, g, b); for (i = 0; i < ww; i++) memcpy(tmp + pixel_size * i, &work, pixel_size); rr = r; gg = g; bb = b; } offset_fb = fscinfo.line_length * y + pixel_size * x; for (i = 0; i < h; i++) { memcpy(buf + offset_fb, tmp, pixel_size * w); offset_fb += fscinfo.line_length; } return 0;}/********* static functions **************/static unsigned longfb_get_packed_color(int r, int g, int b){ if (pixel_size == 1) { return fb_get_cmap_index(r, g, b); } else { return ((r >> (CHAR_BIT - vscinfo.red.length)) << vscinfo.red.offset) + ((g >> (CHAR_BIT - vscinfo.green.length)) << vscinfo.green. offset) + ((b >> (CHAR_BIT - vscinfo.blue.length)) << vscinfo.blue.offset); }}static intfb_get_cmap_index(int r, int g, int b){ int work; if ((r & GREEN_MASK_8BIT) == (g & GREEN_MASK_8BIT) && (g & GREEN_MASK_8BIT) == (b & GREEN_MASK_8BIT)) { work = (r >> MONO_SHIFT_8BIT) + MONO_OFFSET_8BIT; } else { work = ((r & RED_MASK_8BIT) >> RED_SHIFT_8BIT) + ((g & GREEN_MASK_8BIT) >> GREEN_SHIFT_8BIT) + ((b & BLUE_MASK_8BIT) >> BLUE_SHIFT_8BIT) + COLOR_OFFSET_8BIT; } return work;}static intfb_cmap_init(void){ int lp; if (cmap == NULL) return 1; if (cmap->len < COLOR_OFFSET_8BIT + COLORS_8BIT) { fprintf(stderr, "Can't allocate enough color.\n"); return 1; } if (cmap_org == NULL) { if ((cmap_org = fb_cmap_create(&fscinfo, &vscinfo)) == (struct fb_cmap *)-1) { return 1; } if (fb_cmap_get(fbfp, cmap_org)) { fprintf(stderr, "Can't get color map.\n"); fb_cmap_destroy(cmap_org); cmap_org = NULL; return 1; } } cmap->start = MONO_OFFSET_8BIT; cmap->len = COLORS_8BIT + COLORS_MONO_8BIT; for (lp = 0; lp < COLORS_MONO_8BIT; lp++) { int c; c = (lp << (MONO_SHIFT_8BIT + 8)) + (lp ? (0xFFFF - (MONO_MASK_8BIT << 8)) : 0); if (cmap->red) *(cmap->red + lp) = c; if (cmap->green) *(cmap->green + lp) = c; if (cmap->blue) *(cmap->blue + lp) = c; } for (lp = 0; lp < COLORS_8BIT; lp++) { int r, g, b; r = lp & (RED_MASK_8BIT >> RED_SHIFT_8BIT); g = lp & (GREEN_MASK_8BIT >> GREEN_SHIFT_8BIT); b = lp & (BLUE_MASK_8BIT >> BLUE_SHIFT_8BIT); if (cmap->red) *(cmap->red + lp + COLORS_MONO_8BIT) = (r << (RED_SHIFT_8BIT + 8)) + (r ? (0xFFFF - (RED_MASK_8BIT << 8)) : 0); if (cmap->green) *(cmap->green + lp + COLORS_MONO_8BIT) = (g << (GREEN_SHIFT_8BIT + 8)) + (g ? (0xFFFF - (GREEN_MASK_8BIT << 8)) : 0); if (cmap->blue) *(cmap->blue + lp + COLORS_MONO_8BIT) = (b << (BLUE_SHIFT_8BIT + 8)) + (b ? (0xFFFF - (BLUE_MASK_8BIT << 8)) : 0); } if (fb_cmap_set(fbfp, cmap)) { fb_cmap_destroy(cmap); cmap = NULL; fprintf(stderr, "Can't set color map.\n"); return 1; } return 0;}/* * (struct fb_cmap) Device independent colormap information. * * fb_cmap_create() create colormap information * fb_cmap_destroy() destroy colormap information * fb_cmap_get() get information * fb_cmap_set() set information */#define LUT_MAX (256)static struct fb_cmap *fb_cmap_create(struct fb_fix_screeninfo *fscinfo, struct fb_var_screeninfo *vscinfo){ struct fb_cmap *cmap; int cmaplen = LUT_MAX; /* check the existence of colormap */ if (fscinfo->visual == FB_VISUAL_MONO01 || fscinfo->visual == FB_VISUAL_MONO10 || fscinfo->visual == FB_VISUAL_TRUECOLOR) return NULL; cmap = (struct fb_cmap *)malloc(sizeof(struct fb_cmap)); if (!cmap) { perror("cmap malloc error\n"); return (struct fb_cmap *)-1; } memset(cmap, 0, sizeof(struct fb_cmap)); /* Allocates memory for a colormap */ if (vscinfo->red.length) { cmap->red = (__u16 *) malloc(sizeof(__u16) * cmaplen); if (!cmap->red) { perror("red lut malloc error\n"); return (struct fb_cmap *)-1; } } if (vscinfo->green.length) { cmap->green = (__u16 *) malloc(sizeof(__u16) * cmaplen); if (!cmap->green) { if (vscinfo->red.length) free(cmap->red); perror("green lut malloc error\n"); return (struct fb_cmap *)-1; } } if (vscinfo->blue.length) { cmap->blue = (__u16 *) malloc(sizeof(__u16) * cmaplen); if (!cmap->blue) { if (vscinfo->red.length) free(cmap->red); if (vscinfo->green.length) free(cmap->green); perror("blue lut malloc error\n"); return (struct fb_cmap *)-1; } } if (vscinfo->transp.length) { cmap->transp = (__u16 *) malloc(sizeof(__u16) * cmaplen); if (!cmap->transp) { if (vscinfo->red.length) free(cmap->red); if (vscinfo->green.length) free(cmap->green); if (vscinfo->blue.length) free(cmap->blue); perror("transp lut malloc error\n"); return (struct fb_cmap *)-1; } } cmap->len = cmaplen; return cmap;}static voidfb_cmap_destroy(struct fb_cmap *cmap){ if (cmap->red) free(cmap->red); if (cmap->green) free(cmap->green); if (cmap->blue) free(cmap->blue); if (cmap->transp) free(cmap->transp); free(cmap);}static intfb_cmap_get(int fbfp, struct fb_cmap *cmap){ if (ioctl(fbfp, FBIOGETCMAP, cmap)) { perror("ioctl FBIOGETCMAP error\n"); return -1; } return 0;}static intfb_cmap_set(int fbfp, struct fb_cmap *cmap){ if (ioctl(fbfp, FBIOPUTCMAP, cmap)) { perror("ioctl FBIOPUTCMAP error\n"); return -1; } return 0;}/* * access to framebuffer * * fb_mmap() map from framebuffer into memory * fb_munmap() deletes the mappings */static void *fb_mmap(int fbfp, struct fb_fix_screeninfo *scinfo){ void *buf; if ((buf = (unsigned char *) mmap(NULL, scinfo->smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfp, (off_t) 0)) == MAP_FAILED) { perror("mmap error"); return NULL; } return buf;}static intfb_munmap(void *buf, struct fb_fix_screeninfo *scinfo){ return munmap(buf, scinfo->smem_len);}/* * (struct fb_fix_screeninfo) device independent fixed information * * fb_fscrn_get() get information */static intfb_fscrn_get(int fbfp, struct fb_fix_screeninfo *scinfo){ if (ioctl(fbfp, FBIOGET_FSCREENINFO, scinfo)) { perror("ioctl FBIOGET_FSCREENINFO error\n"); return -1; } return 0;}/* * (struct fb_var_screeninfo) device independent variable information * * fb_vscrn_get() get information */static intfb_vscrn_get(int fbfp, struct fb_var_screeninfo *scinfo){ if (ioctl(fbfp, FBIOGET_VSCREENINFO, scinfo)) { perror("ioctl FBIOGET_VSCREENINFO error\n"); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -