Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fbdev/core: Move logo functions into separate source file

Move the fbdev function for displaying boot-up logos into their
own file fb_logo.c. Only build fb_logo.c if CONFIG_LOGO has been
selected. No functional changes.

v2:
* include fb_internal.h (kernel test robot)
* simplify option-parsing ifdefs
* build fb_logo.o iff CONFIG_LOGO has been set

Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Acked-by: Javier Martinez Canillas <javierm@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230907085408.9354-6-tzimmermann@suse.de

+524 -520
+2
drivers/video/fbdev/core/Makefile
··· 23 23 endif 24 24 endif 25 25 26 + fb-$(CONFIG_LOGO) += fb_logo.o 27 + 26 28 obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o 27 29 obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o 28 30 obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
+2 -1
drivers/video/fbdev/core/fb_internal.h
··· 20 20 { } 21 21 #endif 22 22 23 - /* fbmem.c */ 23 + /* fb_logo.c */ 24 24 #if defined(CONFIG_LOGO) 25 25 extern bool fb_center_logo; 26 26 extern int fb_logo_count; ··· 37 37 } 38 38 #endif /* CONFIG_LOGO */ 39 39 40 + /* fbmem.c */ 40 41 extern struct class *fb_class; 41 42 extern struct mutex registration_lock; 42 43 extern struct fb_info *registered_fb[FB_MAX];
+518
drivers/video/fbdev/core/fb_logo.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/fb.h> 4 + #include <linux/linux_logo.h> 5 + 6 + #include "fb_internal.h" 7 + 8 + bool fb_center_logo __read_mostly; 9 + int fb_logo_count __read_mostly = -1; 10 + 11 + static inline unsigned int safe_shift(unsigned int d, int n) 12 + { 13 + return n < 0 ? d >> -n : d << n; 14 + } 15 + 16 + static void fb_set_logocmap(struct fb_info *info, 17 + const struct linux_logo *logo) 18 + { 19 + struct fb_cmap palette_cmap; 20 + u16 palette_green[16]; 21 + u16 palette_blue[16]; 22 + u16 palette_red[16]; 23 + int i, j, n; 24 + const unsigned char *clut = logo->clut; 25 + 26 + palette_cmap.start = 0; 27 + palette_cmap.len = 16; 28 + palette_cmap.red = palette_red; 29 + palette_cmap.green = palette_green; 30 + palette_cmap.blue = palette_blue; 31 + palette_cmap.transp = NULL; 32 + 33 + for (i = 0; i < logo->clutsize; i += n) { 34 + n = logo->clutsize - i; 35 + /* palette_cmap provides space for only 16 colors at once */ 36 + if (n > 16) 37 + n = 16; 38 + palette_cmap.start = 32 + i; 39 + palette_cmap.len = n; 40 + for (j = 0; j < n; ++j) { 41 + palette_cmap.red[j] = clut[0] << 8 | clut[0]; 42 + palette_cmap.green[j] = clut[1] << 8 | clut[1]; 43 + palette_cmap.blue[j] = clut[2] << 8 | clut[2]; 44 + clut += 3; 45 + } 46 + fb_set_cmap(&palette_cmap, info); 47 + } 48 + } 49 + 50 + static void fb_set_logo_truepalette(struct fb_info *info, 51 + const struct linux_logo *logo, 52 + u32 *palette) 53 + { 54 + static const unsigned char mask[] = { 55 + 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 56 + }; 57 + unsigned char redmask, greenmask, bluemask; 58 + int redshift, greenshift, blueshift; 59 + int i; 60 + const unsigned char *clut = logo->clut; 61 + 62 + /* 63 + * We have to create a temporary palette since console palette is only 64 + * 16 colors long. 65 + */ 66 + /* Bug: Doesn't obey msb_right ... (who needs that?) */ 67 + redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; 68 + greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; 69 + bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; 70 + redshift = info->var.red.offset - (8 - info->var.red.length); 71 + greenshift = info->var.green.offset - (8 - info->var.green.length); 72 + blueshift = info->var.blue.offset - (8 - info->var.blue.length); 73 + 74 + for (i = 0; i < logo->clutsize; i++) { 75 + palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | 76 + safe_shift((clut[1] & greenmask), greenshift) | 77 + safe_shift((clut[2] & bluemask), blueshift)); 78 + clut += 3; 79 + } 80 + } 81 + 82 + static void fb_set_logo_directpalette(struct fb_info *info, 83 + const struct linux_logo *logo, 84 + u32 *palette) 85 + { 86 + int redshift, greenshift, blueshift; 87 + int i; 88 + 89 + redshift = info->var.red.offset; 90 + greenshift = info->var.green.offset; 91 + blueshift = info->var.blue.offset; 92 + 93 + for (i = 32; i < 32 + logo->clutsize; i++) 94 + palette[i] = i << redshift | i << greenshift | i << blueshift; 95 + } 96 + 97 + static void fb_set_logo(struct fb_info *info, 98 + const struct linux_logo *logo, u8 *dst, 99 + int depth) 100 + { 101 + int i, j, k; 102 + const u8 *src = logo->data; 103 + u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; 104 + u8 fg = 1, d; 105 + 106 + switch (fb_get_color_depth(&info->var, &info->fix)) { 107 + case 1: 108 + fg = 1; 109 + break; 110 + case 2: 111 + fg = 3; 112 + break; 113 + default: 114 + fg = 7; 115 + break; 116 + } 117 + 118 + if (info->fix.visual == FB_VISUAL_MONO01 || 119 + info->fix.visual == FB_VISUAL_MONO10) 120 + fg = ~((u8) (0xfff << info->var.green.length)); 121 + 122 + switch (depth) { 123 + case 4: 124 + for (i = 0; i < logo->height; i++) 125 + for (j = 0; j < logo->width; src++) { 126 + *dst++ = *src >> 4; 127 + j++; 128 + if (j < logo->width) { 129 + *dst++ = *src & 0x0f; 130 + j++; 131 + } 132 + } 133 + break; 134 + case 1: 135 + for (i = 0; i < logo->height; i++) { 136 + for (j = 0; j < logo->width; src++) { 137 + d = *src ^ xor; 138 + for (k = 7; k >= 0 && j < logo->width; k--) { 139 + *dst++ = ((d >> k) & 1) ? fg : 0; 140 + j++; 141 + } 142 + } 143 + } 144 + break; 145 + } 146 + } 147 + 148 + /* 149 + * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), 150 + * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on 151 + * the visual format and color depth of the framebuffer, the DAC, the 152 + * pseudo_palette, and the logo data will be adjusted accordingly. 153 + * 154 + * Case 1 - linux_logo_clut224: 155 + * Color exceeds the number of console colors (16), thus we set the hardware DAC 156 + * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. 157 + * 158 + * For visuals that require color info from the pseudo_palette, we also construct 159 + * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags 160 + * will be set. 161 + * 162 + * Case 2 - linux_logo_vga16: 163 + * The number of colors just matches the console colors, thus there is no need 164 + * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, 165 + * each byte contains color information for two pixels (upper and lower nibble). 166 + * To be consistent with fb_imageblit() usage, we therefore separate the two 167 + * nibbles into separate bytes. The "depth" flag will be set to 4. 168 + * 169 + * Case 3 - linux_logo_mono: 170 + * This is similar with Case 2. Each byte contains information for 8 pixels. 171 + * We isolate each bit and expand each into a byte. The "depth" flag will 172 + * be set to 1. 173 + */ 174 + static struct logo_data { 175 + int depth; 176 + int needs_directpalette; 177 + int needs_truepalette; 178 + int needs_cmapreset; 179 + const struct linux_logo *logo; 180 + } fb_logo __read_mostly; 181 + 182 + static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) 183 + { 184 + u32 size = width * height, i; 185 + 186 + out += size - 1; 187 + 188 + for (i = size; i--; ) 189 + *out-- = *in++; 190 + } 191 + 192 + static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) 193 + { 194 + int i, j, h = height - 1; 195 + 196 + for (i = 0; i < height; i++) 197 + for (j = 0; j < width; j++) 198 + out[height * j + h - i] = *in++; 199 + } 200 + 201 + static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) 202 + { 203 + int i, j, w = width - 1; 204 + 205 + for (i = 0; i < height; i++) 206 + for (j = 0; j < width; j++) 207 + out[height * (w - j) + i] = *in++; 208 + } 209 + 210 + static void fb_rotate_logo(struct fb_info *info, u8 *dst, 211 + struct fb_image *image, int rotate) 212 + { 213 + u32 tmp; 214 + 215 + if (rotate == FB_ROTATE_UD) { 216 + fb_rotate_logo_ud(image->data, dst, image->width, 217 + image->height); 218 + image->dx = info->var.xres - image->width - image->dx; 219 + image->dy = info->var.yres - image->height - image->dy; 220 + } else if (rotate == FB_ROTATE_CW) { 221 + fb_rotate_logo_cw(image->data, dst, image->width, 222 + image->height); 223 + swap(image->width, image->height); 224 + tmp = image->dy; 225 + image->dy = image->dx; 226 + image->dx = info->var.xres - image->width - tmp; 227 + } else if (rotate == FB_ROTATE_CCW) { 228 + fb_rotate_logo_ccw(image->data, dst, image->width, 229 + image->height); 230 + swap(image->width, image->height); 231 + tmp = image->dx; 232 + image->dx = image->dy; 233 + image->dy = info->var.yres - image->height - tmp; 234 + } 235 + 236 + image->data = dst; 237 + } 238 + 239 + static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, 240 + int rotate, unsigned int num) 241 + { 242 + unsigned int x; 243 + 244 + if (image->width > info->var.xres || image->height > info->var.yres) 245 + return; 246 + 247 + if (rotate == FB_ROTATE_UR) { 248 + for (x = 0; 249 + x < num && image->dx + image->width <= info->var.xres; 250 + x++) { 251 + info->fbops->fb_imageblit(info, image); 252 + image->dx += image->width + 8; 253 + } 254 + } else if (rotate == FB_ROTATE_UD) { 255 + u32 dx = image->dx; 256 + 257 + for (x = 0; x < num && image->dx <= dx; x++) { 258 + info->fbops->fb_imageblit(info, image); 259 + image->dx -= image->width + 8; 260 + } 261 + } else if (rotate == FB_ROTATE_CW) { 262 + for (x = 0; 263 + x < num && image->dy + image->height <= info->var.yres; 264 + x++) { 265 + info->fbops->fb_imageblit(info, image); 266 + image->dy += image->height + 8; 267 + } 268 + } else if (rotate == FB_ROTATE_CCW) { 269 + u32 dy = image->dy; 270 + 271 + for (x = 0; x < num && image->dy <= dy; x++) { 272 + info->fbops->fb_imageblit(info, image); 273 + image->dy -= image->height + 8; 274 + } 275 + } 276 + } 277 + 278 + static int fb_show_logo_line(struct fb_info *info, int rotate, 279 + const struct linux_logo *logo, int y, 280 + unsigned int n) 281 + { 282 + u32 *palette = NULL, *saved_pseudo_palette = NULL; 283 + unsigned char *logo_new = NULL, *logo_rotate = NULL; 284 + struct fb_image image; 285 + 286 + /* Return if the frame buffer is not mapped or suspended */ 287 + if (logo == NULL || info->state != FBINFO_STATE_RUNNING || 288 + info->fbops->owner) 289 + return 0; 290 + 291 + image.depth = 8; 292 + image.data = logo->data; 293 + 294 + if (fb_logo.needs_cmapreset) 295 + fb_set_logocmap(info, logo); 296 + 297 + if (fb_logo.needs_truepalette || 298 + fb_logo.needs_directpalette) { 299 + palette = kmalloc(256 * 4, GFP_KERNEL); 300 + if (palette == NULL) 301 + return 0; 302 + 303 + if (fb_logo.needs_truepalette) 304 + fb_set_logo_truepalette(info, logo, palette); 305 + else 306 + fb_set_logo_directpalette(info, logo, palette); 307 + 308 + saved_pseudo_palette = info->pseudo_palette; 309 + info->pseudo_palette = palette; 310 + } 311 + 312 + if (fb_logo.depth <= 4) { 313 + logo_new = kmalloc_array(logo->width, logo->height, 314 + GFP_KERNEL); 315 + if (logo_new == NULL) { 316 + kfree(palette); 317 + if (saved_pseudo_palette) 318 + info->pseudo_palette = saved_pseudo_palette; 319 + return 0; 320 + } 321 + image.data = logo_new; 322 + fb_set_logo(info, logo, logo_new, fb_logo.depth); 323 + } 324 + 325 + if (fb_center_logo) { 326 + int xres = info->var.xres; 327 + int yres = info->var.yres; 328 + 329 + if (rotate == FB_ROTATE_CW || rotate == FB_ROTATE_CCW) { 330 + xres = info->var.yres; 331 + yres = info->var.xres; 332 + } 333 + 334 + while (n && (n * (logo->width + 8) - 8 > xres)) 335 + --n; 336 + image.dx = (xres - (n * (logo->width + 8) - 8)) / 2; 337 + image.dy = y ?: (yres - logo->height) / 2; 338 + } else { 339 + image.dx = 0; 340 + image.dy = y; 341 + } 342 + 343 + image.width = logo->width; 344 + image.height = logo->height; 345 + 346 + if (rotate) { 347 + logo_rotate = kmalloc_array(logo->width, logo->height, 348 + GFP_KERNEL); 349 + if (logo_rotate) 350 + fb_rotate_logo(info, logo_rotate, &image, rotate); 351 + } 352 + 353 + fb_do_show_logo(info, &image, rotate, n); 354 + 355 + kfree(palette); 356 + if (saved_pseudo_palette != NULL) 357 + info->pseudo_palette = saved_pseudo_palette; 358 + kfree(logo_new); 359 + kfree(logo_rotate); 360 + return image.dy + logo->height; 361 + } 362 + 363 + #ifdef CONFIG_FB_LOGO_EXTRA 364 + 365 + #define FB_LOGO_EX_NUM_MAX 10 366 + static struct logo_data_extra { 367 + const struct linux_logo *logo; 368 + unsigned int n; 369 + } fb_logo_ex[FB_LOGO_EX_NUM_MAX]; 370 + static unsigned int fb_logo_ex_num; 371 + 372 + void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) 373 + { 374 + if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) 375 + return; 376 + 377 + fb_logo_ex[fb_logo_ex_num].logo = logo; 378 + fb_logo_ex[fb_logo_ex_num].n = n; 379 + fb_logo_ex_num++; 380 + } 381 + 382 + static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, 383 + unsigned int yres) 384 + { 385 + unsigned int i; 386 + 387 + /* FIXME: logo_ex supports only truecolor fb. */ 388 + if (info->fix.visual != FB_VISUAL_TRUECOLOR) 389 + fb_logo_ex_num = 0; 390 + 391 + for (i = 0; i < fb_logo_ex_num; i++) { 392 + if (fb_logo_ex[i].logo->type != fb_logo.logo->type) { 393 + fb_logo_ex[i].logo = NULL; 394 + continue; 395 + } 396 + height += fb_logo_ex[i].logo->height; 397 + if (height > yres) { 398 + height -= fb_logo_ex[i].logo->height; 399 + fb_logo_ex_num = i; 400 + break; 401 + } 402 + } 403 + return height; 404 + } 405 + 406 + static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 407 + { 408 + unsigned int i; 409 + 410 + for (i = 0; i < fb_logo_ex_num; i++) 411 + y = fb_show_logo_line(info, rotate, 412 + fb_logo_ex[i].logo, y, fb_logo_ex[i].n); 413 + 414 + return y; 415 + } 416 + 417 + #else /* !CONFIG_FB_LOGO_EXTRA */ 418 + 419 + static inline int fb_prepare_extra_logos(struct fb_info *info, 420 + unsigned int height, 421 + unsigned int yres) 422 + { 423 + return height; 424 + } 425 + 426 + static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 427 + { 428 + return y; 429 + } 430 + 431 + #endif /* CONFIG_FB_LOGO_EXTRA */ 432 + 433 + int fb_prepare_logo(struct fb_info *info, int rotate) 434 + { 435 + int depth = fb_get_color_depth(&info->var, &info->fix); 436 + unsigned int yres; 437 + int height; 438 + 439 + memset(&fb_logo, 0, sizeof(struct logo_data)); 440 + 441 + if (info->flags & FBINFO_MISC_TILEBLITTING || 442 + info->fbops->owner || !fb_logo_count) 443 + return 0; 444 + 445 + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 446 + depth = info->var.blue.length; 447 + if (info->var.red.length < depth) 448 + depth = info->var.red.length; 449 + if (info->var.green.length < depth) 450 + depth = info->var.green.length; 451 + } 452 + 453 + if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { 454 + /* assume console colormap */ 455 + depth = 4; 456 + } 457 + 458 + /* Return if no suitable logo was found */ 459 + fb_logo.logo = fb_find_logo(depth); 460 + 461 + if (!fb_logo.logo) 462 + return 0; 463 + 464 + if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) 465 + yres = info->var.yres; 466 + else 467 + yres = info->var.xres; 468 + 469 + if (fb_logo.logo->height > yres) { 470 + fb_logo.logo = NULL; 471 + return 0; 472 + } 473 + 474 + /* What depth we asked for might be different from what we get */ 475 + if (fb_logo.logo->type == LINUX_LOGO_CLUT224) 476 + fb_logo.depth = 8; 477 + else if (fb_logo.logo->type == LINUX_LOGO_VGA16) 478 + fb_logo.depth = 4; 479 + else 480 + fb_logo.depth = 1; 481 + 482 + 483 + if (fb_logo.depth > 4 && depth > 4) { 484 + switch (info->fix.visual) { 485 + case FB_VISUAL_TRUECOLOR: 486 + fb_logo.needs_truepalette = 1; 487 + break; 488 + case FB_VISUAL_DIRECTCOLOR: 489 + fb_logo.needs_directpalette = 1; 490 + fb_logo.needs_cmapreset = 1; 491 + break; 492 + case FB_VISUAL_PSEUDOCOLOR: 493 + fb_logo.needs_cmapreset = 1; 494 + break; 495 + } 496 + } 497 + 498 + height = fb_logo.logo->height; 499 + if (fb_center_logo) 500 + height += (yres - fb_logo.logo->height) / 2; 501 + 502 + return fb_prepare_extra_logos(info, height, yres); 503 + } 504 + 505 + int fb_show_logo(struct fb_info *info, int rotate) 506 + { 507 + unsigned int count; 508 + int y; 509 + 510 + if (!fb_logo_count) 511 + return 0; 512 + 513 + count = fb_logo_count < 0 ? num_online_cpus() : fb_logo_count; 514 + y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count); 515 + y = fb_show_extra_logos(info, y, rotate); 516 + 517 + return y; 518 + }
+2
drivers/video/fbdev/core/fbcon.c
··· 472 472 } 473 473 #endif 474 474 475 + #ifdef CONFIG_LOGO 475 476 if (!strncmp(options, "logo-pos:", 9)) { 476 477 options += 9; 477 478 if (!strcmp(options, "center")) ··· 486 485 fb_logo_count = simple_strtol(options, &options, 0); 487 486 continue; 488 487 } 488 + #endif 489 489 } 490 490 return 1; 491 491 }
-519
drivers/video/fbdev/core/fbmem.c
··· 21 21 #include <linux/mman.h> 22 22 #include <linux/vt.h> 23 23 #include <linux/init.h> 24 - #include <linux/linux_logo.h> 25 24 #include <linux/platform_device.h> 26 25 #include <linux/console.h> 27 26 #include <linux/kmod.h> ··· 51 52 #define for_each_registered_fb(i) \ 52 53 for (i = 0; i < FB_MAX; i++) \ 53 54 if (!registered_fb[i]) {} else 54 - 55 - bool fb_center_logo __read_mostly; 56 - 57 - int fb_logo_count __read_mostly = -1; 58 55 59 56 struct fb_info *get_fb_info(unsigned int idx) 60 57 { ··· 178 183 return addr; 179 184 } 180 185 EXPORT_SYMBOL(fb_get_buffer_offset); 181 - 182 - #ifdef CONFIG_LOGO 183 - 184 - static inline unsigned int safe_shift(unsigned int d, int n) 185 - { 186 - return n < 0 ? d >> -n : d << n; 187 - } 188 - 189 - static void fb_set_logocmap(struct fb_info *info, 190 - const struct linux_logo *logo) 191 - { 192 - struct fb_cmap palette_cmap; 193 - u16 palette_green[16]; 194 - u16 palette_blue[16]; 195 - u16 palette_red[16]; 196 - int i, j, n; 197 - const unsigned char *clut = logo->clut; 198 - 199 - palette_cmap.start = 0; 200 - palette_cmap.len = 16; 201 - palette_cmap.red = palette_red; 202 - palette_cmap.green = palette_green; 203 - palette_cmap.blue = palette_blue; 204 - palette_cmap.transp = NULL; 205 - 206 - for (i = 0; i < logo->clutsize; i += n) { 207 - n = logo->clutsize - i; 208 - /* palette_cmap provides space for only 16 colors at once */ 209 - if (n > 16) 210 - n = 16; 211 - palette_cmap.start = 32 + i; 212 - palette_cmap.len = n; 213 - for (j = 0; j < n; ++j) { 214 - palette_cmap.red[j] = clut[0] << 8 | clut[0]; 215 - palette_cmap.green[j] = clut[1] << 8 | clut[1]; 216 - palette_cmap.blue[j] = clut[2] << 8 | clut[2]; 217 - clut += 3; 218 - } 219 - fb_set_cmap(&palette_cmap, info); 220 - } 221 - } 222 - 223 - static void fb_set_logo_truepalette(struct fb_info *info, 224 - const struct linux_logo *logo, 225 - u32 *palette) 226 - { 227 - static const unsigned char mask[] = { 228 - 0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff 229 - }; 230 - unsigned char redmask, greenmask, bluemask; 231 - int redshift, greenshift, blueshift; 232 - int i; 233 - const unsigned char *clut = logo->clut; 234 - 235 - /* 236 - * We have to create a temporary palette since console palette is only 237 - * 16 colors long. 238 - */ 239 - /* Bug: Doesn't obey msb_right ... (who needs that?) */ 240 - redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; 241 - greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; 242 - bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; 243 - redshift = info->var.red.offset - (8 - info->var.red.length); 244 - greenshift = info->var.green.offset - (8 - info->var.green.length); 245 - blueshift = info->var.blue.offset - (8 - info->var.blue.length); 246 - 247 - for (i = 0; i < logo->clutsize; i++) { 248 - palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | 249 - safe_shift((clut[1] & greenmask), greenshift) | 250 - safe_shift((clut[2] & bluemask), blueshift)); 251 - clut += 3; 252 - } 253 - } 254 - 255 - static void fb_set_logo_directpalette(struct fb_info *info, 256 - const struct linux_logo *logo, 257 - u32 *palette) 258 - { 259 - int redshift, greenshift, blueshift; 260 - int i; 261 - 262 - redshift = info->var.red.offset; 263 - greenshift = info->var.green.offset; 264 - blueshift = info->var.blue.offset; 265 - 266 - for (i = 32; i < 32 + logo->clutsize; i++) 267 - palette[i] = i << redshift | i << greenshift | i << blueshift; 268 - } 269 - 270 - static void fb_set_logo(struct fb_info *info, 271 - const struct linux_logo *logo, u8 *dst, 272 - int depth) 273 - { 274 - int i, j, k; 275 - const u8 *src = logo->data; 276 - u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; 277 - u8 fg = 1, d; 278 - 279 - switch (fb_get_color_depth(&info->var, &info->fix)) { 280 - case 1: 281 - fg = 1; 282 - break; 283 - case 2: 284 - fg = 3; 285 - break; 286 - default: 287 - fg = 7; 288 - break; 289 - } 290 - 291 - if (info->fix.visual == FB_VISUAL_MONO01 || 292 - info->fix.visual == FB_VISUAL_MONO10) 293 - fg = ~((u8) (0xfff << info->var.green.length)); 294 - 295 - switch (depth) { 296 - case 4: 297 - for (i = 0; i < logo->height; i++) 298 - for (j = 0; j < logo->width; src++) { 299 - *dst++ = *src >> 4; 300 - j++; 301 - if (j < logo->width) { 302 - *dst++ = *src & 0x0f; 303 - j++; 304 - } 305 - } 306 - break; 307 - case 1: 308 - for (i = 0; i < logo->height; i++) { 309 - for (j = 0; j < logo->width; src++) { 310 - d = *src ^ xor; 311 - for (k = 7; k >= 0 && j < logo->width; k--) { 312 - *dst++ = ((d >> k) & 1) ? fg : 0; 313 - j++; 314 - } 315 - } 316 - } 317 - break; 318 - } 319 - } 320 - 321 - /* 322 - * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), 323 - * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on 324 - * the visual format and color depth of the framebuffer, the DAC, the 325 - * pseudo_palette, and the logo data will be adjusted accordingly. 326 - * 327 - * Case 1 - linux_logo_clut224: 328 - * Color exceeds the number of console colors (16), thus we set the hardware DAC 329 - * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. 330 - * 331 - * For visuals that require color info from the pseudo_palette, we also construct 332 - * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags 333 - * will be set. 334 - * 335 - * Case 2 - linux_logo_vga16: 336 - * The number of colors just matches the console colors, thus there is no need 337 - * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, 338 - * each byte contains color information for two pixels (upper and lower nibble). 339 - * To be consistent with fb_imageblit() usage, we therefore separate the two 340 - * nibbles into separate bytes. The "depth" flag will be set to 4. 341 - * 342 - * Case 3 - linux_logo_mono: 343 - * This is similar with Case 2. Each byte contains information for 8 pixels. 344 - * We isolate each bit and expand each into a byte. The "depth" flag will 345 - * be set to 1. 346 - */ 347 - static struct logo_data { 348 - int depth; 349 - int needs_directpalette; 350 - int needs_truepalette; 351 - int needs_cmapreset; 352 - const struct linux_logo *logo; 353 - } fb_logo __read_mostly; 354 - 355 - static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) 356 - { 357 - u32 size = width * height, i; 358 - 359 - out += size - 1; 360 - 361 - for (i = size; i--; ) 362 - *out-- = *in++; 363 - } 364 - 365 - static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) 366 - { 367 - int i, j, h = height - 1; 368 - 369 - for (i = 0; i < height; i++) 370 - for (j = 0; j < width; j++) 371 - out[height * j + h - i] = *in++; 372 - } 373 - 374 - static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) 375 - { 376 - int i, j, w = width - 1; 377 - 378 - for (i = 0; i < height; i++) 379 - for (j = 0; j < width; j++) 380 - out[height * (w - j) + i] = *in++; 381 - } 382 - 383 - static void fb_rotate_logo(struct fb_info *info, u8 *dst, 384 - struct fb_image *image, int rotate) 385 - { 386 - u32 tmp; 387 - 388 - if (rotate == FB_ROTATE_UD) { 389 - fb_rotate_logo_ud(image->data, dst, image->width, 390 - image->height); 391 - image->dx = info->var.xres - image->width - image->dx; 392 - image->dy = info->var.yres - image->height - image->dy; 393 - } else if (rotate == FB_ROTATE_CW) { 394 - fb_rotate_logo_cw(image->data, dst, image->width, 395 - image->height); 396 - swap(image->width, image->height); 397 - tmp = image->dy; 398 - image->dy = image->dx; 399 - image->dx = info->var.xres - image->width - tmp; 400 - } else if (rotate == FB_ROTATE_CCW) { 401 - fb_rotate_logo_ccw(image->data, dst, image->width, 402 - image->height); 403 - swap(image->width, image->height); 404 - tmp = image->dx; 405 - image->dx = image->dy; 406 - image->dy = info->var.yres - image->height - tmp; 407 - } 408 - 409 - image->data = dst; 410 - } 411 - 412 - static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, 413 - int rotate, unsigned int num) 414 - { 415 - unsigned int x; 416 - 417 - if (image->width > info->var.xres || image->height > info->var.yres) 418 - return; 419 - 420 - if (rotate == FB_ROTATE_UR) { 421 - for (x = 0; 422 - x < num && image->dx + image->width <= info->var.xres; 423 - x++) { 424 - info->fbops->fb_imageblit(info, image); 425 - image->dx += image->width + 8; 426 - } 427 - } else if (rotate == FB_ROTATE_UD) { 428 - u32 dx = image->dx; 429 - 430 - for (x = 0; x < num && image->dx <= dx; x++) { 431 - info->fbops->fb_imageblit(info, image); 432 - image->dx -= image->width + 8; 433 - } 434 - } else if (rotate == FB_ROTATE_CW) { 435 - for (x = 0; 436 - x < num && image->dy + image->height <= info->var.yres; 437 - x++) { 438 - info->fbops->fb_imageblit(info, image); 439 - image->dy += image->height + 8; 440 - } 441 - } else if (rotate == FB_ROTATE_CCW) { 442 - u32 dy = image->dy; 443 - 444 - for (x = 0; x < num && image->dy <= dy; x++) { 445 - info->fbops->fb_imageblit(info, image); 446 - image->dy -= image->height + 8; 447 - } 448 - } 449 - } 450 - 451 - static int fb_show_logo_line(struct fb_info *info, int rotate, 452 - const struct linux_logo *logo, int y, 453 - unsigned int n) 454 - { 455 - u32 *palette = NULL, *saved_pseudo_palette = NULL; 456 - unsigned char *logo_new = NULL, *logo_rotate = NULL; 457 - struct fb_image image; 458 - 459 - /* Return if the frame buffer is not mapped or suspended */ 460 - if (logo == NULL || info->state != FBINFO_STATE_RUNNING || 461 - info->fbops->owner) 462 - return 0; 463 - 464 - image.depth = 8; 465 - image.data = logo->data; 466 - 467 - if (fb_logo.needs_cmapreset) 468 - fb_set_logocmap(info, logo); 469 - 470 - if (fb_logo.needs_truepalette || 471 - fb_logo.needs_directpalette) { 472 - palette = kmalloc(256 * 4, GFP_KERNEL); 473 - if (palette == NULL) 474 - return 0; 475 - 476 - if (fb_logo.needs_truepalette) 477 - fb_set_logo_truepalette(info, logo, palette); 478 - else 479 - fb_set_logo_directpalette(info, logo, palette); 480 - 481 - saved_pseudo_palette = info->pseudo_palette; 482 - info->pseudo_palette = palette; 483 - } 484 - 485 - if (fb_logo.depth <= 4) { 486 - logo_new = kmalloc_array(logo->width, logo->height, 487 - GFP_KERNEL); 488 - if (logo_new == NULL) { 489 - kfree(palette); 490 - if (saved_pseudo_palette) 491 - info->pseudo_palette = saved_pseudo_palette; 492 - return 0; 493 - } 494 - image.data = logo_new; 495 - fb_set_logo(info, logo, logo_new, fb_logo.depth); 496 - } 497 - 498 - if (fb_center_logo) { 499 - int xres = info->var.xres; 500 - int yres = info->var.yres; 501 - 502 - if (rotate == FB_ROTATE_CW || rotate == FB_ROTATE_CCW) { 503 - xres = info->var.yres; 504 - yres = info->var.xres; 505 - } 506 - 507 - while (n && (n * (logo->width + 8) - 8 > xres)) 508 - --n; 509 - image.dx = (xres - (n * (logo->width + 8) - 8)) / 2; 510 - image.dy = y ?: (yres - logo->height) / 2; 511 - } else { 512 - image.dx = 0; 513 - image.dy = y; 514 - } 515 - 516 - image.width = logo->width; 517 - image.height = logo->height; 518 - 519 - if (rotate) { 520 - logo_rotate = kmalloc_array(logo->width, logo->height, 521 - GFP_KERNEL); 522 - if (logo_rotate) 523 - fb_rotate_logo(info, logo_rotate, &image, rotate); 524 - } 525 - 526 - fb_do_show_logo(info, &image, rotate, n); 527 - 528 - kfree(palette); 529 - if (saved_pseudo_palette != NULL) 530 - info->pseudo_palette = saved_pseudo_palette; 531 - kfree(logo_new); 532 - kfree(logo_rotate); 533 - return image.dy + logo->height; 534 - } 535 - 536 - 537 - #ifdef CONFIG_FB_LOGO_EXTRA 538 - 539 - #define FB_LOGO_EX_NUM_MAX 10 540 - static struct logo_data_extra { 541 - const struct linux_logo *logo; 542 - unsigned int n; 543 - } fb_logo_ex[FB_LOGO_EX_NUM_MAX]; 544 - static unsigned int fb_logo_ex_num; 545 - 546 - void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) 547 - { 548 - if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) 549 - return; 550 - 551 - fb_logo_ex[fb_logo_ex_num].logo = logo; 552 - fb_logo_ex[fb_logo_ex_num].n = n; 553 - fb_logo_ex_num++; 554 - } 555 - 556 - static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, 557 - unsigned int yres) 558 - { 559 - unsigned int i; 560 - 561 - /* FIXME: logo_ex supports only truecolor fb. */ 562 - if (info->fix.visual != FB_VISUAL_TRUECOLOR) 563 - fb_logo_ex_num = 0; 564 - 565 - for (i = 0; i < fb_logo_ex_num; i++) { 566 - if (fb_logo_ex[i].logo->type != fb_logo.logo->type) { 567 - fb_logo_ex[i].logo = NULL; 568 - continue; 569 - } 570 - height += fb_logo_ex[i].logo->height; 571 - if (height > yres) { 572 - height -= fb_logo_ex[i].logo->height; 573 - fb_logo_ex_num = i; 574 - break; 575 - } 576 - } 577 - return height; 578 - } 579 - 580 - static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 581 - { 582 - unsigned int i; 583 - 584 - for (i = 0; i < fb_logo_ex_num; i++) 585 - y = fb_show_logo_line(info, rotate, 586 - fb_logo_ex[i].logo, y, fb_logo_ex[i].n); 587 - 588 - return y; 589 - } 590 - 591 - #else /* !CONFIG_FB_LOGO_EXTRA */ 592 - 593 - static inline int fb_prepare_extra_logos(struct fb_info *info, 594 - unsigned int height, 595 - unsigned int yres) 596 - { 597 - return height; 598 - } 599 - 600 - static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) 601 - { 602 - return y; 603 - } 604 - 605 - #endif /* CONFIG_FB_LOGO_EXTRA */ 606 - 607 - 608 - int fb_prepare_logo(struct fb_info *info, int rotate) 609 - { 610 - int depth = fb_get_color_depth(&info->var, &info->fix); 611 - unsigned int yres; 612 - int height; 613 - 614 - memset(&fb_logo, 0, sizeof(struct logo_data)); 615 - 616 - if (info->flags & FBINFO_MISC_TILEBLITTING || 617 - info->fbops->owner || !fb_logo_count) 618 - return 0; 619 - 620 - if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { 621 - depth = info->var.blue.length; 622 - if (info->var.red.length < depth) 623 - depth = info->var.red.length; 624 - if (info->var.green.length < depth) 625 - depth = info->var.green.length; 626 - } 627 - 628 - if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { 629 - /* assume console colormap */ 630 - depth = 4; 631 - } 632 - 633 - /* Return if no suitable logo was found */ 634 - fb_logo.logo = fb_find_logo(depth); 635 - 636 - if (!fb_logo.logo) 637 - return 0; 638 - 639 - if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) 640 - yres = info->var.yres; 641 - else 642 - yres = info->var.xres; 643 - 644 - if (fb_logo.logo->height > yres) { 645 - fb_logo.logo = NULL; 646 - return 0; 647 - } 648 - 649 - /* What depth we asked for might be different from what we get */ 650 - if (fb_logo.logo->type == LINUX_LOGO_CLUT224) 651 - fb_logo.depth = 8; 652 - else if (fb_logo.logo->type == LINUX_LOGO_VGA16) 653 - fb_logo.depth = 4; 654 - else 655 - fb_logo.depth = 1; 656 - 657 - 658 - if (fb_logo.depth > 4 && depth > 4) { 659 - switch (info->fix.visual) { 660 - case FB_VISUAL_TRUECOLOR: 661 - fb_logo.needs_truepalette = 1; 662 - break; 663 - case FB_VISUAL_DIRECTCOLOR: 664 - fb_logo.needs_directpalette = 1; 665 - fb_logo.needs_cmapreset = 1; 666 - break; 667 - case FB_VISUAL_PSEUDOCOLOR: 668 - fb_logo.needs_cmapreset = 1; 669 - break; 670 - } 671 - } 672 - 673 - height = fb_logo.logo->height; 674 - if (fb_center_logo) 675 - height += (yres - fb_logo.logo->height) / 2; 676 - 677 - return fb_prepare_extra_logos(info, height, yres); 678 - } 679 - 680 - int fb_show_logo(struct fb_info *info, int rotate) 681 - { 682 - unsigned int count; 683 - int y; 684 - 685 - if (!fb_logo_count) 686 - return 0; 687 - 688 - count = fb_logo_count < 0 ? num_online_cpus() : fb_logo_count; 689 - y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, count); 690 - y = fb_show_extra_logos(info, y, rotate); 691 - 692 - return y; 693 - } 694 - #endif /* CONFIG_LOGO */ 695 186 696 187 int 697 188 fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var)