1 /* 2 * linux/drivers/video/fbmem.c 3 * 4 * Copyright (C) 1994 Martin Schaller 5 * 6 * 2001 - Documented with DocBook 7 * - Brad Douglas <brad@neruo.com> 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file COPYING in the main directory of this archive 11 * for more details. 12 */ 13 14 #include <linux/module.h> 15 16 #include <linux/compat.h> 17 #include <linux/types.h> 18 #include <linux/errno.h> 19 #include <linux/kernel.h> 20 #include <linux/major.h> 21 #include <linux/slab.h> 22 #include <linux/mm.h> 23 #include <linux/mman.h> 24 #include <linux/vt.h> 25 #include <linux/init.h> 26 #include <linux/linux_logo.h> 27 #include <linux/proc_fs.h> 28 #include <linux/seq_file.h> 29 #include <linux/console.h> 30 #include <linux/kmod.h> 31 #include <linux/err.h> 32 #include <linux/device.h> 33 #include <linux/efi.h> 34 #include <linux/fb.h> 35 #include <linux/fbcon.h> 36 #include <linux/mem_encrypt.h> 37 #include <linux/pci.h> 38 39 #include <asm/fb.h> 40 41 42 /* 43 * Frame buffer device initialization and setup routines 44 */ 45 46 #define FBPIXMAPSIZE (1024 * 8) 47 48 static DEFINE_MUTEX(registration_lock); 49 50 struct fb_info *registered_fb[FB_MAX] __read_mostly; 51 EXPORT_SYMBOL(registered_fb); 52 53 int num_registered_fb __read_mostly; 54 EXPORT_SYMBOL(num_registered_fb); 55 56 bool fb_center_logo __read_mostly; 57 EXPORT_SYMBOL(fb_center_logo); 58 59 static struct fb_info *get_fb_info(unsigned int idx) 60 { 61 struct fb_info *fb_info; 62 63 if (idx >= FB_MAX) 64 return ERR_PTR(-ENODEV); 65 66 mutex_lock(®istration_lock); 67 fb_info = registered_fb[idx]; 68 if (fb_info) 69 atomic_inc(&fb_info->count); 70 mutex_unlock(®istration_lock); 71 72 return fb_info; 73 } 74 75 static void put_fb_info(struct fb_info *fb_info) 76 { 77 if (!atomic_dec_and_test(&fb_info->count)) 78 return; 79 if (fb_info->fbops->fb_destroy) 80 fb_info->fbops->fb_destroy(fb_info); 81 } 82 83 int lock_fb_info(struct fb_info *info) 84 { 85 mutex_lock(&info->lock); 86 if (!info->fbops) { 87 mutex_unlock(&info->lock); 88 return 0; 89 } 90 return 1; 91 } 92 EXPORT_SYMBOL(lock_fb_info); 93 94 /* 95 * Helpers 96 */ 97 98 int fb_get_color_depth(struct fb_var_screeninfo *var, 99 struct fb_fix_screeninfo *fix) 100 { 101 int depth = 0; 102 103 if (fix->visual == FB_VISUAL_MONO01 || 104 fix->visual == FB_VISUAL_MONO10) 105 depth = 1; 106 else { 107 if (var->green.length == var->blue.length && 108 var->green.length == var->red.length && 109 var->green.offset == var->blue.offset && 110 var->green.offset == var->red.offset) 111 depth = var->green.length; 112 else 113 depth = var->green.length + var->red.length + 114 var->blue.length; 115 } 116 117 return depth; 118 } 119 EXPORT_SYMBOL(fb_get_color_depth); 120 121 /* 122 * Data padding functions. 123 */ 124 void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height) 125 { 126 __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height); 127 } 128 EXPORT_SYMBOL(fb_pad_aligned_buffer); 129 130 void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height, 131 u32 shift_high, u32 shift_low, u32 mod) 132 { 133 u8 mask = (u8) (0xfff << shift_high), tmp; 134 int i, j; 135 136 for (i = height; i--; ) { 137 for (j = 0; j < idx; j++) { 138 tmp = dst[j]; 139 tmp &= mask; 140 tmp |= *src >> shift_low; 141 dst[j] = tmp; 142 tmp = *src << shift_high; 143 dst[j+1] = tmp; 144 src++; 145 } 146 tmp = dst[idx]; 147 tmp &= mask; 148 tmp |= *src >> shift_low; 149 dst[idx] = tmp; 150 if (shift_high < mod) { 151 tmp = *src << shift_high; 152 dst[idx+1] = tmp; 153 } 154 src++; 155 dst += d_pitch; 156 } 157 } 158 EXPORT_SYMBOL(fb_pad_unaligned_buffer); 159 160 /* 161 * we need to lock this section since fb_cursor 162 * may use fb_imageblit() 163 */ 164 char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size) 165 { 166 u32 align = buf->buf_align - 1, offset; 167 char *addr = buf->addr; 168 169 /* If IO mapped, we need to sync before access, no sharing of 170 * the pixmap is done 171 */ 172 if (buf->flags & FB_PIXMAP_IO) { 173 if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) 174 info->fbops->fb_sync(info); 175 return addr; 176 } 177 178 /* See if we fit in the remaining pixmap space */ 179 offset = buf->offset + align; 180 offset &= ~align; 181 if (offset + size > buf->size) { 182 /* We do not fit. In order to be able to re-use the buffer, 183 * we must ensure no asynchronous DMA'ing or whatever operation 184 * is in progress, we sync for that. 185 */ 186 if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) 187 info->fbops->fb_sync(info); 188 offset = 0; 189 } 190 buf->offset = offset + size; 191 addr += offset; 192 193 return addr; 194 } 195 EXPORT_SYMBOL(fb_get_buffer_offset); 196 197 #ifdef CONFIG_LOGO 198 199 static inline unsigned safe_shift(unsigned d, int n) 200 { 201 return n < 0 ? d >> -n : d << n; 202 } 203 204 static void fb_set_logocmap(struct fb_info *info, 205 const struct linux_logo *logo) 206 { 207 struct fb_cmap palette_cmap; 208 u16 palette_green[16]; 209 u16 palette_blue[16]; 210 u16 palette_red[16]; 211 int i, j, n; 212 const unsigned char *clut = logo->clut; 213 214 palette_cmap.start = 0; 215 palette_cmap.len = 16; 216 palette_cmap.red = palette_red; 217 palette_cmap.green = palette_green; 218 palette_cmap.blue = palette_blue; 219 palette_cmap.transp = NULL; 220 221 for (i = 0; i < logo->clutsize; i += n) { 222 n = logo->clutsize - i; 223 /* palette_cmap provides space for only 16 colors at once */ 224 if (n > 16) 225 n = 16; 226 palette_cmap.start = 32 + i; 227 palette_cmap.len = n; 228 for (j = 0; j < n; ++j) { 229 palette_cmap.red[j] = clut[0] << 8 | clut[0]; 230 palette_cmap.green[j] = clut[1] << 8 | clut[1]; 231 palette_cmap.blue[j] = clut[2] << 8 | clut[2]; 232 clut += 3; 233 } 234 fb_set_cmap(&palette_cmap, info); 235 } 236 } 237 238 static void fb_set_logo_truepalette(struct fb_info *info, 239 const struct linux_logo *logo, 240 u32 *palette) 241 { 242 static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; 243 unsigned char redmask, greenmask, bluemask; 244 int redshift, greenshift, blueshift; 245 int i; 246 const unsigned char *clut = logo->clut; 247 248 /* 249 * We have to create a temporary palette since console palette is only 250 * 16 colors long. 251 */ 252 /* Bug: Doesn't obey msb_right ... (who needs that?) */ 253 redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; 254 greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; 255 bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; 256 redshift = info->var.red.offset - (8 - info->var.red.length); 257 greenshift = info->var.green.offset - (8 - info->var.green.length); 258 blueshift = info->var.blue.offset - (8 - info->var.blue.length); 259 260 for ( i = 0; i < logo->clutsize; i++) { 261 palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | 262 safe_shift((clut[1] & greenmask), greenshift) | 263 safe_shift((clut[2] & bluemask), blueshift)); 264 clut += 3; 265 } 266 } 267 268 static void fb_set_logo_directpalette(struct fb_info *info, 269 const struct linux_logo *logo, 270 u32 *palette) 271 { 272 int redshift, greenshift, blueshift; 273 int i; 274 275 redshift = info->var.red.offset; 276 greenshift = info->var.green.offset; 277 blueshift = info->var.blue.offset; 278 279 for (i = 32; i < 32 + logo->clutsize; i++) 280 palette[i] = i << redshift | i << greenshift | i << blueshift; 281 } 282 283 static void fb_set_logo(struct fb_info *info, 284 const struct linux_logo *logo, u8 *dst, 285 int depth) 286 { 287 int i, j, k; 288 const u8 *src = logo->data; 289 u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; 290 u8 fg = 1, d; 291 292 switch (fb_get_color_depth(&info->var, &info->fix)) { 293 case 1: 294 fg = 1; 295 break; 296 case 2: 297 fg = 3; 298 break; 299 default: 300 fg = 7; 301 break; 302 } 303 304 if (info->fix.visual == FB_VISUAL_MONO01 || 305 info->fix.visual == FB_VISUAL_MONO10) 306 fg = ~((u8) (0xfff << info->var.green.length)); 307 308 switch (depth) { 309 case 4: 310 for (i = 0; i < logo->height; i++) 311 for (j = 0; j < logo->width; src++) { 312 *dst++ = *src >> 4; 313 j++; 314 if (j < logo->width) { 315 *dst++ = *src & 0x0f; 316 j++; 317 } 318 } 319 break; 320 case 1: 321 for (i = 0; i < logo->height; i++) { 322 for (j = 0; j < logo->width; src++) { 323 d = *src ^ xor; 324 for (k = 7; k >= 0 && j < logo->width; k--) { 325 *dst++ = ((d >> k) & 1) ? fg : 0; 326 j++; 327 } 328 } 329 } 330 break; 331 } 332 } 333 334 /* 335 * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), 336 * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on 337 * the visual format and color depth of the framebuffer, the DAC, the 338 * pseudo_palette, and the logo data will be adjusted accordingly. 339 * 340 * Case 1 - linux_logo_clut224: 341 * Color exceeds the number of console colors (16), thus we set the hardware DAC 342 * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. 343 * 344 * For visuals that require color info from the pseudo_palette, we also construct 345 * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags 346 * will be set. 347 * 348 * Case 2 - linux_logo_vga16: 349 * The number of colors just matches the console colors, thus there is no need 350 * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, 351 * each byte contains color information for two pixels (upper and lower nibble). 352 * To be consistent with fb_imageblit() usage, we therefore separate the two 353 * nibbles into separate bytes. The "depth" flag will be set to 4. 354 * 355 * Case 3 - linux_logo_mono: 356 * This is similar with Case 2. Each byte contains information for 8 pixels. 357 * We isolate each bit and expand each into a byte. The "depth" flag will 358 * be set to 1. 359 */ 360 static struct logo_data { 361 int depth; 362 int needs_directpalette; 363 int needs_truepalette; 364 int needs_cmapreset; 365 const struct linux_logo *logo; 366 } fb_logo __read_mostly; 367 368 static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) 369 { 370 u32 size = width * height, i; 371 372 out += size - 1; 373 374 for (i = size; i--; ) 375 *out-- = *in++; 376 } 377 378 static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) 379 { 380 int i, j, h = height - 1; 381 382 for (i = 0; i < height; i++) 383 for (j = 0; j < width; j++) 384 out[height * j + h - i] = *in++; 385 } 386 387 static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) 388 { 389 int i, j, w = width - 1; 390 391 for (i = 0; i < height; i++) 392 for (j = 0; j < width; j++) 393 out[height * (w - j) + i] = *in++; 394 } 395 396 static void fb_rotate_logo(struct fb_info *info, u8 *dst, 397 struct fb_image *image, int rotate) 398 { 399 u32 tmp; 400 401 if (rotate == FB_ROTATE_UD) { 402 fb_rotate_logo_ud(image->data, dst, image->width, 403 image->height); 404 image->dx = info->var.xres - image->width - image->dx; 405 image->dy = info->var.yres - image->height - image->dy; 406 } else if (rotate == FB_ROTATE_CW) { 407 fb_rotate_logo_cw(image->data, dst, image->width, 408 image->height); 409 tmp = image->width; 410 image->width = image->height; 411 image->height = tmp; 412 tmp = image->dy; 413 image->dy = image->dx; 414 image->dx = info->var.xres - image->width - tmp; 415 } else if (rotate == FB_ROTATE_CCW) { 416 fb_rotate_logo_ccw(image->data, dst, image->width, 417 image->height); 418 tmp = image->width; 419 image->width = image->height; 420 image->height = tmp; 421 tmp = image->dx; 422 image->dx = image->dy; 423 image->dy = info->var.yres - image->height - tmp; 424 } 425 426 image->data = dst; 427 } 428 429 static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, 430 int rotate, unsigned int num) 431 { 432 unsigned int x; 433 434 if (rotate == FB_ROTATE_UR) { 435 for (x = 0; 436 x < num && image->dx + image->width <= info->var.xres; 437 x++) { 438 info->fbops->fb_imageblit(info, image); 439 image->dx += image->width + 8; 440 } 441 } else if (rotate == FB_ROTATE_UD) { 442 u32 dx = image->dx; 443 444 for (x = 0; x < num && image->dx <= dx; x++) { 445 info->fbops->fb_imageblit(info, image); 446 image->dx -= image->width + 8; 447 } 448 } else if (rotate == FB_ROTATE_CW) { 449 for (x = 0; 450 x < num && image->dy + image->height <= info->var.yres; 451 x++) { 452 info->fbops->fb_imageblit(info, image); 453 image->dy += image->height + 8; 454 } 455 } else if (rotate == FB_ROTATE_CCW) { 456 u32 dy = image->dy; 457 458 for (x = 0; x < num && image->dy <= dy; x++) { 459 info->fbops->fb_imageblit(info, image); 460 image->dy -= image->height + 8; 461 } 462 } 463 } 464 465 static int fb_show_logo_line(struct fb_info *info, int rotate, 466 const struct linux_logo *logo, int y, 467 unsigned int n) 468 { 469 u32 *palette = NULL, *saved_pseudo_palette = NULL; 470 unsigned char *logo_new = NULL, *logo_rotate = NULL; 471 struct fb_image image; 472 473 /* Return if the frame buffer is not mapped or suspended */ 474 if (logo == NULL || info->state != FBINFO_STATE_RUNNING || 475 info->fbops->owner) 476 return 0; 477 478 image.depth = 8; 479 image.data = logo->data; 480 481 if (fb_logo.needs_cmapreset) 482 fb_set_logocmap(info, logo); 483 484 if (fb_logo.needs_truepalette || 485 fb_logo.needs_directpalette) { 486 palette = kmalloc(256 * 4, GFP_KERNEL); 487 if (palette == NULL) 488 return 0; 489 490 if (fb_logo.needs_truepalette) 491 fb_set_logo_truepalette(info, logo, palette); 492 else 493 fb_set_logo_directpalette(info, logo, palette); 494 495 saved_pseudo_palette = info->pseudo_palette; 496 info->pseudo_palette = palette; 497 } 498 499 if (fb_logo.depth <= 4) { 500 logo_new = kmalloc_array(logo->width, logo->height, 501 GFP_KERNEL); 502 if (logo_new == NULL) { 503 kfree(palette); 504 if (saved_pseudo_palette) 505 info->pseudo_palette = saved_pseudo_palette; 506 return 0; 507 } 508 image.data = logo_new; 509 fb_set_logo(info, logo, logo_new, fb_logo.depth); 510 } 511 512 if (fb_center_logo) { 513 int xres = info->var.xres; 514 int yres = info->var.yres; 515 516 if (rotate == FB_ROTATE_CW || rotate == FB_ROTATE_CCW) { 517 xres = info->var.yres; 518 yres = info->var.xres; 519 } 520 521 while (n && (n * (logo->width + 8) - 8 > xres)) 522 --n; 523 image.dx = (xres - n * (logo->width + 8) - 8) / 2; 524 image.dy = y ?: (yres - logo->height) / 2; 525 } else { 526 image.dx = 0; 527 image.dy = y; 528 } 529 530 image.width = logo->width; 531 image.height = logo->height; 532 533 if (rotate) { 534 logo_rotate = kmalloc_array(logo->width, logo->height, 535 GFP_KERNEL); 536 if (logo_rotate) 537 fb_rotate_logo(info, logo_rotate, &image, rotate); 538 } 539 540 fb_do_show_logo(info, &image, rotate, n); 541 542 kfree(palette); 543 if (saved_pseudo_palette != NULL) 544 info->pseudo_palette = saved_pseudo_palette; 545 kfree(logo_new); 546 kfree(logo_rotate); 547 return image.dy + logo->height; 548 } 549 550 551 #ifdef CONFIG_FB_LOGO_EXTRA 552 553 #define FB_LOGO_EX_NUM_MAX 10 554 static struct logo_data_extra { 555 const struct linux_logo *logo; 556 unsigned int n; 557 } fb_logo_ex[FB_LOGO_EX_NUM_MAX]; 558 static unsigned int fb_logo_ex_num; 559 560 void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) 561 { 562 if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) 563 return; 564 565 fb_logo_ex[fb_logo_ex_num].logo = logo; 566 fb_logo_ex[fb_logo_ex_num].n = n; 567 fb_logo_ex_num++; 568 } 569 570 static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, 571 unsigned int yres) 572 { 573 unsigned int i; 574 575 /* FIXME: logo_ex supports only truecolor fb. */ 576 if (info->fix.visual != FB_VISUAL_TRUECOLOR) 577 fb_logo_ex_num = 0; 578 579 for (i = 0; i < fb_logo_ex_num; i++) { 580 if (fb_logo_ex[i].logo->type != fb_logo.logo->type) { 581 fb_logo_ex[i].logo = NULL; 582 continue; 583 } 584 height += fb_logo_ex[i].logo->height; 585 if (height > yres) { 586 height -= fb_logo_ex[i].logo->height; 587 fb_logo_ex_num = i; 588 break; 589 } 590 } 591 return height; 592 } 593 594 static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 595 { 596 unsigned int i; 597 598 for (i = 0; i < fb_logo_ex_num; i++) 599 y = fb_show_logo_line(info, rotate, 600 fb_logo_ex[i].logo, y, fb_logo_ex[i].n); 601 602 return y; 603 } 604 605 #else /* !CONFIG_FB_LOGO_EXTRA */ 606 607 static inline int fb_prepare_extra_logos(struct fb_info *info, 608 unsigned int height, 609 unsigned int yres) 610 { 611 return height; 612 } 613 614 static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 615 { 616 return y; 617 } 618 619 #endif /* CONFIG_FB_LOGO_EXTRA */ 620 621 622 int fb_prepare_logo(struct fb_info *info, int rotate) 623 { 624 int depth = fb_get_color_depth(&info->var, &info->fix); 625 unsigned int yres; 626 int height; 627 628 memset(&fb_logo, 0, sizeof(struct logo_data)); 629 630 if (info->flags & FBINFO_MISC_TILEBLITTING || 631 info->fbops->owner) 632 return 0; 633 634 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 635 depth = info->var.blue.length; 636 if (info->var.red.length < depth) 637 depth = info->var.red.length; 638 if (info->var.green.length < depth) 639 depth = info->var.green.length; 640 } 641 642 if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { 643 /* assume console colormap */ 644 depth = 4; 645 } 646 647 /* Return if no suitable logo was found */ 648 fb_logo.logo = fb_find_logo(depth); 649 650 if (!fb_logo.logo) { 651 return 0; 652 } 653 654 if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) 655 yres = info->var.yres; 656 else 657 yres = info->var.xres; 658 659 if (fb_logo.logo->height > yres) { 660 fb_logo.logo = NULL; 661 return 0; 662 } 663 664 /* What depth we asked for might be different from what we get */ 665 if (fb_logo.logo->type == LINUX_LOGO_CLUT224) 666 fb_logo.depth = 8; 667 else if (fb_logo.logo->type == LINUX_LOGO_VGA16) 668 fb_logo.depth = 4; 669 else 670 fb_logo.depth = 1; 671 672 673 if (fb_logo.depth > 4 && depth > 4) { 674 switch (info->fix.visual) { 675 case FB_VISUAL_TRUECOLOR: 676 fb_logo.needs_truepalette = 1; 677 break; 678 case FB_VISUAL_DIRECTCOLOR: 679 fb_logo.needs_directpalette = 1; 680 fb_logo.needs_cmapreset = 1; 681 break; 682 case FB_VISUAL_PSEUDOCOLOR: 683 fb_logo.needs_cmapreset = 1; 684 break; 685 } 686 } 687 688 height = fb_logo.logo->height; 689 if (fb_center_logo) 690 height += (yres - fb_logo.logo->height) / 2; 691 692 return fb_prepare_extra_logos(info, height, yres); 693 } 694 695 int fb_show_logo(struct fb_info *info, int rotate) 696 { 697 int y; 698 699 y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, 700 num_online_cpus()); 701 y = fb_show_extra_logos(info, y, rotate); 702 703 return y; 704 } 705 #else 706 int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } 707 int fb_show_logo(struct fb_info *info, int rotate) { return 0; } 708 #endif /* CONFIG_LOGO */ 709 EXPORT_SYMBOL(fb_prepare_logo); 710 EXPORT_SYMBOL(fb_show_logo); 711 712 static void *fb_seq_start(struct seq_file *m, loff_t *pos) 713 { 714 mutex_lock(®istration_lock); 715 return (*pos < FB_MAX) ? pos : NULL; 716 } 717 718 static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) 719 { 720 (*pos)++; 721 return (*pos < FB_MAX) ? pos : NULL; 722 } 723 724 static void fb_seq_stop(struct seq_file *m, void *v) 725 { 726 mutex_unlock(®istration_lock); 727 } 728 729 static int fb_seq_show(struct seq_file *m, void *v) 730 { 731 int i = *(loff_t *)v; 732 struct fb_info *fi = registered_fb[i]; 733 734 if (fi) 735 seq_printf(m, "%d %s\n", fi->node, fi->fix.id); 736 return 0; 737 } 738 739 static const struct seq_operations proc_fb_seq_ops = { 740 .start = fb_seq_start, 741 .next = fb_seq_next, 742 .stop = fb_seq_stop, 743 .show = fb_seq_show, 744 }; 745 746 /* 747 * We hold a reference to the fb_info in file->private_data, 748 * but if the current registered fb has changed, we don't 749 * actually want to use it. 750 * 751 * So look up the fb_info using the inode minor number, 752 * and just verify it against the reference we have. 753 */ 754 static struct fb_info *file_fb_info(struct file *file) 755 { 756 struct inode *inode = file_inode(file); 757 int fbidx = iminor(inode); 758 struct fb_info *info = registered_fb[fbidx]; 759 760 if (info != file->private_data) 761 info = NULL; 762 return info; 763 } 764 765 static ssize_t 766 fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 767 { 768 unsigned long p = *ppos; 769 struct fb_info *info = file_fb_info(file); 770 u8 *buffer, *dst; 771 u8 __iomem *src; 772 int c, cnt = 0, err = 0; 773 unsigned long total_size; 774 775 if (!info || ! info->screen_base) 776 return -ENODEV; 777 778 if (info->state != FBINFO_STATE_RUNNING) 779 return -EPERM; 780 781 if (info->fbops->fb_read) 782 return info->fbops->fb_read(info, buf, count, ppos); 783 784 total_size = info->screen_size; 785 786 if (total_size == 0) 787 total_size = info->fix.smem_len; 788 789 if (p >= total_size) 790 return 0; 791 792 if (count >= total_size) 793 count = total_size; 794 795 if (count + p > total_size) 796 count = total_size - p; 797 798 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, 799 GFP_KERNEL); 800 if (!buffer) 801 return -ENOMEM; 802 803 src = (u8 __iomem *) (info->screen_base + p); 804 805 if (info->fbops->fb_sync) 806 info->fbops->fb_sync(info); 807 808 while (count) { 809 c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 810 dst = buffer; 811 fb_memcpy_fromfb(dst, src, c); 812 dst += c; 813 src += c; 814 815 if (copy_to_user(buf, buffer, c)) { 816 err = -EFAULT; 817 break; 818 } 819 *ppos += c; 820 buf += c; 821 cnt += c; 822 count -= c; 823 } 824 825 kfree(buffer); 826 827 return (err) ? err : cnt; 828 } 829 830 static ssize_t 831 fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 832 { 833 unsigned long p = *ppos; 834 struct fb_info *info = file_fb_info(file); 835 u8 *buffer, *src; 836 u8 __iomem *dst; 837 int c, cnt = 0, err = 0; 838 unsigned long total_size; 839 840 if (!info || !info->screen_base) 841 return -ENODEV; 842 843 if (info->state != FBINFO_STATE_RUNNING) 844 return -EPERM; 845 846 if (info->fbops->fb_write) 847 return info->fbops->fb_write(info, buf, count, ppos); 848 849 total_size = info->screen_size; 850 851 if (total_size == 0) 852 total_size = info->fix.smem_len; 853 854 if (p > total_size) 855 return -EFBIG; 856 857 if (count > total_size) { 858 err = -EFBIG; 859 count = total_size; 860 } 861 862 if (count + p > total_size) { 863 if (!err) 864 err = -ENOSPC; 865 866 count = total_size - p; 867 } 868 869 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, 870 GFP_KERNEL); 871 if (!buffer) 872 return -ENOMEM; 873 874 dst = (u8 __iomem *) (info->screen_base + p); 875 876 if (info->fbops->fb_sync) 877 info->fbops->fb_sync(info); 878 879 while (count) { 880 c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 881 src = buffer; 882 883 if (copy_from_user(src, buf, c)) { 884 err = -EFAULT; 885 break; 886 } 887 888 fb_memcpy_tofb(dst, src, c); 889 dst += c; 890 src += c; 891 *ppos += c; 892 buf += c; 893 cnt += c; 894 count -= c; 895 } 896 897 kfree(buffer); 898 899 return (cnt) ? cnt : err; 900 } 901 902 int 903 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) 904 { 905 struct fb_fix_screeninfo *fix = &info->fix; 906 unsigned int yres = info->var.yres; 907 int err = 0; 908 909 if (var->yoffset > 0) { 910 if (var->vmode & FB_VMODE_YWRAP) { 911 if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep)) 912 err = -EINVAL; 913 else 914 yres = 0; 915 } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep)) 916 err = -EINVAL; 917 } 918 919 if (var->xoffset > 0 && (!fix->xpanstep || 920 (var->xoffset % fix->xpanstep))) 921 err = -EINVAL; 922 923 if (err || !info->fbops->fb_pan_display || 924 var->yoffset > info->var.yres_virtual - yres || 925 var->xoffset > info->var.xres_virtual - info->var.xres) 926 return -EINVAL; 927 928 if ((err = info->fbops->fb_pan_display(var, info))) 929 return err; 930 info->var.xoffset = var->xoffset; 931 info->var.yoffset = var->yoffset; 932 if (var->vmode & FB_VMODE_YWRAP) 933 info->var.vmode |= FB_VMODE_YWRAP; 934 else 935 info->var.vmode &= ~FB_VMODE_YWRAP; 936 return 0; 937 } 938 EXPORT_SYMBOL(fb_pan_display); 939 940 static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, 941 u32 activate) 942 { 943 struct fb_event event; 944 struct fb_blit_caps caps, fbcaps; 945 int err = 0; 946 947 memset(&caps, 0, sizeof(caps)); 948 memset(&fbcaps, 0, sizeof(fbcaps)); 949 caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; 950 event.info = info; 951 event.data = ∩︀ 952 fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); 953 info->fbops->fb_get_caps(info, &fbcaps, var); 954 955 if (((fbcaps.x ^ caps.x) & caps.x) || 956 ((fbcaps.y ^ caps.y) & caps.y) || 957 (fbcaps.len < caps.len)) 958 err = -EINVAL; 959 960 return err; 961 } 962 963 int 964 fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) 965 { 966 int flags = info->flags; 967 int ret = 0; 968 969 if (var->activate & FB_ACTIVATE_INV_MODE) { 970 struct fb_videomode mode1, mode2; 971 972 fb_var_to_videomode(&mode1, var); 973 fb_var_to_videomode(&mode2, &info->var); 974 /* make sure we don't delete the videomode of current var */ 975 ret = fb_mode_is_equal(&mode1, &mode2); 976 977 if (!ret) { 978 struct fb_event event; 979 980 event.info = info; 981 event.data = &mode1; 982 ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event); 983 } 984 985 if (!ret) 986 fb_delete_videomode(&mode1, &info->modelist); 987 988 989 ret = (ret) ? -EINVAL : 0; 990 goto done; 991 } 992 993 if ((var->activate & FB_ACTIVATE_FORCE) || 994 memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { 995 u32 activate = var->activate; 996 997 /* When using FOURCC mode, make sure the red, green, blue and 998 * transp fields are set to 0. 999 */ 1000 if ((info->fix.capabilities & FB_CAP_FOURCC) && 1001 var->grayscale > 1) { 1002 if (var->red.offset || var->green.offset || 1003 var->blue.offset || var->transp.offset || 1004 var->red.length || var->green.length || 1005 var->blue.length || var->transp.length || 1006 var->red.msb_right || var->green.msb_right || 1007 var->blue.msb_right || var->transp.msb_right) 1008 return -EINVAL; 1009 } 1010 1011 if (!info->fbops->fb_check_var) { 1012 *var = info->var; 1013 goto done; 1014 } 1015 1016 ret = info->fbops->fb_check_var(var, info); 1017 1018 if (ret) 1019 goto done; 1020 1021 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { 1022 struct fb_var_screeninfo old_var; 1023 struct fb_videomode mode; 1024 1025 if (info->fbops->fb_get_caps) { 1026 ret = fb_check_caps(info, var, activate); 1027 1028 if (ret) 1029 goto done; 1030 } 1031 1032 old_var = info->var; 1033 info->var = *var; 1034 1035 if (info->fbops->fb_set_par) { 1036 ret = info->fbops->fb_set_par(info); 1037 1038 if (ret) { 1039 info->var = old_var; 1040 printk(KERN_WARNING "detected " 1041 "fb_set_par error, " 1042 "error code: %d\n", ret); 1043 goto done; 1044 } 1045 } 1046 1047 fb_pan_display(info, &info->var); 1048 fb_set_cmap(&info->cmap, info); 1049 fb_var_to_videomode(&mode, &info->var); 1050 1051 if (info->modelist.prev && info->modelist.next && 1052 !list_empty(&info->modelist)) 1053 ret = fb_add_videomode(&mode, &info->modelist); 1054 1055 if (!ret && (flags & FBINFO_MISC_USEREVENT)) { 1056 struct fb_event event; 1057 int evnt = (activate & FB_ACTIVATE_ALL) ? 1058 FB_EVENT_MODE_CHANGE_ALL : 1059 FB_EVENT_MODE_CHANGE; 1060 1061 info->flags &= ~FBINFO_MISC_USEREVENT; 1062 event.info = info; 1063 event.data = &mode; 1064 fb_notifier_call_chain(evnt, &event); 1065 } 1066 } 1067 } 1068 1069 done: 1070 return ret; 1071 } 1072 EXPORT_SYMBOL(fb_set_var); 1073 1074 int 1075 fb_blank(struct fb_info *info, int blank) 1076 { 1077 struct fb_event event; 1078 int ret = -EINVAL, early_ret; 1079 1080 if (blank > FB_BLANK_POWERDOWN) 1081 blank = FB_BLANK_POWERDOWN; 1082 1083 event.info = info; 1084 event.data = ␣ 1085 1086 early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event); 1087 1088 if (info->fbops->fb_blank) 1089 ret = info->fbops->fb_blank(blank, info); 1090 1091 if (!ret) 1092 fb_notifier_call_chain(FB_EVENT_BLANK, &event); 1093 else { 1094 /* 1095 * if fb_blank is failed then revert effects of 1096 * the early blank event. 1097 */ 1098 if (!early_ret) 1099 fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event); 1100 } 1101 1102 return ret; 1103 } 1104 EXPORT_SYMBOL(fb_blank); 1105 1106 static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, 1107 unsigned long arg) 1108 { 1109 struct fb_ops *fb; 1110 struct fb_var_screeninfo var; 1111 struct fb_fix_screeninfo fix; 1112 struct fb_con2fbmap con2fb; 1113 struct fb_cmap cmap_from; 1114 struct fb_cmap_user cmap; 1115 struct fb_event event; 1116 void __user *argp = (void __user *)arg; 1117 long ret = 0; 1118 1119 switch (cmd) { 1120 case FBIOGET_VSCREENINFO: 1121 if (!lock_fb_info(info)) 1122 return -ENODEV; 1123 var = info->var; 1124 unlock_fb_info(info); 1125 1126 ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; 1127 break; 1128 case FBIOPUT_VSCREENINFO: 1129 if (copy_from_user(&var, argp, sizeof(var))) 1130 return -EFAULT; 1131 console_lock(); 1132 if (!lock_fb_info(info)) { 1133 console_unlock(); 1134 return -ENODEV; 1135 } 1136 info->flags |= FBINFO_MISC_USEREVENT; 1137 ret = fb_set_var(info, &var); 1138 info->flags &= ~FBINFO_MISC_USEREVENT; 1139 unlock_fb_info(info); 1140 console_unlock(); 1141 if (!ret && copy_to_user(argp, &var, sizeof(var))) 1142 ret = -EFAULT; 1143 break; 1144 case FBIOGET_FSCREENINFO: 1145 if (!lock_fb_info(info)) 1146 return -ENODEV; 1147 fix = info->fix; 1148 if (info->flags & FBINFO_HIDE_SMEM_START) 1149 fix.smem_start = 0; 1150 unlock_fb_info(info); 1151 1152 ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; 1153 break; 1154 case FBIOPUTCMAP: 1155 if (copy_from_user(&cmap, argp, sizeof(cmap))) 1156 return -EFAULT; 1157 ret = fb_set_user_cmap(&cmap, info); 1158 break; 1159 case FBIOGETCMAP: 1160 if (copy_from_user(&cmap, argp, sizeof(cmap))) 1161 return -EFAULT; 1162 if (!lock_fb_info(info)) 1163 return -ENODEV; 1164 cmap_from = info->cmap; 1165 unlock_fb_info(info); 1166 ret = fb_cmap_to_user(&cmap_from, &cmap); 1167 break; 1168 case FBIOPAN_DISPLAY: 1169 if (copy_from_user(&var, argp, sizeof(var))) 1170 return -EFAULT; 1171 console_lock(); 1172 if (!lock_fb_info(info)) { 1173 console_unlock(); 1174 return -ENODEV; 1175 } 1176 ret = fb_pan_display(info, &var); 1177 unlock_fb_info(info); 1178 console_unlock(); 1179 if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) 1180 return -EFAULT; 1181 break; 1182 case FBIO_CURSOR: 1183 ret = -EINVAL; 1184 break; 1185 case FBIOGET_CON2FBMAP: 1186 if (copy_from_user(&con2fb, argp, sizeof(con2fb))) 1187 return -EFAULT; 1188 if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) 1189 return -EINVAL; 1190 con2fb.framebuffer = -1; 1191 event.data = &con2fb; 1192 if (!lock_fb_info(info)) 1193 return -ENODEV; 1194 event.info = info; 1195 fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); 1196 unlock_fb_info(info); 1197 ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; 1198 break; 1199 case FBIOPUT_CON2FBMAP: 1200 if (copy_from_user(&con2fb, argp, sizeof(con2fb))) 1201 return -EFAULT; 1202 if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) 1203 return -EINVAL; 1204 if (con2fb.framebuffer >= FB_MAX) 1205 return -EINVAL; 1206 if (!registered_fb[con2fb.framebuffer]) 1207 request_module("fb%d", con2fb.framebuffer); 1208 if (!registered_fb[con2fb.framebuffer]) { 1209 ret = -EINVAL; 1210 break; 1211 } 1212 event.data = &con2fb; 1213 console_lock(); 1214 if (!lock_fb_info(info)) { 1215 console_unlock(); 1216 return -ENODEV; 1217 } 1218 event.info = info; 1219 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); 1220 unlock_fb_info(info); 1221 console_unlock(); 1222 break; 1223 case FBIOBLANK: 1224 console_lock(); 1225 if (!lock_fb_info(info)) { 1226 console_unlock(); 1227 return -ENODEV; 1228 } 1229 info->flags |= FBINFO_MISC_USEREVENT; 1230 ret = fb_blank(info, arg); 1231 info->flags &= ~FBINFO_MISC_USEREVENT; 1232 unlock_fb_info(info); 1233 console_unlock(); 1234 break; 1235 default: 1236 if (!lock_fb_info(info)) 1237 return -ENODEV; 1238 fb = info->fbops; 1239 if (fb->fb_ioctl) 1240 ret = fb->fb_ioctl(info, cmd, arg); 1241 else 1242 ret = -ENOTTY; 1243 unlock_fb_info(info); 1244 } 1245 return ret; 1246 } 1247 1248 static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1249 { 1250 struct fb_info *info = file_fb_info(file); 1251 1252 if (!info) 1253 return -ENODEV; 1254 return do_fb_ioctl(info, cmd, arg); 1255 } 1256 1257 #ifdef CONFIG_COMPAT 1258 struct fb_fix_screeninfo32 { 1259 char id[16]; 1260 compat_caddr_t smem_start; 1261 u32 smem_len; 1262 u32 type; 1263 u32 type_aux; 1264 u32 visual; 1265 u16 xpanstep; 1266 u16 ypanstep; 1267 u16 ywrapstep; 1268 u32 line_length; 1269 compat_caddr_t mmio_start; 1270 u32 mmio_len; 1271 u32 accel; 1272 u16 reserved[3]; 1273 }; 1274 1275 struct fb_cmap32 { 1276 u32 start; 1277 u32 len; 1278 compat_caddr_t red; 1279 compat_caddr_t green; 1280 compat_caddr_t blue; 1281 compat_caddr_t transp; 1282 }; 1283 1284 static int fb_getput_cmap(struct fb_info *info, unsigned int cmd, 1285 unsigned long arg) 1286 { 1287 struct fb_cmap_user __user *cmap; 1288 struct fb_cmap32 __user *cmap32; 1289 __u32 data; 1290 int err; 1291 1292 cmap = compat_alloc_user_space(sizeof(*cmap)); 1293 cmap32 = compat_ptr(arg); 1294 1295 if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32))) 1296 return -EFAULT; 1297 1298 if (get_user(data, &cmap32->red) || 1299 put_user(compat_ptr(data), &cmap->red) || 1300 get_user(data, &cmap32->green) || 1301 put_user(compat_ptr(data), &cmap->green) || 1302 get_user(data, &cmap32->blue) || 1303 put_user(compat_ptr(data), &cmap->blue) || 1304 get_user(data, &cmap32->transp) || 1305 put_user(compat_ptr(data), &cmap->transp)) 1306 return -EFAULT; 1307 1308 err = do_fb_ioctl(info, cmd, (unsigned long) cmap); 1309 1310 if (!err) { 1311 if (copy_in_user(&cmap32->start, 1312 &cmap->start, 1313 2 * sizeof(__u32))) 1314 err = -EFAULT; 1315 } 1316 return err; 1317 } 1318 1319 static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, 1320 struct fb_fix_screeninfo32 __user *fix32) 1321 { 1322 __u32 data; 1323 int err; 1324 1325 err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); 1326 1327 data = (__u32) (unsigned long) fix->smem_start; 1328 err |= put_user(data, &fix32->smem_start); 1329 1330 err |= put_user(fix->smem_len, &fix32->smem_len); 1331 err |= put_user(fix->type, &fix32->type); 1332 err |= put_user(fix->type_aux, &fix32->type_aux); 1333 err |= put_user(fix->visual, &fix32->visual); 1334 err |= put_user(fix->xpanstep, &fix32->xpanstep); 1335 err |= put_user(fix->ypanstep, &fix32->ypanstep); 1336 err |= put_user(fix->ywrapstep, &fix32->ywrapstep); 1337 err |= put_user(fix->line_length, &fix32->line_length); 1338 1339 data = (__u32) (unsigned long) fix->mmio_start; 1340 err |= put_user(data, &fix32->mmio_start); 1341 1342 err |= put_user(fix->mmio_len, &fix32->mmio_len); 1343 err |= put_user(fix->accel, &fix32->accel); 1344 err |= copy_to_user(fix32->reserved, fix->reserved, 1345 sizeof(fix->reserved)); 1346 1347 if (err) 1348 return -EFAULT; 1349 return 0; 1350 } 1351 1352 static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, 1353 unsigned long arg) 1354 { 1355 struct fb_fix_screeninfo fix; 1356 1357 if (!lock_fb_info(info)) 1358 return -ENODEV; 1359 fix = info->fix; 1360 if (info->flags & FBINFO_HIDE_SMEM_START) 1361 fix.smem_start = 0; 1362 unlock_fb_info(info); 1363 return do_fscreeninfo_to_user(&fix, compat_ptr(arg)); 1364 } 1365 1366 static long fb_compat_ioctl(struct file *file, unsigned int cmd, 1367 unsigned long arg) 1368 { 1369 struct fb_info *info = file_fb_info(file); 1370 struct fb_ops *fb; 1371 long ret = -ENOIOCTLCMD; 1372 1373 if (!info) 1374 return -ENODEV; 1375 fb = info->fbops; 1376 switch(cmd) { 1377 case FBIOGET_VSCREENINFO: 1378 case FBIOPUT_VSCREENINFO: 1379 case FBIOPAN_DISPLAY: 1380 case FBIOGET_CON2FBMAP: 1381 case FBIOPUT_CON2FBMAP: 1382 arg = (unsigned long) compat_ptr(arg); 1383 /* fall through */ 1384 case FBIOBLANK: 1385 ret = do_fb_ioctl(info, cmd, arg); 1386 break; 1387 1388 case FBIOGET_FSCREENINFO: 1389 ret = fb_get_fscreeninfo(info, cmd, arg); 1390 break; 1391 1392 case FBIOGETCMAP: 1393 case FBIOPUTCMAP: 1394 ret = fb_getput_cmap(info, cmd, arg); 1395 break; 1396 1397 default: 1398 if (fb->fb_compat_ioctl) 1399 ret = fb->fb_compat_ioctl(info, cmd, arg); 1400 break; 1401 } 1402 return ret; 1403 } 1404 #endif 1405 1406 static int 1407 fb_mmap(struct file *file, struct vm_area_struct * vma) 1408 { 1409 struct fb_info *info = file_fb_info(file); 1410 struct fb_ops *fb; 1411 unsigned long mmio_pgoff; 1412 unsigned long start; 1413 u32 len; 1414 1415 if (!info) 1416 return -ENODEV; 1417 fb = info->fbops; 1418 if (!fb) 1419 return -ENODEV; 1420 mutex_lock(&info->mm_lock); 1421 if (fb->fb_mmap) { 1422 int res; 1423 1424 /* 1425 * The framebuffer needs to be accessed decrypted, be sure 1426 * SME protection is removed ahead of the call 1427 */ 1428 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); 1429 res = fb->fb_mmap(info, vma); 1430 mutex_unlock(&info->mm_lock); 1431 return res; 1432 } 1433 1434 /* 1435 * Ugh. This can be either the frame buffer mapping, or 1436 * if pgoff points past it, the mmio mapping. 1437 */ 1438 start = info->fix.smem_start; 1439 len = info->fix.smem_len; 1440 mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT; 1441 if (vma->vm_pgoff >= mmio_pgoff) { 1442 if (info->var.accel_flags) { 1443 mutex_unlock(&info->mm_lock); 1444 return -EINVAL; 1445 } 1446 1447 vma->vm_pgoff -= mmio_pgoff; 1448 start = info->fix.mmio_start; 1449 len = info->fix.mmio_len; 1450 } 1451 mutex_unlock(&info->mm_lock); 1452 1453 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 1454 /* 1455 * The framebuffer needs to be accessed decrypted, be sure 1456 * SME protection is removed 1457 */ 1458 vma->vm_page_prot = pgprot_decrypted(vma->vm_page_prot); 1459 fb_pgprotect(file, vma, start); 1460 1461 return vm_iomap_memory(vma, start, len); 1462 } 1463 1464 static int 1465 fb_open(struct inode *inode, struct file *file) 1466 __acquires(&info->lock) 1467 __releases(&info->lock) 1468 { 1469 int fbidx = iminor(inode); 1470 struct fb_info *info; 1471 int res = 0; 1472 1473 info = get_fb_info(fbidx); 1474 if (!info) { 1475 request_module("fb%d", fbidx); 1476 info = get_fb_info(fbidx); 1477 if (!info) 1478 return -ENODEV; 1479 } 1480 if (IS_ERR(info)) 1481 return PTR_ERR(info); 1482 1483 mutex_lock(&info->lock); 1484 if (!try_module_get(info->fbops->owner)) { 1485 res = -ENODEV; 1486 goto out; 1487 } 1488 file->private_data = info; 1489 if (info->fbops->fb_open) { 1490 res = info->fbops->fb_open(info,1); 1491 if (res) 1492 module_put(info->fbops->owner); 1493 } 1494 #ifdef CONFIG_FB_DEFERRED_IO 1495 if (info->fbdefio) 1496 fb_deferred_io_open(info, inode, file); 1497 #endif 1498 out: 1499 mutex_unlock(&info->lock); 1500 if (res) 1501 put_fb_info(info); 1502 return res; 1503 } 1504 1505 static int 1506 fb_release(struct inode *inode, struct file *file) 1507 __acquires(&info->lock) 1508 __releases(&info->lock) 1509 { 1510 struct fb_info * const info = file->private_data; 1511 1512 mutex_lock(&info->lock); 1513 if (info->fbops->fb_release) 1514 info->fbops->fb_release(info,1); 1515 module_put(info->fbops->owner); 1516 mutex_unlock(&info->lock); 1517 put_fb_info(info); 1518 return 0; 1519 } 1520 1521 #if defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && !defined(CONFIG_MMU) 1522 unsigned long get_fb_unmapped_area(struct file *filp, 1523 unsigned long addr, unsigned long len, 1524 unsigned long pgoff, unsigned long flags) 1525 { 1526 struct fb_info * const info = filp->private_data; 1527 unsigned long fb_size = PAGE_ALIGN(info->fix.smem_len); 1528 1529 if (pgoff > fb_size || len > fb_size - pgoff) 1530 return -EINVAL; 1531 1532 return (unsigned long)info->screen_base + pgoff; 1533 } 1534 #endif 1535 1536 static const struct file_operations fb_fops = { 1537 .owner = THIS_MODULE, 1538 .read = fb_read, 1539 .write = fb_write, 1540 .unlocked_ioctl = fb_ioctl, 1541 #ifdef CONFIG_COMPAT 1542 .compat_ioctl = fb_compat_ioctl, 1543 #endif 1544 .mmap = fb_mmap, 1545 .open = fb_open, 1546 .release = fb_release, 1547 #if defined(HAVE_ARCH_FB_UNMAPPED_AREA) || \ 1548 (defined(CONFIG_FB_PROVIDE_GET_FB_UNMAPPED_AREA) && \ 1549 !defined(CONFIG_MMU)) 1550 .get_unmapped_area = get_fb_unmapped_area, 1551 #endif 1552 #ifdef CONFIG_FB_DEFERRED_IO 1553 .fsync = fb_deferred_io_fsync, 1554 #endif 1555 .llseek = default_llseek, 1556 }; 1557 1558 struct class *fb_class; 1559 EXPORT_SYMBOL(fb_class); 1560 1561 static int fb_check_foreignness(struct fb_info *fi) 1562 { 1563 const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; 1564 1565 fi->flags &= ~FBINFO_FOREIGN_ENDIAN; 1566 1567 #ifdef __BIG_ENDIAN 1568 fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH; 1569 #else 1570 fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0; 1571 #endif /* __BIG_ENDIAN */ 1572 1573 if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) { 1574 pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to " 1575 "support this framebuffer\n", fi->fix.id); 1576 return -ENOSYS; 1577 } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) { 1578 pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to " 1579 "support this framebuffer\n", fi->fix.id); 1580 return -ENOSYS; 1581 } 1582 1583 return 0; 1584 } 1585 1586 static bool apertures_overlap(struct aperture *gen, struct aperture *hw) 1587 { 1588 /* is the generic aperture base the same as the HW one */ 1589 if (gen->base == hw->base) 1590 return true; 1591 /* is the generic aperture base inside the hw base->hw base+size */ 1592 if (gen->base > hw->base && gen->base < hw->base + hw->size) 1593 return true; 1594 return false; 1595 } 1596 1597 static bool fb_do_apertures_overlap(struct apertures_struct *gena, 1598 struct apertures_struct *hwa) 1599 { 1600 int i, j; 1601 if (!hwa || !gena) 1602 return false; 1603 1604 for (i = 0; i < hwa->count; ++i) { 1605 struct aperture *h = &hwa->ranges[i]; 1606 for (j = 0; j < gena->count; ++j) { 1607 struct aperture *g = &gena->ranges[j]; 1608 printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", 1609 (unsigned long long)g->base, 1610 (unsigned long long)g->size, 1611 (unsigned long long)h->base, 1612 (unsigned long long)h->size); 1613 if (apertures_overlap(g, h)) 1614 return true; 1615 } 1616 } 1617 1618 return false; 1619 } 1620 1621 static int do_unregister_framebuffer(struct fb_info *fb_info); 1622 1623 #define VGA_FB_PHYS 0xA0000 1624 static int do_remove_conflicting_framebuffers(struct apertures_struct *a, 1625 const char *name, bool primary) 1626 { 1627 int i, ret; 1628 1629 /* check all firmware fbs and kick off if the base addr overlaps */ 1630 for_each_registered_fb(i) { 1631 struct apertures_struct *gen_aper; 1632 1633 if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) 1634 continue; 1635 1636 gen_aper = registered_fb[i]->apertures; 1637 if (fb_do_apertures_overlap(gen_aper, a) || 1638 (primary && gen_aper && gen_aper->count && 1639 gen_aper->ranges[0].base == VGA_FB_PHYS)) { 1640 1641 printk(KERN_INFO "fb%d: switching to %s from %s\n", 1642 i, name, registered_fb[i]->fix.id); 1643 ret = do_unregister_framebuffer(registered_fb[i]); 1644 if (ret) 1645 return ret; 1646 } 1647 } 1648 1649 return 0; 1650 } 1651 1652 static bool lockless_register_fb; 1653 module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400); 1654 MODULE_PARM_DESC(lockless_register_fb, 1655 "Lockless framebuffer registration for debugging [default=off]"); 1656 1657 static int do_register_framebuffer(struct fb_info *fb_info) 1658 { 1659 int i, ret; 1660 struct fb_event event; 1661 struct fb_videomode mode; 1662 1663 if (fb_check_foreignness(fb_info)) 1664 return -ENOSYS; 1665 1666 ret = do_remove_conflicting_framebuffers(fb_info->apertures, 1667 fb_info->fix.id, 1668 fb_is_primary_device(fb_info)); 1669 if (ret) 1670 return ret; 1671 1672 if (num_registered_fb == FB_MAX) 1673 return -ENXIO; 1674 1675 num_registered_fb++; 1676 for (i = 0 ; i < FB_MAX; i++) 1677 if (!registered_fb[i]) 1678 break; 1679 fb_info->node = i; 1680 atomic_set(&fb_info->count, 1); 1681 mutex_init(&fb_info->lock); 1682 mutex_init(&fb_info->mm_lock); 1683 1684 fb_info->dev = device_create(fb_class, fb_info->device, 1685 MKDEV(FB_MAJOR, i), NULL, "fb%d", i); 1686 if (IS_ERR(fb_info->dev)) { 1687 /* Not fatal */ 1688 printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); 1689 fb_info->dev = NULL; 1690 } else 1691 fb_init_device(fb_info); 1692 1693 if (fb_info->pixmap.addr == NULL) { 1694 fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); 1695 if (fb_info->pixmap.addr) { 1696 fb_info->pixmap.size = FBPIXMAPSIZE; 1697 fb_info->pixmap.buf_align = 1; 1698 fb_info->pixmap.scan_align = 1; 1699 fb_info->pixmap.access_align = 32; 1700 fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; 1701 } 1702 } 1703 fb_info->pixmap.offset = 0; 1704 1705 if (!fb_info->pixmap.blit_x) 1706 fb_info->pixmap.blit_x = ~(u32)0; 1707 1708 if (!fb_info->pixmap.blit_y) 1709 fb_info->pixmap.blit_y = ~(u32)0; 1710 1711 if (!fb_info->modelist.prev || !fb_info->modelist.next) 1712 INIT_LIST_HEAD(&fb_info->modelist); 1713 1714 if (fb_info->skip_vt_switch) 1715 pm_vt_switch_required(fb_info->dev, false); 1716 else 1717 pm_vt_switch_required(fb_info->dev, true); 1718 1719 fb_var_to_videomode(&mode, &fb_info->var); 1720 fb_add_videomode(&mode, &fb_info->modelist); 1721 registered_fb[i] = fb_info; 1722 1723 event.info = fb_info; 1724 if (!lockless_register_fb) 1725 console_lock(); 1726 else 1727 atomic_inc(&ignore_console_lock_warning); 1728 if (!lock_fb_info(fb_info)) { 1729 ret = -ENODEV; 1730 goto unlock_console; 1731 } 1732 ret = 0; 1733 1734 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); 1735 unlock_fb_info(fb_info); 1736 unlock_console: 1737 if (!lockless_register_fb) 1738 console_unlock(); 1739 else 1740 atomic_dec(&ignore_console_lock_warning); 1741 return ret; 1742 } 1743 1744 static int unbind_console(struct fb_info *fb_info) 1745 { 1746 struct fb_event event; 1747 int ret; 1748 int i = fb_info->node; 1749 1750 if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) 1751 return -EINVAL; 1752 1753 console_lock(); 1754 if (!lock_fb_info(fb_info)) { 1755 console_unlock(); 1756 return -ENODEV; 1757 } 1758 1759 event.info = fb_info; 1760 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); 1761 unlock_fb_info(fb_info); 1762 console_unlock(); 1763 1764 return ret; 1765 } 1766 1767 static int __unlink_framebuffer(struct fb_info *fb_info); 1768 1769 static int do_unregister_framebuffer(struct fb_info *fb_info) 1770 { 1771 struct fb_event event; 1772 int ret; 1773 1774 ret = unbind_console(fb_info); 1775 1776 if (ret) 1777 return -EINVAL; 1778 1779 pm_vt_switch_unregister(fb_info->dev); 1780 1781 __unlink_framebuffer(fb_info); 1782 if (fb_info->pixmap.addr && 1783 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) 1784 kfree(fb_info->pixmap.addr); 1785 fb_destroy_modelist(&fb_info->modelist); 1786 registered_fb[fb_info->node] = NULL; 1787 num_registered_fb--; 1788 fb_cleanup_device(fb_info); 1789 event.info = fb_info; 1790 console_lock(); 1791 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1792 console_unlock(); 1793 1794 /* this may free fb info */ 1795 put_fb_info(fb_info); 1796 return 0; 1797 } 1798 1799 static int __unlink_framebuffer(struct fb_info *fb_info) 1800 { 1801 int i; 1802 1803 i = fb_info->node; 1804 if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) 1805 return -EINVAL; 1806 1807 if (fb_info->dev) { 1808 device_destroy(fb_class, MKDEV(FB_MAJOR, i)); 1809 fb_info->dev = NULL; 1810 } 1811 1812 return 0; 1813 } 1814 1815 int unlink_framebuffer(struct fb_info *fb_info) 1816 { 1817 int ret; 1818 1819 ret = __unlink_framebuffer(fb_info); 1820 if (ret) 1821 return ret; 1822 1823 unbind_console(fb_info); 1824 1825 return 0; 1826 } 1827 EXPORT_SYMBOL(unlink_framebuffer); 1828 1829 /** 1830 * remove_conflicting_framebuffers - remove firmware-configured framebuffers 1831 * @a: memory range, users of which are to be removed 1832 * @name: requesting driver name 1833 * @primary: also kick vga16fb if present 1834 * 1835 * This function removes framebuffer devices (initialized by firmware/bootloader) 1836 * which use memory range described by @a. If @a is NULL all such devices are 1837 * removed. 1838 */ 1839 int remove_conflicting_framebuffers(struct apertures_struct *a, 1840 const char *name, bool primary) 1841 { 1842 int ret; 1843 bool do_free = false; 1844 1845 if (!a) { 1846 a = alloc_apertures(1); 1847 if (!a) 1848 return -ENOMEM; 1849 1850 a->ranges[0].base = 0; 1851 a->ranges[0].size = ~0; 1852 do_free = true; 1853 } 1854 1855 mutex_lock(®istration_lock); 1856 ret = do_remove_conflicting_framebuffers(a, name, primary); 1857 mutex_unlock(®istration_lock); 1858 1859 if (do_free) 1860 kfree(a); 1861 1862 return ret; 1863 } 1864 EXPORT_SYMBOL(remove_conflicting_framebuffers); 1865 1866 /** 1867 * remove_conflicting_pci_framebuffers - remove firmware-configured framebuffers for PCI devices 1868 * @pdev: PCI device 1869 * @res_id: index of PCI BAR configuring framebuffer memory 1870 * @name: requesting driver name 1871 * 1872 * This function removes framebuffer devices (eg. initialized by firmware) 1873 * using memory range configured for @pdev's BAR @res_id. 1874 * 1875 * The function assumes that PCI device with shadowed ROM drives a primary 1876 * display and so kicks out vga16fb. 1877 */ 1878 int remove_conflicting_pci_framebuffers(struct pci_dev *pdev, int res_id, const char *name) 1879 { 1880 struct apertures_struct *ap; 1881 bool primary = false; 1882 int err; 1883 1884 ap = alloc_apertures(1); 1885 if (!ap) 1886 return -ENOMEM; 1887 1888 ap->ranges[0].base = pci_resource_start(pdev, res_id); 1889 ap->ranges[0].size = pci_resource_len(pdev, res_id); 1890 #ifdef CONFIG_X86 1891 primary = pdev->resource[PCI_ROM_RESOURCE].flags & 1892 IORESOURCE_ROM_SHADOW; 1893 #endif 1894 err = remove_conflicting_framebuffers(ap, name, primary); 1895 kfree(ap); 1896 return err; 1897 } 1898 EXPORT_SYMBOL(remove_conflicting_pci_framebuffers); 1899 1900 /** 1901 * register_framebuffer - registers a frame buffer device 1902 * @fb_info: frame buffer info structure 1903 * 1904 * Registers a frame buffer device @fb_info. 1905 * 1906 * Returns negative errno on error, or zero for success. 1907 * 1908 */ 1909 int 1910 register_framebuffer(struct fb_info *fb_info) 1911 { 1912 int ret; 1913 1914 mutex_lock(®istration_lock); 1915 ret = do_register_framebuffer(fb_info); 1916 mutex_unlock(®istration_lock); 1917 1918 return ret; 1919 } 1920 EXPORT_SYMBOL(register_framebuffer); 1921 1922 /** 1923 * unregister_framebuffer - releases a frame buffer device 1924 * @fb_info: frame buffer info structure 1925 * 1926 * Unregisters a frame buffer device @fb_info. 1927 * 1928 * Returns negative errno on error, or zero for success. 1929 * 1930 * This function will also notify the framebuffer console 1931 * to release the driver. 1932 * 1933 * This is meant to be called within a driver's module_exit() 1934 * function. If this is called outside module_exit(), ensure 1935 * that the driver implements fb_open() and fb_release() to 1936 * check that no processes are using the device. 1937 */ 1938 int 1939 unregister_framebuffer(struct fb_info *fb_info) 1940 { 1941 int ret; 1942 1943 mutex_lock(®istration_lock); 1944 ret = do_unregister_framebuffer(fb_info); 1945 mutex_unlock(®istration_lock); 1946 1947 return ret; 1948 } 1949 EXPORT_SYMBOL(unregister_framebuffer); 1950 1951 /** 1952 * fb_set_suspend - low level driver signals suspend 1953 * @info: framebuffer affected 1954 * @state: 0 = resuming, !=0 = suspending 1955 * 1956 * This is meant to be used by low level drivers to 1957 * signal suspend/resume to the core & clients. 1958 * It must be called with the console semaphore held 1959 */ 1960 void fb_set_suspend(struct fb_info *info, int state) 1961 { 1962 struct fb_event event; 1963 1964 event.info = info; 1965 if (state) { 1966 fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); 1967 info->state = FBINFO_STATE_SUSPENDED; 1968 } else { 1969 info->state = FBINFO_STATE_RUNNING; 1970 fb_notifier_call_chain(FB_EVENT_RESUME, &event); 1971 } 1972 } 1973 EXPORT_SYMBOL(fb_set_suspend); 1974 1975 /** 1976 * fbmem_init - init frame buffer subsystem 1977 * 1978 * Initialize the frame buffer subsystem. 1979 * 1980 * NOTE: This function is _only_ to be called by drivers/char/mem.c. 1981 * 1982 */ 1983 1984 static int __init 1985 fbmem_init(void) 1986 { 1987 int ret; 1988 1989 if (!proc_create_seq("fb", 0, NULL, &proc_fb_seq_ops)) 1990 return -ENOMEM; 1991 1992 ret = register_chrdev(FB_MAJOR, "fb", &fb_fops); 1993 if (ret) { 1994 printk("unable to get major %d for fb devs\n", FB_MAJOR); 1995 goto err_chrdev; 1996 } 1997 1998 fb_class = class_create(THIS_MODULE, "graphics"); 1999 if (IS_ERR(fb_class)) { 2000 ret = PTR_ERR(fb_class); 2001 pr_warn("Unable to create fb class; errno = %d\n", ret); 2002 fb_class = NULL; 2003 goto err_class; 2004 } 2005 2006 fb_console_init(); 2007 2008 return 0; 2009 2010 err_class: 2011 unregister_chrdev(FB_MAJOR, "fb"); 2012 err_chrdev: 2013 remove_proc_entry("fb", NULL); 2014 return ret; 2015 } 2016 2017 #ifdef MODULE 2018 module_init(fbmem_init); 2019 static void __exit 2020 fbmem_exit(void) 2021 { 2022 fb_console_exit(); 2023 2024 remove_proc_entry("fb", NULL); 2025 class_destroy(fb_class); 2026 unregister_chrdev(FB_MAJOR, "fb"); 2027 } 2028 2029 module_exit(fbmem_exit); 2030 MODULE_LICENSE("GPL"); 2031 MODULE_DESCRIPTION("Framebuffer base"); 2032 #else 2033 subsys_initcall(fbmem_init); 2034 #endif 2035 2036 int fb_new_modelist(struct fb_info *info) 2037 { 2038 struct fb_event event; 2039 struct fb_var_screeninfo var = info->var; 2040 struct list_head *pos, *n; 2041 struct fb_modelist *modelist; 2042 struct fb_videomode *m, mode; 2043 int err = 1; 2044 2045 list_for_each_safe(pos, n, &info->modelist) { 2046 modelist = list_entry(pos, struct fb_modelist, list); 2047 m = &modelist->mode; 2048 fb_videomode_to_var(&var, m); 2049 var.activate = FB_ACTIVATE_TEST; 2050 err = fb_set_var(info, &var); 2051 fb_var_to_videomode(&mode, &var); 2052 if (err || !fb_mode_is_equal(m, &mode)) { 2053 list_del(pos); 2054 kfree(pos); 2055 } 2056 } 2057 2058 err = 1; 2059 2060 if (!list_empty(&info->modelist)) { 2061 event.info = info; 2062 err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); 2063 } 2064 2065 return err; 2066 } 2067 2068 MODULE_LICENSE("GPL"); 2069