#include <linux/export.h>
#include <linux/ioport.h>
#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)
{
memset(r, 0, sizeof(*r));
r->start = start;
r->end = start + size - 1;
r->name = name;
r->flags = flags;
}
static void resource_init_io_named(struct resource *r,
resource_size_t start, resource_size_t size,
const char *name)
{
resource_init_named(r, start, size, name, IORESOURCE_IO);
}
static void resource_init_mem_named(struct resource *r,
resource_size_t start, resource_size_t size,
const char *name)
{
resource_init_named(r, start, size, name, IORESOURCE_MEM);
}
static inline bool __screen_info_has_ega_gfx(unsigned int mode)
{
switch (mode) {
case 0x0d:
case 0x0e:
case 0x0f:
case 0x10:
return true;
default:
return false;
}
}
static inline bool __screen_info_has_vga_gfx(unsigned int mode)
{
switch (mode) {
case 0x10:
case 0x12:
case 0x13:
case 0x6a:
return true;
default:
return __screen_info_has_ega_gfx(mode);
}
}
ssize_t screen_info_resources(const struct screen_info *si, struct resource *r, size_t num)
{
struct resource *pos = r;
unsigned int type = screen_info_video_type(si);
u64 base, size;
switch (type) {
case VIDEO_TYPE_MDA:
if (num > 0)
resource_init_io_named(pos++, 0x3b0, 12, "mda");
if (num > 1)
resource_init_io_named(pos++, 0x3bf, 0x01, "mda");
if (num > 2)
resource_init_mem_named(pos++, 0xb0000, 0x2000, "mda");
break;
case VIDEO_TYPE_CGA:
if (num > 0)
resource_init_io_named(pos++, 0x3d4, 0x02, "cga");
if (num > 1)
resource_init_mem_named(pos++, 0xb8000, 0x2000, "cga");
break;
case VIDEO_TYPE_EGAM:
if (num > 0)
resource_init_io_named(pos++, 0x3bf, 0x10, "ega");
if (num > 1)
resource_init_mem_named(pos++, 0xb0000, 0x8000, "ega");
break;
case VIDEO_TYPE_EGAC:
if (num > 0)
resource_init_io_named(pos++, 0x3c0, 0x20, "ega");
if (num > 1) {
if (__screen_info_has_ega_gfx(si->orig_video_mode))
resource_init_mem_named(pos++, 0xa0000, 0x10000, "ega");
else
resource_init_mem_named(pos++, 0xb8000, 0x8000, "ega");
}
break;
case VIDEO_TYPE_VGAC:
if (num > 0)
resource_init_io_named(pos++, 0x3c0, 0x20, "vga+");
if (num > 1) {
if (__screen_info_has_vga_gfx(si->orig_video_mode))
resource_init_mem_named(pos++, 0xa0000, 0x10000, "vga+");
else
resource_init_mem_named(pos++, 0xb8000, 0x8000, "vga+");
}
break;
case VIDEO_TYPE_VLFB:
case VIDEO_TYPE_EFI:
base = __screen_info_lfb_base(si);
if (!base)
break;
size = __screen_info_lfb_size(si, type);
if (!size)
break;
if (num > 0)
resource_init_mem_named(pos++, base, size, "lfb");
break;
case VIDEO_TYPE_PICA_S3:
case VIDEO_TYPE_MIPS_G364:
case VIDEO_TYPE_SGI:
case VIDEO_TYPE_TGAC:
case VIDEO_TYPE_SUN:
case VIDEO_TYPE_SUNPCI:
case VIDEO_TYPE_PMAC:
default:
return -EINVAL;
}
return pos - r;
}
EXPORT_SYMBOL(screen_info_resources);
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;
}
int screen_info_pixel_format(const struct screen_info *si, struct pixel_format *f)
{
unsigned int type = screen_info_video_type(si);
switch (type) {
case VIDEO_TYPE_VLFB:
case VIDEO_TYPE_EFI:
return __screen_info_lfb_pixel_format(si, f);
}
return -EINVAL;
}
EXPORT_SYMBOL(screen_info_pixel_format);