176195Sbrian/*-
276195Sbrian * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
376358Sbrian *   based on work by Slawa Olhovchenkov
476358Sbrian *                    John Prince <johnp@knight-trosoft.com>
576358Sbrian *                    Eric Hernes
676195Sbrian * All rights reserved.
776195Sbrian *
876195Sbrian * Redistribution and use in source and binary forms, with or without
976195Sbrian * modification, are permitted provided that the following conditions
1076195Sbrian * are met:
1176195Sbrian * 1. Redistributions of source code must retain the above copyright
1276195Sbrian *    notice, this list of conditions and the following disclaimer.
1376195Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1476195Sbrian *    notice, this list of conditions and the following disclaimer in the
1576195Sbrian *    documentation and/or other materials provided with the distribution.
1676195Sbrian *
1776195Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1876195Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1976195Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2076195Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2176195Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2276195Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2376195Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2476195Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2576195Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2676195Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2776195Sbrian * SUCH DAMAGE.
2876195Sbrian */
2976195Sbrian
30119418Sobrien#include <sys/cdefs.h>
31119418Sobrien__FBSDID("$FreeBSD$");
32119418Sobrien
3376195Sbrian#include <sys/param.h>
3476195Sbrian
3576195Sbrian#include <sys/systm.h>
3676195Sbrian#include <sys/kernel.h>
37129879Sphk#include <sys/module.h>
3876195Sbrian#include <sys/tty.h>
3976195Sbrian#include <sys/bus.h>
4076195Sbrian#include <machine/bus.h>
4176195Sbrian#include <sys/rman.h>
4276195Sbrian#include <machine/resource.h>
4376195Sbrian#include <vm/vm.h>
4476195Sbrian#include <vm/pmap.h>
45119277Simp#include <dev/pci/pcivar.h>
4676195Sbrian
4776848Sbrian#include <sys/digiio.h>
4876853Sbrian#include <dev/digi/digireg.h>
4976853Sbrian#include <dev/digi/digi.h>
5076853Sbrian#include <dev/digi/digi_pci.h>
5176195Sbrian
5276195Sbrianstatic u_char *
5376195Sbriandigi_pci_setwin(struct digi_softc *sc, unsigned int addr)
5476195Sbrian{
5576195Sbrian	return (sc->vmem + addr);
5676195Sbrian}
5776195Sbrian
5876195Sbrianstatic void
5976195Sbriandigi_pci_hidewin(struct digi_softc *sc)
6076195Sbrian{
6176195Sbrian	return;
6276195Sbrian}
6376195Sbrian
6476195Sbrianstatic void
6576195Sbriandigi_pci_towin(struct digi_softc *sc, int win)
6676195Sbrian{
6776195Sbrian	return;
6876195Sbrian}
6976195Sbrian
7076195Sbrianstatic int
7176195Sbriandigi_pci_probe(device_t dev)
7276195Sbrian{
7376195Sbrian	unsigned int device_id = pci_get_devid(dev);
7476195Sbrian
7576195Sbrian	if (device_get_unit(dev) >= 16) {
7676195Sbrian		/* Don't overflow our control mask */
7776195Sbrian		device_printf(dev, "At most 16 digiboards may be used\n");
7876195Sbrian		return (ENXIO);
7976195Sbrian	}
8076195Sbrian
8176195Sbrian	if ((device_id & 0xffff) != PCI_VENDOR_DIGI)
8276195Sbrian		return (ENXIO);
8376195Sbrian
8476195Sbrian	switch (device_id >> 16) {
8576195Sbrian	case PCI_DEVICE_EPC:
8676195Sbrian	case PCI_DEVICE_XEM:
8776195Sbrian	case PCI_DEVICE_XR:
8876195Sbrian	case PCI_DEVICE_CX:
8976195Sbrian	case PCI_DEVICE_XRJ:
9076195Sbrian	case PCI_DEVICE_EPCJ:
9176195Sbrian	case PCI_DEVICE_920_4:
9276195Sbrian	case PCI_DEVICE_920_8:
9376195Sbrian	case PCI_DEVICE_920_2:
94143161Simp		return (BUS_PROBE_DEFAULT);
9576195Sbrian	}
9676195Sbrian
9776358Sbrian	return (ENXIO);
9876195Sbrian}
9976195Sbrian
10076195Sbrianstatic int
10176195Sbriandigi_pci_attach(device_t dev)
10276195Sbrian{
10376195Sbrian	struct digi_softc *sc;
10476195Sbrian	u_int32_t device_id;
10576195Sbrian#ifdef DIGI_INTERRUPT
10676195Sbrian	int retVal = 0;
10776195Sbrian#endif
10876195Sbrian
10976195Sbrian	sc = device_get_softc(dev);
11076195Sbrian	KASSERT(sc, ("digi%d: softc not allocated in digi_pci_attach\n",
11176195Sbrian	    device_get_unit(dev)));
11276195Sbrian
11376195Sbrian	bzero(sc, sizeof(*sc));
11476195Sbrian	sc->dev = dev;
11576195Sbrian	sc->res.unit = device_get_unit(dev);
11676195Sbrian
11776195Sbrian	device_id = pci_get_devid(dev);
11876195Sbrian	switch (device_id >> 16) {
11976195Sbrian	case PCI_DEVICE_EPC:
12076195Sbrian		sc->name = "Digiboard PCI EPC/X ASIC";
12176195Sbrian		sc->res.mrid = 0x10;
12276195Sbrian		sc->model = PCIEPCX;
12376195Sbrian		sc->module = "EPCX_PCI";
12476195Sbrian		break;
12576195Sbrian	case PCI_DEVICE_XEM:
12676195Sbrian		sc->name = "Digiboard PCI PC/Xem ASIC";
12776195Sbrian		sc->res.mrid = 0x10;
12876195Sbrian		sc->model = PCXEM;
12976195Sbrian		sc->module = "Xem";
13076195Sbrian		break;
13176195Sbrian	case PCI_DEVICE_XR:
13276195Sbrian		sc->name = "Digiboard PCI PC/Xr ASIC";
13376195Sbrian		sc->res.mrid = 0x10;
13476195Sbrian		sc->model = PCIXR;
13576195Sbrian		sc->module = "Xr";
13676195Sbrian		break;
13776195Sbrian	case PCI_DEVICE_CX:
13876195Sbrian		sc->name = "Digiboard PCI C/X ASIC";
13976195Sbrian		sc->res.mrid = 0x10;
14076195Sbrian		sc->model = PCCX;
14176195Sbrian		sc->module = "CX_PCI";
14276195Sbrian		break;
14376195Sbrian	case PCI_DEVICE_XRJ:
14476195Sbrian		sc->name = "Digiboard PCI PC/Xr PLX";
14576195Sbrian		sc->res.mrid = 0x18;
14676195Sbrian		sc->model = PCIXR;
14776195Sbrian		sc->module = "Xr";
14876195Sbrian		break;
14976195Sbrian	case PCI_DEVICE_EPCJ:
15076195Sbrian		sc->name = "Digiboard PCI EPC/X PLX";
15176195Sbrian		sc->res.mrid = 0x18;
15276195Sbrian		sc->model = PCIEPCX;
15376195Sbrian		sc->module = "EPCX_PCI";
15476195Sbrian		break;
15576195Sbrian	case PCI_DEVICE_920_4:			/* Digi PCI4r 920 */
15676195Sbrian		sc->name = "Digiboard PCI4r 920";
15776195Sbrian		sc->res.mrid = 0x10;
15876195Sbrian		sc->model = PCIXR;
15976195Sbrian		sc->module = "Xr";
16076195Sbrian		break;
16176195Sbrian	case PCI_DEVICE_920_8:			/* Digi PCI8r 920 */
16276195Sbrian		sc->name = "Digiboard PCI8r 920";
16376195Sbrian		sc->res.mrid = 0x10;
16476195Sbrian		sc->model = PCIXR;
16576195Sbrian		sc->module = "Xr";
16676195Sbrian		break;
16776195Sbrian	case PCI_DEVICE_920_2:			/* Digi PCI2r 920 */
16876195Sbrian		sc->name = "Digiboard PCI2r 920";
16976195Sbrian		sc->res.mrid = 0x10;
17076195Sbrian		sc->model = PCIXR;
17176195Sbrian		sc->module = "Xr";
17276195Sbrian		break;
17376195Sbrian	default:
17476195Sbrian		device_printf(dev, "Unknown device id = %08x\n", device_id);
17576195Sbrian		return (ENXIO);
17676195Sbrian	}
17776195Sbrian
17876195Sbrian	pci_write_config(dev, 0x40, 0, 4);
17976195Sbrian	pci_write_config(dev, 0x46, 0, 4);
18076195Sbrian
181127135Snjl	sc->res.mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->res.mrid,
182127135Snjl	    RF_ACTIVE);
18376195Sbrian
18476195Sbrian#ifdef DIGI_INTERRUPT
18576195Sbrian	sc->res.irqrid = 0;
186127135Snjl	sc->res.irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->res.irqrid,
187127135Snjl	    RF_SHAREABLE | RF_ACTIVE);
18876195Sbrian	if (sc->res.irq == NULL) {
18976195Sbrian		device_printf(dev, "couldn't map interrupt\n");
19076358Sbrian		return (ENXIO);
19176195Sbrian	}
19276195Sbrian	retVal = bus_setup_intr(dev, sc->res.irq, INTR_TYPE_TTY,
19376195Sbrian	    digiintr, sc, &sc->res.irqHandler);
19476195Sbrian#else
19576195Sbrian	DLOG(DIGIDB_IRQ, (sc->dev, "Interrupt support compiled out\n"));
19676195Sbrian#endif
19776195Sbrian
19876195Sbrian	sc->vmem = rman_get_virtual(sc->res.mem);
19976195Sbrian	sc->pmem = vtophys(sc->vmem);
20076195Sbrian	sc->pcibus = 1;
20176195Sbrian	sc->win_size = 0x200000;
20276195Sbrian	sc->win_bits = 21;
20376195Sbrian	sc->csigs = &digi_normal_signals;
20476195Sbrian	sc->status = DIGI_STATUS_NOTINIT;
20576195Sbrian	callout_handle_init(&sc->callout);
20676195Sbrian	callout_handle_init(&sc->inttest);
20776195Sbrian	sc->setwin = digi_pci_setwin;
20876195Sbrian	sc->hidewin = digi_pci_hidewin;
20976195Sbrian	sc->towin = digi_pci_towin;
21076195Sbrian
21176195Sbrian	PCIPORT = FEPRST;
21276195Sbrian
21376195Sbrian	return (digi_attach(sc));
21476195Sbrian}
21576195Sbrian
21676195Sbrianstatic device_method_t digi_pci_methods[] = {
21776195Sbrian	/* Device interface */
21876195Sbrian	DEVMETHOD(device_probe, digi_pci_probe),
21976195Sbrian	DEVMETHOD(device_attach, digi_pci_attach),
22076195Sbrian	DEVMETHOD(device_detach, digi_detach),
22176195Sbrian	DEVMETHOD(device_shutdown, digi_shutdown),
222246128Ssbz
223246128Ssbz	DEVMETHOD_END
22476195Sbrian};
22576195Sbrian
22676195Sbrianstatic driver_t digi_pci_drv = {
22776195Sbrian	"digi",
22876195Sbrian	digi_pci_methods,
22976195Sbrian	sizeof(struct digi_softc),
23076195Sbrian};
23191445SpeterDRIVER_MODULE(digi, pci, digi_pci_drv, digi_devclass, 0, 0);
232