1158712Smarius/*	$NetBSD: if_le_isa.c,v 1.41 2005/12/24 20:27:41 perry Exp $	*/
2158712Smarius
3158712Smarius/*-
4158712Smarius * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5158712Smarius * All rights reserved.
6158712Smarius *
7158712Smarius * This code is derived from software contributed to The NetBSD Foundation
8158712Smarius * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9158712Smarius * Simulation Facility, NASA Ames Research Center.
10158712Smarius *
11158712Smarius * Redistribution and use in source and binary forms, with or without
12158712Smarius * modification, are permitted provided that the following conditions
13158712Smarius * are met:
14158712Smarius * 1. Redistributions of source code must retain the above copyright
15158712Smarius *    notice, this list of conditions and the following disclaimer.
16158712Smarius * 2. Redistributions in binary form must reproduce the above copyright
17158712Smarius *    notice, this list of conditions and the following disclaimer in the
18158712Smarius *    documentation and/or other materials provided with the distribution.
19158712Smarius *
20158712Smarius * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21158712Smarius * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22158712Smarius * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23158712Smarius * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24158712Smarius * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25158712Smarius * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26158712Smarius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27158712Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28158712Smarius * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29158712Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30158712Smarius * POSSIBILITY OF SUCH DAMAGE.
31158712Smarius */
32158712Smarius
33158712Smarius/*-
34158712Smarius * Copyright (c) 1992, 1993
35158712Smarius *	The Regents of the University of California.  All rights reserved.
36158712Smarius *
37158712Smarius * This code is derived from software contributed to Berkeley by
38158712Smarius * Ralph Campbell and Rick Macklem.
39158712Smarius *
40158712Smarius * Redistribution and use in source and binary forms, with or without
41158712Smarius * modification, are permitted provided that the following conditions
42158712Smarius * are met:
43158712Smarius * 1. Redistributions of source code must retain the above copyright
44158712Smarius *    notice, this list of conditions and the following disclaimer.
45158712Smarius * 2. Redistributions in binary form must reproduce the above copyright
46158712Smarius *    notice, this list of conditions and the following disclaimer in the
47158712Smarius *    documentation and/or other materials provided with the distribution.
48158712Smarius * 3. Neither the name of the University nor the names of its contributors
49158712Smarius *    may be used to endorse or promote products derived from this software
50158712Smarius *    without specific prior written permission.
51158712Smarius *
52158712Smarius * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53158712Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54158712Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55158712Smarius * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56158712Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57158712Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58158712Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59158712Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60158712Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61158712Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62158712Smarius * SUCH DAMAGE.
63158712Smarius *
64158712Smarius *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
65158712Smarius */
66158712Smarius
67158712Smarius#include <sys/cdefs.h>
68158712Smarius__FBSDID("$FreeBSD: releng/10.3/sys/dev/le/if_le_isa.c 263687 2014-03-24 13:48:04Z emaste $");
69158712Smarius
70158712Smarius#include <sys/param.h>
71158712Smarius#include <sys/systm.h>
72158712Smarius#include <sys/bus.h>
73158712Smarius#include <sys/endian.h>
74158712Smarius#include <sys/kernel.h>
75158712Smarius#include <sys/lock.h>
76158712Smarius#include <sys/module.h>
77158712Smarius#include <sys/mutex.h>
78158712Smarius#include <sys/resource.h>
79158712Smarius#include <sys/rman.h>
80158712Smarius#include <sys/socket.h>
81158712Smarius
82158712Smarius#include <net/ethernet.h>
83158712Smarius#include <net/if.h>
84158712Smarius#include <net/if_media.h>
85158712Smarius
86158712Smarius#include <machine/bus.h>
87158712Smarius#include <machine/resource.h>
88158712Smarius
89158712Smarius#include <isa/isavar.h>
90158712Smarius
91158712Smarius#include <dev/le/lancereg.h>
92158712Smarius#include <dev/le/lancevar.h>
93158712Smarius#include <dev/le/am7990var.h>
94158712Smarius
95158712Smarius#define	LE_ISA_MEMSIZE	(16*1024)
96158712Smarius#define	PCNET_RDP	0x10
97158712Smarius#define	PCNET_RAP	0x12
98158712Smarius
99158712Smariusstruct le_isa_softc {
100158712Smarius	struct am7990_softc	sc_am7990;	/* glue to MI code */
101158712Smarius
102158712Smarius	bus_size_t		sc_rap;		/* offsets to LANCE... */
103158712Smarius	bus_size_t		sc_rdp;		/* ...registers */
104158712Smarius
105158712Smarius	struct resource		*sc_rres;
106158712Smarius
107158712Smarius	struct resource		*sc_dres;
108158712Smarius
109158712Smarius	struct resource		*sc_ires;
110158712Smarius	void			*sc_ih;
111158712Smarius
112158712Smarius	bus_dma_tag_t		sc_pdmat;
113158712Smarius	bus_dma_tag_t		sc_dmat;
114158712Smarius	bus_dmamap_t		sc_dmam;
115158712Smarius};
116158712Smarius
117158712Smariusstatic device_probe_t le_isa_probe;
118158712Smariusstatic device_attach_t le_isa_attach;
119158712Smariusstatic device_detach_t le_isa_detach;
120158712Smariusstatic device_resume_t le_isa_resume;
121158712Smariusstatic device_suspend_t le_isa_suspend;
122158712Smarius
123158712Smariusstatic device_method_t le_isa_methods[] = {
124158712Smarius	/* Device interface */
125158712Smarius	DEVMETHOD(device_probe,		le_isa_probe),
126158712Smarius	DEVMETHOD(device_attach,	le_isa_attach),
127158712Smarius	DEVMETHOD(device_detach,	le_isa_detach),
128158712Smarius	/* We can just use the suspend method here. */
129158712Smarius	DEVMETHOD(device_shutdown,	le_isa_suspend),
130158712Smarius	DEVMETHOD(device_suspend,	le_isa_suspend),
131158712Smarius	DEVMETHOD(device_resume,	le_isa_resume),
132158712Smarius
133158712Smarius	{ 0, 0 }
134158712Smarius};
135158712Smarius
136158712SmariusDEFINE_CLASS_0(le, le_isa_driver, le_isa_methods, sizeof(struct le_isa_softc));
137158712SmariusDRIVER_MODULE(le, isa, le_isa_driver, le_devclass, 0, 0);
138158712SmariusMODULE_DEPEND(le, ether, 1, 1, 1);
139158712Smarius
140158712Smariusstruct le_isa_param {
141158712Smarius	const char	*name;
142158712Smarius	u_long		iosize;
143158712Smarius	bus_size_t	rap;
144158712Smarius	bus_size_t	rdp;
145158712Smarius	bus_size_t	macstart;
146158712Smarius	int		macstride;
147158712Smarius} static const le_isa_params[] = {
148158712Smarius	{ "BICC Isolan", 24, 0xe, 0xc, 0, 2 },
149158712Smarius	{ "Novell NE2100", 16, 0x12, 0x10, 0, 1 }
150158712Smarius};
151158712Smarius
152158712Smariusstatic struct isa_pnp_id le_isa_ids[] = {
153158712Smarius	{ 0x0322690e, "Cabletron E2200 Single Chip" },	/* CSI2203 */
154158712Smarius	{ 0x0110490a, "Boca LANCard Combo" },		/* BRI1001 */
155158712Smarius	{ 0x0100a60a, "Melco Inc. LGY-IV" },		/* BUF0001 */
156158712Smarius	{ 0xd880d041, "Novell NE2100" },		/* PNP80D8 */
157158712Smarius	{ 0x0082d041, "Cabletron E2100 Series DNI" },	/* PNP8200 */
158158712Smarius	{ 0x3182d041, "AMD AM1500T/AM2100" },		/* PNP8231 */
159158712Smarius	{ 0x8c82d041, "AMD PCnet-ISA" },		/* PNP828C */
160158712Smarius	{ 0x8d82d041, "AMD PCnet-32" },			/* PNP828D */
161158712Smarius	{ 0xcefaedfe, "Racal InterLan EtherBlaster" },	/* _WMFACE */
162158712Smarius	{ 0, NULL }
163158712Smarius};
164158712Smarius
165158712Smariusstatic void le_isa_wrcsr(struct lance_softc *, uint16_t, uint16_t);
166158712Smariusstatic uint16_t le_isa_rdcsr(struct lance_softc *, uint16_t);
167158712Smariusstatic bus_dmamap_callback_t le_isa_dma_callback;
168158712Smariusstatic int le_isa_probe_legacy(device_t, const struct le_isa_param *);
169158712Smarius
170158712Smariusstatic void
171158712Smariusle_isa_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
172158712Smarius{
173158712Smarius	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
174158712Smarius
175183337Smarius	bus_write_2(lesc->sc_rres, lesc->sc_rap, port);
176183337Smarius	bus_barrier(lesc->sc_rres, lesc->sc_rap, 2, BUS_SPACE_BARRIER_WRITE);
177183337Smarius	bus_write_2(lesc->sc_rres, lesc->sc_rdp, val);
178158712Smarius}
179158712Smarius
180158712Smariusstatic uint16_t
181158712Smariusle_isa_rdcsr(struct lance_softc *sc, uint16_t port)
182158712Smarius{
183158712Smarius	struct le_isa_softc *lesc = (struct le_isa_softc *)sc;
184158712Smarius
185183337Smarius	bus_write_2(lesc->sc_rres, lesc->sc_rap, port);
186183337Smarius	bus_barrier(lesc->sc_rres, lesc->sc_rap, 2, BUS_SPACE_BARRIER_WRITE);
187183337Smarius	return (bus_read_2(lesc->sc_rres, lesc->sc_rdp));
188158712Smarius}
189158712Smarius
190158712Smariusstatic void
191158712Smariusle_isa_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
192158712Smarius{
193158712Smarius	struct lance_softc *sc = (struct lance_softc *)xsc;
194158712Smarius
195158712Smarius	if (error != 0)
196158712Smarius		return;
197158712Smarius	KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
198158712Smarius	sc->sc_addr = segs[0].ds_addr;
199158712Smarius}
200158712Smarius
201158712Smariusstatic int
202158712Smariusle_isa_probe_legacy(device_t dev, const struct le_isa_param *leip)
203158712Smarius{
204158712Smarius	struct le_isa_softc *lesc;
205158712Smarius	struct lance_softc *sc;
206183337Smarius	int error, i;
207158712Smarius
208158712Smarius	lesc = device_get_softc(dev);
209158712Smarius	sc = &lesc->sc_am7990.lsc;
210158712Smarius
211183337Smarius	i = 0;
212183337Smarius	lesc->sc_rres = bus_alloc_resource(dev, SYS_RES_IOPORT, &i, 0, ~0,
213183337Smarius	    leip->iosize, RF_ACTIVE);
214158712Smarius	if (lesc->sc_rres == NULL)
215158712Smarius		return (ENXIO);
216158712Smarius	lesc->sc_rap = leip->rap;
217158712Smarius	lesc->sc_rdp = leip->rdp;
218158712Smarius
219158712Smarius	/* Stop the chip and put it in a known state. */
220158712Smarius	le_isa_wrcsr(sc, LE_CSR0, LE_C0_STOP);
221158712Smarius	DELAY(100);
222158712Smarius	if (le_isa_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
223158712Smarius		error = ENXIO;
224158712Smarius		goto fail;
225158712Smarius	}
226158712Smarius	le_isa_wrcsr(sc, LE_CSR3, 0);
227158712Smarius	error = 0;
228158712Smarius
229158712Smarius fail:
230183337Smarius	bus_release_resource(dev, SYS_RES_IOPORT,
231183337Smarius	    rman_get_rid(lesc->sc_rres), lesc->sc_rres);
232158712Smarius	return (error);
233158712Smarius}
234158712Smarius
235158712Smariusstatic int
236158712Smariusle_isa_probe(device_t dev)
237158712Smarius{
238158712Smarius	int i;
239158712Smarius
240158712Smarius	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
241158712Smarius	case 0:
242158712Smarius		return (BUS_PROBE_DEFAULT);
243158712Smarius	case ENOENT:
244158712Smarius		for (i = 0; i < sizeof(le_isa_params) /
245158712Smarius		    sizeof(le_isa_params[0]); i++) {
246158712Smarius			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
247158712Smarius				device_set_desc(dev, le_isa_params[i].name);
248158712Smarius				return (BUS_PROBE_DEFAULT);
249158712Smarius			}
250158712Smarius		}
251158712Smarius		/* FALLTHROUGH */
252158712Smarius	case ENXIO:
253158712Smarius	default:
254158712Smarius		return (ENXIO);
255158712Smarius	}
256158712Smarius}
257158712Smarius
258158712Smariusstatic int
259158712Smariusle_isa_attach(device_t dev)
260158712Smarius{
261158712Smarius	struct le_isa_softc *lesc;
262158712Smarius	struct lance_softc *sc;
263158712Smarius	bus_size_t macstart, rap, rdp;
264183337Smarius	int error, i, j, macstride;
265158712Smarius
266158712Smarius	lesc = device_get_softc(dev);
267158712Smarius	sc = &lesc->sc_am7990.lsc;
268158712Smarius
269158712Smarius	LE_LOCK_INIT(sc, device_get_nameunit(dev));
270158712Smarius
271183337Smarius	j = 0;
272158712Smarius	switch (ISA_PNP_PROBE(device_get_parent(dev), dev, le_isa_ids)) {
273158712Smarius	case 0:
274158712Smarius		lesc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
275183337Smarius		    &j, RF_ACTIVE);
276158712Smarius		rap = PCNET_RAP;
277158712Smarius		rdp = PCNET_RDP;
278158712Smarius		macstart = 0;
279158712Smarius		macstride = 1;
280158712Smarius		break;
281158712Smarius	case ENOENT:
282158712Smarius		for (i = 0; i < sizeof(le_isa_params) /
283158712Smarius		    sizeof(le_isa_params[0]); i++) {
284158712Smarius			if (le_isa_probe_legacy(dev, &le_isa_params[i]) == 0) {
285158712Smarius				lesc->sc_rres = bus_alloc_resource(dev,
286183337Smarius				    SYS_RES_IOPORT, &j, 0, ~0,
287158712Smarius				    le_isa_params[i].iosize, RF_ACTIVE);
288158712Smarius				rap = le_isa_params[i].rap;
289158712Smarius				rdp = le_isa_params[i].rdp;
290158712Smarius				macstart = le_isa_params[i].macstart;
291158712Smarius				macstride = le_isa_params[i].macstride;
292158712Smarius				goto found;
293158712Smarius			}
294158712Smarius		}
295158712Smarius		/* FALLTHROUGH */
296158712Smarius	case ENXIO:
297158712Smarius	default:
298158712Smarius		device_printf(dev, "cannot determine chip\n");
299158712Smarius		error = ENXIO;
300158712Smarius		goto fail_mtx;
301158712Smarius	}
302158712Smarius
303158712Smarius found:
304158712Smarius	if (lesc->sc_rres == NULL) {
305158712Smarius		device_printf(dev, "cannot allocate registers\n");
306158712Smarius		error = ENXIO;
307158712Smarius		goto fail_mtx;
308158712Smarius	}
309158712Smarius	lesc->sc_rap = rap;
310158712Smarius	lesc->sc_rdp = rdp;
311158712Smarius
312183337Smarius	i = 0;
313158712Smarius	if ((lesc->sc_dres = bus_alloc_resource_any(dev, SYS_RES_DRQ,
314183337Smarius	    &i, RF_ACTIVE)) == NULL) {
315158712Smarius		device_printf(dev, "cannot allocate DMA channel\n");
316158712Smarius		error = ENXIO;
317158712Smarius		goto fail_rres;
318158712Smarius	}
319158712Smarius
320183337Smarius	i = 0;
321158712Smarius	if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
322183337Smarius	    &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
323158712Smarius		device_printf(dev, "cannot allocate interrupt\n");
324158712Smarius		error = ENXIO;
325158712Smarius		goto fail_dres;
326158712Smarius	}
327158712Smarius
328158712Smarius	error = bus_dma_tag_create(
329166138Smarius	    bus_get_dma_tag(dev),	/* parent */
330158712Smarius	    1, 0,			/* alignment, boundary */
331158712Smarius	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
332158712Smarius	    BUS_SPACE_MAXADDR,		/* highaddr */
333158712Smarius	    NULL, NULL,			/* filter, filterarg */
334158712Smarius	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
335158712Smarius	    0,				/* nsegments */
336158712Smarius	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
337166148Smarius	    0,				/* flags */
338158712Smarius	    NULL, NULL,			/* lockfunc, lockarg */
339158712Smarius	    &lesc->sc_pdmat);
340158712Smarius	if (error != 0) {
341158712Smarius		device_printf(dev, "cannot allocate parent DMA tag\n");
342158712Smarius		goto fail_ires;
343158712Smarius	}
344158712Smarius
345158712Smarius	sc->sc_memsize = LE_ISA_MEMSIZE;
346158712Smarius	/*
347158712Smarius	 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
348158712Smarius	 * aligned and the ring descriptors must be 8-byte aligned.
349158712Smarius	 */
350158712Smarius	error = bus_dma_tag_create(
351158712Smarius	    lesc->sc_pdmat,		/* parent */
352158712Smarius	    8, 0,			/* alignment, boundary */
353158712Smarius	    BUS_SPACE_MAXADDR_24BIT,	/* lowaddr */
354158712Smarius	    BUS_SPACE_MAXADDR,		/* highaddr */
355158712Smarius	    NULL, NULL,			/* filter, filterarg */
356158712Smarius	    sc->sc_memsize,		/* maxsize */
357158712Smarius	    1,				/* nsegments */
358158712Smarius	    sc->sc_memsize,		/* maxsegsize */
359166148Smarius	    0,				/* flags */
360158712Smarius	    NULL, NULL,			/* lockfunc, lockarg */
361158712Smarius	    &lesc->sc_dmat);
362158712Smarius	if (error != 0) {
363158712Smarius		device_printf(dev, "cannot allocate buffer DMA tag\n");
364158712Smarius		goto fail_pdtag;
365158712Smarius	}
366158712Smarius
367158712Smarius	error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
368158712Smarius	    BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
369158712Smarius	if (error != 0) {
370158712Smarius		device_printf(dev, "cannot allocate DMA buffer memory\n");
371158712Smarius		goto fail_dtag;
372158712Smarius	}
373158712Smarius
374158712Smarius	sc->sc_addr = 0;
375158712Smarius	error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
376158712Smarius	    sc->sc_memsize, le_isa_dma_callback, sc, 0);
377158712Smarius	if (error != 0 || sc->sc_addr == 0) {
378183337Smarius		device_printf(dev, "cannot load DMA buffer map\n");
379158712Smarius		goto fail_dmem;
380158712Smarius	}
381158712Smarius
382158712Smarius	isa_dmacascade(rman_get_start(lesc->sc_dres));
383158712Smarius
384158712Smarius	sc->sc_flags = 0;
385158712Smarius	sc->sc_conf3 = 0;
386158712Smarius
387158712Smarius	/*
388158712Smarius	 * Extract the physical MAC address from the ROM.
389158712Smarius	 */
390158712Smarius	for (i = 0; i < sizeof(sc->sc_enaddr); i++)
391183337Smarius		sc->sc_enaddr[i] = bus_read_1(lesc->sc_rres,
392183337Smarius		    macstart + i * macstride);
393158712Smarius
394158712Smarius	sc->sc_copytodesc = lance_copytobuf_contig;
395158712Smarius	sc->sc_copyfromdesc = lance_copyfrombuf_contig;
396158712Smarius	sc->sc_copytobuf = lance_copytobuf_contig;
397158712Smarius	sc->sc_copyfrombuf = lance_copyfrombuf_contig;
398158712Smarius	sc->sc_zerobuf = lance_zerobuf_contig;
399158712Smarius
400158712Smarius	sc->sc_rdcsr = le_isa_rdcsr;
401158712Smarius	sc->sc_wrcsr = le_isa_wrcsr;
402158712Smarius	sc->sc_hwreset = NULL;
403158712Smarius	sc->sc_hwinit = NULL;
404158712Smarius	sc->sc_hwintr = NULL;
405158712Smarius	sc->sc_nocarrier = NULL;
406158712Smarius	sc->sc_mediachange = NULL;
407158712Smarius	sc->sc_mediastatus = NULL;
408158712Smarius	sc->sc_supmedia = NULL;
409158712Smarius
410158712Smarius	error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
411158712Smarius	    device_get_unit(dev));
412158712Smarius	if (error != 0) {
413158712Smarius		device_printf(dev, "cannot attach Am7990\n");
414158712Smarius		goto fail_dmap;
415158712Smarius	}
416158712Smarius
417158712Smarius	error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
418166901Spiso	    NULL, am7990_intr, sc, &lesc->sc_ih);
419158712Smarius	if (error != 0) {
420158712Smarius		device_printf(dev, "cannot set up interrupt\n");
421158712Smarius		goto fail_am7990;
422158712Smarius	}
423158712Smarius
424158712Smarius	return (0);
425158712Smarius
426158712Smarius fail_am7990:
427158712Smarius	am7990_detach(&lesc->sc_am7990);
428158712Smarius fail_dmap:
429158712Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
430158712Smarius fail_dmem:
431158712Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
432158712Smarius fail_dtag:
433158712Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
434158712Smarius fail_pdtag:
435158712Smarius	bus_dma_tag_destroy(lesc->sc_pdmat);
436158712Smarius fail_ires:
437183337Smarius	bus_release_resource(dev, SYS_RES_IRQ,
438183337Smarius	    rman_get_rid(lesc->sc_ires), lesc->sc_ires);
439158712Smarius fail_dres:
440183337Smarius	bus_release_resource(dev, SYS_RES_DRQ,
441183337Smarius	    rman_get_rid(lesc->sc_dres), lesc->sc_dres);
442158712Smarius fail_rres:
443183337Smarius	bus_release_resource(dev, SYS_RES_IOPORT,
444183337Smarius	    rman_get_rid(lesc->sc_rres), lesc->sc_rres);
445158712Smarius fail_mtx:
446158712Smarius	LE_LOCK_DESTROY(sc);
447158712Smarius	return (error);
448158712Smarius}
449158712Smarius
450158712Smariusstatic int
451158712Smariusle_isa_detach(device_t dev)
452158712Smarius{
453158712Smarius	struct le_isa_softc *lesc;
454158712Smarius	struct lance_softc *sc;
455158712Smarius
456158712Smarius	lesc = device_get_softc(dev);
457158712Smarius	sc = &lesc->sc_am7990.lsc;
458158712Smarius
459158712Smarius	bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
460158712Smarius	am7990_detach(&lesc->sc_am7990);
461158712Smarius	bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
462158712Smarius	bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
463158712Smarius	bus_dma_tag_destroy(lesc->sc_dmat);
464158712Smarius	bus_dma_tag_destroy(lesc->sc_pdmat);
465183337Smarius	bus_release_resource(dev, SYS_RES_IRQ,
466183337Smarius	    rman_get_rid(lesc->sc_ires), lesc->sc_ires);
467183337Smarius	bus_release_resource(dev, SYS_RES_DRQ,
468183337Smarius	    rman_get_rid(lesc->sc_dres), lesc->sc_dres);
469183337Smarius	bus_release_resource(dev, SYS_RES_IOPORT,
470183337Smarius	    rman_get_rid(lesc->sc_rres), lesc->sc_rres);
471158712Smarius	LE_LOCK_DESTROY(sc);
472158712Smarius
473158712Smarius	return (0);
474158712Smarius}
475158712Smarius
476158712Smariusstatic int
477158712Smariusle_isa_suspend(device_t dev)
478158712Smarius{
479158712Smarius	struct le_isa_softc *lesc;
480158712Smarius
481158712Smarius	lesc = device_get_softc(dev);
482158712Smarius
483158712Smarius	lance_suspend(&lesc->sc_am7990.lsc);
484158712Smarius
485158712Smarius	return (0);
486158712Smarius}
487158712Smarius
488158712Smariusstatic int
489158712Smariusle_isa_resume(device_t dev)
490158712Smarius{
491158712Smarius	struct le_isa_softc *lesc;
492158712Smarius
493158712Smarius	lesc = device_get_softc(dev);
494158712Smarius
495158712Smarius	lance_resume(&lesc->sc_am7990.lsc);
496158712Smarius
497158712Smarius	return (0);
498158712Smarius}
499