aboutsummaryrefslogtreecommitdiffstats
path: root/w3mimg/fb/fb.c
diff options
context:
space:
mode:
Diffstat (limited to 'w3mimg/fb/fb.c')
-rw-r--r--w3mimg/fb/fb.c663
1 files changed, 663 insertions, 0 deletions
diff --git a/w3mimg/fb/fb.c b/w3mimg/fb/fb.c
new file mode 100644
index 0000000..cd11128
--- /dev/null
+++ b/w3mimg/fb/fb.c
@@ -0,0 +1,663 @@
+/* $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 10000
+
+static 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;
+
+int
+fb_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;
+}
+
+void
+fb_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;
+}
+
+void
+fb_image_free(FB_IMAGE * image)
+{
+ if (image == NULL)
+ return;
+
+ if (image->data != NULL)
+ free(image->data);
+
+ free(image);
+}
+
+void
+fb_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);
+}
+
+void
+fb_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);
+ }
+}
+
+int
+fb_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;
+}
+
+void
+fb_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;
+}
+
+
+void
+fb_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);
+}
+
+int
+fb_width(void)
+{
+ if (is_open != TRUE)
+ return 0;
+
+ return vscinfo.xres;
+}
+
+int
+fb_height(void)
+{
+ if (is_open != TRUE)
+ return 0;
+
+ return vscinfo.yres;
+}
+
+int
+fb_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 long
+fb_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 int
+fb_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 int
+fb_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 void
+fb_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 int
+fb_cmap_get(int fbfp, struct fb_cmap *cmap)
+{
+ if (ioctl(fbfp, FBIOGETCMAP, cmap)) {
+ perror("ioctl FBIOGETCMAP error\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+fb_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 int
+fb_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 int
+fb_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 int
+fb_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;
+}