xref: /haiku/src/add-ons/accelerants/vesa/mode.cpp (revision cfc3fa87da824bdf593eb8b817a83b6376e77935)
1 /*
2  * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include <string.h>
7 
8 #include <create_display_modes.h>
9 
10 #include "accelerant_protos.h"
11 #include "accelerant.h"
12 #include "utility.h"
13 
14 
15 //#define TRACE_MODE
16 #ifdef TRACE_MODE
17 extern "C" void _sPrintf(const char *format, ...);
18 #	define TRACE(x) _sPrintf x
19 #else
20 #	define TRACE(x) ;
21 #endif
22 
23 
24 static uint32
25 get_color_space_for_depth(uint32 depth)
26 {
27 	switch (depth) {
28 		case 4:
29 			return B_GRAY8;
30 				// the app_server is smart enough to translate this to VGA mode
31 		case 8:
32 			return B_CMAP8;
33 		case 15:
34 			return B_RGB15;
35 		case 16:
36 			return B_RGB16;
37 		case 24:
38 			return B_RGB24;
39 		case 32:
40 			return B_RGB32;
41 	}
42 
43 	return 0;
44 }
45 
46 
47 /*!	Checks if the specified \a mode can be set using VESA. */
48 static bool
49 is_mode_supported(display_mode *mode)
50 {
51 	vesa_mode *modes = gInfo->vesa_modes;
52 
53 	for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) {
54 		// search mode in VESA mode list
55 		// TODO: list is ordered, we could use binary search
56 		if (modes[i].width == mode->virtual_width
57 			&& modes[i].height == mode->virtual_height
58 			&& get_color_space_for_depth(modes[i].bits_per_pixel)
59 				== mode->space)
60 			return true;
61 	}
62 
63 	return false;
64 }
65 
66 
67 /*!	Creates the initial mode list of the primary accelerant.
68 	It's called from vesa_init_accelerant().
69 */
70 status_t
71 create_mode_list(void)
72 {
73 	const color_space kVesaSpaces[] = {B_RGB32_LITTLE, B_RGB24_LITTLE,
74 		B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
75 
76 	gInfo->mode_list_area = create_display_modes("vesa modes", NULL, NULL, 0,
77 		kVesaSpaces, sizeof(kVesaSpaces) / sizeof(kVesaSpaces[0]),
78 		is_mode_supported, &gInfo->mode_list, &gInfo->shared_info->mode_count);
79 	if (gInfo->mode_list_area < B_OK)
80 		return gInfo->mode_list_area;
81 
82 	gInfo->shared_info->mode_list_area = gInfo->mode_list_area;
83 	return B_OK;
84 }
85 
86 
87 //	#pragma mark -
88 
89 
90 uint32
91 vesa_accelerant_mode_count(void)
92 {
93 	TRACE(("vesa_accelerant_mode_count()\n"));
94 	return gInfo->shared_info->mode_count;
95 }
96 
97 
98 status_t
99 vesa_get_mode_list(display_mode *modeList)
100 {
101 	TRACE(("vesa_get_mode_info()\n"));
102 	memcpy(modeList, gInfo->mode_list,
103 		gInfo->shared_info->mode_count * sizeof(display_mode));
104 	return B_OK;
105 }
106 
107 
108 status_t
109 vesa_propose_display_mode(display_mode *target, const display_mode *low,
110 	const display_mode *high)
111 {
112 	TRACE(("vesa_propose_display_mode()\n"));
113 
114 	// just search for the specified mode in the list
115 
116 	for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) {
117 		display_mode *current = &gInfo->mode_list[i];
118 
119 		if (target->virtual_width != current->virtual_width
120 			|| target->virtual_height != current->virtual_height
121 			|| target->space != current->space)
122 			continue;
123 
124 		*target = *current;
125 		return B_OK;
126 	}
127 	return B_BAD_VALUE;
128 }
129 
130 
131 status_t
132 vesa_set_display_mode(display_mode *_mode)
133 {
134 	TRACE(("vesa_set_display_mode()\n"));
135 
136 	display_mode mode = *_mode;
137 	if (vesa_propose_display_mode(&mode, &mode, &mode) != B_OK)
138 		return B_BAD_VALUE;
139 
140 	// ToDo: unless we have a VBE3 device, we can't change the display mode
141 	return B_UNSUPPORTED;
142 }
143 
144 
145 status_t
146 vesa_get_display_mode(display_mode *_currentMode)
147 {
148 	TRACE(("vesa_get_display_mode()\n"));
149 	*_currentMode = gInfo->shared_info->current_mode;
150 	return B_OK;
151 }
152 
153 
154 status_t
155 vesa_get_frame_buffer_config(frame_buffer_config *config)
156 {
157 	TRACE(("vesa_get_frame_buffer_config()\n"));
158 
159 	config->frame_buffer = gInfo->shared_info->frame_buffer;
160 	config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer;
161 	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
162 
163 	return B_OK;
164 }
165 
166 
167 status_t
168 vesa_get_pixel_clock_limits(display_mode *mode, uint32 *low, uint32 *high)
169 {
170 	TRACE(("vesa_get_pixel_clock_limits()\n"));
171 
172 	// ToDo: do some real stuff here (taken from radeon driver)
173 	uint32 total_pix = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total;
174 	uint32 clock_limit = 2000000;
175 
176 	/* lower limit of about 48Hz vertical refresh */
177 	*low = (total_pix * 48L) / 1000L;
178 	if (*low > clock_limit)
179 		return B_ERROR;
180 
181 	*high = clock_limit;
182 	return B_OK;
183 }
184 
185 
186 status_t
187 vesa_move_display(uint16 h_display_start, uint16 v_display_start)
188 {
189 	TRACE(("vesa_move_display()\n"));
190 	return B_ERROR;
191 }
192 
193 
194 status_t
195 vesa_get_timing_constraints(display_timing_constraints *dtc)
196 {
197 	TRACE(("vesa_get_timing_constraints()\n"));
198 	return B_ERROR;
199 }
200 
201 
202 void
203 vesa_set_indexed_colors(uint count, uint8 first, uint8 *colors, uint32 flags)
204 {
205 	TRACE(("vesa_set_indexed_colors()\n"));
206 	vga_set_indexed_colors_args args;
207 	args.first = first;
208 	args.count = count;
209 	args.colors = colors;
210 	ioctl(gInfo->device, VGA_SET_INDEXED_COLORS, &args, sizeof(args));
211 }
212 
213