1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/export.h> 4 #include <linux/ioport.h> 5 #include <linux/screen_info.h> 6 #include <linux/string.h> 7 8 #include <video/pixel_format.h> 9 10 static void resource_init_named(struct resource *r, 11 resource_size_t start, resource_size_t size, 12 const char *name, unsigned int flags) 13 { 14 memset(r, 0, sizeof(*r)); 15 16 r->start = start; 17 r->end = start + size - 1; 18 r->name = name; 19 r->flags = flags; 20 } 21 22 static void resource_init_io_named(struct resource *r, 23 resource_size_t start, resource_size_t size, 24 const char *name) 25 { 26 resource_init_named(r, start, size, name, IORESOURCE_IO); 27 } 28 29 static void resource_init_mem_named(struct resource *r, 30 resource_size_t start, resource_size_t size, 31 const char *name) 32 { 33 resource_init_named(r, start, size, name, IORESOURCE_MEM); 34 } 35 36 static inline bool __screen_info_has_ega_gfx(unsigned int mode) 37 { 38 switch (mode) { 39 case 0x0d: /* 320x200-4 */ 40 case 0x0e: /* 640x200-4 */ 41 case 0x0f: /* 640x350-1 */ 42 case 0x10: /* 640x350-4 */ 43 return true; 44 default: 45 return false; 46 } 47 } 48 49 static inline bool __screen_info_has_vga_gfx(unsigned int mode) 50 { 51 switch (mode) { 52 case 0x10: /* 640x480-1 */ 53 case 0x12: /* 640x480-4 */ 54 case 0x13: /* 320-200-8 */ 55 case 0x6a: /* 800x600-4 (VESA) */ 56 return true; 57 default: 58 return __screen_info_has_ega_gfx(mode); 59 } 60 } 61 62 /** 63 * screen_info_resources() - Get resources from screen_info structure 64 * @si: the screen_info 65 * @r: pointer to an array of resource structures 66 * @num: number of elements in @r: 67 * 68 * Returns: 69 * The number of resources stored in @r on success, or a negative errno code otherwise. 70 * 71 * A call to screen_info_resources() returns the resources consumed by the 72 * screen_info's device or framebuffer. The result is stored in the caller-supplied 73 * array @r with up to @num elements. The function returns the number of 74 * initialized elements. 75 */ 76 ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num) 77 { 78 struct resource *pos = r; 79 unsigned int type = screen_info_video_type(si); 80 u64 base, size; 81 82 switch (type) { 83 case VIDEO_TYPE_MDA: 84 if (num > 0) 85 resource_init_io_named(pos++, 0x3b0, 12, "mda"); 86 if (num > 1) 87 resource_init_io_named(pos++, 0x3bf, 0x01, "mda"); 88 if (num > 2) 89 resource_init_mem_named(pos++, 0xb0000, 0x2000, "mda"); 90 break; 91 case VIDEO_TYPE_CGA: 92 if (num > 0) 93 resource_init_io_named(pos++, 0x3d4, 0x02, "cga"); 94 if (num > 1) 95 resource_init_mem_named(pos++, 0xb8000, 0x2000, "cga"); 96 break; 97 case VIDEO_TYPE_EGAM: 98 if (num > 0) 99 resource_init_io_named(pos++, 0x3bf, 0x10, "ega"); 100 if (num > 1) 101 resource_init_mem_named(pos++, 0xb0000, 0x8000, "ega"); 102 break; 103 case VIDEO_TYPE_EGAC: 104 if (num > 0) 105 resource_init_io_named(pos++, 0x3c0, 0x20, "ega"); 106 if (num > 1) { 107 if (__screen_info_has_ega_gfx(si->orig_video_mode)) 108 resource_init_mem_named(pos++, 0xa0000, 0x10000, "ega"); 109 else 110 resource_init_mem_named(pos++, 0xb8000, 0x8000, "ega"); 111 } 112 break; 113 case VIDEO_TYPE_VGAC: 114 if (num > 0) 115 resource_init_io_named(pos++, 0x3c0, 0x20, "vga+"); 116 if (num > 1) { 117 if (__screen_info_has_vga_gfx(si->orig_video_mode)) 118 resource_init_mem_named(pos++, 0xa0000, 0x10000, "vga+"); 119 else 120 resource_init_mem_named(pos++, 0xb8000, 0x8000, "vga+"); 121 } 122 break; 123 case VIDEO_TYPE_VLFB: 124 case VIDEO_TYPE_EFI: 125 base = __screen_info_lfb_base(si); 126 if (!base) 127 break; 128 size = __screen_info_lfb_size(si, type); 129 if (!size) 130 break; 131 if (num > 0) 132 resource_init_mem_named(pos++, base, size, "lfb"); 133 break; 134 case VIDEO_TYPE_PICA_S3: 135 case VIDEO_TYPE_MIPS_G364: 136 case VIDEO_TYPE_SGI: 137 case VIDEO_TYPE_TGAC: 138 case VIDEO_TYPE_SUN: 139 case VIDEO_TYPE_SUNPCI: 140 case VIDEO_TYPE_PMAC: 141 default: 142 /* not supported */ 143 return -EINVAL; 144 } 145 146 return pos - r; 147 } 148 EXPORT_SYMBOL(screen_info_resources); 149 150 /* 151 * The meaning of depth and bpp for direct-color formats is 152 * inconsistent: 153 * 154 * - DRM format info specifies depth as the number of color 155 * bits; including alpha, but not including filler bits. 156 * - Linux' EFI platform code computes lfb_depth from the 157 * individual color channels, including the reserved bits. 158 * - VBE 1.1 defines lfb_depth for XRGB1555 as 16, but later 159 * versions use 15. 160 * - On the kernel command line, 'bpp' of 32 is usually 161 * XRGB8888 including the filler bits, but 15 is XRGB1555 162 * not including the filler bit. 163 * 164 * It is not easily possible to fix this in struct screen_info, 165 * as this could break UAPI. The best solution is to compute 166 * bits_per_pixel from the color bits, reserved bits and 167 * reported lfb_depth, whichever is highest. 168 */ 169 170 u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si) 171 { 172 u32 bits_per_pixel = si->lfb_depth; 173 174 if (bits_per_pixel > 8) { 175 bits_per_pixel = max(max3(si->red_size + si->red_pos, 176 si->green_size + si->green_pos, 177 si->blue_size + si->blue_pos), 178 si->rsvd_size + si->rsvd_pos); 179 bits_per_pixel = max_t(u32, bits_per_pixel, si->lfb_depth); 180 } 181 182 return bits_per_pixel; 183 } 184 EXPORT_SYMBOL(__screen_info_lfb_bits_per_pixel); 185 186 static int __screen_info_lfb_pixel_format(const struct screen_info *si, struct pixel_format *f) 187 { 188 u32 bits_per_pixel = __screen_info_lfb_bits_per_pixel(si); 189 190 if (bits_per_pixel > U8_MAX) 191 return -EINVAL; 192 193 f->bits_per_pixel = bits_per_pixel; 194 195 if (si->lfb_depth > 8) { 196 f->indexed = false; 197 f->alpha.offset = 0; 198 f->alpha.length = 0; 199 f->red.offset = si->red_pos; 200 f->red.length = si->red_size; 201 f->green.offset = si->green_pos; 202 f->green.length = si->green_size; 203 f->blue.offset = si->blue_pos; 204 f->blue.length = si->blue_size; 205 } else { 206 f->indexed = true; 207 f->index.offset = 0; 208 f->index.length = si->lfb_depth; 209 } 210 211 return 0; 212 } 213 214 /** 215 * screen_info_pixel_format - Returns the screen-info format as pixel-format description 216 * 217 * @si: the screen_info 218 * @f: pointer to return pixel-format description 219 * 220 * Returns: 221 * 0 on success, or a negative errno code otherwise. 222 */ 223 int screen_info_pixel_format(const struct screen_info *si, struct pixel_format *f) 224 { 225 unsigned int type = screen_info_video_type(si); 226 227 /* TODO: Add support for additional types as needed. */ 228 switch (type) { 229 case VIDEO_TYPE_VLFB: 230 case VIDEO_TYPE_EFI: 231 return __screen_info_lfb_pixel_format(si, f); 232 } 233 234 /* not supported */ 235 return -EINVAL; 236 } 237 EXPORT_SYMBOL(screen_info_pixel_format); 238