vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / radeon_hd / accelerant.cpp
blob727a3ca38a2c4d68da4037d24cd7aafdf638a119
1 /*
2 * Copyright 2006-2011, 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 * Alexander von Gluck, kallisti5@unixzen.com
8 */
11 #include "accelerant.h"
13 #include <AGP.h>
14 #include <Debug.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <syslog.h>
20 #include <unistd.h>
22 #include "accelerant_protos.h"
24 #include "bios.h"
25 #include "connector.h"
26 #include "display.h"
27 #include "displayport.h"
28 #include "gpu.h"
29 #include "pll.h"
30 #include "utility.h"
33 #undef TRACE
35 #define TRACE_ACCELERANT
36 #ifdef TRACE_ACCELERANT
37 # define TRACE(x...) _sPrintf("radeon_hd: " x)
38 #else
39 # define TRACE(x...) ;
40 #endif
43 struct accelerant_info* gInfo;
44 display_info* gDisplay[MAX_DISPLAY];
45 connector_info* gConnector[ATOM_MAX_SUPPORTED_DEVICE];
46 gpio_info* gGPIOInfo[MAX_GPIO_PINS];
49 class AreaCloner {
50 public:
51 AreaCloner();
52 ~AreaCloner();
54 area_id Clone(const char* name, void** _address,
55 uint32 spec, uint32 protection,
56 area_id sourceArea);
57 status_t InitCheck()
58 {return fArea < 0 ? (status_t)fArea : B_OK;}
59 void Keep();
61 private:
62 area_id fArea;
66 AreaCloner::AreaCloner()
68 fArea(-1)
73 AreaCloner::~AreaCloner()
75 if (fArea >= 0)
76 delete_area(fArea);
80 area_id
81 AreaCloner::Clone(const char* name, void** _address, uint32 spec,
82 uint32 protection, area_id sourceArea)
84 fArea = clone_area(name, _address, spec, protection, sourceArea);
85 return fArea;
89 void
90 AreaCloner::Keep()
92 fArea = -1;
96 // #pragma mark -
99 /*! This is the common accelerant_info initializer. It is called by
100 both, the first accelerant and all clones.
102 static status_t
103 init_common(int device, bool isClone)
105 // initialize global accelerant info structure
107 gInfo = (accelerant_info*)malloc(sizeof(accelerant_info));
109 if (gInfo == NULL)
110 return B_NO_MEMORY;
112 memset(gInfo, 0, sizeof(accelerant_info));
114 // malloc memory for active display information
115 for (uint32 id = 0; id < MAX_DISPLAY; id++) {
116 gDisplay[id] = (display_info*)malloc(sizeof(display_info));
117 if (gDisplay[id] == NULL)
118 return B_NO_MEMORY;
119 memset(gDisplay[id], 0, sizeof(display_info));
121 gDisplay[id]->regs = (register_info*)malloc(sizeof(register_info));
122 if (gDisplay[id]->regs == NULL)
123 return B_NO_MEMORY;
124 memset(gDisplay[id]->regs, 0, sizeof(register_info));
127 // malloc for possible physical card connectors
128 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) {
129 gConnector[id] = (connector_info*)malloc(sizeof(connector_info));
131 if (gConnector[id] == NULL)
132 return B_NO_MEMORY;
133 memset(gConnector[id], 0, sizeof(connector_info));
135 gConnector[id]->encoder.pll.id = ATOM_PPLL_INVALID;
138 // malloc for card gpio pin information
139 for (uint32 id = 0; id < MAX_GPIO_PINS; id++) {
140 gGPIOInfo[id] = (gpio_info*)malloc(sizeof(gpio_info));
142 if (gGPIOInfo[id] == NULL)
143 return B_NO_MEMORY;
144 memset(gGPIOInfo[id], 0, sizeof(gpio_info));
147 gInfo->is_clone = isClone;
148 gInfo->device = device;
150 gInfo->dpms_mode = B_DPMS_ON;
151 // initial state
153 // get basic info from driver
155 radeon_get_private_data data;
156 data.magic = RADEON_PRIVATE_DATA_MAGIC;
158 if (ioctl(device, RADEON_GET_PRIVATE_DATA, &data,
159 sizeof(radeon_get_private_data)) != 0) {
160 free(gInfo);
161 return B_ERROR;
164 AreaCloner sharedCloner;
165 gInfo->shared_info_area = sharedCloner.Clone("radeon hd shared info",
166 (void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
167 data.shared_info_area);
168 status_t status = sharedCloner.InitCheck();
169 if (status < B_OK) {
170 free(gInfo);
171 TRACE("%s, failed to create shared area\n", __func__);
172 return status;
175 AreaCloner regsCloner;
176 gInfo->regs_area = regsCloner.Clone("radeon hd regs",
177 (void**)&gInfo->regs, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
178 gInfo->shared_info->registers_area);
179 status = regsCloner.InitCheck();
180 if (status < B_OK) {
181 free(gInfo);
182 TRACE("%s, failed to create mmio area\n", __func__);
183 return status;
186 gInfo->rom_area = clone_area("radeon hd AtomBIOS",
187 (void**)&gInfo->rom, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
188 gInfo->shared_info->rom_area);
190 if (gInfo->rom_area < 0) {
191 TRACE("%s: Clone of AtomBIOS failed!\n", __func__);
192 gInfo->shared_info->has_rom = false;
195 if (gInfo->rom[0] != 0x55 || gInfo->rom[1] != 0xAA)
196 TRACE("%s: didn't find a VGA bios in cloned region!\n", __func__);
198 sharedCloner.Keep();
199 regsCloner.Keep();
201 return B_OK;
205 /*! Clean up data common to both primary and cloned accelerant */
206 static void
207 uninit_common(void)
209 if (gInfo != NULL) {
210 delete_area(gInfo->regs_area);
211 delete_area(gInfo->shared_info_area);
212 delete_area(gInfo->rom_area);
214 gInfo->regs_area = gInfo->shared_info_area = -1;
216 // close the file handle ONLY if we're the clone
217 if (gInfo->is_clone)
218 close(gInfo->device);
220 free(gInfo);
223 for (uint32 id = 0; id < MAX_DISPLAY; id++) {
224 if (gDisplay[id] != NULL) {
225 free(gDisplay[id]->regs);
226 free(gDisplay[id]);
230 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++)
231 free(gConnector[id]);
233 for (uint32 id = 0; id < MAX_GPIO_PINS; id++)
234 free(gGPIOInfo[id]);
238 // #pragma mark - public accelerant functions
241 /*! Init primary accelerant */
242 status_t
243 radeon_init_accelerant(int device)
245 TRACE("%s enter\n", __func__);
247 status_t status = init_common(device, false);
248 if (status != B_OK)
249 return status;
251 radeon_shared_info &info = *gInfo->shared_info;
253 init_lock(&info.accelerant_lock, "radeon hd accelerant");
254 init_lock(&info.engine_lock, "radeon hd engine");
256 radeon_init_bios(gInfo->rom);
258 // probe firmware information
259 radeon_gpu_probe();
261 // apply GPU quirks
262 radeon_gpu_quirks();
264 // find GPIO pins from AtomBIOS
265 gpio_populate();
267 // find physical card connectors from AtomBIOS
268 status = connector_probe();
270 if (status != B_OK) {
271 TRACE("%s: falling back to legacy connector probe.\n", __func__);
272 status = connector_probe_legacy();
275 if (status != B_OK) {
276 TRACE("%s: couldn't detect supported connectors!\n", __func__);
277 return status;
280 // print found connectors
281 debug_connectors();
283 // setup encoders on each connector if needed
284 encoder_init();
286 // program external pll clock
287 pll_external_init();
289 // setup link on any DisplayPort connectors
290 dp_setup_connectors();
292 // detect attached displays
293 status = detect_displays();
294 //if (status != B_OK)
295 // return status;
297 // print found displays
298 debug_displays();
300 // create initial list of video modes
301 status = create_mode_list();
302 //if (status != B_OK) {
303 // radeon_uninit_accelerant();
304 // return status;
307 radeon_gpu_mc_setup();
309 // Set up data crunching + irq rings
310 radeon_gpu_ring_setup();
312 radeon_gpu_ring_boot(RADEON_QUEUE_TYPE_GFX_INDEX);
314 TRACE("%s done\n", __func__);
315 return B_OK;
319 /*! This function is called for both, the primary accelerant and all of
320 its clones.
322 void
323 radeon_uninit_accelerant(void)
325 TRACE("%s enter\n", __func__);
327 gInfo->mode_list = NULL;
329 radeon_shared_info &info = *gInfo->shared_info;
331 uninit_lock(&info.accelerant_lock);
332 uninit_lock(&info.engine_lock);
334 uninit_common();
335 TRACE("%s done\n", __func__);
339 status_t
340 radeon_get_accelerant_device_info(accelerant_device_info* di)
342 radeon_shared_info &info = *gInfo->shared_info;
344 di->version = B_ACCELERANT_VERSION;
345 strcpy(di->name, info.deviceName);
347 char chipset[32];
348 sprintf(chipset, "%s", gInfo->shared_info->chipsetName);
349 strcpy(di->chipset, chipset);
351 // add flags onto chipset name
352 if ((info.chipsetFlags & CHIP_IGP) != 0)
353 strcat(di->chipset, " IGP");
354 if ((info.chipsetFlags & CHIP_MOBILE) != 0)
355 strcat(di->chipset, " Mobile");
356 if ((info.chipsetFlags & CHIP_APU) != 0)
357 strcat(di->chipset, " APU");
359 strcpy(di->serial_no, "None" );
361 di->memory = gInfo->shared_info->graphics_memory_size;
362 return B_OK;