1/*
2	Copyright (c) 2002, Thomas Kurschel
3
4	Part of Radeon driver
5	Multi-Monitor Settings interface
6*/
7
8
9#include "multimon.h"
10#include "accelerant_ext.h"
11
12#include <OS.h>
13#include <Screen.h>
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19
20// prepare parameters so they recognized as tunneled settings
21static void
22PrepareTunnel(display_mode *mode, display_mode *low, display_mode *high)
23{
24	memset(mode, 0, sizeof(*mode));
25
26	// mark modes as settings tunnel
27	mode->space = low->space = high->space = 0;
28	low->virtual_width = 0xffff;
29	low->virtual_height = 0xffff;
30	high->virtual_width = 0;
31	high->virtual_height = 0;
32	mode->timing.pixel_clock = 0;
33	low->timing.pixel_clock = 'TKTK';
34	high->timing.pixel_clock = 'KTKT';
35}
36
37
38// retrieve value of setting "code"
39static status_t
40GetSetting(BScreen *screen, uint16 code, uint32 *setting)
41{
42	display_mode mode, low, high;
43	status_t result;
44
45	result = TestMultiMonSupport(screen);
46	if (result != B_OK)
47		return result;
48
49	PrepareTunnel(&mode, &low, &high);
50
51	mode.h_display_start = code;
52	mode.v_display_start = 0;
53
54	result = screen->ProposeMode(&mode, &low, &high);
55	if (result != B_OK)
56		return result;
57
58	*setting = mode.timing.flags;
59
60	return B_OK;
61}
62
63
64// set setting "code" to "value"
65static status_t
66SetSetting(BScreen *screen, uint16 code, uint32 value)
67{
68	display_mode mode, low, high;
69	status_t result;
70
71	result = TestMultiMonSupport(screen);
72	if (result != B_OK)
73		return result;
74
75	PrepareTunnel(&mode, &low, &high);
76
77	mode.h_display_start = code;
78	mode.v_display_start = 1;
79	mode.timing.flags = value;
80
81	return screen->ProposeMode(&mode, &low, &high);
82}
83
84
85// retrieve n-th supported value of setting "code"
86static status_t
87GetNthSupportedSetting(BScreen *screen, uint16 code, int32 idx,
88	uint32 *setting)
89{
90	display_mode mode, low, high;
91	status_t result;
92
93	result = TestMultiMonSupport(screen);
94	if (result != B_OK)
95		return result;
96
97	PrepareTunnel(&mode, &low, &high);
98
99	mode.h_display_start = code;
100	mode.v_display_start = 2;
101	mode.timing.flags = idx;
102
103	result = screen->ProposeMode(&mode, &low, &high);
104	if (result != B_OK)
105		return result;
106
107	*setting = mode.timing.flags;
108
109	return B_OK;
110}
111
112
113// get current Swap Displays settings
114status_t
115GetSwapDisplays(BScreen *screen, bool *swap)
116{
117	status_t result;
118	uint32 tmp;
119
120	result = GetSetting(screen, ms_swap, &tmp);
121	if (result != B_OK)
122		return result;
123
124	*swap = tmp != 0;
125
126	return B_OK;
127}
128
129
130// set "Swap Displays"
131status_t
132SetSwapDisplays(BScreen *screen, bool swap)
133{
134	return SetSetting(screen, ms_swap, swap);
135}
136
137
138// get current "Use Laptop Panel" settings
139status_t
140GetUseLaptopPanel(BScreen *screen, bool *use)
141{
142	status_t result;
143	uint32 tmp;
144
145	result = GetSetting(screen, ms_use_laptop_panel, &tmp);
146	if (result != B_OK)
147		return result;
148
149	*use = tmp != 0;
150	return B_OK;
151}
152
153
154// set "Use Laptop Panel"
155status_t
156SetUseLaptopPanel(BScreen *screen, bool use)
157{
158	return SetSetting(screen, ms_use_laptop_panel, use);
159}
160
161
162// get n-th supported TV standard
163status_t
164GetNthSupportedTVStandard(BScreen *screen, int idx, uint32 *standard)
165{
166	return GetNthSupportedSetting(
167		screen, ms_tv_standard, (int32)idx, standard);
168}
169
170
171// get current TV Standard settings
172status_t
173GetTVStandard(BScreen *screen, uint32 *standard)
174{
175	return GetSetting(screen, ms_tv_standard, standard);
176}
177
178
179// set TV Standard
180status_t
181SetTVStandard(BScreen *screen, uint32 standard)
182{
183	return SetSetting(screen, ms_tv_standard, standard);
184}
185
186
187// Verify existence of Multi-Monitor Settings Tunnel
188status_t
189TestMultiMonSupport(BScreen *screen)
190{
191	display_mode *modeList = NULL;
192	display_mode low, high;
193	uint32 count;
194	status_t result;
195
196	// take any valid mode
197	result = screen->GetModeList(&modeList, &count);
198	if (result != B_OK)
199		return result;
200
201	if (count < 1)
202		return B_ERROR;
203
204	// set request bits
205	modeList[0].timing.flags |= RADEON_MODE_MULTIMON_REQUEST;
206	modeList[0].timing.flags &= ~RADEON_MODE_MULTIMON_REPLY;
207	low = high = modeList[0];
208
209	result = screen->ProposeMode(&modeList[0], &low, &high);
210	if (result != B_OK)
211		goto out;
212
213	// check reply bits
214	if ((modeList[0].timing.flags & RADEON_MODE_MULTIMON_REQUEST) == 0
215		&& (modeList[0].timing.flags & RADEON_MODE_MULTIMON_REPLY) != 0)
216		result = B_OK;
217	else
218		result = B_ERROR;
219
220out:
221	free(modeList);
222	return result;
223}
224