mirror of
https://git.hardenedbsd.org/hardenedbsd/HardenedBSD.git
synced 2024-11-15 14:56:13 +01:00
First import of my 3dfx voodoo driver. Currently it supports the Voodoo Graphics and Voodoo2 perfectly. It works just like the 3dfx driver does for linux, by using a character device at /dev/3dfx of Major 107 to provide a window into the 3dfx card's memory space. This interface is used by glide and mesa as far as i know, and probably some other libraries too.
Approved by: jkh
This commit is contained in:
parent
70ccb0b9db
commit
f9c078dffe
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/cvs2svn/branches/COKANE/; revision=61911
68
sys/dev/tdfx/tdfx_io.h
Normal file
68
sys/dev/tdfx/tdfx_io.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* This code originally came from a nice man, I don't have your name,
|
||||
* please email cokane@pohl.ececs.uc.edu for proper recognition
|
||||
* it is basically a derivative of some sys/dhio.h file to work with the 3dfx
|
||||
* cards
|
||||
*/
|
||||
#ifndef TDFX_IO_H
|
||||
#define TDFX_IO_H
|
||||
|
||||
#ifndef KERNEL
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* define an ioctl here
|
||||
*/
|
||||
#define DHIOCRESET _IO('D', 0) /* reset the voodoo device */
|
||||
#define GETVOODOO 0x3302
|
||||
#define SETVOODOO 0x3303
|
||||
#define MOREVOODOO 0x3300
|
||||
#define _IOC_NRBITS 8
|
||||
#define _IOC_TYPEBITS 8
|
||||
#define _IOC_SIZEBITS 14
|
||||
#define _IOC_DIRBITS 2
|
||||
|
||||
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
|
||||
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
|
||||
#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
|
||||
#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
|
||||
|
||||
#define _IOC_NRSHIFT 0
|
||||
#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
|
||||
#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
|
||||
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
|
||||
|
||||
/*
|
||||
* Direction bits.
|
||||
*/
|
||||
#define _IOC_NONE 0U
|
||||
#define _IOC_WRITE 1U
|
||||
#define _IOC_READ 2U
|
||||
|
||||
#define _IOCV(dir,type,nr,size) \
|
||||
(((dir) << _IOC_DIRSHIFT) | \
|
||||
((type) << _IOC_TYPESHIFT) | \
|
||||
((nr) << _IOC_NRSHIFT) | \
|
||||
((size) << _IOC_SIZESHIFT))
|
||||
|
||||
/* used to create numbers */
|
||||
#define _IOV(type,nr) _IOCV(_IOC_NONE,(type),(nr),0)
|
||||
#define _IORV(type,nr,size) _IOCV(_IOC_READ,(type),(nr),sizeof(size))
|
||||
#define _IOWV(type,nr,size) _IOCV(_IOC_WRITE,(type),(nr),sizeof(size))
|
||||
#define _IOWRV(type,nr,size) _IOCV(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
|
||||
|
||||
/* used to decode ioctl numbers.. */
|
||||
#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
|
||||
#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
|
||||
#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
|
||||
#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
|
||||
|
||||
/* ...and for the drivers/sound files... */
|
||||
|
||||
#define IOCV_IN (_IOC_WRITE << _IOC_DIRSHIFT)
|
||||
#define IOCV_OUT (_IOC_READ << _IOC_DIRSHIFT)
|
||||
#define IOCV_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
|
||||
#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
|
||||
#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
|
||||
|
||||
#endif
|
707
sys/dev/tdfx/tdfx_pci.c
Normal file
707
sys/dev/tdfx/tdfx_pci.c
Normal file
@ -0,0 +1,707 @@
|
||||
/* 3dfx driver for FreeBSD 4.x - Finished 11 May 2000, 12:25AM ET
|
||||
*
|
||||
* Copyright (C) 2000, by Coleman Kane <cokane@pohl.ececs.uc.edu>,
|
||||
* based upon the 3dfx driver written for linux, by Daryll Straus, Jon Taylor,
|
||||
* and Jens Axboe, located at http://linux.3dfx.com.
|
||||
*/
|
||||
|
||||
/*
|
||||
* put this here, so as to bail out immediately if we have no PCI BUS installed
|
||||
*/
|
||||
#include "pci.h"
|
||||
#if NPCI > 0
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <sys/bus_private.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/filedesc.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
/*#include <sys/memrange.h>*/
|
||||
#include <sys/mman.h>
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <pci/pcivar.h>
|
||||
#include <pci/pcireg.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_kern.h>
|
||||
#include <vm/pmap.h>
|
||||
#include <vm/vm_extern.h>
|
||||
|
||||
/* rman.h depends on machine/bus.h */
|
||||
#include <machine/resource.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
|
||||
#include <dev/tdfx/tdfx_io.h>
|
||||
#include <dev/tdfx/tdfx_vars.h>
|
||||
#include <dev/tdfx/tdfx_pci.h>
|
||||
|
||||
#include "opt_tdfx.h"
|
||||
|
||||
static devclass_t tdfx_devclass;
|
||||
|
||||
|
||||
static int tdfx_count = 0;
|
||||
|
||||
|
||||
/* Set up the boot probe/attach routines */
|
||||
static device_method_t tdfx_methods[] = {
|
||||
DEVMETHOD(device_probe, tdfx_probe),
|
||||
DEVMETHOD(device_attach, tdfx_attach),
|
||||
DEVMETHOD(device_detach, tdfx_detach),
|
||||
DEVMETHOD(device_shutdown, tdfx_shutdown),
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
MALLOC_DEFINE(M_TDFX,"TDFX Driver","3DFX Graphics[/2D]/3D Accelerator(s)");
|
||||
|
||||
/* Char. Dev. file operations structure */
|
||||
static struct cdevsw tdfx_cdev = {
|
||||
tdfx_open, /* open */
|
||||
tdfx_close, /* close */
|
||||
noread, /* read */
|
||||
nowrite, /* write */
|
||||
tdfx_ioctl, /* ioctl */
|
||||
nopoll, /* poll */
|
||||
tdfx_mmap, /* mmap */
|
||||
nostrategy, /* strategy */
|
||||
"tdfx", /* dev name */
|
||||
CDEV_MAJOR, /* char major */
|
||||
nodump, /* dump */
|
||||
nopsize, /* size */
|
||||
0, /* flags (no set flags) */
|
||||
-1 /* bmaj (no block dev) */
|
||||
};
|
||||
|
||||
static int
|
||||
tdfx_probe(device_t dev)
|
||||
{
|
||||
/*
|
||||
* probe routine called on kernel boot to register supported devices. We get
|
||||
* a device structure to work with, and we can test the VENDOR/DEVICE IDs to
|
||||
* see if this PCI device is one that we support. Return 0 if yes, ENXIO if
|
||||
* not.
|
||||
*/
|
||||
switch(pci_get_devid(dev)) {
|
||||
case PCI_DEVICE_ALLIANCE_AT3D:
|
||||
device_set_desc(dev, "ProMotion At3D 3D Accelerator");
|
||||
return 0;
|
||||
case PCI_DEVICE_3DFX_VOODOO2:
|
||||
device_set_desc(dev, "3DFX Voodoo II 3D Accelerator");
|
||||
return 0;
|
||||
case PCI_DEVICE_3DFX_BANSHEE:
|
||||
device_set_desc(dev, "3DFX Voodoo Banshee 2D/3D Graphics Accelerator");
|
||||
return 0;
|
||||
case PCI_DEVICE_3DFX_VOODOO3:
|
||||
device_set_desc(dev, "3DFX Voodoo3 2D/3D Graphics Accelerator");
|
||||
return 0;
|
||||
case PCI_DEVICE_3DFX_VOODOO1:
|
||||
device_set_desc(dev, "3DFX Voodoo Graphics 3D Accelerator");
|
||||
return 0;;
|
||||
};
|
||||
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_attach(device_t dev) {
|
||||
/*
|
||||
* The attach routine is called after the probe routine successfully says it
|
||||
* supports a given card. We now proceed to initialize this card for use with
|
||||
* the system. I want to map the device memory for userland allocation and
|
||||
* fill an information structure with information on this card. I'd also like
|
||||
* to set Write Combining with the MTRR code so that we can hopefully speed
|
||||
* up memory writes. The last thing is to register the character device
|
||||
* interface to the card, so we can open it from /dev/3dfxN, where N is a
|
||||
* small, whole number.
|
||||
*/
|
||||
|
||||
struct tdfx_softc *tdfx_info;
|
||||
u_long val;
|
||||
/* rid value tells bus_alloc_resource where to find the addresses of ports or
|
||||
* of memory ranges in the PCI config space*/
|
||||
int rid = PCIR_MAPS;
|
||||
|
||||
/* Increment the card counter (for the ioctl code) */
|
||||
tdfx_count++;
|
||||
|
||||
/* Enable MemMap on Voodoo */
|
||||
val = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
val |= (PCIM_CMD_MEMEN);
|
||||
pci_write_config(dev, PCIR_COMMAND, val, 2);
|
||||
val = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||
|
||||
/* Fill the soft config struct with info about this device*/
|
||||
tdfx_info = device_get_softc(dev);
|
||||
tdfx_info->dev = dev;
|
||||
tdfx_info->vendor = pci_get_vendor(dev);
|
||||
tdfx_info->type = pci_get_devid(dev) >> 16;
|
||||
tdfx_info->bus = pci_get_bus(dev);
|
||||
tdfx_info->dv = pci_get_slot(dev);
|
||||
tdfx_info->curFile = NULL;
|
||||
|
||||
/*
|
||||
* Get the Memory Location from the PCI Config, mask out lower word, since
|
||||
* the config space register is only one word long (this is nicer than a
|
||||
* bitshift).
|
||||
*/
|
||||
tdfx_info->addr0 = (pci_read_config(dev, 0x10, 4) & 0xffff0000);
|
||||
#ifdef TDFX_VERBOSE
|
||||
device_printf(dev, "Base0 @ 0x%x\n", tdfx_info->addr0);
|
||||
#endif
|
||||
|
||||
/* Notify the VM that we will be mapping some memory later */
|
||||
tdfx_info->memrange = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, ~0, 1,
|
||||
RF_ACTIVE);
|
||||
if(tdfx_info->memrange == NULL) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
device_printf(dev, "Error mapping mem, won't be able to use mmap()\n");
|
||||
#endif
|
||||
tdfx_info->memrid = 0;
|
||||
}
|
||||
else {
|
||||
tdfx_info->memrid = rid;
|
||||
#ifdef TDFX_VERBOSE
|
||||
device_printf(dev, "Mapped to: 0x%x\n",
|
||||
(unsigned int)rman_get_start(tdfx_info->memrange));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Set Writecombining, or at least Uncacheable for the memory region, if we
|
||||
* are able to
|
||||
*/
|
||||
|
||||
if(tdfx_setmtrr(dev) != 0) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
device_printf(dev, "Some weird error setting MTRRs");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* make_dev registers the cdev to access the 3dfx card from /dev
|
||||
* use hex here for the dev num, simply to provide better support if > 10
|
||||
* voodoo cards, for the mad. The user must set the link, or use MAKEDEV.
|
||||
* Why would we want that many voodoo cards anyhow?
|
||||
*/
|
||||
make_dev(&tdfx_cdev, dev->unit, 0, 0, 02660, "3dfx%x", dev->unit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_detach(device_t dev) {
|
||||
struct tdfx_softc* tdfx_info;
|
||||
int retval;
|
||||
tdfx_info = device_get_softc(dev);
|
||||
|
||||
/* Delete allocated resource, of course */
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, PCI_MAP_REG_START,
|
||||
tdfx_info->memrange);
|
||||
|
||||
/* Though it is safe to leave the WRCOMB support since the
|
||||
mem driver checks for it, we should remove it in order
|
||||
to free an MTRR for another device */
|
||||
retval = tdfx_clrmtrr(dev);
|
||||
#ifdef TDFX_VERBOSE
|
||||
if(retval != 0)
|
||||
printf("tdfx: For some reason, I couldn't clear the mtrr\n");
|
||||
#endif
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_shutdown(device_t dev) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
device_printf(dev, "tdfx: Device Shutdown\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_clrmtrr(device_t dev) {
|
||||
/* This function removes the MTRR set by the attach call, so it can be used
|
||||
* in the future by other drivers.
|
||||
*/
|
||||
int retval, act;
|
||||
struct tdfx_softc *tdfx_info = device_get_softc(dev);
|
||||
|
||||
act = MEMRANGE_SET_REMOVE;
|
||||
retval = mem_range_attr_set(&tdfx_info->mrdesc, &act);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_setmtrr(device_t dev) {
|
||||
/*
|
||||
* This is the MTRR setting function for the 3dfx card. It is called from
|
||||
* tdfx_attach. If we can't set the MTRR properly, it's not the end of the
|
||||
* world. We can still continue, just with slightly (very slightly) degraded
|
||||
* performance.
|
||||
*/
|
||||
int retval = 0, act;
|
||||
struct tdfx_softc *tdfx_info = device_get_softc(dev);
|
||||
/* The memory descriptor is described as the top 15 bits of the real
|
||||
address */
|
||||
tdfx_info->mrdesc.mr_base = pci_read_config(dev, 0x10, 4) & 0xfffe0000;
|
||||
|
||||
/* The older Voodoo cards have a shorter memrange than the newer ones */
|
||||
if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO1) || (pci_get_devid(dev) ==
|
||||
PCI_DEVICE_3DFX_VOODOO2))
|
||||
tdfx_info->mrdesc.mr_len = 0x400000;
|
||||
else if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO3) ||
|
||||
(pci_get_devid(dev) == PCI_DEVICE_3DFX_BANSHEE))
|
||||
tdfx_info->mrdesc.mr_len = 0x1000000;
|
||||
|
||||
else return 0;
|
||||
/*
|
||||
* The Alliance Pro Motion AT3D was not mentioned in the linux
|
||||
* driver as far as MTRR support goes, so I just won't put the
|
||||
* code in here for it. This is where it should go, though.
|
||||
*/
|
||||
|
||||
/* Firstly, try to set write combining */
|
||||
tdfx_info->mrdesc.mr_flags = MDF_WRITECOMBINE;
|
||||
bcopy("tdfx", &tdfx_info->mrdesc.mr_owner, 4);
|
||||
act = MEMRANGE_SET_UPDATE;
|
||||
retval = mem_range_attr_set(&tdfx_info->mrdesc, &act);
|
||||
|
||||
if(retval == 0) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
device_printf(dev, "MTRR Set Correctly for tdfx\n");
|
||||
#endif
|
||||
} else if((pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO2) ||
|
||||
(pci_get_devid(dev) == PCI_DEVICE_3DFX_VOODOO1)) {
|
||||
/* if, for some reason we can't set the WRCOMB range with the V1/V2, we
|
||||
* can still possibly use the UNCACHEABLE region for it instead, and help
|
||||
* out in a small way */
|
||||
tdfx_info->mrdesc.mr_flags = MDF_UNCACHEABLE;
|
||||
/* This length of 1000h was taken from the linux device driver... */
|
||||
tdfx_info->mrdesc.mr_len = 0x1000;
|
||||
|
||||
/*
|
||||
* If, for some reason, we can't set the MTRR (N/A?) we may still continue
|
||||
*/
|
||||
#ifdef TDFX_VERBOSE
|
||||
if(retval == 0) {
|
||||
device_printf(dev, "MTRR Set Type Uncacheable
|
||||
%x\n", (u_int32_t)tdfx_info->mrdesc.mr_base);
|
||||
} else {
|
||||
device_printf(dev, "Couldn't Set MTRR\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef TDFX_VERBOSE
|
||||
else {
|
||||
device_printf(dev, "Couldn't Set MTRR\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_open(dev_t dev, int flags, int fmt, struct proc *p)
|
||||
{
|
||||
/*
|
||||
* The open cdev method handles open(2) calls to /dev/3dfx[n]
|
||||
* We can pretty much allow any opening of the device.
|
||||
*/
|
||||
struct tdfx_softc *tdfx_info = devclass_get_softc(tdfx_devclass,
|
||||
UNIT(minor(dev)));
|
||||
if(tdfx_info->busy != 0) return EBUSY;
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("3dfx: Opened by #%d\n", p->p_pid);
|
||||
#endif
|
||||
/* Set the driver as busy */
|
||||
tdfx_info->busy++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_close(dev_t dev, int fflag, int devtype, struct proc* p)
|
||||
{
|
||||
/*
|
||||
* The close cdev method handles close(2) calls to /dev/3dfx[n]
|
||||
* We'll always want to close the device when it's called.
|
||||
*/
|
||||
struct tdfx_softc *tdfx_info = devclass_get_softc(tdfx_devclass,
|
||||
UNIT(minor(dev)));
|
||||
if(tdfx_info->busy == 0) return EBADF;
|
||||
tdfx_info->busy = 0;
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("Closed by #%d\n", p->p_pid);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_mmap(dev_t dev, vm_offset_t offset, int nprot)
|
||||
{
|
||||
/*
|
||||
* mmap(2) is called by a user process to request that an area of memory
|
||||
* associated with this device be mapped for the process to work with. Nprot
|
||||
* holds the protections requested, PROT_READ, PROT_WRITE, or both.
|
||||
*/
|
||||
struct tdfx_softc* tdfx_info;
|
||||
|
||||
/* Get the configuration for our card XXX*/
|
||||
tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass,
|
||||
UNIT(minor(dev)));
|
||||
|
||||
/* If, for some reason, its not configured, we bail out */
|
||||
if(tdfx_info == NULL) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("tdfx: tdfx_info (softc) is NULL\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We must stay within the bound of our address space */
|
||||
if((offset & 0xff000000) == tdfx_info->addr0)
|
||||
offset &= 0xffffff;
|
||||
if((offset >= 0x1000000) || (offset < 0)) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("tdfx: offset %x out of range\n", offset);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* atop -> address to page
|
||||
* rman_get_start, get the (struct resource*)->r_start member,
|
||||
* the mapping base address.
|
||||
*/
|
||||
return atop(rman_get_start(tdfx_info->memrange) + offset);
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_query_boards(void) {
|
||||
/*
|
||||
* This returns the number of installed tdfx cards, we have been keeping
|
||||
* count, look at tdfx_attach
|
||||
*/
|
||||
return tdfx_count;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_query_fetch(u_int cmd, struct tdfx_pio_data *piod)
|
||||
{
|
||||
/* XXX Comment this later, after careful inspection and spring cleaning :) */
|
||||
/* Various return values 8bit-32bit */
|
||||
u_int8_t ret_byte;
|
||||
u_int16_t ret_word;
|
||||
u_int32_t ret_dword;
|
||||
struct tdfx_softc* tdfx_info = NULL;
|
||||
|
||||
/* This one depend on the tdfx_* structs being properly initialized */
|
||||
|
||||
/*piod->device &= 0xf;*/
|
||||
if((piod == NULL) ||(tdfx_count <= piod->device) ||
|
||||
(piod->device < 0)) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("tdfx: Bad device or internal struct in tdfx_query_fetch\n");
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass,
|
||||
piod->device);
|
||||
|
||||
if(tdfx_info == NULL) return -ENXIO;
|
||||
|
||||
/* We must restrict the size reads from the port, since to high or low of a
|
||||
* size witll result in wrong data being passed, and that's bad */
|
||||
/* A few of these were pulled during the attach phase */
|
||||
switch(piod->port) {
|
||||
case PCI_VENDOR_ID_FREEBSD:
|
||||
if(piod->size != 2) return -EINVAL;
|
||||
copyout(&tdfx_info->vendor, piod->value, piod->size);
|
||||
return 0;
|
||||
case PCI_DEVICE_ID_FREEBSD:
|
||||
if(piod->size != 2) return -EINVAL;
|
||||
copyout(&tdfx_info->type, piod->value, piod->size);
|
||||
return 0;
|
||||
case PCI_BASE_ADDRESS_0_FREEBSD:
|
||||
if(piod->size != 4) return -EINVAL;
|
||||
copyout(&tdfx_info->addr0, piod->value, piod->size);
|
||||
return 0;
|
||||
case SST1_PCI_SPECIAL1_FREEBSD:
|
||||
if(piod->size != 4) return -EINVAL;
|
||||
break;
|
||||
case PCI_REVISION_ID_FREEBSD:
|
||||
if(piod->size != 1) return -EINVAL;
|
||||
break;
|
||||
case SST1_PCI_SPECIAL4_FREEBSD:
|
||||
if(piod->size != 4) return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/* Read the value and return */
|
||||
switch(piod->size) {
|
||||
case 1:
|
||||
ret_byte = pci_read_config(tdfx_info[piod->device].dev,
|
||||
piod->port, 1);
|
||||
copyout(&ret_byte, piod->value, 1);
|
||||
break;
|
||||
case 2:
|
||||
ret_word = pci_read_config(tdfx_info[piod->device].dev,
|
||||
piod->port, 2);
|
||||
copyout(&ret_word, piod->value, 2);
|
||||
break;
|
||||
case 4:
|
||||
ret_dword = pci_read_config(tdfx_info[piod->device].dev,
|
||||
piod->port, 4);
|
||||
copyout(&ret_dword, piod->value, 4);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_query_update(u_int cmd, struct tdfx_pio_data *piod)
|
||||
{
|
||||
/* XXX Comment this later, after careful inspection and spring cleaning :) */
|
||||
/* Return vals */
|
||||
u_int8_t ret_byte;
|
||||
u_int16_t ret_word;
|
||||
u_int32_t ret_dword;
|
||||
|
||||
/* Port vals, mask */
|
||||
u_int32_t retval, preval, mask;
|
||||
struct tdfx_softc* tdfx_info = NULL;
|
||||
|
||||
|
||||
if((piod == NULL) || (piod->device >= (tdfx_count &
|
||||
0xf))) {
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("tdfx: Bad struct or device in tdfx_query_update\n");
|
||||
#endif
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tdfx_info = (struct tdfx_softc*)devclass_get_softc(tdfx_devclass,
|
||||
piod->device);
|
||||
if(tdfx_info == NULL) return -ENXIO;
|
||||
/* Code below this line in the fuction was taken from the
|
||||
* Linux driver and converted for freebsd. */
|
||||
|
||||
/* Check the size for all the ports, to make sure stuff doesn't get messed up
|
||||
* by poorly written clients */
|
||||
|
||||
switch(piod->port) {
|
||||
case PCI_COMMAND_FREEBSD:
|
||||
if(piod->size != 2) return -EINVAL;
|
||||
break;
|
||||
case SST1_PCI_SPECIAL1_FREEBSD:
|
||||
if(piod->size != 4) return -EINVAL;
|
||||
break;
|
||||
case SST1_PCI_SPECIAL2_FREEBSD:
|
||||
if(piod->size != 4) return -EINVAL;
|
||||
break;
|
||||
case SST1_PCI_SPECIAL3_FREEBSD:
|
||||
if(piod->size != 4) return -EINVAL;
|
||||
break;
|
||||
case SST1_PCI_SPECIAL4_FREEBSD:
|
||||
if(piod->size != 4) return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Read the current value */
|
||||
retval = pci_read_config(tdfx_info->dev, piod->port & ~3, 4);
|
||||
|
||||
/* These set up a mask to use, since apparently they wanted to write 4 bytes
|
||||
* at once to the ports */
|
||||
switch (piod->size) {
|
||||
case 1:
|
||||
copyin(piod->value, &ret_byte, 1);
|
||||
preval = ret_byte << (8 * (piod->port & 0x3));
|
||||
mask = 0xff << (8 * (piod->port & 0x3));
|
||||
break;
|
||||
case 2:
|
||||
copyin(piod->value, &ret_word, 2);
|
||||
preval = ret_word << (8 * (piod->port & 0x3));
|
||||
mask = 0xffff << (8 * (piod->port & 0x3));
|
||||
break;
|
||||
case 4:
|
||||
copyin(piod->value, &ret_dword, 4);
|
||||
preval = ret_dword;
|
||||
mask = ~0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Finally, combine the values and write it to the port */
|
||||
retval = (retval & ~mask) | preval;
|
||||
pci_write_config(tdfx_info->dev, piod->port & ~3, retval, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_do_pio_rd(struct tdfx_pio_data *piod)
|
||||
{
|
||||
/* Return val */
|
||||
u_int8_t ret_byte;
|
||||
|
||||
/* Restricts the access of ports other than those we use */
|
||||
if((piod->port != VGA_INPUT_STATUS_1C) || (piod->port != SC_INDEX) ||
|
||||
(piod->port != SC_DATA) || (piod->port != VGA_MISC_OUTPUT_READ))
|
||||
return -EPERM;
|
||||
|
||||
/* All VGA STATUS REGS are byte registers, size should never be > 1 */
|
||||
if(piod->size != 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Write the data to the intended port */
|
||||
ret_byte = inb(piod->port);
|
||||
copyout(&ret_byte, piod->value, sizeof(u_int8_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_do_pio_wt(struct tdfx_pio_data *piod)
|
||||
{
|
||||
/* return val */
|
||||
u_int8_t ret_byte;
|
||||
|
||||
/* Replace old switch w/ massive if(...) */
|
||||
/* Restricts the access of ports other than those we use */
|
||||
if((piod->port != SC_INDEX) && (piod->port != SC_DATA) &&
|
||||
(piod->port != VGA_MISC_OUTPUT_READ)) /* Can't write VGA_ST_1C */
|
||||
return -EPERM;
|
||||
|
||||
/* All VGA STATUS REGS are byte registers, size should never be > 1 */
|
||||
if(piod->size != 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Write the data to the intended port */
|
||||
copyin(piod->value, &ret_byte, sizeof(u_int8_t));
|
||||
outb(piod->port, ret_byte);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_do_query(u_int cmd, struct tdfx_pio_data *piod)
|
||||
{
|
||||
/* There are three sub-commands to the query 0x33 */
|
||||
switch(_IOC_NR(cmd)) {
|
||||
case 2:
|
||||
return tdfx_query_boards();
|
||||
break;
|
||||
case 3:
|
||||
return tdfx_query_fetch(cmd, piod);
|
||||
break;
|
||||
case 4:
|
||||
return tdfx_query_update(cmd, piod);
|
||||
break;
|
||||
default:
|
||||
/* In case we are thrown a bogus sub-command! */
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("Bad Sub-cmd: 0x%x\n", _IOC_NR(cmd));
|
||||
#endif
|
||||
return -EINVAL;
|
||||
};
|
||||
}
|
||||
|
||||
static int
|
||||
tdfx_do_pio(u_int cmd, struct tdfx_pio_data *piod)
|
||||
{
|
||||
/* Two types of PIO, INPUT and OUTPUT, as the name suggests */
|
||||
switch(_IOC_DIR(cmd)) {
|
||||
case IOCV_OUT:
|
||||
return tdfx_do_pio_rd(piod);
|
||||
break;
|
||||
case IOCV_IN:
|
||||
return tdfx_do_pio_wt(piod);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
};
|
||||
}
|
||||
|
||||
/* Calls to ioctl(2) eventually end up here. Unhandled ioctls return an ENXIO,
|
||||
* normally, you would read in the data pointed to by data, then write your
|
||||
* output to it. The ioctl *should* normally return zero if everything is
|
||||
* alright, but 3dfx didn't make it that way...
|
||||
*
|
||||
* For all of the ioctl code, in the event of a real error,
|
||||
* we return -Exxxx rather than simply Exxxx. The reason for this
|
||||
* is that the ioctls actually RET information back to the program
|
||||
* sometimes, rather than filling it in the passed structure. We
|
||||
* want to distinguish errors from useful data, and maintain compatibility.
|
||||
*
|
||||
* There is this portion of the proc struct called p_retval[], we can store a
|
||||
* return value in p->p_retval[0] and place the return value if it is positive
|
||||
* in there, then we can return 0 (good). If the return value is negative, we
|
||||
* can return -retval and the error should be properly handled.
|
||||
*/
|
||||
static int
|
||||
tdfx_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc * p)
|
||||
{
|
||||
int retval = 0;
|
||||
struct tdfx_pio_data *piod = (struct tdfx_pio_data*)data;
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("IOCTL'd by #%d, cmd: 0x%x, data: 0x%x\n", p->p_pid, (u_int32_t)cmd,
|
||||
(unsigned int)piod);
|
||||
#endif
|
||||
switch(_IOC_TYPE(cmd)) {
|
||||
/* Return the real error if negative, or simply stick the valid return
|
||||
* in p->p_retval */
|
||||
case 0x33:
|
||||
/* The '3'(0x33) type IOCTL is for querying the installed cards */
|
||||
if((retval = tdfx_do_query(cmd, piod)) > 0) p->p_retval[0] = retval;
|
||||
else return -retval;
|
||||
break;
|
||||
case 0:
|
||||
/* The 0 type IOCTL is for programmed I/O methods */
|
||||
if((tdfx_do_pio(cmd, piod)) > 0) p->p_retval[0] = retval;
|
||||
else return -retval;
|
||||
break;
|
||||
default:
|
||||
/* Technically, we won't reach this from linux emu, but when glide
|
||||
* finally gets ported, watch out! */
|
||||
#ifdef TDFX_VERBOSE
|
||||
printf("Bad IOCTL from #%d\n", p->p_pid);
|
||||
#endif
|
||||
return ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This is the device driver struct. This is sent to the driver subsystem to
|
||||
* register the method structure and the info strcut space for this particular
|
||||
* instance of the driver.
|
||||
*/
|
||||
static driver_t tdfx_driver = {
|
||||
"tdfx",
|
||||
tdfx_methods,
|
||||
sizeof(struct tdfx_softc),
|
||||
};
|
||||
|
||||
/* Tell Mr. Kernel about us! */
|
||||
DRIVER_MODULE(tdfx, pci, tdfx_driver, tdfx_devclass, 0, 0);
|
||||
|
||||
|
||||
#endif /* NPCI */
|
29
sys/dev/tdfx/tdfx_pci.h
Normal file
29
sys/dev/tdfx/tdfx_pci.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* tdfx_pci.h -- Prototypes for tdfx device methods */
|
||||
/* Copyright (C) 2000 by Coleman Kane <cokane@pohl.ececs.uc.edu>*/
|
||||
#include <sys/proc.h>
|
||||
#include <sys/conf.h>
|
||||
|
||||
/* Driver functions */
|
||||
static int tdfx_probe(device_t dev);
|
||||
static int tdfx_attach(device_t dev);
|
||||
static int tdfx_setmtrr(device_t dev);
|
||||
static int tdfx_clrmtrr(device_t dev);
|
||||
static int tdfx_detach(device_t dev);
|
||||
static int tdfx_shutdown(device_t dev);
|
||||
|
||||
/* CDEV file ops */
|
||||
static d_open_t tdfx_open;
|
||||
static d_close_t tdfx_close;
|
||||
static d_mmap_t tdfx_mmap;
|
||||
static d_ioctl_t tdfx_ioctl;
|
||||
|
||||
/* Card Queries */
|
||||
static int tdfx_do_query(u_int cmd, struct tdfx_pio_data *piod);
|
||||
static int tdfx_query_boards(void);
|
||||
static int tdfx_query_fetch(u_int cmd, struct tdfx_pio_data *piod);
|
||||
static int tdfx_query_update(u_int cmd, struct tdfx_pio_data *piod);
|
||||
|
||||
/* Card PIO funcs */
|
||||
static int tdfx_do_pio(u_int cmd, struct tdfx_pio_data *piod);
|
||||
static int tdfx_do_pio_wt(struct tdfx_pio_data *piod);
|
||||
static int tdfx_do_pio_rd(struct tdfx_pio_data *piod);
|
2
sys/dev/tdfx/tdfx_static.sh
Normal file
2
sys/dev/tdfx/tdfx_static.sh
Normal file
@ -0,0 +1,2 @@
|
||||
echo "dev/tdfx/tdfx_pci.c optional tdfx pci" >> /usr/src/sys/conf/files.i386
|
||||
echo "TDFX_VERBOSE opt_tdfx.h" >> /usr/src/sys/conf/options.i386
|
70
sys/dev/tdfx/tdfx_vars.h
Normal file
70
sys/dev/tdfx/tdfx_vars.h
Normal file
@ -0,0 +1,70 @@
|
||||
/* tdfx_vars.h -- constants and structs used in the tdfx driver
|
||||
Copyright (C) 2000 by Coleman Kane <cokane@pohl.ececs.uc.edu>
|
||||
*/
|
||||
#ifndef TDFX_VARS_H
|
||||
#define TDFX_VARS_H
|
||||
|
||||
#include <sys/memrange.h>
|
||||
|
||||
#define CDEV_MAJOR 107
|
||||
#define PCI_DEVICE_ALLIANCE_AT3D 0x643d1142
|
||||
#define PCI_DEVICE_3DFX_VOODOO1 0x0000121a
|
||||
#define PCI_DEVICE_3DFX_VOODOO2 0x0002121a
|
||||
#define PCI_DEVICE_3DFX_BANSHEE 0x0003121a
|
||||
#define PCI_DEVICE_3DFX_VOODOO3 0x0005121a
|
||||
|
||||
#define PCI_VENDOR_ID_FREEBSD 0x0
|
||||
#define PCI_DEVICE_ID_FREEBSD 0x2
|
||||
#define PCI_COMMAND_FREEBSD 0x4
|
||||
#define PCI_REVISION_ID_FREEBSD 0x8
|
||||
#define PCI_BASE_ADDRESS_0_FREEBSD 0x10
|
||||
#define SST1_PCI_SPECIAL1_FREEBSD 0x40
|
||||
#define SST1_PCI_SPECIAL2_FREEBSD 0x44
|
||||
#define SST1_PCI_SPECIAL3_FREEBSD 0x48
|
||||
#define SST1_PCI_SPECIAL4_FREEBSD 0x54
|
||||
|
||||
#define VGA_INPUT_STATUS_1C 0x3DA
|
||||
#define VGA_MISC_OUTPUT_READ 0x3cc
|
||||
#define VGA_MISC_OUTPUT_WRITE 0x3c2
|
||||
#define SC_INDEX 0x3c4
|
||||
#define SC_DATA 0x3c5
|
||||
|
||||
#define PCI_MAP_REG_START 0x10
|
||||
#define UNIT(m) (m & 0xf)
|
||||
|
||||
/* IOCTL Calls */
|
||||
#define TDFX_IOC_TYPE_PIO 0
|
||||
#define TDFX_IOC_TYPE_QUERY '3'
|
||||
#define TDFX_IOC_QRY_BOARDS 2
|
||||
#define TDFX_IOC_QRY_FETCH 3
|
||||
#define TDFX_IOC_QRY_UPDATE 4
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus_private.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
struct tdfx_softc {
|
||||
int cardno;
|
||||
vm_offset_t addr;
|
||||
struct resource *memrange, *piorange;
|
||||
int memrid, piorid;
|
||||
long range;
|
||||
int vendor;
|
||||
int type;
|
||||
int addr0;
|
||||
unsigned char bus;
|
||||
unsigned char dv;
|
||||
struct file *curFile;
|
||||
device_t dev;
|
||||
struct mem_range_desc mrdesc;
|
||||
int busy;
|
||||
};
|
||||
|
||||
struct tdfx_pio_data {
|
||||
short port;
|
||||
short size;
|
||||
int device;
|
||||
void *value;
|
||||
};
|
||||
|
||||
#endif /* TDFX_VARS_H */
|
Loading…
Reference in New Issue
Block a user