xref: /haiku/src/add-ons/accelerants/vesa/mode.cpp (revision a3e794ae459fec76826407f8ba8c94cd3535f128)
1 /*
2  * Copyright 2005-2015, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <stdlib.h>
8 #include <string.h>
9 
10 #include <compute_display_timing.h>
11 #include <create_display_modes.h>
12 
13 #include "accelerant_protos.h"
14 #include "accelerant.h"
15 #include "utility.h"
16 
17 
18 //#define TRACE_MODE
19 #ifdef TRACE_MODE
20 extern "C" void _sPrintf(const char* format, ...);
21 #	define TRACE(x) _sPrintf x
22 #else
23 #	define TRACE(x) ;
24 #endif
25 
26 
27 static uint32
28 get_color_space_for_depth(uint32 depth)
29 {
30 	switch (depth) {
31 		case 4:
32 			return B_GRAY8;
33 				// the app_server is smart enough to translate this to VGA mode
34 		case 8:
35 			return B_CMAP8;
36 		case 15:
37 			return B_RGB15;
38 		case 16:
39 			return B_RGB16;
40 		case 24:
41 			return B_RGB24;
42 		case 32:
43 			return B_RGB32;
44 	}
45 
46 	return 0;
47 }
48 
49 
50 /*!	Checks if the specified \a mode can be set using VESA. */
51 static bool
52 is_mode_supported(display_mode* mode)
53 {
54 	vesa_mode* modes = gInfo->vesa_modes;
55 
56 	for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) {
57 		// search mode in VESA mode list
58 		// TODO: list is ordered, we could use binary search
59 		if (modes[i].width == mode->virtual_width
60 			&& modes[i].height == mode->virtual_height
61 			&& get_color_space_for_depth(modes[i].bits_per_pixel)
62 				== mode->space)
63 			return true;
64 	}
65 
66 	return false;
67 }
68 
69 
70 /*!	Creates the initial mode list of the primary accelerant.
71 	It's called from vesa_init_accelerant().
72 */
73 status_t
74 create_mode_list(void)
75 {
76 	const color_space kVesaSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
77 		B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
78 
79 	uint32 initialModesCount = 0;
80 
81 	// Add initial VESA modes.
82 	display_mode* initialModes = (display_mode*)malloc(
83 		sizeof(display_mode) * gInfo->shared_info->vesa_mode_count);
84 	if (initialModes != NULL) {
85 		initialModesCount = gInfo->shared_info->vesa_mode_count;
86 		vesa_mode* vesaModes = gInfo->vesa_modes;
87 
88 		for (uint32 i = 0; i < initialModesCount; i++) {
89 			compute_display_timing(vesaModes[i].width, vesaModes[i].height,
90 				60, false, &initialModes[i].timing);
91 			fill_display_mode(vesaModes[i].width, vesaModes[i].height,
92 				&initialModes[i]);
93 		}
94 	}
95 
96 	gInfo->mode_list_area = create_display_modes("vesa modes",
97 		gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL,
98 		initialModes, initialModesCount,
99 		kVesaSpaces, sizeof(kVesaSpaces) / sizeof(kVesaSpaces[0]),
100 		is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count);
101 
102 	free(initialModes);
103 
104 	if (gInfo->mode_list_area < 0)
105 		return gInfo->mode_list_area;
106 
107 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
108 	return B_OK;
109 }
110 
111 
112 //	#pragma mark -
113 
114 
115 uint32
116 vesa_accelerant_mode_count(void)
117 {
118 	TRACE(("vesa_accelerant_mode_count() = %d\n", gInfo->shared_info->mode_count));
119 	return gInfo->shared_info->mode_count;
120 }
121 
122 
123 status_t
124 vesa_get_mode_list(display_mode* modeList)
125 {
126 	TRACE(("vesa_get_mode_info()\n"));
127 	memcpy(modeList, gInfo->mode_list,
128 		gInfo->shared_info->mode_count * sizeof(display_mode));
129 	return B_OK;
130 }
131 
132 
133 status_t
134 vesa_propose_display_mode(display_mode* target, const display_mode* low,
135 	const display_mode* high)
136 {
137 	TRACE(("vesa_propose_display_mode()\n"));
138 
139 	// just search for the specified mode in the list
140 
141 	for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) {
142 		display_mode* current = &gInfo->mode_list[i];
143 
144 		if (target->virtual_width != current->virtual_width
145 			|| target->virtual_height != current->virtual_height
146 			|| target->space != current->space)
147 			continue;
148 
149 		*target = *current;
150 		return B_OK;
151 	}
152 	return B_BAD_VALUE;
153 }
154 
155 
156 status_t
157 vesa_set_display_mode(display_mode* _mode)
158 {
159 	TRACE(("vesa_set_display_mode()\n"));
160 
161 	display_mode mode = *_mode;
162 	if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK)
163 		return B_BAD_VALUE;
164 
165 	if (gInfo->shared_info->current_mode.virtual_width == mode.virtual_width
166 		&& gInfo->shared_info->current_mode.virtual_height
167 			== mode.virtual_height
168 		&& gInfo->shared_info->current_mode.space == mode.space) {
169 		return B_OK;
170 	}
171 
172 	vesa_mode* modes = gInfo->vesa_modes;
173 	for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) {
174 		// search mode in VESA mode list
175 		// TODO: list is ordered, we could use binary search
176 		if (modes[i].width == mode.virtual_width
177 			&& modes[i].height == mode.virtual_height
178 			&& get_color_space_for_depth(modes[i].bits_per_pixel)
179 				== mode.space) {
180 			return ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i));
181 		}
182 	}
183 
184 	return B_UNSUPPORTED;
185 }
186 
187 
188 status_t
189 vesa_get_display_mode(display_mode* _currentMode)
190 {
191 	TRACE(("vesa_get_display_mode()\n"));
192 	*_currentMode = gInfo->shared_info->current_mode;
193 	return B_OK;
194 }
195 
196 
197 status_t
198 vesa_get_edid_info(void* info, size_t size, uint32* _version)
199 {
200 	TRACE(("vesa_get_edid_info()\n"));
201 
202 	if (!gInfo->shared_info->has_edid)
203 		return B_ERROR;
204 	if (size < sizeof(struct edid1_info))
205 		return B_BUFFER_OVERFLOW;
206 
207 	memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
208 	*_version = EDID_VERSION_1;
209 	return B_OK;
210 }
211 
212 
213 status_t
214 vesa_get_frame_buffer_config(frame_buffer_config* config)
215 {
216 	TRACE(("vesa_get_frame_buffer_config()\n"));
217 
218 	config->frame_buffer = gInfo->shared_info->frame_buffer;
219 	config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer;
220 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
221 
222 	return B_OK;
223 }
224 
225 
226 status_t
227 vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high)
228 {
229 	TRACE(("vesa_get_pixel_clock_limits()\n"));
230 
231 	// TODO: do some real stuff here (taken from radeon driver)
232 	uint32 totalPixel = (uint32)mode->timing.h_total
233 		* (uint32)mode->timing.v_total;
234 	uint32 clockLimit = 2000000;
235 
236 	// lower limit of about 48Hz vertical refresh
237 	*_low = totalPixel * 48L / 1000L;
238 	if (*_low > clockLimit)
239 		return B_ERROR;
240 
241 	*_high = clockLimit;
242 	return B_OK;
243 }
244 
245 
246 status_t
247 vesa_move_display(uint16 h_display_start, uint16 v_display_start)
248 {
249 	TRACE(("vesa_move_display()\n"));
250 	return B_ERROR;
251 }
252 
253 
254 status_t
255 vesa_get_timing_constraints(display_timing_constraints* constraints)
256 {
257 	TRACE(("vesa_get_timing_constraints()\n"));
258 	return B_ERROR;
259 }
260 
261 
262 void
263 vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags)
264 {
265 	TRACE(("vesa_set_indexed_colors()\n"));
266 
267 	vesa_set_indexed_colors_args args;
268 	args.first = first;
269 	args.count = count;
270 	args.colors = colors;
271 	ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args));
272 }
273 
274