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/compat/ndis/kern_ndis.c

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

Cache object: 3d9a60c2b63475c9685e8e5bd8c2412f


[ 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.