Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
omapfb-ioctl.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/video/omap2/omapfb-ioctl.c
3  *
4  * Copyright (C) 2008 Nokia Corporation
5  * Author: Tomi Valkeinen <[email protected]>
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 
32 #include <video/omapdss.h>
33 #include <plat/vrfb.h>
34 #include <plat/vram.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 omapfb2_mem_region *rg;
215  int r = 0, i;
216  size_t size;
217 
218  if (mi->type != OMAPFB_MEMTYPE_SDRAM)
219  return -EINVAL;
220 
221  size = PAGE_ALIGN(mi->size);
222 
223  rg = ofbi->region;
224 
225  down_write_nested(&rg->lock, rg->id);
226  atomic_inc(&rg->lock_count);
227 
228  if (rg->size == size && rg->type == mi->type)
229  goto out;
230 
231  if (atomic_read(&rg->map_count)) {
232  r = -EBUSY;
233  goto out;
234  }
235 
236  for (i = 0; i < fbdev->num_fbs; i++) {
237  struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
238  int j;
239 
240  if (ofbi2->region != rg)
241  continue;
242 
243  for (j = 0; j < ofbi2->num_overlays; j++) {
244  struct omap_overlay *ovl;
245  ovl = ofbi2->overlays[j];
246  if (ovl->is_enabled(ovl)) {
247  r = -EBUSY;
248  goto out;
249  }
250  }
251  }
252 
253  r = omapfb_realloc_fbmem(fbi, size, mi->type);
254  if (r) {
255  dev_err(fbdev->dev, "realloc fbmem failed\n");
256  goto out;
257  }
258 
259  out:
260  atomic_dec(&rg->lock_count);
261  up_write(&rg->lock);
262 
263  return r;
264 }
265 
266 static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
267 {
268  struct omapfb_info *ofbi = FB2OFB(fbi);
269  struct omapfb2_mem_region *rg;
270 
271  rg = omapfb_get_mem_region(ofbi->region);
272  memset(mi, 0, sizeof(*mi));
273 
274  mi->size = rg->size;
275  mi->type = rg->type;
276 
277  omapfb_put_mem_region(rg);
278 
279  return 0;
280 }
281 
282 static int omapfb_update_window_nolock(struct fb_info *fbi,
283  u32 x, u32 y, u32 w, u32 h)
284 {
285  struct omap_dss_device *display = fb2display(fbi);
286  u16 dw, dh;
287 
288  if (!display)
289  return 0;
290 
291  if (w == 0 || h == 0)
292  return 0;
293 
294  display->driver->get_resolution(display, &dw, &dh);
295 
296  if (x + w > dw || y + h > dh)
297  return -EINVAL;
298 
299  return display->driver->update(display, x, y, w, h);
300 }
301 
302 /* This function is exported for SGX driver use */
304  u32 x, u32 y, u32 w, u32 h)
305 {
306  struct omapfb_info *ofbi = FB2OFB(fbi);
307  struct omapfb2_device *fbdev = ofbi->fbdev;
308  int r;
309 
310  if (!lock_fb_info(fbi))
311  return -ENODEV;
312  omapfb_lock(fbdev);
313 
314  r = omapfb_update_window_nolock(fbi, x, y, w, h);
315 
316  omapfb_unlock(fbdev);
317  unlock_fb_info(fbi);
318 
319  return r;
320 }
322 
325 {
326  struct omap_dss_device *display = fb2display(fbi);
327  struct omapfb_info *ofbi = FB2OFB(fbi);
328  struct omapfb2_device *fbdev = ofbi->fbdev;
329  struct omapfb_display_data *d;
330  int r;
331 
332  if (!display)
333  return -EINVAL;
334 
335  if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
336  return -EINVAL;
337 
338  omapfb_lock(fbdev);
339 
340  d = get_display_data(fbdev, display);
341 
342  if (d->update_mode == mode) {
343  omapfb_unlock(fbdev);
344  return 0;
345  }
346 
347  r = 0;
348 
349  if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
350  if (mode == OMAPFB_AUTO_UPDATE)
351  omapfb_start_auto_update(fbdev, display);
352  else /* MANUAL_UPDATE */
353  omapfb_stop_auto_update(fbdev, display);
354 
355  d->update_mode = mode;
356  } else { /* AUTO_UPDATE */
357  if (mode == OMAPFB_MANUAL_UPDATE)
358  r = -EINVAL;
359  }
360 
361  omapfb_unlock(fbdev);
362 
363  return r;
364 }
365 
367  enum omapfb_update_mode *mode)
368 {
369  struct omap_dss_device *display = fb2display(fbi);
370  struct omapfb_info *ofbi = FB2OFB(fbi);
371  struct omapfb2_device *fbdev = ofbi->fbdev;
372  struct omapfb_display_data *d;
373 
374  if (!display)
375  return -EINVAL;
376 
377  omapfb_lock(fbdev);
378 
379  d = get_display_data(fbdev, display);
380 
381  *mode = d->update_mode;
382 
383  omapfb_unlock(fbdev);
384 
385  return 0;
386 }
387 
388 /* XXX this color key handling is a hack... */
389 static struct omapfb_color_key omapfb_color_keys[2];
390 
391 static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
392  struct omapfb_color_key *ck)
393 {
395  enum omap_dss_trans_key_type kt;
396  int r;
397 
398  mgr->get_manager_info(mgr, &info);
399 
400  if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
401  info.trans_enabled = false;
402  omapfb_color_keys[mgr->id] = *ck;
403 
404  r = mgr->set_manager_info(mgr, &info);
405  if (r)
406  return r;
407 
408  r = mgr->apply(mgr);
409 
410  return r;
411  }
412 
413  switch (ck->key_type) {
416  break;
419  break;
420  default:
421  return -EINVAL;
422  }
423 
424  info.default_color = ck->background;
425  info.trans_key = ck->trans_key;
426  info.trans_key_type = kt;
427  info.trans_enabled = true;
428 
429  omapfb_color_keys[mgr->id] = *ck;
430 
431  r = mgr->set_manager_info(mgr, &info);
432  if (r)
433  return r;
434 
435  r = mgr->apply(mgr);
436 
437  return r;
438 }
439 
440 static int omapfb_set_color_key(struct fb_info *fbi,
441  struct omapfb_color_key *ck)
442 {
443  struct omapfb_info *ofbi = FB2OFB(fbi);
444  struct omapfb2_device *fbdev = ofbi->fbdev;
445  int r;
446  int i;
447  struct omap_overlay_manager *mgr = NULL;
448 
449  omapfb_lock(fbdev);
450 
451  for (i = 0; i < ofbi->num_overlays; i++) {
452  if (ofbi->overlays[i]->manager) {
453  mgr = ofbi->overlays[i]->manager;
454  break;
455  }
456  }
457 
458  if (!mgr) {
459  r = -EINVAL;
460  goto err;
461  }
462 
463  r = _omapfb_set_color_key(mgr, ck);
464 err:
465  omapfb_unlock(fbdev);
466 
467  return r;
468 }
469 
470 static int omapfb_get_color_key(struct fb_info *fbi,
471  struct omapfb_color_key *ck)
472 {
473  struct omapfb_info *ofbi = FB2OFB(fbi);
474  struct omapfb2_device *fbdev = ofbi->fbdev;
475  struct omap_overlay_manager *mgr = NULL;
476  int r = 0;
477  int i;
478 
479  omapfb_lock(fbdev);
480 
481  for (i = 0; i < ofbi->num_overlays; i++) {
482  if (ofbi->overlays[i]->manager) {
483  mgr = ofbi->overlays[i]->manager;
484  break;
485  }
486  }
487 
488  if (!mgr) {
489  r = -EINVAL;
490  goto err;
491  }
492 
493  *ck = omapfb_color_keys[mgr->id];
494 err:
495  omapfb_unlock(fbdev);
496 
497  return r;
498 }
499 
500 static int omapfb_memory_read(struct fb_info *fbi,
501  struct omapfb_memory_read *mr)
502 {
503  struct omap_dss_device *display = fb2display(fbi);
504  void *buf;
505  int r;
506 
507  if (!display || !display->driver->memory_read)
508  return -ENOENT;
509 
510  if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
511  return -EFAULT;
512 
513  if (mr->w * mr->h * 3 > mr->buffer_size)
514  return -EINVAL;
515 
516  buf = vmalloc(mr->buffer_size);
517  if (!buf) {
518  DBG("vmalloc failed\n");
519  return -ENOMEM;
520  }
521 
522  r = display->driver->memory_read(display, buf, mr->buffer_size,
523  mr->x, mr->y, mr->w, mr->h);
524 
525  if (r > 0) {
526  if (copy_to_user(mr->buffer, buf, mr->buffer_size))
527  r = -EFAULT;
528  }
529 
530  vfree(buf);
531 
532  return r;
533 }
534 
535 static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
536  struct omapfb_ovl_colormode *mode)
537 {
538  int ovl_idx = mode->overlay_idx;
539  int mode_idx = mode->mode_idx;
540  struct omap_overlay *ovl;
542  struct fb_var_screeninfo var;
543  int i;
544 
545  if (ovl_idx >= fbdev->num_overlays)
546  return -ENODEV;
547  ovl = fbdev->overlays[ovl_idx];
548  supported_modes = ovl->supported_modes;
549 
550  mode_idx = mode->mode_idx;
551 
552  for (i = 0; i < sizeof(supported_modes) * 8; i++) {
553  if (!(supported_modes & (1 << i)))
554  continue;
555  /*
556  * It's possible that the FB doesn't support a mode
557  * that is supported by the overlay, so call the
558  * following here.
559  */
560  if (dss_mode_to_fb_mode(1 << i, &var) < 0)
561  continue;
562 
563  mode_idx--;
564  if (mode_idx < 0)
565  break;
566  }
567 
568  if (i == sizeof(supported_modes) * 8)
569  return -ENOENT;
570 
571  mode->bits_per_pixel = var.bits_per_pixel;
572  mode->nonstd = var.nonstd;
573  mode->red = var.red;
574  mode->green = var.green;
575  mode->blue = var.blue;
576  mode->transp = var.transp;
577 
578  return 0;
579 }
580 
581 static int omapfb_wait_for_go(struct fb_info *fbi)
582 {
583  struct omapfb_info *ofbi = FB2OFB(fbi);
584  int r = 0;
585  int i;
586 
587  for (i = 0; i < ofbi->num_overlays; ++i) {
588  struct omap_overlay *ovl = ofbi->overlays[i];
589  r = ovl->wait_for_go(ovl);
590  if (r)
591  break;
592  }
593 
594  return r;
595 }
596 
597 int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
598 {
599  struct omapfb_info *ofbi = FB2OFB(fbi);
600  struct omapfb2_device *fbdev = ofbi->fbdev;
601  struct omap_dss_device *display = fb2display(fbi);
602  struct omap_overlay_manager *mgr;
603 
604  union {
605  struct omapfb_update_window_old uwnd_o;
606  struct omapfb_update_window uwnd;
607  struct omapfb_plane_info plane_info;
608  struct omapfb_caps caps;
609  struct omapfb_mem_info mem_info;
610  struct omapfb_color_key color_key;
611  struct omapfb_ovl_colormode ovl_colormode;
613  int test_num;
614  struct omapfb_memory_read memory_read;
615  struct omapfb_vram_info vram_info;
616  struct omapfb_tearsync_info tearsync_info;
617  struct omapfb_display_info display_info;
618  u32 crt;
619  } p;
620 
621  int r = 0;
622 
623  switch (cmd) {
624  case OMAPFB_SYNC_GFX:
625  DBG("ioctl SYNC_GFX\n");
626  if (!display || !display->driver->sync) {
627  /* DSS1 never returns an error here, so we neither */
628  /*r = -EINVAL;*/
629  break;
630  }
631 
632  r = display->driver->sync(display);
633  break;
634 
636  DBG("ioctl UPDATE_WINDOW_OLD\n");
637  if (!display || !display->driver->update) {
638  r = -EINVAL;
639  break;
640  }
641 
642  if (copy_from_user(&p.uwnd_o,
643  (void __user *)arg,
644  sizeof(p.uwnd_o))) {
645  r = -EFAULT;
646  break;
647  }
648 
649  r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,
650  p.uwnd_o.width, p.uwnd_o.height);
651  break;
652 
654  DBG("ioctl UPDATE_WINDOW\n");
655  if (!display || !display->driver->update) {
656  r = -EINVAL;
657  break;
658  }
659 
660  if (copy_from_user(&p.uwnd, (void __user *)arg,
661  sizeof(p.uwnd))) {
662  r = -EFAULT;
663  break;
664  }
665 
666  r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,
667  p.uwnd.width, p.uwnd.height);
668  break;
669 
670  case OMAPFB_SETUP_PLANE:
671  DBG("ioctl SETUP_PLANE\n");
672  if (copy_from_user(&p.plane_info, (void __user *)arg,
673  sizeof(p.plane_info)))
674  r = -EFAULT;
675  else
676  r = omapfb_setup_plane(fbi, &p.plane_info);
677  break;
678 
679  case OMAPFB_QUERY_PLANE:
680  DBG("ioctl QUERY_PLANE\n");
681  r = omapfb_query_plane(fbi, &p.plane_info);
682  if (r < 0)
683  break;
684  if (copy_to_user((void __user *)arg, &p.plane_info,
685  sizeof(p.plane_info)))
686  r = -EFAULT;
687  break;
688 
689  case OMAPFB_SETUP_MEM:
690  DBG("ioctl SETUP_MEM\n");
691  if (copy_from_user(&p.mem_info, (void __user *)arg,
692  sizeof(p.mem_info)))
693  r = -EFAULT;
694  else
695  r = omapfb_setup_mem(fbi, &p.mem_info);
696  break;
697 
698  case OMAPFB_QUERY_MEM:
699  DBG("ioctl QUERY_MEM\n");
700  r = omapfb_query_mem(fbi, &p.mem_info);
701  if (r < 0)
702  break;
703  if (copy_to_user((void __user *)arg, &p.mem_info,
704  sizeof(p.mem_info)))
705  r = -EFAULT;
706  break;
707 
708  case OMAPFB_GET_CAPS:
709  DBG("ioctl GET_CAPS\n");
710  if (!display) {
711  r = -EINVAL;
712  break;
713  }
714 
715  memset(&p.caps, 0, sizeof(p.caps));
717  p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
718  if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
719  p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
720 
721  if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
722  r = -EFAULT;
723  break;
724 
726  DBG("ioctl GET_OVERLAY_COLORMODE\n");
727  if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
728  sizeof(p.ovl_colormode))) {
729  r = -EFAULT;
730  break;
731  }
732  r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
733  if (r < 0)
734  break;
735  if (copy_to_user((void __user *)arg, &p.ovl_colormode,
736  sizeof(p.ovl_colormode)))
737  r = -EFAULT;
738  break;
739 
741  DBG("ioctl SET_UPDATE_MODE\n");
742  if (get_user(p.update_mode, (int __user *)arg))
743  r = -EFAULT;
744  else
745  r = omapfb_set_update_mode(fbi, p.update_mode);
746  break;
747 
749  DBG("ioctl GET_UPDATE_MODE\n");
750  r = omapfb_get_update_mode(fbi, &p.update_mode);
751  if (r)
752  break;
753  if (put_user(p.update_mode,
754  (enum omapfb_update_mode __user *)arg))
755  r = -EFAULT;
756  break;
757 
759  DBG("ioctl SET_COLOR_KEY\n");
760  if (copy_from_user(&p.color_key, (void __user *)arg,
761  sizeof(p.color_key)))
762  r = -EFAULT;
763  else
764  r = omapfb_set_color_key(fbi, &p.color_key);
765  break;
766 
768  DBG("ioctl GET_COLOR_KEY\n");
769  r = omapfb_get_color_key(fbi, &p.color_key);
770  if (r)
771  break;
772  if (copy_to_user((void __user *)arg, &p.color_key,
773  sizeof(p.color_key)))
774  r = -EFAULT;
775  break;
776 
777  case FBIO_WAITFORVSYNC:
778  if (get_user(p.crt, (__u32 __user *)arg)) {
779  r = -EFAULT;
780  break;
781  }
782  if (p.crt != 0) {
783  r = -ENODEV;
784  break;
785  }
786  /* FALLTHROUGH */
787 
788  case OMAPFB_WAITFORVSYNC:
789  DBG("ioctl WAITFORVSYNC\n");
790  if (!display || !display->output || !display->output->manager) {
791  r = -EINVAL;
792  break;
793  }
794 
795  mgr = display->output->manager;
796 
797  r = mgr->wait_for_vsync(mgr);
798  break;
799 
800  case OMAPFB_WAITFORGO:
801  DBG("ioctl WAITFORGO\n");
802  if (!display) {
803  r = -EINVAL;
804  break;
805  }
806 
807  r = omapfb_wait_for_go(fbi);
808  break;
809 
810  /* LCD and CTRL tests do the same thing for backward
811  * compatibility */
812  case OMAPFB_LCD_TEST:
813  DBG("ioctl LCD_TEST\n");
814  if (get_user(p.test_num, (int __user *)arg)) {
815  r = -EFAULT;
816  break;
817  }
818  if (!display || !display->driver->run_test) {
819  r = -EINVAL;
820  break;
821  }
822 
823  r = display->driver->run_test(display, p.test_num);
824 
825  break;
826 
827  case OMAPFB_CTRL_TEST:
828  DBG("ioctl CTRL_TEST\n");
829  if (get_user(p.test_num, (int __user *)arg)) {
830  r = -EFAULT;
831  break;
832  }
833  if (!display || !display->driver->run_test) {
834  r = -EINVAL;
835  break;
836  }
837 
838  r = display->driver->run_test(display, p.test_num);
839 
840  break;
841 
842  case OMAPFB_MEMORY_READ:
843  DBG("ioctl MEMORY_READ\n");
844 
845  if (copy_from_user(&p.memory_read, (void __user *)arg,
846  sizeof(p.memory_read))) {
847  r = -EFAULT;
848  break;
849  }
850 
851  r = omapfb_memory_read(fbi, &p.memory_read);
852 
853  break;
854 
855  case OMAPFB_GET_VRAM_INFO: {
856  unsigned long vram, free, largest;
857 
858  DBG("ioctl GET_VRAM_INFO\n");
859 
860  omap_vram_get_info(&vram, &free, &largest);
861  p.vram_info.total = vram;
862  p.vram_info.free = free;
863  p.vram_info.largest_free_block = largest;
864 
865  if (copy_to_user((void __user *)arg, &p.vram_info,
866  sizeof(p.vram_info)))
867  r = -EFAULT;
868  break;
869  }
870 
871  case OMAPFB_SET_TEARSYNC: {
872  DBG("ioctl SET_TEARSYNC\n");
873 
874  if (copy_from_user(&p.tearsync_info, (void __user *)arg,
875  sizeof(p.tearsync_info))) {
876  r = -EFAULT;
877  break;
878  }
879 
880  if (!display || !display->driver->enable_te) {
881  r = -ENODEV;
882  break;
883  }
884 
885  r = display->driver->enable_te(display,
886  !!p.tearsync_info.enabled);
887 
888  break;
889  }
890 
892  u16 xres, yres;
893 
894  DBG("ioctl GET_DISPLAY_INFO\n");
895 
896  if (display == NULL) {
897  r = -ENODEV;
898  break;
899  }
900 
901  display->driver->get_resolution(display, &xres, &yres);
902 
903  p.display_info.xres = xres;
904  p.display_info.yres = yres;
905 
906  if (display->driver->get_dimensions) {
907  u32 w, h;
908  display->driver->get_dimensions(display, &w, &h);
909  p.display_info.width = w;
910  p.display_info.height = h;
911  } else {
912  p.display_info.width = 0;
913  p.display_info.height = 0;
914  }
915 
916  if (copy_to_user((void __user *)arg, &p.display_info,
917  sizeof(p.display_info)))
918  r = -EFAULT;
919  break;
920  }
921 
922  default:
923  dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
924  r = -EINVAL;
925  }
926 
927  if (r < 0)
928  DBG("ioctl failed: %d\n", r);
929 
930  return r;
931 }
932 
933