The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/tdfx/tdfx_pci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-4-Clause
    3  *
    4  * Copyright (c) 2000-2001 by Coleman Kane <cokane@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *    must display the following acknowledgement:
   17  *      This product includes software developed by Gardner Buchanan.
   18  * 4. The name of Gardner Buchanan may not be used to endorse or promote
   19  *    products derived from this software without specific prior written
   20  *    permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 /* 3dfx driver for FreeBSD 4.x - Finished 11 May 2000, 12:25AM ET
   38  *
   39  * Copyright (C) 2000-2001, by Coleman Kane <cokane@FreeBSD.org>, 
   40  * based upon the 3dfx driver written for linux, by Daryll Straus, Jon Taylor,
   41  * and Jens Axboe, located at http://linux.3dfx.com.
   42  */
   43 
   44 #include <sys/param.h>
   45 
   46 #include <sys/bus.h>
   47 #include <sys/conf.h>
   48 #include <sys/fcntl.h>
   49 #include <sys/file.h>
   50 #include <sys/filedesc.h>
   51 #include <sys/filio.h>
   52 #include <sys/ioccom.h>
   53 #include <sys/kernel.h>
   54 #include <sys/module.h>
   55 #include <sys/malloc.h>
   56 #include <sys/mman.h>
   57 #include <sys/signalvar.h>
   58 #include <sys/systm.h>
   59 #include <sys/uio.h>
   60 
   61 #include <dev/pci/pcivar.h>
   62 #include <dev/pci/pcireg.h>
   63 
   64 #include <vm/vm.h>
   65 #include <vm/vm_kern.h>
   66 #include <vm/pmap.h>
   67 #include <vm/vm_extern.h>
   68 
   69 /* rman.h depends on machine/bus.h */
   70 #include <machine/resource.h>
   71 #include <machine/bus.h>
   72 #include <sys/rman.h>
   73 
   74 #include <dev/tdfx/tdfx_io.h>
   75 #include <dev/tdfx/tdfx_vars.h>
   76 #include <dev/tdfx/tdfx_pci.h>
   77 
   78 
   79 static devclass_t tdfx_devclass;
   80 
   81 
   82 static int tdfx_count = 0;
   83 
   84 
   85 /* Set up the boot probe/attach routines */
   86 static device_method_t tdfx_methods[] = {
   87         DEVMETHOD(device_probe,         tdfx_probe),
   88         DEVMETHOD(device_attach,        tdfx_attach),
   89         DEVMETHOD(device_detach,        tdfx_detach),
   90         DEVMETHOD(device_shutdown,      tdfx_shutdown),
   91         { 0, 0 }
   92 };
   93 
   94 static MALLOC_DEFINE(M_TDFX,"tdfx_driver","3DFX Graphics[/2D]/3D Accelerators");
   95 
   96 /* Char. Dev. file operations structure */
   97 static struct cdevsw tdfx_cdev = {
   98         .d_version =    D_VERSION,
   99         .d_flags =      D_NEEDGIANT,
  100         .d_open =       tdfx_open,
  101         .d_close =      tdfx_close,
  102         .d_ioctl =      tdfx_ioctl,
  103         .d_mmap =       tdfx_mmap,
  104         .d_name =       "tdfx",
  105 };
  106 
  107 static int
  108 tdfx_probe(device_t dev)
  109 {
  110         /*
  111          * probe routine called on kernel boot to register supported devices. We get
  112          * a device structure to work with, and we can test the VENDOR/DEVICE IDs to
  113          * see if this PCI device is one that we support. Return BUS_PRROBE_DEFAULT
  114          * if yes, ENXIO if not.
  115          */
  116         switch(pci_get_devid(dev)) {
  117         case PCI_DEVICE_ALLIANCE_AT3D:
  118                 device_set_desc(dev, "ProMotion At3D 3D Accelerator");
  119                 return BUS_PROBE_DEFAULT;
  120         case PCI_DEVICE_3DFX_VOODOO2:
  121                 device_set_desc(dev, "3DFX Voodoo II 3D Accelerator");
  122                 return BUS_PROBE_DEFAULT;
  123         /*case PCI_DEVICE_3DFX_BANSHEE:
  124                 device_set_desc(dev, "3DFX Voodoo Banshee 2D/3D Graphics Accelerator");
  125                 return BUS_PROBE_DEFAULT;
  126         case PCI_DEVICE_3DFX_VOODOO3:
  127                 device_set_desc(dev, "3DFX Voodoo3 2D/3D Graphics Accelerator");
  128                 return BUS_PROBE_DEFAULT;*/
  129         case PCI_DEVICE_3DFX_VOODOO1:
  130                 device_set_desc(dev, "3DFX Voodoo Graphics 3D Accelerator");
  131                 return BUS_PROBE_DEFAULT;
  132         }
  133 
  134         return ENXIO;
  135 }
  136 
  137 static int
  138 tdfx_attach(device_t dev) { 
  139         /*
  140          * The attach routine is called after the probe routine successfully says it
  141          * supports a given card. We now proceed to initialize this card for use with
  142          * the system. I want to map the device memory for userland allocation and
  143          * fill an information structure with information on this card. I'd also like
  144          * to set Write Combining with the MTRR code so that we can hopefully speed
  145          * up memory writes. The last thing is to register the character device
  146          * interface to the card, so we can open it from /dev/3dfxN, where N is a
  147          * small, whole number.
  148          */
  149         struct tdfx_softc *tdfx_info;
  150         /* rid value tells bus_alloc_resource where to find the addresses of ports or
  151          * of memory ranges in the PCI config space*/
  152         int rid = PCIR_BAR(0);
  153 
  154         /* Increment the card counter (for the ioctl code) */
  155         tdfx_count++;
  156 
  157         /* Fill the soft config struct with info about this device*/
  158         tdfx_info = device_get_softc(dev);
  159         tdfx_info->dev = dev;
  160         tdfx_info->vendor = pci_get_vendor(dev);
  161         tdfx_info->type = pci_get_devid(dev) >> 16;
  162         tdfx_info->bus = pci_get_bus(dev);
  163         tdfx_info->dv = pci_get_slot(dev);
  164         tdfx_info->curFile = NULL;
  165 
  166         /* 
  167          *      Get the Memory Location from the PCI Config, mask out lower word, since
  168          * the config space register is only one word long (this is nicer than a
  169          * bitshift).
  170          */
  171         tdfx_info->addr0 = (pci_read_config(dev, 0x10, 4) & 0xffff0000);
  172 #ifdef DEBUG
  173         device_printf(dev, "Base0 @ 0x%x\n", tdfx_info->addr0);
  174 #endif
  175         /* Notify the VM that we will be mapping some memory later */
  176         tdfx_info->memrange = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  177                 &rid, RF_ACTIVE | RF_SHAREABLE);
  178         if(tdfx_info->memrange == NULL) {
  179 #ifdef DEBUG
  180                 device_printf(dev, "Error mapping mem, won't be able to use mmap()\n");
  181 #endif
  182                 tdfx_info->memrid = 0;
  183         }
  184         else {
  185                 tdfx_info->memrid = rid;
  186 #ifdef DEBUG
  187                 device_printf(dev, "Mapped to: 0x%x\n", 
  188                                 (unsigned int)rman_get_start(tdfx_info->memrange));
  189 #endif
  190         }
  191 
  192         /* Setup for Voodoo3 and Banshee, PIO and an extram Memrange */
  193         if(pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO3 ||
  194                 pci_get_devid(dev) == PCI_DEVICE_3DFX_BANSHEE) {
  195                 rid = 0x14;     /* 2nd mem map */
  196                 tdfx_info->addr1 = (pci_read_config(dev, 0x14, 4) & 0xffff0000);
  197 #ifdef DEBUG
  198                 device_printf(dev, "Base1 @ 0x%x\n", tdfx_info->addr1);
  199 #endif
  200                 tdfx_info->memrange2 = bus_alloc_resource_any(dev,
  201                         SYS_RES_MEMORY, &rid, RF_ACTIVE | RF_SHAREABLE);
  202                 if(tdfx_info->memrange2 == NULL) {
  203 #ifdef DEBUG
  204                         device_printf(dev, "Mem1 couldn't be allocated, glide may not work.");
  205 #endif
  206                         tdfx_info->memrid2 = 0;
  207                 }
  208                 else {
  209                         tdfx_info->memrid2 = rid;
  210                 }
  211                 /* Now to map the PIO stuff */
  212                 rid = PCIR_IOBASE0_2;
  213                 tdfx_info->pio0 = pci_read_config(dev, 0x2c, 2);
  214                 tdfx_info->pio0max = pci_read_config(dev, 0x30, 2) + tdfx_info->pio0;
  215                 tdfx_info->piorange = bus_alloc_resource_any(dev,
  216                         SYS_RES_IOPORT, &rid, RF_ACTIVE | RF_SHAREABLE);
  217                 if(tdfx_info->piorange == NULL) {
  218 #ifdef DEBUG
  219                         device_printf(dev, "Couldn't map PIO range.");
  220 #endif
  221                         tdfx_info->piorid = 0;
  222                 }
  223                 else {
  224                         tdfx_info->piorid = rid;
  225                 }
  226         } else {
  227           tdfx_info->addr1 = 0;
  228           tdfx_info->memrange2 = NULL;
  229           tdfx_info->piorange = NULL;
  230         }
  231 
  232         /* 
  233          *      Set Writecombining, or at least Uncacheable for the memory region, if we
  234          * are able to
  235          */
  236 
  237         if(tdfx_setmtrr(dev) != 0) {
  238 #ifdef DEBUG
  239                 device_printf(dev, "Some weird error setting MTRRs");
  240 #endif
  241                 return -1;
  242         }
  243 
  244         /* 
  245          * make_dev registers the cdev to access the 3dfx card from /dev
  246          *      use hex here for the dev num, simply to provide better support if > 10
  247          * voodoo cards, for the mad. The user must set the link.
  248          * Why would we want that many voodoo cards anyhow? 
  249          */
  250         tdfx_info->devt = make_dev(&tdfx_cdev, device_get_unit(dev),
  251                 UID_ROOT, GID_WHEEL, 0600, "3dfx%x", device_get_unit(dev));
  252         tdfx_info->devt->si_drv1 = tdfx_info;
  253         
  254         return 0;
  255 }
  256 
  257 static int
  258 tdfx_detach(device_t dev) {
  259         struct tdfx_softc* tdfx_info;
  260         int retval;
  261         tdfx_info = device_get_softc(dev);
  262         
  263         /* Delete allocated resource, of course */
  264         bus_release_resource(dev, SYS_RES_MEMORY, tdfx_info->memrid,
  265                         tdfx_info->memrange);
  266 
  267         /* Release extended Voodoo3/Banshee resources */
  268         if(pci_get_devid(dev) == PCI_DEVICE_3DFX_BANSHEE || 
  269                         pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO3) {
  270                 if(tdfx_info->memrange2 != NULL)
  271                         bus_release_resource(dev, SYS_RES_MEMORY, tdfx_info->memrid2,
  272                                 tdfx_info->memrange);
  273         /*      if(tdfx_info->piorange != NULL)
  274                         bus_release_resource(dev, SYS_RES_IOPORT, tdfx_info->piorid,
  275                                 tdfx_info->piorange);*/
  276         }               
  277 
  278         /* Though it is safe to leave the WRCOMB support since the 
  279                 mem driver checks for it, we should remove it in order
  280                 to free an MTRR for another device */
  281         retval = tdfx_clrmtrr(dev);
  282 #ifdef DEBUG
  283         if(retval != 0) 
  284                 printf("tdfx: For some reason, I couldn't clear the mtrr\n");
  285 #endif
  286         /* Remove device entry when it can no longer be accessed */
  287    destroy_dev(tdfx_info->devt);
  288         return(0);
  289 }
  290 
  291 static int
  292 tdfx_shutdown(device_t dev) {
  293 #ifdef DEBUG
  294         device_printf(dev, "tdfx: Device Shutdown\n");
  295 #endif
  296         return 0;
  297 }
  298 
  299 static int
  300 tdfx_clrmtrr(device_t dev) {
  301         /* This function removes the MTRR set by the attach call, so it can be used
  302          * in the future by other drivers. 
  303          */
  304         int retval, act;
  305         struct tdfx_softc *tdfx_info = device_get_softc(dev);
  306         
  307         act = MEMRANGE_SET_REMOVE;
  308         retval = mem_range_attr_set(&tdfx_info->mrdesc, &act);
  309         return retval;
  310 }
  311         
  312 static int
  313 tdfx_setmtrr(device_t dev) {
  314         /*
  315          * This is the MTRR setting function for the 3dfx card. It is called from
  316          * tdfx_attach. If we can't set the MTRR properly, it's not the end of the
  317          * world. We can still continue, just with slightly (very slightly) degraded
  318          * performance.
  319          */
  320         int retval = 0, act;
  321         struct tdfx_softc *tdfx_info = device_get_softc(dev);
  322 
  323         /* The older Voodoo cards have a shorter memrange than the newer ones */
  324         if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO1) || (pci_get_devid(dev) ==
  325                         PCI_DEVICE_3DFX_VOODOO2)) {
  326                 tdfx_info->mrdesc.mr_len = 0x400000;
  327 
  328                 /* The memory descriptor is described as the top 15 bits of the real
  329                         address */
  330                 tdfx_info->mrdesc.mr_base = tdfx_info->addr0 & 0xfffe0000;
  331         }
  332         else if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO3) ||
  333                         (pci_get_devid(dev) == PCI_DEVICE_3DFX_BANSHEE)) {
  334                 tdfx_info->mrdesc.mr_len = 0x1000000;
  335                 /* The Voodoo3 and Banshee LFB is the second memory address */
  336                 /* The memory descriptor is described as the top 15 bits of the real
  337                         address */
  338                 tdfx_info->mrdesc.mr_base = tdfx_info->addr1 & 0xfffe0000;
  339         }
  340         else
  341                  return 0;      
  342         /* 
  343     *   The Alliance Pro Motion AT3D was not mentioned in the linux
  344          * driver as far as MTRR support goes, so I just won't put the
  345          * code in here for it. This is where it should go, though. 
  346          */
  347 
  348         /* Firstly, try to set write combining */
  349         tdfx_info->mrdesc.mr_flags = MDF_WRITECOMBINE;
  350         bcopy("tdfx", &tdfx_info->mrdesc.mr_owner, 4);
  351         act = MEMRANGE_SET_UPDATE;
  352         retval = mem_range_attr_set(&tdfx_info->mrdesc, &act);
  353 
  354         if(retval == 0) {
  355 #ifdef DEBUG
  356                 device_printf(dev, "MTRR Set Correctly for tdfx\n");
  357 #endif
  358         } else if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO2) ||
  359                 (pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO1)) {
  360                 /* if, for some reason we can't set the WRCOMB range with the V1/V2, we
  361                  * can still possibly use the UNCACHEABLE region for it instead, and help
  362                  * out in a small way */
  363                 tdfx_info->mrdesc.mr_flags = MDF_UNCACHEABLE;
  364                 /* This length of 1000h was taken from the linux device driver... */
  365                 tdfx_info->mrdesc.mr_len = 0x1000;
  366 
  367                 /*
  368                  * If, for some reason, we can't set the MTRR (N/A?) we may still continue
  369                  */
  370 #ifdef DEBUG
  371                 device_printf(dev, "MTRR Set Type Uncacheable %x\n",
  372                     (u_int32_t)tdfx_info->mrdesc.mr_base);
  373 #endif
  374         }
  375 #ifdef DEBUG
  376         else {
  377                 device_printf(dev, "Couldn't Set MTRR\n");
  378                 return 0;
  379         }
  380 #endif
  381         return 0;
  382 }
  383                 
  384 static int
  385 tdfx_open(struct cdev *dev, int flags, int fmt, struct thread *td)
  386 {
  387         /* 
  388          *      The open cdev method handles open(2) calls to /dev/3dfx[n] 
  389          * We can pretty much allow any opening of the device.
  390          */
  391         struct tdfx_softc *tdfx_info = dev->si_drv1;
  392         if(tdfx_info->busy != 0) return EBUSY;
  393 #ifdef  DEBUG
  394         printf("3dfx: Opened by #%d\n", td->td_proc->p_pid);
  395 #endif
  396         /* Set the driver as busy */
  397         tdfx_info->busy++;
  398         return 0;
  399 }
  400 
  401 static int 
  402 tdfx_close(struct cdev *dev, int fflag, int devtype, struct thread *td) 
  403 {
  404         /* 
  405          *      The close cdev method handles close(2) calls to /dev/3dfx[n] 
  406          * We'll always want to close the device when it's called.
  407          */
  408         struct tdfx_softc *tdfx_info = dev->si_drv1;
  409         if(tdfx_info->busy == 0) return EBADF;
  410         tdfx_info->busy = 0;
  411 #ifdef  DEBUG
  412         printf("Closed by #%d\n", td->td_proc->p_pid);
  413 #endif
  414         return 0;
  415 }
  416 
  417 static int
  418 tdfx_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
  419     int nprot, vm_memattr_t *memattr)
  420 {
  421         /* 
  422          * mmap(2) is called by a user process to request that an area of memory
  423          * associated with this device be mapped for the process to work with. Nprot
  424          * holds the protections requested, PROT_READ, PROT_WRITE, or both.
  425          */
  426 
  427         /**** OLD GET CONFIG ****/
  428         /* struct tdfx_softc* tdfx_info; */
  429         
  430         /* Get the configuration for our card XXX*/
  431         /*tdfx_info = dev->si_drv1; */
  432         /************************/
  433 
  434         struct tdfx_softc* tdfx_info[2];
  435         
  436         tdfx_info[0] = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass, 0);
  437 
  438         /* If, for some reason, its not configured, we bail out */
  439         if(tdfx_info[0] == NULL) {
  440 #ifdef  DEBUG
  441            printf("tdfx: tdfx_info (softc) is NULL\n");
  442 #endif
  443            return -1;
  444         }
  445 
  446         /* We must stay within the bound of our address space */
  447         if((offset & 0xff000000) == tdfx_info[0]->addr0) {
  448                 offset &= 0xffffff;
  449                 *paddr = rman_get_start(tdfx_info[0]->memrange) + offset;
  450                 return 0;
  451         }
  452         
  453         if(tdfx_count > 1) {
  454                 tdfx_info[1] = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass, 1);
  455                 if((offset & 0xff000000) == tdfx_info[1]->addr0) {
  456                         offset &= 0xffffff;
  457                         *paddr = rman_get_start(tdfx_info[1]->memrange) +
  458                             offset;
  459                         return 0;
  460                 }
  461         }
  462 
  463         /* See if the Banshee/V3 LFB is being requested */
  464         /*if(tdfx_info->memrange2 != NULL && (offset & 0xff000000) ==
  465                         tdfx_info->addr1) {
  466                 offset &= 0xffffff;
  467                 return atop(rman_get_start(tdfx_info[1]->memrange2) + offset);
  468         }*/ /* VoodooNG code */
  469 
  470         /* The ret call */
  471         /* atop -> address to page
  472          * rman_get_start, get the (struct resource*)->r_start member,
  473          * the mapping base address.
  474          */
  475         return -1;
  476 }
  477 
  478 static int
  479 tdfx_query_boards(void) {
  480         /* 
  481     *   This returns the number of installed tdfx cards, we have been keeping
  482          * count, look at tdfx_attach 
  483          */
  484         return tdfx_count;
  485 }
  486 
  487 static int
  488 tdfx_query_fetch(u_int cmd, struct tdfx_pio_data *piod)
  489 {
  490         /* XXX Comment this later, after careful inspection and spring cleaning :) */
  491         /* Various return values 8bit-32bit */
  492         u_int8_t  ret_byte;
  493         u_int16_t ret_word;
  494         u_int32_t ret_dword;
  495         struct tdfx_softc* tdfx_info = NULL;    
  496 
  497         /* This one depend on the tdfx_* structs being properly initialized */
  498 
  499         /*piod->device &= 0xf;*/
  500         if((piod == NULL) ||(tdfx_count <= piod->device) ||
  501                         (piod->device < 0)) {
  502 #ifdef DEBUG
  503                 printf("tdfx: Bad device or internal struct in tdfx_query_fetch\n");
  504 #endif
  505                 return -EINVAL;
  506         }
  507 
  508         tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass,
  509                         piod->device);
  510 
  511         if(tdfx_info == NULL) return -ENXIO;
  512 
  513         /* We must restrict the size reads from the port, since to high or low of a
  514          * size witll result in wrong data being passed, and that's bad */
  515         /* A few of these were pulled during the attach phase */
  516         switch(piod->port) {
  517                 case PCI_VENDOR_ID_FREEBSD:
  518                         if(piod->size != 2) return -EINVAL;
  519                         copyout(&tdfx_info->vendor, piod->value, piod->size);
  520                         return 0;
  521                 case PCI_DEVICE_ID_FREEBSD:
  522                         if(piod->size != 2) return -EINVAL;
  523                         copyout(&tdfx_info->type, piod->value, piod->size);
  524                         return 0;
  525                 case PCI_BASE_ADDRESS_0_FREEBSD:
  526                         if(piod->size != 4) return -EINVAL;
  527                         copyout(&tdfx_info->addr0, piod->value, piod->size);
  528                         return 0;
  529                 case PCI_BASE_ADDRESS_1_FREEBSD:
  530                         if(piod->size != 4) return -EINVAL;
  531                         copyout(&tdfx_info->addr1, piod->value, piod->size);
  532                         return 0;
  533                 case PCI_PRIBUS_FREEBSD:
  534                         if(piod->size != 1) return -EINVAL;
  535                         break;
  536                 case PCI_IOBASE_0_FREEBSD:
  537                         if(piod->size != 2) return -EINVAL;
  538                         break;
  539                 case PCI_IOLIMIT_0_FREEBSD:
  540                         if(piod->size != 2) return -EINVAL;
  541                         break;
  542                 case SST1_PCI_SPECIAL1_FREEBSD:
  543                         if(piod->size != 4) return -EINVAL;
  544                         break;
  545                 case PCI_REVISION_ID_FREEBSD:
  546                         if(piod->size != 1) return -EINVAL;
  547                         break;
  548                 case SST1_PCI_SPECIAL4_FREEBSD:
  549                         if(piod->size != 4) return -EINVAL;
  550                         break;
  551                 default:
  552                         return -EINVAL;
  553         }
  554 
  555         
  556         /* Read the value and return */
  557         switch(piod->size) {
  558                 case 1:
  559                         ret_byte = pci_read_config(tdfx_info[piod->device].dev, 
  560                                         piod->port, 1);
  561                         copyout(&ret_byte, piod->value, 1);
  562                         break;
  563                 case 2:
  564                         ret_word = pci_read_config(tdfx_info[piod->device].dev, 
  565                                         piod->port, 2);
  566                         copyout(&ret_word, piod->value, 2);
  567                         break;
  568                 case 4:
  569                         ret_dword = pci_read_config(tdfx_info[piod->device].dev, 
  570                                         piod->port, 4);
  571                         copyout(&ret_dword, piod->value, 4);
  572                         break;
  573                 default:
  574                         return -EINVAL;
  575         }
  576         return 0;
  577 }
  578 
  579 static int
  580 tdfx_query_update(u_int cmd, struct tdfx_pio_data *piod)
  581 {
  582         /* XXX Comment this later, after careful inspection and spring cleaning :) */
  583         /* Return vals */
  584         u_int8_t  ret_byte;
  585         u_int16_t ret_word;
  586         u_int32_t ret_dword;
  587 
  588         /* Port vals, mask */
  589         u_int32_t retval, preval, mask;
  590         struct tdfx_softc* tdfx_info = NULL;
  591                         
  592 
  593         if((piod == NULL) || (piod->device >= (tdfx_count &
  594                                         0xf))) {
  595 #ifdef DEBUG
  596                 printf("tdfx: Bad struct or device in tdfx_query_update\n");
  597 #endif
  598                 return -EINVAL;
  599         }
  600 
  601         tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass, 
  602                         piod->device);
  603         if(tdfx_info == NULL) return -ENXIO;
  604         /* Code below this line in the fuction was taken from the 
  605          * Linux driver and converted for freebsd. */
  606 
  607         /* Check the size for all the ports, to make sure stuff doesn't get messed up
  608          * by poorly written clients */
  609 
  610         switch(piod->port) {
  611                 case PCI_COMMAND_FREEBSD:
  612                         if(piod->size != 2) return -EINVAL;
  613                         break;
  614                 case SST1_PCI_SPECIAL1_FREEBSD:
  615                         if(piod->size != 4) return -EINVAL;
  616                         break;
  617                 case SST1_PCI_SPECIAL2_FREEBSD:
  618                         if(piod->size != 4) return -EINVAL;
  619                         break;
  620                 case SST1_PCI_SPECIAL3_FREEBSD:
  621                         if(piod->size != 4) return -EINVAL;
  622                         break;
  623                 case SST1_PCI_SPECIAL4_FREEBSD:
  624                         if(piod->size != 4) return -EINVAL;
  625                         break;
  626                 default:
  627                         return -EINVAL;
  628         }
  629         /* Read the current value */
  630         retval = pci_read_config(tdfx_info->dev, piod->port & ~3, 4);
  631                         
  632         /* These set up a mask to use, since apparently they wanted to write 4 bytes
  633          * at once to the ports */
  634         switch (piod->size) {
  635                 case 1:
  636                         copyin(piod->value, &ret_byte, 1);
  637                         preval = ret_byte << (8 * (piod->port & 0x3));
  638                         mask = 0xff << (8 * (piod->port & 0x3));
  639                         break;
  640                 case 2:
  641                         copyin(piod->value, &ret_word, 2);
  642                         preval = ret_word << (8 * (piod->port & 0x3));
  643                         mask = 0xffff << (8 * (piod->port & 0x3));
  644                         break;
  645                 case 4:
  646                         copyin(piod->value, &ret_dword, 4);
  647                         preval = ret_dword;
  648                         mask = ~0;
  649                         break;
  650                 default:
  651                         return -EINVAL;
  652         }
  653         /* Finally, combine the values and write it to the port */
  654         retval = (retval & ~mask) | preval;
  655         pci_write_config(tdfx_info->dev, piod->port & ~3, retval, 4);
  656    
  657         return 0;
  658 }
  659 
  660 /* For both of these, I added a variable named workport of type u_int so
  661  * that I could eliminate the warning about my data type size. The
  662  * applications expect the port to be of type short, so I needed to change
  663  * this within the function */
  664 static int
  665 tdfx_do_pio_rd(struct tdfx_pio_data *piod)
  666 {
  667         /* Return val */
  668         u_int8_t  ret_byte;
  669         u_int    workport;
  670         struct tdfx_softc *tdfx_info = 
  671                 (struct tdfx_softc*)devclass_get_softc(tdfx_devclass, piod->device);
  672                 
  673         /* Restricts the access of ports other than those we use */
  674         if(((piod->port != VGA_INPUT_STATUS_1C) || (piod->port != SC_INDEX) ||
  675                 (piod->port != SC_DATA) || (piod->port != VGA_MISC_OUTPUT_READ)) &&
  676                 (piod->port < tdfx_info->pio0) && (piod->port > tdfx_info->pio0max))
  677                 return -EPERM;
  678         
  679         /* All VGA STATUS REGS are byte registers, size should never be > 1 */
  680         if(piod->size != 1) {
  681                 return -EINVAL;
  682         }
  683 
  684         /* Write the data to the intended port */
  685         workport = piod->port;
  686         ret_byte = inb(workport);
  687         copyout(&ret_byte, piod->value, sizeof(u_int8_t));
  688         return 0;
  689 }
  690 
  691 static int
  692 tdfx_do_pio_wt(struct tdfx_pio_data *piod) 
  693 {
  694         /* return val */
  695         u_int8_t  ret_byte;
  696         u_int            workport;
  697         struct tdfx_softc *tdfx_info = (struct
  698                         tdfx_softc*)devclass_get_softc(tdfx_devclass, piod->device);
  699         /* Replace old switch w/ massive if(...) */
  700         /* Restricts the access of ports other than those we use */
  701         if(((piod->port != SC_INDEX) && (piod->port != SC_DATA) && 
  702                 (piod->port != VGA_MISC_OUTPUT_READ)) /* Can't write VGA_ST_1C */ &&
  703                 (piod->port < tdfx_info->pio0) && (piod->port > tdfx_info->pio0max))
  704                 return -EPERM;
  705         
  706         /* All VGA STATUS REGS are byte registers, size should never be > 1 */
  707         if(piod->size != 1) {
  708                 return -EINVAL;
  709         }
  710 
  711         /* Write the data to the intended port */
  712         copyin(piod->value, &ret_byte, sizeof(u_int8_t));
  713         workport = piod->port;
  714         outb(workport, ret_byte);
  715         return 0;
  716 }
  717 
  718 static int
  719 tdfx_do_query(u_int cmd, struct tdfx_pio_data *piod)
  720 {
  721         /* There are three sub-commands to the query 0x33 */
  722         switch(_IOC_NR(cmd)) {
  723                 case 2:
  724                         return tdfx_query_boards();
  725                         break;
  726                 case 3:
  727                         return tdfx_query_fetch(cmd, piod);
  728                         break;
  729                 case 4:
  730                         return tdfx_query_update(cmd, piod);
  731                         break;
  732                 default:
  733                         /* In case we are thrown a bogus sub-command! */
  734 #ifdef DEBUG
  735                         printf("Bad Sub-cmd: 0x%x\n", _IOC_NR(cmd));
  736 #endif
  737                         return -EINVAL;
  738         }
  739 }
  740 
  741 static int
  742 tdfx_do_pio(u_int cmd, struct tdfx_pio_data *piod) 
  743 {
  744         /* Two types of PIO, INPUT and OUTPUT, as the name suggests */
  745         switch(_IOC_DIR(cmd)) {
  746                 case IOCV_OUT: 
  747                         return tdfx_do_pio_rd(piod);
  748                         break;
  749                 case IOCV_IN:
  750                         return tdfx_do_pio_wt(piod);
  751                         break;
  752                 default:
  753                         return -EINVAL;
  754         }
  755 }
  756 
  757 /* Calls to ioctl(2) eventually end up here. Unhandled ioctls return an ENXIO,
  758  * normally, you would read in the data pointed to by data, then write your
  759  * output to it. The ioctl *should* normally return zero if everything is
  760  * alright, but 3dfx didn't make it that way...
  761  *
  762  * For all of the ioctl code, in the event of a real error,
  763  * we return -Exxxx rather than simply Exxxx. The reason for this
  764  * is that the ioctls actually RET information back to the program
  765  * sometimes, rather than filling it in the passed structure. We
  766  * want to distinguish errors from useful data, and maintain compatibility.
  767  *
  768  * There is this portion of the proc struct called p_retval[], we can store a
  769  * return value in td->td_retval[0] and place the return value if it is positive
  770  * in there, then we can return 0 (good). If the return value is negative, we
  771  * can return -retval and the error should be properly handled.
  772  */
  773 static int
  774 tdfx_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  775 {
  776         int retval = 0;
  777         struct tdfx_pio_data *piod = (struct tdfx_pio_data*)data;
  778 #ifdef  DEBUG
  779         printf("IOCTL'd by #%d, cmd: 0x%x, data: %p\n", td->td_proc->p_pid, (u_int32_t)cmd,
  780                         piod);
  781 #endif
  782         switch(_IOC_TYPE(cmd)) {
  783                 /* Return the real error if negative, or simply stick the valid return
  784                  * in td->td_retval */
  785         case 0x33:
  786                         /* The '3'(0x33) type IOCTL is for querying the installed cards */
  787                         if((retval = tdfx_do_query(cmd, piod)) > 0) td->td_retval[0] = retval;
  788                         else return -retval;
  789                         break;
  790                 case 0:
  791                         /* The 0 type IOCTL is for programmed I/O methods */
  792                         if((tdfx_do_pio(cmd, piod)) > 0) td->td_retval[0] = retval;
  793                         else return -retval;
  794                         break;
  795                 default:
  796                         /* Technically, we won't reach this from linux emu, but when glide
  797                          * finally gets ported, watch out! */
  798 #ifdef DEBUG
  799                         printf("Bad IOCTL from #%d\n", td->td_proc->p_pid);
  800 #endif
  801                         return ENXIO;
  802         }
  803 
  804         return 0;
  805 }
  806 
  807 /* This is the device driver struct. This is sent to the driver subsystem to
  808  * register the method structure and the info strcut space for this particular
  809  * instance of the driver.
  810  */
  811 static driver_t tdfx_driver = {
  812         "tdfx", 
  813         tdfx_methods,
  814         sizeof(struct tdfx_softc),
  815 };
  816 
  817 /* Tell Mr. Kernel about us! */
  818 DRIVER_MODULE(tdfx, pci, tdfx_driver, tdfx_devclass, 0, 0);
  819 MODULE_DEPEND(tdfx, mem, 1, 1, 1);
  820 MODULE_VERSION(tdfx, 1);

Cache object: 483366f34275051e2cd91989ecd4a7f6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.