kern_ndis.c revision 124697
1123474Swpaul/* 2123474Swpaul * Copyright (c) 2003 3123474Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4123474Swpaul * 5123474Swpaul * Redistribution and use in source and binary forms, with or without 6123474Swpaul * modification, are permitted provided that the following conditions 7123474Swpaul * are met: 8123474Swpaul * 1. Redistributions of source code must retain the above copyright 9123474Swpaul * notice, this list of conditions and the following disclaimer. 10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11123474Swpaul * notice, this list of conditions and the following disclaimer in the 12123474Swpaul * documentation and/or other materials provided with the distribution. 13123474Swpaul * 3. All advertising materials mentioning features or use of this software 14123474Swpaul * must display the following acknowledgement: 15123474Swpaul * This product includes software developed by Bill Paul. 16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17123474Swpaul * may be used to endorse or promote products derived from this software 18123474Swpaul * without specific prior written permission. 19123474Swpaul * 20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23123474Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31123474Swpaul */ 32123474Swpaul 33123474Swpaul#include <sys/cdefs.h> 34123474Swpaul__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 124697 2004-01-18 22:57:11Z wpaul $"); 35123474Swpaul 36123474Swpaul#include <sys/param.h> 37124697Swpaul#include <sys/systm.h> 38124697Swpaul#include <sys/unistd.h> 39123474Swpaul#include <sys/types.h> 40123474Swpaul#include <sys/errno.h> 41123474Swpaul#include <sys/callout.h> 42123474Swpaul#include <sys/socket.h> 43123474Swpaul#include <sys/queue.h> 44123474Swpaul#include <sys/sysctl.h> 45124697Swpaul#include <sys/proc.h> 46123474Swpaul#include <sys/malloc.h> 47123474Swpaul#include <sys/lock.h> 48123474Swpaul#include <sys/mutex.h> 49123474Swpaul#include <sys/conf.h> 50123474Swpaul 51123474Swpaul#include <sys/kernel.h> 52124697Swpaul#include <sys/kthread.h> 53123474Swpaul#include <machine/bus.h> 54123474Swpaul#include <machine/resource.h> 55123474Swpaul#include <sys/bus.h> 56123474Swpaul#include <sys/rman.h> 57123474Swpaul 58124060Swpaul#include <vm/uma.h> 59124060Swpaul 60123474Swpaul#include <net/if.h> 61123474Swpaul#include <net/if_arp.h> 62123474Swpaul#include <net/ethernet.h> 63123474Swpaul#include <net/if_dl.h> 64123474Swpaul#include <net/if_media.h> 65123474Swpaul 66123695Swpaul#include <net80211/ieee80211_var.h> 67123695Swpaul#include <net80211/ieee80211_ioctl.h> 68123695Swpaul 69123474Swpaul#include <dev/pccard/pccardvar.h> 70123474Swpaul#include "card_if.h" 71123474Swpaul 72123474Swpaul#include <compat/ndis/pe_var.h> 73123474Swpaul#include <compat/ndis/resource_var.h> 74123474Swpaul#include <compat/ndis/ndis_var.h> 75123474Swpaul#include <compat/ndis/hal_var.h> 76123474Swpaul#include <compat/ndis/ntoskrnl_var.h> 77123474Swpaul#include <compat/ndis/cfg_var.h> 78123474Swpaul#include <dev/if_ndis/if_ndisvar.h> 79123474Swpaul 80123474Swpaul#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 81123474Swpaul 82123474Swpaul__stdcall static void ndis_status_func(ndis_handle, ndis_status, 83123474Swpaul void *, uint32_t); 84123474Swpaul__stdcall static void ndis_statusdone_func(ndis_handle); 85123474Swpaul__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 86123535Swpaul__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 87123474Swpaul__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 88124100Swpaul__stdcall static void ndis_sendrsrcavail_func(ndis_handle); 89123474Swpaul 90124697Swpaulstatic int ndis_create_kthreads(void); 91124697Swpaulstatic void ndis_destroy_kthreads(void); 92124697Swpaulstatic void ndis_stop_thread(int); 93124697Swpaulstatic int ndis_enlarge_thrqueue(int); 94124697Swpaulstatic int ndis_shrink_thrqueue(int); 95124697Swpaulstatic void ndis_runq(void *); 96124697Swpaulstatic void ndis_intq(void *); 97124697Swpaul 98124697Swpaulextern struct mtx_pool *ndis_mtxpool; 99124060Swpaulstatic uma_zone_t ndis_packet_zone, ndis_buffer_zone; 100124697Swpaulstruct mtx *ndis_thr_mtx; 101124697Swpaulstatic STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; 102124697Swpaulstruct ndisqhead ndis_itodo; 103124697Swpaulstruct ndisqhead ndis_free; 104124697Swpaulstatic int ndis_jobs = 32; 105124697Swpaulstatic struct proc *ndis_tproc; 106124697Swpaulstatic struct proc *ndis_iproc; 107124060Swpaul 108124697Swpaulstruct ndis_req { 109124697Swpaul void (*ndis_func)(void *); 110124697Swpaul void *ndis_arg; 111124697Swpaul int ndis_exit; 112124697Swpaul STAILQ_ENTRY(ndis_req) link; 113124697Swpaul}; 114124697Swpaul 115123474Swpaul/* 116123474Swpaul * This allows us to export our symbols to other modules. 117123474Swpaul * Note that we call ourselves 'ndisapi' to avoid a namespace 118123474Swpaul * collision with if_ndis.ko, which internally calls itself 119123474Swpaul * 'ndis.' 120123474Swpaul */ 121123474Swpaulstatic int 122123474Swpaulndis_modevent(module_t mod, int cmd, void *arg) 123123474Swpaul{ 124124060Swpaul int error = 0; 125124060Swpaul 126124060Swpaul switch (cmd) { 127124060Swpaul case MOD_LOAD: 128124122Swpaul /* Initialize subsystems */ 129124122Swpaul ndis_libinit(); 130124122Swpaul ntoskrnl_libinit(); 131124122Swpaul 132124122Swpaul /* Initialize TX buffer UMA zone. */ 133124060Swpaul ndis_packet_zone = uma_zcreate("NDIS packet", 134124060Swpaul sizeof(ndis_packet), NULL, NULL, NULL, 135124060Swpaul NULL, UMA_ALIGN_PTR, 0); 136124060Swpaul ndis_buffer_zone = uma_zcreate("NDIS buffer", 137124060Swpaul sizeof(ndis_buffer), NULL, NULL, NULL, 138124060Swpaul NULL, UMA_ALIGN_PTR, 0); 139124697Swpaul 140124697Swpaul ndis_create_kthreads(); 141124697Swpaul 142124060Swpaul break; 143124060Swpaul case MOD_UNLOAD: 144124060Swpaul case MOD_SHUTDOWN: 145124697Swpaul /* stop kthreads */ 146124697Swpaul ndis_destroy_kthreads(); 147124697Swpaul 148124122Swpaul /* Shut down subsystems */ 149124122Swpaul ndis_libfini(); 150124122Swpaul ntoskrnl_libfini(); 151124122Swpaul 152124122Swpaul /* Remove zones */ 153124060Swpaul uma_zdestroy(ndis_packet_zone); 154124060Swpaul uma_zdestroy(ndis_buffer_zone); 155124060Swpaul break; 156124060Swpaul default: 157124060Swpaul error = EINVAL; 158124060Swpaul break; 159124060Swpaul } 160124060Swpaul 161124060Swpaul return(error); 162123474Swpaul} 163123474SwpaulDEV_MODULE(ndisapi, ndis_modevent, NULL); 164123474SwpaulMODULE_VERSION(ndisapi, 1); 165123474Swpaul 166124697Swpaul/* 167124697Swpaul * We create two kthreads for the NDIS subsystem. One of them is a task 168124697Swpaul * queue for performing various odd jobs. The other is an swi thread 169124697Swpaul * reserved exclusively for running interrupt handlers. The reason we 170124697Swpaul * have our own task queue is that there are some cases where we may 171124697Swpaul * need to sleep for a significant amount of time, and if we were to 172124697Swpaul * use one of the taskqueue threads, we might delay the processing 173124697Swpaul * of other pending tasks which might need to run right away. We have 174124697Swpaul * a separate swi thread because we don't want our interrupt handling 175124697Swpaul * to be delayed either. 176124697Swpaul * 177124697Swpaul * By default there are 32 jobs available to start, and another 8 178124697Swpaul * are added to the free list each time a new device is created. 179124697Swpaul */ 180123474Swpaul 181124697Swpaulstatic void 182124697Swpaulndis_runq(dummy) 183124697Swpaul void *dummy; 184124697Swpaul{ 185124697Swpaul struct ndis_req *r = NULL, *die = NULL; 186124697Swpaul 187124697Swpaul while (1) { 188124697Swpaul kthread_suspend(ndis_tproc, 0); 189124697Swpaul 190124697Swpaul /* Look for any jobs on the work queue. */ 191124697Swpaul 192124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 193124697Swpaul while(STAILQ_FIRST(&ndis_ttodo) != NULL) { 194124697Swpaul r = STAILQ_FIRST(&ndis_ttodo); 195124697Swpaul STAILQ_REMOVE_HEAD(&ndis_ttodo, link); 196124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 197124697Swpaul 198124697Swpaul /* Do the work. */ 199124697Swpaul 200124697Swpaul if (r->ndis_func != NULL) 201124697Swpaul (*r->ndis_func)(r->ndis_arg); 202124697Swpaul 203124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 204124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 205124697Swpaul 206124697Swpaul /* Check for a shutdown request */ 207124697Swpaul 208124697Swpaul if (r->ndis_exit == TRUE) 209124697Swpaul die = r; 210124697Swpaul } 211124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 212124697Swpaul 213124697Swpaul /* Bail if we were told to shut down. */ 214124697Swpaul 215124697Swpaul if (die != NULL) 216124697Swpaul break; 217124697Swpaul } 218124697Swpaul 219124697Swpaul wakeup(die); 220124697Swpaul mtx_lock(&Giant); 221124697Swpaul kthread_exit(0); 222124697Swpaul} 223124697Swpaul 224124697Swpaulstatic void 225124697Swpaulndis_intq(dummy) 226124697Swpaul void *dummy; 227124697Swpaul{ 228124697Swpaul struct ndis_req *r = NULL, *die = NULL; 229124697Swpaul 230124697Swpaul while (1) { 231124697Swpaul kthread_suspend(ndis_iproc, 0); 232124697Swpaul 233124697Swpaul /* Look for any jobs on the work queue. */ 234124697Swpaul 235124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 236124697Swpaul while(STAILQ_FIRST(&ndis_itodo) != NULL) { 237124697Swpaul r = STAILQ_FIRST(&ndis_itodo); 238124697Swpaul STAILQ_REMOVE_HEAD(&ndis_itodo, link); 239124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 240124697Swpaul 241124697Swpaul /* Do the work. */ 242124697Swpaul 243124697Swpaul if (r->ndis_func != NULL) 244124697Swpaul (*r->ndis_func)(r->ndis_arg); 245124697Swpaul 246124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 247124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 248124697Swpaul 249124697Swpaul /* Check for a shutdown request */ 250124697Swpaul 251124697Swpaul if (r->ndis_exit == TRUE) 252124697Swpaul die = r; 253124697Swpaul } 254124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 255124697Swpaul 256124697Swpaul /* Bail if this is an exit request. */ 257124697Swpaul 258124697Swpaul if (die != NULL) 259124697Swpaul break; 260124697Swpaul } 261124697Swpaul 262124697Swpaul wakeup(die); 263124697Swpaul mtx_lock(&Giant); 264124697Swpaul kthread_exit(0); 265124697Swpaul} 266124697Swpaul 267124697Swpaulstatic int 268124697Swpaulndis_create_kthreads() 269124697Swpaul{ 270124697Swpaul struct ndis_req *r; 271124697Swpaul int i, error = 0; 272124697Swpaul 273124697Swpaul ndis_thr_mtx = mtx_pool_alloc(ndis_mtxpool); 274124697Swpaul STAILQ_INIT(&ndis_ttodo); 275124697Swpaul STAILQ_INIT(&ndis_itodo); 276124697Swpaul STAILQ_INIT(&ndis_free); 277124697Swpaul 278124697Swpaul for (i = 0; i < ndis_jobs; i++) { 279124697Swpaul r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 280124697Swpaul if (r == NULL) { 281124697Swpaul error = ENOMEM; 282124697Swpaul break; 283124697Swpaul } 284124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 285124697Swpaul } 286124697Swpaul 287124697Swpaul if (error == 0) 288124697Swpaul error = kthread_create(ndis_runq, NULL, 289124697Swpaul &ndis_tproc, RFHIGHPID, 0, "ndis taskqueue"); 290124697Swpaul 291124697Swpaul if (error == 0) 292124697Swpaul error = kthread_create(ndis_intq, NULL, 293124697Swpaul &ndis_iproc, RFHIGHPID, 0, "ndis swi"); 294124697Swpaul 295124697Swpaul if (error) { 296124697Swpaul while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 297124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 298124697Swpaul free(r, M_DEVBUF); 299124697Swpaul } 300124697Swpaul return(error); 301124697Swpaul } 302124697Swpaul 303124697Swpaul return(0); 304124697Swpaul} 305124697Swpaul 306124697Swpaulstatic void 307124697Swpaulndis_destroy_kthreads() 308124697Swpaul{ 309124697Swpaul struct ndis_req *r; 310124697Swpaul 311124697Swpaul /* Stop the threads. */ 312124697Swpaul 313124697Swpaul ndis_stop_thread(NDIS_TASKQUEUE); 314124697Swpaul ndis_stop_thread(NDIS_SWI); 315124697Swpaul 316124697Swpaul /* Destroy request structures. */ 317124697Swpaul 318124697Swpaul while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 319124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 320124697Swpaul free(r, M_DEVBUF); 321124697Swpaul } 322124697Swpaul 323124697Swpaul return; 324124697Swpaul} 325124697Swpaul 326124697Swpaulstatic void 327124697Swpaulndis_stop_thread(t) 328124697Swpaul int t; 329124697Swpaul{ 330124697Swpaul struct ndis_req *r; 331124697Swpaul struct timeval tv; 332124697Swpaul struct ndisqhead *q; 333124697Swpaul struct proc *p; 334124697Swpaul 335124697Swpaul if (t == NDIS_TASKQUEUE) { 336124697Swpaul q = &ndis_ttodo; 337124697Swpaul p = ndis_tproc; 338124697Swpaul } else { 339124697Swpaul q = &ndis_itodo; 340124697Swpaul p = ndis_iproc; 341124697Swpaul } 342124697Swpaul 343124697Swpaul /* Create and post a special 'exit' job. */ 344124697Swpaul 345124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 346124697Swpaul r = STAILQ_FIRST(&ndis_free); 347124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 348124697Swpaul r->ndis_func = NULL; 349124697Swpaul r->ndis_arg = NULL; 350124697Swpaul r->ndis_exit = TRUE; 351124697Swpaul STAILQ_INSERT_TAIL(q, r, link); 352124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 353124697Swpaul 354124697Swpaul kthread_resume(p); 355124697Swpaul 356124697Swpaul /* wait for thread exit */ 357124697Swpaul 358124697Swpaul tv.tv_sec = 60; 359124697Swpaul tv.tv_usec = 0; 360124697Swpaul tsleep(r, PPAUSE|PCATCH, "ndisthrexit", tvtohz(&tv)); 361124697Swpaul 362124697Swpaul /* Now empty the job list. */ 363124697Swpaul 364124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 365124697Swpaul while ((r = STAILQ_FIRST(q)) != NULL) { 366124697Swpaul STAILQ_REMOVE_HEAD(q, link); 367124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 368124697Swpaul } 369124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 370124697Swpaul 371124697Swpaul return; 372124697Swpaul} 373124697Swpaul 374124697Swpaulstatic int 375124697Swpaulndis_enlarge_thrqueue(cnt) 376124697Swpaul int cnt; 377124697Swpaul{ 378124697Swpaul struct ndis_req *r; 379124697Swpaul int i; 380124697Swpaul 381124697Swpaul for (i = 0; i < cnt; i++) { 382124697Swpaul r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 383124697Swpaul if (r == NULL) 384124697Swpaul return(ENOMEM); 385124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 386124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 387124697Swpaul ndis_jobs++; 388124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 389124697Swpaul } 390124697Swpaul 391124697Swpaul return(0); 392124697Swpaul} 393124697Swpaul 394124697Swpaulstatic int 395124697Swpaulndis_shrink_thrqueue(cnt) 396124697Swpaul int cnt; 397124697Swpaul{ 398124697Swpaul struct ndis_req *r; 399124697Swpaul int i; 400124697Swpaul 401124697Swpaul for (i = 0; i < cnt; i++) { 402124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 403124697Swpaul r = STAILQ_FIRST(&ndis_free); 404124697Swpaul if (r == NULL) { 405124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 406124697Swpaul return(ENOMEM); 407124697Swpaul } 408124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 409124697Swpaul ndis_jobs--; 410124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 411124697Swpaul free(r, M_DEVBUF); 412124697Swpaul } 413124697Swpaul 414124697Swpaul return(0); 415124697Swpaul} 416124697Swpaul 417124697Swpaulint 418124697Swpaulndis_sched(func, arg, t) 419124697Swpaul void (*func)(void *); 420124697Swpaul void *arg; 421124697Swpaul int t; 422124697Swpaul{ 423124697Swpaul struct ndis_req *r; 424124697Swpaul struct ndisqhead *q; 425124697Swpaul struct proc *p; 426124697Swpaul 427124697Swpaul if (t == NDIS_TASKQUEUE) { 428124697Swpaul q = &ndis_ttodo; 429124697Swpaul p = ndis_tproc; 430124697Swpaul } else { 431124697Swpaul q = &ndis_itodo; 432124697Swpaul p = ndis_iproc; 433124697Swpaul } 434124697Swpaul 435124697Swpaul mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 436124697Swpaul /* 437124697Swpaul * Check to see if an instance of this job is already 438124697Swpaul * pending. If so, don't bother queuing it again. 439124697Swpaul */ 440124697Swpaul STAILQ_FOREACH(r, q, link) { 441124697Swpaul if (r->ndis_func == func && r->ndis_arg == arg) { 442124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 443124697Swpaul return(0); 444124697Swpaul } 445124697Swpaul } 446124697Swpaul r = STAILQ_FIRST(&ndis_free); 447124697Swpaul if (r == NULL) { 448124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 449124697Swpaul return(EAGAIN); 450124697Swpaul } 451124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 452124697Swpaul r->ndis_func = func; 453124697Swpaul r->ndis_arg = arg; 454124697Swpaul r->ndis_exit = FALSE; 455124697Swpaul STAILQ_INSERT_TAIL(q, r, link); 456124697Swpaul mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 457124697Swpaul 458124697Swpaul /* Post the job. */ 459124697Swpaul kthread_resume(p); 460124697Swpaul 461124697Swpaul return(0); 462124697Swpaul} 463124697Swpaul 464123474Swpaul__stdcall static void 465124100Swpaulndis_sendrsrcavail_func(adapter) 466124100Swpaul ndis_handle adapter; 467124100Swpaul{ 468124100Swpaul return; 469124100Swpaul} 470124100Swpaul 471124100Swpaul__stdcall static void 472123474Swpaulndis_status_func(adapter, status, sbuf, slen) 473123474Swpaul ndis_handle adapter; 474123474Swpaul ndis_status status; 475123474Swpaul void *sbuf; 476123474Swpaul uint32_t slen; 477123474Swpaul{ 478124060Swpaul ndis_miniport_block *block; 479124060Swpaul block = adapter; 480124060Swpaul 481124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 482124409Swpaul device_printf (block->nmb_dev, "status: %x\n", status); 483123474Swpaul return; 484123474Swpaul} 485123474Swpaul 486123474Swpaul__stdcall static void 487123474Swpaulndis_statusdone_func(adapter) 488123474Swpaul ndis_handle adapter; 489123474Swpaul{ 490124060Swpaul ndis_miniport_block *block; 491124060Swpaul block = adapter; 492124060Swpaul 493124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 494124409Swpaul device_printf (block->nmb_dev, "status complete\n"); 495123474Swpaul return; 496123474Swpaul} 497123474Swpaul 498123474Swpaul__stdcall static void 499123474Swpaulndis_setdone_func(adapter, status) 500123474Swpaul ndis_handle adapter; 501123474Swpaul ndis_status status; 502123474Swpaul{ 503123695Swpaul ndis_miniport_block *block; 504123695Swpaul block = adapter; 505123695Swpaul 506123695Swpaul block->nmb_setstat = status; 507123695Swpaul wakeup(&block->nmb_wkupdpctimer); 508123474Swpaul return; 509123474Swpaul} 510123474Swpaul 511123474Swpaul__stdcall static void 512123535Swpaulndis_getdone_func(adapter, status) 513123535Swpaul ndis_handle adapter; 514123535Swpaul ndis_status status; 515123535Swpaul{ 516123695Swpaul ndis_miniport_block *block; 517123695Swpaul block = adapter; 518123695Swpaul 519123695Swpaul block->nmb_getstat = status; 520123695Swpaul wakeup(&block->nmb_wkupdpctimer); 521123535Swpaul return; 522123535Swpaul} 523123535Swpaul 524123535Swpaul__stdcall static void 525123474Swpaulndis_resetdone_func(adapter, status, addressingreset) 526123474Swpaul ndis_handle adapter; 527123474Swpaul ndis_status status; 528123474Swpaul uint8_t addressingreset; 529123474Swpaul{ 530124060Swpaul ndis_miniport_block *block; 531124060Swpaul block = adapter; 532124060Swpaul 533124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 534124409Swpaul device_printf (block->nmb_dev, "reset done...\n"); 535123474Swpaul return; 536123474Swpaul} 537123474Swpaul 538123474Swpaul#define NDIS_AM_RID 3 539123474Swpaul 540123474Swpaulint 541123474Swpaulndis_alloc_amem(arg) 542123474Swpaul void *arg; 543123474Swpaul{ 544123474Swpaul struct ndis_softc *sc; 545123474Swpaul int error, rid; 546123474Swpaul 547123474Swpaul if (arg == NULL) 548123474Swpaul return(EINVAL); 549123474Swpaul 550123474Swpaul sc = arg; 551123474Swpaul rid = NDIS_AM_RID; 552123474Swpaul sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 553123474Swpaul &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 554123474Swpaul 555123474Swpaul if (sc->ndis_res_am == NULL) { 556124060Swpaul device_printf(sc->ndis_dev, 557124060Swpaul "failed to allocate attribute memory\n"); 558123474Swpaul return(ENXIO); 559123474Swpaul } 560123474Swpaul 561123474Swpaul error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 562123474Swpaul sc->ndis_dev, rid, 0, NULL); 563123474Swpaul 564123474Swpaul if (error) { 565124060Swpaul device_printf(sc->ndis_dev, 566124060Swpaul "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error); 567123474Swpaul return(error); 568123474Swpaul } 569123474Swpaul 570123474Swpaul error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 571123474Swpaul sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 572123474Swpaul 573123474Swpaul if (error) { 574124060Swpaul device_printf(sc->ndis_dev, 575124060Swpaul "CARD_SET_RES_FLAGS() returned 0x%x\n", error); 576123474Swpaul return(error); 577123474Swpaul } 578123474Swpaul 579123474Swpaul return(0); 580123474Swpaul} 581123474Swpaul 582123474Swpaulint 583123474Swpaulndis_create_sysctls(arg) 584123474Swpaul void *arg; 585123474Swpaul{ 586123474Swpaul struct ndis_softc *sc; 587123474Swpaul ndis_cfg *vals; 588123474Swpaul char buf[256]; 589123474Swpaul 590123474Swpaul if (arg == NULL) 591123474Swpaul return(EINVAL); 592123474Swpaul 593123474Swpaul sc = arg; 594123474Swpaul vals = sc->ndis_regvals; 595123474Swpaul 596123474Swpaul TAILQ_INIT(&sc->ndis_cfglist_head); 597123474Swpaul 598123474Swpaul /* Create the sysctl tree. */ 599123474Swpaul 600123474Swpaul sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 601123474Swpaul SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 602123474Swpaul device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 603123474Swpaul device_get_desc(sc->ndis_dev)); 604123474Swpaul 605123474Swpaul /* Add the driver-specific registry keys. */ 606123474Swpaul 607123474Swpaul vals = sc->ndis_regvals; 608123474Swpaul while(1) { 609123474Swpaul if (vals->nc_cfgkey == NULL) 610123474Swpaul break; 611123620Swpaul if (vals->nc_idx != sc->ndis_devidx) { 612123620Swpaul vals++; 613123620Swpaul continue; 614123620Swpaul } 615123474Swpaul SYSCTL_ADD_STRING(&sc->ndis_ctx, 616123474Swpaul SYSCTL_CHILDREN(sc->ndis_tree), 617123474Swpaul OID_AUTO, vals->nc_cfgkey, 618123474Swpaul CTLFLAG_RW, vals->nc_val, 619123474Swpaul sizeof(vals->nc_val), 620123474Swpaul vals->nc_cfgdesc); 621123474Swpaul vals++; 622123474Swpaul } 623123474Swpaul 624123474Swpaul /* Now add a couple of builtin keys. */ 625123474Swpaul 626123474Swpaul /* 627123474Swpaul * Environment can be either Windows (0) or WindowsNT (1). 628123474Swpaul * We qualify as the latter. 629123474Swpaul */ 630123474Swpaul ndis_add_sysctl(sc, "Environment", 631123474Swpaul "Windows environment", "1", CTLFLAG_RD); 632123474Swpaul 633123474Swpaul /* NDIS version should be 5.1. */ 634123474Swpaul ndis_add_sysctl(sc, "NdisVersion", 635123474Swpaul "NDIS API Version", "0x00050001", CTLFLAG_RD); 636123474Swpaul 637123474Swpaul /* Bus type (PCI, PCMCIA, etc...) */ 638124272Swpaul sprintf(buf, "%d", (int)sc->ndis_iftype); 639123474Swpaul ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 640123474Swpaul 641123474Swpaul if (sc->ndis_res_io != NULL) { 642124272Swpaul sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 643123474Swpaul ndis_add_sysctl(sc, "IOBaseAddress", 644123474Swpaul "Base I/O Address", buf, CTLFLAG_RD); 645123474Swpaul } 646123474Swpaul 647123474Swpaul if (sc->ndis_irq != NULL) { 648124272Swpaul sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 649123474Swpaul ndis_add_sysctl(sc, "InterruptNumber", 650123474Swpaul "Interrupt Number", buf, CTLFLAG_RD); 651123474Swpaul } 652123474Swpaul 653123474Swpaul return(0); 654123474Swpaul} 655123474Swpaul 656123474Swpaulint 657123474Swpaulndis_add_sysctl(arg, key, desc, val, flag) 658123474Swpaul void *arg; 659123474Swpaul char *key; 660123474Swpaul char *desc; 661123474Swpaul char *val; 662123474Swpaul int flag; 663123474Swpaul{ 664123474Swpaul struct ndis_softc *sc; 665123474Swpaul struct ndis_cfglist *cfg; 666123474Swpaul char descstr[256]; 667123474Swpaul 668123474Swpaul sc = arg; 669123474Swpaul 670123474Swpaul cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 671123474Swpaul 672123474Swpaul if (cfg == NULL) 673123474Swpaul return(ENOMEM); 674123474Swpaul 675123474Swpaul cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 676123474Swpaul if (desc == NULL) { 677123474Swpaul snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 678123474Swpaul cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 679123474Swpaul } else 680123474Swpaul cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 681123474Swpaul strcpy(cfg->ndis_cfg.nc_val, val); 682123474Swpaul 683123474Swpaul TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 684123474Swpaul 685123474Swpaul SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 686123474Swpaul OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 687123474Swpaul cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 688123474Swpaul cfg->ndis_cfg.nc_cfgdesc); 689123474Swpaul 690123474Swpaul return(0); 691123474Swpaul} 692123474Swpaul 693123474Swpaulint 694123474Swpaulndis_flush_sysctls(arg) 695123474Swpaul void *arg; 696123474Swpaul{ 697123474Swpaul struct ndis_softc *sc; 698123474Swpaul struct ndis_cfglist *cfg; 699123474Swpaul 700123474Swpaul sc = arg; 701123474Swpaul 702123474Swpaul while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 703123474Swpaul cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 704123474Swpaul TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 705123474Swpaul free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 706123474Swpaul free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 707123474Swpaul free(cfg, M_DEVBUF); 708123474Swpaul } 709123474Swpaul 710123474Swpaul return(0); 711123474Swpaul} 712123474Swpaul 713123474Swpaulvoid 714123826Swpaulndis_return_packet(buf, arg) 715123826Swpaul void *buf; /* not used */ 716123474Swpaul void *arg; 717123474Swpaul{ 718123474Swpaul struct ndis_softc *sc; 719123474Swpaul ndis_handle adapter; 720123535Swpaul ndis_packet *p; 721123474Swpaul __stdcall ndis_return_handler returnfunc; 722123474Swpaul 723123826Swpaul if (arg == NULL) 724123474Swpaul return; 725123474Swpaul 726123826Swpaul p = arg; 727123535Swpaul 728123535Swpaul /* Decrement refcount. */ 729123826Swpaul p->np_refcnt--; 730123535Swpaul 731123535Swpaul /* Release packet when refcount hits zero, otherwise return. */ 732123826Swpaul if (p->np_refcnt) 733123535Swpaul return; 734123536Swpaul 735123826Swpaul sc = p->np_softc; 736123474Swpaul returnfunc = sc->ndis_chars.nmc_return_packet_func; 737123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 738123858Swpaul if (returnfunc != NULL) 739123826Swpaul returnfunc(adapter, p); 740123858Swpaul 741123474Swpaul return; 742123474Swpaul} 743123474Swpaul 744123848Swpaulvoid 745123848Swpaulndis_free_bufs(b0) 746123848Swpaul ndis_buffer *b0; 747123848Swpaul{ 748123848Swpaul ndis_buffer *next; 749123848Swpaul 750123848Swpaul if (b0 == NULL) 751123848Swpaul return; 752123848Swpaul 753123848Swpaul while(b0 != NULL) { 754123848Swpaul next = b0->nb_next; 755124060Swpaul uma_zfree (ndis_buffer_zone, b0); 756123848Swpaul b0 = next; 757123848Swpaul } 758123848Swpaul 759123848Swpaul return; 760123848Swpaul} 761123848Swpaul 762123848Swpaulvoid 763123848Swpaulndis_free_packet(p) 764123848Swpaul ndis_packet *p; 765123848Swpaul{ 766123848Swpaul if (p == NULL) 767123848Swpaul return; 768123848Swpaul 769123848Swpaul ndis_free_bufs(p->np_private.npp_head); 770124060Swpaul uma_zfree(ndis_packet_zone, p); 771123848Swpaul 772123848Swpaul return; 773123848Swpaul} 774123848Swpaul 775123474Swpaulint 776123474Swpaulndis_convert_res(arg) 777123474Swpaul void *arg; 778123474Swpaul{ 779123474Swpaul struct ndis_softc *sc; 780123474Swpaul ndis_resource_list *rl = NULL; 781123474Swpaul cm_partial_resource_desc *prd = NULL; 782123474Swpaul ndis_miniport_block *block; 783123976Swpaul device_t dev; 784123976Swpaul struct resource_list *brl; 785123976Swpaul struct resource_list_entry *brle; 786123474Swpaul 787123474Swpaul sc = arg; 788123474Swpaul block = &sc->ndis_block; 789123976Swpaul dev = sc->ndis_dev; 790123474Swpaul 791123474Swpaul rl = malloc(sizeof(ndis_resource_list) + 792123474Swpaul (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 793123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 794123474Swpaul 795123474Swpaul if (rl == NULL) 796123474Swpaul return(ENOMEM); 797123474Swpaul 798123474Swpaul rl->cprl_version = 5; 799123474Swpaul rl->cprl_version = 1; 800123474Swpaul rl->cprl_count = sc->ndis_rescnt; 801123474Swpaul prd = rl->cprl_partial_descs; 802123474Swpaul 803123976Swpaul brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 804123976Swpaul if (brl != NULL) { 805123976Swpaul SLIST_FOREACH(brle, brl, link) { 806123976Swpaul switch (brle->type) { 807123976Swpaul case SYS_RES_IOPORT: 808123976Swpaul prd->cprd_type = CmResourceTypePort; 809123976Swpaul prd->u.cprd_port.cprd_start.np_quad = 810123976Swpaul brle->start; 811123976Swpaul prd->u.cprd_port.cprd_len = brle->count; 812123976Swpaul break; 813123976Swpaul case SYS_RES_MEMORY: 814123976Swpaul prd->cprd_type = CmResourceTypeMemory; 815123976Swpaul prd->u.cprd_port.cprd_start.np_quad = 816123976Swpaul brle->start; 817123976Swpaul prd->u.cprd_port.cprd_len = brle->count; 818123976Swpaul break; 819123976Swpaul case SYS_RES_IRQ: 820123976Swpaul prd->cprd_type = CmResourceTypeInterrupt; 821123976Swpaul prd->u.cprd_intr.cprd_level = brle->start; 822123976Swpaul prd->u.cprd_intr.cprd_vector = brle->start; 823123976Swpaul prd->u.cprd_intr.cprd_affinity = 0; 824123976Swpaul break; 825123976Swpaul default: 826123976Swpaul break; 827123976Swpaul } 828123976Swpaul prd++; 829123976Swpaul } 830123474Swpaul } 831123474Swpaul 832123474Swpaul block->nmb_rlist = rl; 833123474Swpaul 834123474Swpaul return(0); 835123474Swpaul} 836123474Swpaul 837123474Swpaul/* 838123474Swpaul * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 839123474Swpaul * packet, it will hand it to us in the form of an ndis_packet, 840123474Swpaul * which we need to convert to an mbuf that is then handed off 841123474Swpaul * to the stack. Note: we configure the mbuf list so that it uses 842123474Swpaul * the memory regions specified by the ndis_buffer structures in 843123474Swpaul * the ndis_packet as external storage. In most cases, this will 844123474Swpaul * point to a memory region allocated by the driver (either by 845123474Swpaul * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 846123474Swpaul * the driver to handle free()ing this region for is, so we set up 847123474Swpaul * a dummy no-op free handler for it. 848123474Swpaul */ 849123474Swpaul 850123474Swpaulint 851123474Swpaulndis_ptom(m0, p) 852123474Swpaul struct mbuf **m0; 853123474Swpaul ndis_packet *p; 854123474Swpaul{ 855123474Swpaul struct mbuf *m, *prev = NULL; 856123474Swpaul ndis_buffer *buf; 857123474Swpaul ndis_packet_private *priv; 858123474Swpaul uint32_t totlen = 0; 859123474Swpaul 860123474Swpaul if (p == NULL || m0 == NULL) 861123474Swpaul return(EINVAL); 862123474Swpaul 863123474Swpaul priv = &p->np_private; 864123474Swpaul buf = priv->npp_head; 865123826Swpaul p->np_refcnt = 0; 866123474Swpaul 867123474Swpaul for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 868123474Swpaul if (buf == priv->npp_head) 869123474Swpaul MGETHDR(m, M_DONTWAIT, MT_HEADER); 870123474Swpaul else 871123474Swpaul MGET(m, M_DONTWAIT, MT_DATA); 872123474Swpaul if (m == NULL) { 873123474Swpaul m_freem(*m0); 874123474Swpaul *m0 = NULL; 875123474Swpaul return(ENOBUFS); 876123474Swpaul } 877123757Swpaul m->m_len = buf->nb_bytecount; 878123757Swpaul m->m_data = MDL_VA(buf); 879123535Swpaul MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 880123826Swpaul p, 0, EXT_NDIS); 881123826Swpaul p->np_refcnt++; 882123474Swpaul totlen += m->m_len; 883123474Swpaul if (m->m_flags & MT_HEADER) 884123474Swpaul *m0 = m; 885123474Swpaul else 886123474Swpaul prev->m_next = m; 887123474Swpaul prev = m; 888123474Swpaul } 889123474Swpaul 890123474Swpaul (*m0)->m_pkthdr.len = totlen; 891123474Swpaul 892123474Swpaul return(0); 893123474Swpaul} 894123474Swpaul 895123474Swpaul/* 896123474Swpaul * Create an mbuf chain from an NDIS packet chain. 897123474Swpaul * This is used mainly when transmitting packets, where we need 898123474Swpaul * to turn an mbuf off an interface's send queue and transform it 899123474Swpaul * into an NDIS packet which will be fed into the NDIS driver's 900123474Swpaul * send routine. 901123474Swpaul * 902123474Swpaul * NDIS packets consist of two parts: an ndis_packet structure, 903123474Swpaul * which is vaguely analagous to the pkthdr portion of an mbuf, 904123474Swpaul * and one or more ndis_buffer structures, which define the 905123474Swpaul * actual memory segments in which the packet data resides. 906123474Swpaul * We need to allocate one ndis_buffer for each mbuf in a chain, 907123474Swpaul * plus one ndis_packet as the header. 908123474Swpaul */ 909123474Swpaul 910123474Swpaulint 911123474Swpaulndis_mtop(m0, p) 912123474Swpaul struct mbuf *m0; 913123474Swpaul ndis_packet **p; 914123474Swpaul{ 915123474Swpaul struct mbuf *m; 916123474Swpaul ndis_buffer *buf = NULL, *prev = NULL; 917123474Swpaul ndis_packet_private *priv; 918123474Swpaul 919123474Swpaul if (p == NULL || m0 == NULL) 920123474Swpaul return(EINVAL); 921123474Swpaul 922123474Swpaul /* If caller didn't supply a packet, make one. */ 923123474Swpaul if (*p == NULL) { 924124060Swpaul *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO); 925123474Swpaul 926123474Swpaul if (*p == NULL) 927123474Swpaul return(ENOMEM); 928123474Swpaul } 929123474Swpaul 930123474Swpaul priv = &(*p)->np_private; 931123474Swpaul priv->npp_totlen = m0->m_pkthdr.len; 932123474Swpaul priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 933124278Swpaul priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 934123474Swpaul 935123474Swpaul for (m = m0; m != NULL; m = m->m_next) { 936123810Salfred if (m->m_len == 0) 937123474Swpaul continue; 938124060Swpaul buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); 939123474Swpaul if (buf == NULL) { 940123474Swpaul ndis_free_packet(*p); 941123474Swpaul *p = NULL; 942123474Swpaul return(ENOMEM); 943123474Swpaul } 944123474Swpaul 945123757Swpaul MDL_INIT(buf, m->m_data, m->m_len); 946123474Swpaul if (priv->npp_head == NULL) 947123474Swpaul priv->npp_head = buf; 948123474Swpaul else 949123474Swpaul prev->nb_next = buf; 950123474Swpaul prev = buf; 951123474Swpaul } 952123474Swpaul 953123474Swpaul priv->npp_tail = buf; 954124060Swpaul priv->npp_totlen = m0->m_pkthdr.len; 955123474Swpaul 956123474Swpaul return(0); 957123474Swpaul} 958123474Swpaul 959123474Swpaulint 960123474Swpaulndis_get_supported_oids(arg, oids, oidcnt) 961123474Swpaul void *arg; 962123474Swpaul ndis_oid **oids; 963123474Swpaul int *oidcnt; 964123474Swpaul{ 965123474Swpaul int len, rval; 966123474Swpaul ndis_oid *o; 967123474Swpaul 968123474Swpaul if (arg == NULL || oids == NULL || oidcnt == NULL) 969123474Swpaul return(EINVAL); 970123474Swpaul len = 0; 971123474Swpaul ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 972123474Swpaul 973123474Swpaul o = malloc(len, M_DEVBUF, M_NOWAIT); 974123474Swpaul if (o == NULL) 975123474Swpaul return(ENOMEM); 976123474Swpaul 977123474Swpaul rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 978123474Swpaul 979123474Swpaul if (rval) { 980123474Swpaul free(o, M_DEVBUF); 981123474Swpaul return(rval); 982123474Swpaul } 983123474Swpaul 984123474Swpaul *oids = o; 985123474Swpaul *oidcnt = len / 4; 986123474Swpaul 987123474Swpaul return(0); 988123474Swpaul} 989123474Swpaul 990123474Swpaulint 991123474Swpaulndis_set_info(arg, oid, buf, buflen) 992123474Swpaul void *arg; 993123474Swpaul ndis_oid oid; 994123474Swpaul void *buf; 995123474Swpaul int *buflen; 996123474Swpaul{ 997123474Swpaul struct ndis_softc *sc; 998123474Swpaul ndis_status rval; 999123474Swpaul ndis_handle adapter; 1000123474Swpaul __stdcall ndis_setinfo_handler setfunc; 1001123474Swpaul uint32_t byteswritten = 0, bytesneeded = 0; 1002123695Swpaul struct timeval tv; 1003123695Swpaul int error; 1004123474Swpaul 1005123474Swpaul sc = arg; 1006123474Swpaul setfunc = sc->ndis_chars.nmc_setinfo_func; 1007123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1008123474Swpaul 1009123474Swpaul rval = setfunc(adapter, oid, buf, *buflen, 1010123474Swpaul &byteswritten, &bytesneeded); 1011123474Swpaul 1012123695Swpaul if (rval == NDIS_STATUS_PENDING) { 1013123695Swpaul tv.tv_sec = 60; 1014123695Swpaul tv.tv_usec = 0; 1015123695Swpaul error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1016123757Swpaul PPAUSE|PCATCH, "ndisset", tvtohz(&tv)); 1017123695Swpaul rval = sc->ndis_block.nmb_setstat; 1018123695Swpaul } 1019123695Swpaul 1020123474Swpaul if (byteswritten) 1021123474Swpaul *buflen = byteswritten; 1022123474Swpaul if (bytesneeded) 1023123474Swpaul *buflen = bytesneeded; 1024123474Swpaul 1025123474Swpaul if (rval == NDIS_STATUS_INVALID_LENGTH) 1026123474Swpaul return(ENOSPC); 1027123474Swpaul 1028123474Swpaul if (rval == NDIS_STATUS_INVALID_OID) 1029123474Swpaul return(EINVAL); 1030123474Swpaul 1031123474Swpaul if (rval == NDIS_STATUS_NOT_SUPPORTED || 1032123474Swpaul rval == NDIS_STATUS_NOT_ACCEPTED) 1033123474Swpaul return(ENOTSUP); 1034123474Swpaul 1035123474Swpaul return(0); 1036123474Swpaul} 1037123474Swpaul 1038124202Swpaultypedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 1039124202Swpaul 1040123474Swpaulint 1041123474Swpaulndis_send_packets(arg, packets, cnt) 1042123474Swpaul void *arg; 1043123474Swpaul ndis_packet **packets; 1044123474Swpaul int cnt; 1045123474Swpaul{ 1046123474Swpaul struct ndis_softc *sc; 1047123474Swpaul ndis_handle adapter; 1048123474Swpaul __stdcall ndis_sendmulti_handler sendfunc; 1049124202Swpaul __stdcall ndis_senddone_func senddonefunc; 1050124202Swpaul int i; 1051123858Swpaul ndis_packet *p; 1052123474Swpaul 1053123474Swpaul sc = arg; 1054123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1055123474Swpaul sendfunc = sc->ndis_chars.nmc_sendmulti_func; 1056124202Swpaul senddonefunc = sc->ndis_block.nmb_senddone_func; 1057123474Swpaul sendfunc(adapter, packets, cnt); 1058123474Swpaul 1059123858Swpaul for (i = 0; i < cnt; i++) { 1060123858Swpaul p = packets[i]; 1061124005Swpaul /* 1062124005Swpaul * Either the driver already handed the packet to 1063124005Swpaul * ndis_txeof() due to a failure, or it wants to keep 1064124005Swpaul * it and release it asynchronously later. Skip to the 1065124005Swpaul * next one. 1066124005Swpaul */ 1067124005Swpaul if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 1068123858Swpaul continue; 1069124202Swpaul senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status); 1070123858Swpaul } 1071123858Swpaul 1072123474Swpaul return(0); 1073123474Swpaul} 1074123474Swpaul 1075123474Swpaulint 1076123474Swpaulndis_init_dma(arg) 1077123474Swpaul void *arg; 1078123474Swpaul{ 1079123474Swpaul struct ndis_softc *sc; 1080123474Swpaul int i, error; 1081123474Swpaul 1082123474Swpaul sc = arg; 1083123474Swpaul 1084123474Swpaul sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1085123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1086123474Swpaul 1087123474Swpaul if (sc->ndis_tmaps == NULL) 1088123474Swpaul return(ENOMEM); 1089123474Swpaul 1090123474Swpaul for (i = 0; i < sc->ndis_maxpkts; i++) { 1091123474Swpaul error = bus_dmamap_create(sc->ndis_ttag, 0, 1092123474Swpaul &sc->ndis_tmaps[i]); 1093123474Swpaul if (error) { 1094123474Swpaul free(sc->ndis_tmaps, M_DEVBUF); 1095123474Swpaul return(ENODEV); 1096123474Swpaul } 1097123474Swpaul } 1098123474Swpaul 1099123474Swpaul return(0); 1100123474Swpaul} 1101123474Swpaul 1102123474Swpaulint 1103123474Swpaulndis_destroy_dma(arg) 1104123474Swpaul void *arg; 1105123474Swpaul{ 1106123474Swpaul struct ndis_softc *sc; 1107123535Swpaul struct mbuf *m; 1108123535Swpaul ndis_packet *p = NULL; 1109123474Swpaul int i; 1110123474Swpaul 1111123474Swpaul sc = arg; 1112123474Swpaul 1113123474Swpaul for (i = 0; i < sc->ndis_maxpkts; i++) { 1114123535Swpaul if (sc->ndis_txarray[i] != NULL) { 1115123535Swpaul p = sc->ndis_txarray[i]; 1116123535Swpaul m = (struct mbuf *)p->np_rsvd[1]; 1117123535Swpaul if (m != NULL) 1118123535Swpaul m_freem(m); 1119123535Swpaul ndis_free_packet(sc->ndis_txarray[i]); 1120123535Swpaul } 1121123474Swpaul bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1122123474Swpaul } 1123123474Swpaul 1124123474Swpaul free(sc->ndis_tmaps, M_DEVBUF); 1125123474Swpaul 1126123474Swpaul bus_dma_tag_destroy(sc->ndis_ttag); 1127123474Swpaul 1128123474Swpaul return(0); 1129123474Swpaul} 1130123474Swpaul 1131123474Swpaulint 1132123474Swpaulndis_reset_nic(arg) 1133123474Swpaul void *arg; 1134123474Swpaul{ 1135123474Swpaul struct ndis_softc *sc; 1136123474Swpaul ndis_handle adapter; 1137123474Swpaul __stdcall ndis_reset_handler resetfunc; 1138123474Swpaul uint8_t addressing_reset; 1139123474Swpaul struct ifnet *ifp; 1140123474Swpaul 1141123474Swpaul sc = arg; 1142123474Swpaul ifp = &sc->arpcom.ac_if; 1143123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1144123474Swpaul if (adapter == NULL) 1145123474Swpaul return(EIO); 1146123474Swpaul resetfunc = sc->ndis_chars.nmc_reset_func; 1147123474Swpaul 1148123474Swpaul if (resetfunc == NULL) 1149123474Swpaul return(EINVAL); 1150123474Swpaul 1151123474Swpaul resetfunc(&addressing_reset, adapter); 1152123474Swpaul 1153123474Swpaul return(0); 1154123474Swpaul} 1155123474Swpaul 1156123474Swpaulint 1157123474Swpaulndis_halt_nic(arg) 1158123474Swpaul void *arg; 1159123474Swpaul{ 1160123474Swpaul struct ndis_softc *sc; 1161123474Swpaul ndis_handle adapter; 1162123474Swpaul __stdcall ndis_halt_handler haltfunc; 1163123474Swpaul struct ifnet *ifp; 1164123821Swpaul struct ndis_timer_entry *ne; 1165123474Swpaul 1166123474Swpaul sc = arg; 1167123474Swpaul ifp = &sc->arpcom.ac_if; 1168123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1169123474Swpaul if (adapter == NULL) 1170123474Swpaul return(EIO); 1171123821Swpaul 1172123474Swpaul haltfunc = sc->ndis_chars.nmc_halt_func; 1173123474Swpaul 1174123474Swpaul if (haltfunc == NULL) 1175123474Swpaul return(EINVAL); 1176123474Swpaul 1177123474Swpaul haltfunc(adapter); 1178123474Swpaul 1179123474Swpaul /* 1180123474Swpaul * The adapter context is only valid after the init 1181123474Swpaul * handler has been called, and is invalid once the 1182123474Swpaul * halt handler has been called. 1183123474Swpaul */ 1184123474Swpaul 1185123474Swpaul sc->ndis_block.nmb_miniportadapterctx = NULL; 1186123474Swpaul 1187123821Swpaul /* Clobber all the timers in case the driver left one running. */ 1188123821Swpaul 1189123821Swpaul while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) { 1190123821Swpaul ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist); 1191123821Swpaul TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link); 1192123832Swpaul callout_stop(&ne->nte_ch); 1193123821Swpaul free(ne, M_DEVBUF); 1194123821Swpaul } 1195123821Swpaul 1196123474Swpaul return(0); 1197123474Swpaul} 1198123474Swpaul 1199123474Swpaulint 1200123474Swpaulndis_shutdown_nic(arg) 1201123474Swpaul void *arg; 1202123474Swpaul{ 1203123474Swpaul struct ndis_softc *sc; 1204123474Swpaul ndis_handle adapter; 1205123474Swpaul __stdcall ndis_shutdown_handler shutdownfunc; 1206123474Swpaul 1207123474Swpaul 1208123474Swpaul sc = arg; 1209123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1210123474Swpaul if (adapter == NULL) 1211123474Swpaul return(EIO); 1212123474Swpaul shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 1213123474Swpaul 1214123474Swpaul if (shutdownfunc == NULL) 1215123474Swpaul return(EINVAL); 1216123474Swpaul 1217123485Swpaul if (sc->ndis_chars.nmc_rsvd0 == NULL) 1218123485Swpaul shutdownfunc(adapter); 1219123485Swpaul else 1220123485Swpaul shutdownfunc(sc->ndis_chars.nmc_rsvd0); 1221123474Swpaul 1222123474Swpaul return(0); 1223123474Swpaul} 1224123474Swpaul 1225123474Swpaulint 1226123474Swpaulndis_init_nic(arg) 1227123474Swpaul void *arg; 1228123474Swpaul{ 1229123474Swpaul struct ndis_softc *sc; 1230123474Swpaul ndis_miniport_block *block; 1231123474Swpaul __stdcall ndis_init_handler initfunc; 1232123474Swpaul ndis_status status, openstatus = 0; 1233123474Swpaul ndis_medium mediumarray[NdisMediumMax]; 1234123474Swpaul uint32_t chosenmedium, i; 1235123474Swpaul 1236123474Swpaul if (arg == NULL) 1237123474Swpaul return(EINVAL); 1238123474Swpaul 1239123474Swpaul sc = arg; 1240123474Swpaul block = &sc->ndis_block; 1241123474Swpaul initfunc = sc->ndis_chars.nmc_init_func; 1242123474Swpaul 1243123821Swpaul TAILQ_INIT(&block->nmb_timerlist); 1244123821Swpaul 1245123474Swpaul for (i = 0; i < NdisMediumMax; i++) 1246123474Swpaul mediumarray[i] = i; 1247123474Swpaul 1248123474Swpaul status = initfunc(&openstatus, &chosenmedium, 1249123474Swpaul mediumarray, NdisMediumMax, block, block); 1250123474Swpaul 1251123474Swpaul /* 1252123474Swpaul * If the init fails, blow away the other exported routines 1253123474Swpaul * we obtained from the driver so we can't call them later. 1254123474Swpaul * If the init failed, none of these will work. 1255123474Swpaul */ 1256123474Swpaul if (status != NDIS_STATUS_SUCCESS) { 1257123474Swpaul bzero((char *)&sc->ndis_chars, 1258123474Swpaul sizeof(ndis_miniport_characteristics)); 1259123474Swpaul return(ENXIO); 1260123474Swpaul } 1261123474Swpaul 1262123474Swpaul return(0); 1263123474Swpaul} 1264123474Swpaul 1265123474Swpaulvoid 1266123474Swpaulndis_enable_intr(arg) 1267123474Swpaul void *arg; 1268123474Swpaul{ 1269123474Swpaul struct ndis_softc *sc; 1270123474Swpaul ndis_handle adapter; 1271123474Swpaul __stdcall ndis_enable_interrupts_handler intrenbfunc; 1272123474Swpaul 1273123474Swpaul sc = arg; 1274123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1275123474Swpaul if (adapter == NULL) 1276123474Swpaul return; 1277123474Swpaul intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 1278123474Swpaul if (intrenbfunc == NULL) 1279123474Swpaul return; 1280123474Swpaul intrenbfunc(adapter); 1281123474Swpaul 1282123474Swpaul return; 1283123474Swpaul} 1284123474Swpaul 1285123474Swpaulvoid 1286123474Swpaulndis_disable_intr(arg) 1287123474Swpaul void *arg; 1288123474Swpaul{ 1289123474Swpaul struct ndis_softc *sc; 1290123474Swpaul ndis_handle adapter; 1291123474Swpaul __stdcall ndis_disable_interrupts_handler intrdisfunc; 1292123474Swpaul 1293123474Swpaul sc = arg; 1294123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1295123474Swpaul if (adapter == NULL) 1296123474Swpaul return; 1297123474Swpaul intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 1298123474Swpaul if (intrdisfunc == NULL) 1299123474Swpaul return; 1300123474Swpaul intrdisfunc(adapter); 1301123474Swpaul 1302123474Swpaul return; 1303123474Swpaul} 1304123474Swpaul 1305123474Swpaulint 1306123474Swpaulndis_isr(arg, ourintr, callhandler) 1307123474Swpaul void *arg; 1308123474Swpaul int *ourintr; 1309123474Swpaul int *callhandler; 1310123474Swpaul{ 1311123474Swpaul struct ndis_softc *sc; 1312123474Swpaul ndis_handle adapter; 1313123474Swpaul __stdcall ndis_isr_handler isrfunc; 1314123474Swpaul uint8_t accepted, queue; 1315123474Swpaul 1316123474Swpaul if (arg == NULL || ourintr == NULL || callhandler == NULL) 1317123474Swpaul return(EINVAL); 1318123474Swpaul 1319123474Swpaul sc = arg; 1320123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1321123474Swpaul isrfunc = sc->ndis_chars.nmc_isr_func; 1322123474Swpaul isrfunc(&accepted, &queue, adapter); 1323123474Swpaul *ourintr = accepted; 1324123474Swpaul *callhandler = queue; 1325123474Swpaul 1326123474Swpaul return(0); 1327123474Swpaul} 1328123474Swpaul 1329123474Swpaulint 1330123474Swpaulndis_intrhand(arg) 1331123474Swpaul void *arg; 1332123474Swpaul{ 1333123474Swpaul struct ndis_softc *sc; 1334123474Swpaul ndis_handle adapter; 1335123474Swpaul __stdcall ndis_interrupt_handler intrfunc; 1336123474Swpaul 1337123474Swpaul if (arg == NULL) 1338123474Swpaul return(EINVAL); 1339123474Swpaul 1340123474Swpaul sc = arg; 1341123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1342123474Swpaul intrfunc = sc->ndis_chars.nmc_interrupt_func; 1343123474Swpaul intrfunc(adapter); 1344123474Swpaul 1345123474Swpaul return(0); 1346123474Swpaul} 1347123474Swpaul 1348123474Swpaulint 1349123474Swpaulndis_get_info(arg, oid, buf, buflen) 1350123474Swpaul void *arg; 1351123474Swpaul ndis_oid oid; 1352123474Swpaul void *buf; 1353123474Swpaul int *buflen; 1354123474Swpaul{ 1355123474Swpaul struct ndis_softc *sc; 1356123474Swpaul ndis_status rval; 1357123474Swpaul ndis_handle adapter; 1358123474Swpaul __stdcall ndis_queryinfo_handler queryfunc; 1359123474Swpaul uint32_t byteswritten = 0, bytesneeded = 0; 1360123695Swpaul struct timeval tv; 1361123695Swpaul int error; 1362123474Swpaul 1363123474Swpaul sc = arg; 1364123474Swpaul queryfunc = sc->ndis_chars.nmc_queryinfo_func; 1365123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1366123474Swpaul 1367123474Swpaul rval = queryfunc(adapter, oid, buf, *buflen, 1368123474Swpaul &byteswritten, &bytesneeded); 1369123474Swpaul 1370123695Swpaul /* Wait for requests that block. */ 1371123695Swpaul 1372123695Swpaul if (rval == NDIS_STATUS_PENDING) { 1373123695Swpaul tv.tv_sec = 60; 1374123695Swpaul tv.tv_usec = 0; 1375123695Swpaul error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1376123757Swpaul PPAUSE|PCATCH, "ndisget", tvtohz(&tv)); 1377123695Swpaul rval = sc->ndis_block.nmb_getstat; 1378123695Swpaul } 1379123695Swpaul 1380123474Swpaul if (byteswritten) 1381123474Swpaul *buflen = byteswritten; 1382123474Swpaul if (bytesneeded) 1383123474Swpaul *buflen = bytesneeded; 1384123474Swpaul 1385123474Swpaul if (rval == NDIS_STATUS_INVALID_LENGTH || 1386123474Swpaul rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1387123474Swpaul return(ENOSPC); 1388123474Swpaul 1389123474Swpaul if (rval == NDIS_STATUS_INVALID_OID) 1390123474Swpaul return(EINVAL); 1391123474Swpaul 1392123474Swpaul if (rval == NDIS_STATUS_NOT_SUPPORTED || 1393123474Swpaul rval == NDIS_STATUS_NOT_ACCEPTED) 1394123474Swpaul return(ENOTSUP); 1395123474Swpaul 1396123474Swpaul return(0); 1397123474Swpaul} 1398123474Swpaul 1399123474Swpaulint 1400123474Swpaulndis_unload_driver(arg) 1401123474Swpaul void *arg; 1402123474Swpaul{ 1403123474Swpaul struct ndis_softc *sc; 1404123474Swpaul 1405123474Swpaul sc = arg; 1406123474Swpaul 1407123474Swpaul free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1408123474Swpaul 1409123474Swpaul ndis_flush_sysctls(sc); 1410123474Swpaul 1411124697Swpaul ndis_shrink_thrqueue(8); 1412124697Swpaul 1413123474Swpaul return(0); 1414123474Swpaul} 1415123474Swpaul 1416124446Swpaul#define NDIS_LOADED 0x42534F44 1417124446Swpaul 1418123474Swpaulint 1419123474Swpaulndis_load_driver(img, arg) 1420123474Swpaul vm_offset_t img; 1421123474Swpaul void *arg; 1422123474Swpaul{ 1423123474Swpaul __stdcall driver_entry entry; 1424123474Swpaul image_optional_header opt_hdr; 1425123474Swpaul image_import_descriptor imp_desc; 1426123474Swpaul ndis_unicode_string dummystr; 1427123474Swpaul ndis_driver_object drv; 1428123474Swpaul ndis_miniport_block *block; 1429123474Swpaul ndis_status status; 1430123474Swpaul int idx; 1431123474Swpaul uint32_t *ptr; 1432123474Swpaul struct ndis_softc *sc; 1433123474Swpaul 1434123474Swpaul sc = arg; 1435123474Swpaul 1436124446Swpaul /* 1437124446Swpaul * Only perform the relocation/linking phase once 1438124446Swpaul * since the binary image may be shared among multiple 1439124446Swpaul * device instances. 1440124446Swpaul */ 1441123474Swpaul 1442124446Swpaul ptr = (uint32_t *)(img + 8); 1443124446Swpaul if (*ptr != NDIS_LOADED) { 1444124446Swpaul /* Perform text relocation */ 1445124446Swpaul if (pe_relocate(img)) 1446124446Swpaul return(ENOEXEC); 1447123474Swpaul 1448124446Swpaul /* Dynamically link the NDIS.SYS routines -- required. */ 1449124446Swpaul if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1450124446Swpaul return(ENOEXEC); 1451123474Swpaul 1452124446Swpaul /* Dynamically link the HAL.dll routines -- also required. */ 1453124446Swpaul if (pe_patch_imports(img, "HAL", hal_functbl)) 1454123474Swpaul return(ENOEXEC); 1455124446Swpaul 1456124446Swpaul /* Dynamically link ntoskrnl.exe -- optional. */ 1457124446Swpaul if (pe_get_import_descriptor(img, 1458124446Swpaul &imp_desc, "ntoskrnl") == 0) { 1459124446Swpaul if (pe_patch_imports(img, 1460124446Swpaul "ntoskrnl", ntoskrnl_functbl)) 1461124446Swpaul return(ENOEXEC); 1462124446Swpaul } 1463124446Swpaul *ptr = NDIS_LOADED; 1464123474Swpaul } 1465123474Swpaul 1466123474Swpaul /* Locate the driver entry point */ 1467123474Swpaul pe_get_optional_header(img, &opt_hdr); 1468123474Swpaul entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1469123474Swpaul 1470123474Swpaul /* 1471123474Swpaul * Now call the DriverEntry() routine. This will cause 1472123474Swpaul * a callout to the NdisInitializeWrapper() and 1473123474Swpaul * NdisMRegisterMiniport() routines. 1474123474Swpaul */ 1475123474Swpaul dummystr.nus_len = strlen(NDIS_DUMMY_PATH); 1476123474Swpaul dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH); 1477123474Swpaul dummystr.nus_buf = NULL; 1478123474Swpaul ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1479123474Swpaul drv.ndo_ifname = "ndis0"; 1480123474Swpaul 1481123474Swpaul status = entry(&drv, &dummystr); 1482123474Swpaul 1483123474Swpaul free (dummystr.nus_buf, M_DEVBUF); 1484123474Swpaul 1485123474Swpaul if (status != NDIS_STATUS_SUCCESS) 1486123474Swpaul return(ENODEV); 1487123474Swpaul 1488123474Swpaul /* 1489123474Swpaul * Now that we have the miniport driver characteristics, 1490123474Swpaul * create an NDIS block and call the init handler. 1491123474Swpaul * This will cause the driver to try to probe for 1492123474Swpaul * a device. 1493123474Swpaul */ 1494123474Swpaul 1495123474Swpaul block = &sc->ndis_block; 1496123474Swpaul bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars, 1497123474Swpaul sizeof(ndis_miniport_characteristics)); 1498123474Swpaul 1499123474Swpaul /*block->nmb_signature = 0xcafebabe;*/ 1500123474Swpaul 1501123474Swpaul ptr = (uint32_t *)block; 1502123474Swpaul for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1503123474Swpaul *ptr = idx | 0xdead0000; 1504123474Swpaul ptr++; 1505123474Swpaul } 1506123474Swpaul 1507123474Swpaul block->nmb_signature = (void *)0xcafebabe; 1508123474Swpaul block->nmb_setdone_func = ndis_setdone_func; 1509123535Swpaul block->nmb_querydone_func = ndis_getdone_func; 1510123474Swpaul block->nmb_status_func = ndis_status_func; 1511123474Swpaul block->nmb_statusdone_func = ndis_statusdone_func; 1512123474Swpaul block->nmb_resetdone_func = ndis_resetdone_func; 1513124100Swpaul block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; 1514123474Swpaul 1515123474Swpaul block->nmb_ifp = &sc->arpcom.ac_if; 1516123474Swpaul block->nmb_dev = sc->ndis_dev; 1517124165Swpaul block->nmb_img = img; 1518123474Swpaul 1519124697Swpaul ndis_enlarge_thrqueue(8); 1520124697Swpaul 1521123474Swpaul return(0); 1522123474Swpaul} 1523