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