xref: /haiku/src/add-ons/kernel/drivers/graphics/neomagic/driver.c (revision db10640de90f7f9519ba2da9577b7c1af3c64f6b)
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-8/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 	{
186 		put_module(B_PCI_MODULE_NAME);
187 		return B_ERROR;
188 	}
189 
190 	/* while there are more pci devices */
191 	while ((*pci_bus->get_nth_pci_info)(pci_index, &pcii) == B_NO_ERROR) {
192 		int vendor = 0;
193 
194 		/* if we match a supported vendor */
195 		while (SupportedDevices[vendor].vendor) {
196 			if (SupportedDevices[vendor].vendor == pcii.vendor_id) {
197 				uint16 *devices = SupportedDevices[vendor].devices;
198 				/* while there are more supported devices */
199 				while (*devices) {
200 					/* if we match a supported device */
201 					if (*devices == pcii.device_id ) {
202 
203 						found_one = TRUE;
204 						goto done;
205 					}
206 					/* next supported device */
207 					devices++;
208 				}
209 			}
210 			vendor++;
211 		}
212 		/* next pci_info struct, please */
213 		pci_index++;
214 	}
215 
216 done:
217 	/* put away the module managers */
218 	put_module(B_PCI_MODULE_NAME);
219 	put_module(B_ISA_MODULE_NAME);
220 
221 	return (found_one ? B_OK : B_ERROR);
222 }
223 
224 status_t
225 init_driver(void) {
226 	void *settings_handle;
227 
228 	// get driver/accelerant settings, apsed
229 	settings_handle  = load_driver_settings (DRIVER_PREFIX ".settings");
230 	if (settings_handle != NULL) {
231 		const char *item;
232 		char       *end;
233 		uint32      value;
234 
235 		// for driver
236 		item = get_driver_parameter (settings_handle, "accelerant", "", "");
237 		if ((strlen (item) > 0) && (strlen (item) < sizeof (current_settings.accelerant) - 1)) {
238 			strcpy (current_settings.accelerant, item);
239 		}
240 		current_settings.dumprom = get_driver_boolean_parameter (settings_handle, "dumprom", false, false);
241 
242 		// for accelerant
243 		item = get_driver_parameter (settings_handle, "logmask", "0x00000000", "0x00000000");
244 		value = strtoul (item, &end, 0);
245 		if (*end == '\0') current_settings.logmask = value;
246 
247 		item = get_driver_parameter (settings_handle, "memory", "0", "0");
248 		value = strtoul (item, &end, 0);
249 		if (*end == '\0') current_settings.memory = value;
250 
251 		current_settings.hardcursor = get_driver_boolean_parameter (settings_handle, "hardcursor", false, false);
252 		current_settings.usebios = get_driver_boolean_parameter (settings_handle, "usebios", false, false);
253 
254 		unload_driver_settings (settings_handle);
255 	}
256 
257 	/* get a handle for the pci bus */
258 	if (get_module(B_PCI_MODULE_NAME, (module_info **)&pci_bus) != B_OK)
259 		return B_ERROR;
260 
261 	/* get a handle for the isa bus */
262 	if (get_module(B_ISA_MODULE_NAME, (module_info **)&isa_bus) != B_OK)
263 	{
264 		put_module(B_PCI_MODULE_NAME);
265 		return B_ERROR;
266 	}
267 
268 	/* driver private data */
269 	pd = (DeviceData *)calloc(1, sizeof(DeviceData));
270 	if (!pd) {
271 		put_module(B_PCI_MODULE_NAME);
272 		put_module(B_ISA_MODULE_NAME);
273 		return B_ERROR;
274 	}
275 	/* initialize the benaphore */
276 	INIT_BEN(pd->kernel);
277 	/* find all of our supported devices */
278 	probe_devices();
279 	return B_OK;
280 }
281 
282 const char **
283 publish_devices(void) {
284 	/* return the list of supported devices */
285 	return (const char **)pd->device_names;
286 }
287 
288 device_hooks *
289 find_device(const char *name) {
290 	int index = 0;
291 	while (pd->device_names[index]) {
292 		if (strcmp(name, pd->device_names[index]) == 0)
293 			return &graphics_device_hooks;
294 		index++;
295 	}
296 	return NULL;
297 
298 }
299 
300 void uninit_driver(void) {
301 
302 	/* free the driver data */
303 	DELETE_BEN(pd->kernel);
304 	free(pd);
305 	pd = NULL;
306 
307 	/* put the pci modules away */
308 	put_module(B_PCI_MODULE_NAME);
309 	put_module(B_ISA_MODULE_NAME);
310 }
311 
312 static status_t map_device(device_info *di)
313 {
314 	char buffer[B_OS_NAME_LENGTH]; /*memory for device name*/
315 	shared_info *si = di->si;
316 	uint32	tmpUlong;
317 	pci_info *pcii = &(di->pcii);
318 	system_info sysinfo;
319 
320 	/*variables for making copy of ROM*/
321 	char * rom_temp;
322 	area_id rom_area;
323 
324 	int frame_buffer = 0;
325 	/* only NM2097 and later cards have two register area's:
326 	 * older cards have their PCI registers in the frame_buffer space */
327 	int registers = 1;
328 	int registers2 = 2;
329 
330 	/* enable memory mapped IO, disable VGA I/O - this is standard*/
331 	tmpUlong = get_pci(PCI_command, 4);
332 	/* make sure ISA access is enabled: all Neomagic cards still partly rely on this */
333 	tmpUlong |= PCI_command_io;
334 	/* make sure PCI access is enabled */
335 	tmpUlong |= PCI_command_memory;
336 	tmpUlong |= PCI_command_master;
337 	set_pci(PCI_command, 4, tmpUlong);
338 
339  	/*work out which version of BeOS is running*/
340  	get_system_info(&sysinfo);
341  	if (sysinfo.kernel_build_date[0]=='J')/*FIXME - better ID version*/
342  	{
343  		si->use_clone_bugfix = 1;
344  	}
345  	else
346  	{
347  		si->use_clone_bugfix = 0;
348  	}
349 
350 	/* map card's register area's */
351 	switch (di->pcii.device_id)
352 	{
353 	case 0x0001:
354 	case 0x0002:
355 	case 0x0003:
356 		/* NM2070, NM2090 and NM2093 have no seperate register area's,
357 		 * so do nothing here except notify accelerant. */
358 		si->regs_in_fb = true;
359 		break;
360 	default:
361 		/* we map the registers seperately from the framebuffer */
362 		si->regs_in_fb = false;
363 		/* work out a name for the register mapping */
364 		sprintf(buffer, DEVICE_FORMAT " regs",
365 			di->pcii.vendor_id, di->pcii.device_id,
366 			di->pcii.bus, di->pcii.device, di->pcii.function);
367 
368 		/* get a virtual memory address for the registers*/
369 		si->regs_area = map_physical_memory(
370 			buffer,
371 			(void *) di->pcii.u.h0.base_registers[registers],
372 			di->pcii.u.h0.base_register_sizes[registers],
373 			B_ANY_KERNEL_ADDRESS,
374  			(si->use_clone_bugfix ? B_READ_AREA|B_WRITE_AREA : 0),
375 			(void **)&(di->regs));
376  		si->clone_bugfix_regs = (uint32 *) di->regs;
377 
378 		/* if mapping registers to vmem failed then pass on error */
379 		if (si->regs_area < 0) return si->regs_area;
380 
381 		/* work out a name for the register mapping */
382 		sprintf(buffer, DEVICE_FORMAT " regs2",
383 			di->pcii.vendor_id, di->pcii.device_id,
384 			di->pcii.bus, di->pcii.device, di->pcii.function);
385 
386 		si->regs2_area = map_physical_memory(
387 			buffer,
388 			(void *) di->pcii.u.h0.base_registers[registers2],
389 			di->pcii.u.h0.base_register_sizes[registers2],
390 			B_ANY_KERNEL_ADDRESS,
391 			(si->use_clone_bugfix ? B_READ_AREA|B_WRITE_AREA : 0),
392 			(void **)&(di->regs2));
393 	 	si->clone_bugfix_regs2 = (uint32 *) di->regs2;
394 
395 		/* if mapping registers to vmem failed then pass on error */
396 		if (si->regs2_area < 0)
397 		{
398 			delete_area(si->regs_area);
399 			si->regs_area = -1;
400 
401 			return si->regs2_area;
402 		}
403 		break;
404 	}
405 
406 	/* work out a name for the ROM mapping*/
407 	sprintf(buffer, DEVICE_FORMAT " rom",
408 		di->pcii.vendor_id, di->pcii.device_id,
409 		di->pcii.bus, di->pcii.device, di->pcii.function);
410 
411 	/*place ROM over the fbspace (this is definately safe)*/
412 	tmpUlong = di->pcii.u.h0.base_registers[frame_buffer];
413 	tmpUlong |= 0x00000001;
414 	set_pci(PCI_rom_base, 4, tmpUlong);
415 
416 	rom_area = map_physical_memory(
417 		buffer,
418 		(void *)di->pcii.u.h0.base_registers[frame_buffer],
419 		32768,
420 		B_ANY_KERNEL_ADDRESS,
421 		B_READ_AREA,
422 		(void **)&(rom_temp)
423 	);
424 
425 	/* if mapping ROM to vmem failed then clean up and pass on error */
426 	if (rom_area < 0) {
427 		if (si->regs_area >= 0)
428 		{
429 			delete_area(si->regs_area);
430 			si->regs_area = -1;
431 		}
432 		if (si->regs2_area >= 0)
433 		{
434 			delete_area(si->regs2_area);
435 			si->regs2_area = -1;
436 		}
437 		return rom_area;
438 	}
439 
440 	/* make a copy of ROM for future reference*/
441 	memcpy (si->rom_mirror, rom_temp, 32768);
442 	if (current_settings.dumprom) dumprom (rom_temp, 32768);
443 
444 	/*disable ROM and delete the area*/
445 	set_pci(PCI_rom_base,4,0);
446 	delete_area(rom_area);
447 
448 	/* work out a name for the framebuffer mapping*/
449 	sprintf(buffer, DEVICE_FORMAT " framebuffer",
450 		di->pcii.vendor_id, di->pcii.device_id,
451 		di->pcii.bus, di->pcii.device, di->pcii.function);
452 
453 	/* map the framebuffer into vmem, using Write Combining*/
454 	si->fb_area = map_physical_memory(
455 		buffer,
456 		(void *) di->pcii.u.h0.base_registers[frame_buffer],
457 		di->pcii.u.h0.base_register_sizes[frame_buffer],
458 		B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC,
459 		B_READ_AREA + B_WRITE_AREA,
460 		&(si->framebuffer));
461 
462 	/*if failed with write combining try again without*/
463 	if (si->fb_area < 0) {
464 		si->fb_area = map_physical_memory(
465 			buffer,
466 			(void *) di->pcii.u.h0.base_registers[frame_buffer],
467 			di->pcii.u.h0.base_register_sizes[frame_buffer],
468 			B_ANY_KERNEL_BLOCK_ADDRESS,
469 			B_READ_AREA + B_WRITE_AREA,
470 			&(si->framebuffer));
471 	}
472 
473 	/* if there was an error, delete our other areas and pass on error*/
474 	if (si->fb_area < 0)
475 	{
476 		if (si->regs_area >= 0)
477 		{
478 			delete_area(si->regs_area);
479 			si->regs_area = -1;
480 		}
481 		if (si->regs2_area >= 0)
482 		{
483 			delete_area(si->regs2_area);
484 			si->regs2_area = -1;
485 		}
486 		return si->fb_area;
487 	}
488 
489 	/* older cards have their registers in the framebuffer area */
490 	switch (di->pcii.device_id)
491 	{
492 	case 0x0001:
493 		/* NM2070 cards */
494 		di->regs = (uint32 *)((uint8 *)si->framebuffer + 0x100000);
495  		si->clone_bugfix_regs = (uint32 *) di->regs;
496 		break;
497 	case 0x0002:
498 	case 0x0003:
499 		/* NM2090 and NM2093 cards */
500 		di->regs = (uint32 *)((uint8 *)si->framebuffer + 0x200000);
501  		si->clone_bugfix_regs = (uint32 *) di->regs;
502 		break;
503 	}
504 
505 	/* remember the DMA address of the frame buffer for BDirectWindow?? purposes */
506 	si->framebuffer_pci = (void *) di->pcii.u.h0.base_registers_pci[frame_buffer];
507 
508 	// remember settings for use here and in accelerant
509 	si->settings = current_settings;
510 
511 	/* in any case, return the result */
512 	return si->fb_area;
513 }
514 
515 static void unmap_device(device_info *di) {
516 	shared_info *si = di->si;
517 	uint32	tmpUlong;
518 	pci_info *pcii = &(di->pcii);
519 
520 	/* disable memory mapped IO */
521 	tmpUlong = get_pci(PCI_command, 4);
522 	tmpUlong &= 0xfffffffc;
523 	set_pci(PCI_command, 4, tmpUlong);
524 	/* delete the areas */
525 	if (si->regs2_area >= 0) delete_area(si->regs2_area);
526 	if (si->regs_area >= 0) delete_area(si->regs_area);
527 	if (si->fb_area >= 0) delete_area(si->fb_area);
528 	si->regs2_area = si->regs_area = si->fb_area = -1;
529 	si->framebuffer = NULL;
530 	di->regs = NULL;
531 }
532 
533 static void probe_devices(void) {
534 	uint32 pci_index = 0;
535 	uint32 count = 0;
536 	device_info *di = pd->di;
537 
538 	/* while there are more pci devices */
539 	while ((count < MAX_DEVICES) && ((*pci_bus->get_nth_pci_info)(pci_index, &(di->pcii)) == B_NO_ERROR)) {
540 		int vendor = 0;
541 
542 		/* if we match a supported vendor */
543 		while (SupportedDevices[vendor].vendor) {
544 			if (SupportedDevices[vendor].vendor == di->pcii.vendor_id) {
545 				uint16 *devices = SupportedDevices[vendor].devices;
546 				/* while there are more supported devices */
547 				while (*devices) {
548 					/* if we match a supported device */
549 					if (*devices == di->pcii.device_id ) {
550 						/* publish the device name */
551 						sprintf(di->name, "graphics/" DEVICE_FORMAT,
552 							di->pcii.vendor_id, di->pcii.device_id,
553 							di->pcii.bus, di->pcii.device, di->pcii.function);
554 
555 						/* remember the name */
556 						pd->device_names[count] = di->name;
557 						/* mark the driver as available for R/W open */
558 						di->is_open = 0;
559 						/* mark areas as not yet created */
560 						di->shared_area = -1;
561 						/* mark pointer to shared data as invalid */
562 						di->si = NULL;
563 						/* inc pointer to device info */
564 						di++;
565 						/* inc count */
566 						count++;
567 						/* break out of these while loops */
568 						goto next_device;
569 					}
570 					/* next supported device */
571 					devices++;
572 				}
573 			}
574 			vendor++;
575 		}
576 next_device:
577 		/* next pci_info struct, please */
578 		pci_index++;
579 	}
580 	/* propagate count */
581 	pd->count = count;
582 	/* terminate list of device names with a null pointer */
583 	pd->device_names[pd->count] = NULL;
584 }
585 
586 static uint32 thread_interrupt_work(int32 *flags, vuint32 *regs, vuint32 *regs2, shared_info *si) {
587 	uint32 handled = B_HANDLED_INTERRUPT;
588 	/* release the vblank semaphore */
589 	if (si->vblank >= 0) {
590 		int32 blocked;
591 		if ((get_sem_count(si->vblank, &blocked) == B_OK) && (blocked < 0)) {
592 			release_sem_etc(si->vblank, -blocked, B_DO_NOT_RESCHEDULE);
593 			handled = B_INVOKE_SCHEDULER;
594 		}
595 	}
596 	return handled;
597 }
598 
599 static int32
600 nm_interrupt(void *data)
601 {
602 	int32 handled = B_UNHANDLED_INTERRUPT;
603 	device_info *di = (device_info *)data;
604 	shared_info *si = di->si;
605 	int32 *flags = &(si->flags);
606 	vuint32 *regs, *regs2;
607 
608 	/* is someone already handling an interrupt for this device? */
609 	if (atomic_or(flags, SKD_HANDLER_INSTALLED) & SKD_HANDLER_INSTALLED) {
610 		goto exit0;
611 	}
612 	/* get regs */
613 	regs = di->regs;
614 	regs2 = di->regs2;
615 
616 	/* was it a VBI? */
617 	if (caused_vbi(regs, regs2)) {
618 		/*clear the interrupt*/
619 		clear_vbi(regs, regs2);
620 		/*release the semaphore*/
621 		handled = thread_interrupt_work(flags, regs, regs2, si);
622 	}
623 
624 	/* note that we're not in the handler any more */
625 	atomic_and(flags, ~SKD_HANDLER_INSTALLED);
626 
627 exit0:
628 	return handled;
629 }
630 
631 static status_t open_hook (const char* name, uint32 flags, void** cookie) {
632 	int32 index = 0;
633 	device_info *di;
634 	shared_info *si;
635 	thread_id	thid;
636 	thread_info	thinfo;
637 	status_t	result = B_OK;
638 	vuint32		*regs, *regs2;
639 	char shared_name[B_OS_NAME_LENGTH];
640 
641 	/* find the device name in the list of devices */
642 	/* we're never passed a name we didn't publish */
643 	while (pd->device_names[index] && (strcmp(name, pd->device_names[index]) != 0)) index++;
644 
645 	/* for convienience */
646 	di = &(pd->di[index]);
647 
648 	/* make sure no one else has write access to the common data */
649 	AQUIRE_BEN(pd->kernel);
650 
651 	/* if it's already open for writing */
652 	if (di->is_open) {
653 		/* mark it open another time */
654 		goto mark_as_open;
655 	}
656 	/* create the shared area */
657 	sprintf(shared_name, DEVICE_FORMAT " shared",
658 		di->pcii.vendor_id, di->pcii.device_id,
659 		di->pcii.bus, di->pcii.device, di->pcii.function);
660 	/* create this area with NO user-space read or write permissions, to prevent accidental dammage */
661 	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);
662 	if (di->shared_area < 0) {
663 		/* return the error */
664 		result = di->shared_area;
665 		goto done;
666 	}
667 
668 	/* save a few dereferences */
669 	si = di->si;
670 
671 	/* save the vendor and device IDs */
672 	si->vendor_id = di->pcii.vendor_id;
673 	si->device_id = di->pcii.device_id;
674 	si->revision = di->pcii.revision;
675 
676 	/* map the device */
677 	result = map_device(di);
678 	if (result < 0) goto free_shared;
679 	result = B_OK;
680 
681 	/* create a semaphore for vertical blank management */
682 	si->vblank = create_sem(0, di->name);
683 	if (si->vblank < 0) {
684 		result = si->vblank;
685 		goto unmap;
686 	}
687 
688 	/* change the owner of the semaphores to the opener's team */
689 	/* this is required because apps can't aquire kernel semaphores */
690 	thid = find_thread(NULL);
691 	get_thread_info(thid, &thinfo);
692 	set_sem_owner(si->vblank, thinfo.team);
693 
694 	/* assign local regs pointer for SAMPLExx() macros */
695 	regs = di->regs;
696 	regs2 = di->regs2;
697 
698 	/* disable and clear any pending interrupts */
699 	disable_vbi(regs, regs2);
700 
701 	/* If there is a valid interrupt line assigned then set up interrupts */
702 	if ((di->pcii.u.h0.interrupt_pin == 0x00) ||
703 	    (di->pcii.u.h0.interrupt_line == 0xff) || /* no IRQ assigned */
704 	    (di->pcii.u.h0.interrupt_line <= 0x02))   /* system IRQ assigned */
705 	{
706 		/* we are aborting! */
707 		/* Note: the R4 graphics driver kit lacks this statement!! */
708 		result = B_ERROR;
709 		/* interrupt does not exist so exit without installing our handler */
710 		goto delete_the_sem;
711 	}
712 	else
713 	{
714 		/* otherwise install our interrupt handler */
715 		result = install_io_interrupt_handler(di->pcii.u.h0.interrupt_line, nm_interrupt, (void *)di, 0);
716 		/* bail if we couldn't install the handler */
717 		if (result != B_OK) goto delete_the_sem;
718 	}
719 
720 mark_as_open:
721 	/* mark the device open */
722 	di->is_open++;
723 
724 	/* send the cookie to the opener */
725 	*cookie = di;
726 
727 	goto done;
728 
729 
730 delete_the_sem:
731 	delete_sem(si->vblank);
732 
733 unmap:
734 	unmap_device(di);
735 
736 free_shared:
737 	/* clean up our shared area */
738 	delete_area(di->shared_area);
739 	di->shared_area = -1;
740 	di->si = NULL;
741 
742 done:
743 	/* end of critical section */
744 	RELEASE_BEN(pd->kernel);
745 
746 	/* all done, return the status */
747 	return result;
748 }
749 
750 /* ----------
751 	read_hook - does nothing, gracefully
752 ----- */
753 static status_t
754 read_hook (void* dev, off_t pos, void* buf, size_t* len)
755 {
756 	*len = 0;
757 	return B_NOT_ALLOWED;
758 }
759 
760 
761 /* ----------
762 	write_hook - does nothing, gracefully
763 ----- */
764 static status_t
765 write_hook (void* dev, off_t pos, const void* buf, size_t* len)
766 {
767 	*len = 0;
768 	return B_NOT_ALLOWED;
769 }
770 
771 /* ----------
772 	close_hook - does nothing, gracefully
773 ----- */
774 static status_t
775 close_hook (void* dev)
776 {
777 	/* we don't do anything on close: there might be dup'd fd */
778 	return B_NO_ERROR;
779 }
780 
781 /* -----------
782 	free_hook - close down the device
783 ----------- */
784 static status_t
785 free_hook (void* dev) {
786 	device_info *di = (device_info *)dev;
787 	shared_info	*si = di->si;
788 	vuint32 *regs = di->regs;
789 	vuint32 *regs2 = di->regs2;
790 
791 	/* lock the driver */
792 	AQUIRE_BEN(pd->kernel);
793 
794 	/* if opened multiple times, decrement the open count and exit */
795 	if (di->is_open > 1)
796 		goto unlock_and_exit;
797 
798 	/* disable and clear any pending interrupts */
799 	disable_vbi(regs, regs2);
800 
801 	/* remove interrupt handler */
802 	remove_io_interrupt_handler(di->pcii.u.h0.interrupt_line, nm_interrupt, di);
803 
804 	/* delete the semaphores, ignoring any errors ('cause the owning team may have died on us) */
805 	delete_sem(si->vblank);
806 	si->vblank = -1;
807 
808 	/* free regs and framebuffer areas */
809 	unmap_device(di);
810 
811 	/* clean up our shared area */
812 	delete_area(di->shared_area);
813 	di->shared_area = -1;
814 	di->si = NULL;
815 
816 unlock_and_exit:
817 	/* mark the device available */
818 	di->is_open--;
819 	/* unlock the driver */
820 	RELEASE_BEN(pd->kernel);
821 	/* all done */
822 	return B_OK;
823 }
824 
825 /* -----------
826 	control_hook - where the real work is done
827 ----------- */
828 static status_t
829 control_hook (void* dev, uint32 msg, void *buf, size_t len) {
830 	device_info *di = (device_info *)dev;
831 	status_t result = B_DEV_INVALID_IOCTL;
832 
833 	switch (msg) {
834 		/* the only PUBLIC ioctl */
835 		case B_GET_ACCELERANT_SIGNATURE: {
836 			char *sig = (char *)buf;
837 			strcpy(sig, current_settings.accelerant);
838 			result = B_OK;
839 		} break;
840 
841 		/* PRIVATE ioctl from here on */
842 		case NM_GET_PRIVATE_DATA: {
843 			nm_get_private_data *gpd = (nm_get_private_data *)buf;
844 			if (gpd->magic == NM_PRIVATE_DATA_MAGIC) {
845 				gpd->shared_info_area = di->shared_area;
846 				result = B_OK;
847 			}
848 		} break;
849 		case NM_GET_PCI: {
850 			nm_get_set_pci *gsp = (nm_get_set_pci *)buf;
851 			if (gsp->magic == NM_PRIVATE_DATA_MAGIC) {
852 				pci_info *pcii = &(di->pcii);
853 				gsp->value = get_pci(gsp->offset, gsp->size);
854 				result = B_OK;
855 			}
856 		} break;
857 		case NM_SET_PCI: {
858 			nm_get_set_pci *gsp = (nm_get_set_pci *)buf;
859 			if (gsp->magic == NM_PRIVATE_DATA_MAGIC) {
860 				pci_info *pcii = &(di->pcii);
861 				set_pci(gsp->offset, gsp->size, gsp->value);
862 				result = B_OK;
863 			}
864 		} break;
865 		case NM_DEVICE_NAME: {
866 			nm_device_name *dn = (nm_device_name *)buf;
867 			if (dn->magic == NM_PRIVATE_DATA_MAGIC) {
868 				strcpy(dn->name, di->name);
869 				result = B_OK;
870 			}
871 		} break;
872 		case NM_RUN_INTERRUPTS: {
873 			nm_set_bool_state *ri = (nm_set_bool_state *)buf;
874 			if (ri->magic == NM_PRIVATE_DATA_MAGIC) {
875 				vuint32 *regs = di->regs;
876 				vuint32 *regs2 = di->regs2;
877 				if (ri->do_it) {
878 					enable_vbi(regs, regs2);
879 				} else {
880 					disable_vbi(regs, regs2);
881 				}
882 				result = B_OK;
883 			}
884 		} break;
885 		case NM_ISA_OUT: {
886 			nm_in_out_isa *io_isa = (nm_in_out_isa *)buf;
887 			if (io_isa->magic == NM_PRIVATE_DATA_MAGIC) {
888 				if (io_isa->size == 1)
889   					isa_bus->write_io_8(io_isa->adress, (uint8)io_isa->data);
890    				else
891    					isa_bus->write_io_16(io_isa->adress, io_isa->data);
892   				result = B_OK;
893    			}
894 		} break;
895 		case NM_ISA_IN: {
896 			nm_in_out_isa *io_isa = (nm_in_out_isa *)buf;
897 			if (io_isa->magic == NM_PRIVATE_DATA_MAGIC) {
898 				if (io_isa->size == 1)
899 	   				io_isa->data = isa_bus->read_io_8(io_isa->adress);
900 	   			else
901 	   				io_isa->data = isa_bus->read_io_16(io_isa->adress);
902    				result = B_OK;
903    			}
904 		} break;
905 		case NM_PGM_BES: {
906 			nm_bes_data *bes_isa = (nm_bes_data *)buf;
907 			if (bes_isa->magic == NM_PRIVATE_DATA_MAGIC) {
908 				drv_program_bes_ISA(bes_isa);
909   				result = B_OK;
910    			}
911 		} break;
912 	}
913 	return result;
914 }
915 
916 void drv_program_bes_ISA(nm_bes_data *bes)
917 {
918 	uint8 temp;
919 
920 	/* helper: some cards use pixels to define buffer pitch, others use bytes */
921 	uint16 buf_pitch = bes->ob_width;
922 
923 	/* ISA card */
924 	/* unlock card overlay sequencer registers (b5 = 1) */
925 	temp = (KISAGRPHR(GENLOCK) | 0x20);
926 	/* we need to wait a bit or the card will mess-up it's register values.. (NM2160) */
927 	snooze(10);
928 	KISAGRPHW(GENLOCK, temp);
929 	/* destination rectangle #1 (output window position and size) */
930 	KISAGRPHW(HD1COORD1L, ((bes->hcoordv >> 16) & 0xff));
931 	KISAGRPHW(HD1COORD2L, (bes->hcoordv & 0xff));
932 	KISAGRPHW(HD1COORD21H, (((bes->hcoordv >> 4) & 0xf0) | ((bes->hcoordv >> 24) & 0x0f)));
933 	KISAGRPHW(VD1COORD1L, ((bes->vcoordv >> 16) & 0xff));
934 	KISAGRPHW(VD1COORD2L, (bes->vcoordv & 0xff));
935 	KISAGRPHW(VD1COORD21H, (((bes->vcoordv >> 4) & 0xf0) | ((bes->vcoordv >> 24) & 0x0f)));
936 	/* scaling */
937 	KISAGRPHW(XSCALEL, (bes->hiscalv & 0xff));
938 	KISAGRPHW(XSCALEH, ((bes->hiscalv >> 8) & 0xff));
939 	KISAGRPHW(YSCALEL, (bes->viscalv & 0xff));
940 	KISAGRPHW(YSCALEH, ((bes->viscalv >> 8) & 0xff));
941 	/* inputbuffer #1 origin */
942 	/* (we don't program buffer #2 as it's unused.) */
943 	if (bes->card_type < NM2200)
944 	{
945 		bes->a1orgv >>= 1;
946 		/* horizontal source end does not use subpixelprecision: granularity is 8 pixels */
947 		/* notes:
948 		 * - correctly programming horizontal source end minimizes used bandwidth;
949 		 * - adding 9 below is in fact:
950 		 *   - adding 1 to round-up to the nearest whole source-end value
951 		       (making SURE we NEVER are a (tiny) bit too low);
952 		     - adding 1 to convert 'last used position' to 'number of used pixels';
953 		     - adding 7 to round-up to the nearest higher (or equal) valid register
954 		       value (needed because of it's 8-pixel granularity). */
955 		KISAGRPHW(0xbc, ((((bes->hsrcendv >> 16) + 9) >> 3) - 1));
956 	}
957 	else
958 	{
959 		/* NM2200 and later cards use bytes to define buffer pitch */
960 		buf_pitch <<= 1;
961 		/* horizontal source end does not use subpixelprecision: granularity is 16 pixels */
962 		/* notes:
963 		 * - programming this register just a tiny bit too low messes up vertical
964 		 *   scaling badly (also distortion stripes and flickering are reported)!
965 		 * - not programming this register correctly will mess-up the picture when
966 		 *   it's partly clipping on the right side of the screen...
967 		 * - make absolutely sure the engine can fetch the last pixel needed from
968 		 *   the sourcebitmap even if only to generate a tiny subpixel from it!
969 		 *   (see remarks for < NM2200 cards regarding programming this register) */
970 		KISAGRPHW(0xbc, ((((bes->hsrcendv >> 16) + 17) >> 4) - 1));
971 	}
972 	KISAGRPHW(BUF1ORGL, (bes->a1orgv & 0xff));
973 	KISAGRPHW(BUF1ORGM, ((bes->a1orgv >> 8) & 0xff));
974 	KISAGRPHW(BUF1ORGH, ((bes->a1orgv >> 16) & 0xff));
975 	/* ??? */
976 	KISAGRPHW(0xbd, 0x02);
977 	KISAGRPHW(0xbe, 0x00);
978 	/* b2 = 0: don't use horizontal mirroring (NM2160) */
979 	/* other bits do ??? */
980 	KISAGRPHW(0xbf, 0x02);
981 
982 	/* destination rectangle #2 (output window position and size) */
983 /*
984 	{
985 		uint16 left = 0;
986 		uint16 right = 128;
987 		uint16 top = 0;
988 		uint16 bottom = 128;
989 
990 		KISASEQW(HD2COORD1L, (left & 0xff));
991 		KISASEQW(HD2COORD2L, (right & 0xff));
992 		KISASEQW(HD2COORD21H, (((right >> 4) & 0xf0) | ((left >> 8) & 0x0f)));
993 		KISASEQW(VD2COORD1L, (top & 0xff));
994 		KISASEQW(VD2COORD2L, (bottom & 0xff));
995 		KISASEQW(VD2COORD21H, (((bottom >> 4) & 0xf0) | ((top >> 8) & 0x0f)));
996 	}
997 */
998 	/* ??? */
999     KISASEQW(0x1c, 0xfb);
1000    	KISASEQW(0x1d, 0x00);
1001 	KISASEQW(0x1e, 0xe2);
1002    	KISASEQW(0x1f, 0x02);
1003 	/* b1 = 0: disable alternating hardware buffers (NM2160) */
1004 	/* other bits do ??? */
1005 	KISASEQW(0x09, 0x11);
1006 	/* we don't use PCMCIA Zoomed Video port capturing, set 1:1 scale just in case */
1007 	/* (b6-4 = Y downscale = 100%, b2-0 = X downscale = 100%;
1008 	 *  downscaling selectable in 12.5% steps on increasing setting by 1) */
1009 	KISASEQW(ZVCAP_DSCAL, 0x00);
1010 	/* global BES control */
1011 	KISAGRPHW(BESCTRL1, (bes->globctlv & 0xff));
1012 	KISASEQW(BESCTRL2, ((bes->globctlv >> 8) & 0xff));
1013 
1014 
1015 	/**************************
1016 	 *** setup color keying ***
1017 	 **************************/
1018 
1019 	KISAGRPHW(COLKEY_R, bes->colkey_r);
1020 	KISAGRPHW(COLKEY_G, bes->colkey_g);
1021 	KISAGRPHW(COLKEY_B, bes->colkey_b);
1022 
1023 
1024 	/*************************
1025 	 *** setup misc. stuff ***
1026 	 *************************/
1027 
1028 	/* setup brightness to be 'neutral' (two's complement number) */
1029 	KISAGRPHW(BRIGHTNESS, 0x00);
1030 
1031 	/* setup inputbuffer #1 pitch including slopspace */
1032 	/* (we don't program the pitch for inputbuffer #2 as it's unused.) */
1033 	KISAGRPHW(BUF1PITCHL, (buf_pitch & 0xff));
1034 	KISAGRPHW(BUF1PITCHH, ((buf_pitch >> 8) & 0xff));
1035 }
1036