Initial import
[renesas/gralloc-kms.git] / system / core / 0002-init-Support-DRM-KMS-to-display-the-boot-logo.patch
1 From a99e4e5fea639e2d163071011c2b866dde1e848b Mon Sep 17 00:00:00 2001
2 From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3 Date: Sat, 15 Sep 2012 03:53:03 +0200
4 Subject: [PATCH] init: Support DRM/KMS to display the boot logo
5
6 Change-Id: Ia42ef34a65f8aeebeedb947b2d7067154720f5d2
7 Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
8 ---
9  init/Android.mk |    2 +-
10  init/logo-drm.c |  379 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
11  init/logo-fb.c  |  163 ++++++++++++++++++++++++
12  init/logo.c     |  163 ------------------------
13  4 files changed, 543 insertions(+), 164 deletions(-)
14  create mode 100644 init/logo-drm.c
15  create mode 100644 init/logo-fb.c
16  delete mode 100644 init/logo.c
17
18 diff --git a/init/Android.mk b/init/Android.mk
19 index f3287a8..485fc7f 100644
20 --- a/init/Android.mk
21 +++ b/init/Android.mk
22 @@ -10,7 +10,7 @@ LOCAL_SRC_FILES:= \
23         property_service.c \
24         util.c \
25         parser.c \
26 -       logo.c \
27 +       logo-drm.c \
28         keychords.c \
29         signal_handler.c \
30         init_parser.c \
31 diff --git a/init/logo-drm.c b/init/logo-drm.c
32 new file mode 100644
33 index 0000000..22ecf08
34 --- /dev/null
35 +++ b/init/logo-drm.c
36 @@ -0,0 +1,379 @@
37 +/*
38 + * Copyright (C) 2008 The Android Open Source Project
39 + *
40 + * Licensed under the Apache License, Version 2.0 (the "License");
41 + * you may not use this file except in compliance with the License.
42 + * You may obtain a copy of the License at
43 + *
44 + *      http://www.apache.org/licenses/LICENSE-2.0
45 + *
46 + * Unless required by applicable law or agreed to in writing, software
47 + * distributed under the License is distributed on an "AS IS" BASIS,
48 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
49 + * See the License for the specific language governing permissions and
50 + * limitations under the License.
51 + */
52 +
53 +#include <stdbool.h>
54 +#include <stdio.h>
55 +#include <stdlib.h>
56 +#include <unistd.h>
57 +#include <fcntl.h>
58 +#include <sys/mman.h>
59 +#include <sys/stat.h>
60 +#include <sys/types.h>
61 +
62 +#include <linux/kd.h>
63 +
64 +#include <drm/drm.h>
65 +#include <drm/drm_mode.h>
66 +#include <drm/drm_fourcc.h>
67 +
68 +#include "log.h"
69 +
70 +#ifdef ANDROID
71 +#include <cutils/memory.h>
72 +#else
73 +void android_memset16(void *_ptr, unsigned short val, unsigned count)
74 +{
75 +       unsigned short *ptr = _ptr;
76 +       count >>= 1;
77 +       while(count--)
78 +               *ptr++ = val;
79 +}
80 +#endif
81 +
82 +struct drm {
83 +       int fd;
84 +       struct {
85 +               uint32_t crtc;
86 +               uint32_t connector;
87 +               struct drm_mode_modeinfo mode;
88 +       } kms;
89 +       struct {
90 +               unsigned int handle;
91 +               void *map;
92 +               size_t size;
93 +               size_t pitch;
94 +       } bo;
95 +       struct {
96 +               unsigned int id;
97 +       } fb;
98 +};
99 +
100 +#define U642VOID(x)    ((void *)(unsigned long)(x))
101 +#define VOID2U64(x)    ((uint64_t)(unsigned long)(x))
102 +
103 +static void drm_close(struct drm *drm, bool destroy)
104 +{
105 +       struct drm_mode_destroy_dumb dumb;
106 +       uint32_t id;
107 +
108 +       if (drm->bo.map)
109 +               munmap(drm->bo.map, drm->bo.size);
110 +
111 +       if (destroy) {
112 +               if (drm->fb.id) {
113 +                       id = drm->fb.id;
114 +                       ioctl(drm->fd, DRM_IOCTL_MODE_RMFB, &id);
115 +               }
116 +
117 +               if (drm->bo.handle) {
118 +                       memset(&dumb, 0, sizeof dumb);
119 +                       dumb.handle = drm->bo.handle;
120 +                       ioctl(drm->fd, DRM_IOCTL_MODE_DESTROY_DUMB, dumb);
121 +               }
122 +       }
123 +
124 +       close(drm->fd);
125 +}
126 +
127 +static int drm_get_resources(struct drm *drm)
128 +{
129 +       struct drm_mode_card_res counts;
130 +       struct drm_mode_card_res res;
131 +       int ret;
132 +
133 +retry:
134 +       memset(&res, 0, sizeof res);
135 +       ret = ioctl(drm->fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
136 +       if (ret < 0)
137 +               return -1;
138 +
139 +       counts = res;
140 +       memset(&res, 0, sizeof res);
141 +
142 +       if (counts.count_crtcs) {
143 +               res.count_crtcs = counts.count_crtcs;
144 +               res.crtc_id_ptr = VOID2U64(malloc(res.count_crtcs *
145 +                                                 sizeof(uint32_t)));
146 +               if (!res.crtc_id_ptr) {
147 +                       ret = -1;
148 +                       goto done;
149 +               }
150 +       }
151 +
152 +       if (counts.count_connectors) {
153 +               res.count_connectors = counts.count_connectors;
154 +               res.connector_id_ptr = VOID2U64(malloc(res.count_connectors *
155 +                                                      sizeof(uint32_t)));
156 +               if (!res.connector_id_ptr) {
157 +                       ret = -1;
158 +                       goto done;
159 +               }
160 +       }
161 +
162 +       ret = ioctl(drm->fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
163 +       if (ret < 0)
164 +               goto done;
165 +
166 +       /* The number of available connectors and etc may have changed with a
167 +        * hotplug event in between the ioctls, in which case the field is
168 +        * silently ignored by the kernel.
169 +        */
170 +       if (counts.count_crtcs < res.count_crtcs ||
171 +           counts.count_connectors < res.count_connectors) {
172 +               free(U642VOID(res.crtc_id_ptr));
173 +               free(U642VOID(res.connector_id_ptr));
174 +               goto retry;
175 +       }
176 +
177 +       /* We need at least one CRTC and one connector. */
178 +       if (res.count_crtcs == 0 || res.count_connectors == 0) {
179 +               ret = -1;
180 +               goto done;
181 +       }
182 +
183 +       drm->kms.crtc = *(uint32_t *)U642VOID(res.crtc_id_ptr);
184 +       drm->kms.connector = *(uint32_t *)U642VOID(res.connector_id_ptr);
185 +
186 +       ret = 0;
187 +
188 +done:
189 +       free(U642VOID(res.crtc_id_ptr));
190 +       free(U642VOID(res.connector_id_ptr));
191 +
192 +       return ret;
193 +}
194 +
195 +static int drm_get_modes(struct drm *drm)
196 +{
197 +       struct drm_mode_get_connector counts;
198 +       struct drm_mode_get_connector conn;
199 +       int ret;
200 +
201 +retry:
202 +       memset(&conn, 0, sizeof conn);
203 +       conn.connector_id = drm->kms.connector;
204 +
205 +       ret = ioctl(drm->fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn);
206 +       if (ret < 0)
207 +               return -1;
208 +
209 +       counts = conn;
210 +       memset(&conn, 0, sizeof conn);
211 +       conn.connector_id = drm->kms.connector;
212 +
213 +       if (counts.count_modes) {
214 +               conn.count_modes = counts.count_modes;
215 +               conn.modes_ptr = VOID2U64(malloc(conn.count_modes *
216 +                                                sizeof(struct drm_mode_modeinfo)));
217 +               if (!conn.modes_ptr) {
218 +                       ret = -1;
219 +                       goto done;
220 +               }
221 +       }
222 +
223 +       ret = ioctl(drm->fd, DRM_IOCTL_MODE_GETCONNECTOR, &conn);
224 +       if (ret < 0)
225 +               goto done;
226 +
227 +       /* The number of available connectors and etc may have changed with a
228 +        * hotplug event in between the ioctls, in which case the field is
229 +        * silently ignored by the kernel.
230 +        */
231 +       if (counts.count_modes < conn.count_modes) {
232 +               free(U642VOID(conn.modes_ptr));
233 +               goto retry;
234 +       }
235 +
236 +       /* We need at least one mode. */
237 +       if (conn.count_modes == 0) {
238 +               ret = -1;
239 +               goto done;
240 +       }
241 +
242 +       drm->kms.mode = *(struct drm_mode_modeinfo *)U642VOID(conn.modes_ptr);
243 +
244 +       ret = 0;
245 +
246 +done:
247 +       free(U642VOID(conn.modes_ptr));
248 +
249 +       return ret;
250 +}
251 +
252 +static int drm_open(struct drm *drm)
253 +{
254 +       struct drm_get_cap cap = { DRM_CAP_DUMB_BUFFER, 0 };
255 +       struct drm_mode_create_dumb dumb;
256 +       struct drm_mode_map_dumb map;
257 +       struct drm_mode_fb_cmd2 fb;
258 +       void *mem;
259 +       int ret;
260 +
261 +       drm->fd = open("/dev/dri/card0", O_RDWR);
262 +       if (drm->fd < 0)
263 +               return -1;
264 +
265 +       /* Verify that the driver supports dumb buffers. */
266 +       ret = ioctl(drm->fd, DRM_IOCTL_GET_CAP, &cap);
267 +       if (ret < 0)
268 +               goto error;
269 +       if (!cap.value)
270 +               goto error;
271 +
272 +       ret = drm_get_resources(drm);
273 +       if (ret < 0)
274 +               goto error;
275 +
276 +       ret = drm_get_modes(drm);
277 +       if (ret < 0)
278 +               goto error;
279 +
280 +       /* Create a buffer and map it. */
281 +       memset(&dumb, 0, sizeof dumb);
282 +       dumb.bpp = 16;
283 +       dumb.width = drm->kms.mode.hdisplay;
284 +       dumb.height = drm->kms.mode.vdisplay;
285 +
286 +       ret = ioctl(drm->fd, DRM_IOCTL_MODE_CREATE_DUMB, &dumb);
287 +       if (ret < 0)
288 +               goto error;
289 +
290 +       drm->bo.handle = dumb.handle;
291 +       drm->bo.size = dumb.size;
292 +       drm->bo.pitch = dumb.pitch;
293 +
294 +       memset(&map, 0, sizeof map);
295 +       map.handle = drm->bo.handle;
296 +
297 +       ret = ioctl(drm->fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
298 +       if (ret < 0)
299 +               goto error;
300 +
301 +       mem = mmap(0, drm->bo.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm->fd,
302 +                  map.offset);
303 +       if (mem == MAP_FAILED)
304 +               goto error;
305 +
306 +       drm->bo.map = mem;
307 +
308 +       /* Create a frame buffer. */
309 +       memset(&fb, 0, sizeof fb);
310 +       fb.width = drm->kms.mode.hdisplay;
311 +       fb.height = drm->kms.mode.vdisplay;
312 +       fb.pixel_format = DRM_FORMAT_RGB565;
313 +       fb.handles[0] = drm->bo.handle;
314 +       fb.pitches[0] = drm->bo.pitch;
315 +
316 +       ret = ioctl (drm->fd, DRM_IOCTL_MODE_ADDFB2, &fb);
317 +       if (ret < 0)
318 +               goto error;
319 +
320 +       drm->fb.id = fb.fb_id;
321 +
322 +       return 0;
323 +
324 +error:
325 +       drm_close(drm, true);
326 +       return -1;
327 +}
328 +
329 +static void drm_update(struct drm *drm)
330 +{
331 +       struct drm_mode_crtc crtc;
332 +       uint32_t connector = drm->kms.connector;
333 +       int ret;
334 +
335 +       memset(&crtc, 0, sizeof crtc);
336 +       crtc.crtc_id = drm->kms.crtc;
337 +       crtc.fb_id = drm->fb.id;
338 +       crtc.set_connectors_ptr = VOID2U64(&connector);
339 +       crtc.count_connectors = 1;
340 +       crtc.mode = drm->kms.mode;
341 +       crtc.mode_valid = 1;
342 +
343 +       ioctl(drm->fd, DRM_IOCTL_MODE_SETCRTC, &crtc);
344 +}
345 +
346 +static int vt_set_mode(int graphics)
347 +{
348 +       int fd, r;
349 +       fd = open("/dev/tty0", O_RDWR | O_SYNC);
350 +       if (fd < 0)
351 +               return -1;
352 +       r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT));
353 +       close(fd);
354 +       return r;
355 +}
356 +
357 +/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
358 +
359 +int load_565rle_image(char *fn)
360 +{
361 +       struct drm drm;
362 +       struct stat s;
363 +       unsigned short *data, *bits, *ptr;
364 +       unsigned count, max;
365 +       int fd;
366 +
367 +       if (vt_set_mode(1))
368 +               return -1;
369 +
370 +       fd = open(fn, O_RDONLY);
371 +       if (fd < 0) {
372 +               ERROR("cannot open '%s'\n", fn);
373 +               goto fail_restore_text;
374 +       }
375 +
376 +       if (fstat(fd, &s) < 0)
377 +               goto fail_close_file;
378 +
379 +       data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
380 +       if (data == MAP_FAILED)
381 +               goto fail_close_file;
382 +
383 +       if (drm_open(&drm))
384 +               goto fail_unmap_data;
385 +
386 +       max = drm.bo.size;
387 +       ptr = data;
388 +       count = s.st_size;
389 +       bits = drm.bo.map;
390 +       while (count > 3) {
391 +               unsigned n = ptr[0];
392 +               if (n > max)
393 +                       break;
394 +               android_memset16(bits, ptr[1], n << 1);
395 +               bits += n;
396 +               max -= n;
397 +               ptr += 2;
398 +               count -= 4;
399 +       }
400 +
401 +       munmap(data, s.st_size);
402 +       drm_update(&drm);
403 +       drm_close(&drm, false);
404 +       close(fd);
405 +       unlink(fn);
406 +       return 0;
407 +
408 +fail_unmap_data:
409 +       munmap(data, s.st_size);
410 +fail_close_file:
411 +       close(fd);
412 +fail_restore_text:
413 +       vt_set_mode(0);
414 +       return -1;
415 +}
416 diff --git a/init/logo-fb.c b/init/logo-fb.c
417 new file mode 100644
418 index 0000000..614224c
419 --- /dev/null
420 +++ b/init/logo-fb.c
421 @@ -0,0 +1,163 @@
422 +/*
423 + * Copyright (C) 2008 The Android Open Source Project
424 + *
425 + * Licensed under the Apache License, Version 2.0 (the "License");
426 + * you may not use this file except in compliance with the License.
427 + * You may obtain a copy of the License at
428 + *
429 + *      http://www.apache.org/licenses/LICENSE-2.0
430 + *
431 + * Unless required by applicable law or agreed to in writing, software
432 + * distributed under the License is distributed on an "AS IS" BASIS,
433 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
434 + * See the License for the specific language governing permissions and
435 + * limitations under the License.
436 + */
437 +
438 +#include <stdio.h>
439 +#include <stdlib.h>
440 +#include <unistd.h>
441 +#include <fcntl.h>
442 +#include <sys/mman.h>
443 +#include <sys/stat.h>
444 +#include <sys/types.h>
445 +
446 +#include <linux/fb.h>
447 +#include <linux/kd.h>
448 +
449 +#include "log.h"
450 +
451 +#ifdef ANDROID
452 +#include <cutils/memory.h>
453 +#else
454 +void android_memset16(void *_ptr, unsigned short val, unsigned count)
455 +{
456 +    unsigned short *ptr = _ptr;
457 +    count >>= 1;
458 +    while(count--)
459 +        *ptr++ = val;
460 +}
461 +#endif
462 +
463 +struct FB {
464 +    unsigned short *bits;
465 +    unsigned size;
466 +    int fd;
467 +    struct fb_fix_screeninfo fi;
468 +    struct fb_var_screeninfo vi;
469 +};
470 +
471 +#define fb_width(fb) ((fb)->vi.xres)
472 +#define fb_height(fb) ((fb)->vi.yres)
473 +#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2)
474 +
475 +static int fb_open(struct FB *fb)
476 +{
477 +    fb->fd = open("/dev/graphics/fb0", O_RDWR);
478 +    if (fb->fd < 0)
479 +        return -1;
480 +
481 +    if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)
482 +        goto fail;
483 +    if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)
484 +        goto fail;
485 +
486 +    fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, 
487 +                    MAP_SHARED, fb->fd, 0);
488 +    if (fb->bits == MAP_FAILED)
489 +        goto fail;
490 +
491 +    return 0;
492 +
493 +fail:
494 +    close(fb->fd);
495 +    return -1;
496 +}
497 +
498 +static void fb_close(struct FB *fb)
499 +{
500 +    munmap(fb->bits, fb_size(fb));
501 +    close(fb->fd);
502 +}
503 +
504 +/* there's got to be a more portable way to do this ... */
505 +static void fb_update(struct FB *fb)
506 +{
507 +    fb->vi.yoffset = 1;
508 +    ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
509 +    fb->vi.yoffset = 0;
510 +    ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
511 +}
512 +
513 +static int vt_set_mode(int graphics)
514 +{
515 +    int fd, r;
516 +    fd = open("/dev/tty0", O_RDWR | O_SYNC);
517 +    if (fd < 0)
518 +        return -1;
519 +    r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT));
520 +    close(fd);
521 +    return r;
522 +}
523 +
524 +/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
525 +
526 +int load_565rle_image(char *fn)
527 +{
528 +    struct FB fb;
529 +    struct stat s;
530 +    unsigned short *data, *bits, *ptr;
531 +    unsigned count, max;
532 +    int fd;
533 +
534 +    if (vt_set_mode(1)) 
535 +        return -1;
536 +
537 +    fd = open(fn, O_RDONLY);
538 +    if (fd < 0) {
539 +        ERROR("cannot open '%s'\n", fn);
540 +        goto fail_restore_text;
541 +    }
542 +
543 +    if (fstat(fd, &s) < 0) {
544 +        goto fail_close_file;
545 +    }
546 +
547 +    data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
548 +    if (data == MAP_FAILED)
549 +        goto fail_close_file;
550 +
551 +    if (fb_open(&fb))
552 +        goto fail_unmap_data;
553 +
554 +    max = fb_width(&fb) * fb_height(&fb);
555 +    ptr = data;
556 +    count = s.st_size;
557 +    bits = fb.bits;
558 +    while (count > 3) {
559 +        unsigned n = ptr[0];
560 +        if (n > max)
561 +            break;
562 +        android_memset16(bits, ptr[1], n << 1);
563 +        bits += n;
564 +        max -= n;
565 +        ptr += 2;
566 +        count -= 4;
567 +    }
568 +
569 +    munmap(data, s.st_size);
570 +    fb_update(&fb);
571 +    fb_close(&fb);
572 +    close(fd);
573 +    unlink(fn);
574 +    return 0;
575 +
576 +fail_unmap_data:
577 +    munmap(data, s.st_size);    
578 +fail_close_file:
579 +    close(fd);
580 +fail_restore_text:
581 +    vt_set_mode(0);
582 +    return -1;
583 +}
584 +
585 diff --git a/init/logo.c b/init/logo.c
586 deleted file mode 100644
587 index 614224c..0000000
588 --- a/init/logo.c
589 +++ /dev/null
590 @@ -1,163 +0,0 @@
591 -/*
592 - * Copyright (C) 2008 The Android Open Source Project
593 - *
594 - * Licensed under the Apache License, Version 2.0 (the "License");
595 - * you may not use this file except in compliance with the License.
596 - * You may obtain a copy of the License at
597 - *
598 - *      http://www.apache.org/licenses/LICENSE-2.0
599 - *
600 - * Unless required by applicable law or agreed to in writing, software
601 - * distributed under the License is distributed on an "AS IS" BASIS,
602 - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
603 - * See the License for the specific language governing permissions and
604 - * limitations under the License.
605 - */
606 -
607 -#include <stdio.h>
608 -#include <stdlib.h>
609 -#include <unistd.h>
610 -#include <fcntl.h>
611 -#include <sys/mman.h>
612 -#include <sys/stat.h>
613 -#include <sys/types.h>
614 -
615 -#include <linux/fb.h>
616 -#include <linux/kd.h>
617 -
618 -#include "log.h"
619 -
620 -#ifdef ANDROID
621 -#include <cutils/memory.h>
622 -#else
623 -void android_memset16(void *_ptr, unsigned short val, unsigned count)
624 -{
625 -    unsigned short *ptr = _ptr;
626 -    count >>= 1;
627 -    while(count--)
628 -        *ptr++ = val;
629 -}
630 -#endif
631 -
632 -struct FB {
633 -    unsigned short *bits;
634 -    unsigned size;
635 -    int fd;
636 -    struct fb_fix_screeninfo fi;
637 -    struct fb_var_screeninfo vi;
638 -};
639 -
640 -#define fb_width(fb) ((fb)->vi.xres)
641 -#define fb_height(fb) ((fb)->vi.yres)
642 -#define fb_size(fb) ((fb)->vi.xres * (fb)->vi.yres * 2)
643 -
644 -static int fb_open(struct FB *fb)
645 -{
646 -    fb->fd = open("/dev/graphics/fb0", O_RDWR);
647 -    if (fb->fd < 0)
648 -        return -1;
649 -
650 -    if (ioctl(fb->fd, FBIOGET_FSCREENINFO, &fb->fi) < 0)
651 -        goto fail;
652 -    if (ioctl(fb->fd, FBIOGET_VSCREENINFO, &fb->vi) < 0)
653 -        goto fail;
654 -
655 -    fb->bits = mmap(0, fb_size(fb), PROT_READ | PROT_WRITE, 
656 -                    MAP_SHARED, fb->fd, 0);
657 -    if (fb->bits == MAP_FAILED)
658 -        goto fail;
659 -
660 -    return 0;
661 -
662 -fail:
663 -    close(fb->fd);
664 -    return -1;
665 -}
666 -
667 -static void fb_close(struct FB *fb)
668 -{
669 -    munmap(fb->bits, fb_size(fb));
670 -    close(fb->fd);
671 -}
672 -
673 -/* there's got to be a more portable way to do this ... */
674 -static void fb_update(struct FB *fb)
675 -{
676 -    fb->vi.yoffset = 1;
677 -    ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
678 -    fb->vi.yoffset = 0;
679 -    ioctl(fb->fd, FBIOPUT_VSCREENINFO, &fb->vi);
680 -}
681 -
682 -static int vt_set_mode(int graphics)
683 -{
684 -    int fd, r;
685 -    fd = open("/dev/tty0", O_RDWR | O_SYNC);
686 -    if (fd < 0)
687 -        return -1;
688 -    r = ioctl(fd, KDSETMODE, (void*) (graphics ? KD_GRAPHICS : KD_TEXT));
689 -    close(fd);
690 -    return r;
691 -}
692 -
693 -/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
694 -
695 -int load_565rle_image(char *fn)
696 -{
697 -    struct FB fb;
698 -    struct stat s;
699 -    unsigned short *data, *bits, *ptr;
700 -    unsigned count, max;
701 -    int fd;
702 -
703 -    if (vt_set_mode(1)) 
704 -        return -1;
705 -
706 -    fd = open(fn, O_RDONLY);
707 -    if (fd < 0) {
708 -        ERROR("cannot open '%s'\n", fn);
709 -        goto fail_restore_text;
710 -    }
711 -
712 -    if (fstat(fd, &s) < 0) {
713 -        goto fail_close_file;
714 -    }
715 -
716 -    data = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
717 -    if (data == MAP_FAILED)
718 -        goto fail_close_file;
719 -
720 -    if (fb_open(&fb))
721 -        goto fail_unmap_data;
722 -
723 -    max = fb_width(&fb) * fb_height(&fb);
724 -    ptr = data;
725 -    count = s.st_size;
726 -    bits = fb.bits;
727 -    while (count > 3) {
728 -        unsigned n = ptr[0];
729 -        if (n > max)
730 -            break;
731 -        android_memset16(bits, ptr[1], n << 1);
732 -        bits += n;
733 -        max -= n;
734 -        ptr += 2;
735 -        count -= 4;
736 -    }
737 -
738 -    munmap(data, s.st_size);
739 -    fb_update(&fb);
740 -    fb_close(&fb);
741 -    close(fd);
742 -    unlink(fn);
743 -    return 0;
744 -
745 -fail_unmap_data:
746 -    munmap(data, s.st_size);    
747 -fail_close_file:
748 -    close(fd);
749 -fail_restore_text:
750 -    vt_set_mode(0);
751 -    return -1;
752 -}
753 -
754 -- 
755 1.7.8.6
756