Deleted Added
sdiff udiff text old ( 129972 ) new ( 131953 )
full compact
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_pci.c 129972 2004-06-01 23:27:36Z wpaul $");
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/kernel.h>
39#include <sys/module.h>
40#include <sys/socket.h>
41#include <sys/queue.h>
42#include <sys/sysctl.h>
43
44#include <net/if.h>
45#include <net/if_arp.h>
46#include <net/if_media.h>
47
48#include <machine/bus.h>
49#include <machine/resource.h>
50#include <sys/bus.h>
51#include <sys/rman.h>
52
53#include <net80211/ieee80211_var.h>
54
55#include <dev/pci/pcireg.h>
56#include <dev/pci/pcivar.h>
57
58#include <compat/ndis/pe_var.h>
59#include <compat/ndis/resource_var.h>
60#include <compat/ndis/ntoskrnl_var.h>
61#include <compat/ndis/ndis_var.h>
62#include <compat/ndis/cfg_var.h>
63#include <dev/if_ndis/if_ndisvar.h>
64
65#include "ndis_driver_data.h"
66
67#ifdef NDIS_PCI_DEV_TABLE
68
69MODULE_DEPEND(ndis, pci, 1, 1, 1);
70MODULE_DEPEND(ndis, ether, 1, 1, 1);
71MODULE_DEPEND(ndis, wlan, 1, 1, 1);
72MODULE_DEPEND(ndis, ndisapi, 1, 1, 1);
73
74/*
75 * Various supported device vendors/types and their names.
76 * These are defined in the ndis_driver_data.h file.
77 */
78static struct ndis_pci_type ndis_devs[] = {
79#ifdef NDIS_PCI_DEV_TABLE
80 NDIS_PCI_DEV_TABLE
81#endif
82 { 0, 0, 0, NULL }
83};
84
85static int ndis_probe_pci (device_t);
86static int ndis_attach_pci (device_t);
87extern int ndis_attach (device_t);
88extern int ndis_shutdown (device_t);
89extern int ndis_detach (device_t);
90extern int ndis_suspend (device_t);
91extern int ndis_resume (device_t);
92
93extern struct mtx_pool *ndis_mtxpool;
94
95static device_method_t ndis_methods[] = {
96 /* Device interface */
97 DEVMETHOD(device_probe, ndis_probe_pci),
98 DEVMETHOD(device_attach, ndis_attach_pci),
99 DEVMETHOD(device_detach, ndis_detach),
100 DEVMETHOD(device_shutdown, ndis_shutdown),
101 DEVMETHOD(device_suspend, ndis_suspend),
102 DEVMETHOD(device_resume, ndis_resume),
103
104 { 0, 0 }
105};
106
107static driver_t ndis_driver = {
108#ifdef NDIS_DEVNAME
109 NDIS_DEVNAME,
110#else
111 "ndis",
112#endif
113 ndis_methods,
114 sizeof(struct ndis_softc)
115};
116
117static devclass_t ndis_devclass;
118
119#ifdef NDIS_MODNAME
120#define NDIS_MODNAME_OVERRIDE_PCI(x) \
121 DRIVER_MODULE(x, pci, ndis_driver, ndis_devclass, 0, 0)
122#define NDIS_MODNAME_OVERRIDE_CARDBUS(x) \
123 DRIVER_MODULE(x, cardbus, ndis_driver, ndis_devclass, 0, 0)
124NDIS_MODNAME_OVERRIDE_PCI(NDIS_MODNAME);
125NDIS_MODNAME_OVERRIDE_CARDBUS(NDIS_MODNAME);
126#else
127DRIVER_MODULE(ndis, pci, ndis_driver, ndis_devclass, 0, 0);
128DRIVER_MODULE(ndis, cardbus, ndis_driver, ndis_devclass, 0, 0);
129#endif
130
131/*
132 * Probe for an NDIS device. Check the PCI vendor and device
133 * IDs against our list and return a device name if we find a match.
134 */
135static int
136ndis_probe_pci(dev)
137 device_t dev;
138{
139 struct ndis_pci_type *t;
140
141 t = ndis_devs;
142
143 while(t->ndis_name != NULL) {
144 if ((pci_get_vendor(dev) == t->ndis_vid) &&
145 (pci_get_device(dev) == t->ndis_did) &&
146 ((pci_read_config(dev, PCIR_SUBVEND_0, 4) ==
147 t->ndis_subsys) || t->ndis_subsys == 0)) {
148 device_set_desc(dev, t->ndis_name);
149 return(0);
150 }
151 t++;
152 }
153
154 return(ENXIO);
155}
156
157/*
158 * Attach the interface. Allocate softc structures, do ifmedia
159 * setup and ethernet/BPF attach.
160 */
161static int
162ndis_attach_pci(dev)
163 device_t dev;
164{
165 struct ndis_softc *sc;
166 int unit, error = 0, rid;
167 struct ndis_pci_type *t;
168 int devidx = 0, defidx = 0;
169 struct resource_list *rl;
170 struct resource_list_entry *rle;
171
172 sc = device_get_softc(dev);
173 unit = device_get_unit(dev);
174 sc->ndis_dev = dev;
175
176 /*
177 * Map control/status registers.
178 */
179
180 pci_enable_busmaster(dev);
181
182 rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
183 if (rl != NULL) {
184 SLIST_FOREACH(rle, rl, link) {
185 switch (rle->type) {
186 case SYS_RES_IOPORT:
187 sc->ndis_io_rid = rle->rid;
188 sc->ndis_res_io = bus_alloc_resource(dev,
189 SYS_RES_IOPORT, &sc->ndis_io_rid,
190 0, ~0, 1, RF_ACTIVE);
191 if (sc->ndis_res_io == NULL) {
192 device_printf(dev,
193 "couldn't map iospace\n");
194 error = ENXIO;
195 goto fail;
196 }
197 break;
198 case SYS_RES_MEMORY:
199 if (sc->ndis_res_altmem != NULL &&
200 sc->ndis_res_mem != NULL) {
201 device_printf(dev,
202 "too many memory resources\n");
203 error = ENXIO;
204 goto fail;
205 }
206 if (rle->rid == PCIR_BAR(2)) {
207 sc->ndis_altmem_rid = rle->rid;
208 sc->ndis_res_altmem =
209 bus_alloc_resource(dev,
210 SYS_RES_MEMORY,
211 &sc->ndis_altmem_rid,
212 0, ~0, 1, RF_ACTIVE);
213 if (sc->ndis_res_altmem == NULL) {
214 device_printf(dev,
215 "couldn't map alt "
216 "memory\n");
217 error = ENXIO;
218 goto fail;
219 }
220 } else {
221 sc->ndis_mem_rid = rle->rid;
222 sc->ndis_res_mem =
223 bus_alloc_resource(dev,
224 SYS_RES_MEMORY,
225 &sc->ndis_mem_rid,
226 0, ~0, 1, RF_ACTIVE);
227 if (sc->ndis_res_mem == NULL) {
228 device_printf(dev,
229 "couldn't map memory\n");
230 error = ENXIO;
231 goto fail;
232 }
233 }
234 break;
235 case SYS_RES_IRQ:
236 rid = rle->rid;
237 sc->ndis_irq = bus_alloc_resource(dev,
238 SYS_RES_IRQ, &rid, 0, ~0, 1,
239 RF_SHAREABLE | RF_ACTIVE);
240 if (sc->ndis_irq == NULL) {
241 device_printf(dev,
242 "couldn't map interrupt\n");
243 error = ENXIO;
244 goto fail;
245 }
246 break;
247 default:
248 break;
249 }
250 sc->ndis_rescnt++;
251 }
252 }
253
254 /*
255 * If the BIOS did not set up an interrupt for this device,
256 * the resource traversal code above will fail to set up
257 * an IRQ resource. This is usually a bad thing, so try to
258 * force the allocation of an interrupt here. If one was
259 * not assigned to us by the BIOS, bus_alloc_resource()
260 * should route one for us.
261 */
262 if (sc->ndis_irq == NULL) {
263 rid = 0;
264 sc->ndis_irq = bus_alloc_resource(dev, SYS_RES_IRQ,
265 &rid, 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
266 if (sc->ndis_irq == NULL) {
267 device_printf(dev, "couldn't route interrupt\n");
268 error = ENXIO;
269 goto fail;
270 }
271 sc->ndis_rescnt++;
272 }
273
274 /*
275 * Allocate the parent bus DMA tag appropriate for PCI.
276 */
277#define NDIS_NSEG_NEW 32
278 error = bus_dma_tag_create(NULL, /* parent */
279 1, 0, /* alignment, boundary */
280 BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
281 BUS_SPACE_MAXADDR, /* highaddr */
282 NULL, NULL, /* filter, filterarg */
283 MAXBSIZE, NDIS_NSEG_NEW,/* maxsize, nsegments */
284 BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
285 BUS_DMA_ALLOCNOW, /* flags */
286 NULL, NULL, /* lockfunc, lockarg */
287 &sc->ndis_parent_tag);
288
289 if (error)
290 goto fail;
291
292 sc->ndis_iftype = PCIBus;
293
294 /* Figure out exactly which device we matched. */
295
296 t = ndis_devs;
297
298 while(t->ndis_name != NULL) {
299 if ((pci_get_vendor(dev) == t->ndis_vid) &&
300 (pci_get_device(dev) == t->ndis_did)) {
301 if (t->ndis_subsys == 0)
302 defidx = devidx;
303 else {
304 if (t->ndis_subsys ==
305 pci_read_config(dev, PCIR_SUBVEND_0, 4))
306 break;
307 }
308 }
309 t++;
310 devidx++;
311 }
312
313 if (ndis_devs[devidx].ndis_name == NULL)
314 sc->ndis_devidx = defidx;
315 else
316 sc->ndis_devidx = devidx;
317
318 error = ndis_attach(dev);
319
320fail:
321 return(error);
322}
323
324#endif /* NDIS_PCI_DEV_TABLE */