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) goto error0;
32
33	/* clone the shared area for our use */
34	shared_info_area = clone_area(DRIVER_PREFIX " shared", (void **)&si, B_ANY_ADDRESS,
35		B_READ_AREA | B_WRITE_AREA, gpd.shared_info_area);
36	if (shared_info_area < 0) {
37			result = shared_info_area;
38			goto error0;
39	}
40	// LOG is now available, si !NULL
41	LOG(4,("init_common: logmask 0x%08x, memory %dMB, hardcursor %d, usebios %d, switchhead %d, force_pci %d\n",
42		si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios, si->settings.switchhead, si->settings.force_pci));
43	LOG(4,("init_common: dumprom %d, unhide_fw %d, pgm_panel %d\n",
44		si->settings.dumprom, si->settings.unhide_fw, si->settings.pgm_panel));
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 accelrants */
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	status_t result;
99	int pointer_reservation; //mem reserved for pointer
100	int cnt; 				 //used for iteration through the overlay buffers
101
102	if (0) {
103		time_t now = time (NULL);
104		// LOG not available from here to next LOG: NULL si
105		MSG(("INIT_ACCELERANT: %s", ctime (&now)));
106	}
107
108	/* note that we're the primary accelerant (accelerantIsClone is global) */
109	accelerantIsClone = 0;
110
111	/* do the initialization common to both the primary and the clones */
112	result = init_common(the_fd);
113
114	/* bail out if the common initialization failed */
115	if (result != B_OK) goto error0;
116	// LOG now available: !NULL si
117
118	/* call the device specific init code */
119	result = eng_general_powerup();
120
121	/* bail out if it failed */
122	if (result != B_OK) goto error1;
123
124	/*
125	Now would be a good time to figure out what video modes your card supports.
126	We'll place the list of modes in another shared area so all of the copies
127	of the driver can see them.  The primary copy of the accelerant (ie the one
128	initialized with this routine) will own the "one true copy" of the list.
129	Everybody else get's a read-only clone.
130	*/
131	result = create_mode_list();
132	if (result != B_OK)
133	{
134		goto error1;
135	}
136
137	/*
138	Put the cursor at the start of the frame buffer.
139	Nvidia cursor is 32x32 16 color? takes up 4096 bytes of RAM.
140	*/
141	/* Initialize the rest of the cursor information while we're here */
142	si->cursor.width = 16;
143	si->cursor.height = 16;
144	si->cursor.hot_x = 0;
145	si->cursor.hot_y = 0;
146	si->cursor.x = 0;
147	si->cursor.y = 0;
148	si->cursor.dh_right = false;
149
150	/*
151	Put the frame buffer immediately following the cursor data. We store this
152	info in a frame_buffer_config structure to make it convienient to return
153	to the app_server later.
154	*/
155	pointer_reservation = 0;
156	/* VIA hardcursor needs 4kB space */
157	if (si->settings.hardcursor) pointer_reservation = 4096;
158
159	si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation);
160	si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation);
161
162	/* count of issued parameters or commands */
163	si->engine.last_idle = si->engine.count = 0;
164	INIT_BEN(si->engine.lock);
165
166	INIT_BEN(si->overlay.lock);
167	for (cnt = 0; cnt < MAXBUFFERS; cnt++)
168	{
169		/* make sure overlay buffers are 'marked' as being free */
170		si->overlay.myBuffer[cnt].buffer = NULL;
171		si->overlay.myBuffer[cnt].buffer_dma = NULL;
172	}
173	/* make sure overlay unit is 'marked' as being free */
174	si->overlay.myToken = NULL;
175
176	/* note that overlay is not in use (for eng_bes_move_overlay()) */
177	si->overlay.active = false;
178
179	/* bail out if something failed */
180	if (result != B_OK) goto error1;
181
182	/* initialise various cursor stuff */
183	head1_cursor_init();
184	if (si->ps.secondary_head) head2_cursor_init();
185
186	/* ensure cursor state */
187	head1_cursor_hide();
188	if (si->ps.secondary_head) head2_cursor_hide();
189
190	/* a winner! */
191	result = B_OK;
192	goto error0;
193
194error1:
195	/*
196	Initialization failed after init_common() succeeded, so we need to clean
197	up before quiting.
198	*/
199	uninit_common();
200
201error0:
202	return result;
203}
204
205/*
206Return the number of bytes required to hold the information required
207to clone the device.
208*/
209ssize_t ACCELERANT_CLONE_INFO_SIZE(void) {
210	/*
211	Since we're passing the name of the device as the only required
212	info, return the size of the name buffer
213	*/
214	return B_OS_NAME_LENGTH; // apsed, was MAX_ENG_DEVICE_NAME_LENGTH;
215}
216
217
218/*
219Return the info required to clone the device.  void *data points to
220a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
221*/
222void GET_ACCELERANT_CLONE_INFO(void *data) {
223	eng_device_name dn;
224	status_t result;
225
226	/* call the kernel driver to get the device name */
227	dn.magic = VIA_PRIVATE_DATA_MAGIC;
228	/* store the returned info directly into the passed buffer */
229	dn.name = (char *)data;
230	result = ioctl(fd, ENG_DEVICE_NAME, &dn, sizeof(dn));
231}
232
233/*
234Initialize a copy of the accelerant as a clone.  void *data points to
235a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
236*/
237status_t CLONE_ACCELERANT(void *data) {
238	status_t result;
239	char path[MAXPATHLEN];
240
241	/* the data is the device name */
242	/* Note: the R4 graphics driver kit is in error here (missing trailing '/') */
243	strcpy(path, "/dev/");
244	strcat(path, (const char *)data);
245	/* open the device, the permissions aren't important */
246	fd = open(path, B_READ_WRITE);
247	if (fd < 0)
248	{
249		/* we can't use LOG because we didn't get the shared_info struct.. */
250		char     fname[64];
251		FILE    *myhand = NULL;
252
253		sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log");
254		myhand=fopen(fname,"a+");
255		fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path);
256		fclose(myhand);
257
258		/* abort with resultcode from open attempt on kerneldriver */
259		result = fd;
260		goto error0;
261	}
262
263	/* note that we're a clone accelerant */
264	accelerantIsClone = 1;
265
266	/* call the shared initialization code */
267	result = init_common(fd);
268
269	/* setup CRTC and DAC functions access */
270	setup_virtualized_heads(si->crtc_switch_mode);
271
272	/* bail out if the common initialization failed */
273	if (result != B_OK) goto error1;
274
275	/* get shared area for display modes */
276	result = my_mode_list_area = clone_area(
277		DRIVER_PREFIX " cloned display_modes",
278		(void **)&my_mode_list,
279		B_ANY_ADDRESS,
280		B_READ_AREA,
281		si->mode_area
282	);
283	if (result < B_OK) goto error2;
284
285	/* all done */
286	LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
287
288	result = B_OK;
289	goto error0;
290
291error2:
292	/* free up the areas we cloned */
293	uninit_common();
294error1:
295	/* close the device we opened */
296	close(fd);
297error0:
298	return result;
299}
300
301void UNINIT_ACCELERANT(void)
302{
303	if (accelerantIsClone)
304	{
305		LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n"));
306	}
307	else
308	{
309		LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n"));
310
311		/* delete benaphores ONLY if we are the primary accelerant */
312		DELETE_BEN(si->engine.lock);
313		DELETE_BEN(si->overlay.lock);
314	}
315
316	/* free our mode list area */
317	delete_area(my_mode_list_area);
318	/* paranoia */
319	my_mode_list = 0;
320	/* release our cloned data */
321	uninit_common();
322	/* close the file handle ONLY if we're the clone */
323	if (accelerantIsClone) close(fd);
324}
325