10Sstevel@tonic-gate/*-
20Sstevel@tonic-gate * Copyright (c) 1997-2001 Granch, Ltd. All rights reserved.
30Sstevel@tonic-gate * Author: Denis I.Timofeev <timofeev@granch.ru>
40Sstevel@tonic-gate *
50Sstevel@tonic-gate * Redistributon and use in source and binary forms, with or without
60Sstevel@tonic-gate * modification, are permitted provided that the following conditions
70Sstevel@tonic-gate * are met:
80Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
90Sstevel@tonic-gate *    notice unmodified, this list of conditions, and the following
100Sstevel@tonic-gate *    disclaimer.
110Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
120Sstevel@tonic-gate *    notice, this list of conditions and the following disclaimer in the
130Sstevel@tonic-gate *    documentation and/or other materials provided with the distribution.
140Sstevel@tonic-gate *
150Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
160Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
170Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
180Sstevel@tonic-gate * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
190Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
200Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
210Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
220Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
230Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEIGENCE OR OTHERWISE) ARISING IN ANY WAY
240Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
250Sstevel@tonic-gate * SUCH DAMAGE.
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate#include <sys/param.h>
290Sstevel@tonic-gate#include <sys/systm.h>
300Sstevel@tonic-gate#include <sys/socket.h>
310Sstevel@tonic-gate#include <sys/bus.h>
320Sstevel@tonic-gate#include <sys/kernel.h>
330Sstevel@tonic-gate#include <sys/module.h>
340Sstevel@tonic-gate#include <machine/bus.h>
350Sstevel@tonic-gate#include <machine/resource.h>
360Sstevel@tonic-gate#include <sys/rman.h>
370Sstevel@tonic-gate#include <sys/malloc.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate#include <net/if.h>
400Sstevel@tonic-gate#include <net/ethernet.h>
410Sstevel@tonic-gate#include <net/if_arp.h>
420Sstevel@tonic-gate
430Sstevel@tonic-gate#include <dev/pci/pcivar.h>
440Sstevel@tonic-gate#include <dev/pci/pcireg.h>
450Sstevel@tonic-gate
460Sstevel@tonic-gate#include <dev/sbni/if_sbnireg.h>
470Sstevel@tonic-gate#include <dev/sbni/if_sbnivar.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gatestatic int	sbni_pci_probe(device_t);
500Sstevel@tonic-gatestatic int	sbni_pci_attach(device_t);
510Sstevel@tonic-gatestatic int	sbni_pci_detach(device_t);
520Sstevel@tonic-gate
530Sstevel@tonic-gatestatic device_method_t sbni_pci_methods[] = {
540Sstevel@tonic-gate	/* Device interface */
550Sstevel@tonic-gate	DEVMETHOD(device_probe,	sbni_pci_probe),
560Sstevel@tonic-gate	DEVMETHOD(device_attach, sbni_pci_attach),
570Sstevel@tonic-gate	DEVMETHOD(device_detach, sbni_pci_detach),
580Sstevel@tonic-gate	{ 0, 0 }
590Sstevel@tonic-gate};
600Sstevel@tonic-gate
610Sstevel@tonic-gatestatic driver_t sbni_pci_driver = {
620Sstevel@tonic-gate	"sbni",
630Sstevel@tonic-gate	sbni_pci_methods,
640Sstevel@tonic-gate	sizeof(struct sbni_softc)
650Sstevel@tonic-gate};
660Sstevel@tonic-gate
670Sstevel@tonic-gateDRIVER_MODULE(sbni, pci, sbni_pci_driver, 0, 0);
680Sstevel@tonic-gateMODULE_DEPEND(sbni, pci, 1, 1, 1);
690Sstevel@tonic-gate
700Sstevel@tonic-gatestatic int
710Sstevel@tonic-gatesbni_pci_probe(device_t dev)
720Sstevel@tonic-gate{
730Sstevel@tonic-gate	struct sbni_softc  *sc;
740Sstevel@tonic-gate
750Sstevel@tonic-gate	if (pci_get_vendor(dev) != SBNI_PCI_VENDOR ||
760Sstevel@tonic-gate	    pci_get_device(dev) != SBNI_PCI_DEVICE)
770Sstevel@tonic-gate		return (ENXIO);
780Sstevel@tonic-gate
790Sstevel@tonic-gate	sc = device_get_softc(dev);
800Sstevel@tonic-gate	if (pci_get_subdevice(dev) == 2) {
810Sstevel@tonic-gate		sc->slave_sc = malloc(sizeof(struct sbni_softc),
820Sstevel@tonic-gate				      M_DEVBUF, M_NOWAIT | M_ZERO);
830Sstevel@tonic-gate		if (!sc->slave_sc)
840Sstevel@tonic-gate			return (ENOMEM);
850Sstevel@tonic-gate		device_set_desc(dev, "Granch SBNI12/PCI Dual adapter");
860Sstevel@tonic-gate	} else
870Sstevel@tonic-gate		device_set_desc(dev, "Granch SBNI12/PCI adapter");
880Sstevel@tonic-gate
890Sstevel@tonic-gate	sc->io_rid = PCIR_BAR(0);
900Sstevel@tonic-gate 	sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
910Sstevel@tonic-gate					    &sc->io_rid, RF_ACTIVE);
920Sstevel@tonic-gate	if (!sc->io_res) {
930Sstevel@tonic-gate		device_printf(dev, "cannot allocate io ports!\n");
940Sstevel@tonic-gate		if (sc->slave_sc)
950Sstevel@tonic-gate			free(sc->slave_sc, M_DEVBUF);
960Sstevel@tonic-gate		return (ENOENT);
970Sstevel@tonic-gate	}
980Sstevel@tonic-gate
990Sstevel@tonic-gate	if (sc->slave_sc) {
1000Sstevel@tonic-gate		sc->slave_sc->io_res = sc->io_res;
101		sc->slave_sc->io_off = 4;
102	}
103	if (sbni_probe(sc) != 0) {
104		sbni_release_resources(sc);
105		if (sc->slave_sc)
106			free(sc->slave_sc, M_DEVBUF);
107		return (ENXIO);
108	}
109
110	return (0);
111}
112
113static int
114sbni_pci_attach(device_t dev)
115{
116	struct sbni_softc *sc;
117	struct sbni_flags flags;
118	int error;
119
120	sc = device_get_softc(dev);
121	sc->dev = dev;
122
123	sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
124					     RF_SHAREABLE);
125
126	if (sc->irq_res == NULL) {
127		device_printf(dev, "cannot claim irq!\n");
128		error = ENOENT;
129		goto attach_failed;
130	}
131
132	memset(&flags, 0, sizeof(flags));
133
134	error = sbni_attach(sc, device_get_unit(dev) * 2, flags);
135	if (error) {
136		device_printf(dev, "cannot initialize driver\n");
137		goto attach_failed;
138	}
139	if (sc->slave_sc) {
140		error = sbni_attach(sc->slave_sc, device_get_unit(dev) * 2 + 1,
141		    flags);
142		if (error) {
143			device_printf(dev, "cannot initialize slave\n");
144			sbni_detach(sc);
145			goto attach_failed;
146		}
147	}
148
149	if (sc->irq_res) {
150		error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET |
151		    INTR_MPSAFE, NULL, sbni_intr, sc, &sc->irq_handle);
152		if (error) {
153			device_printf(dev, "bus_setup_intr\n");
154			sbni_detach(sc);
155			if (sc->slave_sc)
156				sbni_detach(sc);
157			goto attach_failed;
158		}
159	}
160	return (0);
161
162attach_failed:
163	sbni_release_resources(sc);
164	if (sc->slave_sc)
165		free(sc->slave_sc, M_DEVBUF);
166	return (error);
167}
168
169static int
170sbni_pci_detach(device_t dev)
171{
172	struct sbni_softc *sc;
173
174	sc = device_get_softc(dev);
175	sbni_detach(sc);
176	if (sc->slave_sc)
177		sbni_detach(sc);
178
179	sbni_release_resources(sc);
180	if (sc->slave_sc)
181		free(sc->slave_sc, M_DEVBUF);
182	return (0);
183}
184