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