aic_isa.c revision 69960
152417Sluoqi/*-
252417Sluoqi * Copyright (c) 1999 Luoqi Chen.
352417Sluoqi * All rights reserved.
452417Sluoqi *
552417Sluoqi * Redistribution and use in source and binary forms, with or without
652417Sluoqi * modification, are permitted provided that the following conditions
752417Sluoqi * are met:
852417Sluoqi * 1. Redistributions of source code must retain the above copyright
952417Sluoqi *    notice, this list of conditions and the following disclaimer.
1052417Sluoqi * 2. Redistributions in binary form must reproduce the above copyright
1152417Sluoqi *    notice, this list of conditions and the following disclaimer in the
1252417Sluoqi *    documentation and/or other materials provided with the distribution.
1352417Sluoqi *
1452417Sluoqi * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1552417Sluoqi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1652417Sluoqi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1752417Sluoqi * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1852417Sluoqi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1952417Sluoqi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2052417Sluoqi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2152417Sluoqi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2252417Sluoqi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2352417Sluoqi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2452417Sluoqi * SUCH DAMAGE.
2552417Sluoqi *
2652417Sluoqi * $FreeBSD: head/sys/dev/aic/aic_isa.c 69960 2000-12-13 05:46:23Z imp $
2752417Sluoqi */
2852417Sluoqi
2952417Sluoqi#include <sys/param.h>
3052417Sluoqi#include <sys/kernel.h>
3152417Sluoqi#include <sys/module.h>
3252417Sluoqi#include <sys/bus.h>
3352417Sluoqi
3452417Sluoqi#include <machine/bus_pio.h>
3552417Sluoqi#include <machine/bus.h>
3652417Sluoqi#include <machine/resource.h>
3752417Sluoqi#include <sys/rman.h>
3852417Sluoqi
3952417Sluoqi#include <isa/isavar.h>
4052417Sluoqi#include <dev/aic/aic6360reg.h>
4152417Sluoqi#include <dev/aic/aicvar.h>
4252417Sluoqi
4352417Sluoqistruct aic_isa_softc {
4452417Sluoqi	struct	aic_softc sc_aic;
4552417Sluoqi	struct	resource *sc_port;
4652417Sluoqi	struct	resource *sc_irq;
4752417Sluoqi	struct	resource *sc_drq;
4852417Sluoqi	void	*sc_ih;
4952417Sluoqi};
5052417Sluoqi
5152417Sluoqistatic int aic_isa_alloc_resources __P((device_t));
5252417Sluoqistatic void aic_isa_release_resources __P((device_t));
5354136Sluoqistatic int aic_isa_probe __P((device_t));
5454136Sluoqistatic int aic_isa_attach __P((device_t));
5552417Sluoqi
5652417Sluoqistatic u_int aic_isa_ports[] = { 0x340, 0x140 };
5752417Sluoqi#define	AIC_ISA_NUMPORTS (sizeof(aic_isa_ports) / sizeof(aic_isa_ports[0]))
5852417Sluoqi#define	AIC_ISA_PORTSIZE 0x20
5952417Sluoqi
6052417Sluoqistatic int
6152417Sluoqiaic_isa_alloc_resources(device_t dev)
6252417Sluoqi{
6352417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
6452417Sluoqi	int rid;
6552417Sluoqi
6652417Sluoqi	sc->sc_port = sc->sc_irq = sc->sc_drq = 0;
6752417Sluoqi
6852417Sluoqi	rid = 0;
6952417Sluoqi	sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
7052417Sluoqi					0ul, ~0ul, AIC_ISA_PORTSIZE, RF_ACTIVE);
7152417Sluoqi	if (!sc->sc_port)
7252417Sluoqi		return (ENOMEM);
7352417Sluoqi
7452417Sluoqi	if (isa_get_irq(dev) != -1) {
7552417Sluoqi		rid = 0;
7652417Sluoqi		sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
7752417Sluoqi						0ul, ~0ul, 1, RF_ACTIVE);
7852417Sluoqi		if (!sc->sc_irq) {
7952417Sluoqi			aic_isa_release_resources(dev);
8052417Sluoqi			return (ENOMEM);
8152417Sluoqi		}
8252417Sluoqi	}
8352417Sluoqi
8452417Sluoqi	if (isa_get_drq(dev) != -1) {
8552417Sluoqi		rid = 0;
8652417Sluoqi		sc->sc_drq = bus_alloc_resource(dev, SYS_RES_DRQ, &rid,
8752417Sluoqi						0ul, ~0ul, 1, RF_ACTIVE);
8852417Sluoqi		if (!sc->sc_drq) {
8952417Sluoqi			aic_isa_release_resources(dev);
9052417Sluoqi			return (ENOMEM);
9152417Sluoqi		}
9252417Sluoqi	}
9352417Sluoqi
9452417Sluoqi	sc->sc_aic.unit = device_get_unit(dev);
9552417Sluoqi	sc->sc_aic.tag = rman_get_bustag(sc->sc_port);
9652417Sluoqi	sc->sc_aic.bsh = rman_get_bushandle(sc->sc_port);
9752417Sluoqi	return (0);
9852417Sluoqi}
9952417Sluoqi
10052417Sluoqistatic void
10152417Sluoqiaic_isa_release_resources(device_t dev)
10252417Sluoqi{
10352417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
10452417Sluoqi
10552417Sluoqi	if (sc->sc_port)
10652417Sluoqi		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port);
10752417Sluoqi	if (sc->sc_irq)
10852417Sluoqi		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
10952417Sluoqi	if (sc->sc_drq)
11052417Sluoqi		bus_release_resource(dev, SYS_RES_DRQ, 0, sc->sc_drq);
11152417Sluoqi	sc->sc_port = sc->sc_irq = sc->sc_drq = 0;
11252417Sluoqi}
11352417Sluoqi
11452417Sluoqistatic int
11552417Sluoqiaic_isa_probe(device_t dev)
11652417Sluoqi{
11752417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
11852417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
11952417Sluoqi	int numports, i;
12052417Sluoqi	u_int port, *ports;
12152417Sluoqi	u_int8_t porta;
12252417Sluoqi
12352417Sluoqi	if (isa_get_vendorid(dev))
12452417Sluoqi		return (ENXIO);
12552417Sluoqi
12652417Sluoqi	port = isa_get_port(dev);
12752417Sluoqi	if (port != -1) {
12852417Sluoqi		ports = &port;
12952417Sluoqi		numports = 1;
13052417Sluoqi	} else {
13152417Sluoqi		ports = aic_isa_ports;
13252417Sluoqi		numports = AIC_ISA_NUMPORTS;
13352417Sluoqi	}
13452417Sluoqi
13552417Sluoqi	for (i = 0; i < numports; i++) {
13652417Sluoqi		if (bus_set_resource(dev, SYS_RES_IOPORT, 0, ports[i],
13752417Sluoqi				     AIC_ISA_PORTSIZE))
13852417Sluoqi			continue;
13952417Sluoqi		if (aic_isa_alloc_resources(dev))
14052417Sluoqi			continue;
14152417Sluoqi		if (!aic_probe(aic)) {
14252417Sluoqi			aic_isa_release_resources(dev);
14352417Sluoqi			break;
14452417Sluoqi		}
14552417Sluoqi		aic_isa_release_resources(dev);
14652417Sluoqi	}
14752417Sluoqi
14852417Sluoqi	if (i == numports)
14952417Sluoqi		return (ENXIO);
15052417Sluoqi
15152417Sluoqi	porta = aic_inb(aic, PORTA);
15252417Sluoqi	if (isa_get_irq(dev) == -1)
15352417Sluoqi		bus_set_resource(dev, SYS_RES_IRQ, 0, PORTA_IRQ(porta), 1);
15452417Sluoqi	if ((aic->flags & AIC_DMA_ENABLE) && isa_get_drq(dev) == -1)
15552417Sluoqi		bus_set_resource(dev, SYS_RES_DRQ, 0, PORTA_DRQ(porta), 1);
15654136Sluoqi	device_set_desc(dev, "Adaptec 6260/6360 SCSI controller");
15752417Sluoqi	return (0);
15852417Sluoqi}
15952417Sluoqi
16052417Sluoqistatic int
16152417Sluoqiaic_isa_attach(device_t dev)
16252417Sluoqi{
16352417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
16452417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
16552417Sluoqi	int error;
16652417Sluoqi
16752417Sluoqi	error = aic_isa_alloc_resources(dev);
16852417Sluoqi	if (error) {
16952417Sluoqi		device_printf(dev, "resource allocation failed\n");
17052417Sluoqi		return (error);
17152417Sluoqi	}
17252417Sluoqi
17352417Sluoqi	error = aic_attach(aic);
17452417Sluoqi	if (error) {
17552417Sluoqi		device_printf(dev, "attach failed\n");
17652417Sluoqi		aic_isa_release_resources(dev);
17752417Sluoqi		return (error);
17852417Sluoqi	}
17952417Sluoqi
18052417Sluoqi	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_CAM, aic_intr,
18152417Sluoqi				aic, &sc->sc_ih);
18252417Sluoqi	if (error) {
18352417Sluoqi		device_printf(dev, "failed to register interrupt handler\n");
18452417Sluoqi		aic_isa_release_resources(dev);
18552417Sluoqi		return (error);
18652417Sluoqi	}
18752417Sluoqi	return (0);
18852417Sluoqi}
18952417Sluoqi
19052417Sluoqistatic int
19152417Sluoqiaic_isa_detach(device_t dev)
19252417Sluoqi{
19352417Sluoqi	struct aic_isa_softc *sc = device_get_softc(dev);
19452417Sluoqi	struct aic_softc *aic = &sc->sc_aic;
19552417Sluoqi	int error;
19652417Sluoqi
19752417Sluoqi	error = aic_detach(aic);
19852417Sluoqi	if (error) {
19952417Sluoqi		device_printf(dev, "detach failed\n");
20052417Sluoqi		return (error);
20152417Sluoqi	}
20252417Sluoqi
20352417Sluoqi	error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
20452417Sluoqi	if (error) {
20552417Sluoqi		device_printf(dev, "failed to unregister interrupt handler\n");
20652417Sluoqi	}
20752417Sluoqi
20852417Sluoqi	aic_isa_release_resources(dev);
20952417Sluoqi	return (0);
21052417Sluoqi}
21152417Sluoqi
21252417Sluoqistatic device_method_t aic_isa_methods[] = {
21352417Sluoqi	/* Device interface */
21452417Sluoqi	DEVMETHOD(device_probe,		aic_isa_probe),
21552417Sluoqi	DEVMETHOD(device_attach,	aic_isa_attach),
21652417Sluoqi	DEVMETHOD(device_detach,	aic_isa_detach),
21752417Sluoqi	{ 0, 0 }
21852417Sluoqi};
21952417Sluoqi
22052417Sluoqistatic driver_t aic_isa_driver = {
22152417Sluoqi	"aic",
22252417Sluoqi	aic_isa_methods, sizeof(struct aic_isa_softc),
22352417Sluoqi};
22452417Sluoqi
22555997Simpextern devclass_t aic_devclass;
22652417Sluoqi
22769960SimpMODULE_DEPEND(aic, cam, 1,1,1);
22852417SluoqiDRIVER_MODULE(aic, isa, aic_isa_driver, aic_devclass, 0, 0);
229