kern_ndis.c revision 127393
1/* 2 * Copyright (c) 2003 3 * Bill Paul <wpaul@windriver.com>. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Bill Paul. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 127393 2004-03-25 08:23:08Z wpaul $"); 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/unistd.h> 39#include <sys/types.h> 40#include <sys/errno.h> 41#include <sys/callout.h> 42#include <sys/socket.h> 43#include <sys/queue.h> 44#include <sys/sysctl.h> 45#include <sys/proc.h> 46#include <sys/malloc.h> 47#include <sys/lock.h> 48#include <sys/mutex.h> 49#include <sys/conf.h> 50 51#include <sys/kernel.h> 52#include <sys/kthread.h> 53#include <machine/bus.h> 54#include <machine/resource.h> 55#include <sys/bus.h> 56#include <sys/rman.h> 57 58#include <vm/uma.h> 59 60#include <net/if.h> 61#include <net/if_arp.h> 62#include <net/ethernet.h> 63#include <net/if_dl.h> 64#include <net/if_media.h> 65 66#include <net80211/ieee80211_var.h> 67#include <net80211/ieee80211_ioctl.h> 68 69#include <compat/ndis/pe_var.h> 70#include <compat/ndis/resource_var.h> 71#include <compat/ndis/ntoskrnl_var.h> 72#include <compat/ndis/ndis_var.h> 73#include <compat/ndis/hal_var.h> 74#include <compat/ndis/cfg_var.h> 75#include <dev/if_ndis/if_ndisvar.h> 76 77#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 78 79__stdcall static void ndis_status_func(ndis_handle, ndis_status, 80 void *, uint32_t); 81__stdcall static void ndis_statusdone_func(ndis_handle); 82__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 83__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 84__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 85__stdcall static void ndis_sendrsrcavail_func(ndis_handle); 86 87struct nd_head ndis_devhead; 88 89struct ndis_req { 90 void (*nr_func)(void *); 91 void *nr_arg; 92 int nr_exit; 93 STAILQ_ENTRY(ndis_req) link; 94}; 95 96struct ndisproc { 97 struct ndisqhead *np_q; 98 struct proc *np_p; 99 int np_state; 100}; 101 102static int ndis_create_kthreads(void); 103static void ndis_destroy_kthreads(void); 104static void ndis_stop_thread(int); 105static int ndis_enlarge_thrqueue(int); 106static int ndis_shrink_thrqueue(int); 107static void ndis_runq(void *); 108 109extern struct mtx_pool *ndis_mtxpool; 110static uma_zone_t ndis_packet_zone, ndis_buffer_zone; 111struct mtx *ndis_thr_mtx; 112static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; 113struct ndisqhead ndis_itodo; 114struct ndisqhead ndis_free; 115static int ndis_jobs = 32; 116 117static struct ndisproc ndis_tproc; 118static struct ndisproc ndis_iproc; 119 120/* 121 * This allows us to export our symbols to other modules. 122 * Note that we call ourselves 'ndisapi' to avoid a namespace 123 * collision with if_ndis.ko, which internally calls itself 124 * 'ndis.' 125 */ 126static int 127ndis_modevent(module_t mod, int cmd, void *arg) 128{ 129 int error = 0; 130 131 switch (cmd) { 132 case MOD_LOAD: 133 /* Initialize subsystems */ 134 ndis_libinit(); 135 ntoskrnl_libinit(); 136 137 /* Initialize TX buffer UMA zone. */ 138 ndis_packet_zone = uma_zcreate("NDIS packet", 139 sizeof(ndis_packet), NULL, NULL, NULL, 140 NULL, UMA_ALIGN_PTR, 0); 141 ndis_buffer_zone = uma_zcreate("NDIS buffer", 142 sizeof(ndis_buffer), NULL, NULL, NULL, 143 NULL, UMA_ALIGN_PTR, 0); 144 145 ndis_create_kthreads(); 146 147 TAILQ_INIT(&ndis_devhead); 148 149 break; 150 case MOD_SHUTDOWN: 151 /* stop kthreads */ 152 ndis_destroy_kthreads(); 153 if (TAILQ_FIRST(&ndis_devhead) == NULL) { 154 /* Shut down subsystems */ 155 ndis_libfini(); 156 ntoskrnl_libfini(); 157 158 /* Remove zones */ 159 uma_zdestroy(ndis_packet_zone); 160 uma_zdestroy(ndis_buffer_zone); 161 } 162 break; 163 case MOD_UNLOAD: 164 /* stop kthreads */ 165 ndis_destroy_kthreads(); 166 167 /* Shut down subsystems */ 168 ndis_libfini(); 169 ntoskrnl_libfini(); 170 171 /* Remove zones */ 172 uma_zdestroy(ndis_packet_zone); 173 uma_zdestroy(ndis_buffer_zone); 174 break; 175 default: 176 error = EINVAL; 177 break; 178 } 179 180 return(error); 181} 182DEV_MODULE(ndisapi, ndis_modevent, NULL); 183MODULE_VERSION(ndisapi, 1); 184 185/* 186 * We create two kthreads for the NDIS subsystem. One of them is a task 187 * queue for performing various odd jobs. The other is an swi thread 188 * reserved exclusively for running interrupt handlers. The reason we 189 * have our own task queue is that there are some cases where we may 190 * need to sleep for a significant amount of time, and if we were to 191 * use one of the taskqueue threads, we might delay the processing 192 * of other pending tasks which might need to run right away. We have 193 * a separate swi thread because we don't want our interrupt handling 194 * to be delayed either. 195 * 196 * By default there are 32 jobs available to start, and another 8 197 * are added to the free list each time a new device is created. 198 */ 199 200static void 201ndis_runq(arg) 202 void *arg; 203{ 204 struct ndis_req *r = NULL, *die = NULL; 205 struct ndisproc *p; 206 207 p = arg; 208 209 while (1) { 210 kthread_suspend(p->np_p, 0); 211 212 /* Look for any jobs on the work queue. */ 213 214 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 215 p->np_state = NDIS_PSTATE_RUNNING; 216 while(STAILQ_FIRST(p->np_q) != NULL) { 217 r = STAILQ_FIRST(p->np_q); 218 STAILQ_REMOVE_HEAD(p->np_q, link); 219 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 220 221 /* Do the work. */ 222 223 if (r->nr_func != NULL) 224 (*r->nr_func)(r->nr_arg); 225 226 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 227 STAILQ_INSERT_HEAD(&ndis_free, r, link); 228 229 /* Check for a shutdown request */ 230 231 if (r->nr_exit == TRUE) 232 die = r; 233 } 234 p->np_state = NDIS_PSTATE_SLEEPING; 235 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 236 237 /* Bail if we were told to shut down. */ 238 239 if (die != NULL) 240 break; 241 } 242 243 wakeup(die); 244 kthread_exit(0); 245} 246 247static int 248ndis_create_kthreads() 249{ 250 struct ndis_req *r; 251 int i, error = 0; 252 253 ndis_thr_mtx = mtx_pool_alloc(ndis_mtxpool); 254 STAILQ_INIT(&ndis_ttodo); 255 STAILQ_INIT(&ndis_itodo); 256 STAILQ_INIT(&ndis_free); 257 258 for (i = 0; i < ndis_jobs; i++) { 259 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 260 if (r == NULL) { 261 error = ENOMEM; 262 break; 263 } 264 STAILQ_INSERT_HEAD(&ndis_free, r, link); 265 } 266 267 if (error == 0) { 268 ndis_tproc.np_q = &ndis_ttodo; 269 ndis_tproc.np_state = NDIS_PSTATE_SLEEPING; 270 error = kthread_create(ndis_runq, &ndis_tproc, 271 &ndis_tproc.np_p, RFHIGHPID, 272 NDIS_KSTACK_PAGES, "ndis taskqueue"); 273 } 274 275 if (error == 0) { 276 ndis_iproc.np_q = &ndis_itodo; 277 ndis_iproc.np_state = NDIS_PSTATE_SLEEPING; 278 error = kthread_create(ndis_runq, &ndis_iproc, 279 &ndis_iproc.np_p, RFHIGHPID, 280 NDIS_KSTACK_PAGES, "ndis swi"); 281 } 282 283 if (error) { 284 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 285 STAILQ_REMOVE_HEAD(&ndis_free, link); 286 free(r, M_DEVBUF); 287 } 288 return(error); 289 } 290 291 return(0); 292} 293 294static void 295ndis_destroy_kthreads() 296{ 297 struct ndis_req *r; 298 299 /* Stop the threads. */ 300 301 ndis_stop_thread(NDIS_TASKQUEUE); 302 ndis_stop_thread(NDIS_SWI); 303 304 /* Destroy request structures. */ 305 306 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 307 STAILQ_REMOVE_HEAD(&ndis_free, link); 308 free(r, M_DEVBUF); 309 } 310 311 return; 312} 313 314static void 315ndis_stop_thread(t) 316 int t; 317{ 318 struct ndis_req *r; 319 struct timeval tv; 320 struct ndisqhead *q; 321 struct proc *p; 322 323 if (t == NDIS_TASKQUEUE) { 324 q = &ndis_ttodo; 325 p = ndis_tproc.np_p; 326 } else { 327 q = &ndis_itodo; 328 p = ndis_iproc.np_p; 329 } 330 331 /* Create and post a special 'exit' job. */ 332 333 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 334 r = STAILQ_FIRST(&ndis_free); 335 STAILQ_REMOVE_HEAD(&ndis_free, link); 336 r->nr_func = NULL; 337 r->nr_arg = NULL; 338 r->nr_exit = TRUE; 339 STAILQ_INSERT_TAIL(q, r, link); 340 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 341 342 kthread_resume(p); 343 344 /* wait for thread exit */ 345 346 tv.tv_sec = 60; 347 tv.tv_usec = 0; 348 tsleep(r, PPAUSE|PCATCH, "ndisthrexit", tvtohz(&tv)); 349 350 /* Now empty the job list. */ 351 352 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 353 while ((r = STAILQ_FIRST(q)) != NULL) { 354 STAILQ_REMOVE_HEAD(q, link); 355 STAILQ_INSERT_HEAD(&ndis_free, r, link); 356 } 357 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 358 359 return; 360} 361 362static int 363ndis_enlarge_thrqueue(cnt) 364 int cnt; 365{ 366 struct ndis_req *r; 367 int i; 368 369 for (i = 0; i < cnt; i++) { 370 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 371 if (r == NULL) 372 return(ENOMEM); 373 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 374 STAILQ_INSERT_HEAD(&ndis_free, r, link); 375 ndis_jobs++; 376 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 377 } 378 379 return(0); 380} 381 382static int 383ndis_shrink_thrqueue(cnt) 384 int cnt; 385{ 386 struct ndis_req *r; 387 int i; 388 389 for (i = 0; i < cnt; i++) { 390 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 391 r = STAILQ_FIRST(&ndis_free); 392 if (r == NULL) { 393 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 394 return(ENOMEM); 395 } 396 STAILQ_REMOVE_HEAD(&ndis_free, link); 397 ndis_jobs--; 398 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 399 free(r, M_DEVBUF); 400 } 401 402 return(0); 403} 404 405int 406ndis_unsched(func, arg, t) 407 void (*func)(void *); 408 void *arg; 409 int t; 410{ 411 struct ndis_req *r; 412 struct ndisqhead *q; 413 struct proc *p; 414 415 if (t == NDIS_TASKQUEUE) { 416 q = &ndis_ttodo; 417 p = ndis_tproc.np_p; 418 } else { 419 q = &ndis_itodo; 420 p = ndis_iproc.np_p; 421 } 422 423 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 424 STAILQ_FOREACH(r, q, link) { 425 if (r->nr_func == func && r->nr_arg == arg) { 426 STAILQ_REMOVE(q, r, ndis_req, link); 427 STAILQ_INSERT_HEAD(&ndis_free, r, link); 428 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 429 return(0); 430 } 431 } 432 433 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 434 435 return(ENOENT); 436} 437 438int 439ndis_sched(func, arg, t) 440 void (*func)(void *); 441 void *arg; 442 int t; 443{ 444 struct ndis_req *r; 445 struct ndisqhead *q; 446 struct proc *p; 447 int s; 448 449 if (t == NDIS_TASKQUEUE) { 450 q = &ndis_ttodo; 451 p = ndis_tproc.np_p; 452 } else { 453 q = &ndis_itodo; 454 p = ndis_iproc.np_p; 455 } 456 457 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 458 /* 459 * Check to see if an instance of this job is already 460 * pending. If so, don't bother queuing it again. 461 */ 462 STAILQ_FOREACH(r, q, link) { 463 if (r->nr_func == func && r->nr_arg == arg) { 464 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 465 return(0); 466 } 467 } 468 r = STAILQ_FIRST(&ndis_free); 469 if (r == NULL) { 470 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 471 return(EAGAIN); 472 } 473 STAILQ_REMOVE_HEAD(&ndis_free, link); 474 r->nr_func = func; 475 r->nr_arg = arg; 476 r->nr_exit = FALSE; 477 STAILQ_INSERT_TAIL(q, r, link); 478 if (t == NDIS_TASKQUEUE) 479 s = ndis_tproc.np_state; 480 else 481 s = ndis_iproc.np_state; 482 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 483 484 /* 485 * Post the job, but only if the thread is actually blocked 486 * on its own suspend call. If a driver queues up a job with 487 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(), 488 * it may suspend there, and in that case we don't want to wake 489 * it up until KeWaitForObject() gets woken up on its own. 490 */ 491 if (s == NDIS_PSTATE_SLEEPING) 492 kthread_resume(p); 493 494 return(0); 495} 496 497__stdcall static void 498ndis_sendrsrcavail_func(adapter) 499 ndis_handle adapter; 500{ 501 return; 502} 503 504__stdcall static void 505ndis_status_func(adapter, status, sbuf, slen) 506 ndis_handle adapter; 507 ndis_status status; 508 void *sbuf; 509 uint32_t slen; 510{ 511 ndis_miniport_block *block; 512 block = adapter; 513 514 if (block->nmb_ifp->if_flags & IFF_DEBUG) 515 device_printf (block->nmb_dev, "status: %x\n", status); 516 return; 517} 518 519__stdcall static void 520ndis_statusdone_func(adapter) 521 ndis_handle adapter; 522{ 523 ndis_miniport_block *block; 524 block = adapter; 525 526 if (block->nmb_ifp->if_flags & IFF_DEBUG) 527 device_printf (block->nmb_dev, "status complete\n"); 528 return; 529} 530 531__stdcall static void 532ndis_setdone_func(adapter, status) 533 ndis_handle adapter; 534 ndis_status status; 535{ 536 ndis_miniport_block *block; 537 block = adapter; 538 539 block->nmb_setstat = status; 540 wakeup(&block->nmb_wkupdpctimer); 541 return; 542} 543 544__stdcall static void 545ndis_getdone_func(adapter, status) 546 ndis_handle adapter; 547 ndis_status status; 548{ 549 ndis_miniport_block *block; 550 block = adapter; 551 552 block->nmb_getstat = status; 553 wakeup(&block->nmb_wkupdpctimer); 554 return; 555} 556 557__stdcall static void 558ndis_resetdone_func(adapter, status, addressingreset) 559 ndis_handle adapter; 560 ndis_status status; 561 uint8_t addressingreset; 562{ 563 ndis_miniport_block *block; 564 block = adapter; 565 566 if (block->nmb_ifp->if_flags & IFF_DEBUG) 567 device_printf (block->nmb_dev, "reset done...\n"); 568 return; 569} 570 571int 572ndis_create_sysctls(arg) 573 void *arg; 574{ 575 struct ndis_softc *sc; 576 ndis_cfg *vals; 577 char buf[256]; 578 579 if (arg == NULL) 580 return(EINVAL); 581 582 sc = arg; 583 vals = sc->ndis_regvals; 584 585 TAILQ_INIT(&sc->ndis_cfglist_head); 586 587 /* Create the sysctl tree. */ 588 589 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 590 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 591 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 592 device_get_desc(sc->ndis_dev)); 593 594 /* Add the driver-specific registry keys. */ 595 596 vals = sc->ndis_regvals; 597 while(1) { 598 if (vals->nc_cfgkey == NULL) 599 break; 600 if (vals->nc_idx != sc->ndis_devidx) { 601 vals++; 602 continue; 603 } 604 SYSCTL_ADD_STRING(&sc->ndis_ctx, 605 SYSCTL_CHILDREN(sc->ndis_tree), 606 OID_AUTO, vals->nc_cfgkey, 607 CTLFLAG_RW, vals->nc_val, 608 sizeof(vals->nc_val), 609 vals->nc_cfgdesc); 610 vals++; 611 } 612 613 /* Now add a couple of builtin keys. */ 614 615 /* 616 * Environment can be either Windows (0) or WindowsNT (1). 617 * We qualify as the latter. 618 */ 619 ndis_add_sysctl(sc, "Environment", 620 "Windows environment", "1", CTLFLAG_RD); 621 622 /* NDIS version should be 5.1. */ 623 ndis_add_sysctl(sc, "NdisVersion", 624 "NDIS API Version", "0x00050001", CTLFLAG_RD); 625 626 /* Bus type (PCI, PCMCIA, etc...) */ 627 sprintf(buf, "%d", (int)sc->ndis_iftype); 628 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 629 630 if (sc->ndis_res_io != NULL) { 631 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 632 ndis_add_sysctl(sc, "IOBaseAddress", 633 "Base I/O Address", buf, CTLFLAG_RD); 634 } 635 636 if (sc->ndis_irq != NULL) { 637 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 638 ndis_add_sysctl(sc, "InterruptNumber", 639 "Interrupt Number", buf, CTLFLAG_RD); 640 } 641 642 return(0); 643} 644 645int 646ndis_add_sysctl(arg, key, desc, val, flag) 647 void *arg; 648 char *key; 649 char *desc; 650 char *val; 651 int flag; 652{ 653 struct ndis_softc *sc; 654 struct ndis_cfglist *cfg; 655 char descstr[256]; 656 657 sc = arg; 658 659 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 660 661 if (cfg == NULL) 662 return(ENOMEM); 663 664 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 665 if (desc == NULL) { 666 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 667 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 668 } else 669 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 670 strcpy(cfg->ndis_cfg.nc_val, val); 671 672 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 673 674 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 675 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 676 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 677 cfg->ndis_cfg.nc_cfgdesc); 678 679 return(0); 680} 681 682int 683ndis_flush_sysctls(arg) 684 void *arg; 685{ 686 struct ndis_softc *sc; 687 struct ndis_cfglist *cfg; 688 689 sc = arg; 690 691 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 692 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 693 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 694 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 695 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 696 free(cfg, M_DEVBUF); 697 } 698 699 return(0); 700} 701 702void 703ndis_return_packet(buf, arg) 704 void *buf; /* not used */ 705 void *arg; 706{ 707 struct ndis_softc *sc; 708 ndis_handle adapter; 709 ndis_packet *p; 710 __stdcall ndis_return_handler returnfunc; 711 712 if (arg == NULL) 713 return; 714 715 p = arg; 716 717 /* Decrement refcount. */ 718 p->np_refcnt--; 719 720 /* Release packet when refcount hits zero, otherwise return. */ 721 if (p->np_refcnt) 722 return; 723 724 sc = p->np_softc; 725 returnfunc = sc->ndis_chars.nmc_return_packet_func; 726 adapter = sc->ndis_block.nmb_miniportadapterctx; 727 if (adapter != NULL) 728 returnfunc(adapter, p); 729 730 return; 731} 732 733void 734ndis_free_bufs(b0) 735 ndis_buffer *b0; 736{ 737 ndis_buffer *next; 738 739 if (b0 == NULL) 740 return; 741 742 while(b0 != NULL) { 743 next = b0->nb_next; 744 uma_zfree (ndis_buffer_zone, b0); 745 b0 = next; 746 } 747 748 return; 749} 750 751void 752ndis_free_packet(p) 753 ndis_packet *p; 754{ 755 if (p == NULL) 756 return; 757 758 ndis_free_bufs(p->np_private.npp_head); 759 uma_zfree(ndis_packet_zone, p); 760 761 return; 762} 763 764int 765ndis_convert_res(arg) 766 void *arg; 767{ 768 struct ndis_softc *sc; 769 ndis_resource_list *rl = NULL; 770 cm_partial_resource_desc *prd = NULL; 771 ndis_miniport_block *block; 772 device_t dev; 773 struct resource_list *brl; 774 struct resource_list_entry *brle; 775 776 sc = arg; 777 block = &sc->ndis_block; 778 dev = sc->ndis_dev; 779 780 rl = malloc(sizeof(ndis_resource_list) + 781 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 782 M_DEVBUF, M_NOWAIT|M_ZERO); 783 784 if (rl == NULL) 785 return(ENOMEM); 786 787 rl->cprl_version = 5; 788 rl->cprl_version = 1; 789 rl->cprl_count = sc->ndis_rescnt; 790 prd = rl->cprl_partial_descs; 791 792 brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 793 if (brl != NULL) { 794 SLIST_FOREACH(brle, brl, link) { 795 switch (brle->type) { 796 case SYS_RES_IOPORT: 797 prd->cprd_type = CmResourceTypePort; 798 prd->u.cprd_port.cprd_start.np_quad = 799 brle->start; 800 prd->u.cprd_port.cprd_len = brle->count; 801 break; 802 case SYS_RES_MEMORY: 803 prd->cprd_type = CmResourceTypeMemory; 804 prd->u.cprd_port.cprd_start.np_quad = 805 brle->start; 806 prd->u.cprd_port.cprd_len = brle->count; 807 break; 808 case SYS_RES_IRQ: 809 prd->cprd_type = CmResourceTypeInterrupt; 810 prd->u.cprd_intr.cprd_level = brle->start; 811 prd->u.cprd_intr.cprd_vector = brle->start; 812 prd->u.cprd_intr.cprd_affinity = 0; 813 break; 814 default: 815 break; 816 } 817 prd++; 818 } 819 } 820 821 block->nmb_rlist = rl; 822 823 return(0); 824} 825 826/* 827 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 828 * packet, it will hand it to us in the form of an ndis_packet, 829 * which we need to convert to an mbuf that is then handed off 830 * to the stack. Note: we configure the mbuf list so that it uses 831 * the memory regions specified by the ndis_buffer structures in 832 * the ndis_packet as external storage. In most cases, this will 833 * point to a memory region allocated by the driver (either by 834 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 835 * the driver to handle free()ing this region for is, so we set up 836 * a dummy no-op free handler for it. 837 */ 838 839int 840ndis_ptom(m0, p) 841 struct mbuf **m0; 842 ndis_packet *p; 843{ 844 struct mbuf *m, *prev = NULL; 845 ndis_buffer *buf; 846 ndis_packet_private *priv; 847 uint32_t totlen = 0; 848 849 if (p == NULL || m0 == NULL) 850 return(EINVAL); 851 852 priv = &p->np_private; 853 buf = priv->npp_head; 854 p->np_refcnt = 0; 855 856 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 857 if (buf == priv->npp_head) 858 MGETHDR(m, M_DONTWAIT, MT_HEADER); 859 else 860 MGET(m, M_DONTWAIT, MT_DATA); 861 if (m == NULL) { 862 m_freem(*m0); 863 *m0 = NULL; 864 return(ENOBUFS); 865 } 866 m->m_len = buf->nb_bytecount; 867 m->m_data = MDL_VA(buf); 868 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 869 p, 0, EXT_NDIS); 870 p->np_refcnt++; 871 totlen += m->m_len; 872 if (m->m_flags & MT_HEADER) 873 *m0 = m; 874 else 875 prev->m_next = m; 876 prev = m; 877 } 878 879 (*m0)->m_pkthdr.len = totlen; 880 881 return(0); 882} 883 884/* 885 * Create an mbuf chain from an NDIS packet chain. 886 * This is used mainly when transmitting packets, where we need 887 * to turn an mbuf off an interface's send queue and transform it 888 * into an NDIS packet which will be fed into the NDIS driver's 889 * send routine. 890 * 891 * NDIS packets consist of two parts: an ndis_packet structure, 892 * which is vaguely analagous to the pkthdr portion of an mbuf, 893 * and one or more ndis_buffer structures, which define the 894 * actual memory segments in which the packet data resides. 895 * We need to allocate one ndis_buffer for each mbuf in a chain, 896 * plus one ndis_packet as the header. 897 */ 898 899int 900ndis_mtop(m0, p) 901 struct mbuf *m0; 902 ndis_packet **p; 903{ 904 struct mbuf *m; 905 ndis_buffer *buf = NULL, *prev = NULL; 906 ndis_packet_private *priv; 907 908 if (p == NULL || m0 == NULL) 909 return(EINVAL); 910 911 /* If caller didn't supply a packet, make one. */ 912 if (*p == NULL) { 913 *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO); 914 915 if (*p == NULL) 916 return(ENOMEM); 917 } 918 919 priv = &(*p)->np_private; 920 priv->npp_totlen = m0->m_pkthdr.len; 921 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 922 priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 923 924 for (m = m0; m != NULL; m = m->m_next) { 925 if (m->m_len == 0) 926 continue; 927 buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); 928 if (buf == NULL) { 929 ndis_free_packet(*p); 930 *p = NULL; 931 return(ENOMEM); 932 } 933 934 MDL_INIT(buf, m->m_data, m->m_len); 935 if (priv->npp_head == NULL) 936 priv->npp_head = buf; 937 else 938 prev->nb_next = buf; 939 prev = buf; 940 } 941 942 priv->npp_tail = buf; 943 priv->npp_totlen = m0->m_pkthdr.len; 944 945 return(0); 946} 947 948int 949ndis_get_supported_oids(arg, oids, oidcnt) 950 void *arg; 951 ndis_oid **oids; 952 int *oidcnt; 953{ 954 int len, rval; 955 ndis_oid *o; 956 957 if (arg == NULL || oids == NULL || oidcnt == NULL) 958 return(EINVAL); 959 len = 0; 960 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 961 962 o = malloc(len, M_DEVBUF, M_NOWAIT); 963 if (o == NULL) 964 return(ENOMEM); 965 966 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 967 968 if (rval) { 969 free(o, M_DEVBUF); 970 return(rval); 971 } 972 973 *oids = o; 974 *oidcnt = len / 4; 975 976 return(0); 977} 978 979int 980ndis_set_info(arg, oid, buf, buflen) 981 void *arg; 982 ndis_oid oid; 983 void *buf; 984 int *buflen; 985{ 986 struct ndis_softc *sc; 987 ndis_status rval; 988 ndis_handle adapter; 989 __stdcall ndis_setinfo_handler setfunc; 990 uint32_t byteswritten = 0, bytesneeded = 0; 991 struct timeval tv; 992 int error; 993 994 sc = arg; 995 NDIS_LOCK(sc); 996 setfunc = sc->ndis_chars.nmc_setinfo_func; 997 adapter = sc->ndis_block.nmb_miniportadapterctx; 998 NDIS_UNLOCK(sc); 999 1000 if (adapter == NULL || setfunc == NULL) 1001 return(ENXIO); 1002 1003 rval = setfunc(adapter, oid, buf, *buflen, 1004 &byteswritten, &bytesneeded); 1005 1006 if (rval == NDIS_STATUS_PENDING) { 1007 tv.tv_sec = 60; 1008 tv.tv_usec = 0; 1009 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1010 PPAUSE|PCATCH, "ndisset", tvtohz(&tv)); 1011 rval = sc->ndis_block.nmb_setstat; 1012 } 1013 1014 if (byteswritten) 1015 *buflen = byteswritten; 1016 if (bytesneeded) 1017 *buflen = bytesneeded; 1018 1019 if (rval == NDIS_STATUS_INVALID_LENGTH) 1020 return(ENOSPC); 1021 1022 if (rval == NDIS_STATUS_INVALID_OID) 1023 return(EINVAL); 1024 1025 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1026 rval == NDIS_STATUS_NOT_ACCEPTED) 1027 return(ENOTSUP); 1028 1029 if (rval != NDIS_STATUS_SUCCESS) 1030 return(ENODEV); 1031 1032 return(0); 1033} 1034 1035typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 1036 1037int 1038ndis_send_packets(arg, packets, cnt) 1039 void *arg; 1040 ndis_packet **packets; 1041 int cnt; 1042{ 1043 struct ndis_softc *sc; 1044 ndis_handle adapter; 1045 __stdcall ndis_sendmulti_handler sendfunc; 1046 __stdcall ndis_senddone_func senddonefunc; 1047 int i; 1048 ndis_packet *p; 1049 1050 sc = arg; 1051 adapter = sc->ndis_block.nmb_miniportadapterctx; 1052 if (adapter == NULL) 1053 return(ENXIO); 1054 sendfunc = sc->ndis_chars.nmc_sendmulti_func; 1055 senddonefunc = sc->ndis_block.nmb_senddone_func; 1056 sendfunc(adapter, packets, cnt); 1057 1058 for (i = 0; i < cnt; i++) { 1059 p = packets[i]; 1060 /* 1061 * Either the driver already handed the packet to 1062 * ndis_txeof() due to a failure, or it wants to keep 1063 * it and release it asynchronously later. Skip to the 1064 * next one. 1065 */ 1066 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 1067 continue; 1068 senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status); 1069 } 1070 1071 return(0); 1072} 1073 1074int 1075ndis_send_packet(arg, packet) 1076 void *arg; 1077 ndis_packet *packet; 1078{ 1079 struct ndis_softc *sc; 1080 ndis_handle adapter; 1081 ndis_status status; 1082 __stdcall ndis_sendsingle_handler sendfunc; 1083 __stdcall ndis_senddone_func senddonefunc; 1084 1085 sc = arg; 1086 adapter = sc->ndis_block.nmb_miniportadapterctx; 1087 if (adapter == NULL) 1088 return(ENXIO); 1089 sendfunc = sc->ndis_chars.nmc_sendsingle_func; 1090 senddonefunc = sc->ndis_block.nmb_senddone_func; 1091 1092 status = sendfunc(adapter, packet, packet->np_private.npp_flags); 1093 1094 if (status == NDIS_STATUS_PENDING) 1095 return(0); 1096 1097 senddonefunc(&sc->ndis_block, packet, status); 1098 1099 return(0); 1100} 1101 1102int 1103ndis_init_dma(arg) 1104 void *arg; 1105{ 1106 struct ndis_softc *sc; 1107 int i, error; 1108 1109 sc = arg; 1110 1111 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1112 M_DEVBUF, M_NOWAIT|M_ZERO); 1113 1114 if (sc->ndis_tmaps == NULL) 1115 return(ENOMEM); 1116 1117 for (i = 0; i < sc->ndis_maxpkts; i++) { 1118 error = bus_dmamap_create(sc->ndis_ttag, 0, 1119 &sc->ndis_tmaps[i]); 1120 if (error) { 1121 free(sc->ndis_tmaps, M_DEVBUF); 1122 return(ENODEV); 1123 } 1124 } 1125 1126 return(0); 1127} 1128 1129int 1130ndis_destroy_dma(arg) 1131 void *arg; 1132{ 1133 struct ndis_softc *sc; 1134 struct mbuf *m; 1135 ndis_packet *p = NULL; 1136 int i; 1137 1138 sc = arg; 1139 1140 for (i = 0; i < sc->ndis_maxpkts; i++) { 1141 if (sc->ndis_txarray[i] != NULL) { 1142 p = sc->ndis_txarray[i]; 1143 m = (struct mbuf *)p->np_rsvd[1]; 1144 if (m != NULL) 1145 m_freem(m); 1146 ndis_free_packet(sc->ndis_txarray[i]); 1147 } 1148 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1149 } 1150 1151 free(sc->ndis_tmaps, M_DEVBUF); 1152 1153 bus_dma_tag_destroy(sc->ndis_ttag); 1154 1155 return(0); 1156} 1157 1158int 1159ndis_reset_nic(arg) 1160 void *arg; 1161{ 1162 struct ndis_softc *sc; 1163 ndis_handle adapter; 1164 __stdcall ndis_reset_handler resetfunc; 1165 uint8_t addressing_reset; 1166 struct ifnet *ifp; 1167 1168 sc = arg; 1169 ifp = &sc->arpcom.ac_if; 1170 NDIS_LOCK(sc); 1171 adapter = sc->ndis_block.nmb_miniportadapterctx; 1172 resetfunc = sc->ndis_chars.nmc_reset_func; 1173 NDIS_UNLOCK(sc); 1174 if (adapter == NULL || resetfunc == NULL) 1175 return(EIO); 1176 1177 resetfunc(&addressing_reset, adapter); 1178 1179 return(0); 1180} 1181 1182int 1183ndis_halt_nic(arg) 1184 void *arg; 1185{ 1186 struct ndis_softc *sc; 1187 ndis_handle adapter; 1188 __stdcall ndis_halt_handler haltfunc; 1189 struct ifnet *ifp; 1190 1191 sc = arg; 1192 ifp = &sc->arpcom.ac_if; 1193 1194 NDIS_LOCK(sc); 1195 adapter = sc->ndis_block.nmb_miniportadapterctx; 1196 if (adapter == NULL) { 1197 NDIS_UNLOCK(sc); 1198 return(EIO); 1199 } 1200 1201 /* 1202 * The adapter context is only valid after the init 1203 * handler has been called, and is invalid once the 1204 * halt handler has been called. 1205 */ 1206 1207 haltfunc = sc->ndis_chars.nmc_halt_func; 1208 NDIS_UNLOCK(sc); 1209 1210 haltfunc(adapter); 1211 1212 NDIS_LOCK(sc); 1213 sc->ndis_block.nmb_miniportadapterctx = NULL; 1214 NDIS_UNLOCK(sc); 1215 1216 return(0); 1217} 1218 1219int 1220ndis_shutdown_nic(arg) 1221 void *arg; 1222{ 1223 struct ndis_softc *sc; 1224 ndis_handle adapter; 1225 __stdcall ndis_shutdown_handler shutdownfunc; 1226 1227 sc = arg; 1228 NDIS_LOCK(sc); 1229 adapter = sc->ndis_block.nmb_miniportadapterctx; 1230 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 1231 NDIS_UNLOCK(sc); 1232 if (adapter == NULL || shutdownfunc == NULL) 1233 return(EIO); 1234 1235 if (sc->ndis_chars.nmc_rsvd0 == NULL) 1236 shutdownfunc(adapter); 1237 else 1238 shutdownfunc(sc->ndis_chars.nmc_rsvd0); 1239 1240 ndis_shrink_thrqueue(8); 1241 TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1242 1243 return(0); 1244} 1245 1246int 1247ndis_init_nic(arg) 1248 void *arg; 1249{ 1250 struct ndis_softc *sc; 1251 ndis_miniport_block *block; 1252 __stdcall ndis_init_handler initfunc; 1253 ndis_status status, openstatus = 0; 1254 ndis_medium mediumarray[NdisMediumMax]; 1255 uint32_t chosenmedium, i; 1256 1257 if (arg == NULL) 1258 return(EINVAL); 1259 1260 sc = arg; 1261 NDIS_LOCK(sc); 1262 block = &sc->ndis_block; 1263 initfunc = sc->ndis_chars.nmc_init_func; 1264 NDIS_UNLOCK(sc); 1265 1266 TAILQ_INIT(&block->nmb_timerlist); 1267 1268 for (i = 0; i < NdisMediumMax; i++) 1269 mediumarray[i] = i; 1270 1271 status = initfunc(&openstatus, &chosenmedium, 1272 mediumarray, NdisMediumMax, block, block); 1273 1274 /* 1275 * If the init fails, blow away the other exported routines 1276 * we obtained from the driver so we can't call them later. 1277 * If the init failed, none of these will work. 1278 */ 1279 if (status != NDIS_STATUS_SUCCESS) { 1280 NDIS_LOCK(sc); 1281 sc->ndis_block.nmb_miniportadapterctx = NULL; 1282 NDIS_UNLOCK(sc); 1283 return(ENXIO); 1284 } 1285 1286 return(0); 1287} 1288 1289void 1290ndis_enable_intr(arg) 1291 void *arg; 1292{ 1293 struct ndis_softc *sc; 1294 ndis_handle adapter; 1295 __stdcall ndis_enable_interrupts_handler intrenbfunc; 1296 1297 sc = arg; 1298 NDIS_LOCK(sc); 1299 adapter = sc->ndis_block.nmb_miniportadapterctx; 1300 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 1301 NDIS_UNLOCK(sc); 1302 if (adapter == NULL || intrenbfunc == NULL) 1303 return; 1304 intrenbfunc(adapter); 1305 1306 return; 1307} 1308 1309void 1310ndis_disable_intr(arg) 1311 void *arg; 1312{ 1313 struct ndis_softc *sc; 1314 ndis_handle adapter; 1315 __stdcall ndis_disable_interrupts_handler intrdisfunc; 1316 1317 sc = arg; 1318 NDIS_LOCK(sc); 1319 adapter = sc->ndis_block.nmb_miniportadapterctx; 1320 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 1321 NDIS_UNLOCK(sc); 1322 if (adapter == NULL || intrdisfunc == NULL) 1323 return; 1324 intrdisfunc(adapter); 1325 1326 return; 1327} 1328 1329int 1330ndis_isr(arg, ourintr, callhandler) 1331 void *arg; 1332 int *ourintr; 1333 int *callhandler; 1334{ 1335 struct ndis_softc *sc; 1336 ndis_handle adapter; 1337 __stdcall ndis_isr_handler isrfunc; 1338 uint8_t accepted, queue; 1339 1340 if (arg == NULL || ourintr == NULL || callhandler == NULL) 1341 return(EINVAL); 1342 1343 sc = arg; 1344 NDIS_LOCK(sc); 1345 adapter = sc->ndis_block.nmb_miniportadapterctx; 1346 isrfunc = sc->ndis_chars.nmc_isr_func; 1347 NDIS_UNLOCK(sc); 1348 if (adapter == NULL || isrfunc == NULL) 1349 return(ENXIO); 1350 1351 isrfunc(&accepted, &queue, adapter); 1352 *ourintr = accepted; 1353 *callhandler = queue; 1354 1355 return(0); 1356} 1357 1358int 1359ndis_intrhand(arg) 1360 void *arg; 1361{ 1362 struct ndis_softc *sc; 1363 ndis_handle adapter; 1364 __stdcall ndis_interrupt_handler intrfunc; 1365 1366 if (arg == NULL) 1367 return(EINVAL); 1368 1369 sc = arg; 1370 NDIS_LOCK(sc); 1371 adapter = sc->ndis_block.nmb_miniportadapterctx; 1372 intrfunc = sc->ndis_chars.nmc_interrupt_func; 1373 NDIS_UNLOCK(sc); 1374 if (adapter == NULL || intrfunc == NULL) 1375 return(EINVAL); 1376 1377 intrfunc(adapter); 1378 1379 return(0); 1380} 1381 1382int 1383ndis_get_info(arg, oid, buf, buflen) 1384 void *arg; 1385 ndis_oid oid; 1386 void *buf; 1387 int *buflen; 1388{ 1389 struct ndis_softc *sc; 1390 ndis_status rval; 1391 ndis_handle adapter; 1392 __stdcall ndis_queryinfo_handler queryfunc; 1393 uint32_t byteswritten = 0, bytesneeded = 0; 1394 struct timeval tv; 1395 int error; 1396 1397 sc = arg; 1398 NDIS_LOCK(sc); 1399 queryfunc = sc->ndis_chars.nmc_queryinfo_func; 1400 adapter = sc->ndis_block.nmb_miniportadapterctx; 1401 NDIS_UNLOCK(sc); 1402 1403 if (adapter == NULL || queryfunc == NULL) 1404 return(ENXIO); 1405 1406 rval = queryfunc(adapter, oid, buf, *buflen, 1407 &byteswritten, &bytesneeded); 1408 1409 /* Wait for requests that block. */ 1410 1411 if (rval == NDIS_STATUS_PENDING) { 1412 tv.tv_sec = 60; 1413 tv.tv_usec = 0; 1414 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1415 PPAUSE|PCATCH, "ndisget", tvtohz(&tv)); 1416 rval = sc->ndis_block.nmb_getstat; 1417 } 1418 1419 if (byteswritten) 1420 *buflen = byteswritten; 1421 if (bytesneeded) 1422 *buflen = bytesneeded; 1423 1424 if (rval == NDIS_STATUS_INVALID_LENGTH || 1425 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1426 return(ENOSPC); 1427 1428 if (rval == NDIS_STATUS_INVALID_OID) 1429 return(EINVAL); 1430 1431 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1432 rval == NDIS_STATUS_NOT_ACCEPTED) 1433 return(ENOTSUP); 1434 1435 if (rval != NDIS_STATUS_SUCCESS) 1436 return(ENODEV); 1437 1438 return(0); 1439} 1440 1441int 1442ndis_unload_driver(arg) 1443 void *arg; 1444{ 1445 struct ndis_softc *sc; 1446 1447 sc = arg; 1448 1449 free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1450 1451 ndis_flush_sysctls(sc); 1452 1453 ndis_shrink_thrqueue(8); 1454 TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1455 1456 return(0); 1457} 1458 1459#define NDIS_LOADED 0x42534F44 1460 1461int 1462ndis_load_driver(img, arg) 1463 vm_offset_t img; 1464 void *arg; 1465{ 1466 __stdcall driver_entry entry; 1467 image_optional_header opt_hdr; 1468 image_import_descriptor imp_desc; 1469 ndis_unicode_string dummystr; 1470 ndis_miniport_block *block; 1471 ndis_status status; 1472 int idx; 1473 uint32_t *ptr; 1474 struct ndis_softc *sc; 1475 1476 sc = arg; 1477 1478 /* 1479 * Only perform the relocation/linking phase once 1480 * since the binary image may be shared among multiple 1481 * device instances. 1482 */ 1483 1484 ptr = (uint32_t *)(img + 8); 1485 if (*ptr != NDIS_LOADED) { 1486 /* Perform text relocation */ 1487 if (pe_relocate(img)) 1488 return(ENOEXEC); 1489 1490 /* Dynamically link the NDIS.SYS routines -- required. */ 1491 if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1492 return(ENOEXEC); 1493 1494 /* Dynamically link the HAL.dll routines -- also required. */ 1495 if (pe_patch_imports(img, "HAL", hal_functbl)) 1496 return(ENOEXEC); 1497 1498 /* Dynamically link ntoskrnl.exe -- optional. */ 1499 if (pe_get_import_descriptor(img, 1500 &imp_desc, "ntoskrnl") == 0) { 1501 if (pe_patch_imports(img, 1502 "ntoskrnl", ntoskrnl_functbl)) 1503 return(ENOEXEC); 1504 } 1505 *ptr = NDIS_LOADED; 1506 } 1507 1508 /* Locate the driver entry point */ 1509 pe_get_optional_header(img, &opt_hdr); 1510 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1511 1512 dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2; 1513 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2; 1514 dummystr.nus_buf = NULL; 1515 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1516 1517 /* 1518 * Now that we have the miniport driver characteristics, 1519 * create an NDIS block and call the init handler. 1520 * This will cause the driver to try to probe for 1521 * a device. 1522 */ 1523 1524 block = &sc->ndis_block; 1525 1526 ptr = (uint32_t *)block; 1527 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1528 *ptr = idx | 0xdead0000; 1529 ptr++; 1530 } 1531 1532 block->nmb_signature = (void *)0xcafebabe; 1533 block->nmb_setdone_func = ndis_setdone_func; 1534 block->nmb_querydone_func = ndis_getdone_func; 1535 block->nmb_status_func = ndis_status_func; 1536 block->nmb_statusdone_func = ndis_statusdone_func; 1537 block->nmb_resetdone_func = ndis_resetdone_func; 1538 block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; 1539 1540 block->nmb_ifp = &sc->arpcom.ac_if; 1541 block->nmb_dev = sc->ndis_dev; 1542 block->nmb_img = img; 1543 block->nmb_devobj.do_rsvd = block; 1544 1545 /* 1546 * Now call the DriverEntry() routine. This will cause 1547 * a callout to the NdisInitializeWrapper() and 1548 * NdisMRegisterMiniport() routines. 1549 */ 1550 status = entry(&block->nmb_devobj, &dummystr); 1551 1552 free (dummystr.nus_buf, M_DEVBUF); 1553 1554 if (status != NDIS_STATUS_SUCCESS) 1555 return(ENODEV); 1556 1557 ndis_enlarge_thrqueue(8); 1558 1559 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1560 1561 return(0); 1562} 1563