1/* $NetBSD$ */ 2 3/*- 4 * Copyright (c) 2003 5 * Bill Paul <wpaul@windriver.com>. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Bill Paul. 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 32 * THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36#ifdef __FreeBSD__ 37__FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.60.2.5 2005/04/01 17:14:20 wpaul Exp $"); 38#endif 39#ifdef __NetBSD__ 40__KERNEL_RCSID(0, "$NetBSD: kern_ndis.c,v 1.21 2009/05/11 21:31:29 cegger Exp $"); 41#endif 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/unistd.h> 46#include <sys/types.h> 47#include <sys/errno.h> 48#include <sys/callout.h> 49#include <sys/socket.h> 50#include <sys/queue.h> 51#include <sys/sysctl.h> 52#include <sys/proc.h> 53#include <sys/malloc.h> 54#include <sys/lock.h> 55#include <sys/mutex.h> 56#include <sys/conf.h> 57 58#include <sys/kernel.h> 59#include <sys/module.h> 60#include <sys/mbuf.h> 61#include <sys/kthread.h> 62#include <sys/bus.h> 63#ifdef __FreeBSD__ 64#include <machine/resource.h> 65#include <sys/rman.h> 66#endif 67 68#ifdef __NetBSD__ 69#include <dev/pci/pcivar.h> 70#include <dev/pci/pcireg.h> 71#endif 72 73#include <net/if.h> 74#include <net/if_arp.h> 75#ifdef __FreeBSD__ 76#include <net/ethernet.h> 77#else 78#include <net/if_ether.h> 79#endif 80#include <net/if_dl.h> 81#include <net/if_media.h> 82 83#include <net80211/ieee80211_var.h> 84#include <net80211/ieee80211_ioctl.h> 85 86#include <compat/ndis/pe_var.h> 87#include <compat/ndis/resource_var.h> 88#include <compat/ndis/ntoskrnl_var.h> 89#include <compat/ndis/ndis_var.h> 90#include <compat/ndis/hal_var.h> 91#include <compat/ndis/cfg_var.h> 92#include <compat/ndis/usbd_var.h> 93#include <dev/if_ndis/if_ndisvar.h> 94 95MODULE(MODULE_CLASS_MISC, ndis, NULL); 96 97#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 98 99__stdcall static void ndis_status_func(ndis_handle, ndis_status, 100 void *, uint32_t); 101__stdcall static void ndis_statusdone_func(ndis_handle); 102__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 103__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 104__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 105__stdcall static void ndis_sendrsrcavail_func(ndis_handle); 106__stdcall static void ndis_intrhand(kdpc *, device_object *, 107 irp *, struct ndis_softc *); 108 109static image_patch_table kernndis_functbl[] = { 110 IMPORT_FUNC(ndis_status_func), 111 IMPORT_FUNC(ndis_statusdone_func), 112 IMPORT_FUNC(ndis_setdone_func), 113 IMPORT_FUNC(ndis_getdone_func), 114 IMPORT_FUNC(ndis_resetdone_func), 115 IMPORT_FUNC(ndis_sendrsrcavail_func), 116 IMPORT_FUNC(ndis_intrhand), 117 118 { NULL, NULL, NULL } 119}; 120 121struct nd_head ndis_devhead; 122 123struct ndis_req { 124 void (*nr_func)(void *); 125 void *nr_arg; 126 int nr_exit; 127 STAILQ_ENTRY(ndis_req) link; 128 /* just for debugging */ 129 int area; 130}; 131 132struct ndisproc { 133 struct ndisqhead *np_q; 134 struct proc *np_p; 135 int np_state; 136 uint8_t np_stack[PAGE_SIZE*NDIS_KSTACK_PAGES]; 137}; 138 139static void ndis_return(void *); 140static int ndis_create_kthreads(void); 141static void ndis_destroy_kthreads(void); 142static void ndis_stop_thread(int); 143static int ndis_enlarge_thrqueue(int); 144static int ndis_shrink_thrqueue(int); 145//#ifdef NDIS_LKM 146static void ndis_runq(void *); 147//#endif 148 149#ifdef __FreeBSD__ 150static struct mtx ndis_thr_mtx; 151#else /* __NetBSD__ */ 152static kmutex_t ndis_thr_mtx; 153#endif 154 155static struct mtx ndis_req_mtx; 156static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; 157static struct ndisqhead ndis_itodo; 158static struct ndisqhead ndis_free; 159static int ndis_jobs = 32; 160 161static struct ndisproc ndis_tproc; 162static struct ndisproc ndis_iproc; 163 164/* 165 * This allows us to export our symbols to other modules. 166 * Note that we call ourselves 'ndisapi' to avoid a namespace 167 * collision with if_ndis.ko, which internally calls itself 168 * 'ndis.' 169 */ 170 171#ifdef __FreeBSD__ 172static int 173ndis_modevent(module_t mod, int cmd, void *arg) 174{ 175 int error = 0; 176 image_patch_table *patch; 177 178 switch (cmd) { 179 case MOD_LOAD: 180 /* Initialize subsystems */ 181 windrv_libinit(); 182 hal_libinit(); 183 ndis_libinit(); 184 ntoskrnl_libinit(); 185#ifdef usbimplemented 186 usbd_libinit(); 187#endif 188 189 patch = kernndis_functbl; 190 while (patch->ipt_func != NULL) { 191 windrv_wrap((funcptr)patch->ipt_func, 192 (funcptr *)&patch->ipt_wrap); 193 patch++; 194 } 195 196 ndis_create_kthreads(); 197 198 TAILQ_INIT(&ndis_devhead); 199 200 break; 201 case MOD_SHUTDOWN: 202 /* stop kthreads */ 203 ndis_destroy_kthreads(); 204 if (TAILQ_FIRST(&ndis_devhead) == NULL) { 205 /* Shut down subsystems */ 206 hal_libfini(); 207 ndis_libfini(); 208 ntoskrnl_libfini(); 209#ifdef usbimplemented 210 usbd_libfini(); 211#endif 212 windrv_libfini(); 213 214 patch = kernndis_functbl; 215 while (patch->ipt_func != NULL) { 216 windrv_unwrap(patch->ipt_wrap); 217 patch++; 218 } 219 } 220 break; 221 case MOD_UNLOAD: 222 /* stop kthreads */ 223 ndis_destroy_kthreads(); 224 225 /* Shut down subsystems */ 226 hal_libfini(); 227 ndis_libfini(); 228 ntoskrnl_libfini(); 229 usbd_libfini(); 230 windrv_libfini(); 231 232 patch = kernndis_functbl; 233 while (patch->ipt_func != NULL) { 234 windrv_unwrap(patch->ipt_wrap); 235 patch++; 236 } 237 238 break; 239 default: 240 error = EINVAL; 241 break; 242 } 243 244 return(error); 245} 246DEV_MODULE(ndisapi, ndis_modevent, NULL); 247MODULE_VERSION(ndisapi, 1); 248#endif 249 250static int 251ndis_modcmd(modcmd_t cmd, void *arg) 252{ 253 int error = 0; 254 image_patch_table *patch; 255 256 switch (cmd) { 257 case MODULE_CMD_INIT: 258 /* Initialize subsystems */ 259 windrv_libinit(); 260 hal_libinit(); 261 ndis_libinit(); 262 ntoskrnl_libinit(); 263#ifdef usbimplemented 264 usbd_libinit(); 265#endif 266 267 patch = kernndis_functbl; 268 while (patch->ipt_func != NULL) { 269 windrv_wrap((funcptr)patch->ipt_func, 270 (funcptr *)&patch->ipt_wrap); 271 patch++; 272 } 273 274 TAILQ_INIT(&ndis_devhead); 275 276 ndis_create_kthreads(); 277 break; 278 279 case MODULE_CMD_FINI: 280 /* stop kthreads */ 281 ndis_destroy_kthreads(); 282 283 /* Shut down subsystems */ 284 hal_libfini(); 285 ndis_libfini(); 286 ntoskrnl_libfini(); 287#ifdef usbimplemented 288 usbd_libfini(); 289#endif 290 windrv_libfini(); 291 292 patch = kernndis_functbl; 293 while (patch->ipt_func != NULL) { 294 windrv_unwrap(patch->ipt_wrap); 295 patch++; 296 } 297 298 break; 299 300 default: 301 error = ENOTTY; 302 break; 303 } 304 305 return(error); 306} 307 308/* 309 * We create two kthreads for the NDIS subsystem. One of them is a task 310 * queue for performing various odd jobs. The other is an swi thread 311 * reserved exclusively for running interrupt handlers. The reason we 312 * have our own task queue is that there are some cases where we may 313 * need to sleep for a significant amount of time, and if we were to 314 * use one of the taskqueue threads, we might delay the processing 315 * of other pending tasks which might need to run right away. We have 316 * a separate swi thread because we don't want our interrupt handling 317 * to be delayed either. 318 * 319 * By default there are 32 jobs available to start, and another 8 320 * are added to the free list each time a new device is created. 321 */ 322 323/* Just for testing this can be removed later */ 324struct ndis_req *_ndis_taskqueue_req; 325struct ndis_req *_ndis_swi_req; 326int calling_in_swi = FALSE; 327int calling_in_tq = FALSE; 328int num_swi = 0; 329int num_tq = 0; 330 331static void 332ndis_runq(void *arg) 333{ 334 struct ndis_req *r = NULL, *die = NULL; 335 struct ndisproc *p; 336 337 p = arg; 338 339 for (;;) { 340 mtx_lock_spin(&ndis_thr_mtx); 341 ndis_thsuspend(p->np_p, &ndis_thr_mtx, 0); 342 343 /* Look for any jobs on the work queue. */ 344 p->np_state = NDIS_PSTATE_RUNNING; 345 while (!STAILQ_EMPTY(p->np_q)) { 346 r = STAILQ_FIRST(p->np_q); 347 STAILQ_REMOVE_HEAD(p->np_q, link); 348 349 /* for debugging */ 350 351 if(p == &ndis_tproc) { 352 num_tq++; 353 _ndis_taskqueue_req = r; 354 r->area = 1; 355 } else if(p == &ndis_iproc) { 356 num_swi++; 357 _ndis_swi_req = r; 358 r->area = 2; 359 } 360 mtx_unlock_spin(&ndis_thr_mtx); 361 362 /* Just for debugging */ 363 364 if(p == &ndis_tproc) { 365 calling_in_tq = TRUE; 366 } else if(p == &ndis_iproc) { 367 calling_in_swi = TRUE; 368 } 369 370 /* Do the work. */ 371 if (r->nr_func != NULL) 372 (*r->nr_func)(r->nr_arg); 373 374 /* Just for debugging */ 375 if(p == &ndis_tproc) { 376 calling_in_tq = FALSE; 377 } else if(p == &ndis_iproc) { 378 calling_in_swi = FALSE; 379 } 380 381 mtx_lock_spin(&ndis_thr_mtx); 382 383 /* Zeroing out the ndis_req is just for debugging */ 384 //memset(r, 0, sizeof(struct ndis_req)); 385 STAILQ_INSERT_HEAD(&ndis_free, r, link); 386 387 /* Check for a shutdown request */ 388 if (r->nr_exit == TRUE) 389 die = r; 390 } 391 p->np_state = NDIS_PSTATE_SLEEPING; 392 393 mtx_unlock_spin(&ndis_thr_mtx); 394 395 /* Bail if we were told to shut down. */ 396 397 if (die != NULL) 398 break; 399 } 400 401 wakeup(die); 402 403 kthread_exit(0); 404 /* NOTREACHED */ 405} 406 407/*static*/ int 408ndis_create_kthreads(void) 409{ 410 struct ndis_req *r; 411 int i, error = 0; 412 413 printf("in ndis_create_kthreads\n"); 414 415#ifdef __FreeBSD__ 416 mtx_init(&ndis_thr_mtx, "NDIS thread lock", NULL, MTX_SPIN); 417#else /* __NetBSD__ */ 418 mutex_init(&ndis_thr_mtx, MUTEX_DEFAULT, IPL_NET); 419#endif 420 mtx_init(&ndis_req_mtx, "NDIS request lock", MTX_NDIS_LOCK, MTX_DEF); 421 422 STAILQ_INIT(&ndis_ttodo); 423 STAILQ_INIT(&ndis_itodo); 424 STAILQ_INIT(&ndis_free); 425 426 for (i = 0; i < ndis_jobs; i++) { 427 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK|M_ZERO); 428 if (r == NULL) { 429 error = ENOMEM; 430 break; 431 } 432 STAILQ_INSERT_HEAD(&ndis_free, r, link); 433 } 434 435 if (error == 0) { 436 ndis_tproc.np_q = &ndis_ttodo; 437 ndis_tproc.np_state = NDIS_PSTATE_SLEEPING; 438#ifdef __FreeBSD__ 439 error = kthread_create(ndis_runq, &ndis_tproc, 440 &ndis_tproc.np_p, RFHIGHPID, 441 NDIS_KSTACK_PAGES, "ndis taskqueue"); 442#else /* __NetBSD__ */ 443 error = ndis_kthread_create(ndis_runq, &ndis_tproc, 444 &ndis_tproc.np_p, ndis_tproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis taskqueue"); 445#endif 446 } 447 448 if (error == 0) { 449 ndis_iproc.np_q = &ndis_itodo; 450 ndis_iproc.np_state = NDIS_PSTATE_SLEEPING; 451#ifdef __FreeBSD__ 452 error = kthread_create(ndis_runq, &ndis_iproc, 453 &ndis_iproc.np_p, RFHIGHPID, 454 NDIS_KSTACK_PAGES, "ndis swi"); 455#else 456 error = ndis_kthread_create(ndis_runq, &ndis_iproc, 457 &ndis_iproc.np_p, ndis_iproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis swi"); 458#endif 459 } 460 461 if (error) { 462 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 463 STAILQ_REMOVE_HEAD(&ndis_free, link); 464 free(r, M_DEVBUF); 465 } 466 return(error); 467 } 468 469 return(0); 470} 471 472static void 473ndis_destroy_kthreads(void) 474{ 475 struct ndis_req *r; 476 477 /* Stop the threads. */ 478 479 ndis_stop_thread(NDIS_TASKQUEUE); 480 ndis_stop_thread(NDIS_SWI); 481 482 /* Destroy request structures. */ 483 484 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 485 STAILQ_REMOVE_HEAD(&ndis_free, link); 486 free(r, M_DEVBUF); 487 } 488 489 mtx_destroy(&ndis_req_mtx); 490 mtx_destroy(&ndis_thr_mtx); 491 492 return; 493} 494 495static void 496ndis_stop_thread(int t) 497{ 498 struct ndis_req *r; 499 struct ndisqhead *q; 500 struct proc *p; 501 502 if (t == NDIS_TASKQUEUE) { 503 q = &ndis_ttodo; 504 p = ndis_tproc.np_p; 505 } else { 506 q = &ndis_itodo; 507 p = ndis_iproc.np_p; 508 } 509 510 /* Create and post a special 'exit' job. */ 511 512 mtx_lock_spin(&ndis_thr_mtx); 513 514 r = STAILQ_FIRST(&ndis_free); 515 STAILQ_REMOVE_HEAD(&ndis_free, link); 516 r->nr_func = NULL; 517 r->nr_arg = NULL; 518 r->nr_exit = TRUE; 519 r->area = 3; 520 STAILQ_INSERT_TAIL(q, r, link); 521 mtx_unlock_spin(&ndis_thr_mtx); 522 523 ndis_thresume(p); 524 525 /* Wait for thread exit */ 526 tsleep(r, PZERO | PCATCH, "ndisthexit", hz * 60); 527 528 /* Now empty the job list. */ 529 mtx_lock_spin(&ndis_thr_mtx); 530 while ((r = STAILQ_FIRST(q)) != NULL) { 531 STAILQ_REMOVE_HEAD(q, link); 532 STAILQ_INSERT_HEAD(&ndis_free, r, link); 533 } 534 mtx_unlock_spin(&ndis_thr_mtx); 535} 536 537static int 538ndis_enlarge_thrqueue(int cnt) 539{ 540 struct ndis_req *r; 541 int i; 542 543 for (i = 0; i < cnt; i++) { 544 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 545 if (r == NULL) 546 return(ENOMEM); 547 548 mtx_lock_spin(&ndis_thr_mtx); 549 STAILQ_INSERT_HEAD(&ndis_free, r, link); 550 ndis_jobs++; 551 mtx_unlock_spin(&ndis_thr_mtx); 552 } 553 554 return(0); 555} 556 557static int 558ndis_shrink_thrqueue(int cnt) 559{ 560 struct ndis_req *r; 561 int i; 562 563 for (i = 0; i < cnt; i++) { 564 mtx_lock_spin(&ndis_thr_mtx); 565 r = STAILQ_FIRST(&ndis_free); 566 if (r == NULL) { 567 mtx_unlock_spin(&ndis_thr_mtx); 568 return(ENOMEM); 569 } 570 STAILQ_REMOVE_HEAD(&ndis_free, link); 571 ndis_jobs--; 572 mtx_unlock_spin(&ndis_thr_mtx); 573 free(r, M_DEVBUF); 574 } 575 576 return(0); 577} 578 579int 580ndis_unsched(void (*func)(void *), void *arg, int t) 581{ 582 struct ndis_req *r; 583 struct ndisqhead *q; 584 struct proc *p; 585 586 if (t == NDIS_TASKQUEUE) { 587 q = &ndis_ttodo; 588 p = ndis_tproc.np_p; 589 } else { 590 q = &ndis_itodo; 591 p = ndis_iproc.np_p; 592 } 593 594 mtx_lock_spin(&ndis_thr_mtx); 595 STAILQ_FOREACH(r, q, link) { 596 if (r->nr_func == func && r->nr_arg == arg) { 597 r->area = 4; 598 STAILQ_REMOVE(q, r, ndis_req, link); 599 STAILQ_INSERT_HEAD(&ndis_free, r, link); 600 mtx_unlock_spin(&ndis_thr_mtx); 601 return(0); 602 } 603 } 604 mtx_unlock_spin(&ndis_thr_mtx); 605 606 return(ENOENT); 607} 608 609/* just for testing */ 610struct ndis_req *ls_tq_req = NULL; 611struct ndis_req *ls_swi_req = NULL; 612 613int 614ndis_sched(void (*func)(void *), void *arg, int t) 615{ 616 struct ndis_req *r; 617 struct ndisqhead *q; 618 struct proc *p; 619 int s; 620#ifdef __NetBSD__ 621 /* just for debugging */ 622 struct ndis_req **ls; 623 //struct lwp *l = curlwp; 624#endif 625 626 if (t == NDIS_TASKQUEUE) { 627 ls = &ls_tq_req; 628 q = &ndis_ttodo; 629 p = ndis_tproc.np_p; 630 } else { 631 ls = &ls_swi_req; 632 q = &ndis_itodo; 633 p = ndis_iproc.np_p; 634 } 635 636 mtx_lock_spin(&ndis_thr_mtx); 637 638 /* 639 * Check to see if an instance of this job is already 640 * pending. If so, don't bother queuing it again. 641 */ 642 STAILQ_FOREACH(r, q, link) { 643 if (r->nr_func == func && r->nr_arg == arg) { 644#ifdef __NetBSD__ 645 if (t == NDIS_TASKQUEUE) 646 s = ndis_tproc.np_state; 647 else 648 s = ndis_iproc.np_state; 649#endif 650 mtx_unlock_spin(&ndis_thr_mtx); 651#ifdef __NetBSD__ 652 /* The swi thread seemed to be going to sleep, and not waking up 653 * again, so I thought I'd try this out... 654 */ 655 if (s == NDIS_PSTATE_SLEEPING) 656 ndis_thresume(p); 657#endif 658 return(0); 659 } 660 } 661 r = STAILQ_FIRST(&ndis_free); 662 if (r == NULL) { 663 mtx_unlock_spin(&ndis_thr_mtx); 664 return(EAGAIN); 665 } 666 STAILQ_REMOVE_HEAD(&ndis_free, link); 667#ifdef __NetBSD__ 668 //memset(r, 0, sizeof(struct ndis_req)); 669#endif 670 *ls = r; 671 r->nr_func = func; 672 r->nr_arg = arg; 673 r->nr_exit = FALSE; 674 r->area = 5; 675 STAILQ_INSERT_TAIL(q, r, link); 676 if (t == NDIS_TASKQUEUE) { 677 s = ndis_tproc.np_state; 678 } else { 679 s = ndis_iproc.np_state; 680 } 681 mtx_unlock_spin(&ndis_thr_mtx); 682 683 /* 684 * Post the job, but only if the thread is actually blocked 685 * on its own suspend call. If a driver queues up a job with 686 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(), 687 * it may suspend there, and in that case we don't want to wake 688 * it up until KeWaitForObject() gets woken up on its own. 689 */ 690 if (s == NDIS_PSTATE_SLEEPING) { 691 ndis_thresume(p); 692 } 693 694 return(0); 695} 696 697/* Try out writing my own version of ndis_sched() for NetBSD in which I just 698 * call the function instead of scheduling it. I know this isn't 699 * what's supposed to be done, but I've been having a lot of problems 700 * with the SWI and taskqueue threads, and just thought I'd give this 701 * a try. 702 */ 703 704 /* I don't think this will work, because it means that DPC's will be 705 * called from the bottom half of the kernel, so they won't be able 706 * to sleep using KeWaitForSingleObject. 707 */ 708 /* 709 int 710ndis_sched(void (*func)(void *), void *arg, int t) 711{ 712 if(func != NULL) { 713 (*func)(arg); 714 } 715 716 return 0; 717} 718*/ 719 720int 721ndis_thsuspend(proc_t *p, kmutex_t *m, int timo) 722{ 723 724 return mtsleep(&p->p_sigpend.sp_set, PZERO, "ndissp", timo, m); 725} 726 727void 728ndis_thresume(struct proc *p) 729{ 730 731 wakeup(&p->p_sigpend.sp_set); 732} 733 734__stdcall static void 735ndis_sendrsrcavail_func(ndis_handle adapter) 736{ 737 return; 738} 739 740__stdcall static void 741ndis_status_func(ndis_handle adapter, ndis_status status, void *sbuf, 742 uint32_t slen) 743{ 744 ndis_miniport_block *block; 745 struct ndis_softc *sc; 746 struct ifnet *ifp; 747 748 block = adapter; 749#ifdef __FreeBSD__ 750 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 751#else /* __NetBSD__ */ 752 sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc; 753#endif 754 755#ifdef __FreeBSD__ 756 ifp = &sc->arpcom.ac_if; 757#else 758 ifp = &sc->arpcom.ec_if; 759#endif 760 if (ifp->if_flags & IFF_DEBUG) 761 printf("%s: status: %x\n", 762 device_xname(sc->ndis_dev), status); 763 return; 764} 765 766__stdcall static void 767ndis_statusdone_func(ndis_handle adapter) 768{ 769 ndis_miniport_block *block; 770 struct ndis_softc *sc; 771 struct ifnet *ifp; 772 773 block = adapter; 774#ifdef __FreeBSD__ 775 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 776#else /* __NetBSD__ */ 777 sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc; 778#endif 779 780#ifdef __FreeBSD__ 781 ifp = &sc->arpcom.ac_if; 782#else 783 ifp = &sc->arpcom.ec_if; 784#endif 785 if (ifp->if_flags & IFF_DEBUG) 786 printf("%s: status complete\n", 787 device_xname(sc->ndis_dev)); 788 return; 789} 790 791__stdcall static void 792ndis_setdone_func(ndis_handle adapter, ndis_status status) 793{ 794 ndis_miniport_block *block; 795 block = adapter; 796 797 block->nmb_setstat = status; 798 wakeup(&block->nmb_setstat); 799 return; 800} 801 802__stdcall static void 803ndis_getdone_func(ndis_handle adapter, ndis_status status) 804{ 805 ndis_miniport_block *block; 806 block = adapter; 807 808 block->nmb_getstat = status; 809 wakeup(&block->nmb_getstat); 810 return; 811} 812 813__stdcall static void 814ndis_resetdone_func(ndis_handle adapter, ndis_status status, 815 uint8_t addressingreset) 816{ 817 ndis_miniport_block *block; 818 struct ndis_softc *sc; 819 struct ifnet *ifp; 820 821 block = adapter; 822#ifdef __FreeBSD__ 823 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 824#else /* __NetBSD__ */ 825 sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc; 826#endif 827 828#ifdef __FreeBSD__ 829 ifp = &sc->arpcom.ac_if; 830#else 831 ifp = &sc->arpcom.ec_if; 832#endif 833 834 if (ifp->if_flags & IFF_DEBUG) 835 printf("%s: reset done...\n", 836 device_xname(sc->ndis_dev)); 837 wakeup(sc); 838 return; 839} 840 841#ifdef __FreeBSD__ 842/* FreeBSD version of ndis_create_sysctls() */ 843int 844ndis_create_sysctls(void *arg) 845{ 846 struct ndis_softc *sc; 847 ndis_cfg *vals; 848 char buf[256]; 849 struct sysctl_oid *oidp; 850 struct sysctl_ctx_entry *e; 851 852 if (arg == NULL) 853 return(EINVAL); 854 855 sc = arg; 856 vals = sc->ndis_regvals; 857 858 TAILQ_INIT(&sc->ndis_cfglist_head); 859 860#if __FreeBSD_version < 502113 861 /* Create the sysctl tree. */ 862 863 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 864 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 865 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 866 device_get_desc(sc->ndis_dev)); 867 868#endif 869 /* Add the driver-specific registry keys. */ 870 871 vals = sc->ndis_regvals; 872 while(1) { 873 if (vals->nc_cfgkey == NULL) 874 break; 875 if (vals->nc_idx != sc->ndis_devidx) { 876 vals++; 877 continue; 878 } 879 880 /* See if we already have a sysctl with this name */ 881 882 oidp = NULL; 883#if __FreeBSD_version < 502113 884 TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 885#else 886 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 887#endif 888 oidp = e->entry; 889 if (ndis_strcasecmp(oidp->oid_name, 890 vals->nc_cfgkey) == 0) 891 break; 892 oidp = NULL; 893 } 894 895 if (oidp != NULL) { 896 vals++; 897 continue; 898 } 899 900#if __FreeBSD_version < 502113 901 SYSCTL_ADD_STRING(&sc->ndis_ctx, 902 SYSCTL_CHILDREN(sc->ndis_tree), 903#else 904 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 905 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 906#endif 907 OID_AUTO, vals->nc_cfgkey, 908 CTLFLAG_RW, vals->nc_val, 909 sizeof(vals->nc_val), 910 vals->nc_cfgdesc); 911 vals++; 912 } 913 914 /* Now add a couple of builtin keys. */ 915 916 /* 917 * Environment can be either Windows (0) or WindowsNT (1). 918 * We qualify as the latter. 919 */ 920 ndis_add_sysctl(sc, "Environment", 921 "Windows environment", "1", CTLFLAG_RD); 922 923 /* NDIS version should be 5.1. */ 924 ndis_add_sysctl(sc, "NdisVersion", 925 "NDIS API Version", "0x00050001", CTLFLAG_RD); 926 927 /* Bus type (PCI, PCMCIA, etc...) */ 928 sprintf(buf, "%d", (int)sc->ndis_iftype); 929 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 930 931 if (sc->ndis_res_io != NULL) { 932 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 933 ndis_add_sysctl(sc, "IOBaseAddress", 934 "Base I/O Address", buf, CTLFLAG_RD); 935 } 936 937 if (sc->ndis_irq != NULL) { 938 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 939 ndis_add_sysctl(sc, "InterruptNumber", 940 "Interrupt Number", buf, CTLFLAG_RD); 941 } 942 943 return(0); 944} 945#endif /* __FreeBSD__ */ 946 947#ifdef __NetBSD__ 948/* NetBSD version of ndis_create_sysctls() */ 949int 950ndis_create_sysctls(void *arg) 951{ 952 struct ndis_softc *sc; 953 ndis_cfg *vals; 954 const struct sysctlnode *ndis_node; 955 char buf[256]; 956 957 printf("in ndis_create_sysctls()\n"); 958 959 if (arg == NULL) 960 return(EINVAL); 961 962 sc = arg; 963 vals = sc->ndis_regvals; 964 965 TAILQ_INIT(&sc->ndis_cfglist_head); 966 967 /* Create the sysctl tree. */ 968 sysctl_createv(&sc->sysctllog, 0, NULL, &ndis_node, CTLFLAG_READWRITE, CTLTYPE_NODE, 969 device_xname(sc->ndis_dev), NULL, NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 970 971 /* Store the number of the ndis mib */ 972 sc->ndis_sysctl_mib = ndis_node->sysctl_num; 973 974 /* Add the driver-specific registry keys. */ 975 vals = sc->ndis_regvals; 976 while(1) { 977 if (vals->nc_cfgkey == NULL) 978 break; 979 if (vals->nc_idx != sc->ndis_devidx) { 980 vals++; 981 continue; 982 } 983 984 /* See if we already have a sysctl with this name */ 985/* TODO: Is something like this necessary in NetBSD? I'm guessing this 986 TODO: is just checking if any of the information in the .inf file was 987 TODO: already determined by FreeBSD's autoconfiguration which seems to 988 TODO: add dev.XXX sysctl's beginning with %. (NetBSD dosen't seem to do this). 989*/ 990 991/* TODO: use CTLFLAG_OWNDATA or not? */ 992 /* 993 sysctl_createv(&sc->sysctllog, 0, NULL, NULL, 994 CTLFLAG_READWRITE|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA, CTLTYPE_STRING, 995 vals->nc_cfgkey, vals->nc_cfgdesc, NULL, 0, vals->nc_val, strlen(vals->nc_val), 996 ndis_node->sysctl_num, CTL_CREATE, CTL_EOL); 997 */ 998 ndis_add_sysctl(sc, vals->nc_cfgkey, 999 vals->nc_cfgdesc, vals->nc_val, CTLFLAG_READWRITE); 1000 1001 vals++; 1002 } /* end while */ 1003 1004 /* Now add a couple of builtin keys. */ 1005 1006 /* 1007 * Environment can be either Windows (0) or WindowsNT (1). 1008 * We qualify as the latter. 1009 */ 1010#ifdef __NetBSD__ 1011#define CTLFLAG_RD CTLFLAG_READONLY 1012/* TODO: do we need something like rman_get_start? */ 1013#define rman_get_start(x) x 1014#endif 1015 ndis_add_sysctl(sc, "Environment", 1016 "Windows environment", "1", CTLFLAG_RD); 1017 1018 /* NDIS version should be 5.1. */ 1019 ndis_add_sysctl(sc, "NdisVersion", 1020 /*"NDIS API Version"*/ "Version", "0x00050001", CTLFLAG_RD); 1021 1022 /* Bus type (PCI, PCMCIA, etc...) */ 1023 sprintf(buf, "%d", (int)sc->ndis_iftype); 1024 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 1025 1026 if (sc->ndis_res_io != NULL) { 1027 sprintf(buf, "0x%lx", (long unsigned int)rman_get_start(sc->ndis_res_io)); 1028 ndis_add_sysctl(sc, "IOBaseAddress", 1029 /*"Base I/O Address"*/ "Base I/O", buf, CTLFLAG_RD); 1030 } 1031 1032 if (sc->ndis_irq != NULL) { 1033 sprintf(buf, "%lu", (long unsigned int)rman_get_start(sc->ndis_irq)); 1034 ndis_add_sysctl(sc, "InterruptNumber", 1035 "Interrupt Number", buf, CTLFLAG_RD); 1036 } 1037 1038 return(0); 1039} 1040#endif /* __NetBSD__ */ 1041 1042char *ndis_strdup(const char *src); 1043 1044char *ndis_strdup(const char *src) 1045{ 1046 char *ret; 1047 1048 ret = malloc(strlen(src), M_DEVBUF, M_NOWAIT|M_ZERO); 1049 if (ret == NULL) { 1050 printf("ndis_strdup failed\n"); 1051 return(NULL); 1052 } 1053 strcpy(ret, src); 1054 1055 return ret; 1056} 1057 1058int 1059ndis_add_sysctl(void *arg, const char *key, const char *desc, const char *val, int flag) 1060{ 1061 struct ndis_softc *sc; 1062 struct ndis_cfglist *cfg; 1063 char descstr[256]; 1064#ifdef __NetBSD__ 1065 char newkey[MAX_SYSCTL_LEN+1]; 1066#endif 1067 1068 sc = arg; 1069 1070 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 1071 1072 if (cfg == NULL) 1073 return(ENOMEM); 1074 1075 /* I added this because NetBSD sysctl node names can't begin with 1076 * a digit. 1077 */ 1078#ifdef __NetBSD__ 1079 if(strlen(key) + strlen("ndis_") > MAX_SYSCTL_LEN) { 1080 panic("sysctl name too long: %s\n", key); 1081 } 1082 strcpy(newkey, "ndis_"); 1083 strcpy(newkey + strlen("ndis_"), key); 1084 key = newkey; 1085#endif 1086 1087 cfg->ndis_cfg.nc_cfgkey = ndis_strdup(key); 1088 1089 if (desc == NULL) { 1090 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 1091 cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(descstr); 1092 } else 1093 cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(desc); 1094 strcpy(cfg->ndis_cfg.nc_val, val); 1095 1096 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 1097 1098#ifdef __FreeBSD__ 1099#if __FreeBSD_version < 502113 1100 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 1101#else 1102 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 1103 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 1104#endif 1105 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 1106 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 1107 cfg->ndis_cfg.nc_cfgdesc); 1108#else /* __NetBSD__ */ 1109/* TODO: use CTLFLAG_OWNDATA or not? */ 1110 sysctl_createv(&sc->sysctllog, 0, NULL, NULL, flag/*|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA*/, CTLTYPE_STRING, 1111 cfg->ndis_cfg.nc_cfgkey, cfg->ndis_cfg.nc_cfgdesc, NULL, 0, cfg->ndis_cfg.nc_val, 1112 strlen(cfg->ndis_cfg.nc_val), sc->ndis_sysctl_mib, CTL_CREATE, CTL_EOL); 1113#endif 1114 return(0); 1115} 1116 1117int 1118ndis_flush_sysctls(void *arg) 1119{ 1120 struct ndis_softc *sc; 1121 struct ndis_cfglist *cfg; 1122 1123 sc = arg; 1124 1125 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 1126 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 1127 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 1128#ifdef __FreeBSD__ 1129 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 1130 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 1131#endif 1132 free(cfg, M_DEVBUF); 1133 } 1134 1135 return(0); 1136} 1137 1138static void 1139ndis_return(void *arg) 1140{ 1141 struct ndis_softc *sc; 1142 __stdcall ndis_return_handler returnfunc; 1143 ndis_handle adapter; 1144 ndis_packet *p; 1145 uint8_t irql = 0; /* XXX: gcc */ 1146 1147 p = arg; 1148 sc = p->np_softc; 1149 adapter = sc->ndis_block->nmb_miniportadapterctx; 1150 1151 if (adapter == NULL) 1152 return; 1153 1154 returnfunc = sc->ndis_chars->nmc_return_packet_func; 1155 1156 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1157 MSCALL2(returnfunc, adapter, p); 1158 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1159 1160 return; 1161} 1162 1163void 1164#ifdef __FreeBSD__ 1165ndis_return_packet(buf, arg) 1166 void *buf; /* not used */ 1167 void *arg; 1168#else 1169ndis_return_packet(struct mbuf *m, void *buf, 1170 size_t size, void *arg) 1171#endif 1172 1173{ 1174 ndis_packet *p; 1175 1176 if (arg == NULL) 1177 return; 1178 1179 p = arg; 1180 1181 /* Decrement refcount. */ 1182 p->np_refcnt--; 1183 1184 /* Release packet when refcount hits zero, otherwise return. */ 1185 if (p->np_refcnt) 1186 return; 1187 1188 ndis_sched(ndis_return, p, NDIS_TASKQUEUE); 1189 1190 return; 1191} 1192 1193void 1194ndis_free_bufs(ndis_buffer *b0) 1195{ 1196 ndis_buffer *next; 1197 1198 if (b0 == NULL) 1199 return; 1200 1201 while(b0 != NULL) { 1202 next = b0->mdl_next; 1203 IoFreeMdl(b0); 1204 b0 = next; 1205 } 1206 1207 return; 1208} 1209int in_reset = 0; 1210void 1211ndis_free_packet(ndis_packet *p) 1212{ 1213 if (p == NULL) 1214 return; 1215 1216 ndis_free_bufs(p->np_private.npp_head); 1217 NdisFreePacket(p); 1218 return; 1219} 1220 1221#ifdef __FreeBSD__ 1222int 1223ndis_convert_res(void *arg) 1224{ 1225 struct ndis_softc *sc; 1226 ndis_resource_list *rl = NULL; 1227 cm_partial_resource_desc *prd = NULL; 1228 ndis_miniport_block *block; 1229 device_t dev; 1230 struct resource_list *brl; 1231 struct resource_list_entry *brle; 1232#if __FreeBSD_version < 600022 1233 struct resource_list brl_rev; 1234 struct resource_list_entry *n; 1235#endif 1236 int error = 0; 1237 1238 sc = arg; 1239 block = sc->ndis_block; 1240 dev = sc->ndis_dev; 1241 1242#if __FreeBSD_version < 600022 1243 SLIST_INIT(&brl_rev); 1244#endif 1245 rl = malloc(sizeof(ndis_resource_list) + 1246 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 1247 M_DEVBUF, M_NOWAIT|M_ZERO); 1248 1249 if (rl == NULL) 1250 return(ENOMEM); 1251 1252 rl->cprl_version = 5; 1253 rl->cprl_version = 1; 1254 rl->cprl_count = sc->ndis_rescnt; 1255 prd = rl->cprl_partial_descs; 1256 1257 brl = BUS_GET_RESOURCE_LIST(dev, dev); 1258 1259 if (brl != NULL) { 1260 1261#if __FreeBSD_version < 600022 1262 /* 1263 * We have a small problem. Some PCI devices have 1264 * multiple I/O ranges. Windows orders them starting 1265 * from lowest numbered BAR to highest. We discover 1266 * them in that order too, but insert them into a singly 1267 * linked list head first, which means when time comes 1268 * to traverse the list, we enumerate them in reverse 1269 * order. This screws up some drivers which expect the 1270 * BARs to be in ascending order so that they can choose 1271 * the "first" one as their register space. Unfortunately, 1272 * in order to fix this, we have to create our own 1273 * temporary list with the entries in reverse order. 1274 */ 1275 SLIST_FOREACH(brle, brl, link) { 1276 n = malloc(sizeof(struct resource_list_entry), 1277 M_TEMP, M_NOWAIT); 1278 if (n == NULL) { 1279 error = ENOMEM; 1280 goto bad; 1281 } 1282 memcpy( (char *)n, (char *)brle, 1283 sizeof(struct resource_list_entry)); 1284 SLIST_INSERT_HEAD(&brl_rev, n, link); 1285 } 1286 1287 SLIST_FOREACH(brle, &brl_rev, link) { 1288#else 1289 STAILQ_FOREACH(brle, brl, link) { 1290#endif 1291 switch (brle->type) { 1292 case SYS_RES_IOPORT: 1293 prd->cprd_type = CmResourceTypePort; 1294 prd->cprd_flags = CM_RESOURCE_PORT_IO; 1295 prd->cprd_sharedisp = 1296 CmResourceShareDeviceExclusive; 1297 prd->u.cprd_port.cprd_start.np_quad = 1298 brle->start; 1299 prd->u.cprd_port.cprd_len = brle->count; 1300 break; 1301 case SYS_RES_MEMORY: 1302 prd->cprd_type = CmResourceTypeMemory; 1303 prd->cprd_flags = 1304 CM_RESOURCE_MEMORY_READ_WRITE; 1305 prd->cprd_sharedisp = 1306 CmResourceShareDeviceExclusive; 1307 prd->u.cprd_port.cprd_start.np_quad = 1308 brle->start; 1309 prd->u.cprd_port.cprd_len = brle->count; 1310 break; 1311 case SYS_RES_IRQ: 1312 prd->cprd_type = CmResourceTypeInterrupt; 1313 prd->cprd_flags = 0; 1314 prd->cprd_sharedisp = 1315 CmResourceShareDeviceExclusive; 1316 prd->u.cprd_intr.cprd_level = brle->start; 1317 prd->u.cprd_intr.cprd_vector = brle->start; 1318 prd->u.cprd_intr.cprd_affinity = 0; 1319 break; 1320 default: 1321 break; 1322 } 1323 prd++; 1324 } 1325 } 1326 1327 block->nmb_rlist = rl; 1328 1329#if __FreeBSD_version < 600022 1330bad: 1331 1332 while (!SLIST_EMPTY(&brl_rev)) { 1333 n = SLIST_FIRST(&brl_rev); 1334 SLIST_REMOVE_HEAD(&brl_rev, link); 1335 free (n, M_TEMP); 1336 } 1337#endif 1338 1339 return(error); 1340} 1341#endif /* __FreeBSD__ */ 1342/* 1343 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 1344 * packet, it will hand it to us in the form of an ndis_packet, 1345 * which we need to convert to an mbuf that is then handed off 1346 * to the stack. Note: we configure the mbuf list so that it uses 1347 * the memory regions specified by the ndis_buffer structures in 1348 * the ndis_packet as external storage. In most cases, this will 1349 * point to a memory region allocated by the driver (either by 1350 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 1351 * the driver to handle free()ing this region for is, so we set up 1352 * a dummy no-op free handler for it. 1353 */ 1354 1355int 1356ndis_ptom(struct mbuf **m0, ndis_packet *p) 1357{ 1358 struct mbuf *m, *prev = NULL; 1359 ndis_buffer *buf; 1360 ndis_packet_private *priv; 1361 uint32_t totlen = 0; 1362 1363 if (p == NULL || m0 == NULL) 1364 return(EINVAL); 1365 1366 priv = &p->np_private; 1367 buf = priv->npp_head; 1368 p->np_refcnt = 0; 1369 1370 for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { 1371 if (buf == priv->npp_head) 1372 MGETHDR(m, M_DONTWAIT, MT_HEADER); 1373 else 1374 MGET(m, M_DONTWAIT, MT_DATA); 1375 if (m == NULL) { 1376 m_freem(*m0); 1377 *m0 = NULL; 1378 return(ENOBUFS); 1379 } 1380 m->m_len = MmGetMdlByteCount(buf); 1381 m->m_data = MmGetMdlVirtualAddress(buf); 1382#ifdef __FreeBSD__ 1383 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 1384 p, 0, EXT_NDIS); 1385#else 1386 MEXTADD(m, m->m_data, m->m_len, M_DEVBUF, 1387 ndis_return_packet, p); 1388#endif 1389 p->np_refcnt++; 1390 totlen += m->m_len; 1391 if (m->m_flags & MT_HEADER) 1392 *m0 = m; 1393 else 1394 prev->m_next = m; 1395 prev = m; 1396 } 1397 1398 (*m0)->m_pkthdr.len = totlen; 1399 1400 return(0); 1401} 1402 1403/* 1404 * Create an NDIS packet from an mbuf chain. 1405 * This is used mainly when transmitting packets, where we need 1406 * to turn an mbuf off an interface's send queue and transform it 1407 * into an NDIS packet which will be fed into the NDIS driver's 1408 * send routine. 1409 * 1410 * NDIS packets consist of two parts: an ndis_packet structure, 1411 * which is vaguely analagous to the pkthdr portion of an mbuf, 1412 * and one or more ndis_buffer structures, which define the 1413 * actual memory segments in which the packet data resides. 1414 * We need to allocate one ndis_buffer for each mbuf in a chain, 1415 * plus one ndis_packet as the header. 1416 */ 1417 1418int 1419ndis_mtop(struct mbuf *m0, ndis_packet **p) 1420{ 1421 struct mbuf *m; 1422 ndis_buffer *buf = NULL, *prev = NULL; 1423 ndis_packet_private *priv; 1424 1425 if (p == NULL || *p == NULL || m0 == NULL) 1426 return(EINVAL); 1427 1428 priv = &(*p)->np_private; 1429 priv->npp_totlen = m0->m_pkthdr.len; 1430 1431 for (m = m0; m != NULL; m = m->m_next) { 1432 if (m->m_len == 0) 1433 continue; 1434 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL); 1435 if (buf == NULL) { 1436 ndis_free_packet(*p); 1437 *p = NULL; 1438 return(ENOMEM); 1439 } 1440 1441 if (priv->npp_head == NULL) 1442 priv->npp_head = buf; 1443 else 1444 prev->mdl_next = buf; 1445 prev = buf; 1446 } 1447 1448 priv->npp_tail = buf; 1449 1450 return(0); 1451} 1452 1453int 1454ndis_get_supported_oids(void *arg, ndis_oid **oids, int *oidcnt) 1455{ 1456 int len, rval; 1457 ndis_oid *o; 1458 1459 if (arg == NULL || oids == NULL || oidcnt == NULL) 1460 return(EINVAL); 1461 len = 0; 1462 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 1463 1464 o = malloc(len, M_DEVBUF, M_NOWAIT); 1465 if (o == NULL) 1466 return(ENOMEM); 1467 1468 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 1469 1470 if (rval) { 1471 free(o, M_DEVBUF); 1472 return(rval); 1473 } 1474 1475 *oids = o; 1476 *oidcnt = len / 4; 1477 1478 return(0); 1479} 1480 1481int 1482ndis_set_info(void *arg, ndis_oid oid, void *buf, int *buflen) 1483{ 1484 struct ndis_softc *sc; 1485 ndis_status rval; 1486 ndis_handle adapter; 1487 __stdcall ndis_setinfo_handler setfunc; 1488 uint32_t byteswritten = 0, bytesneeded = 0; 1489 int error; 1490 uint8_t irql = 0; /* XXX: gcc */ 1491 1492 /* 1493 * According to the NDIS spec, MiniportQueryInformation() 1494 * and MiniportSetInformation() requests are handled serially: 1495 * once one request has been issued, we must wait for it to 1496 * finish before allowing another request to proceed. 1497 */ 1498 1499 sc = arg; 1500 1501 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1502 1503 if (sc->ndis_block->nmb_pendingreq != NULL) 1504 panic("ndis_set_info() called while other request pending"); 1505 else 1506 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 1507 1508 /* I added this lock because it was present in the FreeBSD-current sources */ 1509 NDIS_LOCK(sc); 1510 1511 setfunc = sc->ndis_chars->nmc_setinfo_func; 1512 adapter = sc->ndis_block->nmb_miniportadapterctx; 1513 1514 if (adapter == NULL || setfunc == NULL) { 1515 sc->ndis_block->nmb_pendingreq = NULL; 1516 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1517 NDIS_UNLOCK(sc); 1518 return(ENXIO); 1519 } 1520 1521 NDIS_UNLOCK(sc); 1522 1523 rval = MSCALL6(setfunc, adapter, oid, buf, *buflen, 1524 &byteswritten, &bytesneeded); 1525 1526 sc->ndis_block->nmb_pendingreq = NULL; 1527 1528 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1529 1530 if (rval == NDIS_STATUS_PENDING) { 1531 mtx_lock(&ndis_req_mtx); 1532 error = mtsleep(&sc->ndis_block->nmb_setstat, 1533 PZERO | PNORELOCK, 1534 "ndisset", 5 * hz, &ndis_req_mtx); 1535 rval = sc->ndis_block->nmb_setstat; 1536 } 1537 1538 if (byteswritten) 1539 *buflen = byteswritten; 1540 if (bytesneeded) 1541 *buflen = bytesneeded; 1542 1543 if (rval == NDIS_STATUS_INVALID_LENGTH) 1544 return(ENOSPC); 1545 1546 if (rval == NDIS_STATUS_INVALID_OID) 1547 return(EINVAL); 1548 1549 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1550 rval == NDIS_STATUS_NOT_ACCEPTED) 1551 return(ENOTSUP); 1552 1553 if (rval != NDIS_STATUS_SUCCESS) 1554 return(ENODEV); 1555 1556 return(0); 1557} 1558 1559typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 1560 1561int 1562ndis_send_packets(void *arg, ndis_packet **packets, int cnt) 1563{ 1564 struct ndis_softc *sc; 1565 ndis_handle adapter; 1566 __stdcall ndis_sendmulti_handler sendfunc; 1567 __stdcall ndis_senddone_func senddonefunc; 1568 int i; 1569 ndis_packet *p; 1570 uint8_t irql = 0; /* XXX: gcc */ 1571 1572 sc = arg; 1573 adapter = sc->ndis_block->nmb_miniportadapterctx; 1574 if (adapter == NULL) 1575 return(ENXIO); 1576 sendfunc = sc->ndis_chars->nmc_sendmulti_func; 1577 senddonefunc = sc->ndis_block->nmb_senddone_func; 1578 1579 if (NDIS_SERIALIZED(sc->ndis_block)) 1580 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1581 1582 MSCALL3(sendfunc, adapter, packets, cnt); 1583 1584 for (i = 0; i < cnt; i++) { 1585 p = packets[i]; 1586 /* 1587 * Either the driver already handed the packet to 1588 * ndis_txeof() due to a failure, or it wants to keep 1589 * it and release it asynchronously later. Skip to the 1590 * next one. 1591 */ 1592 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 1593 continue; 1594 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status); 1595 } 1596 1597 if (NDIS_SERIALIZED(sc->ndis_block)) 1598 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1599 1600 return(0); 1601} 1602 1603int 1604ndis_send_packet(void *arg, ndis_packet *packet) 1605{ 1606 struct ndis_softc *sc; 1607 ndis_handle adapter; 1608 ndis_status status; 1609 __stdcall ndis_sendsingle_handler sendfunc; 1610 __stdcall ndis_senddone_func senddonefunc; 1611 uint8_t irql = 0; /* XXX: gcc */ 1612 1613 sc = arg; 1614 adapter = sc->ndis_block->nmb_miniportadapterctx; 1615 if (adapter == NULL) 1616 return(ENXIO); 1617 sendfunc = sc->ndis_chars->nmc_sendsingle_func; 1618 senddonefunc = sc->ndis_block->nmb_senddone_func; 1619 1620 if (NDIS_SERIALIZED(sc->ndis_block)) 1621 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1622 status = MSCALL3(sendfunc, adapter, packet, 1623 packet->np_private.npp_flags); 1624 1625 if (status == NDIS_STATUS_PENDING) { 1626 if (NDIS_SERIALIZED(sc->ndis_block)) 1627 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1628 return(0); 1629 } 1630 1631 MSCALL3(senddonefunc, sc->ndis_block, packet, status); 1632 1633 if (NDIS_SERIALIZED(sc->ndis_block)) 1634 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1635 1636 return(0); 1637} 1638 1639int 1640ndis_init_dma(void *arg) 1641{ 1642 struct ndis_softc *sc; 1643 int i, error = 0; 1644 1645 sc = arg; 1646 1647 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1648 M_DEVBUF, M_NOWAIT|M_ZERO); 1649 1650 if (sc->ndis_tmaps == NULL) 1651 return(ENOMEM); 1652 1653 for (i = 0; i < sc->ndis_maxpkts; i++) { 1654#ifdef __FreeBSD__ 1655 error = bus_dmamap_create(sc->ndis_ttag, 0, 1656 &sc->ndis_tmaps[i]); 1657#else 1658 /* 1659 bus_dmamap_create(sc->ndis_mtag, sizeof(bus_dmamap_t), 1660 1, sizeof(bus_dmamap_t), BUS_DMA_NOWAIT, 1661 0, &sc->ndis_mmaps[i]); 1662 */ 1663 bus_dmamap_create(sc->ndis_ttag, NDIS_MAXSEG * MCLBYTES, 1664 NDIS_MAXSEG, MCLBYTES, 0, 1665 BUS_DMA_NOWAIT, &sc->ndis_tmaps[i]); 1666#endif 1667 if (error) { 1668 free(sc->ndis_tmaps, M_DEVBUF); 1669 return(ENODEV); 1670 } 1671 } 1672 1673 return(0); 1674} 1675 1676int 1677ndis_destroy_dma(void *arg) 1678{ 1679 struct ndis_softc *sc; 1680 struct mbuf *m; 1681 ndis_packet *p = NULL; 1682 int i; 1683 1684 sc = arg; 1685 1686 for (i = 0; i < sc->ndis_maxpkts; i++) { 1687 if (sc->ndis_txarray[i] != NULL) { 1688 p = sc->ndis_txarray[i]; 1689 m = (struct mbuf *)p->np_rsvd[1]; 1690 if (m != NULL) 1691 m_freem(m); 1692 ndis_free_packet(sc->ndis_txarray[i]); 1693 } 1694 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1695 } 1696 1697 free(sc->ndis_tmaps, M_DEVBUF); 1698 1699#ifdef __FreeBSD__ 1700 bus_dma_tag_destroy(sc->ndis_ttag); 1701#endif 1702 1703 return(0); 1704} 1705 1706int 1707ndis_reset_nic(void *arg) 1708{ 1709 struct ndis_softc *sc; 1710 ndis_handle adapter; 1711 __stdcall ndis_reset_handler resetfunc; 1712 uint8_t addressing_reset; 1713 struct ifnet *ifp; 1714 int rval; 1715 uint8_t irql = 0; /* XXX: gcc */ 1716 1717 sc = arg; 1718#ifdef __FreeBSD__ 1719 ifp = &sc->arpcom.ac_if; 1720#else 1721 ifp = &sc->arpcom.ec_if; 1722#endif 1723 1724 adapter = sc->ndis_block->nmb_miniportadapterctx; 1725 resetfunc = sc->ndis_chars->nmc_reset_func; 1726 1727 if (adapter == NULL || resetfunc == NULL) 1728 return(EIO); 1729 1730 if (NDIS_SERIALIZED(sc->ndis_block)) 1731 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1732 1733 rval = MSCALL2(resetfunc, &addressing_reset, adapter); 1734 1735 if (NDIS_SERIALIZED(sc->ndis_block)) 1736 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1737 1738 if (rval == NDIS_STATUS_PENDING) { 1739 mtsleep(sc, PZERO | PNORELOCK, "ndisrst", 0, &ndis_req_mtx); 1740 } 1741 1742 return(0); 1743} 1744 1745int 1746ndis_halt_nic(void *arg) 1747{ 1748 struct ndis_softc *sc; 1749 ndis_handle adapter; 1750 __stdcall ndis_halt_handler haltfunc; 1751 struct ifnet *ifp; 1752 1753 sc = arg; 1754#ifdef __FreeBSD__ 1755 ifp = &sc->arpcom.ac_if; 1756#else 1757 ifp = &sc->arpcom.ec_if; 1758#endif 1759 1760 NDIS_LOCK(sc); 1761 1762 adapter = sc->ndis_block->nmb_miniportadapterctx; 1763 if (adapter == NULL) { 1764 NDIS_UNLOCK(sc); 1765 return(EIO); 1766 } 1767 1768 /* 1769 * The adapter context is only valid after the init 1770 * handler has been called, and is invalid once the 1771 * halt handler has been called. 1772 */ 1773 1774 haltfunc = sc->ndis_chars->nmc_halt_func; 1775 1776 NDIS_UNLOCK(sc); 1777 1778 MSCALL1(haltfunc, adapter); 1779 1780 NDIS_LOCK(sc); 1781 1782 sc->ndis_block->nmb_miniportadapterctx = NULL; 1783 1784 NDIS_UNLOCK(sc); 1785 1786 return(0); 1787} 1788 1789int 1790ndis_shutdown_nic(void *arg) 1791{ 1792 struct ndis_softc *sc; 1793 ndis_handle adapter; 1794 __stdcall ndis_shutdown_handler shutdownfunc; 1795 1796 sc = arg; 1797 1798 NDIS_LOCK(sc); 1799 1800 adapter = sc->ndis_block->nmb_miniportadapterctx; 1801 shutdownfunc = sc->ndis_chars->nmc_shutdown_handler; 1802 1803 NDIS_UNLOCK(sc); 1804 1805 if (adapter == NULL || shutdownfunc == NULL) 1806 return(EIO); 1807 1808 if (sc->ndis_chars->nmc_rsvd0 == NULL) 1809 MSCALL1(shutdownfunc, adapter); 1810 else 1811 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0); 1812 1813 ndis_shrink_thrqueue(8); 1814 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 1815 1816 return(0); 1817} 1818 1819int 1820ndis_init_nic(void *arg) 1821{ 1822 struct ndis_softc *sc; 1823 ndis_miniport_block *block; 1824 __stdcall ndis_init_handler initfunc; 1825 ndis_status status, openstatus = 0; 1826 ndis_medium mediumarray[NdisMediumMax]; 1827 uint32_t chosenmedium, i; 1828 1829 if (arg == NULL) 1830 return(EINVAL); 1831 1832 sc = arg; 1833 1834 NDIS_LOCK(sc); 1835 1836 block = sc->ndis_block; 1837 initfunc = sc->ndis_chars->nmc_init_func; 1838 1839 NDIS_UNLOCK(sc); 1840 1841 printf("sc->ndis_chars->nmc_version_major = %d\n\ 1842 sc->ndis_chars->nmc_version_minor = %d\n", 1843 sc->ndis_chars->nmc_version_major, 1844 sc->ndis_chars->nmc_version_minor); 1845 1846 for (i = 0; i < NdisMediumMax; i++) 1847 mediumarray[i] = i; 1848 1849 status = MSCALL6(initfunc, &openstatus, &chosenmedium, 1850 mediumarray, NdisMediumMax, block, block); 1851 1852 printf("status = %x", status); 1853 1854 /* 1855 * If the init fails, blow away the other exported routines 1856 * we obtained from the driver so we can't call them later. 1857 * If the init failed, none of these will work. 1858 */ 1859 if (status != NDIS_STATUS_SUCCESS) { 1860 NDIS_LOCK(sc); 1861 1862 sc->ndis_block->nmb_miniportadapterctx = NULL; 1863 1864 NDIS_UNLOCK(sc); 1865 return(ENXIO); 1866 } 1867 1868 return(0); 1869} 1870 1871void 1872ndis_enable_intr(void *arg) 1873{ 1874 struct ndis_softc *sc; 1875 ndis_handle adapter; 1876 __stdcall ndis_enable_interrupts_handler intrenbfunc; 1877 1878 sc = arg; 1879 adapter = sc->ndis_block->nmb_miniportadapterctx; 1880 intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func; 1881 if (adapter == NULL || intrenbfunc == NULL) 1882 return; 1883 MSCALL1(intrenbfunc, adapter); 1884 1885 return; 1886} 1887 1888void 1889ndis_disable_intr(void *arg) 1890{ 1891 struct ndis_softc *sc; 1892 ndis_handle adapter; 1893 __stdcall ndis_disable_interrupts_handler intrdisfunc; 1894 1895 sc = arg; 1896 adapter = sc->ndis_block->nmb_miniportadapterctx; 1897 intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func; 1898 if (adapter == NULL || intrdisfunc == NULL) 1899 return; 1900 1901 MSCALL1(intrdisfunc, adapter); 1902 1903 return; 1904} 1905 1906int 1907ndis_isr(void *arg, int *ourintr, int *callhandler) 1908{ 1909 struct ndis_softc *sc; 1910 ndis_handle adapter; 1911 __stdcall ndis_isr_handler isrfunc; 1912 uint8_t accepted, queue; 1913 1914 if (arg == NULL || ourintr == NULL || callhandler == NULL) 1915 return(EINVAL); 1916 1917 sc = arg; 1918 adapter = sc->ndis_block->nmb_miniportadapterctx; 1919 isrfunc = sc->ndis_chars->nmc_isr_func; 1920 1921 if (adapter == NULL || isrfunc == NULL) 1922 return(ENXIO); 1923 1924 MSCALL3(isrfunc, &accepted, &queue, adapter); 1925 1926 *ourintr = accepted; 1927 *callhandler = queue; 1928 1929 return(0); 1930} 1931 1932__stdcall static void 1933ndis_intrhand(kdpc *dpc, device_object *dobj, 1934 irp *ip, struct ndis_softc *sc) 1935{ 1936 ndis_handle adapter; 1937 __stdcall ndis_interrupt_handler intrfunc; 1938 uint8_t irql = 0; /* XXX: gcc */ 1939 1940 adapter = sc->ndis_block->nmb_miniportadapterctx; 1941 intrfunc = sc->ndis_chars->nmc_interrupt_func; 1942 1943 if (adapter == NULL || intrfunc == NULL) 1944 return; 1945 1946 if (NDIS_SERIALIZED(sc->ndis_block)) 1947 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1948 1949 MSCALL1(intrfunc, adapter); 1950 1951 /* If there's a MiniportEnableInterrupt() routine, call it. */ 1952 1953 ndis_enable_intr(sc); 1954 1955 if (NDIS_SERIALIZED(sc->ndis_block)) 1956 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1957 1958 return; 1959} 1960 1961int 1962ndis_get_info(void *arg, ndis_oid oid, void *buf, int *buflen) 1963{ 1964 struct ndis_softc *sc; 1965 ndis_status rval; 1966 ndis_handle adapter; 1967 __stdcall ndis_queryinfo_handler queryfunc; 1968 uint32_t byteswritten = 0, bytesneeded = 0; 1969#ifdef __FreeBSD__ 1970 int error; 1971#endif 1972 uint8_t irql = 0; /* XXX: gcc */ 1973 1974 //printf("in ndis_get_info\n"); 1975 1976 sc = arg; 1977 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql); 1978 1979 if (sc->ndis_block->nmb_pendingreq != NULL) 1980 panic("ndis_get_info() called while other request pending"); 1981 else 1982 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc; 1983 1984 queryfunc = sc->ndis_chars->nmc_queryinfo_func; 1985 adapter = sc->ndis_block->nmb_miniportadapterctx; 1986 1987 if (adapter == NULL || queryfunc == NULL) { 1988 sc->ndis_block->nmb_pendingreq = NULL; 1989 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1990 return(ENXIO); 1991 } 1992 1993 rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen, 1994 &byteswritten, &bytesneeded); 1995 1996 sc->ndis_block->nmb_pendingreq = NULL; 1997 1998 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql); 1999 2000 /* Wait for requests that block. */ 2001 2002 if (rval == NDIS_STATUS_PENDING) { 2003 mtx_lock(&ndis_req_mtx); 2004 mtsleep(&sc->ndis_block->nmb_getstat, PZERO | PNORELOCK, 2005 "ndisget", 5 * hz, &ndis_req_mtx); 2006 rval = sc->ndis_block->nmb_getstat; 2007 } 2008 2009 if (byteswritten) 2010 *buflen = byteswritten; 2011 if (bytesneeded) 2012 *buflen = bytesneeded; 2013 2014 if (rval == NDIS_STATUS_INVALID_LENGTH || 2015 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 2016 return(ENOSPC); 2017 2018 if (rval == NDIS_STATUS_INVALID_OID) 2019 return(EINVAL); 2020 2021 if (rval == NDIS_STATUS_NOT_SUPPORTED || 2022 rval == NDIS_STATUS_NOT_ACCEPTED) 2023 return(ENOTSUP); 2024 2025 if (rval != NDIS_STATUS_SUCCESS) 2026 return(ENODEV); 2027 2028 return(0); 2029} 2030 2031__stdcall uint32_t 2032NdisAddDevice(driver_object *drv, device_object *pdo) 2033{ 2034 device_object *fdo; 2035 ndis_miniport_block *block; 2036 struct ndis_softc *sc; 2037 uint32_t status; 2038 2039 status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL, 2040 FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo); 2041 2042 if (status != STATUS_SUCCESS) 2043 return(status); 2044 2045 block = fdo->do_devext; 2046 block->nmb_deviceobj = fdo; 2047 block->nmb_physdeviceobj = pdo; 2048 block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo); 2049 KeInitializeSpinLock(&block->nmb_lock); 2050 2051#ifdef __NetBSD__ 2052 /* NetBSD has a pointer to the callout object */ 2053 block->nmb_wkupdpctimer.nt_ktimer.k_handle = 2054 malloc(sizeof(struct callout), M_DEVBUF, M_NOWAIT|M_ZERO); 2055#endif 2056 2057 /* 2058 * Stash pointers to the miniport block and miniport 2059 * characteristics info in the if_ndis softc so the 2060 * UNIX wrapper driver can get to them later. 2061 */ 2062#ifdef __FreeBSD__ 2063 sc = device_get_softc(pdo->do_devext); 2064#else /* __NetBSD__ */ 2065 sc = pdo->pdo_sc; 2066 fdo->fdo_sc = sc; 2067#endif 2068 sc->ndis_block = block; 2069 sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1); 2070 2071 IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap); 2072 2073 /* Finish up BSD-specific setup. */ 2074 2075 block->nmb_signature = (void *)0xcafebabe; 2076 block->nmb_status_func = kernndis_functbl[0].ipt_wrap; 2077 block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap; 2078 block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap; 2079 block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap; 2080 block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap; 2081 block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap; 2082 block->nmb_pendingreq = NULL; 2083 2084 ndis_enlarge_thrqueue(8); 2085 2086 TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 2087 2088 return (STATUS_SUCCESS); 2089} 2090 2091int 2092ndis_unload_driver(void *arg) 2093{ 2094 struct ndis_softc *sc; 2095 device_object *fdo; 2096 2097 sc = arg; 2098 2099 if (sc->ndis_block->nmb_rlist != NULL) 2100 free(sc->ndis_block->nmb_rlist, M_DEVBUF); 2101 2102 ndis_flush_sysctls(sc); 2103 2104 ndis_shrink_thrqueue(8); 2105 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link); 2106 2107 fdo = sc->ndis_block->nmb_deviceobj; 2108 IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj); 2109 IoDeleteDevice(fdo); 2110 2111 return(0); 2112} 2113