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