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