kern_ndis.c revision 168421
1343173Sdim/*- 2343173Sdim * Copyright (c) 2003 3353358Sdim * Bill Paul <wpaul@windriver.com>. All rights reserved. 4353358Sdim * 5353358Sdim * Redistribution and use in source and binary forms, with or without 6343173Sdim * modification, are permitted provided that the following conditions 7343173Sdim * are met: 8343173Sdim * 1. Redistributions of source code must retain the above copyright 9343173Sdim * notice, this list of conditions and the following disclaimer. 10343173Sdim * 2. Redistributions in binary form must reproduce the above copyright 11343173Sdim * notice, this list of conditions and the following disclaimer in the 12343173Sdim * documentation and/or other materials provided with the distribution. 13343173Sdim * 3. All advertising materials mentioning features or use of this software 14343173Sdim * must display the following acknowledgement: 15343173Sdim * This product includes software developed by Bill Paul. 16343173Sdim * 4. Neither the name of the author nor the names of any co-contributors 17343173Sdim * may be used to endorse or promote products derived from this software 18353358Sdim * without specific prior written permission. 19353358Sdim * 20343173Sdim * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21343173Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22343173Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23343173Sdim * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24353358Sdim * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25353358Sdim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26343173Sdim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27343173Sdim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28343173Sdim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29343173Sdim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30343173Sdim * THE POSSIBILITY OF SUCH DAMAGE. 31343173Sdim */ 32343173Sdim 33343173Sdim#include <sys/cdefs.h> 34353358Sdim__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 168421 2007-04-06 11:18:57Z pjd $"); 35353358Sdim 36353358Sdim#include <sys/param.h> 37353358Sdim#include <sys/systm.h> 38343173Sdim#include <sys/unistd.h> 39353358Sdim#include <sys/types.h> 40353358Sdim#include <sys/errno.h> 41353358Sdim#include <sys/callout.h> 42353358Sdim#include <sys/socket.h> 43343173Sdim#include <sys/queue.h> 44353358Sdim#include <sys/sysctl.h> 45353358Sdim#include <sys/proc.h> 46353358Sdim#include <sys/malloc.h> 47343173Sdim#include <sys/lock.h> 48353358Sdim#include <sys/mutex.h> 49353358Sdim#include <sys/conf.h> 50353358Sdim 51353358Sdim#include <sys/kernel.h> 52353358Sdim#include <sys/module.h> 53343173Sdim#include <sys/kthread.h> 54353358Sdim#include <machine/bus.h> 55353358Sdim#include <machine/resource.h> 56343173Sdim#include <sys/bus.h> 57343173Sdim#include <sys/rman.h> 58343173Sdim 59343173Sdim#include <net/if.h> 60343173Sdim#include <net/if_arp.h> 61343173Sdim#include <net/ethernet.h> 62343173Sdim#include <net/if_dl.h> 63343173Sdim#include <net/if_media.h> 64343173Sdim 65343173Sdim#include <net80211/ieee80211_var.h> 66343173Sdim#include <net80211/ieee80211_ioctl.h> 67343173Sdim 68343173Sdim#include <compat/ndis/pe_var.h> 69343173Sdim#include <compat/ndis/cfg_var.h> 70343173Sdim#include <compat/ndis/resource_var.h> 71343173Sdim#include <compat/ndis/ntoskrnl_var.h> 72343173Sdim#include <compat/ndis/ndis_var.h> 73343173Sdim#include <compat/ndis/hal_var.h> 74343173Sdim#include <compat/ndis/usbd_var.h> 75343173Sdim#include <dev/if_ndis/if_ndisvar.h> 76343173Sdim 77343173Sdim#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 78343173Sdim 79343173Sdimstatic void ndis_status_func(ndis_handle, ndis_status, void *, uint32_t); 80343173Sdimstatic void ndis_statusdone_func(ndis_handle); 81343173Sdimstatic void ndis_setdone_func(ndis_handle, ndis_status); 82343173Sdimstatic void ndis_getdone_func(ndis_handle, ndis_status); 83343173Sdimstatic void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 84343173Sdimstatic void ndis_sendrsrcavail_func(ndis_handle); 85343173Sdimstatic void ndis_intrsetup(kdpc *, device_object *, 86343173Sdim irp *, struct ndis_softc *); 87343173Sdimstatic void ndis_return(device_object *, void *); 88343173Sdim 89343173Sdimstatic image_patch_table kernndis_functbl[] = { 90343173Sdim IMPORT_SFUNC(ndis_status_func, 4), 91343173Sdim IMPORT_SFUNC(ndis_statusdone_func, 1), 92343173Sdim IMPORT_SFUNC(ndis_setdone_func, 2), 93343173Sdim IMPORT_SFUNC(ndis_getdone_func, 2), 94343173Sdim IMPORT_SFUNC(ndis_resetdone_func, 3), 95343173Sdim IMPORT_SFUNC(ndis_sendrsrcavail_func, 1), 96343173Sdim IMPORT_SFUNC(ndis_intrsetup, 4), 97343173Sdim IMPORT_SFUNC(ndis_return, 1), 98343173Sdim 99343173Sdim { NULL, NULL, NULL } 100343173Sdim}; 101343173Sdim 102343173Sdimstatic struct nd_head ndis_devhead; 103343173Sdim 104343173Sdim/* 105343173Sdim * This allows us to export our symbols to other modules. 106343173Sdim * Note that we call ourselves 'ndisapi' to avoid a namespace 107343173Sdim * collision with if_ndis.ko, which internally calls itself 108343173Sdim * 'ndis.' 109343173Sdim * 110343173Sdim * Note: some of the subsystems depend on each other, so the 111343173Sdim * order in which they're started is important. The order of 112343173Sdim * importance is: 113343173Sdim * 114343173Sdim * HAL - spinlocks and IRQL manipulation 115343173Sdim * ntoskrnl - DPC and workitem threads, object waiting 116343173Sdim * windrv - driver/device registration 117343173Sdim * 118343173Sdim * The HAL should also be the last thing shut down, since 119343173Sdim * the ntoskrnl subsystem will use spinlocks right up until 120343173Sdim * the DPC and workitem threads are terminated. 121343173Sdim */ 122343173Sdim 123343173Sdimstatic int 124343173Sdimndis_modevent(module_t mod, int cmd, void *arg) 125343173Sdim{ 126343173Sdim int error = 0; 127353358Sdim image_patch_table *patch; 128353358Sdim 129353358Sdim switch (cmd) { 130353358Sdim case MOD_LOAD: 131353358Sdim /* Initialize subsystems */ 132353358Sdim hal_libinit(); 133353358Sdim ntoskrnl_libinit(); 134353358Sdim windrv_libinit(); 135353358Sdim ndis_libinit(); 136353358Sdim usbd_libinit(); 137353358Sdim 138353358Sdim patch = kernndis_functbl; 139353358Sdim while (patch->ipt_func != NULL) { 140353358Sdim windrv_wrap((funcptr)patch->ipt_func, 141353358Sdim (funcptr *)&patch->ipt_wrap, 142353358Sdim patch->ipt_argcnt, patch->ipt_ftype); 143353358Sdim patch++; 144353358Sdim } 145353358Sdim 146353358Sdim TAILQ_INIT(&ndis_devhead); 147353358Sdim 148353358Sdim break; 149353358Sdim case MOD_SHUTDOWN: 150353358Sdim if (TAILQ_FIRST(&ndis_devhead) == NULL) { 151353358Sdim /* Shut down subsystems */ 152353358Sdim ndis_libfini(); 153353358Sdim usbd_libfini(); 154353358Sdim windrv_libfini(); 155353358Sdim ntoskrnl_libfini(); 156353358Sdim hal_libfini(); 157353358Sdim 158353358Sdim patch = kernndis_functbl; 159353358Sdim while (patch->ipt_func != NULL) { 160353358Sdim windrv_unwrap(patch->ipt_wrap); 161353358Sdim patch++; 162353358Sdim } 163353358Sdim } 164353358Sdim break; 165353358Sdim case MOD_UNLOAD: 166353358Sdim /* Shut down subsystems */ 167353358Sdim ndis_libfini(); 168353358Sdim usbd_libfini(); 169353358Sdim windrv_libfini(); 170353358Sdim ntoskrnl_libfini(); 171353358Sdim hal_libfini(); 172353358Sdim 173353358Sdim patch = kernndis_functbl; 174353358Sdim while (patch->ipt_func != NULL) { 175353358Sdim windrv_unwrap(patch->ipt_wrap); 176353358Sdim patch++; 177353358Sdim } 178353358Sdim 179353358Sdim break; 180353358Sdim default: 181353358Sdim error = EINVAL; 182353358Sdim break; 183353358Sdim } 184353358Sdim 185353358Sdim return(error); 186353358Sdim} 187353358SdimDEV_MODULE(ndisapi, ndis_modevent, NULL); 188353358SdimMODULE_VERSION(ndisapi, 1); 189353358Sdim 190353358Sdimstatic void 191353358Sdimndis_sendrsrcavail_func(adapter) 192353358Sdim ndis_handle adapter; 193353358Sdim{ 194353358Sdim return; 195353358Sdim} 196353358Sdim 197353358Sdimstatic void 198353358Sdimndis_status_func(adapter, status, sbuf, slen) 199353358Sdim ndis_handle adapter; 200353358Sdim ndis_status status; 201353358Sdim void *sbuf; 202353358Sdim uint32_t slen; 203353358Sdim{ 204353358Sdim ndis_miniport_block *block; 205353358Sdim struct ndis_softc *sc; 206353358Sdim struct ifnet *ifp; 207353358Sdim 208353358Sdim block = adapter; 209353358Sdim sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 210353358Sdim ifp = sc->ifp; 211353358Sdim if (ifp->if_flags & IFF_DEBUG) 212353358Sdim device_printf (sc->ndis_dev, "status: %x\n", status); 213353358Sdim return; 214353358Sdim} 215353358Sdim 216353358Sdimstatic void 217353358Sdimndis_statusdone_func(adapter) 218353358Sdim ndis_handle adapter; 219353358Sdim{ 220353358Sdim ndis_miniport_block *block; 221353358Sdim struct ndis_softc *sc; 222353358Sdim struct ifnet *ifp; 223353358Sdim 224353358Sdim block = adapter; 225353358Sdim sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 226353358Sdim ifp = sc->ifp; 227353358Sdim if (ifp->if_flags & IFF_DEBUG) 228353358Sdim device_printf (sc->ndis_dev, "status complete\n"); 229353358Sdim return; 230353358Sdim} 231353358Sdim 232353358Sdimstatic void 233353358Sdimndis_setdone_func(adapter, status) 234353358Sdim ndis_handle adapter; 235353358Sdim ndis_status status; 236353358Sdim{ 237353358Sdim ndis_miniport_block *block; 238353358Sdim block = adapter; 239353358Sdim 240353358Sdim block->nmb_setstat = status; 241353358Sdim KeSetEvent(&block->nmb_setevent, IO_NO_INCREMENT, FALSE); 242353358Sdim return; 243353358Sdim} 244353358Sdim 245353358Sdimstatic void 246353358Sdimndis_getdone_func(adapter, status) 247353358Sdim ndis_handle adapter; 248353358Sdim ndis_status status; 249353358Sdim{ 250353358Sdim ndis_miniport_block *block; 251353358Sdim block = adapter; 252353358Sdim 253353358Sdim block->nmb_getstat = status; 254353358Sdim KeSetEvent(&block->nmb_getevent, IO_NO_INCREMENT, FALSE); 255353358Sdim return; 256353358Sdim} 257353358Sdim 258343173Sdimstatic void 259ndis_resetdone_func(adapter, status, addressingreset) 260 ndis_handle adapter; 261 ndis_status status; 262 uint8_t addressingreset; 263{ 264 ndis_miniport_block *block; 265 struct ndis_softc *sc; 266 struct ifnet *ifp; 267 268 block = adapter; 269 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 270 ifp = sc->ifp; 271 272 if (ifp->if_flags & IFF_DEBUG) 273 device_printf (sc->ndis_dev, "reset done...\n"); 274 KeSetEvent(&block->nmb_resetevent, IO_NO_INCREMENT, FALSE); 275 276 return; 277} 278 279int 280ndis_create_sysctls(arg) 281 void *arg; 282{ 283 struct ndis_softc *sc; 284 ndis_cfg *vals; 285 char buf[256]; 286 struct sysctl_oid *oidp; 287 struct sysctl_ctx_entry *e; 288 289 if (arg == NULL) 290 return(EINVAL); 291 292 sc = arg; 293 vals = sc->ndis_regvals; 294 295 TAILQ_INIT(&sc->ndis_cfglist_head); 296 297#if __FreeBSD_version < 502113 298 /* Create the sysctl tree. */ 299 300 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 301 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 302 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 303 device_get_desc(sc->ndis_dev)); 304 305#endif 306 /* Add the driver-specific registry keys. */ 307 308 while(1) { 309 if (vals->nc_cfgkey == NULL) 310 break; 311 312 if (vals->nc_idx != sc->ndis_devidx) { 313 vals++; 314 continue; 315 } 316 317 /* See if we already have a sysctl with this name */ 318 319 oidp = NULL; 320#if __FreeBSD_version < 502113 321 TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 322#else 323 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 324#endif 325 oidp = e->entry; 326 if (strcasecmp(oidp->oid_name, vals->nc_cfgkey) == 0) 327 break; 328 oidp = NULL; 329 } 330 331 if (oidp != NULL) { 332 vals++; 333 continue; 334 } 335 336 ndis_add_sysctl(sc, vals->nc_cfgkey, vals->nc_cfgdesc, 337 vals->nc_val, CTLFLAG_RW); 338 vals++; 339 } 340 341 /* Now add a couple of builtin keys. */ 342 343 /* 344 * Environment can be either Windows (0) or WindowsNT (1). 345 * We qualify as the latter. 346 */ 347 ndis_add_sysctl(sc, "Environment", 348 "Windows environment", "1", CTLFLAG_RD); 349 350 /* NDIS version should be 5.1. */ 351 ndis_add_sysctl(sc, "NdisVersion", 352 "NDIS API Version", "0x00050001", CTLFLAG_RD); 353 354 /* Bus type (PCI, PCMCIA, etc...) */ 355 sprintf(buf, "%d", (int)sc->ndis_iftype); 356 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 357 358 if (sc->ndis_res_io != NULL) { 359 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 360 ndis_add_sysctl(sc, "IOBaseAddress", 361 "Base I/O Address", buf, CTLFLAG_RD); 362 } 363 364 if (sc->ndis_irq != NULL) { 365 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 366 ndis_add_sysctl(sc, "InterruptNumber", 367 "Interrupt Number", buf, CTLFLAG_RD); 368 } 369 370 return(0); 371} 372 373int 374ndis_add_sysctl(arg, key, desc, val, flag) 375 void *arg; 376 char *key; 377 char *desc; 378 char *val; 379 int flag; 380{ 381 struct ndis_softc *sc; 382 struct ndis_cfglist *cfg; 383 char descstr[256]; 384 385 sc = arg; 386 387 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 388 389 if (cfg == NULL) { 390 printf("failed for %s\n", key); 391 return(ENOMEM); 392 } 393 394 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 395 if (desc == NULL) { 396 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 397 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 398 } else 399 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 400 strcpy(cfg->ndis_cfg.nc_val, val); 401 402 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 403 404 cfg->ndis_oid = 405#if __FreeBSD_version < 502113 406 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 407 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 408 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 409 cfg->ndis_cfg.nc_cfgdesc); 410#else 411 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 412 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 413 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 414 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 415 cfg->ndis_cfg.nc_cfgdesc); 416#endif 417 418 return(0); 419} 420 421/* 422 * Somewhere, somebody decided "hey, let's automatically create 423 * a sysctl tree for each device instance as it's created -- it'll 424 * make life so much easier!" Lies. Why must they turn the kernel 425 * into a house of lies? 426 */ 427 428int 429ndis_flush_sysctls(arg) 430 void *arg; 431{ 432 struct ndis_softc *sc; 433 struct ndis_cfglist *cfg; 434 struct sysctl_ctx_list *clist; 435 436 sc = arg; 437 438#if __FreeBSD_version < 502113 439 clist = &sc->ndis_ctx; 440#else 441 clist = device_get_sysctl_ctx(sc->ndis_dev); 442#endif 443 444 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 445 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 446 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 447 sysctl_ctx_entry_del(clist, cfg->ndis_oid); 448 sysctl_remove_oid(cfg->ndis_oid, 1, 0); 449 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 450 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 451 free(cfg, M_DEVBUF); 452 } 453 454 return(0); 455} 456 457static void 458ndis_return(dobj, arg) 459 device_object *dobj; 460 void *arg; 461{ 462 ndis_miniport_block *block; 463 ndis_miniport_characteristics *ch; 464 ndis_return_handler returnfunc; 465 ndis_handle adapter; 466 ndis_packet *p; 467 uint8_t irql; 468 list_entry *l; 469 470 block = arg; 471 ch = IoGetDriverObjectExtension(dobj->do_drvobj, (void *)1); 472 473 p = arg; 474 adapter = block->nmb_miniportadapterctx; 475 476 if (adapter == NULL) 477 return; 478 479 returnfunc = ch->nmc_return_packet_func; 480 481 KeAcquireSpinLock(&block->nmb_returnlock, &irql); 482 while (!IsListEmpty(&block->nmb_returnlist)) { 483 l = RemoveHeadList((&block->nmb_returnlist)); 484 p = CONTAINING_RECORD(l, ndis_packet, np_list); 485 InitializeListHead((&p->np_list)); 486 KeReleaseSpinLock(&block->nmb_returnlock, irql); 487 MSCALL2(returnfunc, adapter, p); 488 KeAcquireSpinLock(&block->nmb_returnlock, &irql); 489 } 490 KeReleaseSpinLock(&block->nmb_returnlock, irql); 491 492 return; 493} 494 495void 496ndis_return_packet(buf, arg) 497 void *buf; /* not used */ 498 void *arg; 499{ 500 ndis_packet *p; 501 ndis_miniport_block *block; 502 503 if (arg == NULL) 504 return; 505 506 p = arg; 507 508 /* Decrement refcount. */ 509 p->np_refcnt--; 510 511 /* Release packet when refcount hits zero, otherwise return. */ 512 if (p->np_refcnt) 513 return; 514 515 block = ((struct ndis_softc *)p->np_softc)->ndis_block; 516 517 KeAcquireSpinLockAtDpcLevel(&block->nmb_returnlock); 518 InitializeListHead((&p->np_list)); 519 InsertHeadList((&block->nmb_returnlist), (&p->np_list)); 520 KeReleaseSpinLockFromDpcLevel(&block->nmb_returnlock); 521 522 IoQueueWorkItem(block->nmb_returnitem, 523 (io_workitem_func)kernndis_functbl[7].ipt_wrap, 524 WORKQUEUE_CRITICAL, block); 525 526 return; 527} 528 529void 530ndis_free_bufs(b0) 531 ndis_buffer *b0; 532{ 533 ndis_buffer *next; 534 535 if (b0 == NULL) 536 return; 537 538 while(b0 != NULL) { 539 next = b0->mdl_next; 540 IoFreeMdl(b0); 541 b0 = next; 542 } 543 544 return; 545} 546int in_reset = 0; 547void 548ndis_free_packet(p) 549 ndis_packet *p; 550{ 551 if (p == NULL) 552 return; 553 554 ndis_free_bufs(p->np_private.npp_head); 555 NdisFreePacket(p); 556 return; 557} 558 559int 560ndis_convert_res(arg) 561 void *arg; 562{ 563 struct ndis_softc *sc; 564 ndis_resource_list *rl = NULL; 565 cm_partial_resource_desc *prd = NULL; 566 ndis_miniport_block *block; 567 device_t dev; 568 struct resource_list *brl; 569 struct resource_list_entry *brle; 570#if __FreeBSD_version < 600022 571 struct resource_list brl_rev; 572 struct resource_list_entry *n; 573#endif 574 int error = 0; 575 576 sc = arg; 577 block = sc->ndis_block; 578 dev = sc->ndis_dev; 579 580#if __FreeBSD_version < 600022 581 SLIST_INIT(&brl_rev); 582#endif 583 584 rl = malloc(sizeof(ndis_resource_list) + 585 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 586 M_DEVBUF, M_NOWAIT|M_ZERO); 587 588 if (rl == NULL) 589 return(ENOMEM); 590 591 rl->cprl_version = 5; 592 rl->cprl_version = 1; 593 rl->cprl_count = sc->ndis_rescnt; 594 prd = rl->cprl_partial_descs; 595 596 brl = BUS_GET_RESOURCE_LIST(dev, dev); 597 598 if (brl != NULL) { 599 600#if __FreeBSD_version < 600022 601 /* 602 * We have a small problem. Some PCI devices have 603 * multiple I/O ranges. Windows orders them starting 604 * from lowest numbered BAR to highest. We discover 605 * them in that order too, but insert them into a singly 606 * linked list head first, which means when time comes 607 * to traverse the list, we enumerate them in reverse 608 * order. This screws up some drivers which expect the 609 * BARs to be in ascending order so that they can choose 610 * the "first" one as their register space. Unfortunately, 611 * in order to fix this, we have to create our own 612 * temporary list with the entries in reverse order. 613 */ 614 615 SLIST_FOREACH(brle, brl, link) { 616 n = malloc(sizeof(struct resource_list_entry), 617 M_TEMP, M_NOWAIT); 618 if (n == NULL) { 619 error = ENOMEM; 620 goto bad; 621 } 622 bcopy((char *)brle, (char *)n, 623 sizeof(struct resource_list_entry)); 624 SLIST_INSERT_HEAD(&brl_rev, n, link); 625 } 626 627 SLIST_FOREACH(brle, &brl_rev, link) { 628#else 629 STAILQ_FOREACH(brle, brl, link) { 630#endif 631 switch (brle->type) { 632 case SYS_RES_IOPORT: 633 prd->cprd_type = CmResourceTypePort; 634 prd->cprd_flags = CM_RESOURCE_PORT_IO; 635 prd->cprd_sharedisp = 636 CmResourceShareDeviceExclusive; 637 prd->u.cprd_port.cprd_start.np_quad = 638 brle->start; 639 prd->u.cprd_port.cprd_len = brle->count; 640 break; 641 case SYS_RES_MEMORY: 642 prd->cprd_type = CmResourceTypeMemory; 643 prd->cprd_flags = 644 CM_RESOURCE_MEMORY_READ_WRITE; 645 prd->cprd_sharedisp = 646 CmResourceShareDeviceExclusive; 647 prd->u.cprd_port.cprd_start.np_quad = 648 brle->start; 649 prd->u.cprd_port.cprd_len = brle->count; 650 break; 651 case SYS_RES_IRQ: 652 prd->cprd_type = CmResourceTypeInterrupt; 653 prd->cprd_flags = 0; 654 /* 655 * Always mark interrupt resources as 656 * shared, since in our implementation, 657 * they will be. 658 */ 659 prd->cprd_sharedisp = 660 CmResourceShareShared; 661 prd->u.cprd_intr.cprd_level = brle->start; 662 prd->u.cprd_intr.cprd_vector = brle->start; 663 prd->u.cprd_intr.cprd_affinity = 0; 664 break; 665 default: 666 break; 667 } 668 prd++; 669 } 670 } 671 672 block->nmb_rlist = rl; 673 674#if __FreeBSD_version < 600022 675bad: 676 677 while (!SLIST_EMPTY(&brl_rev)) { 678 n = SLIST_FIRST(&brl_rev); 679 SLIST_REMOVE_HEAD(&brl_rev, link); 680 free (n, M_TEMP); 681 } 682#endif 683 684 return(error); 685} 686 687/* 688 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 689 * packet, it will hand it to us in the form of an ndis_packet, 690 * which we need to convert to an mbuf that is then handed off 691 * to the stack. Note: we configure the mbuf list so that it uses 692 * the memory regions specified by the ndis_buffer structures in 693 * the ndis_packet as external storage. In most cases, this will 694 * point to a memory region allocated by the driver (either by 695 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 696 * the driver to handle free()ing this region for is, so we set up 697 * a dummy no-op free handler for it. 698 */ 699 700int 701ndis_ptom(m0, p) 702 struct mbuf **m0; 703 ndis_packet *p; 704{ 705 struct mbuf *m = NULL, *prev = NULL; 706 ndis_buffer *buf; 707 ndis_packet_private *priv; 708 uint32_t totlen = 0; 709 struct ifnet *ifp; 710 struct ether_header *eh; 711 int diff; 712 713 if (p == NULL || m0 == NULL) 714 return(EINVAL); 715 716 priv = &p->np_private; 717 buf = priv->npp_head; 718 p->np_refcnt = 0; 719 720 for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { 721 if (buf == priv->npp_head) 722#ifdef MT_HEADER 723 MGETHDR(m, M_DONTWAIT, MT_HEADER); 724#else 725 MGETHDR(m, M_DONTWAIT, MT_DATA); 726#endif 727 else 728 MGET(m, M_DONTWAIT, MT_DATA); 729 if (m == NULL) { 730 m_freem(*m0); 731 *m0 = NULL; 732 return(ENOBUFS); 733 } 734 m->m_len = MmGetMdlByteCount(buf); 735 m->m_data = MmGetMdlVirtualAddress(buf); 736 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 737 p, 0, EXT_NDIS); 738 p->np_refcnt++; 739 740 totlen += m->m_len; 741 if (m->m_flags & M_PKTHDR) 742 *m0 = m; 743 else 744 prev->m_next = m; 745 prev = m; 746 } 747 748 /* 749 * This is a hack to deal with the Marvell 8335 driver 750 * which, when associated with an AP in WPA-PSK mode, 751 * seems to overpad its frames by 8 bytes. I don't know 752 * that the extra 8 bytes are for, and they're not there 753 * in open mode, so for now clamp the frame size at 1514 754 * until I can figure out how to deal with this properly, 755 * otherwise if_ethersubr() will spank us by discarding 756 * the 'oversize' frames. 757 */ 758 759 eh = mtod((*m0), struct ether_header *); 760 ifp = ((struct ndis_softc *)p->np_softc)->ifp; 761 if (totlen > ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE)) { 762 diff = totlen - ETHER_MAX_FRAME(ifp, eh->ether_type, FALSE); 763 totlen -= diff; 764 m->m_len -= diff; 765 } 766 (*m0)->m_pkthdr.len = totlen; 767 768 return(0); 769} 770 771/* 772 * Create an NDIS packet from an mbuf chain. 773 * This is used mainly when transmitting packets, where we need 774 * to turn an mbuf off an interface's send queue and transform it 775 * into an NDIS packet which will be fed into the NDIS driver's 776 * send routine. 777 * 778 * NDIS packets consist of two parts: an ndis_packet structure, 779 * which is vaguely analagous to the pkthdr portion of an mbuf, 780 * and one or more ndis_buffer structures, which define the 781 * actual memory segments in which the packet data resides. 782 * We need to allocate one ndis_buffer for each mbuf in a chain, 783 * plus one ndis_packet as the header. 784 */ 785 786int 787ndis_mtop(m0, p) 788 struct mbuf *m0; 789 ndis_packet **p; 790{ 791 struct mbuf *m; 792 ndis_buffer *buf = NULL, *prev = NULL; 793 ndis_packet_private *priv; 794 795 if (p == NULL || *p == NULL || m0 == NULL) 796 return(EINVAL); 797 798 priv = &(*p)->np_private; 799 priv->npp_totlen = m0->m_pkthdr.len; 800 801 for (m = m0; m != NULL; m = m->m_next) { 802 if (m->m_len == 0) 803 continue; 804 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); 805 if (buf == NULL) { 806 ndis_free_packet(*p); 807 *p = NULL; 808 return(ENOMEM); 809 } 810 MmBuildMdlForNonPagedPool(buf); 811 812 if (priv->npp_head == NULL) 813 priv->npp_head = buf; 814 else 815 prev->mdl_next = buf; 816 prev = buf; 817 } 818 819 priv->npp_tail = buf; 820 821 return(0); 822} 823 824int 825ndis_get_supported_oids(arg, oids, oidcnt) 826 void *arg; 827 ndis_oid **oids; 828 int *oidcnt; 829{ 830 int len, rval; 831 ndis_oid *o; 832 833 if (arg == NULL || oids == NULL || oidcnt == NULL) 834 return(EINVAL); 835 len = 0; 836 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 837 838 o = malloc(len, M_DEVBUF, M_NOWAIT); 839 if (o == NULL) 840 return(ENOMEM); 841 842 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 843 844 if (rval) { 845 free(o, M_DEVBUF); 846 return(rval); 847 } 848 849 *oids = o; 850 *oidcnt = len / 4; 851 852 return(0); 853} 854 855int 856ndis_set_info(arg, oid, buf, buflen) 857 void *arg; 858 ndis_oid oid; 859 void *buf; 860 int *buflen; 861{ 862 struct ndis_softc *sc; 863 ndis_status rval; 864 ndis_handle adapter; 865 ndis_setinfo_handler setfunc; 866 uint32_t byteswritten = 0, bytesneeded = 0; 867 uint8_t irql; 868 uint64_t duetime; 869 870 /* 871 * According to the NDIS spec, MiniportQueryInformation() 872 * and MiniportSetInformation() requests are handled serially: 873 * once one request has been issued, we must wait for it to 874 * finish before allowing another request to proceed. 875 */ 876 877 sc = arg; 878 879 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 880 881 if (sc->ndis_block->nmb_pendingreq != NULL) { 882 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 883 panic("ndis_set_info() called while other request pending"); 884 } else 885 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 886 887 setfunc = sc->ndis_chars->nmc_setinfo_func; 888 adapter = sc->ndis_block->nmb_miniportadapterctx; 889 890 if (adapter == NULL || setfunc == NULL || 891 sc->ndis_block->nmb_devicectx == NULL) { 892 sc->ndis_block->nmb_pendingreq = NULL; 893 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 894 return(ENXIO); 895 } 896 897 rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, 898 &byteswritten, &bytesneeded); 899 900 sc->ndis_block->nmb_pendingreq = NULL; 901 902 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 903 904 if (rval == NDIS_STATUS_PENDING) { 905 /* Wait up to 5 seconds. */ 906 duetime = (5 * 1000000) * -10; 907 KeResetEvent(&sc->ndis_block->nmb_setevent); 908 KeWaitForSingleObject(&sc->ndis_block->nmb_setevent, 909 0, 0, FALSE, &duetime); 910 rval = sc->ndis_block->nmb_setstat; 911 } 912 913 if (byteswritten) 914 *buflen = byteswritten; 915 if (bytesneeded) 916 *buflen = bytesneeded; 917 918 if (rval == NDIS_STATUS_INVALID_LENGTH) 919 return(ENOSPC); 920 921 if (rval == NDIS_STATUS_INVALID_OID) 922 return(EINVAL); 923 924 if (rval == NDIS_STATUS_NOT_SUPPORTED || 925 rval == NDIS_STATUS_NOT_ACCEPTED) 926 return(ENOTSUP); 927 928 if (rval != NDIS_STATUS_SUCCESS) 929 return(ENODEV); 930 931 return(0); 932} 933 934typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 935 936int 937ndis_send_packets(arg, packets, cnt) 938 void *arg; 939 ndis_packet **packets; 940 int cnt; 941{ 942 struct ndis_softc *sc; 943 ndis_handle adapter; 944 ndis_sendmulti_handler sendfunc; 945 ndis_senddone_func senddonefunc; 946 int i; 947 ndis_packet *p; 948 uint8_t irql; 949 950 sc = arg; 951 adapter = sc->ndis_block->nmb_miniportadapterctx; 952 if (adapter == NULL) 953 return(ENXIO); 954 sendfunc = sc->ndis_chars->nmc_sendmulti_func; 955 senddonefunc = sc->ndis_block->nmb_senddone_func; 956 957 if (NDIS_SERIALIZED(sc->ndis_block)) 958 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 959 960 MSCALL3(sendfunc, adapter, packets, cnt); 961 962 for (i = 0; i < cnt; i++) { 963 p = packets[i]; 964 /* 965 * Either the driver already handed the packet to 966 * ndis_txeof() due to a failure, or it wants to keep 967 * it and release it asynchronously later. Skip to the 968 * next one. 969 */ 970 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 971 continue; 972 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); 973 } 974 975 if (NDIS_SERIALIZED(sc->ndis_block)) 976 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 977 978 return(0); 979} 980 981int 982ndis_send_packet(arg, packet) 983 void *arg; 984 ndis_packet *packet; 985{ 986 struct ndis_softc *sc; 987 ndis_handle adapter; 988 ndis_status status; 989 ndis_sendsingle_handler sendfunc; 990 ndis_senddone_func senddonefunc; 991 uint8_t irql; 992 993 sc = arg; 994 adapter = sc->ndis_block->nmb_miniportadapterctx; 995 if (adapter == NULL) 996 return(ENXIO); 997 sendfunc = sc->ndis_chars->nmc_sendsingle_func; 998 senddonefunc = sc->ndis_block->nmb_senddone_func; 999 1000 if (NDIS_SERIALIZED(sc->ndis_block)) 1001 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1002 status = MSCALL3(sendfunc, adapter, packet, 1003 packet->np_private.npp_flags); 1004 1005 if (status == NDIS_STATUS_PENDING) { 1006 if (NDIS_SERIALIZED(sc->ndis_block)) 1007 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1008 return(0); 1009 } 1010 1011 MSCALL3(senddonefunc, sc->ndis_block, packet, status); 1012 1013 if (NDIS_SERIALIZED(sc->ndis_block)) 1014 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1015 1016 return(0); 1017} 1018 1019int 1020ndis_init_dma(arg) 1021 void *arg; 1022{ 1023 struct ndis_softc *sc; 1024 int i, error; 1025 1026 sc = arg; 1027 1028 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1029 M_DEVBUF, M_NOWAIT|M_ZERO); 1030 1031 if (sc->ndis_tmaps == NULL) 1032 return(ENOMEM); 1033 1034 for (i = 0; i < sc->ndis_maxpkts; i++) { 1035 error = bus_dmamap_create(sc->ndis_ttag, 0, 1036 &sc->ndis_tmaps[i]); 1037 if (error) { 1038 free(sc->ndis_tmaps, M_DEVBUF); 1039 return(ENODEV); 1040 } 1041 } 1042 1043 return(0); 1044} 1045 1046int 1047ndis_destroy_dma(arg) 1048 void *arg; 1049{ 1050 struct ndis_softc *sc; 1051 struct mbuf *m; 1052 ndis_packet *p = NULL; 1053 int i; 1054 1055 sc = arg; 1056 1057 for (i = 0; i < sc->ndis_maxpkts; i++) { 1058 if (sc->ndis_txarray[i] != NULL) { 1059 p = sc->ndis_txarray[i]; 1060 m = (struct mbuf *)p->np_rsvd[1]; 1061 if (m != NULL) 1062 m_freem(m); 1063 ndis_free_packet(sc->ndis_txarray[i]); 1064 } 1065 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1066 } 1067 1068 free(sc->ndis_tmaps, M_DEVBUF); 1069 1070 bus_dma_tag_destroy(sc->ndis_ttag); 1071 1072 return(0); 1073} 1074 1075int 1076ndis_reset_nic(arg) 1077 void *arg; 1078{ 1079 struct ndis_softc *sc; 1080 ndis_handle adapter; 1081 ndis_reset_handler resetfunc; 1082 uint8_t addressing_reset; 1083 int rval; 1084 uint8_t irql; 1085 1086 sc = arg; 1087 1088 NDIS_LOCK(sc); 1089 adapter = sc->ndis_block->nmb_miniportadapterctx; 1090 resetfunc = sc->ndis_chars->nmc_reset_func; 1091 1092 if (adapter == NULL || resetfunc == NULL || 1093 sc->ndis_block->nmb_devicectx == NULL) { 1094 NDIS_UNLOCK(sc); 1095 return(EIO); 1096 } 1097 1098 NDIS_UNLOCK(sc); 1099 1100 if (NDIS_SERIALIZED(sc->ndis_block)) 1101 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1102 1103 rval = MSCALL2(resetfunc, &addressing_reset, adapter); 1104 1105 if (NDIS_SERIALIZED(sc->ndis_block)) 1106 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1107 1108 if (rval == NDIS_STATUS_PENDING) { 1109 KeResetEvent(&sc->ndis_block->nmb_resetevent); 1110 KeWaitForSingleObject(&sc->ndis_block->nmb_resetevent, 1111 0, 0, FALSE, NULL); 1112 } 1113 1114 return(0); 1115} 1116 1117int 1118ndis_halt_nic(arg) 1119 void *arg; 1120{ 1121 struct ndis_softc *sc; 1122 ndis_handle adapter; 1123 ndis_halt_handler haltfunc; 1124 ndis_miniport_block *block; 1125 int empty = 0; 1126 uint8_t irql; 1127 1128 sc = arg; 1129 block = sc->ndis_block; 1130 1131 if (!cold) 1132 KeFlushQueuedDpcs(); 1133 1134 /* 1135 * Wait for all packets to be returned. 1136 */ 1137 1138 while (1) { 1139 KeAcquireSpinLock(&block->nmb_returnlock, &irql); 1140 empty = IsListEmpty(&block->nmb_returnlist); 1141 KeReleaseSpinLock(&block->nmb_returnlock, irql); 1142 if (empty) 1143 break; 1144 NdisMSleep(1000); 1145 } 1146 1147 NDIS_LOCK(sc); 1148 adapter = sc->ndis_block->nmb_miniportadapterctx; 1149 if (adapter == NULL) { 1150 NDIS_UNLOCK(sc); 1151 return(EIO); 1152 } 1153 1154 sc->ndis_block->nmb_devicectx = NULL; 1155 1156 /* 1157 * The adapter context is only valid after the init 1158 * handler has been called, and is invalid once the 1159 * halt handler has been called. 1160 */ 1161 1162 haltfunc = sc->ndis_chars->nmc_halt_func; 1163 NDIS_UNLOCK(sc); 1164 1165 MSCALL1(haltfunc, adapter); 1166 1167 NDIS_LOCK(sc); 1168 sc->ndis_block->nmb_miniportadapterctx = NULL; 1169 NDIS_UNLOCK(sc); 1170 1171 return(0); 1172} 1173 1174int 1175ndis_shutdown_nic(arg) 1176 void *arg; 1177{ 1178 struct ndis_softc *sc; 1179 ndis_handle adapter; 1180 ndis_shutdown_handler shutdownfunc; 1181 1182 sc = arg; 1183 NDIS_LOCK(sc); 1184 adapter = sc->ndis_block->nmb_miniportadapterctx; 1185 shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; 1186 NDIS_UNLOCK(sc); 1187 if (adapter == NULL || shutdownfunc == NULL) 1188 return(EIO); 1189 1190 if (sc->ndis_chars->nmc_rsvd0 == NULL) 1191 MSCALL1(shutdownfunc, adapter); 1192 else 1193 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0); 1194 1195 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1196 1197 return(0); 1198} 1199 1200int 1201ndis_init_nic(arg) 1202 void *arg; 1203{ 1204 struct ndis_softc *sc; 1205 ndis_miniport_block *block; 1206 ndis_init_handler initfunc; 1207 ndis_status status, openstatus = 0; 1208 ndis_medium mediumarray[NdisMediumMax]; 1209 uint32_t chosenmedium, i; 1210 1211 if (arg == NULL) 1212 return(EINVAL); 1213 1214 sc = arg; 1215 NDIS_LOCK(sc); 1216 block = sc->ndis_block; 1217 initfunc = sc->ndis_chars->nmc_init_func; 1218 NDIS_UNLOCK(sc); 1219 1220 sc->ndis_block->nmb_timerlist = NULL; 1221 1222 for (i = 0; i < NdisMediumMax; i++) 1223 mediumarray[i] = i; 1224 1225 status = MSCALL6(initfunc, &openstatus, &chosenmedium, 1226 mediumarray, NdisMediumMax, block, block); 1227 1228 /* 1229 * If the init fails, blow away the other exported routines 1230 * we obtained from the driver so we can't call them later. 1231 * If the init failed, none of these will work. 1232 */ 1233 if (status != NDIS_STATUS_SUCCESS) { 1234 NDIS_LOCK(sc); 1235 sc->ndis_block->nmb_miniportadapterctx = NULL; 1236 NDIS_UNLOCK(sc); 1237 return(ENXIO); 1238 } 1239 1240 /* 1241 * This may look really goofy, but apparently it is possible 1242 * to halt a miniport too soon after it's been initialized. 1243 * After MiniportInitialize() finishes, pause for 1 second 1244 * to give the chip a chance to handle any short-lived timers 1245 * that were set in motion. If we call MiniportHalt() too soon, 1246 * some of the timers may not be cancelled, because the driver 1247 * expects them to fire before the halt is called. 1248 */ 1249 1250 pause("ndwait", hz); 1251 1252 NDIS_LOCK(sc); 1253 sc->ndis_block->nmb_devicectx = sc; 1254 NDIS_UNLOCK(sc); 1255 1256 return(0); 1257} 1258 1259static void 1260ndis_intrsetup(dpc, dobj, ip, sc) 1261 kdpc *dpc; 1262 device_object *dobj; 1263 irp *ip; 1264 struct ndis_softc *sc; 1265{ 1266 ndis_miniport_interrupt *intr; 1267 1268 intr = sc->ndis_block->nmb_interrupt; 1269 1270 /* Sanity check. */ 1271 1272 if (intr == NULL) 1273 return; 1274 1275 KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock); 1276 KeResetEvent(&intr->ni_dpcevt); 1277 if (KeInsertQueueDpc(&intr->ni_dpc, NULL, NULL) == TRUE) 1278 intr->ni_dpccnt++; 1279 KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock); 1280 1281 return; 1282} 1283 1284int 1285ndis_get_info(arg, oid, buf, buflen) 1286 void *arg; 1287 ndis_oid oid; 1288 void *buf; 1289 int *buflen; 1290{ 1291 struct ndis_softc *sc; 1292 ndis_status rval; 1293 ndis_handle adapter; 1294 ndis_queryinfo_handler queryfunc; 1295 uint32_t byteswritten = 0, bytesneeded = 0; 1296 uint8_t irql; 1297 uint64_t duetime; 1298 1299 sc = arg; 1300 1301 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1302 1303 if (sc->ndis_block->nmb_pendingreq != NULL) { 1304 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1305 panic("ndis_get_info() called while other request pending"); 1306 } else 1307 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 1308 1309 queryfunc = sc->ndis_chars->nmc_queryinfo_func; 1310 adapter = sc->ndis_block->nmb_miniportadapterctx; 1311 1312 if (adapter == NULL || queryfunc == NULL || 1313 sc->ndis_block->nmb_devicectx == NULL) { 1314 sc->ndis_block->nmb_pendingreq = NULL; 1315 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1316 return(ENXIO); 1317 } 1318 1319 rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, 1320 &byteswritten, &bytesneeded); 1321 1322 sc->ndis_block->nmb_pendingreq = NULL; 1323 1324 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1325 1326 /* Wait for requests that block. */ 1327 1328 if (rval == NDIS_STATUS_PENDING) { 1329 /* Wait up to 5 seconds. */ 1330 duetime = (5 * 1000000) * -10; 1331 KeResetEvent(&sc->ndis_block->nmb_getevent); 1332 KeWaitForSingleObject(&sc->ndis_block->nmb_getevent, 1333 0, 0, FALSE, &duetime); 1334 rval = sc->ndis_block->nmb_getstat; 1335 } 1336 1337 if (byteswritten) 1338 *buflen = byteswritten; 1339 if (bytesneeded) 1340 *buflen = bytesneeded; 1341 1342 if (rval == NDIS_STATUS_INVALID_LENGTH || 1343 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1344 return(ENOSPC); 1345 1346 if (rval == NDIS_STATUS_INVALID_OID) 1347 return(EINVAL); 1348 1349 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1350 rval == NDIS_STATUS_NOT_ACCEPTED) 1351 return(ENOTSUP); 1352 1353 if (rval != NDIS_STATUS_SUCCESS) 1354 return(ENODEV); 1355 1356 return(0); 1357} 1358 1359uint32_t 1360NdisAddDevice(drv, pdo) 1361 driver_object *drv; 1362 device_object *pdo; 1363{ 1364 device_object *fdo; 1365 ndis_miniport_block *block; 1366 struct ndis_softc *sc; 1367 uint32_t status; 1368 int error; 1369 1370 sc = device_get_softc(pdo->do_devext); 1371 1372 if (sc->ndis_iftype == PCMCIABus || sc->ndis_iftype == PCIBus) { 1373 error = bus_setup_intr(sc->ndis_dev, sc->ndis_irq, 1374 INTR_TYPE_NET | INTR_MPSAFE, 1375 NULL, ntoskrnl_intr, NULL, &sc->ndis_intrhand); 1376 if (error) 1377 return(NDIS_STATUS_FAILURE); 1378 } 1379 1380 status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, 1381 FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); 1382 1383 if (status != STATUS_SUCCESS) 1384 return(status); 1385 1386 block = fdo->do_devext; 1387 1388 block->nmb_filterdbs.nf_ethdb = block; 1389 block->nmb_deviceobj = fdo; 1390 block->nmb_physdeviceobj = pdo; 1391 block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); 1392 KeInitializeSpinLock(&block->nmb_lock); 1393 KeInitializeSpinLock(&block->nmb_returnlock); 1394 KeInitializeEvent(&block->nmb_getevent, EVENT_TYPE_NOTIFY, TRUE); 1395 KeInitializeEvent(&block->nmb_setevent, EVENT_TYPE_NOTIFY, TRUE); 1396 KeInitializeEvent(&block->nmb_resetevent, EVENT_TYPE_NOTIFY, TRUE); 1397 InitializeListHead(&block->nmb_parmlist); 1398 InitializeListHead(&block->nmb_returnlist); 1399 block->nmb_returnitem = IoAllocateWorkItem(fdo); 1400 1401 /* 1402 * Stash pointers to the miniport block and miniport 1403 * characteristics info in the if_ndis softc so the 1404 * UNIX wrapper driver can get to them later. 1405 */ 1406 sc->ndis_block = block; 1407 sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); 1408 1409 /* 1410 * If the driver has a MiniportTransferData() function, 1411 * we should allocate a private RX packet pool. 1412 */ 1413 1414 if (sc->ndis_chars->nmc_transferdata_func != NULL) { 1415 NdisAllocatePacketPool(&status, &block->nmb_rxpool, 1416 32, PROTOCOL_RESERVED_SIZE_IN_PACKET); 1417 if (status != NDIS_STATUS_SUCCESS) { 1418 IoDetachDevice(block->nmb_nextdeviceobj); 1419 IoDeleteDevice(fdo); 1420 return(status); 1421 } 1422 InitializeListHead((&block->nmb_packetlist)); 1423 } 1424 1425 /* Give interrupt handling priority over timers. */ 1426 IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap); 1427 KeSetImportanceDpc(&fdo->do_dpc, KDPC_IMPORTANCE_HIGH); 1428 1429 /* Finish up BSD-specific setup. */ 1430 1431 block->nmb_signature = (void *)0xcafebabe; 1432 block->nmb_status_func = kernndis_functbl[0].ipt_wrap; 1433 block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; 1434 block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; 1435 block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; 1436 block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; 1437 block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; 1438 block->nmb_pendingreq = NULL; 1439 1440 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1441 1442 return (STATUS_SUCCESS); 1443} 1444 1445int 1446ndis_unload_driver(arg) 1447 void *arg; 1448{ 1449 struct ndis_softc *sc; 1450 device_object *fdo; 1451 1452 sc = arg; 1453 1454 if (sc->ndis_intrhand) 1455 bus_teardown_intr(sc->ndis_dev, 1456 sc->ndis_irq, sc->ndis_intrhand); 1457 1458 if (sc->ndis_block->nmb_rlist != NULL) 1459 free(sc->ndis_block->nmb_rlist, M_DEVBUF); 1460 1461 ndis_flush_sysctls(sc); 1462 1463 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1464 1465 if (sc->ndis_chars->nmc_transferdata_func != NULL) 1466 NdisFreePacketPool(sc->ndis_block->nmb_rxpool); 1467 fdo = sc->ndis_block->nmb_deviceobj; 1468 IoFreeWorkItem(sc->ndis_block->nmb_returnitem); 1469 IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); 1470 IoDeleteDevice(fdo); 1471 1472 return(0); 1473} 1474