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