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