The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/emulation/ndis/kern_ndis.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: fc3746a36947d5b075f2042234ecef75


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.