xref: /haiku/src/add-ons/kernel/drivers/graphics/radeon_hd/driver.cpp (revision 1b6bc2675fe3691538c8764ab016593f3b06ca53)
1 /*
2  * Copyright (c) 2002, Thomas Kurschel
3  * Copyright 2004-2011 Haiku, Inc. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  *
6  * Authors:
7  *		Thomas Kurschel
8  *		Clemens Zeidler, <haiku@clemens-zeidler.de>
9  *		Alexander von Gluck IV, kallisti5@unixzen.com
10  */
11 
12 
13 #include "driver.h"
14 #include "device.h"
15 #include "lock.h"
16 
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <AGP.h>
22 #include <KernelExport.h>
23 #include <OS.h>
24 #include <PCI.h>
25 #include <SupportDefs.h>
26 
27 
28 #define TRACE_DRIVER
29 #ifdef TRACE_DRIVER
30 #	define TRACE(x...) dprintf("radeon_hd: " x)
31 #else
32 #	define TRACE(x...) ;
33 #endif
34 
35 #define ERROR(x...) dprintf("radeon_hd: " x)
36 
37 #define MAX_CARDS 1
38 
39 
40 // ATI / AMD cards starting at the Radeon X700 have an AtomBIOS
41 
42 // list of supported devices
43 const struct supported_device {
44 	uint32		pciID;
45 	uint8		dceMajor;	// Display block family
46 	uint8		dceMinor;	// Display block family
47 	uint16		chipsetID;
48 	uint32		chipsetFlags;
49 	const char*	deviceName;
50 } kSupportedDevices[] = {
51 	// Marketing Names: Radeon X?00
52 	// Intorduced: 2004
53 	// Codename: Loki
54 	// R420 Series  (Radeon) DCE 0.0 (*very* early AtomBIOS)
55 
56 	// Marketing Names: Radeon X1?00
57 	// Introduced: 2005
58 	// Codename: Fudo
59 	#if 0
60 	{0x791e, 1, 0, RADEON_RS690, CHIP_IGP, "Radeon X1200"},
61 	{0x791f, 1, 0, RADEON_RS690, CHIP_IGP, "Radeon X1200"},
62 	{0x793f, 1, 0, RADEON_RS600, CHIP_IGP, "Radeon X1200"},
63 	{0x7941, 1, 0, RADEON_RS600, CHIP_IGP, "Radeon X1200"},
64 	{0x7942, 1, 0, RADEON_RS600, CHIP_IGP, "Radeon X1250"},
65 	{0x796c, 1, 0, RADEON_RS740, CHIP_IGP, "Radeon RS740"},
66 	{0x796d, 1, 0, RADEON_RS740, CHIP_IGP, "Radeon RS740"},
67 	{0x796e, 1, 0, RADEON_RS740, CHIP_IGP, "Radeon 2100"},
68 	{0x796f, 1, 0, RADEON_RS740, CHIP_IGP, "Radeon RS740"},
69 	{0x7140, 1, 0, RADEON_RV515, CHIP_STD, "Radeon X1600"},
70 	{0x7100, 1, 0, RADEON_R520,  CHIP_STD, "Radeon X1800"},
71 	{0x7104, 1, 0, RADEON_R520,  CHIP_STD, "FireGL v7200"},
72 	{0x7109, 1, 0, RADEON_R520,  CHIP_STD, "Radeon X1800"},
73 	{0x710a, 1, 0, RADEON_R520,  CHIP_STD, "Radeon X1800"},
74 	{0x710b, 1, 0, RADEON_R520,  CHIP_STD, "Radeon X1800"},
75 	{0x710c, 1, 0, RADEON_R520,  CHIP_STD, "Radeon X1800"},
76 	{0x7120, 1, 0, RADEON_R520,  CHIP_STD, "Radeon X1800"},
77 	{0x7129, 1, 0, RADEON_R520,  CHIP_STD, "Radeon X1800"},
78 	#endif
79 
80 	// Marketing Names: Radeon HD 24xx - HD 42xx
81 	// Introduced: 2006
82 	// Codename: Pele
83 	{0x94c7, 2, 0, RADEON_RV610, CHIP_STD, "Radeon HD 2350"},
84 	{0x94c1, 2, 0, RADEON_RV610, CHIP_IGP, "Radeon HD 2400"},
85 	{0x94c3, 2, 0, RADEON_RV610, CHIP_STD, "Radeon HD 2400"},
86 	{0x94cc, 2, 0, RADEON_RV610, CHIP_STD, "Radeon HD 2400"},
87 	{0x9586, 2, 0, RADEON_RV630, CHIP_STD, "Radeon HD 2600"},
88 	{0x9588, 2, 0, RADEON_RV630, CHIP_STD, "Radeon HD 2600"},
89 	{0x958a, 2, 0, RADEON_RV630, CHIP_STD, "Radeon HD 2600 X2"},
90 	//	Radeon 2700		- RV630
91 	{0x9400, 2, 0, RADEON_R600,  CHIP_STD, "Radeon HD 2900"},
92 	{0x9401, 2, 0, RADEON_R600,  CHIP_STD, "Radeon HD 2900"},
93 	{0x9402, 2, 0, RADEON_R600,  CHIP_STD, "Radeon HD 2900"},
94 	{0x9403, 2, 0, RADEON_R600,  CHIP_STD, "Radeon HD 2900 Pro"},
95 	{0x9405, 2, 0, RADEON_R600,  CHIP_STD, "Radeon HD 2900"},
96 	{0x940a, 2, 0, RADEON_R600,  CHIP_STD, "Radeon FireGL V8650"},
97 	{0x940b, 2, 0, RADEON_R600,  CHIP_STD, "Radeon FireGL V8600"},
98 	{0x940f, 2, 0, RADEON_R600,  CHIP_STD, "Radeon FireGL V7600"},
99 	{0x9616, 2, 0, RADEON_RV610, CHIP_IGP, "Radeon HD 3000"},
100 	{0x9611, 3, 0, RADEON_RV620, CHIP_IGP, "Radeon HD 3100"},
101 	{0x9613, 3, 0, RADEON_RV620, CHIP_IGP, "Radeon HD 3100"},
102 	{0x9610, 2, 0, RADEON_RV610, CHIP_IGP, "Radeon HD 3200"},
103 	{0x9612, 2, 0, RADEON_RV610, CHIP_IGP, "Radeon HD 3200"},
104 	{0x9615, 2, 0, RADEON_RV610, CHIP_IGP, "Radeon HD 3200"},
105 	{0x9614, 2, 0, RADEON_RV610, CHIP_IGP, "Radeon HD 3300"},
106 	//  Radeon 3430		- RV620
107 	{0x95c5, 3, 0, RADEON_RV620, CHIP_STD, "Radeon HD 3450"},
108 	{0x95c6, 3, 0, RADEON_RV620, CHIP_STD, "Radeon HD 3450"},
109 	{0x95c7, 3, 0, RADEON_RV620, CHIP_STD, "Radeon HD 3450"},
110 	{0x95c9, 3, 0, RADEON_RV620, CHIP_STD, "Radeon HD 3450"},
111 	{0x95c4, 3, 0, RADEON_RV620, CHIP_STD, "Radeon HD 3470"},
112 	{0x95c0, 3, 0, RADEON_RV620, CHIP_STD, "Radeon HD 3550"},
113 	{0x9581, 2, 0, RADEON_RV630, CHIP_STD, "Radeon HD 3600"},
114 	{0x9583, 2, 0, RADEON_RV630, CHIP_STD, "Radeon HD 3600"},
115 	{0x9598, 2, 0, RADEON_RV630, CHIP_STD, "Radeon HD 3600"},
116 	{0x9591, 3, 0, RADEON_RV635, CHIP_STD, "Radeon HD 3600"},
117 	{0x9589, 2, 0, RADEON_RV630, CHIP_STD, "Radeon HD 3610"},
118 	//  Radeon 3650		- RV635
119 	//  Radeon 3670		- RV635
120 	{0x9507, 2, 0, RADEON_RV670, CHIP_STD, "Radeon HD 3830"},
121 	{0x9505, 2, 0, RADEON_RV670, CHIP_STD, "Radeon HD 3850"},
122 	{0x9513, 2, 0, RADEON_RV670, CHIP_STD, "Radeon HD 3850 X2"},
123 	{0x9515, 2, 0, RADEON_RV670, CHIP_STD, "Radeon HD 3850"},
124 	{0x9501, 2, 0, RADEON_RV670, CHIP_STD, "Radeon HD 3870"},
125 	{0x950F, 2, 0, RADEON_RV670, CHIP_STD, "Radeon HD 3870 X2"},
126 	{0x9710, 3, 0, RADEON_RV620, CHIP_IGP, "Radeon HD 4200"},
127 	{0x9715, 3, 0, RADEON_RV620, CHIP_IGP, "Radeon HD 4250"},
128 	{0x9712, 3, 0, RADEON_RV620, CHIP_IGP, "Radeon HD 4270"},
129 	{0x9714, 3, 0, RADEON_RV620, CHIP_IGP, "Radeon HD 4290"},
130 
131 	// Marketing Names: Radeon HD 4330 - HD 4890, HD 51xx, HD 5xxV
132 	// Introduced: 2008
133 	// Codename: Wekiva
134 	//	Radeon 4330		- RV710
135 	{0x954f, 3, 2, RADEON_RV710, CHIP_IGP, "Radeon HD 4300"},
136 	{0x9552, 3, 2, RADEON_RV710, CHIP_IGP, "Radeon HD 4300"},
137 	{0x9555, 3, 2, RADEON_RV710, CHIP_STD, "Radeon HD 4350"},
138 	{0x9540, 3, 2, RADEON_RV710, CHIP_STD, "Radeon HD 4550"},
139 	{0x9480, 3, 2, RADEON_RV730, CHIP_STD, "Radeon HD 4650"},
140 	{0x9498, 3, 2, RADEON_RV730, CHIP_STD, "Radeon HD 4650"},
141 	{0x94b4, 3, 2, RADEON_RV740, CHIP_STD, "Radeon HD 4700"},
142 	{0x9490, 3, 2, RADEON_RV730, CHIP_STD, "Radeon HD 4710"},
143 	{0x94b3, 3, 2, RADEON_RV740, CHIP_STD, "Radeon HD 4770"},
144 	{0x94b5, 3, 2, RADEON_RV740, CHIP_STD, "Radeon HD 4770"},
145 	{0x944a, 3, 1, RADEON_RV770, CHIP_MOBILE, "Radeon HD 4850"},
146 	{0x944e, 3, 1, RADEON_RV770, CHIP_STD, "Radeon HD 4810"},
147 	{0x944c, 3, 1, RADEON_RV770, CHIP_STD, "Radeon HD 4830"},
148 	{0x9442, 3, 1, RADEON_RV770, CHIP_STD, "Radeon HD 4850"},
149 	{0x9443, 3, 1, RADEON_RV770, CHIP_STD, "Radeon HD 4850 X2"},
150 	{0x94a1, 3, 1, RADEON_RV770, CHIP_IGP, "Radeon HD 4860"},
151 	{0x9440, 3, 1, RADEON_RV770, CHIP_STD, "Radeon HD 4870"},
152 	{0x9441, 3, 1, RADEON_RV770, CHIP_STD, "Radeon HD 4870 X2"},
153 	{0x9460, 3, 1, RADEON_RV770, CHIP_STD, "Radeon HD 4890"},
154 
155 	// From here on AMD no longer used numeric identifiers
156 
157 	// Marketing Names: Radeon HD 54xx ~ HD 63xx
158 	// Introduced: 2009
159 	// Codename: Evergreen
160 	//  Cedar
161 	{0x68e1, 4, 0, RADEON_CEDAR, CHIP_STD, "Radeon HD 5430"},
162 	{0x68f9, 4, 0, RADEON_CEDAR, CHIP_STD, "Radeon HD 5450"},
163 	{0x68e0, 4, 0, RADEON_CEDAR, CHIP_IGP, "Radeon HD 5470"},
164 	//  Redwood
165 	{0x68da, 4, 0, RADEON_REDWOOD, CHIP_STD, "Radeon HD 5500"},
166 	{0x68d9, 4, 0, RADEON_REDWOOD, CHIP_STD, "Radeon HD 5570"},
167 	{0x68b9, 4, 0, RADEON_REDWOOD, CHIP_STD, "Radeon HD 5600"},
168 	{0x68c1, 4, 0, RADEON_REDWOOD, CHIP_STD, "Radeon HD 5650"},
169 	{0x68d8, 4, 0, RADEON_REDWOOD, CHIP_STD, "Radeon HD 5670"},
170 	//  Juniper
171 	{0x68be, 4, 0, RADEON_JUNIPER, CHIP_STD, "Radeon HD 5700"},
172 	{0x68b8, 4, 0, RADEON_JUNIPER, CHIP_STD, "Radeon HD 5770"},
173 	//  Juniper LE / XT (67X0 is rebranded 57X0 + tweaks)
174 	{0x68bf, 4, 0, RADEON_JUNIPER, CHIP_STD, "Radeon HD 6750"},
175 	{0x68ba, 4, 0, RADEON_JUNIPER, CHIP_STD, "Radeon HD 6770"},
176 	//  Cypress
177 	{0x689e, 4, 0, RADEON_CYPRESS, CHIP_STD, "Radeon HD 5800"},
178 	{0x6899, 4, 0, RADEON_CYPRESS, CHIP_STD, "Radeon HD 5850"},
179 	{0x6898, 4, 0, RADEON_CYPRESS, CHIP_STD, "Radeon HD 5870"},
180 	//  Hemlock
181 	{0x689c, 4, 0, RADEON_HEMLOCK, CHIP_STD, "Radeon HD 5900"},
182 	// Fusion APUS
183 	//  Palm
184 	{0x9804, 4, 1, RADEON_PALM, CHIP_APU, "Radeon HD 6250"},
185 	{0x9805, 4, 1, RADEON_PALM, CHIP_APU, "Radeon HD 6290"},
186 	{0x9807, 4, 1, RADEON_PALM, CHIP_APU, "Radeon HD 6290"},
187 	{0x9802, 4, 1, RADEON_PALM, CHIP_APU, "Radeon HD 6310"},
188 	{0x9803, 4, 1, RADEON_PALM, CHIP_APU, "Radeon HD 6310"},
189 	{0x9806, 4, 1, RADEON_PALM, CHIP_APU, "Radeon HD 6320"},
190 	//  Sumo (no VGA / LVDS!, only DP)
191 	{0x9640, 4, 1, RADEON_SUMO, CHIP_APU, "Radeon HD 6550D"},
192 	{0x9641, 4, 1, RADEON_SUMO, CHIP_APU, "Radeon HD SUMO M"},
193 	{0x9647, 4, 1, RADEON_SUMO, CHIP_APU, "Radeon HD 6520G (M)"},
194 	{0x9648, 4, 1, RADEON_SUMO, CHIP_APU, "Radeon HD 6480G (M)"},
195 	{0x964a, 4, 1, RADEON_SUMO, CHIP_APU, "Radeon HD 6530D"},
196 	{0x964e, 4, 1, RADEON_SUMO, CHIP_APU, "Radeon HD SUMO M"},
197 	{0x964f, 4, 1, RADEON_SUMO, CHIP_APU, "Radeon HD SUMO M"},
198 	//  Sumo2 (no VGA / LVDS!, only DP)
199 	{0x9642, 4, 1, RADEON_SUMO2, CHIP_APU, "Radeon HD 6370D"},
200 	{0x9643, 4, 1, RADEON_SUMO2, CHIP_APU, "Radeon HD SUMO2 M"},
201 	{0x9644, 4, 1, RADEON_SUMO2, CHIP_APU, "Radeon HD 6410D"},
202 	{0x9645, 4, 1, RADEON_SUMO2, CHIP_APU, "Radeon HD SUMO2 M"},
203 
204 	// Radeon HD 64xx - HD 69xx
205 	// Introduced: 2010
206 	// Codename: Nothern Islands
207 	//  Caicos
208 	{0x6760, 5, 0, RADEON_CAICOS, CHIP_MOBILE, "Radeon HD 6470M"},
209 	{0x6761, 5, 0, RADEON_CAICOS, CHIP_MOBILE, "Radeon HD 6430M"},
210 	{0x6762, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD CAICOS"},
211 	{0x6763, 5, 0, RADEON_CAICOS, CHIP_DISCREET, "Radeon HD E6460"},
212 	{0x6764, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD CAICOS"},
213 	{0x6765, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD CAICOS"},
214 	{0x6766, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD CAICOS"},
215 	{0x6767, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD CAICOS"},
216 	{0x6768, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD CAICOS"},
217 	{0x6770, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD 6400"},
218 	{0x6778, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD CAICOS"},
219 	{0x6779, 5, 0, RADEON_CAICOS, CHIP_STD, "Radeon HD 6450"},
220 	//  Turks
221 	{0x6740, 5, 0, RADEON_TURKS, CHIP_MOBILE, "Radeon HD 6770M"},
222 	{0x6741, 5, 0, RADEON_TURKS, CHIP_MOBILE, "Radeon HD 6650M"},
223 	{0x6742, 5, 0, RADEON_TURKS, CHIP_MOBILE, "Radeon HD 6625M"},
224 	{0x6743, 5, 0, RADEON_TURKS, CHIP_DISCREET, "Radeon HD E6760"},
225 	{0x6744, 5, 0, RADEON_TURKS, CHIP_MOBILE, "Radeon HD TURKS M"},
226 	{0x6745, 5, 0, RADEON_TURKS, CHIP_MOBILE, "Radeon HD TURKS M"},
227 	{0x6746, 5, 0, RADEON_TURKS, CHIP_STD, "Radeon HD TURKS"},
228 	{0x6747, 5, 0, RADEON_TURKS, CHIP_STD, "Radeon HD TURKS"},
229 	{0x6748, 5, 0, RADEON_TURKS, CHIP_STD, "Radeon HD TURKS"},
230 	{0x6749, 5, 0, RADEON_TURKS, CHIP_STD, "FirePro v4900"},
231 	{0x6750, 5, 0, RADEON_TURKS, CHIP_STD, "Radeon HD 6500"},
232 	{0x6758, 5, 0, RADEON_TURKS, CHIP_STD, "Radeon HD 6670"},
233 	{0x6759, 5, 0, RADEON_TURKS, CHIP_STD, "Radeon HD 6570"},
234 	//  Barts
235 	{0x673e, 5, 0, RADEON_BARTS, CHIP_STD, "Radeon HD 6790"},
236 	{0x6739, 5, 0, RADEON_BARTS, CHIP_STD, "Radeon HD 6850"},
237 	{0x6738, 5, 0, RADEON_BARTS, CHIP_STD, "Radeon HD 6870"},
238 	//  Cayman
239 	{0x6700, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
240 	{0x6701, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
241 	{0x6702, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
242 	{0x6703, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
243 	{0x6704, 5, 0, RADEON_CAYMAN, CHIP_STD, "FirePro v????"},
244 	{0x6705, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
245 	{0x6706, 5, 0, RADEON_CAYMAN, CHIP_STD, "FirePro v????"},
246 	{0x6707, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
247 	{0x6708, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
248 	{0x6709, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
249 	{0x6718, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD 6970"},
250 	{0x6719, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD 6950"},
251 	{0x671C, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD CAYMAN"},
252 	{0x671F, 5, 0, RADEON_CAYMAN, CHIP_STD, "Radeon HD 6900"},
253 	//  Antilles
254 	{0x671d, 5, 0, RADEON_ANTILLES, CHIP_STD, "Radeon HD 6990"},
255 
256 	// Marketing Names: Radeon HD 74xx - HD 79xx
257 	// Introduced: Late 2011
258 	// Codename: Southern Islands
259 	//  Lombok
260 	//  Thames
261 	//  Tahiti
262 	{0x679A, 6, 0, RADEON_TAHITI, CHIP_STD, "Radeon HD 7950"},
263 	{0x6798, 6, 0, RADEON_TAHITI, CHIP_STD, "Radeon HD 7970"}
264 	//  New Zealand
265 };
266 
267 
268 int32 api_version = B_CUR_DRIVER_API_VERSION;
269 
270 
271 char* gDeviceNames[MAX_CARDS + 1];
272 radeon_info* gDeviceInfo[MAX_CARDS];
273 pci_module_info* gPCI;
274 mutex gLock;
275 
276 
277 static status_t
278 get_next_radeon_hd(int32* _cookie, pci_info &info, uint32 &type)
279 {
280 	int32 index = *_cookie;
281 
282 	// find devices
283 
284 	for (; gPCI->get_nth_pci_info(index, &info) == B_OK; index++) {
285 		// check vendor
286 		if (info.vendor_id != VENDOR_ID_ATI
287 			|| info.class_base != PCI_display
288 			|| info.class_sub != PCI_vga)
289 			continue;
290 
291 		// check device
292 		for (uint32 i = 0; i < sizeof(kSupportedDevices)
293 				/ sizeof(kSupportedDevices[0]); i++) {
294 			if (info.device_id == kSupportedDevices[i].pciID) {
295 				type = i;
296 				*_cookie = index + 1;
297 				return B_OK;
298 			}
299 		}
300 	}
301 
302 	return B_ENTRY_NOT_FOUND;
303 }
304 
305 
306 extern "C" const char**
307 publish_devices(void)
308 {
309 	TRACE("%s\n", __func__);
310 	return (const char**)gDeviceNames;
311 }
312 
313 
314 extern "C" status_t
315 init_hardware(void)
316 {
317 	TRACE("%s\n", __func__);
318 
319 	status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
320 	if (status != B_OK) {
321 		ERROR("%s: ERROR: pci module unavailable\n", __func__);
322 		return status;
323 	}
324 
325 	int32 cookie = 0;
326 	uint32 type;
327 	pci_info info;
328 	status = get_next_radeon_hd(&cookie, info, type);
329 
330 	put_module(B_PCI_MODULE_NAME);
331 	return status;
332 }
333 
334 
335 extern "C" status_t
336 init_driver(void)
337 {
338 	TRACE("%s\n", __func__);
339 
340 	status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
341 	if (status != B_OK) {
342 		ERROR("%s: ERROR: pci module unavailable\n", __func__);
343 		return status;
344 	}
345 
346 	mutex_init(&gLock, "radeon hd ksync");
347 
348 	// find devices
349 
350 	int32 found = 0;
351 
352 	for (int32 cookie = 0; found < MAX_CARDS;) {
353 		pci_info* info = (pci_info*)malloc(sizeof(pci_info));
354 		if (info == NULL)
355 			break;
356 
357 		uint32 type;
358 		status = get_next_radeon_hd(&cookie, *info, type);
359 		if (status < B_OK) {
360 			free(info);
361 			break;
362 		}
363 
364 		// create device names & allocate device info structure
365 
366 		char name[64];
367 		sprintf(name, "graphics/radeon_hd_%02x%02x%02x",
368 			info->bus, info->device,
369 			info->function);
370 
371 		gDeviceNames[found] = strdup(name);
372 		if (gDeviceNames[found] == NULL)
373 			break;
374 
375 		gDeviceInfo[found] = (radeon_info*)malloc(sizeof(radeon_info));
376 		if (gDeviceInfo[found] == NULL) {
377 			free(gDeviceNames[found]);
378 			break;
379 		}
380 
381 		// initialize the structure for later use
382 
383 		memset(gDeviceInfo[found], 0, sizeof(radeon_info));
384 		gDeviceInfo[found]->init_status = B_NO_INIT;
385 		gDeviceInfo[found]->id = found;
386 		gDeviceInfo[found]->pci = info;
387 		gDeviceInfo[found]->registers = (uint8*)info->u.h0.base_registers[0];
388 		gDeviceInfo[found]->pciID = kSupportedDevices[type].pciID;
389 		gDeviceInfo[found]->deviceName = kSupportedDevices[type].deviceName;
390 		gDeviceInfo[found]->chipsetID = kSupportedDevices[type].chipsetID;
391 		gDeviceInfo[found]->dceMajor = kSupportedDevices[type].dceMajor;
392 		gDeviceInfo[found]->dceMinor = kSupportedDevices[type].dceMinor;
393 		gDeviceInfo[found]->chipsetFlags = kSupportedDevices[type].chipsetFlags;
394 
395 		ERROR("%s: GPU(%ld) %s, revision = 0x%x\n", __func__, found,
396 			kSupportedDevices[type].deviceName, info->revision);
397 
398 		found++;
399 	}
400 
401 	gDeviceNames[found] = NULL;
402 
403 	if (found == 0) {
404 		mutex_destroy(&gLock);
405 		put_module(B_AGP_GART_MODULE_NAME);
406 		put_module(B_PCI_MODULE_NAME);
407 		ERROR("%s: no supported devices found\n", __func__);
408 		return ENODEV;
409 	}
410 
411 	return B_OK;
412 }
413 
414 
415 extern "C" void
416 uninit_driver(void)
417 {
418 	TRACE("%s\n", __func__);
419 
420 	mutex_destroy(&gLock);
421 
422 	// free device related structures
423 	char* name;
424 	for (int32 index = 0; (name = gDeviceNames[index]) != NULL; index++) {
425 		free(gDeviceInfo[index]);
426 		free(name);
427 	}
428 
429 	put_module(B_PCI_MODULE_NAME);
430 }
431 
432 
433 extern "C" device_hooks*
434 find_device(const char* name)
435 {
436 	int index;
437 
438 	TRACE("%s\n", __func__);
439 
440 	for (index = 0; gDeviceNames[index] != NULL; index++) {
441 		if (!strcmp(name, gDeviceNames[index]))
442 			return &gDeviceHooks;
443 	}
444 
445 	ERROR("%s: %s wasn't found!\n", __func__, name);
446 	return NULL;
447 }
448 
449