kern_ndis.c revision 146427
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 146427 2005-05-20 04:00:50Z 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/module.h> 53#include <sys/kthread.h> 54#include <machine/bus.h> 55#include <machine/resource.h> 56#include <sys/bus.h> 57#include <sys/rman.h> 58 59#include <net/if.h> 60#include <net/if_arp.h> 61#include <net/ethernet.h> 62#include <net/if_dl.h> 63#include <net/if_media.h> 64 65#include <net80211/ieee80211_var.h> 66#include <net80211/ieee80211_ioctl.h> 67 68#include <compat/ndis/pe_var.h> 69#include <compat/ndis/cfg_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/usbd_var.h> 75#include <dev/if_ndis/if_ndisvar.h> 76 77#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 78 79static void ndis_status_func(ndis_handle, ndis_status, void *, uint32_t); 80static void ndis_statusdone_func(ndis_handle); 81static void ndis_setdone_func(ndis_handle, ndis_status); 82static void ndis_getdone_func(ndis_handle, ndis_status); 83static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 84static void ndis_sendrsrcavail_func(ndis_handle); 85static void ndis_intrhand(kdpc *, device_object *, 86 irp *, struct ndis_softc *); 87static void ndis_return(kdpc *, void *, void *, void *); 88 89static image_patch_table kernndis_functbl[] = { 90 IMPORT_SFUNC(ndis_status_func, 4), 91 IMPORT_SFUNC(ndis_statusdone_func, 1), 92 IMPORT_SFUNC(ndis_setdone_func, 2), 93 IMPORT_SFUNC(ndis_getdone_func, 2), 94 IMPORT_SFUNC(ndis_resetdone_func, 3), 95 IMPORT_SFUNC(ndis_sendrsrcavail_func, 1), 96 IMPORT_SFUNC(ndis_intrhand, 4), 97 IMPORT_SFUNC(ndis_return, 1), 98 99 { NULL, NULL, NULL } 100}; 101 102struct nd_head ndis_devhead; 103 104static struct mtx ndis_req_mtx; 105 106/* 107 * This allows us to export our symbols to other modules. 108 * Note that we call ourselves 'ndisapi' to avoid a namespace 109 * collision with if_ndis.ko, which internally calls itself 110 * 'ndis.' 111 */ 112 113static int 114ndis_modevent(module_t mod, int cmd, void *arg) 115{ 116 int error = 0; 117 image_patch_table *patch; 118 119 switch (cmd) { 120 case MOD_LOAD: 121 /* Initialize subsystems */ 122 windrv_libinit(); 123 hal_libinit(); 124 ndis_libinit(); 125 ntoskrnl_libinit(); 126 usbd_libinit(); 127 128 patch = kernndis_functbl; 129 while (patch->ipt_func != NULL) { 130 windrv_wrap((funcptr)patch->ipt_func, 131 (funcptr *)&patch->ipt_wrap, 132 patch->ipt_argcnt, patch->ipt_ftype); 133 patch++; 134 } 135 136 TAILQ_INIT(&ndis_devhead); 137 138 mtx_init(&ndis_req_mtx, "NDIS request lock", 139 MTX_NDIS_LOCK, MTX_DEF); 140 141 break; 142 case MOD_SHUTDOWN: 143 if (TAILQ_FIRST(&ndis_devhead) == NULL) { 144 /* Shut down subsystems */ 145 hal_libfini(); 146 ndis_libfini(); 147 ntoskrnl_libfini(); 148 usbd_libfini(); 149 windrv_libfini(); 150 151 patch = kernndis_functbl; 152 while (patch->ipt_func != NULL) { 153 windrv_unwrap(patch->ipt_wrap); 154 patch++; 155 } 156 mtx_destroy(&ndis_req_mtx); 157 } 158 break; 159 case MOD_UNLOAD: 160 /* Shut down subsystems */ 161 hal_libfini(); 162 ndis_libfini(); 163 ntoskrnl_libfini(); 164 usbd_libfini(); 165 windrv_libfini(); 166 167 patch = kernndis_functbl; 168 while (patch->ipt_func != NULL) { 169 windrv_unwrap(patch->ipt_wrap); 170 patch++; 171 } 172 173 mtx_destroy(&ndis_req_mtx); 174 175 break; 176 default: 177 error = EINVAL; 178 break; 179 } 180 181 return(error); 182} 183DEV_MODULE(ndisapi, ndis_modevent, NULL); 184MODULE_VERSION(ndisapi, 1); 185 186int 187ndis_thsuspend(p, m, timo) 188 struct proc *p; 189 struct mtx *m; 190 int timo; 191{ 192 int error; 193 194 if (m != NULL) { 195 error = msleep(&p->p_siglist, m, 196 curthread->td_priority, "ndissp", timo); 197 } else { 198 PROC_LOCK(p); 199 error = msleep(&p->p_siglist, &p->p_mtx, 200 curthread->td_priority|PDROP, "ndissp", timo); 201 } 202 203 return(error); 204} 205 206void 207ndis_thresume(p) 208 struct proc *p; 209{ 210 wakeup(&p->p_siglist); 211 return; 212} 213 214static void 215ndis_sendrsrcavail_func(adapter) 216 ndis_handle adapter; 217{ 218 return; 219} 220 221static void 222ndis_status_func(adapter, status, sbuf, slen) 223 ndis_handle adapter; 224 ndis_status status; 225 void *sbuf; 226 uint32_t slen; 227{ 228 ndis_miniport_block *block; 229 struct ndis_softc *sc; 230 struct ifnet *ifp; 231 232 block = adapter; 233 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 234 ifp = &sc->arpcom.ac_if; 235 if (ifp->if_flags & IFF_DEBUG) 236 device_printf (sc->ndis_dev, "status: %x\n", status); 237 return; 238} 239 240static void 241ndis_statusdone_func(adapter) 242 ndis_handle adapter; 243{ 244 ndis_miniport_block *block; 245 struct ndis_softc *sc; 246 struct ifnet *ifp; 247 248 block = adapter; 249 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 250 ifp = &sc->arpcom.ac_if; 251 if (ifp->if_flags & IFF_DEBUG) 252 device_printf (sc->ndis_dev, "status complete\n"); 253 return; 254} 255 256static void 257ndis_setdone_func(adapter, status) 258 ndis_handle adapter; 259 ndis_status status; 260{ 261 ndis_miniport_block *block; 262 block = adapter; 263 264 block->nmb_setstat = status; 265 wakeup(&block->nmb_setstat); 266 return; 267} 268 269static void 270ndis_getdone_func(adapter, status) 271 ndis_handle adapter; 272 ndis_status status; 273{ 274 ndis_miniport_block *block; 275 block = adapter; 276 277 block->nmb_getstat = status; 278 wakeup(&block->nmb_getstat); 279 return; 280} 281 282static void 283ndis_resetdone_func(adapter, status, addressingreset) 284 ndis_handle adapter; 285 ndis_status status; 286 uint8_t addressingreset; 287{ 288 ndis_miniport_block *block; 289 struct ndis_softc *sc; 290 struct ifnet *ifp; 291 292 block = adapter; 293 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 294 ifp = &sc->arpcom.ac_if; 295 296 if (ifp->if_flags & IFF_DEBUG) 297 device_printf (sc->ndis_dev, "reset done...\n"); 298 wakeup(sc); 299 return; 300} 301 302int 303ndis_create_sysctls(arg) 304 void *arg; 305{ 306 struct ndis_softc *sc; 307 ndis_cfg *vals; 308 char buf[256]; 309 struct sysctl_oid *oidp; 310 struct sysctl_ctx_entry *e; 311 312 if (arg == NULL) 313 return(EINVAL); 314 315 sc = arg; 316 vals = sc->ndis_regvals; 317 318 TAILQ_INIT(&sc->ndis_cfglist_head); 319 320#if __FreeBSD_version < 502113 321 /* Create the sysctl tree. */ 322 323 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 324 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 325 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 326 device_get_desc(sc->ndis_dev)); 327 328#endif 329 /* Add the driver-specific registry keys. */ 330 331 vals = sc->ndis_regvals; 332 while(1) { 333 if (vals->nc_cfgkey == NULL) 334 break; 335 336 if (vals->nc_idx != sc->ndis_devidx) { 337 vals++; 338 continue; 339 } 340 341 /* See if we already have a sysctl with this name */ 342 343 oidp = NULL; 344#if __FreeBSD_version < 502113 345 TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 346#else 347 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 348#endif 349 oidp = e->entry; 350 if (ndis_strcasecmp(oidp->oid_name, 351 vals->nc_cfgkey) == 0) 352 break; 353 oidp = NULL; 354 } 355 356 if (oidp != NULL) { 357 vals++; 358 continue; 359 } 360 361#if __FreeBSD_version < 502113 362 SYSCTL_ADD_STRING(&sc->ndis_ctx, 363 SYSCTL_CHILDREN(sc->ndis_tree), 364#else 365 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 366 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 367#endif 368 OID_AUTO, vals->nc_cfgkey, 369 CTLFLAG_RW, vals->nc_val, 370 sizeof(vals->nc_val), 371 vals->nc_cfgdesc); 372 vals++; 373 } 374 375 /* Now add a couple of builtin keys. */ 376 377 /* 378 * Environment can be either Windows (0) or WindowsNT (1). 379 * We qualify as the latter. 380 */ 381 ndis_add_sysctl(sc, "Environment", 382 "Windows environment", "1", CTLFLAG_RD); 383 384 /* NDIS version should be 5.1. */ 385 ndis_add_sysctl(sc, "NdisVersion", 386 "NDIS API Version", "0x00050001", CTLFLAG_RD); 387 388 /* Bus type (PCI, PCMCIA, etc...) */ 389 sprintf(buf, "%d", (int)sc->ndis_iftype); 390 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 391 392 if (sc->ndis_res_io != NULL) { 393 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 394 ndis_add_sysctl(sc, "IOBaseAddress", 395 "Base I/O Address", buf, CTLFLAG_RD); 396 } 397 398 if (sc->ndis_irq != NULL) { 399 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 400 ndis_add_sysctl(sc, "InterruptNumber", 401 "Interrupt Number", buf, CTLFLAG_RD); 402 } 403 404 return(0); 405} 406 407int 408ndis_add_sysctl(arg, key, desc, val, flag) 409 void *arg; 410 char *key; 411 char *desc; 412 char *val; 413 int flag; 414{ 415 struct ndis_softc *sc; 416 struct ndis_cfglist *cfg; 417 char descstr[256]; 418 419 sc = arg; 420 421 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 422 423 if (cfg == NULL) 424 return(ENOMEM); 425 426 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 427 if (desc == NULL) { 428 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 429 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 430 } else 431 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 432 strcpy(cfg->ndis_cfg.nc_val, val); 433 434 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 435 436#if __FreeBSD_version < 502113 437 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 438#else 439 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 440 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 441#endif 442 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 443 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 444 cfg->ndis_cfg.nc_cfgdesc); 445 446 return(0); 447} 448 449int 450ndis_flush_sysctls(arg) 451 void *arg; 452{ 453 struct ndis_softc *sc; 454 struct ndis_cfglist *cfg; 455 456 sc = arg; 457 458 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 459 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 460 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 461 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 462 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 463 free(cfg, M_DEVBUF); 464 } 465 466 return(0); 467} 468 469static void 470ndis_return(dpc, arg, sysarg1, sysarg2) 471 kdpc *dpc; 472 void *arg; 473 void *sysarg1; 474 void *sysarg2; 475{ 476 struct ndis_softc *sc; 477 ndis_return_handler returnfunc; 478 ndis_handle adapter; 479 ndis_packet *p; 480 uint8_t irql; 481 482 p = arg; 483 sc = p->np_softc; 484 adapter = sc->ndis_block->nmb_miniportadapterctx; 485 486 if (adapter == NULL) 487 return; 488 489 returnfunc = sc->ndis_chars->nmc_return_packet_func; 490 491 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 492 MSCALL2(returnfunc, adapter, p); 493 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 494 495 return; 496} 497 498void 499ndis_return_packet(buf, arg) 500 void *buf; /* not used */ 501 void *arg; 502{ 503 ndis_packet *p; 504 505 if (arg == NULL) 506 return; 507 508 p = arg; 509 510 /* Decrement refcount. */ 511 p->np_refcnt--; 512 513 /* Release packet when refcount hits zero, otherwise return. */ 514 if (p->np_refcnt) 515 return; 516 517 KeInitializeDpc(&p->np_dpc, kernndis_functbl[7].ipt_wrap, p); 518 KeInsertQueueDpc(&p->np_dpc, NULL, NULL); 519 520 return; 521} 522 523void 524ndis_free_bufs(b0) 525 ndis_buffer *b0; 526{ 527 ndis_buffer *next; 528 529 if (b0 == NULL) 530 return; 531 532 while(b0 != NULL) { 533 next = b0->mdl_next; 534 IoFreeMdl(b0); 535 b0 = next; 536 } 537 538 return; 539} 540int in_reset = 0; 541void 542ndis_free_packet(p) 543 ndis_packet *p; 544{ 545 if (p == NULL) 546 return; 547 548 ndis_free_bufs(p->np_private.npp_head); 549 NdisFreePacket(p); 550 return; 551} 552 553int 554ndis_convert_res(arg) 555 void *arg; 556{ 557 struct ndis_softc *sc; 558 ndis_resource_list *rl = NULL; 559 cm_partial_resource_desc *prd = NULL; 560 ndis_miniport_block *block; 561 device_t dev; 562 struct resource_list *brl; 563 struct resource_list_entry *brle; 564#if __FreeBSD_version < 600022 565 struct resource_list brl_rev; 566 struct resource_list_entry *n; 567#endif 568 int error = 0; 569 570 sc = arg; 571 block = sc->ndis_block; 572 dev = sc->ndis_dev; 573 574#if __FreeBSD_version < 600022 575 SLIST_INIT(&brl_rev); 576#endif 577 578 rl = malloc(sizeof(ndis_resource_list) + 579 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 580 M_DEVBUF, M_NOWAIT|M_ZERO); 581 582 if (rl == NULL) 583 return(ENOMEM); 584 585 rl->cprl_version = 5; 586 rl->cprl_version = 1; 587 rl->cprl_count = sc->ndis_rescnt; 588 prd = rl->cprl_partial_descs; 589 590 brl = BUS_GET_RESOURCE_LIST(dev, dev); 591 592 if (brl != NULL) { 593 594#if __FreeBSD_version < 600022 595 /* 596 * We have a small problem. Some PCI devices have 597 * multiple I/O ranges. Windows orders them starting 598 * from lowest numbered BAR to highest. We discover 599 * them in that order too, but insert them into a singly 600 * linked list head first, which means when time comes 601 * to traverse the list, we enumerate them in reverse 602 * order. This screws up some drivers which expect the 603 * BARs to be in ascending order so that they can choose 604 * the "first" one as their register space. Unfortunately, 605 * in order to fix this, we have to create our own 606 * temporary list with the entries in reverse order. 607 */ 608 609 SLIST_FOREACH(brle, brl, link) { 610 n = malloc(sizeof(struct resource_list_entry), 611 M_TEMP, M_NOWAIT); 612 if (n == NULL) { 613 error = ENOMEM; 614 goto bad; 615 } 616 bcopy((char *)brle, (char *)n, 617 sizeof(struct resource_list_entry)); 618 SLIST_INSERT_HEAD(&brl_rev, n, link); 619 } 620 621 SLIST_FOREACH(brle, &brl_rev, link) { 622#else 623 STAILQ_FOREACH(brle, brl, link) { 624#endif 625 switch (brle->type) { 626 case SYS_RES_IOPORT: 627 prd->cprd_type = CmResourceTypePort; 628 prd->cprd_flags = CM_RESOURCE_PORT_IO; 629 prd->cprd_sharedisp = 630 CmResourceShareDeviceExclusive; 631 prd->u.cprd_port.cprd_start.np_quad = 632 brle->start; 633 prd->u.cprd_port.cprd_len = brle->count; 634 break; 635 case SYS_RES_MEMORY: 636 prd->cprd_type = CmResourceTypeMemory; 637 prd->cprd_flags = 638 CM_RESOURCE_MEMORY_READ_WRITE; 639 prd->cprd_sharedisp = 640 CmResourceShareDeviceExclusive; 641 prd->u.cprd_port.cprd_start.np_quad = 642 brle->start; 643 prd->u.cprd_port.cprd_len = brle->count; 644 break; 645 case SYS_RES_IRQ: 646 prd->cprd_type = CmResourceTypeInterrupt; 647 prd->cprd_flags = 0; 648 prd->cprd_sharedisp = 649 CmResourceShareDeviceExclusive; 650 prd->u.cprd_intr.cprd_level = brle->start; 651 prd->u.cprd_intr.cprd_vector = brle->start; 652 prd->u.cprd_intr.cprd_affinity = 0; 653 break; 654 default: 655 break; 656 } 657 prd++; 658 } 659 } 660 661 block->nmb_rlist = rl; 662 663#if __FreeBSD_version < 600022 664bad: 665 666 while (!SLIST_EMPTY(&brl_rev)) { 667 n = SLIST_FIRST(&brl_rev); 668 SLIST_REMOVE_HEAD(&brl_rev, link); 669 free (n, M_TEMP); 670 } 671#endif 672 673 return(error); 674} 675 676/* 677 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 678 * packet, it will hand it to us in the form of an ndis_packet, 679 * which we need to convert to an mbuf that is then handed off 680 * to the stack. Note: we configure the mbuf list so that it uses 681 * the memory regions specified by the ndis_buffer structures in 682 * the ndis_packet as external storage. In most cases, this will 683 * point to a memory region allocated by the driver (either by 684 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 685 * the driver to handle free()ing this region for is, so we set up 686 * a dummy no-op free handler for it. 687 */ 688 689int 690ndis_ptom(m0, p) 691 struct mbuf **m0; 692 ndis_packet *p; 693{ 694 struct mbuf *m, *prev = NULL; 695 ndis_buffer *buf; 696 ndis_packet_private *priv; 697 uint32_t totlen = 0; 698 699 if (p == NULL || m0 == NULL) 700 return(EINVAL); 701 702 priv = &p->np_private; 703 buf = priv->npp_head; 704 p->np_refcnt = 0; 705 706 for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { 707 if (buf == priv->npp_head) 708 MGETHDR(m, M_DONTWAIT, MT_HEADER); 709 else 710 MGET(m, M_DONTWAIT, MT_DATA); 711 if (m == NULL) { 712 m_freem(*m0); 713 *m0 = NULL; 714 return(ENOBUFS); 715 } 716 m->m_len = MmGetMdlByteCount(buf); 717 m->m_data = MmGetMdlVirtualAddress(buf); 718 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 719 p, 0, EXT_NDIS); 720 p->np_refcnt++; 721 totlen += m->m_len; 722 if (m->m_flags & MT_HEADER) 723 *m0 = m; 724 else 725 prev->m_next = m; 726 prev = m; 727 } 728 729 (*m0)->m_pkthdr.len = totlen; 730 731 return(0); 732} 733 734/* 735 * Create an NDIS packet from an mbuf chain. 736 * This is used mainly when transmitting packets, where we need 737 * to turn an mbuf off an interface's send queue and transform it 738 * into an NDIS packet which will be fed into the NDIS driver's 739 * send routine. 740 * 741 * NDIS packets consist of two parts: an ndis_packet structure, 742 * which is vaguely analagous to the pkthdr portion of an mbuf, 743 * and one or more ndis_buffer structures, which define the 744 * actual memory segments in which the packet data resides. 745 * We need to allocate one ndis_buffer for each mbuf in a chain, 746 * plus one ndis_packet as the header. 747 */ 748 749int 750ndis_mtop(m0, p) 751 struct mbuf *m0; 752 ndis_packet **p; 753{ 754 struct mbuf *m; 755 ndis_buffer *buf = NULL, *prev = NULL; 756 ndis_packet_private *priv; 757 758 if (p == NULL || *p == NULL || m0 == NULL) 759 return(EINVAL); 760 761 priv = &(*p)->np_private; 762 priv->npp_totlen = m0->m_pkthdr.len; 763 764 for (m = m0; m != NULL; m = m->m_next) { 765 if (m->m_len == 0) 766 continue; 767 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); 768 if (buf == NULL) { 769 ndis_free_packet(*p); 770 *p = NULL; 771 return(ENOMEM); 772 } 773 774 if (priv->npp_head == NULL) 775 priv->npp_head = buf; 776 else 777 prev->mdl_next = buf; 778 prev = buf; 779 } 780 781 priv->npp_tail = buf; 782 783 return(0); 784} 785 786int 787ndis_get_supported_oids(arg, oids, oidcnt) 788 void *arg; 789 ndis_oid **oids; 790 int *oidcnt; 791{ 792 int len, rval; 793 ndis_oid *o; 794 795 if (arg == NULL || oids == NULL || oidcnt == NULL) 796 return(EINVAL); 797 len = 0; 798 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 799 800 o = malloc(len, M_DEVBUF, M_NOWAIT); 801 if (o == NULL) 802 return(ENOMEM); 803 804 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 805 806 if (rval) { 807 free(o, M_DEVBUF); 808 return(rval); 809 } 810 811 *oids = o; 812 *oidcnt = len / 4; 813 814 return(0); 815} 816 817int 818ndis_set_info(arg, oid, buf, buflen) 819 void *arg; 820 ndis_oid oid; 821 void *buf; 822 int *buflen; 823{ 824 struct ndis_softc *sc; 825 ndis_status rval; 826 ndis_handle adapter; 827 ndis_setinfo_handler setfunc; 828 uint32_t byteswritten = 0, bytesneeded = 0; 829 int error; 830 uint8_t irql; 831 832 /* 833 * According to the NDIS spec, MiniportQueryInformation() 834 * and MiniportSetInformation() requests are handled serially: 835 * once one request has been issued, we must wait for it to 836 * finish before allowing another request to proceed. 837 */ 838 839 sc = arg; 840 841 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 842 843 if (sc->ndis_block->nmb_pendingreq != NULL) 844 panic("ndis_set_info() called while other request pending"); 845 else 846 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 847 848 NDIS_LOCK(sc); 849 setfunc = sc->ndis_chars->nmc_setinfo_func; 850 adapter = sc->ndis_block->nmb_miniportadapterctx; 851 852 if (adapter == NULL || setfunc == NULL || 853 sc->ndis_block->nmb_devicectx == NULL) { 854 sc->ndis_block->nmb_pendingreq = NULL; 855 NDIS_UNLOCK(sc); 856 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 857 return(ENXIO); 858 } 859 860 NDIS_UNLOCK(sc); 861 862 rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, 863 &byteswritten, &bytesneeded); 864 865 sc->ndis_block->nmb_pendingreq = NULL; 866 867 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 868 869 if (rval == NDIS_STATUS_PENDING) { 870 mtx_lock(&ndis_req_mtx); 871 error = msleep(&sc->ndis_block->nmb_setstat, 872 &ndis_req_mtx, 873 curthread->td_priority|PDROP, 874 "ndisset", 5 * hz); 875 rval = sc->ndis_block->nmb_setstat; 876 } 877 878 879 if (byteswritten) 880 *buflen = byteswritten; 881 if (bytesneeded) 882 *buflen = bytesneeded; 883 884 if (rval == NDIS_STATUS_INVALID_LENGTH) 885 return(ENOSPC); 886 887 if (rval == NDIS_STATUS_INVALID_OID) 888 return(EINVAL); 889 890 if (rval == NDIS_STATUS_NOT_SUPPORTED || 891 rval == NDIS_STATUS_NOT_ACCEPTED) 892 return(ENOTSUP); 893 894 if (rval != NDIS_STATUS_SUCCESS) 895 return(ENODEV); 896 897 return(0); 898} 899 900typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 901 902int 903ndis_send_packets(arg, packets, cnt) 904 void *arg; 905 ndis_packet **packets; 906 int cnt; 907{ 908 struct ndis_softc *sc; 909 ndis_handle adapter; 910 ndis_sendmulti_handler sendfunc; 911 ndis_senddone_func senddonefunc; 912 int i; 913 ndis_packet *p; 914 uint8_t irql; 915 916 sc = arg; 917 adapter = sc->ndis_block->nmb_miniportadapterctx; 918 if (adapter == NULL) 919 return(ENXIO); 920 sendfunc = sc->ndis_chars->nmc_sendmulti_func; 921 senddonefunc = sc->ndis_block->nmb_senddone_func; 922 923 if (NDIS_SERIALIZED(sc->ndis_block)) 924 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 925 926 MSCALL3(sendfunc, adapter, packets, cnt); 927 928 for (i = 0; i < cnt; i++) { 929 p = packets[i]; 930 /* 931 * Either the driver already handed the packet to 932 * ndis_txeof() due to a failure, or it wants to keep 933 * it and release it asynchronously later. Skip to the 934 * next one. 935 */ 936 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 937 continue; 938 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); 939 } 940 941 if (NDIS_SERIALIZED(sc->ndis_block)) 942 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 943 944 return(0); 945} 946 947int 948ndis_send_packet(arg, packet) 949 void *arg; 950 ndis_packet *packet; 951{ 952 struct ndis_softc *sc; 953 ndis_handle adapter; 954 ndis_status status; 955 ndis_sendsingle_handler sendfunc; 956 ndis_senddone_func senddonefunc; 957 uint8_t irql; 958 959 sc = arg; 960 adapter = sc->ndis_block->nmb_miniportadapterctx; 961 if (adapter == NULL) 962 return(ENXIO); 963 sendfunc = sc->ndis_chars->nmc_sendsingle_func; 964 senddonefunc = sc->ndis_block->nmb_senddone_func; 965 966 if (NDIS_SERIALIZED(sc->ndis_block)) 967 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 968 status = MSCALL3(sendfunc, adapter, packet, 969 packet->np_private.npp_flags); 970 971 if (status == NDIS_STATUS_PENDING) { 972 if (NDIS_SERIALIZED(sc->ndis_block)) 973 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 974 return(0); 975 } 976 977 MSCALL3(senddonefunc, sc->ndis_block, packet, status); 978 979 if (NDIS_SERIALIZED(sc->ndis_block)) 980 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 981 982 return(0); 983} 984 985int 986ndis_init_dma(arg) 987 void *arg; 988{ 989 struct ndis_softc *sc; 990 int i, error; 991 992 sc = arg; 993 994 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 995 M_DEVBUF, M_NOWAIT|M_ZERO); 996 997 if (sc->ndis_tmaps == NULL) 998 return(ENOMEM); 999 1000 for (i = 0; i < sc->ndis_maxpkts; i++) { 1001 error = bus_dmamap_create(sc->ndis_ttag, 0, 1002 &sc->ndis_tmaps[i]); 1003 if (error) { 1004 free(sc->ndis_tmaps, M_DEVBUF); 1005 return(ENODEV); 1006 } 1007 } 1008 1009 return(0); 1010} 1011 1012int 1013ndis_destroy_dma(arg) 1014 void *arg; 1015{ 1016 struct ndis_softc *sc; 1017 struct mbuf *m; 1018 ndis_packet *p = NULL; 1019 int i; 1020 1021 sc = arg; 1022 1023 for (i = 0; i < sc->ndis_maxpkts; i++) { 1024 if (sc->ndis_txarray[i] != NULL) { 1025 p = sc->ndis_txarray[i]; 1026 m = (struct mbuf *)p->np_rsvd[1]; 1027 if (m != NULL) 1028 m_freem(m); 1029 ndis_free_packet(sc->ndis_txarray[i]); 1030 } 1031 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1032 } 1033 1034 free(sc->ndis_tmaps, M_DEVBUF); 1035 1036 bus_dma_tag_destroy(sc->ndis_ttag); 1037 1038 return(0); 1039} 1040 1041int 1042ndis_reset_nic(arg) 1043 void *arg; 1044{ 1045 struct ndis_softc *sc; 1046 ndis_handle adapter; 1047 ndis_reset_handler resetfunc; 1048 uint8_t addressing_reset; 1049 int rval; 1050 uint8_t irql; 1051 1052 sc = arg; 1053 1054 NDIS_LOCK(sc); 1055 adapter = sc->ndis_block->nmb_miniportadapterctx; 1056 resetfunc = sc->ndis_chars->nmc_reset_func; 1057 1058 if (adapter == NULL || resetfunc == NULL || 1059 sc->ndis_block->nmb_devicectx == NULL) { 1060 NDIS_UNLOCK(sc); 1061 return(EIO); 1062 } 1063 1064 NDIS_UNLOCK(sc); 1065 1066 if (NDIS_SERIALIZED(sc->ndis_block)) 1067 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1068 1069 rval = MSCALL2(resetfunc, &addressing_reset, adapter); 1070 1071 if (NDIS_SERIALIZED(sc->ndis_block)) 1072 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1073 1074 if (rval == NDIS_STATUS_PENDING) { 1075 mtx_lock(&ndis_req_mtx); 1076 msleep(sc, &ndis_req_mtx, 1077 curthread->td_priority|PDROP, "ndisrst", 0); 1078 } 1079 1080 return(0); 1081} 1082 1083#define NDIS_REAP_TIMERS 1084 1085int 1086ndis_halt_nic(arg) 1087 void *arg; 1088{ 1089 struct ndis_softc *sc; 1090 ndis_handle adapter; 1091 ndis_halt_handler haltfunc; 1092#ifdef NDIS_REAP_TIMERS 1093 ndis_miniport_timer *t, *n; 1094#endif 1095 1096 sc = arg; 1097 1098#ifdef NDIS_REAP_TIMERS 1099 /* 1100 * Drivers are sometimes very lax about cancelling all 1101 * their timers. Cancel them all ourselves, just to be 1102 * safe. We must do this before invoking MiniportHalt(), 1103 * since if we wait until after, the memory in which 1104 * the timers reside will no longer be valid. 1105 */ 1106 1107 t = sc->ndis_block->nmb_timerlist; 1108 while (t != NULL) { 1109 KeCancelTimer(&t->nmt_ktimer); 1110 n = t; 1111 t = t->nmt_nexttimer; 1112 n->nmt_nexttimer = NULL; 1113 } 1114 sc->ndis_block->nmb_timerlist = NULL; 1115 if (!cold) 1116 KeFlushQueuedDpcs(); 1117#endif 1118 1119 NDIS_LOCK(sc); 1120 adapter = sc->ndis_block->nmb_miniportadapterctx; 1121 if (adapter == NULL) { 1122 NDIS_UNLOCK(sc); 1123 return(EIO); 1124 } 1125 1126 sc->ndis_block->nmb_miniportadapterctx = NULL; 1127 sc->ndis_block->nmb_devicectx = NULL; 1128 1129 /* 1130 * The adapter context is only valid after the init 1131 * handler has been called, and is invalid once the 1132 * halt handler has been called. 1133 */ 1134 1135 haltfunc = sc->ndis_chars->nmc_halt_func; 1136 NDIS_UNLOCK(sc); 1137 1138 MSCALL1(haltfunc, adapter); 1139 1140 return(0); 1141} 1142 1143int 1144ndis_shutdown_nic(arg) 1145 void *arg; 1146{ 1147 struct ndis_softc *sc; 1148 ndis_handle adapter; 1149 ndis_shutdown_handler shutdownfunc; 1150 1151 sc = arg; 1152 NDIS_LOCK(sc); 1153 adapter = sc->ndis_block->nmb_miniportadapterctx; 1154 shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; 1155 NDIS_UNLOCK(sc); 1156 if (adapter == NULL || shutdownfunc == NULL) 1157 return(EIO); 1158 1159 if (sc->ndis_chars->nmc_rsvd0 == NULL) 1160 MSCALL1(shutdownfunc, adapter); 1161 else 1162 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0); 1163 1164 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1165 1166 return(0); 1167} 1168 1169int 1170ndis_init_nic(arg) 1171 void *arg; 1172{ 1173 struct ndis_softc *sc; 1174 ndis_miniport_block *block; 1175 ndis_init_handler initfunc; 1176 ndis_status status, openstatus = 0; 1177 ndis_medium mediumarray[NdisMediumMax]; 1178 uint32_t chosenmedium, i; 1179 1180 if (arg == NULL) 1181 return(EINVAL); 1182 1183 sc = arg; 1184 NDIS_LOCK(sc); 1185 block = sc->ndis_block; 1186 initfunc = sc->ndis_chars->nmc_init_func; 1187 NDIS_UNLOCK(sc); 1188 1189 sc->ndis_block->nmb_timerlist = NULL; 1190 1191 for (i = 0; i < NdisMediumMax; i++) 1192 mediumarray[i] = i; 1193 1194 status = MSCALL6(initfunc, &openstatus, &chosenmedium, 1195 mediumarray, NdisMediumMax, block, block); 1196 1197 /* 1198 * If the init fails, blow away the other exported routines 1199 * we obtained from the driver so we can't call them later. 1200 * If the init failed, none of these will work. 1201 */ 1202 if (status != NDIS_STATUS_SUCCESS) { 1203 NDIS_LOCK(sc); 1204 sc->ndis_block->nmb_miniportadapterctx = NULL; 1205 NDIS_UNLOCK(sc); 1206 return(ENXIO); 1207 } 1208 1209 /* 1210 * This may look really goofy, but apparently it is possible 1211 * to halt a miniport too soon after it's been initialized. 1212 * After MiniportInitialize() finishes, pause for 1 second 1213 * to give the chip a chance to handle any short-lived timers 1214 * that were set in motion. If we call MiniportHalt() too soon, 1215 * some of the timers may not be cancelled, because the driver 1216 * expects them to fire before the halt is called. 1217 */ 1218 1219 ndis_thsuspend(curthread->td_proc, NULL, hz); 1220 1221 NDIS_LOCK(sc); 1222 sc->ndis_block->nmb_devicectx = sc; 1223 NDIS_UNLOCK(sc); 1224 1225 return(0); 1226} 1227 1228void 1229ndis_enable_intr(arg) 1230 void *arg; 1231{ 1232 struct ndis_softc *sc; 1233 ndis_handle adapter; 1234 ndis_enable_interrupts_handler intrenbfunc; 1235 1236 sc = arg; 1237 adapter = sc->ndis_block->nmb_miniportadapterctx; 1238 intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func; 1239 if (adapter == NULL || intrenbfunc == NULL) 1240 return; 1241 MSCALL1(intrenbfunc, adapter); 1242 1243 return; 1244} 1245 1246void 1247ndis_disable_intr(arg) 1248 void *arg; 1249{ 1250 struct ndis_softc *sc; 1251 ndis_handle adapter; 1252 ndis_disable_interrupts_handler intrdisfunc; 1253 1254 sc = arg; 1255 adapter = sc->ndis_block->nmb_miniportadapterctx; 1256 intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func; 1257 if (adapter == NULL || intrdisfunc == NULL) 1258 return; 1259 1260 MSCALL1(intrdisfunc, adapter); 1261 1262 return; 1263} 1264 1265int 1266ndis_isr(arg, ourintr, callhandler) 1267 void *arg; 1268 int *ourintr; 1269 int *callhandler; 1270{ 1271 struct ndis_softc *sc; 1272 ndis_handle adapter; 1273 ndis_isr_handler isrfunc; 1274 uint8_t accepted, queue; 1275 1276 if (arg == NULL || ourintr == NULL || callhandler == NULL) 1277 return(EINVAL); 1278 1279 sc = arg; 1280 adapter = sc->ndis_block->nmb_miniportadapterctx; 1281 isrfunc = sc->ndis_chars->nmc_isr_func; 1282 1283 if (adapter == NULL || isrfunc == NULL) 1284 return(ENXIO); 1285 1286 MSCALL3(isrfunc, &accepted, &queue, adapter); 1287 1288 *ourintr = accepted; 1289 *callhandler = queue; 1290 1291 return(0); 1292} 1293 1294static void 1295ndis_intrhand(dpc, dobj, ip, sc) 1296 kdpc *dpc; 1297 device_object *dobj; 1298 irp *ip; 1299 struct ndis_softc *sc; 1300{ 1301 ndis_handle adapter; 1302 ndis_interrupt_handler intrfunc; 1303 uint8_t irql; 1304 1305 adapter = sc->ndis_block->nmb_miniportadapterctx; 1306 intrfunc = sc->ndis_chars->nmc_interrupt_func; 1307 1308 if (adapter == NULL || intrfunc == NULL) 1309 return; 1310 1311 if (NDIS_SERIALIZED(sc->ndis_block)) 1312 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1313 1314 MSCALL1(intrfunc, adapter); 1315 1316 /* If there's a MiniportEnableInterrupt() routine, call it. */ 1317 1318 ndis_enable_intr(sc); 1319 1320 if (NDIS_SERIALIZED(sc->ndis_block)) 1321 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1322 1323 return; 1324} 1325 1326int 1327ndis_get_info(arg, oid, buf, buflen) 1328 void *arg; 1329 ndis_oid oid; 1330 void *buf; 1331 int *buflen; 1332{ 1333 struct ndis_softc *sc; 1334 ndis_status rval; 1335 ndis_handle adapter; 1336 ndis_queryinfo_handler queryfunc; 1337 uint32_t byteswritten = 0, bytesneeded = 0; 1338 int error; 1339 uint8_t irql; 1340 1341 sc = arg; 1342 1343 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1344 1345 if (sc->ndis_block->nmb_pendingreq != NULL) 1346 panic("ndis_get_info() called while other request pending"); 1347 else 1348 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 1349 1350 NDIS_LOCK(sc); 1351 queryfunc = sc->ndis_chars->nmc_queryinfo_func; 1352 adapter = sc->ndis_block->nmb_miniportadapterctx; 1353 1354 if (adapter == NULL || queryfunc == NULL || 1355 sc->ndis_block->nmb_devicectx == NULL) { 1356 sc->ndis_block->nmb_pendingreq = NULL; 1357 NDIS_UNLOCK(sc); 1358 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1359 return(ENXIO); 1360 } 1361 1362 NDIS_UNLOCK(sc); 1363 1364 rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, 1365 &byteswritten, &bytesneeded); 1366 1367 sc->ndis_block->nmb_pendingreq = NULL; 1368 1369 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1370 1371 /* Wait for requests that block. */ 1372 1373 if (rval == NDIS_STATUS_PENDING) { 1374 mtx_lock(&ndis_req_mtx); 1375 error = msleep(&sc->ndis_block->nmb_getstat, 1376 &ndis_req_mtx, 1377 curthread->td_priority|PDROP, 1378 "ndisget", 5 * hz); 1379 rval = sc->ndis_block->nmb_getstat; 1380 } 1381 1382 if (byteswritten) 1383 *buflen = byteswritten; 1384 if (bytesneeded) 1385 *buflen = bytesneeded; 1386 1387 if (rval == NDIS_STATUS_INVALID_LENGTH || 1388 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1389 return(ENOSPC); 1390 1391 if (rval == NDIS_STATUS_INVALID_OID) 1392 return(EINVAL); 1393 1394 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1395 rval == NDIS_STATUS_NOT_ACCEPTED) 1396 return(ENOTSUP); 1397 1398 if (rval != NDIS_STATUS_SUCCESS) 1399 return(ENODEV); 1400 1401 return(0); 1402} 1403 1404uint32_t 1405NdisAddDevice(drv, pdo) 1406 driver_object *drv; 1407 device_object *pdo; 1408{ 1409 device_object *fdo; 1410 ndis_miniport_block *block; 1411 struct ndis_softc *sc; 1412 uint32_t status; 1413 1414 status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, 1415 FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); 1416 1417 if (status != STATUS_SUCCESS) 1418 return(status); 1419 1420 block = fdo->do_devext; 1421 1422 block->nmb_filterdbs.nf_ethdb = block; 1423 block->nmb_deviceobj = fdo; 1424 block->nmb_physdeviceobj = pdo; 1425 block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); 1426 KeInitializeSpinLock(&block->nmb_lock); 1427 1428 /* 1429 * Stash pointers to the miniport block and miniport 1430 * characteristics info in the if_ndis softc so the 1431 * UNIX wrapper driver can get to them later. 1432 */ 1433 sc = device_get_softc(pdo->do_devext); 1434 sc->ndis_block = block; 1435 sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); 1436 1437 /* 1438 * If the driver has a MiniportTransferData() function, 1439 * we should allocate a private RX packet pool. 1440 */ 1441 1442 if (sc->ndis_chars->nmc_transferdata_func != NULL) { 1443 NdisAllocatePacketPool(&status, &block->nmb_rxpool, 1444 32, PROTOCOL_RESERVED_SIZE_IN_PACKET); 1445 if (status != NDIS_STATUS_SUCCESS) { 1446 IoDetachDevice(block->nmb_nextdeviceobj); 1447 IoDeleteDevice(fdo); 1448 return(status); 1449 } 1450 INIT_LIST_HEAD((&block->nmb_packetlist)); 1451 } 1452 1453 /* Give interrupt handling priority over timers. */ 1454 IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap); 1455 KeSetImportanceDpc(&fdo->do_dpc, KDPC_IMPORTANCE_HIGH); 1456 1457 /* Finish up BSD-specific setup. */ 1458 1459 block->nmb_signature = (void *)0xcafebabe; 1460 block->nmb_status_func = kernndis_functbl[0].ipt_wrap; 1461 block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; 1462 block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; 1463 block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; 1464 block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; 1465 block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; 1466 block->nmb_pendingreq = NULL; 1467 1468 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1469 1470 return (STATUS_SUCCESS); 1471} 1472 1473int 1474ndis_unload_driver(arg) 1475 void *arg; 1476{ 1477 struct ndis_softc *sc; 1478 device_object *fdo; 1479 1480 sc = arg; 1481 1482 if (sc->ndis_block->nmb_rlist != NULL) 1483 free(sc->ndis_block->nmb_rlist, M_DEVBUF); 1484 1485 ndis_flush_sysctls(sc); 1486 1487 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1488 1489 if (sc->ndis_chars->nmc_transferdata_func != NULL) 1490 NdisFreePacketPool(sc->ndis_block->nmb_rxpool); 1491 fdo = sc->ndis_block->nmb_deviceobj; 1492 IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); 1493 IoDeleteDevice(fdo); 1494 1495 return(0); 1496} 1497