1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2002 4 * Detlev Zundel, DENX Software Engineering, dzu@denx.de. 5 */ 6 7/* 8 * BMP handling routines 9 */ 10 11#include <common.h> 12#include <bmp_layout.h> 13#include <command.h> 14#include <dm.h> 15#include <gzip.h> 16#include <log.h> 17#include <malloc.h> 18#include <mapmem.h> 19#include <splash.h> 20#include <video.h> 21#include <asm/byteorder.h> 22 23/* 24 * Allocate and decompress a BMP image using gunzip(). 25 * 26 * Returns a pointer to the decompressed image data. This pointer is 27 * aligned to 32-bit-aligned-address + 2. 28 * See doc/README.displaying-bmps for explanation. 29 * 30 * The allocation address is passed to 'alloc_addr' and must be freed 31 * by the caller after use. 32 * 33 * Returns NULL if decompression failed, or if the decompressed data 34 * didn't contain a valid BMP signature or decompression is not enabled in 35 * Kconfig. 36 */ 37struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp, 38 void **alloc_addr) 39{ 40 void *dst; 41 unsigned long len; 42 struct bmp_image *bmp; 43 44 if (!CONFIG_IS_ENABLED(VIDEO_BMP_GZIP)) 45 return NULL; 46 47 /* 48 * Decompress bmp image 49 */ 50 len = CONFIG_VAL(VIDEO_LOGO_MAX_SIZE); 51 /* allocate extra 3 bytes for 32-bit-aligned-address + 2 alignment */ 52 dst = malloc(CONFIG_VAL(VIDEO_LOGO_MAX_SIZE) + 3); 53 if (!dst) { 54 puts("Error: malloc in gunzip failed!\n"); 55 return NULL; 56 } 57 58 /* align to 32-bit-aligned-address + 2 */ 59 bmp = dst + 2; 60 61 if (gunzip(bmp, CONFIG_VAL(VIDEO_LOGO_MAX_SIZE), map_sysmem(addr, 0), 62 &len)) { 63 free(dst); 64 return NULL; 65 } 66 if (len == CONFIG_VAL(VIDEO_LOGO_MAX_SIZE)) 67 puts("Image could be truncated (increase CONFIG_VIDEO_LOGO_MAX_SIZE)!\n"); 68 69 /* 70 * Check for bmp mark 'BM' 71 */ 72 if (!((bmp->header.signature[0] == 'B') && 73 (bmp->header.signature[1] == 'M'))) { 74 free(dst); 75 return NULL; 76 } 77 78 debug("Gzipped BMP image detected!\n"); 79 80 *alloc_addr = dst; 81 return bmp; 82} 83 84int bmp_info(ulong addr) 85{ 86 struct bmp_image *bmp = (struct bmp_image *)map_sysmem(addr, 0); 87 void *bmp_alloc_addr = NULL; 88 unsigned long len; 89 90 if (!((bmp->header.signature[0] == 'B') && 91 (bmp->header.signature[1] == 'M'))) 92 bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); 93 94 if (!bmp) { 95 printf("There is no valid bmp file at the given address\n"); 96 return 1; 97 } 98 99 printf("Image size : %d x %d\n", le32_to_cpu(bmp->header.width), 100 le32_to_cpu(bmp->header.height)); 101 printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count)); 102 printf("Compression : %d\n", le32_to_cpu(bmp->header.compression)); 103 104 if (bmp_alloc_addr) 105 free(bmp_alloc_addr); 106 107 return 0; 108} 109 110int bmp_display(ulong addr, int x, int y) 111{ 112 struct udevice *dev; 113 int ret; 114 struct bmp_image *bmp = map_sysmem(addr, 0); 115 void *bmp_alloc_addr = NULL; 116 unsigned long len; 117 118 if (!((bmp->header.signature[0] == 'B') && 119 (bmp->header.signature[1] == 'M'))) 120 bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); 121 122 if (!bmp) { 123 printf("There is no valid bmp file at the given address\n"); 124 return 1; 125 } 126 addr = map_to_sysmem(bmp); 127 128 ret = uclass_first_device_err(UCLASS_VIDEO, &dev); 129 if (!ret) { 130 bool align = false; 131 132 if (x == BMP_ALIGN_CENTER || y == BMP_ALIGN_CENTER) 133 align = true; 134 135 ret = video_bmp_display(dev, addr, x, y, align); 136 } 137 138 if (bmp_alloc_addr) 139 free(bmp_alloc_addr); 140 141 return ret ? CMD_RET_FAILURE : 0; 142} 143