diff options
Diffstat (limited to 'drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c')
-rw-r--r-- | drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c | 922 |
1 files changed, 922 insertions, 0 deletions
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c new file mode 100644 index 000000000000..146b6f5428db --- /dev/null +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c | |||
@@ -0,0 +1,922 @@ | |||
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 | #include <linux/export.h> | ||
31 | #include <linux/sizes.h> | ||
32 | |||
33 | #include <video/omapdss.h> | ||
34 | #include <video/omapvrfb.h> | ||
35 | |||
36 | #include "omapfb.h" | ||
37 | |||
38 | static u8 get_mem_idx(struct omapfb_info *ofbi) | ||
39 | { | ||
40 | if (ofbi->id == ofbi->region->id) | ||
41 | return 0; | ||
42 | |||
43 | return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id; | ||
44 | } | ||
45 | |||
46 | static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, | ||
47 | u8 mem_idx) | ||
48 | { | ||
49 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
50 | |||
51 | if (mem_idx & OMAPFB_MEM_IDX_ENABLED) | ||
52 | mem_idx &= OMAPFB_MEM_IDX_MASK; | ||
53 | else | ||
54 | mem_idx = ofbi->id; | ||
55 | |||
56 | if (mem_idx >= fbdev->num_fbs) | ||
57 | return NULL; | ||
58 | |||
59 | return &fbdev->regions[mem_idx]; | ||
60 | } | ||
61 | |||
62 | static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
63 | { | ||
64 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
65 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
66 | struct omap_overlay *ovl; | ||
67 | struct omap_overlay_info old_info; | ||
68 | struct omapfb2_mem_region *old_rg, *new_rg; | ||
69 | int r = 0; | ||
70 | |||
71 | DBG("omapfb_setup_plane\n"); | ||
72 | |||
73 | if (ofbi->num_overlays == 0) { | ||
74 | r = -EINVAL; | ||
75 | goto out; | ||
76 | } | ||
77 | |||
78 | /* XXX uses only the first overlay */ | ||
79 | ovl = ofbi->overlays[0]; | ||
80 | |||
81 | old_rg = ofbi->region; | ||
82 | new_rg = get_mem_region(ofbi, pi->mem_idx); | ||
83 | if (!new_rg) { | ||
84 | r = -EINVAL; | ||
85 | goto out; | ||
86 | } | ||
87 | |||
88 | /* Take the locks in a specific order to keep lockdep happy */ | ||
89 | if (old_rg->id < new_rg->id) { | ||
90 | omapfb_get_mem_region(old_rg); | ||
91 | omapfb_get_mem_region(new_rg); | ||
92 | } else if (new_rg->id < old_rg->id) { | ||
93 | omapfb_get_mem_region(new_rg); | ||
94 | omapfb_get_mem_region(old_rg); | ||
95 | } else | ||
96 | omapfb_get_mem_region(old_rg); | ||
97 | |||
98 | if (pi->enabled && !new_rg->size) { | ||
99 | /* | ||
100 | * This plane's memory was freed, can't enable it | ||
101 | * until it's reallocated. | ||
102 | */ | ||
103 | r = -EINVAL; | ||
104 | goto put_mem; | ||
105 | } | ||
106 | |||
107 | ovl->get_overlay_info(ovl, &old_info); | ||
108 | |||
109 | if (old_rg != new_rg) { | ||
110 | ofbi->region = new_rg; | ||
111 | set_fb_fix(fbi); | ||
112 | } | ||
113 | |||
114 | if (!pi->enabled) { | ||
115 | r = ovl->disable(ovl); | ||
116 | if (r) | ||
117 | goto undo; | ||
118 | } | ||
119 | |||
120 | if (pi->enabled) { | ||
121 | r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, | ||
122 | pi->out_width, pi->out_height); | ||
123 | if (r) | ||
124 | goto undo; | ||
125 | } else { | ||
126 | struct omap_overlay_info info; | ||
127 | |||
128 | ovl->get_overlay_info(ovl, &info); | ||
129 | |||
130 | info.pos_x = pi->pos_x; | ||
131 | info.pos_y = pi->pos_y; | ||
132 | info.out_width = pi->out_width; | ||
133 | info.out_height = pi->out_height; | ||
134 | |||
135 | r = ovl->set_overlay_info(ovl, &info); | ||
136 | if (r) | ||
137 | goto undo; | ||
138 | } | ||
139 | |||
140 | if (ovl->manager) | ||
141 | ovl->manager->apply(ovl->manager); | ||
142 | |||
143 | if (pi->enabled) { | ||
144 | r = ovl->enable(ovl); | ||
145 | if (r) | ||
146 | goto undo; | ||
147 | } | ||
148 | |||
149 | /* Release the locks in a specific order to keep lockdep happy */ | ||
150 | if (old_rg->id > new_rg->id) { | ||
151 | omapfb_put_mem_region(old_rg); | ||
152 | omapfb_put_mem_region(new_rg); | ||
153 | } else if (new_rg->id > old_rg->id) { | ||
154 | omapfb_put_mem_region(new_rg); | ||
155 | omapfb_put_mem_region(old_rg); | ||
156 | } else | ||
157 | omapfb_put_mem_region(old_rg); | ||
158 | |||
159 | return 0; | ||
160 | |||
161 | undo: | ||
162 | if (old_rg != new_rg) { | ||
163 | ofbi->region = old_rg; | ||
164 | set_fb_fix(fbi); | ||
165 | } | ||
166 | |||
167 | ovl->set_overlay_info(ovl, &old_info); | ||
168 | put_mem: | ||
169 | /* Release the locks in a specific order to keep lockdep happy */ | ||
170 | if (old_rg->id > new_rg->id) { | ||
171 | omapfb_put_mem_region(old_rg); | ||
172 | omapfb_put_mem_region(new_rg); | ||
173 | } else if (new_rg->id > old_rg->id) { | ||
174 | omapfb_put_mem_region(new_rg); | ||
175 | omapfb_put_mem_region(old_rg); | ||
176 | } else | ||
177 | omapfb_put_mem_region(old_rg); | ||
178 | out: | ||
179 | dev_err(fbdev->dev, "setup_plane failed\n"); | ||
180 | |||
181 | return r; | ||
182 | } | ||
183 | |||
184 | static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | ||
185 | { | ||
186 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
187 | |||
188 | if (ofbi->num_overlays == 0) { | ||
189 | memset(pi, 0, sizeof(*pi)); | ||
190 | } else { | ||
191 | struct omap_overlay *ovl; | ||
192 | struct omap_overlay_info ovli; | ||
193 | |||
194 | ovl = ofbi->overlays[0]; | ||
195 | ovl->get_overlay_info(ovl, &ovli); | ||
196 | |||
197 | pi->pos_x = ovli.pos_x; | ||
198 | pi->pos_y = ovli.pos_y; | ||
199 | pi->enabled = ovl->is_enabled(ovl); | ||
200 | pi->channel_out = 0; /* xxx */ | ||
201 | pi->mirror = 0; | ||
202 | pi->mem_idx = get_mem_idx(ofbi); | ||
203 | pi->out_width = ovli.out_width; | ||
204 | pi->out_height = ovli.out_height; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
211 | { | ||
212 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
213 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
214 | struct omap_dss_device *display = fb2display(fbi); | ||
215 | struct omapfb2_mem_region *rg; | ||
216 | int r = 0, i; | ||
217 | size_t size; | ||
218 | |||
219 | if (mi->type != OMAPFB_MEMTYPE_SDRAM) | ||
220 | return -EINVAL; | ||
221 | |||
222 | size = PAGE_ALIGN(mi->size); | ||
223 | |||
224 | if (display && display->driver->sync) | ||
225 | display->driver->sync(display); | ||
226 | |||
227 | rg = ofbi->region; | ||
228 | |||
229 | down_write_nested(&rg->lock, rg->id); | ||
230 | atomic_inc(&rg->lock_count); | ||
231 | |||
232 | if (rg->size == size && rg->type == mi->type) | ||
233 | goto out; | ||
234 | |||
235 | if (atomic_read(&rg->map_count)) { | ||
236 | r = -EBUSY; | ||
237 | goto out; | ||
238 | } | ||
239 | |||
240 | for (i = 0; i < fbdev->num_fbs; i++) { | ||
241 | struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); | ||
242 | int j; | ||
243 | |||
244 | if (ofbi2->region != rg) | ||
245 | continue; | ||
246 | |||
247 | for (j = 0; j < ofbi2->num_overlays; j++) { | ||
248 | struct omap_overlay *ovl; | ||
249 | ovl = ofbi2->overlays[j]; | ||
250 | if (ovl->is_enabled(ovl)) { | ||
251 | r = -EBUSY; | ||
252 | goto out; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | r = omapfb_realloc_fbmem(fbi, size, mi->type); | ||
258 | if (r) { | ||
259 | dev_err(fbdev->dev, "realloc fbmem failed\n"); | ||
260 | goto out; | ||
261 | } | ||
262 | |||
263 | out: | ||
264 | atomic_dec(&rg->lock_count); | ||
265 | up_write(&rg->lock); | ||
266 | |||
267 | return r; | ||
268 | } | ||
269 | |||
270 | static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | ||
271 | { | ||
272 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
273 | struct omapfb2_mem_region *rg; | ||
274 | |||
275 | rg = omapfb_get_mem_region(ofbi->region); | ||
276 | memset(mi, 0, sizeof(*mi)); | ||
277 | |||
278 | mi->size = rg->size; | ||
279 | mi->type = rg->type; | ||
280 | |||
281 | omapfb_put_mem_region(rg); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int omapfb_update_window(struct fb_info *fbi, | ||
287 | u32 x, u32 y, u32 w, u32 h) | ||
288 | { | ||
289 | struct omap_dss_device *display = fb2display(fbi); | ||
290 | u16 dw, dh; | ||
291 | |||
292 | if (!display) | ||
293 | return 0; | ||
294 | |||
295 | if (w == 0 || h == 0) | ||
296 | return 0; | ||
297 | |||
298 | display->driver->get_resolution(display, &dw, &dh); | ||
299 | |||
300 | if (x + w > dw || y + h > dh) | ||
301 | return -EINVAL; | ||
302 | |||
303 | return display->driver->update(display, x, y, w, h); | ||
304 | } | ||
305 | |||
306 | int omapfb_set_update_mode(struct fb_info *fbi, | ||
307 | enum omapfb_update_mode mode) | ||
308 | { | ||
309 | struct omap_dss_device *display = fb2display(fbi); | ||
310 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
311 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
312 | struct omapfb_display_data *d; | ||
313 | int r; | ||
314 | |||
315 | if (!display) | ||
316 | return -EINVAL; | ||
317 | |||
318 | if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE) | ||
319 | return -EINVAL; | ||
320 | |||
321 | omapfb_lock(fbdev); | ||
322 | |||
323 | d = get_display_data(fbdev, display); | ||
324 | |||
325 | if (d->update_mode == mode) { | ||
326 | omapfb_unlock(fbdev); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | r = 0; | ||
331 | |||
332 | if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) { | ||
333 | if (mode == OMAPFB_AUTO_UPDATE) | ||
334 | omapfb_start_auto_update(fbdev, display); | ||
335 | else /* MANUAL_UPDATE */ | ||
336 | omapfb_stop_auto_update(fbdev, display); | ||
337 | |||
338 | d->update_mode = mode; | ||
339 | } else { /* AUTO_UPDATE */ | ||
340 | if (mode == OMAPFB_MANUAL_UPDATE) | ||
341 | r = -EINVAL; | ||
342 | } | ||
343 | |||
344 | omapfb_unlock(fbdev); | ||
345 | |||
346 | return r; | ||
347 | } | ||
348 | |||
349 | int omapfb_get_update_mode(struct fb_info *fbi, | ||
350 | enum omapfb_update_mode *mode) | ||
351 | { | ||
352 | struct omap_dss_device *display = fb2display(fbi); | ||
353 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
354 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
355 | struct omapfb_display_data *d; | ||
356 | |||
357 | if (!display) | ||
358 | return -EINVAL; | ||
359 | |||
360 | omapfb_lock(fbdev); | ||
361 | |||
362 | d = get_display_data(fbdev, display); | ||
363 | |||
364 | *mode = d->update_mode; | ||
365 | |||
366 | omapfb_unlock(fbdev); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | /* XXX this color key handling is a hack... */ | ||
372 | static struct omapfb_color_key omapfb_color_keys[2]; | ||
373 | |||
374 | static int _omapfb_set_color_key(struct omap_overlay_manager *mgr, | ||
375 | struct omapfb_color_key *ck) | ||
376 | { | ||
377 | struct omap_overlay_manager_info info; | ||
378 | enum omap_dss_trans_key_type kt; | ||
379 | int r; | ||
380 | |||
381 | mgr->get_manager_info(mgr, &info); | ||
382 | |||
383 | if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) { | ||
384 | info.trans_enabled = false; | ||
385 | omapfb_color_keys[mgr->id] = *ck; | ||
386 | |||
387 | r = mgr->set_manager_info(mgr, &info); | ||
388 | if (r) | ||
389 | return r; | ||
390 | |||
391 | r = mgr->apply(mgr); | ||
392 | |||
393 | return r; | ||
394 | } | ||
395 | |||
396 | switch (ck->key_type) { | ||
397 | case OMAPFB_COLOR_KEY_GFX_DST: | ||
398 | kt = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
399 | break; | ||
400 | case OMAPFB_COLOR_KEY_VID_SRC: | ||
401 | kt = OMAP_DSS_COLOR_KEY_VID_SRC; | ||
402 | break; | ||
403 | default: | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | info.default_color = ck->background; | ||
408 | info.trans_key = ck->trans_key; | ||
409 | info.trans_key_type = kt; | ||
410 | info.trans_enabled = true; | ||
411 | |||
412 | omapfb_color_keys[mgr->id] = *ck; | ||
413 | |||
414 | r = mgr->set_manager_info(mgr, &info); | ||
415 | if (r) | ||
416 | return r; | ||
417 | |||
418 | r = mgr->apply(mgr); | ||
419 | |||
420 | return r; | ||
421 | } | ||
422 | |||
423 | static int omapfb_set_color_key(struct fb_info *fbi, | ||
424 | struct omapfb_color_key *ck) | ||
425 | { | ||
426 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
427 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
428 | int r; | ||
429 | int i; | ||
430 | struct omap_overlay_manager *mgr = NULL; | ||
431 | |||
432 | omapfb_lock(fbdev); | ||
433 | |||
434 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
435 | if (ofbi->overlays[i]->manager) { | ||
436 | mgr = ofbi->overlays[i]->manager; | ||
437 | break; | ||
438 | } | ||
439 | } | ||
440 | |||
441 | if (!mgr) { | ||
442 | r = -EINVAL; | ||
443 | goto err; | ||
444 | } | ||
445 | |||
446 | r = _omapfb_set_color_key(mgr, ck); | ||
447 | err: | ||
448 | omapfb_unlock(fbdev); | ||
449 | |||
450 | return r; | ||
451 | } | ||
452 | |||
453 | static int omapfb_get_color_key(struct fb_info *fbi, | ||
454 | struct omapfb_color_key *ck) | ||
455 | { | ||
456 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
457 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
458 | struct omap_overlay_manager *mgr = NULL; | ||
459 | int r = 0; | ||
460 | int i; | ||
461 | |||
462 | omapfb_lock(fbdev); | ||
463 | |||
464 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
465 | if (ofbi->overlays[i]->manager) { | ||
466 | mgr = ofbi->overlays[i]->manager; | ||
467 | break; | ||
468 | } | ||
469 | } | ||
470 | |||
471 | if (!mgr) { | ||
472 | r = -EINVAL; | ||
473 | goto err; | ||
474 | } | ||
475 | |||
476 | *ck = omapfb_color_keys[mgr->id]; | ||
477 | err: | ||
478 | omapfb_unlock(fbdev); | ||
479 | |||
480 | return r; | ||
481 | } | ||
482 | |||
483 | static int omapfb_memory_read(struct fb_info *fbi, | ||
484 | struct omapfb_memory_read *mr) | ||
485 | { | ||
486 | struct omap_dss_device *display = fb2display(fbi); | ||
487 | void *buf; | ||
488 | int r; | ||
489 | |||
490 | if (!display || !display->driver->memory_read) | ||
491 | return -ENOENT; | ||
492 | |||
493 | if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size)) | ||
494 | return -EFAULT; | ||
495 | |||
496 | if (mr->w * mr->h * 3 > mr->buffer_size) | ||
497 | return -EINVAL; | ||
498 | |||
499 | buf = vmalloc(mr->buffer_size); | ||
500 | if (!buf) { | ||
501 | DBG("vmalloc failed\n"); | ||
502 | return -ENOMEM; | ||
503 | } | ||
504 | |||
505 | r = display->driver->memory_read(display, buf, mr->buffer_size, | ||
506 | mr->x, mr->y, mr->w, mr->h); | ||
507 | |||
508 | if (r > 0) { | ||
509 | if (copy_to_user(mr->buffer, buf, mr->buffer_size)) | ||
510 | r = -EFAULT; | ||
511 | } | ||
512 | |||
513 | vfree(buf); | ||
514 | |||
515 | return r; | ||
516 | } | ||
517 | |||
518 | static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev, | ||
519 | struct omapfb_ovl_colormode *mode) | ||
520 | { | ||
521 | int ovl_idx = mode->overlay_idx; | ||
522 | int mode_idx = mode->mode_idx; | ||
523 | struct omap_overlay *ovl; | ||
524 | enum omap_color_mode supported_modes; | ||
525 | struct fb_var_screeninfo var; | ||
526 | int i; | ||
527 | |||
528 | if (ovl_idx >= fbdev->num_overlays) | ||
529 | return -ENODEV; | ||
530 | ovl = fbdev->overlays[ovl_idx]; | ||
531 | supported_modes = ovl->supported_modes; | ||
532 | |||
533 | mode_idx = mode->mode_idx; | ||
534 | |||
535 | for (i = 0; i < sizeof(supported_modes) * 8; i++) { | ||
536 | if (!(supported_modes & (1 << i))) | ||
537 | continue; | ||
538 | /* | ||
539 | * It's possible that the FB doesn't support a mode | ||
540 | * that is supported by the overlay, so call the | ||
541 | * following here. | ||
542 | */ | ||
543 | if (dss_mode_to_fb_mode(1 << i, &var) < 0) | ||
544 | continue; | ||
545 | |||
546 | mode_idx--; | ||
547 | if (mode_idx < 0) | ||
548 | break; | ||
549 | } | ||
550 | |||
551 | if (i == sizeof(supported_modes) * 8) | ||
552 | return -ENOENT; | ||
553 | |||
554 | mode->bits_per_pixel = var.bits_per_pixel; | ||
555 | mode->nonstd = var.nonstd; | ||
556 | mode->red = var.red; | ||
557 | mode->green = var.green; | ||
558 | mode->blue = var.blue; | ||
559 | mode->transp = var.transp; | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | static int omapfb_wait_for_go(struct fb_info *fbi) | ||
565 | { | ||
566 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
567 | int r = 0; | ||
568 | int i; | ||
569 | |||
570 | for (i = 0; i < ofbi->num_overlays; ++i) { | ||
571 | struct omap_overlay *ovl = ofbi->overlays[i]; | ||
572 | r = ovl->wait_for_go(ovl); | ||
573 | if (r) | ||
574 | break; | ||
575 | } | ||
576 | |||
577 | return r; | ||
578 | } | ||
579 | |||
580 | int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | ||
581 | { | ||
582 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
583 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
584 | struct omap_dss_device *display = fb2display(fbi); | ||
585 | struct omap_overlay_manager *mgr; | ||
586 | |||
587 | union { | ||
588 | struct omapfb_update_window_old uwnd_o; | ||
589 | struct omapfb_update_window uwnd; | ||
590 | struct omapfb_plane_info plane_info; | ||
591 | struct omapfb_caps caps; | ||
592 | struct omapfb_mem_info mem_info; | ||
593 | struct omapfb_color_key color_key; | ||
594 | struct omapfb_ovl_colormode ovl_colormode; | ||
595 | enum omapfb_update_mode update_mode; | ||
596 | int test_num; | ||
597 | struct omapfb_memory_read memory_read; | ||
598 | struct omapfb_vram_info vram_info; | ||
599 | struct omapfb_tearsync_info tearsync_info; | ||
600 | struct omapfb_display_info display_info; | ||
601 | u32 crt; | ||
602 | } p; | ||
603 | |||
604 | int r = 0; | ||
605 | |||
606 | switch (cmd) { | ||
607 | case OMAPFB_SYNC_GFX: | ||
608 | DBG("ioctl SYNC_GFX\n"); | ||
609 | if (!display || !display->driver->sync) { | ||
610 | /* DSS1 never returns an error here, so we neither */ | ||
611 | /*r = -EINVAL;*/ | ||
612 | break; | ||
613 | } | ||
614 | |||
615 | r = display->driver->sync(display); | ||
616 | break; | ||
617 | |||
618 | case OMAPFB_UPDATE_WINDOW_OLD: | ||
619 | DBG("ioctl UPDATE_WINDOW_OLD\n"); | ||
620 | if (!display || !display->driver->update) { | ||
621 | r = -EINVAL; | ||
622 | break; | ||
623 | } | ||
624 | |||
625 | if (copy_from_user(&p.uwnd_o, | ||
626 | (void __user *)arg, | ||
627 | sizeof(p.uwnd_o))) { | ||
628 | r = -EFAULT; | ||
629 | break; | ||
630 | } | ||
631 | |||
632 | r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y, | ||
633 | p.uwnd_o.width, p.uwnd_o.height); | ||
634 | break; | ||
635 | |||
636 | case OMAPFB_UPDATE_WINDOW: | ||
637 | DBG("ioctl UPDATE_WINDOW\n"); | ||
638 | if (!display || !display->driver->update) { | ||
639 | r = -EINVAL; | ||
640 | break; | ||
641 | } | ||
642 | |||
643 | if (copy_from_user(&p.uwnd, (void __user *)arg, | ||
644 | sizeof(p.uwnd))) { | ||
645 | r = -EFAULT; | ||
646 | break; | ||
647 | } | ||
648 | |||
649 | r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y, | ||
650 | p.uwnd.width, p.uwnd.height); | ||
651 | break; | ||
652 | |||
653 | case OMAPFB_SETUP_PLANE: | ||
654 | DBG("ioctl SETUP_PLANE\n"); | ||
655 | if (copy_from_user(&p.plane_info, (void __user *)arg, | ||
656 | sizeof(p.plane_info))) | ||
657 | r = -EFAULT; | ||
658 | else | ||
659 | r = omapfb_setup_plane(fbi, &p.plane_info); | ||
660 | break; | ||
661 | |||
662 | case OMAPFB_QUERY_PLANE: | ||
663 | DBG("ioctl QUERY_PLANE\n"); | ||
664 | r = omapfb_query_plane(fbi, &p.plane_info); | ||
665 | if (r < 0) | ||
666 | break; | ||
667 | if (copy_to_user((void __user *)arg, &p.plane_info, | ||
668 | sizeof(p.plane_info))) | ||
669 | r = -EFAULT; | ||
670 | break; | ||
671 | |||
672 | case OMAPFB_SETUP_MEM: | ||
673 | DBG("ioctl SETUP_MEM\n"); | ||
674 | if (copy_from_user(&p.mem_info, (void __user *)arg, | ||
675 | sizeof(p.mem_info))) | ||
676 | r = -EFAULT; | ||
677 | else | ||
678 | r = omapfb_setup_mem(fbi, &p.mem_info); | ||
679 | break; | ||
680 | |||
681 | case OMAPFB_QUERY_MEM: | ||
682 | DBG("ioctl QUERY_MEM\n"); | ||
683 | r = omapfb_query_mem(fbi, &p.mem_info); | ||
684 | if (r < 0) | ||
685 | break; | ||
686 | if (copy_to_user((void __user *)arg, &p.mem_info, | ||
687 | sizeof(p.mem_info))) | ||
688 | r = -EFAULT; | ||
689 | break; | ||
690 | |||
691 | case OMAPFB_GET_CAPS: | ||
692 | DBG("ioctl GET_CAPS\n"); | ||
693 | if (!display) { | ||
694 | r = -EINVAL; | ||
695 | break; | ||
696 | } | ||
697 | |||
698 | memset(&p.caps, 0, sizeof(p.caps)); | ||
699 | if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
700 | p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE; | ||
701 | if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM) | ||
702 | p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC; | ||
703 | |||
704 | if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) | ||
705 | r = -EFAULT; | ||
706 | break; | ||
707 | |||
708 | case OMAPFB_GET_OVERLAY_COLORMODE: | ||
709 | DBG("ioctl GET_OVERLAY_COLORMODE\n"); | ||
710 | if (copy_from_user(&p.ovl_colormode, (void __user *)arg, | ||
711 | sizeof(p.ovl_colormode))) { | ||
712 | r = -EFAULT; | ||
713 | break; | ||
714 | } | ||
715 | r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode); | ||
716 | if (r < 0) | ||
717 | break; | ||
718 | if (copy_to_user((void __user *)arg, &p.ovl_colormode, | ||
719 | sizeof(p.ovl_colormode))) | ||
720 | r = -EFAULT; | ||
721 | break; | ||
722 | |||
723 | case OMAPFB_SET_UPDATE_MODE: | ||
724 | DBG("ioctl SET_UPDATE_MODE\n"); | ||
725 | if (get_user(p.update_mode, (int __user *)arg)) | ||
726 | r = -EFAULT; | ||
727 | else | ||
728 | r = omapfb_set_update_mode(fbi, p.update_mode); | ||
729 | break; | ||
730 | |||
731 | case OMAPFB_GET_UPDATE_MODE: | ||
732 | DBG("ioctl GET_UPDATE_MODE\n"); | ||
733 | r = omapfb_get_update_mode(fbi, &p.update_mode); | ||
734 | if (r) | ||
735 | break; | ||
736 | if (put_user(p.update_mode, | ||
737 | (enum omapfb_update_mode __user *)arg)) | ||
738 | r = -EFAULT; | ||
739 | break; | ||
740 | |||
741 | case OMAPFB_SET_COLOR_KEY: | ||
742 | DBG("ioctl SET_COLOR_KEY\n"); | ||
743 | if (copy_from_user(&p.color_key, (void __user *)arg, | ||
744 | sizeof(p.color_key))) | ||
745 | r = -EFAULT; | ||
746 | else | ||
747 | r = omapfb_set_color_key(fbi, &p.color_key); | ||
748 | break; | ||
749 | |||
750 | case OMAPFB_GET_COLOR_KEY: | ||
751 | DBG("ioctl GET_COLOR_KEY\n"); | ||
752 | r = omapfb_get_color_key(fbi, &p.color_key); | ||
753 | if (r) | ||
754 | break; | ||
755 | if (copy_to_user((void __user *)arg, &p.color_key, | ||
756 | sizeof(p.color_key))) | ||
757 | r = -EFAULT; | ||
758 | break; | ||
759 | |||
760 | case FBIO_WAITFORVSYNC: | ||
761 | if (get_user(p.crt, (__u32 __user *)arg)) { | ||
762 | r = -EFAULT; | ||
763 | break; | ||
764 | } | ||
765 | if (p.crt != 0) { | ||
766 | r = -ENODEV; | ||
767 | break; | ||
768 | } | ||
769 | /* FALLTHROUGH */ | ||
770 | |||
771 | case OMAPFB_WAITFORVSYNC: | ||
772 | DBG("ioctl WAITFORVSYNC\n"); | ||
773 | |||
774 | if (!display) { | ||
775 | r = -EINVAL; | ||
776 | break; | ||
777 | } | ||
778 | |||
779 | mgr = omapdss_find_mgr_from_display(display); | ||
780 | if (!mgr) { | ||
781 | r = -EINVAL; | ||
782 | break; | ||
783 | } | ||
784 | |||
785 | r = mgr->wait_for_vsync(mgr); | ||
786 | break; | ||
787 | |||
788 | case OMAPFB_WAITFORGO: | ||
789 | DBG("ioctl WAITFORGO\n"); | ||
790 | if (!display) { | ||
791 | r = -EINVAL; | ||
792 | break; | ||
793 | } | ||
794 | |||
795 | r = omapfb_wait_for_go(fbi); | ||
796 | break; | ||
797 | |||
798 | /* LCD and CTRL tests do the same thing for backward | ||
799 | * compatibility */ | ||
800 | case OMAPFB_LCD_TEST: | ||
801 | DBG("ioctl LCD_TEST\n"); | ||
802 | if (get_user(p.test_num, (int __user *)arg)) { | ||
803 | r = -EFAULT; | ||
804 | break; | ||
805 | } | ||
806 | if (!display || !display->driver->run_test) { | ||
807 | r = -EINVAL; | ||
808 | break; | ||
809 | } | ||
810 | |||
811 | r = display->driver->run_test(display, p.test_num); | ||
812 | |||
813 | break; | ||
814 | |||
815 | case OMAPFB_CTRL_TEST: | ||
816 | DBG("ioctl CTRL_TEST\n"); | ||
817 | if (get_user(p.test_num, (int __user *)arg)) { | ||
818 | r = -EFAULT; | ||
819 | break; | ||
820 | } | ||
821 | if (!display || !display->driver->run_test) { | ||
822 | r = -EINVAL; | ||
823 | break; | ||
824 | } | ||
825 | |||
826 | r = display->driver->run_test(display, p.test_num); | ||
827 | |||
828 | break; | ||
829 | |||
830 | case OMAPFB_MEMORY_READ: | ||
831 | DBG("ioctl MEMORY_READ\n"); | ||
832 | |||
833 | if (copy_from_user(&p.memory_read, (void __user *)arg, | ||
834 | sizeof(p.memory_read))) { | ||
835 | r = -EFAULT; | ||
836 | break; | ||
837 | } | ||
838 | |||
839 | r = omapfb_memory_read(fbi, &p.memory_read); | ||
840 | |||
841 | break; | ||
842 | |||
843 | case OMAPFB_GET_VRAM_INFO: { | ||
844 | DBG("ioctl GET_VRAM_INFO\n"); | ||
845 | |||
846 | /* | ||
847 | * We don't have the ability to get this vram info anymore. | ||
848 | * Fill in something that should keep the applications working. | ||
849 | */ | ||
850 | p.vram_info.total = SZ_1M * 64; | ||
851 | p.vram_info.free = SZ_1M * 64; | ||
852 | p.vram_info.largest_free_block = SZ_1M * 64; | ||
853 | |||
854 | if (copy_to_user((void __user *)arg, &p.vram_info, | ||
855 | sizeof(p.vram_info))) | ||
856 | r = -EFAULT; | ||
857 | break; | ||
858 | } | ||
859 | |||
860 | case OMAPFB_SET_TEARSYNC: { | ||
861 | DBG("ioctl SET_TEARSYNC\n"); | ||
862 | |||
863 | if (copy_from_user(&p.tearsync_info, (void __user *)arg, | ||
864 | sizeof(p.tearsync_info))) { | ||
865 | r = -EFAULT; | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | if (!display || !display->driver->enable_te) { | ||
870 | r = -ENODEV; | ||
871 | break; | ||
872 | } | ||
873 | |||
874 | r = display->driver->enable_te(display, | ||
875 | !!p.tearsync_info.enabled); | ||
876 | |||
877 | break; | ||
878 | } | ||
879 | |||
880 | case OMAPFB_GET_DISPLAY_INFO: { | ||
881 | u16 xres, yres; | ||
882 | |||
883 | DBG("ioctl GET_DISPLAY_INFO\n"); | ||
884 | |||
885 | if (display == NULL) { | ||
886 | r = -ENODEV; | ||
887 | break; | ||
888 | } | ||
889 | |||
890 | display->driver->get_resolution(display, &xres, &yres); | ||
891 | |||
892 | p.display_info.xres = xres; | ||
893 | p.display_info.yres = yres; | ||
894 | |||
895 | if (display->driver->get_dimensions) { | ||
896 | u32 w, h; | ||
897 | display->driver->get_dimensions(display, &w, &h); | ||
898 | p.display_info.width = w; | ||
899 | p.display_info.height = h; | ||
900 | } else { | ||
901 | p.display_info.width = 0; | ||
902 | p.display_info.height = 0; | ||
903 | } | ||
904 | |||
905 | if (copy_to_user((void __user *)arg, &p.display_info, | ||
906 | sizeof(p.display_info))) | ||
907 | r = -EFAULT; | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | default: | ||
912 | dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); | ||
913 | r = -EINVAL; | ||
914 | } | ||
915 | |||
916 | if (r < 0) | ||
917 | DBG("ioctl failed: %d\n", r); | ||
918 | |||
919 | return r; | ||
920 | } | ||
921 | |||
922 | |||