1119419Sobrien/*-
286752Sfjoe * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved.
386752Sfjoe * Author: Denis I.Timofeev <timofeev@granch.ru>
486752Sfjoe *
586752Sfjoe * Redistributon and use in source and binary forms, with or without
686752Sfjoe * modification, are permitted provided that the following conditions
786752Sfjoe * are met:
886752Sfjoe * 1. Redistributions of source code must retain the above copyright
986752Sfjoe *    notice unmodified, this list of conditions, and the following
1086752Sfjoe *    disclaimer.
1186752Sfjoe * 2. Redistributions in binary form must reproduce the above copyright
1286752Sfjoe *    notice, this list of conditions and the following disclaimer in the
1386752Sfjoe *    documentation and/or other materials provided with the distribution.
1486752Sfjoe *
1586752Sfjoe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1686752Sfjoe * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1786752Sfjoe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1886752Sfjoe * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1986752Sfjoe * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2086752Sfjoe * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2186752Sfjoe * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2286752Sfjoe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2386752Sfjoe * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY
2486752Sfjoe * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2586752Sfjoe * SUCH DAMAGE.
2686752Sfjoe */
2786752Sfjoe
28119419Sobrien#include <sys/cdefs.h>
29119419Sobrien__FBSDID("$FreeBSD$");
30119419Sobrien
3186752Sfjoe#include <sys/param.h>
3286752Sfjoe#include <sys/systm.h>
3386752Sfjoe#include <sys/socket.h>
3486752Sfjoe#include <sys/bus.h>
3586752Sfjoe#include <sys/kernel.h>
3686752Sfjoe#include <sys/module.h>
3786752Sfjoe#include <machine/bus.h>
3886752Sfjoe#include <machine/resource.h>
3986752Sfjoe#include <sys/rman.h>
4086752Sfjoe#include <sys/malloc.h>
4186752Sfjoe
4286752Sfjoe#include <net/if.h>
4386752Sfjoe#include <net/ethernet.h>
4486752Sfjoe#include <net/if_arp.h>
4586752Sfjoe
46119287Simp#include <dev/pci/pcivar.h>
47119287Simp#include <dev/pci/pcireg.h>
4886752Sfjoe
4986752Sfjoe#include <dev/sbni/if_sbnireg.h>
5086752Sfjoe#include <dev/sbni/if_sbnivar.h>
5186752Sfjoe
5286752Sfjoestatic int	sbni_pci_probe(device_t);
5386752Sfjoestatic int	sbni_pci_attach(device_t);
54180263Sjhbstatic int	sbni_pci_detach(device_t);
5586752Sfjoe
5686752Sfjoestatic device_method_t sbni_pci_methods[] = {
5786752Sfjoe	/* Device interface */
5886752Sfjoe	DEVMETHOD(device_probe,	sbni_pci_probe),
5986752Sfjoe	DEVMETHOD(device_attach, sbni_pci_attach),
60180263Sjhb	DEVMETHOD(device_detach, sbni_pci_detach),
6186752Sfjoe	{ 0, 0 }
6286752Sfjoe};
6386752Sfjoe
6486752Sfjoestatic driver_t sbni_pci_driver = {
6586752Sfjoe	"sbni",
6686752Sfjoe	sbni_pci_methods,
6786752Sfjoe	sizeof(struct sbni_softc)
6886752Sfjoe};
6986752Sfjoe
7086752Sfjoestatic devclass_t sbni_pci_devclass;
7186752Sfjoe
72113506SmdoddDRIVER_MODULE(sbni, pci, sbni_pci_driver, sbni_pci_devclass, 0, 0);
73113506SmdoddMODULE_DEPEND(sbni, pci, 1, 1, 1);
7486752Sfjoe
7586752Sfjoestatic int
7686752Sfjoesbni_pci_probe(device_t dev)
7786752Sfjoe{
7886752Sfjoe	struct sbni_softc  *sc;
7986752Sfjoe	u_int32_t  ports;
80180263Sjhb
8186752Sfjoe	ports = SBNI_PORTS;
82101393Sfjoe	if (pci_get_vendor(dev) != SBNI_PCI_VENDOR ||
83101393Sfjoe	    pci_get_device(dev) != SBNI_PCI_DEVICE)
8486752Sfjoe		return (ENXIO);
8586752Sfjoe
8686752Sfjoe	sc = device_get_softc(dev);
8786752Sfjoe	if (pci_get_subdevice(dev) == 2) {
8886752Sfjoe		ports <<= 1;
8986752Sfjoe		sc->slave_sc = malloc(sizeof(struct sbni_softc),
90101400Sfjoe				      M_DEVBUF, M_NOWAIT | M_ZERO);
9186752Sfjoe		if (!sc->slave_sc)
9286752Sfjoe			return (ENOMEM);
9386752Sfjoe		device_set_desc(dev, "Granch SBNI12/PCI Dual adapter");
9486752Sfjoe	} else
9586752Sfjoe		device_set_desc(dev, "Granch SBNI12/PCI adapter");
9686752Sfjoe
97119690Sjhb	sc->io_rid = PCIR_BAR(0);
9886752Sfjoe 	sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->io_rid,
9986752Sfjoe					0ul, ~0ul, ports, RF_ACTIVE);
10086752Sfjoe	if (!sc->io_res) {
101180263Sjhb		device_printf(dev, "cannot allocate io ports!\n");
10286752Sfjoe		if (sc->slave_sc)
10386752Sfjoe			free(sc->slave_sc, M_DEVBUF);
10486752Sfjoe		return (ENOENT);
10586752Sfjoe	}
10686752Sfjoe
107101400Sfjoe	if (sc->slave_sc) {
108101400Sfjoe		sc->slave_sc->io_res = sc->io_res;
109101400Sfjoe		sc->slave_sc->io_off = 4;
110101400Sfjoe	}
11186752Sfjoe	if (sbni_probe(sc) != 0) {
112180263Sjhb		sbni_release_resources(sc);
11386752Sfjoe		if (sc->slave_sc)
11486752Sfjoe			free(sc->slave_sc, M_DEVBUF);
11586752Sfjoe		return (ENXIO);
11686752Sfjoe	}
11786752Sfjoe
11886752Sfjoe	return (0);
11986752Sfjoe}
12086752Sfjoe
12186752Sfjoestatic int
12286752Sfjoesbni_pci_attach(device_t dev)
12386752Sfjoe{
12486752Sfjoe	struct sbni_softc *sc;
12586752Sfjoe	struct sbni_flags flags;
12686752Sfjoe	int error;
12786752Sfjoe
12886752Sfjoe	sc = device_get_softc(dev);
129180263Sjhb	sc->dev = dev;
13086752Sfjoe
131127135Snjl	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
132127135Snjl					     RF_SHAREABLE);
13386752Sfjoe
134180263Sjhb	if (sc->irq_res == NULL) {
135180263Sjhb		device_printf(dev, "cannot claim irq!\n");
13686752Sfjoe		error = ENOENT;
13786752Sfjoe		goto attach_failed;
13886752Sfjoe	}
13986752Sfjoe
14086752Sfjoe	*(u_int32_t*)&flags = 0;
14186752Sfjoe
142180263Sjhb	error = sbni_attach(sc, device_get_unit(dev) * 2, flags);
143180263Sjhb	if (error) {
144180263Sjhb		device_printf(dev, "cannot initialize driver\n");
145180263Sjhb		goto attach_failed;
146180263Sjhb	}
147180263Sjhb	if (sc->slave_sc) {
148180263Sjhb		error = sbni_attach(sc->slave_sc, device_get_unit(dev) * 2 + 1,
149180263Sjhb		    flags);
150180263Sjhb		if (error) {
151180263Sjhb			device_printf(dev, "cannot initialize slave\n");
152180263Sjhb			sbni_detach(sc);
153180263Sjhb			goto attach_failed;
154180263Sjhb		}
155180263Sjhb	}
156180263Sjhb
157180263Sjhb	if (sc->irq_res) {
158180263Sjhb		error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET |
159180263Sjhb		    INTR_MPSAFE, NULL, sbni_intr, sc, &sc->irq_handle);
160180263Sjhb		if (error) {
161180263Sjhb			device_printf(dev, "bus_setup_intr\n");
162180263Sjhb			sbni_detach(sc);
163180263Sjhb			if (sc->slave_sc)
164180263Sjhb				sbni_detach(sc);
165180263Sjhb			goto attach_failed;
166180263Sjhb		}
167180263Sjhb	}
16886752Sfjoe	return (0);
16986752Sfjoe
17086752Sfjoeattach_failed:
171180263Sjhb	sbni_release_resources(sc);
17286752Sfjoe	if (sc->slave_sc)
17386752Sfjoe		free(sc->slave_sc, M_DEVBUF);
17486752Sfjoe	return (error);
17586752Sfjoe}
176180263Sjhb
177180263Sjhbstatic int
178180263Sjhbsbni_pci_detach(device_t dev)
179180263Sjhb{
180180263Sjhb	struct sbni_softc *sc;
181180263Sjhb
182180263Sjhb	sc = device_get_softc(dev);
183180263Sjhb	sbni_detach(sc);
184180263Sjhb	if (sc->slave_sc)
185180263Sjhb		sbni_detach(sc);
186180263Sjhb
187180263Sjhb	sbni_release_resources(sc);
188180263Sjhb	if (sc->slave_sc)
189180263Sjhb		free(sc->slave_sc, M_DEVBUF);
190180263Sjhb	return (0);
191180263Sjhb}
192