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