if_ndis_pccard.c revision 129972
1121986Sjhb/*
2121986Sjhb * Copyright (c) 2003
3121986Sjhb *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4121986Sjhb *
5121986Sjhb * Redistribution and use in source and binary forms, with or without
6121986Sjhb * modification, are permitted provided that the following conditions
7121986Sjhb * are met:
8121986Sjhb * 1. Redistributions of source code must retain the above copyright
9121986Sjhb *    notice, this list of conditions and the following disclaimer.
10121986Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11121986Sjhb *    notice, this list of conditions and the following disclaimer in the
12121986Sjhb *    documentation and/or other materials provided with the distribution.
13121986Sjhb * 3. All advertising materials mentioning features or use of this software
14121986Sjhb *    must display the following acknowledgement:
15121986Sjhb *	This product includes software developed by Bill Paul.
16121986Sjhb * 4. Neither the name of the author nor the names of any co-contributors
17121986Sjhb *    may be used to endorse or promote products derived from this software
18121986Sjhb *    without specific prior written permission.
19121986Sjhb *
20121986Sjhb * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21121986Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22121986Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23121986Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24121986Sjhb * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25121986Sjhb * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26121986Sjhb * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27121986Sjhb * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28121986Sjhb * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29121986Sjhb * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30121986Sjhb * THE POSSIBILITY OF SUCH DAMAGE.
31121986Sjhb */
32121986Sjhb
33121986Sjhb#include <sys/cdefs.h>
34121986Sjhb__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_pccard.c 129972 2004-06-01 23:27:36Z wpaul $");
35121986Sjhb
36167240Sjhb#include <sys/ctype.h>
37121986Sjhb#include <sys/param.h>
38167240Sjhb#include <sys/systm.h>
39121986Sjhb#include <sys/kernel.h>
40148538Sjhb#include <sys/module.h>
41121986Sjhb#include <sys/socket.h>
42167240Sjhb#include <sys/queue.h>
43167240Sjhb#include <sys/sysctl.h>
44167240Sjhb
45121986Sjhb#include <net/if.h>
46121986Sjhb#include <net/if_arp.h>
47121986Sjhb#include <net/if_media.h>
48214631Sjhb
49121986Sjhb#include <machine/bus.h>
50121986Sjhb#include <machine/resource.h>
51121986Sjhb#include <sys/bus.h>
52167747Sjhb#include <sys/rman.h>
53121986Sjhb
54121986Sjhb#include <net80211/ieee80211_var.h>
55121986Sjhb
56121986Sjhb#include <compat/ndis/pe_var.h>
57121986Sjhb#include <compat/ndis/resource_var.h>
58121986Sjhb#include <compat/ndis/ntoskrnl_var.h>
59121986Sjhb#include <compat/ndis/ndis_var.h>
60151979Sjhb#include <compat/ndis/cfg_var.h>
61151979Sjhb#include <dev/if_ndis/if_ndisvar.h>
62151979Sjhb
63151979Sjhb#include <dev/pccard/pccardvar.h>
64121986Sjhb#include "card_if.h"
65151897Srwatson
66121986Sjhb#include "ndis_driver_data.h"
67121986Sjhb
68151979Sjhb#ifdef NDIS_PCMCIA_DEV_TABLE
69151979Sjhb
70151979SjhbMODULE_DEPEND(ndis, pccard, 1, 1, 1);
71151979SjhbMODULE_DEPEND(ndis, ether, 1, 1, 1);
72151979SjhbMODULE_DEPEND(ndis, wlan, 1, 1, 1);
73151979SjhbMODULE_DEPEND(ndis, ndisapi, 1, 1, 1);
74151979Sjhb
75152461Sandre/*
76152461Sandre * Various supported device vendors/types and their names.
77152461Sandre * These are defined in the ndis_driver_data.h file.
78152461Sandre */
79121986Sjhbstatic struct ndis_pccard_type ndis_devs[] = {
80121986Sjhb#ifdef NDIS_PCMCIA_DEV_TABLE
81121986Sjhb	NDIS_PCMCIA_DEV_TABLE
82121986Sjhb#endif
83151979Sjhb	{ NULL, NULL, NULL }
84122124Sjhb};
85122124Sjhb
86156124Sjhbstatic int ndis_probe_pccard	(device_t);
87122124Sjhbstatic int ndis_attach_pccard	(device_t);
88122124Sjhbextern int ndis_attach		(device_t);
89122124Sjhbextern int ndis_shutdown	(device_t);
90130980Sjhbextern int ndis_detach		(device_t);
91157541Sjhbextern int ndis_suspend		(device_t);
92121986Sjhbextern int ndis_resume		(device_t);
93121986Sjhb
94121986Sjhbstatic int my_strcasecmp	(const char *, const char *, int);
95121986Sjhb
96121986Sjhbextern struct mtx_pool *ndis_mtxpool;
97121986Sjhb
98121986Sjhbstatic device_method_t ndis_methods[] = {
99121986Sjhb	/* Device interface */
100121986Sjhb	DEVMETHOD(device_probe,		ndis_probe_pccard),
101167747Sjhb	DEVMETHOD(device_attach,	ndis_attach_pccard),
102121986Sjhb	DEVMETHOD(device_detach,	ndis_detach),
103121986Sjhb	DEVMETHOD(device_shutdown,	ndis_shutdown),
104121986Sjhb	DEVMETHOD(device_suspend,	ndis_suspend),
105121986Sjhb	DEVMETHOD(device_resume,	ndis_resume),
106121986Sjhb
107121986Sjhb	{ 0, 0 }
108130980Sjhb};
109151979Sjhb
110121986Sjhbstatic driver_t ndis_driver = {
111133017Sscottl#ifdef NDIS_DEVNAME
112121986Sjhb	NDIS_DEVNAME,
113121986Sjhb#else
114169391Sjhb	"ndis",
115121986Sjhb#endif
116121986Sjhb	ndis_methods,
117128931Sjhb	sizeof(struct ndis_softc)
118128931Sjhb};
119163219Sjhb
120195249Sjhbstatic devclass_t ndis_devclass;
121129964Sjhb
122121986Sjhb#ifdef NDIS_MODNAME
123129097Sjhb#define NDIS_MODNAME_OVERRIDE_PCMCIA(x)					\
124121986Sjhb	DRIVER_MODULE(x, pccard, ndis_driver, ndis_devclass, 0, 0)
125121986SjhbNDIS_MODNAME_OVERRIDE_PCMCIA(NDIS_MODNAME);
126169391Sjhb#else
127169391SjhbDRIVER_MODULE(ndis, pccard, ndis_driver, ndis_devclass, 0, 0);
128156124Sjhb#endif
129121986Sjhb
130156124Sjhbstatic int my_strcasecmp(s1, s2, len)
131156124Sjhb	const char		*s1;
132156124Sjhb	const char		*s2;
133248085Smarius	int			len;
134148538Sjhb{
135148538Sjhb	int			i;
136148538Sjhb
137148538Sjhb	for (i = 0; i < len; i++) {
138148538Sjhb		if (toupper(s1[i]) != toupper(s2[i]))
139133017Sscottl			return(0);
140133017Sscottl	}
141133017Sscottl
142133017Sscottl	return(1);
143133017Sscottl}
144133017Sscottl
145121986Sjhb
146121986Sjhb/*
147121986Sjhb * Probe for an NDIS device. Check the PCI vendor and device
148121986Sjhb * IDs against our list and return a device name if we find a match.
149121986Sjhb */
150121986Sjhbstatic int
151121986Sjhbndis_probe_pccard(dev)
152121986Sjhb	device_t		dev;
153121986Sjhb{
154121986Sjhb	struct ndis_pccard_type	*t;
155121986Sjhb	const char		*prodstr, *vendstr;
156121986Sjhb	int			error;
157121986Sjhb
158121986Sjhb	t = ndis_devs;
159121986Sjhb
160121986Sjhb	error = pccard_get_product_str(dev, &prodstr);
161121986Sjhb	if (error)
162121986Sjhb		return(error);
163130980Sjhb	error = pccard_get_vendor_str(dev, &vendstr);
164130980Sjhb	if (error)
165130980Sjhb		return(error);
166130980Sjhb
167130980Sjhb	while(t->ndis_name != NULL) {
168130980Sjhb		if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) &&
169130980Sjhb		    my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr))) {
170130980Sjhb			device_set_desc(dev, t->ndis_name);
171130980Sjhb			return(0);
172130980Sjhb		}
173130980Sjhb		t++;
174130980Sjhb	}
175130980Sjhb
176130980Sjhb	return(ENXIO);
177130980Sjhb}
178130980Sjhb
179121986Sjhb/*
180151979Sjhb * Attach the interface. Allocate softc structures, do ifmedia
181130980Sjhb * setup and ethernet/BPF attach.
182130980Sjhb */
183151979Sjhbstatic int
184151979Sjhbndis_attach_pccard(dev)
185130980Sjhb	device_t		dev;
186130980Sjhb{
187151979Sjhb	struct ndis_softc	*sc;
188130980Sjhb	int			unit, error = 0, rid;
189130980Sjhb	struct ndis_pccard_type	*t;
190151979Sjhb	int			devidx = 0;
191130980Sjhb	const char		*prodstr, *vendstr;
192130980Sjhb
193151979Sjhb	sc = device_get_softc(dev);
194130980Sjhb	unit = device_get_unit(dev);
195130980Sjhb	sc->ndis_dev = dev;
196130980Sjhb
197130980Sjhb	sc->ndis_io_rid = 0;
198151979Sjhb	sc->ndis_res_io = bus_alloc_resource(dev,
199130980Sjhb	    SYS_RES_IOPORT, &sc->ndis_io_rid,
200130980Sjhb	    0, ~0, 1, RF_ACTIVE);
201130980Sjhb	if (sc->ndis_res_io == NULL) {
202130980Sjhb		device_printf(dev,
203121986Sjhb		    "couldn't map iospace\n");
204121986Sjhb		error = ENXIO;
205121986Sjhb		goto fail;
206121986Sjhb	}
207121986Sjhb	sc->ndis_rescnt++;
208121986Sjhb
209121986Sjhb	rid = 0;
210121986Sjhb	sc->ndis_irq = bus_alloc_resource(dev,
211157541Sjhb	    SYS_RES_IRQ, &rid, 0, ~0, 1,
212121986Sjhb	    RF_SHAREABLE | RF_ACTIVE);
213121986Sjhb	if (sc->ndis_irq == NULL) {
214121986Sjhb		device_printf(dev,
215121986Sjhb		    "couldn't map interrupt\n");
216121986Sjhb		error = ENXIO;
217121986Sjhb		goto fail;
218121986Sjhb	}
219121986Sjhb	sc->ndis_rescnt++;
220133017Sscottl
221121986Sjhb	sc->ndis_iftype = PCMCIABus;
222121986Sjhb
223121986Sjhb	/* Figure out exactly which device we matched. */
224121986Sjhb
225121986Sjhb	t = ndis_devs;
226121986Sjhb
227121986Sjhb	error = pccard_get_product_str(dev, &prodstr);
228157541Sjhb	if (error)
229121986Sjhb		return(error);
230121986Sjhb	error = pccard_get_vendor_str(dev, &vendstr);
231121986Sjhb	if (error)
232121986Sjhb		return(error);
233133017Sscottl
234133017Sscottl	while(t->ndis_name != NULL) {
235133017Sscottl		if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) &&
236133017Sscottl		    my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr)))
237121986Sjhb			break;
238121986Sjhb		t++;
239121986Sjhb		devidx++;
240121986Sjhb	}
241121986Sjhb
242121986Sjhb	sc->ndis_devidx = devidx;
243122148Sjhb
244133017Sscottl	error = ndis_attach(dev);
245121986Sjhb
246121986Sjhbfail:
247121986Sjhb	return(error);
248129964Sjhb}
249129964Sjhb
250129964Sjhb#endif /* NDIS_PCI_DEV_TABLE */
251129964Sjhb
252129964Sjhb#define NDIS_AM_RID 3
253129964Sjhb
254129964Sjhbint
255129964Sjhbndis_alloc_amem(arg)
256129964Sjhb	void			*arg;
257151979Sjhb{
258151979Sjhb	struct ndis_softc	*sc;
259151979Sjhb	int			error, rid;
260151979Sjhb
261208915Sjhb	if (arg == NULL)
262151979Sjhb		return(EINVAL);
263151979Sjhb
264129964Sjhb	sc = arg;
265129964Sjhb	rid = NDIS_AM_RID;
266129964Sjhb	sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
267129964Sjhb	    &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
268129964Sjhb
269129964Sjhb	if (sc->ndis_res_am == NULL) {
270129964Sjhb		device_printf(sc->ndis_dev,
271129964Sjhb		    "failed to allocate attribute memory\n");
272129964Sjhb		return(ENXIO);
273129964Sjhb	}
274156124Sjhb
275156124Sjhb	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
276129964Sjhb	    sc->ndis_dev, rid, 0, NULL);
277129964Sjhb
278129964Sjhb	if (error) {
279129964Sjhb		device_printf(sc->ndis_dev,
280129964Sjhb		    "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error);
281129964Sjhb		return(error);
282129964Sjhb	}
283129964Sjhb
284129964Sjhb	error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
285129964Sjhb	    sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
286129964Sjhb
287129964Sjhb	if (error) {
288151979Sjhb		device_printf(sc->ndis_dev,
289151979Sjhb		    "CARD_SET_RES_FLAGS() returned 0x%x\n", error);
290129964Sjhb		return(error);
291148538Sjhb	}
292129964Sjhb
293129964Sjhb	return(0);
294151979Sjhb}
295129964Sjhb