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