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