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