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