diff options
Diffstat (limited to 'drivers/video/screen_info_generic.c')
| -rw-r--r-- | drivers/video/screen_info_generic.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/drivers/video/screen_info_generic.c b/drivers/video/screen_info_generic.c index 64117c6367ab..763adbba71cb 100644 --- a/drivers/video/screen_info_generic.c +++ b/drivers/video/screen_info_generic.c @@ -5,6 +5,8 @@ #include <linux/screen_info.h> #include <linux/string.h> +#include <video/pixel_format.h> + static void resource_init_named(struct resource *r, resource_size_t start, resource_size_t size, const char *name, unsigned int flags) @@ -144,3 +146,92 @@ ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, return pos - r; } EXPORT_SYMBOL(screen_info_resources); + +/* + * The meaning of depth and bpp for direct-color formats is + * inconsistent: + * + * - DRM format info specifies depth as the number of color + * bits; including alpha, but not including filler bits. + * - Linux' EFI platform code computes lfb_depth from the + * individual color channels, including the reserved bits. + * - VBE 1.1 defines lfb_depth for XRGB1555 as 16, but later + * versions use 15. + * - On the kernel command line, 'bpp' of 32 is usually + * XRGB8888 including the filler bits, but 15 is XRGB1555 + * not including the filler bit. + * + * It is not easily possible to fix this in struct screen_info, + * as this could break UAPI. The best solution is to compute + * bits_per_pixel from the color bits, reserved bits and + * reported lfb_depth, whichever is highest. + */ + +u32 __screen_info_lfb_bits_per_pixel(const struct screen_info *si) +{ + u32 bits_per_pixel = si->lfb_depth; + + if (bits_per_pixel > 8) { + bits_per_pixel = max(max3(si->red_size + si->red_pos, + si->green_size + si->green_pos, + si->blue_size + si->blue_pos), + si->rsvd_size + si->rsvd_pos); + bits_per_pixel = max_t(u32, bits_per_pixel, si->lfb_depth); + } + + return bits_per_pixel; +} +EXPORT_SYMBOL(__screen_info_lfb_bits_per_pixel); + +static int __screen_info_lfb_pixel_format(const struct screen_info *si, struct pixel_format *f) +{ + u32 bits_per_pixel = __screen_info_lfb_bits_per_pixel(si); + + if (bits_per_pixel > U8_MAX) + return -EINVAL; + + f->bits_per_pixel = bits_per_pixel; + + if (si->lfb_depth > 8) { + f->indexed = false; + f->alpha.offset = 0; + f->alpha.length = 0; + f->red.offset = si->red_pos; + f->red.length = si->red_size; + f->green.offset = si->green_pos; + f->green.length = si->green_size; + f->blue.offset = si->blue_pos; + f->blue.length = si->blue_size; + } else { + f->indexed = true; + f->index.offset = 0; + f->index.length = si->lfb_depth; + } + + return 0; +} + +/** + * screen_info_pixel_format - Returns the screen-info format as pixel-format description + * + * @si: the screen_info + * @f: pointer to return pixel-format description + * + * Returns: + * 0 on success, or a negative errno code otherwise. + */ +int screen_info_pixel_format(const struct screen_info *si, struct pixel_format *f) +{ + unsigned int type = screen_info_video_type(si); + + /* TODO: Add support for additional types as needed. */ + switch (type) { + case VIDEO_TYPE_VLFB: + case VIDEO_TYPE_EFI: + return __screen_info_lfb_pixel_format(si, f); + } + + /* not supported */ + return -EINVAL; +} +EXPORT_SYMBOL(screen_info_pixel_format); |
