blob: cc57f6a33b15bac804faa8d5d76874a0995062b0 [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/* Copyright (C) 2007-2008 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10** GNU General Public License for more details.
11*/
12#include "qemu_file.h"
13#include "android/android.h"
14#include "goldfish_device.h"
David 'Digit' Turner055ae422010-07-27 11:34:16 -070015#include "console.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080016
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +010017/* These values *must* match the platform definitions found under
18 * hardware/libhardware/include/hardware/hardware.h
19 */
20enum {
21 HAL_PIXEL_FORMAT_RGBA_8888 = 1,
22 HAL_PIXEL_FORMAT_RGBX_8888 = 2,
23 HAL_PIXEL_FORMAT_RGB_888 = 3,
24 HAL_PIXEL_FORMAT_RGB_565 = 4,
25 HAL_PIXEL_FORMAT_BGRA_8888 = 5,
26 HAL_PIXEL_FORMAT_RGBA_5551 = 6,
27 HAL_PIXEL_FORMAT_RGBA_4444 = 7,
28};
29
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080030enum {
31 FB_GET_WIDTH = 0x00,
32 FB_GET_HEIGHT = 0x04,
33 FB_INT_STATUS = 0x08,
34 FB_INT_ENABLE = 0x0c,
35 FB_SET_BASE = 0x10,
36 FB_SET_ROTATION = 0x14,
37 FB_SET_BLANK = 0x18,
38 FB_GET_PHYS_WIDTH = 0x1c,
39 FB_GET_PHYS_HEIGHT = 0x20,
40
41 FB_INT_VSYNC = 1U << 0,
42 FB_INT_BASE_UPDATE_DONE = 1U << 1
43};
44
45struct goldfish_fb_state {
46 struct goldfish_device dev;
David 'Digit' Turner055ae422010-07-27 11:34:16 -070047 DisplayState* ds;
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +010048 int pixel_format;
49 int bytes_per_pixel;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080050 uint32_t fb_base;
51 uint32_t base_valid : 1;
52 uint32_t need_update : 1;
53 uint32_t need_int : 1;
54 uint32_t set_rotation : 2;
55 uint32_t blank : 1;
56 uint32_t int_status;
57 uint32_t int_enable;
58 int rotation; /* 0, 1, 2 or 3 */
David 'Digit' Turner055ae422010-07-27 11:34:16 -070059 int dpi;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080060};
61
David 'Digit' Turner055ae422010-07-27 11:34:16 -070062#define GOLDFISH_FB_SAVE_VERSION 2
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080063
64static void goldfish_fb_save(QEMUFile* f, void* opaque)
65{
66 struct goldfish_fb_state* s = opaque;
67
David 'Digit' Turner055ae422010-07-27 11:34:16 -070068 DisplayState* ds = s->ds;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080069
David 'Digit' Turner055ae422010-07-27 11:34:16 -070070 qemu_put_be32(f, ds->surface->width);
71 qemu_put_be32(f, ds->surface->height);
72 qemu_put_be32(f, ds->surface->linesize);
73 qemu_put_byte(f, 0);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080074
75 qemu_put_be32(f, s->fb_base);
76 qemu_put_byte(f, s->base_valid);
77 qemu_put_byte(f, s->need_update);
78 qemu_put_byte(f, s->need_int);
79 qemu_put_byte(f, s->set_rotation);
80 qemu_put_byte(f, s->blank);
81 qemu_put_be32(f, s->int_status);
82 qemu_put_be32(f, s->int_enable);
83 qemu_put_be32(f, s->rotation);
David 'Digit' Turner055ae422010-07-27 11:34:16 -070084 qemu_put_be32(f, s->dpi);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080085}
86
87static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id)
88{
89 struct goldfish_fb_state* s = opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080090 int ret = -1;
91 int ds_w, ds_h, ds_pitch, ds_rot;
92
93 if (version_id != GOLDFISH_FB_SAVE_VERSION)
94 goto Exit;
95
96 ds_w = qemu_get_be32(f);
97 ds_h = qemu_get_be32(f);
98 ds_pitch = qemu_get_be32(f);
99 ds_rot = qemu_get_byte(f);
100
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700101 DisplayState* ds = s->ds;
102
103 if (ds->surface->width != ds_w ||
104 ds->surface->height != ds_h ||
105 ds->surface->linesize != ds_pitch ||
106 ds_rot != 0)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800107 {
108 /* XXX: We should be able to force a resize/rotation from here ? */
109 fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__);
110 goto Exit;
111 }
112
113 s->fb_base = qemu_get_be32(f);
114 s->base_valid = qemu_get_byte(f);
115 s->need_update = qemu_get_byte(f);
116 s->need_int = qemu_get_byte(f);
117 s->set_rotation = qemu_get_byte(f);
118 s->blank = qemu_get_byte(f);
119 s->int_status = qemu_get_be32(f);
120 s->int_enable = qemu_get_be32(f);
121 s->rotation = qemu_get_be32(f);
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700122 s->dpi = qemu_get_be32(f);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800123
124 /* force a refresh */
125 s->need_update = 1;
126
127 ret = 0;
128Exit:
129 return ret;
130}
131
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100132/* Type used to record a mapping from display surface pixel format to
133 * HAL pixel format */
134typedef struct {
135 int pixel_format; /* HAL pixel format */
136 uint8_t bits;
137 uint8_t bytes;
138 uint32_t rmask, gmask, bmask, amask;
139} FbConfig;
140
141
142/* Return the pixel format of the current framebuffer, based on
143 * the current display surface's pixel format.
144 *
145 * Note that you should not call this function from the device initialization
146 * function, because the display surface will change format before the kernel
147 * start.
148 */
149static int goldfish_fb_get_pixel_format(struct goldfish_fb_state *s)
150{
151 if (s->pixel_format >= 0) {
152 return s->pixel_format;
153 }
154 static const FbConfig fb_configs[] = {
155 { HAL_PIXEL_FORMAT_RGB_565, 16, 2, 0xf800, 0x7e0, 0x1f, 0x0 },
156 { -1, }
157 };
158
159 /* Determine HAL pixel format value based on s->ds */
160 struct PixelFormat* pf = &s->ds->surface->pf;
161#if 0
162 printf("%s:%d: display surface,pixel format:\n", __FUNCTION__, __LINE__);
163 printf(" bits/pixel: %d\n", pf->bits_per_pixel);
164 printf(" bytes/pixel: %d\n", pf->bytes_per_pixel);
165 printf(" depth: %d\n", pf->depth);
166 printf(" red: bits=%d mask=0x%x shift=%d max=0x%x\n",
167 pf->rbits, pf->rmask, pf->rshift, pf->rmax);
168 printf(" green: bits=%d mask=0x%x shift=%d max=0x%x\n",
169 pf->gbits, pf->gmask, pf->gshift, pf->gmax);
170 printf(" blue: bits=%d mask=0x%x shift=%d max=0x%x\n",
171 pf->bbits, pf->bmask, pf->bshift, pf->bmax);
172 printf(" alpha: bits=%d mask=0x%x shift=%d max=0x%x\n",
173 pf->abits, pf->amask, pf->ashift, pf->amax);
174
175#endif
176 s->bytes_per_pixel = pf->bytes_per_pixel;
177 int nn;
178 for (nn = 0; fb_configs[nn].pixel_format >= 0; nn++) {
179 const FbConfig* fbc = &fb_configs[nn];
180 if (pf->bits_per_pixel == fbc->bits &&
181 pf->bytes_per_pixel == fbc->bytes &&
182 pf->rmask == fbc->rmask &&
183 pf->gmask == fbc->gmask &&
184 pf->bmask == fbc->bmask &&
185 pf->amask == fbc->amask) {
186 /* We found it */
187 s->pixel_format = fbc->pixel_format;
188 return s->pixel_format;
189 }
190 }
191 fprintf(stderr, "%s:%d: Unsupported display pixel format (depth=%d, bytespp=%d, bitspp=%d)\n",
192 __FUNCTION__, __LINE__,
193 pf->depth,
194 pf->bytes_per_pixel,
195 pf->bits_per_pixel);
196 exit(1);
197 return -1;
198}
199
200static int goldfish_fb_get_bytes_per_pixel(struct goldfish_fb_state *s)
201{
202 if (s->pixel_format < 0) {
203 (void) goldfish_fb_get_pixel_format(s);
204 }
205 return s->bytes_per_pixel;
206}
207
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700208static int
209pixels_to_mm(int pixels, int dpi)
210{
211 /* dpi = dots / inch
212 ** inch = dots / dpi
213 ** mm / 25.4 = dots / dpi
214 ** mm = (dots * 25.4)/dpi
215 */
216 return (int)(0.5 + 25.4 * pixels / dpi);
217}
218
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800219
220#define STATS 0
221
222#if STATS
223static int stats_counter;
224static long stats_total;
225static int stats_full_updates;
226static long stats_total_full_updates;
227#endif
228
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100229/* This structure is used to hold the inputs for
230 * compute_fb_update_rect_linear below.
231 * This corresponds to the source framebuffer and destination
232 * surface pixel buffers.
233 */
234typedef struct {
235 int width;
236 int height;
237 int bytes_per_pixel;
238 const uint8_t* src_pixels;
239 int src_pitch;
240 uint8_t* dst_pixels;
241 int dst_pitch;
242} FbUpdateState;
243
244/* This structure is used to hold the outputs for
245 * compute_fb_update_rect_linear below.
246 * This corresponds to the smalled bounding rectangle of the
247 * latest framebuffer update.
248 */
249typedef struct {
250 int xmin, ymin, xmax, ymax;
251} FbUpdateRect;
252
253/* Determine the smallest bounding rectangle of pixels which changed
254 * between the source (framebuffer) and destination (surface) pixel
255 * buffers.
256 *
257 * Return 0 if there was no change, otherwise, populate '*rect'
258 * and return 1.
259 *
260 * If 'dirty_base' is not 0, it is a physical address that will be
261 * used to speed-up the check using the VGA dirty bits. In practice
262 * this is only used if your kernel driver does not implement.
263 *
264 * This function assumes that the framebuffers are in linear memory.
265 * This may change later when we want to support larger framebuffers
266 * that exceed the max DMA aperture size though.
267 */
268static int
269compute_fb_update_rect_linear(FbUpdateState* fbs,
270 uint32_t dirty_base,
271 FbUpdateRect* rect)
272{
273 int yy;
274 int width = fbs->width;
275 const uint8_t* src_line = fbs->src_pixels;
276 uint8_t* dst_line = fbs->dst_pixels;
277 uint32_t dirty_addr = dirty_base;
278 rect->xmin = rect->ymin = INT_MAX;
279 rect->xmax = rect->ymax = INT_MIN;
280 for (yy = 0; yy < fbs->height; yy++) {
281 int xx1, xx2;
282 /* If dirty_addr is != 0, then use it as a physical address to
283 * use the VGA dirty bits table to speed up the detection of
284 * changed pixels.
285 */
286 if (dirty_addr != 0) {
287 int dirty = 0;
288 int len = fbs->src_pitch;
289
290 while (len > 0) {
291 int len2 = TARGET_PAGE_SIZE - (dirty_addr & (TARGET_PAGE_SIZE-1));
292
293 if (len2 > len)
294 len2 = len;
295
296 dirty |= cpu_physical_memory_get_dirty(dirty_addr, VGA_DIRTY_FLAG);
297 dirty_addr += len2;
298 len -= len2;
299 }
300
301 if (!dirty) { /* this line was not modified, skip to next one */
302 goto NEXT_LINE;
303 }
304 }
305
306 /* Then compute actual bounds of the changed pixels, while
307 * copying them from 'src' to 'dst'. This depends on the pixel depth.
308 */
309 switch (fbs->bytes_per_pixel) {
310 case 2:
311 {
312 const uint16_t* src = (const uint16_t*) src_line;
313 uint16_t* dst = (uint16_t*) dst_line;
314
315 for (xx1 = 0; xx1 < width; xx1++) {
316 if (src[xx1] != dst[xx1]) {
317 break;
318 }
319 }
320 if (xx1 == width) {
321 break;
322 }
323 for (xx2 = width-1; xx2 > xx1; xx2--) {
324 if (src[xx2] != dst[xx2]) {
325 break;
326 }
327 }
328#if HOST_WORDS_BIGENDIAN
329 /* Convert the guest little-endian pixels into big-endian ones */
330 int xx = xx1;
331 for ( ; xx <= xx2; xx++ ) {
332 unsigned spix = src[xx];
333 dst[xx] = (uint16_t)((spix << 8) | (spix >> 8));
334 }
335#else
336 memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*2 );
337#endif
338 break;
339 }
340
341 case 3:
342 {
343 for (xx1 = 0; xx1 < width; xx1 += 1) {
344 int xx = xx1*3;
345 if (src_line[xx+0] != dst_line[xx+0] ||
346 src_line[xx+1] != dst_line[xx+1] ||
347 src_line[xx+2] != dst_line[xx+2]) {
348 break;
349 }
350 }
351 if (xx1 == width) {
352 break;
353 }
354 for (xx2 = width-1; xx2 > xx1; xx2--) {
355 int xx = xx2*3;
356 if (src_line[xx+0] != dst_line[xx+0] ||
357 src_line[xx+1] != dst_line[xx+1] ||
358 src_line[xx+2] != dst_line[xx+2]) {
359 break;
360 }
361 }
362 memcpy( dst_line+xx1*3, src_line+xx1*3, (xx2-xx1+1)*3 );
363 break;
364 }
365
366 case 4:
367 {
368 const uint32_t* src = (const uint32_t*) src_line;
369 uint32_t* dst = (uint32_t*) dst_line;
370
371 for (xx1 = 0; xx1 < width; xx1++) {
372 if (src[xx1] != dst[xx1]) {
373 break;
374 }
375 }
376 if (xx1 == width) {
377 break;
378 }
379 for (xx2 = width-1; xx2 > xx1; xx2--) {
380 if (src[xx2] != dst[xx2]) {
381 break;
382 }
383 }
384#if HOST_WORDS_BIGENDIAN
385 /* Convert the guest little-endian pixels into big-endian ones */
386 int xx = xx1;
387 for ( ; xx <= xx2; xx++ ) {
388 uint32_t spix = src[xx];
389 spix = (spix << 16) | (spix >> 16);
390 spix = ((spix << 8) & 0xff00ff00) | ((spix >> 8) & 0x00ff00ff);
391 dst[xx] = spix;
392 }
393#else
394 memcpy( dst+xx1, src+xx1, (xx2-xx1+1)*4 );
395#endif
396 break;
397 }
398 default:
399 return 0;
400 }
401 /* Update bounds if pixels on this line were modified */
402 if (xx1 < width) {
403 if (xx1 < rect->xmin) rect->xmin = xx1;
404 if (xx2 > rect->xmax) rect->xmax = xx2;
405 if (yy < rect->ymin) rect->ymin = yy;
406 if (yy > rect->ymax) rect->ymax = yy;
407 }
408 NEXT_LINE:
409 src_line += fbs->src_pitch;
410 dst_line += fbs->dst_pitch;
411 }
412
413 if (rect->ymin > rect->ymax) { /* nothing changed */
414 return 0;
415 }
416
417 /* Always clear the dirty VGA bits */
418 cpu_physical_memory_reset_dirty(dirty_base + rect->ymin * fbs->src_pitch,
419 dirty_base + (rect->ymax+1)* fbs->src_pitch,
420 VGA_DIRTY_FLAG);
421 return 1;
422}
423
424
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800425static void goldfish_fb_update_display(void *opaque)
426{
427 struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800428 uint32_t base;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800429 uint8_t* dst_line;
430 uint8_t* src_line;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800431 int full_update = 0;
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100432 int width, height, pitch;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800433
434 base = s->fb_base;
435 if(base == 0)
436 return;
437
438 if((s->int_enable & FB_INT_VSYNC) && !(s->int_status & FB_INT_VSYNC)) {
439 s->int_status |= FB_INT_VSYNC;
440 goldfish_device_set_irq(&s->dev, 0, 1);
441 }
442
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800443 if(s->need_update) {
444 full_update = 1;
445 if(s->need_int) {
446 s->int_status |= FB_INT_BASE_UPDATE_DONE;
447 if(s->int_enable & FB_INT_BASE_UPDATE_DONE)
448 goldfish_device_set_irq(&s->dev, 0, 1);
449 }
450 s->need_int = 0;
451 s->need_update = 0;
452 }
453
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700454 src_line = qemu_get_ram_ptr( base );
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700455
456 dst_line = s->ds->surface->data;
457 pitch = s->ds->surface->linesize;
458 width = s->ds->surface->width;
459 height = s->ds->surface->height;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800460
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100461 FbUpdateState fbs;
462 FbUpdateRect rect;
463
464 fbs.width = width;
465 fbs.height = height;
466 fbs.dst_pixels = dst_line;
467 fbs.dst_pitch = pitch;
468 fbs.bytes_per_pixel = goldfish_fb_get_bytes_per_pixel(s);
469
470 fbs.src_pixels = src_line;
471 fbs.src_pitch = width*s->ds->surface->pf.bytes_per_pixel;
472
473
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800474#if STATS
475 if (full_update)
476 stats_full_updates += 1;
477 if (++stats_counter == 120) {
478 stats_total += stats_counter;
479 stats_total_full_updates += stats_full_updates;
480
481 printf( "full update stats: peak %.2f %% total %.2f %%\n",
482 stats_full_updates*100.0/stats_counter,
483 stats_total_full_updates*100.0/stats_total );
484
485 stats_counter = 0;
486 stats_full_updates = 0;
487 }
488#endif /* STATS */
489
490 if (s->blank)
491 {
492 memset( dst_line, 0, height*pitch );
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100493 rect.xmin = 0;
494 rect.ymin = 0;
495 rect.xmax = width-1;
496 rect.ymax = height-1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800497 }
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100498 else
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800499 {
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100500 if (full_update) { /* don't use dirty-bits optimization */
501 base = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800502 }
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100503 if (compute_fb_update_rect_linear(&fbs, base, &rect) == 0) {
504 return;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800505 }
506 }
507
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100508 rect.xmax += 1;
509 rect.ymax += 1;
510#if 0
511 printf("goldfish_fb_update_display (y:%d,h:%d,x=%d,w=%d)\n",
512 rect.ymin, rect.ymax-rect.ymin, rect.xmin, rect.xmax-rect.xmin);
513#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800514
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100515 dpy_update(s->ds, rect.xmin, rect.ymin, rect.xmax-rect.xmin, rect.ymax-rect.ymin);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800516}
517
518static void goldfish_fb_invalidate_display(void * opaque)
519{
520 // is this called?
521 struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
522 s->need_update = 1;
523}
524
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800525static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset)
526{
527 uint32_t ret;
528 struct goldfish_fb_state *s = opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700529
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800530 switch(offset) {
531 case FB_GET_WIDTH:
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700532 ret = ds_get_width(s->ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800533 //printf("FB_GET_WIDTH => %d\n", ret);
534 return ret;
535
536 case FB_GET_HEIGHT:
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700537 ret = ds_get_height(s->ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800538 //printf( "FB_GET_HEIGHT = %d\n", ret);
539 return ret;
540
541 case FB_INT_STATUS:
542 ret = s->int_status & s->int_enable;
543 if(ret) {
544 s->int_status &= ~ret;
545 goldfish_device_set_irq(&s->dev, 0, 0);
546 }
547 return ret;
548
549 case FB_GET_PHYS_WIDTH:
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700550 ret = pixels_to_mm( ds_get_width(s->ds), s->dpi );
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800551 //printf( "FB_GET_PHYS_WIDTH => %d\n", ret );
552 return ret;
553
554 case FB_GET_PHYS_HEIGHT:
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700555 ret = pixels_to_mm( ds_get_height(s->ds), s->dpi );
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800556 //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret );
557 return ret;
558
559 default:
560 cpu_abort (cpu_single_env, "goldfish_fb_read: Bad offset %x\n", offset);
561 return 0;
562 }
563}
564
565static void goldfish_fb_write(void *opaque, target_phys_addr_t offset,
566 uint32_t val)
567{
568 struct goldfish_fb_state *s = opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700569
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800570 switch(offset) {
571 case FB_INT_ENABLE:
572 s->int_enable = val;
573 goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
574 break;
575 case FB_SET_BASE: {
576 int need_resize = !s->base_valid;
577 s->fb_base = val;
578 s->int_status &= ~FB_INT_BASE_UPDATE_DONE;
579 s->need_update = 1;
580 s->need_int = 1;
581 s->base_valid = 1;
582 if(s->set_rotation != s->rotation) {
583 //printf("FB_SET_BASE: rotation : %d => %d\n", s->rotation, s->set_rotation);
584 s->rotation = s->set_rotation;
585 need_resize = 1;
586 }
587 goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
588 if (need_resize) {
589 //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation );
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700590 dpy_resize(s->ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800591 }
592 } break;
593 case FB_SET_ROTATION:
594 //printf( "FB_SET_ROTATION %d\n", val);
595 s->set_rotation = val;
596 break;
597 case FB_SET_BLANK:
598 s->blank = val;
599 s->need_update = 1;
600 break;
601 default:
602 cpu_abort (cpu_single_env, "goldfish_fb_write: Bad offset %x\n", offset);
603 }
604}
605
606static CPUReadMemoryFunc *goldfish_fb_readfn[] = {
607 goldfish_fb_read,
608 goldfish_fb_read,
609 goldfish_fb_read
610};
611
612static CPUWriteMemoryFunc *goldfish_fb_writefn[] = {
613 goldfish_fb_write,
614 goldfish_fb_write,
615 goldfish_fb_write
616};
617
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700618void goldfish_fb_init(int id)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800619{
620 struct goldfish_fb_state *s;
621
622 s = (struct goldfish_fb_state *)qemu_mallocz(sizeof(*s));
623 s->dev.name = "goldfish_fb";
624 s->dev.id = id;
625 s->dev.size = 0x1000;
626 s->dev.irq_count = 1;
627
David 'Digit' Turner055ae422010-07-27 11:34:16 -0700628 s->ds = graphic_console_init(goldfish_fb_update_display,
629 goldfish_fb_invalidate_display,
630 NULL,
631 NULL,
632 s);
633
634 s->dpi = 165; /* XXX: Find better way to get actual value ! */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800635
David 'Digit' Turnerd8a3d5c2011-01-16 01:05:43 +0100636 /* IMPORTANT: DO NOT COMPUTE s->pixel_format and s->bytes_per_pixel
637 * here because the display surface is going to change later.
638 */
639 s->bytes_per_pixel = 0;
640 s->pixel_format = -1;
641
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800642 goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s);
643
644 register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION,
645 goldfish_fb_save, goldfish_fb_load, s);
646}