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