BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / accelerants / intel_extreme / accelerant.cpp
blob903fbd28e016ba4e64678cd7e38256234aba85ae
1 /*
2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 */
10 #include "accelerant_protos.h"
11 #include "accelerant.h"
13 #include "utility.h"
15 #include <Debug.h>
16 #include <errno.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <syslog.h>
22 #include <AGP.h>
25 #undef TRACE
26 #define TRACE_ACCELERANT
27 #ifdef TRACE_ACCELERANT
28 # define TRACE(x...) _sPrintf("intel_extreme accelerant:" x)
29 #else
30 # define TRACE(x...)
31 #endif
33 #define ERROR(x...) _sPrintf("intel_extreme accelerant: " x)
34 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
37 struct accelerant_info* gInfo;
40 class AreaCloner {
41 public:
42 AreaCloner();
43 ~AreaCloner();
45 area_id Clone(const char* name, void** _address,
46 uint32 spec, uint32 protection,
47 area_id sourceArea);
48 status_t InitCheck()
49 { return fArea < 0 ? (status_t)fArea : B_OK; }
50 void Keep();
52 private:
53 area_id fArea;
57 AreaCloner::AreaCloner()
59 fArea(-1)
64 AreaCloner::~AreaCloner()
66 if (fArea >= 0)
67 delete_area(fArea);
71 area_id
72 AreaCloner::Clone(const char* name, void** _address, uint32 spec,
73 uint32 protection, area_id sourceArea)
75 fArea = clone_area(name, _address, spec, protection, sourceArea);
76 return fArea;
80 void
81 AreaCloner::Keep()
83 fArea = -1;
87 // #pragma mark -
90 /*! This is the common accelerant_info initializer. It is called by
91 both, the first accelerant and all clones.
93 static status_t
94 init_common(int device, bool isClone)
96 // initialize global accelerant info structure
98 gInfo = (accelerant_info*)malloc(sizeof(accelerant_info));
99 if (gInfo == NULL)
100 return B_NO_MEMORY;
102 memset(gInfo, 0, sizeof(accelerant_info));
104 gInfo->is_clone = isClone;
105 gInfo->device = device;
107 // get basic info from driver
109 intel_get_private_data data;
110 data.magic = INTEL_PRIVATE_DATA_MAGIC;
112 if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data,
113 sizeof(intel_get_private_data)) != 0) {
114 free(gInfo);
115 return B_ERROR;
118 AreaCloner sharedCloner;
119 gInfo->shared_info_area = sharedCloner.Clone("intel extreme shared info",
120 (void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
121 data.shared_info_area);
122 status_t status = sharedCloner.InitCheck();
123 if (status < B_OK) {
124 free(gInfo);
125 return status;
128 AreaCloner regsCloner;
129 gInfo->regs_area = regsCloner.Clone("intel extreme regs",
130 (void**)&gInfo->registers, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
131 gInfo->shared_info->registers_area);
132 status = regsCloner.InitCheck();
133 if (status < B_OK) {
134 free(gInfo);
135 return status;
138 sharedCloner.Keep();
139 regsCloner.Keep();
141 // The overlay registers, hardware status, and cursor memory share
142 // a single area with the shared_info
144 if (gInfo->shared_info->overlay_offset != 0) {
145 gInfo->overlay_registers = (struct overlay_registers*)
146 (gInfo->shared_info->graphics_memory
147 + gInfo->shared_info->overlay_offset);
150 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) {
151 // allocate some extra memory for the 3D context
152 if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE,
153 B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) {
154 gInfo->context_offset = gInfo->context_base
155 - (addr_t)gInfo->shared_info->graphics_memory;
159 return B_OK;
163 /*! Clean up data common to both primary and cloned accelerant */
164 static void
165 uninit_common(void)
167 intel_free_memory(gInfo->context_base);
169 delete_area(gInfo->regs_area);
170 delete_area(gInfo->shared_info_area);
172 gInfo->regs_area = gInfo->shared_info_area = -1;
174 // close the file handle ONLY if we're the clone
175 if (gInfo->is_clone)
176 close(gInfo->device);
178 free(gInfo);
182 // #pragma mark - public accelerant functions
185 /*! Init primary accelerant */
186 status_t
187 intel_init_accelerant(int device)
189 CALLED();
191 status_t status = init_common(device, false);
192 if (status != B_OK)
193 return status;
195 intel_shared_info &info = *gInfo->shared_info;
197 init_lock(&info.accelerant_lock, "intel extreme accelerant");
198 init_lock(&info.engine_lock, "intel extreme engine");
200 setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer");
202 // determine head depending on what's already enabled from the BIOS
203 // TODO: it would be nicer to retrieve this data via DDC - else the
204 // display is gone for good if the BIOS decides to only show the
205 // picture on the connected analog monitor!
206 gInfo->head_mode = 0;
207 if (read32(INTEL_DISPLAY_B_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
208 gInfo->head_mode |= HEAD_MODE_B_DIGITAL;
209 if (read32(INTEL_DISPLAY_A_PIPE_CONTROL) & DISPLAY_PIPE_ENABLED)
210 gInfo->head_mode |= HEAD_MODE_A_ANALOG;
212 uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT);
214 // If we have an enabled display pipe we save the passed information and
215 // assume it is the valid panel size..
216 // Later we query for proper EDID info if it exists, or figure something
217 // else out. (Default modes, etc.)
218 bool hasPCH = gInfo->shared_info->device_type.HasPlatformControlHub();
219 if ((hasPCH && (lvds & PCH_LVDS_DETECTED) != 0)
220 || (!hasPCH && (lvds & DISPLAY_PIPE_ENABLED) != 0)) {
221 save_lvds_mode();
222 gInfo->head_mode |= HEAD_MODE_LVDS_PANEL;
225 TRACE("head detected: %#x\n", gInfo->head_mode);
226 TRACE("adpa: %08" B_PRIx32 ", dova: %08" B_PRIx32 ", dovb: %08" B_PRIx32
227 ", lvds: %08" B_PRIx32 "\n",
228 read32(INTEL_DISPLAY_A_ANALOG_PORT),
229 read32(INTEL_DISPLAY_A_DIGITAL_PORT),
230 read32(INTEL_DISPLAY_B_DIGITAL_PORT),
231 read32(INTEL_DISPLAY_LVDS_PORT));
233 status = create_mode_list();
234 if (status != B_OK) {
235 uninit_common();
236 return status;
239 return B_OK;
243 ssize_t
244 intel_accelerant_clone_info_size(void)
246 CALLED();
247 // clone info is device name, so return its maximum size
248 return B_PATH_NAME_LENGTH;
252 void
253 intel_get_accelerant_clone_info(void* info)
255 CALLED();
256 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH);
260 status_t
261 intel_clone_accelerant(void* info)
263 CALLED();
265 // create full device name
266 char path[B_PATH_NAME_LENGTH];
267 strcpy(path, "/dev/");
268 #ifdef __HAIKU__
269 strlcat(path, (const char*)info, sizeof(path));
270 #else
271 strcat(path, (const char*)info);
272 #endif
274 int fd = open(path, B_READ_WRITE);
275 if (fd < 0)
276 return errno;
278 status_t status = init_common(fd, true);
279 if (status != B_OK)
280 goto err1;
282 // get read-only clone of supported display modes
283 status = gInfo->mode_list_area = clone_area(
284 "intel extreme cloned modes", (void**)&gInfo->mode_list,
285 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area);
286 if (status < B_OK)
287 goto err2;
289 return B_OK;
291 err2:
292 uninit_common();
293 err1:
294 close(fd);
295 return status;
299 /*! This function is called for both, the primary accelerant and all of
300 its clones.
302 void
303 intel_uninit_accelerant(void)
305 CALLED();
307 // delete accelerant instance data
308 delete_area(gInfo->mode_list_area);
309 gInfo->mode_list = NULL;
311 intel_shared_info &info = *gInfo->shared_info;
313 uninit_lock(&info.accelerant_lock);
314 uninit_lock(&info.engine_lock);
316 uninit_ring_buffer(info.primary_ring_buffer);
318 uninit_common();
322 status_t
323 intel_get_accelerant_device_info(accelerant_device_info* info)
325 CALLED();
327 info->version = B_ACCELERANT_VERSION;
328 strcpy(info->name, gInfo->shared_info->device_type.InFamily(INTEL_TYPE_7xx)
329 ? "Intel Extreme Graphics 1" : "Intel Extreme Graphics 2");
330 strcpy(info->chipset, gInfo->shared_info->device_identifier);
331 strcpy(info->serial_no, "None");
333 info->memory = gInfo->shared_info->graphics_memory_size;
334 info->dac_speed = gInfo->shared_info->pll_info.max_frequency;
336 return B_OK;
340 sem_id
341 intel_accelerant_retrace_semaphore()
343 CALLED();
344 return gInfo->shared_info->vblank_sem;