xref: /haiku/src/add-ons/accelerants/neomagic/InitAccelerant.c (revision 2600324b57fa31cdea1627d584d314f2a579c4a8)
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 "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 {
21 	status_t result;
22 	nm_get_private_data gpd;
23 
24 	// LOG not available from here to next LOG: NULL si
25 
26 	/* memorize the file descriptor */
27 	fd = the_fd;
28 	/* set the magic number so the driver knows we're for real */
29 	gpd.magic = NM_PRIVATE_DATA_MAGIC;
30 	/* contact driver and get a pointer to the registers and shared data */
31 	result = ioctl(fd, NM_GET_PRIVATE_DATA, &gpd, sizeof(gpd));
32 	if (result != B_OK) 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\n",
43 		si->settings.logmask, si->settings.memory, si->settings.hardcursor, si->settings.usebios));
44 
45 	/* clone register area(s) */
46 	if (si->regs_in_fb)
47 	{
48 		/* we can't clone as no register area exists! */
49 		LOG(2,("InitACC: Can't clone register area, integrated in framebuffer!\n"));
50 
51 		/* the kerneldriver already did some calcs for us */
52 		regs = si->clone_bugfix_regs;
53 		/* not used */
54 		regs2 = 0;
55 	}
56 	else
57  	{
58  		/*Check for R4.5.0 and if it is running, use work around*/
59  		if (si->use_clone_bugfix)
60  		{
61  			/*check for R4.5.0 bug and attempt to work around*/
62  			LOG(2,("InitACC: Found R4.5.0 bug - attempting to work around\n"));
63  			regs = si->clone_bugfix_regs;
64  			regs2 = si->clone_bugfix_regs2;
65  		}
66  		else
67  		{
68 			/* clone the memory mapped registers for our use  - does not work on <4.5.2 (but is better this way)*/
69 			regs_area = clone_area(DRIVER_PREFIX " regs", (void **)&regs, B_ANY_ADDRESS,
70 				B_READ_AREA | B_WRITE_AREA, si->regs_area);
71 			if (regs_area < 0)
72 			{
73 				result = regs_area;
74 				goto error1;
75 			}
76 			else
77 			{
78 				regs2_area = clone_area(DRIVER_PREFIX " regs2", (void **)&regs2, B_ANY_ADDRESS,
79 				B_READ_AREA | B_WRITE_AREA, si->regs2_area);
80 				if (regs2_area < 0)
81 				{
82 					result = regs2_area;
83 					goto error2;
84 				}
85 			}
86  		}
87  	}
88 
89 	/*FIXME - print dma addresses*/
90 	//LOG(4,("DMA_virtual:%x\tDMA_physical:%x\tDMA_area:%x\n",si->dma_buffer,si->dma_buffer_pci,si->dma_buffer_area));
91 
92 	/* all done */
93 	goto error0;
94 
95 error2:
96 	delete_area(regs_area);
97 error1:
98 	delete_area(shared_info_area);
99 error0:
100 	return result;
101 }
102 
103 /* Clean up code shared between primary and cloned accelrants */
104 static void uninit_common(void)
105 {
106 	/* release the memory mapped registers if they exist */
107 	if (si->ps.card_type > NM2093)
108 	{
109 		delete_area(regs2_area);
110 		delete_area(regs_area);
111 	}
112 	/* a little cheap paranoia */
113 	regs = 0;
114 	regs2 = 0;
115 	/* release our copy of the shared info from the kernel driver */
116 	delete_area(shared_info_area);
117 	/* more cheap paranoia */
118 	si = 0;
119 }
120 
121 /*
122 Initialize the accelerant.  the_fd is the file handle of the device (in
123 /dev/graphics) that has been opened by the app_server (or some test harness).
124 We need to determine if the kernel driver and the accelerant are compatible.
125 If they are, get the accelerant ready to handle other hook functions and
126 report success or failure.
127 */
128 status_t INIT_ACCELERANT(int the_fd)
129 {
130 	status_t result;
131 	int cnt; 				 //used for iteration through the overlay buffers
132 
133 	if (0) {
134 		time_t now = time (NULL);
135 		// LOG not available from here to next LOG: NULL si
136 		MSG(("INIT_ACCELERANT: %s", ctime (&now)));
137 	}
138 
139 	/* note that we're the primary accelerant (accelerantIsClone is global) */
140 	accelerantIsClone = 0;
141 
142 	/* do the initialization common to both the primary and the clones */
143 	result = init_common(the_fd);
144 
145 	/* bail out if the common initialization failed */
146 	if (result != B_OK) goto error0;
147 	// LOG now available: !NULL si
148 
149 	/* ensure that INIT_ACCELERANT is executed just once (copies should be clones) */
150 	if (si->accelerant_in_use)
151 	{
152 		result = B_NOT_ALLOWED;
153 		goto error1;
154 	}
155 
156 	/* call the device specific init code */
157 	result = nm_general_powerup();
158 
159 	/* bail out if it failed */
160 	if (result != B_OK) goto error1;
161 
162 	/*
163 	Now would be a good time to figure out what video modes your card supports.
164 	We'll place the list of modes in another shared area so all of the copies
165 	of the driver can see them.  The primary copy of the accelerant (ie the one
166 	initialized with this routine) will own the "one true copy" of the list.
167 	Everybody else get's a read-only clone.
168 	*/
169 	result = create_mode_list();
170 	if (result != B_OK)
171 	{
172 		goto error1;
173 	}
174 
175 	/*
176 	Put the cursor at the start of the frame buffer.  The typical 64x64 4 color
177 	(black, white, transparent, inverse) takes up 1024 bytes of RAM.
178 	*/
179 	/* Initialize the rest of the cursor information while we're here */
180 	si->cursor.width = 16;
181 	si->cursor.height = 16;
182 	si->cursor.hot_x = 0;
183 	si->cursor.hot_y = 0;
184 	si->cursor.x = 0;
185 	si->cursor.y = 0;
186 
187 	/*
188 	Put the frame buffer at the beginning of the cardRAM because the acc engine
189 	does not support offsets, or we lack info to get that ability. We store this
190 	info in a frame_buffer_config structure to make it convienient to return
191 	to the app_server later.
192 	*/
193 	si->fbc.frame_buffer = si->framebuffer;
194 	si->fbc.frame_buffer_dma = si->framebuffer_pci;
195 
196 	/* count of issued parameters or commands */
197 	si->engine.last_idle = si->engine.count = 0;
198 	INIT_BEN(si->engine.lock);
199 
200 	INIT_BEN(si->overlay.lock);
201 	for (cnt = 0; cnt < MAXBUFFERS; cnt++)
202 	{
203 		/* make sure overlay buffers are 'marked' as being free */
204 		si->overlay.myBuffer[cnt].buffer = NULL;
205 		si->overlay.myBuffer[cnt].buffer_dma = NULL;
206 	}
207 	/* make sure overlay unit is 'marked' as being free */
208 	si->overlay.myToken = NULL;
209 
210 	/* note that overlay is not in use (for nm_bes_move_overlay()) */
211 	si->overlay.active = false;
212 
213 	/* bail out if something failed */
214 	if (result != B_OK) goto error1;
215 
216 	/* initialise various cursor stuff*/
217 	nm_crtc_cursor_init();
218 
219 	/* ensure cursor state */
220 	SHOW_CURSOR(false);
221 
222 	/* ensure DPMS state */
223 	si->dpms_flags = B_DPMS_ON;
224 
225 	/* a winner! */
226 	result = B_OK;
227 	/* ensure that INIT_ACCELERANT won't be executed again (copies should be clones) */
228 	si->accelerant_in_use = true;
229 	goto error0;
230 
231 error1:
232 	/*
233 	Initialization failed after init_common() succeeded, so we need to clean
234 	up before quiting.
235 	*/
236 	uninit_common();
237 
238 error0:
239 	return result;
240 }
241 
242 /*
243 Return the number of bytes required to hold the information required
244 to clone the device.
245 */
246 ssize_t ACCELERANT_CLONE_INFO_SIZE(void)
247 {
248 	/*
249 	Since we're passing the name of the device as the only required
250 	info, return the size of the name buffer
251 	*/
252 	return B_OS_NAME_LENGTH;
253 }
254 
255 
256 /*
257 Return the info required to clone the device.  void *data points to
258 a buffer at least ACCELERANT_CLONE_INFO_SIZE() bytes in length.
259 */
260 void GET_ACCELERANT_CLONE_INFO(void *data)
261 {
262 	nm_device_name dn;
263 	status_t result;
264 
265 	/* call the kernel driver to get the device name */
266 	dn.magic = NM_PRIVATE_DATA_MAGIC;
267 	/* store the returned info directly into the passed buffer */
268 	dn.name = (char *)data;
269 	result = ioctl(fd, NM_DEVICE_NAME, &dn, sizeof(dn));
270 }
271 
272 /*
273 Initialize a copy of the accelerant as a clone.  void *data points to
274 a copy of the data returned by GET_ACCELERANT_CLONE_INFO().
275 */
276 status_t CLONE_ACCELERANT(void *data)
277 {
278 	status_t result;
279 	char path[MAXPATHLEN];
280 
281 	/* the data is the device name */
282 	/* Note: the R4 graphics driver kit is in error here (missing trailing '/') */
283 	strcpy(path, "/dev/");
284 	strcat(path, (const char *)data);
285 	/* open the device, the permissions aren't important */
286 	fd = open(path, B_READ_WRITE);
287 	if (fd < 0)
288 	{
289 		/* we can't use LOG because we didn't get the shared_info struct.. */
290 		char     fname[64];
291 		FILE    *myhand = NULL;
292 
293 		sprintf (fname, "/boot/home/" DRIVER_PREFIX ".accelerant.0.log");
294 		myhand=fopen(fname,"a+");
295 		fprintf(myhand, "CLONE_ACCELERANT: couldn't open kerneldriver %s! Aborting.\n", path);
296 		fclose(myhand);
297 
298 		/* abort with resultcode from open attempt on kerneldriver */
299 		result = fd;
300 		goto error0;
301 	}
302 
303 	/* note that we're a clone accelerant */
304 	accelerantIsClone = 1;
305 
306 	/* call the shared initialization code */
307 	result = init_common(fd);
308 
309 	/* bail out if the common initialization failed */
310 	if (result != B_OK) goto error1;
311 
312 	/* ensure that INIT_ACCELERANT is executed first (i.e. primary accelerant exists) */
313 	if (!(si->accelerant_in_use))
314 	{
315 		result = B_NOT_ALLOWED;
316 		goto error2;
317 	}
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