]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/compat/ndis/kern_ndis.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / compat / ndis / kern_ndis.c
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$");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/unistd.h>
39 #include <sys/types.h>
40 #include <sys/errno.h>
41 #include <sys/callout.h>
42 #include <sys/socket.h>
43 #include <sys/queue.h>
44 #include <sys/sysctl.h>
45 #include <sys/proc.h>
46 #include <sys/malloc.h>
47 #include <sys/lock.h>
48 #include <sys/mutex.h>
49 #include <sys/conf.h>
50
51 #include <sys/kernel.h>
52 #include <sys/module.h>
53 #include <sys/kthread.h>
54 #include <machine/bus.h>
55 #include <machine/resource.h>
56 #include <sys/bus.h>
57 #include <sys/rman.h>
58
59 #include <net/if.h>
60 #include <net/if_arp.h>
61 #include <net/ethernet.h>
62 #include <net/if_dl.h>
63 #include <net/if_media.h>
64
65 #include <net80211/ieee80211_var.h>
66 #include <net80211/ieee80211_ioctl.h>
67
68 #include <compat/ndis/pe_var.h>
69 #include <compat/ndis/cfg_var.h>
70 #include <compat/ndis/resource_var.h>
71 #include <compat/ndis/ntoskrnl_var.h>
72 #include <compat/ndis/ndis_var.h>
73 #include <compat/ndis/hal_var.h>
74 #include <compat/ndis/usbd_var.h>
75 #include <dev/if_ndis/if_ndisvar.h>
76
77 #define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
78
79 static void ndis_status_func(ndis_handle, ndis_status, void *, uint32_t);
80 static void ndis_statusdone_func(ndis_handle);
81 static void ndis_setdone_func(ndis_handle, ndis_status);
82 static void ndis_getdone_func(ndis_handle, ndis_status);
83 static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
84 static void ndis_sendrsrcavail_func(ndis_handle);
85 static void ndis_intrsetup(kdpc *, device_object *,
86         irp *, struct ndis_softc *);
87 static void ndis_return(device_object *, void *);
88
89 static image_patch_table kernndis_functbl[] = {
90         IMPORT_SFUNC(ndis_status_func, 4),
91         IMPORT_SFUNC(ndis_statusdone_func, 1),
92         IMPORT_SFUNC(ndis_setdone_func, 2),
93         IMPORT_SFUNC(ndis_getdone_func, 2),
94         IMPORT_SFUNC(ndis_resetdone_func, 3),
95         IMPORT_SFUNC(ndis_sendrsrcavail_func, 1),
96         IMPORT_SFUNC(ndis_intrsetup, 4),
97         IMPORT_SFUNC(ndis_return, 1),
98
99         { NULL, NULL, NULL }
100 };
101
102 static struct nd_head ndis_devhead;
103
104 /*
105  * This allows us to export our symbols to other modules.
106  * Note that we call ourselves 'ndisapi' to avoid a namespace
107  * collision with if_ndis.ko, which internally calls itself
108  * 'ndis.'
109  *
110  * Note: some of the subsystems depend on each other, so the
111  * order in which they're started is important. The order of
112  * importance is:
113  *
114  * HAL - spinlocks and IRQL manipulation
115  * ntoskrnl - DPC and workitem threads, object waiting
116  * windrv - driver/device registration
117  *
118  * The HAL should also be the last thing shut down, since
119  * the ntoskrnl subsystem will use spinlocks right up until
120  * the DPC and workitem threads are terminated.
121  */
122
123 static int
124 ndis_modevent(module_t mod, int cmd, void *arg)
125 {
126         int                     error = 0;
127         image_patch_table       *patch;
128
129         switch (cmd) {
130         case MOD_LOAD:
131                 /* Initialize subsystems */
132                 hal_libinit();
133                 ntoskrnl_libinit();
134                 windrv_libinit();
135                 ndis_libinit();
136                 usbd_libinit();
137
138                 patch = kernndis_functbl;
139                 while (patch->ipt_func != NULL) {
140                         windrv_wrap((funcptr)patch->ipt_func,
141                             (funcptr *)&patch->ipt_wrap,
142                             patch->ipt_argcnt, patch->ipt_ftype);
143                         patch++;
144                 }
145
146                 TAILQ_INIT(&ndis_devhead);
147
148                 break;
149         case MOD_SHUTDOWN:
150                 if (TAILQ_FIRST(&ndis_devhead) == NULL) {
151                         /* Shut down subsystems */
152                         ndis_libfini();
153                         usbd_libfini();
154                         windrv_libfini();
155                         ntoskrnl_libfini();
156                         hal_libfini();
157
158                         patch = kernndis_functbl;
159                         while (patch->ipt_func != NULL) {
160                                 windrv_unwrap(patch->ipt_wrap);
161                                 patch++;
162                         }
163                 }
164                 break;
165         case MOD_UNLOAD:
166                 /* Shut down subsystems */
167                 ndis_libfini();
168                 usbd_libfini();
169                 windrv_libfini();
170                 ntoskrnl_libfini();
171                 hal_libfini();
172
173                 patch = kernndis_functbl;
174                 while (patch->ipt_func != NULL) {
175                         windrv_unwrap(patch->ipt_wrap);
176                         patch++;
177                 }
178
179                 break;
180         default:
181                 error = EINVAL;
182                 break;
183         }
184
185         return(error);
186 }
187 DEV_MODULE(ndisapi, ndis_modevent, NULL);
188 MODULE_VERSION(ndisapi, 1);
189
190 static void
191 ndis_sendrsrcavail_func(adapter)
192         ndis_handle             adapter;
193 {
194         return;
195 }
196
197 static void
198 ndis_status_func(adapter, status, sbuf, slen)
199         ndis_handle             adapter;
200         ndis_status             status;
201         void                    *sbuf;
202         uint32_t                slen;
203 {
204         ndis_miniport_block     *block;
205         struct ndis_softc       *sc;
206         struct ifnet            *ifp;
207
208         block = adapter;
209         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
210         ifp = sc->ifp;
211         if (ifp->if_flags & IFF_DEBUG)
212                 device_printf (sc->ndis_dev, "status: %x\n", status);
213         return;
214 }
215
216 static void
217 ndis_statusdone_func(adapter)
218         ndis_handle             adapter;
219 {
220         ndis_miniport_block     *block;
221         struct ndis_softc       *sc;
222         struct ifnet            *ifp;
223
224         block = adapter;
225         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
226         ifp = sc->ifp;
227         if (ifp->if_flags & IFF_DEBUG)
228                 device_printf (sc->ndis_dev, "status complete\n");
229         return;
230 }
231
232 static void
233 ndis_setdone_func(adapter, status)
234         ndis_handle             adapter;
235         ndis_status             status;
236 {
237         ndis_miniport_block     *block;
238         block = adapter;
239
240         block->nmb_setstat = status;
241         KeSetEvent(&block->nmb_setevent, IO_NO_INCREMENT, FALSE);
242         return;
243 }
244
245 static void
246 ndis_getdone_func(adapter, status)
247         ndis_handle             adapter;
248         ndis_status             status;
249 {
250         ndis_miniport_block     *block;
251         block = adapter;
252
253         block->nmb_getstat = status;
254         KeSetEvent(&block->nmb_getevent, IO_NO_INCREMENT, FALSE);
255         return;
256 }
257
258 static void
259 ndis_resetdone_func(ndis_handle adapter, ndis_status status,
260         uint8_t addressingreset)
261 {
262         ndis_miniport_block     *block;
263         struct ndis_softc       *sc;
264         struct ifnet            *ifp;
265
266         block = adapter;
267         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
268         ifp = sc->ifp;
269
270         if (ifp->if_flags & IFF_DEBUG)
271                 device_printf (sc->ndis_dev, "reset done...\n");
272         KeSetEvent(&block->nmb_resetevent, IO_NO_INCREMENT, FALSE);
273
274         return;
275 }
276
277 int
278 ndis_create_sysctls(arg)
279         void                    *arg;
280 {
281         struct ndis_softc       *sc;
282         ndis_cfg                *vals;
283         char                    buf[256];
284         struct sysctl_oid       *oidp;
285         struct sysctl_ctx_entry *e;
286
287         if (arg == NULL)
288                 return(EINVAL);
289
290         sc = arg;
291         vals = sc->ndis_regvals;
292
293         TAILQ_INIT(&sc->ndis_cfglist_head);
294
295 #if __FreeBSD_version < 502113
296         /* Create the sysctl tree. */
297
298         sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
299             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
300             device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
301             device_get_desc(sc->ndis_dev));
302
303 #endif
304         /* Add the driver-specific registry keys. */
305
306         while(1) {
307                 if (vals->nc_cfgkey == NULL)
308                         break;
309
310                 if (vals->nc_idx != sc->ndis_devidx) {
311                         vals++;
312                         continue;
313                 }
314
315                 /* See if we already have a sysctl with this name */
316
317                 oidp = NULL;
318 #if __FreeBSD_version < 502113
319                 TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
320 #else
321                 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
322 #endif
323                         oidp = e->entry;
324                         if (strcasecmp(oidp->oid_name, vals->nc_cfgkey) == 0)
325                                 break;
326                         oidp = NULL;
327                 }
328
329                 if (oidp != NULL) {
330                         vals++;
331                         continue;
332                 }
333
334                 ndis_add_sysctl(sc, vals->nc_cfgkey, vals->nc_cfgdesc,
335                     vals->nc_val, CTLFLAG_RW);
336                 vals++;
337         }
338
339         /* Now add a couple of builtin keys. */
340
341         /*
342          * Environment can be either Windows (0) or WindowsNT (1).
343          * We qualify as the latter.
344          */
345         ndis_add_sysctl(sc, "Environment",
346             "Windows environment", "1", CTLFLAG_RD);
347
348         /* NDIS version should be 5.1. */
349         ndis_add_sysctl(sc, "NdisVersion",
350             "NDIS API Version", "0x00050001", CTLFLAG_RD);
351
352         /* Bus type (PCI, PCMCIA, etc...) */
353         sprintf(buf, "%d", (int)sc->ndis_iftype);
354         ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
355
356         if (sc->ndis_res_io != NULL) {
357                 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io));
358                 ndis_add_sysctl(sc, "IOBaseAddress",
359                     "Base I/O Address", buf, CTLFLAG_RD);
360         }
361
362         if (sc->ndis_irq != NULL) {
363                 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq));
364                 ndis_add_sysctl(sc, "InterruptNumber",
365                     "Interrupt Number", buf, CTLFLAG_RD);
366         }
367
368         return(0);
369 }
370
371 int
372 ndis_add_sysctl(arg, key, desc, val, flag)
373         void                    *arg;
374         char                    *key;
375         char                    *desc;
376         char                    *val;
377         int                     flag;
378 {
379         struct ndis_softc       *sc;
380         struct ndis_cfglist     *cfg;
381         char                    descstr[256];
382
383         sc = arg;
384
385         cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
386
387         if (cfg == NULL) {
388                 printf("failed for %s\n", key);
389                 return(ENOMEM);
390         }
391
392         cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
393         if (desc == NULL) {
394                 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
395                 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
396         } else
397                 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
398         strcpy(cfg->ndis_cfg.nc_val, val);
399
400         TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
401
402         cfg->ndis_oid =
403 #if __FreeBSD_version < 502113
404         SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
405             OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
406             cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
407             cfg->ndis_cfg.nc_cfgdesc);
408 #else
409         SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
410             SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
411             OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
412             cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
413             cfg->ndis_cfg.nc_cfgdesc);
414 #endif
415
416         return(0);
417 }
418
419 /*
420  * Somewhere, somebody decided "hey, let's automatically create
421  * a sysctl tree for each device instance as it's created -- it'll
422  * make life so much easier!" Lies. Why must they turn the kernel
423  * into a house of lies?
424  */
425
426 int
427 ndis_flush_sysctls(arg)
428         void                    *arg;
429 {
430         struct ndis_softc       *sc;
431         struct ndis_cfglist     *cfg;
432         struct sysctl_ctx_list  *clist;
433
434         sc = arg;
435
436 #if __FreeBSD_version < 502113
437         clist = &sc->ndis_ctx;
438 #else
439         clist = device_get_sysctl_ctx(sc->ndis_dev);
440 #endif
441
442         while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
443                 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
444                 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
445                 sysctl_ctx_entry_del(clist, cfg->ndis_oid);
446                 sysctl_remove_oid(cfg->ndis_oid, 1, 0);
447                 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
448                 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
449                 free(cfg, M_DEVBUF);
450         }
451
452         return(0);
453 }
454
455 static void
456 ndis_return(dobj, arg)
457         device_object           *dobj;
458         void                    *arg;
459 {
460         ndis_miniport_block     *block;
461         ndis_miniport_characteristics   *ch;
462         ndis_return_handler     returnfunc;
463         ndis_handle             adapter;
464         ndis_packet             *p;
465         uint8_t                 irql;
466         list_entry              *l;
467
468         block = arg;
469         ch = IoGetDriverObjectExtension(dobj->do_drvobj, (void *)1);
470
471         p = arg;
472         adapter = block->nmb_miniportadapterctx;
473
474         if (adapter == NULL)
475                 return;
476
477         returnfunc = ch->nmc_return_packet_func;
478
479         KeAcquireSpinLock(&block->nmb_returnlock, &irql);
480         while (!IsListEmpty(&block->nmb_returnlist)) {
481                 l = RemoveHeadList((&block->nmb_returnlist));
482                 p = CONTAINING_RECORD(l, ndis_packet, np_list);
483                 InitializeListHead((&p->np_list));
484                 KeReleaseSpinLock(&block->nmb_returnlock, irql);
485                 MSCALL2(returnfunc, adapter, p);
486                 KeAcquireSpinLock(&block->nmb_returnlock, &irql);
487         }
488         KeReleaseSpinLock(&block->nmb_returnlock, irql);
489
490         return;
491 }
492
493 void
494 ndis_return_packet(buf, arg)
495         void                    *buf;   /* not used */
496         void                    *arg;
497 {
498         ndis_packet             *p;
499         ndis_miniport_block     *block;
500
501         if (arg == NULL)
502                 return;
503
504         p = arg;
505
506         /* Decrement refcount. */
507         p->np_refcnt--;
508
509         /* Release packet when refcount hits zero, otherwise return. */
510         if (p->np_refcnt)
511                 return;
512
513         block = ((struct ndis_softc *)p->np_softc)->ndis_block;
514
515         KeAcquireSpinLockAtDpcLevel(&block->nmb_returnlock);
516         InitializeListHead((&p->np_list));
517         InsertHeadList((&block->nmb_returnlist), (&p->np_list));
518         KeReleaseSpinLockFromDpcLevel(&block->nmb_returnlock);
519
520         IoQueueWorkItem(block->nmb_returnitem,
521             (io_workitem_func)kernndis_functbl[7].ipt_wrap,
522             WORKQUEUE_CRITICAL, block);
523
524         return;
525 }
526
527 void
528 ndis_free_bufs(b0)
529         ndis_buffer             *b0;
530 {
531         ndis_buffer             *next;
532
533         if (b0 == NULL)
534                 return;
535
536         while(b0 != NULL) {
537                 next = b0->mdl_next;
538                 IoFreeMdl(b0);
539                 b0 = next;
540         }
541
542         return;
543 }
544 int in_reset = 0;
545 void
546 ndis_free_packet(p)
547         ndis_packet             *p;
548 {
549         if (p == NULL)
550                 return;
551
552         ndis_free_bufs(p->np_private.npp_head);
553         NdisFreePacket(p);
554         return;
555 }
556
557 int
558 ndis_convert_res(arg)
559         void                    *arg;
560 {
561         struct ndis_softc       *sc;
562         ndis_resource_list      *rl = NULL;
563         cm_partial_resource_desc        *prd = NULL;
564         ndis_miniport_block     *block;
565         device_t                dev;
566         struct resource_list    *brl;
567         struct resource_list_entry      *brle;
568 #if __FreeBSD_version < 600022
569         struct resource_list    brl_rev;
570         struct resource_list_entry      *n;
571 #endif
572         int                     error = 0;
573
574         sc = arg;
575         block = sc->ndis_block;
576         dev = sc->ndis_dev;
577
578 #if __FreeBSD_version < 600022
579         SLIST_INIT(&brl_rev);
580 #endif
581
582         rl = malloc(sizeof(ndis_resource_list) +
583             (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
584             M_DEVBUF, M_NOWAIT|M_ZERO);
585
586         if (rl == NULL)
587                 return(ENOMEM);
588
589         rl->cprl_version = 5;
590         rl->cprl_version = 1;
591         rl->cprl_count = sc->ndis_rescnt;
592         prd = rl->cprl_partial_descs;
593
594         brl = BUS_GET_RESOURCE_LIST(dev, dev);
595
596         if (brl != NULL) {
597
598 #if __FreeBSD_version < 600022
599                 /*
600                  * We have a small problem. Some PCI devices have
601                  * multiple I/O ranges. Windows orders them starting
602                  * from lowest numbered BAR to highest. We discover
603                  * them in that order too, but insert them into a singly
604                  * linked list head first, which means when time comes
605                  * to traverse the list, we enumerate them in reverse
606                  * order. This screws up some drivers which expect the
607                  * BARs to be in ascending order so that they can choose
608                  * the "first" one as their register space. Unfortunately,
609                  * in order to fix this, we have to create our own
610                  * temporary list with the entries in reverse order.
611                  */
612
613                 SLIST_FOREACH(brle, brl, link) {
614                         n = malloc(sizeof(struct resource_list_entry),
615                             M_TEMP, M_NOWAIT);
616                         if (n == NULL) {
617                                 error = ENOMEM;
618                                 goto bad;
619                         }
620                         bcopy((char *)brle, (char *)n,
621                             sizeof(struct resource_list_entry));
622                         SLIST_INSERT_HEAD(&brl_rev, n, link);
623                 }
624
625                 SLIST_FOREACH(brle, &brl_rev, link) {
626 #else
627                 STAILQ_FOREACH(brle, brl, link) {
628 #endif
629                         switch (brle->type) {
630                         case SYS_RES_IOPORT:
631                                 prd->cprd_type = CmResourceTypePort;
632                                 prd->cprd_flags = CM_RESOURCE_PORT_IO;
633                                 prd->cprd_sharedisp =
634                                     CmResourceShareDeviceExclusive;
635                                 prd->u.cprd_port.cprd_start.np_quad =
636                                     brle->start;
637                                 prd->u.cprd_port.cprd_len = brle->count;
638                                 break;
639                         case SYS_RES_MEMORY:
640                                 prd->cprd_type = CmResourceTypeMemory;
641                                 prd->cprd_flags =
642                                     CM_RESOURCE_MEMORY_READ_WRITE;
643                                 prd->cprd_sharedisp =
644                                     CmResourceShareDeviceExclusive;
645                                 prd->u.cprd_port.cprd_start.np_quad =
646                                     brle->start;
647                                 prd->u.cprd_port.cprd_len = brle->count;
648                                 break;
649                         case SYS_RES_IRQ:
650                                 prd->cprd_type = CmResourceTypeInterrupt;
651                                 prd->cprd_flags = 0;
652                                 /*
653                                  * Always mark interrupt resources as
654                                  * shared, since in our implementation,
655                                  * they will be.
656                                  */
657                                 prd->cprd_sharedisp =
658                                     CmResourceShareShared;
659                                 prd->u.cprd_intr.cprd_level = brle->start;
660                                 prd->u.cprd_intr.cprd_vector = brle->start;
661                                 prd->u.cprd_intr.cprd_affinity = 0;
662                                 break;
663                         default:
664                                 break;
665                         }
666                         prd++;
667                 }
668         }
669
670         block->nmb_rlist = rl;
671
672 #if __FreeBSD_version < 600022
673 bad:
674
675         while (!SLIST_EMPTY(&brl_rev)) {
676                 n = SLIST_FIRST(&brl_rev);
677                 SLIST_REMOVE_HEAD(&brl_rev, link);
678                 free (n, M_TEMP);
679         }
680 #endif
681
682         return(error);
683 }
684
685 /*
686  * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
687  * packet, it will hand it to us in the form of an ndis_packet,
688  * which we need to convert to an mbuf that is then handed off
689  * to the stack. Note: we configure the mbuf list so that it uses
690  * the memory regions specified by the ndis_buffer structures in
691  * the ndis_packet as external storage. In most cases, this will
692  * point to a memory region allocated by the driver (either by
693  * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
694  * the driver to handle free()ing this region for is, so we set up
695  * a dummy no-op free handler for it.
696  */ 
697
698 int
699 ndis_ptom(m0, p)
700         struct mbuf             **m0;
701         ndis_packet             *p;
702 {
703         struct mbuf             *m = NULL, *prev = NULL;
704         ndis_buffer             *buf;
705         ndis_packet_private     *priv;
706         uint32_t                totlen = 0;
707         struct ifnet            *ifp;
708         struct ether_header     *eh;
709         int                     diff;
710
711         if (p == NULL || m0 == NULL)
712                 return(EINVAL);
713
714         priv = &p->np_private;
715         buf = priv->npp_head;
716         p->np_refcnt = 0;
717
718         for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) {
719                 if (buf == priv->npp_head)
720 #ifdef MT_HEADER
721                         MGETHDR(m, M_DONTWAIT, MT_HEADER);
722 #else
723                         MGETHDR(m, M_DONTWAIT, MT_DATA);
724 #endif
725                 else
726                         MGET(m, M_DONTWAIT, MT_DATA);
727                 if (m == NULL) {
728                         m_freem(*m0);
729                         *m0 = NULL;
730                         return(ENOBUFS);
731                 }
732                 m->m_len = MmGetMdlByteCount(buf);
733                 m->m_data = MmGetMdlVirtualAddress(buf);
734                 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
735                     p, 0, EXT_NDIS);
736                 p->np_refcnt++;
737
738                 totlen += m->m_len;
739                 if (m->m_flags & M_PKTHDR)
740                         *m0 = m;
741                 else
742                         prev->m_next = m;
743                 prev = m;
744         }
745
746         /*
747          * This is a hack to deal with the Marvell 8335 driver
748          * which, when associated with an AP in WPA-PSK mode,
749          * seems to overpad its frames by 8 bytes. I don't know
750          * that the extra 8 bytes are for, and they're not there
751          * in open mode, so for now clamp the frame size at 1514
752          * until I can figure out how to deal with this properly,
753          * otherwise if_ethersubr() will spank us by discarding
754          * the 'oversize' frames.
755          */
756
757         eh = mtod((*m0), struct ether_header *);
758         ifp = ((struct ndis_softc *)p->np_softc)->ifp;
759         if (totlen > ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE)) {
760                 diff = totlen - ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE);
761                 totlen -= diff;
762                 m->m_len -= diff;
763         }
764         (*m0)->m_pkthdr.len = totlen;
765
766         return(0);
767 }
768
769 /*
770  * Create an NDIS packet from an mbuf chain.
771  * This is used mainly when transmitting packets, where we need
772  * to turn an mbuf off an interface's send queue and transform it
773  * into an NDIS packet which will be fed into the NDIS driver's
774  * send routine.
775  *
776  * NDIS packets consist of two parts: an ndis_packet structure,
777  * which is vaguely analagous to the pkthdr portion of an mbuf,
778  * and one or more ndis_buffer structures, which define the
779  * actual memory segments in which the packet data resides.
780  * We need to allocate one ndis_buffer for each mbuf in a chain,
781  * plus one ndis_packet as the header.
782  */
783
784 int
785 ndis_mtop(m0, p)
786         struct mbuf             *m0;
787         ndis_packet             **p;
788 {
789         struct mbuf             *m;
790         ndis_buffer             *buf = NULL, *prev = NULL;
791         ndis_packet_private     *priv;
792
793         if (p == NULL || *p == NULL || m0 == NULL)
794                 return(EINVAL);
795
796         priv = &(*p)->np_private;
797         priv->npp_totlen = m0->m_pkthdr.len;
798
799         for (m = m0; m != NULL; m = m->m_next) {
800                 if (m->m_len == 0)
801                         continue;
802                 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL);
803                 if (buf == NULL) {
804                         ndis_free_packet(*p);
805                         *p = NULL;
806                         return(ENOMEM);
807                 }
808                 MmBuildMdlForNonPagedPool(buf);
809
810                 if (priv->npp_head == NULL)
811                         priv->npp_head = buf;
812                 else
813                         prev->mdl_next = buf;
814                 prev = buf;
815         }
816
817         priv->npp_tail = buf;
818
819         return(0);
820 }
821
822 int
823 ndis_get_supported_oids(arg, oids, oidcnt)
824         void                    *arg;
825         ndis_oid                **oids;
826         int                     *oidcnt;
827 {
828         int                     len, rval;
829         ndis_oid                *o;
830
831         if (arg == NULL || oids == NULL || oidcnt == NULL)
832                 return(EINVAL);
833         len = 0;
834         ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
835
836         o = malloc(len, M_DEVBUF, M_NOWAIT);
837         if (o == NULL)
838                 return(ENOMEM);
839
840         rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
841
842         if (rval) {
843                 free(o, M_DEVBUF);
844                 return(rval);
845         }
846
847         *oids = o;
848         *oidcnt = len / 4;
849
850         return(0);
851 }
852
853 int
854 ndis_set_info(arg, oid, buf, buflen)
855         void                    *arg;
856         ndis_oid                oid;
857         void                    *buf;
858         int                     *buflen;
859 {
860         struct ndis_softc       *sc;
861         ndis_status             rval;
862         ndis_handle             adapter;
863         ndis_setinfo_handler    setfunc;
864         uint32_t                byteswritten = 0, bytesneeded = 0;
865         uint8_t                 irql;
866         uint64_t                duetime;
867
868         /*
869          * According to the NDIS spec, MiniportQueryInformation()
870          * and MiniportSetInformation() requests are handled serially:
871          * once one request has been issued, we must wait for it to
872          * finish before allowing another request to proceed.
873          */
874
875         sc = arg;
876
877         KeResetEvent(&sc->ndis_block->nmb_setevent);
878
879         KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
880
881         if (sc->ndis_block->nmb_pendingreq != NULL) {
882                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
883                 panic("ndis_set_info() called while other request pending");
884         } else
885                 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
886
887         setfunc = sc->ndis_chars->nmc_setinfo_func;
888         adapter = sc->ndis_block->nmb_miniportadapterctx;
889
890         if (adapter == NULL || setfunc == NULL ||
891             sc->ndis_block->nmb_devicectx == NULL) {
892                 sc->ndis_block->nmb_pendingreq = NULL;
893                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
894                 return(ENXIO);
895         }
896
897         rval = MSCALL6(setfunc, adapter, oid, buf, *buflen,
898             &byteswritten, &bytesneeded);
899
900         sc->ndis_block->nmb_pendingreq = NULL;
901
902         KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
903
904         if (rval == NDIS_STATUS_PENDING) {
905                 /* Wait up to 5 seconds. */
906                 duetime = (5 * 1000000) * -10;
907                 KeWaitForSingleObject(&sc->ndis_block->nmb_setevent,
908                     0, 0, FALSE, &duetime);
909                 rval = sc->ndis_block->nmb_setstat;
910         }
911
912         if (byteswritten)
913                 *buflen = byteswritten;
914         if (bytesneeded)
915                 *buflen = bytesneeded;
916
917         if (rval == NDIS_STATUS_INVALID_LENGTH)
918                 return(ENOSPC);
919
920         if (rval == NDIS_STATUS_INVALID_OID)
921                 return(EINVAL);
922
923         if (rval == NDIS_STATUS_NOT_SUPPORTED ||
924             rval == NDIS_STATUS_NOT_ACCEPTED)
925                 return(ENOTSUP);
926
927         if (rval != NDIS_STATUS_SUCCESS)
928                 return(ENODEV);
929
930         return(0);
931 }
932
933 typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
934
935 int
936 ndis_send_packets(arg, packets, cnt)
937         void                    *arg;
938         ndis_packet             **packets;
939         int                     cnt;
940 {
941         struct ndis_softc       *sc;
942         ndis_handle             adapter;
943         ndis_sendmulti_handler  sendfunc;
944         ndis_senddone_func              senddonefunc;
945         int                     i;
946         ndis_packet             *p;
947         uint8_t                 irql = 0;
948
949         sc = arg;
950         adapter = sc->ndis_block->nmb_miniportadapterctx;
951         if (adapter == NULL)
952                 return(ENXIO);
953         sendfunc = sc->ndis_chars->nmc_sendmulti_func;
954         senddonefunc = sc->ndis_block->nmb_senddone_func;
955
956         if (NDIS_SERIALIZED(sc->ndis_block))
957                 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
958
959         MSCALL3(sendfunc, adapter, packets, cnt);
960
961         for (i = 0; i < cnt; i++) {
962                 p = packets[i];
963                 /*
964                  * Either the driver already handed the packet to
965                  * ndis_txeof() due to a failure, or it wants to keep
966                  * it and release it asynchronously later. Skip to the
967                  * next one.
968                  */
969                 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
970                         continue;
971                 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status);
972         }
973
974         if (NDIS_SERIALIZED(sc->ndis_block))
975                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
976
977         return(0);
978 }
979
980 int
981 ndis_send_packet(arg, packet)
982         void                    *arg;
983         ndis_packet             *packet;
984 {
985         struct ndis_softc       *sc;
986         ndis_handle             adapter;
987         ndis_status             status;
988         ndis_sendsingle_handler sendfunc;
989         ndis_senddone_func              senddonefunc;
990         uint8_t                 irql = 0;
991
992         sc = arg;
993         adapter = sc->ndis_block->nmb_miniportadapterctx;
994         if (adapter == NULL)
995                 return(ENXIO);
996         sendfunc = sc->ndis_chars->nmc_sendsingle_func;
997         senddonefunc = sc->ndis_block->nmb_senddone_func;
998
999         if (NDIS_SERIALIZED(sc->ndis_block))
1000                 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1001         status = MSCALL3(sendfunc, adapter, packet,
1002             packet->np_private.npp_flags);
1003
1004         if (status == NDIS_STATUS_PENDING) {
1005                 if (NDIS_SERIALIZED(sc->ndis_block))
1006                         KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1007                 return(0);
1008         }
1009
1010         MSCALL3(senddonefunc, sc->ndis_block, packet, status);
1011
1012         if (NDIS_SERIALIZED(sc->ndis_block))
1013                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1014
1015         return(0);
1016 }
1017
1018 int
1019 ndis_init_dma(arg)
1020         void                    *arg;
1021 {
1022         struct ndis_softc       *sc;
1023         int                     i, error;
1024
1025         sc = arg;
1026
1027         sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
1028             M_DEVBUF, M_NOWAIT|M_ZERO);
1029
1030         if (sc->ndis_tmaps == NULL)
1031                 return(ENOMEM);
1032
1033         for (i = 0; i < sc->ndis_maxpkts; i++) {
1034                 error = bus_dmamap_create(sc->ndis_ttag, 0,
1035                     &sc->ndis_tmaps[i]);
1036                 if (error) {
1037                         free(sc->ndis_tmaps, M_DEVBUF);
1038                         return(ENODEV);
1039                 }
1040         }
1041
1042         return(0);
1043 }
1044
1045 int
1046 ndis_destroy_dma(arg)
1047         void                    *arg;
1048 {
1049         struct ndis_softc       *sc;
1050         struct mbuf             *m;
1051         ndis_packet             *p = NULL;
1052         int                     i;
1053
1054         sc = arg;
1055
1056         for (i = 0; i < sc->ndis_maxpkts; i++) {
1057                 if (sc->ndis_txarray[i] != NULL) {
1058                         p = sc->ndis_txarray[i];
1059                         m = (struct mbuf *)p->np_rsvd[1];
1060                         if (m != NULL)
1061                                 m_freem(m);
1062                         ndis_free_packet(sc->ndis_txarray[i]);
1063                 }
1064                 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
1065         }
1066
1067         free(sc->ndis_tmaps, M_DEVBUF);
1068
1069         bus_dma_tag_destroy(sc->ndis_ttag);
1070
1071         return(0);
1072 }
1073
1074 int
1075 ndis_reset_nic(arg)
1076         void                    *arg;
1077 {
1078         struct ndis_softc       *sc;
1079         ndis_handle             adapter;
1080         ndis_reset_handler      resetfunc;
1081         uint8_t                 addressing_reset;
1082         int                     rval;
1083         uint8_t                 irql = 0;
1084
1085         sc = arg;
1086
1087         NDIS_LOCK(sc);
1088         adapter = sc->ndis_block->nmb_miniportadapterctx;
1089         resetfunc = sc->ndis_chars->nmc_reset_func;
1090
1091         if (adapter == NULL || resetfunc == NULL ||
1092             sc->ndis_block->nmb_devicectx == NULL) {
1093                 NDIS_UNLOCK(sc);
1094                 return(EIO);
1095         }
1096
1097         NDIS_UNLOCK(sc);
1098
1099         KeResetEvent(&sc->ndis_block->nmb_resetevent);
1100
1101         if (NDIS_SERIALIZED(sc->ndis_block))
1102                 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1103
1104         rval = MSCALL2(resetfunc, &addressing_reset, adapter);
1105
1106         if (NDIS_SERIALIZED(sc->ndis_block))
1107                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1108
1109         if (rval == NDIS_STATUS_PENDING)
1110                 KeWaitForSingleObject(&sc->ndis_block->nmb_resetevent,
1111                     0, 0, FALSE, NULL);
1112
1113         return(0);
1114 }
1115
1116 int
1117 ndis_halt_nic(arg)
1118         void                    *arg;
1119 {
1120         struct ndis_softc       *sc;
1121         ndis_handle             adapter;
1122         ndis_halt_handler       haltfunc;
1123         ndis_miniport_block     *block;
1124         int                     empty = 0;
1125         uint8_t                 irql;
1126
1127         sc = arg;
1128         block = sc->ndis_block;
1129
1130         if (!cold)
1131                 KeFlushQueuedDpcs();
1132
1133         /*
1134          * Wait for all packets to be returned.
1135          */
1136
1137         while (1) {
1138                 KeAcquireSpinLock(&block->nmb_returnlock, &irql);
1139                 empty = IsListEmpty(&block->nmb_returnlist);
1140                 KeReleaseSpinLock(&block->nmb_returnlock, irql);
1141                 if (empty)
1142                         break;
1143                 NdisMSleep(1000);
1144         }
1145
1146         NDIS_LOCK(sc);
1147         adapter = sc->ndis_block->nmb_miniportadapterctx;
1148         if (adapter == NULL) {
1149                 NDIS_UNLOCK(sc);
1150                 return(EIO);
1151         }
1152
1153         sc->ndis_block->nmb_devicectx = NULL;
1154
1155         /*
1156          * The adapter context is only valid after the init
1157          * handler has been called, and is invalid once the
1158          * halt handler has been called.
1159          */
1160
1161         haltfunc = sc->ndis_chars->nmc_halt_func;
1162         NDIS_UNLOCK(sc);
1163
1164         MSCALL1(haltfunc, adapter);
1165
1166         NDIS_LOCK(sc);
1167         sc->ndis_block->nmb_miniportadapterctx = NULL;
1168         NDIS_UNLOCK(sc);
1169
1170         return(0);
1171 }
1172
1173 int
1174 ndis_shutdown_nic(arg)
1175         void                    *arg;
1176 {
1177         struct ndis_softc       *sc;
1178         ndis_handle             adapter;
1179         ndis_shutdown_handler   shutdownfunc;
1180
1181         sc = arg;
1182         NDIS_LOCK(sc);
1183         adapter = sc->ndis_block->nmb_miniportadapterctx;
1184         shutdownfunc = sc->ndis_chars->nmc_shutdown_handler;
1185         NDIS_UNLOCK(sc);
1186         if (adapter == NULL || shutdownfunc == NULL)
1187                 return(EIO);
1188
1189         if (sc->ndis_chars->nmc_rsvd0 == NULL)
1190                 MSCALL1(shutdownfunc, adapter);
1191         else
1192                 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0);
1193
1194         TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
1195
1196         return(0);
1197 }
1198
1199 int
1200 ndis_init_nic(arg)
1201         void                    *arg;
1202 {
1203         struct ndis_softc       *sc;
1204         ndis_miniport_block     *block;
1205         ndis_init_handler       initfunc;
1206         ndis_status             status, openstatus = 0;
1207         ndis_medium             mediumarray[NdisMediumMax];
1208         uint32_t                chosenmedium, i;
1209
1210         if (arg == NULL)
1211                 return(EINVAL);
1212
1213         sc = arg;
1214         NDIS_LOCK(sc);
1215         block = sc->ndis_block;
1216         initfunc = sc->ndis_chars->nmc_init_func;
1217         NDIS_UNLOCK(sc);
1218
1219         sc->ndis_block->nmb_timerlist = NULL;
1220
1221         for (i = 0; i < NdisMediumMax; i++)
1222                 mediumarray[i] = i;
1223
1224         status = MSCALL6(initfunc, &openstatus, &chosenmedium,
1225             mediumarray, NdisMediumMax, block, block);
1226
1227         /*
1228          * If the init fails, blow away the other exported routines
1229          * we obtained from the driver so we can't call them later.
1230          * If the init failed, none of these will work.
1231          */
1232         if (status != NDIS_STATUS_SUCCESS) {
1233                 NDIS_LOCK(sc);
1234                 sc->ndis_block->nmb_miniportadapterctx = NULL;
1235                 NDIS_UNLOCK(sc);
1236                 return(ENXIO);
1237         }
1238
1239         /*
1240          * This may look really goofy, but apparently it is possible
1241          * to halt a miniport too soon after it's been initialized.
1242          * After MiniportInitialize() finishes, pause for 1 second
1243          * to give the chip a chance to handle any short-lived timers
1244          * that were set in motion. If we call MiniportHalt() too soon,
1245          * some of the timers may not be cancelled, because the driver
1246          * expects them to fire before the halt is called.
1247          */
1248
1249         pause("ndwait", hz);
1250
1251         NDIS_LOCK(sc);
1252         sc->ndis_block->nmb_devicectx = sc;
1253         NDIS_UNLOCK(sc);
1254
1255         return(0);
1256 }
1257
1258 static void
1259 ndis_intrsetup(dpc, dobj, ip, sc)
1260         kdpc                    *dpc;
1261         device_object           *dobj;
1262         irp                     *ip;
1263         struct ndis_softc       *sc;
1264 {
1265         ndis_miniport_interrupt *intr;
1266
1267         intr = sc->ndis_block->nmb_interrupt;
1268
1269         /* Sanity check. */
1270
1271         if (intr == NULL)
1272                 return;
1273
1274         KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
1275         KeResetEvent(&intr->ni_dpcevt);
1276         if (KeInsertQueueDpc(&intr->ni_dpc, NULL, NULL) == TRUE)
1277                 intr->ni_dpccnt++;
1278         KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
1279
1280         return;
1281 }
1282
1283 int
1284 ndis_get_info(arg, oid, buf, buflen)
1285         void                    *arg;
1286         ndis_oid                oid;
1287         void                    *buf;
1288         int                     *buflen;
1289 {
1290         struct ndis_softc       *sc;
1291         ndis_status             rval;
1292         ndis_handle             adapter;
1293         ndis_queryinfo_handler  queryfunc;
1294         uint32_t                byteswritten = 0, bytesneeded = 0;
1295         uint8_t                 irql;
1296         uint64_t                duetime;
1297
1298         sc = arg;
1299
1300         KeResetEvent(&sc->ndis_block->nmb_getevent);
1301
1302         KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1303
1304         if (sc->ndis_block->nmb_pendingreq != NULL) {
1305                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1306                 panic("ndis_get_info() called while other request pending");
1307         } else
1308                 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
1309
1310         queryfunc = sc->ndis_chars->nmc_queryinfo_func;
1311         adapter = sc->ndis_block->nmb_miniportadapterctx;
1312
1313         if (adapter == NULL || queryfunc == NULL ||
1314             sc->ndis_block->nmb_devicectx == NULL) {
1315                 sc->ndis_block->nmb_pendingreq = NULL;
1316                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1317                 return(ENXIO);
1318         }
1319
1320         rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen,
1321             &byteswritten, &bytesneeded);
1322
1323         sc->ndis_block->nmb_pendingreq = NULL;
1324
1325         KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1326
1327         /* Wait for requests that block. */
1328
1329         if (rval == NDIS_STATUS_PENDING) {
1330                 /* Wait up to 5 seconds. */
1331                 duetime = (5 * 1000000) * -10;
1332                 KeWaitForSingleObject(&sc->ndis_block->nmb_getevent,
1333                     0, 0, FALSE, &duetime);
1334                 rval = sc->ndis_block->nmb_getstat;
1335         }
1336
1337         if (byteswritten)
1338                 *buflen = byteswritten;
1339         if (bytesneeded)
1340                 *buflen = bytesneeded;
1341
1342         if (rval == NDIS_STATUS_INVALID_LENGTH ||
1343             rval == NDIS_STATUS_BUFFER_TOO_SHORT)
1344                 return(ENOSPC);
1345
1346         if (rval == NDIS_STATUS_INVALID_OID)
1347                 return(EINVAL);
1348
1349         if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1350             rval == NDIS_STATUS_NOT_ACCEPTED)
1351                 return(ENOTSUP);
1352
1353         if (rval != NDIS_STATUS_SUCCESS)
1354                 return(ENODEV);
1355
1356         return(0);
1357 }
1358
1359 uint32_t
1360 NdisAddDevice(drv, pdo)
1361         driver_object           *drv;
1362         device_object           *pdo;
1363 {
1364         device_object           *fdo;
1365         ndis_miniport_block     *block;
1366         struct ndis_softc       *sc;
1367         uint32_t                status;
1368         int                     error;
1369
1370         sc = device_get_softc(pdo->do_devext);
1371
1372         if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) {
1373                 error = bus_setup_intr(sc->ndis_dev, sc->ndis_irq,
1374                     INTR_TYPE_NET | INTR_MPSAFE,
1375                     NULL, ntoskrnl_intr, NULL, &sc->ndis_intrhand);
1376                 if (error)
1377                         return(NDIS_STATUS_FAILURE);
1378         }
1379
1380         status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL,
1381             FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
1382
1383         if (status != STATUS_SUCCESS)
1384                 return(status);
1385
1386         block = fdo->do_devext;
1387
1388         block->nmb_filterdbs.nf_ethdb = block;
1389         block->nmb_deviceobj = fdo;
1390         block->nmb_physdeviceobj = pdo;
1391         block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo);
1392         KeInitializeSpinLock(&block->nmb_lock);
1393         KeInitializeSpinLock(&block->nmb_returnlock);
1394         KeInitializeEvent(&block->nmb_getevent, EVENT_TYPE_NOTIFY, TRUE);
1395         KeInitializeEvent(&block->nmb_setevent, EVENT_TYPE_NOTIFY, TRUE);
1396         KeInitializeEvent(&block->nmb_resetevent, EVENT_TYPE_NOTIFY, TRUE);
1397         InitializeListHead(&block->nmb_parmlist);
1398         InitializeListHead(&block->nmb_returnlist);
1399         block->nmb_returnitem = IoAllocateWorkItem(fdo);
1400
1401         /*
1402          * Stash pointers to the miniport block and miniport
1403          * characteristics info in the if_ndis softc so the
1404          * UNIX wrapper driver can get to them later.
1405          */
1406         sc->ndis_block = block;
1407         sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1);
1408
1409         /*
1410          * If the driver has a MiniportTransferData() function,
1411          * we should allocate a private RX packet pool.
1412          */
1413
1414         if (sc->ndis_chars->nmc_transferdata_func != NULL) {
1415                 NdisAllocatePacketPool(&status, &block->nmb_rxpool,
1416                     32, PROTOCOL_RESERVED_SIZE_IN_PACKET);
1417                 if (status != NDIS_STATUS_SUCCESS) {
1418                         IoDetachDevice(block->nmb_nextdeviceobj);
1419                         IoDeleteDevice(fdo);
1420                         return(status);
1421                 }
1422                 InitializeListHead((&block->nmb_packetlist));
1423         }
1424
1425         /* Give interrupt handling priority over timers. */
1426         IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap);
1427         KeSetImportanceDpc(&fdo->do_dpc, KDPC_IMPORTANCE_HIGH);
1428
1429         /* Finish up BSD-specific setup. */
1430
1431         block->nmb_signature = (void *)0xcafebabe;
1432         block->nmb_status_func = kernndis_functbl[0].ipt_wrap;
1433         block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap;
1434         block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap;
1435         block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap;
1436         block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap;
1437         block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap;
1438         block->nmb_pendingreq = NULL;
1439
1440         TAILQ_INSERT_TAIL(&ndis_devhead, block, link);
1441
1442         return (STATUS_SUCCESS);
1443 }
1444
1445 int
1446 ndis_unload_driver(arg)
1447         void                    *arg;
1448 {
1449         struct ndis_softc       *sc;
1450         device_object           *fdo;
1451
1452         sc = arg;
1453
1454         if (sc->ndis_intrhand)
1455                 bus_teardown_intr(sc->ndis_dev,
1456                     sc->ndis_irq, sc->ndis_intrhand);
1457
1458         if (sc->ndis_block->nmb_rlist != NULL)
1459                 free(sc->ndis_block->nmb_rlist, M_DEVBUF);
1460
1461         ndis_flush_sysctls(sc);
1462
1463         TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
1464
1465         if (sc->ndis_chars->nmc_transferdata_func != NULL)
1466                 NdisFreePacketPool(sc->ndis_block->nmb_rxpool);
1467         fdo = sc->ndis_block->nmb_deviceobj;
1468         IoFreeWorkItem(sc->ndis_block->nmb_returnitem);
1469         IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj);
1470         IoDeleteDevice(fdo);
1471
1472         return(0);
1473 }