File:  [DragonFly] / src / sys / dev / video / tga / Attic / tga_pci.c
Revision 1.6: download - view: text, annotated - select for diffs
Thu May 13 23:49:23 2004 UTC (10 years, 6 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
device switch 1/many: Remove d_autoq, add d_clone (where d_autoq was).

d_autoq was used to allow the device port dispatch to mix old-style synchronous
calls with new style messaging calls within a particular device.  It was never
used for that purpose.

d_clone will be more fully implemented as work continues.  We are going to
install d_port in the dev_t (struct specinfo) structure itself and d_clone
will be needed to allow devices to 'revector' the port on a minor-number
by minor-number basis, in particular allowing minor numbers to be directly
dispatched to distinct threads.  This is something we will be needing later
on.

/*
 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 * 
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 *
 * Copyright (c) 2000 Andrew Miklic, Andrew Gallatin, and Thomas V. Crimi
 *
 * $FreeBSD: src/sys/dev/tga/tga_pci.c,v 1.1.2.1 2001/11/01 08:33:15 obrien Exp $
 * $DragonFly: src/sys/dev/video/tga/tga_pci.c,v 1.6 2004/05/13 23:49:23 dillon Exp $
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/proc.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/fbio.h>

#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>

#include <machine/md_var.h>
#include <machine/pc/bios.h>
#include <machine/clock.h>
#include <machine/bus_memio.h>
#include <machine/bus.h>
#include <machine/pc/vesa.h>
#include <machine/resource.h>

#include <sys/bus.h>
#include <sys/rman.h>

#include <bus/pci/pcireg.h>
#include <bus/pci/pcivar.h>

#include <dev/fb/fbreg.h>
#include <dev/fb/tga.h>
#include "tga_pci.h"
#include <dev/fb/gfb.h>
#include <dev/gfb/gfb_pci.h>

#include "opt_fb.h"

static int tga_probe(device_t);
static int tga_attach(device_t);
static void tga_intr(void *);

static device_method_t tga_methods[] = {
	DEVMETHOD(device_probe, tga_probe),
	DEVMETHOD(device_attach, tga_attach),
	DEVMETHOD(device_detach, pcigfb_detach),
	{ 0, 0 }
};

static driver_t tga_driver = {
	"tga",
	tga_methods,
	sizeof(struct gfb_softc)
};

static devclass_t tga_devclass;

DRIVER_MODULE(tga, pci, tga_driver, tga_devclass, 0, 0);

static struct gfb_type tga_devs[] = {
	{ DEC_VENDORID, DEC_DEVICEID_TGA,
	"DEC TGA (21030) 2D Graphics Accelerator" },
	{ DEC_VENDORID, DEC_DEVICEID_TGA2,
	"DEC TGA2 (21130) 3D Graphics Accelerator" },
	{ 0, 0, NULL }
};

#ifdef FB_INSTALL_CDEV

static struct cdevsw tga_cdevsw = {
	/* name */	"tga",
	/* maj */	-1,
	/* flags */	0,
	/* port */	NULL,
	/* clone */	NULL,

	/* open */	pcigfb_open,
	/* close */	pcigfb_close,
	/* read */	pcigfb_read,
	/* write */	pcigfb_write,
	/* ioctl */	pcigfb_ioctl,
	/* poll */	nopoll,
	/* mmap */	pcigfb_mmap,
	/* strategy */	nostrategy,
	/* dump */	nodump,
	/* psize */	nopsize
};

#endif /*FB_INSTALL_CDEV*/

static int
tga_probe(device_t dev)
{
	int error;
	gfb_type_t t;

	t = tga_devs;
	error = ENXIO;
	while(t->name != NULL) {
		if((pci_get_vendor(dev) == t->vendor_id) &&
		   (pci_get_device(dev) == t->device_id)) {
			device_set_desc(dev, t->name);
			error = 0;
			break;
		}
		t++;
	}
	return(error);
}

static int
tga_attach(device_t dev)
{
	gfb_softc_t sc;
	int unit, error, rid;

	error = 0;
	unit = device_get_unit(dev);
	sc = device_get_softc(dev);
	bzero(sc, sizeof(struct gfb_softc));
	sc->driver_name = TGA_DRIVER_NAME;
	switch(pci_get_device(dev)) {
	case DEC_DEVICEID_TGA2:
		sc->model = 1;
		sc->type = KD_TGA2;
		break;
	case DEC_DEVICEID_TGA:
		sc->model = 0;
		sc->type = KD_TGA;
		break;
	default:
		device_printf(dev, "Unrecognized TGA type\n");
		goto fail;
	}
	if((error = pcigfb_attach(dev))) {
		goto fail;
	}
	sc->regs = sc->bhandle + TGA_MEM_CREGS;
	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_TTY, tga_intr, sc,
		    &sc->intrhand);
	if(error) {
		device_printf(dev, "couldn't set up irq\n");
		goto fail;
	}
	switch(sc->rev) {
	case 0x1:
	case 0x2:
	case 0x3:
		device_printf(dev, "TGA (21030) step %c\n", 'A' + sc->rev - 1);
		break;

	case 0x20:
		device_printf(dev, "TGA2 (21130) abstract software model\n");
		break;

	case 0x21:
	case 0x22:
		device_printf(dev, "TGA2 (21130) pass %d\n", sc->rev - 0x20);
		break;

	default:
		device_printf(dev, "Unknown stepping (0x%x)\n", sc->rev);
		break;
	}
#ifdef FB_INSTALL_CDEV
	sc->devt = make_dev(&tga_cdevsw, unit, 0, 0, 02660, "tga%x", unit);
	/* XXX fb_attach done too early in pcigfb_attach? */
#endif /*FB_INSTALL_CDEV*/
	goto done;
fail:
	if(sc->intrhand != NULL) {
		bus_teardown_intr(dev, sc->irq, sc->intrhand);
		sc->intrhand = NULL;
	}
	if(sc->irq != NULL) {
		rid = 0x0;
		bus_release_resource(dev, SYS_RES_IRQ, rid, sc->irq);
		sc->irq = NULL;
	}
	if(sc->res != NULL) {
		rid = GFB_MEM_BASE_RID;
		bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->res);
		sc->res = NULL;
	}
	error = ENXIO;
done:
	return(error);
}

static void 
tga_intr(void *v)
{
	struct gfb_softc *sc = (struct gfb_softc *)v;
	u_int32_t reg;

	reg = READ_GFB_REGISTER(sc->adp, TGA_REG_SISR);
	if((reg & 0x00010001) != 0x00010001) {

		/* Odd. We never set any of the other interrupt enables. */
		if((reg & 0x1f) != 0) {

			/* Clear the mysterious pending interrupts. */
			WRITE_GFB_REGISTER(sc->adp, TGA_REG_SISR, (reg & 0x1f));
			GFB_REGISTER_WRITE_BARRIER(sc, TGA_REG_SISR, 1);

			/* This was our interrupt, even if we're puzzled as to
			 * why we got it.  Don't make the interrupt handler
			 * think it was a stray.
			 */
		}
	}

	/* Call the scheduled handler... */
	sc->gfbc->ramdac_intr(sc);

	/*
	   Clear interrupt field (this way, we will force a
	   memory error if we get an unexpected interrupt)...
	*/
	sc->gfbc->ramdac_intr = NULL;

	/* Disable the interrupt... */
	WRITE_GFB_REGISTER(sc->adp, TGA_REG_SISR, 0x00000001);
	GFB_REGISTER_WRITE_BARRIER(sc, TGA_REG_SISR, 1);
}