if_wi_pci.c revision 119287
1/*
2 * Copyright (c) 1997, 1998, 1999
3 *	Bill Paul <wpaul@ctr.columbia.edu>.  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, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * $FreeBSD: head/sys/dev/wi/if_wi_pci.c 119287 2003-08-22 07:08:17Z imp $
33 */
34
35/*
36 * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for FreeBSD.
37 *
38 * Written by Bill Paul <wpaul@ctr.columbia.edu>
39 * Electrical Engineering Department
40 * Columbia University, New York City
41 */
42
43#include <sys/param.h>
44#include <sys/kernel.h>
45#include <sys/socket.h>
46#include <sys/systm.h>
47#include <sys/module.h>
48#include <sys/bus.h>
49
50#include <machine/bus.h>
51#include <machine/resource.h>
52#include <machine/clock.h>
53#include <sys/rman.h>
54
55#include <dev/pci/pcireg.h>
56#include <dev/pci/pcivar.h>
57
58#include <net/if.h>
59#include <net/if_arp.h>
60#include <net/ethernet.h>
61#include <net/if_media.h>
62#include <net/if_types.h>
63
64#include <net80211/ieee80211_var.h>
65
66#include <dev/wi/if_wavelan_ieee.h>
67#include <dev/wi/if_wivar.h>
68#include <dev/wi/if_wireg.h>
69
70static int wi_pci_probe(device_t);
71static int wi_pci_attach(device_t);
72static int wi_pci_suspend(device_t);
73static int wi_pci_resume(device_t);
74
75static device_method_t wi_pci_methods[] = {
76	/* Device interface */
77	DEVMETHOD(device_probe,		wi_pci_probe),
78	DEVMETHOD(device_attach,	wi_pci_attach),
79	DEVMETHOD(device_detach,	wi_detach),
80	DEVMETHOD(device_shutdown,	wi_shutdown),
81	DEVMETHOD(device_suspend,	wi_pci_suspend),
82	DEVMETHOD(device_resume,	wi_pci_resume),
83
84	{ 0, 0 }
85};
86
87static driver_t wi_pci_driver = {
88	"wi",
89	wi_pci_methods,
90	sizeof(struct wi_softc)
91};
92
93static struct {
94	unsigned int vendor,device;
95	int bus_type;
96	char *desc;
97} pci_ids[] = {
98	/* Sorted by description */
99	{0x10b7, 0x7770, WI_BUS_PCI_PLX, "3Com Airconnect"},
100	{0x16ab, 0x1101, WI_BUS_PCI_PLX, "GLPRISM2 WaveLAN"},
101	{0x1260, 0x3872, WI_BUS_PCI_NATIVE, "Intersil Prism3"},
102	{0x1260, 0x3873, WI_BUS_PCI_NATIVE, "Intersil Prism2.5"},
103	{0x16ab, 0x1102, WI_BUS_PCI_PLX, "Linksys WDT11"},
104	{0x1385, 0x4100, WI_BUS_PCI_PLX, "Netgear MA301"},
105	{0x1638, 0x1100, WI_BUS_PCI_PLX, "PRISM2STA WaveLAN"},
106	{0x111a, 0x1023, WI_BUS_PCI_PLX, "Siemens SpeedStream"},
107	{0x10b5, 0x9050, WI_BUS_PCI_PLX, "SMC 2602W"},
108	{0x16ec, 0x3685, WI_BUS_PCI_PLX, "US Robotics 2415"},
109	{0x4033, 0x7001, WI_BUS_PCI_PLX, "Addtron AWA-100 PCI"},
110	{0, 0, 0, NULL}
111};
112
113DRIVER_MODULE(wi, pci, wi_pci_driver, wi_devclass, 0, 0);
114MODULE_DEPEND(wi, pci, 1, 1, 1);
115MODULE_DEPEND(wi, wlan, 1, 1, 1);
116
117static int
118wi_pci_probe(dev)
119	device_t	dev;
120{
121	struct wi_softc		*sc;
122	int i;
123
124	sc = device_get_softc(dev);
125	for(i=0; pci_ids[i].vendor != 0; i++) {
126		if ((pci_get_vendor(dev) == pci_ids[i].vendor) &&
127			(pci_get_device(dev) == pci_ids[i].device)) {
128			sc->wi_bus_type = pci_ids[i].bus_type;
129			device_set_desc(dev, pci_ids[i].desc);
130			return (0);
131		}
132	}
133	return(ENXIO);
134}
135
136static int
137wi_pci_attach(device_t dev)
138{
139	struct wi_softc		*sc;
140	u_int32_t		command, wanted;
141	u_int16_t		reg;
142	int			error;
143	int			timeout;
144
145	sc = device_get_softc(dev);
146
147	command = pci_read_config(dev, PCIR_COMMAND, 4);
148	wanted = PCIM_CMD_PORTEN|PCIM_CMD_MEMEN;
149	command |= wanted;
150	pci_write_config(dev, PCIR_COMMAND, command, 4);
151	command = pci_read_config(dev, PCIR_COMMAND, 4);
152	if ((command & wanted) != wanted) {
153		device_printf(dev, "wi_pci_attach() failed to enable pci!\n");
154		return (ENXIO);
155	}
156
157	if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) {
158		error = wi_alloc(dev, WI_PCI_IORES);
159		if (error)
160			return (error);
161
162		/* Make sure interrupts are disabled. */
163		CSR_WRITE_2(sc, WI_INT_EN, 0);
164		CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF);
165
166		/* We have to do a magic PLX poke to enable interrupts */
167		sc->local_rid = WI_PCI_LOCALRES;
168		sc->local = bus_alloc_resource(dev, SYS_RES_IOPORT,
169		    &sc->local_rid, 0, ~0, 1, RF_ACTIVE);
170		sc->wi_localtag = rman_get_bustag(sc->local);
171		sc->wi_localhandle = rman_get_bushandle(sc->local);
172		command = bus_space_read_4(sc->wi_localtag, sc->wi_localhandle,
173		    WI_LOCAL_INTCSR);
174		command |= WI_LOCAL_INTEN;
175		bus_space_write_4(sc->wi_localtag, sc->wi_localhandle,
176		    WI_LOCAL_INTCSR, command);
177		bus_release_resource(dev, SYS_RES_IOPORT, sc->local_rid,
178		    sc->local);
179		sc->local = NULL;
180
181		sc->mem_rid = WI_PCI_MEMRES;
182		sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->mem_rid,
183					0, ~0, 1, RF_ACTIVE);
184		if (sc->mem == NULL) {
185			device_printf(dev, "couldn't allocate memory\n");
186			wi_free(dev);
187			return (ENXIO);
188		}
189		sc->wi_bmemtag = rman_get_bustag(sc->mem);
190		sc->wi_bmemhandle = rman_get_bushandle(sc->mem);
191
192		/*
193		 * From Linux driver:
194		 * Write COR to enable PC card
195		 * This is a subset of the protocol that the pccard bus code
196		 * would do.
197		 */
198		CSM_WRITE_1(sc, WI_COR_OFFSET, WI_COR_VALUE);
199		reg = CSM_READ_1(sc, WI_COR_OFFSET);
200		if (reg != WI_COR_VALUE) {
201			device_printf(dev, "CSM_READ_1(WI_COR_OFFSET) "
202			    "wanted %d, got %d\n", WI_COR_VALUE, reg);
203			wi_free(dev);
204			return (ENXIO);
205		}
206	} else {
207		error = wi_alloc(dev, WI_PCI_LMEMRES);
208		if (error)
209			return (error);
210
211		CSR_WRITE_2(sc, WI_HFA384X_PCICOR_OFF, 0x0080);
212		DELAY(250000);
213
214		CSR_WRITE_2(sc, WI_HFA384X_PCICOR_OFF, 0x0000);
215		DELAY(500000);
216
217		timeout=2000000;
218		while ((--timeout > 0) &&
219		    (CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY))
220			DELAY(10);
221
222		if (timeout == 0) {
223			device_printf(dev, "couldn't reset prism2.5 core.\n");
224			wi_free(dev);
225			return(ENXIO);
226		}
227	}
228
229	CSR_WRITE_2(sc, WI_HFA384X_SWSUPPORT0_OFF, WI_PRISM2STA_MAGIC);
230	reg = CSR_READ_2(sc, WI_HFA384X_SWSUPPORT0_OFF);
231	if (reg != WI_PRISM2STA_MAGIC) {
232		device_printf(dev,
233		    "CSR_READ_2(WI_HFA384X_SWSUPPORT0_OFF) "
234		    "wanted %d, got %d\n", WI_PRISM2STA_MAGIC, reg);
235		wi_free(dev);
236		return (ENXIO);
237	}
238
239	error = wi_attach(dev);
240	if (error != 0)
241		wi_free(dev);
242	return (error);
243}
244
245static int
246wi_pci_suspend(device_t dev)
247{
248	struct wi_softc		*sc;
249	struct ifnet *ifp;
250	sc = device_get_softc(dev);
251	ifp = &sc->sc_if;
252
253	wi_stop(ifp, 1);
254
255	return (0);
256}
257
258static int
259wi_pci_resume(device_t dev)
260{
261	struct wi_softc *sc;
262	struct ifnet *ifp;
263	sc = device_get_softc(dev);
264	ifp = &sc->sc_if;
265
266	if (sc->wi_bus_type != WI_BUS_PCI_NATIVE)
267		return (0);
268
269	if (ifp->if_flags & IFF_UP) {
270		ifp->if_init(ifp->if_softc);
271		if (ifp->if_flags & IFF_RUNNING)
272			ifp->if_start(ifp);
273	}
274
275	return (0);
276}
277