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