kern_ndis.c revision 142530
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 142530 2005-02-26 00:22:16Z 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 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(&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(&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(&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(&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", 286 MTX_NDIS_LOCK, MTX_DEF); 287 mtx_init(&ndis_req_mtx, "NDIS request lock", 288 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(&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(&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(&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(&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(&ndis_thr_mtx); 410 STAILQ_INSERT_HEAD(&ndis_free, r, link); 411 ndis_jobs++; 412 mtx_unlock(&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(&ndis_thr_mtx); 427 r = STAILQ_FIRST(&ndis_free); 428 if (r == NULL) { 429 mtx_unlock(&ndis_thr_mtx); 430 return(ENOMEM); 431 } 432 STAILQ_REMOVE_HEAD(&ndis_free, link); 433 ndis_jobs--; 434 mtx_unlock(&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(&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(&ndis_thr_mtx); 465 return(0); 466 } 467 } 468 469 mtx_unlock(&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(&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(&ndis_thr_mtx); 501 return(0); 502 } 503 } 504 r = STAILQ_FIRST(&ndis_free); 505 if (r == NULL) { 506 mtx_unlock(&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(&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, timo) 535 struct proc *p; 536 int timo; 537{ 538 int error; 539 540 PROC_LOCK(p); 541 error = msleep(&p->p_siglist, &p->p_mtx, 542 curthread->td_priority|PDROP, "ndissp", timo); 543 return(error); 544} 545 546void 547ndis_thresume(p) 548 struct proc *p; 549{ 550 wakeup(&p->p_siglist); 551 return; 552} 553 554__stdcall static void 555ndis_sendrsrcavail_func(adapter) 556 ndis_handle adapter; 557{ 558 return; 559} 560 561__stdcall static void 562ndis_status_func(adapter, status, sbuf, slen) 563 ndis_handle adapter; 564 ndis_status status; 565 void *sbuf; 566 uint32_t slen; 567{ 568 ndis_miniport_block *block; 569 struct ndis_softc *sc; 570 struct ifnet *ifp; 571 572 block = adapter; 573 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 574 ifp = &sc->arpcom.ac_if; 575 if (ifp->if_flags & IFF_DEBUG) 576 device_printf (sc->ndis_dev, "status: %x\n", status); 577 return; 578} 579 580__stdcall static void 581ndis_statusdone_func(adapter) 582 ndis_handle adapter; 583{ 584 ndis_miniport_block *block; 585 struct ndis_softc *sc; 586 struct ifnet *ifp; 587 588 block = adapter; 589 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 590 ifp = &sc->arpcom.ac_if; 591 if (ifp->if_flags & IFF_DEBUG) 592 device_printf (sc->ndis_dev, "status complete\n"); 593 return; 594} 595 596__stdcall static void 597ndis_setdone_func(adapter, status) 598 ndis_handle adapter; 599 ndis_status status; 600{ 601 ndis_miniport_block *block; 602 block = adapter; 603 604 block->nmb_setstat = status; 605 wakeup(&block->nmb_setstat); 606 return; 607} 608 609__stdcall static void 610ndis_getdone_func(adapter, status) 611 ndis_handle adapter; 612 ndis_status status; 613{ 614 ndis_miniport_block *block; 615 block = adapter; 616 617 block->nmb_getstat = status; 618 wakeup(&block->nmb_getstat); 619 return; 620} 621 622__stdcall static void 623ndis_resetdone_func(adapter, status, addressingreset) 624 ndis_handle adapter; 625 ndis_status status; 626 uint8_t addressingreset; 627{ 628 ndis_miniport_block *block; 629 struct ndis_softc *sc; 630 struct ifnet *ifp; 631 632 block = adapter; 633 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 634 ifp = &sc->arpcom.ac_if; 635 636 if (ifp->if_flags & IFF_DEBUG) 637 device_printf (sc->ndis_dev, "reset done...\n"); 638 wakeup(ifp); 639 return; 640} 641 642int 643ndis_create_sysctls(arg) 644 void *arg; 645{ 646 struct ndis_softc *sc; 647 ndis_cfg *vals; 648 char buf[256]; 649 struct sysctl_oid *oidp; 650 struct sysctl_ctx_entry *e; 651 652 if (arg == NULL) 653 return(EINVAL); 654 655 sc = arg; 656 vals = sc->ndis_regvals; 657 658 TAILQ_INIT(&sc->ndis_cfglist_head); 659 660#if __FreeBSD_version < 502113 661 /* Create the sysctl tree. */ 662 663 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 664 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 665 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 666 device_get_desc(sc->ndis_dev)); 667 668#endif 669 /* Add the driver-specific registry keys. */ 670 671 vals = sc->ndis_regvals; 672 while(1) { 673 if (vals->nc_cfgkey == NULL) 674 break; 675 if (vals->nc_idx != sc->ndis_devidx) { 676 vals++; 677 continue; 678 } 679 680 /* See if we already have a sysctl with this name */ 681 682 oidp = NULL; 683#if __FreeBSD_version < 502113 684 TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 685#else 686 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 687#endif 688 oidp = e->entry; 689 if (ndis_strcasecmp(oidp->oid_name, 690 vals->nc_cfgkey) == 0) 691 break; 692 oidp = NULL; 693 } 694 695 if (oidp != NULL) { 696 vals++; 697 continue; 698 } 699 700#if __FreeBSD_version < 502113 701 SYSCTL_ADD_STRING(&sc->ndis_ctx, 702 SYSCTL_CHILDREN(sc->ndis_tree), 703#else 704 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 705 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 706#endif 707 OID_AUTO, vals->nc_cfgkey, 708 CTLFLAG_RW, vals->nc_val, 709 sizeof(vals->nc_val), 710 vals->nc_cfgdesc); 711 vals++; 712 } 713 714 /* Now add a couple of builtin keys. */ 715 716 /* 717 * Environment can be either Windows (0) or WindowsNT (1). 718 * We qualify as the latter. 719 */ 720 ndis_add_sysctl(sc, "Environment", 721 "Windows environment", "1", CTLFLAG_RD); 722 723 /* NDIS version should be 5.1. */ 724 ndis_add_sysctl(sc, "NdisVersion", 725 "NDIS API Version", "0x00050001", CTLFLAG_RD); 726 727 /* Bus type (PCI, PCMCIA, etc...) */ 728 sprintf(buf, "%d", (int)sc->ndis_iftype); 729 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 730 731 if (sc->ndis_res_io != NULL) { 732 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 733 ndis_add_sysctl(sc, "IOBaseAddress", 734 "Base I/O Address", buf, CTLFLAG_RD); 735 } 736 737 if (sc->ndis_irq != NULL) { 738 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 739 ndis_add_sysctl(sc, "InterruptNumber", 740 "Interrupt Number", buf, CTLFLAG_RD); 741 } 742 743 return(0); 744} 745 746int 747ndis_add_sysctl(arg, key, desc, val, flag) 748 void *arg; 749 char *key; 750 char *desc; 751 char *val; 752 int flag; 753{ 754 struct ndis_softc *sc; 755 struct ndis_cfglist *cfg; 756 char descstr[256]; 757 758 sc = arg; 759 760 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 761 762 if (cfg == NULL) 763 return(ENOMEM); 764 765 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 766 if (desc == NULL) { 767 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 768 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 769 } else 770 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 771 strcpy(cfg->ndis_cfg.nc_val, val); 772 773 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 774 775#if __FreeBSD_version < 502113 776 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 777#else 778 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 779 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 780#endif 781 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 782 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 783 cfg->ndis_cfg.nc_cfgdesc); 784 785 return(0); 786} 787 788int 789ndis_flush_sysctls(arg) 790 void *arg; 791{ 792 struct ndis_softc *sc; 793 struct ndis_cfglist *cfg; 794 795 sc = arg; 796 797 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 798 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 799 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 800 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 801 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 802 free(cfg, M_DEVBUF); 803 } 804 805 return(0); 806} 807 808static void 809ndis_return(arg) 810 void *arg; 811{ 812 struct ndis_softc *sc; 813 __stdcall ndis_return_handler returnfunc; 814 ndis_handle adapter; 815 ndis_packet *p; 816 uint8_t irql; 817 818 p = arg; 819 sc = p->np_softc; 820 adapter = sc->ndis_block->nmb_miniportadapterctx; 821 822 if (adapter == NULL) 823 return; 824 825 returnfunc = sc->ndis_chars->nmc_return_packet_func; 826 irql = KeRaiseIrql(DISPATCH_LEVEL); 827 MSCALL2(returnfunc, adapter, p); 828 KeLowerIrql(irql); 829 830 return; 831} 832 833void 834ndis_return_packet(buf, arg) 835 void *buf; /* not used */ 836 void *arg; 837{ 838 ndis_packet *p; 839 840 if (arg == NULL) 841 return; 842 843 p = arg; 844 845 /* Decrement refcount. */ 846 p->np_refcnt--; 847 848 /* Release packet when refcount hits zero, otherwise return. */ 849 if (p->np_refcnt) 850 return; 851 852 ndis_sched(ndis_return, p, NDIS_SWI); 853 854 return; 855} 856 857void 858ndis_free_bufs(b0) 859 ndis_buffer *b0; 860{ 861 ndis_buffer *next; 862 863 if (b0 == NULL) 864 return; 865 866 while(b0 != NULL) { 867 next = b0->mdl_next; 868 IoFreeMdl(b0); 869 b0 = next; 870 } 871 872 return; 873} 874 875void 876ndis_free_packet(p) 877 ndis_packet *p; 878{ 879 if (p == NULL) 880 return; 881 882 ndis_free_bufs(p->np_private.npp_head); 883 NdisFreePacket(p); 884 885 return; 886} 887 888int 889ndis_convert_res(arg) 890 void *arg; 891{ 892 struct ndis_softc *sc; 893 ndis_resource_list *rl = NULL; 894 cm_partial_resource_desc *prd = NULL; 895 ndis_miniport_block *block; 896 device_t dev; 897 struct resource_list *brl; 898 struct resource_list brl_rev; 899 struct resource_list_entry *brle, *n; 900 int error = 0; 901 902 sc = arg; 903 block = sc->ndis_block; 904 dev = sc->ndis_dev; 905 906 SLIST_INIT(&brl_rev); 907 908 rl = malloc(sizeof(ndis_resource_list) + 909 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 910 M_DEVBUF, M_NOWAIT|M_ZERO); 911 912 if (rl == NULL) 913 return(ENOMEM); 914 915 rl->cprl_version = 5; 916 rl->cprl_version = 1; 917 rl->cprl_count = sc->ndis_rescnt; 918 prd = rl->cprl_partial_descs; 919 920 brl = BUS_GET_RESOURCE_LIST(dev, dev); 921 922 if (brl != NULL) { 923 924 /* 925 * We have a small problem. Some PCI devices have 926 * multiple I/O ranges. Windows orders them starting 927 * from lowest numbered BAR to highest. We discover 928 * them in that order too, but insert them into a singly 929 * linked list head first, which means when time comes 930 * to traverse the list, we enumerate them in reverse 931 * order. This screws up some drivers which expect the 932 * BARs to be in ascending order so that they can choose 933 * the "first" one as their register space. Unfortunately, 934 * in order to fix this, we have to create our own 935 * temporary list with the entries in reverse order. 936 */ 937 SLIST_FOREACH(brle, brl, link) { 938 n = malloc(sizeof(struct resource_list_entry), 939 M_TEMP, M_NOWAIT); 940 if (n == NULL) { 941 error = ENOMEM; 942 goto bad; 943 } 944 bcopy((char *)brle, (char *)n, 945 sizeof(struct resource_list_entry)); 946 SLIST_INSERT_HEAD(&brl_rev, n, link); 947 } 948 949 SLIST_FOREACH(brle, &brl_rev, link) { 950 switch (brle->type) { 951 case SYS_RES_IOPORT: 952 prd->cprd_type = CmResourceTypePort; 953 prd->cprd_flags = CM_RESOURCE_PORT_IO; 954 prd->cprd_sharedisp = 955 CmResourceShareDeviceExclusive; 956 prd->u.cprd_port.cprd_start.np_quad = 957 brle->start; 958 prd->u.cprd_port.cprd_len = brle->count; 959 break; 960 case SYS_RES_MEMORY: 961 prd->cprd_type = CmResourceTypeMemory; 962 prd->cprd_flags = 963 CM_RESOURCE_MEMORY_READ_WRITE; 964 prd->cprd_sharedisp = 965 CmResourceShareDeviceExclusive; 966 prd->u.cprd_port.cprd_start.np_quad = 967 brle->start; 968 prd->u.cprd_port.cprd_len = brle->count; 969 break; 970 case SYS_RES_IRQ: 971 prd->cprd_type = CmResourceTypeInterrupt; 972 prd->cprd_flags = 0; 973 prd->cprd_sharedisp = 974 CmResourceShareDeviceExclusive; 975 prd->u.cprd_intr.cprd_level = brle->start; 976 prd->u.cprd_intr.cprd_vector = brle->start; 977 prd->u.cprd_intr.cprd_affinity = 0; 978 break; 979 default: 980 break; 981 } 982 prd++; 983 } 984 } 985 986 block->nmb_rlist = rl; 987 988bad: 989 990 while (!SLIST_EMPTY(&brl_rev)) { 991 n = SLIST_FIRST(&brl_rev); 992 SLIST_REMOVE_HEAD(&brl_rev, link); 993 free (n, M_TEMP); 994 } 995 996 return(error); 997} 998 999/* 1000 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 1001 * packet, it will hand it to us in the form of an ndis_packet, 1002 * which we need to convert to an mbuf that is then handed off 1003 * to the stack. Note: we configure the mbuf list so that it uses 1004 * the memory regions specified by the ndis_buffer structures in 1005 * the ndis_packet as external storage. In most cases, this will 1006 * point to a memory region allocated by the driver (either by 1007 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 1008 * the driver to handle free()ing this region for is, so we set up 1009 * a dummy no-op free handler for it. 1010 */ 1011 1012int 1013ndis_ptom(m0, p) 1014 struct mbuf **m0; 1015 ndis_packet *p; 1016{ 1017 struct mbuf *m, *prev = NULL; 1018 ndis_buffer *buf; 1019 ndis_packet_private *priv; 1020 uint32_t totlen = 0; 1021 1022 if (p == NULL || m0 == NULL) 1023 return(EINVAL); 1024 1025 priv = &p->np_private; 1026 buf = priv->npp_head; 1027 p->np_refcnt = 0; 1028 1029 for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { 1030 if (buf == priv->npp_head) 1031 MGETHDR(m, M_DONTWAIT, MT_HEADER); 1032 else 1033 MGET(m, M_DONTWAIT, MT_DATA); 1034 if (m == NULL) { 1035 m_freem(*m0); 1036 *m0 = NULL; 1037 return(ENOBUFS); 1038 } 1039 m->m_len = MmGetMdlByteCount(buf); 1040 m->m_data = MmGetMdlVirtualAddress(buf); 1041 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 1042 p, 0, EXT_NDIS); 1043 p->np_refcnt++; 1044 totlen += m->m_len; 1045 if (m->m_flags & MT_HEADER) 1046 *m0 = m; 1047 else 1048 prev->m_next = m; 1049 prev = m; 1050 } 1051 1052 (*m0)->m_pkthdr.len = totlen; 1053 1054 return(0); 1055} 1056 1057/* 1058 * Create an mbuf chain from an NDIS packet chain. 1059 * This is used mainly when transmitting packets, where we need 1060 * to turn an mbuf off an interface's send queue and transform it 1061 * into an NDIS packet which will be fed into the NDIS driver's 1062 * send routine. 1063 * 1064 * NDIS packets consist of two parts: an ndis_packet structure, 1065 * which is vaguely analagous to the pkthdr portion of an mbuf, 1066 * and one or more ndis_buffer structures, which define the 1067 * actual memory segments in which the packet data resides. 1068 * We need to allocate one ndis_buffer for each mbuf in a chain, 1069 * plus one ndis_packet as the header. 1070 */ 1071 1072int 1073ndis_mtop(m0, p) 1074 struct mbuf *m0; 1075 ndis_packet **p; 1076{ 1077 struct mbuf *m; 1078 ndis_buffer *buf = NULL, *prev = NULL; 1079 ndis_packet_private *priv; 1080 1081 if (p == NULL || *p == NULL || m0 == NULL) 1082 return(EINVAL); 1083 1084 priv = &(*p)->np_private; 1085 priv->npp_totlen = m0->m_pkthdr.len; 1086 1087 for (m = m0; m != NULL; m = m->m_next) { 1088 if (m->m_len == 0) 1089 continue; 1090 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); 1091 if (buf == NULL) { 1092 ndis_free_packet(*p); 1093 *p = NULL; 1094 return(ENOMEM); 1095 } 1096 1097 MmInitializeMdl(buf, m->m_data, m->m_len); 1098 if (priv->npp_head == NULL) 1099 priv->npp_head = buf; 1100 else 1101 prev->mdl_next = buf; 1102 prev = buf; 1103 } 1104 1105 priv->npp_tail = buf; 1106 priv->npp_totlen = m0->m_pkthdr.len; 1107 1108 return(0); 1109} 1110 1111int 1112ndis_get_supported_oids(arg, oids, oidcnt) 1113 void *arg; 1114 ndis_oid **oids; 1115 int *oidcnt; 1116{ 1117 int len, rval; 1118 ndis_oid *o; 1119 1120 if (arg == NULL || oids == NULL || oidcnt == NULL) 1121 return(EINVAL); 1122 len = 0; 1123 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 1124 1125 o = malloc(len, M_DEVBUF, M_NOWAIT); 1126 if (o == NULL) 1127 return(ENOMEM); 1128 1129 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 1130 1131 if (rval) { 1132 free(o, M_DEVBUF); 1133 return(rval); 1134 } 1135 1136 *oids = o; 1137 *oidcnt = len / 4; 1138 1139 return(0); 1140} 1141 1142int 1143ndis_set_info(arg, oid, buf, buflen) 1144 void *arg; 1145 ndis_oid oid; 1146 void *buf; 1147 int *buflen; 1148{ 1149 struct ndis_softc *sc; 1150 ndis_status rval; 1151 ndis_handle adapter; 1152 __stdcall ndis_setinfo_handler setfunc; 1153 uint32_t byteswritten = 0, bytesneeded = 0; 1154 int error; 1155 uint8_t irql; 1156 1157 sc = arg; 1158 NDIS_LOCK(sc); 1159 setfunc = sc->ndis_chars->nmc_setinfo_func; 1160 adapter = sc->ndis_block->nmb_miniportadapterctx; 1161 NDIS_UNLOCK(sc); 1162 1163 if (adapter == NULL || setfunc == NULL) 1164 return(ENXIO); 1165 1166 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1167 rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, 1168 &byteswritten, &bytesneeded); 1169 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1170 1171 if (rval == NDIS_STATUS_PENDING) { 1172 mtx_lock(&ndis_req_mtx); 1173 error = msleep(&sc->ndis_block->nmb_setstat, 1174 &ndis_req_mtx, 1175 curthread->td_priority|PDROP, 1176 "ndisset", 5 * hz); 1177 rval = sc->ndis_block->nmb_setstat; 1178 } 1179 1180 if (byteswritten) 1181 *buflen = byteswritten; 1182 if (bytesneeded) 1183 *buflen = bytesneeded; 1184 1185 if (rval == NDIS_STATUS_INVALID_LENGTH) 1186 return(ENOSPC); 1187 1188 if (rval == NDIS_STATUS_INVALID_OID) 1189 return(EINVAL); 1190 1191 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1192 rval == NDIS_STATUS_NOT_ACCEPTED) 1193 return(ENOTSUP); 1194 1195 if (rval != NDIS_STATUS_SUCCESS) 1196 return(ENODEV); 1197 1198 return(0); 1199} 1200 1201typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 1202 1203int 1204ndis_send_packets(arg, packets, cnt) 1205 void *arg; 1206 ndis_packet **packets; 1207 int cnt; 1208{ 1209 struct ndis_softc *sc; 1210 ndis_handle adapter; 1211 __stdcall ndis_sendmulti_handler sendfunc; 1212 __stdcall ndis_senddone_func senddonefunc; 1213 int i; 1214 ndis_packet *p; 1215 uint8_t irql; 1216 1217 sc = arg; 1218 adapter = sc->ndis_block->nmb_miniportadapterctx; 1219 if (adapter == NULL) 1220 return(ENXIO); 1221 sendfunc = sc->ndis_chars->nmc_sendmulti_func; 1222 senddonefunc = sc->ndis_block->nmb_senddone_func; 1223 irql = KeRaiseIrql(DISPATCH_LEVEL); 1224 MSCALL3(sendfunc, adapter, packets, cnt); 1225 KeLowerIrql(irql); 1226 1227 for (i = 0; i < cnt; i++) { 1228 p = packets[i]; 1229 /* 1230 * Either the driver already handed the packet to 1231 * ndis_txeof() due to a failure, or it wants to keep 1232 * it and release it asynchronously later. Skip to the 1233 * next one. 1234 */ 1235 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 1236 continue; 1237 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); 1238 } 1239 1240 return(0); 1241} 1242 1243int 1244ndis_send_packet(arg, packet) 1245 void *arg; 1246 ndis_packet *packet; 1247{ 1248 struct ndis_softc *sc; 1249 ndis_handle adapter; 1250 ndis_status status; 1251 __stdcall ndis_sendsingle_handler sendfunc; 1252 __stdcall ndis_senddone_func senddonefunc; 1253 uint8_t irql; 1254 1255 sc = arg; 1256 adapter = sc->ndis_block->nmb_miniportadapterctx; 1257 if (adapter == NULL) 1258 return(ENXIO); 1259 sendfunc = sc->ndis_chars->nmc_sendsingle_func; 1260 senddonefunc = sc->ndis_block->nmb_senddone_func; 1261 1262 irql = KeRaiseIrql(DISPATCH_LEVEL); 1263 status = MSCALL3(sendfunc, adapter, packet, 1264 packet->np_private.npp_flags); 1265 KeLowerIrql(irql); 1266 1267 if (status == NDIS_STATUS_PENDING) 1268 return(0); 1269 1270 MSCALL3(senddonefunc, sc->ndis_block, packet, status); 1271 1272 return(0); 1273} 1274 1275int 1276ndis_init_dma(arg) 1277 void *arg; 1278{ 1279 struct ndis_softc *sc; 1280 int i, error; 1281 1282 sc = arg; 1283 1284 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1285 M_DEVBUF, M_NOWAIT|M_ZERO); 1286 1287 if (sc->ndis_tmaps == NULL) 1288 return(ENOMEM); 1289 1290 for (i = 0; i < sc->ndis_maxpkts; i++) { 1291 error = bus_dmamap_create(sc->ndis_ttag, 0, 1292 &sc->ndis_tmaps[i]); 1293 if (error) { 1294 free(sc->ndis_tmaps, M_DEVBUF); 1295 return(ENODEV); 1296 } 1297 } 1298 1299 return(0); 1300} 1301 1302int 1303ndis_destroy_dma(arg) 1304 void *arg; 1305{ 1306 struct ndis_softc *sc; 1307 struct mbuf *m; 1308 ndis_packet *p = NULL; 1309 int i; 1310 1311 sc = arg; 1312 1313 for (i = 0; i < sc->ndis_maxpkts; i++) { 1314 if (sc->ndis_txarray[i] != NULL) { 1315 p = sc->ndis_txarray[i]; 1316 m = (struct mbuf *)p->np_rsvd[1]; 1317 if (m != NULL) 1318 m_freem(m); 1319 ndis_free_packet(sc->ndis_txarray[i]); 1320 } 1321 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1322 } 1323 1324 free(sc->ndis_tmaps, M_DEVBUF); 1325 1326 bus_dma_tag_destroy(sc->ndis_ttag); 1327 1328 return(0); 1329} 1330 1331int 1332ndis_reset_nic(arg) 1333 void *arg; 1334{ 1335 struct ndis_softc *sc; 1336 ndis_handle adapter; 1337 __stdcall ndis_reset_handler resetfunc; 1338 uint8_t addressing_reset; 1339 struct ifnet *ifp; 1340 int rval; 1341 uint8_t irql; 1342 1343 sc = arg; 1344 ifp = &sc->arpcom.ac_if; 1345 NDIS_LOCK(sc); 1346 adapter = sc->ndis_block->nmb_miniportadapterctx; 1347 resetfunc = sc->ndis_chars->nmc_reset_func; 1348 NDIS_UNLOCK(sc); 1349 if (adapter == NULL || resetfunc == NULL) 1350 return(EIO); 1351 1352 irql = KeRaiseIrql(DISPATCH_LEVEL); 1353 rval = MSCALL2(resetfunc, &addressing_reset, adapter); 1354 KeLowerIrql(irql); 1355 1356 if (rval == NDIS_STATUS_PENDING) { 1357 mtx_lock(&ndis_req_mtx); 1358 msleep(sc, &ndis_req_mtx, 1359 curthread->td_priority|PDROP, "ndisrst", 0); 1360 } 1361 1362 return(0); 1363} 1364 1365int 1366ndis_halt_nic(arg) 1367 void *arg; 1368{ 1369 struct ndis_softc *sc; 1370 ndis_handle adapter; 1371 __stdcall ndis_halt_handler haltfunc; 1372 struct ifnet *ifp; 1373 1374 sc = arg; 1375 ifp = &sc->arpcom.ac_if; 1376 1377 NDIS_LOCK(sc); 1378 adapter = sc->ndis_block->nmb_miniportadapterctx; 1379 if (adapter == NULL) { 1380 NDIS_UNLOCK(sc); 1381 return(EIO); 1382 } 1383 1384 /* 1385 * The adapter context is only valid after the init 1386 * handler has been called, and is invalid once the 1387 * halt handler has been called. 1388 */ 1389 1390 haltfunc = sc->ndis_chars->nmc_halt_func; 1391 NDIS_UNLOCK(sc); 1392 1393 MSCALL1(haltfunc, adapter); 1394 1395 NDIS_LOCK(sc); 1396 sc->ndis_block->nmb_miniportadapterctx = NULL; 1397 NDIS_UNLOCK(sc); 1398 1399 return(0); 1400} 1401 1402int 1403ndis_shutdown_nic(arg) 1404 void *arg; 1405{ 1406 struct ndis_softc *sc; 1407 ndis_handle adapter; 1408 __stdcall ndis_shutdown_handler shutdownfunc; 1409 1410 sc = arg; 1411 NDIS_LOCK(sc); 1412 adapter = sc->ndis_block->nmb_miniportadapterctx; 1413 shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; 1414 NDIS_UNLOCK(sc); 1415 if (adapter == NULL || shutdownfunc == NULL) 1416 return(EIO); 1417 1418 if (sc->ndis_chars->nmc_rsvd0 == NULL) 1419 MSCALL1(shutdownfunc, adapter); 1420 else 1421 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0); 1422 1423 ndis_shrink_thrqueue(8); 1424 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1425 1426 return(0); 1427} 1428 1429int 1430ndis_init_nic(arg) 1431 void *arg; 1432{ 1433 struct ndis_softc *sc; 1434 ndis_miniport_block *block; 1435 __stdcall ndis_init_handler initfunc; 1436 ndis_status status, openstatus = 0; 1437 ndis_medium mediumarray[NdisMediumMax]; 1438 uint32_t chosenmedium, i; 1439 1440 if (arg == NULL) 1441 return(EINVAL); 1442 1443 sc = arg; 1444 NDIS_LOCK(sc); 1445 block = sc->ndis_block; 1446 initfunc = sc->ndis_chars->nmc_init_func; 1447 NDIS_UNLOCK(sc); 1448 1449 for (i = 0; i < NdisMediumMax; i++) 1450 mediumarray[i] = i; 1451 1452 status = MSCALL6(initfunc, &openstatus, &chosenmedium, 1453 mediumarray, NdisMediumMax, block, block); 1454 1455 /* 1456 * If the init fails, blow away the other exported routines 1457 * we obtained from the driver so we can't call them later. 1458 * If the init failed, none of these will work. 1459 */ 1460 if (status != NDIS_STATUS_SUCCESS) { 1461 NDIS_LOCK(sc); 1462 sc->ndis_block->nmb_miniportadapterctx = NULL; 1463 NDIS_UNLOCK(sc); 1464 return(ENXIO); 1465 } 1466 1467 return(0); 1468} 1469 1470void 1471ndis_enable_intr(arg) 1472 void *arg; 1473{ 1474 struct ndis_softc *sc; 1475 ndis_handle adapter; 1476 __stdcall ndis_enable_interrupts_handler intrenbfunc; 1477 1478 sc = arg; 1479 adapter = sc->ndis_block->nmb_miniportadapterctx; 1480 intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func; 1481 if (adapter == NULL || intrenbfunc == NULL) 1482 return; 1483 MSCALL1(intrenbfunc, adapter); 1484 1485 return; 1486} 1487 1488void 1489ndis_disable_intr(arg) 1490 void *arg; 1491{ 1492 struct ndis_softc *sc; 1493 ndis_handle adapter; 1494 __stdcall ndis_disable_interrupts_handler intrdisfunc; 1495 1496 sc = arg; 1497 adapter = sc->ndis_block->nmb_miniportadapterctx; 1498 intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func; 1499 if (adapter == NULL || intrdisfunc == NULL) 1500 return; 1501 MSCALL1(intrdisfunc, adapter); 1502 1503 return; 1504} 1505 1506int 1507ndis_isr(arg, ourintr, callhandler) 1508 void *arg; 1509 int *ourintr; 1510 int *callhandler; 1511{ 1512 struct ndis_softc *sc; 1513 ndis_handle adapter; 1514 __stdcall ndis_isr_handler isrfunc; 1515 uint8_t accepted, queue; 1516 1517 if (arg == NULL || ourintr == NULL || callhandler == NULL) 1518 return(EINVAL); 1519 1520 sc = arg; 1521 adapter = sc->ndis_block->nmb_miniportadapterctx; 1522 isrfunc = sc->ndis_chars->nmc_isr_func; 1523 if (adapter == NULL || isrfunc == NULL) 1524 return(ENXIO); 1525 1526 MSCALL3(isrfunc, &accepted, &queue, adapter); 1527 *ourintr = accepted; 1528 *callhandler = queue; 1529 1530 return(0); 1531} 1532 1533int 1534ndis_intrhand(arg) 1535 void *arg; 1536{ 1537 struct ndis_softc *sc; 1538 ndis_handle adapter; 1539 __stdcall ndis_interrupt_handler intrfunc; 1540 1541 if (arg == NULL) 1542 return(EINVAL); 1543 1544 sc = arg; 1545 NDIS_LOCK(sc); 1546 adapter = sc->ndis_block->nmb_miniportadapterctx; 1547 intrfunc = sc->ndis_chars->nmc_interrupt_func; 1548 NDIS_UNLOCK(sc); 1549 if (adapter == NULL || intrfunc == NULL) 1550 return(EINVAL); 1551 1552 MSCALL1(intrfunc, adapter); 1553 1554 return(0); 1555} 1556 1557int 1558ndis_get_info(arg, oid, buf, buflen) 1559 void *arg; 1560 ndis_oid oid; 1561 void *buf; 1562 int *buflen; 1563{ 1564 struct ndis_softc *sc; 1565 ndis_status rval; 1566 ndis_handle adapter; 1567 __stdcall ndis_queryinfo_handler queryfunc; 1568 uint32_t byteswritten = 0, bytesneeded = 0; 1569 int error; 1570 uint8_t irql; 1571 1572 sc = arg; 1573 NDIS_LOCK(sc); 1574 queryfunc = sc->ndis_chars->nmc_queryinfo_func; 1575 adapter = sc->ndis_block->nmb_miniportadapterctx; 1576 NDIS_UNLOCK(sc); 1577 1578 if (adapter == NULL || queryfunc == NULL) 1579 return(ENXIO); 1580 1581 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1582 rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, 1583 &byteswritten, &bytesneeded); 1584 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1585 1586 /* Wait for requests that block. */ 1587 1588 if (rval == NDIS_STATUS_PENDING) { 1589 mtx_lock(&ndis_req_mtx); 1590 error = msleep(&sc->ndis_block->nmb_getstat, 1591 &ndis_req_mtx, 1592 curthread->td_priority|PDROP, 1593 "ndisget", 5 * hz); 1594 rval = sc->ndis_block->nmb_getstat; 1595 } 1596 1597 if (byteswritten) 1598 *buflen = byteswritten; 1599 if (bytesneeded) 1600 *buflen = bytesneeded; 1601 1602 if (rval == NDIS_STATUS_INVALID_LENGTH || 1603 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1604 return(ENOSPC); 1605 1606 if (rval == NDIS_STATUS_INVALID_OID) 1607 return(EINVAL); 1608 1609 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1610 rval == NDIS_STATUS_NOT_ACCEPTED) 1611 return(ENOTSUP); 1612 1613 if (rval != NDIS_STATUS_SUCCESS) 1614 return(ENODEV); 1615 1616 return(0); 1617} 1618 1619__stdcall uint32_t 1620NdisAddDevice(drv, pdo) 1621 driver_object *drv; 1622 device_object *pdo; 1623{ 1624 device_object *fdo; 1625 ndis_miniport_block *block; 1626 struct ndis_softc *sc; 1627 uint32_t status; 1628 1629 status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, 1630 FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); 1631 1632 if (status != STATUS_SUCCESS) 1633 return(status); 1634 1635 block = fdo->do_devext; 1636 block->nmb_deviceobj = fdo; 1637 block->nmb_physdeviceobj = pdo; 1638 block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); 1639 KeInitializeSpinLock(&block->nmb_lock); 1640 1641 /* 1642 * Stash pointers to the miniport block and miniport 1643 * characteristics info in the if_ndis softc so the 1644 * UNIX wrapper driver can get to them later. 1645 */ 1646 sc = device_get_softc(pdo->do_devext); 1647 sc->ndis_block = block; 1648 sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); 1649 1650 /* Finish up BSD-specific setup. */ 1651 1652 block->nmb_signature = (void *)0xcafebabe; 1653 block->nmb_status_func = kernndis_functbl[0].ipt_wrap; 1654 block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; 1655 block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; 1656 block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; 1657 block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; 1658 block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; 1659 1660 ndis_enlarge_thrqueue(8); 1661 1662 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1663 1664 return (STATUS_SUCCESS); 1665} 1666 1667int 1668ndis_unload_driver(arg) 1669 void *arg; 1670{ 1671 struct ndis_softc *sc; 1672 device_object *fdo; 1673 1674 sc = arg; 1675 1676 if (sc->ndis_block->nmb_rlist != NULL) 1677 free(sc->ndis_block->nmb_rlist, M_DEVBUF); 1678 1679 ndis_flush_sysctls(sc); 1680 1681 ndis_shrink_thrqueue(8); 1682 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1683 1684 fdo = sc->ndis_block->nmb_deviceobj; 1685 IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); 1686 IoDeleteDevice(fdo); 1687 1688 return(0); 1689} 1690