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