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