if_ndis_pccard.c revision 126706
1/*
2 * Copyright (c) 2003
3 *	Bill Paul <wpaul@windriver.com>.  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
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/if_ndis/if_ndis_pccard.c 126706 2004-03-07 02:49:06Z wpaul $");
35
36#include <sys/ctype.h>
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/sockio.h>
40#include <sys/mbuf.h>
41#include <sys/malloc.h>
42#include <sys/kernel.h>
43#include <sys/socket.h>
44#include <sys/queue.h>
45#include <sys/sysctl.h>
46
47#include <net/if.h>
48#include <net/if_arp.h>
49#include <net/ethernet.h>
50#include <net/if_dl.h>
51#include <net/if_media.h>
52
53#include <net/bpf.h>
54
55#include <machine/bus_memio.h>
56#include <machine/bus_pio.h>
57#include <machine/bus.h>
58#include <machine/resource.h>
59#include <sys/bus.h>
60#include <sys/rman.h>
61
62#include <net80211/ieee80211_var.h>
63#include <net80211/ieee80211_ioctl.h>
64
65#include <dev/wi/if_wavelan_ieee.h>
66
67#include <compat/ndis/pe_var.h>
68#include <compat/ndis/resource_var.h>
69#include <compat/ndis/ntoskrnl_var.h>
70#include <compat/ndis/ndis_var.h>
71#include <compat/ndis/cfg_var.h>
72#include <dev/if_ndis/if_ndisvar.h>
73
74#include <dev/pccard/pccardvar.h>
75#include "card_if.h"
76
77#include "ndis_driver_data.h"
78
79#ifdef NDIS_PCMCIA_DEV_TABLE
80
81MODULE_DEPEND(ndis, pccard, 1, 1, 1);
82MODULE_DEPEND(ndis, ether, 1, 1, 1);
83MODULE_DEPEND(ndis, wlan, 1, 1, 1);
84MODULE_DEPEND(ndis, ndisapi, 1, 1, 1);
85
86/*
87 * Various supported device vendors/types and their names.
88 * These are defined in the ndis_driver_data.h file.
89 */
90static struct ndis_pccard_type ndis_devs[] = {
91#ifdef NDIS_PCMCIA_DEV_TABLE
92	NDIS_PCMCIA_DEV_TABLE
93#endif
94	{ NULL, NULL, NULL }
95};
96
97static int ndis_probe_pccard	(device_t);
98static int ndis_attach_pccard	(device_t);
99extern int ndis_attach		(device_t);
100extern int ndis_shutdown	(device_t);
101extern int ndis_detach		(device_t);
102extern int ndis_suspend		(device_t);
103extern int ndis_resume		(device_t);
104
105static int my_strcasecmp	(const char *, const char *, int);
106
107extern struct mtx_pool *ndis_mtxpool;
108
109static device_method_t ndis_methods[] = {
110	/* Device interface */
111	DEVMETHOD(device_probe,		ndis_probe_pccard),
112	DEVMETHOD(device_attach,	ndis_attach_pccard),
113	DEVMETHOD(device_detach,	ndis_detach),
114	DEVMETHOD(device_shutdown,	ndis_shutdown),
115	DEVMETHOD(device_suspend,	ndis_suspend),
116	DEVMETHOD(device_resume,	ndis_resume),
117
118	{ 0, 0 }
119};
120
121static driver_t ndis_driver = {
122#ifdef NDIS_DEVNAME
123	NDIS_DEVNAME,
124#else
125	"ndis",
126#endif
127	ndis_methods,
128	sizeof(struct ndis_softc)
129};
130
131static devclass_t ndis_devclass;
132
133#ifdef NDIS_MODNAME
134#define NDIS_MODNAME_OVERRIDE_PCMCIA(x)					\
135	DRIVER_MODULE(x, pccard, ndis_driver, ndis_devclass, 0, 0)
136NDIS_MODNAME_OVERRIDE_PCMCIA(NDIS_MODNAME);
137#else
138DRIVER_MODULE(ndis, pccard, ndis_driver, ndis_devclass, 0, 0);
139#endif
140
141static int my_strcasecmp(s1, s2, len)
142	const char		*s1;
143	const char		*s2;
144	int			len;
145{
146	int			i;
147
148	for (i = 0; i < len; i++) {
149		if (toupper(s1[i]) != toupper(s2[i]))
150			return(0);
151	}
152
153	return(1);
154}
155
156
157/*
158 * Probe for an NDIS device. Check the PCI vendor and device
159 * IDs against our list and return a device name if we find a match.
160 */
161static int
162ndis_probe_pccard(dev)
163	device_t		dev;
164{
165	struct ndis_pccard_type	*t;
166	const char		*prodstr, *vendstr;
167	int			error;
168
169	t = ndis_devs;
170
171	error = pccard_get_product_str(dev, &prodstr);
172	if (error)
173		return(error);
174	error = pccard_get_vendor_str(dev, &vendstr);
175	if (error)
176		return(error);
177
178	while(t->ndis_name != NULL) {
179		if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) &&
180		    my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr))) {
181			device_set_desc(dev, t->ndis_name);
182			return(0);
183		}
184		t++;
185	}
186
187	return(ENXIO);
188}
189
190/*
191 * Attach the interface. Allocate softc structures, do ifmedia
192 * setup and ethernet/BPF attach.
193 */
194static int
195ndis_attach_pccard(dev)
196	device_t		dev;
197{
198	struct ndis_softc	*sc;
199	int			unit, error = 0, rid;
200	struct ndis_pccard_type	*t;
201	int			devidx = 0;
202	const char		*prodstr, *vendstr;
203	struct resource_list	*rl;
204	struct resource_list_entry	*rle;
205
206	sc = device_get_softc(dev);
207	unit = device_get_unit(dev);
208	sc->ndis_dev = dev;
209
210	sc->ndis_io_rid = 0;
211	sc->ndis_res_io = bus_alloc_resource(dev,
212	    SYS_RES_IOPORT, &sc->ndis_io_rid,
213	    0, ~0, 1, RF_ACTIVE);
214	if (sc->ndis_res_io == NULL) {
215		device_printf(dev,
216		    "couldn't map iospace\n");
217		error = ENXIO;
218		goto fail;
219	}
220	sc->ndis_rescnt++;
221
222	rid = 0;
223	sc->ndis_irq = bus_alloc_resource(dev,
224	    SYS_RES_IRQ, &rid, 0, ~0, 1,
225	    RF_SHAREABLE | RF_ACTIVE);
226	if (sc->ndis_irq == NULL) {
227		device_printf(dev,
228		    "couldn't map interrupt\n");
229		error = ENXIO;
230		goto fail;
231	}
232	sc->ndis_rescnt++;
233
234	sc->ndis_iftype = PCMCIABus;
235
236	/* Figure out exactly which device we matched. */
237
238	t = ndis_devs;
239
240	error = pccard_get_product_str(dev, &prodstr);
241	if (error)
242		return(error);
243	error = pccard_get_vendor_str(dev, &vendstr);
244	if (error)
245		return(error);
246
247	while(t->ndis_name != NULL) {
248		if (my_strcasecmp(vendstr, t->ndis_vid, strlen(vendstr)) &&
249		    my_strcasecmp(prodstr, t->ndis_did, strlen(prodstr)))
250			break;
251		t++;
252		devidx++;
253	}
254
255	sc->ndis_devidx = devidx;
256
257	error = ndis_attach(dev);
258
259fail:
260	return(error);
261}
262
263#endif /* NDIS_PCI_DEV_TABLE */
264
265#define NDIS_AM_RID 3
266
267int
268ndis_alloc_amem(arg)
269	void			*arg;
270{
271	struct ndis_softc	*sc;
272	int			error, rid;
273
274	if (arg == NULL)
275		return(EINVAL);
276
277	sc = arg;
278	rid = NDIS_AM_RID;
279	sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
280	    &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
281
282	if (sc->ndis_res_am == NULL) {
283		device_printf(sc->ndis_dev,
284		    "failed to allocate attribute memory\n");
285		return(ENXIO);
286	}
287
288	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
289	    sc->ndis_dev, rid, 0, NULL);
290
291	if (error) {
292		device_printf(sc->ndis_dev,
293		    "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error);
294		return(error);
295	}
296
297	error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
298	    sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
299
300	if (error) {
301		device_printf(sc->ndis_dev,
302		    "CARD_SET_RES_FLAGS() returned 0x%x\n", error);
303		return(error);
304	}
305
306	return(0);
307}
308