subr_ndis.c revision 179720
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/subr_ndis.c 179720 2008-06-11 07:55:07Z weongyo $"); 35 36/* 37 * This file implements a translation layer between the BSD networking 38 * infrasturcture and Windows(R) NDIS network driver modules. A Windows 39 * NDIS driver calls into several functions in the NDIS.SYS Windows 40 * kernel module and exports a table of functions designed to be called 41 * by the NDIS subsystem. Using the PE loader, we can patch our own 42 * versions of the NDIS routines into a given Windows driver module and 43 * convince the driver that it is in fact running on Windows. 44 * 45 * We provide a table of all our implemented NDIS routines which is patched 46 * into the driver object code. All our exported routines must use the 47 * _stdcall calling convention, since that's what the Windows object code 48 * expects. 49 */ 50 51 52#include <sys/ctype.h> 53#include <sys/param.h> 54#include <sys/types.h> 55#include <sys/errno.h> 56 57#include <sys/callout.h> 58#include <sys/kernel.h> 59#include <sys/systm.h> 60#include <sys/malloc.h> 61#include <sys/lock.h> 62#include <sys/mutex.h> 63#include <sys/socket.h> 64#include <sys/sysctl.h> 65#include <sys/timespec.h> 66#include <sys/smp.h> 67#include <sys/queue.h> 68#include <sys/proc.h> 69#include <sys/filedesc.h> 70#include <sys/namei.h> 71#include <sys/fcntl.h> 72#include <sys/vnode.h> 73#include <sys/kthread.h> 74#include <sys/linker.h> 75#include <sys/mount.h> 76#include <sys/sysproto.h> 77 78#include <net/if.h> 79#include <net/if_arp.h> 80#include <net/ethernet.h> 81#include <net/if_dl.h> 82#include <net/if_media.h> 83 84#include <machine/atomic.h> 85#include <machine/bus.h> 86#include <machine/resource.h> 87 88#include <sys/bus.h> 89#include <sys/rman.h> 90 91#include <machine/stdarg.h> 92 93#include <net80211/ieee80211_var.h> 94#include <net80211/ieee80211_ioctl.h> 95 96#include <dev/pci/pcireg.h> 97#include <dev/pci/pcivar.h> 98 99#include <compat/ndis/pe_var.h> 100#include <compat/ndis/cfg_var.h> 101#include <compat/ndis/resource_var.h> 102#include <compat/ndis/ntoskrnl_var.h> 103#include <compat/ndis/hal_var.h> 104#include <compat/ndis/ndis_var.h> 105#include <dev/if_ndis/if_ndisvar.h> 106 107#include <vm/vm.h> 108#include <vm/vm_param.h> 109#include <vm/pmap.h> 110#include <vm/uma.h> 111#include <vm/vm_kern.h> 112#include <vm/vm_map.h> 113 114static char ndis_filepath[MAXPATHLEN]; 115 116SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath, 117 MAXPATHLEN, "Path used by NdisOpenFile() to search for files"); 118 119static void NdisInitializeWrapper(ndis_handle *, 120 driver_object *, void *, void *); 121static ndis_status NdisMRegisterMiniport(ndis_handle, 122 ndis_miniport_characteristics *, int); 123static ndis_status NdisAllocateMemoryWithTag(void **, 124 uint32_t, uint32_t); 125static ndis_status NdisAllocateMemory(void **, 126 uint32_t, uint32_t, ndis_physaddr); 127static void NdisFreeMemory(void *, uint32_t, uint32_t); 128static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle, 129 uint32_t, uint32_t, ndis_interface_type); 130static void NdisOpenConfiguration(ndis_status *, 131 ndis_handle *, ndis_handle); 132static void NdisOpenConfigurationKeyByIndex(ndis_status *, 133 ndis_handle, uint32_t, unicode_string *, ndis_handle *); 134static void NdisOpenConfigurationKeyByName(ndis_status *, 135 ndis_handle, unicode_string *, ndis_handle *); 136static ndis_status ndis_encode_parm(ndis_miniport_block *, 137 struct sysctl_oid *, ndis_parm_type, ndis_config_parm **); 138static ndis_status ndis_decode_parm(ndis_miniport_block *, 139 ndis_config_parm *, char *); 140static void NdisReadConfiguration(ndis_status *, ndis_config_parm **, 141 ndis_handle, unicode_string *, ndis_parm_type); 142static void NdisWriteConfiguration(ndis_status *, ndis_handle, 143 unicode_string *, ndis_config_parm *); 144static void NdisCloseConfiguration(ndis_handle); 145static void NdisAllocateSpinLock(ndis_spin_lock *); 146static void NdisFreeSpinLock(ndis_spin_lock *); 147static void NdisAcquireSpinLock(ndis_spin_lock *); 148static void NdisReleaseSpinLock(ndis_spin_lock *); 149static void NdisDprAcquireSpinLock(ndis_spin_lock *); 150static void NdisDprReleaseSpinLock(ndis_spin_lock *); 151static void NdisInitializeReadWriteLock(ndis_rw_lock *); 152static void NdisAcquireReadWriteLock(ndis_rw_lock *, 153 uint8_t, ndis_lock_state *); 154static void NdisReleaseReadWriteLock(ndis_rw_lock *, ndis_lock_state *); 155static uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t, 156 uint32_t, void *, uint32_t); 157static uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t, 158 uint32_t, void *, uint32_t); 159static void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...); 160static void ndis_map_cb(void *, bus_dma_segment_t *, int, int); 161static void NdisMStartBufferPhysicalMapping(ndis_handle, 162 ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *); 163static void NdisMCompleteBufferPhysicalMapping(ndis_handle, 164 ndis_buffer *, uint32_t); 165static void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle, 166 ndis_timer_function, void *); 167static void NdisInitializeTimer(ndis_timer *, 168 ndis_timer_function, void *); 169static void NdisSetTimer(ndis_timer *, uint32_t); 170static void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t); 171static void NdisMCancelTimer(ndis_timer *, uint8_t *); 172static void ndis_timercall(kdpc *, ndis_miniport_timer *, 173 void *, void *); 174static void NdisMQueryAdapterResources(ndis_status *, ndis_handle, 175 ndis_resource_list *, uint32_t *); 176static ndis_status NdisMRegisterIoPortRange(void **, 177 ndis_handle, uint32_t, uint32_t); 178static void NdisMDeregisterIoPortRange(ndis_handle, 179 uint32_t, uint32_t, void *); 180static void NdisReadNetworkAddress(ndis_status *, void **, 181 uint32_t *, ndis_handle); 182static ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *); 183static ndis_status NdisMAllocateMapRegisters(ndis_handle, 184 uint32_t, uint8_t, uint32_t, uint32_t); 185static void NdisMFreeMapRegisters(ndis_handle); 186static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int); 187static void NdisMAllocateSharedMemory(ndis_handle, uint32_t, 188 uint8_t, void **, ndis_physaddr *); 189static void ndis_asyncmem_complete(device_object *, void *); 190static ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle, 191 uint32_t, uint8_t, void *); 192static void NdisMFreeSharedMemory(ndis_handle, uint32_t, 193 uint8_t, void *, ndis_physaddr); 194static ndis_status NdisMMapIoSpace(void **, ndis_handle, 195 ndis_physaddr, uint32_t); 196static void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t); 197static uint32_t NdisGetCacheFillSize(void); 198static uint32_t NdisMGetDmaAlignment(ndis_handle); 199static ndis_status NdisMInitializeScatterGatherDma(ndis_handle, 200 uint8_t, uint32_t); 201static void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **); 202static void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **); 203static void NdisAllocateBufferPool(ndis_status *, 204 ndis_handle *, uint32_t); 205static void NdisFreeBufferPool(ndis_handle); 206static void NdisAllocateBuffer(ndis_status *, ndis_buffer **, 207 ndis_handle, void *, uint32_t); 208static void NdisFreeBuffer(ndis_buffer *); 209static uint32_t NdisBufferLength(ndis_buffer *); 210static void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *); 211static void NdisQueryBufferSafe(ndis_buffer *, void **, 212 uint32_t *, uint32_t); 213static void *NdisBufferVirtualAddress(ndis_buffer *); 214static void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t); 215static void NdisAdjustBufferLength(ndis_buffer *, int); 216static uint32_t NdisInterlockedIncrement(uint32_t *); 217static uint32_t NdisInterlockedDecrement(uint32_t *); 218static void NdisInitializeEvent(ndis_event *); 219static void NdisSetEvent(ndis_event *); 220static void NdisResetEvent(ndis_event *); 221static uint8_t NdisWaitEvent(ndis_event *, uint32_t); 222static ndis_status NdisUnicodeStringToAnsiString(ansi_string *, 223 unicode_string *); 224static ndis_status 225 NdisAnsiStringToUnicodeString(unicode_string *, ansi_string *); 226static ndis_status NdisMPciAssignResources(ndis_handle, 227 uint32_t, ndis_resource_list **); 228static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *, 229 ndis_handle, uint32_t, uint32_t, uint8_t, 230 uint8_t, ndis_interrupt_mode); 231static void NdisMDeregisterInterrupt(ndis_miniport_interrupt *); 232static void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *, 233 ndis_shutdown_handler); 234static void NdisMDeregisterAdapterShutdownHandler(ndis_handle); 235static uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *); 236static void NdisGetBufferPhysicalArraySize(ndis_buffer *, 237 uint32_t *); 238static void NdisQueryBufferOffset(ndis_buffer *, 239 uint32_t *, uint32_t *); 240static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle, 241 uint32_t, void *, uint32_t); 242static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle, 243 uint32_t, void *, uint32_t); 244static list_entry *NdisInterlockedInsertHeadList(list_entry *, 245 list_entry *, ndis_spin_lock *); 246static list_entry *NdisInterlockedRemoveHeadList(list_entry *, 247 ndis_spin_lock *); 248static list_entry *NdisInterlockedInsertTailList(list_entry *, 249 list_entry *, ndis_spin_lock *); 250static uint8_t 251 NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *, 252 void *, void *); 253static void NdisGetCurrentSystemTime(uint64_t *); 254static void NdisGetSystemUpTime(uint32_t *); 255static void NdisInitializeString(unicode_string *, char *); 256static void NdisInitAnsiString(ansi_string *, char *); 257static void NdisInitUnicodeString(unicode_string *, uint16_t *); 258static void NdisFreeString(unicode_string *); 259static ndis_status NdisMRemoveMiniport(ndis_handle *); 260static void NdisTerminateWrapper(ndis_handle, void *); 261static void NdisMGetDeviceProperty(ndis_handle, device_object **, 262 device_object **, device_object **, cm_resource_list *, 263 cm_resource_list *); 264static void NdisGetFirstBufferFromPacket(ndis_packet *, 265 ndis_buffer **, void **, uint32_t *, uint32_t *); 266static void NdisGetFirstBufferFromPacketSafe(ndis_packet *, 267 ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t); 268static int ndis_find_sym(linker_file_t, char *, char *, caddr_t *); 269static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *, 270 unicode_string *, ndis_physaddr); 271static void NdisMapFile(ndis_status *, void **, ndis_handle); 272static void NdisUnmapFile(ndis_handle); 273static void NdisCloseFile(ndis_handle); 274static uint8_t NdisSystemProcessorCount(void); 275static void NdisMIndicateStatusComplete(ndis_handle); 276static void NdisMIndicateStatus(ndis_handle, ndis_status, 277 void *, uint32_t); 278static uint8_t ndis_intr(kinterrupt *, void *); 279static void ndis_intrhand(kdpc *, ndis_miniport_interrupt *, void *, void *); 280static funcptr ndis_findwrap(funcptr); 281static void NdisCopyFromPacketToPacket(ndis_packet *, 282 uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *); 283static void NdisCopyFromPacketToPacketSafe(ndis_packet *, 284 uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t); 285static void NdisIMCopySendPerPacketInfo(ndis_packet *, ndis_packet *); 286static ndis_status NdisMRegisterDevice(ndis_handle, 287 unicode_string *, unicode_string *, driver_dispatch **, 288 void **, ndis_handle *); 289static ndis_status NdisMDeregisterDevice(ndis_handle); 290static ndis_status 291 NdisMQueryAdapterInstanceName(unicode_string *, ndis_handle); 292static void NdisMRegisterUnloadHandler(ndis_handle, void *); 293static void dummy(void); 294 295/* 296 * Some really old drivers do not properly check the return value 297 * from NdisAllocatePacket() and NdisAllocateBuffer() and will 298 * sometimes allocate few more buffers/packets that they originally 299 * requested when they created the pool. To prevent this from being 300 * a problem, we allocate a few extra buffers/packets beyond what 301 * the driver asks for. This #define controls how many. 302 */ 303#define NDIS_POOL_EXTRA 16 304 305int 306ndis_libinit() 307{ 308 image_patch_table *patch; 309 310 strcpy(ndis_filepath, "/compat/ndis"); 311 312 patch = ndis_functbl; 313 while (patch->ipt_func != NULL) { 314 windrv_wrap((funcptr)patch->ipt_func, 315 (funcptr *)&patch->ipt_wrap, 316 patch->ipt_argcnt, patch->ipt_ftype); 317 patch++; 318 } 319 320 return(0); 321} 322 323int 324ndis_libfini() 325{ 326 image_patch_table *patch; 327 328 patch = ndis_functbl; 329 while (patch->ipt_func != NULL) { 330 windrv_unwrap(patch->ipt_wrap); 331 patch++; 332 } 333 334 return(0); 335} 336 337static funcptr 338ndis_findwrap(func) 339 funcptr func; 340{ 341 image_patch_table *patch; 342 343 patch = ndis_functbl; 344 while (patch->ipt_func != NULL) { 345 if ((funcptr)patch->ipt_func == func) 346 return((funcptr)patch->ipt_wrap); 347 patch++; 348 } 349 350 return(NULL); 351} 352 353/* 354 * This routine does the messy Windows Driver Model device attachment 355 * stuff on behalf of NDIS drivers. We register our own AddDevice 356 * routine here 357 */ 358static void 359NdisInitializeWrapper(wrapper, drv, path, unused) 360 ndis_handle *wrapper; 361 driver_object *drv; 362 void *path; 363 void *unused; 364{ 365 /* 366 * As of yet, I haven't come up with a compelling 367 * reason to define a private NDIS wrapper structure, 368 * so we use a pointer to the driver object as the 369 * wrapper handle. The driver object has the miniport 370 * characteristics struct for this driver hung off it 371 * via IoAllocateDriverObjectExtension(), and that's 372 * really all the private data we need. 373 */ 374 375 *wrapper = drv; 376 377 /* 378 * If this was really Windows, we'd be registering dispatch 379 * routines for the NDIS miniport module here, but we're 380 * not Windows so all we really need to do is set up an 381 * AddDevice function that'll be invoked when a new device 382 * instance appears. 383 */ 384 385 drv->dro_driverext->dre_adddevicefunc = NdisAddDevice; 386 387 return; 388} 389 390static void 391NdisTerminateWrapper(handle, syspec) 392 ndis_handle handle; 393 void *syspec; 394{ 395 /* Nothing to see here, move along. */ 396 return; 397} 398 399static ndis_status 400NdisMRegisterMiniport(handle, characteristics, len) 401 ndis_handle handle; 402 ndis_miniport_characteristics *characteristics; 403 int len; 404{ 405 ndis_miniport_characteristics *ch = NULL; 406 driver_object *drv; 407 408 drv = (driver_object *)handle; 409 410 /* 411 * We need to save the NDIS miniport characteristics 412 * somewhere. This data is per-driver, not per-device 413 * (all devices handled by the same driver have the 414 * same characteristics) so we hook it onto the driver 415 * object using IoAllocateDriverObjectExtension(). 416 * The extra extension info is automagically deleted when 417 * the driver is unloaded (see windrv_unload()). 418 */ 419 420 if (IoAllocateDriverObjectExtension(drv, (void *)1, 421 sizeof(ndis_miniport_characteristics), (void **)&ch) != 422 STATUS_SUCCESS) { 423 return(NDIS_STATUS_RESOURCES); 424 } 425 426 bzero((char *)ch, sizeof(ndis_miniport_characteristics)); 427 428 bcopy((char *)characteristics, (char *)ch, len); 429 430 if (ch->nmc_version_major < 5 || ch->nmc_version_minor < 1) { 431 ch->nmc_shutdown_handler = NULL; 432 ch->nmc_canceltxpkts_handler = NULL; 433 ch->nmc_pnpevent_handler = NULL; 434 } 435 436 return(NDIS_STATUS_SUCCESS); 437} 438 439static ndis_status 440NdisAllocateMemoryWithTag(vaddr, len, tag) 441 void **vaddr; 442 uint32_t len; 443 uint32_t tag; 444{ 445 void *mem; 446 447 mem = ExAllocatePoolWithTag(NonPagedPool, len, tag); 448 if (mem == NULL) { 449 return(NDIS_STATUS_RESOURCES); 450 } 451 *vaddr = mem; 452 453 return(NDIS_STATUS_SUCCESS); 454} 455 456static ndis_status 457NdisAllocateMemory(vaddr, len, flags, highaddr) 458 void **vaddr; 459 uint32_t len; 460 uint32_t flags; 461 ndis_physaddr highaddr; 462{ 463 void *mem; 464 465 mem = ExAllocatePoolWithTag(NonPagedPool, len, 0); 466 if (mem == NULL) 467 return(NDIS_STATUS_RESOURCES); 468 *vaddr = mem; 469 470 return(NDIS_STATUS_SUCCESS); 471} 472 473static void 474NdisFreeMemory(vaddr, len, flags) 475 void *vaddr; 476 uint32_t len; 477 uint32_t flags; 478{ 479 if (len == 0) 480 return; 481 482 ExFreePool(vaddr); 483 484 return; 485} 486 487static ndis_status 488NdisMSetAttributesEx(adapter_handle, adapter_ctx, hangsecs, 489 flags, iftype) 490 ndis_handle adapter_handle; 491 ndis_handle adapter_ctx; 492 uint32_t hangsecs; 493 uint32_t flags; 494 ndis_interface_type iftype; 495{ 496 ndis_miniport_block *block; 497 498 /* 499 * Save the adapter context, we need it for calling 500 * the driver's internal functions. 501 */ 502 block = (ndis_miniport_block *)adapter_handle; 503 block->nmb_miniportadapterctx = adapter_ctx; 504 block->nmb_checkforhangsecs = hangsecs; 505 block->nmb_flags = flags; 506 507 return(NDIS_STATUS_SUCCESS); 508} 509 510static void 511NdisOpenConfiguration(status, cfg, wrapctx) 512 ndis_status *status; 513 ndis_handle *cfg; 514 ndis_handle wrapctx; 515{ 516 *cfg = wrapctx; 517 *status = NDIS_STATUS_SUCCESS; 518 519 return; 520} 521 522static void 523NdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle) 524 ndis_status *status; 525 ndis_handle cfg; 526 unicode_string *subkey; 527 ndis_handle *subhandle; 528{ 529 *subhandle = cfg; 530 *status = NDIS_STATUS_SUCCESS; 531 532 return; 533} 534 535static void 536NdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle) 537 ndis_status *status; 538 ndis_handle cfg; 539 uint32_t idx; 540 unicode_string *subkey; 541 ndis_handle *subhandle; 542{ 543 *status = NDIS_STATUS_FAILURE; 544 545 return; 546} 547 548static ndis_status 549ndis_encode_parm(block, oid, type, parm) 550 ndis_miniport_block *block; 551 struct sysctl_oid *oid; 552 ndis_parm_type type; 553 ndis_config_parm **parm; 554{ 555 ndis_config_parm *p; 556 ndis_parmlist_entry *np; 557 unicode_string *us; 558 ansi_string as; 559 int base = 0; 560 uint32_t val; 561 char tmp[32]; 562 563 np = ExAllocatePoolWithTag(NonPagedPool, 564 sizeof(ndis_parmlist_entry), 0); 565 if (np == NULL) 566 return(NDIS_STATUS_RESOURCES); 567 InsertHeadList((&block->nmb_parmlist), (&np->np_list)); 568 *parm = p = &np->np_parm; 569 570 switch(type) { 571 case ndis_parm_string: 572 /* See if this might be a number. */ 573 val = strtoul((char *)oid->oid_arg1, NULL, 10); 574 us = &p->ncp_parmdata.ncp_stringdata; 575 p->ncp_type = ndis_parm_string; 576 if (val) { 577 snprintf(tmp, 32, "%x", val); 578 RtlInitAnsiString(&as, tmp); 579 } else { 580 RtlInitAnsiString(&as, (char *)oid->oid_arg1); 581 } 582 583 if (RtlAnsiStringToUnicodeString(us, &as, TRUE)) { 584 ExFreePool(np); 585 return(NDIS_STATUS_RESOURCES); 586 } 587 break; 588 case ndis_parm_int: 589 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0) 590 base = 16; 591 else 592 base = 10; 593 p->ncp_type = ndis_parm_int; 594 p->ncp_parmdata.ncp_intdata = 595 strtol((char *)oid->oid_arg1, NULL, base); 596 break; 597 case ndis_parm_hexint: 598#ifdef notdef 599 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0) 600 base = 16; 601 else 602 base = 10; 603#endif 604 base = 16; 605 p->ncp_type = ndis_parm_hexint; 606 p->ncp_parmdata.ncp_intdata = 607 strtoul((char *)oid->oid_arg1, NULL, base); 608 break; 609 default: 610 return(NDIS_STATUS_FAILURE); 611 break; 612 } 613 614 return(NDIS_STATUS_SUCCESS); 615} 616 617static void 618NdisReadConfiguration(status, parm, cfg, key, type) 619 ndis_status *status; 620 ndis_config_parm **parm; 621 ndis_handle cfg; 622 unicode_string *key; 623 ndis_parm_type type; 624{ 625 char *keystr = NULL; 626 ndis_miniport_block *block; 627 struct ndis_softc *sc; 628 struct sysctl_oid *oidp; 629 struct sysctl_ctx_entry *e; 630 ansi_string as; 631 632 block = (ndis_miniport_block *)cfg; 633 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 634 635 if (key->us_len == 0 || key->us_buf == NULL) { 636 *status = NDIS_STATUS_FAILURE; 637 return; 638 } 639 640 if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) { 641 *status = NDIS_STATUS_RESOURCES; 642 return; 643 } 644 645 keystr = as.as_buf; 646 647 /* 648 * See if registry key is already in a list of known keys 649 * included with the driver. 650 */ 651#if __FreeBSD_version < 502113 652 TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 653#else 654 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 655#endif 656 oidp = e->entry; 657 if (strcasecmp(oidp->oid_name, keystr) == 0) { 658 if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) { 659 RtlFreeAnsiString(&as); 660 *status = NDIS_STATUS_FAILURE; 661 return; 662 } 663 664 *status = ndis_encode_parm(block, oidp, type, parm); 665 RtlFreeAnsiString(&as); 666 return; 667 } 668 } 669 670 /* 671 * If the key didn't match, add it to the list of dynamically 672 * created ones. Sometimes, drivers refer to registry keys 673 * that aren't documented in their .INF files. These keys 674 * are supposed to be created by some sort of utility or 675 * control panel snap-in that comes with the driver software. 676 * Sometimes it's useful to be able to manipulate these. 677 * If the driver requests the key in the form of a string, 678 * make its default value an empty string, otherwise default 679 * it to "0". 680 */ 681 682 if (type == ndis_parm_int || type == ndis_parm_hexint) 683 ndis_add_sysctl(sc, keystr, "(dynamic integer key)", 684 "UNSET", CTLFLAG_RW); 685 else 686 ndis_add_sysctl(sc, keystr, "(dynamic string key)", 687 "UNSET", CTLFLAG_RW); 688 689 RtlFreeAnsiString(&as); 690 *status = NDIS_STATUS_FAILURE; 691 692 return; 693} 694 695static ndis_status 696ndis_decode_parm(block, parm, val) 697 ndis_miniport_block *block; 698 ndis_config_parm *parm; 699 char *val; 700{ 701 unicode_string *ustr; 702 ansi_string as; 703 704 switch(parm->ncp_type) { 705 case ndis_parm_string: 706 ustr = &parm->ncp_parmdata.ncp_stringdata; 707 if (RtlUnicodeStringToAnsiString(&as, ustr, TRUE)) 708 return(NDIS_STATUS_RESOURCES); 709 bcopy(as.as_buf, val, as.as_len); 710 RtlFreeAnsiString(&as); 711 break; 712 case ndis_parm_int: 713 sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata); 714 break; 715 case ndis_parm_hexint: 716 sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata); 717 break; 718 default: 719 return(NDIS_STATUS_FAILURE); 720 break; 721 } 722 return(NDIS_STATUS_SUCCESS); 723} 724 725static void 726NdisWriteConfiguration(status, cfg, key, parm) 727 ndis_status *status; 728 ndis_handle cfg; 729 unicode_string *key; 730 ndis_config_parm *parm; 731{ 732 ansi_string as; 733 char *keystr = NULL; 734 ndis_miniport_block *block; 735 struct ndis_softc *sc; 736 struct sysctl_oid *oidp; 737 struct sysctl_ctx_entry *e; 738 char val[256]; 739 740 block = (ndis_miniport_block *)cfg; 741 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 742 743 if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) { 744 *status = NDIS_STATUS_RESOURCES; 745 return; 746 } 747 748 keystr = as.as_buf; 749 750 /* Decode the parameter into a string. */ 751 bzero(val, sizeof(val)); 752 *status = ndis_decode_parm(block, parm, val); 753 if (*status != NDIS_STATUS_SUCCESS) { 754 RtlFreeAnsiString(&as); 755 return; 756 } 757 758 /* See if the key already exists. */ 759 760#if __FreeBSD_version < 502113 761 TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 762#else 763 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 764#endif 765 oidp = e->entry; 766 if (strcasecmp(oidp->oid_name, keystr) == 0) { 767 /* Found it, set the value. */ 768 strcpy((char *)oidp->oid_arg1, val); 769 RtlFreeAnsiString(&as); 770 return; 771 } 772 } 773 774 /* Not found, add a new key with the specified value. */ 775 ndis_add_sysctl(sc, keystr, "(dynamically set key)", 776 val, CTLFLAG_RW); 777 778 RtlFreeAnsiString(&as); 779 *status = NDIS_STATUS_SUCCESS; 780 return; 781} 782 783static void 784NdisCloseConfiguration(cfg) 785 ndis_handle cfg; 786{ 787 list_entry *e; 788 ndis_parmlist_entry *pe; 789 ndis_miniport_block *block; 790 ndis_config_parm *p; 791 792 block = (ndis_miniport_block *)cfg; 793 794 while (!IsListEmpty(&block->nmb_parmlist)) { 795 e = RemoveHeadList(&block->nmb_parmlist); 796 pe = CONTAINING_RECORD(e, ndis_parmlist_entry, np_list); 797 p = &pe->np_parm; 798 if (p->ncp_type == ndis_parm_string) 799 RtlFreeUnicodeString(&p->ncp_parmdata.ncp_stringdata); 800 ExFreePool(e); 801 } 802 803 return; 804} 805 806/* 807 * Initialize a Windows spinlock. 808 */ 809static void 810NdisAllocateSpinLock(lock) 811 ndis_spin_lock *lock; 812{ 813 KeInitializeSpinLock(&lock->nsl_spinlock); 814 lock->nsl_kirql = 0; 815 816 return; 817} 818 819/* 820 * Destroy a Windows spinlock. This is a no-op for now. There are two reasons 821 * for this. One is that it's sort of superfluous: we don't have to do anything 822 * special to deallocate the spinlock. The other is that there are some buggy 823 * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on 824 * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm 825 * talking to you.) 826 */ 827static void 828NdisFreeSpinLock(lock) 829 ndis_spin_lock *lock; 830{ 831#ifdef notdef 832 KeInitializeSpinLock(&lock->nsl_spinlock); 833 lock->nsl_kirql = 0; 834#endif 835 return; 836} 837 838/* 839 * Acquire a spinlock from IRQL <= DISPATCH_LEVEL. 840 */ 841 842static void 843NdisAcquireSpinLock(lock) 844 ndis_spin_lock *lock; 845{ 846 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 847 return; 848} 849 850/* 851 * Release a spinlock from IRQL == DISPATCH_LEVEL. 852 */ 853 854static void 855NdisReleaseSpinLock(lock) 856 ndis_spin_lock *lock; 857{ 858 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 859 return; 860} 861 862/* 863 * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL. 864 */ 865static void 866NdisDprAcquireSpinLock(lock) 867 ndis_spin_lock *lock; 868{ 869 KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock); 870 return; 871} 872 873/* 874 * Release a spinlock without leaving IRQL == DISPATCH_LEVEL. 875 */ 876static void 877NdisDprReleaseSpinLock(lock) 878 ndis_spin_lock *lock; 879{ 880 KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock); 881 return; 882} 883 884static void 885NdisInitializeReadWriteLock(lock) 886 ndis_rw_lock *lock; 887{ 888 KeInitializeSpinLock(&lock->nrl_spinlock); 889 bzero((char *)&lock->nrl_rsvd, sizeof(lock->nrl_rsvd)); 890 return; 891} 892 893static void 894NdisAcquireReadWriteLock(lock, writeacc, state) 895 ndis_rw_lock *lock; 896 uint8_t writeacc; 897 ndis_lock_state *state; 898{ 899 if (writeacc == TRUE) { 900 KeAcquireSpinLock(&lock->nrl_spinlock, &state->nls_oldirql); 901 lock->nrl_rsvd[0]++; 902 } else 903 lock->nrl_rsvd[1]++; 904 905 return; 906} 907 908static void 909NdisReleaseReadWriteLock(lock, state) 910 ndis_rw_lock *lock; 911 ndis_lock_state *state; 912{ 913 if (lock->nrl_rsvd[0]) { 914 lock->nrl_rsvd[0]--; 915 KeReleaseSpinLock(&lock->nrl_spinlock, state->nls_oldirql); 916 } else 917 lock->nrl_rsvd[1]--; 918 919 return; 920} 921 922static uint32_t 923NdisReadPciSlotInformation(adapter, slot, offset, buf, len) 924 ndis_handle adapter; 925 uint32_t slot; 926 uint32_t offset; 927 void *buf; 928 uint32_t len; 929{ 930 ndis_miniport_block *block; 931 int i; 932 char *dest; 933 device_t dev; 934 935 block = (ndis_miniport_block *)adapter; 936 dest = buf; 937 if (block == NULL) 938 return(0); 939 940 dev = block->nmb_physdeviceobj->do_devext; 941 942 /* 943 * I have a test system consisting of a Sun w2100z 944 * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g 945 * "Aries" miniPCI NIC. (The NIC is installed in the 946 * machine using a miniPCI to PCI bus adapter card.) 947 * When running in SMP mode, I found that 948 * performing a large number of consecutive calls to 949 * NdisReadPciSlotInformation() would result in a 950 * sudden system reset (or in some cases a freeze). 951 * My suspicion is that the multiple reads are somehow 952 * triggering a fatal PCI bus error that leads to a 953 * machine check. The 1us delay in the loop below 954 * seems to prevent this problem. 955 */ 956 957 for (i = 0; i < len; i++) { 958 DELAY(1); 959 dest[i] = pci_read_config(dev, i + offset, 1); 960 } 961 962 return(len); 963} 964 965static uint32_t 966NdisWritePciSlotInformation(adapter, slot, offset, buf, len) 967 ndis_handle adapter; 968 uint32_t slot; 969 uint32_t offset; 970 void *buf; 971 uint32_t len; 972{ 973 ndis_miniport_block *block; 974 int i; 975 char *dest; 976 device_t dev; 977 978 block = (ndis_miniport_block *)adapter; 979 dest = buf; 980 981 if (block == NULL) 982 return(0); 983 984 dev = block->nmb_physdeviceobj->do_devext; 985 for (i = 0; i < len; i++) { 986 DELAY(1); 987 pci_write_config(dev, i + offset, dest[i], 1); 988 } 989 990 return(len); 991} 992 993/* 994 * The errorlog routine uses a variable argument list, so we 995 * have to declare it this way. 996 */ 997 998#define ERRMSGLEN 512 999static void 1000NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code, 1001 uint32_t numerrors, ...) 1002{ 1003 ndis_miniport_block *block; 1004 va_list ap; 1005 int i, error; 1006 char *str = NULL; 1007 uint16_t flags; 1008 device_t dev; 1009 driver_object *drv; 1010 struct ndis_softc *sc; 1011 struct ifnet *ifp; 1012 unicode_string us; 1013 ansi_string as = { 0, 0, NULL }; 1014 1015 block = (ndis_miniport_block *)adapter; 1016 dev = block->nmb_physdeviceobj->do_devext; 1017 drv = block->nmb_deviceobj->do_drvobj; 1018 sc = device_get_softc(dev); 1019 ifp = sc->ifp; 1020 1021 if (ifp != NULL && ifp->if_flags & IFF_DEBUG) { 1022 error = pe_get_message((vm_offset_t)drv->dro_driverstart, 1023 code, &str, &i, &flags); 1024 if (error == 0) { 1025 if (flags & MESSAGE_RESOURCE_UNICODE) { 1026 RtlInitUnicodeString(&us, (uint16_t *)str); 1027 if (RtlUnicodeStringToAnsiString(&as, 1028 &us, TRUE) == STATUS_SUCCESS) 1029 str = as.as_buf; 1030 else 1031 str = NULL; 1032 } 1033 } 1034 } 1035 1036 device_printf (dev, "NDIS ERROR: %x (%s)\n", code, 1037 str == NULL ? "unknown error" : str); 1038 1039 if (ifp != NULL && ifp->if_flags & IFF_DEBUG) { 1040 device_printf (dev, "NDIS NUMERRORS: %x\n", numerrors); 1041 va_start(ap, numerrors); 1042 for (i = 0; i < numerrors; i++) 1043 device_printf (dev, "argptr: %p\n", 1044 va_arg(ap, void *)); 1045 va_end(ap); 1046 } 1047 1048 if (as.as_len) 1049 RtlFreeAnsiString(&as); 1050 1051 return; 1052} 1053 1054static void 1055ndis_map_cb(arg, segs, nseg, error) 1056 void *arg; 1057 bus_dma_segment_t *segs; 1058 int nseg; 1059 int error; 1060{ 1061 struct ndis_map_arg *ctx; 1062 int i; 1063 1064 if (error) 1065 return; 1066 1067 ctx = arg; 1068 1069 for (i = 0; i < nseg; i++) { 1070 ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr; 1071 ctx->nma_fraglist[i].npu_len = segs[i].ds_len; 1072 } 1073 1074 ctx->nma_cnt = nseg; 1075 1076 return; 1077} 1078 1079static void 1080NdisMStartBufferPhysicalMapping(adapter, buf, mapreg, writedev, addrarray, arraysize) 1081 ndis_handle adapter; 1082 ndis_buffer *buf; 1083 uint32_t mapreg; 1084 uint8_t writedev; 1085 ndis_paddr_unit *addrarray; 1086 uint32_t *arraysize; 1087{ 1088 ndis_miniport_block *block; 1089 struct ndis_softc *sc; 1090 struct ndis_map_arg nma; 1091 bus_dmamap_t map; 1092 int error; 1093 1094 if (adapter == NULL) 1095 return; 1096 1097 block = (ndis_miniport_block *)adapter; 1098 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1099 1100 if (mapreg > sc->ndis_mmapcnt) 1101 return; 1102 1103 map = sc->ndis_mmaps[mapreg]; 1104 nma.nma_fraglist = addrarray; 1105 1106 error = bus_dmamap_load(sc->ndis_mtag, map, 1107 MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf), ndis_map_cb, 1108 (void *)&nma, BUS_DMA_NOWAIT); 1109 1110 if (error) 1111 return; 1112 1113 bus_dmamap_sync(sc->ndis_mtag, map, 1114 writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD); 1115 1116 *arraysize = nma.nma_cnt; 1117 1118 return; 1119} 1120 1121static void 1122NdisMCompleteBufferPhysicalMapping(adapter, buf, mapreg) 1123 ndis_handle adapter; 1124 ndis_buffer *buf; 1125 uint32_t mapreg; 1126{ 1127 ndis_miniport_block *block; 1128 struct ndis_softc *sc; 1129 bus_dmamap_t map; 1130 1131 if (adapter == NULL) 1132 return; 1133 1134 block = (ndis_miniport_block *)adapter; 1135 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1136 1137 if (mapreg > sc->ndis_mmapcnt) 1138 return; 1139 1140 map = sc->ndis_mmaps[mapreg]; 1141 1142 bus_dmamap_sync(sc->ndis_mtag, map, 1143 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 1144 1145 bus_dmamap_unload(sc->ndis_mtag, map); 1146 1147 return; 1148} 1149 1150/* 1151 * This is an older (?) timer init routine which doesn't 1152 * accept a miniport context handle. Serialized miniports should 1153 * never call this function. 1154 */ 1155 1156static void 1157NdisInitializeTimer(timer, func, ctx) 1158 ndis_timer *timer; 1159 ndis_timer_function func; 1160 void *ctx; 1161{ 1162 KeInitializeTimer(&timer->nt_ktimer); 1163 KeInitializeDpc(&timer->nt_kdpc, func, ctx); 1164 KeSetImportanceDpc(&timer->nt_kdpc, KDPC_IMPORTANCE_LOW); 1165 1166 return; 1167} 1168 1169static void 1170ndis_timercall(dpc, timer, sysarg1, sysarg2) 1171 kdpc *dpc; 1172 ndis_miniport_timer *timer; 1173 void *sysarg1; 1174 void *sysarg2; 1175{ 1176 /* 1177 * Since we're called as a DPC, we should be running 1178 * at DISPATCH_LEVEL here. This means to acquire the 1179 * spinlock, we can use KeAcquireSpinLockAtDpcLevel() 1180 * rather than KeAcquireSpinLock(). 1181 */ 1182 if (NDIS_SERIALIZED(timer->nmt_block)) 1183 KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock); 1184 1185 MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx, 1186 sysarg1, sysarg2); 1187 1188 if (NDIS_SERIALIZED(timer->nmt_block)) 1189 KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock); 1190 1191 return; 1192} 1193 1194/* 1195 * For a long time I wondered why there were two NDIS timer initialization 1196 * routines, and why this one needed an NDIS_MINIPORT_TIMER and the 1197 * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout 1198 * function and context pointers separate from those in the DPC, which 1199 * allows for another level of indirection: when the timer fires, we 1200 * can have our own timer function invoked, and from there we can call 1201 * the driver's function. But why go to all that trouble? Then it hit 1202 * me: for serialized miniports, the timer callouts are not re-entrant. 1203 * By trapping the callouts and having access to the MiniportAdapterHandle, 1204 * we can protect the driver callouts by acquiring the NDIS serialization 1205 * lock. This is essential for allowing serialized miniports to work 1206 * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL 1207 * is enough to prevent other threads from pre-empting you, but with 1208 * SMP, you must acquire a lock as well, otherwise the other CPU is 1209 * free to clobber you. 1210 */ 1211static void 1212NdisMInitializeTimer(timer, handle, func, ctx) 1213 ndis_miniport_timer *timer; 1214 ndis_handle handle; 1215 ndis_timer_function func; 1216 void *ctx; 1217{ 1218 /* Save the driver's funcptr and context */ 1219 1220 timer->nmt_timerfunc = func; 1221 timer->nmt_timerctx = ctx; 1222 timer->nmt_block = handle; 1223 1224 /* 1225 * Set up the timer so it will call our intermediate DPC. 1226 * Be sure to use the wrapped entry point, since 1227 * ntoskrnl_run_dpc() expects to invoke a function with 1228 * Microsoft calling conventions. 1229 */ 1230 KeInitializeTimer(&timer->nmt_ktimer); 1231 KeInitializeDpc(&timer->nmt_kdpc, 1232 ndis_findwrap((funcptr)ndis_timercall), timer); 1233 timer->nmt_ktimer.k_dpc = &timer->nmt_kdpc; 1234 1235 return; 1236} 1237 1238/* 1239 * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(), 1240 * but the former is just a macro wrapper around the latter. 1241 */ 1242static void 1243NdisSetTimer(timer, msecs) 1244 ndis_timer *timer; 1245 uint32_t msecs; 1246{ 1247 /* 1248 * KeSetTimer() wants the period in 1249 * hundred nanosecond intervals. 1250 */ 1251 KeSetTimer(&timer->nt_ktimer, 1252 ((int64_t)msecs * -10000), &timer->nt_kdpc); 1253 1254 return; 1255} 1256 1257static void 1258NdisMSetPeriodicTimer(timer, msecs) 1259 ndis_miniport_timer *timer; 1260 uint32_t msecs; 1261{ 1262 KeSetTimerEx(&timer->nmt_ktimer, 1263 ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc); 1264 1265 return; 1266} 1267 1268/* 1269 * Technically, this is really NdisCancelTimer(), but we also 1270 * (ab)use it for NdisMCancelTimer(), since in our implementation 1271 * we don't need the extra info in the ndis_miniport_timer 1272 * structure just to cancel a timer. 1273 */ 1274 1275static void 1276NdisMCancelTimer(timer, cancelled) 1277 ndis_timer *timer; 1278 uint8_t *cancelled; 1279{ 1280 *cancelled = KeCancelTimer(&timer->nt_ktimer); 1281 return; 1282} 1283 1284static void 1285NdisMQueryAdapterResources(status, adapter, list, buflen) 1286 ndis_status *status; 1287 ndis_handle adapter; 1288 ndis_resource_list *list; 1289 uint32_t *buflen; 1290{ 1291 ndis_miniport_block *block; 1292 struct ndis_softc *sc; 1293 int rsclen; 1294 1295 block = (ndis_miniport_block *)adapter; 1296 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1297 1298 rsclen = sizeof(ndis_resource_list) + 1299 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)); 1300 if (*buflen < rsclen) { 1301 *buflen = rsclen; 1302 *status = NDIS_STATUS_INVALID_LENGTH; 1303 return; 1304 } 1305 1306 bcopy((char *)block->nmb_rlist, (char *)list, rsclen); 1307 *status = NDIS_STATUS_SUCCESS; 1308 1309 return; 1310} 1311 1312static ndis_status 1313NdisMRegisterIoPortRange(offset, adapter, port, numports) 1314 void **offset; 1315 ndis_handle adapter; 1316 uint32_t port; 1317 uint32_t numports; 1318{ 1319 struct ndis_miniport_block *block; 1320 struct ndis_softc *sc; 1321 1322 if (adapter == NULL) 1323 return(NDIS_STATUS_FAILURE); 1324 1325 block = (ndis_miniport_block *)adapter; 1326 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1327 1328 if (sc->ndis_res_io == NULL) 1329 return(NDIS_STATUS_FAILURE); 1330 1331 /* Don't let the device map more ports than we have. */ 1332 if (rman_get_size(sc->ndis_res_io) < numports) 1333 return(NDIS_STATUS_INVALID_LENGTH); 1334 1335 *offset = (void *)rman_get_start(sc->ndis_res_io); 1336 1337 return(NDIS_STATUS_SUCCESS); 1338} 1339 1340static void 1341NdisMDeregisterIoPortRange(adapter, port, numports, offset) 1342 ndis_handle adapter; 1343 uint32_t port; 1344 uint32_t numports; 1345 void *offset; 1346{ 1347 return; 1348} 1349 1350static void 1351NdisReadNetworkAddress(status, addr, addrlen, adapter) 1352 ndis_status *status; 1353 void **addr; 1354 uint32_t *addrlen; 1355 ndis_handle adapter; 1356{ 1357 struct ndis_softc *sc; 1358 ndis_miniport_block *block; 1359 uint8_t empty[] = { 0, 0, 0, 0, 0, 0 }; 1360 1361 block = (ndis_miniport_block *)adapter; 1362 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1363 if (sc->ifp == NULL) { 1364 *status = NDIS_STATUS_FAILURE; 1365 return; 1366 } 1367 1368#ifdef IFP2ENADDR 1369 if (bcmp(IFP2ENADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0) 1370#elif __FreeBSD_version >= 700000 1371 if (sc->ifp->if_addr == NULL || 1372 bcmp(IF_LLADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0) 1373#else 1374 if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0) 1375#endif 1376 *status = NDIS_STATUS_FAILURE; 1377 else { 1378#ifdef IFP2ENADDR 1379 *addr = IFP2ENADDR(sc->ifp); 1380#elif __FreeBSD_version >= 700000 1381 *addr = IF_LLADDR(sc->ifp); 1382#else 1383 *addr = sc->arpcom.ac_enaddr; 1384#endif 1385 *addrlen = ETHER_ADDR_LEN; 1386 *status = NDIS_STATUS_SUCCESS; 1387 } 1388 1389 return; 1390} 1391 1392static ndis_status 1393NdisQueryMapRegisterCount(bustype, cnt) 1394 uint32_t bustype; 1395 uint32_t *cnt; 1396{ 1397 *cnt = 8192; 1398 return(NDIS_STATUS_SUCCESS); 1399} 1400 1401static ndis_status 1402NdisMAllocateMapRegisters(adapter, dmachannel, dmasize, physmapneeded, maxmap) 1403 ndis_handle adapter; 1404 uint32_t dmachannel; 1405 uint8_t dmasize; 1406 uint32_t physmapneeded; 1407 uint32_t maxmap; 1408{ 1409 struct ndis_softc *sc; 1410 ndis_miniport_block *block; 1411 int error, i, nseg = NDIS_MAXSEG; 1412 1413 block = (ndis_miniport_block *)adapter; 1414 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1415 1416 sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded, 1417 M_DEVBUF, M_NOWAIT|M_ZERO); 1418 1419 if (sc->ndis_mmaps == NULL) 1420 return(NDIS_STATUS_RESOURCES); 1421 1422 error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1423 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1424 NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW, 1425 NULL, NULL, &sc->ndis_mtag); 1426 1427 if (error) { 1428 free(sc->ndis_mmaps, M_DEVBUF); 1429 return(NDIS_STATUS_RESOURCES); 1430 } 1431 1432 for (i = 0; i < physmapneeded; i++) 1433 bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]); 1434 1435 sc->ndis_mmapcnt = physmapneeded; 1436 1437 return(NDIS_STATUS_SUCCESS); 1438} 1439 1440static void 1441NdisMFreeMapRegisters(adapter) 1442 ndis_handle adapter; 1443{ 1444 struct ndis_softc *sc; 1445 ndis_miniport_block *block; 1446 int i; 1447 1448 block = (ndis_miniport_block *)adapter; 1449 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1450 1451 for (i = 0; i < sc->ndis_mmapcnt; i++) 1452 bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]); 1453 1454 free(sc->ndis_mmaps, M_DEVBUF); 1455 1456 bus_dma_tag_destroy(sc->ndis_mtag); 1457 1458 return; 1459} 1460 1461static void 1462ndis_mapshared_cb(arg, segs, nseg, error) 1463 void *arg; 1464 bus_dma_segment_t *segs; 1465 int nseg; 1466 int error; 1467{ 1468 ndis_physaddr *p; 1469 1470 if (error || nseg > 1) 1471 return; 1472 1473 p = arg; 1474 1475 p->np_quad = segs[0].ds_addr; 1476 1477 return; 1478} 1479 1480/* 1481 * This maps to bus_dmamem_alloc(). 1482 */ 1483 1484static void 1485NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr) 1486 ndis_handle adapter; 1487 uint32_t len; 1488 uint8_t cached; 1489 void **vaddr; 1490 ndis_physaddr *paddr; 1491{ 1492 ndis_miniport_block *block; 1493 struct ndis_softc *sc; 1494 struct ndis_shmem *sh; 1495 int error; 1496 1497 if (adapter == NULL) 1498 return; 1499 1500 block = (ndis_miniport_block *)adapter; 1501 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1502 1503 sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO); 1504 if (sh == NULL) 1505 return; 1506 1507 InitializeListHead(&sh->ndis_list); 1508 1509 /* 1510 * When performing shared memory allocations, create a tag 1511 * with a lowaddr limit that restricts physical memory mappings 1512 * so that they all fall within the first 1GB of memory. 1513 * At least one device/driver combination (Linksys Instant 1514 * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have 1515 * problems with performing DMA operations with physical 1516 * addresses that lie above the 1GB mark. I don't know if this 1517 * is a hardware limitation or if the addresses are being 1518 * truncated within the driver, but this seems to be the only 1519 * way to make these cards work reliably in systems with more 1520 * than 1GB of physical memory. 1521 */ 1522 1523 error = bus_dma_tag_create(sc->ndis_parent_tag, 64, 1524 0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL, 1525 NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL, 1526 &sh->ndis_stag); 1527 1528 if (error) { 1529 free(sh, M_DEVBUF); 1530 return; 1531 } 1532 1533 error = bus_dmamem_alloc(sh->ndis_stag, vaddr, 1534 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap); 1535 1536 if (error) { 1537 bus_dma_tag_destroy(sh->ndis_stag); 1538 free(sh, M_DEVBUF); 1539 return; 1540 } 1541 1542 error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr, 1543 len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT); 1544 1545 if (error) { 1546 bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap); 1547 bus_dma_tag_destroy(sh->ndis_stag); 1548 free(sh, M_DEVBUF); 1549 return; 1550 } 1551 1552 /* 1553 * Save the physical address along with the source address. 1554 * The AirGo MIMO driver will call NdisMFreeSharedMemory() 1555 * with a bogus virtual address sometimes, but with a valid 1556 * physical address. To keep this from causing trouble, we 1557 * use the physical address to as a sanity check in case 1558 * searching based on the virtual address fails. 1559 */ 1560 1561 NDIS_LOCK(sc); 1562 sh->ndis_paddr.np_quad = paddr->np_quad; 1563 sh->ndis_saddr = *vaddr; 1564 InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list)); 1565 NDIS_UNLOCK(sc); 1566 1567 return; 1568} 1569 1570struct ndis_allocwork { 1571 uint32_t na_len; 1572 uint8_t na_cached; 1573 void *na_ctx; 1574 io_workitem *na_iw; 1575}; 1576 1577static void 1578ndis_asyncmem_complete(dobj, arg) 1579 device_object *dobj; 1580 void *arg; 1581{ 1582 ndis_miniport_block *block; 1583 struct ndis_softc *sc; 1584 struct ndis_allocwork *w; 1585 void *vaddr; 1586 ndis_physaddr paddr; 1587 ndis_allocdone_handler donefunc; 1588 1589 w = arg; 1590 block = (ndis_miniport_block *)dobj->do_devext; 1591 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1592 1593 vaddr = NULL; 1594 paddr.np_quad = 0; 1595 1596 donefunc = sc->ndis_chars->nmc_allocate_complete_func; 1597 NdisMAllocateSharedMemory(block, w->na_len, 1598 w->na_cached, &vaddr, &paddr); 1599 MSCALL5(donefunc, block, vaddr, &paddr, w->na_len, w->na_ctx); 1600 1601 IoFreeWorkItem(w->na_iw); 1602 free(w, M_DEVBUF); 1603 1604 return; 1605} 1606 1607static ndis_status 1608NdisMAllocateSharedMemoryAsync(adapter, len, cached, ctx) 1609 ndis_handle adapter; 1610 uint32_t len; 1611 uint8_t cached; 1612 void *ctx; 1613{ 1614 ndis_miniport_block *block; 1615 struct ndis_allocwork *w; 1616 io_workitem *iw; 1617 io_workitem_func ifw; 1618 1619 if (adapter == NULL) 1620 return(NDIS_STATUS_FAILURE); 1621 1622 block = adapter; 1623 1624 iw = IoAllocateWorkItem(block->nmb_deviceobj); 1625 if (iw == NULL) 1626 return(NDIS_STATUS_FAILURE); 1627 1628 w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT); 1629 1630 if (w == NULL) 1631 return(NDIS_STATUS_FAILURE); 1632 1633 w->na_cached = cached; 1634 w->na_len = len; 1635 w->na_ctx = ctx; 1636 w->na_iw = iw; 1637 1638 ifw = (io_workitem_func)ndis_findwrap((funcptr)ndis_asyncmem_complete); 1639 IoQueueWorkItem(iw, ifw, WORKQUEUE_DELAYED, w); 1640 1641 return(NDIS_STATUS_PENDING); 1642} 1643 1644static void 1645NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr) 1646 ndis_handle adapter; 1647 uint32_t len; 1648 uint8_t cached; 1649 void *vaddr; 1650 ndis_physaddr paddr; 1651{ 1652 ndis_miniport_block *block; 1653 struct ndis_softc *sc; 1654 struct ndis_shmem *sh = NULL; 1655 list_entry *l; 1656 1657 if (vaddr == NULL || adapter == NULL) 1658 return; 1659 1660 block = (ndis_miniport_block *)adapter; 1661 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1662 1663 /* Sanity check: is list empty? */ 1664 1665 if (IsListEmpty(&sc->ndis_shlist)) 1666 return; 1667 1668 NDIS_LOCK(sc); 1669 l = sc->ndis_shlist.nle_flink; 1670 while (l != &sc->ndis_shlist) { 1671 sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list); 1672 if (sh->ndis_saddr == vaddr) 1673 break; 1674 /* 1675 * Check the physaddr too, just in case the driver lied 1676 * about the virtual address. 1677 */ 1678 if (sh->ndis_paddr.np_quad == paddr.np_quad) 1679 break; 1680 l = l->nle_flink; 1681 } 1682 1683 if (sh == NULL) { 1684 NDIS_UNLOCK(sc); 1685 printf("NDIS: buggy driver tried to free " 1686 "invalid shared memory: vaddr: %p paddr: 0x%jx\n", 1687 vaddr, (uintmax_t)paddr.np_quad); 1688 return; 1689 } 1690 1691 RemoveEntryList(&sh->ndis_list); 1692 1693 NDIS_UNLOCK(sc); 1694 1695 bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap); 1696 bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap); 1697 bus_dma_tag_destroy(sh->ndis_stag); 1698 1699 free(sh, M_DEVBUF); 1700 1701 return; 1702} 1703 1704static ndis_status 1705NdisMMapIoSpace(vaddr, adapter, paddr, len) 1706 void **vaddr; 1707 ndis_handle adapter; 1708 ndis_physaddr paddr; 1709 uint32_t len; 1710{ 1711 if (adapter == NULL) 1712 return(NDIS_STATUS_FAILURE); 1713 1714 *vaddr = MmMapIoSpace(paddr.np_quad, len, 0); 1715 1716 if (*vaddr == NULL) 1717 return(NDIS_STATUS_FAILURE); 1718 1719 return(NDIS_STATUS_SUCCESS); 1720} 1721 1722static void 1723NdisMUnmapIoSpace(adapter, vaddr, len) 1724 ndis_handle adapter; 1725 void *vaddr; 1726 uint32_t len; 1727{ 1728 MmUnmapIoSpace(vaddr, len); 1729 return; 1730} 1731 1732static uint32_t 1733NdisGetCacheFillSize(void) 1734{ 1735 return(128); 1736} 1737 1738static uint32_t 1739NdisMGetDmaAlignment(handle) 1740 ndis_handle handle; 1741{ 1742 return(16); 1743} 1744 1745/* 1746 * NDIS has two methods for dealing with NICs that support DMA. 1747 * One is to just pass packets to the driver and let it call 1748 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet 1749 * all by itself, and the other is to let the NDIS library handle the 1750 * buffer mapping internally, and hand the driver an already populated 1751 * scatter/gather fragment list. If the driver calls 1752 * NdisMInitializeScatterGatherDma(), it wants to use the latter 1753 * method. 1754 */ 1755 1756static ndis_status 1757NdisMInitializeScatterGatherDma(adapter, is64, maxphysmap) 1758 ndis_handle adapter; 1759 uint8_t is64; 1760 uint32_t maxphysmap; 1761{ 1762 struct ndis_softc *sc; 1763 ndis_miniport_block *block; 1764 int error; 1765 1766 if (adapter == NULL) 1767 return(NDIS_STATUS_FAILURE); 1768 block = (ndis_miniport_block *)adapter; 1769 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1770 1771 /* Don't do this twice. */ 1772 if (sc->ndis_sc == 1) 1773 return(NDIS_STATUS_SUCCESS); 1774 1775 error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1776 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 1777 MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW, 1778 NULL, NULL, &sc->ndis_ttag); 1779 1780 sc->ndis_sc = 1; 1781 1782 return(NDIS_STATUS_SUCCESS); 1783} 1784 1785void 1786NdisAllocatePacketPool(status, pool, descnum, protrsvdlen) 1787 ndis_status *status; 1788 ndis_handle *pool; 1789 uint32_t descnum; 1790 uint32_t protrsvdlen; 1791{ 1792 ndis_packet_pool *p; 1793 ndis_packet *packets; 1794 int i; 1795 1796 p = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_packet_pool), 0); 1797 if (p == NULL) { 1798 *status = NDIS_STATUS_RESOURCES; 1799 return; 1800 } 1801 1802 p->np_cnt = descnum + NDIS_POOL_EXTRA; 1803 p->np_protrsvd = protrsvdlen; 1804 p->np_len = sizeof(ndis_packet) + protrsvdlen; 1805 1806 packets = ExAllocatePoolWithTag(NonPagedPool, p->np_cnt * 1807 p->np_len, 0); 1808 1809 1810 if (packets == NULL) { 1811 ExFreePool(p); 1812 *status = NDIS_STATUS_RESOURCES; 1813 return; 1814 } 1815 1816 p->np_pktmem = packets; 1817 1818 for (i = 0; i < p->np_cnt; i++) 1819 InterlockedPushEntrySList(&p->np_head, 1820 (struct slist_entry *)&packets[i]); 1821 1822#ifdef NDIS_DEBUG_PACKETS 1823 p->np_dead = 0; 1824 KeInitializeSpinLock(&p->np_lock); 1825 KeInitializeEvent(&p->np_event, EVENT_TYPE_NOTIFY, TRUE); 1826#endif 1827 1828 *pool = p; 1829 *status = NDIS_STATUS_SUCCESS; 1830 return; 1831} 1832 1833void 1834NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen) 1835 ndis_status *status; 1836 ndis_handle *pool; 1837 uint32_t descnum; 1838 uint32_t oflowdescnum; 1839 uint32_t protrsvdlen; 1840{ 1841 return(NdisAllocatePacketPool(status, pool, 1842 descnum + oflowdescnum, protrsvdlen)); 1843} 1844 1845uint32_t 1846NdisPacketPoolUsage(pool) 1847 ndis_handle pool; 1848{ 1849 ndis_packet_pool *p; 1850 1851 p = (ndis_packet_pool *)pool; 1852 return(p->np_cnt - ExQueryDepthSList(&p->np_head)); 1853} 1854 1855void 1856NdisFreePacketPool(pool) 1857 ndis_handle pool; 1858{ 1859 ndis_packet_pool *p; 1860 int usage; 1861#ifdef NDIS_DEBUG_PACKETS 1862 uint8_t irql; 1863#endif 1864 1865 p = (ndis_packet_pool *)pool; 1866 1867#ifdef NDIS_DEBUG_PACKETS 1868 KeAcquireSpinLock(&p->np_lock, &irql); 1869#endif 1870 1871 usage = NdisPacketPoolUsage(pool); 1872 1873#ifdef NDIS_DEBUG_PACKETS 1874 if (usage) { 1875 p->np_dead = 1; 1876 KeResetEvent(&p->np_event); 1877 KeReleaseSpinLock(&p->np_lock, irql); 1878 KeWaitForSingleObject(&p->np_event, 0, 0, FALSE, NULL); 1879 } else 1880 KeReleaseSpinLock(&p->np_lock, irql); 1881#endif 1882 1883 ExFreePool(p->np_pktmem); 1884 ExFreePool(p); 1885 1886 return; 1887} 1888 1889void 1890NdisAllocatePacket(status, packet, pool) 1891 ndis_status *status; 1892 ndis_packet **packet; 1893 ndis_handle pool; 1894{ 1895 ndis_packet_pool *p; 1896 ndis_packet *pkt; 1897#ifdef NDIS_DEBUG_PACKETS 1898 uint8_t irql; 1899#endif 1900 1901 p = (ndis_packet_pool *)pool; 1902 1903#ifdef NDIS_DEBUG_PACKETS 1904 KeAcquireSpinLock(&p->np_lock, &irql); 1905 if (p->np_dead) { 1906 KeReleaseSpinLock(&p->np_lock, irql); 1907 printf("NDIS: tried to allocate packet from dead pool %p\n", 1908 pool); 1909 *status = NDIS_STATUS_RESOURCES; 1910 return; 1911 } 1912#endif 1913 1914 pkt = (ndis_packet *)InterlockedPopEntrySList(&p->np_head); 1915 1916#ifdef NDIS_DEBUG_PACKETS 1917 KeReleaseSpinLock(&p->np_lock, irql); 1918#endif 1919 1920 if (pkt == NULL) { 1921 *status = NDIS_STATUS_RESOURCES; 1922 return; 1923 } 1924 1925 1926 bzero((char *)pkt, sizeof(ndis_packet)); 1927 1928 /* Save pointer to the pool. */ 1929 pkt->np_private.npp_pool = pool; 1930 1931 /* Set the oob offset pointer. Lots of things expect this. */ 1932 pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob); 1933 1934 /* 1935 * We must initialize the packet flags correctly in order 1936 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and 1937 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work 1938 * correctly. 1939 */ 1940 pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 1941 pkt->np_private.npp_validcounts = FALSE; 1942 1943 *packet = pkt; 1944 1945 *status = NDIS_STATUS_SUCCESS; 1946 1947 return; 1948} 1949 1950void 1951NdisFreePacket(packet) 1952 ndis_packet *packet; 1953{ 1954 ndis_packet_pool *p; 1955#ifdef NDIS_DEBUG_PACKETS 1956 uint8_t irql; 1957#endif 1958 1959 p = (ndis_packet_pool *)packet->np_private.npp_pool; 1960 1961#ifdef NDIS_DEBUG_PACKETS 1962 KeAcquireSpinLock(&p->np_lock, &irql); 1963#endif 1964 1965 InterlockedPushEntrySList(&p->np_head, (slist_entry *)packet); 1966 1967#ifdef NDIS_DEBUG_PACKETS 1968 if (p->np_dead) { 1969 if (ExQueryDepthSList(&p->np_head) == p->np_cnt) 1970 KeSetEvent(&p->np_event, IO_NO_INCREMENT, FALSE); 1971 } 1972 KeReleaseSpinLock(&p->np_lock, irql); 1973#endif 1974 1975 return; 1976} 1977 1978static void 1979NdisUnchainBufferAtFront(packet, buf) 1980 ndis_packet *packet; 1981 ndis_buffer **buf; 1982{ 1983 ndis_packet_private *priv; 1984 1985 if (packet == NULL || buf == NULL) 1986 return; 1987 1988 priv = &packet->np_private; 1989 1990 priv->npp_validcounts = FALSE; 1991 1992 if (priv->npp_head == priv->npp_tail) { 1993 *buf = priv->npp_head; 1994 priv->npp_head = priv->npp_tail = NULL; 1995 } else { 1996 *buf = priv->npp_head; 1997 priv->npp_head = (*buf)->mdl_next; 1998 } 1999 2000 return; 2001} 2002 2003static void 2004NdisUnchainBufferAtBack(packet, buf) 2005 ndis_packet *packet; 2006 ndis_buffer **buf; 2007{ 2008 ndis_packet_private *priv; 2009 ndis_buffer *tmp; 2010 2011 if (packet == NULL || buf == NULL) 2012 return; 2013 2014 priv = &packet->np_private; 2015 2016 priv->npp_validcounts = FALSE; 2017 2018 if (priv->npp_head == priv->npp_tail) { 2019 *buf = priv->npp_head; 2020 priv->npp_head = priv->npp_tail = NULL; 2021 } else { 2022 *buf = priv->npp_tail; 2023 tmp = priv->npp_head; 2024 while (tmp->mdl_next != priv->npp_tail) 2025 tmp = tmp->mdl_next; 2026 priv->npp_tail = tmp; 2027 tmp->mdl_next = NULL; 2028 } 2029 2030 return; 2031} 2032 2033/* 2034 * The NDIS "buffer" is really an MDL (memory descriptor list) 2035 * which is used to describe a buffer in a way that allows it 2036 * to mapped into different contexts. We have to be careful how 2037 * we handle them: in some versions of Windows, the NdisFreeBuffer() 2038 * routine is an actual function in the NDIS API, but in others 2039 * it's just a macro wrapper around IoFreeMdl(). There's really 2040 * no way to use the 'descnum' parameter to count how many 2041 * "buffers" are allocated since in order to use IoFreeMdl() to 2042 * dispose of a buffer, we have to use IoAllocateMdl() to allocate 2043 * them, and IoAllocateMdl() just grabs them out of the heap. 2044 */ 2045 2046static void 2047NdisAllocateBufferPool(status, pool, descnum) 2048 ndis_status *status; 2049 ndis_handle *pool; 2050 uint32_t descnum; 2051{ 2052 2053 /* 2054 * The only thing we can really do here is verify that descnum 2055 * is a reasonable value, but I really don't know what to check 2056 * it against. 2057 */ 2058 2059 *pool = NonPagedPool; 2060 *status = NDIS_STATUS_SUCCESS; 2061 return; 2062} 2063 2064static void 2065NdisFreeBufferPool(pool) 2066 ndis_handle pool; 2067{ 2068 return; 2069} 2070 2071static void 2072NdisAllocateBuffer(status, buffer, pool, vaddr, len) 2073 ndis_status *status; 2074 ndis_buffer **buffer; 2075 ndis_handle pool; 2076 void *vaddr; 2077 uint32_t len; 2078{ 2079 ndis_buffer *buf; 2080 2081 buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL); 2082 if (buf == NULL) { 2083 *status = NDIS_STATUS_RESOURCES; 2084 return; 2085 } 2086 2087 MmBuildMdlForNonPagedPool(buf); 2088 2089 *buffer = buf; 2090 *status = NDIS_STATUS_SUCCESS; 2091 2092 return; 2093} 2094 2095static void 2096NdisFreeBuffer(buf) 2097 ndis_buffer *buf; 2098{ 2099 IoFreeMdl(buf); 2100 return; 2101} 2102 2103/* Aw c'mon. */ 2104 2105static uint32_t 2106NdisBufferLength(buf) 2107 ndis_buffer *buf; 2108{ 2109 return(MmGetMdlByteCount(buf)); 2110} 2111 2112/* 2113 * Get the virtual address and length of a buffer. 2114 * Note: the vaddr argument is optional. 2115 */ 2116 2117static void 2118NdisQueryBuffer(buf, vaddr, len) 2119 ndis_buffer *buf; 2120 void **vaddr; 2121 uint32_t *len; 2122{ 2123 if (vaddr != NULL) 2124 *vaddr = MmGetMdlVirtualAddress(buf); 2125 *len = MmGetMdlByteCount(buf); 2126 2127 return; 2128} 2129 2130/* Same as above -- we don't care about the priority. */ 2131 2132static void 2133NdisQueryBufferSafe(buf, vaddr, len, prio) 2134 ndis_buffer *buf; 2135 void **vaddr; 2136 uint32_t *len; 2137 uint32_t prio; 2138{ 2139 if (vaddr != NULL) 2140 *vaddr = MmGetMdlVirtualAddress(buf); 2141 *len = MmGetMdlByteCount(buf); 2142 2143 return; 2144} 2145 2146/* Damnit Microsoft!! How many ways can you do the same thing?! */ 2147 2148static void * 2149NdisBufferVirtualAddress(buf) 2150 ndis_buffer *buf; 2151{ 2152 return(MmGetMdlVirtualAddress(buf)); 2153} 2154 2155static void * 2156NdisBufferVirtualAddressSafe(buf, prio) 2157 ndis_buffer *buf; 2158 uint32_t prio; 2159{ 2160 return(MmGetMdlVirtualAddress(buf)); 2161} 2162 2163static void 2164NdisAdjustBufferLength(buf, len) 2165 ndis_buffer *buf; 2166 int len; 2167{ 2168 MmGetMdlByteCount(buf) = len; 2169 2170 return; 2171} 2172 2173static uint32_t 2174NdisInterlockedIncrement(addend) 2175 uint32_t *addend; 2176{ 2177 atomic_add_long((u_long *)addend, 1); 2178 return(*addend); 2179} 2180 2181static uint32_t 2182NdisInterlockedDecrement(addend) 2183 uint32_t *addend; 2184{ 2185 atomic_subtract_long((u_long *)addend, 1); 2186 return(*addend); 2187} 2188 2189static void 2190NdisInitializeEvent(event) 2191 ndis_event *event; 2192{ 2193 /* 2194 * NDIS events are always notification 2195 * events, and should be initialized to the 2196 * not signaled state. 2197 */ 2198 KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE); 2199 return; 2200} 2201 2202static void 2203NdisSetEvent(event) 2204 ndis_event *event; 2205{ 2206 KeSetEvent(&event->ne_event, IO_NO_INCREMENT, FALSE); 2207 return; 2208} 2209 2210static void 2211NdisResetEvent(event) 2212 ndis_event *event; 2213{ 2214 KeResetEvent(&event->ne_event); 2215 return; 2216} 2217 2218static uint8_t 2219NdisWaitEvent(event, msecs) 2220 ndis_event *event; 2221 uint32_t msecs; 2222{ 2223 int64_t duetime; 2224 uint32_t rval; 2225 2226 duetime = ((int64_t)msecs * -10000); 2227 rval = KeWaitForSingleObject(event, 2228 0, 0, TRUE, msecs ? & duetime : NULL); 2229 2230 if (rval == STATUS_TIMEOUT) 2231 return(FALSE); 2232 2233 return(TRUE); 2234} 2235 2236static ndis_status 2237NdisUnicodeStringToAnsiString(dstr, sstr) 2238 ansi_string *dstr; 2239 unicode_string *sstr; 2240{ 2241 uint32_t rval; 2242 2243 rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE); 2244 2245 if (rval == STATUS_INSUFFICIENT_RESOURCES) 2246 return(NDIS_STATUS_RESOURCES); 2247 if (rval) 2248 return(NDIS_STATUS_FAILURE); 2249 2250 return (NDIS_STATUS_SUCCESS); 2251} 2252 2253static ndis_status 2254NdisAnsiStringToUnicodeString(dstr, sstr) 2255 unicode_string *dstr; 2256 ansi_string *sstr; 2257{ 2258 uint32_t rval; 2259 2260 rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE); 2261 2262 if (rval == STATUS_INSUFFICIENT_RESOURCES) 2263 return(NDIS_STATUS_RESOURCES); 2264 if (rval) 2265 return(NDIS_STATUS_FAILURE); 2266 2267 return (NDIS_STATUS_SUCCESS); 2268} 2269 2270static ndis_status 2271NdisMPciAssignResources(adapter, slot, list) 2272 ndis_handle adapter; 2273 uint32_t slot; 2274 ndis_resource_list **list; 2275{ 2276 ndis_miniport_block *block; 2277 2278 if (adapter == NULL || list == NULL) 2279 return (NDIS_STATUS_FAILURE); 2280 2281 block = (ndis_miniport_block *)adapter; 2282 *list = block->nmb_rlist; 2283 2284 return (NDIS_STATUS_SUCCESS); 2285} 2286 2287static uint8_t 2288ndis_intr(iobj, arg) 2289 kinterrupt *iobj; 2290 void *arg; 2291{ 2292 struct ndis_softc *sc; 2293 uint8_t is_our_intr = FALSE; 2294 int call_isr = 0; 2295 ndis_miniport_interrupt *intr; 2296 2297 sc = arg; 2298 intr = sc->ndis_block->nmb_interrupt; 2299 2300 if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL) 2301 return(FALSE); 2302 2303 if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE) 2304 MSCALL3(intr->ni_isrfunc, &is_our_intr, &call_isr, 2305 sc->ndis_block->nmb_miniportadapterctx); 2306 else { 2307 MSCALL1(sc->ndis_chars->nmc_disable_interrupts_func, 2308 sc->ndis_block->nmb_miniportadapterctx); 2309 call_isr = 1; 2310 } 2311 2312 if (call_isr) 2313 IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc); 2314 2315 return(is_our_intr); 2316} 2317 2318static void 2319ndis_intrhand(dpc, intr, sysarg1, sysarg2) 2320 kdpc *dpc; 2321 ndis_miniport_interrupt *intr; 2322 void *sysarg1; 2323 void *sysarg2; 2324{ 2325 struct ndis_softc *sc; 2326 ndis_miniport_block *block; 2327 ndis_handle adapter; 2328 2329 block = intr->ni_block; 2330 adapter = block->nmb_miniportadapterctx; 2331 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2332 2333 if (NDIS_SERIALIZED(sc->ndis_block)) 2334 KeAcquireSpinLockAtDpcLevel(&block->nmb_lock); 2335 2336 MSCALL1(intr->ni_dpcfunc, adapter); 2337 2338 /* If there's a MiniportEnableInterrupt() routine, call it. */ 2339 2340 if (sc->ndis_chars->nmc_enable_interrupts_func != NULL) 2341 MSCALL1(sc->ndis_chars->nmc_enable_interrupts_func, adapter); 2342 2343 if (NDIS_SERIALIZED(sc->ndis_block)) 2344 KeReleaseSpinLockFromDpcLevel(&block->nmb_lock); 2345 2346 /* 2347 * Set the completion event if we've drained all 2348 * pending interrupts. 2349 */ 2350 2351 KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock); 2352 intr->ni_dpccnt--; 2353 if (intr->ni_dpccnt == 0) 2354 KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE); 2355 KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock); 2356 2357 return; 2358} 2359 2360static ndis_status 2361NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode) 2362 ndis_miniport_interrupt *intr; 2363 ndis_handle adapter; 2364 uint32_t ivec; 2365 uint32_t ilevel; 2366 uint8_t reqisr; 2367 uint8_t shared; 2368 ndis_interrupt_mode imode; 2369{ 2370 ndis_miniport_block *block; 2371 ndis_miniport_characteristics *ch; 2372 struct ndis_softc *sc; 2373 int error; 2374 2375 block = adapter; 2376 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2377 ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj, 2378 (void *)1); 2379 2380 intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool, 2381 sizeof(struct mtx), 0); 2382 if (intr->ni_rsvd == NULL) 2383 return(NDIS_STATUS_RESOURCES); 2384 2385 intr->ni_block = adapter; 2386 intr->ni_isrreq = reqisr; 2387 intr->ni_shared = shared; 2388 intr->ni_dpccnt = 0; 2389 intr->ni_isrfunc = ch->nmc_isr_func; 2390 intr->ni_dpcfunc = ch->nmc_interrupt_func; 2391 2392 KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE); 2393 KeInitializeDpc(&intr->ni_dpc, 2394 ndis_findwrap((funcptr)ndis_intrhand), intr); 2395 KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW); 2396 2397 error = IoConnectInterrupt(&intr->ni_introbj, 2398 ndis_findwrap((funcptr)ndis_intr), sc, NULL, 2399 ivec, ilevel, 0, imode, shared, 0, FALSE); 2400 2401 if (error != STATUS_SUCCESS) 2402 return(NDIS_STATUS_FAILURE); 2403 2404 block->nmb_interrupt = intr; 2405 2406 return(NDIS_STATUS_SUCCESS); 2407} 2408 2409static void 2410NdisMDeregisterInterrupt(intr) 2411 ndis_miniport_interrupt *intr; 2412{ 2413 ndis_miniport_block *block; 2414 struct ndis_softc *sc; 2415 uint8_t irql; 2416 2417 block = intr->ni_block; 2418 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2419 2420 /* Should really be KeSynchronizeExecution() */ 2421 2422 KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql); 2423 block->nmb_interrupt = NULL; 2424 KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql); 2425/* 2426 KeFlushQueuedDpcs(); 2427*/ 2428 /* Disconnect our ISR */ 2429 2430 IoDisconnectInterrupt(intr->ni_introbj); 2431 2432 KeWaitForSingleObject(&intr->ni_dpcevt, 0, 0, FALSE, NULL); 2433 KeResetEvent(&intr->ni_dpcevt); 2434 2435 return; 2436} 2437 2438static void 2439NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc) 2440 ndis_handle adapter; 2441 void *shutdownctx; 2442 ndis_shutdown_handler shutdownfunc; 2443{ 2444 ndis_miniport_block *block; 2445 ndis_miniport_characteristics *chars; 2446 struct ndis_softc *sc; 2447 2448 if (adapter == NULL) 2449 return; 2450 2451 block = (ndis_miniport_block *)adapter; 2452 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2453 chars = sc->ndis_chars; 2454 2455 chars->nmc_shutdown_handler = shutdownfunc; 2456 chars->nmc_rsvd0 = shutdownctx; 2457 2458 return; 2459} 2460 2461static void 2462NdisMDeregisterAdapterShutdownHandler(adapter) 2463 ndis_handle adapter; 2464{ 2465 ndis_miniport_block *block; 2466 ndis_miniport_characteristics *chars; 2467 struct ndis_softc *sc; 2468 2469 if (adapter == NULL) 2470 return; 2471 2472 block = (ndis_miniport_block *)adapter; 2473 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2474 chars = sc->ndis_chars; 2475 2476 chars->nmc_shutdown_handler = NULL; 2477 chars->nmc_rsvd0 = NULL; 2478 2479 return; 2480} 2481 2482static uint32_t 2483NDIS_BUFFER_TO_SPAN_PAGES(buf) 2484 ndis_buffer *buf; 2485{ 2486 if (buf == NULL) 2487 return(0); 2488 if (MmGetMdlByteCount(buf) == 0) 2489 return(1); 2490 return(SPAN_PAGES(MmGetMdlVirtualAddress(buf), 2491 MmGetMdlByteCount(buf))); 2492} 2493 2494static void 2495NdisGetBufferPhysicalArraySize(buf, pages) 2496 ndis_buffer *buf; 2497 uint32_t *pages; 2498{ 2499 if (buf == NULL) 2500 return; 2501 2502 *pages = NDIS_BUFFER_TO_SPAN_PAGES(buf); 2503 return; 2504} 2505 2506static void 2507NdisQueryBufferOffset(buf, off, len) 2508 ndis_buffer *buf; 2509 uint32_t *off; 2510 uint32_t *len; 2511{ 2512 if (buf == NULL) 2513 return; 2514 2515 *off = MmGetMdlByteOffset(buf); 2516 *len = MmGetMdlByteCount(buf); 2517 2518 return; 2519} 2520 2521void 2522NdisMSleep(usecs) 2523 uint32_t usecs; 2524{ 2525 ktimer timer; 2526 2527 /* 2528 * During system bootstrap, (i.e. cold == 1), we aren't 2529 * allowed to sleep, so we have to do a hard DELAY() 2530 * instead. 2531 */ 2532 2533 if (cold) 2534 DELAY(usecs); 2535 else { 2536 KeInitializeTimer(&timer); 2537 KeSetTimer(&timer, ((int64_t)usecs * -10), NULL); 2538 KeWaitForSingleObject(&timer, 0, 0, FALSE, NULL); 2539 } 2540 2541 return; 2542} 2543 2544static uint32_t 2545NdisReadPcmciaAttributeMemory(handle, offset, buf, len) 2546 ndis_handle handle; 2547 uint32_t offset; 2548 void *buf; 2549 uint32_t len; 2550{ 2551 struct ndis_softc *sc; 2552 ndis_miniport_block *block; 2553 bus_space_handle_t bh; 2554 bus_space_tag_t bt; 2555 char *dest; 2556 int i; 2557 2558 if (handle == NULL) 2559 return(0); 2560 2561 block = (ndis_miniport_block *)handle; 2562 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2563 dest = buf; 2564 2565 bh = rman_get_bushandle(sc->ndis_res_am); 2566 bt = rman_get_bustag(sc->ndis_res_am); 2567 2568 for (i = 0; i < len; i++) 2569 dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2); 2570 2571 return(i); 2572} 2573 2574static uint32_t 2575NdisWritePcmciaAttributeMemory(handle, offset, buf, len) 2576 ndis_handle handle; 2577 uint32_t offset; 2578 void *buf; 2579 uint32_t len; 2580{ 2581 struct ndis_softc *sc; 2582 ndis_miniport_block *block; 2583 bus_space_handle_t bh; 2584 bus_space_tag_t bt; 2585 char *src; 2586 int i; 2587 2588 if (handle == NULL) 2589 return(0); 2590 2591 block = (ndis_miniport_block *)handle; 2592 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2593 src = buf; 2594 2595 bh = rman_get_bushandle(sc->ndis_res_am); 2596 bt = rman_get_bustag(sc->ndis_res_am); 2597 2598 for (i = 0; i < len; i++) 2599 bus_space_write_1(bt, bh, (offset + i) * 2, src[i]); 2600 2601 return(i); 2602} 2603 2604static list_entry * 2605NdisInterlockedInsertHeadList(head, entry, lock) 2606 list_entry *head; 2607 list_entry *entry; 2608 ndis_spin_lock *lock; 2609{ 2610 list_entry *flink; 2611 2612 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2613 flink = head->nle_flink; 2614 entry->nle_flink = flink; 2615 entry->nle_blink = head; 2616 flink->nle_blink = entry; 2617 head->nle_flink = entry; 2618 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2619 2620 return(flink); 2621} 2622 2623static list_entry * 2624NdisInterlockedRemoveHeadList(head, lock) 2625 list_entry *head; 2626 ndis_spin_lock *lock; 2627{ 2628 list_entry *flink; 2629 list_entry *entry; 2630 2631 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2632 entry = head->nle_flink; 2633 flink = entry->nle_flink; 2634 head->nle_flink = flink; 2635 flink->nle_blink = head; 2636 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2637 2638 return(entry); 2639} 2640 2641static list_entry * 2642NdisInterlockedInsertTailList(head, entry, lock) 2643 list_entry *head; 2644 list_entry *entry; 2645 ndis_spin_lock *lock; 2646{ 2647 list_entry *blink; 2648 2649 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2650 blink = head->nle_blink; 2651 entry->nle_flink = head; 2652 entry->nle_blink = blink; 2653 blink->nle_flink = entry; 2654 head->nle_blink = entry; 2655 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2656 2657 return(blink); 2658} 2659 2660static uint8_t 2661NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx) 2662 ndis_miniport_interrupt *intr; 2663 void *syncfunc; 2664 void *syncctx; 2665{ 2666 return(KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx)); 2667} 2668 2669static void 2670NdisGetCurrentSystemTime(tval) 2671 uint64_t *tval; 2672{ 2673 ntoskrnl_time(tval); 2674 return; 2675} 2676 2677/* 2678 * Return the number of milliseconds since the system booted. 2679 */ 2680static void 2681NdisGetSystemUpTime(tval) 2682 uint32_t *tval; 2683{ 2684 struct timespec ts; 2685 2686 nanouptime(&ts); 2687 *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000; 2688 2689 return; 2690} 2691 2692static void 2693NdisInitializeString(dst, src) 2694 unicode_string *dst; 2695 char *src; 2696{ 2697 ansi_string as; 2698 RtlInitAnsiString(&as, src); 2699 RtlAnsiStringToUnicodeString(dst, &as, TRUE); 2700 return; 2701} 2702 2703static void 2704NdisFreeString(str) 2705 unicode_string *str; 2706{ 2707 RtlFreeUnicodeString(str); 2708 return; 2709} 2710 2711static ndis_status 2712NdisMRemoveMiniport(adapter) 2713 ndis_handle *adapter; 2714{ 2715 return(NDIS_STATUS_SUCCESS); 2716} 2717 2718static void 2719NdisInitAnsiString(dst, src) 2720 ansi_string *dst; 2721 char *src; 2722{ 2723 RtlInitAnsiString(dst, src); 2724 return; 2725} 2726 2727static void 2728NdisInitUnicodeString(dst, src) 2729 unicode_string *dst; 2730 uint16_t *src; 2731{ 2732 RtlInitUnicodeString(dst, src); 2733 return; 2734} 2735 2736static void NdisMGetDeviceProperty(adapter, phydevobj, 2737 funcdevobj, nextdevobj, resources, transresources) 2738 ndis_handle adapter; 2739 device_object **phydevobj; 2740 device_object **funcdevobj; 2741 device_object **nextdevobj; 2742 cm_resource_list *resources; 2743 cm_resource_list *transresources; 2744{ 2745 ndis_miniport_block *block; 2746 2747 block = (ndis_miniport_block *)adapter; 2748 2749 if (phydevobj != NULL) 2750 *phydevobj = block->nmb_physdeviceobj; 2751 if (funcdevobj != NULL) 2752 *funcdevobj = block->nmb_deviceobj; 2753 if (nextdevobj != NULL) 2754 *nextdevobj = block->nmb_nextdeviceobj; 2755 2756 return; 2757} 2758 2759static void 2760NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen) 2761 ndis_packet *packet; 2762 ndis_buffer **buf; 2763 void **firstva; 2764 uint32_t *firstlen; 2765 uint32_t *totlen; 2766{ 2767 ndis_buffer *tmp; 2768 2769 tmp = packet->np_private.npp_head; 2770 *buf = tmp; 2771 if (tmp == NULL) { 2772 *firstva = NULL; 2773 *firstlen = *totlen = 0; 2774 } else { 2775 *firstva = MmGetMdlVirtualAddress(tmp); 2776 *firstlen = *totlen = MmGetMdlByteCount(tmp); 2777 for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next) 2778 *totlen += MmGetMdlByteCount(tmp); 2779 } 2780 2781 return; 2782} 2783 2784static void 2785NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio) 2786 ndis_packet *packet; 2787 ndis_buffer **buf; 2788 void **firstva; 2789 uint32_t *firstlen; 2790 uint32_t *totlen; 2791 uint32_t prio; 2792{ 2793 NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen); 2794} 2795 2796static int 2797ndis_find_sym(lf, filename, suffix, sym) 2798 linker_file_t lf; 2799 char *filename; 2800 char *suffix; 2801 caddr_t *sym; 2802{ 2803 char *fullsym; 2804 char *suf; 2805 int i; 2806 2807 fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2808 if (fullsym == NULL) 2809 return(ENOMEM); 2810 2811 bzero(fullsym, MAXPATHLEN); 2812 strncpy(fullsym, filename, MAXPATHLEN); 2813 if (strlen(filename) < 4) { 2814 ExFreePool(fullsym); 2815 return(EINVAL); 2816 } 2817 2818 /* If the filename has a .ko suffix, strip if off. */ 2819 suf = fullsym + (strlen(filename) - 3); 2820 if (strcmp(suf, ".ko") == 0) 2821 *suf = '\0'; 2822 2823 for (i = 0; i < strlen(fullsym); i++) { 2824 if (fullsym[i] == '.') 2825 fullsym[i] = '_'; 2826 else 2827 fullsym[i] = tolower(fullsym[i]); 2828 } 2829 strcat(fullsym, suffix); 2830 *sym = linker_file_lookup_symbol(lf, fullsym, 0); 2831 ExFreePool(fullsym); 2832 if (*sym == 0) 2833 return(ENOENT); 2834 2835 return(0); 2836} 2837 2838struct ndis_checkmodule { 2839 char *afilename; 2840 ndis_fh *fh; 2841}; 2842 2843/* 2844 * See if a single module contains the symbols for a specified file. 2845 */ 2846static int 2847NdisCheckModule(linker_file_t lf, void *context) 2848{ 2849 struct ndis_checkmodule *nc; 2850 caddr_t kldstart, kldend; 2851 2852 nc = (struct ndis_checkmodule *)context; 2853 if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart)) 2854 return (0); 2855 if (ndis_find_sym(lf, nc->afilename, "_end", &kldend)) 2856 return (0); 2857 nc->fh->nf_vp = lf; 2858 nc->fh->nf_map = NULL; 2859 nc->fh->nf_type = NDIS_FH_TYPE_MODULE; 2860 nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; 2861 return (1); 2862} 2863 2864/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ 2865static void 2866NdisOpenFile(status, filehandle, filelength, filename, highestaddr) 2867 ndis_status *status; 2868 ndis_handle *filehandle; 2869 uint32_t *filelength; 2870 unicode_string *filename; 2871 ndis_physaddr highestaddr; 2872{ 2873 ansi_string as; 2874 char *afilename = NULL; 2875 struct thread *td = curthread; 2876 struct nameidata nd; 2877 int flags, error, vfslocked; 2878 struct vattr vat; 2879 struct vattr *vap = &vat; 2880 ndis_fh *fh; 2881 char *path; 2882 struct ndis_checkmodule nc; 2883 2884 if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) { 2885 *status = NDIS_STATUS_RESOURCES; 2886 return; 2887 } 2888 2889 afilename = strdup(as.as_buf, M_DEVBUF); 2890 RtlFreeAnsiString(&as); 2891 2892 fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0); 2893 if (fh == NULL) { 2894 free(afilename, M_DEVBUF); 2895 *status = NDIS_STATUS_RESOURCES; 2896 return; 2897 } 2898 2899 fh->nf_name = afilename; 2900 2901 /* 2902 * During system bootstrap, it's impossible to load files 2903 * from the rootfs since it's not mounted yet. We therefore 2904 * offer the possibility of opening files that have been 2905 * preloaded as modules instead. Both choices will work 2906 * when kldloading a module from multiuser, but only the 2907 * module option will work during bootstrap. The module 2908 * loading option works by using the ndiscvt(8) utility 2909 * to convert the arbitrary file into a .ko using objcopy(1). 2910 * This file will contain two special symbols: filename_start 2911 * and filename_end. All we have to do is traverse the KLD 2912 * list in search of those symbols and we've found the file 2913 * data. As an added bonus, ndiscvt(8) will also generate 2914 * a normal .o file which can be linked statically with 2915 * the kernel. This means that the symbols will actual reside 2916 * in the kernel's symbol table, but that doesn't matter to 2917 * us since the kernel appears to us as just another module. 2918 */ 2919 2920 nc.afilename = afilename; 2921 nc.fh = fh; 2922 if (linker_file_foreach(NdisCheckModule, &nc)) { 2923 *filelength = fh->nf_maplen; 2924 *filehandle = fh; 2925 *status = NDIS_STATUS_SUCCESS; 2926 return; 2927 } 2928 2929 if (TAILQ_EMPTY(&mountlist)) { 2930 ExFreePool(fh); 2931 *status = NDIS_STATUS_FILE_NOT_FOUND; 2932 printf("NDIS: could not find file %s in linker list\n", 2933 afilename); 2934 printf("NDIS: and no filesystems mounted yet, " 2935 "aborting NdisOpenFile()\n"); 2936 free(afilename, M_DEVBUF); 2937 return; 2938 } 2939 2940 path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2941 if (path == NULL) { 2942 ExFreePool(fh); 2943 free(afilename, M_DEVBUF); 2944 *status = NDIS_STATUS_RESOURCES; 2945 return; 2946 } 2947 2948 snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); 2949 2950 /* Some threads don't have a current working directory. */ 2951 2952 if (td->td_proc->p_fd->fd_rdir == NULL) 2953 td->td_proc->p_fd->fd_rdir = rootvnode; 2954 if (td->td_proc->p_fd->fd_cdir == NULL) 2955 td->td_proc->p_fd->fd_cdir = rootvnode; 2956 2957 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, path, td); 2958 2959 flags = FREAD; 2960 error = vn_open(&nd, &flags, 0, NULL); 2961 if (error) { 2962 *status = NDIS_STATUS_FILE_NOT_FOUND; 2963 ExFreePool(fh); 2964 printf("NDIS: open file %s failed: %d\n", path, error); 2965 ExFreePool(path); 2966 free(afilename, M_DEVBUF); 2967 return; 2968 } 2969 vfslocked = NDHASGIANT(&nd); 2970 2971 ExFreePool(path); 2972 2973 NDFREE(&nd, NDF_ONLY_PNBUF); 2974 2975 /* Get the file size. */ 2976 VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 2977 VOP_UNLOCK(nd.ni_vp, 0); 2978 VFS_UNLOCK_GIANT(vfslocked); 2979 2980 fh->nf_vp = nd.ni_vp; 2981 fh->nf_map = NULL; 2982 fh->nf_type = NDIS_FH_TYPE_VFS; 2983 *filehandle = fh; 2984 *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; 2985 *status = NDIS_STATUS_SUCCESS; 2986 2987 return; 2988} 2989 2990static void 2991NdisMapFile(status, mappedbuffer, filehandle) 2992 ndis_status *status; 2993 void **mappedbuffer; 2994 ndis_handle filehandle; 2995{ 2996 ndis_fh *fh; 2997 struct thread *td = curthread; 2998 linker_file_t lf; 2999 caddr_t kldstart; 3000 int error, resid, vfslocked; 3001 struct vnode *vp; 3002 3003 if (filehandle == NULL) { 3004 *status = NDIS_STATUS_FAILURE; 3005 return; 3006 } 3007 3008 fh = (ndis_fh *)filehandle; 3009 3010 if (fh->nf_vp == NULL) { 3011 *status = NDIS_STATUS_FAILURE; 3012 return; 3013 } 3014 3015 if (fh->nf_map != NULL) { 3016 *status = NDIS_STATUS_ALREADY_MAPPED; 3017 return; 3018 } 3019 3020 if (fh->nf_type == NDIS_FH_TYPE_MODULE) { 3021 lf = fh->nf_vp; 3022 if (ndis_find_sym(lf, fh->nf_name, "_start", &kldstart)) { 3023 *status = NDIS_STATUS_FAILURE; 3024 return; 3025 } 3026 fh->nf_map = kldstart; 3027 *status = NDIS_STATUS_SUCCESS; 3028 *mappedbuffer = fh->nf_map; 3029 return; 3030 } 3031 3032 fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0); 3033 3034 if (fh->nf_map == NULL) { 3035 *status = NDIS_STATUS_RESOURCES; 3036 return; 3037 } 3038 3039 vp = fh->nf_vp; 3040 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 3041 error = vn_rdwr(UIO_READ, vp, fh->nf_map, fh->nf_maplen, 0, 3042 UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); 3043 VFS_UNLOCK_GIANT(vfslocked); 3044 3045 if (error) 3046 *status = NDIS_STATUS_FAILURE; 3047 else { 3048 *status = NDIS_STATUS_SUCCESS; 3049 *mappedbuffer = fh->nf_map; 3050 } 3051 3052 return; 3053} 3054 3055static void 3056NdisUnmapFile(filehandle) 3057 ndis_handle filehandle; 3058{ 3059 ndis_fh *fh; 3060 fh = (ndis_fh *)filehandle; 3061 3062 if (fh->nf_map == NULL) 3063 return; 3064 3065 if (fh->nf_type == NDIS_FH_TYPE_VFS) 3066 ExFreePool(fh->nf_map); 3067 fh->nf_map = NULL; 3068 3069 return; 3070} 3071 3072static void 3073NdisCloseFile(filehandle) 3074 ndis_handle filehandle; 3075{ 3076 struct thread *td = curthread; 3077 ndis_fh *fh; 3078 int vfslocked; 3079 struct vnode *vp; 3080 3081 if (filehandle == NULL) 3082 return; 3083 3084 fh = (ndis_fh *)filehandle; 3085 if (fh->nf_map != NULL) { 3086 if (fh->nf_type == NDIS_FH_TYPE_VFS) 3087 ExFreePool(fh->nf_map); 3088 fh->nf_map = NULL; 3089 } 3090 3091 if (fh->nf_vp == NULL) 3092 return; 3093 3094 if (fh->nf_type == NDIS_FH_TYPE_VFS) { 3095 vp = fh->nf_vp; 3096 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 3097 vn_close(vp, FREAD, td->td_ucred, td); 3098 VFS_UNLOCK_GIANT(vfslocked); 3099 } 3100 3101 fh->nf_vp = NULL; 3102 free(fh->nf_name, M_DEVBUF); 3103 ExFreePool(fh); 3104 3105 return; 3106} 3107 3108static uint8_t 3109NdisSystemProcessorCount() 3110{ 3111 return(mp_ncpus); 3112} 3113 3114typedef void (*ndis_statusdone_handler)(ndis_handle); 3115typedef void (*ndis_status_handler)(ndis_handle, ndis_status, 3116 void *, uint32_t); 3117 3118static void 3119NdisMIndicateStatusComplete(adapter) 3120 ndis_handle adapter; 3121{ 3122 ndis_miniport_block *block; 3123 ndis_statusdone_handler statusdonefunc; 3124 3125 block = (ndis_miniport_block *)adapter; 3126 statusdonefunc = block->nmb_statusdone_func; 3127 3128 MSCALL1(statusdonefunc, adapter); 3129 return; 3130} 3131 3132static void 3133NdisMIndicateStatus(adapter, status, sbuf, slen) 3134 ndis_handle adapter; 3135 ndis_status status; 3136 void *sbuf; 3137 uint32_t slen; 3138{ 3139 ndis_miniport_block *block; 3140 ndis_status_handler statusfunc; 3141 3142 block = (ndis_miniport_block *)adapter; 3143 statusfunc = block->nmb_status_func; 3144 3145 MSCALL4(statusfunc, adapter, status, sbuf, slen); 3146 return; 3147} 3148 3149/* 3150 * The DDK documentation says that you should use IoQueueWorkItem() 3151 * instead of ExQueueWorkItem(). The problem is, IoQueueWorkItem() 3152 * is fundamentally incompatible with NdisScheduleWorkItem(), which 3153 * depends on the API semantics of ExQueueWorkItem(). In our world, 3154 * ExQueueWorkItem() is implemented on top of IoAllocateQueueItem() 3155 * anyway. 3156 * 3157 * There are actually three distinct APIs here. NdisScheduleWorkItem() 3158 * takes a pointer to an NDIS_WORK_ITEM. ExQueueWorkItem() takes a pointer 3159 * to a WORK_QUEUE_ITEM. And finally, IoQueueWorkItem() takes a pointer 3160 * to an opaque work item thingie which you get from IoAllocateWorkItem(). 3161 * An NDIS_WORK_ITEM is not the same as a WORK_QUEUE_ITEM. However, 3162 * the NDIS_WORK_ITEM has some opaque storage at the end of it, and we 3163 * (ab)use this storage as a WORK_QUEUE_ITEM, which is what we submit 3164 * to ExQueueWorkItem(). 3165 * 3166 * Got all that? (Sheesh.) 3167 */ 3168 3169ndis_status 3170NdisScheduleWorkItem(work) 3171 ndis_work_item *work; 3172{ 3173 work_queue_item *wqi; 3174 3175 wqi = (work_queue_item *)work->nwi_wraprsvd; 3176 ExInitializeWorkItem(wqi, 3177 (work_item_func)work->nwi_func, work->nwi_ctx); 3178 ExQueueWorkItem(wqi, WORKQUEUE_DELAYED); 3179 3180 return(NDIS_STATUS_SUCCESS); 3181} 3182 3183static void 3184NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen) 3185 ndis_packet *dpkt; 3186 uint32_t doff; 3187 uint32_t reqlen; 3188 ndis_packet *spkt; 3189 uint32_t soff; 3190 uint32_t *cpylen; 3191{ 3192 ndis_buffer *src, *dst; 3193 char *sptr, *dptr; 3194 int resid, copied, len, scnt, dcnt; 3195 3196 *cpylen = 0; 3197 3198 src = spkt->np_private.npp_head; 3199 dst = dpkt->np_private.npp_head; 3200 3201 sptr = MmGetMdlVirtualAddress(src); 3202 dptr = MmGetMdlVirtualAddress(dst); 3203 scnt = MmGetMdlByteCount(src); 3204 dcnt = MmGetMdlByteCount(dst); 3205 3206 while (soff) { 3207 if (MmGetMdlByteCount(src) > soff) { 3208 sptr += soff; 3209 scnt = MmGetMdlByteCount(src)- soff; 3210 break; 3211 } 3212 soff -= MmGetMdlByteCount(src); 3213 src = src->mdl_next; 3214 if (src == NULL) 3215 return; 3216 sptr = MmGetMdlVirtualAddress(src); 3217 } 3218 3219 while (doff) { 3220 if (MmGetMdlByteCount(dst) > doff) { 3221 dptr += doff; 3222 dcnt = MmGetMdlByteCount(dst) - doff; 3223 break; 3224 } 3225 doff -= MmGetMdlByteCount(dst); 3226 dst = dst->mdl_next; 3227 if (dst == NULL) 3228 return; 3229 dptr = MmGetMdlVirtualAddress(dst); 3230 } 3231 3232 resid = reqlen; 3233 copied = 0; 3234 3235 while(1) { 3236 if (resid < scnt) 3237 len = resid; 3238 else 3239 len = scnt; 3240 if (dcnt < len) 3241 len = dcnt; 3242 3243 bcopy(sptr, dptr, len); 3244 3245 copied += len; 3246 resid -= len; 3247 if (resid == 0) 3248 break; 3249 3250 dcnt -= len; 3251 if (dcnt == 0) { 3252 dst = dst->mdl_next; 3253 if (dst == NULL) 3254 break; 3255 dptr = MmGetMdlVirtualAddress(dst); 3256 dcnt = MmGetMdlByteCount(dst); 3257 } 3258 3259 scnt -= len; 3260 if (scnt == 0) { 3261 src = src->mdl_next; 3262 if (src == NULL) 3263 break; 3264 sptr = MmGetMdlVirtualAddress(src); 3265 scnt = MmGetMdlByteCount(src); 3266 } 3267 } 3268 3269 *cpylen = copied; 3270 return; 3271} 3272 3273static void 3274NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio) 3275 ndis_packet *dpkt; 3276 uint32_t doff; 3277 uint32_t reqlen; 3278 ndis_packet *spkt; 3279 uint32_t soff; 3280 uint32_t *cpylen; 3281 uint32_t prio; 3282{ 3283 NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen); 3284 return; 3285} 3286 3287static void 3288NdisIMCopySendPerPacketInfo(dpkt, spkt) 3289 ndis_packet *dpkt; 3290 ndis_packet *spkt; 3291{ 3292 memcpy(&dpkt->np_ext, &spkt->np_ext, sizeof(ndis_packet_extension)); 3293} 3294 3295static ndis_status 3296NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle) 3297 ndis_handle handle; 3298 unicode_string *devname; 3299 unicode_string *symname; 3300 driver_dispatch *majorfuncs[]; 3301 void **devobj; 3302 ndis_handle *devhandle; 3303{ 3304 uint32_t status; 3305 device_object *dobj; 3306 3307 status = IoCreateDevice(handle, 0, devname, 3308 FILE_DEVICE_UNKNOWN, 0, FALSE, &dobj); 3309 3310 if (status == STATUS_SUCCESS) { 3311 *devobj = dobj; 3312 *devhandle = dobj; 3313 } 3314 3315 return(status); 3316} 3317 3318static ndis_status 3319NdisMDeregisterDevice(handle) 3320 ndis_handle handle; 3321{ 3322 IoDeleteDevice(handle); 3323 return(NDIS_STATUS_SUCCESS); 3324} 3325 3326static ndis_status 3327NdisMQueryAdapterInstanceName(name, handle) 3328 unicode_string *name; 3329 ndis_handle handle; 3330{ 3331 ndis_miniport_block *block; 3332 device_t dev; 3333 ansi_string as; 3334 3335 block = (ndis_miniport_block *)handle; 3336 dev = block->nmb_physdeviceobj->do_devext; 3337 3338 RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev))); 3339 if (RtlAnsiStringToUnicodeString(name, &as, TRUE)) 3340 return(NDIS_STATUS_RESOURCES); 3341 3342 return(NDIS_STATUS_SUCCESS); 3343} 3344 3345static void 3346NdisMRegisterUnloadHandler(handle, func) 3347 ndis_handle handle; 3348 void *func; 3349{ 3350 return; 3351} 3352 3353static void 3354dummy() 3355{ 3356 printf ("NDIS dummy called...\n"); 3357 return; 3358} 3359 3360/* 3361 * Note: a couple of entries in this table specify the 3362 * number of arguments as "foo + 1". These are routines 3363 * that accept a 64-bit argument, passed by value. On 3364 * x86, these arguments consume two longwords on the stack, 3365 * so we lie and say there's one additional argument so 3366 * that the wrapping routines will do the right thing. 3367 */ 3368 3369image_patch_table ndis_functbl[] = { 3370 IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6), 3371 IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7), 3372 IMPORT_SFUNC(NdisIMCopySendPerPacketInfo, 2), 3373 IMPORT_SFUNC(NdisScheduleWorkItem, 1), 3374 IMPORT_SFUNC(NdisMIndicateStatusComplete, 1), 3375 IMPORT_SFUNC(NdisMIndicateStatus, 4), 3376 IMPORT_SFUNC(NdisSystemProcessorCount, 0), 3377 IMPORT_SFUNC(NdisUnchainBufferAtBack, 2), 3378 IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5), 3379 IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6), 3380 IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2), 3381 IMPORT_SFUNC(NdisMGetDeviceProperty, 6), 3382 IMPORT_SFUNC(NdisInitAnsiString, 2), 3383 IMPORT_SFUNC(NdisInitUnicodeString, 2), 3384 IMPORT_SFUNC(NdisWriteConfiguration, 4), 3385 IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2), 3386 IMPORT_SFUNC(NdisTerminateWrapper, 2), 3387 IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4), 3388 IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5), 3389 IMPORT_SFUNC(NdisMRemoveMiniport, 1), 3390 IMPORT_SFUNC(NdisInitializeString, 2), 3391 IMPORT_SFUNC(NdisFreeString, 1), 3392 IMPORT_SFUNC(NdisGetCurrentSystemTime, 1), 3393 IMPORT_SFUNC(NdisGetSystemUpTime, 1), 3394 IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3), 3395 IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4), 3396 IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3), 3397 IMPORT_SFUNC(NdisInterlockedInsertTailList, 3), 3398 IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2), 3399 IMPORT_SFUNC(NdisInitializeWrapper, 4), 3400 IMPORT_SFUNC(NdisMRegisterMiniport, 3), 3401 IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3), 3402 IMPORT_SFUNC(NdisAllocateMemory, 4 + 1), 3403 IMPORT_SFUNC(NdisMSetAttributesEx, 5), 3404 IMPORT_SFUNC(NdisCloseConfiguration, 1), 3405 IMPORT_SFUNC(NdisReadConfiguration, 5), 3406 IMPORT_SFUNC(NdisOpenConfiguration, 3), 3407 IMPORT_SFUNC(NdisAcquireSpinLock, 1), 3408 IMPORT_SFUNC(NdisReleaseSpinLock, 1), 3409 IMPORT_SFUNC(NdisDprAcquireSpinLock, 1), 3410 IMPORT_SFUNC(NdisDprReleaseSpinLock, 1), 3411 IMPORT_SFUNC(NdisAllocateSpinLock, 1), 3412 IMPORT_SFUNC(NdisInitializeReadWriteLock, 1), 3413 IMPORT_SFUNC(NdisAcquireReadWriteLock, 3), 3414 IMPORT_SFUNC(NdisReleaseReadWriteLock, 2), 3415 IMPORT_SFUNC(NdisFreeSpinLock, 1), 3416 IMPORT_SFUNC(NdisFreeMemory, 3), 3417 IMPORT_SFUNC(NdisReadPciSlotInformation, 5), 3418 IMPORT_SFUNC(NdisWritePciSlotInformation, 5), 3419 IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation, 3420 NdisReadPciSlotInformation, 5), 3421 IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation, 3422 NdisWritePciSlotInformation, 5), 3423 IMPORT_CFUNC(NdisWriteErrorLogEntry, 0), 3424 IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6), 3425 IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3), 3426 IMPORT_SFUNC(NdisMInitializeTimer, 4), 3427 IMPORT_SFUNC(NdisInitializeTimer, 3), 3428 IMPORT_SFUNC(NdisSetTimer, 2), 3429 IMPORT_SFUNC(NdisMCancelTimer, 2), 3430 IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2), 3431 IMPORT_SFUNC(NdisMSetPeriodicTimer, 2), 3432 IMPORT_SFUNC(NdisMQueryAdapterResources, 4), 3433 IMPORT_SFUNC(NdisMRegisterIoPortRange, 4), 3434 IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4), 3435 IMPORT_SFUNC(NdisReadNetworkAddress, 4), 3436 IMPORT_SFUNC(NdisQueryMapRegisterCount, 2), 3437 IMPORT_SFUNC(NdisMAllocateMapRegisters, 5), 3438 IMPORT_SFUNC(NdisMFreeMapRegisters, 1), 3439 IMPORT_SFUNC(NdisMAllocateSharedMemory, 5), 3440 IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1), 3441 IMPORT_SFUNC(NdisMUnmapIoSpace, 3), 3442 IMPORT_SFUNC(NdisGetCacheFillSize, 0), 3443 IMPORT_SFUNC(NdisMGetDmaAlignment, 1), 3444 IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3), 3445 IMPORT_SFUNC(NdisAllocatePacketPool, 4), 3446 IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5), 3447 IMPORT_SFUNC(NdisAllocatePacket, 3), 3448 IMPORT_SFUNC(NdisFreePacket, 1), 3449 IMPORT_SFUNC(NdisFreePacketPool, 1), 3450 IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3), 3451 IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1), 3452 IMPORT_SFUNC(NdisAllocateBufferPool, 3), 3453 IMPORT_SFUNC(NdisAllocateBuffer, 5), 3454 IMPORT_SFUNC(NdisQueryBuffer, 3), 3455 IMPORT_SFUNC(NdisQueryBufferSafe, 4), 3456 IMPORT_SFUNC(NdisBufferVirtualAddress, 1), 3457 IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2), 3458 IMPORT_SFUNC(NdisBufferLength, 1), 3459 IMPORT_SFUNC(NdisFreeBuffer, 1), 3460 IMPORT_SFUNC(NdisFreeBufferPool, 1), 3461 IMPORT_SFUNC(NdisInterlockedIncrement, 1), 3462 IMPORT_SFUNC(NdisInterlockedDecrement, 1), 3463 IMPORT_SFUNC(NdisInitializeEvent, 1), 3464 IMPORT_SFUNC(NdisSetEvent, 1), 3465 IMPORT_SFUNC(NdisResetEvent, 1), 3466 IMPORT_SFUNC(NdisWaitEvent, 2), 3467 IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2), 3468 IMPORT_SFUNC(NdisMPciAssignResources, 3), 3469 IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1), 3470 IMPORT_SFUNC(NdisMRegisterInterrupt, 7), 3471 IMPORT_SFUNC(NdisMDeregisterInterrupt, 1), 3472 IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3), 3473 IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1), 3474 IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1), 3475 IMPORT_SFUNC(NdisQueryBufferOffset, 3), 3476 IMPORT_SFUNC(NdisAdjustBufferLength, 2), 3477 IMPORT_SFUNC(NdisPacketPoolUsage, 1), 3478 IMPORT_SFUNC(NdisMSleep, 1), 3479 IMPORT_SFUNC(NdisUnchainBufferAtFront, 2), 3480 IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4), 3481 IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4), 3482 IMPORT_SFUNC(NdisOpenFile, 5 + 1), 3483 IMPORT_SFUNC(NdisMapFile, 3), 3484 IMPORT_SFUNC(NdisUnmapFile, 1), 3485 IMPORT_SFUNC(NdisCloseFile, 1), 3486 IMPORT_SFUNC(NdisMRegisterDevice, 6), 3487 IMPORT_SFUNC(NdisMDeregisterDevice, 1), 3488 IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2), 3489 IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2), 3490 IMPORT_SFUNC(ndis_timercall, 4), 3491 IMPORT_SFUNC(ndis_asyncmem_complete, 2), 3492 IMPORT_SFUNC(ndis_intr, 2), 3493 IMPORT_SFUNC(ndis_intrhand, 4), 3494 3495 /* 3496 * This last entry is a catch-all for any function we haven't 3497 * implemented yet. The PE import list patching routine will 3498 * use it for any function that doesn't have an explicit match 3499 * in this table. 3500 */ 3501 3502 { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL }, 3503 3504 /* End of list. */ 3505 3506 { NULL, NULL, NULL } 3507}; 3508