summaryrefslogtreecommitdiffstats
path: root/drivers/video/screen_info_generic.c
blob: 64117c6367abbeff11065e40b9ce20c5f9f707e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// SPDX-License-Identifier: GPL-2.0

#include <linux/export.h>
#include <linux/ioport.h>
#include <linux/screen_info.h>
#include <linux/string.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:	/* 320x200-4 */
	case 0x0e:	/* 640x200-4 */
	case 0x0f:	/* 640x350-1 */
	case 0x10:	/* 640x350-4 */
		return true;
	default:
		return false;
	}
}

static inline bool __screen_info_has_vga_gfx(unsigned int mode)
{
	switch (mode) {
	case 0x10:	/* 640x480-1 */
	case 0x12:	/* 640x480-4 */
	case 0x13:	/* 320-200-8 */
	case 0x6a:	/* 800x600-4 (VESA) */
		return true;
	default:
		return __screen_info_has_ega_gfx(mode);
	}
}

/**
 * screen_info_resources() - Get resources from screen_info structure
 * @si: the screen_info
 * @r: pointer to an array of resource structures
 * @num: number of elements in @r:
 *
 * Returns:
 * The number of resources stored in @r on success, or a negative errno code otherwise.
 *
 * A call to screen_info_resources() returns the resources consumed by the
 * screen_info's device or framebuffer. The result is stored in the caller-supplied
 * array @r with up to @num elements. The function returns the number of
 * initialized elements.
 */
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:
		/* not supported */
		return -EINVAL;
	}

	return pos - r;
}
EXPORT_SYMBOL(screen_info_resources);