pcii.c revision 141398
119370Spst/*-
298944Sobrien * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
3130803Smarcel * All rights reserved.
446283Sdfr *
519370Spst * Redistribution and use in source and binary forms, with or without
698944Sobrien * modification, are permitted provided that the following conditions
719370Spst * are met:
898944Sobrien * 1. Redistributions of source code must retain the above copyright
998944Sobrien *    notice, this list of conditions and the following disclaimer.
1098944Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1198944Sobrien *    notice, this list of conditions and the following disclaimer in the
1219370Spst *    documentation and/or other materials provided with the distribution.
1398944Sobrien *
1498944Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1598944Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1698944Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1719370Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1898944Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1998944Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2098944Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2198944Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2219370Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2319370Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2419370Spst * SUCH DAMAGE.
2519370Spst *
2619370Spst * Driver for GPIB cards based on NEC �PD7210 and compatibles.
2719370Spst *
2819370Spst * This driver just hooks up to the hardware and leaves all the interesting
2919370Spst * stuff to upd7210.c.
3019370Spst *
3119370Spst * Supported hardware:
3219370Spst *    PCIIA compatible cards.
3398944Sobrien *
3419370Spst *    Tested and known working:
3519370Spst *	"B&C Microsystems PC488A-0"
3619370Spst *
3746283Sdfr */
3846283Sdfr
3998944Sobrien#include <sys/cdefs.h>
4098944Sobrien__FBSDID("$FreeBSD: head/sys/dev/ieee488/pcii.c 141398 2005-02-06 15:22:23Z phk $");
4198944Sobrien
4298944Sobrien#include <sys/param.h>
43130803Smarcel#include <sys/systm.h>
44130803Smarcel#include <sys/lock.h>
45130803Smarcel#include <sys/mutex.h>
46130803Smarcel#include <sys/kernel.h>
47130803Smarcel#include <sys/module.h>
4819370Spst#include <sys/bus.h>
49130803Smarcel#include <machine/bus.h>
5019370Spst#include <machine/resource.h>
5198944Sobrien#include <sys/rman.h>
5246283Sdfr#include <isa/isavar.h>
5398944Sobrien
5446283Sdfr#include <dev/ieee488/upd7210.h>
55130803Smarcel
5646283Sdfrstruct pcii_softc {
57130803Smarcel	int foo;
58130803Smarcel	struct resource	*port[8];
5998944Sobrien	struct resource	*irq;
6046283Sdfr	struct resource	*dma;
61130803Smarcel	void *intr_handler;
62130803Smarcel	struct upd7210	upd7210;
63130803Smarcel};
64130803Smarcel
65130803Smarcelstatic devclass_t pcii_devclass;
66130803Smarcel
6798944Sobrienstatic int	pcii_probe(device_t dev);
6819370Spststatic int	pcii_attach(device_t dev);
6998944Sobrien
7019370Spststatic device_method_t pcii_methods[] = {
7198944Sobrien	DEVMETHOD(device_probe,		pcii_probe),
7219370Spst	DEVMETHOD(device_attach,	pcii_attach),
7398944Sobrien	DEVMETHOD(device_suspend,	bus_generic_suspend),
7419370Spst	DEVMETHOD(device_resume,	bus_generic_resume),
7598944Sobrien
7619370Spst	{ 0, 0 }
7798944Sobrien};
7819370Spst
7998944Sobrienstatic driver_t pcii_driver = {
8019370Spst	"pcii",
8198944Sobrien	pcii_methods,
8219370Spst	sizeof(struct pcii_softc *),
8398944Sobrien};
8419370Spst
85130803Smarcelstatic int
8619370Spstpcii_probe(device_t dev)
8798944Sobrien{
8819370Spst	struct resource	*port;
8998944Sobrien	int rid;
9019370Spst	u_long start, count;
9198944Sobrien	int i, j, error = 0;
9219370Spst
9398944Sobrien	device_set_desc(dev, "PCII IEEE-4888 controller");
9419370Spst
9598944Sobrien	rid = 0;
9619370Spst	if (bus_get_resource(dev, SYS_RES_IOPORT, rid, &start, &count) != 0)
9798944Sobrien		return ENXIO;
9819370Spst	if ((start & 0x3ff) != 0x2e1)
9998944Sobrien		return (ENXIO);
10019370Spst	count = 1;
10198944Sobrien	if (bus_set_resource(dev, SYS_RES_IOPORT, rid, start, count) != 0)
10298944Sobrien		return ENXIO;
10398944Sobrien	for (i = 0; i < 8; i++) {
10419370Spst		j = bus_set_resource(dev, SYS_RES_IOPORT, i,
10598944Sobrien		    start + 0x400 * i, 1);
10619370Spst		if (j) {
10798944Sobrien			error = ENXIO;
10846283Sdfr			break;
10998944Sobrien		}
11098944Sobrien		rid = i;
11198944Sobrien		port = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
11298944Sobrien		    &rid, RF_ACTIVE);
11398944Sobrien		if (port == NULL)
11498944Sobrien			return (ENXIO);
11598944Sobrien		else
11698944Sobrien			bus_release_resource(dev, SYS_RES_IOPORT, i, port);
11798944Sobrien	}
11898944Sobrien
11946283Sdfr	rid = 0;
12046283Sdfr	port = bus_alloc_resource_any(dev,
12119370Spst	    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
12219370Spst	if (port == NULL)
12319370Spst		return (ENXIO);
12419370Spst	bus_release_resource(dev, SYS_RES_IRQ, rid, port);
12519370Spst
12619370Spst	return (error);
12719370Spst}
12819370Spst
12998944Sobrienstatic int
13098944Sobrienpcii_attach(device_t dev)
13198944Sobrien{
13298944Sobrien	struct pcii_softc *sc;
13398944Sobrien	int		unit;
13498944Sobrien	int		rid;
13519370Spst	int i, error = 0;
13619370Spst
13719370Spst	unit = device_get_unit(dev);
13819370Spst	sc = device_get_softc(dev);
13919370Spst	memset(sc, 0, sizeof *sc);
14019370Spst
14119370Spst	device_set_desc(dev, "PCII IEEE-4888 controller");
14219370Spst
14319370Spst	for (rid = 0; rid < 8; rid++) {
14498944Sobrien		sc->port[rid] = bus_alloc_resource_any(dev,
14519370Spst		    SYS_RES_IOPORT, &rid, RF_ACTIVE);
14619370Spst		if (sc->port[rid] == NULL) {
14719370Spst			error = ENXIO;
14819370Spst			break;
14919370Spst		}
15019370Spst		sc->upd7210.reg_tag[rid] = rman_get_bustag(sc->port[rid]);
15119370Spst		sc->upd7210.reg_handle[rid] = rman_get_bushandle(sc->port[rid]);
15219370Spst	}
15319370Spst	if (!error) {
15419370Spst		rid = 0;
15519370Spst		sc->irq = bus_alloc_resource_any(dev,
15619370Spst		    SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE);
15719370Spst		if (sc->irq == NULL) {
15819370Spst			error = ENXIO;
15919370Spst		} else {
16019370Spst			error = bus_setup_intr(dev, sc->irq,
16119370Spst			    INTR_TYPE_MISC | INTR_MPSAFE,
16219370Spst			    upd7210intr, &sc->upd7210, &sc->intr_handler);
16319370Spst		}
16419370Spst	}
16519370Spst	if (!error) {
16619370Spst		rid = 0;
16719370Spst		sc->dma = bus_alloc_resource_any(dev,
16819370Spst		    SYS_RES_DRQ, &rid, RF_ACTIVE | RF_SHAREABLE);
16919370Spst		if (sc->dma == NULL)
17019370Spst			sc->upd7210.dmachan = -1;
17119370Spst		else
17219370Spst			sc->upd7210.dmachan = rman_get_start(sc->dma);
17319370Spst	}
17419370Spst	if (error) {
17519370Spst		for (i = 0; i < 8; i++) {
17619370Spst			if (sc->port[i] == NULL)
17719370Spst				break;
17819370Spst			bus_release_resource(dev, SYS_RES_IOPORT,
17919370Spst			    0, sc->port[i]);
18098944Sobrien		}
18198944Sobrien		if (sc->intr_handler != NULL)
18219370Spst			bus_teardown_intr(dev, sc->irq, sc->intr_handler);
18319370Spst		if (sc->irq != NULL)
18419370Spst			bus_release_resource(dev, SYS_RES_IRQ, i, sc->irq);
18519370Spst	}
18619370Spst	upd7210attach(&sc->upd7210);
187130803Smarcel	return (error);
18819370Spst}
18919370Spst
19019370SpstDRIVER_MODULE(pcii, isa, pcii_driver, pcii_devclass, 0, 0);
19119370SpstDRIVER_MODULE(pcii, acpi, pcii_driver, pcii_devclass, 0, 0);
19219370Spst