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