Commit | Line | Data |
---|---|---|
2480eccc RSZ |
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 <sys/mman.h> | |
18 | ||
19 | #include <dlfcn.h> | |
20 | ||
21 | #include <cutils/ashmem.h> | |
22 | #include <cutils/log.h> | |
23 | ||
24 | #include <hardware/hardware.h> | |
25 | #include <hardware/gralloc.h> | |
26 | ||
27 | #include <fcntl.h> | |
28 | #include <errno.h> | |
29 | #include <sys/ioctl.h> | |
30 | #include <string.h> | |
31 | #include <stdlib.h> | |
32 | ||
33 | #include <utils/Vector.h> | |
34 | ||
35 | #include <cutils/log.h> | |
36 | #include <cutils/atomic.h> | |
37 | ||
38 | #if HAVE_ANDROID_OS | |
39 | #include <linux/fb.h> | |
40 | #endif | |
41 | ||
42 | #include "gralloc_priv.h" | |
2480eccc RSZ |
43 | |
44 | /*****************************************************************************/ | |
45 | ||
46 | // numbers of buffers for page flipping | |
47 | #define NUM_BUFFERS 2 | |
48 | ||
49 | struct hwc_callback_entry | |
50 | { | |
51 | void (*callback)(void *, private_handle_t *); | |
52 | void *data; | |
53 | }; | |
54 | ||
55 | typedef android::Vector<struct hwc_callback_entry> hwc_callback_queue_t; | |
56 | ||
57 | struct fb_context_t { | |
58 | framebuffer_device_t device; | |
59 | }; | |
60 | ||
61 | /*****************************************************************************/ | |
62 | ||
63 | static int fb_setSwapInterval(struct framebuffer_device_t* dev, | |
64 | int interval) | |
65 | { | |
66 | fb_context_t* ctx = (fb_context_t*)dev; | |
67 | if (interval < dev->minSwapInterval || interval > dev->maxSwapInterval) | |
68 | return -EINVAL; | |
69 | // FIXME: implement fb_setSwapInterval | |
70 | return 0; | |
71 | } | |
72 | ||
73 | static int fb_post(struct framebuffer_device_t* dev, buffer_handle_t buffer) | |
74 | { | |
75 | if (private_handle_t::validate(buffer) < 0) | |
76 | return -EINVAL; | |
77 | ||
78 | private_handle_t const* hnd = reinterpret_cast<private_handle_t const*>(buffer); | |
79 | private_module_t* m = reinterpret_cast<private_module_t*>(dev->common.module); | |
80 | ||
81 | hwc_callback_queue_t *queue = reinterpret_cast<hwc_callback_queue_t *>(m->queue); | |
82 | pthread_mutex_lock(&m->queue_lock); | |
83 | if(queue->isEmpty()) | |
84 | pthread_mutex_unlock(&m->queue_lock); | |
85 | else { | |
86 | private_handle_t *hnd = private_handle_t::dynamicCast(buffer); | |
87 | struct hwc_callback_entry entry = queue->top(); | |
88 | queue->pop(); | |
89 | pthread_mutex_unlock(&m->queue_lock); | |
90 | entry.callback(entry.data, hnd); | |
91 | } | |
92 | ||
93 | return 0; | |
94 | } | |
95 | ||
96 | /*****************************************************************************/ | |
97 | ||
98 | static int fb_close(struct hw_device_t *dev) | |
99 | { | |
100 | fb_context_t* ctx = (fb_context_t*)dev; | |
101 | if (ctx) { | |
102 | free(ctx); | |
103 | } | |
104 | return 0; | |
105 | } | |
106 | ||
9d35e001 DZ |
107 | static void get_screen_res(const char *fbname, int32_t *xres, int32_t *yres, |
108 | int32_t *refresh) | |
109 | { | |
110 | char *path; | |
111 | int fd; | |
112 | char buf[128]; | |
113 | int ret; | |
114 | unsigned int _x, _y, _r; | |
115 | ||
116 | asprintf(&path, "/sys/class/graphics/%s/modes", fbname); | |
117 | if (!path) | |
118 | goto err_asprintf; | |
119 | fd = open(path, O_RDONLY); | |
120 | if (fd < 0) | |
121 | goto err_open; | |
122 | ret = read(fd, buf, sizeof(buf)); | |
123 | if (ret <= 0) | |
124 | goto err_read; | |
125 | buf[sizeof(buf)-1] = '\0'; | |
126 | ||
127 | ret = sscanf(buf, "U:%ux%up-%u", &_x, &_y, &_r); | |
128 | if (ret != 3) | |
129 | goto err_sscanf; | |
130 | ||
131 | ALOGI("Using %ux%u %uHz resolution for '%s' from modes list\n", | |
132 | _x, _y, _r, fbname); | |
133 | ||
134 | *xres = (int32_t)_x; | |
135 | *yres = (int32_t)_y; | |
136 | *refresh = (int32_t)_r; | |
137 | ||
138 | close(fd); | |
139 | free(path); | |
140 | return; | |
141 | ||
142 | err_sscanf: | |
143 | err_read: | |
144 | close(fd); | |
145 | err_open: | |
146 | free(path); | |
147 | err_asprintf: | |
148 | *xres = 2560; | |
149 | *yres = 1600; | |
150 | *refresh = 60; | |
151 | } | |
152 | ||
2480eccc RSZ |
153 | int init_fb(struct private_module_t* module) |
154 | { | |
155 | char const * const device_template[] = { | |
156 | "/dev/graphics/fb%u", | |
157 | "/dev/fb%u", | |
158 | NULL | |
159 | }; | |
160 | ||
161 | int fd = -1; | |
162 | int i = 0; | |
163 | char name[64]; | |
164 | ||
165 | fd = open("/dev/graphics/fb0", O_RDWR); | |
166 | if (fd < 0) { | |
167 | ALOGE("/dev/graphics/fb0 Open fail"); | |
168 | return -errno; | |
169 | } | |
170 | ||
171 | struct fb_fix_screeninfo finfo; | |
172 | if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) { | |
173 | ALOGE("Fail to get FB Screen Info"); | |
174 | return -errno; | |
175 | } | |
176 | ||
177 | struct fb_var_screeninfo info; | |
178 | if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1) { | |
179 | ALOGE("First, Fail to get FB VScreen Info"); | |
180 | return -errno; | |
181 | } | |
182 | ||
9d35e001 DZ |
183 | int32_t refreshRate; |
184 | get_screen_res("fb0", &module->xres, &module->yres, &refreshRate); | |
2480eccc | 185 | if (refreshRate == 0) |
9d35e001 | 186 | refreshRate = 60; /* 60 Hz */ |
2480eccc | 187 | |
9d35e001 DZ |
188 | float xdpi = (module->xres * 25.4f) / info.width; |
189 | float ydpi = (module->yres * 25.4f) / info.height; | |
2480eccc RSZ |
190 | |
191 | ALOGI("using (id=%s)\n" | |
192 | "xres = %d px\n" | |
193 | "yres = %d px\n" | |
194 | "width = %d mm (%f dpi)\n" | |
195 | "height = %d mm (%f dpi)\n" | |
196 | "refresh rate = %.2f Hz\n", | |
9d35e001 DZ |
197 | finfo.id, module->xres, module->yres, info.width, xdpi, info.height, |
198 | ydpi, (float)refreshRate); | |
2480eccc | 199 | |
9d35e001 | 200 | module->line_length = module->xres * 4; |
2480eccc RSZ |
201 | module->xdpi = xdpi; |
202 | module->ydpi = ydpi; | |
9d35e001 | 203 | module->fps = (float)refreshRate; |
2480eccc RSZ |
204 | |
205 | return 0; | |
206 | } | |
207 | ||
208 | int fb_device_open(hw_module_t const* module, const char* name, | |
209 | hw_device_t** device) | |
210 | { | |
211 | int status = -EINVAL; | |
212 | #ifdef GRALLOC_16_BITS | |
213 | int bits_per_pixel = 16; | |
214 | int format = HAL_PIXEL_FORMAT_RGB_565; | |
215 | #else | |
216 | int bits_per_pixel = 32; | |
217 | int format = HAL_PIXEL_FORMAT_RGBA_8888; | |
218 | #endif | |
219 | ||
220 | alloc_device_t* gralloc_device; | |
221 | status = gralloc_open(module, &gralloc_device); | |
222 | if (status < 0) { | |
223 | ALOGE("Fail to Open gralloc device"); | |
224 | return status; | |
225 | } | |
226 | ||
227 | framebuffer_device_t *dev = (framebuffer_device_t *)malloc(sizeof(framebuffer_device_t)); | |
228 | if (dev == NULL) { | |
229 | ALOGE("Failed to allocate memory for dev"); | |
230 | gralloc_close(gralloc_device); | |
231 | return status; | |
232 | } | |
233 | ||
234 | private_module_t* m = (private_module_t*)module; | |
235 | status = init_fb(m); | |
236 | if (status < 0) { | |
237 | ALOGE("Fail to init framebuffer"); | |
238 | free(dev); | |
239 | gralloc_close(gralloc_device); | |
240 | return status; | |
241 | } | |
242 | ||
243 | /* initialize our state here */ | |
244 | memset(dev, 0, sizeof(*dev)); | |
245 | ||
246 | /* initialize the procs */ | |
247 | dev->common.tag = HARDWARE_DEVICE_TAG; | |
248 | dev->common.version = 0; | |
249 | dev->common.module = const_cast<hw_module_t*>(module); | |
250 | dev->common.close = fb_close; | |
251 | dev->setSwapInterval = 0; | |
252 | dev->post = fb_post; | |
253 | dev->setUpdateRect = 0; | |
254 | dev->compositionComplete = 0; | |
255 | m->queue = new hwc_callback_queue_t; | |
256 | pthread_mutex_init(&m->queue_lock, NULL); | |
257 | ||
258 | int stride = m->line_length / (bits_per_pixel >> 3); | |
259 | const_cast<uint32_t&>(dev->flags) = 0; | |
260 | const_cast<uint32_t&>(dev->width) = m->xres; | |
261 | const_cast<uint32_t&>(dev->height) = m->yres; | |
262 | const_cast<int&>(dev->stride) = stride; | |
263 | const_cast<int&>(dev->format) = format; | |
264 | const_cast<float&>(dev->xdpi) = m->xdpi; | |
265 | const_cast<float&>(dev->ydpi) = m->ydpi; | |
266 | const_cast<float&>(dev->fps) = m->fps; | |
267 | const_cast<int&>(dev->minSwapInterval) = 1; | |
268 | const_cast<int&>(dev->maxSwapInterval) = 1; | |
269 | *device = &dev->common; | |
270 | status = 0; | |
271 | ||
272 | return status; | |
273 | } |