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