diff options
Diffstat (limited to 'drivers/video/omap2/omapfb/omapfb-ioctl.c')
-rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 785 |
1 files changed, 785 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..1ffa760b8545 --- /dev/null +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
@@ -0,0 +1,785 @@ | |||
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->driver->get_resolution(display, &dw, &dh); | ||
171 | |||
172 | if (x + w > dw || y + h > dh) | ||
173 | return -EINVAL; | ||
174 | |||
175 | return display->driver->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->driver->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->driver->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) | ||
237 | return -EINVAL; | ||
238 | |||
239 | if (!display->driver->get_update_mode) { | ||
240 | *mode = OMAPFB_AUTO_UPDATE; | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | m = display->driver->get_update_mode(display); | ||
245 | |||
246 | switch (m) { | ||
247 | case OMAP_DSS_UPDATE_DISABLED: | ||
248 | *mode = OMAPFB_UPDATE_DISABLED; | ||
249 | break; | ||
250 | case OMAP_DSS_UPDATE_AUTO: | ||
251 | *mode = OMAPFB_AUTO_UPDATE; | ||
252 | break; | ||
253 | case OMAP_DSS_UPDATE_MANUAL: | ||
254 | *mode = OMAPFB_MANUAL_UPDATE; | ||
255 | break; | ||
256 | default: | ||
257 | BUG(); | ||
258 | } | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | /* XXX this color key handling is a hack... */ | ||
264 | static struct omapfb_color_key omapfb_color_keys[2]; | ||
265 | |||
266 | static int _omapfb_set_color_key(struct omap_overlay_manager *mgr, | ||
267 | struct omapfb_color_key *ck) | ||
268 | { | ||
269 | struct omap_overlay_manager_info info; | ||
270 | enum omap_dss_trans_key_type kt; | ||
271 | int r; | ||
272 | |||
273 | mgr->get_manager_info(mgr, &info); | ||
274 | |||
275 | if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) { | ||
276 | info.trans_enabled = false; | ||
277 | omapfb_color_keys[mgr->id] = *ck; | ||
278 | |||
279 | r = mgr->set_manager_info(mgr, &info); | ||
280 | if (r) | ||
281 | return r; | ||
282 | |||
283 | r = mgr->apply(mgr); | ||
284 | |||
285 | return r; | ||
286 | } | ||
287 | |||
288 | switch (ck->key_type) { | ||
289 | case OMAPFB_COLOR_KEY_GFX_DST: | ||
290 | kt = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
291 | break; | ||
292 | case OMAPFB_COLOR_KEY_VID_SRC: | ||
293 | kt = OMAP_DSS_COLOR_KEY_VID_SRC; | ||
294 | break; | ||
295 | default: | ||
296 | return -EINVAL; | ||
297 | } | ||
298 | |||
299 | info.default_color = ck->background; | ||
300 | info.trans_key = ck->trans_key; | ||
301 | info.trans_key_type = kt; | ||
302 | info.trans_enabled = true; | ||
303 | |||
304 | omapfb_color_keys[mgr->id] = *ck; | ||
305 | |||
306 | r = mgr->set_manager_info(mgr, &info); | ||
307 | if (r) | ||
308 | return r; | ||
309 | |||
310 | r = mgr->apply(mgr); | ||
311 | |||
312 | return r; | ||
313 | } | ||
314 | |||
315 | static int omapfb_set_color_key(struct fb_info *fbi, | ||
316 | struct omapfb_color_key *ck) | ||
317 | { | ||
318 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
319 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
320 | int r; | ||
321 | int i; | ||
322 | struct omap_overlay_manager *mgr = NULL; | ||
323 | |||
324 | omapfb_lock(fbdev); | ||
325 | |||
326 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
327 | if (ofbi->overlays[i]->manager) { | ||
328 | mgr = ofbi->overlays[i]->manager; | ||
329 | break; | ||
330 | } | ||
331 | } | ||
332 | |||
333 | if (!mgr) { | ||
334 | r = -EINVAL; | ||
335 | goto err; | ||
336 | } | ||
337 | |||
338 | r = _omapfb_set_color_key(mgr, ck); | ||
339 | err: | ||
340 | omapfb_unlock(fbdev); | ||
341 | |||
342 | return r; | ||
343 | } | ||
344 | |||
345 | static int omapfb_get_color_key(struct fb_info *fbi, | ||
346 | struct omapfb_color_key *ck) | ||
347 | { | ||
348 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
349 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
350 | struct omap_overlay_manager *mgr = NULL; | ||
351 | int r = 0; | ||
352 | int i; | ||
353 | |||
354 | omapfb_lock(fbdev); | ||
355 | |||
356 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
357 | if (ofbi->overlays[i]->manager) { | ||
358 | mgr = ofbi->overlays[i]->manager; | ||
359 | break; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | if (!mgr) { | ||
364 | r = -EINVAL; | ||
365 | goto err; | ||
366 | } | ||
367 | |||
368 | *ck = omapfb_color_keys[mgr->id]; | ||
369 | err: | ||
370 | omapfb_unlock(fbdev); | ||
371 | |||
372 | return r; | ||
373 | } | ||
374 | |||
375 | static int omapfb_memory_read(struct fb_info *fbi, | ||
376 | struct omapfb_memory_read *mr) | ||
377 | { | ||
378 | struct omap_dss_device *display = fb2display(fbi); | ||
379 | void *buf; | ||
380 | int r; | ||
381 | |||
382 | if (!display || !display->driver->memory_read) | ||
383 | return -ENOENT; | ||
384 | |||
385 | if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size)) | ||
386 | return -EFAULT; | ||
387 | |||
388 | if (mr->w * mr->h * 3 > mr->buffer_size) | ||
389 | return -EINVAL; | ||
390 | |||
391 | buf = vmalloc(mr->buffer_size); | ||
392 | if (!buf) { | ||
393 | DBG("vmalloc failed\n"); | ||
394 | return -ENOMEM; | ||
395 | } | ||
396 | |||
397 | r = display->driver->memory_read(display, buf, mr->buffer_size, | ||
398 | mr->x, mr->y, mr->w, mr->h); | ||
399 | |||
400 | if (r > 0) { | ||
401 | if (copy_to_user(mr->buffer, buf, mr->buffer_size)) | ||
402 | r = -EFAULT; | ||
403 | } | ||
404 | |||
405 | vfree(buf); | ||
406 | |||
407 | return r; | ||
408 | } | ||
409 | |||
410 | static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev, | ||
411 | struct omapfb_ovl_colormode *mode) | ||
412 | { | ||
413 | int ovl_idx = mode->overlay_idx; | ||
414 | int mode_idx = mode->mode_idx; | ||
415 | struct omap_overlay *ovl; | ||
416 | enum omap_color_mode supported_modes; | ||
417 | struct fb_var_screeninfo var; | ||
418 | int i; | ||
419 | |||
420 | if (ovl_idx >= fbdev->num_overlays) | ||
421 | return -ENODEV; | ||
422 | ovl = fbdev->overlays[ovl_idx]; | ||
423 | supported_modes = ovl->supported_modes; | ||
424 | |||
425 | mode_idx = mode->mode_idx; | ||
426 | |||
427 | for (i = 0; i < sizeof(supported_modes) * 8; i++) { | ||
428 | if (!(supported_modes & (1 << i))) | ||
429 | continue; | ||
430 | /* | ||
431 | * It's possible that the FB doesn't support a mode | ||
432 | * that is supported by the overlay, so call the | ||
433 | * following here. | ||
434 | */ | ||
435 | if (dss_mode_to_fb_mode(1 << i, &var) < 0) | ||
436 | continue; | ||
437 | |||
438 | mode_idx--; | ||
439 | if (mode_idx < 0) | ||
440 | break; | ||
441 | } | ||
442 | |||
443 | if (i == sizeof(supported_modes) * 8) | ||
444 | return -ENOENT; | ||
445 | |||
446 | mode->bits_per_pixel = var.bits_per_pixel; | ||
447 | mode->nonstd = var.nonstd; | ||
448 | mode->red = var.red; | ||
449 | mode->green = var.green; | ||
450 | mode->blue = var.blue; | ||
451 | mode->transp = var.transp; | ||
452 | |||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static int omapfb_wait_for_go(struct fb_info *fbi) | ||
457 | { | ||
458 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
459 | int r = 0; | ||
460 | int i; | ||
461 | |||
462 | for (i = 0; i < ofbi->num_overlays; ++i) { | ||
463 | struct omap_overlay *ovl = ofbi->overlays[i]; | ||
464 | r = ovl->wait_for_go(ovl); | ||
465 | if (r) | ||
466 | break; | ||
467 | } | ||
468 | |||
469 | return r; | ||
470 | } | ||
471 | |||
472 | int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | ||
473 | { | ||
474 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
475 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
476 | struct omap_dss_device *display = fb2display(fbi); | ||
477 | |||
478 | union { | ||
479 | struct omapfb_update_window_old uwnd_o; | ||
480 | struct omapfb_update_window uwnd; | ||
481 | struct omapfb_plane_info plane_info; | ||
482 | struct omapfb_caps caps; | ||
483 | struct omapfb_mem_info mem_info; | ||
484 | struct omapfb_color_key color_key; | ||
485 | struct omapfb_ovl_colormode ovl_colormode; | ||
486 | enum omapfb_update_mode update_mode; | ||
487 | int test_num; | ||
488 | struct omapfb_memory_read memory_read; | ||
489 | struct omapfb_vram_info vram_info; | ||
490 | struct omapfb_tearsync_info tearsync_info; | ||
491 | struct omapfb_display_info display_info; | ||
492 | } p; | ||
493 | |||
494 | int r = 0; | ||
495 | |||
496 | switch (cmd) { | ||
497 | case OMAPFB_SYNC_GFX: | ||
498 | DBG("ioctl SYNC_GFX\n"); | ||
499 | if (!display || !display->driver->sync) { | ||
500 | /* DSS1 never returns an error here, so we neither */ | ||
501 | /*r = -EINVAL;*/ | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | r = display->driver->sync(display); | ||
506 | break; | ||
507 | |||
508 | case OMAPFB_UPDATE_WINDOW_OLD: | ||
509 | DBG("ioctl UPDATE_WINDOW_OLD\n"); | ||
510 | if (!display || !display->driver->update) { | ||
511 | r = -EINVAL; | ||
512 | break; | ||
513 | } | ||
514 | |||
515 | if (copy_from_user(&p.uwnd_o, | ||
516 | (void __user *)arg, | ||
517 | sizeof(p.uwnd_o))) { | ||
518 | r = -EFAULT; | ||
519 | break; | ||
520 | } | ||
521 | |||
522 | r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y, | ||
523 | p.uwnd_o.width, p.uwnd_o.height); | ||
524 | break; | ||
525 | |||
526 | case OMAPFB_UPDATE_WINDOW: | ||
527 | DBG("ioctl UPDATE_WINDOW\n"); | ||
528 | if (!display || !display->driver->update) { | ||
529 | r = -EINVAL; | ||
530 | break; | ||
531 | } | ||
532 | |||
533 | if (copy_from_user(&p.uwnd, (void __user *)arg, | ||
534 | sizeof(p.uwnd))) { | ||
535 | r = -EFAULT; | ||
536 | break; | ||
537 | } | ||
538 | |||
539 | r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y, | ||
540 | p.uwnd.width, p.uwnd.height); | ||
541 | break; | ||
542 | |||
543 | case OMAPFB_SETUP_PLANE: | ||
544 | DBG("ioctl SETUP_PLANE\n"); | ||
545 | if (copy_from_user(&p.plane_info, (void __user *)arg, | ||
546 | sizeof(p.plane_info))) | ||
547 | r = -EFAULT; | ||
548 | else | ||
549 | r = omapfb_setup_plane(fbi, &p.plane_info); | ||
550 | break; | ||
551 | |||
552 | case OMAPFB_QUERY_PLANE: | ||
553 | DBG("ioctl QUERY_PLANE\n"); | ||
554 | r = omapfb_query_plane(fbi, &p.plane_info); | ||
555 | if (r < 0) | ||
556 | break; | ||
557 | if (copy_to_user((void __user *)arg, &p.plane_info, | ||
558 | sizeof(p.plane_info))) | ||
559 | r = -EFAULT; | ||
560 | break; | ||
561 | |||
562 | case OMAPFB_SETUP_MEM: | ||
563 | DBG("ioctl SETUP_MEM\n"); | ||
564 | if (copy_from_user(&p.mem_info, (void __user *)arg, | ||
565 | sizeof(p.mem_info))) | ||
566 | r = -EFAULT; | ||
567 | else | ||
568 | r = omapfb_setup_mem(fbi, &p.mem_info); | ||
569 | break; | ||
570 | |||
571 | case OMAPFB_QUERY_MEM: | ||
572 | DBG("ioctl QUERY_MEM\n"); | ||
573 | r = omapfb_query_mem(fbi, &p.mem_info); | ||
574 | if (r < 0) | ||
575 | break; | ||
576 | if (copy_to_user((void __user *)arg, &p.mem_info, | ||
577 | sizeof(p.mem_info))) | ||
578 | r = -EFAULT; | ||
579 | break; | ||
580 | |||
581 | case OMAPFB_GET_CAPS: | ||
582 | DBG("ioctl GET_CAPS\n"); | ||
583 | if (!display) { | ||
584 | r = -EINVAL; | ||
585 | break; | ||
586 | } | ||
587 | |||
588 | memset(&p.caps, 0, sizeof(p.caps)); | ||
589 | if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
590 | p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE; | ||
591 | if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM) | ||
592 | p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
593 | |||
594 | if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) | ||
595 | r = -EFAULT; | ||
596 | break; | ||
597 | |||
598 | case OMAPFB_GET_OVERLAY_COLORMODE: | ||
599 | DBG("ioctl GET_OVERLAY_COLORMODE\n"); | ||
600 | if (copy_from_user(&p.ovl_colormode, (void __user *)arg, | ||
601 | sizeof(p.ovl_colormode))) { | ||
602 | r = -EFAULT; | ||
603 | break; | ||
604 | } | ||
605 | r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode); | ||
606 | if (r < 0) | ||
607 | break; | ||
608 | if (copy_to_user((void __user *)arg, &p.ovl_colormode, | ||
609 | sizeof(p.ovl_colormode))) | ||
610 | r = -EFAULT; | ||
611 | break; | ||
612 | |||
613 | case OMAPFB_SET_UPDATE_MODE: | ||
614 | DBG("ioctl SET_UPDATE_MODE\n"); | ||
615 | if (get_user(p.update_mode, (int __user *)arg)) | ||
616 | r = -EFAULT; | ||
617 | else | ||
618 | r = omapfb_set_update_mode(fbi, p.update_mode); | ||
619 | break; | ||
620 | |||
621 | case OMAPFB_GET_UPDATE_MODE: | ||
622 | DBG("ioctl GET_UPDATE_MODE\n"); | ||
623 | r = omapfb_get_update_mode(fbi, &p.update_mode); | ||
624 | if (r) | ||
625 | break; | ||
626 | if (put_user(p.update_mode, | ||
627 | (enum omapfb_update_mode __user *)arg)) | ||
628 | r = -EFAULT; | ||
629 | break; | ||
630 | |||
631 | case OMAPFB_SET_COLOR_KEY: | ||
632 | DBG("ioctl SET_COLOR_KEY\n"); | ||
633 | if (copy_from_user(&p.color_key, (void __user *)arg, | ||
634 | sizeof(p.color_key))) | ||
635 | r = -EFAULT; | ||
636 | else | ||
637 | r = omapfb_set_color_key(fbi, &p.color_key); | ||
638 | break; | ||
639 | |||
640 | case OMAPFB_GET_COLOR_KEY: | ||
641 | DBG("ioctl GET_COLOR_KEY\n"); | ||
642 | r = omapfb_get_color_key(fbi, &p.color_key); | ||
643 | if (r) | ||
644 | break; | ||
645 | if (copy_to_user((void __user *)arg, &p.color_key, | ||
646 | sizeof(p.color_key))) | ||
647 | r = -EFAULT; | ||
648 | break; | ||
649 | |||
650 | case OMAPFB_WAITFORVSYNC: | ||
651 | DBG("ioctl WAITFORVSYNC\n"); | ||
652 | if (!display) { | ||
653 | r = -EINVAL; | ||
654 | break; | ||
655 | } | ||
656 | |||
657 | r = display->manager->wait_for_vsync(display->manager); | ||
658 | break; | ||
659 | |||
660 | case OMAPFB_WAITFORGO: | ||
661 | DBG("ioctl WAITFORGO\n"); | ||
662 | if (!display) { | ||
663 | r = -EINVAL; | ||
664 | break; | ||
665 | } | ||
666 | |||
667 | r = omapfb_wait_for_go(fbi); | ||
668 | break; | ||
669 | |||
670 | /* LCD and CTRL tests do the same thing for backward | ||
671 | * compatibility */ | ||
672 | case OMAPFB_LCD_TEST: | ||
673 | DBG("ioctl LCD_TEST\n"); | ||
674 | if (get_user(p.test_num, (int __user *)arg)) { | ||
675 | r = -EFAULT; | ||
676 | break; | ||
677 | } | ||
678 | if (!display || !display->driver->run_test) { | ||
679 | r = -EINVAL; | ||
680 | break; | ||
681 | } | ||
682 | |||
683 | r = display->driver->run_test(display, p.test_num); | ||
684 | |||
685 | break; | ||
686 | |||
687 | case OMAPFB_CTRL_TEST: | ||
688 | DBG("ioctl CTRL_TEST\n"); | ||
689 | if (get_user(p.test_num, (int __user *)arg)) { | ||
690 | r = -EFAULT; | ||
691 | break; | ||
692 | } | ||
693 | if (!display || !display->driver->run_test) { | ||
694 | r = -EINVAL; | ||
695 | break; | ||
696 | } | ||
697 | |||
698 | r = display->driver->run_test(display, p.test_num); | ||
699 | |||
700 | break; | ||
701 | |||
702 | case OMAPFB_MEMORY_READ: | ||
703 | DBG("ioctl MEMORY_READ\n"); | ||
704 | |||
705 | if (copy_from_user(&p.memory_read, (void __user *)arg, | ||
706 | sizeof(p.memory_read))) { | ||
707 | r = -EFAULT; | ||
708 | break; | ||
709 | } | ||
710 | |||
711 | r = omapfb_memory_read(fbi, &p.memory_read); | ||
712 | |||
713 | break; | ||
714 | |||
715 | case OMAPFB_GET_VRAM_INFO: { | ||
716 | unsigned long vram, free, largest; | ||
717 | |||
718 | DBG("ioctl GET_VRAM_INFO\n"); | ||
719 | |||
720 | omap_vram_get_info(&vram, &free, &largest); | ||
721 | p.vram_info.total = vram; | ||
722 | p.vram_info.free = free; | ||
723 | p.vram_info.largest_free_block = largest; | ||
724 | |||
725 | if (copy_to_user((void __user *)arg, &p.vram_info, | ||
726 | sizeof(p.vram_info))) | ||
727 | r = -EFAULT; | ||
728 | break; | ||
729 | } | ||
730 | |||
731 | case OMAPFB_SET_TEARSYNC: { | ||
732 | DBG("ioctl SET_TEARSYNC\n"); | ||
733 | |||
734 | if (copy_from_user(&p.tearsync_info, (void __user *)arg, | ||
735 | sizeof(p.tearsync_info))) { | ||
736 | r = -EFAULT; | ||
737 | break; | ||
738 | } | ||
739 | |||
740 | if (!display->driver->enable_te) { | ||
741 | r = -ENODEV; | ||
742 | break; | ||
743 | } | ||
744 | |||
745 | r = display->driver->enable_te(display, | ||
746 | !!p.tearsync_info.enabled); | ||
747 | |||
748 | break; | ||
749 | } | ||
750 | |||
751 | case OMAPFB_GET_DISPLAY_INFO: { | ||
752 | u16 xres, yres; | ||
753 | |||
754 | DBG("ioctl GET_DISPLAY_INFO\n"); | ||
755 | |||
756 | if (display == NULL) { | ||
757 | r = -ENODEV; | ||
758 | break; | ||
759 | } | ||
760 | |||
761 | display->driver->get_resolution(display, &xres, &yres); | ||
762 | |||
763 | p.display_info.xres = xres; | ||
764 | p.display_info.yres = yres; | ||
765 | p.display_info.width = 0; | ||
766 | p.display_info.height = 0; | ||
767 | |||
768 | if (copy_to_user((void __user *)arg, &p.display_info, | ||
769 | sizeof(p.display_info))) | ||
770 | r = -EFAULT; | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | default: | ||
775 | dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); | ||
776 | r = -EINVAL; | ||
777 | } | ||
778 | |||
779 | if (r < 0) | ||
780 | DBG("ioctl failed: %d\n", r); | ||
781 | |||
782 | return r; | ||
783 | } | ||
784 | |||
785 | |||