diff options
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-ioctl.c')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c new file mode 100644 index 000000000000..4c4bafdfaa43 --- /dev/null +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
@@ -0,0 +1,755 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/omap2/omapfb-ioctl.c | ||
3 | * | ||
4 | * Copyright (C) 2008 Nokia Corporation | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
6 | * | ||
7 | * Some code and ideas taken from drivers/video/omap/ driver | ||
8 | * by Imre Deak. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License version 2 as published by | ||
12 | * the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along with | ||
20 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
21 | */ | ||
22 | |||
23 | #include <linux/fb.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/uaccess.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/omapfb.h> | ||
29 | #include <linux/vmalloc.h> | ||
30 | |||
31 | #include <plat/display.h> | ||
32 | #include <plat/vrfb.h> | ||
33 | #include <plat/vram.h> | ||
34 | |||
35 | #include "omapfb.h" | ||
36 | |||
37 | static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
38 | { | ||
39 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
40 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
41 | struct omap_overlay *ovl; | ||
42 | struct omap_overlay_info info; | ||
43 | int r = 0; | ||
44 | |||
45 | DBG("omapfb_setup_plane\n"); | ||
46 | |||
47 | if (ofbi->num_overlays != 1) { | ||
48 | r = -EINVAL; | ||
49 | goto out; | ||
50 | } | ||
51 | |||
52 | /* XXX uses only the first overlay */ | ||
53 | ovl = ofbi->overlays[0]; | ||
54 | |||
55 | if (pi->enabled && !ofbi->region.size) { | ||
56 | /* | ||
57 | * This plane's memory was freed, can't enable it | ||
58 | * until it's reallocated. | ||
59 | */ | ||
60 | r = -EINVAL; | ||
61 | goto out; | ||
62 | } | ||
63 | |||
64 | ovl->get_overlay_info(ovl, &info); | ||
65 | |||
66 | info.pos_x = pi->pos_x; | ||
67 | info.pos_y = pi->pos_y; | ||
68 | info.out_width = pi->out_width; | ||
69 | info.out_height = pi->out_height; | ||
70 | info.enabled = pi->enabled; | ||
71 | |||
72 | r = ovl->set_overlay_info(ovl, &info); | ||
73 | if (r) | ||
74 | goto out; | ||
75 | |||
76 | if (ovl->manager) { | ||
77 | r = ovl->manager->apply(ovl->manager); | ||
78 | if (r) | ||
79 | goto out; | ||
80 | } | ||
81 | |||
82 | out: | ||
83 | if (r) | ||
84 | dev_err(fbdev->dev, "setup_plane failed\n"); | ||
85 | return r; | ||
86 | } | ||
87 | |||
88 | static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
89 | { | ||
90 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
91 | |||
92 | if (ofbi->num_overlays != 1) { | ||
93 | memset(pi, 0, sizeof(*pi)); | ||
94 | } else { | ||
95 | struct omap_overlay_info *ovli; | ||
96 | struct omap_overlay *ovl; | ||
97 | |||
98 | ovl = ofbi->overlays[0]; | ||
99 | ovli = &ovl->info; | ||
100 | |||
101 | pi->pos_x = ovli->pos_x; | ||
102 | pi->pos_y = ovli->pos_y; | ||
103 | pi->enabled = ovli->enabled; | ||
104 | pi->channel_out = 0; /* xxx */ | ||
105 | pi->mirror = 0; | ||
106 | pi->out_width = ovli->out_width; | ||
107 | pi->out_height = ovli->out_height; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
114 | { | ||
115 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
116 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
117 | struct omapfb2_mem_region *rg; | ||
118 | int r, i; | ||
119 | size_t size; | ||
120 | |||
121 | if (mi->type > OMAPFB_MEMTYPE_MAX) | ||
122 | return -EINVAL; | ||
123 | |||
124 | size = PAGE_ALIGN(mi->size); | ||
125 | |||
126 | rg = &ofbi->region; | ||
127 | |||
128 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
129 | if (ofbi->overlays[i]->info.enabled) | ||
130 | return -EBUSY; | ||
131 | } | ||
132 | |||
133 | if (rg->size != size || rg->type != mi->type) { | ||
134 | r = omapfb_realloc_fbmem(fbi, size, mi->type); | ||
135 | if (r) { | ||
136 | dev_err(fbdev->dev, "realloc fbmem failed\n"); | ||
137 | return r; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
145 | { | ||
146 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
147 | struct omapfb2_mem_region *rg; | ||
148 | |||
149 | rg = &ofbi->region; | ||
150 | memset(mi, 0, sizeof(*mi)); | ||
151 | |||
152 | mi->size = rg->size; | ||
153 | mi->type = rg->type; | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int omapfb_update_window_nolock(struct fb_info *fbi, | ||
159 | u32 x, u32 y, u32 w, u32 h) | ||
160 | { | ||
161 | struct omap_dss_device *display = fb2display(fbi); | ||
162 | u16 dw, dh; | ||
163 | |||
164 | if (!display) | ||
165 | return 0; | ||
166 | |||
167 | if (w == 0 || h == 0) | ||
168 | return 0; | ||
169 | |||
170 | display->get_resolution(display, &dw, &dh); | ||
171 | |||
172 | if (x + w > dw || y + h > dh) | ||
173 | return -EINVAL; | ||
174 | |||
175 | return display->update(display, x, y, w, h); | ||
176 | } | ||
177 | |||
178 | /* This function is exported for SGX driver use */ | ||
179 | int omapfb_update_window(struct fb_info *fbi, | ||
180 | u32 x, u32 y, u32 w, u32 h) | ||
181 | { | ||
182 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
183 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
184 | int r; | ||
185 | |||
186 | omapfb_lock(fbdev); | ||
187 | lock_fb_info(fbi); | ||
188 | |||
189 | r = omapfb_update_window_nolock(fbi, x, y, w, h); | ||
190 | |||
191 | unlock_fb_info(fbi); | ||
192 | omapfb_unlock(fbdev); | ||
193 | |||
194 | return r; | ||
195 | } | ||
196 | EXPORT_SYMBOL(omapfb_update_window); | ||
197 | |||
198 | static int omapfb_set_update_mode(struct fb_info *fbi, | ||
199 | enum omapfb_update_mode mode) | ||
200 | { | ||
201 | struct omap_dss_device *display = fb2display(fbi); | ||
202 | enum omap_dss_update_mode um; | ||
203 | int r; | ||
204 | |||
205 | if (!display || !display->set_update_mode) | ||
206 | return -EINVAL; | ||
207 | |||
208 | switch (mode) { | ||
209 | case OMAPFB_UPDATE_DISABLED: | ||
210 | um = OMAP_DSS_UPDATE_DISABLED; | ||
211 | break; | ||
212 | |||
213 | case OMAPFB_AUTO_UPDATE: | ||
214 | um = OMAP_DSS_UPDATE_AUTO; | ||
215 | break; | ||
216 | |||
217 | case OMAPFB_MANUAL_UPDATE: | ||
218 | um = OMAP_DSS_UPDATE_MANUAL; | ||
219 | break; | ||
220 | |||
221 | default: | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | r = display->set_update_mode(display, um); | ||
226 | |||
227 | return r; | ||
228 | } | ||
229 | |||
230 | static int omapfb_get_update_mode(struct fb_info *fbi, | ||
231 | enum omapfb_update_mode *mode) | ||
232 | { | ||
233 | struct omap_dss_device *display = fb2display(fbi); | ||
234 | enum omap_dss_update_mode m; | ||
235 | |||
236 | if (!display || !display->get_update_mode) | ||
237 | return -EINVAL; | ||
238 | |||
239 | m = display->get_update_mode(display); | ||
240 | |||
241 | switch (m) { | ||
242 | case OMAP_DSS_UPDATE_DISABLED: | ||
243 | *mode = OMAPFB_UPDATE_DISABLED; | ||
244 | break; | ||
245 | case OMAP_DSS_UPDATE_AUTO: | ||
246 | *mode = OMAPFB_AUTO_UPDATE; | ||
247 | break; | ||
248 | case OMAP_DSS_UPDATE_MANUAL: | ||
249 | *mode = OMAPFB_MANUAL_UPDATE; | ||
250 | break; | ||
251 | default: | ||
252 | BUG(); | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | /* XXX this color key handling is a hack... */ | ||
259 | static struct omapfb_color_key omapfb_color_keys[2]; | ||
260 | |||
261 | static int _omapfb_set_color_key(struct omap_overlay_manager *mgr, | ||
262 | struct omapfb_color_key *ck) | ||
263 | { | ||
264 | struct omap_overlay_manager_info info; | ||
265 | enum omap_dss_trans_key_type kt; | ||
266 | int r; | ||
267 | |||
268 | mgr->get_manager_info(mgr, &info); | ||
269 | |||
270 | if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) { | ||
271 | info.trans_enabled = false; | ||
272 | omapfb_color_keys[mgr->id] = *ck; | ||
273 | |||
274 | r = mgr->set_manager_info(mgr, &info); | ||
275 | if (r) | ||
276 | return r; | ||
277 | |||
278 | r = mgr->apply(mgr); | ||
279 | |||
280 | return r; | ||
281 | } | ||
282 | |||
283 | switch (ck->key_type) { | ||
284 | case OMAPFB_COLOR_KEY_GFX_DST: | ||
285 | kt = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
286 | break; | ||
287 | case OMAPFB_COLOR_KEY_VID_SRC: | ||
288 | kt = OMAP_DSS_COLOR_KEY_VID_SRC; | ||
289 | break; | ||
290 | default: | ||
291 | return -EINVAL; | ||
292 | } | ||
293 | |||
294 | info.default_color = ck->background; | ||
295 | info.trans_key = ck->trans_key; | ||
296 | info.trans_key_type = kt; | ||
297 | info.trans_enabled = true; | ||
298 | |||
299 | omapfb_color_keys[mgr->id] = *ck; | ||
300 | |||
301 | r = mgr->set_manager_info(mgr, &info); | ||
302 | if (r) | ||
303 | return r; | ||
304 | |||
305 | r = mgr->apply(mgr); | ||
306 | |||
307 | return r; | ||
308 | } | ||
309 | |||
310 | static int omapfb_set_color_key(struct fb_info *fbi, | ||
311 | struct omapfb_color_key *ck) | ||
312 | { | ||
313 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
314 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
315 | int r; | ||
316 | int i; | ||
317 | struct omap_overlay_manager *mgr = NULL; | ||
318 | |||
319 | omapfb_lock(fbdev); | ||
320 | |||
321 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
322 | if (ofbi->overlays[i]->manager) { | ||
323 | mgr = ofbi->overlays[i]->manager; | ||
324 | break; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | if (!mgr) { | ||
329 | r = -EINVAL; | ||
330 | goto err; | ||
331 | } | ||
332 | |||
333 | r = _omapfb_set_color_key(mgr, ck); | ||
334 | err: | ||
335 | omapfb_unlock(fbdev); | ||
336 | |||
337 | return r; | ||
338 | } | ||
339 | |||
340 | static int omapfb_get_color_key(struct fb_info *fbi, | ||
341 | struct omapfb_color_key *ck) | ||
342 | { | ||
343 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
344 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
345 | struct omap_overlay_manager *mgr = NULL; | ||
346 | int r = 0; | ||
347 | int i; | ||
348 | |||
349 | omapfb_lock(fbdev); | ||
350 | |||
351 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
352 | if (ofbi->overlays[i]->manager) { | ||
353 | mgr = ofbi->overlays[i]->manager; | ||
354 | break; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | if (!mgr) { | ||
359 | r = -EINVAL; | ||
360 | goto err; | ||
361 | } | ||
362 | |||
363 | *ck = omapfb_color_keys[mgr->id]; | ||
364 | err: | ||
365 | omapfb_unlock(fbdev); | ||
366 | |||
367 | return r; | ||
368 | } | ||
369 | |||
370 | static int omapfb_memory_read(struct fb_info *fbi, | ||
371 | struct omapfb_memory_read *mr) | ||
372 | { | ||
373 | struct omap_dss_device *display = fb2display(fbi); | ||
374 | void *buf; | ||
375 | int r; | ||
376 | |||
377 | if (!display || !display->memory_read) | ||
378 | return -ENOENT; | ||
379 | |||
380 | if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size)) | ||
381 | return -EFAULT; | ||
382 | |||
383 | if (mr->w * mr->h * 3 > mr->buffer_size) | ||
384 | return -EINVAL; | ||
385 | |||
386 | buf = vmalloc(mr->buffer_size); | ||
387 | if (!buf) { | ||
388 | DBG("vmalloc failed\n"); | ||
389 | return -ENOMEM; | ||
390 | } | ||
391 | |||
392 | r = display->memory_read(display, buf, mr->buffer_size, | ||
393 | mr->x, mr->y, mr->w, mr->h); | ||
394 | |||
395 | if (r > 0) { | ||
396 | if (copy_to_user(mr->buffer, buf, mr->buffer_size)) | ||
397 | r = -EFAULT; | ||
398 | } | ||
399 | |||
400 | vfree(buf); | ||
401 | |||
402 | return r; | ||
403 | } | ||
404 | |||
405 | static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev, | ||
406 | struct omapfb_ovl_colormode *mode) | ||
407 | { | ||
408 | int ovl_idx = mode->overlay_idx; | ||
409 | int mode_idx = mode->mode_idx; | ||
410 | struct omap_overlay *ovl; | ||
411 | enum omap_color_mode supported_modes; | ||
412 | struct fb_var_screeninfo var; | ||
413 | int i; | ||
414 | |||
415 | if (ovl_idx >= fbdev->num_overlays) | ||
416 | return -ENODEV; | ||
417 | ovl = fbdev->overlays[ovl_idx]; | ||
418 | supported_modes = ovl->supported_modes; | ||
419 | |||
420 | mode_idx = mode->mode_idx; | ||
421 | |||
422 | for (i = 0; i < sizeof(supported_modes) * 8; i++) { | ||
423 | if (!(supported_modes & (1 << i))) | ||
424 | continue; | ||
425 | /* | ||
426 | * It's possible that the FB doesn't support a mode | ||
427 | * that is supported by the overlay, so call the | ||
428 | * following here. | ||
429 | */ | ||
430 | if (dss_mode_to_fb_mode(1 << i, &var) < 0) | ||
431 | continue; | ||
432 | |||
433 | mode_idx--; | ||
434 | if (mode_idx < 0) | ||
435 | break; | ||
436 | } | ||
437 | |||
438 | if (i == sizeof(supported_modes) * 8) | ||
439 | return -ENOENT; | ||
440 | |||
441 | mode->bits_per_pixel = var.bits_per_pixel; | ||
442 | mode->nonstd = var.nonstd; | ||
443 | mode->red = var.red; | ||
444 | mode->green = var.green; | ||
445 | mode->blue = var.blue; | ||
446 | mode->transp = var.transp; | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static int omapfb_wait_for_go(struct fb_info *fbi) | ||
452 | { | ||
453 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
454 | int r = 0; | ||
455 | int i; | ||
456 | |||
457 | for (i = 0; i < ofbi->num_overlays; ++i) { | ||
458 | struct omap_overlay *ovl = ofbi->overlays[i]; | ||
459 | r = ovl->wait_for_go(ovl); | ||
460 | if (r) | ||
461 | break; | ||
462 | } | ||
463 | |||
464 | return r; | ||
465 | } | ||
466 | |||
467 | int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | ||
468 | { | ||
469 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
470 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
471 | struct omap_dss_device *display = fb2display(fbi); | ||
472 | |||
473 | union { | ||
474 | struct omapfb_update_window_old uwnd_o; | ||
475 | struct omapfb_update_window uwnd; | ||
476 | struct omapfb_plane_info plane_info; | ||
477 | struct omapfb_caps caps; | ||
478 | struct omapfb_mem_info mem_info; | ||
479 | struct omapfb_color_key color_key; | ||
480 | struct omapfb_ovl_colormode ovl_colormode; | ||
481 | enum omapfb_update_mode update_mode; | ||
482 | int test_num; | ||
483 | struct omapfb_memory_read memory_read; | ||
484 | struct omapfb_vram_info vram_info; | ||
485 | struct omapfb_tearsync_info tearsync_info; | ||
486 | } p; | ||
487 | |||
488 | int r = 0; | ||
489 | |||
490 | switch (cmd) { | ||
491 | case OMAPFB_SYNC_GFX: | ||
492 | DBG("ioctl SYNC_GFX\n"); | ||
493 | if (!display || !display->sync) { | ||
494 | /* DSS1 never returns an error here, so we neither */ | ||
495 | /*r = -EINVAL;*/ | ||
496 | break; | ||
497 | } | ||
498 | |||
499 | r = display->sync(display); | ||
500 | break; | ||
501 | |||
502 | case OMAPFB_UPDATE_WINDOW_OLD: | ||
503 | DBG("ioctl UPDATE_WINDOW_OLD\n"); | ||
504 | if (!display || !display->update) { | ||
505 | r = -EINVAL; | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | if (copy_from_user(&p.uwnd_o, | ||
510 | (void __user *)arg, | ||
511 | sizeof(p.uwnd_o))) { | ||
512 | r = -EFAULT; | ||
513 | break; | ||
514 | } | ||
515 | |||
516 | r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y, | ||
517 | p.uwnd_o.width, p.uwnd_o.height); | ||
518 | break; | ||
519 | |||
520 | case OMAPFB_UPDATE_WINDOW: | ||
521 | DBG("ioctl UPDATE_WINDOW\n"); | ||
522 | if (!display || !display->update) { | ||
523 | r = -EINVAL; | ||
524 | break; | ||
525 | } | ||
526 | |||
527 | if (copy_from_user(&p.uwnd, (void __user *)arg, | ||
528 | sizeof(p.uwnd))) { | ||
529 | r = -EFAULT; | ||
530 | break; | ||
531 | } | ||
532 | |||
533 | r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y, | ||
534 | p.uwnd.width, p.uwnd.height); | ||
535 | break; | ||
536 | |||
537 | case OMAPFB_SETUP_PLANE: | ||
538 | DBG("ioctl SETUP_PLANE\n"); | ||
539 | if (copy_from_user(&p.plane_info, (void __user *)arg, | ||
540 | sizeof(p.plane_info))) | ||
541 | r = -EFAULT; | ||
542 | else | ||
543 | r = omapfb_setup_plane(fbi, &p.plane_info); | ||
544 | break; | ||
545 | |||
546 | case OMAPFB_QUERY_PLANE: | ||
547 | DBG("ioctl QUERY_PLANE\n"); | ||
548 | r = omapfb_query_plane(fbi, &p.plane_info); | ||
549 | if (r < 0) | ||
550 | break; | ||
551 | if (copy_to_user((void __user *)arg, &p.plane_info, | ||
552 | sizeof(p.plane_info))) | ||
553 | r = -EFAULT; | ||
554 | break; | ||
555 | |||
556 | case OMAPFB_SETUP_MEM: | ||
557 | DBG("ioctl SETUP_MEM\n"); | ||
558 | if (copy_from_user(&p.mem_info, (void __user *)arg, | ||
559 | sizeof(p.mem_info))) | ||
560 | r = -EFAULT; | ||
561 | else | ||
562 | r = omapfb_setup_mem(fbi, &p.mem_info); | ||
563 | break; | ||
564 | |||
565 | case OMAPFB_QUERY_MEM: | ||
566 | DBG("ioctl QUERY_MEM\n"); | ||
567 | r = omapfb_query_mem(fbi, &p.mem_info); | ||
568 | if (r < 0) | ||
569 | break; | ||
570 | if (copy_to_user((void __user *)arg, &p.mem_info, | ||
571 | sizeof(p.mem_info))) | ||
572 | r = -EFAULT; | ||
573 | break; | ||
574 | |||
575 | case OMAPFB_GET_CAPS: | ||
576 | DBG("ioctl GET_CAPS\n"); | ||
577 | if (!display) { | ||
578 | r = -EINVAL; | ||
579 | break; | ||
580 | } | ||
581 | |||
582 | memset(&p.caps, 0, sizeof(p.caps)); | ||
583 | if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
584 | p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE; | ||
585 | if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM) | ||
586 | p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
587 | |||
588 | if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) | ||
589 | r = -EFAULT; | ||
590 | break; | ||
591 | |||
592 | case OMAPFB_GET_OVERLAY_COLORMODE: | ||
593 | DBG("ioctl GET_OVERLAY_COLORMODE\n"); | ||
594 | if (copy_from_user(&p.ovl_colormode, (void __user *)arg, | ||
595 | sizeof(p.ovl_colormode))) { | ||
596 | r = -EFAULT; | ||
597 | break; | ||
598 | } | ||
599 | r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode); | ||
600 | if (r < 0) | ||
601 | break; | ||
602 | if (copy_to_user((void __user *)arg, &p.ovl_colormode, | ||
603 | sizeof(p.ovl_colormode))) | ||
604 | r = -EFAULT; | ||
605 | break; | ||
606 | |||
607 | case OMAPFB_SET_UPDATE_MODE: | ||
608 | DBG("ioctl SET_UPDATE_MODE\n"); | ||
609 | if (get_user(p.update_mode, (int __user *)arg)) | ||
610 | r = -EFAULT; | ||
611 | else | ||
612 | r = omapfb_set_update_mode(fbi, p.update_mode); | ||
613 | break; | ||
614 | |||
615 | case OMAPFB_GET_UPDATE_MODE: | ||
616 | DBG("ioctl GET_UPDATE_MODE\n"); | ||
617 | r = omapfb_get_update_mode(fbi, &p.update_mode); | ||
618 | if (r) | ||
619 | break; | ||
620 | if (put_user(p.update_mode, | ||
621 | (enum omapfb_update_mode __user *)arg)) | ||
622 | r = -EFAULT; | ||
623 | break; | ||
624 | |||
625 | case OMAPFB_SET_COLOR_KEY: | ||
626 | DBG("ioctl SET_COLOR_KEY\n"); | ||
627 | if (copy_from_user(&p.color_key, (void __user *)arg, | ||
628 | sizeof(p.color_key))) | ||
629 | r = -EFAULT; | ||
630 | else | ||
631 | r = omapfb_set_color_key(fbi, &p.color_key); | ||
632 | break; | ||
633 | |||
634 | case OMAPFB_GET_COLOR_KEY: | ||
635 | DBG("ioctl GET_COLOR_KEY\n"); | ||
636 | r = omapfb_get_color_key(fbi, &p.color_key); | ||
637 | if (r) | ||
638 | break; | ||
639 | if (copy_to_user((void __user *)arg, &p.color_key, | ||
640 | sizeof(p.color_key))) | ||
641 | r = -EFAULT; | ||
642 | break; | ||
643 | |||
644 | case OMAPFB_WAITFORVSYNC: | ||
645 | DBG("ioctl WAITFORVSYNC\n"); | ||
646 | if (!display) { | ||
647 | r = -EINVAL; | ||
648 | break; | ||
649 | } | ||
650 | |||
651 | r = display->wait_vsync(display); | ||
652 | break; | ||
653 | |||
654 | case OMAPFB_WAITFORGO: | ||
655 | DBG("ioctl WAITFORGO\n"); | ||
656 | if (!display) { | ||
657 | r = -EINVAL; | ||
658 | break; | ||
659 | } | ||
660 | |||
661 | r = omapfb_wait_for_go(fbi); | ||
662 | break; | ||
663 | |||
664 | /* LCD and CTRL tests do the same thing for backward | ||
665 | * compatibility */ | ||
666 | case OMAPFB_LCD_TEST: | ||
667 | DBG("ioctl LCD_TEST\n"); | ||
668 | if (get_user(p.test_num, (int __user *)arg)) { | ||
669 | r = -EFAULT; | ||
670 | break; | ||
671 | } | ||
672 | if (!display || !display->run_test) { | ||
673 | r = -EINVAL; | ||
674 | break; | ||
675 | } | ||
676 | |||
677 | r = display->run_test(display, p.test_num); | ||
678 | |||
679 | break; | ||
680 | |||
681 | case OMAPFB_CTRL_TEST: | ||
682 | DBG("ioctl CTRL_TEST\n"); | ||
683 | if (get_user(p.test_num, (int __user *)arg)) { | ||
684 | r = -EFAULT; | ||
685 | break; | ||
686 | } | ||
687 | if (!display || !display->run_test) { | ||
688 | r = -EINVAL; | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | r = display->run_test(display, p.test_num); | ||
693 | |||
694 | break; | ||
695 | |||
696 | case OMAPFB_MEMORY_READ: | ||
697 | DBG("ioctl MEMORY_READ\n"); | ||
698 | |||
699 | if (copy_from_user(&p.memory_read, (void __user *)arg, | ||
700 | sizeof(p.memory_read))) { | ||
701 | r = -EFAULT; | ||
702 | break; | ||
703 | } | ||
704 | |||
705 | r = omapfb_memory_read(fbi, &p.memory_read); | ||
706 | |||
707 | break; | ||
708 | |||
709 | case OMAPFB_GET_VRAM_INFO: { | ||
710 | unsigned long vram, free, largest; | ||
711 | |||
712 | DBG("ioctl GET_VRAM_INFO\n"); | ||
713 | |||
714 | omap_vram_get_info(&vram, &free, &largest); | ||
715 | p.vram_info.total = vram; | ||
716 | p.vram_info.free = free; | ||
717 | p.vram_info.largest_free_block = largest; | ||
718 | |||
719 | if (copy_to_user((void __user *)arg, &p.vram_info, | ||
720 | sizeof(p.vram_info))) | ||
721 | r = -EFAULT; | ||
722 | break; | ||
723 | } | ||
724 | |||
725 | case OMAPFB_SET_TEARSYNC: { | ||
726 | DBG("ioctl SET_TEARSYNC\n"); | ||
727 | |||
728 | if (copy_from_user(&p.tearsync_info, (void __user *)arg, | ||
729 | sizeof(p.tearsync_info))) { | ||
730 | r = -EFAULT; | ||
731 | break; | ||
732 | } | ||
733 | |||
734 | if (!display->enable_te) { | ||
735 | r = -ENODEV; | ||
736 | break; | ||
737 | } | ||
738 | |||
739 | r = display->enable_te(display, !!p.tearsync_info.enabled); | ||
740 | |||
741 | break; | ||
742 | } | ||
743 | |||
744 | default: | ||
745 | dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); | ||
746 | r = -EINVAL; | ||
747 | } | ||
748 | |||
749 | if (r < 0) | ||
750 | DBG("ioctl failed: %d\n", r); | ||
751 | |||
752 | return r; | ||
753 | } | ||
754 | |||
755 | |||