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