1/*-
2 * Copyright (c) 1995, David Greenman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice unmodified, this list of conditions, and the following
10 *    disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32/*
33 *	National Semiconductor  DP8393X SONIC Driver
34 *
35 *	This is the bus independent attachment on FreeBSD 4.x
36 *		written by Motomichi Matsuzaki <mzaki@e-mail.ne.jp>
37 */
38
39#include <sys/param.h>
40#include <sys/socket.h>
41
42#include <sys/bus.h>
43#include <machine/bus.h>
44#include <sys/rman.h>
45#include <machine/resource.h>
46
47#include <net/ethernet.h>
48#include <net/if.h>
49#include <net/if_arp.h>
50#include <net/if_media.h>
51
52#include <dev/snc/dp83932reg.h>
53#include <dev/snc/dp83932var.h>
54#include <dev/snc/dp83932subr.h>
55#include <dev/snc/if_sncreg.h>
56#include <dev/snc/if_sncvar.h>
57
58/* devclass for "snc" */
59devclass_t snc_devclass;
60
61/****************************************************************
62  Resource management functions
63 ****************************************************************/
64
65/*
66 * Allocate a port resource with the given resource id.
67 */
68int
69snc_alloc_port(device_t dev, int rid)
70{
71	struct snc_softc *sc = device_get_softc(dev);
72	struct resource *res;
73
74	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
75				 0ul, ~0ul, SNEC_NREGS, RF_ACTIVE);
76	if (res) {
77		sc->ioport = res;
78		sc->ioport_rid = rid;
79		sc->sc_iot = rman_get_bustag(res);
80		sc->sc_ioh = rman_get_bushandle(res);
81		return (0);
82	} else {
83		device_printf(dev, "can't assign port\n");
84		return (ENOENT);
85	}
86}
87
88/*
89 * Allocate a memory resource with the given resource id.
90 */
91int
92snc_alloc_memory(device_t dev, int rid)
93{
94	struct snc_softc *sc = device_get_softc(dev);
95	struct resource *res;
96
97	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
98				 0ul, ~0ul, SNEC_NMEMS, RF_ACTIVE);
99	if (res) {
100		sc->iomem = res;
101		sc->iomem_rid = rid;
102		sc->sc_memt = rman_get_bustag(res);
103		sc->sc_memh = rman_get_bushandle(res);
104		return (0);
105	} else {
106		device_printf(dev, "can't assign memory\n");
107		return (ENOENT);
108	}
109}
110
111/*
112 * Allocate an irq resource with the given resource id.
113 */
114int
115snc_alloc_irq(device_t dev, int rid, int flags)
116{
117	struct snc_softc *sc = device_get_softc(dev);
118	struct resource *res;
119
120	res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE | flags);
121	if (res) {
122		sc->irq = res;
123		sc->irq_rid = rid;
124		return (0);
125	} else {
126		device_printf(dev, "can't assign irq\n");
127		return (ENOENT);
128	}
129}
130
131/*
132 * Release all resources
133 */
134void
135snc_release_resources(device_t dev)
136{
137	struct snc_softc *sc = device_get_softc(dev);
138
139	if (sc->ioport) {
140		bus_release_resource(dev, SYS_RES_IOPORT,
141				     sc->ioport_rid, sc->ioport);
142		sc->ioport = 0;
143	}
144	if (sc->iomem) {
145		bus_release_resource(dev, SYS_RES_MEMORY,
146				     sc->iomem_rid, sc->iomem);
147		sc->iomem = 0;
148	}
149	if (sc->irq) {
150		bus_release_resource(dev, SYS_RES_IRQ,
151				     sc->irq_rid, sc->irq);
152		sc->irq = 0;
153	}
154	if (sc->sc_ifp) {
155		if_free(sc->sc_ifp);
156		sc->sc_ifp = 0;
157	}
158}
159
160/****************************************************************
161  Probe routine
162 ****************************************************************/
163
164int
165snc_probe(device_t dev, int type)
166{
167	struct snc_softc *sc = device_get_softc(dev);
168
169	return snc_nec16_detectsubr(sc->sc_iot, sc->sc_ioh,
170				    sc->sc_memt, sc->sc_memh,
171				    rman_get_start(sc->irq),
172				    rman_get_start(sc->iomem),
173				    type);
174}
175
176/****************************************************************
177  Attach routine
178 ****************************************************************/
179
180int
181snc_attach(device_t dev)
182{
183	struct snc_softc *sc = device_get_softc(dev);
184	u_int8_t myea[ETHER_ADDR_LEN];
185	int error;
186
187	if (snc_nec16_register_irq(sc, rman_get_start(sc->irq)) == 0 ||
188	    snc_nec16_register_mem(sc, rman_get_start(sc->iomem)) == 0) {
189		snc_release_resources(dev);
190		return(ENOENT);
191	}
192
193	snc_nec16_get_enaddr(sc->sc_iot, sc->sc_ioh, myea);
194	device_printf(dev, "%s Ethernet\n", snc_nec16_detect_type(myea));
195
196	sc->sc_dev = dev;
197
198	sc->sncr_dcr = DCR_SYNC | DCR_WAIT0 |
199            DCR_DMABLOCK | DCR_RFT16 | DCR_TFT28;
200	sc->sncr_dcr2 = 0;	/* XXX */
201	sc->bitmode = 0;	/* 16 bit card */
202
203	sc->sc_nic_put = snc_nec16_nic_put;
204	sc->sc_nic_get = snc_nec16_nic_get;
205	sc->sc_writetodesc = snc_nec16_writetodesc;
206	sc->sc_readfromdesc = snc_nec16_readfromdesc;
207	sc->sc_copytobuf = snc_nec16_copytobuf;
208	sc->sc_copyfrombuf = snc_nec16_copyfrombuf;
209	sc->sc_zerobuf = snc_nec16_zerobuf;
210
211	/* sncsetup returns 1 if something fails */
212	if (sncsetup(sc, myea)) {
213		snc_release_resources(dev);
214		return(ENOENT);
215	}
216
217	mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK,
218	    MTX_DEF);
219	callout_init_mtx(&sc->sc_timer, &sc->sc_lock, 0);
220	error = sncconfig(sc, NULL, 0, 0, myea);
221	if (error) {
222		snc_release_resources(dev);
223		mtx_destroy(&sc->sc_lock);
224		return (error);
225	}
226
227	error = bus_setup_intr(dev, sc->irq, INTR_TYPE_NET | INTR_MPSAFE,
228			       NULL, sncintr, sc, &sc->irq_handle);
229	if (error) {
230		printf("snc_isa_attach: bus_setup_intr() failed\n");
231		ether_ifdetach(sc->sc_ifp);
232		snc_release_resources(dev);
233		mtx_destroy(&sc->sc_lock);
234		return (error);
235	}
236
237	return 0;
238}
239
240/****************************************************************
241  Shutdown routine
242 ****************************************************************/
243
244int
245snc_shutdown(device_t dev)
246{
247	struct snc_softc *sc = device_get_softc(dev);
248
249	SNC_LOCK(sc);
250	sncshutdown(sc);
251	SNC_UNLOCK(sc);
252
253	return (0);
254}
255