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 #ifdef __FreeBSD__
   35 __FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.60.2.5 2005/04/01 17:14:20 wpaul Exp $");
   36 #endif
   37 #ifdef __NetBSD__
   38 __KERNEL_RCSID(0, "$NetBSD: kern_ndis.c,v 1.14 2008/01/18 09:38:06 skrll Exp $");
   39 #endif
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/unistd.h>
   44 #include <sys/types.h>
   45 #include <sys/errno.h>
   46 #include <sys/callout.h>
   47 #include <sys/socket.h>
   48 #include <sys/queue.h>
   49 #include <sys/sysctl.h>
   50 #include <sys/proc.h>
   51 #include <sys/malloc.h>
   52 #include <sys/lock.h>
   53 #ifdef __FreeBSD__
   54 #include <sys/mutex.h>
   55 #endif
   56 #include <sys/conf.h>
   57 
   58 #include <sys/kernel.h>
   59 #ifdef __FreeBSD__
   60 #include <sys/module.h>
   61 #else
   62 #include <sys/lkm.h>
   63 #include <sys/mbuf.h>
   64 #endif
   65 #include <sys/kthread.h>
   66 #include <sys/bus.h>
   67 #ifdef __FreeBSD__
   68 #include <machine/resource.h>
   69 #include <sys/bus.h>
   70 #include <sys/rman.h>
   71 #endif
   72 
   73 #ifdef __NetBSD__
   74 #include <dev/pci/pcivar.h>
   75 #include <dev/pci/pcireg.h>
   76 #endif
   77 
   78 #include <net/if.h>
   79 #include <net/if_arp.h>
   80 #ifdef __FreeBSD__
   81 #include <net/ethernet.h>
   82 #else
   83 #include <net/if_ether.h>
   84 #endif
   85 #include <net/if_dl.h>
   86 #include <net/if_media.h>
   87 
   88 #include <net80211/ieee80211_var.h>
   89 #include <net80211/ieee80211_ioctl.h>
   90 
   91 #include <compat/ndis/pe_var.h>
   92 #include <compat/ndis/resource_var.h>
   93 #include <compat/ndis/ntoskrnl_var.h>
   94 #include <compat/ndis/ndis_var.h>
   95 #include <compat/ndis/hal_var.h>
   96 #include <compat/ndis/cfg_var.h>
   97 #include <compat/ndis/usbd_var.h>
   98 #include <dev/if_ndis/if_ndisvar.h>
   99 
  100 #define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
  101 
  102 __stdcall static void ndis_status_func(ndis_handle, ndis_status,
  103         void *, uint32_t);
  104 __stdcall static void ndis_statusdone_func(ndis_handle);
  105 __stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
  106 __stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
  107 __stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
  108 __stdcall static void ndis_sendrsrcavail_func(ndis_handle);
  109 __stdcall static void ndis_intrhand(kdpc *, device_object *,
  110         irp *, struct ndis_softc *);
  111 
  112 #ifdef __NetBSD__
  113 extern int ndis_lkmentry(struct lkm_table *lkmtp, int cmd, int ver);
  114 #endif
  115         
  116 static image_patch_table kernndis_functbl[] = {
  117         IMPORT_FUNC(ndis_status_func),
  118         IMPORT_FUNC(ndis_statusdone_func),
  119         IMPORT_FUNC(ndis_setdone_func),
  120         IMPORT_FUNC(ndis_getdone_func),
  121         IMPORT_FUNC(ndis_resetdone_func),
  122         IMPORT_FUNC(ndis_sendrsrcavail_func),
  123         IMPORT_FUNC(ndis_intrhand),
  124 
  125         { NULL, NULL, NULL }
  126 };
  127 
  128 struct nd_head ndis_devhead;
  129 
  130 struct ndis_req {
  131         void                    (*nr_func)(void *);
  132         void                    *nr_arg;
  133         int                     nr_exit;
  134         STAILQ_ENTRY(ndis_req)  link;
  135         /* just for debugging */
  136         int                     area;
  137 };
  138 
  139 struct ndisproc {
  140         struct ndisqhead        *np_q;
  141         struct proc             *np_p;
  142         int                     np_state;
  143         uint8_t                 np_stack[PAGE_SIZE*NDIS_KSTACK_PAGES];
  144 #ifdef __NetBSD__
  145         int                     np_needs_wakeup;
  146 #endif
  147 };
  148 
  149 static void ndis_return(void *);
  150 static int ndis_create_kthreads(void);
  151 static void ndis_destroy_kthreads(void);
  152 static void ndis_stop_thread(int);
  153 static int ndis_enlarge_thrqueue(int);
  154 static int ndis_shrink_thrqueue(int);
  155 //#ifdef NDIS_LKM
  156 static void ndis_runq(void *);
  157 //#endif
  158 
  159 #ifdef __FreeBSD__
  160 static struct mtx ndis_thr_mtx;
  161 #else /* __NetBSD__ */
  162 static struct simplelock ndis_thr_mtx;
  163 #define THR_LOCK()       do {old_ipl = splnet(); simple_lock(&ndis_thr_mtx);} while(0)
  164 #define THR_UNLOCK()     do {simple_unlock(&ndis_thr_mtx); splx(old_ipl);} while(0)
  165 #endif
  166 
  167 static struct mtx ndis_req_mtx;
  168 static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo;
  169 static struct ndisqhead ndis_itodo;
  170 static struct ndisqhead ndis_free;
  171 static int ndis_jobs = 32;
  172 
  173 static struct ndisproc ndis_tproc;
  174 static struct ndisproc ndis_iproc;
  175 
  176 /*
  177  * This allows us to export our symbols to other modules.
  178  * Note that we call ourselves 'ndisapi' to avoid a namespace
  179  * collision with if_ndis.ko, which internally calls itself
  180  * 'ndis.'
  181  */
  182 
  183 #ifdef __FreeBSD__
  184 static int
  185 ndis_modevent(module_t mod, int cmd, void *arg)
  186 {
  187         int                     error = 0;
  188         image_patch_table       *patch;
  189 
  190         switch (cmd) {
  191         case MOD_LOAD:
  192                 /* Initialize subsystems */
  193                 windrv_libinit();
  194                 hal_libinit();
  195                 ndis_libinit();
  196                 ntoskrnl_libinit();
  197 #ifdef usbimplemented
  198                 usbd_libinit();
  199 #endif
  200 
  201                 patch = kernndis_functbl;
  202                 while (patch->ipt_func != NULL) {
  203                         windrv_wrap((funcptr)patch->ipt_func,
  204                             (funcptr *)&patch->ipt_wrap);
  205                         patch++;
  206                 }
  207 
  208                 ndis_create_kthreads();
  209 
  210                 TAILQ_INIT(&ndis_devhead);
  211 
  212                 break;
  213         case MOD_SHUTDOWN:
  214                 /* stop kthreads */
  215                 ndis_destroy_kthreads();
  216                 if (TAILQ_FIRST(&ndis_devhead) == NULL) {
  217                         /* Shut down subsystems */
  218                         hal_libfini();
  219                         ndis_libfini();
  220                         ntoskrnl_libfini();
  221 #ifdef usbimplemented
  222                         usbd_libfini();
  223 #endif
  224                         windrv_libfini();
  225 
  226                         patch = kernndis_functbl;
  227                         while (patch->ipt_func != NULL) {
  228                                 windrv_unwrap(patch->ipt_wrap);
  229                                 patch++;
  230                         }
  231                 }
  232                 break;
  233         case MOD_UNLOAD:
  234                 /* stop kthreads */
  235                 ndis_destroy_kthreads();
  236 
  237                 /* Shut down subsystems */
  238                 hal_libfini();
  239                 ndis_libfini();
  240                 ntoskrnl_libfini();
  241                 usbd_libfini();
  242                 windrv_libfini();
  243 
  244                 patch = kernndis_functbl;
  245                 while (patch->ipt_func != NULL) {
  246                         windrv_unwrap(patch->ipt_wrap);
  247                         patch++;
  248                 }
  249 
  250                 break;
  251         default:
  252                 error = EINVAL;
  253                 break;
  254         }
  255 
  256         return(error);
  257 }
  258 DEV_MODULE(ndisapi, ndis_modevent, NULL);
  259 MODULE_VERSION(ndisapi, 1);
  260 #endif
  261 #ifdef __NetBSD__
  262 MOD_MISC( "ndisapi");
  263 
  264 #ifndef NDIS_LKM
  265 int ndis_lkm_handle(struct lkm_table *lkmtp, int cmd);
  266 #endif
  267 
  268 /*static*/ int
  269 ndis_lkm_handle(struct lkm_table *lkmtp, int cmd)
  270 {
  271         int                     error = 0;
  272         image_patch_table       *patch;
  273 
  274         switch (cmd) {
  275         case LKM_E_LOAD:
  276                 /* Initialize subsystems */
  277                 windrv_libinit();
  278                 hal_libinit();
  279                 ndis_libinit();
  280                 ntoskrnl_libinit();
  281 #ifdef usbimplemented
  282                 usbd_libinit();
  283 #endif
  284 
  285                 patch = kernndis_functbl;
  286                 while (patch->ipt_func != NULL) {
  287                         windrv_wrap((funcptr)patch->ipt_func,
  288                             (funcptr *)&patch->ipt_wrap);
  289                         patch++;
  290                 }
  291 
  292                 TAILQ_INIT(&ndis_devhead);
  293 
  294                 ndis_create_kthreads();
  295                 break;
  296         case LKM_E_UNLOAD:
  297                 /* stop kthreads */
  298                 ndis_destroy_kthreads();
  299 
  300                 /* Shut down subsystems */
  301                 hal_libfini();
  302                 ndis_libfini();
  303                 ntoskrnl_libfini();
  304 #ifdef usbimplemented           
  305                 usbd_libfini();
  306 #endif          
  307                 windrv_libfini();
  308 
  309                 patch = kernndis_functbl;
  310                 while (patch->ipt_func != NULL) {
  311                         windrv_unwrap(patch->ipt_wrap);
  312                         patch++;
  313                 }
  314 
  315                 break;
  316         case LKM_E_STAT:
  317                 break;
  318         default:
  319                 error = EINVAL;
  320                 break;
  321         }
  322 
  323         return(error);
  324 }
  325 
  326 int
  327 ndis_lkmentry(struct lkm_table *lkmtp, int cmd, int ver)
  328 {
  329         DISPATCH(lkmtp, cmd, ver, 
  330                  ndis_lkm_handle, ndis_lkm_handle, ndis_lkm_handle);
  331 }
  332 #endif /* __NetBSD__ */
  333 
  334 /*
  335  * We create two kthreads for the NDIS subsystem. One of them is a task
  336  * queue for performing various odd jobs. The other is an swi thread
  337  * reserved exclusively for running interrupt handlers. The reason we
  338  * have our own task queue is that there are some cases where we may
  339  * need to sleep for a significant amount of time, and if we were to
  340  * use one of the taskqueue threads, we might delay the processing
  341  * of other pending tasks which might need to run right away. We have
  342  * a separate swi thread because we don't want our interrupt handling
  343  * to be delayed either.
  344  *
  345  * By default there are 32 jobs available to start, and another 8
  346  * are added to the free list each time a new device is created.
  347  */
  348  
  349 /* Just for testing this can be removed later */
  350 struct ndis_req *_ndis_taskqueue_req;
  351 struct ndis_req *_ndis_swi_req;
  352 int calling_in_swi = FALSE;
  353 int calling_in_tq  = FALSE;
  354 int num_swi              = 0;
  355 int num_tq               = 0;
  356 
  357 static void
  358 ndis_runq(arg)
  359         void                    *arg;
  360 {
  361         struct ndis_req         *r = NULL, *die = NULL;
  362         struct ndisproc         *p;
  363 #ifdef __NetBSD__
  364         int old_ipl;
  365 #endif
  366 
  367         p = arg;
  368 
  369         while (1) {
  370 
  371                 /* Protect against interrupts between checking if the queue is empty, and going to sleep
  372                  * to avoid a wakeup before sleep.
  373                  */
  374                 old_ipl = splnet();
  375                 /* Sleep, but preserve our original priority. */
  376                 if(STAILQ_EMPTY(p->np_q)) {
  377                         /* TODO: If we get an interrupt between checking if the queue is empty, 
  378                          * TODO: and sleeping, then in the interrupt, an item could be placed
  379                          * TODO: on the queue, and we could be woken up before we sleep.
  380                          * 
  381                          */
  382                         ndis_thsuspend(p->np_p, NULL, 0);
  383                 }
  384                 splx(old_ipl);
  385                 
  386 #ifdef __NetBSD__
  387                 p->np_needs_wakeup = FALSE;
  388 #endif
  389                 
  390                 /* Look for any jobs on the work queue. */
  391 #ifdef __FreeBSD__              
  392                 mtx_lock_spin(&ndis_thr_mtx);
  393 #else /* __NetBSD__ */
  394                 THR_LOCK();
  395 #endif
  396                 
  397                 p->np_state = NDIS_PSTATE_RUNNING;
  398                 while(!STAILQ_EMPTY(p->np_q)/*STAILQ_FIRST(p->np_q) != NULL*/) {        
  399                         r = STAILQ_FIRST(p->np_q);
  400                         STAILQ_REMOVE_HEAD(p->np_q, link);                      
  401 
  402                         /* for debugging */
  403                         
  404                         if(p == &ndis_tproc) {
  405                                 num_tq++;
  406                                 _ndis_taskqueue_req = r;
  407                                 r->area = 1;
  408                         } else if(p == &ndis_iproc) {
  409                                 num_swi++;
  410                                 _ndis_swi_req = r;
  411                                 r->area = 2;
  412                         }
  413 #ifdef __FreeBSD__              
  414                         mtx_unlock_spin(&ndis_thr_mtx);
  415 #else /* __NetBSD__ */
  416                         THR_UNLOCK();
  417 #endif                  
  418                         /* Just for debugging */
  419 
  420                         if(p == &ndis_tproc) {
  421                                 calling_in_tq = TRUE;
  422                         } else if(p == &ndis_iproc) {
  423                                 calling_in_swi     = TRUE;
  424                         }
  425                         
  426                         /* Do the work. */
  427                         if (r->nr_func != NULL)
  428                                 (*r->nr_func)(r->nr_arg);
  429                         
  430                         /* Just for debugging */
  431                         if(p == &ndis_tproc) {
  432                                 calling_in_tq = FALSE;
  433                         } else if(p == &ndis_iproc) {
  434                                 calling_in_swi     = FALSE;
  435                         }
  436 
  437 #ifdef __FreeBSD__                              
  438                         mtx_lock_spin(&ndis_thr_mtx);
  439 #else /* __NetBSD__ */
  440                         THR_LOCK();
  441 #endif
  442 
  443                         /* Zeroing out the ndis_req is just for debugging */
  444                         //memset(r, 0, sizeof(struct ndis_req));
  445                         STAILQ_INSERT_HEAD(&ndis_free, r, link);
  446                         
  447                         /* Check for a shutdown request */
  448                         if (r->nr_exit == TRUE)
  449                                 die = r;
  450                 }
  451                 p->np_state = NDIS_PSTATE_SLEEPING;
  452 
  453 #ifdef __FreeBSD__              
  454                 mtx_unlock_spin(&ndis_thr_mtx);
  455 #else /* __NetBSD__ */
  456                 THR_UNLOCK();
  457 #endif
  458 
  459                 /* Bail if we were told to shut down. */
  460 
  461                 if (die != NULL)
  462                         break;
  463         }
  464 
  465         wakeup(die);
  466 #ifdef __FreeBSD__
  467 #if __FreeBSD_version < 502113
  468         mtx_lock(&Giant);
  469 #endif
  470 #endif
  471         if(p == &ndis_tproc) {
  472                 printf("taskqueue thread exiting!\n");
  473         } else if(p == &ndis_iproc) {
  474                 printf("swi thread exiting!\n");
  475         }
  476         kthread_exit(0);
  477         return; /* notreached */
  478 }
  479 
  480 /*static*/ int
  481 ndis_create_kthreads()
  482 {
  483         struct ndis_req         *r;
  484         int                     i, error = 0;
  485 
  486         printf("in ndis_create_kthreads\n");
  487         
  488 #ifdef __FreeBSD__
  489         mtx_init(&ndis_thr_mtx, "NDIS thread lock", NULL, MTX_SPIN);
  490 #else /* __NetBSD__ */
  491         simple_lock_init(&ndis_thr_mtx);
  492         //lockinit(&ndis_thr_mtx, PWAIT, "NDIS thread lock", 0, 0/*LK_CANRECURSE*//*LK_SPIN*/);
  493 #endif  
  494         mtx_init(&ndis_req_mtx, "NDIS request lock", MTX_NDIS_LOCK, MTX_DEF);
  495 
  496         STAILQ_INIT(&ndis_ttodo);
  497         STAILQ_INIT(&ndis_itodo);
  498         STAILQ_INIT(&ndis_free);
  499 
  500         for (i = 0; i < ndis_jobs; i++) {
  501                 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK|M_ZERO); 
  502                 if (r == NULL) {
  503                         error = ENOMEM;
  504                         break;
  505                 }
  506                 STAILQ_INSERT_HEAD(&ndis_free, r, link);
  507         }
  508 
  509         if (error == 0) {
  510                 ndis_tproc.np_q = &ndis_ttodo;
  511                 ndis_tproc.np_state = NDIS_PSTATE_SLEEPING;
  512 #ifdef __FreeBSD__
  513                 error = kthread_create(ndis_runq, &ndis_tproc,
  514                     &ndis_tproc.np_p, RFHIGHPID,
  515                     NDIS_KSTACK_PAGES, "ndis taskqueue");
  516 #else /* __NetBSD__ */
  517                 error = ndis_kthread_create(ndis_runq, &ndis_tproc,
  518                     &ndis_tproc.np_p, ndis_tproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis taskqueue");
  519 #endif
  520         }
  521 
  522         if (error == 0) {
  523                 ndis_iproc.np_q = &ndis_itodo;
  524                 ndis_iproc.np_state = NDIS_PSTATE_SLEEPING;
  525 #ifdef __FreeBSD__
  526                 error = kthread_create(ndis_runq, &ndis_iproc,
  527                     &ndis_iproc.np_p, RFHIGHPID,
  528                     NDIS_KSTACK_PAGES, "ndis swi");
  529 #else
  530                 error = ndis_kthread_create(ndis_runq, &ndis_iproc,
  531                     &ndis_iproc.np_p, ndis_iproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis swi");
  532 #endif
  533         }
  534 
  535         if (error) {
  536                 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
  537                         STAILQ_REMOVE_HEAD(&ndis_free, link);
  538                         free(r, M_DEVBUF);
  539                 }
  540                 return(error);
  541         }
  542 
  543         return(0);
  544 }
  545 
  546 static void
  547 ndis_destroy_kthreads()
  548 {
  549         struct ndis_req         *r;
  550 
  551         /* Stop the threads. */
  552 
  553         ndis_stop_thread(NDIS_TASKQUEUE);
  554         ndis_stop_thread(NDIS_SWI);
  555 
  556         /* Destroy request structures. */
  557 
  558         while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
  559                 STAILQ_REMOVE_HEAD(&ndis_free, link);
  560                 free(r, M_DEVBUF);
  561         }
  562 
  563         mtx_destroy(&ndis_req_mtx);
  564 #ifndef __NetBSD__
  565         mtx_destroy(&ndis_thr_mtx);
  566 #endif
  567 
  568         return;
  569 }
  570 
  571 static void
  572 ndis_stop_thread(t)
  573         int                     t;
  574 {
  575         struct ndis_req         *r;
  576         struct ndisqhead        *q;
  577         struct proc             *p;
  578 #ifdef __NetBSD__
  579         int old_ipl;
  580 #endif
  581 
  582         if (t == NDIS_TASKQUEUE) {
  583                 q = &ndis_ttodo;
  584                 p = ndis_tproc.np_p;
  585         } else {
  586                 q = &ndis_itodo;
  587                 p = ndis_iproc.np_p;
  588         }
  589 
  590         /* Create and post a special 'exit' job. */
  591 
  592 #ifdef __FreeBSD__
  593         mtx_lock_spin(&ndis_thr_mtx);
  594 #else /* __NetBSD__ */
  595         THR_LOCK();
  596 #endif  
  597         r = STAILQ_FIRST(&ndis_free);
  598         STAILQ_REMOVE_HEAD(&ndis_free, link);
  599         r->nr_func = NULL;
  600         r->nr_arg = NULL;
  601         r->nr_exit = TRUE;
  602         r->area    = 3;
  603         STAILQ_INSERT_TAIL(q, r, link);
  604 #ifdef __FreeBSD__      
  605         mtx_unlock_spin(&ndis_thr_mtx);
  606 #else /* __NetBSD__ */
  607         THR_UNLOCK();
  608 #endif  
  609 
  610         ndis_thresume(p);
  611 
  612         /* wait for thread exit */
  613 
  614 #ifdef __FreeBSD__
  615         tsleep(r, curthread->td_priority|PCATCH, "ndisthexit", hz * 60);
  616 #else
  617         tsleep(r, curlwp->l_priority|PCATCH, "ndisthexit", hz * 60);
  618 #endif
  619 
  620         /* Now empty the job list. */
  621 #ifdef __FreeBSD__
  622         mtx_lock_spin(&ndis_thr_mtx);
  623 #else /* __NetBSD__ */
  624         THR_LOCK();
  625 #endif  
  626         while ((r = STAILQ_FIRST(q)) != NULL) {
  627                 STAILQ_REMOVE_HEAD(q, link);
  628                 STAILQ_INSERT_HEAD(&ndis_free, r, link);
  629         }
  630 
  631 #ifdef __FreeBSD__              
  632         mtx_unlock_spin(&ndis_thr_mtx);
  633 #else /* __NetBSD__ */
  634         THR_UNLOCK();
  635 #endif
  636 
  637         return;
  638 }
  639 
  640 static int
  641 ndis_enlarge_thrqueue(cnt)
  642         int                     cnt;
  643 {
  644         struct ndis_req         *r;
  645         int                     i;
  646 #ifdef __NetBSD__
  647         int                     old_ipl;
  648 #endif  
  649 
  650         for (i = 0; i < cnt; i++) {
  651                 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
  652                 if (r == NULL)
  653                         return(ENOMEM);
  654 #ifdef __FreeBSD__
  655                 mtx_lock_spin(&ndis_thr_mtx);
  656 #else /* __NetBSD__ */
  657                 THR_LOCK();
  658 #endif
  659                 STAILQ_INSERT_HEAD(&ndis_free, r, link);
  660                 ndis_jobs++;
  661 #ifdef __FreeBSD__              
  662                 mtx_unlock_spin(&ndis_thr_mtx);
  663 #else /* __NetBSD__ */
  664                 THR_UNLOCK();
  665 #endif          
  666         }
  667 
  668         return(0);
  669 }
  670 
  671 static int
  672 ndis_shrink_thrqueue(cnt)
  673         int                     cnt;
  674 {
  675         struct ndis_req         *r;
  676         int                     i;
  677 #ifdef __NetBSD__
  678         int                     old_ipl;
  679 #endif  
  680 
  681         for (i = 0; i < cnt; i++) {
  682 #ifdef __FreeBSD__      
  683                 mtx_lock_spin(&ndis_thr_mtx);
  684 #else /* __NetBSD__ */
  685                 THR_LOCK();
  686 #endif          
  687                 r = STAILQ_FIRST(&ndis_free);
  688                 if (r == NULL) {
  689 #ifdef __FreeBSD__              
  690                         mtx_unlock_spin(&ndis_thr_mtx);
  691 #else /* __NetBSD__ */
  692                         THR_UNLOCK();
  693 #endif
  694                         return(ENOMEM);
  695                 }
  696                 STAILQ_REMOVE_HEAD(&ndis_free, link);
  697                 ndis_jobs--;
  698 #ifdef __FreeBSD__              
  699                 mtx_unlock_spin(&ndis_thr_mtx);
  700 #else /* __NetBSD__ */
  701                 THR_UNLOCK();
  702 #endif          
  703 
  704                 free(r, M_DEVBUF);
  705         }
  706 
  707         return(0);
  708 }
  709 
  710 int
  711 ndis_unsched(func, arg, t)
  712         void                    (*func)(void *);
  713         void                    *arg;
  714         int                     t;
  715 {
  716         struct ndis_req         *r;
  717         struct ndisqhead        *q;
  718         struct proc             *p;
  719 #ifdef __NetBSD__
  720         int                     old_ipl;
  721 #endif  
  722 
  723         if (t == NDIS_TASKQUEUE) {
  724                 q = &ndis_ttodo;
  725                 p = ndis_tproc.np_p;
  726         } else {
  727                 q = &ndis_itodo;
  728                 p = ndis_iproc.np_p;
  729         }
  730 
  731 #ifdef __FreeBSD__      
  732         mtx_lock_spin(&ndis_thr_mtx);
  733 #else /* __NetBSD__ */
  734         THR_LOCK();
  735 #endif  
  736         STAILQ_FOREACH(r, q, link) {
  737                 if (r->nr_func == func && r->nr_arg == arg) {
  738                         r->area = 4;
  739                         STAILQ_REMOVE(q, r, ndis_req, link);
  740                         STAILQ_INSERT_HEAD(&ndis_free, r, link);
  741 #ifdef __FreeBSD__                      
  742                         mtx_unlock_spin(&ndis_thr_mtx);
  743 #else /* __NetBSD__ */
  744                         THR_UNLOCK();
  745 #endif                  
  746                         return(0);
  747                 }
  748         }
  749 #ifdef __FreeBSD__
  750         mtx_unlock_spin(&ndis_thr_mtx);
  751 #else /* __NetBSD__ */
  752         THR_UNLOCK();
  753 #endif
  754         return(ENOENT);
  755 }
  756 
  757 /* just for testing */
  758 struct ndis_req *ls_tq_req = NULL;
  759 struct ndis_req *ls_swi_req = NULL;
  760 
  761 int
  762 ndis_sched(func, arg, t)
  763         void                    (*func)(void *);
  764         void                    *arg;
  765         int                     t;
  766 {
  767         struct ndis_req         *r;
  768         struct ndisqhead        *q;
  769         struct proc             *p;
  770         int                     s;
  771 #ifdef __NetBSD__
  772         int                     old_ipl;
  773         /* just for debugging */
  774         struct ndis_req         **ls;
  775         //struct lwp            *l = curlwp;
  776 #endif
  777 
  778         if (t == NDIS_TASKQUEUE) {
  779                 ls = &ls_tq_req;
  780                 q = &ndis_ttodo;
  781                 p = ndis_tproc.np_p;
  782         } else {
  783                 ls = &ls_swi_req;
  784                 q = &ndis_itodo;
  785                 p = ndis_iproc.np_p;
  786         }
  787 
  788 #ifdef __FreeBSD__
  789         mtx_lock_spin(&ndis_thr_mtx);
  790 #else /* __NetBSD__ */
  791         THR_LOCK();
  792 #endif
  793         
  794         /*
  795          * Check to see if an instance of this job is already
  796          * pending. If so, don't bother queuing it again.
  797          */
  798         STAILQ_FOREACH(r, q, link) {
  799                 if (r->nr_func == func && r->nr_arg == arg) {
  800 #ifdef __NetBSD__
  801                         if (t == NDIS_TASKQUEUE)
  802                                 s = ndis_tproc.np_state;
  803                         else
  804                                 s = ndis_iproc.np_state;
  805 #endif
  806 #ifdef __FreeBSD__              
  807                         mtx_unlock_spin(&ndis_thr_mtx);
  808 #else /* __NetBSD__ */
  809                         THR_UNLOCK();
  810 #endif
  811 #ifdef __NetBSD__
  812                         /* The swi thread seemed to be going to sleep, and not waking up
  813                          * again, so I thought I'd try this out...
  814                          */
  815                         if (s == NDIS_PSTATE_SLEEPING)
  816                                 ndis_thresume(p);
  817 #endif
  818                         return(0);
  819                 }
  820         }
  821         r = STAILQ_FIRST(&ndis_free);
  822         if (r == NULL) {
  823 #ifdef __FreeBSD__              
  824                 mtx_unlock_spin(&ndis_thr_mtx);
  825 #else /* __NetBSD__ */
  826                 THR_UNLOCK();
  827 #endif
  828                 return(EAGAIN);
  829         }
  830         STAILQ_REMOVE_HEAD(&ndis_free, link);
  831 #ifdef __NetBSD__
  832         //memset(r, 0, sizeof(struct ndis_req));
  833 #endif
  834         *ls = r;
  835         r->nr_func = func;
  836         r->nr_arg = arg;
  837         r->nr_exit = FALSE;
  838         r->area    = 5;
  839         STAILQ_INSERT_TAIL(q, r, link);
  840         if (t == NDIS_TASKQUEUE) {
  841                 s = ndis_tproc.np_state;
  842 #ifdef __NetBSD__
  843                 ndis_tproc.np_needs_wakeup = TRUE;
  844 #endif
  845         } else {
  846                 s = ndis_iproc.np_state;
  847 #ifdef __NetBSD__
  848                 ndis_iproc.np_needs_wakeup = TRUE;
  849 #endif
  850         }
  851         
  852 #ifdef __FreeBSD__              
  853         mtx_unlock_spin(&ndis_thr_mtx);
  854 #else /* __NetBSD__ */
  855         THR_UNLOCK();
  856 #endif
  857 
  858         /*
  859          * Post the job, but only if the thread is actually blocked
  860          * on its own suspend call. If a driver queues up a job with
  861          * NdisScheduleWorkItem() which happens to do a KeWaitForObject(),
  862          * it may suspend there, and in that case we don't want to wake
  863          * it up until KeWaitForObject() gets woken up on its own.
  864          */
  865         if (s == NDIS_PSTATE_SLEEPING) {
  866                 ndis_thresume(p);
  867         }
  868 
  869         return(0);
  870 }
  871 
  872 /* Try out writing my own version of ndis_sched() for NetBSD in which I just
  873  * call the function instead of scheduling it.  I know this isn't
  874  * what's supposed to be done, but I've been having a lot of problems
  875  * with the SWI and taskqueue threads, and just thought I'd give this
  876  * a try.
  877  */
  878  
  879  /* I don't think this will work, because it means that DPC's will be
  880   * called from the bottom half of the kernel, so they won't be able
  881   * to sleep using KeWaitForSingleObject.
  882   */
  883  /*
  884  int
  885 ndis_sched(func, arg, t)
  886         void                    (*func)(void *);
  887         void                    *arg;
  888         int                     t;
  889 {
  890         if(func != NULL) {
  891                 (*func)(arg);
  892         }
  893         
  894         return 0;
  895 }
  896 */
  897 
  898 int
  899 ndis_thsuspend(p, m, timo)
  900         struct proc             *p;
  901 #ifdef __FreeBSD__      
  902         struct mtx              *m;
  903 #else /* __NetBSD__*/
  904         struct simplelock       *m;
  905 #endif          
  906         int                     timo;
  907 {
  908         int                     error;
  909 
  910 #ifdef __FreeBSD__
  911         if (m != NULL) {
  912                 error = msleep(&p->p_siglist, m,
  913                     curthread->td_priority, "ndissp", timo);
  914         } else {
  915                 PROC_LOCK(p);
  916                 error = msleep(&p->p_siglist, &p->p_mtx,
  917                     curthread->td_priority|PDROP, "ndissp", timo);
  918         }
  919 #else
  920 /* TODO: Why do they wait on &p->p_siglist?  I noticed that in FreeBSD's 
  921  * src/sys/sys/proc.h there is some mention of p_siglist having to do with
  922  * M:N threading.
  923  */
  924         if (m != NULL) {
  925                 //mtx_unlock(m);
  926                 error = ltsleep(&p->p_sigpend.sp_set, curlwp->l_priority, 
  927                                 "ndissp", timo, m);
  928                 //mtx_lock(m);
  929         } else {
  930                 error = ltsleep(&p->p_sigpend.sp_set, curlwp->l_priority/*|PNORELOCK*/, 
  931                                 "ndissp", timo, 0 /*&p->p_lock*/);
  932         }
  933 
  934 #endif
  935 
  936         return(error);
  937 }
  938 
  939 void
  940 ndis_thresume(p)
  941         struct proc             *p;
  942 {
  943         wakeup(&p->p_sigpend.sp_set);
  944         
  945         return;
  946 }
  947 
  948 __stdcall static void
  949 ndis_sendrsrcavail_func(ndis_handle adapter)
  950 {
  951         return;
  952 }
  953 
  954 __stdcall static void
  955 ndis_status_func(ndis_handle adapter, ndis_status status, void *sbuf,
  956     uint32_t slen)
  957 {
  958         ndis_miniport_block     *block;
  959         struct ndis_softc       *sc;
  960         struct ifnet            *ifp;
  961 
  962         block = adapter;
  963 #ifdef __FreeBSD__      
  964         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
  965 #else /* __NetBSD__ */
  966         sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
  967 #endif  
  968         
  969 #ifdef __FreeBSD__
  970         ifp = &sc->arpcom.ac_if;
  971 #else
  972         ifp = &sc->arpcom.ec_if;
  973 #endif
  974         if (ifp->if_flags & IFF_DEBUG)
  975                 printf("%s: status: %x\n", 
  976                        sc->ndis_dev->dv_xname, status);
  977         return;
  978 }
  979 
  980 __stdcall static void
  981 ndis_statusdone_func(adapter)
  982         ndis_handle             adapter;
  983 {
  984         ndis_miniport_block     *block;
  985         struct ndis_softc       *sc;
  986         struct ifnet            *ifp;
  987 
  988         block = adapter;
  989 #ifdef __FreeBSD__      
  990         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
  991 #else /* __NetBSD__ */
  992         sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
  993 #endif  
  994         
  995 #ifdef __FreeBSD__
  996         ifp = &sc->arpcom.ac_if;
  997 #else
  998         ifp = &sc->arpcom.ec_if;
  999 #endif
 1000         if (ifp->if_flags & IFF_DEBUG)
 1001                 printf("%s: status complete\n",
 1002                        sc->ndis_dev->dv_xname);
 1003         return;
 1004 }
 1005 
 1006 __stdcall static void
 1007 ndis_setdone_func(adapter, status)
 1008         ndis_handle             adapter;
 1009         ndis_status             status;
 1010 {
 1011         ndis_miniport_block     *block;
 1012         block = adapter;
 1013 
 1014         block->nmb_setstat = status;
 1015         wakeup(&block->nmb_setstat);
 1016         return;
 1017 }
 1018 
 1019 __stdcall static void
 1020 ndis_getdone_func(adapter, status)
 1021         ndis_handle             adapter;
 1022         ndis_status             status;
 1023 {
 1024         ndis_miniport_block     *block;
 1025         block = adapter;
 1026 
 1027         block->nmb_getstat = status;
 1028         wakeup(&block->nmb_getstat);
 1029         return;
 1030 }
 1031 
 1032 __stdcall static void
 1033 ndis_resetdone_func(ndis_handle adapter, ndis_status status,
 1034     uint8_t addressingreset)
 1035 {
 1036         ndis_miniport_block     *block;
 1037         struct ndis_softc       *sc;
 1038         struct ifnet            *ifp;
 1039 
 1040         block = adapter;
 1041 #ifdef __FreeBSD__      
 1042         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
 1043 #else /* __NetBSD__ */
 1044         sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
 1045 #endif  
 1046         
 1047 #ifdef __FreeBSD__
 1048         ifp = &sc->arpcom.ac_if;
 1049 #else
 1050         ifp = &sc->arpcom.ec_if;
 1051 #endif
 1052 
 1053         if (ifp->if_flags & IFF_DEBUG)
 1054                 printf("%s: reset done...\n",
 1055                        sc->ndis_dev->dv_xname);
 1056         wakeup(sc);
 1057         return;
 1058 }
 1059 
 1060 #ifdef __FreeBSD__
 1061 /* FreeBSD version of ndis_create_sysctls() */
 1062 int
 1063 ndis_create_sysctls(arg)
 1064         void                    *arg;
 1065 {
 1066         struct ndis_softc       *sc;
 1067         ndis_cfg                *vals;
 1068         char                    buf[256];
 1069         struct sysctl_oid       *oidp;
 1070         struct sysctl_ctx_entry *e;
 1071 
 1072         if (arg == NULL)
 1073                 return(EINVAL);
 1074 
 1075         sc = arg;
 1076         vals = sc->ndis_regvals;
 1077 
 1078         TAILQ_INIT(&sc->ndis_cfglist_head);
 1079 
 1080 #if __FreeBSD_version < 502113
 1081         /* Create the sysctl tree. */
 1082 
 1083         sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
 1084             SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
 1085             device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
 1086             device_get_desc(sc->ndis_dev));
 1087 
 1088 #endif
 1089         /* Add the driver-specific registry keys. */
 1090 
 1091         vals = sc->ndis_regvals;
 1092         while(1) {
 1093                 if (vals->nc_cfgkey == NULL)
 1094                         break;
 1095                 if (vals->nc_idx != sc->ndis_devidx) {
 1096                         vals++;
 1097                         continue;
 1098                 }
 1099 
 1100                 /* See if we already have a sysctl with this name */
 1101 
 1102                 oidp = NULL;
 1103 #if __FreeBSD_version < 502113
 1104                 TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
 1105 #else
 1106                 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
 1107 #endif
 1108                         oidp = e->entry;
 1109                         if (ndis_strcasecmp(oidp->oid_name,
 1110                             vals->nc_cfgkey) == 0)
 1111                                 break;
 1112                         oidp = NULL;
 1113                 }
 1114 
 1115                 if (oidp != NULL) {
 1116                         vals++;
 1117                         continue;
 1118                 }
 1119 
 1120 #if __FreeBSD_version < 502113
 1121                 SYSCTL_ADD_STRING(&sc->ndis_ctx,
 1122                     SYSCTL_CHILDREN(sc->ndis_tree),
 1123 #else
 1124                 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
 1125                     SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
 1126 #endif
 1127                     OID_AUTO, vals->nc_cfgkey,
 1128                     CTLFLAG_RW, vals->nc_val,
 1129                     sizeof(vals->nc_val),
 1130                     vals->nc_cfgdesc);
 1131                 vals++;
 1132         }
 1133 
 1134         /* Now add a couple of builtin keys. */
 1135 
 1136         /*
 1137          * Environment can be either Windows (0) or WindowsNT (1).
 1138          * We qualify as the latter.
 1139          */
 1140         ndis_add_sysctl(sc, "Environment",
 1141             "Windows environment", "1", CTLFLAG_RD);
 1142 
 1143         /* NDIS version should be 5.1. */
 1144         ndis_add_sysctl(sc, "NdisVersion",
 1145             "NDIS API Version", "0x00050001", CTLFLAG_RD);
 1146 
 1147         /* Bus type (PCI, PCMCIA, etc...) */
 1148         sprintf(buf, "%d", (int)sc->ndis_iftype);
 1149         ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
 1150 
 1151         if (sc->ndis_res_io != NULL) {
 1152                 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io));
 1153                 ndis_add_sysctl(sc, "IOBaseAddress",
 1154                     "Base I/O Address", buf, CTLFLAG_RD);
 1155         }
 1156 
 1157         if (sc->ndis_irq != NULL) {
 1158                 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq));
 1159                 ndis_add_sysctl(sc, "InterruptNumber",
 1160                     "Interrupt Number", buf, CTLFLAG_RD);
 1161         }
 1162 
 1163         return(0);
 1164 }
 1165 #endif /* __FreeBSD__ */
 1166 
 1167 #ifdef __NetBSD__
 1168 /* NetBSD version of ndis_create_sysctls() */
 1169 int
 1170 ndis_create_sysctls(arg)
 1171         void                    *arg;
 1172 {
 1173         struct ndis_softc       *sc;
 1174         ndis_cfg                *vals;
 1175         const struct sysctlnode *ndis_node;
 1176         char buf[256];
 1177         
 1178         printf("in ndis_create_sysctls()\n");
 1179 
 1180         if (arg == NULL)
 1181                 return(EINVAL);
 1182 
 1183         sc = arg;
 1184         vals = sc->ndis_regvals;
 1185 
 1186         TAILQ_INIT(&sc->ndis_cfglist_head);
 1187 
 1188         /* Create the sysctl tree. */
 1189         sysctl_createv(&sc->sysctllog, 0, NULL, &ndis_node, CTLFLAG_READWRITE, CTLTYPE_NODE,
 1190                                         sc->ndis_dev->dv_xname, NULL, NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
 1191 
 1192         /* Store the number of the ndis mib */  
 1193         sc->ndis_sysctl_mib = ndis_node->sysctl_num;
 1194         
 1195         /* Add the driver-specific registry keys. */
 1196         vals = sc->ndis_regvals;
 1197         while(1) {
 1198                 if (vals->nc_cfgkey == NULL)
 1199                         break;
 1200                 if (vals->nc_idx != sc->ndis_devidx) {
 1201                         vals++;
 1202                         continue;
 1203                 }
 1204 
 1205                 /* See if we already have a sysctl with this name */
 1206 /* TODO: Is something like this necessary in NetBSD?  I'm guessing this
 1207    TODO: is just checking if any of the information in the .inf file was
 1208    TODO: already determined by FreeBSD's autoconfiguration which seems to
 1209    TODO: add dev.XXX sysctl's beginning with %.  (NetBSD dosen't seem to do this).
 1210 */                 
 1211 
 1212 /* TODO: use CTLFLAG_OWNDATA or not? */
 1213                    /*              
 1214                 sysctl_createv(&sc->sysctllog, 0, NULL, NULL, 
 1215                                                 CTLFLAG_READWRITE|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA, CTLTYPE_STRING, 
 1216                                                 vals->nc_cfgkey, vals->nc_cfgdesc, NULL, 0, vals->nc_val, strlen(vals->nc_val),
 1217                                             ndis_node->sysctl_num, CTL_CREATE, CTL_EOL);
 1218                    */
 1219                    ndis_add_sysctl(sc, vals->nc_cfgkey,
 1220                                                    vals->nc_cfgdesc, vals->nc_val, CTLFLAG_READWRITE);             
 1221                         
 1222                 vals++;
 1223         } /* end while */       
 1224 
 1225                 /* Now add a couple of builtin keys. */
 1226 
 1227         /*
 1228          * Environment can be either Windows (0) or WindowsNT (1).
 1229          * We qualify as the latter.
 1230          */     
 1231 #ifdef __NetBSD__
 1232 #define CTLFLAG_RD CTLFLAG_READONLY
 1233 /* TODO: do we need something like rman_get_start? */
 1234 #define rman_get_start(x) x
 1235 #endif                                          
 1236                 ndis_add_sysctl(sc, "Environment",
 1237                                                 "Windows environment", "1", CTLFLAG_RD);
 1238                                                 
 1239                 /* NDIS version should be 5.1. */
 1240                 ndis_add_sysctl(sc, "NdisVersion",
 1241                                                 /*"NDIS API Version"*/ "Version", "0x00050001", CTLFLAG_RD);
 1242                 
 1243                 /* Bus type (PCI, PCMCIA, etc...) */
 1244                 sprintf(buf, "%d", (int)sc->ndis_iftype);
 1245                 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
 1246 
 1247                 if (sc->ndis_res_io != NULL) {
 1248                         sprintf(buf, "0x%lx", (long unsigned int)rman_get_start(sc->ndis_res_io));
 1249                         ndis_add_sysctl(sc, "IOBaseAddress",
 1250                                                         /*"Base I/O Address"*/ "Base I/O", buf, CTLFLAG_RD);
 1251                 }
 1252 
 1253                 if (sc->ndis_irq != NULL) {
 1254                         sprintf(buf, "%lu", (long unsigned int)rman_get_start(sc->ndis_irq));
 1255                         ndis_add_sysctl(sc, "InterruptNumber",
 1256                                                         "Interrupt Number", buf, CTLFLAG_RD);
 1257                 }
 1258 
 1259                 return(0);      
 1260 }
 1261 #endif /* __NetBSD__ */
 1262 
 1263 char *ndis_strdup(const char *src);
 1264 
 1265 char *ndis_strdup(const char *src)
 1266 {
 1267         char *ret;
 1268         
 1269         ret = malloc(strlen(src), M_DEVBUF, M_NOWAIT|M_ZERO);
 1270         if (ret == NULL) {
 1271                 printf("ndis_strdup failed\n");
 1272                 return(NULL);
 1273         }
 1274         strcpy(ret, src);
 1275         
 1276         return ret;
 1277 }
 1278 
 1279 int
 1280 ndis_add_sysctl(arg, key, desc, val, flag)
 1281         void                    *arg;
 1282         const char              *key;
 1283         const char              *desc;
 1284         const char              *val;
 1285         int                     flag;
 1286 {
 1287         struct ndis_softc       *sc;
 1288         struct ndis_cfglist     *cfg;
 1289         char                    descstr[256];
 1290 #ifdef __NetBSD__
 1291         char newkey[MAX_SYSCTL_LEN+1];
 1292 #endif  
 1293 
 1294         sc = arg;
 1295 
 1296         cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
 1297 
 1298         if (cfg == NULL)
 1299                 return(ENOMEM);
 1300 
 1301         /* I added this because NetBSD sysctl node names can't begin with
 1302          * a digit.
 1303          */
 1304 #ifdef __NetBSD__       
 1305         if(strlen(key) + strlen("ndis_") > MAX_SYSCTL_LEN) {
 1306                 panic("sysctl name too long: %s\n", key);
 1307         }
 1308         strcpy(newkey, "ndis_");
 1309         strcpy(newkey + strlen("ndis_"), key);  
 1310         key = newkey;
 1311 #endif  
 1312         
 1313         cfg->ndis_cfg.nc_cfgkey = ndis_strdup(key);
 1314         
 1315         if (desc == NULL) {
 1316                 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
 1317                 cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(descstr);
 1318         } else
 1319                 cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(desc);
 1320         strcpy(cfg->ndis_cfg.nc_val, val);
 1321 
 1322         TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
 1323 
 1324 #ifdef __FreeBSD__
 1325 #if __FreeBSD_version < 502113
 1326         SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
 1327 #else
 1328         SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
 1329             SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
 1330 #endif
 1331             OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
 1332             cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
 1333             cfg->ndis_cfg.nc_cfgdesc);
 1334 #else /* __NetBSD__ */
 1335 /* TODO: use CTLFLAG_OWNDATA or not? */
 1336         sysctl_createv(&sc->sysctllog, 0, NULL, NULL, flag/*|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA*/, CTLTYPE_STRING, 
 1337                                         cfg->ndis_cfg.nc_cfgkey, cfg->ndis_cfg.nc_cfgdesc, NULL, 0, cfg->ndis_cfg.nc_val,
 1338                                         strlen(cfg->ndis_cfg.nc_val), sc->ndis_sysctl_mib, CTL_CREATE, CTL_EOL);        
 1339 #endif  
 1340         return(0);
 1341 }
 1342 
 1343 int
 1344 ndis_flush_sysctls(arg)
 1345         void                    *arg;
 1346 {
 1347         struct ndis_softc       *sc;
 1348         struct ndis_cfglist     *cfg;
 1349 
 1350         sc = arg;
 1351 
 1352         while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
 1353                 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
 1354                 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
 1355 #ifdef __FreeBSD__              
 1356                 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
 1357                 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
 1358 #endif          
 1359                 free(cfg, M_DEVBUF);
 1360         }
 1361 
 1362         return(0);
 1363 }
 1364 
 1365 static void
 1366 ndis_return(arg)
 1367         void                    *arg;
 1368 {
 1369         struct ndis_softc       *sc;
 1370         __stdcall ndis_return_handler   returnfunc;
 1371         ndis_handle             adapter;
 1372         ndis_packet             *p;
 1373         uint8_t                 irql = 0;       /* XXX: gcc */
 1374 
 1375         p = arg;
 1376         sc = p->np_softc;
 1377         adapter = sc->ndis_block->nmb_miniportadapterctx;
 1378 
 1379         if (adapter == NULL)
 1380                 return;
 1381 
 1382         returnfunc = sc->ndis_chars->nmc_return_packet_func;
 1383 
 1384         KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
 1385         MSCALL2(returnfunc, adapter, p);
 1386         KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 1387 
 1388         return;
 1389 }
 1390 
 1391 void
 1392 #ifdef __FreeBSD__
 1393 ndis_return_packet(buf, arg)
 1394         void                    *buf;   /* not used */
 1395         void                    *arg;
 1396 #else
 1397 ndis_return_packet(struct mbuf *m, void *buf,
 1398     size_t size, void *arg)
 1399 #endif
 1400 
 1401 {
 1402         ndis_packet             *p;
 1403 
 1404         if (arg == NULL)
 1405                 return;
 1406 
 1407         p = arg;
 1408 
 1409         /* Decrement refcount. */
 1410         p->np_refcnt--;
 1411 
 1412         /* Release packet when refcount hits zero, otherwise return. */
 1413         if (p->np_refcnt)
 1414                 return;
 1415 
 1416         ndis_sched(ndis_return, p, NDIS_TASKQUEUE);
 1417 
 1418         return;
 1419 }
 1420 
 1421 void
 1422 ndis_free_bufs(b0)
 1423         ndis_buffer             *b0;
 1424 {
 1425         ndis_buffer             *next;
 1426 
 1427         if (b0 == NULL)
 1428                 return;
 1429 
 1430         while(b0 != NULL) {
 1431                 next = b0->mdl_next;
 1432                 IoFreeMdl(b0);
 1433                 b0 = next;
 1434         }
 1435 
 1436         return;
 1437 }
 1438 int in_reset = 0;
 1439 void
 1440 ndis_free_packet(p)
 1441         ndis_packet             *p;
 1442 {
 1443         if (p == NULL)
 1444                 return;
 1445 
 1446         ndis_free_bufs(p->np_private.npp_head);
 1447         NdisFreePacket(p);
 1448         return;
 1449 }
 1450 
 1451 #ifdef __FreeBSD__
 1452 int
 1453 ndis_convert_res(arg)
 1454         void                    *arg;
 1455 {
 1456         struct ndis_softc       *sc;
 1457         ndis_resource_list      *rl = NULL;
 1458         cm_partial_resource_desc        *prd = NULL;
 1459         ndis_miniport_block     *block;
 1460         device_t                dev;
 1461         struct resource_list    *brl;
 1462         struct resource_list_entry      *brle;
 1463 #if __FreeBSD_version < 600022
 1464         struct resource_list    brl_rev;
 1465         struct resource_list_entry      *n;
 1466 #endif
 1467         int                     error = 0;
 1468 
 1469         sc = arg;
 1470         block = sc->ndis_block;
 1471         dev = sc->ndis_dev;
 1472 
 1473 #if __FreeBSD_version < 600022
 1474         SLIST_INIT(&brl_rev);
 1475 #endif
 1476         rl = malloc(sizeof(ndis_resource_list) +
 1477             (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
 1478             M_DEVBUF, M_NOWAIT|M_ZERO);
 1479 
 1480         if (rl == NULL)
 1481                 return(ENOMEM);
 1482 
 1483         rl->cprl_version = 5;
 1484         rl->cprl_version = 1;
 1485         rl->cprl_count = sc->ndis_rescnt;
 1486         prd = rl->cprl_partial_descs;
 1487 
 1488         brl = BUS_GET_RESOURCE_LIST(dev, dev);
 1489 
 1490         if (brl != NULL) {
 1491 
 1492 #if __FreeBSD_version < 600022
 1493                 /*
 1494                  * We have a small problem. Some PCI devices have
 1495                  * multiple I/O ranges. Windows orders them starting
 1496                  * from lowest numbered BAR to highest. We discover
 1497                  * them in that order too, but insert them into a singly
 1498                  * linked list head first, which means when time comes
 1499                  * to traverse the list, we enumerate them in reverse
 1500                  * order. This screws up some drivers which expect the
 1501                  * BARs to be in ascending order so that they can choose
 1502                  * the "first" one as their register space. Unfortunately,
 1503                  * in order to fix this, we have to create our own
 1504                  * temporary list with the entries in reverse order.
 1505                  */
 1506                 SLIST_FOREACH(brle, brl, link) {
 1507                         n = malloc(sizeof(struct resource_list_entry),
 1508                             M_TEMP, M_NOWAIT);
 1509                         if (n == NULL) {
 1510                                 error = ENOMEM;
 1511                                 goto bad;
 1512                         }
 1513                         bcopy((char *)brle, (char *)n,
 1514                             sizeof(struct resource_list_entry));
 1515                         SLIST_INSERT_HEAD(&brl_rev, n, link);
 1516                 }
 1517 
 1518                 SLIST_FOREACH(brle, &brl_rev, link) {
 1519 #else
 1520                 STAILQ_FOREACH(brle, brl, link) {
 1521 #endif
 1522                         switch (brle->type) {
 1523                         case SYS_RES_IOPORT:
 1524                                 prd->cprd_type = CmResourceTypePort;
 1525                                 prd->cprd_flags = CM_RESOURCE_PORT_IO;
 1526                                 prd->cprd_sharedisp =
 1527                                     CmResourceShareDeviceExclusive;
 1528                                 prd->u.cprd_port.cprd_start.np_quad =
 1529                                     brle->start;
 1530                                 prd->u.cprd_port.cprd_len = brle->count;
 1531                                 break;
 1532                         case SYS_RES_MEMORY:
 1533                                 prd->cprd_type = CmResourceTypeMemory;
 1534                                 prd->cprd_flags =
 1535                                     CM_RESOURCE_MEMORY_READ_WRITE;
 1536                                 prd->cprd_sharedisp =
 1537                                     CmResourceShareDeviceExclusive;
 1538                                 prd->u.cprd_port.cprd_start.np_quad =
 1539                                     brle->start;
 1540                                 prd->u.cprd_port.cprd_len = brle->count;
 1541                                 break;
 1542                         case SYS_RES_IRQ:
 1543                                 prd->cprd_type = CmResourceTypeInterrupt;
 1544                                 prd->cprd_flags = 0;
 1545                                 prd->cprd_sharedisp =
 1546                                     CmResourceShareDeviceExclusive;
 1547                                 prd->u.cprd_intr.cprd_level = brle->start;
 1548                                 prd->u.cprd_intr.cprd_vector = brle->start;
 1549                                 prd->u.cprd_intr.cprd_affinity = 0;
 1550                                 break;
 1551                         default:
 1552                                 break;
 1553                         }
 1554                         prd++;
 1555                 }
 1556         }
 1557 
 1558         block->nmb_rlist = rl;
 1559 
 1560 #if __FreeBSD_version < 600022
 1561 bad:
 1562 
 1563         while (!SLIST_EMPTY(&brl_rev)) {
 1564                 n = SLIST_FIRST(&brl_rev);
 1565                 SLIST_REMOVE_HEAD(&brl_rev, link);
 1566                 free (n, M_TEMP);
 1567         }
 1568 #endif
 1569 
 1570         return(error);
 1571 }
 1572 #endif /* __FreeBSD__ */
 1573 /*
 1574  * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
 1575  * packet, it will hand it to us in the form of an ndis_packet,
 1576  * which we need to convert to an mbuf that is then handed off
 1577  * to the stack. Note: we configure the mbuf list so that it uses
 1578  * the memory regions specified by the ndis_buffer structures in
 1579  * the ndis_packet as external storage. In most cases, this will
 1580  * point to a memory region allocated by the driver (either by
 1581  * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
 1582  * the driver to handle free()ing this region for is, so we set up
 1583  * a dummy no-op free handler for it.
 1584  */ 
 1585 
 1586 int
 1587 ndis_ptom(m0, p)
 1588         struct mbuf             **m0;
 1589         ndis_packet             *p;
 1590 {
 1591         struct mbuf             *m, *prev = NULL;
 1592         ndis_buffer             *buf;
 1593         ndis_packet_private     *priv;
 1594         uint32_t                totlen = 0;
 1595 
 1596         if (p == NULL || m0 == NULL)
 1597                 return(EINVAL);
 1598 
 1599         priv = &p->np_private;
 1600         buf = priv->npp_head;
 1601         p->np_refcnt = 0;
 1602 
 1603         for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) {
 1604                 if (buf == priv->npp_head)
 1605                         MGETHDR(m, M_DONTWAIT, MT_HEADER);
 1606                 else
 1607                         MGET(m, M_DONTWAIT, MT_DATA);
 1608                 if (m == NULL) {
 1609                         m_freem(*m0);
 1610                         *m0 = NULL;
 1611                         return(ENOBUFS);
 1612                 }
 1613                 m->m_len = MmGetMdlByteCount(buf);
 1614                 m->m_data = MmGetMdlVirtualAddress(buf);
 1615 #ifdef __FreeBSD__
 1616                 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
 1617                         p, 0, EXT_NDIS);
 1618 #else
 1619                 MEXTADD(m, m->m_data, m->m_len, M_DEVBUF,
 1620                         ndis_return_packet, p);
 1621 #endif
 1622                 p->np_refcnt++;
 1623                 totlen += m->m_len;
 1624                 if (m->m_flags & MT_HEADER)
 1625                         *m0 = m;
 1626                 else
 1627                         prev->m_next = m;
 1628                 prev = m;
 1629         }
 1630 
 1631         (*m0)->m_pkthdr.len = totlen;
 1632 
 1633         return(0);
 1634 }
 1635 
 1636 /*
 1637  * Create an NDIS packet from an mbuf chain.
 1638  * This is used mainly when transmitting packets, where we need
 1639  * to turn an mbuf off an interface's send queue and transform it
 1640  * into an NDIS packet which will be fed into the NDIS driver's
 1641  * send routine.
 1642  *
 1643  * NDIS packets consist of two parts: an ndis_packet structure,
 1644  * which is vaguely analagous to the pkthdr portion of an mbuf,
 1645  * and one or more ndis_buffer structures, which define the
 1646  * actual memory segments in which the packet data resides.
 1647  * We need to allocate one ndis_buffer for each mbuf in a chain,
 1648  * plus one ndis_packet as the header.
 1649  */
 1650 
 1651 int
 1652 ndis_mtop(m0, p)
 1653         struct mbuf             *m0;
 1654         ndis_packet             **p;
 1655 {
 1656         struct mbuf             *m;
 1657         ndis_buffer             *buf = NULL, *prev = NULL;
 1658         ndis_packet_private     *priv;
 1659 
 1660         if (p == NULL || *p == NULL || m0 == NULL)
 1661                 return(EINVAL);
 1662 
 1663         priv = &(*p)->np_private;
 1664         priv->npp_totlen = m0->m_pkthdr.len;
 1665 
 1666         for (m = m0; m != NULL; m = m->m_next) {
 1667                 if (m->m_len == 0)
 1668                         continue;
 1669                 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL);
 1670                 if (buf == NULL) {
 1671                         ndis_free_packet(*p);
 1672                         *p = NULL;
 1673                         return(ENOMEM);
 1674                 }
 1675 
 1676                 if (priv->npp_head == NULL)
 1677                         priv->npp_head = buf;
 1678                 else
 1679                         prev->mdl_next = buf;
 1680                 prev = buf;
 1681         }
 1682 
 1683         priv->npp_tail = buf;
 1684 
 1685         return(0);
 1686 }
 1687 
 1688 int
 1689 ndis_get_supported_oids(arg, oids, oidcnt)
 1690         void                    *arg;
 1691         ndis_oid                **oids;
 1692         int                     *oidcnt;
 1693 {
 1694         int                     len, rval;
 1695         ndis_oid                *o;
 1696 
 1697         if (arg == NULL || oids == NULL || oidcnt == NULL)
 1698                 return(EINVAL);
 1699         len = 0;
 1700         ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
 1701 
 1702         o = malloc(len, M_DEVBUF, M_NOWAIT);
 1703         if (o == NULL)
 1704                 return(ENOMEM);
 1705 
 1706         rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
 1707 
 1708         if (rval) {
 1709                 free(o, M_DEVBUF);
 1710                 return(rval);
 1711         }
 1712 
 1713         *oids = o;
 1714         *oidcnt = len / 4;
 1715 
 1716         return(0);
 1717 }
 1718 
 1719 int
 1720 ndis_set_info(arg, oid, buf, buflen)
 1721         void                    *arg;
 1722         ndis_oid                oid;
 1723         void                    *buf;
 1724         int                     *buflen;
 1725 {
 1726         struct ndis_softc       *sc;
 1727         ndis_status             rval;
 1728         ndis_handle             adapter;
 1729         __stdcall ndis_setinfo_handler  setfunc;
 1730         uint32_t                byteswritten = 0, bytesneeded = 0;
 1731         int                     error;
 1732         uint8_t                 irql = 0;       /* XXX: gcc */
 1733 #ifdef __NetBSD__
 1734         int                     s;
 1735 #endif
 1736 
 1737         /*
 1738          * According to the NDIS spec, MiniportQueryInformation()
 1739          * and MiniportSetInformation() requests are handled serially:
 1740          * once one request has been issued, we must wait for it to
 1741          * finish before allowing another request to proceed.
 1742          */
 1743 
 1744         sc = arg;
 1745 
 1746         KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
 1747 
 1748         if (sc->ndis_block->nmb_pendingreq != NULL)
 1749                 panic("ndis_set_info() called while other request pending");
 1750         else
 1751                 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
 1752 
 1753         /* I added this lock because it was present in the FreeBSD-current sources */
 1754         NDIS_LOCK(sc);
 1755         
 1756         setfunc = sc->ndis_chars->nmc_setinfo_func;
 1757         adapter = sc->ndis_block->nmb_miniportadapterctx;
 1758 
 1759         if (adapter == NULL || setfunc == NULL) {
 1760                 sc->ndis_block->nmb_pendingreq = NULL;
 1761                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 1762                 NDIS_UNLOCK(sc);
 1763                 return(ENXIO);
 1764         }
 1765         
 1766         NDIS_UNLOCK(sc);
 1767         
 1768         rval = MSCALL6(setfunc, adapter, oid, buf, *buflen,
 1769             &byteswritten, &bytesneeded);
 1770 
 1771         sc->ndis_block->nmb_pendingreq = NULL;
 1772 
 1773         KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 1774 
 1775         if (rval == NDIS_STATUS_PENDING) {
 1776                 mtx_lock(&ndis_req_mtx);
 1777 #ifdef __FreeBSD__
 1778                 error = msleep(&sc->ndis_block->nmb_setstat,
 1779                     &ndis_req_mtx,
 1780                     curthread->td_priority|PDROP,
 1781                     "ndisset", 5 * hz);
 1782 #else
 1783                 error = ltsleep(&sc->ndis_block->nmb_setstat,
 1784                                 curlwp->l_priority|PNORELOCK, 
 1785                                 "ndisset", 5 * hz, 0);
 1786 #endif
 1787                 rval = sc->ndis_block->nmb_setstat;
 1788 #ifdef __NetBSD__
 1789                 mtx_unlock(&ndis_req_mtx);
 1790 #endif
 1791         }
 1792 
 1793 
 1794         if (byteswritten)
 1795                 *buflen = byteswritten;
 1796         if (bytesneeded)
 1797                 *buflen = bytesneeded;
 1798 
 1799         if (rval == NDIS_STATUS_INVALID_LENGTH)
 1800                 return(ENOSPC);
 1801 
 1802         if (rval == NDIS_STATUS_INVALID_OID)
 1803                 return(EINVAL);
 1804 
 1805         if (rval == NDIS_STATUS_NOT_SUPPORTED ||
 1806             rval == NDIS_STATUS_NOT_ACCEPTED)
 1807                 return(ENOTSUP);
 1808 
 1809         if (rval != NDIS_STATUS_SUCCESS)
 1810                 return(ENODEV);
 1811 
 1812         return(0);
 1813 }
 1814 
 1815 typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
 1816 
 1817 int
 1818 ndis_send_packets(arg, packets, cnt)
 1819         void                    *arg;
 1820         ndis_packet             **packets;
 1821         int                     cnt;
 1822 {
 1823         struct ndis_softc       *sc;
 1824         ndis_handle             adapter;
 1825         __stdcall ndis_sendmulti_handler        sendfunc;
 1826         __stdcall ndis_senddone_func            senddonefunc;
 1827         int                     i;
 1828         ndis_packet             *p;
 1829         uint8_t                 irql = 0;       /* XXX: gcc */
 1830 
 1831         sc = arg;
 1832         adapter = sc->ndis_block->nmb_miniportadapterctx;
 1833         if (adapter == NULL)
 1834                 return(ENXIO);
 1835         sendfunc = sc->ndis_chars->nmc_sendmulti_func;
 1836         senddonefunc = sc->ndis_block->nmb_senddone_func;
 1837 
 1838         if (NDIS_SERIALIZED(sc->ndis_block))
 1839                 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
 1840 
 1841         MSCALL3(sendfunc, adapter, packets, cnt);
 1842 
 1843         for (i = 0; i < cnt; i++) {
 1844                 p = packets[i];
 1845                 /*
 1846                  * Either the driver already handed the packet to
 1847                  * ndis_txeof() due to a failure, or it wants to keep
 1848                  * it and release it asynchronously later. Skip to the
 1849                  * next one.
 1850                  */
 1851                 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
 1852                         continue;
 1853                 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status);
 1854         }
 1855 
 1856         if (NDIS_SERIALIZED(sc->ndis_block))
 1857                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 1858 
 1859         return(0);
 1860 }
 1861 
 1862 int
 1863 ndis_send_packet(arg, packet)
 1864         void                    *arg;
 1865         ndis_packet             *packet;
 1866 {
 1867         struct ndis_softc       *sc;
 1868         ndis_handle             adapter;
 1869         ndis_status             status;
 1870         __stdcall ndis_sendsingle_handler       sendfunc;
 1871         __stdcall ndis_senddone_func            senddonefunc;
 1872         uint8_t                 irql = 0;       /* XXX: gcc */
 1873 
 1874         sc = arg;
 1875         adapter = sc->ndis_block->nmb_miniportadapterctx;
 1876         if (adapter == NULL)
 1877                 return(ENXIO);
 1878         sendfunc = sc->ndis_chars->nmc_sendsingle_func;
 1879         senddonefunc = sc->ndis_block->nmb_senddone_func;
 1880 
 1881         if (NDIS_SERIALIZED(sc->ndis_block))
 1882                 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
 1883         status = MSCALL3(sendfunc, adapter, packet,
 1884             packet->np_private.npp_flags);
 1885 
 1886         if (status == NDIS_STATUS_PENDING) {
 1887                 if (NDIS_SERIALIZED(sc->ndis_block))
 1888                         KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 1889                 return(0);
 1890         }
 1891 
 1892         MSCALL3(senddonefunc, sc->ndis_block, packet, status);
 1893 
 1894         if (NDIS_SERIALIZED(sc->ndis_block))
 1895                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 1896 
 1897         return(0);
 1898 }
 1899 
 1900 int
 1901 ndis_init_dma(arg)
 1902         void                    *arg;
 1903 {
 1904         struct ndis_softc       *sc;
 1905         int                     i, error = 0;
 1906 
 1907         sc = arg;
 1908 
 1909         sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
 1910             M_DEVBUF, M_NOWAIT|M_ZERO);
 1911 
 1912         if (sc->ndis_tmaps == NULL)
 1913                 return(ENOMEM);
 1914 
 1915         for (i = 0; i < sc->ndis_maxpkts; i++) {
 1916 #ifdef __FreeBSD__
 1917                 error = bus_dmamap_create(sc->ndis_ttag, 0,
 1918                     &sc->ndis_tmaps[i]);
 1919 #else
 1920                 /*
 1921                 bus_dmamap_create(sc->ndis_mtag, sizeof(bus_dmamap_t), 
 1922                                   1, sizeof(bus_dmamap_t), BUS_DMA_NOWAIT, 
 1923                                   0, &sc->ndis_mmaps[i]);
 1924                 */      
 1925                 bus_dmamap_create(sc->ndis_ttag, NDIS_MAXSEG * MCLBYTES, 
 1926                                   NDIS_MAXSEG, MCLBYTES, 0, 
 1927                                   BUS_DMA_NOWAIT, &sc->ndis_tmaps[i]);
 1928 #endif
 1929                 if (error) {
 1930                         free(sc->ndis_tmaps, M_DEVBUF);
 1931                         return(ENODEV);
 1932                 }
 1933         }
 1934 
 1935         return(0);
 1936 }
 1937 
 1938 int
 1939 ndis_destroy_dma(arg)
 1940         void                    *arg;
 1941 {
 1942         struct ndis_softc       *sc;
 1943         struct mbuf             *m;
 1944         ndis_packet             *p = NULL;
 1945         int                     i;
 1946 
 1947         sc = arg;
 1948 
 1949         for (i = 0; i < sc->ndis_maxpkts; i++) {
 1950                 if (sc->ndis_txarray[i] != NULL) {
 1951                         p = sc->ndis_txarray[i];
 1952                         m = (struct mbuf *)p->np_rsvd[1];
 1953                         if (m != NULL)
 1954                                 m_freem(m);
 1955                         ndis_free_packet(sc->ndis_txarray[i]);
 1956                 }
 1957                 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
 1958         }
 1959 
 1960         free(sc->ndis_tmaps, M_DEVBUF);
 1961 
 1962 #ifdef __FreeBSD__
 1963         bus_dma_tag_destroy(sc->ndis_ttag);
 1964 #endif
 1965 
 1966         return(0);
 1967 }
 1968 
 1969 int
 1970 ndis_reset_nic(arg)
 1971         void                    *arg;
 1972 {
 1973         struct ndis_softc       *sc;
 1974         ndis_handle             adapter;
 1975         __stdcall ndis_reset_handler    resetfunc;
 1976         uint8_t                 addressing_reset;
 1977         struct ifnet            *ifp;
 1978         int                     rval;
 1979         uint8_t                 irql = 0;       /* XXX: gcc */
 1980 
 1981         sc = arg;
 1982 #ifdef __FreeBSD__
 1983         ifp = &sc->arpcom.ac_if;
 1984 #else
 1985         ifp = &sc->arpcom.ec_if;
 1986 #endif
 1987 
 1988         adapter = sc->ndis_block->nmb_miniportadapterctx;
 1989         resetfunc = sc->ndis_chars->nmc_reset_func;
 1990 
 1991         if (adapter == NULL || resetfunc == NULL)
 1992                 return(EIO);
 1993 
 1994         if (NDIS_SERIALIZED(sc->ndis_block))
 1995                 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
 1996 
 1997         rval = MSCALL2(resetfunc, &addressing_reset, adapter);
 1998 
 1999         if (NDIS_SERIALIZED(sc->ndis_block))
 2000                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 2001 
 2002         if (rval == NDIS_STATUS_PENDING) {
 2003                 mtx_lock(&ndis_req_mtx);
 2004 #ifdef __FreeBSD__
 2005                 msleep(sc, &ndis_req_mtx,
 2006                        curthread->td_priority|PDROP, "ndisrst", 0);
 2007 #else
 2008                 ltsleep(sc, curlwp->l_priority|PNORELOCK, "ndisrst", 0, 0);
 2009 #endif
 2010         }
 2011 
 2012         return(0);
 2013 }
 2014 
 2015 int
 2016 ndis_halt_nic(arg)
 2017         void                    *arg;
 2018 {
 2019         struct ndis_softc       *sc;
 2020         ndis_handle             adapter;
 2021         __stdcall ndis_halt_handler     haltfunc;
 2022         struct ifnet            *ifp;
 2023 #ifdef __NetBSD__
 2024         int                     s;
 2025 #endif  
 2026 
 2027         sc = arg;
 2028 #ifdef __FreeBSD__
 2029         ifp = &sc->arpcom.ac_if;
 2030 #else
 2031         ifp = &sc->arpcom.ec_if;
 2032 #endif
 2033 
 2034         NDIS_LOCK(sc);
 2035         
 2036         adapter = sc->ndis_block->nmb_miniportadapterctx;
 2037         if (adapter == NULL) {
 2038                 NDIS_UNLOCK(sc);        
 2039                 return(EIO);
 2040         }
 2041 
 2042         /*
 2043          * The adapter context is only valid after the init
 2044          * handler has been called, and is invalid once the
 2045          * halt handler has been called.
 2046          */
 2047 
 2048         haltfunc = sc->ndis_chars->nmc_halt_func;
 2049                 
 2050         NDIS_UNLOCK(sc);
 2051 
 2052         MSCALL1(haltfunc, adapter);
 2053 
 2054         NDIS_LOCK(sc);
 2055                         
 2056         sc->ndis_block->nmb_miniportadapterctx = NULL;
 2057 
 2058         NDIS_UNLOCK(sc);        
 2059 
 2060         return(0);
 2061 }
 2062 
 2063 int
 2064 ndis_shutdown_nic(arg)
 2065         void                    *arg;
 2066 {
 2067         struct ndis_softc       *sc;
 2068         ndis_handle             adapter;
 2069         __stdcall ndis_shutdown_handler shutdownfunc;
 2070 #ifdef __NetBSD__
 2071         int                     s;
 2072 #endif  
 2073 
 2074         sc = arg;
 2075         
 2076         NDIS_LOCK(sc);
 2077         
 2078         adapter = sc->ndis_block->nmb_miniportadapterctx;
 2079         shutdownfunc = sc->ndis_chars->nmc_shutdown_handler;
 2080         
 2081         NDIS_UNLOCK(sc);
 2082 
 2083         if (adapter == NULL || shutdownfunc == NULL)
 2084                 return(EIO);
 2085 
 2086         if (sc->ndis_chars->nmc_rsvd0 == NULL)
 2087                 MSCALL1(shutdownfunc, adapter);
 2088         else
 2089                 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0);
 2090 
 2091         ndis_shrink_thrqueue(8);
 2092         TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
 2093 
 2094         return(0);
 2095 }
 2096 
 2097 int
 2098 ndis_init_nic(arg)
 2099         void                    *arg;
 2100 {
 2101         struct ndis_softc       *sc;
 2102         ndis_miniport_block     *block;
 2103         __stdcall ndis_init_handler     initfunc;
 2104         ndis_status             status, openstatus = 0;
 2105         ndis_medium             mediumarray[NdisMediumMax];
 2106         uint32_t                chosenmedium, i;
 2107 #ifdef __NetBSD__
 2108         int                     s;
 2109 #endif  
 2110 
 2111         if (arg == NULL)
 2112                 return(EINVAL);
 2113 
 2114         sc = arg;
 2115 
 2116         NDIS_LOCK(sc);
 2117         
 2118         block = sc->ndis_block;
 2119         initfunc = sc->ndis_chars->nmc_init_func;
 2120 
 2121         NDIS_UNLOCK(sc);        
 2122         
 2123         printf("sc->ndis_chars->nmc_version_major = %d\n\
 2124                         sc->ndis_chars->nmc_version_minor = %d\n", 
 2125                         sc->ndis_chars->nmc_version_major,
 2126                         sc->ndis_chars->nmc_version_minor);
 2127 
 2128         for (i = 0; i < NdisMediumMax; i++)
 2129                 mediumarray[i] = i;
 2130 
 2131         status = MSCALL6(initfunc, &openstatus, &chosenmedium,
 2132             mediumarray, NdisMediumMax, block, block);
 2133                 
 2134         printf("status = %x", status);          
 2135 
 2136         /*
 2137          * If the init fails, blow away the other exported routines
 2138          * we obtained from the driver so we can't call them later.
 2139          * If the init failed, none of these will work.
 2140          */
 2141         if (status != NDIS_STATUS_SUCCESS) {
 2142                 NDIS_LOCK(sc);
 2143                                         
 2144                 sc->ndis_block->nmb_miniportadapterctx = NULL;
 2145                 
 2146                 NDIS_UNLOCK(sc);                        
 2147                 return(ENXIO);
 2148         }
 2149 
 2150         return(0);
 2151 }
 2152 
 2153 void
 2154 ndis_enable_intr(arg)
 2155         void                    *arg;
 2156 {
 2157         struct ndis_softc       *sc;
 2158         ndis_handle             adapter;
 2159         __stdcall ndis_enable_interrupts_handler        intrenbfunc;
 2160 
 2161         sc = arg;
 2162         adapter = sc->ndis_block->nmb_miniportadapterctx;
 2163         intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func;
 2164         if (adapter == NULL || intrenbfunc == NULL)
 2165                 return;
 2166         MSCALL1(intrenbfunc, adapter);
 2167 
 2168         return;
 2169 }
 2170 
 2171 void
 2172 ndis_disable_intr(arg)
 2173         void                    *arg;
 2174 {
 2175         struct ndis_softc       *sc;
 2176         ndis_handle             adapter;
 2177         __stdcall ndis_disable_interrupts_handler       intrdisfunc;
 2178 
 2179         sc = arg;
 2180         adapter = sc->ndis_block->nmb_miniportadapterctx;
 2181         intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func;
 2182         if (adapter == NULL || intrdisfunc == NULL)
 2183             return;
 2184 
 2185         MSCALL1(intrdisfunc, adapter);
 2186 
 2187         return;
 2188 }
 2189 
 2190 int
 2191 ndis_isr(arg, ourintr, callhandler)
 2192         void                    *arg;
 2193         int                     *ourintr;
 2194         int                     *callhandler;
 2195 {
 2196         struct ndis_softc       *sc;
 2197         ndis_handle             adapter;
 2198         __stdcall ndis_isr_handler      isrfunc;
 2199         uint8_t                 accepted, queue;
 2200 
 2201         if (arg == NULL || ourintr == NULL || callhandler == NULL)
 2202                 return(EINVAL);
 2203 
 2204         sc = arg;
 2205         adapter = sc->ndis_block->nmb_miniportadapterctx;
 2206         isrfunc = sc->ndis_chars->nmc_isr_func;
 2207 
 2208         if (adapter == NULL || isrfunc == NULL)
 2209                 return(ENXIO);
 2210 
 2211         MSCALL3(isrfunc, &accepted, &queue, adapter);
 2212 
 2213         *ourintr = accepted;
 2214         *callhandler = queue;
 2215 
 2216         return(0);
 2217 }
 2218 
 2219 __stdcall static void
 2220 ndis_intrhand(kdpc *dpc, device_object *dobj,
 2221     irp *ip, struct ndis_softc *sc)
 2222 {
 2223         ndis_handle             adapter;
 2224         __stdcall ndis_interrupt_handler        intrfunc;
 2225         uint8_t                 irql = 0;       /* XXX: gcc */
 2226 
 2227         adapter = sc->ndis_block->nmb_miniportadapterctx;
 2228         intrfunc = sc->ndis_chars->nmc_interrupt_func;
 2229 
 2230         if (adapter == NULL || intrfunc == NULL)
 2231                 return;
 2232 
 2233         if (NDIS_SERIALIZED(sc->ndis_block))
 2234                 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
 2235 
 2236         MSCALL1(intrfunc, adapter);
 2237 
 2238         /* If there's a MiniportEnableInterrupt() routine, call it. */
 2239 
 2240         ndis_enable_intr(sc);
 2241 
 2242         if (NDIS_SERIALIZED(sc->ndis_block))
 2243                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 2244 
 2245         return;
 2246 }
 2247 
 2248 int
 2249 ndis_get_info(arg, oid, buf, buflen)
 2250         void                    *arg;
 2251         ndis_oid                oid;
 2252         void                    *buf;
 2253         int                     *buflen;
 2254 {
 2255         struct ndis_softc       *sc;
 2256         ndis_status             rval;
 2257         ndis_handle             adapter;
 2258         __stdcall ndis_queryinfo_handler        queryfunc;
 2259         uint32_t                byteswritten = 0, bytesneeded = 0;
 2260 #ifdef __FreeBSD__      
 2261         int                     error;
 2262 #endif
 2263         uint8_t                 irql = 0;       /* XXX: gcc */
 2264         
 2265         //printf("in ndis_get_info\n");
 2266         
 2267         sc = arg;
 2268         KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
 2269 
 2270         if (sc->ndis_block->nmb_pendingreq != NULL)
 2271                 panic("ndis_get_info() called while other request pending");
 2272         else
 2273                 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
 2274 
 2275         queryfunc = sc->ndis_chars->nmc_queryinfo_func;
 2276         adapter = sc->ndis_block->nmb_miniportadapterctx;
 2277 
 2278         if (adapter == NULL || queryfunc == NULL) {
 2279                 sc->ndis_block->nmb_pendingreq = NULL;
 2280                 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 2281                 return(ENXIO);
 2282         }
 2283 
 2284         rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen,
 2285             &byteswritten, &bytesneeded);
 2286 
 2287         sc->ndis_block->nmb_pendingreq = NULL;
 2288 
 2289         KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
 2290 
 2291         /* Wait for requests that block. */
 2292 
 2293         if (rval == NDIS_STATUS_PENDING) {
 2294                 mtx_lock(&ndis_req_mtx);
 2295 #ifdef __FreeBSD__
 2296                 error = msleep(&sc->ndis_block->nmb_getstat,
 2297                     &ndis_req_mtx,
 2298                     curthread->td_priority|PDROP,
 2299                     "ndisget", 5 * hz);
 2300 #else
 2301                 ltsleep(&sc->ndis_block->nmb_getstat,
 2302                         curlwp->l_priority|PNORELOCK, "ndisget", 5 * hz, 0);
 2303 #endif
 2304                 rval = sc->ndis_block->nmb_getstat;
 2305         }
 2306 
 2307         if (byteswritten)
 2308                 *buflen = byteswritten;
 2309         if (bytesneeded)
 2310                 *buflen = bytesneeded;
 2311 
 2312         if (rval == NDIS_STATUS_INVALID_LENGTH ||
 2313             rval == NDIS_STATUS_BUFFER_TOO_SHORT)
 2314                 return(ENOSPC);
 2315 
 2316         if (rval == NDIS_STATUS_INVALID_OID)
 2317                 return(EINVAL);
 2318 
 2319         if (rval == NDIS_STATUS_NOT_SUPPORTED ||
 2320             rval == NDIS_STATUS_NOT_ACCEPTED)
 2321                 return(ENOTSUP);
 2322 
 2323         if (rval != NDIS_STATUS_SUCCESS)
 2324                 return(ENODEV);
 2325 
 2326         return(0);
 2327 }
 2328 
 2329 __stdcall uint32_t
 2330 NdisAddDevice(drv, pdo)
 2331         driver_object           *drv;
 2332         device_object           *pdo;
 2333 {
 2334         device_object           *fdo;
 2335         ndis_miniport_block     *block;
 2336         struct ndis_softc       *sc;
 2337         uint32_t                status;
 2338 
 2339         status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL,
 2340             FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
 2341 
 2342         if (status != STATUS_SUCCESS)
 2343                 return(status);
 2344 
 2345         block = fdo->do_devext;
 2346         block->nmb_deviceobj = fdo;
 2347         block->nmb_physdeviceobj = pdo;
 2348         block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo);
 2349         KeInitializeSpinLock(&block->nmb_lock);
 2350         
 2351 #ifdef __NetBSD__
 2352         /* NetBSD has a pointer to the callout object */
 2353         block->nmb_wkupdpctimer.nt_ktimer.k_handle = 
 2354                 malloc(sizeof(struct callout), M_DEVBUF, M_NOWAIT|M_ZERO);
 2355 #endif  
 2356 
 2357         /*
 2358          * Stash pointers to the miniport block and miniport
 2359          * characteristics info in the if_ndis softc so the
 2360          * UNIX wrapper driver can get to them later.
 2361      */
 2362 #ifdef __FreeBSD__                      
 2363         sc = device_get_softc(pdo->do_devext);
 2364 #else /* __NetBSD__ */
 2365         sc = pdo->pdo_sc;
 2366         fdo->fdo_sc = sc;
 2367 #endif   
 2368         sc->ndis_block = block;
 2369         sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1);
 2370 
 2371         IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap);
 2372 
 2373         /* Finish up BSD-specific setup. */
 2374 
 2375         block->nmb_signature = (void *)0xcafebabe;
 2376         block->nmb_status_func = kernndis_functbl[0].ipt_wrap;
 2377         block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap;
 2378         block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap;
 2379         block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap;
 2380         block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap;
 2381         block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap;
 2382         block->nmb_pendingreq = NULL;
 2383 
 2384         ndis_enlarge_thrqueue(8);
 2385 
 2386         TAILQ_INSERT_TAIL(&ndis_devhead, block, link);
 2387 
 2388         return (STATUS_SUCCESS);
 2389 }
 2390 
 2391 int
 2392 ndis_unload_driver(arg)
 2393         void                    *arg;
 2394 {
 2395         struct ndis_softc       *sc;
 2396         device_object           *fdo;
 2397 
 2398         sc = arg;
 2399 
 2400         if (sc->ndis_block->nmb_rlist != NULL)
 2401                 free(sc->ndis_block->nmb_rlist, M_DEVBUF);
 2402 
 2403         ndis_flush_sysctls(sc);
 2404 
 2405         ndis_shrink_thrqueue(8);
 2406         TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
 2407 
 2408         fdo = sc->ndis_block->nmb_deviceobj;
 2409         IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj);
 2410         IoDeleteDevice(fdo);
 2411 
 2412         return(0);
 2413 }

Cache object: 6248fa8f1ebcb7792453997780101a90


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