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 33 void 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 42 struct 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 54 static 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 72 fail: 73 close(fb->fd); 74 return -1; 75 } 76 77 static 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 ... */ 84 static 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 92 static 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 105 int 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 155 fail_unmap_data: 156 munmap(data, s.st_size); 157 fail_close_file: 158 close(fd); 159 fail_restore_text: 160 vt_set_mode(0); 161 return -1; 162 } 163 164