diff options
Diffstat (limited to 'init/logo.c')
-rw-r--r-- | init/logo.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/init/logo.c b/init/logo.c new file mode 100644 index 0000000..6a740bf --- /dev/null +++ b/init/logo.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <linux/fb.h> +#include <linux/kd.h> + +#include "init.h" + +#ifdef ANDROID +#include <cutils/memory.h> +#else +void android_memset16(void *_ptr, unsigned short val, unsigned count) +{ + unsigned short *ptr = _ptr; + count >>= 1; + while(count--) + *ptr++ = val; +} +#endif + +struct FB { + unsigned short *bits; + unsigned size; + int fd; + struct fb_fix_screeninfo fi; + struct fb_var_screeninfo vi; +}; + +#define fb_width(fb) ((fb)->vi.xres) +#define fb_height(fb) ((fb)->vi.yres) +#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2) + +static int fb_open(struct FB *fb) +{ + fb->fd = open("/dev/graphics/fb0", O_RDWR); + if (fb->fd < 0) + return -1; + + if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0) + goto fail; + if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0) + goto fail; + + fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, + MAP_SHARED, fb->fd, 0); + if (fb->bits == MAP_FAILED) + goto fail; + + return 0; + +fail: + close(fb->fd); + return -1; +} + +static void fb_close(struct FB *fb) +{ + munmap(fb->bits, fb_size(fb)); + close(fb->fd); +} + +/* there's got to be a more portable way to do this ... */ +static void fb_update(struct FB *fb) +{ + fb->vi.yoffset = 1; + ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); + fb->vi.yoffset = 0; + ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi); +} + +static int vt_set_mode(int graphics) +{ + int fd, r; + fd = open("/dev/tty0", O_RDWR | O_SYNC); + if (fd < 0) + return -1; + r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT)); + close(fd); + return r; +} + +/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */ + +int load_565rle_image(char *fn) +{ + struct FB fb; + struct stat s; + unsigned short *data, *bits, *ptr; + unsigned count, max; + int fd; + + if (vt_set_mode(1)) + return -1; + + fd = open(fn, O_RDONLY); + if (fd < 0) { + ERROR("cannot open '%s'\n", fn); + goto fail_restore_text; + } + + if (fstat(fd, &s) < 0) { + goto fail_close_file; + } + + data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + goto fail_close_file; + + if (fb_open(&fb)) + goto fail_unmap_data; + + max = fb_width(&fb) * fb_height(&fb); + ptr = data; + count = s.st_size; + bits = fb.bits; + while (count > 3) { + unsigned n = ptr[0]; + if (n > max) + break; + android_memset16(bits, ptr[1], n << 1); + bits += n; + max -= n; + ptr += 2; + count -= 4; + } + + munmap(data, s.st_size); + fb_update(&fb); + fb_close(&fb); + close(fd); + unlink(fn); + return 0; + +fail_unmap_data: + munmap(data, s.st_size); +fail_close_file: + close(fd); +fail_restore_text: + vt_set_mode(0); + return -1; +} + |