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