1/*
2 * Copyright 2006-2009, 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 "driver.h"
11#include "device.h"
12#include "lock.h"
13
14#include <stdlib.h>
15#include <stdio.h>
16#include <string.h>
17
18#include <AGP.h>
19#include <KernelExport.h>
20#include <OS.h>
21#include <PCI.h>
22#include <SupportDefs.h>
23
24
25#define TRACE_DRIVER
26#ifdef TRACE_DRIVER
27#	define TRACE(x...) dprintf("intel_extreme: " x)
28#else
29#	define TRACE(x) ;
30#endif
31
32#define ERROR(x...) dprintf("intel_extreme: " x)
33#define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
34
35
36#define MAX_CARDS 4
37
38
39// list of supported devices
40const struct supported_device {
41	uint32		device_id;
42	int32		type;
43	const char*	name;
44} kSupportedDevices[] = {
45	{0x3577, INTEL_TYPE_83x, "i830GM"},
46	{0x2562, INTEL_TYPE_83x, "i845G"},
47
48	{0x2572, INTEL_TYPE_85x, "i865G"},
49	{0x3582, INTEL_TYPE_85x, "i855G"},
50	{0x358e, INTEL_TYPE_85x, "i855G"},
51
52	{0x2582, INTEL_TYPE_915, "i915G"},
53	{0x258a, INTEL_TYPE_915, "i915"},
54	{0x2592, INTEL_TYPE_915M, "i915GM"},
55	{0x2792, INTEL_TYPE_915, "i910"},
56	{0x2772, INTEL_TYPE_945, "i945G"},
57	{0x27a2, INTEL_TYPE_945M, "i945GM"},
58	{0x27ae, INTEL_TYPE_945M, "i945GME"},
59	{0x2972, INTEL_TYPE_965, "i946G"},
60	{0x2982, INTEL_TYPE_965, "G35"},
61	{0x2992, INTEL_TYPE_965, "i965Q"},
62	{0x29a2, INTEL_TYPE_965, "i965G"},
63	{0x2a02, INTEL_TYPE_965M, "i965GM"},
64	{0x2a12, INTEL_TYPE_965M, "i965GME"},
65	{0x29b2, INTEL_TYPE_G33, "G33G"},
66	{0x29c2, INTEL_TYPE_G33, "Q35G"},
67	{0x29d2, INTEL_TYPE_G33, "Q33G"},
68
69	{0x2a42, INTEL_TYPE_GM45, "GM45"},
70	{0x2e02, INTEL_TYPE_G45, "IGD"},
71	{0x2e12, INTEL_TYPE_G45, "Q45"},
72	{0x2e22, INTEL_TYPE_G45, "G45"},
73	{0x2e32, INTEL_TYPE_G45, "G41"},
74	{0x2e42, INTEL_TYPE_G45, "B43"},
75	{0x2e92, INTEL_TYPE_G45, "B43"},
76
77	{0xa001, INTEL_TYPE_IGDG, "Atom_Dx10"},
78	{0xa011, INTEL_TYPE_IGDGM, "Atom_N4x0"},
79
80	{0x0042, INTEL_TYPE_ILKG, "IronLake Desktop"},
81	{0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
82	{0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
83	{0x0046, INTEL_TYPE_ILKGM, "IronLake Mobile"},
84
85	{0x0102, INTEL_TYPE_SNBG, "SandyBridge Desktop GT1"},
86	{0x0112, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2"},
87	{0x0122, INTEL_TYPE_SNBG, "SandyBridge Desktop GT2+"},
88	{0x0106, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT1"},
89	{0x0116, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2"},
90	{0x0126, INTEL_TYPE_SNBGM, "SandyBridge Mobile GT2+"},
91	{0x010a, INTEL_TYPE_SNBGS, "SandyBridge Server"},
92
93	{0x0152, INTEL_TYPE_IVBG, "IvyBridge Desktop GT1"},
94	{0x0162, INTEL_TYPE_IVBG, "IvyBridge Desktop GT2"},
95	{0x0156, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT1"},
96	{0x0166, INTEL_TYPE_IVBGM, "IvyBridge Mobile GT2"},
97	{0x015a, INTEL_TYPE_IVBGS, "IvyBridge Server GT1"},
98	{0x016a, INTEL_TYPE_IVBGS, "IvyBridge Server GT2"},
99};
100
101int32 api_version = B_CUR_DRIVER_API_VERSION;
102
103char* gDeviceNames[MAX_CARDS + 1];
104intel_info* gDeviceInfo[MAX_CARDS];
105pci_module_info* gPCI;
106agp_gart_module_info* gGART;
107mutex gLock;
108
109
110static status_t
111get_next_intel_extreme(int32* _cookie, pci_info &info, uint32 &type)
112{
113	int32 index = *_cookie;
114
115	// find devices
116
117	for (; gPCI->get_nth_pci_info(index, &info) == B_OK; index++) {
118		// check vendor
119		if (info.vendor_id != VENDOR_ID_INTEL
120			|| info.class_base != PCI_display
121			|| info.class_sub != PCI_vga)
122			continue;
123
124		// check device
125		for (uint32 i = 0; i < sizeof(kSupportedDevices)
126				/ sizeof(kSupportedDevices[0]); i++) {
127			if (info.device_id == kSupportedDevices[i].device_id) {
128				type = i;
129				*_cookie = index + 1;
130				return B_OK;
131			}
132		}
133	}
134
135	return B_ENTRY_NOT_FOUND;
136}
137
138
139extern "C" const char**
140publish_devices(void)
141{
142	CALLED();
143	return (const char**)gDeviceNames;
144}
145
146
147extern "C" status_t
148init_hardware(void)
149{
150	CALLED();
151
152	status_t status = get_module(B_PCI_MODULE_NAME,(module_info**)&gPCI);
153	if (status != B_OK) {
154		ERROR("pci module unavailable\n");
155		return status;
156	}
157
158	int32 cookie = 0;
159	uint32 type;
160	pci_info info;
161	status = get_next_intel_extreme(&cookie, info, type);
162
163	put_module(B_PCI_MODULE_NAME);
164	return status;
165}
166
167
168extern "C" status_t
169init_driver(void)
170{
171	CALLED();
172
173	status_t status = get_module(B_PCI_MODULE_NAME, (module_info**)&gPCI);
174	if (status != B_OK) {
175		ERROR("pci module unavailable\n");
176		return status;
177	}
178
179	status = get_module(B_AGP_GART_MODULE_NAME, (module_info**)&gGART);
180	if (status != B_OK) {
181		ERROR("AGP GART module unavailable\n");
182		put_module(B_PCI_MODULE_NAME);
183		return status;
184	}
185
186	mutex_init(&gLock, "intel extreme ksync");
187
188	// find devices
189
190	int32 found = 0;
191
192	for (int32 cookie = 0; found < MAX_CARDS;) {
193		pci_info* info = (pci_info*)malloc(sizeof(pci_info));
194		if (info == NULL)
195			break;
196
197		uint32 type;
198		status = get_next_intel_extreme(&cookie, *info, type);
199		if (status < B_OK) {
200			free(info);
201			break;
202		}
203
204		// create device names & allocate device info structure
205
206		char name[64];
207		sprintf(name, "graphics/intel_extreme_%02x%02x%02x",
208			 info->bus, info->device,
209			 info->function);
210
211		gDeviceNames[found] = strdup(name);
212		if (gDeviceNames[found] == NULL)
213			break;
214
215		gDeviceInfo[found] = (intel_info*)malloc(sizeof(intel_info));
216		if (gDeviceInfo[found] == NULL) {
217			free(gDeviceNames[found]);
218			break;
219		}
220
221		// initialize the structure for later use
222
223		memset(gDeviceInfo[found], 0, sizeof(intel_info));
224		gDeviceInfo[found]->init_status = B_NO_INIT;
225		gDeviceInfo[found]->id = found;
226		gDeviceInfo[found]->pci = info;
227		gDeviceInfo[found]->registers = (uint8*)info->u.h0.base_registers[0];
228		gDeviceInfo[found]->device_identifier = kSupportedDevices[type].name;
229		gDeviceInfo[found]->device_type = kSupportedDevices[type].type;
230
231		dprintf(DEVICE_NAME ": (%ld) %s, revision = 0x%x\n", found,
232			kSupportedDevices[type].name, info->revision);
233
234		found++;
235	}
236
237	gDeviceNames[found] = NULL;
238
239	if (found == 0) {
240		mutex_destroy(&gLock);
241		put_module(B_AGP_GART_MODULE_NAME);
242		put_module(B_PCI_MODULE_NAME);
243		return ENODEV;
244	}
245
246	return B_OK;
247}
248
249
250extern "C" void
251uninit_driver(void)
252{
253	CALLED();
254
255	mutex_destroy(&gLock);
256
257	// free device related structures
258	char* name;
259	for (int32 index = 0; (name = gDeviceNames[index]) != NULL; index++) {
260		free(gDeviceInfo[index]);
261		free(name);
262	}
263
264	put_module(B_AGP_GART_MODULE_NAME);
265	put_module(B_PCI_MODULE_NAME);
266}
267
268
269extern "C" device_hooks*
270find_device(const char* name)
271{
272	CALLED();
273
274	int index;
275	for (index = 0; gDeviceNames[index] != NULL; index++) {
276		if (!strcmp(name, gDeviceNames[index]))
277			return &gDeviceHooks;
278	}
279
280	return NULL;
281}
282
283