xref: /haiku/src/add-ons/kernel/drivers/graphics/neomagic/driver.c (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
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 	Apsed;
8 	Rudolf Cornelissen 5/2002-4/2004.
9 */
10 
11 /* standard kernel driver stuff */
12 #include <KernelExport.h>
13 #include <ISA.h>
14 #include <PCI.h>
15 #include <OS.h>
16 #include <driver_settings.h>
17 #include <malloc.h>
18 #include <stdlib.h> // for strtoXX
19 
20 /* this is for the standardized portion of the driver API */
21 /* currently only one operation is defined: B_GET_ACCELERANT_SIGNATURE */
22 #include <graphic_driver.h>
23 
24 /* this is for sprintf() */
25 #include <stdio.h>
26 
27 /* this is for string compares */
28 #include <string.h>
29 
30 /* The private interface between the accelerant and the kernel driver. */
31 #include "DriverInterface.h"
32 #include "nm_macros.h"
33 
34 #define get_pci(o, s) (*pci_bus->read_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s))
35 #define set_pci(o, s, v) (*pci_bus->write_pci_config)(pcii->bus, pcii->device, pcii->function, (o), (s), (v))
36 #define KISAGRPHW(A,B)(isa_bus->write_io_16(NMISA16_GRPHIND, ((NMGRPHX_##A) | ((B) << 8))))
37 #define KISAGRPHR(A)  (isa_bus->write_io_8(NMISA8_GRPHIND, (NMGRPHX_##A)), isa_bus->read_io_8(NMISA8_GRPHDAT))
38 #define KISASEQW(A,B)(isa_bus->write_io_16(NMISA16_SEQIND, ((NMSEQX_##A) | ((B) << 8))))
39 
40 #define MAX_DEVICES	  8
41 
42 #define DEVICE_FORMAT "%04X_%04X_%02X%02X%02X" // apsed
43 
44 /* Tell the kernel what revision of the driver API we support */
45 int32	api_version = B_CUR_DRIVER_API_VERSION; // apsed, was 2, is 2 in R5
46 
47 /* these structures are private to the kernel driver */
48 typedef struct device_info device_info;
49 
50 typedef struct {
51 	timer		te;				/* timer entry for add_timer() */
52 	device_info	*di;			/* pointer to the owning device */
53 	bigtime_t	when_target;	/* when we're supposed to wake up */
54 } timer_info;
55 
56 struct device_info {
57 	uint32		is_open;			/* a count of how many times the devices has been opened */
58 	area_id		shared_area;		/* the area shared between the driver and all of the accelerants */
59 	shared_info	*si;				/* a pointer to the shared area, for convenience */
60 	vuint32		*regs, *regs2;		/* kernel's pointer to memory mapped registers */
61 	pci_info	pcii;					/* a convenience copy of the pci info for this device */
62 	char		name[B_OS_NAME_LENGTH];	/* where we keep the name of the device for publishing and comparing */
63 };
64 
65 typedef struct {
66 	uint32		count;				/* number of devices actually found */
67 	benaphore	kernel;				/* for serializing opens/closes */
68 	char		*device_names[MAX_DEVICES+1];	/* device name pointer storage */
69 	device_info	di[MAX_DEVICES];	/* device specific stuff */
70 } DeviceData;
71 
72 /* prototypes for our private functions */
73 static status_t open_hook (const char* name, uint32 flags, void** cookie);
74 static status_t close_hook (void* dev);
75 static status_t free_hook (void* dev);
76 static status_t read_hook (void* dev, off_t pos, void* buf, size_t* len);
77 static status_t write_hook (void* dev, off_t pos, const void* buf, size_t* len);
78 static status_t control_hook (void* dev, uint32 msg, void *buf, size_t len);
79 static status_t map_device(device_info *di);
80 static void unmap_device(device_info *di);
81 static void probe_devices(void);
82 static int32 nm_interrupt(void *data);
83 void drv_program_bes_ISA(nm_bes_data *bes);
84 
85 static DeviceData		*pd;
86 static pci_module_info	*pci_bus;
87 static isa_module_info	*isa_bus;
88 
89 static device_hooks graphics_device_hooks = {
90 	open_hook,
91 	close_hook,
92 	free_hook,
93 	control_hook,
94 	read_hook,
95 	write_hook,
96 	NULL,
97 	NULL,
98 	NULL,
99 	NULL
100 };
101 
102 #define VENDOR_ID			0x10c8	/* Neomagic inc. */
103 
104 static uint16 nm_device_list[] = {
105 	0x0001,	/* MagicGraph 128 (NM2070) */
106 	0x0002,	/* MagicGraph 128V (NM2090)	0x42 */
107 	0x0003,	/* MagicGraph 128ZV (NM2093) 0x43 */
108 	0x0083, /* MagicGraph 128ZV+ (NM2097) */
109 	0x0004, /* MagicGraph 128XD (NM2160) 0x44 */
110 	0x0005,	/* MagicMedia 256AV (NM2200) 0x45 */
111 	0x0025,	/* MagicMedia 256AV+ (NM2230) */
112 	0x0006,	/* MagicMedia 256ZX (NM2360) */
113 	0x0016,	/* MagicMedia 256XL+ (NM2380) */
114 	0
115 };
116 
117 static struct {
118 	uint16	vendor;
119 	uint16	*devices;
120 } SupportedDevices[] = {
121 	{VENDOR_ID, nm_device_list},
122 	{0x0000, NULL}
123 };
124 
125 static settings current_settings = { // see comments in nm.settings
126 	// for driver
127 	DRIVER_PREFIX ".accelerant",
128 	false,      // dumprom
129 	// for accelerant
130 	0x00000000, // logmask
131 	0,          // memory
132 	false,      // usebios
133 	false,      // hardcursor
134 };
135 
136 static void dumprom (void *rom, size_t size)
137 {
138 	int fd = open ("/boot/home/" DRIVER_PREFIX ".rom", O_WRONLY | O_CREAT, 0666);
139 	if (fd < 0) return;
140 	write (fd, rom, size);
141 	close (fd);
142 }
143 
144 /*return 1, is interrupt has occured*/
145 static int caused_vbi(vuint32 * regs, vuint32 * regs2)
146 {
147 //	return (ACCR(STATUS)&0x20);
148 return 0;
149 }
150 
151 /*clear the interrupt*/
152 static void clear_vbi(vuint32 * regs, vuint32 * regs2)
153 {
154 //	ACCW(ICLEAR,0x20);
155 }
156 
157 static void enable_vbi(vuint32 * regs, vuint32 * regs2)
158 {
159 //	ACCW(IEN,ACCR(IEN)|0x20);
160 }
161 
162 static void disable_vbi(vuint32 * regs, vuint32 * regs2)
163 {
164 //	ACCW(IEN,(ACCR(IEN)&~0x20));
165 //	ACCW(ICLEAR,0x20);
166 }
167 
168 
169 /*
170 	init_hardware() - Returns B_OK if one is
171 	found, otherwise returns B_ERROR so the driver will be unloaded.
172 */
173 status_t
174 init_hardware(void) {
175 	long		pci_index = 0;
176 	pci_info	pcii;
177 	bool		found_one = FALSE;
178 
179 	/* choke if we can't find the PCI bus */
180 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
181 		return B_ERROR;
182 
183 	/* choke if we can't find the ISA bus */
184 	if (get_module(B_ISA_MODULE_NAME, (module_info **)&isa_bus) != B_OK)
185 		return B_ERROR;
186 
187 	/* while there are more pci devices */
188 	while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) {
189 		int vendor = 0;
190 
191 		/* if we match a supported vendor */
192 		while (SupportedDevices[vendor].vendor) {
193 			if (SupportedDevices[vendor].vendor == pcii.vendor_id) {
194 				uint16 *devices = SupportedDevices[vendor].devices;
195 				/* while there are more supported devices */
196 				while (*devices) {
197 					/* if we match a supported device */
198 					if (*devices == pcii.device_id ) {
199 
200 						found_one = TRUE;
201 						goto done;
202 					}
203 					/* next supported device */
204 					devices++;
205 				}
206 			}
207 			vendor++;
208 		}
209 		/* next pci_info struct, please */
210 		pci_index++;
211 	}
212 
213 done:
214 	/* put away the module managers */
215 	put_module(B_PCI_MODULE_NAME);
216 	put_module(B_ISA_MODULE_NAME);
217 
218 	return (found_one ? B_OK : B_ERROR);
219 }
220 
221 status_t
222 init_driver(void) {
223 	void *settings_handle;
224 
225 	// get driver/accelerant settings, apsed
226 	settings_handle  = load_driver_settings (DRIVER_PREFIX ".settings");
227 	if (settings_handle != NULL) {
228 		const char *item;
229 		char       *end;
230 		uint32      value;
231 
232 		// for driver
233 		item = get_driver_parameter (settings_handle, "accelerant", "", "");
234 		if ((strlen (item) > 0) && (strlen (item) < sizeof (current_settings.accelerant) - 1)) {
235 			strcpy (current_settings.accelerant, item);
236 		}
237 		current_settings.dumprom = get_driver_boolean_parameter (settings_handle, "dumprom", false, false);
238 
239 		// for accelerant
240 		item = get_driver_parameter (settings_handle, "logmask", "0x00000000", "0x00000000");
241 		value = strtoul (item, &end, 0);
242 		if (*end == '\0') current_settings.logmask = value;
243 
244 		item = get_driver_parameter (settings_handle, "memory", "0", "0");
245 		value = strtoul (item, &end, 0);
246 		if (*end == '\0') current_settings.memory = value;
247 
248 		current_settings.hardcursor = get_driver_boolean_parameter (settings_handle, "hardcursor", false, false);
249 		current_settings.usebios = get_driver_boolean_parameter (settings_handle, "usebios", false, false);
250 
251 		unload_driver_settings (settings_handle);
252 	}
253 
254 	/* get a handle for the pci bus */
255 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
256 		return B_ERROR;
257 
258 	/* get a handle for the isa bus */
259 	if (get_module(B_ISA_MODULE_NAME, (module_info **)&isa_bus) != B_OK)
260 		return B_ERROR;
261 
262 	/* driver private data */
263 	pd = (DeviceData *)calloc(1, sizeof(DeviceData));
264 	if (!pd) {
265 		put_module(B_PCI_MODULE_NAME);
266 		put_module(B_ISA_MODULE_NAME);
267 		return B_ERROR;
268 	}
269 	/* initialize the benaphore */
270 	INIT_BEN(pd->kernel);
271 	/* find all of our supported devices */
272 	probe_devices();
273 	return B_OK;
274 }
275 
276 const char **
277 publish_devices(void) {
278 	/* return the list of supported devices */
279 	return (const char **)pd->device_names;
280 }
281 
282 device_hooks *
283 find_device(const char *name) {
284 	int index = 0;
285 	while (pd->device_names[index]) {
286 		if (strcmp(name, pd->device_names[index]) == 0)
287 			return &graphics_device_hooks;
288 		index++;
289 	}
290 	return NULL;
291 
292 }
293 
294 void uninit_driver(void) {
295 
296 	/* free the driver data */
297 	DELETE_BEN(pd->kernel);
298 	free(pd);
299 	pd = NULL;
300 
301 	/* put the pci modules away */
302 	put_module(B_PCI_MODULE_NAME);
303 	put_module(B_ISA_MODULE_NAME);
304 }
305 
306 static status_t map_device(device_info *di)
307 {
308 	char buffer[B_OS_NAME_LENGTH]; /*memory for device name*/
309 	shared_info *si = di->si;
310 	uint32	tmpUlong;
311 	pci_info *pcii = &(di->pcii);
312 	system_info sysinfo;
313 
314 	/*variables for making copy of ROM*/
315 	char * rom_temp;
316 	area_id rom_area;
317 
318 	int frame_buffer = 0;
319 	/* only NM2097 and later cards have two register area's:
320 	 * older cards have their PCI registers in the frame_buffer space */
321 	int registers = 1;
322 	int registers2 = 2;
323 
324 	/* enable memory mapped IO, disable VGA I/O - this is standard*/
325 	tmpUlong = get_pci(PCI_command, 4);
326 	/* make sure ISA access is enabled: all Neomagic cards still partly rely on this */
327 	tmpUlong |= PCI_command_io;
328 	/* make sure PCI access is enabled */
329 	tmpUlong |= PCI_command_memory;
330 	tmpUlong |= PCI_command_master;
331 	set_pci(PCI_command, 4, tmpUlong);
332 
333  	/*work out which version of BeOS is running*/
334  	get_system_info(&sysinfo);
335  	if (sysinfo.kernel_build_date[0]=='J')/*FIXME - better ID version*/
336  	{
337  		si->use_clone_bugfix = 1;
338  	}
339  	else
340  	{
341  		si->use_clone_bugfix = 0;
342  	}
343 
344 	/* map card's register area's */
345 	switch (di->pcii.device_id)
346 	{
347 	case 0x0001:
348 	case 0x0002:
349 	case 0x0003:
350 		/* NM2070, NM2090 and NM2093 have no seperate register area's,
351 		 * so do nothing here except notify accelerant. */
352 		si->regs_in_fb = true;
353 		break;
354 	default:
355 		/* we map the registers seperately from the framebuffer */
356 		si->regs_in_fb = false;
357 		/* work out a name for the register mapping */
358 		sprintf(buffer, DEVICE_FORMAT " regs",
359 			di->pcii.vendor_id, di->pcii.device_id,
360 			di->pcii.bus, di->pcii.device, di->pcii.function);
361 
362 		/* get a virtual memory address for the registers*/
363 		si->regs_area = map_physical_memory(
364 			buffer,
365 			(void *) di->pcii.u.h0.base_registers[registers],
366 			di->pcii.u.h0.base_register_sizes[registers],
367 			B_ANY_KERNEL_ADDRESS,
368  			(si->use_clone_bugfix ? B_READ_AREA|B_WRITE_AREA : 0),
369 			(void **)&(di->regs));
370  		si->clone_bugfix_regs = (uint32 *) di->regs;
371 
372 		/* if mapping registers to vmem failed then pass on error */
373 		if (si->regs_area < 0) return si->regs_area;
374 
375 		/* work out a name for the register mapping */
376 		sprintf(buffer, DEVICE_FORMAT " regs2",
377 			di->pcii.vendor_id, di->pcii.device_id,
378 			di->pcii.bus, di->pcii.device, di->pcii.function);
379 
380 		si->regs2_area = map_physical_memory(
381 			buffer,
382 			(void *) di->pcii.u.h0.base_registers[registers2],
383 			di->pcii.u.h0.base_register_sizes[registers2],
384 			B_ANY_KERNEL_ADDRESS,
385 			(si->use_clone_bugfix ? B_READ_AREA|B_WRITE_AREA : 0),
386 			(void **)&(di->regs2));
387 	 	si->clone_bugfix_regs2 = (uint32 *) di->regs2;
388 
389 		/* if mapping registers to vmem failed then pass on error */
390 		if (si->regs2_area < 0)
391 		{
392 			delete_area(si->regs_area);
393 			si->regs_area = -1;
394 
395 			return si->regs2_area;
396 		}
397 		break;
398 	}
399 
400 	/* work out a name for the ROM mapping*/
401 	sprintf(buffer, DEVICE_FORMAT " rom",
402 		di->pcii.vendor_id, di->pcii.device_id,
403 		di->pcii.bus, di->pcii.device, di->pcii.function);
404 
405 	/*place ROM over the fbspace (this is definately safe)*/
406 	tmpUlong = di->pcii.u.h0.base_registers[frame_buffer];
407 	tmpUlong |= 0x00000001;
408 	set_pci(PCI_rom_base, 4, tmpUlong);
409 
410 	rom_area = map_physical_memory(
411 		buffer,
412 		(void *)di->pcii.u.h0.base_registers[frame_buffer],
413 		32768,
414 		B_ANY_KERNEL_ADDRESS,
415 		B_READ_AREA,
416 		(void **)&(rom_temp)
417 	);
418 
419 	/* if mapping ROM to vmem failed then clean up and pass on error */
420 	if (rom_area < 0) {
421 		if (si->regs_area >= 0)
422 		{
423 			delete_area(si->regs_area);
424 			si->regs_area = -1;
425 		}
426 		if (si->regs2_area >= 0)
427 		{
428 			delete_area(si->regs2_area);
429 			si->regs2_area = -1;
430 		}
431 		return rom_area;
432 	}
433 
434 	/* make a copy of ROM for future reference*/
435 	memcpy (si->rom_mirror, rom_temp, 32768);
436 	if (current_settings.dumprom) dumprom (rom_temp, 32768);
437 
438 	/*disable ROM and delete the area*/
439 	set_pci(PCI_rom_base,4,0);
440 	delete_area(rom_area);
441 
442 	/* work out a name for the framebuffer mapping*/
443 	sprintf(buffer, DEVICE_FORMAT " framebuffer",
444 		di->pcii.vendor_id, di->pcii.device_id,
445 		di->pcii.bus, di->pcii.device, di->pcii.function);
446 
447 	/* map the framebuffer into vmem, using Write Combining*/
448 	si->fb_area = map_physical_memory(
449 		buffer,
450 		(void *) di->pcii.u.h0.base_registers[frame_buffer],
451 		di->pcii.u.h0.base_register_sizes[frame_buffer],
452 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
453 		B_READ_AREA + B_WRITE_AREA,
454 		&(si->framebuffer));
455 
456 	/*if failed with write combining try again without*/
457 	if (si->fb_area < 0) {
458 		si->fb_area = map_physical_memory(
459 			buffer,
460 			(void *) di->pcii.u.h0.base_registers[frame_buffer],
461 			di->pcii.u.h0.base_register_sizes[frame_buffer],
462 			B_ANY_KERNEL_BLOCK_ADDRESS,
463 			B_READ_AREA + B_WRITE_AREA,
464 			&(si->framebuffer));
465 	}
466 
467 	/* if there was an error, delete our other areas and pass on error*/
468 	if (si->fb_area < 0)
469 	{
470 		if (si->regs_area >= 0)
471 		{
472 			delete_area(si->regs_area);
473 			si->regs_area = -1;
474 		}
475 		if (si->regs2_area >= 0)
476 		{
477 			delete_area(si->regs2_area);
478 			si->regs2_area = -1;
479 		}
480 		return si->fb_area;
481 	}
482 
483 	/* older cards have their registers in the framebuffer area */
484 	switch (di->pcii.device_id)
485 	{
486 	case 0x0001:
487 		/* NM2070 cards */
488 		di->regs = (uint32 *)((uint8 *)si->framebuffer + 0x100000);
489  		si->clone_bugfix_regs = (uint32 *) di->regs;
490 		break;
491 	case 0x0002:
492 	case 0x0003:
493 		/* NM2090 and NM2093 cards */
494 		di->regs = (uint32 *)((uint8 *)si->framebuffer + 0x200000);
495  		si->clone_bugfix_regs = (uint32 *) di->regs;
496 		break;
497 	}
498 
499 	/* remember the DMA address of the frame buffer for BDirectWindow?? purposes */
500 	si->framebuffer_pci = (void *) di->pcii.u.h0.base_registers_pci[frame_buffer];
501 
502 	// remember settings for use here and in accelerant
503 	si->settings = current_settings;
504 
505 	/* in any case, return the result */
506 	return si->fb_area;
507 }
508 
509 static void unmap_device(device_info *di) {
510 	shared_info *si = di->si;
511 	uint32	tmpUlong;
512 	pci_info *pcii = &(di->pcii);
513 
514 	/* disable memory mapped IO */
515 	tmpUlong = get_pci(PCI_command, 4);
516 	tmpUlong &= 0xfffffffc;
517 	set_pci(PCI_command, 4, tmpUlong);
518 	/* delete the areas */
519 	if (si->regs2_area >= 0) delete_area(si->regs2_area);
520 	if (si->regs_area >= 0) delete_area(si->regs_area);
521 	if (si->fb_area >= 0) delete_area(si->fb_area);
522 	si->regs2_area = si->regs_area = si->fb_area = -1;
523 	si->framebuffer = NULL;
524 	di->regs = NULL;
525 }
526 
527 static void probe_devices(void) {
528 	uint32 pci_index = 0;
529 	uint32 count = 0;
530 	device_info *di = pd->di;
531 
532 	/* while there are more pci devices */
533 	while ((count < MAX_DEVICES) && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) {
534 		int vendor = 0;
535 
536 		/* if we match a supported vendor */
537 		while (SupportedDevices[vendor].vendor) {
538 			if (SupportedDevices[vendor].vendor == di->pcii.vendor_id) {
539 				uint16 *devices = SupportedDevices[vendor].devices;
540 				/* while there are more supported devices */
541 				while (*devices) {
542 					/* if we match a supported device */
543 					if (*devices == di->pcii.device_id ) {
544 						/* publish the device name */
545 						sprintf(di->name, "graphics/" DEVICE_FORMAT,
546 							di->pcii.vendor_id, di->pcii.device_id,
547 							di->pcii.bus, di->pcii.device, di->pcii.function);
548 
549 						/* remember the name */
550 						pd->device_names[count] = di->name;
551 						/* mark the driver as available for R/W open */
552 						di->is_open = 0;
553 						/* mark areas as not yet created */
554 						di->shared_area = -1;
555 						/* mark pointer to shared data as invalid */
556 						di->si = NULL;
557 						/* inc pointer to device info */
558 						di++;
559 						/* inc count */
560 						count++;
561 						/* break out of these while loops */
562 						goto next_device;
563 					}
564 					/* next supported device */
565 					devices++;
566 				}
567 			}
568 			vendor++;
569 		}
570 next_device:
571 		/* next pci_info struct, please */
572 		pci_index++;
573 	}
574 	/* propagate count */
575 	pd->count = count;
576 	/* terminate list of device names with a null pointer */
577 	pd->device_names[pd->count] = NULL;
578 }
579 
580 static uint32 thread_interrupt_work(int32 *flags, vuint32 *regs, vuint32 *regs2, shared_info *si) {
581 	uint32 handled = B_HANDLED_INTERRUPT;
582 	/* release the vblank semaphore */
583 	if (si->vblank >= 0) {
584 		int32 blocked;
585 		if ((get_sem_count(si->vblank, &blocked) == B_OK) && (blocked < 0)) {
586 			release_sem_etc(si->vblank, -blocked, B_DO_NOT_RESCHEDULE);
587 			handled = B_INVOKE_SCHEDULER;
588 		}
589 	}
590 	return handled;
591 }
592 
593 static int32
594 nm_interrupt(void *data)
595 {
596 	int32 handled = B_UNHANDLED_INTERRUPT;
597 	device_info *di = (device_info *)data;
598 	shared_info *si = di->si;
599 	int32 *flags = &(si->flags);
600 	vuint32 *regs, *regs2;
601 
602 	/* is someone already handling an interrupt for this device? */
603 	if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) {
604 		goto exit0;
605 	}
606 	/* get regs */
607 	regs = di->regs;
608 	regs2 = di->regs2;
609 
610 	/* was it a VBI? */
611 	if (caused_vbi(regs, regs2)) {
612 		/*clear the interrupt*/
613 		clear_vbi(regs, regs2);
614 		/*release the semaphore*/
615 		handled = thread_interrupt_work(flags, regs, regs2, si);
616 	}
617 
618 	/* note that we're not in the handler any more */
619 	atomic_and(flags, ~SKD_HANDLER_INSTALLED);
620 
621 exit0:
622 	return handled;
623 }
624 
625 static status_t open_hook (const char* name, uint32 flags, void** cookie) {
626 	int32 index = 0;
627 	device_info *di;
628 	shared_info *si;
629 	thread_id	thid;
630 	thread_info	thinfo;
631 	status_t	result = B_OK;
632 	vuint32		*regs, *regs2;
633 	char shared_name[B_OS_NAME_LENGTH];
634 
635 	/* find the device name in the list of devices */
636 	/* we're never passed a name we didn't publish */
637 	while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++;
638 
639 	/* for convienience */
640 	di = &(pd->di[index]);
641 
642 	/* make sure no one else has write access to the common data */
643 	AQUIRE_BEN(pd->kernel);
644 
645 	/* if it's already open for writing */
646 	if (di->is_open) {
647 		/* mark it open another time */
648 		goto mark_as_open;
649 	}
650 	/* create the shared area */
651 	sprintf(shared_name, DEVICE_FORMAT " shared",
652 		di->pcii.vendor_id, di->pcii.device_id,
653 		di->pcii.bus, di->pcii.device, di->pcii.function);
654 	/* create this area with NO user-space read or write permissions, to prevent accidental dammage */
655 	di->shared_area = create_area(shared_name, (void **)&(di->si), B_ANY_KERNEL_ADDRESS, ((sizeof(shared_info) + (B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1)), B_FULL_LOCK, 0);
656 	if (di->shared_area < 0) {
657 		/* return the error */
658 		result = di->shared_area;
659 		goto done;
660 	}
661 
662 	/* save a few dereferences */
663 	si = di->si;
664 
665 	/* save the vendor and device IDs */
666 	si->vendor_id = di->pcii.vendor_id;
667 	si->device_id = di->pcii.device_id;
668 	si->revision = di->pcii.revision;
669 
670 	/* map the device */
671 	result = map_device(di);
672 	if (result < 0) goto free_shared;
673 	result = B_OK;
674 
675 	/* create a semaphore for vertical blank management */
676 	si->vblank = create_sem(0, di->name);
677 	if (si->vblank < 0) {
678 		result = si->vblank;
679 		goto unmap;
680 	}
681 
682 	/* change the owner of the semaphores to the opener's team */
683 	/* this is required because apps can't aquire kernel semaphores */
684 	thid = find_thread(NULL);
685 	get_thread_info(thid, &thinfo);
686 	set_sem_owner(si->vblank, thinfo.team);
687 
688 	/* assign local regs pointer for SAMPLExx() macros */
689 	regs = di->regs;
690 	regs2 = di->regs2;
691 
692 	/* disable and clear any pending interrupts */
693 	disable_vbi(regs, regs2);
694 
695 	/* If there is a valid interrupt line assigned then set up interrupts */
696 	if ((di->pcii.u.h0.interrupt_pin == 0x00) ||
697 	    (di->pcii.u.h0.interrupt_line == 0xff) || /* no IRQ assigned */
698 	    (di->pcii.u.h0.interrupt_line <= 0x02))   /* system IRQ assigned */
699 	{
700 		/* we are aborting! */
701 		/* Note: the R4 graphics driver kit lacks this statement!! */
702 		result = B_ERROR;
703 		/* interrupt does not exist so exit without installing our handler */
704 		goto delete_the_sem;
705 	}
706 	else
707 	{
708 		/* otherwise install our interrupt handler */
709 		result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, nm_interrupt, (void *)di, 0);
710 		/* bail if we couldn't install the handler */
711 		if (result != B_OK) goto delete_the_sem;
712 	}
713 
714 mark_as_open:
715 	/* mark the device open */
716 	di->is_open++;
717 
718 	/* send the cookie to the opener */
719 	*cookie = di;
720 
721 	goto done;
722 
723 
724 delete_the_sem:
725 	delete_sem(si->vblank);
726 
727 unmap:
728 	unmap_device(di);
729 
730 free_shared:
731 	/* clean up our shared area */
732 	delete_area(di->shared_area);
733 	di->shared_area = -1;
734 	di->si = NULL;
735 
736 done:
737 	/* end of critical section */
738 	RELEASE_BEN(pd->kernel);
739 
740 	/* all done, return the status */
741 	return result;
742 }
743 
744 /* ----------
745 	read_hook - does nothing, gracefully
746 ----- */
747 static status_t
748 read_hook (void* dev, off_t pos, void* buf, size_t* len)
749 {
750 	*len = 0;
751 	return B_NOT_ALLOWED;
752 }
753 
754 
755 /* ----------
756 	write_hook - does nothing, gracefully
757 ----- */
758 static status_t
759 write_hook (void* dev, off_t pos, const void* buf, size_t* len)
760 {
761 	*len = 0;
762 	return B_NOT_ALLOWED;
763 }
764 
765 /* ----------
766 	close_hook - does nothing, gracefully
767 ----- */
768 static status_t
769 close_hook (void* dev)
770 {
771 	/* we don't do anything on close: there might be dup'd fd */
772 	return B_NO_ERROR;
773 }
774 
775 /* -----------
776 	free_hook - close down the device
777 ----------- */
778 static status_t
779 free_hook (void* dev) {
780 	device_info *di = (device_info *)dev;
781 	shared_info	*si = di->si;
782 	vuint32 *regs = di->regs;
783 	vuint32 *regs2 = di->regs2;
784 
785 	/* lock the driver */
786 	AQUIRE_BEN(pd->kernel);
787 
788 	/* if opened multiple times, decrement the open count and exit */
789 	if (di->is_open > 1)
790 		goto unlock_and_exit;
791 
792 	/* disable and clear any pending interrupts */
793 	disable_vbi(regs, regs2);
794 
795 	/* remove interrupt handler */
796 	remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, nm_interrupt, di);
797 
798 	/* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */
799 	delete_sem(si->vblank);
800 	si->vblank = -1;
801 
802 	/* free regs and framebuffer areas */
803 	unmap_device(di);
804 
805 	/* clean up our shared area */
806 	delete_area(di->shared_area);
807 	di->shared_area = -1;
808 	di->si = NULL;
809 
810 unlock_and_exit:
811 	/* mark the device available */
812 	di->is_open--;
813 	/* unlock the driver */
814 	RELEASE_BEN(pd->kernel);
815 	/* all done */
816 	return B_OK;
817 }
818 
819 /* -----------
820 	control_hook - where the real work is done
821 ----------- */
822 static status_t
823 control_hook (void* dev, uint32 msg, void *buf, size_t len) {
824 	device_info *di = (device_info *)dev;
825 	status_t result = B_DEV_INVALID_IOCTL;
826 
827 	switch (msg) {
828 		/* the only PUBLIC ioctl */
829 		case B_GET_ACCELERANT_SIGNATURE: {
830 			char *sig = (char *)buf;
831 			strcpy(sig, current_settings.accelerant);
832 			result = B_OK;
833 		} break;
834 
835 		/* PRIVATE ioctl from here on */
836 		case NM_GET_PRIVATE_DATA: {
837 			nm_get_private_data *gpd = (nm_get_private_data *)buf;
838 			if (gpd->magic == NM_PRIVATE_DATA_MAGIC) {
839 				gpd->shared_info_area = di->shared_area;
840 				result = B_OK;
841 			}
842 		} break;
843 		case NM_GET_PCI: {
844 			nm_get_set_pci *gsp = (nm_get_set_pci *)buf;
845 			if (gsp->magic == NM_PRIVATE_DATA_MAGIC) {
846 				pci_info *pcii = &(di->pcii);
847 				gsp->value = get_pci(gsp->offset, gsp->size);
848 				result = B_OK;
849 			}
850 		} break;
851 		case NM_SET_PCI: {
852 			nm_get_set_pci *gsp = (nm_get_set_pci *)buf;
853 			if (gsp->magic == NM_PRIVATE_DATA_MAGIC) {
854 				pci_info *pcii = &(di->pcii);
855 				set_pci(gsp->offset, gsp->size, gsp->value);
856 				result = B_OK;
857 			}
858 		} break;
859 		case NM_DEVICE_NAME: {
860 			nm_device_name *dn = (nm_device_name *)buf;
861 			if (dn->magic == NM_PRIVATE_DATA_MAGIC) {
862 				strcpy(dn->name, di->name);
863 				result = B_OK;
864 			}
865 		} break;
866 		case NM_RUN_INTERRUPTS: {
867 			nm_set_bool_state *ri = (nm_set_bool_state *)buf;
868 			if (ri->magic == NM_PRIVATE_DATA_MAGIC) {
869 				vuint32 *regs = di->regs;
870 				vuint32 *regs2 = di->regs2;
871 				if (ri->do_it) {
872 					enable_vbi(regs, regs2);
873 				} else {
874 					disable_vbi(regs, regs2);
875 				}
876 				result = B_OK;
877 			}
878 		} break;
879 		case NM_ISA_OUT: {
880 			nm_in_out_isa *io_isa = (nm_in_out_isa *)buf;
881 			if (io_isa->magic == NM_PRIVATE_DATA_MAGIC) {
882 				if (io_isa->size == 1)
883   					isa_bus->write_io_8(io_isa->adress, (uint8)io_isa->data);
884    				else
885    					isa_bus->write_io_16(io_isa->adress, io_isa->data);
886   				result = B_OK;
887    			}
888 		} break;
889 		case NM_ISA_IN: {
890 			nm_in_out_isa *io_isa = (nm_in_out_isa *)buf;
891 			if (io_isa->magic == NM_PRIVATE_DATA_MAGIC) {
892 				if (io_isa->size == 1)
893 	   				io_isa->data = isa_bus->read_io_8(io_isa->adress);
894 	   			else
895 	   				io_isa->data = isa_bus->read_io_16(io_isa->adress);
896    				result = B_OK;
897    			}
898 		} break;
899 		case NM_PGM_BES: {
900 			nm_bes_data *bes_isa = (nm_bes_data *)buf;
901 			if (bes_isa->magic == NM_PRIVATE_DATA_MAGIC) {
902 				drv_program_bes_ISA(bes_isa);
903   				result = B_OK;
904    			}
905 		} break;
906 	}
907 	return result;
908 }
909 
910 void drv_program_bes_ISA(nm_bes_data *bes)
911 {
912 	uint8 temp;
913 
914 	/* ISA card */
915 	/* unlock card overlay sequencer registers (b5 = 1) */
916 	temp = (KISAGRPHR(GENLOCK) | 0x20);
917 	/* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */
918 	snooze(10);
919 	KISAGRPHW(GENLOCK, temp);
920 	/* destination rectangle */
921 	KISAGRPHW(HDCOORD1L, ((bes->hcoordv >> 16) & 0xff));
922 	KISAGRPHW(HDCOORD2L, (bes->hcoordv & 0xff));
923 	KISAGRPHW(HDCOORD21H, (((bes->hcoordv >> 4) & 0xf0) | ((bes->hcoordv >> 24) & 0x0f)));
924 	KISAGRPHW(VDCOORD1L, ((bes->vcoordv >> 16) & 0xff));
925 	KISAGRPHW(VDCOORD2L, (bes->vcoordv & 0xff));
926 	KISAGRPHW(VDCOORD21H, (((bes->vcoordv >> 4) & 0xf0) | ((bes->vcoordv >> 24) & 0x0f)));
927 	/* scaling */
928 	KISAGRPHW(XSCALEL, (bes->hiscalv & 0xff));
929 	KISAGRPHW(XSCALEH, ((bes->hiscalv >> 8) & 0xff));
930 	KISAGRPHW(YSCALEL, (bes->viscalv & 0xff));
931 	KISAGRPHW(YSCALEH, ((bes->viscalv >> 8) & 0xff));
932 	/* inputbuffer #1 origin */
933 	/* (we don't program buffer #2 as it's unused.) */
934 	/* first include 'pixel precise' left clipping...
935 	 * (subpixel precision is not supported by NeoMagic cards) */
936 	bes->a1orgv += ((bes->hsrcstv >> 16) * 2);
937 	/* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */
938 	bes->a1orgv &= ~0x03;
939 	/* now setup buffer startadress and horizontal source end (minimizes used bandwidth) */
940 	if (bes->card_type < NM2200)
941 	{
942 		bes->a1orgv >>= 1;
943 		/* horizontal source end does not use subpixelprecision: granularity is 8 pixels */
944 		KISAGRPHW(0xbc, (((((bes->hsrcendv >> 16) + 7) & ~8) / 8) - 1));
945 	}
946 	else
947 	{
948 		/* horizontal source end does not use subpixelprecision: granularity is 16 pixels */
949 		//fixme? divide by 16 instead of 8 (if >= NM2200 owners report trouble then use 8!)
950 		//fixme? check if overlaybuffer width should also have granularity of 16 now!
951 		KISAGRPHW(0xbc, (((((bes->hsrcendv >> 16) + 15) & ~16) / 16) - 1));
952 	}
953 	KISAGRPHW(BUF1ORGL, (bes->a1orgv & 0xff));
954 	KISAGRPHW(BUF1ORGM, ((bes->a1orgv >> 8) & 0xff));
955 	KISAGRPHW(BUF1ORGH, ((bes->a1orgv >> 16) & 0xff));
956 	/* b2 = 0: don't use horizontal mirroring (NM2160) */
957 	/* other bits do ??? */
958 	KISAGRPHW(0xbf, 0x02);
959 	/* ??? */
960 	KISAGRPHW(0xbd, 0x02);
961 	KISAGRPHW(0xbe, 0x00);
962 	/* (subpixel precise) source rect clipping is not supported on NeoMagic cards;
963 	 * so we do 'pixel precise' left clipping via modification of buffer
964 	 * startadress above instead.
965 	 * (pixel precise top clipping is also done this way..) */
966 	//fixme: checkout real pixel precise clipping on NM2200 and later cards!!!
967 /*
968 	{
969 		uint16 left = 0;
970 		uint16 right = 128;
971 		uint16 top = 0;
972 		uint16 bottom = 128;
973 
974 		left = (bes->hsrcstv >> 16);
975 		right = (bes->hsrclstv >> 16);
976 		top = (bes->weight >> 16);
977 		bottom = (bes->v1srclstv >> 16);
978 
979 		KISASEQW(HSCOORD1L, (left & 0xff));
980 		KISASEQW(HSCOORD2L, (right & 0xff));
981 		KISASEQW(HSCOORD21H, (((right >> 4) & 0xf0) | ((left >> 8) & 0x0f)));
982 		KISASEQW(VSCOORD1L, (top & 0xff));
983 		KISASEQW(VSCOORD2L, (bottom & 0xff));
984 		KISASEQW(VSCOORD21H, (((bottom >> 4) & 0xf0) | ((top >> 8) & 0x0f)));
985 	}
986 */
987 	/* ??? */
988     KISASEQW(0x1c, 0xfb);
989    	KISASEQW(0x1d, 0x00);
990 	KISASEQW(0x1e, 0xe2);
991    	KISASEQW(0x1f, 0x02);
992 	/* b1 = 0: disable alternating hardware buffers (NM2160) */
993 	/* other bits do ??? */
994 	KISASEQW(0x09, 0x11);
995 	/* ??? */
996 	KISASEQW(0x0a, 0x00);
997 	/* global BES control */
998 	KISAGRPHW(BESCTRL1, (bes->globctlv & 0xff));
999 	KISASEQW(BESCTRL2, ((bes->globctlv >> 8) & 0xff));
1000 
1001 
1002 	/**************************
1003 	 *** setup color keying ***
1004 	 **************************/
1005 
1006 	KISAGRPHW(COLKEY_R, bes->colkey_r);
1007 	KISAGRPHW(COLKEY_G, bes->colkey_g);
1008 	KISAGRPHW(COLKEY_B, bes->colkey_b);
1009 
1010 
1011 	/*************************
1012 	 *** setup misc. stuff ***
1013 	 *************************/
1014 
1015 	/* setup brightness to be 'neutral' (two's complement number) */
1016 	KISAGRPHW(BRIGHTNESS, 0x00);
1017 
1018 	/* setup inputbuffer #1 pitch including slopspace (in pixels) */
1019 	/* (we don't program the pitch for inputbuffer #2 as it's unused.) */
1020 	KISAGRPHW(BUF1PITCHL, (bes->ob_width & 0xff));
1021 	KISAGRPHW(BUF1PITCHH, ((bes->ob_width >> 8) & 0xff));
1022 }
1023