xref: /haiku/src/add-ons/accelerants/nvidia/InitAccelerant.c (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
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/2016.
8 */
9 
10 #define MODULE_BIT 0x00800000
11 
12 #include <string.h>
13 #include <unistd.h>
14 #include "acc_std.h"
15 
16 static status_t init_common(int the_fd);
17 
18 /* Initialization code shared between primary and cloned accelerants */
19 static status_t init_common(int the_fd) {
20 	status_t result;
21 	nv_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 = NV_PRIVATE_DATA_MAGIC;
29 	/* contact driver and get a pointer to the registers and shared data */
30 	result = ioctl(fd, NV_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, dma_acc %d, tv_output %d, vga_on_tv %d\n",
45 		si->settings.dumprom, si->settings.unhide_fw, si->settings.pgm_panel, si->settings.dma_acc, si->settings.tv_output, si->settings.vga_on_tv));
46 	LOG(4,("init_common: force_sync %d, gpu_clk %dMhz, ram_clk %dMhz, force_ws %d, block_acc %d, check_edid %d\n",
47 		si->settings.force_sync, si->settings.gpu_clk, si->settings.ram_clk, si->settings.force_ws, si->settings.block_acc, si->settings.check_edid));
48 
49  	/*Check for R4.5.0 and if it is running, use work around*/
50  	{
51  		if (si->use_clone_bugfix)
52  		{
53  			/*check for R4.5.0 bug and attempt to work around*/
54  			LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n"));
55  			regs = si->clone_bugfix_regs;
56  		}
57  		else
58  		{
59 			/* clone the memory mapped registers for our use  - does not work on <4.5.2 (but is better this way)*/
60 			regs_area = clone_area(DRIVER_PREFIX " regs", (void **)&regs, B_ANY_ADDRESS,
61 				B_READ_AREA | B_WRITE_AREA, si->regs_area);
62 			if (regs_area < 0) {
63 				result = regs_area;
64 				goto error1;
65 			}
66  		}
67  	}
68 
69 	/* all done */
70 	goto error0;
71 
72 error1:
73 	delete_area(shared_info_area);
74 error0:
75 	return result;
76 }
77 
78 /* Clean up code shared between primary and cloned accelrants */
79 static 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 /*
91 Initialize 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).
93 We need to determine if the kernel driver and the accelerant are compatible.
94 If they are, get the accelerant ready to handle other hook functions and
95 report success or failure.
96 */
97 status_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: %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 	/* 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 	/* call the device specific init code */
128 	result = nv_general_powerup();
129 
130 	/* bail out if it failed */
131 	if (result != B_OK)
132 		goto error1;
133 
134 	/*
135 	Now would be a good time to figure out what video modes your card supports.
136 	We'll place the list of modes in another shared area so all of the copies
137 	of the driver can see them.  The primary copy of the accelerant (ie the one
138 	initialized with this routine) will own the "one true copy" of the list.
139 	Everybody else get's a read-only clone.
140 	*/
141 	result = create_mode_list();
142 	if (result != B_OK)
143 		goto error1;
144 
145 	/*
146 	Put the cursor at the start of the frame buffer.
147 	Nvidia cursor is 32x32 16 color? takes up 4096 bytes of RAM.
148 	*/
149 	/* Initialize the rest of the cursor information while we're here */
150 	si->cursor.width = 16;
151 	si->cursor.height = 16;
152 	si->cursor.hot_x = 0;
153 	si->cursor.hot_y = 0;
154 	si->cursor.x = 0;
155 	si->cursor.y = 0;
156 	si->cursor.dh_right = false;
157 
158 	/*
159 	Put the frame buffer immediately following the cursor data. We store this
160 	info in a frame_buffer_config structure to make it convienient to return
161 	to the app_server later.
162 	*/
163 	pointer_reservation = 0;
164 	/* Nvidia hardcursor needs 2kB space */
165 	if (si->settings.hardcursor) pointer_reservation = 2048;
166 
167 	si->fbc.frame_buffer = (void *)((char *)si->framebuffer+pointer_reservation);
168 	si->fbc.frame_buffer_dma = (void *)((char *)si->framebuffer_pci+pointer_reservation);
169 
170 	/* count of issued parameters or commands */
171 	si->engine.last_idle = si->engine.count = 0;
172 	/* no 3D clones are currently loaded */
173 	si->engine.threeD.clones = 0;
174 	/* tell 3D add-ons that they should reload their rendering states and surfaces */
175 	si->engine.threeD.reload = 0xffffffff;
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 
186 	/* make sure overlay unit is 'marked' as being free */
187 	si->overlay.myToken = NULL;
188 
189 	/* note that overlay is not in use (for nv_bes_move_overlay()) */
190 	si->overlay.active = false;
191 
192 	/* initialise various cursor stuff */
193 	head1_cursor_init();
194 	if (si->ps.secondary_head) head2_cursor_init();
195 
196 	/* ensure cursor state */
197 	head1_cursor_hide();
198 	if (si->ps.secondary_head) head2_cursor_hide();
199 
200 	/* ensure DPMS state */
201 	si->dpms_flags = B_DPMS_ON;
202 
203 	/* ensure TVout state:
204 	 * TVencoder is on head to be assigned primary, no dualhead switch mode active. */
205 	//fixme: actually check on what CRTC TVout was active during boot (if any)...
206 	si->dm.flags = TV_PRIMARY;
207 
208 	/* make sure a possible 3D add-on will block rendering and re-initialize itself.
209 	 * note: update in _this_ order only */
210 	/* SET_DISPLAY_MODE will reset this flag when it's done. */
211 	si->engine.threeD.mode_changing = true;
212 	/* every 3D add-on will reset this bit-flag when it's done. */
213 	si->engine.threeD.newmode = 0xffffffff;
214 
215 	/* we did not detect the Haiku ScreenPrefs app yet */
216 	si->haiku_prefs_used = false;
217 	si->Haiku_switch_head = false;
218 
219 	/* a winner! */
220 	result = B_OK;
221 	/* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */
222 	si->accelerant_in_use = true;
223 	goto error0;
224 
225 error1:
226 	/*
227 	Initialization failed after init_common() succeeded, so we need to clean
228 	up before quiting.
229 	*/
230 	uninit_common();
231 
232 error0:
233 	return result;
234 }
235 
236 /*
237 Return the number of bytes required to hold the information required
238 to clone the device.
239 */
240 ssize_t ACCELERANT_CLONE_INFO_SIZE(void) {
241 	/*
242 	Since we're passing the name of the device as the only required
243 	info, return the size of the name buffer
244 	*/
245 	return B_OS_NAME_LENGTH; // apsed, was MAX_NV_DEVICE_NAME_LENGTH;
246 }
247 
248 
249 /*
250 Return the info required to clone the device.  void *data points to
251 a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
252 */
253 void GET_ACCELERANT_CLONE_INFO(void *data) {
254 	nv_device_name dn;
255 	status_t result;
256 
257 	/* call the kernel driver to get the device name */
258 	dn.magic = NV_PRIVATE_DATA_MAGIC;
259 	/* store the returned info directly into the passed buffer */
260 	dn.name = (char *)data;
261 	result = ioctl(fd, NV_DEVICE_NAME, &dn, sizeof(dn));
262 }
263 
264 /*
265 Initialize a copy of the accelerant as a clone.  void *data points to
266 a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
267 */
268 status_t CLONE_ACCELERANT(void *data)
269 {
270 	status_t result;
271 	char path[MAXPATHLEN];
272 
273 	/* the data is the device name */
274 	/* Note: the R4 graphics driver kit is in error here (missing trailing '/') */
275 	strcpy(path, "/dev/");
276 	strcat(path, (const char *)data);
277 	/* open the device, the permissions aren't important */
278 	fd = open(path, B_READ_WRITE);
279 	if (fd < 0)
280 	{
281 		/* we can't use LOG because we didn't get the shared_info struct.. */
282 		char     fname[64];
283 		FILE    *myhand = NULL;
284 
285 		sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log");
286 		myhand=fopen(fname,"a+");
287 		fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path);
288 		fclose(myhand);
289 
290 		/* abort with resultcode from open attempt on kerneldriver */
291 		result = fd;
292 		goto error0;
293 	}
294 
295 	/* note that we're a clone accelerant */
296 	accelerantIsClone = 1;
297 
298 	/* call the shared initialization code */
299 	result = init_common(fd);
300 
301 	/* bail out if the common initialization failed */
302 	if (result != B_OK) goto error1;
303 
304 	/* ensure that INIT_ACCELERANT is executed first (i.e. primary accelerant exists) */
305 	if (!(si->accelerant_in_use))
306 	{
307 		result = B_NOT_ALLOWED;
308 		goto error2;
309 	}
310 
311 	/* setup CRTC and DAC functions access */
312 	//fixme: setup_virtualized_heads is a problem for clones: needs to be run
313 	//for each clone if the mode is changed!
314 	if (si->ps.secondary_head)
315 		setup_virtualized_heads(si->crtc_switch_mode);
316 	else
317 		setup_virtualized_heads(si->ps.crtc2_prim);
318 
319 	/* get shared area for display modes */
320 	result = my_mode_list_area = clone_area(
321 		DRIVER_PREFIX " cloned display_modes",
322 		(void **)&my_mode_list,
323 		B_ANY_ADDRESS,
324 		B_READ_AREA,
325 		si->mode_area
326 	);
327 	if (result < B_OK) goto error2;
328 
329 	/* all done */
330 	LOG(4,("CLONE_ACCELERANT: cloning was succesfull.\n"));
331 
332 	result = B_OK;
333 	goto error0;
334 
335 error2:
336 	/* free up the areas we cloned */
337 	uninit_common();
338 error1:
339 	/* close the device we opened */
340 	close(fd);
341 error0:
342 	return result;
343 }
344 
345 void UNINIT_ACCELERANT(void)
346 {
347 	if (accelerantIsClone)
348 	{
349 		LOG(4,("UNINIT_ACCELERANT: shutting down clone accelerant.\n"));
350 	}
351 	else
352 	{
353 		LOG(4,("UNINIT_ACCELERANT: shutting down primary accelerant.\n"));
354 
355 		/* delete benaphores ONLY if we are the primary accelerant */
356 		DELETE_BEN(si->engine.lock);
357 		DELETE_BEN(si->overlay.lock);
358 
359 		/* ensure that INIT_ACCELERANT can be executed again */
360 		si->accelerant_in_use = false;
361 	}
362 
363 	/* free our mode list area */
364 	delete_area(my_mode_list_area);
365 	/* paranoia */
366 	my_mode_list = 0;
367 	/* release our cloned data */
368 	uninit_common();
369 	/* close the file handle ONLY if we're the clone */
370 	if (accelerantIsClone) close(fd);
371 }
372