1/*
2	Copyright 1999, Be Incorporated.   All Rights Reserved.
3	This file may be used under the terms of the Be Sample Code License.
4
5	Other authors:
6	Mark Watson,
7	Rudolf Cornelissen 10/2002-1/2006.
8*/
9
10#define MODULE_BIT 0x00800000
11
12#include <string.h>
13#include <unistd.h>
14#include <errno.h>
15#include "acc_std.h"
16
17static status_t init_common(int the_fd);
18
19/* Initialization code shared between primary and cloned accelerants */
20static status_t init_common(int the_fd)
21{
22	status_t result;
23	gx00_get_private_data gpd;
24
25	// LOG not available from here to next LOG: NULL si
26
27	/* memorize the file descriptor */
28	fd = the_fd;
29	/* set the magic number so the driver knows we're for real */
30	gpd.magic = GX00_PRIVATE_DATA_MAGIC;
31	/* contact driver and get a pointer to the registers and shared data */
32	result = ioctl(fd, GX00_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
33	if (result != B_OK) goto error0;
34
35	/* clone the shared area for our use */
36	shared_info_area = clone_area(DRIVER_PREFIX " shared", (void **)&si, B_ANY_ADDRESS,
37		B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
38	if (shared_info_area < 0) {
39			result = shared_info_area;
40			goto error0;
41	}
42	// LOG is now available, si !NULL
43	LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, greensync %d\n",
44		si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.greensync));
45
46 	/*Check for R4.5.0 and if it is running, use work around*/
47 	{
48 		if (si->use_clone_bugfix)
49 		{
50 			/*check for R4.5.0 bug and attempt to work around*/
51 			LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n"));
52 			regs = si->clone_bugfix_regs;
53 		}
54 		else
55 		{
56			/* clone the memory mapped registers for our use  - does not work on <4.5.2 (but is better this way)*/
57			regs_area = clone_area(DRIVER_PREFIX " regs", (void **)&regs, B_ANY_ADDRESS,
58				B_READ_AREA | B_WRITE_AREA, si->regs_area);
59			if (regs_area < 0) {
60				result = regs_area;
61				goto error1;
62			}
63 		}
64 	}
65
66	/*FIXME - print dma addresses*/
67	//LOG(4,("DMA_virtual:%x\tDMA_physical:%x\tDMA_area:%x\n",si->dma_buffer,si->dma_buffer_pci,si->dma_buffer_area));
68
69	/* all done */
70	goto error0;
71
72error1:
73	delete_area(shared_info_area);
74error0:
75	return result;
76}
77
78/* Clean up code shared between primary and cloned accelerants */
79static void uninit_common(void) {
80	/* release the memory mapped registers */
81	delete_area(regs_area);
82	/* a little cheap paranoia */
83	regs = 0;
84	/* release our copy of the shared info from the kernel driver */
85	delete_area(shared_info_area);
86	/* more cheap paranoia */
87	si = 0;
88}
89
90/*
91Initialize the accelerant.  the_fd is the file handle of the device (in
92/dev/graphics) that has been opened by the app_server (or some test harness).
93We need to determine if the kernel driver and the accelerant are compatible.
94If they are, get the accelerant ready to handle other hook functions and
95report success or failure.
96*/
97status_t INIT_ACCELERANT(int the_fd)
98{
99	status_t result;
100	int pointer_reservation; //mem reserved for pointer
101	int cnt; 				 //used for iteration through the overlay buffers
102
103	if (0) {
104		time_t now = time (NULL);
105		// LOG not available from here to next LOG: NULL si
106//		MSG(("INIT_ACCELERANT: booted since %f ms %s\n", system_time()/1000.0, real_time_clock()));
107		MSG(("INIT_ACCELERANT: %s", ctime (&now)));
108	}
109
110	/* note that we're the primary accelerant (accelerantIsClone is global) */
111	accelerantIsClone = 0;
112
113	/* do the initialization common to both the primary and the clones */
114	result = init_common(the_fd);
115
116	/* bail out if the common initialization failed */
117	if (result != B_OK) goto error0;
118	// LOG now available: !NULL si
119
120	/* ensure that INIT_ACCELERANT is executed just once (copies should be clones) */
121	if (si->accelerant_in_use)
122	{
123		result = B_NOT_ALLOWED;
124		goto error1;
125	}
126
127	/* assume G450/G550 signals are connected straight through (before powerup) */
128	si->crossed_conns = false;
129
130	/* call the device specific init code */
131	result = gx00_general_powerup();
132
133	/* bail out if it failed */
134	if (result != B_OK) goto error1;
135
136	/*
137	Now would be a good time to figure out what video modes your card supports.
138	We'll place the list of modes in another shared area so all of the copies
139	of the driver can see them.  The primary copy of the accelerant (ie the one
140	initialized with this routine) will own the "one true copy" of the list.
141	Everybody else get's a read-only clone.
142	*/
143	result = create_mode_list();
144	if (result != B_OK)
145	{
146		goto error1;
147	}
148
149	/*
150	Put the cursor at the start of the frame buffer.  The typical 64x64 4 color
151	(black, white, transparent, inverse) takes up 1024 bytes of RAM.
152	*/
153	/* Initialize the rest of the cursor information while we're here */
154	si->cursor.width = 16;
155	si->cursor.height = 16;
156	si->cursor.hot_x = 0;
157	si->cursor.hot_y = 0;
158	si->cursor.x = 0;
159	si->cursor.y = 0;
160
161	/*
162	Put the frame buffer immediately following the cursor data. We store this
163	info in a frame_buffer_config structure to make it convienient to return
164	to the app_server later.
165	*/
166	pointer_reservation = 0;
167	/* MIL 1/2 cards have a seperate buffer for the cursorbitmap inside the DAC */
168	if ((si->ps.card_type >= G100) && si->settings.hardcursor)
169		pointer_reservation = 1024;
170
171	si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation);
172	si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation);
173
174	/* count of issued parameters or commands */
175	si->engine.last_idle = si->engine.count = 0;
176	INIT_BEN(si->engine.lock);
177
178	INIT_BEN(si->overlay.lock);
179	for (cnt = 0; cnt < MAXBUFFERS; cnt++)
180	{
181		/* make sure overlay buffers are 'marked' as being free */
182		si->overlay.myBuffer[cnt].buffer = NULL;
183		si->overlay.myBuffer[cnt].buffer_dma = NULL;
184	}
185	/* make sure overlay unit is 'marked' as being free */
186	si->overlay.myToken = NULL;
187
188	/* note that overlay is not in use (for gx00_bes_move_overlay()) */
189	si->overlay.active = false;
190
191	/* bail out if something failed */
192	if (result != B_OK) goto error1;
193
194	/* initialise various cursor stuff*/
195	gx00_crtc_cursor_init();
196
197	/* ensure cursor state */
198	SHOW_CURSOR(false);
199
200	/* ensure DPMS state */
201	si->dpms_flags = B_DPMS_ON;
202
203	/* a winner! */
204	result = B_OK;
205	/* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */
206	si->accelerant_in_use = true;
207	goto error0;
208
209error1:
210	/*
211	Initialization failed after init_common() succeeded, so we need to clean
212	up before quiting.
213	*/
214	uninit_common();
215
216error0:
217	return result;
218}
219
220/*
221Return the number of bytes required to hold the information required
222to clone the device.
223*/
224ssize_t ACCELERANT_CLONE_INFO_SIZE(void) {
225	/*
226	Since we're passing the name of the device as the only required
227	info, return the size of the name buffer
228	*/
229	return B_OS_NAME_LENGTH; // apsed, was MAX_GX00_DEVICE_NAME_LENGTH;
230}
231
232
233/*
234Return the info required to clone the device.  void *data points to
235a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
236*/
237void GET_ACCELERANT_CLONE_INFO(void *data) {
238	gx00_device_name dn;
239	status_t result;
240
241	/* call the kernel driver to get the device name */
242	dn.magic = GX00_PRIVATE_DATA_MAGIC;
243	/* store the returned info directly into the passed buffer */
244	dn.name = (char *)data;
245	result = ioctl(fd, GX00_DEVICE_NAME, &dn, sizeof(dn));
246}
247
248/*
249Initialize a copy of the accelerant as a clone.  void *data points to
250a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
251*/
252status_t CLONE_ACCELERANT(void *data) {
253	status_t result;
254	char path[MAXPATHLEN];
255
256	/* the data is the device name */
257	/* Note: the R4 graphics driver kit is in error here (missing trailing '/') */
258	strcpy(path, "/dev/");
259	strcat(path, (const char *)data);
260	/* open the device, the permissions aren't important */
261	fd = open(path, B_READ_WRITE);
262	if (fd < 0)
263	{
264		/* we can't use LOG because we didn't get the shared_info struct.. */
265		char     fname[64];
266		FILE    *myhand = NULL;
267
268		sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log");
269		myhand=fopen(fname,"a+");
270		fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path);
271		fclose(myhand);
272
273		/* abort with resultcode from open attempt on kerneldriver */
274		result = errno;
275		goto error0;
276	}
277
278	/* note that we're a clone accelerant */
279	accelerantIsClone = 1;
280
281	/* call the shared initialization code */
282	result = init_common(fd);
283
284	/* bail out if the common initialization failed */
285	if (result != B_OK) goto error1;
286
287	/* ensure that INIT_ACCELERANT is executed first (i.e. primary accelerant exists) */
288	if (!(si->accelerant_in_use))
289	{
290		result = B_NOT_ALLOWED;
291		goto error2;
292	}
293
294	/* get shared area for display modes */
295	result = my_mode_list_area = clone_area(
296		DRIVER_PREFIX " cloned display_modes",
297		(void **)&my_mode_list,
298		B_ANY_ADDRESS,
299		B_READ_AREA,
300		si->mode_area
301	);
302	if (result < B_OK) goto error2;
303
304	/* all done */
305	LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
306
307	result = B_OK;
308	goto error0;
309
310error2:
311	/* free up the areas we cloned */
312	uninit_common();
313error1:
314	/* close the device we opened */
315	close(fd);
316error0:
317	return result;
318}
319
320void UNINIT_ACCELERANT(void)
321{
322	if (accelerantIsClone)
323	{
324		LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n"));
325	}
326	else
327	{
328		LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n"));
329
330		/* delete benaphores ONLY if we are the primary accelerant */
331		DELETE_BEN(si->engine.lock);
332		DELETE_BEN(si->overlay.lock);
333
334		/* ensure that INIT_ACCELERANT can be executed again */
335		si->accelerant_in_use = false;
336	}
337
338	/* free our mode list area */
339	delete_area(my_mode_list_area);
340	/* paranoia */
341	my_mode_list = 0;
342	/* release our cloned data */
343	uninit_common();
344	/* close the file handle ONLY if we're the clone */
345	if (accelerantIsClone) close(fd);
346}
347