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