xref: /haiku/src/add-ons/accelerants/intel_extreme/accelerant.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 /*
2  * Copyright 2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "accelerant_protos.h"
11 #include "accelerant.h"
12 
13 #include "utility.h"
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <syslog.h>
19 
20 
21 #define TRACE_ACCELERANT
22 #ifdef TRACE_ACCELERANT
23 extern "C" void _sPrintf(const char *format, ...);
24 #	define TRACE(x) _sPrintf x
25 #else
26 #	define TRACE(x) ;
27 #endif
28 
29 
30 struct accelerant_info *gInfo;
31 
32 
33 class AreaCloner {
34 	public:
35 		AreaCloner();
36 		~AreaCloner();
37 
38 		area_id Clone(const char *name, void **_address, uint32 spec,
39 					uint32 protection, area_id sourceArea);
40 		status_t InitCheck() { return fArea < B_OK ? (status_t)fArea : B_OK; }
41 		void Keep();
42 
43 	private:
44 		area_id	fArea;
45 };
46 
47 
48 AreaCloner::AreaCloner()
49 	:
50 	fArea(-1)
51 {
52 }
53 
54 
55 AreaCloner::~AreaCloner()
56 {
57 	if (fArea >= B_OK)
58 		delete_area(fArea);
59 }
60 
61 
62 area_id
63 AreaCloner::Clone(const char *name, void **_address, uint32 spec,
64 	uint32 protection, area_id sourceArea)
65 {
66 	fArea = clone_area(name, _address, spec, protection, sourceArea);
67 	return fArea;
68 }
69 
70 
71 void
72 AreaCloner::Keep()
73 {
74 	fArea = -1;
75 }
76 
77 
78 //	#pragma mark -
79 
80 
81 /** This is the common accelerant_info initializer. It is called by
82  *	both, the first accelerant and all clones.
83  */
84 
85 static status_t
86 init_common(int device, bool isClone)
87 {
88 	// initialize global accelerant info structure
89 
90 	gInfo = (accelerant_info *)malloc(sizeof(accelerant_info));
91 	if (gInfo == NULL)
92 		return B_NO_MEMORY;
93 
94 	memset(gInfo, 0, sizeof(accelerant_info));
95 
96 	gInfo->is_clone = isClone;
97 	gInfo->device = device;
98 
99 	// get basic info from driver
100 
101 	intel_get_private_data data;
102 	data.magic = INTEL_PRIVATE_DATA_MAGIC;
103 
104 	if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data, sizeof(intel_get_private_data)) != 0) {
105 		free(gInfo);
106 		return B_ERROR;
107 	}
108 
109 	AreaCloner sharedCloner;
110 	gInfo->shared_info_area = sharedCloner.Clone("intel extreme shared info",
111 								(void **)&gInfo->shared_info, B_ANY_ADDRESS,
112 								B_READ_AREA | B_WRITE_AREA,
113 								data.shared_info_area);
114 	status_t status = sharedCloner.InitCheck();
115 	if (status < B_OK) {
116 		free(gInfo);
117 		return status;
118 	}
119 
120 	AreaCloner regsCloner;
121 	gInfo->regs_area = regsCloner.Clone("intel extreme regs",
122 							(void **)&gInfo->regs, B_ANY_ADDRESS,
123 							B_READ_AREA | B_WRITE_AREA,
124 							gInfo->shared_info->registers_area);
125 	status = regsCloner.InitCheck();
126 	if (status < B_OK) {
127 		free(gInfo);
128 		return status;
129 	}
130 
131 	sharedCloner.Keep();
132 	regsCloner.Keep();
133 
134 	// The overlay registers, hardware status, and cursor memory share
135 	// a single area with the shared_info
136 
137 	gInfo->overlay_registers = (struct overlay_registers *)((uint8 *)gInfo->shared_info
138 		+ ROUND_TO_PAGE_SIZE(sizeof(intel_shared_info)));
139 	gInfo->status = (hardware_status *)((uint8 *)gInfo->overlay_registers + B_PAGE_SIZE);
140 
141 	if (gInfo->shared_info->hardware_cursor_enabled)
142 		gInfo->cursor_memory = (uint8 *)gInfo->overlay_registers + 2 * B_PAGE_SIZE;
143 
144 	return B_OK;
145 }
146 
147 
148 /** Clean up data common to both primary and cloned accelerant */
149 
150 static void
151 uninit_common(void)
152 {
153 	delete_area(gInfo->regs_area);
154 	delete_area(gInfo->shared_info_area);
155 
156 	gInfo->regs_area = gInfo->shared_info_area = -1;
157 
158 	// close the file handle ONLY if we're the clone
159 	if (gInfo->is_clone)
160 		close(gInfo->device);
161 
162 	free(gInfo);
163 }
164 
165 
166 //	#pragma mark - public accelerant functions
167 
168 
169 /** Init primary accelerant */
170 
171 status_t
172 intel_init_accelerant(int device)
173 {
174 	TRACE(("intel_init_accelerant()\n"));
175 
176 	status_t status = init_common(device, false);
177 	if (status != B_OK)
178 		return status;
179 
180 	intel_shared_info &info = *gInfo->shared_info;
181 
182 	init_lock(&info.accelerant_lock, "intel extreme accelerant");
183 	init_lock(&info.engine_lock, "intel extreme engine");
184 
185 	setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer");
186 	setup_ring_buffer(info.secondary_ring_buffer, "intel secondary ring buffer");
187 
188 	// determine head depending on what's already enabled from the BIOS
189 	// TODO: it would be nicer to retrieve this data via DDC - else the
190 	//	display is gone for good if the BIOS decides to only show the
191 	//	picture on the connected analog monitor!
192 	gInfo->head_mode = 0;
193 	if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
194 		gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
195 	if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
196 		gInfo->head_mode |= HEAD_MODE_A_ANALOG;
197 
198 	TRACE(("head detected: %d\n", gInfo->head_mode));
199 	TRACE(("adpa: %08lx, dova: %08lx, dovb: %08lx, lvds: %08lx\n",
200 		read32(INTEL_DISPLAY_A_ANALOG_PORT), read32(INTEL_DISPLAY_A_DIGITAL_PORT),
201 		read32(INTEL_DISPLAY_B_DIGITAL_PORT), read32(INTEL_DISPLAY_LVDS_PORT)));
202 
203 	status = create_mode_list();
204 	if (status != B_OK) {
205 		uninit_common();
206 		return status;
207 	}
208 
209 	return B_OK;
210 }
211 
212 
213 ssize_t
214 intel_accelerant_clone_info_size(void)
215 {
216 	TRACE(("intel_accelerant_clone_info_size()\n"));
217 	// clone info is device name, so return its maximum size
218 	return B_PATH_NAME_LENGTH;
219 }
220 
221 
222 void
223 intel_get_accelerant_clone_info(void *info)
224 {
225 	TRACE(("intel_get_accelerant_clone_info()\n"));
226 	ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH);
227 }
228 
229 
230 status_t
231 intel_clone_accelerant(void *info)
232 {
233 	TRACE(("intel_clone_accelerant()\n"));
234 
235 	// create full device name
236 	char path[B_PATH_NAME_LENGTH];
237 	strcpy(path, "/dev/");
238 #ifdef __HAIKU__
239 	strlcat(path, (const char *)info, sizeof(path));
240 #else
241 	strcat(path, (const char *)info);
242 #endif
243 
244 	int fd = open(path, B_READ_WRITE);
245 	if (fd < 0)
246 		return fd;
247 
248 	status_t status = init_common(fd, true);
249 	if (status != B_OK)
250 		goto err1;
251 
252 	// get read-only clone of supported display modes
253 	status = gInfo->mode_list_area = clone_area(
254 		"intel extreme cloned modes", (void **)&gInfo->mode_list,
255 		B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area);
256 	if (status < B_OK)
257 		goto err2;
258 
259 	return B_OK;
260 
261 err2:
262 	uninit_common();
263 err1:
264 	close(fd);
265 	return status;
266 }
267 
268 
269 /** This function is called for both, the primary accelerant and all of
270  *	its clones.
271  */
272 
273 void
274 intel_uninit_accelerant(void)
275 {
276 	TRACE(("intel_uninit_accelerant()\n"));
277 
278 	// delete accelerant instance data
279 	delete_area(gInfo->mode_list_area);
280 	gInfo->mode_list = NULL;
281 
282 	intel_shared_info &info = *gInfo->shared_info;
283 
284 	uninit_lock(&info.accelerant_lock);
285 	uninit_lock(&info.engine_lock);
286 
287 	uninit_ring_buffer(info.primary_ring_buffer);
288 	uninit_ring_buffer(info.secondary_ring_buffer);
289 
290 	uninit_common();
291 }
292 
293 
294 status_t
295 intel_get_accelerant_device_info(accelerant_device_info *info)
296 {
297 	TRACE(("intel_get_accelerant_device_info()\n"));
298 
299 	info->version = B_ACCELERANT_VERSION;
300 	strcpy(info->name,
301 		(gInfo->shared_info->device_type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_7xx
302 		? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2");
303 	strcpy(info->chipset, gInfo->shared_info->device_identifier);
304 	strcpy(info->serial_no, "None");
305 
306 	info->memory = gInfo->shared_info->graphics_memory_size;
307 	info->dac_speed = gInfo->shared_info->pll_info.max_frequency;
308 
309 	return B_OK;
310 }
311 
312 
313 sem_id
314 intel_accelerant_retrace_semaphore()
315 {
316 	TRACE(("intel_accelerant_retrace_semaphore()\n"));
317 	return gInfo->shared_info->vblank_sem;
318 }
319 
320