1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <unistd.h> 20#include <fcntl.h> 21#include <sys/mman.h> 22#include <sys/stat.h> 23#include <sys/types.h> 24 25#include <linux/fb.h> 26#include <linux/kd.h> 27 28#include "log.h" 29 30#ifdef ANDROID 31#include <cutils/memory.h> 32#else 33void android_memset16(void *_ptr, unsigned short val, unsigned count) 34{ 35 unsigned short *ptr = _ptr; 36 count >>= 1; 37 while(count--) 38 *ptr++ = val; 39} 40#endif 41 42struct FB { 43 unsigned short *bits; 44 unsigned size; 45 int fd; 46 struct fb_fix_screeninfo fi; 47 struct fb_var_screeninfo vi; 48}; 49 50#define fb_width(fb) ((fb)->vi.xres) 51#define fb_height(fb) ((fb)->vi.yres) 52#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2) 53 54static int fb_open(struct FB *fb) 55{ 56 fb->fd = open("/dev/graphics/fb0", O_RDWR); 57 if (fb->fd < 0) 58 return -1; 59 60 if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) 61 goto fail; 62 if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) 63 goto fail; 64 65 fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, 66 MAP_SHARED, fb->fd, 0); 67 if (fb->bits == MAP_FAILED) 68 goto fail; 69 70 return 0; 71 72fail: 73 close(fb->fd); 74 return -1; 75} 76 77static void fb_close(struct FB *fb) 78{ 79 munmap(fb->bits, fb_size(fb)); 80 close(fb->fd); 81} 82 83/* there's got to be a more portable way to do this ... */ 84static void fb_update(struct FB *fb) 85{ 86 fb->vi.yoffset = 1; 87 ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); 88 fb->vi.yoffset = 0; 89 ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); 90} 91 92static int vt_set_mode(int graphics) 93{ 94 int fd, r; 95 fd = open("/dev/tty0", O_RDWR | O_SYNC); 96 if (fd < 0) 97 return -1; 98 r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT)); 99 close(fd); 100 return r; 101} 102 103/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ 104 105int load_565rle_image(char *fn) 106{ 107 struct FB fb; 108 struct stat s; 109 unsigned short *data, *bits, *ptr; 110 unsigned count, max; 111 int fd; 112 113 if (vt_set_mode(1)) 114 return -1; 115 116 fd = open(fn, O_RDONLY); 117 if (fd < 0) { 118 ERROR("cannot open '%s'\n", fn); 119 goto fail_restore_text; 120 } 121 122 if (fstat(fd, &s) < 0) { 123 goto fail_close_file; 124 } 125 126 data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); 127 if (data == MAP_FAILED) 128 goto fail_close_file; 129 130 if (fb_open(&fb)) 131 goto fail_unmap_data; 132 133 max = fb_width(&fb) * fb_height(&fb); 134 ptr = data; 135 count = s.st_size; 136 bits = fb.bits; 137 while (count > 3) { 138 unsigned n = ptr[0]; 139 if (n > max) 140 break; 141 android_memset16(bits, ptr[1], n << 1); 142 bits += n; 143 max -= n; 144 ptr += 2; 145 count -= 4; 146 } 147 148 munmap(data, s.st_size); 149 fb_update(&fb); 150 fb_close(&fb); 151 close(fd); 152 unlink(fn); 153 return 0; 154 155fail_unmap_data: 156 munmap(data, s.st_size); 157fail_close_file: 158 close(fd); 159fail_restore_text: 160 vt_set_mode(0); 161 return -1; 162} 163 164