kern_ndis.c revision 126706
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 126706 2004-03-07 02:49:06Z 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, 0, "ndis taskqueue"); 272 } 273 274 if (error == 0) { 275 ndis_iproc.np_q = &ndis_itodo; 276 ndis_iproc.np_state = NDIS_PSTATE_SLEEPING; 277 error = kthread_create(ndis_runq, &ndis_iproc, 278 &ndis_iproc.np_p, RFHIGHPID, 0, "ndis swi"); 279 } 280 281 if (error) { 282 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 283 STAILQ_REMOVE_HEAD(&ndis_free, link); 284 free(r, M_DEVBUF); 285 } 286 return(error); 287 } 288 289 return(0); 290} 291 292static void 293ndis_destroy_kthreads() 294{ 295 struct ndis_req *r; 296 297 /* Stop the threads. */ 298 299 ndis_stop_thread(NDIS_TASKQUEUE); 300 ndis_stop_thread(NDIS_SWI); 301 302 /* Destroy request structures. */ 303 304 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 305 STAILQ_REMOVE_HEAD(&ndis_free, link); 306 free(r, M_DEVBUF); 307 } 308 309 return; 310} 311 312static void 313ndis_stop_thread(t) 314 int t; 315{ 316 struct ndis_req *r; 317 struct timeval tv; 318 struct ndisqhead *q; 319 struct proc *p; 320 321 if (t == NDIS_TASKQUEUE) { 322 q = &ndis_ttodo; 323 p = ndis_tproc.np_p; 324 } else { 325 q = &ndis_itodo; 326 p = ndis_iproc.np_p; 327 } 328 329 /* Create and post a special 'exit' job. */ 330 331 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 332 r = STAILQ_FIRST(&ndis_free); 333 STAILQ_REMOVE_HEAD(&ndis_free, link); 334 r->nr_func = NULL; 335 r->nr_arg = NULL; 336 r->nr_exit = TRUE; 337 STAILQ_INSERT_TAIL(q, r, link); 338 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 339 340 kthread_resume(p); 341 342 /* wait for thread exit */ 343 344 tv.tv_sec = 60; 345 tv.tv_usec = 0; 346 tsleep(r, PPAUSE|PCATCH, "ndisthrexit", tvtohz(&tv)); 347 348 /* Now empty the job list. */ 349 350 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 351 while ((r = STAILQ_FIRST(q)) != NULL) { 352 STAILQ_REMOVE_HEAD(q, link); 353 STAILQ_INSERT_HEAD(&ndis_free, r, link); 354 } 355 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 356 357 return; 358} 359 360static int 361ndis_enlarge_thrqueue(cnt) 362 int cnt; 363{ 364 struct ndis_req *r; 365 int i; 366 367 for (i = 0; i < cnt; i++) { 368 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 369 if (r == NULL) 370 return(ENOMEM); 371 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 372 STAILQ_INSERT_HEAD(&ndis_free, r, link); 373 ndis_jobs++; 374 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 375 } 376 377 return(0); 378} 379 380static int 381ndis_shrink_thrqueue(cnt) 382 int cnt; 383{ 384 struct ndis_req *r; 385 int i; 386 387 for (i = 0; i < cnt; i++) { 388 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 389 r = STAILQ_FIRST(&ndis_free); 390 if (r == NULL) { 391 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 392 return(ENOMEM); 393 } 394 STAILQ_REMOVE_HEAD(&ndis_free, link); 395 ndis_jobs--; 396 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 397 free(r, M_DEVBUF); 398 } 399 400 return(0); 401} 402 403int 404ndis_sched(func, arg, t) 405 void (*func)(void *); 406 void *arg; 407 int t; 408{ 409 struct ndis_req *r; 410 struct ndisqhead *q; 411 struct proc *p; 412 int s; 413 414 if (t == NDIS_TASKQUEUE) { 415 q = &ndis_ttodo; 416 p = ndis_tproc.np_p; 417 } else { 418 q = &ndis_itodo; 419 p = ndis_iproc.np_p; 420 } 421 422 mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx); 423 /* 424 * Check to see if an instance of this job is already 425 * pending. If so, don't bother queuing it again. 426 */ 427 STAILQ_FOREACH(r, q, link) { 428 if (r->nr_func == func && r->nr_arg == arg) { 429 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 430 return(0); 431 } 432 } 433 r = STAILQ_FIRST(&ndis_free); 434 if (r == NULL) { 435 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 436 return(EAGAIN); 437 } 438 STAILQ_REMOVE_HEAD(&ndis_free, link); 439 r->nr_func = func; 440 r->nr_arg = arg; 441 r->nr_exit = FALSE; 442 STAILQ_INSERT_TAIL(q, r, link); 443 if (t == NDIS_TASKQUEUE) 444 s = ndis_tproc.np_state; 445 else 446 s = ndis_iproc.np_state; 447 mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx); 448 449 /* 450 * Post the job, but only if the thread is actually blocked 451 * on its own suspend call. If a driver queues up a job with 452 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(), 453 * it may suspend there, and in that case we don't want to wake 454 * it up until KeWaitForObject() gets woken up on its own. 455 */ 456 if (s == NDIS_PSTATE_SLEEPING) 457 kthread_resume(p); 458 459 return(0); 460} 461 462__stdcall static void 463ndis_sendrsrcavail_func(adapter) 464 ndis_handle adapter; 465{ 466 return; 467} 468 469__stdcall static void 470ndis_status_func(adapter, status, sbuf, slen) 471 ndis_handle adapter; 472 ndis_status status; 473 void *sbuf; 474 uint32_t slen; 475{ 476 ndis_miniport_block *block; 477 block = adapter; 478 479 if (block->nmb_ifp->if_flags & IFF_DEBUG) 480 device_printf (block->nmb_dev, "status: %x\n", status); 481 return; 482} 483 484__stdcall static void 485ndis_statusdone_func(adapter) 486 ndis_handle adapter; 487{ 488 ndis_miniport_block *block; 489 block = adapter; 490 491 if (block->nmb_ifp->if_flags & IFF_DEBUG) 492 device_printf (block->nmb_dev, "status complete\n"); 493 return; 494} 495 496__stdcall static void 497ndis_setdone_func(adapter, status) 498 ndis_handle adapter; 499 ndis_status status; 500{ 501 ndis_miniport_block *block; 502 block = adapter; 503 504 block->nmb_setstat = status; 505 wakeup(&block->nmb_wkupdpctimer); 506 return; 507} 508 509__stdcall static void 510ndis_getdone_func(adapter, status) 511 ndis_handle adapter; 512 ndis_status status; 513{ 514 ndis_miniport_block *block; 515 block = adapter; 516 517 block->nmb_getstat = status; 518 wakeup(&block->nmb_wkupdpctimer); 519 return; 520} 521 522__stdcall static void 523ndis_resetdone_func(adapter, status, addressingreset) 524 ndis_handle adapter; 525 ndis_status status; 526 uint8_t addressingreset; 527{ 528 ndis_miniport_block *block; 529 block = adapter; 530 531 if (block->nmb_ifp->if_flags & IFF_DEBUG) 532 device_printf (block->nmb_dev, "reset done...\n"); 533 return; 534} 535 536int 537ndis_create_sysctls(arg) 538 void *arg; 539{ 540 struct ndis_softc *sc; 541 ndis_cfg *vals; 542 char buf[256]; 543 544 if (arg == NULL) 545 return(EINVAL); 546 547 sc = arg; 548 vals = sc->ndis_regvals; 549 550 TAILQ_INIT(&sc->ndis_cfglist_head); 551 552 /* Create the sysctl tree. */ 553 554 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 555 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 556 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 557 device_get_desc(sc->ndis_dev)); 558 559 /* Add the driver-specific registry keys. */ 560 561 vals = sc->ndis_regvals; 562 while(1) { 563 if (vals->nc_cfgkey == NULL) 564 break; 565 if (vals->nc_idx != sc->ndis_devidx) { 566 vals++; 567 continue; 568 } 569 SYSCTL_ADD_STRING(&sc->ndis_ctx, 570 SYSCTL_CHILDREN(sc->ndis_tree), 571 OID_AUTO, vals->nc_cfgkey, 572 CTLFLAG_RW, vals->nc_val, 573 sizeof(vals->nc_val), 574 vals->nc_cfgdesc); 575 vals++; 576 } 577 578 /* Now add a couple of builtin keys. */ 579 580 /* 581 * Environment can be either Windows (0) or WindowsNT (1). 582 * We qualify as the latter. 583 */ 584 ndis_add_sysctl(sc, "Environment", 585 "Windows environment", "1", CTLFLAG_RD); 586 587 /* NDIS version should be 5.1. */ 588 ndis_add_sysctl(sc, "NdisVersion", 589 "NDIS API Version", "0x00050001", CTLFLAG_RD); 590 591 /* Bus type (PCI, PCMCIA, etc...) */ 592 sprintf(buf, "%d", (int)sc->ndis_iftype); 593 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 594 595 if (sc->ndis_res_io != NULL) { 596 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 597 ndis_add_sysctl(sc, "IOBaseAddress", 598 "Base I/O Address", buf, CTLFLAG_RD); 599 } 600 601 if (sc->ndis_irq != NULL) { 602 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 603 ndis_add_sysctl(sc, "InterruptNumber", 604 "Interrupt Number", buf, CTLFLAG_RD); 605 } 606 607 return(0); 608} 609 610int 611ndis_add_sysctl(arg, key, desc, val, flag) 612 void *arg; 613 char *key; 614 char *desc; 615 char *val; 616 int flag; 617{ 618 struct ndis_softc *sc; 619 struct ndis_cfglist *cfg; 620 char descstr[256]; 621 622 sc = arg; 623 624 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 625 626 if (cfg == NULL) 627 return(ENOMEM); 628 629 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 630 if (desc == NULL) { 631 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 632 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 633 } else 634 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 635 strcpy(cfg->ndis_cfg.nc_val, val); 636 637 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 638 639 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 640 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 641 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 642 cfg->ndis_cfg.nc_cfgdesc); 643 644 return(0); 645} 646 647int 648ndis_flush_sysctls(arg) 649 void *arg; 650{ 651 struct ndis_softc *sc; 652 struct ndis_cfglist *cfg; 653 654 sc = arg; 655 656 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 657 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 658 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 659 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 660 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 661 free(cfg, M_DEVBUF); 662 } 663 664 return(0); 665} 666 667void 668ndis_return_packet(buf, arg) 669 void *buf; /* not used */ 670 void *arg; 671{ 672 struct ndis_softc *sc; 673 ndis_handle adapter; 674 ndis_packet *p; 675 __stdcall ndis_return_handler returnfunc; 676 677 if (arg == NULL) 678 return; 679 680 p = arg; 681 682 /* Decrement refcount. */ 683 p->np_refcnt--; 684 685 /* Release packet when refcount hits zero, otherwise return. */ 686 if (p->np_refcnt) 687 return; 688 689 sc = p->np_softc; 690 returnfunc = sc->ndis_chars.nmc_return_packet_func; 691 adapter = sc->ndis_block.nmb_miniportadapterctx; 692 if (adapter != NULL) 693 returnfunc(adapter, p); 694 695 return; 696} 697 698void 699ndis_free_bufs(b0) 700 ndis_buffer *b0; 701{ 702 ndis_buffer *next; 703 704 if (b0 == NULL) 705 return; 706 707 while(b0 != NULL) { 708 next = b0->nb_next; 709 uma_zfree (ndis_buffer_zone, b0); 710 b0 = next; 711 } 712 713 return; 714} 715 716void 717ndis_free_packet(p) 718 ndis_packet *p; 719{ 720 if (p == NULL) 721 return; 722 723 ndis_free_bufs(p->np_private.npp_head); 724 uma_zfree(ndis_packet_zone, p); 725 726 return; 727} 728 729int 730ndis_convert_res(arg) 731 void *arg; 732{ 733 struct ndis_softc *sc; 734 ndis_resource_list *rl = NULL; 735 cm_partial_resource_desc *prd = NULL; 736 ndis_miniport_block *block; 737 device_t dev; 738 struct resource_list *brl; 739 struct resource_list_entry *brle; 740 741 sc = arg; 742 block = &sc->ndis_block; 743 dev = sc->ndis_dev; 744 745 rl = malloc(sizeof(ndis_resource_list) + 746 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 747 M_DEVBUF, M_NOWAIT|M_ZERO); 748 749 if (rl == NULL) 750 return(ENOMEM); 751 752 rl->cprl_version = 5; 753 rl->cprl_version = 1; 754 rl->cprl_count = sc->ndis_rescnt; 755 prd = rl->cprl_partial_descs; 756 757 brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 758 if (brl != NULL) { 759 SLIST_FOREACH(brle, brl, link) { 760 switch (brle->type) { 761 case SYS_RES_IOPORT: 762 prd->cprd_type = CmResourceTypePort; 763 prd->u.cprd_port.cprd_start.np_quad = 764 brle->start; 765 prd->u.cprd_port.cprd_len = brle->count; 766 break; 767 case SYS_RES_MEMORY: 768 prd->cprd_type = CmResourceTypeMemory; 769 prd->u.cprd_port.cprd_start.np_quad = 770 brle->start; 771 prd->u.cprd_port.cprd_len = brle->count; 772 break; 773 case SYS_RES_IRQ: 774 prd->cprd_type = CmResourceTypeInterrupt; 775 prd->u.cprd_intr.cprd_level = brle->start; 776 prd->u.cprd_intr.cprd_vector = brle->start; 777 prd->u.cprd_intr.cprd_affinity = 0; 778 break; 779 default: 780 break; 781 } 782 prd++; 783 } 784 } 785 786 block->nmb_rlist = rl; 787 788 return(0); 789} 790 791/* 792 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 793 * packet, it will hand it to us in the form of an ndis_packet, 794 * which we need to convert to an mbuf that is then handed off 795 * to the stack. Note: we configure the mbuf list so that it uses 796 * the memory regions specified by the ndis_buffer structures in 797 * the ndis_packet as external storage. In most cases, this will 798 * point to a memory region allocated by the driver (either by 799 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 800 * the driver to handle free()ing this region for is, so we set up 801 * a dummy no-op free handler for it. 802 */ 803 804int 805ndis_ptom(m0, p) 806 struct mbuf **m0; 807 ndis_packet *p; 808{ 809 struct mbuf *m, *prev = NULL; 810 ndis_buffer *buf; 811 ndis_packet_private *priv; 812 uint32_t totlen = 0; 813 814 if (p == NULL || m0 == NULL) 815 return(EINVAL); 816 817 priv = &p->np_private; 818 buf = priv->npp_head; 819 p->np_refcnt = 0; 820 821 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 822 if (buf == priv->npp_head) 823 MGETHDR(m, M_DONTWAIT, MT_HEADER); 824 else 825 MGET(m, M_DONTWAIT, MT_DATA); 826 if (m == NULL) { 827 m_freem(*m0); 828 *m0 = NULL; 829 return(ENOBUFS); 830 } 831 m->m_len = buf->nb_bytecount; 832 m->m_data = MDL_VA(buf); 833 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 834 p, 0, EXT_NDIS); 835 p->np_refcnt++; 836 totlen += m->m_len; 837 if (m->m_flags & MT_HEADER) 838 *m0 = m; 839 else 840 prev->m_next = m; 841 prev = m; 842 } 843 844 (*m0)->m_pkthdr.len = totlen; 845 846 return(0); 847} 848 849/* 850 * Create an mbuf chain from an NDIS packet chain. 851 * This is used mainly when transmitting packets, where we need 852 * to turn an mbuf off an interface's send queue and transform it 853 * into an NDIS packet which will be fed into the NDIS driver's 854 * send routine. 855 * 856 * NDIS packets consist of two parts: an ndis_packet structure, 857 * which is vaguely analagous to the pkthdr portion of an mbuf, 858 * and one or more ndis_buffer structures, which define the 859 * actual memory segments in which the packet data resides. 860 * We need to allocate one ndis_buffer for each mbuf in a chain, 861 * plus one ndis_packet as the header. 862 */ 863 864int 865ndis_mtop(m0, p) 866 struct mbuf *m0; 867 ndis_packet **p; 868{ 869 struct mbuf *m; 870 ndis_buffer *buf = NULL, *prev = NULL; 871 ndis_packet_private *priv; 872 873 if (p == NULL || m0 == NULL) 874 return(EINVAL); 875 876 /* If caller didn't supply a packet, make one. */ 877 if (*p == NULL) { 878 *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO); 879 880 if (*p == NULL) 881 return(ENOMEM); 882 } 883 884 priv = &(*p)->np_private; 885 priv->npp_totlen = m0->m_pkthdr.len; 886 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 887 priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 888 889 for (m = m0; m != NULL; m = m->m_next) { 890 if (m->m_len == 0) 891 continue; 892 buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); 893 if (buf == NULL) { 894 ndis_free_packet(*p); 895 *p = NULL; 896 return(ENOMEM); 897 } 898 899 MDL_INIT(buf, m->m_data, m->m_len); 900 if (priv->npp_head == NULL) 901 priv->npp_head = buf; 902 else 903 prev->nb_next = buf; 904 prev = buf; 905 } 906 907 priv->npp_tail = buf; 908 priv->npp_totlen = m0->m_pkthdr.len; 909 910 return(0); 911} 912 913int 914ndis_get_supported_oids(arg, oids, oidcnt) 915 void *arg; 916 ndis_oid **oids; 917 int *oidcnt; 918{ 919 int len, rval; 920 ndis_oid *o; 921 922 if (arg == NULL || oids == NULL || oidcnt == NULL) 923 return(EINVAL); 924 len = 0; 925 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 926 927 o = malloc(len, M_DEVBUF, M_NOWAIT); 928 if (o == NULL) 929 return(ENOMEM); 930 931 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 932 933 if (rval) { 934 free(o, M_DEVBUF); 935 return(rval); 936 } 937 938 *oids = o; 939 *oidcnt = len / 4; 940 941 return(0); 942} 943 944int 945ndis_set_info(arg, oid, buf, buflen) 946 void *arg; 947 ndis_oid oid; 948 void *buf; 949 int *buflen; 950{ 951 struct ndis_softc *sc; 952 ndis_status rval; 953 ndis_handle adapter; 954 __stdcall ndis_setinfo_handler setfunc; 955 uint32_t byteswritten = 0, bytesneeded = 0; 956 struct timeval tv; 957 int error; 958 959 sc = arg; 960 NDIS_LOCK(sc); 961 setfunc = sc->ndis_chars.nmc_setinfo_func; 962 adapter = sc->ndis_block.nmb_miniportadapterctx; 963 NDIS_UNLOCK(sc); 964 965 if (adapter == NULL || setfunc == NULL) 966 return(ENXIO); 967 968 rval = setfunc(adapter, oid, buf, *buflen, 969 &byteswritten, &bytesneeded); 970 971 if (rval == NDIS_STATUS_PENDING) { 972 tv.tv_sec = 60; 973 tv.tv_usec = 0; 974 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 975 PPAUSE|PCATCH, "ndisset", tvtohz(&tv)); 976 rval = sc->ndis_block.nmb_setstat; 977 } 978 979 if (byteswritten) 980 *buflen = byteswritten; 981 if (bytesneeded) 982 *buflen = bytesneeded; 983 984 if (rval == NDIS_STATUS_INVALID_LENGTH) 985 return(ENOSPC); 986 987 if (rval == NDIS_STATUS_INVALID_OID) 988 return(EINVAL); 989 990 if (rval == NDIS_STATUS_NOT_SUPPORTED || 991 rval == NDIS_STATUS_NOT_ACCEPTED) 992 return(ENOTSUP); 993 994 if (rval != NDIS_STATUS_SUCCESS) 995 return(ENODEV); 996 997 return(0); 998} 999 1000typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 1001 1002int 1003ndis_send_packets(arg, packets, cnt) 1004 void *arg; 1005 ndis_packet **packets; 1006 int cnt; 1007{ 1008 struct ndis_softc *sc; 1009 ndis_handle adapter; 1010 __stdcall ndis_sendmulti_handler sendfunc; 1011 __stdcall ndis_senddone_func senddonefunc; 1012 int i; 1013 ndis_packet *p; 1014 1015 sc = arg; 1016 adapter = sc->ndis_block.nmb_miniportadapterctx; 1017 if (adapter == NULL) 1018 return(ENXIO); 1019 sendfunc = sc->ndis_chars.nmc_sendmulti_func; 1020 senddonefunc = sc->ndis_block.nmb_senddone_func; 1021 sendfunc(adapter, packets, cnt); 1022 1023 for (i = 0; i < cnt; i++) { 1024 p = packets[i]; 1025 /* 1026 * Either the driver already handed the packet to 1027 * ndis_txeof() due to a failure, or it wants to keep 1028 * it and release it asynchronously later. Skip to the 1029 * next one. 1030 */ 1031 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 1032 continue; 1033 senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status); 1034 } 1035 1036 return(0); 1037} 1038 1039int 1040ndis_send_packet(arg, packet) 1041 void *arg; 1042 ndis_packet *packet; 1043{ 1044 struct ndis_softc *sc; 1045 ndis_handle adapter; 1046 ndis_status status; 1047 __stdcall ndis_sendsingle_handler sendfunc; 1048 __stdcall ndis_senddone_func senddonefunc; 1049 1050 sc = arg; 1051 adapter = sc->ndis_block.nmb_miniportadapterctx; 1052 if (adapter == NULL) 1053 return(ENXIO); 1054 sendfunc = sc->ndis_chars.nmc_sendsingle_func; 1055 senddonefunc = sc->ndis_block.nmb_senddone_func; 1056 1057 status = sendfunc(adapter, packet, packet->np_private.npp_flags); 1058 1059 if (status == NDIS_STATUS_PENDING) 1060 return(0); 1061 1062 senddonefunc(&sc->ndis_block, packet, status); 1063 1064 return(0); 1065} 1066 1067int 1068ndis_init_dma(arg) 1069 void *arg; 1070{ 1071 struct ndis_softc *sc; 1072 int i, error; 1073 1074 sc = arg; 1075 1076 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1077 M_DEVBUF, M_NOWAIT|M_ZERO); 1078 1079 if (sc->ndis_tmaps == NULL) 1080 return(ENOMEM); 1081 1082 for (i = 0; i < sc->ndis_maxpkts; i++) { 1083 error = bus_dmamap_create(sc->ndis_ttag, 0, 1084 &sc->ndis_tmaps[i]); 1085 if (error) { 1086 free(sc->ndis_tmaps, M_DEVBUF); 1087 return(ENODEV); 1088 } 1089 } 1090 1091 return(0); 1092} 1093 1094int 1095ndis_destroy_dma(arg) 1096 void *arg; 1097{ 1098 struct ndis_softc *sc; 1099 struct mbuf *m; 1100 ndis_packet *p = NULL; 1101 int i; 1102 1103 sc = arg; 1104 1105 for (i = 0; i < sc->ndis_maxpkts; i++) { 1106 if (sc->ndis_txarray[i] != NULL) { 1107 p = sc->ndis_txarray[i]; 1108 m = (struct mbuf *)p->np_rsvd[1]; 1109 if (m != NULL) 1110 m_freem(m); 1111 ndis_free_packet(sc->ndis_txarray[i]); 1112 } 1113 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1114 } 1115 1116 free(sc->ndis_tmaps, M_DEVBUF); 1117 1118 bus_dma_tag_destroy(sc->ndis_ttag); 1119 1120 return(0); 1121} 1122 1123int 1124ndis_reset_nic(arg) 1125 void *arg; 1126{ 1127 struct ndis_softc *sc; 1128 ndis_handle adapter; 1129 __stdcall ndis_reset_handler resetfunc; 1130 uint8_t addressing_reset; 1131 struct ifnet *ifp; 1132 1133 sc = arg; 1134 ifp = &sc->arpcom.ac_if; 1135 NDIS_LOCK(sc); 1136 adapter = sc->ndis_block.nmb_miniportadapterctx; 1137 resetfunc = sc->ndis_chars.nmc_reset_func; 1138 NDIS_UNLOCK(sc); 1139 if (adapter == NULL || resetfunc == NULL) 1140 return(EIO); 1141 1142 resetfunc(&addressing_reset, adapter); 1143 1144 return(0); 1145} 1146 1147int 1148ndis_halt_nic(arg) 1149 void *arg; 1150{ 1151 struct ndis_softc *sc; 1152 ndis_handle adapter; 1153 __stdcall ndis_halt_handler haltfunc; 1154 struct ifnet *ifp; 1155 struct ndis_timer_entry *ne; 1156 1157 sc = arg; 1158 ifp = &sc->arpcom.ac_if; 1159 1160 NDIS_LOCK(sc); 1161 adapter = sc->ndis_block.nmb_miniportadapterctx; 1162 if (adapter == NULL) { 1163 NDIS_UNLOCK(sc); 1164 return(EIO); 1165 } 1166 1167 /* 1168 * The adapter context is only valid after the init 1169 * handler has been called, and is invalid once the 1170 * halt handler has been called. 1171 */ 1172 1173 haltfunc = sc->ndis_chars.nmc_halt_func; 1174 NDIS_UNLOCK(sc); 1175 1176 haltfunc(adapter); 1177 1178 NDIS_LOCK(sc); 1179 sc->ndis_block.nmb_miniportadapterctx = NULL; 1180 NDIS_UNLOCK(sc); 1181 /* Clobber all the timers in case the driver left one running. */ 1182 1183 while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) { 1184 ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist); 1185 TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link); 1186 callout_stop(&ne->nte_ch); 1187 free(ne, M_DEVBUF); 1188 } 1189 1190 return(0); 1191} 1192 1193int 1194ndis_shutdown_nic(arg) 1195 void *arg; 1196{ 1197 struct ndis_softc *sc; 1198 ndis_handle adapter; 1199 __stdcall ndis_shutdown_handler shutdownfunc; 1200 1201 sc = arg; 1202 NDIS_LOCK(sc); 1203 adapter = sc->ndis_block.nmb_miniportadapterctx; 1204 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 1205 NDIS_UNLOCK(sc); 1206 if (adapter == NULL || shutdownfunc == NULL) 1207 return(EIO); 1208 1209 if (sc->ndis_chars.nmc_rsvd0 == NULL) 1210 shutdownfunc(adapter); 1211 else 1212 shutdownfunc(sc->ndis_chars.nmc_rsvd0); 1213 1214 ndis_shrink_thrqueue(8); 1215 TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1216 1217 return(0); 1218} 1219 1220int 1221ndis_init_nic(arg) 1222 void *arg; 1223{ 1224 struct ndis_softc *sc; 1225 ndis_miniport_block *block; 1226 __stdcall ndis_init_handler initfunc; 1227 ndis_status status, openstatus = 0; 1228 ndis_medium mediumarray[NdisMediumMax]; 1229 uint32_t chosenmedium, i; 1230 1231 if (arg == NULL) 1232 return(EINVAL); 1233 1234 sc = arg; 1235 NDIS_LOCK(sc); 1236 block = &sc->ndis_block; 1237 initfunc = sc->ndis_chars.nmc_init_func; 1238 NDIS_UNLOCK(sc); 1239 1240 TAILQ_INIT(&block->nmb_timerlist); 1241 1242 for (i = 0; i < NdisMediumMax; i++) 1243 mediumarray[i] = i; 1244 1245 status = initfunc(&openstatus, &chosenmedium, 1246 mediumarray, NdisMediumMax, block, block); 1247 1248 /* 1249 * If the init fails, blow away the other exported routines 1250 * we obtained from the driver so we can't call them later. 1251 * If the init failed, none of these will work. 1252 */ 1253 if (status != NDIS_STATUS_SUCCESS) { 1254 NDIS_LOCK(sc); 1255 sc->ndis_block.nmb_miniportadapterctx = NULL; 1256 NDIS_UNLOCK(sc); 1257 return(ENXIO); 1258 } 1259 1260 return(0); 1261} 1262 1263void 1264ndis_enable_intr(arg) 1265 void *arg; 1266{ 1267 struct ndis_softc *sc; 1268 ndis_handle adapter; 1269 __stdcall ndis_enable_interrupts_handler intrenbfunc; 1270 1271 sc = arg; 1272 NDIS_LOCK(sc); 1273 adapter = sc->ndis_block.nmb_miniportadapterctx; 1274 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 1275 NDIS_UNLOCK(sc); 1276 if (adapter == NULL || intrenbfunc == NULL) 1277 return; 1278 intrenbfunc(adapter); 1279 1280 return; 1281} 1282 1283void 1284ndis_disable_intr(arg) 1285 void *arg; 1286{ 1287 struct ndis_softc *sc; 1288 ndis_handle adapter; 1289 __stdcall ndis_disable_interrupts_handler intrdisfunc; 1290 1291 sc = arg; 1292 NDIS_LOCK(sc); 1293 adapter = sc->ndis_block.nmb_miniportadapterctx; 1294 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 1295 NDIS_UNLOCK(sc); 1296 if (adapter == NULL || intrdisfunc) 1297 return; 1298 intrdisfunc(adapter); 1299 1300 return; 1301} 1302 1303int 1304ndis_isr(arg, ourintr, callhandler) 1305 void *arg; 1306 int *ourintr; 1307 int *callhandler; 1308{ 1309 struct ndis_softc *sc; 1310 ndis_handle adapter; 1311 __stdcall ndis_isr_handler isrfunc; 1312 uint8_t accepted, queue; 1313 1314 if (arg == NULL || ourintr == NULL || callhandler == NULL) 1315 return(EINVAL); 1316 1317 sc = arg; 1318 NDIS_LOCK(sc); 1319 adapter = sc->ndis_block.nmb_miniportadapterctx; 1320 isrfunc = sc->ndis_chars.nmc_isr_func; 1321 NDIS_UNLOCK(sc); 1322 if (adapter == NULL || isrfunc == NULL) 1323 return(ENXIO); 1324 1325 isrfunc(&accepted, &queue, adapter); 1326 *ourintr = accepted; 1327 *callhandler = queue; 1328 1329 return(0); 1330} 1331 1332int 1333ndis_intrhand(arg) 1334 void *arg; 1335{ 1336 struct ndis_softc *sc; 1337 ndis_handle adapter; 1338 __stdcall ndis_interrupt_handler intrfunc; 1339 1340 if (arg == NULL) 1341 return(EINVAL); 1342 1343 sc = arg; 1344 NDIS_LOCK(sc); 1345 adapter = sc->ndis_block.nmb_miniportadapterctx; 1346 intrfunc = sc->ndis_chars.nmc_interrupt_func; 1347 NDIS_UNLOCK(sc); 1348 if (adapter == NULL || intrfunc == NULL) 1349 return(EINVAL); 1350 1351 intrfunc(adapter); 1352 1353 return(0); 1354} 1355 1356int 1357ndis_get_info(arg, oid, buf, buflen) 1358 void *arg; 1359 ndis_oid oid; 1360 void *buf; 1361 int *buflen; 1362{ 1363 struct ndis_softc *sc; 1364 ndis_status rval; 1365 ndis_handle adapter; 1366 __stdcall ndis_queryinfo_handler queryfunc; 1367 uint32_t byteswritten = 0, bytesneeded = 0; 1368 struct timeval tv; 1369 int error; 1370 1371 sc = arg; 1372 NDIS_LOCK(sc); 1373 queryfunc = sc->ndis_chars.nmc_queryinfo_func; 1374 adapter = sc->ndis_block.nmb_miniportadapterctx; 1375 NDIS_UNLOCK(sc); 1376 1377 if (adapter == NULL || queryfunc == NULL) 1378 return(ENXIO); 1379 1380 rval = queryfunc(adapter, oid, buf, *buflen, 1381 &byteswritten, &bytesneeded); 1382 1383 /* Wait for requests that block. */ 1384 1385 if (rval == NDIS_STATUS_PENDING) { 1386 tv.tv_sec = 60; 1387 tv.tv_usec = 0; 1388 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1389 PPAUSE|PCATCH, "ndisget", tvtohz(&tv)); 1390 rval = sc->ndis_block.nmb_getstat; 1391 } 1392 1393 if (byteswritten) 1394 *buflen = byteswritten; 1395 if (bytesneeded) 1396 *buflen = bytesneeded; 1397 1398 if (rval == NDIS_STATUS_INVALID_LENGTH || 1399 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1400 return(ENOSPC); 1401 1402 if (rval == NDIS_STATUS_INVALID_OID) 1403 return(EINVAL); 1404 1405 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1406 rval == NDIS_STATUS_NOT_ACCEPTED) 1407 return(ENOTSUP); 1408 1409 if (rval != NDIS_STATUS_SUCCESS) 1410 return(ENODEV); 1411 1412 return(0); 1413} 1414 1415int 1416ndis_unload_driver(arg) 1417 void *arg; 1418{ 1419 struct ndis_softc *sc; 1420 1421 sc = arg; 1422 1423 free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1424 1425 ndis_flush_sysctls(sc); 1426 1427 ndis_shrink_thrqueue(8); 1428 TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1429 1430 return(0); 1431} 1432 1433#define NDIS_LOADED 0x42534F44 1434 1435int 1436ndis_load_driver(img, arg) 1437 vm_offset_t img; 1438 void *arg; 1439{ 1440 __stdcall driver_entry entry; 1441 image_optional_header opt_hdr; 1442 image_import_descriptor imp_desc; 1443 ndis_unicode_string dummystr; 1444 ndis_miniport_block *block; 1445 ndis_status status; 1446 int idx; 1447 uint32_t *ptr; 1448 struct ndis_softc *sc; 1449 1450 sc = arg; 1451 1452 /* 1453 * Only perform the relocation/linking phase once 1454 * since the binary image may be shared among multiple 1455 * device instances. 1456 */ 1457 1458 ptr = (uint32_t *)(img + 8); 1459 if (*ptr != NDIS_LOADED) { 1460 /* Perform text relocation */ 1461 if (pe_relocate(img)) 1462 return(ENOEXEC); 1463 1464 /* Dynamically link the NDIS.SYS routines -- required. */ 1465 if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1466 return(ENOEXEC); 1467 1468 /* Dynamically link the HAL.dll routines -- also required. */ 1469 if (pe_patch_imports(img, "HAL", hal_functbl)) 1470 return(ENOEXEC); 1471 1472 /* Dynamically link ntoskrnl.exe -- optional. */ 1473 if (pe_get_import_descriptor(img, 1474 &imp_desc, "ntoskrnl") == 0) { 1475 if (pe_patch_imports(img, 1476 "ntoskrnl", ntoskrnl_functbl)) 1477 return(ENOEXEC); 1478 } 1479 *ptr = NDIS_LOADED; 1480 } 1481 1482 /* Locate the driver entry point */ 1483 pe_get_optional_header(img, &opt_hdr); 1484 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1485 1486 dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2; 1487 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2; 1488 dummystr.nus_buf = NULL; 1489 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1490 1491 /* 1492 * Now that we have the miniport driver characteristics, 1493 * create an NDIS block and call the init handler. 1494 * This will cause the driver to try to probe for 1495 * a device. 1496 */ 1497 1498 block = &sc->ndis_block; 1499 1500 ptr = (uint32_t *)block; 1501 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1502 *ptr = idx | 0xdead0000; 1503 ptr++; 1504 } 1505 1506 block->nmb_signature = (void *)0xcafebabe; 1507 block->nmb_setdone_func = ndis_setdone_func; 1508 block->nmb_querydone_func = ndis_getdone_func; 1509 block->nmb_status_func = ndis_status_func; 1510 block->nmb_statusdone_func = ndis_statusdone_func; 1511 block->nmb_resetdone_func = ndis_resetdone_func; 1512 block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; 1513 1514 block->nmb_ifp = &sc->arpcom.ac_if; 1515 block->nmb_dev = sc->ndis_dev; 1516 block->nmb_img = img; 1517 block->nmb_devobj.do_rsvd = block; 1518 1519 /* 1520 * Now call the DriverEntry() routine. This will cause 1521 * a callout to the NdisInitializeWrapper() and 1522 * NdisMRegisterMiniport() routines. 1523 */ 1524 status = entry(&block->nmb_devobj, &dummystr); 1525 1526 free (dummystr.nus_buf, M_DEVBUF); 1527 1528 if (status != NDIS_STATUS_SUCCESS) 1529 return(ENODEV); 1530 1531 ndis_enlarge_thrqueue(8); 1532 1533 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1534 1535 return(0); 1536} 1537