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/omapfb_dss.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 > 4096 || mr->h > 4096)
 500                return -EINVAL;
 501
 502        if (mr->w * mr->h * 3 > mr->buffer_size)
 503                return -EINVAL;
 504
 505        buf = vmalloc(mr->buffer_size);
 506        if (!buf) {
 507                DBG("vmalloc failed\n");
 508                return -ENOMEM;
 509        }
 510
 511        r = display->driver->memory_read(display, buf, mr->buffer_size,
 512                        mr->x, mr->y, mr->w, mr->h);
 513
 514        if (r > 0) {
 515                if (copy_to_user(mr->buffer, buf, r))
 516                        r = -EFAULT;
 517        }
 518
 519        vfree(buf);
 520
 521        return r;
 522}
 523
 524static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
 525                             struct omapfb_ovl_colormode *mode)
 526{
 527        int ovl_idx = mode->overlay_idx;
 528        int mode_idx = mode->mode_idx;
 529        struct omap_overlay *ovl;
 530        enum omap_color_mode supported_modes;
 531        struct fb_var_screeninfo var;
 532        int i;
 533
 534        if (ovl_idx >= fbdev->num_overlays)
 535                return -ENODEV;
 536        ovl = fbdev->overlays[ovl_idx];
 537        supported_modes = ovl->supported_modes;
 538
 539        mode_idx = mode->mode_idx;
 540
 541        for (i = 0; i < sizeof(supported_modes) * 8; i++) {
 542                if (!(supported_modes & (1 << i)))
 543                        continue;
 544                /*
 545                 * It's possible that the FB doesn't support a mode
 546                 * that is supported by the overlay, so call the
 547                 * following here.
 548                 */
 549                if (dss_mode_to_fb_mode(1 << i, &var) < 0)
 550                        continue;
 551
 552                mode_idx--;
 553                if (mode_idx < 0)
 554                        break;
 555        }
 556
 557        if (i == sizeof(supported_modes) * 8)
 558                return -ENOENT;
 559
 560        mode->bits_per_pixel = var.bits_per_pixel;
 561        mode->nonstd = var.nonstd;
 562        mode->red = var.red;
 563        mode->green = var.green;
 564        mode->blue = var.blue;
 565        mode->transp = var.transp;
 566
 567        return 0;
 568}
 569
 570static int omapfb_wait_for_go(struct fb_info *fbi)
 571{
 572        struct omapfb_info *ofbi = FB2OFB(fbi);
 573        int r = 0;
 574        int i;
 575
 576        for (i = 0; i < ofbi->num_overlays; ++i) {
 577                struct omap_overlay *ovl = ofbi->overlays[i];
 578                r = ovl->wait_for_go(ovl);
 579                if (r)
 580                        break;
 581        }
 582
 583        return r;
 584}
 585
 586int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
 587{
 588        struct omapfb_info *ofbi = FB2OFB(fbi);
 589        struct omapfb2_device *fbdev = ofbi->fbdev;
 590        struct omap_dss_device *display = fb2display(fbi);
 591        struct omap_overlay_manager *mgr;
 592
 593        union {
 594                struct omapfb_update_window_old uwnd_o;
 595                struct omapfb_update_window     uwnd;
 596                struct omapfb_plane_info        plane_info;
 597                struct omapfb_caps              caps;
 598                struct omapfb_mem_info          mem_info;
 599                struct omapfb_color_key         color_key;
 600                struct omapfb_ovl_colormode     ovl_colormode;
 601                enum omapfb_update_mode         update_mode;
 602                int test_num;
 603                struct omapfb_memory_read       memory_read;
 604                struct omapfb_vram_info         vram_info;
 605                struct omapfb_tearsync_info     tearsync_info;
 606                struct omapfb_display_info      display_info;
 607                u32                             crt;
 608        } p;
 609
 610        int r = 0;
 611
 612        switch (cmd) {
 613        case OMAPFB_SYNC_GFX:
 614                DBG("ioctl SYNC_GFX\n");
 615                if (!display || !display->driver->sync) {
 616                        /* DSS1 never returns an error here, so we neither */
 617                        /*r = -EINVAL;*/
 618                        break;
 619                }
 620
 621                r = display->driver->sync(display);
 622                break;
 623
 624        case OMAPFB_UPDATE_WINDOW_OLD:
 625                DBG("ioctl UPDATE_WINDOW_OLD\n");
 626                if (!display || !display->driver->update) {
 627                        r = -EINVAL;
 628                        break;
 629                }
 630
 631                if (copy_from_user(&p.uwnd_o,
 632                                        (void __user *)arg,
 633                                        sizeof(p.uwnd_o))) {
 634                        r = -EFAULT;
 635                        break;
 636                }
 637
 638                r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
 639                                p.uwnd_o.width, p.uwnd_o.height);
 640                break;
 641
 642        case OMAPFB_UPDATE_WINDOW:
 643                DBG("ioctl UPDATE_WINDOW\n");
 644                if (!display || !display->driver->update) {
 645                        r = -EINVAL;
 646                        break;
 647                }
 648
 649                if (copy_from_user(&p.uwnd, (void __user *)arg,
 650                                        sizeof(p.uwnd))) {
 651                        r = -EFAULT;
 652                        break;
 653                }
 654
 655                r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
 656                                p.uwnd.width, p.uwnd.height);
 657                break;
 658
 659        case OMAPFB_SETUP_PLANE:
 660                DBG("ioctl SETUP_PLANE\n");
 661                if (copy_from_user(&p.plane_info, (void __user *)arg,
 662                                        sizeof(p.plane_info)))
 663                        r = -EFAULT;
 664                else
 665                        r = omapfb_setup_plane(fbi, &p.plane_info);
 666                break;
 667
 668        case OMAPFB_QUERY_PLANE:
 669                DBG("ioctl QUERY_PLANE\n");
 670                r = omapfb_query_plane(fbi, &p.plane_info);
 671                if (r < 0)
 672                        break;
 673                if (copy_to_user((void __user *)arg, &p.plane_info,
 674                                        sizeof(p.plane_info)))
 675                        r = -EFAULT;
 676                break;
 677
 678        case OMAPFB_SETUP_MEM:
 679                DBG("ioctl SETUP_MEM\n");
 680                if (copy_from_user(&p.mem_info, (void __user *)arg,
 681                                        sizeof(p.mem_info)))
 682                        r = -EFAULT;
 683                else
 684                        r = omapfb_setup_mem(fbi, &p.mem_info);
 685                break;
 686
 687        case OMAPFB_QUERY_MEM:
 688                DBG("ioctl QUERY_MEM\n");
 689                r = omapfb_query_mem(fbi, &p.mem_info);
 690                if (r < 0)
 691                        break;
 692                if (copy_to_user((void __user *)arg, &p.mem_info,
 693                                        sizeof(p.mem_info)))
 694                        r = -EFAULT;
 695                break;
 696
 697        case OMAPFB_GET_CAPS:
 698                DBG("ioctl GET_CAPS\n");
 699                if (!display) {
 700                        r = -EINVAL;
 701                        break;
 702                }
 703
 704                memset(&p.caps, 0, sizeof(p.caps));
 705                if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
 706                        p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
 707                if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
 708                        p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
 709
 710                if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
 711                        r = -EFAULT;
 712                break;
 713
 714        case OMAPFB_GET_OVERLAY_COLORMODE:
 715                DBG("ioctl GET_OVERLAY_COLORMODE\n");
 716                if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
 717                                   sizeof(p.ovl_colormode))) {
 718                        r = -EFAULT;
 719                        break;
 720                }
 721                r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
 722                if (r < 0)
 723                        break;
 724                if (copy_to_user((void __user *)arg, &p.ovl_colormode,
 725                                 sizeof(p.ovl_colormode)))
 726                        r = -EFAULT;
 727                break;
 728
 729        case OMAPFB_SET_UPDATE_MODE:
 730                DBG("ioctl SET_UPDATE_MODE\n");
 731                if (get_user(p.update_mode, (int __user *)arg))
 732                        r = -EFAULT;
 733                else
 734                        r = omapfb_set_update_mode(fbi, p.update_mode);
 735                break;
 736
 737        case OMAPFB_GET_UPDATE_MODE:
 738                DBG("ioctl GET_UPDATE_MODE\n");
 739                r = omapfb_get_update_mode(fbi, &p.update_mode);
 740                if (r)
 741                        break;
 742                if (put_user(p.update_mode,
 743                                        (enum omapfb_update_mode __user *)arg))
 744                        r = -EFAULT;
 745                break;
 746
 747        case OMAPFB_SET_COLOR_KEY:
 748                DBG("ioctl SET_COLOR_KEY\n");
 749                if (copy_from_user(&p.color_key, (void __user *)arg,
 750                                   sizeof(p.color_key)))
 751                        r = -EFAULT;
 752                else
 753                        r = omapfb_set_color_key(fbi, &p.color_key);
 754                break;
 755
 756        case OMAPFB_GET_COLOR_KEY:
 757                DBG("ioctl GET_COLOR_KEY\n");
 758                r = omapfb_get_color_key(fbi, &p.color_key);
 759                if (r)
 760                        break;
 761                if (copy_to_user((void __user *)arg, &p.color_key,
 762                                 sizeof(p.color_key)))
 763                        r = -EFAULT;
 764                break;
 765
 766        case FBIO_WAITFORVSYNC:
 767                if (get_user(p.crt, (__u32 __user *)arg)) {
 768                        r = -EFAULT;
 769                        break;
 770                }
 771                if (p.crt != 0) {
 772                        r = -ENODEV;
 773                        break;
 774                }
 775                /* FALLTHROUGH */
 776
 777        case OMAPFB_WAITFORVSYNC:
 778                DBG("ioctl WAITFORVSYNC\n");
 779
 780                if (!display) {
 781                        r = -EINVAL;
 782                        break;
 783                }
 784
 785                mgr = omapdss_find_mgr_from_display(display);
 786                if (!mgr) {
 787                        r = -EINVAL;
 788                        break;
 789                }
 790
 791                r = mgr->wait_for_vsync(mgr);
 792                break;
 793
 794        case OMAPFB_WAITFORGO:
 795                DBG("ioctl WAITFORGO\n");
 796                if (!display) {
 797                        r = -EINVAL;
 798                        break;
 799                }
 800
 801                r = omapfb_wait_for_go(fbi);
 802                break;
 803
 804        /* LCD and CTRL tests do the same thing for backward
 805         * compatibility */
 806        case OMAPFB_LCD_TEST:
 807                DBG("ioctl LCD_TEST\n");
 808                if (get_user(p.test_num, (int __user *)arg)) {
 809                        r = -EFAULT;
 810                        break;
 811                }
 812                if (!display || !display->driver->run_test) {
 813                        r = -EINVAL;
 814                        break;
 815                }
 816
 817                r = display->driver->run_test(display, p.test_num);
 818
 819                break;
 820
 821        case OMAPFB_CTRL_TEST:
 822                DBG("ioctl CTRL_TEST\n");
 823                if (get_user(p.test_num, (int __user *)arg)) {
 824                        r = -EFAULT;
 825                        break;
 826                }
 827                if (!display || !display->driver->run_test) {
 828                        r = -EINVAL;
 829                        break;
 830                }
 831
 832                r = display->driver->run_test(display, p.test_num);
 833
 834                break;
 835
 836        case OMAPFB_MEMORY_READ:
 837                DBG("ioctl MEMORY_READ\n");
 838
 839                if (copy_from_user(&p.memory_read, (void __user *)arg,
 840                                        sizeof(p.memory_read))) {
 841                        r = -EFAULT;
 842                        break;
 843                }
 844
 845                r = omapfb_memory_read(fbi, &p.memory_read);
 846
 847                break;
 848
 849        case OMAPFB_GET_VRAM_INFO: {
 850                DBG("ioctl GET_VRAM_INFO\n");
 851
 852                /*
 853                 * We don't have the ability to get this vram info anymore.
 854                 * Fill in something that should keep the applications working.
 855                 */
 856                p.vram_info.total = SZ_1M * 64;
 857                p.vram_info.free = SZ_1M * 64;
 858                p.vram_info.largest_free_block = SZ_1M * 64;
 859
 860                if (copy_to_user((void __user *)arg, &p.vram_info,
 861                                        sizeof(p.vram_info)))
 862                        r = -EFAULT;
 863                break;
 864        }
 865
 866        case OMAPFB_SET_TEARSYNC: {
 867                DBG("ioctl SET_TEARSYNC\n");
 868
 869                if (copy_from_user(&p.tearsync_info, (void __user *)arg,
 870                                        sizeof(p.tearsync_info))) {
 871                        r = -EFAULT;
 872                        break;
 873                }
 874
 875                if (!display || !display->driver->enable_te) {
 876                        r = -ENODEV;
 877                        break;
 878                }
 879
 880                r = display->driver->enable_te(display,
 881                                !!p.tearsync_info.enabled);
 882
 883                break;
 884        }
 885
 886        case OMAPFB_GET_DISPLAY_INFO: {
 887                u16 xres, yres;
 888
 889                DBG("ioctl GET_DISPLAY_INFO\n");
 890
 891                if (display == NULL) {
 892                        r = -ENODEV;
 893                        break;
 894                }
 895
 896                display->driver->get_resolution(display, &xres, &yres);
 897
 898                p.display_info.xres = xres;
 899                p.display_info.yres = yres;
 900
 901                if (display->driver->get_dimensions) {
 902                        u32 w, h;
 903                        display->driver->get_dimensions(display, &w, &h);
 904                        p.display_info.width = w;
 905                        p.display_info.height = h;
 906                } else {
 907                        p.display_info.width = 0;
 908                        p.display_info.height = 0;
 909                }
 910
 911                if (copy_to_user((void __user *)arg, &p.display_info,
 912                                        sizeof(p.display_info)))
 913                        r = -EFAULT;
 914                break;
 915        }
 916
 917        default:
 918                dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
 919                r = -EINVAL;
 920        }
 921
 922        if (r < 0)
 923                DBG("ioctl failed: %d\n", r);
 924
 925        return r;
 926}
 927
 928
 929