22
33#include <linux/fb.h>
44#include <linux/linux_logo.h>
5+ #include <linux/fs.h>
6+ #include <linux/slab.h>
7+ #include <linux/string.h>
8+ #include <linux/uaccess.h>
9+ #include <linux/file.h>
10+ #include <linux/kernel.h>
11+ #include <linux/firmware.h>
512
613#include "fb_internal.h"
714
815bool fb_center_logo __read_mostly ;
916int fb_logo_count __read_mostly = -1 ;
17+ static int fullscreen_logo_enabled __initdata ;
18+ static char * fullscreen_logo_path __initdata ;
19+ typedef long ImagePalette [224 ][3 ];
1020
1121static inline unsigned int safe_shift (unsigned int d , int n )
1222{
@@ -79,6 +89,19 @@ static void fb_set_logo_truepalette(struct fb_info *info,
7989 }
8090}
8191
92+ static void fb_set_logo_RGB_palette (ImagePalette palette , u32 * palette_to_write , int current_rows )
93+ {
94+ // Set the kernel palette from an array of RGB values
95+ uint32_t color_code ;
96+ int i ;
97+
98+ // Color format is RGB565, remove LSB 3 bits, and move to correct position
99+ for (i = 0 ; i < current_rows ; i ++ ) {
100+ color_code = ((((uint16_t )palette [i ][0 ]) >> 3 ) << 11 ) | ((((uint16_t )palette [i ][1 ]) >> 2 ) << 5 ) | (((uint16_t )palette [i ][2 ]) >> 3 );
101+ palette_to_write [i + 32 ] = color_code ;
102+ }
103+ }
104+
82105static void fb_set_logo_directpalette (struct fb_info * info ,
83106 const struct linux_logo * logo ,
84107 u32 * palette )
@@ -275,6 +298,162 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
275298 }
276299}
277300
301+ static int __init fb_fullscreen_logo_setup (char * str ){
302+ fullscreen_logo_enabled = 1 ;
303+ fullscreen_logo_path = str ;
304+ pr_info ("Fullscreen Logo Enabled: %d" , fullscreen_logo_enabled );
305+ pr_info ("Fullscreen Logo Path: %s" , fullscreen_logo_path );
306+ return 1 ;
307+ }
308+
309+ __setup ("fullscreen_logo_name=" , fb_fullscreen_logo_setup );
310+
311+ static bool fb_palette_contains_entry (ImagePalette palette , int num_existing_rows , long * entry_to_add , int cols , int * index ) {
312+ for (int i = 0 ; i < num_existing_rows ; i ++ ) {
313+ bool match = true;
314+ for (int j = 0 ; j < cols ; j ++ ) {
315+ if (palette [i ][j ] != entry_to_add [j ]) {
316+ match = false;
317+ break ;
318+ }
319+ }
320+ if (match ) {
321+ * index = i ; // Update the index
322+ return true; // Found a duplicate
323+ }
324+ }
325+ return false; // No duplicate found
326+ }
327+
328+ static void fb_set_logo_from_file (struct fb_info * info , const char * filepath , struct fb_image * image , u32 * palette , u32 * saved_pseudo_palette ) {
329+ ImagePalette image_palette ;
330+ const char * file_content = NULL ;
331+ unsigned char * read_logo = NULL ;
332+ long width = 0 , height = 0 ;
333+ ssize_t len ;
334+ int ret ;
335+ const struct firmware * fw ;
336+
337+ ret = request_firmware (& fw , filepath , info -> device );
338+ if (ret ) {
339+ pr_info ("Failed to load logo file '%s': %d\n" , filepath , ret );
340+ goto cleanup ;
341+ }
342+ len = fw -> size ;
343+ file_content = fw -> data ;
344+
345+ if (len > 0 ) {
346+ int current_rows = 0 ;
347+ const char * current_ptr = file_content ;
348+ const char * end_ptr = file_content + len ;
349+
350+ if (len < 18 ) {
351+ pr_info ("Invalid logo file: TGA file too small for header\n" );
352+ goto cleanup ;
353+ }
354+
355+ unsigned char * header = (unsigned char * )file_content ;
356+
357+ // Parse TGA header
358+ unsigned char id_length = header [0 ];
359+ unsigned char image_type = header [2 ];
360+ // Skip color map info (bytes 3-7)
361+ // Skip image origin (bytes 8-11)
362+ width = header [12 ] | (header [13 ] << 8 );
363+ height = header [14 ] | (header [15 ] << 8 );
364+ image -> width = width ;
365+ image -> height = height ;
366+ unsigned char pixel_depth = header [16 ];
367+ unsigned char image_descriptor = header [17 ];
368+
369+ // Only supports uncompressed true-color images (type 2) with 24-bit depth
370+ if (image_type != 2 || pixel_depth != 24 ) {
371+ pr_info ("Unsupported TGA logo format: Type=%d, Depth=%d (only support Type=2, Depth=24)\n" ,
372+ image_type , pixel_depth );
373+ goto cleanup ;
374+ }
375+ // Skip header + ID field
376+ current_ptr = file_content + 18 + id_length ;
377+
378+ read_logo = kmalloc_array (width , height , GFP_KERNEL );
379+ if (read_logo == NULL ) {
380+ pr_info ("Failed to allocate memory for fullscreen logo" );
381+ goto cleanup ;
382+ }
383+ image -> data = read_logo ;
384+
385+ // TGA pixels are stored bottom-to-top by default, unless bit 5 of image_descriptor is set
386+ bool top_to_bottom = (image_descriptor & 0x20 ) != 0 ;
387+
388+ int skip_x = 0 , skip_y = 0 ;
389+ if (image -> width > info -> var .xres ) {
390+ pr_info ("Logo is larger than screen, clipping horizontally" );
391+ skip_x = (image -> width - info -> var .xres ) / 2 ;
392+ }
393+ if (image -> height > info -> var .yres ) {
394+ pr_info ("Logo is larger than screen, clipping vertically" );
395+ skip_y = (image -> height - info -> var .yres ) / 2 ;
396+ }
397+ current_ptr += skip_y * width * 3 + skip_x * 3 ;
398+ // Parse pixel data (BGR format in TGA)
399+ for (int i = 0 ; i < height - 2 * skip_y ; i ++ ) {
400+ for (int j = 0 ; j < width - 2 * skip_x ; j ++ ) {
401+ if (current_ptr + 3 > end_ptr ) {
402+ pr_info ("TGA: Unexpected end of file\n" );
403+ goto cleanup ;
404+ }
405+ long B = (unsigned char )* current_ptr ++ ;
406+ long G = (unsigned char )* current_ptr ++ ;
407+ long R = (unsigned char )* current_ptr ++ ;
408+ long entry [3 ] = {R , G , B };
409+ int palette_index = 0 ;
410+
411+ if (!fb_palette_contains_entry (image_palette , current_rows , entry , 3 , & palette_index )) {
412+ for (int k = 0 ; k < 3 ; k ++ ) {
413+ image_palette [current_rows ][k ] = entry [k ];
414+ }
415+ palette_index = current_rows ;
416+ current_rows ++ ;
417+ }
418+ int actual_row = top_to_bottom ? i : (height - 1 - i );
419+ read_logo [actual_row * (width - 2 * skip_x ) + j ] = palette_index + 32 ;
420+ }
421+ current_ptr += skip_x * 3 * 2 ;
422+ }
423+
424+ // Set logo palette
425+ palette = kmalloc (256 * 4 , GFP_KERNEL );
426+ if (palette == NULL )
427+ goto cleanup ;
428+
429+ fb_set_logo_RGB_palette (image_palette , palette , current_rows );
430+ saved_pseudo_palette = info -> pseudo_palette ;
431+ info -> pseudo_palette = palette ;
432+
433+ }
434+ else {
435+ pr_info ("Error: logo TGA file is empty. Not drawing fullscreen logo.\n" );
436+ }
437+
438+ image -> width = min ((unsigned int )width , info -> var .xres );
439+ image -> height = min ((unsigned int )height , info -> var .yres );
440+ image -> dx = 0 ;
441+ image -> dy = 0 ;
442+ image -> depth = 8 ;
443+
444+ if (image -> height < info -> var .yres ) {
445+ image -> dy = (info -> var .yres - image -> height ) / 2 ;
446+ }
447+ if (image -> width < info -> var .xres ) {
448+ image -> dx = (info -> var .xres - image -> width ) / 2 ;
449+ }
450+
451+ cleanup :
452+ if (file_content ) {
453+ kvfree (file_content );
454+ }
455+ }
456+
278457static int fb_show_logo_line (struct fb_info * info , int rotate ,
279458 const struct linux_logo * logo , int y ,
280459 unsigned int n )
@@ -288,6 +467,11 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
288467 info -> fbops -> owner )
289468 return 0 ;
290469
470+
471+ if (fullscreen_logo_enabled ) {
472+ fb_set_logo_from_file (info , fullscreen_logo_path , & image , palette , saved_pseudo_palette );
473+ } else {
474+
291475 image .depth = 8 ;
292476 image .data = logo -> data ;
293477
@@ -350,6 +534,21 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
350534 fb_rotate_logo (info , logo_rotate , & image , rotate );
351535 }
352536
537+ }
538+ if (fullscreen_logo_enabled ) {
539+ // Fullscreen logo data may not fill screen
540+ // Fill remainder of screen with border color of logo for continuous feel
541+ u32 fill_color = image .data [0 ];
542+ struct fb_fillrect region ;
543+ region .color = fill_color ;
544+ region .dx = 0 ;
545+ region .dy = 0 ;
546+ region .width = info -> var .xres ;
547+ region .height = info -> var .yres ;
548+ region .rop = ROP_COPY ;
549+ info -> fbops -> fb_fillrect (info , & region );
550+ }
551+
353552 fb_do_show_logo (info , & image , rotate , n );
354553
355554 kfree (palette );
0 commit comments