Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.26-rc4 1728 lines 41 kB view raw
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/smp_lock.h> 20#include <linux/kernel.h> 21#include <linux/major.h> 22#include <linux/slab.h> 23#include <linux/mm.h> 24#include <linux/mman.h> 25#include <linux/vt.h> 26#include <linux/init.h> 27#include <linux/linux_logo.h> 28#include <linux/proc_fs.h> 29#include <linux/seq_file.h> 30#include <linux/console.h> 31#ifdef CONFIG_KMOD 32#include <linux/kmod.h> 33#endif 34#include <linux/err.h> 35#include <linux/device.h> 36#include <linux/efi.h> 37#include <linux/fb.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 48struct fb_info *registered_fb[FB_MAX] __read_mostly; 49int num_registered_fb __read_mostly; 50 51/* 52 * Helpers 53 */ 54 55int fb_get_color_depth(struct fb_var_screeninfo *var, 56 struct fb_fix_screeninfo *fix) 57{ 58 int depth = 0; 59 60 if (fix->visual == FB_VISUAL_MONO01 || 61 fix->visual == FB_VISUAL_MONO10) 62 depth = 1; 63 else { 64 if (var->green.length == var->blue.length && 65 var->green.length == var->red.length && 66 var->green.offset == var->blue.offset && 67 var->green.offset == var->red.offset) 68 depth = var->green.length; 69 else 70 depth = var->green.length + var->red.length + 71 var->blue.length; 72 } 73 74 return depth; 75} 76EXPORT_SYMBOL(fb_get_color_depth); 77 78/* 79 * Data padding functions. 80 */ 81void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height) 82{ 83 __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height); 84} 85EXPORT_SYMBOL(fb_pad_aligned_buffer); 86 87void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height, 88 u32 shift_high, u32 shift_low, u32 mod) 89{ 90 u8 mask = (u8) (0xfff << shift_high), tmp; 91 int i, j; 92 93 for (i = height; i--; ) { 94 for (j = 0; j < idx; j++) { 95 tmp = dst[j]; 96 tmp &= mask; 97 tmp |= *src >> shift_low; 98 dst[j] = tmp; 99 tmp = *src << shift_high; 100 dst[j+1] = tmp; 101 src++; 102 } 103 tmp = dst[idx]; 104 tmp &= mask; 105 tmp |= *src >> shift_low; 106 dst[idx] = tmp; 107 if (shift_high < mod) { 108 tmp = *src << shift_high; 109 dst[idx+1] = tmp; 110 } 111 src++; 112 dst += d_pitch; 113 } 114} 115EXPORT_SYMBOL(fb_pad_unaligned_buffer); 116 117/* 118 * we need to lock this section since fb_cursor 119 * may use fb_imageblit() 120 */ 121char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size) 122{ 123 u32 align = buf->buf_align - 1, offset; 124 char *addr = buf->addr; 125 126 /* If IO mapped, we need to sync before access, no sharing of 127 * the pixmap is done 128 */ 129 if (buf->flags & FB_PIXMAP_IO) { 130 if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) 131 info->fbops->fb_sync(info); 132 return addr; 133 } 134 135 /* See if we fit in the remaining pixmap space */ 136 offset = buf->offset + align; 137 offset &= ~align; 138 if (offset + size > buf->size) { 139 /* We do not fit. In order to be able to re-use the buffer, 140 * we must ensure no asynchronous DMA'ing or whatever operation 141 * is in progress, we sync for that. 142 */ 143 if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) 144 info->fbops->fb_sync(info); 145 offset = 0; 146 } 147 buf->offset = offset + size; 148 addr += offset; 149 150 return addr; 151} 152 153#ifdef CONFIG_LOGO 154 155static inline unsigned safe_shift(unsigned d, int n) 156{ 157 return n < 0 ? d >> -n : d << n; 158} 159 160static void fb_set_logocmap(struct fb_info *info, 161 const struct linux_logo *logo) 162{ 163 struct fb_cmap palette_cmap; 164 u16 palette_green[16]; 165 u16 palette_blue[16]; 166 u16 palette_red[16]; 167 int i, j, n; 168 const unsigned char *clut = logo->clut; 169 170 palette_cmap.start = 0; 171 palette_cmap.len = 16; 172 palette_cmap.red = palette_red; 173 palette_cmap.green = palette_green; 174 palette_cmap.blue = palette_blue; 175 palette_cmap.transp = NULL; 176 177 for (i = 0; i < logo->clutsize; i += n) { 178 n = logo->clutsize - i; 179 /* palette_cmap provides space for only 16 colors at once */ 180 if (n > 16) 181 n = 16; 182 palette_cmap.start = 32 + i; 183 palette_cmap.len = n; 184 for (j = 0; j < n; ++j) { 185 palette_cmap.red[j] = clut[0] << 8 | clut[0]; 186 palette_cmap.green[j] = clut[1] << 8 | clut[1]; 187 palette_cmap.blue[j] = clut[2] << 8 | clut[2]; 188 clut += 3; 189 } 190 fb_set_cmap(&palette_cmap, info); 191 } 192} 193 194static void fb_set_logo_truepalette(struct fb_info *info, 195 const struct linux_logo *logo, 196 u32 *palette) 197{ 198 static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; 199 unsigned char redmask, greenmask, bluemask; 200 int redshift, greenshift, blueshift; 201 int i; 202 const unsigned char *clut = logo->clut; 203 204 /* 205 * We have to create a temporary palette since console palette is only 206 * 16 colors long. 207 */ 208 /* Bug: Doesn't obey msb_right ... (who needs that?) */ 209 redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; 210 greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; 211 bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; 212 redshift = info->var.red.offset - (8 - info->var.red.length); 213 greenshift = info->var.green.offset - (8 - info->var.green.length); 214 blueshift = info->var.blue.offset - (8 - info->var.blue.length); 215 216 for ( i = 0; i < logo->clutsize; i++) { 217 palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | 218 safe_shift((clut[1] & greenmask), greenshift) | 219 safe_shift((clut[2] & bluemask), blueshift)); 220 clut += 3; 221 } 222} 223 224static void fb_set_logo_directpalette(struct fb_info *info, 225 const struct linux_logo *logo, 226 u32 *palette) 227{ 228 int redshift, greenshift, blueshift; 229 int i; 230 231 redshift = info->var.red.offset; 232 greenshift = info->var.green.offset; 233 blueshift = info->var.blue.offset; 234 235 for (i = 32; i < logo->clutsize; i++) 236 palette[i] = i << redshift | i << greenshift | i << blueshift; 237} 238 239static void fb_set_logo(struct fb_info *info, 240 const struct linux_logo *logo, u8 *dst, 241 int depth) 242{ 243 int i, j, k; 244 const u8 *src = logo->data; 245 u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; 246 u8 fg = 1, d; 247 248 switch (fb_get_color_depth(&info->var, &info->fix)) { 249 case 1: 250 fg = 1; 251 break; 252 case 2: 253 fg = 3; 254 break; 255 default: 256 fg = 7; 257 break; 258 } 259 260 if (info->fix.visual == FB_VISUAL_MONO01 || 261 info->fix.visual == FB_VISUAL_MONO10) 262 fg = ~((u8) (0xfff << info->var.green.length)); 263 264 switch (depth) { 265 case 4: 266 for (i = 0; i < logo->height; i++) 267 for (j = 0; j < logo->width; src++) { 268 *dst++ = *src >> 4; 269 j++; 270 if (j < logo->width) { 271 *dst++ = *src & 0x0f; 272 j++; 273 } 274 } 275 break; 276 case 1: 277 for (i = 0; i < logo->height; i++) { 278 for (j = 0; j < logo->width; src++) { 279 d = *src ^ xor; 280 for (k = 7; k >= 0; k--) { 281 *dst++ = ((d >> k) & 1) ? fg : 0; 282 j++; 283 } 284 } 285 } 286 break; 287 } 288} 289 290/* 291 * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), 292 * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on 293 * the visual format and color depth of the framebuffer, the DAC, the 294 * pseudo_palette, and the logo data will be adjusted accordingly. 295 * 296 * Case 1 - linux_logo_clut224: 297 * Color exceeds the number of console colors (16), thus we set the hardware DAC 298 * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. 299 * 300 * For visuals that require color info from the pseudo_palette, we also construct 301 * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags 302 * will be set. 303 * 304 * Case 2 - linux_logo_vga16: 305 * The number of colors just matches the console colors, thus there is no need 306 * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, 307 * each byte contains color information for two pixels (upper and lower nibble). 308 * To be consistent with fb_imageblit() usage, we therefore separate the two 309 * nibbles into separate bytes. The "depth" flag will be set to 4. 310 * 311 * Case 3 - linux_logo_mono: 312 * This is similar with Case 2. Each byte contains information for 8 pixels. 313 * We isolate each bit and expand each into a byte. The "depth" flag will 314 * be set to 1. 315 */ 316static struct logo_data { 317 int depth; 318 int needs_directpalette; 319 int needs_truepalette; 320 int needs_cmapreset; 321 const struct linux_logo *logo; 322} fb_logo __read_mostly; 323 324static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) 325{ 326 u32 size = width * height, i; 327 328 out += size - 1; 329 330 for (i = size; i--; ) 331 *out-- = *in++; 332} 333 334static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) 335{ 336 int i, j, h = height - 1; 337 338 for (i = 0; i < height; i++) 339 for (j = 0; j < width; j++) 340 out[height * j + h - i] = *in++; 341} 342 343static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) 344{ 345 int i, j, w = width - 1; 346 347 for (i = 0; i < height; i++) 348 for (j = 0; j < width; j++) 349 out[height * (w - j) + i] = *in++; 350} 351 352static void fb_rotate_logo(struct fb_info *info, u8 *dst, 353 struct fb_image *image, int rotate) 354{ 355 u32 tmp; 356 357 if (rotate == FB_ROTATE_UD) { 358 fb_rotate_logo_ud(image->data, dst, image->width, 359 image->height); 360 image->dx = info->var.xres - image->width - image->dx; 361 image->dy = info->var.yres - image->height - image->dy; 362 } else if (rotate == FB_ROTATE_CW) { 363 fb_rotate_logo_cw(image->data, dst, image->width, 364 image->height); 365 tmp = image->width; 366 image->width = image->height; 367 image->height = tmp; 368 tmp = image->dy; 369 image->dy = image->dx; 370 image->dx = info->var.xres - image->width - tmp; 371 } else if (rotate == FB_ROTATE_CCW) { 372 fb_rotate_logo_ccw(image->data, dst, image->width, 373 image->height); 374 tmp = image->width; 375 image->width = image->height; 376 image->height = tmp; 377 tmp = image->dx; 378 image->dx = image->dy; 379 image->dy = info->var.yres - image->height - tmp; 380 } 381 382 image->data = dst; 383} 384 385static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, 386 int rotate, unsigned int num) 387{ 388 unsigned int x; 389 390 if (rotate == FB_ROTATE_UR) { 391 for (x = 0; 392 x < num && image->dx + image->width <= info->var.xres; 393 x++) { 394 info->fbops->fb_imageblit(info, image); 395 image->dx += image->width + 8; 396 } 397 } else if (rotate == FB_ROTATE_UD) { 398 for (x = 0; x < num && image->dx >= 0; x++) { 399 info->fbops->fb_imageblit(info, image); 400 image->dx -= image->width + 8; 401 } 402 } else if (rotate == FB_ROTATE_CW) { 403 for (x = 0; 404 x < num && image->dy + image->height <= info->var.yres; 405 x++) { 406 info->fbops->fb_imageblit(info, image); 407 image->dy += image->height + 8; 408 } 409 } else if (rotate == FB_ROTATE_CCW) { 410 for (x = 0; x < num && image->dy >= 0; x++) { 411 info->fbops->fb_imageblit(info, image); 412 image->dy -= image->height + 8; 413 } 414 } 415} 416 417static int fb_show_logo_line(struct fb_info *info, int rotate, 418 const struct linux_logo *logo, int y, 419 unsigned int n) 420{ 421 u32 *palette = NULL, *saved_pseudo_palette = NULL; 422 unsigned char *logo_new = NULL, *logo_rotate = NULL; 423 struct fb_image image; 424 425 /* Return if the frame buffer is not mapped or suspended */ 426 if (logo == NULL || info->state != FBINFO_STATE_RUNNING || 427 info->flags & FBINFO_MODULE) 428 return 0; 429 430 image.depth = 8; 431 image.data = logo->data; 432 433 if (fb_logo.needs_cmapreset) 434 fb_set_logocmap(info, logo); 435 436 if (fb_logo.needs_truepalette || 437 fb_logo.needs_directpalette) { 438 palette = kmalloc(256 * 4, GFP_KERNEL); 439 if (palette == NULL) 440 return 0; 441 442 if (fb_logo.needs_truepalette) 443 fb_set_logo_truepalette(info, logo, palette); 444 else 445 fb_set_logo_directpalette(info, logo, palette); 446 447 saved_pseudo_palette = info->pseudo_palette; 448 info->pseudo_palette = palette; 449 } 450 451 if (fb_logo.depth <= 4) { 452 logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL); 453 if (logo_new == NULL) { 454 kfree(palette); 455 if (saved_pseudo_palette) 456 info->pseudo_palette = saved_pseudo_palette; 457 return 0; 458 } 459 image.data = logo_new; 460 fb_set_logo(info, logo, logo_new, fb_logo.depth); 461 } 462 463 image.dx = 0; 464 image.dy = y; 465 image.width = logo->width; 466 image.height = logo->height; 467 468 if (rotate) { 469 logo_rotate = kmalloc(logo->width * 470 logo->height, GFP_KERNEL); 471 if (logo_rotate) 472 fb_rotate_logo(info, logo_rotate, &image, rotate); 473 } 474 475 fb_do_show_logo(info, &image, rotate, n); 476 477 kfree(palette); 478 if (saved_pseudo_palette != NULL) 479 info->pseudo_palette = saved_pseudo_palette; 480 kfree(logo_new); 481 kfree(logo_rotate); 482 return logo->height; 483} 484 485 486#ifdef CONFIG_FB_LOGO_EXTRA 487 488#define FB_LOGO_EX_NUM_MAX 10 489static struct logo_data_extra { 490 const struct linux_logo *logo; 491 unsigned int n; 492} fb_logo_ex[FB_LOGO_EX_NUM_MAX]; 493static unsigned int fb_logo_ex_num; 494 495void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) 496{ 497 if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) 498 return; 499 500 fb_logo_ex[fb_logo_ex_num].logo = logo; 501 fb_logo_ex[fb_logo_ex_num].n = n; 502 fb_logo_ex_num++; 503} 504 505static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, 506 unsigned int yres) 507{ 508 unsigned int i; 509 510 /* FIXME: logo_ex supports only truecolor fb. */ 511 if (info->fix.visual != FB_VISUAL_TRUECOLOR) 512 fb_logo_ex_num = 0; 513 514 for (i = 0; i < fb_logo_ex_num; i++) { 515 height += fb_logo_ex[i].logo->height; 516 if (height > yres) { 517 height -= fb_logo_ex[i].logo->height; 518 fb_logo_ex_num = i; 519 break; 520 } 521 } 522 return height; 523} 524 525static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 526{ 527 unsigned int i; 528 529 for (i = 0; i < fb_logo_ex_num; i++) 530 y += fb_show_logo_line(info, rotate, 531 fb_logo_ex[i].logo, y, fb_logo_ex[i].n); 532 533 return y; 534} 535 536#else /* !CONFIG_FB_LOGO_EXTRA */ 537 538static inline int fb_prepare_extra_logos(struct fb_info *info, 539 unsigned int height, 540 unsigned int yres) 541{ 542 return height; 543} 544 545static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 546{ 547 return y; 548} 549 550#endif /* CONFIG_FB_LOGO_EXTRA */ 551 552 553int fb_prepare_logo(struct fb_info *info, int rotate) 554{ 555 int depth = fb_get_color_depth(&info->var, &info->fix); 556 unsigned int yres; 557 558 memset(&fb_logo, 0, sizeof(struct logo_data)); 559 560 if (info->flags & FBINFO_MISC_TILEBLITTING || 561 info->flags & FBINFO_MODULE) 562 return 0; 563 564 if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 565 depth = info->var.blue.length; 566 if (info->var.red.length < depth) 567 depth = info->var.red.length; 568 if (info->var.green.length < depth) 569 depth = info->var.green.length; 570 } 571 572 if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { 573 /* assume console colormap */ 574 depth = 4; 575 } 576 577 /* Return if no suitable logo was found */ 578 fb_logo.logo = fb_find_logo(depth); 579 580 if (!fb_logo.logo) { 581 return 0; 582 } 583 584 if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) 585 yres = info->var.yres; 586 else 587 yres = info->var.xres; 588 589 if (fb_logo.logo->height > yres) { 590 fb_logo.logo = NULL; 591 return 0; 592 } 593 594 /* What depth we asked for might be different from what we get */ 595 if (fb_logo.logo->type == LINUX_LOGO_CLUT224) 596 fb_logo.depth = 8; 597 else if (fb_logo.logo->type == LINUX_LOGO_VGA16) 598 fb_logo.depth = 4; 599 else 600 fb_logo.depth = 1; 601 602 603 if (fb_logo.depth > 4 && depth > 4) { 604 switch (info->fix.visual) { 605 case FB_VISUAL_TRUECOLOR: 606 fb_logo.needs_truepalette = 1; 607 break; 608 case FB_VISUAL_DIRECTCOLOR: 609 fb_logo.needs_directpalette = 1; 610 fb_logo.needs_cmapreset = 1; 611 break; 612 case FB_VISUAL_PSEUDOCOLOR: 613 fb_logo.needs_cmapreset = 1; 614 break; 615 } 616 } 617 618 return fb_prepare_extra_logos(info, fb_logo.logo->height, yres); 619} 620 621int fb_show_logo(struct fb_info *info, int rotate) 622{ 623 int y; 624 625 y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, 626 num_online_cpus()); 627 y = fb_show_extra_logos(info, y, rotate); 628 629 return y; 630} 631#else 632int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } 633int fb_show_logo(struct fb_info *info, int rotate) { return 0; } 634#endif /* CONFIG_LOGO */ 635 636static void *fb_seq_start(struct seq_file *m, loff_t *pos) 637{ 638 return (*pos < FB_MAX) ? pos : NULL; 639} 640 641static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) 642{ 643 (*pos)++; 644 return (*pos < FB_MAX) ? pos : NULL; 645} 646 647static void fb_seq_stop(struct seq_file *m, void *v) 648{ 649} 650 651static int fb_seq_show(struct seq_file *m, void *v) 652{ 653 int i = *(loff_t *)v; 654 struct fb_info *fi = registered_fb[i]; 655 656 if (fi) 657 seq_printf(m, "%d %s\n", fi->node, fi->fix.id); 658 return 0; 659} 660 661static const struct seq_operations proc_fb_seq_ops = { 662 .start = fb_seq_start, 663 .next = fb_seq_next, 664 .stop = fb_seq_stop, 665 .show = fb_seq_show, 666}; 667 668static int proc_fb_open(struct inode *inode, struct file *file) 669{ 670 return seq_open(file, &proc_fb_seq_ops); 671} 672 673static const struct file_operations fb_proc_fops = { 674 .owner = THIS_MODULE, 675 .open = proc_fb_open, 676 .read = seq_read, 677 .llseek = seq_lseek, 678 .release = seq_release, 679}; 680 681static ssize_t 682fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 683{ 684 unsigned long p = *ppos; 685 struct inode *inode = file->f_path.dentry->d_inode; 686 int fbidx = iminor(inode); 687 struct fb_info *info = registered_fb[fbidx]; 688 u32 *buffer, *dst; 689 u32 __iomem *src; 690 int c, i, cnt = 0, err = 0; 691 unsigned long total_size; 692 693 if (!info || ! info->screen_base) 694 return -ENODEV; 695 696 if (info->state != FBINFO_STATE_RUNNING) 697 return -EPERM; 698 699 if (info->fbops->fb_read) 700 return info->fbops->fb_read(info, buf, count, ppos); 701 702 total_size = info->screen_size; 703 704 if (total_size == 0) 705 total_size = info->fix.smem_len; 706 707 if (p >= total_size) 708 return 0; 709 710 if (count >= total_size) 711 count = total_size; 712 713 if (count + p > total_size) 714 count = total_size - p; 715 716 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, 717 GFP_KERNEL); 718 if (!buffer) 719 return -ENOMEM; 720 721 src = (u32 __iomem *) (info->screen_base + p); 722 723 if (info->fbops->fb_sync) 724 info->fbops->fb_sync(info); 725 726 while (count) { 727 c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 728 dst = buffer; 729 for (i = c >> 2; i--; ) 730 *dst++ = fb_readl(src++); 731 if (c & 3) { 732 u8 *dst8 = (u8 *) dst; 733 u8 __iomem *src8 = (u8 __iomem *) src; 734 735 for (i = c & 3; i--;) 736 *dst8++ = fb_readb(src8++); 737 738 src = (u32 __iomem *) src8; 739 } 740 741 if (copy_to_user(buf, buffer, c)) { 742 err = -EFAULT; 743 break; 744 } 745 *ppos += c; 746 buf += c; 747 cnt += c; 748 count -= c; 749 } 750 751 kfree(buffer); 752 753 return (err) ? err : cnt; 754} 755 756static ssize_t 757fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) 758{ 759 unsigned long p = *ppos; 760 struct inode *inode = file->f_path.dentry->d_inode; 761 int fbidx = iminor(inode); 762 struct fb_info *info = registered_fb[fbidx]; 763 u32 *buffer, *src; 764 u32 __iomem *dst; 765 int c, i, cnt = 0, err = 0; 766 unsigned long total_size; 767 768 if (!info || !info->screen_base) 769 return -ENODEV; 770 771 if (info->state != FBINFO_STATE_RUNNING) 772 return -EPERM; 773 774 if (info->fbops->fb_write) 775 return info->fbops->fb_write(info, buf, count, ppos); 776 777 total_size = info->screen_size; 778 779 if (total_size == 0) 780 total_size = info->fix.smem_len; 781 782 if (p > total_size) 783 return -EFBIG; 784 785 if (count > total_size) { 786 err = -EFBIG; 787 count = total_size; 788 } 789 790 if (count + p > total_size) { 791 if (!err) 792 err = -ENOSPC; 793 794 count = total_size - p; 795 } 796 797 buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, 798 GFP_KERNEL); 799 if (!buffer) 800 return -ENOMEM; 801 802 dst = (u32 __iomem *) (info->screen_base + p); 803 804 if (info->fbops->fb_sync) 805 info->fbops->fb_sync(info); 806 807 while (count) { 808 c = (count > PAGE_SIZE) ? PAGE_SIZE : count; 809 src = buffer; 810 811 if (copy_from_user(src, buf, c)) { 812 err = -EFAULT; 813 break; 814 } 815 816 for (i = c >> 2; i--; ) 817 fb_writel(*src++, dst++); 818 819 if (c & 3) { 820 u8 *src8 = (u8 *) src; 821 u8 __iomem *dst8 = (u8 __iomem *) dst; 822 823 for (i = c & 3; i--; ) 824 fb_writeb(*src8++, dst8++); 825 826 dst = (u32 __iomem *) dst8; 827 } 828 829 *ppos += c; 830 buf += c; 831 cnt += c; 832 count -= c; 833 } 834 835 kfree(buffer); 836 837 return (cnt) ? cnt : err; 838} 839 840#ifdef CONFIG_KMOD 841static void try_to_load(int fb) 842{ 843 request_module("fb%d", fb); 844} 845#endif /* CONFIG_KMOD */ 846 847int 848fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) 849{ 850 struct fb_fix_screeninfo *fix = &info->fix; 851 int xoffset = var->xoffset; 852 int yoffset = var->yoffset; 853 int err = 0, yres = info->var.yres; 854 855 if (var->yoffset > 0) { 856 if (var->vmode & FB_VMODE_YWRAP) { 857 if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep)) 858 err = -EINVAL; 859 else 860 yres = 0; 861 } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep)) 862 err = -EINVAL; 863 } 864 865 if (var->xoffset > 0 && (!fix->xpanstep || 866 (var->xoffset % fix->xpanstep))) 867 err = -EINVAL; 868 869 if (err || !info->fbops->fb_pan_display || xoffset < 0 || 870 yoffset < 0 || var->yoffset + yres > info->var.yres_virtual || 871 var->xoffset + info->var.xres > info->var.xres_virtual) 872 return -EINVAL; 873 874 if ((err = info->fbops->fb_pan_display(var, info))) 875 return err; 876 info->var.xoffset = var->xoffset; 877 info->var.yoffset = var->yoffset; 878 if (var->vmode & FB_VMODE_YWRAP) 879 info->var.vmode |= FB_VMODE_YWRAP; 880 else 881 info->var.vmode &= ~FB_VMODE_YWRAP; 882 return 0; 883} 884 885static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, 886 u32 activate) 887{ 888 struct fb_event event; 889 struct fb_blit_caps caps, fbcaps; 890 int err = 0; 891 892 memset(&caps, 0, sizeof(caps)); 893 memset(&fbcaps, 0, sizeof(fbcaps)); 894 caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; 895 event.info = info; 896 event.data = &caps; 897 fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); 898 info->fbops->fb_get_caps(info, &fbcaps, var); 899 900 if (((fbcaps.x ^ caps.x) & caps.x) || 901 ((fbcaps.y ^ caps.y) & caps.y) || 902 (fbcaps.len < caps.len)) 903 err = -EINVAL; 904 905 return err; 906} 907 908int 909fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) 910{ 911 int flags = info->flags; 912 int ret = 0; 913 914 if (var->activate & FB_ACTIVATE_INV_MODE) { 915 struct fb_videomode mode1, mode2; 916 917 fb_var_to_videomode(&mode1, var); 918 fb_var_to_videomode(&mode2, &info->var); 919 /* make sure we don't delete the videomode of current var */ 920 ret = fb_mode_is_equal(&mode1, &mode2); 921 922 if (!ret) { 923 struct fb_event event; 924 925 event.info = info; 926 event.data = &mode1; 927 ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event); 928 } 929 930 if (!ret) 931 fb_delete_videomode(&mode1, &info->modelist); 932 933 934 ret = (ret) ? -EINVAL : 0; 935 goto done; 936 } 937 938 if ((var->activate & FB_ACTIVATE_FORCE) || 939 memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { 940 u32 activate = var->activate; 941 942 if (!info->fbops->fb_check_var) { 943 *var = info->var; 944 goto done; 945 } 946 947 ret = info->fbops->fb_check_var(var, info); 948 949 if (ret) 950 goto done; 951 952 if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { 953 struct fb_videomode mode; 954 955 if (info->fbops->fb_get_caps) { 956 ret = fb_check_caps(info, var, activate); 957 958 if (ret) 959 goto done; 960 } 961 962 info->var = *var; 963 964 if (info->fbops->fb_set_par) 965 info->fbops->fb_set_par(info); 966 967 fb_pan_display(info, &info->var); 968 fb_set_cmap(&info->cmap, info); 969 fb_var_to_videomode(&mode, &info->var); 970 971 if (info->modelist.prev && info->modelist.next && 972 !list_empty(&info->modelist)) 973 ret = fb_add_videomode(&mode, &info->modelist); 974 975 if (!ret && (flags & FBINFO_MISC_USEREVENT)) { 976 struct fb_event event; 977 int evnt = (activate & FB_ACTIVATE_ALL) ? 978 FB_EVENT_MODE_CHANGE_ALL : 979 FB_EVENT_MODE_CHANGE; 980 981 info->flags &= ~FBINFO_MISC_USEREVENT; 982 event.info = info; 983 fb_notifier_call_chain(evnt, &event); 984 } 985 } 986 } 987 988 done: 989 return ret; 990} 991 992int 993fb_blank(struct fb_info *info, int blank) 994{ 995 int ret = -EINVAL; 996 997 if (blank > FB_BLANK_POWERDOWN) 998 blank = FB_BLANK_POWERDOWN; 999 1000 if (info->fbops->fb_blank) 1001 ret = info->fbops->fb_blank(blank, info); 1002 1003 if (!ret) { 1004 struct fb_event event; 1005 1006 event.info = info; 1007 event.data = &blank; 1008 fb_notifier_call_chain(FB_EVENT_BLANK, &event); 1009 } 1010 1011 return ret; 1012} 1013 1014static int 1015fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 1016 unsigned long arg) 1017{ 1018 int fbidx = iminor(inode); 1019 struct fb_info *info = registered_fb[fbidx]; 1020 struct fb_ops *fb = info->fbops; 1021 struct fb_var_screeninfo var; 1022 struct fb_fix_screeninfo fix; 1023 struct fb_con2fbmap con2fb; 1024 struct fb_cmap_user cmap; 1025 struct fb_event event; 1026 void __user *argp = (void __user *)arg; 1027 int i; 1028 1029 if (!fb) 1030 return -ENODEV; 1031 switch (cmd) { 1032 case FBIOGET_VSCREENINFO: 1033 return copy_to_user(argp, &info->var, 1034 sizeof(var)) ? -EFAULT : 0; 1035 case FBIOPUT_VSCREENINFO: 1036 if (copy_from_user(&var, argp, sizeof(var))) 1037 return -EFAULT; 1038 acquire_console_sem(); 1039 info->flags |= FBINFO_MISC_USEREVENT; 1040 i = fb_set_var(info, &var); 1041 info->flags &= ~FBINFO_MISC_USEREVENT; 1042 release_console_sem(); 1043 if (i) return i; 1044 if (copy_to_user(argp, &var, sizeof(var))) 1045 return -EFAULT; 1046 return 0; 1047 case FBIOGET_FSCREENINFO: 1048 return copy_to_user(argp, &info->fix, 1049 sizeof(fix)) ? -EFAULT : 0; 1050 case FBIOPUTCMAP: 1051 if (copy_from_user(&cmap, argp, sizeof(cmap))) 1052 return -EFAULT; 1053 return (fb_set_user_cmap(&cmap, info)); 1054 case FBIOGETCMAP: 1055 if (copy_from_user(&cmap, argp, sizeof(cmap))) 1056 return -EFAULT; 1057 return fb_cmap_to_user(&info->cmap, &cmap); 1058 case FBIOPAN_DISPLAY: 1059 if (copy_from_user(&var, argp, sizeof(var))) 1060 return -EFAULT; 1061 acquire_console_sem(); 1062 i = fb_pan_display(info, &var); 1063 release_console_sem(); 1064 if (i) 1065 return i; 1066 if (copy_to_user(argp, &var, sizeof(var))) 1067 return -EFAULT; 1068 return 0; 1069 case FBIO_CURSOR: 1070 return -EINVAL; 1071 case FBIOGET_CON2FBMAP: 1072 if (copy_from_user(&con2fb, argp, sizeof(con2fb))) 1073 return -EFAULT; 1074 if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) 1075 return -EINVAL; 1076 con2fb.framebuffer = -1; 1077 event.info = info; 1078 event.data = &con2fb; 1079 fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); 1080 return copy_to_user(argp, &con2fb, 1081 sizeof(con2fb)) ? -EFAULT : 0; 1082 case FBIOPUT_CON2FBMAP: 1083 if (copy_from_user(&con2fb, argp, sizeof(con2fb))) 1084 return - EFAULT; 1085 if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) 1086 return -EINVAL; 1087 if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) 1088 return -EINVAL; 1089#ifdef CONFIG_KMOD 1090 if (!registered_fb[con2fb.framebuffer]) 1091 try_to_load(con2fb.framebuffer); 1092#endif /* CONFIG_KMOD */ 1093 if (!registered_fb[con2fb.framebuffer]) 1094 return -EINVAL; 1095 event.info = info; 1096 event.data = &con2fb; 1097 return fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, 1098 &event); 1099 case FBIOBLANK: 1100 acquire_console_sem(); 1101 info->flags |= FBINFO_MISC_USEREVENT; 1102 i = fb_blank(info, arg); 1103 info->flags &= ~FBINFO_MISC_USEREVENT; 1104 release_console_sem(); 1105 return i; 1106 default: 1107 if (fb->fb_ioctl == NULL) 1108 return -EINVAL; 1109 return fb->fb_ioctl(info, cmd, arg); 1110 } 1111} 1112 1113#ifdef CONFIG_COMPAT 1114struct fb_fix_screeninfo32 { 1115 char id[16]; 1116 compat_caddr_t smem_start; 1117 u32 smem_len; 1118 u32 type; 1119 u32 type_aux; 1120 u32 visual; 1121 u16 xpanstep; 1122 u16 ypanstep; 1123 u16 ywrapstep; 1124 u32 line_length; 1125 compat_caddr_t mmio_start; 1126 u32 mmio_len; 1127 u32 accel; 1128 u16 reserved[3]; 1129}; 1130 1131struct fb_cmap32 { 1132 u32 start; 1133 u32 len; 1134 compat_caddr_t red; 1135 compat_caddr_t green; 1136 compat_caddr_t blue; 1137 compat_caddr_t transp; 1138}; 1139 1140static int fb_getput_cmap(struct inode *inode, struct file *file, 1141 unsigned int cmd, unsigned long arg) 1142{ 1143 struct fb_cmap_user __user *cmap; 1144 struct fb_cmap32 __user *cmap32; 1145 __u32 data; 1146 int err; 1147 1148 cmap = compat_alloc_user_space(sizeof(*cmap)); 1149 cmap32 = compat_ptr(arg); 1150 1151 if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32))) 1152 return -EFAULT; 1153 1154 if (get_user(data, &cmap32->red) || 1155 put_user(compat_ptr(data), &cmap->red) || 1156 get_user(data, &cmap32->green) || 1157 put_user(compat_ptr(data), &cmap->green) || 1158 get_user(data, &cmap32->blue) || 1159 put_user(compat_ptr(data), &cmap->blue) || 1160 get_user(data, &cmap32->transp) || 1161 put_user(compat_ptr(data), &cmap->transp)) 1162 return -EFAULT; 1163 1164 err = fb_ioctl(inode, file, cmd, (unsigned long) cmap); 1165 1166 if (!err) { 1167 if (copy_in_user(&cmap32->start, 1168 &cmap->start, 1169 2 * sizeof(__u32))) 1170 err = -EFAULT; 1171 } 1172 return err; 1173} 1174 1175static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, 1176 struct fb_fix_screeninfo32 __user *fix32) 1177{ 1178 __u32 data; 1179 int err; 1180 1181 err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); 1182 1183 data = (__u32) (unsigned long) fix->smem_start; 1184 err |= put_user(data, &fix32->smem_start); 1185 1186 err |= put_user(fix->smem_len, &fix32->smem_len); 1187 err |= put_user(fix->type, &fix32->type); 1188 err |= put_user(fix->type_aux, &fix32->type_aux); 1189 err |= put_user(fix->visual, &fix32->visual); 1190 err |= put_user(fix->xpanstep, &fix32->xpanstep); 1191 err |= put_user(fix->ypanstep, &fix32->ypanstep); 1192 err |= put_user(fix->ywrapstep, &fix32->ywrapstep); 1193 err |= put_user(fix->line_length, &fix32->line_length); 1194 1195 data = (__u32) (unsigned long) fix->mmio_start; 1196 err |= put_user(data, &fix32->mmio_start); 1197 1198 err |= put_user(fix->mmio_len, &fix32->mmio_len); 1199 err |= put_user(fix->accel, &fix32->accel); 1200 err |= copy_to_user(fix32->reserved, fix->reserved, 1201 sizeof(fix->reserved)); 1202 1203 return err; 1204} 1205 1206static int fb_get_fscreeninfo(struct inode *inode, struct file *file, 1207 unsigned int cmd, unsigned long arg) 1208{ 1209 mm_segment_t old_fs; 1210 struct fb_fix_screeninfo fix; 1211 struct fb_fix_screeninfo32 __user *fix32; 1212 int err; 1213 1214 fix32 = compat_ptr(arg); 1215 1216 old_fs = get_fs(); 1217 set_fs(KERNEL_DS); 1218 err = fb_ioctl(inode, file, cmd, (unsigned long) &fix); 1219 set_fs(old_fs); 1220 1221 if (!err) 1222 err = do_fscreeninfo_to_user(&fix, fix32); 1223 1224 return err; 1225} 1226 1227static long 1228fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1229{ 1230 struct inode *inode = file->f_path.dentry->d_inode; 1231 int fbidx = iminor(inode); 1232 struct fb_info *info = registered_fb[fbidx]; 1233 struct fb_ops *fb = info->fbops; 1234 long ret = -ENOIOCTLCMD; 1235 1236 lock_kernel(); 1237 switch(cmd) { 1238 case FBIOGET_VSCREENINFO: 1239 case FBIOPUT_VSCREENINFO: 1240 case FBIOPAN_DISPLAY: 1241 case FBIOGET_CON2FBMAP: 1242 case FBIOPUT_CON2FBMAP: 1243 arg = (unsigned long) compat_ptr(arg); 1244 case FBIOBLANK: 1245 ret = fb_ioctl(inode, file, cmd, arg); 1246 break; 1247 1248 case FBIOGET_FSCREENINFO: 1249 ret = fb_get_fscreeninfo(inode, file, cmd, arg); 1250 break; 1251 1252 case FBIOGETCMAP: 1253 case FBIOPUTCMAP: 1254 ret = fb_getput_cmap(inode, file, cmd, arg); 1255 break; 1256 1257 default: 1258 if (fb->fb_compat_ioctl) 1259 ret = fb->fb_compat_ioctl(info, cmd, arg); 1260 break; 1261 } 1262 unlock_kernel(); 1263 return ret; 1264} 1265#endif 1266 1267static int 1268fb_mmap(struct file *file, struct vm_area_struct * vma) 1269{ 1270 int fbidx = iminor(file->f_path.dentry->d_inode); 1271 struct fb_info *info = registered_fb[fbidx]; 1272 struct fb_ops *fb = info->fbops; 1273 unsigned long off; 1274 unsigned long start; 1275 u32 len; 1276 1277 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) 1278 return -EINVAL; 1279 off = vma->vm_pgoff << PAGE_SHIFT; 1280 if (!fb) 1281 return -ENODEV; 1282 if (fb->fb_mmap) { 1283 int res; 1284 lock_kernel(); 1285 res = fb->fb_mmap(info, vma); 1286 unlock_kernel(); 1287 return res; 1288 } 1289 1290 lock_kernel(); 1291 1292 /* frame buffer memory */ 1293 start = info->fix.smem_start; 1294 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len); 1295 if (off >= len) { 1296 /* memory mapped io */ 1297 off -= len; 1298 if (info->var.accel_flags) { 1299 unlock_kernel(); 1300 return -EINVAL; 1301 } 1302 start = info->fix.mmio_start; 1303 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len); 1304 } 1305 unlock_kernel(); 1306 start &= PAGE_MASK; 1307 if ((vma->vm_end - vma->vm_start + off) > len) 1308 return -EINVAL; 1309 off += start; 1310 vma->vm_pgoff = off >> PAGE_SHIFT; 1311 /* This is an IO map - tell maydump to skip this VMA */ 1312 vma->vm_flags |= VM_IO | VM_RESERVED; 1313 fb_pgprotect(file, vma, off); 1314 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, 1315 vma->vm_end - vma->vm_start, vma->vm_page_prot)) 1316 return -EAGAIN; 1317 return 0; 1318} 1319 1320static int 1321fb_open(struct inode *inode, struct file *file) 1322{ 1323 int fbidx = iminor(inode); 1324 struct fb_info *info; 1325 int res = 0; 1326 1327 if (fbidx >= FB_MAX) 1328 return -ENODEV; 1329#ifdef CONFIG_KMOD 1330 if (!(info = registered_fb[fbidx])) 1331 try_to_load(fbidx); 1332#endif /* CONFIG_KMOD */ 1333 if (!(info = registered_fb[fbidx])) 1334 return -ENODEV; 1335 if (!try_module_get(info->fbops->owner)) 1336 return -ENODEV; 1337 file->private_data = info; 1338 if (info->fbops->fb_open) { 1339 res = info->fbops->fb_open(info,1); 1340 if (res) 1341 module_put(info->fbops->owner); 1342 } 1343 return res; 1344} 1345 1346static int 1347fb_release(struct inode *inode, struct file *file) 1348{ 1349 struct fb_info * const info = file->private_data; 1350 1351 lock_kernel(); 1352 if (info->fbops->fb_release) 1353 info->fbops->fb_release(info,1); 1354 module_put(info->fbops->owner); 1355 unlock_kernel(); 1356 return 0; 1357} 1358 1359static const struct file_operations fb_fops = { 1360 .owner = THIS_MODULE, 1361 .read = fb_read, 1362 .write = fb_write, 1363 .ioctl = fb_ioctl, 1364#ifdef CONFIG_COMPAT 1365 .compat_ioctl = fb_compat_ioctl, 1366#endif 1367 .mmap = fb_mmap, 1368 .open = fb_open, 1369 .release = fb_release, 1370#ifdef HAVE_ARCH_FB_UNMAPPED_AREA 1371 .get_unmapped_area = get_fb_unmapped_area, 1372#endif 1373#ifdef CONFIG_FB_DEFERRED_IO 1374 .fsync = fb_deferred_io_fsync, 1375#endif 1376}; 1377 1378struct class *fb_class; 1379EXPORT_SYMBOL(fb_class); 1380 1381static int fb_check_foreignness(struct fb_info *fi) 1382{ 1383 const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; 1384 1385 fi->flags &= ~FBINFO_FOREIGN_ENDIAN; 1386 1387#ifdef __BIG_ENDIAN 1388 fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH; 1389#else 1390 fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0; 1391#endif /* __BIG_ENDIAN */ 1392 1393 if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) { 1394 pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to " 1395 "support this framebuffer\n", fi->fix.id); 1396 return -ENOSYS; 1397 } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) { 1398 pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to " 1399 "support this framebuffer\n", fi->fix.id); 1400 return -ENOSYS; 1401 } 1402 1403 return 0; 1404} 1405 1406/** 1407 * register_framebuffer - registers a frame buffer device 1408 * @fb_info: frame buffer info structure 1409 * 1410 * Registers a frame buffer device @fb_info. 1411 * 1412 * Returns negative errno on error, or zero for success. 1413 * 1414 */ 1415 1416int 1417register_framebuffer(struct fb_info *fb_info) 1418{ 1419 int i; 1420 struct fb_event event; 1421 struct fb_videomode mode; 1422 1423 if (num_registered_fb == FB_MAX) 1424 return -ENXIO; 1425 1426 if (fb_check_foreignness(fb_info)) 1427 return -ENOSYS; 1428 1429 num_registered_fb++; 1430 for (i = 0 ; i < FB_MAX; i++) 1431 if (!registered_fb[i]) 1432 break; 1433 fb_info->node = i; 1434 1435 fb_info->dev = device_create(fb_class, fb_info->device, 1436 MKDEV(FB_MAJOR, i), "fb%d", i); 1437 if (IS_ERR(fb_info->dev)) { 1438 /* Not fatal */ 1439 printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); 1440 fb_info->dev = NULL; 1441 } else 1442 fb_init_device(fb_info); 1443 1444 if (fb_info->pixmap.addr == NULL) { 1445 fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); 1446 if (fb_info->pixmap.addr) { 1447 fb_info->pixmap.size = FBPIXMAPSIZE; 1448 fb_info->pixmap.buf_align = 1; 1449 fb_info->pixmap.scan_align = 1; 1450 fb_info->pixmap.access_align = 32; 1451 fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; 1452 } 1453 } 1454 fb_info->pixmap.offset = 0; 1455 1456 if (!fb_info->pixmap.blit_x) 1457 fb_info->pixmap.blit_x = ~(u32)0; 1458 1459 if (!fb_info->pixmap.blit_y) 1460 fb_info->pixmap.blit_y = ~(u32)0; 1461 1462 if (!fb_info->modelist.prev || !fb_info->modelist.next) 1463 INIT_LIST_HEAD(&fb_info->modelist); 1464 1465 fb_var_to_videomode(&mode, &fb_info->var); 1466 fb_add_videomode(&mode, &fb_info->modelist); 1467 registered_fb[i] = fb_info; 1468 1469 event.info = fb_info; 1470 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); 1471 return 0; 1472} 1473 1474 1475/** 1476 * unregister_framebuffer - releases a frame buffer device 1477 * @fb_info: frame buffer info structure 1478 * 1479 * Unregisters a frame buffer device @fb_info. 1480 * 1481 * Returns negative errno on error, or zero for success. 1482 * 1483 * This function will also notify the framebuffer console 1484 * to release the driver. 1485 * 1486 * This is meant to be called within a driver's module_exit() 1487 * function. If this is called outside module_exit(), ensure 1488 * that the driver implements fb_open() and fb_release() to 1489 * check that no processes are using the device. 1490 */ 1491 1492int 1493unregister_framebuffer(struct fb_info *fb_info) 1494{ 1495 struct fb_event event; 1496 int i, ret = 0; 1497 1498 i = fb_info->node; 1499 if (!registered_fb[i]) { 1500 ret = -EINVAL; 1501 goto done; 1502 } 1503 1504 event.info = fb_info; 1505 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); 1506 1507 if (ret) { 1508 ret = -EINVAL; 1509 goto done; 1510 } 1511 1512 if (fb_info->pixmap.addr && 1513 (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) 1514 kfree(fb_info->pixmap.addr); 1515 fb_destroy_modelist(&fb_info->modelist); 1516 registered_fb[i]=NULL; 1517 num_registered_fb--; 1518 fb_cleanup_device(fb_info); 1519 device_destroy(fb_class, MKDEV(FB_MAJOR, i)); 1520 event.info = fb_info; 1521 fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); 1522done: 1523 return ret; 1524} 1525 1526/** 1527 * fb_set_suspend - low level driver signals suspend 1528 * @info: framebuffer affected 1529 * @state: 0 = resuming, !=0 = suspending 1530 * 1531 * This is meant to be used by low level drivers to 1532 * signal suspend/resume to the core & clients. 1533 * It must be called with the console semaphore held 1534 */ 1535void fb_set_suspend(struct fb_info *info, int state) 1536{ 1537 struct fb_event event; 1538 1539 event.info = info; 1540 if (state) { 1541 fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); 1542 info->state = FBINFO_STATE_SUSPENDED; 1543 } else { 1544 info->state = FBINFO_STATE_RUNNING; 1545 fb_notifier_call_chain(FB_EVENT_RESUME, &event); 1546 } 1547} 1548 1549/** 1550 * fbmem_init - init frame buffer subsystem 1551 * 1552 * Initialize the frame buffer subsystem. 1553 * 1554 * NOTE: This function is _only_ to be called by drivers/char/mem.c. 1555 * 1556 */ 1557 1558static int __init 1559fbmem_init(void) 1560{ 1561 proc_create("fb", 0, NULL, &fb_proc_fops); 1562 1563 if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) 1564 printk("unable to get major %d for fb devs\n", FB_MAJOR); 1565 1566 fb_class = class_create(THIS_MODULE, "graphics"); 1567 if (IS_ERR(fb_class)) { 1568 printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); 1569 fb_class = NULL; 1570 } 1571 return 0; 1572} 1573 1574#ifdef MODULE 1575module_init(fbmem_init); 1576static void __exit 1577fbmem_exit(void) 1578{ 1579 remove_proc_entry("fb", NULL); 1580 class_destroy(fb_class); 1581 unregister_chrdev(FB_MAJOR, "fb"); 1582} 1583 1584module_exit(fbmem_exit); 1585MODULE_LICENSE("GPL"); 1586MODULE_DESCRIPTION("Framebuffer base"); 1587#else 1588subsys_initcall(fbmem_init); 1589#endif 1590 1591int fb_new_modelist(struct fb_info *info) 1592{ 1593 struct fb_event event; 1594 struct fb_var_screeninfo var = info->var; 1595 struct list_head *pos, *n; 1596 struct fb_modelist *modelist; 1597 struct fb_videomode *m, mode; 1598 int err = 1; 1599 1600 list_for_each_safe(pos, n, &info->modelist) { 1601 modelist = list_entry(pos, struct fb_modelist, list); 1602 m = &modelist->mode; 1603 fb_videomode_to_var(&var, m); 1604 var.activate = FB_ACTIVATE_TEST; 1605 err = fb_set_var(info, &var); 1606 fb_var_to_videomode(&mode, &var); 1607 if (err || !fb_mode_is_equal(m, &mode)) { 1608 list_del(pos); 1609 kfree(pos); 1610 } 1611 } 1612 1613 err = 1; 1614 1615 if (!list_empty(&info->modelist)) { 1616 event.info = info; 1617 err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); 1618 } 1619 1620 return err; 1621} 1622 1623static char *video_options[FB_MAX] __read_mostly; 1624static int ofonly __read_mostly; 1625 1626/** 1627 * fb_get_options - get kernel boot parameters 1628 * @name: framebuffer name as it would appear in 1629 * the boot parameter line 1630 * (video=<name>:<options>) 1631 * @option: the option will be stored here 1632 * 1633 * NOTE: Needed to maintain backwards compatibility 1634 */ 1635int fb_get_options(char *name, char **option) 1636{ 1637 char *opt, *options = NULL; 1638 int opt_len, retval = 0; 1639 int name_len = strlen(name), i; 1640 1641 if (name_len && ofonly && strncmp(name, "offb", 4)) 1642 retval = 1; 1643 1644 if (name_len && !retval) { 1645 for (i = 0; i < FB_MAX; i++) { 1646 if (video_options[i] == NULL) 1647 continue; 1648 opt_len = strlen(video_options[i]); 1649 if (!opt_len) 1650 continue; 1651 opt = video_options[i]; 1652 if (!strncmp(name, opt, name_len) && 1653 opt[name_len] == ':') 1654 options = opt + name_len + 1; 1655 } 1656 } 1657 if (options && !strncmp(options, "off", 3)) 1658 retval = 1; 1659 1660 if (option) 1661 *option = options; 1662 1663 return retval; 1664} 1665 1666#ifndef MODULE 1667/** 1668 * video_setup - process command line options 1669 * @options: string of options 1670 * 1671 * Process command line options for frame buffer subsystem. 1672 * 1673 * NOTE: This function is a __setup and __init function. 1674 * It only stores the options. Drivers have to call 1675 * fb_get_options() as necessary. 1676 * 1677 * Returns zero. 1678 * 1679 */ 1680static int __init video_setup(char *options) 1681{ 1682 int i, global = 0; 1683 1684 if (!options || !*options) 1685 global = 1; 1686 1687 if (!global && !strncmp(options, "ofonly", 6)) { 1688 ofonly = 1; 1689 global = 1; 1690 } 1691 1692 if (!global && !strstr(options, "fb:")) { 1693 fb_mode_option = options; 1694 global = 1; 1695 } 1696 1697 if (!global) { 1698 for (i = 0; i < FB_MAX; i++) { 1699 if (video_options[i] == NULL) { 1700 video_options[i] = options; 1701 break; 1702 } 1703 1704 } 1705 } 1706 1707 return 1; 1708} 1709__setup("video=", video_setup); 1710#endif 1711 1712 /* 1713 * Visible symbols for modules 1714 */ 1715 1716EXPORT_SYMBOL(register_framebuffer); 1717EXPORT_SYMBOL(unregister_framebuffer); 1718EXPORT_SYMBOL(num_registered_fb); 1719EXPORT_SYMBOL(registered_fb); 1720EXPORT_SYMBOL(fb_show_logo); 1721EXPORT_SYMBOL(fb_set_var); 1722EXPORT_SYMBOL(fb_blank); 1723EXPORT_SYMBOL(fb_pan_display); 1724EXPORT_SYMBOL(fb_get_buffer_offset); 1725EXPORT_SYMBOL(fb_set_suspend); 1726EXPORT_SYMBOL(fb_get_options); 1727 1728MODULE_LICENSE("GPL");