155997Simp/*-
255997Simp * Copyright (c) 1999 Luoqi Chen.
355997Simp * All rights reserved.
455997Simp *
555997Simp * Redistribution and use in source and binary forms, with or without
655997Simp * modification, are permitted provided that the following conditions
755997Simp * are met:
855997Simp * 1. Redistributions of source code must retain the above copyright
955997Simp *    notice, this list of conditions and the following disclaimer.
1055997Simp * 2. Redistributions in binary form must reproduce the above copyright
1155997Simp *    notice, this list of conditions and the following disclaimer in the
1255997Simp *    documentation and/or other materials provided with the distribution.
1355997Simp *
1455997Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1555997Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1655997Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1755997Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1855997Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1955997Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2055997Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2155997Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2255997Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2355997Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2455997Simp * SUCH DAMAGE.
2555997Simp */
2655997Simp
27119418Sobrien#include <sys/cdefs.h>
28119418Sobrien__FBSDID("$FreeBSD$");
29119418Sobrien
3055997Simp#include <sys/param.h>
31241591Sjhb#include <sys/callout.h>
3255997Simp#include <sys/kernel.h>
33241591Sjhb#include <sys/lock.h>
3455997Simp#include <sys/module.h>
35241591Sjhb#include <sys/mutex.h>
3655997Simp#include <sys/bus.h>
3755997Simp
3855997Simp#include <machine/bus.h>
3955997Simp#include <machine/resource.h>
4055997Simp#include <sys/rman.h>
4155997Simp
4255997Simp#include <dev/aic/aicvar.h>
4370782Simp#include <dev/pccard/pccardvar.h>
4455997Simp
4570782Simp#include "card_if.h"
46129764Simp#include "pccarddevs.h"
4770782Simp
4855997Simpstruct aic_pccard_softc {
4955997Simp	struct	aic_softc sc_aic;
5055997Simp	struct	resource *sc_port;
5155997Simp	struct	resource *sc_irq;
5255997Simp	void	*sc_ih;
5355997Simp};
5455997Simp
5570782Simpstatic int aic_pccard_alloc_resources(device_t);
5670782Simpstatic void aic_pccard_release_resources(device_t);
5770782Simpstatic int aic_pccard_probe(device_t);
5870782Simpstatic int aic_pccard_attach(device_t);
5955997Simp
60162979Simpstatic const struct pccard_product aic_pccard_products[] = {
61147580Simp	PCMCIA_CARD(ADAPTEC, APA1460),
62147580Simp	PCMCIA_CARD(ADAPTEC, APA1460A),
63147580Simp	PCMCIA_CARD(NEWMEDIA, BUSTOASTER),
64147580Simp	PCMCIA_CARD(NEWMEDIA, BUSTOASTER2),
65147580Simp	PCMCIA_CARD(NEWMEDIA, BUSTOASTER3),
6670782Simp	{ NULL }
6770782Simp};
6870782Simp
6955997Simp#define	AIC_PCCARD_PORTSIZE 0x20
7055997Simp
7155997Simpstatic int
7255997Simpaic_pccard_alloc_resources(device_t dev)
7355997Simp{
7455997Simp	struct aic_pccard_softc *sc = device_get_softc(dev);
7555997Simp	int rid;
7655997Simp
77241591Sjhb	sc->sc_port = sc->sc_irq = NULL;
7855997Simp
7955997Simp	rid = 0;
8055997Simp	sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
8155997Simp	    0ul, ~0ul, AIC_PCCARD_PORTSIZE, RF_ACTIVE);
8255997Simp	if (!sc->sc_port)
8355997Simp		return (ENOMEM);
8455997Simp
8555997Simp	rid = 0;
86127135Snjl	sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE);
8755997Simp	if (!sc->sc_irq) {
8855997Simp		aic_pccard_release_resources(dev);
8955997Simp		return (ENOMEM);
9055997Simp	}
9155997Simp
92170872Sscottl	sc->sc_aic.dev = dev;
93241591Sjhb	sc->sc_aic.res = sc->sc_port;
94241591Sjhb	mtx_init(&sc->sc_aic.lock, "aic", NULL, MTX_DEF);
9555997Simp	return (0);
9655997Simp}
9755997Simp
9855997Simpstatic void
9955997Simpaic_pccard_release_resources(device_t dev)
10055997Simp{
10155997Simp	struct aic_pccard_softc *sc = device_get_softc(dev);
10255997Simp
10355997Simp	if (sc->sc_port)
10455997Simp		bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->sc_port);
10555997Simp	if (sc->sc_irq)
10655997Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq);
107241591Sjhb	sc->sc_port = sc->sc_irq = NULL;
108241591Sjhb	mtx_destroy(&sc->sc_aic.lock);
10955997Simp}
11055997Simp
11155997Simpstatic int
112150392Simpaic_pccard_probe(device_t dev)
11370782Simp{
11470782Simp	const struct pccard_product *pp;
11570782Simp
11670782Simp	if ((pp = pccard_product_lookup(dev, aic_pccard_products,
11770782Simp	    sizeof(aic_pccard_products[0]), NULL)) != NULL) {
118113315Simp		if (pp->pp_name != NULL)
119113315Simp			device_set_desc(dev, pp->pp_name);
120241591Sjhb		else
121241591Sjhb			device_set_desc(dev,
122241591Sjhb			    "Adaptec 6260/6360 SCSI controller");
123241591Sjhb		return (BUS_PROBE_DEFAULT);
12470782Simp	}
125241591Sjhb	return (ENXIO);
12670782Simp}
12770782Simp
12870782Simpstatic int
129150392Simpaic_pccard_attach(device_t dev)
13055997Simp{
13155997Simp	struct aic_pccard_softc *sc = device_get_softc(dev);
13255997Simp	struct aic_softc *aic = &sc->sc_aic;
133150392Simp	int error;
13455997Simp
13555997Simp	if (aic_pccard_alloc_resources(dev))
13655997Simp		return (ENXIO);
13755997Simp	if (aic_probe(aic)) {
13855997Simp		aic_pccard_release_resources(dev);
13955997Simp		return (ENXIO);
14055997Simp	}
14155997Simp
14255997Simp	error = aic_attach(aic);
14355997Simp	if (error) {
14455997Simp		device_printf(dev, "attach failed\n");
14555997Simp		aic_pccard_release_resources(dev);
14655997Simp		return (error);
14755997Simp	}
14855997Simp
149241591Sjhb	error = bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_CAM | INTR_ENTROPY |
150241591Sjhb	    INTR_MPSAFE, NULL, aic_intr, aic, &sc->sc_ih);
15155997Simp	if (error) {
15255997Simp		device_printf(dev, "failed to register interrupt handler\n");
15355997Simp		aic_pccard_release_resources(dev);
15455997Simp		return (error);
15555997Simp	}
15655997Simp	return (0);
15755997Simp}
15855997Simp
15955997Simpstatic int
16055997Simpaic_pccard_detach(device_t dev)
16155997Simp{
16255997Simp	struct aic_pccard_softc *sc = device_get_softc(dev);
16355997Simp	struct aic_softc *aic = &sc->sc_aic;
16455997Simp	int error;
16555997Simp
16655997Simp	error = bus_teardown_intr(dev, sc->sc_irq, sc->sc_ih);
16755997Simp	if (error) {
16855997Simp		device_printf(dev, "failed to unregister interrupt handler\n");
16955997Simp	}
17055997Simp
17155997Simp	error = aic_detach(aic);
17255997Simp	if (error) {
17355997Simp		device_printf(dev, "detach failed\n");
17455997Simp		return (error);
17555997Simp	}
17655997Simp
17755997Simp	aic_pccard_release_resources(dev);
17855997Simp	return (0);
17955997Simp}
18055997Simp
18155997Simpstatic device_method_t aic_pccard_methods[] = {
18255997Simp	/* Device interface */
183150392Simp	DEVMETHOD(device_probe,		aic_pccard_probe),
184150392Simp	DEVMETHOD(device_attach,	aic_pccard_attach),
18555997Simp	DEVMETHOD(device_detach,	aic_pccard_detach),
18670782Simp
18755997Simp	{ 0, 0 }
18855997Simp};
18955997Simp
19055997Simpstatic driver_t aic_pccard_driver = {
19155997Simp	"aic",
19255997Simp	aic_pccard_methods, sizeof(struct aic_pccard_softc),
19355997Simp};
19455997Simp
19555997Simpextern devclass_t aic_devclass;
19655997Simp
19769960SimpMODULE_DEPEND(aic, cam, 1,1,1);
19855997SimpDRIVER_MODULE(aic, pccard, aic_pccard_driver, aic_devclass, 0, 0);
199