kern_ndis.c revision 124005
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 124005 2003-12-30 21:33:26Z wpaul $"); 35 36#include <sys/param.h> 37#include <sys/types.h> 38#include <sys/errno.h> 39#include <sys/callout.h> 40#include <sys/socket.h> 41#include <sys/queue.h> 42#include <sys/sysctl.h> 43#include <sys/systm.h> 44#include <sys/malloc.h> 45#include <sys/lock.h> 46#include <sys/mutex.h> 47#include <sys/conf.h> 48 49#include <sys/kernel.h> 50#include <machine/bus.h> 51#include <machine/resource.h> 52#include <sys/bus.h> 53#include <sys/rman.h> 54 55#include <net/if.h> 56#include <net/if_arp.h> 57#include <net/ethernet.h> 58#include <net/if_dl.h> 59#include <net/if_media.h> 60 61#include <net80211/ieee80211_var.h> 62#include <net80211/ieee80211_ioctl.h> 63 64#include <dev/pccard/pccardvar.h> 65#include "card_if.h" 66 67#include <compat/ndis/pe_var.h> 68#include <compat/ndis/resource_var.h> 69#include <compat/ndis/ndis_var.h> 70#include <compat/ndis/hal_var.h> 71#include <compat/ndis/ntoskrnl_var.h> 72#include <compat/ndis/cfg_var.h> 73#include <dev/if_ndis/if_ndisvar.h> 74 75#define __stdcall __attribute__((__stdcall__)) 76#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 77 78__stdcall static void ndis_status_func(ndis_handle, ndis_status, 79 void *, uint32_t); 80__stdcall static void ndis_statusdone_func(ndis_handle); 81__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 82__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 83__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 84 85/* 86 * This allows us to export our symbols to other modules. 87 * Note that we call ourselves 'ndisapi' to avoid a namespace 88 * collision with if_ndis.ko, which internally calls itself 89 * 'ndis.' 90 */ 91static int 92ndis_modevent(module_t mod, int cmd, void *arg) 93{ 94 return(0); 95} 96DEV_MODULE(ndisapi, ndis_modevent, NULL); 97MODULE_VERSION(ndisapi, 1); 98 99 100__stdcall static void 101ndis_status_func(adapter, status, sbuf, slen) 102 ndis_handle adapter; 103 ndis_status status; 104 void *sbuf; 105 uint32_t slen; 106{ 107 printf ("status: %x\n", status); 108 return; 109} 110 111__stdcall static void 112ndis_statusdone_func(adapter) 113 ndis_handle adapter; 114{ 115 printf ("status complete\n"); 116 return; 117} 118 119__stdcall static void 120ndis_setdone_func(adapter, status) 121 ndis_handle adapter; 122 ndis_status status; 123{ 124 ndis_miniport_block *block; 125 block = adapter; 126 127 block->nmb_setstat = status; 128 wakeup(&block->nmb_wkupdpctimer); 129 return; 130} 131 132__stdcall static void 133ndis_getdone_func(adapter, status) 134 ndis_handle adapter; 135 ndis_status status; 136{ 137 ndis_miniport_block *block; 138 block = adapter; 139 140 block->nmb_getstat = status; 141 wakeup(&block->nmb_wkupdpctimer); 142 return; 143} 144 145__stdcall static void 146ndis_resetdone_func(adapter, status, addressingreset) 147 ndis_handle adapter; 148 ndis_status status; 149 uint8_t addressingreset; 150{ 151 printf ("reset done...\n"); 152 return; 153} 154 155#define NDIS_AM_RID 3 156 157int 158ndis_alloc_amem(arg) 159 void *arg; 160{ 161 struct ndis_softc *sc; 162 int error, rid; 163 164 if (arg == NULL) 165 return(EINVAL); 166 167 sc = arg; 168 rid = NDIS_AM_RID; 169 sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 170 &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 171 172 if (sc->ndis_res_am == NULL) { 173 printf("ndis%d: failed to allocate attribute memory\n", 174 sc->ndis_unit); 175 return(ENXIO); 176 } 177 178 error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 179 sc->ndis_dev, rid, 0, NULL); 180 181 if (error) { 182 printf("ndis%d: CARD_SET_MEMORY_OFFSET() returned 0x%x\n", 183 sc->ndis_unit, error); 184 return(error); 185 } 186 187 error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 188 sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 189 190 if (error) { 191 printf("ndis%d: CARD_SET_RES_FLAGS() returned 0x%x\n", 192 sc->ndis_unit, error); 193 return(error); 194 } 195 196 return(0); 197} 198 199int 200ndis_create_sysctls(arg) 201 void *arg; 202{ 203 struct ndis_softc *sc; 204 ndis_cfg *vals; 205 char buf[256]; 206 207 if (arg == NULL) 208 return(EINVAL); 209 210 sc = arg; 211 vals = sc->ndis_regvals; 212 213 TAILQ_INIT(&sc->ndis_cfglist_head); 214 215 /* Create the sysctl tree. */ 216 217 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 218 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 219 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 220 device_get_desc(sc->ndis_dev)); 221 222 /* Add the driver-specific registry keys. */ 223 224 vals = sc->ndis_regvals; 225 while(1) { 226 if (vals->nc_cfgkey == NULL) 227 break; 228 if (vals->nc_idx != sc->ndis_devidx) { 229 vals++; 230 continue; 231 } 232 SYSCTL_ADD_STRING(&sc->ndis_ctx, 233 SYSCTL_CHILDREN(sc->ndis_tree), 234 OID_AUTO, vals->nc_cfgkey, 235 CTLFLAG_RW, vals->nc_val, 236 sizeof(vals->nc_val), 237 vals->nc_cfgdesc); 238 vals++; 239 } 240 241 /* Now add a couple of builtin keys. */ 242 243 /* 244 * Environment can be either Windows (0) or WindowsNT (1). 245 * We qualify as the latter. 246 */ 247 ndis_add_sysctl(sc, "Environment", 248 "Windows environment", "1", CTLFLAG_RD); 249 250 /* NDIS version should be 5.1. */ 251 ndis_add_sysctl(sc, "NdisVersion", 252 "NDIS API Version", "0x00050001", CTLFLAG_RD); 253 254 /* Bus type (PCI, PCMCIA, etc...) */ 255 sprintf(buf, "%d\n", (int)sc->ndis_iftype); 256 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 257 258 if (sc->ndis_res_io != NULL) { 259 sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io)); 260 ndis_add_sysctl(sc, "IOBaseAddress", 261 "Base I/O Address", buf, CTLFLAG_RD); 262 } 263 264 if (sc->ndis_irq != NULL) { 265 sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq)); 266 ndis_add_sysctl(sc, "InterruptNumber", 267 "Interrupt Number", buf, CTLFLAG_RD); 268 } 269 270 return(0); 271} 272 273int 274ndis_add_sysctl(arg, key, desc, val, flag) 275 void *arg; 276 char *key; 277 char *desc; 278 char *val; 279 int flag; 280{ 281 struct ndis_softc *sc; 282 struct ndis_cfglist *cfg; 283 char descstr[256]; 284 285 sc = arg; 286 287 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 288 289 if (cfg == NULL) 290 return(ENOMEM); 291 292 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 293 if (desc == NULL) { 294 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 295 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 296 } else 297 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 298 strcpy(cfg->ndis_cfg.nc_val, val); 299 300 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 301 302 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 303 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 304 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 305 cfg->ndis_cfg.nc_cfgdesc); 306 307 return(0); 308} 309 310int 311ndis_flush_sysctls(arg) 312 void *arg; 313{ 314 struct ndis_softc *sc; 315 struct ndis_cfglist *cfg; 316 317 sc = arg; 318 319 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 320 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 321 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 322 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 323 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 324 free(cfg, M_DEVBUF); 325 } 326 327 return(0); 328} 329 330void 331ndis_return_packet(buf, arg) 332 void *buf; /* not used */ 333 void *arg; 334{ 335 struct ndis_softc *sc; 336 ndis_handle adapter; 337 ndis_packet *p; 338 __stdcall ndis_return_handler returnfunc; 339 340 if (arg == NULL) 341 return; 342 343 p = arg; 344 345 /* Decrement refcount. */ 346 p->np_refcnt--; 347 348 /* Release packet when refcount hits zero, otherwise return. */ 349 if (p->np_refcnt) 350 return; 351 352 sc = p->np_softc; 353 returnfunc = sc->ndis_chars.nmc_return_packet_func; 354 adapter = sc->ndis_block.nmb_miniportadapterctx; 355 if (returnfunc != NULL) 356 returnfunc(adapter, p); 357 358 return; 359} 360 361void 362ndis_free_bufs(b0) 363 ndis_buffer *b0; 364{ 365 ndis_buffer *next; 366 367 if (b0 == NULL) 368 return; 369 370 while(b0 != NULL) { 371 next = b0->nb_next; 372 free (b0, M_DEVBUF); 373 b0 = next; 374 } 375 376 return; 377} 378 379void 380ndis_free_packet(p) 381 ndis_packet *p; 382{ 383 if (p == NULL) 384 return; 385 386 ndis_free_bufs(p->np_private.npp_head); 387 free(p, M_DEVBUF); 388 389 return; 390} 391 392int 393ndis_convert_res(arg) 394 void *arg; 395{ 396 struct ndis_softc *sc; 397 ndis_resource_list *rl = NULL; 398 cm_partial_resource_desc *prd = NULL; 399 ndis_miniport_block *block; 400 device_t dev; 401 struct resource_list *brl; 402 struct resource_list_entry *brle; 403 404 sc = arg; 405 block = &sc->ndis_block; 406 dev = sc->ndis_dev; 407 408 rl = malloc(sizeof(ndis_resource_list) + 409 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 410 M_DEVBUF, M_NOWAIT|M_ZERO); 411 412 if (rl == NULL) 413 return(ENOMEM); 414 415 rl->cprl_version = 5; 416 rl->cprl_version = 1; 417 rl->cprl_count = sc->ndis_rescnt; 418 prd = rl->cprl_partial_descs; 419 420 brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 421 if (brl != NULL) { 422 SLIST_FOREACH(brle, brl, link) { 423 switch (brle->type) { 424 case SYS_RES_IOPORT: 425 prd->cprd_type = CmResourceTypePort; 426 prd->u.cprd_port.cprd_start.np_quad = 427 brle->start; 428 prd->u.cprd_port.cprd_len = brle->count; 429 break; 430 case SYS_RES_MEMORY: 431 prd->cprd_type = CmResourceTypeMemory; 432 prd->u.cprd_port.cprd_start.np_quad = 433 brle->start; 434 prd->u.cprd_port.cprd_len = brle->count; 435 break; 436 case SYS_RES_IRQ: 437 prd->cprd_type = CmResourceTypeInterrupt; 438 prd->u.cprd_intr.cprd_level = brle->start; 439 prd->u.cprd_intr.cprd_vector = brle->start; 440 prd->u.cprd_intr.cprd_affinity = 0; 441 break; 442 default: 443 break; 444 } 445 prd++; 446 } 447 } 448 449 block->nmb_rlist = rl; 450 451 return(0); 452} 453 454/* 455 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 456 * packet, it will hand it to us in the form of an ndis_packet, 457 * which we need to convert to an mbuf that is then handed off 458 * to the stack. Note: we configure the mbuf list so that it uses 459 * the memory regions specified by the ndis_buffer structures in 460 * the ndis_packet as external storage. In most cases, this will 461 * point to a memory region allocated by the driver (either by 462 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 463 * the driver to handle free()ing this region for is, so we set up 464 * a dummy no-op free handler for it. 465 */ 466 467int 468ndis_ptom(m0, p) 469 struct mbuf **m0; 470 ndis_packet *p; 471{ 472 struct mbuf *m, *prev = NULL; 473 ndis_buffer *buf; 474 ndis_packet_private *priv; 475 uint32_t totlen = 0; 476 477 if (p == NULL || m0 == NULL) 478 return(EINVAL); 479 480 priv = &p->np_private; 481 buf = priv->npp_head; 482 p->np_refcnt = 0; 483 484 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 485 if (buf == priv->npp_head) 486 MGETHDR(m, M_DONTWAIT, MT_HEADER); 487 else 488 MGET(m, M_DONTWAIT, MT_DATA); 489 if (m == NULL) { 490 m_freem(*m0); 491 *m0 = NULL; 492 return(ENOBUFS); 493 } 494 m->m_len = buf->nb_bytecount; 495 m->m_data = MDL_VA(buf); 496 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 497 p, 0, EXT_NDIS); 498 p->np_refcnt++; 499 totlen += m->m_len; 500 if (m->m_flags & MT_HEADER) 501 *m0 = m; 502 else 503 prev->m_next = m; 504 prev = m; 505 } 506 507 (*m0)->m_pkthdr.len = totlen; 508 509 return(0); 510} 511 512/* 513 * Create an mbuf chain from an NDIS packet chain. 514 * This is used mainly when transmitting packets, where we need 515 * to turn an mbuf off an interface's send queue and transform it 516 * into an NDIS packet which will be fed into the NDIS driver's 517 * send routine. 518 * 519 * NDIS packets consist of two parts: an ndis_packet structure, 520 * which is vaguely analagous to the pkthdr portion of an mbuf, 521 * and one or more ndis_buffer structures, which define the 522 * actual memory segments in which the packet data resides. 523 * We need to allocate one ndis_buffer for each mbuf in a chain, 524 * plus one ndis_packet as the header. 525 */ 526 527int 528ndis_mtop(m0, p) 529 struct mbuf *m0; 530 ndis_packet **p; 531{ 532 struct mbuf *m; 533 ndis_buffer *buf = NULL, *prev = NULL; 534 ndis_packet_private *priv; 535 536 if (p == NULL || m0 == NULL) 537 return(EINVAL); 538 539 /* If caller didn't supply a packet, make one. */ 540 if (*p == NULL) { 541 *p = malloc(sizeof(ndis_packet), M_DEVBUF, M_NOWAIT|M_ZERO); 542 543 if (*p == NULL) 544 return(ENOMEM); 545 } 546 547 priv = &(*p)->np_private; 548 priv->npp_totlen = m0->m_pkthdr.len; 549 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 550 551 for (m = m0; m != NULL; m = m->m_next) { 552 if (m->m_len == 0) 553 continue; 554 buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO); 555 if (buf == NULL) { 556 ndis_free_packet(*p); 557 *p = NULL; 558 return(ENOMEM); 559 } 560 561 MDL_INIT(buf, m->m_data, m->m_len); 562 if (priv->npp_head == NULL) 563 priv->npp_head = buf; 564 else 565 prev->nb_next = buf; 566 prev = buf; 567 } 568 569 priv->npp_tail = buf; 570 571 return(0); 572} 573 574int 575ndis_get_supported_oids(arg, oids, oidcnt) 576 void *arg; 577 ndis_oid **oids; 578 int *oidcnt; 579{ 580 int len, rval; 581 ndis_oid *o; 582 583 if (arg == NULL || oids == NULL || oidcnt == NULL) 584 return(EINVAL); 585 len = 0; 586 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 587 588 o = malloc(len, M_DEVBUF, M_NOWAIT); 589 if (o == NULL) 590 return(ENOMEM); 591 592 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 593 594 if (rval) { 595 free(o, M_DEVBUF); 596 return(rval); 597 } 598 599 *oids = o; 600 *oidcnt = len / 4; 601 602 return(0); 603} 604 605int 606ndis_set_info(arg, oid, buf, buflen) 607 void *arg; 608 ndis_oid oid; 609 void *buf; 610 int *buflen; 611{ 612 struct ndis_softc *sc; 613 ndis_status rval; 614 ndis_handle adapter; 615 __stdcall ndis_setinfo_handler setfunc; 616 uint32_t byteswritten = 0, bytesneeded = 0; 617 struct timeval tv; 618 int error; 619 620 sc = arg; 621 setfunc = sc->ndis_chars.nmc_setinfo_func; 622 adapter = sc->ndis_block.nmb_miniportadapterctx; 623 624 rval = setfunc(adapter, oid, buf, *buflen, 625 &byteswritten, &bytesneeded); 626 627 if (rval == NDIS_STATUS_PENDING) { 628 tv.tv_sec = 60; 629 tv.tv_usec = 0; 630 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 631 PPAUSE|PCATCH, "ndisset", tvtohz(&tv)); 632 rval = sc->ndis_block.nmb_setstat; 633 } 634 635 if (byteswritten) 636 *buflen = byteswritten; 637 if (bytesneeded) 638 *buflen = bytesneeded; 639 640 if (rval == NDIS_STATUS_INVALID_LENGTH) 641 return(ENOSPC); 642 643 if (rval == NDIS_STATUS_INVALID_OID) 644 return(EINVAL); 645 646 if (rval == NDIS_STATUS_NOT_SUPPORTED || 647 rval == NDIS_STATUS_NOT_ACCEPTED) 648 return(ENOTSUP); 649 650 return(0); 651} 652 653int 654ndis_send_packets(arg, packets, cnt) 655 void *arg; 656 ndis_packet **packets; 657 int cnt; 658{ 659 struct ndis_softc *sc; 660 ndis_handle adapter; 661 __stdcall ndis_sendmulti_handler sendfunc; 662 int i, idx; 663 struct ifnet *ifp; 664 struct mbuf *m; 665 ndis_packet *p; 666 667 sc = arg; 668 adapter = sc->ndis_block.nmb_miniportadapterctx; 669 sendfunc = sc->ndis_chars.nmc_sendmulti_func; 670 sendfunc(adapter, packets, cnt); 671 672 for (i = 0; i < cnt; i++) { 673 p = packets[i]; 674 /* 675 * Either the driver already handed the packet to 676 * ndis_txeof() due to a failure, or it wants to keep 677 * it and release it asynchronously later. Skip to the 678 * next one. 679 */ 680 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 681 continue; 682 idx = p->np_txidx; 683 m = p->np_m0; 684 ifp = &sc->arpcom.ac_if; 685 if (sc->ndis_sc) 686 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]); 687 sc->ndis_txarray[idx] = NULL; 688 sc->ndis_txpending++; 689 m_freem(m); 690 ndis_free_packet(p); 691 if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) 692 ifp->if_opackets++; 693 else 694 ifp->if_oerrors++; 695 ifp->if_timer = 0; 696 ifp->if_flags &= ~IFF_OACTIVE; 697 } 698 699 return(0); 700} 701 702int 703ndis_init_dma(arg) 704 void *arg; 705{ 706 struct ndis_softc *sc; 707 int i, error; 708 709 sc = arg; 710 711 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 712 M_DEVBUF, M_NOWAIT|M_ZERO); 713 714 if (sc->ndis_tmaps == NULL) 715 return(ENOMEM); 716 717 for (i = 0; i < sc->ndis_maxpkts; i++) { 718 error = bus_dmamap_create(sc->ndis_ttag, 0, 719 &sc->ndis_tmaps[i]); 720 if (error) { 721 free(sc->ndis_tmaps, M_DEVBUF); 722 return(ENODEV); 723 } 724 } 725 726 return(0); 727} 728 729int 730ndis_destroy_dma(arg) 731 void *arg; 732{ 733 struct ndis_softc *sc; 734 struct mbuf *m; 735 ndis_packet *p = NULL; 736 int i; 737 738 sc = arg; 739 740 for (i = 0; i < sc->ndis_maxpkts; i++) { 741 if (sc->ndis_txarray[i] != NULL) { 742 p = sc->ndis_txarray[i]; 743 m = (struct mbuf *)p->np_rsvd[1]; 744 if (m != NULL) 745 m_freem(m); 746 ndis_free_packet(sc->ndis_txarray[i]); 747 } 748 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 749 } 750 751 free(sc->ndis_tmaps, M_DEVBUF); 752 753 bus_dma_tag_destroy(sc->ndis_ttag); 754 755 return(0); 756} 757 758int 759ndis_reset_nic(arg) 760 void *arg; 761{ 762 struct ndis_softc *sc; 763 ndis_handle adapter; 764 __stdcall ndis_reset_handler resetfunc; 765 uint8_t addressing_reset; 766 struct ifnet *ifp; 767 768 sc = arg; 769 ifp = &sc->arpcom.ac_if; 770 adapter = sc->ndis_block.nmb_miniportadapterctx; 771 if (adapter == NULL) 772 return(EIO); 773 resetfunc = sc->ndis_chars.nmc_reset_func; 774 775 if (resetfunc == NULL) 776 return(EINVAL); 777 778 resetfunc(&addressing_reset, adapter); 779 780 return(0); 781} 782 783int 784ndis_halt_nic(arg) 785 void *arg; 786{ 787 struct ndis_softc *sc; 788 ndis_handle adapter; 789 __stdcall ndis_halt_handler haltfunc; 790 struct ifnet *ifp; 791 struct ndis_timer_entry *ne; 792 793 sc = arg; 794 ifp = &sc->arpcom.ac_if; 795 adapter = sc->ndis_block.nmb_miniportadapterctx; 796 if (adapter == NULL) 797 return(EIO); 798 799 haltfunc = sc->ndis_chars.nmc_halt_func; 800 801 if (haltfunc == NULL) 802 return(EINVAL); 803 804 haltfunc(adapter); 805 806 /* 807 * The adapter context is only valid after the init 808 * handler has been called, and is invalid once the 809 * halt handler has been called. 810 */ 811 812 sc->ndis_block.nmb_miniportadapterctx = NULL; 813 814 /* Clobber all the timers in case the driver left one running. */ 815 816 while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) { 817 ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist); 818 TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link); 819 callout_stop(&ne->nte_ch); 820 free(ne, M_DEVBUF); 821 } 822 823 return(0); 824} 825 826int 827ndis_shutdown_nic(arg) 828 void *arg; 829{ 830 struct ndis_softc *sc; 831 ndis_handle adapter; 832 __stdcall ndis_shutdown_handler shutdownfunc; 833 834 835 sc = arg; 836 adapter = sc->ndis_block.nmb_miniportadapterctx; 837 if (adapter == NULL) 838 return(EIO); 839 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 840 841 if (shutdownfunc == NULL) 842 return(EINVAL); 843 844 if (sc->ndis_chars.nmc_rsvd0 == NULL) 845 shutdownfunc(adapter); 846 else 847 shutdownfunc(sc->ndis_chars.nmc_rsvd0); 848 849 return(0); 850} 851 852int 853ndis_init_nic(arg) 854 void *arg; 855{ 856 struct ndis_softc *sc; 857 ndis_miniport_block *block; 858 __stdcall ndis_init_handler initfunc; 859 ndis_status status, openstatus = 0; 860 ndis_medium mediumarray[NdisMediumMax]; 861 uint32_t chosenmedium, i; 862 863 if (arg == NULL) 864 return(EINVAL); 865 866 sc = arg; 867 block = &sc->ndis_block; 868 initfunc = sc->ndis_chars.nmc_init_func; 869 870 TAILQ_INIT(&block->nmb_timerlist); 871 872 for (i = 0; i < NdisMediumMax; i++) 873 mediumarray[i] = i; 874 875 status = initfunc(&openstatus, &chosenmedium, 876 mediumarray, NdisMediumMax, block, block); 877 878 /* 879 * If the init fails, blow away the other exported routines 880 * we obtained from the driver so we can't call them later. 881 * If the init failed, none of these will work. 882 */ 883 if (status != NDIS_STATUS_SUCCESS) { 884 bzero((char *)&sc->ndis_chars, 885 sizeof(ndis_miniport_characteristics)); 886 return(ENXIO); 887 } 888 889 return(0); 890} 891 892void 893ndis_enable_intr(arg) 894 void *arg; 895{ 896 struct ndis_softc *sc; 897 ndis_handle adapter; 898 __stdcall ndis_enable_interrupts_handler intrenbfunc; 899 900 sc = arg; 901 adapter = sc->ndis_block.nmb_miniportadapterctx; 902 if (adapter == NULL) 903 return; 904 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 905 if (intrenbfunc == NULL) 906 return; 907 intrenbfunc(adapter); 908 909 return; 910} 911 912void 913ndis_disable_intr(arg) 914 void *arg; 915{ 916 struct ndis_softc *sc; 917 ndis_handle adapter; 918 __stdcall ndis_disable_interrupts_handler intrdisfunc; 919 920 sc = arg; 921 adapter = sc->ndis_block.nmb_miniportadapterctx; 922 if (adapter == NULL) 923 return; 924 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 925 if (intrdisfunc == NULL) 926 return; 927 intrdisfunc(adapter); 928 929 return; 930} 931 932int 933ndis_isr(arg, ourintr, callhandler) 934 void *arg; 935 int *ourintr; 936 int *callhandler; 937{ 938 struct ndis_softc *sc; 939 ndis_handle adapter; 940 __stdcall ndis_isr_handler isrfunc; 941 uint8_t accepted, queue; 942 943 if (arg == NULL || ourintr == NULL || callhandler == NULL) 944 return(EINVAL); 945 946 sc = arg; 947 adapter = sc->ndis_block.nmb_miniportadapterctx; 948 isrfunc = sc->ndis_chars.nmc_isr_func; 949 isrfunc(&accepted, &queue, adapter); 950 *ourintr = accepted; 951 *callhandler = queue; 952 953 return(0); 954} 955 956int 957ndis_intrhand(arg) 958 void *arg; 959{ 960 struct ndis_softc *sc; 961 ndis_handle adapter; 962 __stdcall ndis_interrupt_handler intrfunc; 963 964 if (arg == NULL) 965 return(EINVAL); 966 967 sc = arg; 968 adapter = sc->ndis_block.nmb_miniportadapterctx; 969 intrfunc = sc->ndis_chars.nmc_interrupt_func; 970 intrfunc(adapter); 971 972 return(0); 973} 974 975int 976ndis_get_info(arg, oid, buf, buflen) 977 void *arg; 978 ndis_oid oid; 979 void *buf; 980 int *buflen; 981{ 982 struct ndis_softc *sc; 983 ndis_status rval; 984 ndis_handle adapter; 985 __stdcall ndis_queryinfo_handler queryfunc; 986 uint32_t byteswritten = 0, bytesneeded = 0; 987 struct timeval tv; 988 int error; 989 990 sc = arg; 991 queryfunc = sc->ndis_chars.nmc_queryinfo_func; 992 adapter = sc->ndis_block.nmb_miniportadapterctx; 993 994 rval = queryfunc(adapter, oid, buf, *buflen, 995 &byteswritten, &bytesneeded); 996 997 /* Wait for requests that block. */ 998 999 if (rval == NDIS_STATUS_PENDING) { 1000 tv.tv_sec = 60; 1001 tv.tv_usec = 0; 1002 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 1003 PPAUSE|PCATCH, "ndisget", tvtohz(&tv)); 1004 rval = sc->ndis_block.nmb_getstat; 1005 } 1006 1007 if (byteswritten) 1008 *buflen = byteswritten; 1009 if (bytesneeded) 1010 *buflen = bytesneeded; 1011 1012 if (rval == NDIS_STATUS_INVALID_LENGTH || 1013 rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1014 return(ENOSPC); 1015 1016 if (rval == NDIS_STATUS_INVALID_OID) 1017 return(EINVAL); 1018 1019 if (rval == NDIS_STATUS_NOT_SUPPORTED || 1020 rval == NDIS_STATUS_NOT_ACCEPTED) 1021 return(ENOTSUP); 1022 1023 return(0); 1024} 1025 1026int 1027ndis_unload_driver(arg) 1028 void *arg; 1029{ 1030 struct ndis_softc *sc; 1031 1032 sc = arg; 1033 1034 free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1035 1036 ndis_flush_sysctls(sc); 1037 ndis_libfini(); 1038 ntoskrnl_libfini(); 1039 1040 return(0); 1041} 1042 1043int 1044ndis_load_driver(img, arg) 1045 vm_offset_t img; 1046 void *arg; 1047{ 1048 __stdcall driver_entry entry; 1049 image_optional_header opt_hdr; 1050 image_import_descriptor imp_desc; 1051 ndis_unicode_string dummystr; 1052 ndis_driver_object drv; 1053 ndis_miniport_block *block; 1054 ndis_status status; 1055 int idx; 1056 uint32_t *ptr; 1057 struct ndis_softc *sc; 1058 1059 sc = arg; 1060 1061 /* Perform text relocation */ 1062 if (pe_relocate(img)) 1063 return(ENOEXEC); 1064 1065 /* Dynamically link the NDIS.SYS routines -- required. */ 1066 if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1067 return(ENOEXEC); 1068 1069 /* Dynamically link the HAL.dll routines -- also required. */ 1070 if (pe_patch_imports(img, "HAL", hal_functbl)) 1071 return(ENOEXEC); 1072 1073 /* Dynamically link ntoskrnl.exe -- optional. */ 1074 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) { 1075 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl)) 1076 return(ENOEXEC); 1077 } 1078 1079 /* Initialize subsystems */ 1080 ndis_libinit(); 1081 ntoskrnl_libinit(); 1082 1083 /* Locate the driver entry point */ 1084 pe_get_optional_header(img, &opt_hdr); 1085 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1086 1087 /* 1088 * Now call the DriverEntry() routine. This will cause 1089 * a callout to the NdisInitializeWrapper() and 1090 * NdisMRegisterMiniport() routines. 1091 */ 1092 dummystr.nus_len = strlen(NDIS_DUMMY_PATH); 1093 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH); 1094 dummystr.nus_buf = NULL; 1095 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1096 drv.ndo_ifname = "ndis0"; 1097 1098 status = entry(&drv, &dummystr); 1099 1100 free (dummystr.nus_buf, M_DEVBUF); 1101 1102 if (status != NDIS_STATUS_SUCCESS) 1103 return(ENODEV); 1104 1105 /* 1106 * Now that we have the miniport driver characteristics, 1107 * create an NDIS block and call the init handler. 1108 * This will cause the driver to try to probe for 1109 * a device. 1110 */ 1111 1112 block = &sc->ndis_block; 1113 bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars, 1114 sizeof(ndis_miniport_characteristics)); 1115 1116 /*block->nmb_signature = 0xcafebabe;*/ 1117 1118 ptr = (uint32_t *)block; 1119 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1120 *ptr = idx | 0xdead0000; 1121 ptr++; 1122 } 1123 1124 block->nmb_signature = (void *)0xcafebabe; 1125 block->nmb_setdone_func = ndis_setdone_func; 1126 block->nmb_querydone_func = ndis_getdone_func; 1127 block->nmb_status_func = ndis_status_func; 1128 block->nmb_statusdone_func = ndis_statusdone_func; 1129 block->nmb_resetdone_func = ndis_resetdone_func; 1130 1131 block->nmb_ifp = &sc->arpcom.ac_if; 1132 block->nmb_dev = sc->ndis_dev; 1133 1134 return(0); 1135} 1136