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
20extern "C" void _sPrintf(const char* format, ...);
21#	define TRACE(x) _sPrintf x
22#else
23#	define TRACE(x) ;
24#endif
25
26
27static uint32
28get_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. */
51static bool
52is_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*/
73status_t
74create_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
115uint32
116vesa_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
123status_t
124vesa_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
133status_t
134vesa_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
156status_t
157vesa_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	vesa_mode* modes = gInfo->vesa_modes;
166	for (uint32 i = gInfo->shared_info->vesa_mode_count; i-- > 0;) {
167		// search mode in VESA mode list
168		// TODO: list is ordered, we could use binary search
169		if (modes[i].width == mode.virtual_width
170			&& modes[i].height == mode.virtual_height
171			&& get_color_space_for_depth(modes[i].bits_per_pixel)
172				== mode.space)
173			return ioctl(gInfo->device, VESA_SET_DISPLAY_MODE, &i, sizeof(i));
174	}
175
176	return B_UNSUPPORTED;
177}
178
179
180status_t
181vesa_get_display_mode(display_mode* _currentMode)
182{
183	TRACE(("vesa_get_display_mode()\n"));
184	*_currentMode = gInfo->shared_info->current_mode;
185	return B_OK;
186}
187
188
189status_t
190vesa_get_edid_info(void* info, size_t size, uint32* _version)
191{
192	TRACE(("vesa_get_edid_info()\n"));
193
194	if (!gInfo->shared_info->has_edid)
195		return B_ERROR;
196	if (size < sizeof(struct edid1_info))
197		return B_BUFFER_OVERFLOW;
198
199	memcpy(info, &gInfo->shared_info->edid_info, sizeof(struct edid1_info));
200	*_version = EDID_VERSION_1;
201	return B_OK;
202}
203
204
205status_t
206vesa_get_frame_buffer_config(frame_buffer_config* config)
207{
208	TRACE(("vesa_get_frame_buffer_config()\n"));
209
210	config->frame_buffer = gInfo->shared_info->frame_buffer;
211	config->frame_buffer_dma = gInfo->shared_info->physical_frame_buffer;
212	config->bytes_per_row = gInfo->shared_info->bytes_per_row;
213
214	return B_OK;
215}
216
217
218status_t
219vesa_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high)
220{
221	TRACE(("vesa_get_pixel_clock_limits()\n"));
222
223	// TODO: do some real stuff here (taken from radeon driver)
224	uint32 totalPixel = (uint32)mode->timing.h_total
225		* (uint32)mode->timing.v_total;
226	uint32 clockLimit = 2000000;
227
228	// lower limit of about 48Hz vertical refresh
229	*_low = totalPixel * 48L / 1000L;
230	if (*_low > clockLimit)
231		return B_ERROR;
232
233	*_high = clockLimit;
234	return B_OK;
235}
236
237
238status_t
239vesa_move_display(uint16 h_display_start, uint16 v_display_start)
240{
241	TRACE(("vesa_move_display()\n"));
242	return B_ERROR;
243}
244
245
246status_t
247vesa_get_timing_constraints(display_timing_constraints* constraints)
248{
249	TRACE(("vesa_get_timing_constraints()\n"));
250	return B_ERROR;
251}
252
253
254void
255vesa_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags)
256{
257	TRACE(("vesa_set_indexed_colors()\n"));
258
259	vesa_set_indexed_colors_args args;
260	args.first = first;
261	args.count = count;
262	args.colors = colors;
263	ioctl(gInfo->device, VESA_SET_INDEXED_COLORS, &args, sizeof(args));
264}
265
266