kern_ndis.c revision 144888
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 144888 2005-04-11 02:02:35Z 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 79static void ndis_status_func(ndis_handle, ndis_status, void *, uint32_t); 80static void ndis_statusdone_func(ndis_handle); 81static void ndis_setdone_func(ndis_handle, ndis_status); 82static void ndis_getdone_func(ndis_handle, ndis_status); 83static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 84static void ndis_sendrsrcavail_func(ndis_handle); 85static void ndis_intrhand(kdpc *, device_object *, 86 irp *, struct ndis_softc *); 87 88static image_patch_table kernndis_functbl[] = { 89 IMPORT_SFUNC(ndis_status_func, 4), 90 IMPORT_SFUNC(ndis_statusdone_func, 1), 91 IMPORT_SFUNC(ndis_setdone_func, 2), 92 IMPORT_SFUNC(ndis_getdone_func, 2), 93 IMPORT_SFUNC(ndis_resetdone_func, 3), 94 IMPORT_SFUNC(ndis_sendrsrcavail_func, 1), 95 IMPORT_SFUNC(ndis_intrhand, 4), 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->ipt_argcnt, patch->ipt_ftype); 160 patch++; 161 } 162 163 ndis_create_kthreads(); 164 165 TAILQ_INIT(&ndis_devhead); 166 167 break; 168 case MOD_SHUTDOWN: 169 /* stop kthreads */ 170 ndis_destroy_kthreads(); 171 if (TAILQ_FIRST(&ndis_devhead) == NULL) { 172 /* Shut down subsystems */ 173 hal_libfini(); 174 ndis_libfini(); 175 ntoskrnl_libfini(); 176 usbd_libfini(); 177 windrv_libfini(); 178 179 patch = kernndis_functbl; 180 while (patch->ipt_func != NULL) { 181 windrv_unwrap(patch->ipt_wrap); 182 patch++; 183 } 184 } 185 break; 186 case MOD_UNLOAD: 187 /* stop kthreads */ 188 ndis_destroy_kthreads(); 189 190 /* Shut down subsystems */ 191 hal_libfini(); 192 ndis_libfini(); 193 ntoskrnl_libfini(); 194 usbd_libfini(); 195 windrv_libfini(); 196 197 patch = kernndis_functbl; 198 while (patch->ipt_func != NULL) { 199 windrv_unwrap(patch->ipt_wrap); 200 patch++; 201 } 202 203 break; 204 default: 205 error = EINVAL; 206 break; 207 } 208 209 return(error); 210} 211DEV_MODULE(ndisapi, ndis_modevent, NULL); 212MODULE_VERSION(ndisapi, 1); 213 214/* 215 * We create two kthreads for the NDIS subsystem. One of them is a task 216 * queue for performing various odd jobs. The other is an swi thread 217 * reserved exclusively for running interrupt handlers. The reason we 218 * have our own task queue is that there are some cases where we may 219 * need to sleep for a significant amount of time, and if we were to 220 * use one of the taskqueue threads, we might delay the processing 221 * of other pending tasks which might need to run right away. We have 222 * a separate swi thread because we don't want our interrupt handling 223 * to be delayed either. 224 * 225 * By default there are 32 jobs available to start, and another 8 226 * are added to the free list each time a new device is created. 227 */ 228 229static void 230ndis_runq(arg) 231 void *arg; 232{ 233 struct ndis_req *r = NULL, *die = NULL; 234 struct ndisproc *p; 235 236 p = arg; 237 238 while (1) { 239 240 /* Sleep, but preserve our original priority. */ 241 ndis_thsuspend(p->np_p, NULL, 0); 242 243 /* Look for any jobs on the work queue. */ 244 245 mtx_lock_spin(&ndis_thr_mtx); 246 p->np_state = NDIS_PSTATE_RUNNING; 247 while(STAILQ_FIRST(p->np_q) != NULL) { 248 r = STAILQ_FIRST(p->np_q); 249 STAILQ_REMOVE_HEAD(p->np_q, link); 250 mtx_unlock_spin(&ndis_thr_mtx); 251 252 /* Do the work. */ 253 254 if (r->nr_func != NULL) 255 (*r->nr_func)(r->nr_arg); 256 257 mtx_lock_spin(&ndis_thr_mtx); 258 STAILQ_INSERT_HEAD(&ndis_free, r, link); 259 260 /* Check for a shutdown request */ 261 262 if (r->nr_exit == TRUE) 263 die = r; 264 } 265 p->np_state = NDIS_PSTATE_SLEEPING; 266 mtx_unlock_spin(&ndis_thr_mtx); 267 268 /* Bail if we were told to shut down. */ 269 270 if (die != NULL) 271 break; 272 } 273 274 wakeup(die); 275#if __FreeBSD_version < 502113 276 mtx_lock(&Giant); 277#endif 278 kthread_exit(0); 279 return; /* notreached */ 280} 281 282static int 283ndis_create_kthreads() 284{ 285 struct ndis_req *r; 286 int i, error = 0; 287 288 mtx_init(&ndis_thr_mtx, "NDIS thread lock", NULL, MTX_SPIN); 289 mtx_init(&ndis_req_mtx, "NDIS request lock", MTX_NDIS_LOCK, MTX_DEF); 290 291 STAILQ_INIT(&ndis_ttodo); 292 STAILQ_INIT(&ndis_itodo); 293 STAILQ_INIT(&ndis_free); 294 295 for (i = 0; i < ndis_jobs; i++) { 296 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 297 if (r == NULL) { 298 error = ENOMEM; 299 break; 300 } 301 STAILQ_INSERT_HEAD(&ndis_free, r, link); 302 } 303 304 if (error == 0) { 305 ndis_tproc.np_q = &ndis_ttodo; 306 ndis_tproc.np_state = NDIS_PSTATE_SLEEPING; 307 error = kthread_create(ndis_runq, &ndis_tproc, 308 &ndis_tproc.np_p, RFHIGHPID, 309 NDIS_KSTACK_PAGES, "ndis taskqueue"); 310 } 311 312 if (error == 0) { 313 ndis_iproc.np_q = &ndis_itodo; 314 ndis_iproc.np_state = NDIS_PSTATE_SLEEPING; 315 error = kthread_create(ndis_runq, &ndis_iproc, 316 &ndis_iproc.np_p, RFHIGHPID, 317 NDIS_KSTACK_PAGES, "ndis swi"); 318 } 319 320 if (error) { 321 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 322 STAILQ_REMOVE_HEAD(&ndis_free, link); 323 free(r, M_DEVBUF); 324 } 325 return(error); 326 } 327 328 return(0); 329} 330 331static void 332ndis_destroy_kthreads() 333{ 334 struct ndis_req *r; 335 336 /* Stop the threads. */ 337 338 ndis_stop_thread(NDIS_TASKQUEUE); 339 ndis_stop_thread(NDIS_SWI); 340 341 /* Destroy request structures. */ 342 343 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 344 STAILQ_REMOVE_HEAD(&ndis_free, link); 345 free(r, M_DEVBUF); 346 } 347 348 mtx_destroy(&ndis_req_mtx); 349 mtx_destroy(&ndis_thr_mtx); 350 351 return; 352} 353 354static void 355ndis_stop_thread(t) 356 int t; 357{ 358 struct ndis_req *r; 359 struct ndisqhead *q; 360 struct proc *p; 361 362 if (t == NDIS_TASKQUEUE) { 363 q = &ndis_ttodo; 364 p = ndis_tproc.np_p; 365 } else { 366 q = &ndis_itodo; 367 p = ndis_iproc.np_p; 368 } 369 370 /* Create and post a special 'exit' job. */ 371 372 mtx_lock_spin(&ndis_thr_mtx); 373 r = STAILQ_FIRST(&ndis_free); 374 STAILQ_REMOVE_HEAD(&ndis_free, link); 375 r->nr_func = NULL; 376 r->nr_arg = NULL; 377 r->nr_exit = TRUE; 378 STAILQ_INSERT_TAIL(q, r, link); 379 mtx_unlock_spin(&ndis_thr_mtx); 380 381 ndis_thresume(p); 382 383 /* wait for thread exit */ 384 385 tsleep(r, curthread->td_priority|PCATCH, "ndisthexit", hz * 60); 386 387 /* Now empty the job list. */ 388 389 mtx_lock_spin(&ndis_thr_mtx); 390 while ((r = STAILQ_FIRST(q)) != NULL) { 391 STAILQ_REMOVE_HEAD(q, link); 392 STAILQ_INSERT_HEAD(&ndis_free, r, link); 393 } 394 mtx_unlock_spin(&ndis_thr_mtx); 395 396 return; 397} 398 399static int 400ndis_enlarge_thrqueue(cnt) 401 int cnt; 402{ 403 struct ndis_req *r; 404 int i; 405 406 for (i = 0; i < cnt; i++) { 407 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 408 if (r == NULL) 409 return(ENOMEM); 410 mtx_lock_spin(&ndis_thr_mtx); 411 STAILQ_INSERT_HEAD(&ndis_free, r, link); 412 ndis_jobs++; 413 mtx_unlock_spin(&ndis_thr_mtx); 414 } 415 416 return(0); 417} 418 419static int 420ndis_shrink_thrqueue(cnt) 421 int cnt; 422{ 423 struct ndis_req *r; 424 int i; 425 426 for (i = 0; i < cnt; i++) { 427 mtx_lock_spin(&ndis_thr_mtx); 428 r = STAILQ_FIRST(&ndis_free); 429 if (r == NULL) { 430 mtx_unlock_spin(&ndis_thr_mtx); 431 return(ENOMEM); 432 } 433 STAILQ_REMOVE_HEAD(&ndis_free, link); 434 ndis_jobs--; 435 mtx_unlock_spin(&ndis_thr_mtx); 436 free(r, M_DEVBUF); 437 } 438 439 return(0); 440} 441 442int 443ndis_unsched(func, arg, t) 444 void (*func)(void *); 445 void *arg; 446 int t; 447{ 448 struct ndis_req *r; 449 struct ndisqhead *q; 450 struct proc *p; 451 452 if (t == NDIS_TASKQUEUE) { 453 q = &ndis_ttodo; 454 p = ndis_tproc.np_p; 455 } else { 456 q = &ndis_itodo; 457 p = ndis_iproc.np_p; 458 } 459 460 mtx_lock_spin(&ndis_thr_mtx); 461 STAILQ_FOREACH(r, q, link) { 462 if (r->nr_func == func && r->nr_arg == arg) { 463 STAILQ_REMOVE(q, r, ndis_req, link); 464 STAILQ_INSERT_HEAD(&ndis_free, r, link); 465 mtx_unlock_spin(&ndis_thr_mtx); 466 return(0); 467 } 468 } 469 470 mtx_unlock_spin(&ndis_thr_mtx); 471 472 return(ENOENT); 473} 474 475int 476ndis_sched(func, arg, t) 477 void (*func)(void *); 478 void *arg; 479 int t; 480{ 481 struct ndis_req *r; 482 struct ndisqhead *q; 483 struct proc *p; 484 int s; 485 486 if (t == NDIS_TASKQUEUE) { 487 q = &ndis_ttodo; 488 p = ndis_tproc.np_p; 489 } else { 490 q = &ndis_itodo; 491 p = ndis_iproc.np_p; 492 } 493 494 mtx_lock_spin(&ndis_thr_mtx); 495 /* 496 * Check to see if an instance of this job is already 497 * pending. If so, don't bother queuing it again. 498 */ 499 STAILQ_FOREACH(r, q, link) { 500 if (r->nr_func == func && r->nr_arg == arg) { 501 mtx_unlock_spin(&ndis_thr_mtx); 502 return(0); 503 } 504 } 505 r = STAILQ_FIRST(&ndis_free); 506 if (r == NULL) { 507 mtx_unlock_spin(&ndis_thr_mtx); 508 return(EAGAIN); 509 } 510 STAILQ_REMOVE_HEAD(&ndis_free, link); 511 r->nr_func = func; 512 r->nr_arg = arg; 513 r->nr_exit = FALSE; 514 STAILQ_INSERT_TAIL(q, r, link); 515 if (t == NDIS_TASKQUEUE) 516 s = ndis_tproc.np_state; 517 else 518 s = ndis_iproc.np_state; 519 mtx_unlock_spin(&ndis_thr_mtx); 520 521 /* 522 * Post the job, but only if the thread is actually blocked 523 * on its own suspend call. If a driver queues up a job with 524 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(), 525 * it may suspend there, and in that case we don't want to wake 526 * it up until KeWaitForObject() gets woken up on its own. 527 */ 528 if (s == NDIS_PSTATE_SLEEPING) 529 ndis_thresume(p); 530 531 return(0); 532} 533 534int 535ndis_thsuspend(p, m, timo) 536 struct proc *p; 537 struct mtx *m; 538 int timo; 539{ 540 int error; 541 542 if (m != NULL) { 543 error = msleep(&p->p_siglist, m, 544 curthread->td_priority, "ndissp", timo); 545 } else { 546 PROC_LOCK(p); 547 error = msleep(&p->p_siglist, &p->p_mtx, 548 curthread->td_priority|PDROP, "ndissp", timo); 549 } 550 551 return(error); 552} 553 554void 555ndis_thresume(p) 556 struct proc *p; 557{ 558 wakeup(&p->p_siglist); 559 return; 560} 561 562static void 563ndis_sendrsrcavail_func(adapter) 564 ndis_handle adapter; 565{ 566 return; 567} 568 569static void 570ndis_status_func(adapter, status, sbuf, slen) 571 ndis_handle adapter; 572 ndis_status status; 573 void *sbuf; 574 uint32_t slen; 575{ 576 ndis_miniport_block *block; 577 struct ndis_softc *sc; 578 struct ifnet *ifp; 579 580 block = adapter; 581 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 582 ifp = &sc->arpcom.ac_if; 583 if (ifp->if_flags & IFF_DEBUG) 584 device_printf (sc->ndis_dev, "status: %x\n", status); 585 return; 586} 587 588static void 589ndis_statusdone_func(adapter) 590 ndis_handle adapter; 591{ 592 ndis_miniport_block *block; 593 struct ndis_softc *sc; 594 struct ifnet *ifp; 595 596 block = adapter; 597 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 598 ifp = &sc->arpcom.ac_if; 599 if (ifp->if_flags & IFF_DEBUG) 600 device_printf (sc->ndis_dev, "status complete\n"); 601 return; 602} 603 604static void 605ndis_setdone_func(adapter, status) 606 ndis_handle adapter; 607 ndis_status status; 608{ 609 ndis_miniport_block *block; 610 block = adapter; 611 612 block->nmb_setstat = status; 613 wakeup(&block->nmb_setstat); 614 return; 615} 616 617static void 618ndis_getdone_func(adapter, status) 619 ndis_handle adapter; 620 ndis_status status; 621{ 622 ndis_miniport_block *block; 623 block = adapter; 624 625 block->nmb_getstat = status; 626 wakeup(&block->nmb_getstat); 627 return; 628} 629 630static void 631ndis_resetdone_func(adapter, status, addressingreset) 632 ndis_handle adapter; 633 ndis_status status; 634 uint8_t addressingreset; 635{ 636 ndis_miniport_block *block; 637 struct ndis_softc *sc; 638 struct ifnet *ifp; 639 640 block = adapter; 641 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 642 ifp = &sc->arpcom.ac_if; 643 644 if (ifp->if_flags & IFF_DEBUG) 645 device_printf (sc->ndis_dev, "reset done...\n"); 646 wakeup(sc); 647 return; 648} 649 650int 651ndis_create_sysctls(arg) 652 void *arg; 653{ 654 struct ndis_softc *sc; 655 ndis_cfg *vals; 656 char buf[256]; 657 struct sysctl_oid *oidp; 658 struct sysctl_ctx_entry *e; 659 660 if (arg == NULL) 661 return(EINVAL); 662 663 sc = arg; 664 vals = sc->ndis_regvals; 665 666 TAILQ_INIT(&sc->ndis_cfglist_head); 667 668#if __FreeBSD_version < 502113 669 /* Create the sysctl tree. */ 670 671 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 672 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 673 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 674 device_get_desc(sc->ndis_dev)); 675 676#endif 677 /* Add the driver-specific registry keys. */ 678 679 vals = sc->ndis_regvals; 680 while(1) { 681 if (vals->nc_cfgkey == NULL) 682 break; 683 if (vals->nc_idx != sc->ndis_devidx) { 684 vals++; 685 continue; 686 } 687 688 /* See if we already have a sysctl with this name */ 689 690 oidp = NULL; 691#if __FreeBSD_version < 502113 692 TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 693#else 694 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 695#endif 696 oidp = e->entry; 697 if (ndis_strcasecmp(oidp->oid_name, 698 vals->nc_cfgkey) == 0) 699 break; 700 oidp = NULL; 701 } 702 703 if (oidp != NULL) { 704 vals++; 705 continue; 706 } 707 708#if __FreeBSD_version < 502113 709 SYSCTL_ADD_STRING(&sc->ndis_ctx, 710 SYSCTL_CHILDREN(sc->ndis_tree), 711#else 712 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 713 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 714#endif 715 OID_AUTO, vals->nc_cfgkey, 716 CTLFLAG_RW, vals->nc_val, 717 sizeof(vals->nc_val), 718 vals->nc_cfgdesc); 719 vals++; 720 } 721 722 /* Now add a couple of builtin keys. */ 723 724 /* 725 * Environment can be either Windows (0) or WindowsNT (1). 726 * We qualify as the latter. 727 */ 728 ndis_add_sysctl(sc, "Environment", 729 "Windows environment", "1", CTLFLAG_RD); 730 731 /* NDIS version should be 5.1. */ 732 ndis_add_sysctl(sc, "NdisVersion", 733 "NDIS API Version", "0x00050001", CTLFLAG_RD); 734 735 /* Bus type (PCI, PCMCIA, etc...) */ 736 sprintf(buf, "%d", (int)sc->ndis_iftype); 737 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 738 739 if (sc->ndis_res_io != NULL) { 740 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 741 ndis_add_sysctl(sc, "IOBaseAddress", 742 "Base I/O Address", buf, CTLFLAG_RD); 743 } 744 745 if (sc->ndis_irq != NULL) { 746 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 747 ndis_add_sysctl(sc, "InterruptNumber", 748 "Interrupt Number", buf, CTLFLAG_RD); 749 } 750 751 return(0); 752} 753 754int 755ndis_add_sysctl(arg, key, desc, val, flag) 756 void *arg; 757 char *key; 758 char *desc; 759 char *val; 760 int flag; 761{ 762 struct ndis_softc *sc; 763 struct ndis_cfglist *cfg; 764 char descstr[256]; 765 766 sc = arg; 767 768 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 769 770 if (cfg == NULL) 771 return(ENOMEM); 772 773 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 774 if (desc == NULL) { 775 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 776 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 777 } else 778 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 779 strcpy(cfg->ndis_cfg.nc_val, val); 780 781 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 782 783#if __FreeBSD_version < 502113 784 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 785#else 786 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 787 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 788#endif 789 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 790 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 791 cfg->ndis_cfg.nc_cfgdesc); 792 793 return(0); 794} 795 796int 797ndis_flush_sysctls(arg) 798 void *arg; 799{ 800 struct ndis_softc *sc; 801 struct ndis_cfglist *cfg; 802 803 sc = arg; 804 805 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 806 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 807 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 808 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 809 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 810 free(cfg, M_DEVBUF); 811 } 812 813 return(0); 814} 815 816static void 817ndis_return(arg) 818 void *arg; 819{ 820 struct ndis_softc *sc; 821 ndis_return_handler returnfunc; 822 ndis_handle adapter; 823 ndis_packet *p; 824 uint8_t irql; 825 826 p = arg; 827 sc = p->np_softc; 828 adapter = sc->ndis_block->nmb_miniportadapterctx; 829 830 if (adapter == NULL) 831 return; 832 833 returnfunc = sc->ndis_chars->nmc_return_packet_func; 834 835 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 836 MSCALL2(returnfunc, adapter, p); 837 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 838 839 return; 840} 841 842void 843ndis_return_packet(buf, arg) 844 void *buf; /* not used */ 845 void *arg; 846{ 847 ndis_packet *p; 848 849 if (arg == NULL) 850 return; 851 852 p = arg; 853 854 /* Decrement refcount. */ 855 p->np_refcnt--; 856 857 /* Release packet when refcount hits zero, otherwise return. */ 858 if (p->np_refcnt) 859 return; 860 861 ndis_sched(ndis_return, p, NDIS_TASKQUEUE); 862 863 return; 864} 865 866void 867ndis_free_bufs(b0) 868 ndis_buffer *b0; 869{ 870 ndis_buffer *next; 871 872 if (b0 == NULL) 873 return; 874 875 while(b0 != NULL) { 876 next = b0->mdl_next; 877 IoFreeMdl(b0); 878 b0 = next; 879 } 880 881 return; 882} 883int in_reset = 0; 884void 885ndis_free_packet(p) 886 ndis_packet *p; 887{ 888 if (p == NULL) 889 return; 890 891 ndis_free_bufs(p->np_private.npp_head); 892 NdisFreePacket(p); 893 return; 894} 895 896int 897ndis_convert_res(arg) 898 void *arg; 899{ 900 struct ndis_softc *sc; 901 ndis_resource_list *rl = NULL; 902 cm_partial_resource_desc *prd = NULL; 903 ndis_miniport_block *block; 904 device_t dev; 905 struct resource_list *brl; 906 struct resource_list_entry *brle; 907#if __FreeBSD_version < 600022 908 struct resource_list brl_rev; 909 struct resource_list_entry *n; 910#endif 911 int error = 0; 912 913 sc = arg; 914 block = sc->ndis_block; 915 dev = sc->ndis_dev; 916 917#if __FreeBSD_version < 600022 918 SLIST_INIT(&brl_rev); 919#endif 920 921 rl = malloc(sizeof(ndis_resource_list) + 922 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 923 M_DEVBUF, M_NOWAIT|M_ZERO); 924 925 if (rl == NULL) 926 return(ENOMEM); 927 928 rl->cprl_version = 5; 929 rl->cprl_version = 1; 930 rl->cprl_count = sc->ndis_rescnt; 931 prd = rl->cprl_partial_descs; 932 933 brl = BUS_GET_RESOURCE_LIST(dev, dev); 934 935 if (brl != NULL) { 936 937#if __FreeBSD_version < 600022 938 /* 939 * We have a small problem. Some PCI devices have 940 * multiple I/O ranges. Windows orders them starting 941 * from lowest numbered BAR to highest. We discover 942 * them in that order too, but insert them into a singly 943 * linked list head first, which means when time comes 944 * to traverse the list, we enumerate them in reverse 945 * order. This screws up some drivers which expect the 946 * BARs to be in ascending order so that they can choose 947 * the "first" one as their register space. Unfortunately, 948 * in order to fix this, we have to create our own 949 * temporary list with the entries in reverse order. 950 */ 951 SLIST_FOREACH(brle, brl, link) { 952 n = malloc(sizeof(struct resource_list_entry), 953 M_TEMP, M_NOWAIT); 954 if (n == NULL) { 955 error = ENOMEM; 956 goto bad; 957 } 958 bcopy((char *)brle, (char *)n, 959 sizeof(struct resource_list_entry)); 960 SLIST_INSERT_HEAD(&brl_rev, n, link); 961 } 962 963 SLIST_FOREACH(brle, &brl_rev, link) { 964#else 965 STAILQ_FOREACH(brle, brl, link) { 966#endif 967 switch (brle->type) { 968 case SYS_RES_IOPORT: 969 prd->cprd_type = CmResourceTypePort; 970 prd->cprd_flags = CM_RESOURCE_PORT_IO; 971 prd->cprd_sharedisp = 972 CmResourceShareDeviceExclusive; 973 prd->u.cprd_port.cprd_start.np_quad = 974 brle->start; 975 prd->u.cprd_port.cprd_len = brle->count; 976 break; 977 case SYS_RES_MEMORY: 978 prd->cprd_type = CmResourceTypeMemory; 979 prd->cprd_flags = 980 CM_RESOURCE_MEMORY_READ_WRITE; 981 prd->cprd_sharedisp = 982 CmResourceShareDeviceExclusive; 983 prd->u.cprd_port.cprd_start.np_quad = 984 brle->start; 985 prd->u.cprd_port.cprd_len = brle->count; 986 break; 987 case SYS_RES_IRQ: 988 prd->cprd_type = CmResourceTypeInterrupt; 989 prd->cprd_flags = 0; 990 prd->cprd_sharedisp = 991 CmResourceShareDeviceExclusive; 992 prd->u.cprd_intr.cprd_level = brle->start; 993 prd->u.cprd_intr.cprd_vector = brle->start; 994 prd->u.cprd_intr.cprd_affinity = 0; 995 break; 996 default: 997 break; 998 } 999 prd++; 1000 } 1001 } 1002 1003 block->nmb_rlist = rl; 1004 1005#if __FreeBSD_version < 600022 1006bad: 1007 1008 while (!SLIST_EMPTY(&brl_rev)) { 1009 n = SLIST_FIRST(&brl_rev); 1010 SLIST_REMOVE_HEAD(&brl_rev, link); 1011 free (n, M_TEMP); 1012 } 1013#endif 1014 1015 return(error); 1016} 1017 1018/* 1019 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 1020 * packet, it will hand it to us in the form of an ndis_packet, 1021 * which we need to convert to an mbuf that is then handed off 1022 * to the stack. Note: we configure the mbuf list so that it uses 1023 * the memory regions specified by the ndis_buffer structures in 1024 * the ndis_packet as external storage. In most cases, this will 1025 * point to a memory region allocated by the driver (either by 1026 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 1027 * the driver to handle free()ing this region for is, so we set up 1028 * a dummy no-op free handler for it. 1029 */ 1030 1031int 1032ndis_ptom(m0, p) 1033 struct mbuf **m0; 1034 ndis_packet *p; 1035{ 1036 struct mbuf *m, *prev = NULL; 1037 ndis_buffer *buf; 1038 ndis_packet_private *priv; 1039 uint32_t totlen = 0; 1040 1041 if (p == NULL || m0 == NULL) 1042 return(EINVAL); 1043 1044 priv = &p->np_private; 1045 buf = priv->npp_head; 1046 p->np_refcnt = 0; 1047 1048 for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { 1049 if (buf == priv->npp_head) 1050 MGETHDR(m, M_DONTWAIT, MT_HEADER); 1051 else 1052 MGET(m, M_DONTWAIT, MT_DATA); 1053 if (m == NULL) { 1054 m_freem(*m0); 1055 *m0 = NULL; 1056 return(ENOBUFS); 1057 } 1058 m->m_len = MmGetMdlByteCount(buf); 1059 m->m_data = MmGetMdlVirtualAddress(buf); 1060 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 1061 p, 0, EXT_NDIS); 1062 p->np_refcnt++; 1063 totlen += m->m_len; 1064 if (m->m_flags & MT_HEADER) 1065 *m0 = m; 1066 else 1067 prev->m_next = m; 1068 prev = m; 1069 } 1070 1071 (*m0)->m_pkthdr.len = totlen; 1072 1073 return(0); 1074} 1075 1076/* 1077 * Create an NDIS packet from an mbuf chain. 1078 * This is used mainly when transmitting packets, where we need 1079 * to turn an mbuf off an interface's send queue and transform it 1080 * into an NDIS packet which will be fed into the NDIS driver's 1081 * send routine. 1082 * 1083 * NDIS packets consist of two parts: an ndis_packet structure, 1084 * which is vaguely analagous to the pkthdr portion of an mbuf, 1085 * and one or more ndis_buffer structures, which define the 1086 * actual memory segments in which the packet data resides. 1087 * We need to allocate one ndis_buffer for each mbuf in a chain, 1088 * plus one ndis_packet as the header. 1089 */ 1090 1091int 1092ndis_mtop(m0, p) 1093 struct mbuf *m0; 1094 ndis_packet **p; 1095{ 1096 struct mbuf *m; 1097 ndis_buffer *buf = NULL, *prev = NULL; 1098 ndis_packet_private *priv; 1099 1100 if (p == NULL || *p == NULL || m0 == NULL) 1101 return(EINVAL); 1102 1103 priv = &(*p)->np_private; 1104 priv->npp_totlen = m0->m_pkthdr.len; 1105 1106 for (m = m0; m != NULL; m = m->m_next) { 1107 if (m->m_len == 0) 1108 continue; 1109 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); 1110 if (buf == NULL) { 1111 ndis_free_packet(*p); 1112 *p = NULL; 1113 return(ENOMEM); 1114 } 1115 1116 if (priv->npp_head == NULL) 1117 priv->npp_head = buf; 1118 else 1119 prev->mdl_next = buf; 1120 prev = buf; 1121 } 1122 1123 priv->npp_tail = buf; 1124 1125 return(0); 1126} 1127 1128int 1129ndis_get_supported_oids(arg, oids, oidcnt) 1130 void *arg; 1131 ndis_oid **oids; 1132 int *oidcnt; 1133{ 1134 int len, rval; 1135 ndis_oid *o; 1136 1137 if (arg == NULL || oids == NULL || oidcnt == NULL) 1138 return(EINVAL); 1139 len = 0; 1140 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 1141 1142 o = malloc(len, M_DEVBUF, M_NOWAIT); 1143 if (o == NULL) 1144 return(ENOMEM); 1145 1146 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 1147 1148 if (rval) { 1149 free(o, M_DEVBUF); 1150 return(rval); 1151 } 1152 1153 *oids = o; 1154 *oidcnt = len / 4; 1155 1156 return(0); 1157} 1158 1159int 1160ndis_set_info(arg, oid, buf, buflen) 1161 void *arg; 1162 ndis_oid oid; 1163 void *buf; 1164 int *buflen; 1165{ 1166 struct ndis_softc *sc; 1167 ndis_status rval; 1168 ndis_handle adapter; 1169 ndis_setinfo_handler setfunc; 1170 uint32_t byteswritten = 0, bytesneeded = 0; 1171 int error; 1172 uint8_t irql; 1173 1174 /* 1175 * According to the NDIS spec, MiniportQueryInformation() 1176 * and MiniportSetInformation() requests are handled serially: 1177 * once one request has been issued, we must wait for it to 1178 * finish before allowing another request to proceed. 1179 */ 1180 1181 sc = arg; 1182 1183 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1184 1185 if (sc->ndis_block->nmb_pendingreq != NULL) 1186 panic("ndis_set_info() called while other request pending"); 1187 else 1188 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 1189 1190 setfunc = sc->ndis_chars->nmc_setinfo_func; 1191 adapter = sc->ndis_block->nmb_miniportadapterctx; 1192 1193 if (adapter == NULL || setfunc == NULL) { 1194 sc->ndis_block->nmb_pendingreq = 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 ndis_sendmulti_handler sendfunc; 1248 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 ndis_sendsingle_handler sendfunc; 1293 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 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 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 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 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 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 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 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 MSCALL3(isrfunc, &accepted, &queue, adapter); 1580 1581 *ourintr = accepted; 1582 *callhandler = queue; 1583 1584 return(0); 1585} 1586 1587static void 1588ndis_intrhand(dpc, dobj, ip, sc) 1589 kdpc *dpc; 1590 device_object *dobj; 1591 irp *ip; 1592 struct ndis_softc *sc; 1593{ 1594 ndis_handle adapter; 1595 ndis_interrupt_handler intrfunc; 1596 uint8_t irql; 1597 1598 adapter = sc->ndis_block->nmb_miniportadapterctx; 1599 intrfunc = sc->ndis_chars->nmc_interrupt_func; 1600 1601 if (adapter == NULL || intrfunc == NULL) 1602 return; 1603 1604 if (NDIS_SERIALIZED(sc->ndis_block)) 1605 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1606 1607 MSCALL1(intrfunc, adapter); 1608 1609 /* If there's a MiniportEnableInterrupt() routine, call it. */ 1610 1611 ndis_enable_intr(sc); 1612 1613 if (NDIS_SERIALIZED(sc->ndis_block)) 1614 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1615 1616 return; 1617} 1618 1619int 1620ndis_get_info(arg, oid, buf, buflen) 1621 void *arg; 1622 ndis_oid oid; 1623 void *buf; 1624 int *buflen; 1625{ 1626 struct ndis_softc *sc; 1627 ndis_status rval; 1628 ndis_handle adapter; 1629 ndis_queryinfo_handler queryfunc; 1630 uint32_t byteswritten = 0, bytesneeded = 0; 1631 int error; 1632 uint8_t irql; 1633 1634 sc = arg; 1635 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1636 1637 if (sc->ndis_block->nmb_pendingreq != NULL) 1638 panic("ndis_get_info() called while other request pending"); 1639 else 1640 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 1641 1642 queryfunc = sc->ndis_chars->nmc_queryinfo_func; 1643 adapter = sc->ndis_block->nmb_miniportadapterctx; 1644 1645 if (adapter == NULL || queryfunc == NULL) { 1646 sc->ndis_block->nmb_pendingreq = NULL; 1647 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1648 return(ENXIO); 1649 } 1650 1651 rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, 1652 &byteswritten, &bytesneeded); 1653 1654 sc->ndis_block->nmb_pendingreq = NULL; 1655 1656 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1657 1658 /* Wait for requests that block. */ 1659 1660 if (rval == NDIS_STATUS_PENDING) { 1661 mtx_lock(&ndis_req_mtx); 1662 error = msleep(&sc->ndis_block->nmb_getstat, 1663 &ndis_req_mtx, 1664 curthread->td_priority|PDROP, 1665 "ndisget", 5 * hz); 1666 rval = sc->ndis_block->nmb_getstat; 1667 } 1668 1669 if (byteswritten) 1670 *buflen = byteswritten; 1671 if (bytesneeded) 1672 *buflen = bytesneeded; 1673 1674 if (rval == NDIS_STATUS_INVALID_LENGTH || 1675 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1676 return(ENOSPC); 1677 1678 if (rval == NDIS_STATUS_INVALID_OID) 1679 return(EINVAL); 1680 1681 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1682 rval == NDIS_STATUS_NOT_ACCEPTED) 1683 return(ENOTSUP); 1684 1685 if (rval != NDIS_STATUS_SUCCESS) 1686 return(ENODEV); 1687 1688 return(0); 1689} 1690 1691uint32_t 1692NdisAddDevice(drv, pdo) 1693 driver_object *drv; 1694 device_object *pdo; 1695{ 1696 device_object *fdo; 1697 ndis_miniport_block *block; 1698 struct ndis_softc *sc; 1699 uint32_t status; 1700 1701 status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, 1702 FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); 1703 1704 if (status != STATUS_SUCCESS) 1705 return(status); 1706 1707 block = fdo->do_devext; 1708 block->nmb_deviceobj = fdo; 1709 block->nmb_physdeviceobj = pdo; 1710 block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); 1711 KeInitializeSpinLock(&block->nmb_lock); 1712 1713 /* 1714 * Stash pointers to the miniport block and miniport 1715 * characteristics info in the if_ndis softc so the 1716 * UNIX wrapper driver can get to them later. 1717 */ 1718 sc = device_get_softc(pdo->do_devext); 1719 sc->ndis_block = block; 1720 sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); 1721 1722 IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap); 1723 1724 /* Finish up BSD-specific setup. */ 1725 1726 block->nmb_signature = (void *)0xcafebabe; 1727 block->nmb_status_func = kernndis_functbl[0].ipt_wrap; 1728 block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; 1729 block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; 1730 block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; 1731 block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; 1732 block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; 1733 block->nmb_pendingreq = NULL; 1734 1735 ndis_enlarge_thrqueue(8); 1736 1737 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1738 1739 return (STATUS_SUCCESS); 1740} 1741 1742int 1743ndis_unload_driver(arg) 1744 void *arg; 1745{ 1746 struct ndis_softc *sc; 1747 device_object *fdo; 1748 1749 sc = arg; 1750 1751 if (sc->ndis_block->nmb_rlist != NULL) 1752 free(sc->ndis_block->nmb_rlist, M_DEVBUF); 1753 1754 ndis_flush_sysctls(sc); 1755 1756 ndis_shrink_thrqueue(8); 1757 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1758 1759 fdo = sc->ndis_block->nmb_deviceobj; 1760 IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); 1761 IoDeleteDevice(fdo); 1762 1763 return(0); 1764} 1765