1/*
2 * Copyright 2007-2012 Haiku, Inc.  All rights reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		Gerald Zajac
7 */
8
9
10#include "accelerant.h"
11
12#include <errno.h>
13#include <string.h>
14#include <unistd.h>
15
16
17AccelerantInfo gInfo;	// global data used by source files of accelerant
18
19static uint32 videoValue;
20
21
22static int32
23SuppressArtifacts(void* dataPtr)
24{
25	// The Intel 810 & 815 video chips create annoying artifacts which are
26	// most noticeable when the cursor is moved by itself or the user goes up
27	// and down through a menu.  However, if a large number of video memory
28	// locations are accessed frequently like when the GLTeapot demo is
29	// running, the artifacts are greatly suppressed.  Thus, that is the reason
30	// why this function accesses a large number of video memory locations
31	// frequently.  Note that the accessed memory locations are at the end of
32	// the video memory.  This is because some artifacts still occur at the
33	// top of the screen if the accessed memory is at the beginning of the
34	// video memory.
35
36	// Note that this function will reduce the general performance of a
37	// computer somewhat, but it is much less of a hit than if double
38	// buffering was used for the video.  Base on the frame rate of the
39	// the GLTeapot demo, it is less than a 10% reduction.
40
41	SharedInfo& si = *((SharedInfo*)dataPtr);
42
43	while (true) {
44		uint32* src = ((uint32*)(si.videoMemAddr)) + si.videoMemSize / 4 - 1;
45		uint32 count = 65000;
46
47		while (count-- > 0)
48			videoValue = *src--;
49
50		snooze(30000);		// sleep for 30 msec
51	}
52
53	return 0;
54}
55
56
57static status_t
58InitCommon(int fileDesc)
59{
60	// Initialization function used by primary and cloned accelerants.
61
62	gInfo.deviceFileDesc = fileDesc;
63
64	// Get area ID of shared data from driver.
65
66	area_id sharedArea;
67	status_t result = ioctl(gInfo.deviceFileDesc, INTEL_GET_SHARED_DATA,
68		&sharedArea, sizeof(sharedArea));
69	if (result != B_OK)
70		return result;
71
72	gInfo.sharedInfoArea = clone_area("i810 shared info",
73		(void**)&(gInfo.sharedInfo), B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA,
74		sharedArea);
75	if (gInfo.sharedInfoArea < 0)
76		return gInfo.sharedInfoArea; // sharedInfoArea has error code
77
78	gInfo.regsArea = clone_area("i810 regs area", (void**)&(gInfo.regs),
79		B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, gInfo.sharedInfo->regsArea);
80	if (gInfo.regsArea < 0) {
81		delete_area(gInfo.sharedInfoArea);
82		return gInfo.regsArea; // regsArea has error code
83	}
84
85	return B_OK;
86}
87
88
89static void
90UninitCommon(void)
91{
92	// This function is used by both primary and cloned accelerants.
93
94	delete_area(gInfo.regsArea);
95	gInfo.regs = 0;
96
97	delete_area(gInfo.sharedInfoArea);
98	gInfo.sharedInfo = 0;
99}
100
101
102status_t
103InitAccelerant(int fileDesc)
104{
105	// Initialize the accelerant.	fileDesc is the file handle of the device
106	// (in /dev/graphics) that has been opened by the app_server.
107
108	TRACE("Enter InitAccelerant()\n");
109
110	gInfo.bAccelerantIsClone = false;	// indicate this is primary accelerant
111
112	status_t result = InitCommon(fileDesc);
113	if (result == B_OK) {
114		SharedInfo& si = *gInfo.sharedInfo;
115
116		TRACE("Vendor ID: 0x%X,  Device ID: 0x%X\n", si.vendorID, si.deviceID);
117
118		// Ensure that InitAccelerant is executed just once (copies should be
119		// clones)
120
121		if (si.bAccelerantInUse) {
122			result = B_NOT_ALLOWED;
123		} else {
124			result = I810_Init();	// perform init related to current chip
125			if (result == B_OK) {
126				result = si.engineLock.Init("i810 engine lock");
127				if (result == B_OK) {
128					// Ensure that this function won't be executed again
129					// (copies should be clones)
130					si.bAccelerantInUse = true;
131
132					thread_id threadID = spawn_thread(SuppressArtifacts,
133						"SuppressArtifacts_Thread", B_DISPLAY_PRIORITY,
134						gInfo.sharedInfo);
135					result = resume_thread(threadID);
136				}
137			}
138		}
139
140		if (result != B_OK)
141			UninitCommon();
142	}
143
144	TRACE("Leave InitAccelerant(), result: 0x%X\n", result);
145	return result;
146}
147
148
149ssize_t
150AccelerantCloneInfoSize(void)
151{
152	// Return the number of bytes required to hold the information required
153	// to clone the device.  The information is merely the name of the device;
154	// thus, return the size of the name buffer.
155
156	return B_OS_NAME_LENGTH;
157}
158
159
160void
161GetAccelerantCloneInfo(void* data)
162{
163	// Return the info required to clone the device.  Argument data points to
164	// a buffer which is the size returned by AccelerantCloneInfoSize().
165
166	ioctl(gInfo.deviceFileDesc, INTEL_DEVICE_NAME, data, B_OS_NAME_LENGTH);
167}
168
169
170status_t
171CloneAccelerant(void* data)
172{
173	// Initialize a copy of the accelerant as a clone.  Argument data points to
174	// a copy of the data which was returned by GetAccelerantCloneInfo().
175
176	TRACE("Enter CloneAccelerant()\n");
177
178	char path[MAXPATHLEN] = "/dev/";
179	strcat(path, (const char*)data);
180
181	gInfo.deviceFileDesc = open(path, B_READ_WRITE);	// open the device
182	if (gInfo.deviceFileDesc < 0)
183		return errno;
184
185	gInfo.bAccelerantIsClone = true;
186
187	status_t result = InitCommon(gInfo.deviceFileDesc);
188	if (result != B_OK) {
189		close(gInfo.deviceFileDesc);
190		return result;
191	}
192
193	result = gInfo.modeListArea = clone_area("i810 cloned display_modes",
194		(void**) &gInfo.modeList, B_ANY_ADDRESS, B_READ_AREA,
195		gInfo.sharedInfo->modeArea);
196	if (result < 0) {
197		UninitCommon();
198		close(gInfo.deviceFileDesc);
199		return result;
200	}
201
202	TRACE("Leave CloneAccelerant()\n");
203	return B_OK;
204}
205
206
207void
208UninitAccelerant(void)
209{
210	delete_area(gInfo.modeListArea);
211	gInfo.modeList = NULL;
212
213	UninitCommon();
214
215	if (gInfo.bAccelerantIsClone)
216		close(gInfo.deviceFileDesc);
217}
218
219
220status_t
221GetAccelerantDeviceInfo(accelerant_device_info* adi)
222{
223	// Get info about the device.
224
225	SharedInfo& si = *gInfo.sharedInfo;
226
227	adi->version = 1;
228	strcpy(adi->name, "Intel 810/815 chipset");
229	strcpy(adi->chipset, si.chipName);
230	strcpy(adi->serial_no, "unknown");
231	adi->memory = si.maxFrameBufferSize;
232	adi->dac_speed = 270;
233
234	return B_OK;
235}
236