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

Cache object: eacf043d8fcaae7731397b3777f48768


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