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