tdfx_pci.c revision 61911
1/* 3dfx driver for FreeBSD 4.x - Finished 11 May 2000, 12:25AM ET
2 *
3 * Copyright (C) 2000, by Coleman Kane <cokane@pohl.ececs.uc.edu>,
4 * based upon the 3dfx driver written for linux, by Daryll Straus, Jon Taylor,
5 * and Jens Axboe, located at http://linux.3dfx.com.
6 */
7
8/*
9 * put this here, so as to bail out immediately if we have no PCI BUS installed
10 */
11#include	"pci.h"
12#if NPCI > 0
13
14#include <sys/param.h>
15
16#include <sys/bus_private.h>
17#include <sys/bus.h>
18#include <sys/cdefs.h>
19#include <sys/conf.h>
20#include <sys/fcntl.h>
21#include <sys/file.h>
22#include <sys/filedesc.h>
23#include <sys/filio.h>
24#include <sys/ioccom.h>
25#include <sys/kernel.h>
26#include	<sys/malloc.h>
27/*#include <sys/memrange.h>*/
28#include <sys/mman.h>
29#include <sys/signalvar.h>
30#include <sys/systm.h>
31#include <sys/uio.h>
32
33#include <pci/pcivar.h>
34#include <pci/pcireg.h>
35
36#include <vm/vm.h>
37#include <vm/vm_kern.h>
38#include <vm/pmap.h>
39#include <vm/vm_extern.h>
40
41/* rman.h depends on machine/bus.h */
42#include <machine/resource.h>
43#include <machine/bus.h>
44#include <sys/rman.h>
45
46#include <dev/tdfx/tdfx_io.h>
47#include <dev/tdfx/tdfx_vars.h>
48#include <dev/tdfx/tdfx_pci.h>
49
50#include "opt_tdfx.h"
51
52static devclass_t tdfx_devclass;
53
54
55static int tdfx_count = 0;
56
57
58/* Set up the boot probe/attach routines */
59static device_method_t tdfx_methods[] = {
60	DEVMETHOD(device_probe,		tdfx_probe),
61	DEVMETHOD(device_attach,	tdfx_attach),
62	DEVMETHOD(device_detach,	tdfx_detach),
63	DEVMETHOD(device_shutdown,	tdfx_shutdown),
64	{ 0, 0 }
65};
66
67MALLOC_DEFINE(M_TDFX,"TDFX Driver","3DFX Graphics[/2D]/3D Accelerator(s)");
68
69/* Char. Dev. file operations structure */
70static struct cdevsw tdfx_cdev = {
71	tdfx_open,		/* open */
72	tdfx_close,		/* close */
73	noread,			/* read */
74	nowrite,			/* write */
75	tdfx_ioctl,		/* ioctl */
76	nopoll,			/* poll */
77	tdfx_mmap,		/* mmap */
78	nostrategy,		/* strategy */
79	"tdfx",			/* dev name */
80	CDEV_MAJOR, 	/* char major */
81	nodump,			/* dump */
82	nopsize,			/* size */
83	0,					/* flags (no set flags) */
84	-1 				/* bmaj (no block dev) */
85};
86
87static int
88tdfx_probe(device_t dev)
89{
90	/*
91	 * probe routine called on kernel boot to register supported devices. We get
92	 * a device structure to work with, and we can test the VENDOR/DEVICE IDs to
93	 * see if this PCI device is one that we support. Return 0 if yes, ENXIO if
94	 * not.
95	 */
96	switch(pci_get_devid(dev)) {
97	case PCI_DEVICE_ALLIANCE_AT3D:
98		device_set_desc(dev, "ProMotion At3D 3D Accelerator");
99		return 0;
100	case PCI_DEVICE_3DFX_VOODOO2:
101		device_set_desc(dev, "3DFX Voodoo II 3D Accelerator");
102		return 0;
103	case PCI_DEVICE_3DFX_BANSHEE:
104		device_set_desc(dev, "3DFX Voodoo Banshee 2D/3D Graphics Accelerator");
105		return 0;
106	case PCI_DEVICE_3DFX_VOODOO3:
107		device_set_desc(dev, "3DFX Voodoo3 2D/3D Graphics Accelerator");
108		return 0;
109	case PCI_DEVICE_3DFX_VOODOO1:
110		device_set_desc(dev, "3DFX Voodoo Graphics 3D Accelerator");
111		return 0;;
112	};
113
114	return ENXIO;
115}
116
117static int
118tdfx_attach(device_t dev) {
119	/*
120	 * The attach routine is called after the probe routine successfully says it
121	 * supports a given card. We now proceed to initialize this card for use with
122	 * the system. I want to map the device memory for userland allocation and
123	 * fill an information structure with information on this card. I'd also like
124	 * to set Write Combining with the MTRR code so that we can hopefully speed
125	 * up memory writes. The last thing is to register the character device
126	 * interface to the card, so we can open it from /dev/3dfxN, where N is a
127	 * small, whole number.
128	 */
129
130	struct tdfx_softc *tdfx_info;
131	u_long	val;
132	/* rid value tells bus_alloc_resource where to find the addresses of ports or
133	 * of memory ranges in the PCI config space*/
134	int rid = PCIR_MAPS;
135
136	/* Increment the card counter (for the ioctl code) */
137	tdfx_count++;
138
139 	/* Enable MemMap on Voodoo */
140	val = pci_read_config(dev, PCIR_COMMAND, 2);
141	val |= (PCIM_CMD_MEMEN);
142	pci_write_config(dev, PCIR_COMMAND, val, 2);
143	val = pci_read_config(dev, PCIR_COMMAND, 2);
144
145	/* Fill the soft config struct with info about this device*/
146	tdfx_info = device_get_softc(dev);
147	tdfx_info->dev = dev;
148	tdfx_info->vendor = pci_get_vendor(dev);
149	tdfx_info->type = pci_get_devid(dev) >> 16;
150	tdfx_info->bus = pci_get_bus(dev);
151	tdfx_info->dv = pci_get_slot(dev);
152	tdfx_info->curFile = NULL;
153
154	/*
155	 *	Get the Memory Location from the PCI Config, mask out lower word, since
156	 * the config space register is only one word long (this is nicer than a
157	 * bitshift).
158	 */
159	tdfx_info->addr0 = (pci_read_config(dev, 0x10, 4) & 0xffff0000);
160#ifdef TDFX_VERBOSE
161	device_printf(dev, "Base0 @ 0x%x\n", tdfx_info->addr0);
162#endif
163
164	/* Notify the VM that we will be mapping some memory later */
165	tdfx_info->memrange = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1,
166			RF_ACTIVE);
167	if(tdfx_info->memrange == NULL) {
168#ifdef TDFX_VERBOSE
169		device_printf(dev, "Error mapping mem, won't be able to use mmap()\n");
170#endif
171		tdfx_info->memrid = 0;
172	}
173	else {
174		tdfx_info->memrid = rid;
175#ifdef TDFX_VERBOSE
176		device_printf(dev, "Mapped to: 0x%x\n",
177				(unsigned int)rman_get_start(tdfx_info->memrange));
178#endif
179	}
180
181	/*
182	 *	Set Writecombining, or at least Uncacheable for the memory region, if we
183	 * are able to
184	 */
185
186	if(tdfx_setmtrr(dev) != 0) {
187#ifdef TDFX_VERBOSE
188		device_printf(dev, "Some weird error setting MTRRs");
189#endif
190		return -1;
191	}
192
193	/*
194	 * make_dev registers the cdev to access the 3dfx card from /dev
195	 *	use hex here for the dev num, simply to provide better support if > 10
196	 * voodoo cards, for the mad. The user must set the link, or use MAKEDEV.
197	 * Why would we want that many voodoo cards anyhow?
198	 */
199	make_dev(&tdfx_cdev, dev->unit, 0, 0, 02660, "3dfx%x", dev->unit);
200
201	return 0;
202}
203
204static int
205tdfx_detach(device_t dev) {
206	struct tdfx_softc* tdfx_info;
207	int retval;
208	tdfx_info = device_get_softc(dev);
209
210	/* Delete allocated resource, of course */
211	bus_release_resource(dev, SYS_RES_MEMORY, PCI_MAP_REG_START,
212			tdfx_info->memrange);
213
214	/* Though it is safe to leave the WRCOMB support since the
215		mem driver checks for it, we should remove it in order
216		to free an MTRR for another device */
217	retval = tdfx_clrmtrr(dev);
218#ifdef TDFX_VERBOSE
219	if(retval != 0)
220		printf("tdfx: For some reason, I couldn't clear the mtrr\n");
221#endif
222	return(0);
223}
224
225static int
226tdfx_shutdown(device_t dev) {
227#ifdef TDFX_VERBOSE
228	device_printf(dev, "tdfx: Device Shutdown\n");
229#endif
230	return 0;
231}
232
233static int
234tdfx_clrmtrr(device_t dev) {
235	/* This function removes the MTRR set by the attach call, so it can be used
236	 * in the future by other drivers.
237	 */
238	int retval, act;
239	struct tdfx_softc *tdfx_info = device_get_softc(dev);
240
241	act = MEMRANGE_SET_REMOVE;
242	retval = mem_range_attr_set(&tdfx_info->mrdesc, &act);
243	return retval;
244}
245
246static int
247tdfx_setmtrr(device_t dev) {
248	/*
249	 * This is the MTRR setting function for the 3dfx card. It is called from
250	 * tdfx_attach. If we can't set the MTRR properly, it's not the end of the
251	 * world. We can still continue, just with slightly (very slightly) degraded
252	 * performance.
253	 */
254	int retval = 0, act;
255	struct tdfx_softc *tdfx_info = device_get_softc(dev);
256	/* The memory descriptor is described as the top 15 bits of the real
257		address */
258	tdfx_info->mrdesc.mr_base = pci_read_config(dev, 0x10, 4) & 0xfffe0000;
259
260	/* The older Voodoo cards have a shorter memrange than the newer ones */
261	if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO1) || (pci_get_devid(dev) ==
262			PCI_DEVICE_3DFX_VOODOO2))
263		tdfx_info->mrdesc.mr_len = 0x400000;
264	else if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO3) ||
265			(pci_get_devid(dev) == PCI_DEVICE_3DFX_BANSHEE))
266		tdfx_info->mrdesc.mr_len = 0x1000000;
267
268	else return 0;
269	/*
270    *	The Alliance Pro Motion AT3D was not mentioned in the linux
271	 * driver as far as MTRR support goes, so I just won't put the
272	 * code in here for it. This is where it should go, though.
273	 */
274
275	/* Firstly, try to set write combining */
276	tdfx_info->mrdesc.mr_flags = MDF_WRITECOMBINE;
277	bcopy("tdfx", &tdfx_info->mrdesc.mr_owner, 4);
278	act = MEMRANGE_SET_UPDATE;
279	retval = mem_range_attr_set(&tdfx_info->mrdesc, &act);
280
281	if(retval == 0) {
282#ifdef TDFX_VERBOSE
283		device_printf(dev, "MTRR Set Correctly for tdfx\n");
284#endif
285	} else if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO2) ||
286		(pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO1)) {
287		/* if, for some reason we can't set the WRCOMB range with the V1/V2, we
288		 * can still possibly use the UNCACHEABLE region for it instead, and help
289		 * out in a small way */
290		tdfx_info->mrdesc.mr_flags = MDF_UNCACHEABLE;
291		/* This length of 1000h was taken from the linux device driver... */
292		tdfx_info->mrdesc.mr_len = 0x1000;
293
294		/*
295		 * If, for some reason, we can't set the MTRR (N/A?) we may still continue
296		 */
297#ifdef TDFX_VERBOSE
298		if(retval == 0) {
299			device_printf(dev, "MTRR Set Type Uncacheable
300					%x\n", (u_int32_t)tdfx_info->mrdesc.mr_base);
301		} else {
302			device_printf(dev, "Couldn't Set MTRR\n");
303		}
304#endif
305	}
306#ifdef TDFX_VERBOSE
307	else {
308		device_printf(dev, "Couldn't Set MTRR\n");
309		return 0;
310	}
311#endif
312	return 0;
313}
314
315static int
316tdfx_open(dev_t dev, int flags, int fmt, struct proc *p)
317{
318	/*
319	 *	The open cdev method handles open(2) calls to /dev/3dfx[n]
320	 * We can pretty much allow any opening of the device.
321	 */
322	struct tdfx_softc *tdfx_info = devclass_get_softc(tdfx_devclass,
323			UNIT(minor(dev)));
324	if(tdfx_info->busy != 0) return EBUSY;
325#ifdef	TDFX_VERBOSE
326	printf("3dfx: Opened by #%d\n", p->p_pid);
327#endif
328	/* Set the driver as busy */
329	tdfx_info->busy++;
330	return 0;
331}
332
333static int
334tdfx_close(dev_t dev, int fflag, int devtype, struct proc* p)
335{
336	/*
337	 *	The close cdev method handles close(2) calls to /dev/3dfx[n]
338	 * We'll always want to close the device when it's called.
339	 */
340	struct tdfx_softc *tdfx_info = devclass_get_softc(tdfx_devclass,
341		UNIT(minor(dev)));
342	if(tdfx_info->busy == 0) return EBADF;
343	tdfx_info->busy = 0;
344#ifdef	TDFX_VERBOSE
345	printf("Closed by #%d\n", p->p_pid);
346#endif
347	return 0;
348}
349
350static int
351tdfx_mmap(dev_t dev, vm_offset_t offset, int nprot)
352{
353	/*
354	 * mmap(2) is called by a user process to request that an area of memory
355	 * associated with this device be mapped for the process to work with. Nprot
356	 * holds the protections requested, PROT_READ, PROT_WRITE, or both.
357	 */
358	struct tdfx_softc* tdfx_info;
359
360	/* Get the configuration for our card XXX*/
361	tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass,
362			UNIT(minor(dev)));
363
364	/* If, for some reason, its not configured, we bail out */
365	if(tdfx_info == NULL) {
366#ifdef	TDFX_VERBOSE
367	   printf("tdfx: tdfx_info (softc) is NULL\n");
368#endif
369	   return -1;
370	}
371
372	/* We must stay within the bound of our address space */
373	if((offset & 0xff000000) == tdfx_info->addr0)
374		offset &= 0xffffff;
375	if((offset >= 0x1000000) || (offset < 0)) {
376#ifdef  TDFX_VERBOSE
377	   printf("tdfx: offset %x out of range\n", offset);
378#endif
379	   return -1;
380	}
381
382	/* atop -> address to page
383	 * rman_get_start, get the (struct resource*)->r_start member,
384	 * the mapping base address.
385	 */
386	return atop(rman_get_start(tdfx_info->memrange) + offset);
387}
388
389static int
390tdfx_query_boards(void) {
391	/*
392    *	This returns the number of installed tdfx cards, we have been keeping
393	 * count, look at tdfx_attach
394	 */
395	return tdfx_count;
396}
397
398static int
399tdfx_query_fetch(u_int cmd, struct tdfx_pio_data *piod)
400{
401	/* XXX Comment this later, after careful inspection and spring cleaning :) */
402	/* Various return values 8bit-32bit */
403	u_int8_t  ret_byte;
404	u_int16_t ret_word;
405	u_int32_t ret_dword;
406	struct tdfx_softc* tdfx_info = NULL;
407
408	/* This one depend on the tdfx_* structs being properly initialized */
409
410	/*piod->device &= 0xf;*/
411	if((piod == NULL) ||(tdfx_count <= piod->device) ||
412			(piod->device < 0)) {
413#ifdef TDFX_VERBOSE
414		printf("tdfx: Bad device or internal struct in tdfx_query_fetch\n");
415#endif
416		return -EINVAL;
417	}
418
419	tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass,
420			piod->device);
421
422	if(tdfx_info == NULL) return -ENXIO;
423
424	/* We must restrict the size reads from the port, since to high or low of a
425	 * size witll result in wrong data being passed, and that's bad */
426	/* A few of these were pulled during the attach phase */
427	switch(piod->port) {
428		case PCI_VENDOR_ID_FREEBSD:
429			if(piod->size != 2) return -EINVAL;
430			copyout(&tdfx_info->vendor, piod->value, piod->size);
431			return 0;
432		case PCI_DEVICE_ID_FREEBSD:
433			if(piod->size != 2) return -EINVAL;
434			copyout(&tdfx_info->type, piod->value, piod->size);
435			return 0;
436		case PCI_BASE_ADDRESS_0_FREEBSD:
437			if(piod->size != 4) return -EINVAL;
438			copyout(&tdfx_info->addr0, piod->value, piod->size);
439			return 0;
440		case SST1_PCI_SPECIAL1_FREEBSD:
441			if(piod->size != 4) return -EINVAL;
442			break;
443		case PCI_REVISION_ID_FREEBSD:
444			if(piod->size != 1) return -EINVAL;
445			break;
446		case SST1_PCI_SPECIAL4_FREEBSD:
447			if(piod->size != 4) return -EINVAL;
448			break;
449		default:
450			return -EINVAL;
451	}
452
453
454	/* Read the value and return */
455	switch(piod->size) {
456		case 1:
457			ret_byte = pci_read_config(tdfx_info[piod->device].dev,
458					piod->port, 1);
459			copyout(&ret_byte, piod->value, 1);
460			break;
461		case 2:
462			ret_word = pci_read_config(tdfx_info[piod->device].dev,
463					piod->port, 2);
464			copyout(&ret_word, piod->value, 2);
465			break;
466		case 4:
467			ret_dword = pci_read_config(tdfx_info[piod->device].dev,
468					piod->port, 4);
469			copyout(&ret_dword, piod->value, 4);
470			break;
471		default:
472			return -EINVAL;
473	}
474	return 0;
475}
476
477static int
478tdfx_query_update(u_int cmd, struct tdfx_pio_data *piod)
479{
480	/* XXX Comment this later, after careful inspection and spring cleaning :) */
481	/* Return vals */
482	u_int8_t  ret_byte;
483	u_int16_t ret_word;
484	u_int32_t ret_dword;
485
486	/* Port vals, mask */
487	u_int32_t retval, preval, mask;
488	struct tdfx_softc* tdfx_info = NULL;
489
490
491	if((piod == NULL) || (piod->device >= (tdfx_count &
492					0xf))) {
493#ifdef TDFX_VERBOSE
494		printf("tdfx: Bad struct or device in tdfx_query_update\n");
495#endif
496		return -EINVAL;
497	}
498
499	tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass,
500			piod->device);
501	if(tdfx_info == NULL) return -ENXIO;
502	/* Code below this line in the fuction was taken from the
503	 * Linux driver and converted for freebsd. */
504
505	/* Check the size for all the ports, to make sure stuff doesn't get messed up
506	 * by poorly written clients */
507
508	switch(piod->port) {
509		case PCI_COMMAND_FREEBSD:
510			if(piod->size != 2) return -EINVAL;
511			break;
512		case SST1_PCI_SPECIAL1_FREEBSD:
513			if(piod->size != 4) return -EINVAL;
514			break;
515		case SST1_PCI_SPECIAL2_FREEBSD:
516			if(piod->size != 4) return -EINVAL;
517			break;
518		case SST1_PCI_SPECIAL3_FREEBSD:
519			if(piod->size != 4) return -EINVAL;
520			break;
521		case SST1_PCI_SPECIAL4_FREEBSD:
522			if(piod->size != 4) return -EINVAL;
523			break;
524		default:
525			return -EINVAL;
526	}
527	/* Read the current value */
528	retval = pci_read_config(tdfx_info->dev, piod->port & ~3, 4);
529
530	/* These set up a mask to use, since apparently they wanted to write 4 bytes
531	 * at once to the ports */
532	switch (piod->size) {
533		case 1:
534			copyin(piod->value, &ret_byte, 1);
535			preval = ret_byte << (8 * (piod->port & 0x3));
536			mask = 0xff << (8 * (piod->port & 0x3));
537			break;
538		case 2:
539			copyin(piod->value, &ret_word, 2);
540			preval = ret_word << (8 * (piod->port & 0x3));
541			mask = 0xffff << (8 * (piod->port & 0x3));
542			break;
543		case 4:
544			copyin(piod->value, &ret_dword, 4);
545			preval = ret_dword;
546			mask = ~0;
547			break;
548		default:
549			return -EINVAL;
550	}
551	/* Finally, combine the values and write it to the port */
552	retval = (retval & ~mask) | preval;
553	pci_write_config(tdfx_info->dev, piod->port & ~3, retval, 4);
554
555	return 0;
556}
557
558static int
559tdfx_do_pio_rd(struct tdfx_pio_data *piod)
560{
561	/* Return val */
562	u_int8_t  ret_byte;
563
564	/* Restricts the access of ports other than those we use */
565	if((piod->port != VGA_INPUT_STATUS_1C) || (piod->port != SC_INDEX) ||
566		(piod->port != SC_DATA) || (piod->port != VGA_MISC_OUTPUT_READ))
567		return -EPERM;
568
569	/* All VGA STATUS REGS are byte registers, size should never be > 1 */
570	if(piod->size != 1) {
571		return -EINVAL;
572	}
573
574	/* Write the data to the intended port */
575	ret_byte = inb(piod->port);
576	copyout(&ret_byte, piod->value, sizeof(u_int8_t));
577	return 0;
578}
579
580static int
581tdfx_do_pio_wt(struct tdfx_pio_data *piod)
582{
583	/* return val */
584	u_int8_t  ret_byte;
585
586	/* Replace old switch w/ massive if(...) */
587	/* Restricts the access of ports other than those we use */
588	if((piod->port != SC_INDEX) && (piod->port != SC_DATA) &&
589		(piod->port != VGA_MISC_OUTPUT_READ)) /* Can't write VGA_ST_1C */
590		return -EPERM;
591
592	/* All VGA STATUS REGS are byte registers, size should never be > 1 */
593	if(piod->size != 1) {
594		return -EINVAL;
595	}
596
597	/* Write the data to the intended port */
598	copyin(piod->value, &ret_byte, sizeof(u_int8_t));
599	outb(piod->port, ret_byte);
600	return 0;
601}
602
603static int
604tdfx_do_query(u_int cmd, struct tdfx_pio_data *piod)
605{
606	/* There are three sub-commands to the query 0x33 */
607	switch(_IOC_NR(cmd)) {
608		case 2:
609			return tdfx_query_boards();
610			break;
611		case 3:
612			return tdfx_query_fetch(cmd, piod);
613			break;
614		case 4:
615			return tdfx_query_update(cmd, piod);
616			break;
617		default:
618			/* In case we are thrown a bogus sub-command! */
619#ifdef TDFX_VERBOSE
620			printf("Bad Sub-cmd: 0x%x\n", _IOC_NR(cmd));
621#endif
622			return -EINVAL;
623	};
624}
625
626static int
627tdfx_do_pio(u_int cmd, struct tdfx_pio_data *piod)
628{
629	/* Two types of PIO, INPUT and OUTPUT, as the name suggests */
630	switch(_IOC_DIR(cmd)) {
631		case IOCV_OUT:
632			return tdfx_do_pio_rd(piod);
633			break;
634		case IOCV_IN:
635			return tdfx_do_pio_wt(piod);
636			break;
637		default:
638			return -EINVAL;
639	};
640}
641
642/* Calls to ioctl(2) eventually end up here. Unhandled ioctls return an ENXIO,
643 * normally, you would read in the data pointed to by data, then write your
644 * output to it. The ioctl *should* normally return zero if everything is
645 * alright, but 3dfx didn't make it that way...
646 *
647 * For all of the ioctl code, in the event of a real error,
648 * we return -Exxxx rather than simply Exxxx. The reason for this
649 * is that the ioctls actually RET information back to the program
650 * sometimes, rather than filling it in the passed structure. We
651 * want to distinguish errors from useful data, and maintain compatibility.
652 *
653 * There is this portion of the proc struct called p_retval[], we can store a
654 * return value in p->p_retval[0] and place the return value if it is positive
655 * in there, then we can return 0 (good). If the return value is negative, we
656 * can return -retval and the error should be properly handled.
657 */
658static int
659tdfx_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc * p)
660{
661	int retval = 0;
662	struct tdfx_pio_data *piod = (struct tdfx_pio_data*)data;
663#ifdef	TDFX_VERBOSE
664	printf("IOCTL'd by #%d, cmd: 0x%x, data: 0x%x\n", p->p_pid, (u_int32_t)cmd,
665			(unsigned int)piod);
666#endif
667	switch(_IOC_TYPE(cmd)) {
668		/* Return the real error if negative, or simply stick the valid return
669		 * in p->p_retval */
670	case 0x33:
671			/* The '3'(0x33) type IOCTL is for querying the installed cards */
672			if((retval = tdfx_do_query(cmd, piod)) > 0) p->p_retval[0] = retval;
673			else return -retval;
674			break;
675		case 0:
676			/* The 0 type IOCTL is for programmed I/O methods */
677			if((tdfx_do_pio(cmd, piod)) > 0) p->p_retval[0] = retval;
678			else return -retval;
679			break;
680		default:
681			/* Technically, we won't reach this from linux emu, but when glide
682			 * finally gets ported, watch out! */
683#ifdef TDFX_VERBOSE
684			printf("Bad IOCTL from #%d\n", p->p_pid);
685#endif
686			return ENXIO;
687	}
688
689	return 0;
690}
691
692
693/* This is the device driver struct. This is sent to the driver subsystem to
694 * register the method structure and the info strcut space for this particular
695 * instance of the driver.
696 */
697static driver_t tdfx_driver = {
698	"tdfx",
699	tdfx_methods,
700	sizeof(struct tdfx_softc),
701};
702
703/* Tell Mr. Kernel about us! */
704DRIVER_MODULE(tdfx, pci, tdfx_driver, tdfx_devclass, 0, 0);
705
706
707#endif	/* NPCI */
708