blob: c54403ec9380f8a1271fbbc0459c592604309bc8 [file] [log] [blame]
The Android Open Source Project52d4c302009-03-03 19:29:09 -08001/*
2 * Copyright 2007 The Android Open Source Project
3 *
4 * Fake device support.
5 */
6#include "Common.h"
7
8#include <stdlib.h>
9#include <string.h>
10#include <assert.h>
11
12#include <sys/mman.h>
13#include <sys/ioctl.h>
14#include <linux/fb.h>
15
16typedef struct FbState {
17 /* index into gWrapSim.display[] */
18 int displayIdx;
19
20 /* VRAM address, set by mmap() call */
21 void* vramAddr;
22
23 /* kernel data structures */
24 struct fb_var_screeninfo vinfo;
25 struct fb_fix_screeninfo finfo;
26} FbState;
27
28
29/*
30 * Set up the initial values of the structs.
31 *
32 * The FbState struct is zeroed out initially, so we only need to set the
33 * fields that don't default to zero.
34 */
35static void configureInitialState(int displayIdx, FbState* fbState)
36{
37 int width, height;
38
39 assert(displayIdx >= 0 && displayIdx < gWrapSim.numDisplays);
40
41 width = gWrapSim.display[displayIdx].width;
42 height = gWrapSim.display[displayIdx].height;
43 wsLog("Configuring FbState for display %d (%dx%x key=0x%08x)\n",
44 displayIdx, width, height, gWrapSim.display[displayIdx].shmemKey);
45
46 /* fb_fix_screeninfo */
47 strcpy(fbState->finfo.id, "omapfb");
48 fbState->finfo.smem_len = (width * 2) * height * 2;
49 fbState->finfo.line_length = width * 2;
50
51 /* fb_var_screeninfo */
52 fbState->vinfo.xres = width;
53 fbState->vinfo.yres = height;
54 fbState->vinfo.xres_virtual = width;
55 fbState->vinfo.yres_virtual = height * 2;
56 fbState->vinfo.bits_per_pixel = 16;
57
58 fbState->vinfo.red.offset = 11;
59 fbState->vinfo.red.length = 5;
60 fbState->vinfo.green.offset = 5;
61 fbState->vinfo.green.length = 6;
62 fbState->vinfo.blue.offset = 0;
63 fbState->vinfo.blue.length = 5;
64
65 fbState->vinfo.width = 51; // physical dimension, used for dpi
66 fbState->vinfo.height = 76;
67
68 fbState->vinfo.pixclock = 103092;
69 fbState->vinfo.upper_margin = 3;
70 fbState->vinfo.lower_margin = 227;
71 fbState->vinfo.left_margin = 12;
72 fbState->vinfo.right_margin = 8;
73}
74
75/*
76 * Free allocated state.
77 */
78static void freeState(FbState* fbState)
79{
80 free(fbState);
81}
82
83/*
84 * Wait for our synthetic vsync to happen.
85 */
86static void waitForVsync(FbState* state)
87{
88 /* TODO: simulate a real interval */
89 usleep(1000000/60);
90}
91
92/*
93 * Forward pixels to the simulator.
94 */
95static void sendPixelsToSim(FbState* state)
96{
97 if (state->vramAddr == 0) {
98 wsLog("## not sending pixels (no addr yet)\n");
99 return;
100 }
101
102 //wsLog("+++ sending pixels to sim (disp=%d yoff=%d)\n",
103 // state->displayIdx, state->vinfo.yoffset);
104
105 wsLockDisplay(state->displayIdx);
106
107 uint8_t* dst = gWrapSim.display[state->displayIdx].addr;
108
109 int l,t,r,b,w,h;
110 w = gWrapSim.display[state->displayIdx].width;
111 h = gWrapSim.display[state->displayIdx].height;
112
113#if 0
114 /*
115 * TODO: surfaceflinger encodes the dirty region in vinfo.reserved[]. We
116 * can use that to perform a partial update.
117 */
118 const Rect dirty(dirtyReg.bounds());
119 l = dirty.left >=0 ? dirty.left : 0;
120 t = dirty.top >=0 ? dirty.top : 0;
121 r = dirty.right <=w ? dirty.right : w;
122 b = dirty.bottom<=h ? dirty.bottom : h;
123#else
124 l = t = 0;
125 r = w;
126 b = h;
127#endif
128
129 /* find the right page */
130 int ypage = state->vinfo.yoffset;
131
132 int x, y;
133 for (y = t ; y < b ; y++) {
134 // no "stride" issues with this display
135 uint8_t* outPtr = dst + (y*w+l)*3;
136 const uint16_t* ptr16 = (uint16_t*)state->vramAddr + ((y+ypage)*w+l);
137 for (x = l; x < r; x++) {
138 uint16_t in = *ptr16++;
139 uint32_t R,G,B;
140 R = ((in>>8)&0xF8) | (in>>(8+5));
141 G = (in & 0x7E0)>>3;
142 G |= G>>6;
143 B = (in & 0x1F)<<3;
144 B |= B>>5;
145 *outPtr++ = R;
146 *outPtr++ = G;
147 *outPtr++ = B;
148 }
149 }
150
151 wsUnlockDisplay(state->displayIdx);
152
153 /* notify the simulator */
154 wsPostDisplayUpdate(state->displayIdx);
155}
156
157/*
158 * Provide a memory-mapped region for framebuffer data. We want to use a
159 * real mmap() call, not fake it with a malloc, so that related calls
160 * (munmap, madvise) will just work.
161 */
162static void* mmapFb(FakeDev* dev, void* start, size_t length, int prot,
163 int flags, int fd, __off_t offset)
164{
165 FbState* state = (FbState*) dev->state;
166 void* map;
167
168 /* be reasonable */
169 if (length > (640*480*2)*4) {
170 errno = EINVAL;
171 return MAP_FAILED;
172 }
173
174 /* this is supposed to be VRAM, so just map a chunk */
175 map = mmap(start, length, prot, MAP_PRIVATE | MAP_ANON, -1, 0);
176
177 /* update our "VRAM address"; this feels a bit fragile */
178 if (state->vramAddr != NULL) {
179 wsLog("%s: NOTE: changing vram address from %p\n",
180 dev->debugName, state->vramAddr);
181 }
182 state->vramAddr = map;
183
184 wsLog("%s: mmap %u bytes --> %p\n", dev->debugName, length, map);
185 return map;
186}
187
188/*
189 * Handle framebuffer ioctls.
190 */
191static int ioctlFb(FakeDev* dev, int fd, int request, void* argp)
192{
193 FbState* state = (FbState*) dev->state;
194
195 wsLog("%s: ioctl(0x%x, %p)\n", dev->debugName, request, argp);
196
197 switch (request) {
198 case FBIOGET_FSCREENINFO: // struct fb_fix_screeninfo*
199 memcpy(argp, &state->finfo, sizeof(struct fb_fix_screeninfo));
200 break;
201 case FBIOGET_VSCREENINFO: // struct fb_var_screeninfo*
202 memcpy(argp, &state->vinfo, sizeof(struct fb_var_screeninfo));
203 break;
204 case FBIOPUT_VSCREENINFO: // struct fb_var_screeninfo*
205 memcpy(&state->vinfo, argp, sizeof(struct fb_var_screeninfo));
206 if (state->vinfo.activate == FB_ACTIVATE_NOW) {
207 //wsLog("%s: activate now\n", dev->debugName);
208 sendPixelsToSim(state);
209 } else if (state->vinfo.activate == FB_ACTIVATE_VBL) {
210 //wsLog("%s: activate on VBL\n", dev->debugName);
211 sendPixelsToSim(state);
212 /* we wait *after* so other process gets scheduled to draw */
213 waitForVsync(state);
214 } else {
215 wsLog("%s: activate value is %d\n",
216 dev->debugName, state->vinfo.activate);
217 }
218 break;
219 case FBIOGET_VBLANK: // struct fb_vblank*
220 /* the device doesn't actually implement this */
221 //memset(argp, 0, sizeof(struct fb_vblank));
222 errno = EINVAL;
223 return -1;
224 default:
225 /*case FBIO_WAITFORVSYNC:*/
226 wsLog("GLITCH: UNKNOWN ioctl request 0x%x on %s\n",
227 request, dev->debugName);
228 return -1;
229 }
230
231 return 0;
232}
233
234/*
235 * Free up our state before closing down the fake descriptor.
236 */
237static int closeFb(FakeDev* dev, int fd)
238{
239 freeState((FbState*)dev->state);
240 dev->state = NULL;
241 return 0;
242}
243
244/*
245 * Open the console TTY device, which responds to a collection of ioctl()s.
246 */
247FakeDev* wsOpenDevFb(const char* pathName, int flags)
248{
249 FakeDev* newDev = wsCreateFakeDev(pathName);
250 if (newDev != NULL) {
251 newDev->mmap = mmapFb;
252 newDev->ioctl = ioctlFb;
253 newDev->close = closeFb;
254
255 FbState* fbState = calloc(1, sizeof(FbState));
256
257 /* establish a connection to the front-end if necessary */
258 /* (also gets display configuration) */
259 wsSimConnect();
260
261 configureInitialState(0, fbState); // always use display 0 for now
262 newDev->state = fbState;
263 }
264
265 return newDev;
266}
267