xref: /haiku/src/add-ons/accelerants/vesa/mode.cpp (revision 6cb28af8fdade41425f3c9c21dcb9d3a23bc8775)
1 /*
2  * Copyright 2005-2011, 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 	// Create the initial list from the support mode list - but only if we don't
80 	// have EDID info available, as that should be good enough.
81 	display_mode* initialModes = NULL;
82 	uint32 initialModesCount = 0;
83 	if (!gInfo->shared_info->has_edid) {
84 		initialModes = (display_mode*)malloc(
85 			sizeof(display_mode) * gInfo->shared_info->vesa_mode_count);
86 		if (initialModes != NULL) {
87 			initialModesCount = gInfo->shared_info->vesa_mode_count;
88 			vesa_mode* vesaModes = gInfo->vesa_modes;
89 
90 			for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) {
91 				compute_display_timing(vesaModes[i].width, vesaModes[i].height,
92 					60, false, &initialModes[i].timing);
93 				fill_display_mode(vesaModes[i].width, vesaModes[i].height,
94 					&initialModes[i]);
95 			}
96 		}
97 	}
98 
99 	gInfo->mode_list_area = create_display_modes("vesa modes",
100 		gInfo->shared_info->has_edid ? &gInfo->shared_info->edid_info : NULL,
101 		initialModes, initialModesCount,
102 		kVesaSpaces, sizeof(kVesaSpaces) / sizeof(kVesaSpaces[0]),
103 		is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count);
104 
105 	free(initialModes);
106 
107 	if (gInfo->mode_list_area < 0)
108 		return gInfo->mode_list_area;
109 
110 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
111 	return B_OK;
112 }
113 
114 
115 //	#pragma mark -
116 
117 
118 uint32
119 vesa_accelerant_mode_count(void)
120 {
121 	TRACE(("vesa_accelerant_mode_count()\n"));
122 	return gInfo->shared_info->mode_count;
123 }
124 
125 
126 status_t
127 vesa_get_mode_list(display_mode* modeList)
128 {
129 	TRACE(("vesa_get_mode_info()\n"));
130 	memcpy(modeList, gInfo->mode_list,
131 		gInfo->shared_info->mode_count * sizeof(display_mode));
132 	return B_OK;
133 }
134 
135 
136 status_t
137 vesa_propose_display_mode(display_mode* target, const display_mode* low,
138 	const display_mode* high)
139 {
140 	TRACE(("vesa_propose_display_mode()\n"));
141 
142 	// just search for the specified mode in the list
143 
144 	for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) {
145 		display_mode* current = &gInfo->mode_list[i];
146 
147 		if (target->virtual_width != current->virtual_width
148 			|| target->virtual_height != current->virtual_height
149 			|| target->space != current->space)
150 			continue;
151 
152 		*target = *current;
153 		return B_OK;
154 	}
155 	return B_BAD_VALUE;
156 }
157 
158 
159 status_t
160 vesa_set_display_mode(display_mode* _mode)
161 {
162 	TRACE(("vesa_set_display_mode()\n"));
163 
164 	display_mode mode = *_mode;
165 	if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK)
166 		return B_BAD_VALUE;
167 
168 	vesa_mode* modes = gInfo->vesa_modes;
169 	for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) {
170 		// search mode in VESA mode list
171 		// TODO: list is ordered, we could use binary search
172 		if (modes[i].width == mode.virtual_width
173 			&& modes[i].height == mode.virtual_height
174 			&& get_color_space_for_depth(modes[i].bits_per_pixel)
175 				== mode.space)
176 			return ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i));
177 	}
178 
179 	return B_UNSUPPORTED;
180 }
181 
182 
183 status_t
184 vesa_get_display_mode(display_mode* _currentMode)
185 {
186 	TRACE(("vesa_get_display_mode()\n"));
187 	*_currentMode = gInfo->shared_info->current_mode;
188 	return B_OK;
189 }
190 
191 
192 status_t
193 vesa_get_edid_info(void* info, size_t size, uint32* _version)
194 {
195 	TRACE(("intel_get_edid_info()\n"));
196 
197 	if (!gInfo->shared_info->has_edid)
198 		return B_ERROR;
199 	if (size < sizeof(struct edid1_info))
200 		return B_BUFFER_OVERFLOW;
201 
202 	memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
203 	*_version = EDID_VERSION_1;
204 	return B_OK;
205 }
206 
207 
208 status_t
209 vesa_get_frame_buffer_config(frame_buffer_config* config)
210 {
211 	TRACE(("vesa_get_frame_buffer_config()\n"));
212 
213 	config->frame_buffer = gInfo->shared_info->frame_buffer;
214 	config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer;
215 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
216 
217 	return B_OK;
218 }
219 
220 
221 status_t
222 vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high)
223 {
224 	TRACE(("vesa_get_pixel_clock_limits()\n"));
225 
226 	// TODO: do some real stuff here (taken from radeon driver)
227 	uint32 totalPixel = (uint32)mode->timing.h_total
228 		* (uint32)mode->timing.v_total;
229 	uint32 clockLimit = 2000000;
230 
231 	// lower limit of about 48Hz vertical refresh
232 	*_low = totalPixel * 48L / 1000L;
233 	if (*_low > clockLimit)
234 		return B_ERROR;
235 
236 	*_high = clockLimit;
237 	return B_OK;
238 }
239 
240 
241 status_t
242 vesa_move_display(uint16 h_display_start, uint16 v_display_start)
243 {
244 	TRACE(("vesa_move_display()\n"));
245 	return B_ERROR;
246 }
247 
248 
249 status_t
250 vesa_get_timing_constraints(display_timing_constraints* constraints)
251 {
252 	TRACE(("vesa_get_timing_constraints()\n"));
253 	return B_ERROR;
254 }
255 
256 
257 void
258 vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags)
259 {
260 	TRACE(("vesa_set_indexed_colors()\n"));
261 
262 	vesa_set_indexed_colors_args args;
263 	args.first = first;
264 	args.count = count;
265 	args.colors = colors;
266 	ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args));
267 }
268 
269