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 38 static 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 46 static 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 62 static 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 187 static 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 213 static 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 273 static 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 289 static 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 309 int 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 352 int 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... */ 375 static struct omapfb_color_key omapfb_color_keys[2]; 376 377 static 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 426 static 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); 450 err: 451 omapfb_unlock(fbdev); 452 453 return r; 454 } 455 456 static 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]; 480 err: 481 omapfb_unlock(fbdev); 482 483 return r; 484 } 485 486 static 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(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 524 static 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 570 static 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 586 int 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 memset(&p, 0, sizeof(p)); 613 614 switch (cmd) { 615 case OMAPFB_SYNC_GFX: 616 DBG("ioctl SYNC_GFX\n"); 617 if (!display || !display->driver->sync) { 618 /* DSS1 never returns an error here, so we neither */ 619 /*r = -EINVAL;*/ 620 break; 621 } 622 623 r = display->driver->sync(display); 624 break; 625 626 case OMAPFB_UPDATE_WINDOW_OLD: 627 DBG("ioctl UPDATE_WINDOW_OLD\n"); 628 if (!display || !display->driver->update) { 629 r = -EINVAL; 630 break; 631 } 632 633 if (copy_from_user(&p.uwnd_o, 634 (void __user *)arg, 635 sizeof(p.uwnd_o))) { 636 r = -EFAULT; 637 break; 638 } 639 640 r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y, 641 p.uwnd_o.width, p.uwnd_o.height); 642 break; 643 644 case OMAPFB_UPDATE_WINDOW: 645 DBG("ioctl UPDATE_WINDOW\n"); 646 if (!display || !display->driver->update) { 647 r = -EINVAL; 648 break; 649 } 650 651 if (copy_from_user(&p.uwnd, (void __user *)arg, 652 sizeof(p.uwnd))) { 653 r = -EFAULT; 654 break; 655 } 656 657 r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y, 658 p.uwnd.width, p.uwnd.height); 659 break; 660 661 case OMAPFB_SETUP_PLANE: 662 DBG("ioctl SETUP_PLANE\n"); 663 if (copy_from_user(&p.plane_info, (void __user *)arg, 664 sizeof(p.plane_info))) 665 r = -EFAULT; 666 else 667 r = omapfb_setup_plane(fbi, &p.plane_info); 668 break; 669 670 case OMAPFB_QUERY_PLANE: 671 DBG("ioctl QUERY_PLANE\n"); 672 r = omapfb_query_plane(fbi, &p.plane_info); 673 if (r < 0) 674 break; 675 if (copy_to_user((void __user *)arg, &p.plane_info, 676 sizeof(p.plane_info))) 677 r = -EFAULT; 678 break; 679 680 case OMAPFB_SETUP_MEM: 681 DBG("ioctl SETUP_MEM\n"); 682 if (copy_from_user(&p.mem_info, (void __user *)arg, 683 sizeof(p.mem_info))) 684 r = -EFAULT; 685 else 686 r = omapfb_setup_mem(fbi, &p.mem_info); 687 break; 688 689 case OMAPFB_QUERY_MEM: 690 DBG("ioctl QUERY_MEM\n"); 691 r = omapfb_query_mem(fbi, &p.mem_info); 692 if (r < 0) 693 break; 694 if (copy_to_user((void __user *)arg, &p.mem_info, 695 sizeof(p.mem_info))) 696 r = -EFAULT; 697 break; 698 699 case OMAPFB_GET_CAPS: 700 DBG("ioctl GET_CAPS\n"); 701 if (!display) { 702 r = -EINVAL; 703 break; 704 } 705 706 memset(&p.caps, 0, sizeof(p.caps)); 707 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) 708 p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE; 709 if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM) 710 p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC; 711 712 if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) 713 r = -EFAULT; 714 break; 715 716 case OMAPFB_GET_OVERLAY_COLORMODE: 717 DBG("ioctl GET_OVERLAY_COLORMODE\n"); 718 if (copy_from_user(&p.ovl_colormode, (void __user *)arg, 719 sizeof(p.ovl_colormode))) { 720 r = -EFAULT; 721 break; 722 } 723 r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode); 724 if (r < 0) 725 break; 726 if (copy_to_user((void __user *)arg, &p.ovl_colormode, 727 sizeof(p.ovl_colormode))) 728 r = -EFAULT; 729 break; 730 731 case OMAPFB_SET_UPDATE_MODE: 732 DBG("ioctl SET_UPDATE_MODE\n"); 733 if (get_user(p.update_mode, (int __user *)arg)) 734 r = -EFAULT; 735 else 736 r = omapfb_set_update_mode(fbi, p.update_mode); 737 break; 738 739 case OMAPFB_GET_UPDATE_MODE: 740 DBG("ioctl GET_UPDATE_MODE\n"); 741 r = omapfb_get_update_mode(fbi, &p.update_mode); 742 if (r) 743 break; 744 if (put_user(p.update_mode, 745 (enum omapfb_update_mode __user *)arg)) 746 r = -EFAULT; 747 break; 748 749 case OMAPFB_SET_COLOR_KEY: 750 DBG("ioctl SET_COLOR_KEY\n"); 751 if (copy_from_user(&p.color_key, (void __user *)arg, 752 sizeof(p.color_key))) 753 r = -EFAULT; 754 else 755 r = omapfb_set_color_key(fbi, &p.color_key); 756 break; 757 758 case OMAPFB_GET_COLOR_KEY: 759 DBG("ioctl GET_COLOR_KEY\n"); 760 r = omapfb_get_color_key(fbi, &p.color_key); 761 if (r) 762 break; 763 if (copy_to_user((void __user *)arg, &p.color_key, 764 sizeof(p.color_key))) 765 r = -EFAULT; 766 break; 767 768 case FBIO_WAITFORVSYNC: 769 if (get_user(p.crt, (__u32 __user *)arg)) { 770 r = -EFAULT; 771 break; 772 } 773 if (p.crt != 0) { 774 r = -ENODEV; 775 break; 776 } 777 /* FALLTHROUGH */ 778 779 case OMAPFB_WAITFORVSYNC: 780 DBG("ioctl WAITFORVSYNC\n"); 781 782 if (!display) { 783 r = -EINVAL; 784 break; 785 } 786 787 mgr = omapdss_find_mgr_from_display(display); 788 if (!mgr) { 789 r = -EINVAL; 790 break; 791 } 792 793 r = mgr->wait_for_vsync(mgr); 794 break; 795 796 case OMAPFB_WAITFORGO: 797 DBG("ioctl WAITFORGO\n"); 798 if (!display) { 799 r = -EINVAL; 800 break; 801 } 802 803 r = omapfb_wait_for_go(fbi); 804 break; 805 806 /* LCD and CTRL tests do the same thing for backward 807 * compatibility */ 808 case OMAPFB_LCD_TEST: 809 DBG("ioctl LCD_TEST\n"); 810 if (get_user(p.test_num, (int __user *)arg)) { 811 r = -EFAULT; 812 break; 813 } 814 if (!display || !display->driver->run_test) { 815 r = -EINVAL; 816 break; 817 } 818 819 r = display->driver->run_test(display, p.test_num); 820 821 break; 822 823 case OMAPFB_CTRL_TEST: 824 DBG("ioctl CTRL_TEST\n"); 825 if (get_user(p.test_num, (int __user *)arg)) { 826 r = -EFAULT; 827 break; 828 } 829 if (!display || !display->driver->run_test) { 830 r = -EINVAL; 831 break; 832 } 833 834 r = display->driver->run_test(display, p.test_num); 835 836 break; 837 838 case OMAPFB_MEMORY_READ: 839 DBG("ioctl MEMORY_READ\n"); 840 841 if (copy_from_user(&p.memory_read, (void __user *)arg, 842 sizeof(p.memory_read))) { 843 r = -EFAULT; 844 break; 845 } 846 847 r = omapfb_memory_read(fbi, &p.memory_read); 848 849 break; 850 851 case OMAPFB_GET_VRAM_INFO: { 852 DBG("ioctl GET_VRAM_INFO\n"); 853 854 /* 855 * We don't have the ability to get this vram info anymore. 856 * Fill in something that should keep the applications working. 857 */ 858 p.vram_info.total = SZ_1M * 64; 859 p.vram_info.free = SZ_1M * 64; 860 p.vram_info.largest_free_block = SZ_1M * 64; 861 862 if (copy_to_user((void __user *)arg, &p.vram_info, 863 sizeof(p.vram_info))) 864 r = -EFAULT; 865 break; 866 } 867 868 case OMAPFB_SET_TEARSYNC: { 869 DBG("ioctl SET_TEARSYNC\n"); 870 871 if (copy_from_user(&p.tearsync_info, (void __user *)arg, 872 sizeof(p.tearsync_info))) { 873 r = -EFAULT; 874 break; 875 } 876 877 if (!display || !display->driver->enable_te) { 878 r = -ENODEV; 879 break; 880 } 881 882 r = display->driver->enable_te(display, 883 !!p.tearsync_info.enabled); 884 885 break; 886 } 887 888 case OMAPFB_GET_DISPLAY_INFO: { 889 u16 xres, yres; 890 891 DBG("ioctl GET_DISPLAY_INFO\n"); 892 893 if (display == NULL) { 894 r = -ENODEV; 895 break; 896 } 897 898 display->driver->get_resolution(display, &xres, &yres); 899 900 p.display_info.xres = xres; 901 p.display_info.yres = yres; 902 903 if (display->driver->get_dimensions) { 904 u32 w, h; 905 display->driver->get_dimensions(display, &w, &h); 906 p.display_info.width = w; 907 p.display_info.height = h; 908 } else { 909 p.display_info.width = 0; 910 p.display_info.height = 0; 911 } 912 913 if (copy_to_user((void __user *)arg, &p.display_info, 914 sizeof(p.display_info))) 915 r = -EFAULT; 916 break; 917 } 918 919 default: 920 dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd); 921 r = -EINVAL; 922 } 923 924 if (r < 0) 925 DBG("ioctl failed: %d\n", r); 926 927 return r; 928 } 929 930 931