subr_ndis.c revision 175294
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 175294 2008-01-13 14:44:15Z attilio $"); 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->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->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 1364#ifdef IFP2ENADDR 1365 if (bcmp(IFP2ENADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0) 1366#elif __FreeBSD_version >= 700000 1367 if (sc->ifp->if_addr == NULL || 1368 bcmp(IF_LLADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0) 1369#else 1370 if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0) 1371#endif 1372 *status = NDIS_STATUS_FAILURE; 1373 else { 1374#ifdef IFP2ENADDR 1375 *addr = IFP2ENADDR(sc->ifp); 1376#elif __FreeBSD_version >= 700000 1377 *addr = IF_LLADDR(sc->ifp); 1378#else 1379 *addr = sc->arpcom.ac_enaddr; 1380#endif 1381 *addrlen = ETHER_ADDR_LEN; 1382 *status = NDIS_STATUS_SUCCESS; 1383 } 1384 1385 return; 1386} 1387 1388static ndis_status 1389NdisQueryMapRegisterCount(bustype, cnt) 1390 uint32_t bustype; 1391 uint32_t *cnt; 1392{ 1393 *cnt = 8192; 1394 return(NDIS_STATUS_SUCCESS); 1395} 1396 1397static ndis_status 1398NdisMAllocateMapRegisters(adapter, dmachannel, dmasize, physmapneeded, maxmap) 1399 ndis_handle adapter; 1400 uint32_t dmachannel; 1401 uint8_t dmasize; 1402 uint32_t physmapneeded; 1403 uint32_t maxmap; 1404{ 1405 struct ndis_softc *sc; 1406 ndis_miniport_block *block; 1407 int error, i, nseg = NDIS_MAXSEG; 1408 1409 block = (ndis_miniport_block *)adapter; 1410 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1411 1412 sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded, 1413 M_DEVBUF, M_NOWAIT|M_ZERO); 1414 1415 if (sc->ndis_mmaps == NULL) 1416 return(NDIS_STATUS_RESOURCES); 1417 1418 error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1419 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1420 NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW, 1421 NULL, NULL, &sc->ndis_mtag); 1422 1423 if (error) { 1424 free(sc->ndis_mmaps, M_DEVBUF); 1425 return(NDIS_STATUS_RESOURCES); 1426 } 1427 1428 for (i = 0; i < physmapneeded; i++) 1429 bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]); 1430 1431 sc->ndis_mmapcnt = physmapneeded; 1432 1433 return(NDIS_STATUS_SUCCESS); 1434} 1435 1436static void 1437NdisMFreeMapRegisters(adapter) 1438 ndis_handle adapter; 1439{ 1440 struct ndis_softc *sc; 1441 ndis_miniport_block *block; 1442 int i; 1443 1444 block = (ndis_miniport_block *)adapter; 1445 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1446 1447 for (i = 0; i < sc->ndis_mmapcnt; i++) 1448 bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]); 1449 1450 free(sc->ndis_mmaps, M_DEVBUF); 1451 1452 bus_dma_tag_destroy(sc->ndis_mtag); 1453 1454 return; 1455} 1456 1457static void 1458ndis_mapshared_cb(arg, segs, nseg, error) 1459 void *arg; 1460 bus_dma_segment_t *segs; 1461 int nseg; 1462 int error; 1463{ 1464 ndis_physaddr *p; 1465 1466 if (error || nseg > 1) 1467 return; 1468 1469 p = arg; 1470 1471 p->np_quad = segs[0].ds_addr; 1472 1473 return; 1474} 1475 1476/* 1477 * This maps to bus_dmamem_alloc(). 1478 */ 1479 1480static void 1481NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr) 1482 ndis_handle adapter; 1483 uint32_t len; 1484 uint8_t cached; 1485 void **vaddr; 1486 ndis_physaddr *paddr; 1487{ 1488 ndis_miniport_block *block; 1489 struct ndis_softc *sc; 1490 struct ndis_shmem *sh; 1491 int error; 1492 1493 if (adapter == NULL) 1494 return; 1495 1496 block = (ndis_miniport_block *)adapter; 1497 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1498 1499 sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO); 1500 if (sh == NULL) 1501 return; 1502 1503 InitializeListHead(&sh->ndis_list); 1504 1505 /* 1506 * When performing shared memory allocations, create a tag 1507 * with a lowaddr limit that restricts physical memory mappings 1508 * so that they all fall within the first 1GB of memory. 1509 * At least one device/driver combination (Linksys Instant 1510 * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have 1511 * problems with performing DMA operations with physical 1512 * addresses that lie above the 1GB mark. I don't know if this 1513 * is a hardware limitation or if the addresses are being 1514 * truncated within the driver, but this seems to be the only 1515 * way to make these cards work reliably in systems with more 1516 * than 1GB of physical memory. 1517 */ 1518 1519 error = bus_dma_tag_create(sc->ndis_parent_tag, 64, 1520 0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL, 1521 NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL, 1522 &sh->ndis_stag); 1523 1524 if (error) { 1525 free(sh, M_DEVBUF); 1526 return; 1527 } 1528 1529 error = bus_dmamem_alloc(sh->ndis_stag, vaddr, 1530 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap); 1531 1532 if (error) { 1533 bus_dma_tag_destroy(sh->ndis_stag); 1534 free(sh, M_DEVBUF); 1535 return; 1536 } 1537 1538 error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr, 1539 len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT); 1540 1541 if (error) { 1542 bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap); 1543 bus_dma_tag_destroy(sh->ndis_stag); 1544 free(sh, M_DEVBUF); 1545 return; 1546 } 1547 1548 /* 1549 * Save the physical address along with the source address. 1550 * The AirGo MIMO driver will call NdisMFreeSharedMemory() 1551 * with a bogus virtual address sometimes, but with a valid 1552 * physical address. To keep this from causing trouble, we 1553 * use the physical address to as a sanity check in case 1554 * searching based on the virtual address fails. 1555 */ 1556 1557 NDIS_LOCK(sc); 1558 sh->ndis_paddr.np_quad = paddr->np_quad; 1559 sh->ndis_saddr = *vaddr; 1560 InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list)); 1561 NDIS_UNLOCK(sc); 1562 1563 return; 1564} 1565 1566struct ndis_allocwork { 1567 uint32_t na_len; 1568 uint8_t na_cached; 1569 void *na_ctx; 1570 io_workitem *na_iw; 1571}; 1572 1573static void 1574ndis_asyncmem_complete(dobj, arg) 1575 device_object *dobj; 1576 void *arg; 1577{ 1578 ndis_miniport_block *block; 1579 struct ndis_softc *sc; 1580 struct ndis_allocwork *w; 1581 void *vaddr; 1582 ndis_physaddr paddr; 1583 ndis_allocdone_handler donefunc; 1584 1585 w = arg; 1586 block = (ndis_miniport_block *)dobj->do_devext; 1587 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1588 1589 vaddr = NULL; 1590 paddr.np_quad = 0; 1591 1592 donefunc = sc->ndis_chars->nmc_allocate_complete_func; 1593 NdisMAllocateSharedMemory(block, w->na_len, 1594 w->na_cached, &vaddr, &paddr); 1595 MSCALL5(donefunc, block, vaddr, &paddr, w->na_len, w->na_ctx); 1596 1597 IoFreeWorkItem(w->na_iw); 1598 free(w, M_DEVBUF); 1599 1600 return; 1601} 1602 1603static ndis_status 1604NdisMAllocateSharedMemoryAsync(adapter, len, cached, ctx) 1605 ndis_handle adapter; 1606 uint32_t len; 1607 uint8_t cached; 1608 void *ctx; 1609{ 1610 ndis_miniport_block *block; 1611 struct ndis_allocwork *w; 1612 io_workitem *iw; 1613 io_workitem_func ifw; 1614 1615 if (adapter == NULL) 1616 return(NDIS_STATUS_FAILURE); 1617 1618 block = adapter; 1619 1620 iw = IoAllocateWorkItem(block->nmb_deviceobj); 1621 if (iw == NULL) 1622 return(NDIS_STATUS_FAILURE); 1623 1624 w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT); 1625 1626 if (w == NULL) 1627 return(NDIS_STATUS_FAILURE); 1628 1629 w->na_cached = cached; 1630 w->na_len = len; 1631 w->na_ctx = ctx; 1632 w->na_iw = iw; 1633 1634 ifw = (io_workitem_func)ndis_findwrap((funcptr)ndis_asyncmem_complete); 1635 IoQueueWorkItem(iw, ifw, WORKQUEUE_DELAYED, w); 1636 1637 return(NDIS_STATUS_PENDING); 1638} 1639 1640static void 1641NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr) 1642 ndis_handle adapter; 1643 uint32_t len; 1644 uint8_t cached; 1645 void *vaddr; 1646 ndis_physaddr paddr; 1647{ 1648 ndis_miniport_block *block; 1649 struct ndis_softc *sc; 1650 struct ndis_shmem *sh = NULL; 1651 list_entry *l; 1652 1653 if (vaddr == NULL || adapter == NULL) 1654 return; 1655 1656 block = (ndis_miniport_block *)adapter; 1657 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1658 1659 /* Sanity check: is list empty? */ 1660 1661 if (IsListEmpty(&sc->ndis_shlist)) 1662 return; 1663 1664 NDIS_LOCK(sc); 1665 l = sc->ndis_shlist.nle_flink; 1666 while (l != &sc->ndis_shlist) { 1667 sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list); 1668 if (sh->ndis_saddr == vaddr) 1669 break; 1670 /* 1671 * Check the physaddr too, just in case the driver lied 1672 * about the virtual address. 1673 */ 1674 if (sh->ndis_paddr.np_quad == paddr.np_quad) 1675 break; 1676 l = l->nle_flink; 1677 } 1678 1679 if (sh == NULL) { 1680 NDIS_UNLOCK(sc); 1681 printf("NDIS: buggy driver tried to free " 1682 "invalid shared memory: vaddr: %p paddr: 0x%jx\n", 1683 vaddr, (uintmax_t)paddr.np_quad); 1684 return; 1685 } 1686 1687 RemoveEntryList(&sh->ndis_list); 1688 1689 NDIS_UNLOCK(sc); 1690 1691 bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap); 1692 bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap); 1693 bus_dma_tag_destroy(sh->ndis_stag); 1694 1695 free(sh, M_DEVBUF); 1696 1697 return; 1698} 1699 1700static ndis_status 1701NdisMMapIoSpace(vaddr, adapter, paddr, len) 1702 void **vaddr; 1703 ndis_handle adapter; 1704 ndis_physaddr paddr; 1705 uint32_t len; 1706{ 1707 if (adapter == NULL) 1708 return(NDIS_STATUS_FAILURE); 1709 1710 *vaddr = MmMapIoSpace(paddr.np_quad, len, 0); 1711 1712 if (*vaddr == NULL) 1713 return(NDIS_STATUS_FAILURE); 1714 1715 return(NDIS_STATUS_SUCCESS); 1716} 1717 1718static void 1719NdisMUnmapIoSpace(adapter, vaddr, len) 1720 ndis_handle adapter; 1721 void *vaddr; 1722 uint32_t len; 1723{ 1724 MmUnmapIoSpace(vaddr, len); 1725 return; 1726} 1727 1728static uint32_t 1729NdisGetCacheFillSize(void) 1730{ 1731 return(128); 1732} 1733 1734static uint32_t 1735NdisMGetDmaAlignment(handle) 1736 ndis_handle handle; 1737{ 1738 return(16); 1739} 1740 1741/* 1742 * NDIS has two methods for dealing with NICs that support DMA. 1743 * One is to just pass packets to the driver and let it call 1744 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet 1745 * all by itself, and the other is to let the NDIS library handle the 1746 * buffer mapping internally, and hand the driver an already populated 1747 * scatter/gather fragment list. If the driver calls 1748 * NdisMInitializeScatterGatherDma(), it wants to use the latter 1749 * method. 1750 */ 1751 1752static ndis_status 1753NdisMInitializeScatterGatherDma(adapter, is64, maxphysmap) 1754 ndis_handle adapter; 1755 uint8_t is64; 1756 uint32_t maxphysmap; 1757{ 1758 struct ndis_softc *sc; 1759 ndis_miniport_block *block; 1760 int error; 1761 1762 if (adapter == NULL) 1763 return(NDIS_STATUS_FAILURE); 1764 block = (ndis_miniport_block *)adapter; 1765 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1766 1767 /* Don't do this twice. */ 1768 if (sc->ndis_sc == 1) 1769 return(NDIS_STATUS_SUCCESS); 1770 1771 error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1772 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 1773 MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW, 1774 NULL, NULL, &sc->ndis_ttag); 1775 1776 sc->ndis_sc = 1; 1777 1778 return(NDIS_STATUS_SUCCESS); 1779} 1780 1781void 1782NdisAllocatePacketPool(status, pool, descnum, protrsvdlen) 1783 ndis_status *status; 1784 ndis_handle *pool; 1785 uint32_t descnum; 1786 uint32_t protrsvdlen; 1787{ 1788 ndis_packet_pool *p; 1789 ndis_packet *packets; 1790 int i; 1791 1792 p = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_packet_pool), 0); 1793 if (p == NULL) { 1794 *status = NDIS_STATUS_RESOURCES; 1795 return; 1796 } 1797 1798 p->np_cnt = descnum + NDIS_POOL_EXTRA; 1799 p->np_protrsvd = protrsvdlen; 1800 p->np_len = sizeof(ndis_packet) + protrsvdlen; 1801 1802 packets = ExAllocatePoolWithTag(NonPagedPool, p->np_cnt * 1803 p->np_len, 0); 1804 1805 1806 if (packets == NULL) { 1807 ExFreePool(p); 1808 *status = NDIS_STATUS_RESOURCES; 1809 return; 1810 } 1811 1812 p->np_pktmem = packets; 1813 1814 for (i = 0; i < p->np_cnt; i++) 1815 InterlockedPushEntrySList(&p->np_head, 1816 (struct slist_entry *)&packets[i]); 1817 1818#ifdef NDIS_DEBUG_PACKETS 1819 p->np_dead = 0; 1820 KeInitializeSpinLock(&p->np_lock); 1821 KeInitializeEvent(&p->np_event, EVENT_TYPE_NOTIFY, TRUE); 1822#endif 1823 1824 *pool = p; 1825 *status = NDIS_STATUS_SUCCESS; 1826 return; 1827} 1828 1829void 1830NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen) 1831 ndis_status *status; 1832 ndis_handle *pool; 1833 uint32_t descnum; 1834 uint32_t oflowdescnum; 1835 uint32_t protrsvdlen; 1836{ 1837 return(NdisAllocatePacketPool(status, pool, 1838 descnum + oflowdescnum, protrsvdlen)); 1839} 1840 1841uint32_t 1842NdisPacketPoolUsage(pool) 1843 ndis_handle pool; 1844{ 1845 ndis_packet_pool *p; 1846 1847 p = (ndis_packet_pool *)pool; 1848 return(p->np_cnt - ExQueryDepthSList(&p->np_head)); 1849} 1850 1851void 1852NdisFreePacketPool(pool) 1853 ndis_handle pool; 1854{ 1855 ndis_packet_pool *p; 1856 int usage; 1857#ifdef NDIS_DEBUG_PACKETS 1858 uint8_t irql; 1859#endif 1860 1861 p = (ndis_packet_pool *)pool; 1862 1863#ifdef NDIS_DEBUG_PACKETS 1864 KeAcquireSpinLock(&p->np_lock, &irql); 1865#endif 1866 1867 usage = NdisPacketPoolUsage(pool); 1868 1869#ifdef NDIS_DEBUG_PACKETS 1870 if (usage) { 1871 p->np_dead = 1; 1872 KeResetEvent(&p->np_event); 1873 KeReleaseSpinLock(&p->np_lock, irql); 1874 KeWaitForSingleObject(&p->np_event, 0, 0, FALSE, NULL); 1875 } else 1876 KeReleaseSpinLock(&p->np_lock, irql); 1877#endif 1878 1879 ExFreePool(p->np_pktmem); 1880 ExFreePool(p); 1881 1882 return; 1883} 1884 1885void 1886NdisAllocatePacket(status, packet, pool) 1887 ndis_status *status; 1888 ndis_packet **packet; 1889 ndis_handle pool; 1890{ 1891 ndis_packet_pool *p; 1892 ndis_packet *pkt; 1893#ifdef NDIS_DEBUG_PACKETS 1894 uint8_t irql; 1895#endif 1896 1897 p = (ndis_packet_pool *)pool; 1898 1899#ifdef NDIS_DEBUG_PACKETS 1900 KeAcquireSpinLock(&p->np_lock, &irql); 1901 if (p->np_dead) { 1902 KeReleaseSpinLock(&p->np_lock, irql); 1903 printf("NDIS: tried to allocate packet from dead pool %p\n", 1904 pool); 1905 *status = NDIS_STATUS_RESOURCES; 1906 return; 1907 } 1908#endif 1909 1910 pkt = (ndis_packet *)InterlockedPopEntrySList(&p->np_head); 1911 1912#ifdef NDIS_DEBUG_PACKETS 1913 KeReleaseSpinLock(&p->np_lock, irql); 1914#endif 1915 1916 if (pkt == NULL) { 1917 *status = NDIS_STATUS_RESOURCES; 1918 return; 1919 } 1920 1921 1922 bzero((char *)pkt, sizeof(ndis_packet)); 1923 1924 /* Save pointer to the pool. */ 1925 pkt->np_private.npp_pool = pool; 1926 1927 /* Set the oob offset pointer. Lots of things expect this. */ 1928 pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob); 1929 1930 /* 1931 * We must initialize the packet flags correctly in order 1932 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and 1933 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work 1934 * correctly. 1935 */ 1936 pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 1937 pkt->np_private.npp_validcounts = FALSE; 1938 1939 *packet = pkt; 1940 1941 *status = NDIS_STATUS_SUCCESS; 1942 1943 return; 1944} 1945 1946void 1947NdisFreePacket(packet) 1948 ndis_packet *packet; 1949{ 1950 ndis_packet_pool *p; 1951#ifdef NDIS_DEBUG_PACKETS 1952 uint8_t irql; 1953#endif 1954 1955 p = (ndis_packet_pool *)packet->np_private.npp_pool; 1956 1957#ifdef NDIS_DEBUG_PACKETS 1958 KeAcquireSpinLock(&p->np_lock, &irql); 1959#endif 1960 1961 InterlockedPushEntrySList(&p->np_head, (slist_entry *)packet); 1962 1963#ifdef NDIS_DEBUG_PACKETS 1964 if (p->np_dead) { 1965 if (ExQueryDepthSList(&p->np_head) == p->np_cnt) 1966 KeSetEvent(&p->np_event, IO_NO_INCREMENT, FALSE); 1967 } 1968 KeReleaseSpinLock(&p->np_lock, irql); 1969#endif 1970 1971 return; 1972} 1973 1974static void 1975NdisUnchainBufferAtFront(packet, buf) 1976 ndis_packet *packet; 1977 ndis_buffer **buf; 1978{ 1979 ndis_packet_private *priv; 1980 1981 if (packet == NULL || buf == NULL) 1982 return; 1983 1984 priv = &packet->np_private; 1985 1986 priv->npp_validcounts = FALSE; 1987 1988 if (priv->npp_head == priv->npp_tail) { 1989 *buf = priv->npp_head; 1990 priv->npp_head = priv->npp_tail = NULL; 1991 } else { 1992 *buf = priv->npp_head; 1993 priv->npp_head = (*buf)->mdl_next; 1994 } 1995 1996 return; 1997} 1998 1999static void 2000NdisUnchainBufferAtBack(packet, buf) 2001 ndis_packet *packet; 2002 ndis_buffer **buf; 2003{ 2004 ndis_packet_private *priv; 2005 ndis_buffer *tmp; 2006 2007 if (packet == NULL || buf == NULL) 2008 return; 2009 2010 priv = &packet->np_private; 2011 2012 priv->npp_validcounts = FALSE; 2013 2014 if (priv->npp_head == priv->npp_tail) { 2015 *buf = priv->npp_head; 2016 priv->npp_head = priv->npp_tail = NULL; 2017 } else { 2018 *buf = priv->npp_tail; 2019 tmp = priv->npp_head; 2020 while (tmp->mdl_next != priv->npp_tail) 2021 tmp = tmp->mdl_next; 2022 priv->npp_tail = tmp; 2023 tmp->mdl_next = NULL; 2024 } 2025 2026 return; 2027} 2028 2029/* 2030 * The NDIS "buffer" is really an MDL (memory descriptor list) 2031 * which is used to describe a buffer in a way that allows it 2032 * to mapped into different contexts. We have to be careful how 2033 * we handle them: in some versions of Windows, the NdisFreeBuffer() 2034 * routine is an actual function in the NDIS API, but in others 2035 * it's just a macro wrapper around IoFreeMdl(). There's really 2036 * no way to use the 'descnum' parameter to count how many 2037 * "buffers" are allocated since in order to use IoFreeMdl() to 2038 * dispose of a buffer, we have to use IoAllocateMdl() to allocate 2039 * them, and IoAllocateMdl() just grabs them out of the heap. 2040 */ 2041 2042static void 2043NdisAllocateBufferPool(status, pool, descnum) 2044 ndis_status *status; 2045 ndis_handle *pool; 2046 uint32_t descnum; 2047{ 2048 2049 /* 2050 * The only thing we can really do here is verify that descnum 2051 * is a reasonable value, but I really don't know what to check 2052 * it against. 2053 */ 2054 2055 *pool = NonPagedPool; 2056 *status = NDIS_STATUS_SUCCESS; 2057 return; 2058} 2059 2060static void 2061NdisFreeBufferPool(pool) 2062 ndis_handle pool; 2063{ 2064 return; 2065} 2066 2067static void 2068NdisAllocateBuffer(status, buffer, pool, vaddr, len) 2069 ndis_status *status; 2070 ndis_buffer **buffer; 2071 ndis_handle pool; 2072 void *vaddr; 2073 uint32_t len; 2074{ 2075 ndis_buffer *buf; 2076 2077 buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL); 2078 if (buf == NULL) { 2079 *status = NDIS_STATUS_RESOURCES; 2080 return; 2081 } 2082 2083 MmBuildMdlForNonPagedPool(buf); 2084 2085 *buffer = buf; 2086 *status = NDIS_STATUS_SUCCESS; 2087 2088 return; 2089} 2090 2091static void 2092NdisFreeBuffer(buf) 2093 ndis_buffer *buf; 2094{ 2095 IoFreeMdl(buf); 2096 return; 2097} 2098 2099/* Aw c'mon. */ 2100 2101static uint32_t 2102NdisBufferLength(buf) 2103 ndis_buffer *buf; 2104{ 2105 return(MmGetMdlByteCount(buf)); 2106} 2107 2108/* 2109 * Get the virtual address and length of a buffer. 2110 * Note: the vaddr argument is optional. 2111 */ 2112 2113static void 2114NdisQueryBuffer(buf, vaddr, len) 2115 ndis_buffer *buf; 2116 void **vaddr; 2117 uint32_t *len; 2118{ 2119 if (vaddr != NULL) 2120 *vaddr = MmGetMdlVirtualAddress(buf); 2121 *len = MmGetMdlByteCount(buf); 2122 2123 return; 2124} 2125 2126/* Same as above -- we don't care about the priority. */ 2127 2128static void 2129NdisQueryBufferSafe(buf, vaddr, len, prio) 2130 ndis_buffer *buf; 2131 void **vaddr; 2132 uint32_t *len; 2133 uint32_t prio; 2134{ 2135 if (vaddr != NULL) 2136 *vaddr = MmGetMdlVirtualAddress(buf); 2137 *len = MmGetMdlByteCount(buf); 2138 2139 return; 2140} 2141 2142/* Damnit Microsoft!! How many ways can you do the same thing?! */ 2143 2144static void * 2145NdisBufferVirtualAddress(buf) 2146 ndis_buffer *buf; 2147{ 2148 return(MmGetMdlVirtualAddress(buf)); 2149} 2150 2151static void * 2152NdisBufferVirtualAddressSafe(buf, prio) 2153 ndis_buffer *buf; 2154 uint32_t prio; 2155{ 2156 return(MmGetMdlVirtualAddress(buf)); 2157} 2158 2159static void 2160NdisAdjustBufferLength(buf, len) 2161 ndis_buffer *buf; 2162 int len; 2163{ 2164 MmGetMdlByteCount(buf) = len; 2165 2166 return; 2167} 2168 2169static uint32_t 2170NdisInterlockedIncrement(addend) 2171 uint32_t *addend; 2172{ 2173 atomic_add_long((u_long *)addend, 1); 2174 return(*addend); 2175} 2176 2177static uint32_t 2178NdisInterlockedDecrement(addend) 2179 uint32_t *addend; 2180{ 2181 atomic_subtract_long((u_long *)addend, 1); 2182 return(*addend); 2183} 2184 2185static void 2186NdisInitializeEvent(event) 2187 ndis_event *event; 2188{ 2189 /* 2190 * NDIS events are always notification 2191 * events, and should be initialized to the 2192 * not signaled state. 2193 */ 2194 KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE); 2195 return; 2196} 2197 2198static void 2199NdisSetEvent(event) 2200 ndis_event *event; 2201{ 2202 KeSetEvent(&event->ne_event, IO_NO_INCREMENT, FALSE); 2203 return; 2204} 2205 2206static void 2207NdisResetEvent(event) 2208 ndis_event *event; 2209{ 2210 KeResetEvent(&event->ne_event); 2211 return; 2212} 2213 2214static uint8_t 2215NdisWaitEvent(event, msecs) 2216 ndis_event *event; 2217 uint32_t msecs; 2218{ 2219 int64_t duetime; 2220 uint32_t rval; 2221 2222 duetime = ((int64_t)msecs * -10000); 2223 rval = KeWaitForSingleObject(event, 2224 0, 0, TRUE, msecs ? & duetime : NULL); 2225 2226 if (rval == STATUS_TIMEOUT) 2227 return(FALSE); 2228 2229 return(TRUE); 2230} 2231 2232static ndis_status 2233NdisUnicodeStringToAnsiString(dstr, sstr) 2234 ansi_string *dstr; 2235 unicode_string *sstr; 2236{ 2237 uint32_t rval; 2238 2239 rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE); 2240 2241 if (rval == STATUS_INSUFFICIENT_RESOURCES) 2242 return(NDIS_STATUS_RESOURCES); 2243 if (rval) 2244 return(NDIS_STATUS_FAILURE); 2245 2246 return (NDIS_STATUS_SUCCESS); 2247} 2248 2249static ndis_status 2250NdisAnsiStringToUnicodeString(dstr, sstr) 2251 unicode_string *dstr; 2252 ansi_string *sstr; 2253{ 2254 uint32_t rval; 2255 2256 rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE); 2257 2258 if (rval == STATUS_INSUFFICIENT_RESOURCES) 2259 return(NDIS_STATUS_RESOURCES); 2260 if (rval) 2261 return(NDIS_STATUS_FAILURE); 2262 2263 return (NDIS_STATUS_SUCCESS); 2264} 2265 2266static ndis_status 2267NdisMPciAssignResources(adapter, slot, list) 2268 ndis_handle adapter; 2269 uint32_t slot; 2270 ndis_resource_list **list; 2271{ 2272 ndis_miniport_block *block; 2273 2274 if (adapter == NULL || list == NULL) 2275 return (NDIS_STATUS_FAILURE); 2276 2277 block = (ndis_miniport_block *)adapter; 2278 *list = block->nmb_rlist; 2279 2280 return (NDIS_STATUS_SUCCESS); 2281} 2282 2283static uint8_t 2284ndis_intr(iobj, arg) 2285 kinterrupt *iobj; 2286 void *arg; 2287{ 2288 struct ndis_softc *sc; 2289 uint8_t is_our_intr = FALSE; 2290 int call_isr = 0; 2291 ndis_miniport_interrupt *intr; 2292 2293 sc = arg; 2294 intr = sc->ndis_block->nmb_interrupt; 2295 2296 if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL) 2297 return(FALSE); 2298 2299 if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE) 2300 MSCALL3(intr->ni_isrfunc, &is_our_intr, &call_isr, 2301 sc->ndis_block->nmb_miniportadapterctx); 2302 else { 2303 MSCALL1(sc->ndis_chars->nmc_disable_interrupts_func, 2304 sc->ndis_block->nmb_miniportadapterctx); 2305 call_isr = 1; 2306 } 2307 2308 if (call_isr) 2309 IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc); 2310 2311 return(is_our_intr); 2312} 2313 2314static void 2315ndis_intrhand(dpc, intr, sysarg1, sysarg2) 2316 kdpc *dpc; 2317 ndis_miniport_interrupt *intr; 2318 void *sysarg1; 2319 void *sysarg2; 2320{ 2321 struct ndis_softc *sc; 2322 ndis_miniport_block *block; 2323 ndis_handle adapter; 2324 2325 block = intr->ni_block; 2326 adapter = block->nmb_miniportadapterctx; 2327 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2328 2329 if (NDIS_SERIALIZED(sc->ndis_block)) 2330 KeAcquireSpinLockAtDpcLevel(&block->nmb_lock); 2331 2332 MSCALL1(intr->ni_dpcfunc, adapter); 2333 2334 /* If there's a MiniportEnableInterrupt() routine, call it. */ 2335 2336 if (sc->ndis_chars->nmc_enable_interrupts_func != NULL) 2337 MSCALL1(sc->ndis_chars->nmc_enable_interrupts_func, adapter); 2338 2339 if (NDIS_SERIALIZED(sc->ndis_block)) 2340 KeReleaseSpinLockFromDpcLevel(&block->nmb_lock); 2341 2342 /* 2343 * Set the completion event if we've drained all 2344 * pending interrupts. 2345 */ 2346 2347 KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock); 2348 intr->ni_dpccnt--; 2349 if (intr->ni_dpccnt == 0) 2350 KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE); 2351 KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock); 2352 2353 return; 2354} 2355 2356static ndis_status 2357NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode) 2358 ndis_miniport_interrupt *intr; 2359 ndis_handle adapter; 2360 uint32_t ivec; 2361 uint32_t ilevel; 2362 uint8_t reqisr; 2363 uint8_t shared; 2364 ndis_interrupt_mode imode; 2365{ 2366 ndis_miniport_block *block; 2367 ndis_miniport_characteristics *ch; 2368 struct ndis_softc *sc; 2369 int error; 2370 2371 block = adapter; 2372 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2373 ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj, 2374 (void *)1); 2375 2376 intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool, 2377 sizeof(struct mtx), 0); 2378 if (intr->ni_rsvd == NULL) 2379 return(NDIS_STATUS_RESOURCES); 2380 2381 intr->ni_block = adapter; 2382 intr->ni_isrreq = reqisr; 2383 intr->ni_shared = shared; 2384 intr->ni_dpccnt = 0; 2385 intr->ni_isrfunc = ch->nmc_isr_func; 2386 intr->ni_dpcfunc = ch->nmc_interrupt_func; 2387 2388 KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE); 2389 KeInitializeDpc(&intr->ni_dpc, 2390 ndis_findwrap((funcptr)ndis_intrhand), intr); 2391 KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW); 2392 2393 error = IoConnectInterrupt(&intr->ni_introbj, 2394 ndis_findwrap((funcptr)ndis_intr), sc, NULL, 2395 ivec, ilevel, 0, imode, shared, 0, FALSE); 2396 2397 if (error != STATUS_SUCCESS) 2398 return(NDIS_STATUS_FAILURE); 2399 2400 block->nmb_interrupt = intr; 2401 2402 return(NDIS_STATUS_SUCCESS); 2403} 2404 2405static void 2406NdisMDeregisterInterrupt(intr) 2407 ndis_miniport_interrupt *intr; 2408{ 2409 ndis_miniport_block *block; 2410 struct ndis_softc *sc; 2411 uint8_t irql; 2412 2413 block = intr->ni_block; 2414 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2415 2416 /* Should really be KeSynchronizeExecution() */ 2417 2418 KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql); 2419 block->nmb_interrupt = NULL; 2420 KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql); 2421/* 2422 KeFlushQueuedDpcs(); 2423*/ 2424 /* Disconnect our ISR */ 2425 2426 IoDisconnectInterrupt(intr->ni_introbj); 2427 2428 KeWaitForSingleObject(&intr->ni_dpcevt, 0, 0, FALSE, NULL); 2429 KeResetEvent(&intr->ni_dpcevt); 2430 2431 return; 2432} 2433 2434static void 2435NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc) 2436 ndis_handle adapter; 2437 void *shutdownctx; 2438 ndis_shutdown_handler shutdownfunc; 2439{ 2440 ndis_miniport_block *block; 2441 ndis_miniport_characteristics *chars; 2442 struct ndis_softc *sc; 2443 2444 if (adapter == NULL) 2445 return; 2446 2447 block = (ndis_miniport_block *)adapter; 2448 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2449 chars = sc->ndis_chars; 2450 2451 chars->nmc_shutdown_handler = shutdownfunc; 2452 chars->nmc_rsvd0 = shutdownctx; 2453 2454 return; 2455} 2456 2457static void 2458NdisMDeregisterAdapterShutdownHandler(adapter) 2459 ndis_handle adapter; 2460{ 2461 ndis_miniport_block *block; 2462 ndis_miniport_characteristics *chars; 2463 struct ndis_softc *sc; 2464 2465 if (adapter == NULL) 2466 return; 2467 2468 block = (ndis_miniport_block *)adapter; 2469 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2470 chars = sc->ndis_chars; 2471 2472 chars->nmc_shutdown_handler = NULL; 2473 chars->nmc_rsvd0 = NULL; 2474 2475 return; 2476} 2477 2478static uint32_t 2479NDIS_BUFFER_TO_SPAN_PAGES(buf) 2480 ndis_buffer *buf; 2481{ 2482 if (buf == NULL) 2483 return(0); 2484 if (MmGetMdlByteCount(buf) == 0) 2485 return(1); 2486 return(SPAN_PAGES(MmGetMdlVirtualAddress(buf), 2487 MmGetMdlByteCount(buf))); 2488} 2489 2490static void 2491NdisGetBufferPhysicalArraySize(buf, pages) 2492 ndis_buffer *buf; 2493 uint32_t *pages; 2494{ 2495 if (buf == NULL) 2496 return; 2497 2498 *pages = NDIS_BUFFER_TO_SPAN_PAGES(buf); 2499 return; 2500} 2501 2502static void 2503NdisQueryBufferOffset(buf, off, len) 2504 ndis_buffer *buf; 2505 uint32_t *off; 2506 uint32_t *len; 2507{ 2508 if (buf == NULL) 2509 return; 2510 2511 *off = MmGetMdlByteOffset(buf); 2512 *len = MmGetMdlByteCount(buf); 2513 2514 return; 2515} 2516 2517void 2518NdisMSleep(usecs) 2519 uint32_t usecs; 2520{ 2521 ktimer timer; 2522 2523 /* 2524 * During system bootstrap, (i.e. cold == 1), we aren't 2525 * allowed to sleep, so we have to do a hard DELAY() 2526 * instead. 2527 */ 2528 2529 if (cold) 2530 DELAY(usecs); 2531 else { 2532 KeInitializeTimer(&timer); 2533 KeSetTimer(&timer, ((int64_t)usecs * -10), NULL); 2534 KeWaitForSingleObject(&timer, 0, 0, FALSE, NULL); 2535 } 2536 2537 return; 2538} 2539 2540static uint32_t 2541NdisReadPcmciaAttributeMemory(handle, offset, buf, len) 2542 ndis_handle handle; 2543 uint32_t offset; 2544 void *buf; 2545 uint32_t len; 2546{ 2547 struct ndis_softc *sc; 2548 ndis_miniport_block *block; 2549 bus_space_handle_t bh; 2550 bus_space_tag_t bt; 2551 char *dest; 2552 int i; 2553 2554 if (handle == NULL) 2555 return(0); 2556 2557 block = (ndis_miniport_block *)handle; 2558 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2559 dest = buf; 2560 2561 bh = rman_get_bushandle(sc->ndis_res_am); 2562 bt = rman_get_bustag(sc->ndis_res_am); 2563 2564 for (i = 0; i < len; i++) 2565 dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2); 2566 2567 return(i); 2568} 2569 2570static uint32_t 2571NdisWritePcmciaAttributeMemory(handle, offset, buf, len) 2572 ndis_handle handle; 2573 uint32_t offset; 2574 void *buf; 2575 uint32_t len; 2576{ 2577 struct ndis_softc *sc; 2578 ndis_miniport_block *block; 2579 bus_space_handle_t bh; 2580 bus_space_tag_t bt; 2581 char *src; 2582 int i; 2583 2584 if (handle == NULL) 2585 return(0); 2586 2587 block = (ndis_miniport_block *)handle; 2588 sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2589 src = buf; 2590 2591 bh = rman_get_bushandle(sc->ndis_res_am); 2592 bt = rman_get_bustag(sc->ndis_res_am); 2593 2594 for (i = 0; i < len; i++) 2595 bus_space_write_1(bt, bh, (offset + i) * 2, src[i]); 2596 2597 return(i); 2598} 2599 2600static list_entry * 2601NdisInterlockedInsertHeadList(head, entry, lock) 2602 list_entry *head; 2603 list_entry *entry; 2604 ndis_spin_lock *lock; 2605{ 2606 list_entry *flink; 2607 2608 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2609 flink = head->nle_flink; 2610 entry->nle_flink = flink; 2611 entry->nle_blink = head; 2612 flink->nle_blink = entry; 2613 head->nle_flink = entry; 2614 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2615 2616 return(flink); 2617} 2618 2619static list_entry * 2620NdisInterlockedRemoveHeadList(head, lock) 2621 list_entry *head; 2622 ndis_spin_lock *lock; 2623{ 2624 list_entry *flink; 2625 list_entry *entry; 2626 2627 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2628 entry = head->nle_flink; 2629 flink = entry->nle_flink; 2630 head->nle_flink = flink; 2631 flink->nle_blink = head; 2632 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2633 2634 return(entry); 2635} 2636 2637static list_entry * 2638NdisInterlockedInsertTailList(head, entry, lock) 2639 list_entry *head; 2640 list_entry *entry; 2641 ndis_spin_lock *lock; 2642{ 2643 list_entry *blink; 2644 2645 KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2646 blink = head->nle_blink; 2647 entry->nle_flink = head; 2648 entry->nle_blink = blink; 2649 blink->nle_flink = entry; 2650 head->nle_blink = entry; 2651 KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2652 2653 return(blink); 2654} 2655 2656static uint8_t 2657NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx) 2658 ndis_miniport_interrupt *intr; 2659 void *syncfunc; 2660 void *syncctx; 2661{ 2662 return(KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx)); 2663} 2664 2665static void 2666NdisGetCurrentSystemTime(tval) 2667 uint64_t *tval; 2668{ 2669 ntoskrnl_time(tval); 2670 return; 2671} 2672 2673/* 2674 * Return the number of milliseconds since the system booted. 2675 */ 2676static void 2677NdisGetSystemUpTime(tval) 2678 uint32_t *tval; 2679{ 2680 struct timespec ts; 2681 2682 nanouptime(&ts); 2683 *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000; 2684 2685 return; 2686} 2687 2688static void 2689NdisInitializeString(dst, src) 2690 unicode_string *dst; 2691 char *src; 2692{ 2693 ansi_string as; 2694 RtlInitAnsiString(&as, src); 2695 RtlAnsiStringToUnicodeString(dst, &as, TRUE); 2696 return; 2697} 2698 2699static void 2700NdisFreeString(str) 2701 unicode_string *str; 2702{ 2703 RtlFreeUnicodeString(str); 2704 return; 2705} 2706 2707static ndis_status 2708NdisMRemoveMiniport(adapter) 2709 ndis_handle *adapter; 2710{ 2711 return(NDIS_STATUS_SUCCESS); 2712} 2713 2714static void 2715NdisInitAnsiString(dst, src) 2716 ansi_string *dst; 2717 char *src; 2718{ 2719 RtlInitAnsiString(dst, src); 2720 return; 2721} 2722 2723static void 2724NdisInitUnicodeString(dst, src) 2725 unicode_string *dst; 2726 uint16_t *src; 2727{ 2728 RtlInitUnicodeString(dst, src); 2729 return; 2730} 2731 2732static void NdisMGetDeviceProperty(adapter, phydevobj, 2733 funcdevobj, nextdevobj, resources, transresources) 2734 ndis_handle adapter; 2735 device_object **phydevobj; 2736 device_object **funcdevobj; 2737 device_object **nextdevobj; 2738 cm_resource_list *resources; 2739 cm_resource_list *transresources; 2740{ 2741 ndis_miniport_block *block; 2742 2743 block = (ndis_miniport_block *)adapter; 2744 2745 if (phydevobj != NULL) 2746 *phydevobj = block->nmb_physdeviceobj; 2747 if (funcdevobj != NULL) 2748 *funcdevobj = block->nmb_deviceobj; 2749 if (nextdevobj != NULL) 2750 *nextdevobj = block->nmb_nextdeviceobj; 2751 2752 return; 2753} 2754 2755static void 2756NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen) 2757 ndis_packet *packet; 2758 ndis_buffer **buf; 2759 void **firstva; 2760 uint32_t *firstlen; 2761 uint32_t *totlen; 2762{ 2763 ndis_buffer *tmp; 2764 2765 tmp = packet->np_private.npp_head; 2766 *buf = tmp; 2767 if (tmp == NULL) { 2768 *firstva = NULL; 2769 *firstlen = *totlen = 0; 2770 } else { 2771 *firstva = MmGetMdlVirtualAddress(tmp); 2772 *firstlen = *totlen = MmGetMdlByteCount(tmp); 2773 for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next) 2774 *totlen += MmGetMdlByteCount(tmp); 2775 } 2776 2777 return; 2778} 2779 2780static void 2781NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio) 2782 ndis_packet *packet; 2783 ndis_buffer **buf; 2784 void **firstva; 2785 uint32_t *firstlen; 2786 uint32_t *totlen; 2787 uint32_t prio; 2788{ 2789 NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen); 2790} 2791 2792static int 2793ndis_find_sym(lf, filename, suffix, sym) 2794 linker_file_t lf; 2795 char *filename; 2796 char *suffix; 2797 caddr_t *sym; 2798{ 2799 char *fullsym; 2800 char *suf; 2801 int i; 2802 2803 fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2804 if (fullsym == NULL) 2805 return(ENOMEM); 2806 2807 bzero(fullsym, MAXPATHLEN); 2808 strncpy(fullsym, filename, MAXPATHLEN); 2809 if (strlen(filename) < 4) { 2810 ExFreePool(fullsym); 2811 return(EINVAL); 2812 } 2813 2814 /* If the filename has a .ko suffix, strip if off. */ 2815 suf = fullsym + (strlen(filename) - 3); 2816 if (strcmp(suf, ".ko") == 0) 2817 *suf = '\0'; 2818 2819 for (i = 0; i < strlen(fullsym); i++) { 2820 if (fullsym[i] == '.') 2821 fullsym[i] = '_'; 2822 else 2823 fullsym[i] = tolower(fullsym[i]); 2824 } 2825 strcat(fullsym, suffix); 2826 *sym = linker_file_lookup_symbol(lf, fullsym, 0); 2827 ExFreePool(fullsym); 2828 if (*sym == 0) 2829 return(ENOENT); 2830 2831 return(0); 2832} 2833 2834struct ndis_checkmodule { 2835 char *afilename; 2836 ndis_fh *fh; 2837}; 2838 2839/* 2840 * See if a single module contains the symbols for a specified file. 2841 */ 2842static int 2843NdisCheckModule(linker_file_t lf, void *context) 2844{ 2845 struct ndis_checkmodule *nc; 2846 caddr_t kldstart, kldend; 2847 2848 nc = (struct ndis_checkmodule *)context; 2849 if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart)) 2850 return (0); 2851 if (ndis_find_sym(lf, nc->afilename, "_end", &kldend)) 2852 return (0); 2853 nc->fh->nf_vp = lf; 2854 nc->fh->nf_map = NULL; 2855 nc->fh->nf_type = NDIS_FH_TYPE_MODULE; 2856 nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; 2857 return (1); 2858} 2859 2860/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ 2861static void 2862NdisOpenFile(status, filehandle, filelength, filename, highestaddr) 2863 ndis_status *status; 2864 ndis_handle *filehandle; 2865 uint32_t *filelength; 2866 unicode_string *filename; 2867 ndis_physaddr highestaddr; 2868{ 2869 ansi_string as; 2870 char *afilename = NULL; 2871 struct thread *td = curthread; 2872 struct nameidata nd; 2873 int flags, error, vfslocked; 2874 struct vattr vat; 2875 struct vattr *vap = &vat; 2876 ndis_fh *fh; 2877 char *path; 2878 struct ndis_checkmodule nc; 2879 2880 if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) { 2881 *status = NDIS_STATUS_RESOURCES; 2882 return; 2883 } 2884 2885 afilename = strdup(as.as_buf, M_DEVBUF); 2886 RtlFreeAnsiString(&as); 2887 2888 fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0); 2889 if (fh == NULL) { 2890 free(afilename, M_DEVBUF); 2891 *status = NDIS_STATUS_RESOURCES; 2892 return; 2893 } 2894 2895 fh->nf_name = afilename; 2896 2897 /* 2898 * During system bootstrap, it's impossible to load files 2899 * from the rootfs since it's not mounted yet. We therefore 2900 * offer the possibility of opening files that have been 2901 * preloaded as modules instead. Both choices will work 2902 * when kldloading a module from multiuser, but only the 2903 * module option will work during bootstrap. The module 2904 * loading option works by using the ndiscvt(8) utility 2905 * to convert the arbitrary file into a .ko using objcopy(1). 2906 * This file will contain two special symbols: filename_start 2907 * and filename_end. All we have to do is traverse the KLD 2908 * list in search of those symbols and we've found the file 2909 * data. As an added bonus, ndiscvt(8) will also generate 2910 * a normal .o file which can be linked statically with 2911 * the kernel. This means that the symbols will actual reside 2912 * in the kernel's symbol table, but that doesn't matter to 2913 * us since the kernel appears to us as just another module. 2914 */ 2915 2916 nc.afilename = afilename; 2917 nc.fh = fh; 2918 if (linker_file_foreach(NdisCheckModule, &nc)) { 2919 *filelength = fh->nf_maplen; 2920 *filehandle = fh; 2921 *status = NDIS_STATUS_SUCCESS; 2922 return; 2923 } 2924 2925 if (TAILQ_EMPTY(&mountlist)) { 2926 ExFreePool(fh); 2927 *status = NDIS_STATUS_FILE_NOT_FOUND; 2928 printf("NDIS: could not find file %s in linker list\n", 2929 afilename); 2930 printf("NDIS: and no filesystems mounted yet, " 2931 "aborting NdisOpenFile()\n"); 2932 free(afilename, M_DEVBUF); 2933 return; 2934 } 2935 2936 path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2937 if (path == NULL) { 2938 ExFreePool(fh); 2939 free(afilename, M_DEVBUF); 2940 *status = NDIS_STATUS_RESOURCES; 2941 return; 2942 } 2943 2944 snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); 2945 2946 /* Some threads don't have a current working directory. */ 2947 2948 if (td->td_proc->p_fd->fd_rdir == NULL) 2949 td->td_proc->p_fd->fd_rdir = rootvnode; 2950 if (td->td_proc->p_fd->fd_cdir == NULL) 2951 td->td_proc->p_fd->fd_cdir = rootvnode; 2952 2953 NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, path, td); 2954 2955 flags = FREAD; 2956 error = vn_open(&nd, &flags, 0, NULL); 2957 if (error) { 2958 *status = NDIS_STATUS_FILE_NOT_FOUND; 2959 ExFreePool(fh); 2960 printf("NDIS: open file %s failed: %d\n", path, error); 2961 ExFreePool(path); 2962 free(afilename, M_DEVBUF); 2963 return; 2964 } 2965 vfslocked = NDHASGIANT(&nd); 2966 2967 ExFreePool(path); 2968 2969 NDFREE(&nd, NDF_ONLY_PNBUF); 2970 2971 /* Get the file size. */ 2972 VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 2973 VOP_UNLOCK(nd.ni_vp, 0); 2974 VFS_UNLOCK_GIANT(vfslocked); 2975 2976 fh->nf_vp = nd.ni_vp; 2977 fh->nf_map = NULL; 2978 fh->nf_type = NDIS_FH_TYPE_VFS; 2979 *filehandle = fh; 2980 *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; 2981 *status = NDIS_STATUS_SUCCESS; 2982 2983 return; 2984} 2985 2986static void 2987NdisMapFile(status, mappedbuffer, filehandle) 2988 ndis_status *status; 2989 void **mappedbuffer; 2990 ndis_handle filehandle; 2991{ 2992 ndis_fh *fh; 2993 struct thread *td = curthread; 2994 linker_file_t lf; 2995 caddr_t kldstart; 2996 int error, resid, vfslocked; 2997 struct vnode *vp; 2998 2999 if (filehandle == NULL) { 3000 *status = NDIS_STATUS_FAILURE; 3001 return; 3002 } 3003 3004 fh = (ndis_fh *)filehandle; 3005 3006 if (fh->nf_vp == NULL) { 3007 *status = NDIS_STATUS_FAILURE; 3008 return; 3009 } 3010 3011 if (fh->nf_map != NULL) { 3012 *status = NDIS_STATUS_ALREADY_MAPPED; 3013 return; 3014 } 3015 3016 if (fh->nf_type == NDIS_FH_TYPE_MODULE) { 3017 lf = fh->nf_vp; 3018 if (ndis_find_sym(lf, fh->nf_name, "_start", &kldstart)) { 3019 *status = NDIS_STATUS_FAILURE; 3020 return; 3021 } 3022 fh->nf_map = kldstart; 3023 *status = NDIS_STATUS_SUCCESS; 3024 *mappedbuffer = fh->nf_map; 3025 return; 3026 } 3027 3028 fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0); 3029 3030 if (fh->nf_map == NULL) { 3031 *status = NDIS_STATUS_RESOURCES; 3032 return; 3033 } 3034 3035 vp = fh->nf_vp; 3036 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 3037 error = vn_rdwr(UIO_READ, vp, fh->nf_map, fh->nf_maplen, 0, 3038 UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); 3039 VFS_UNLOCK_GIANT(vfslocked); 3040 3041 if (error) 3042 *status = NDIS_STATUS_FAILURE; 3043 else { 3044 *status = NDIS_STATUS_SUCCESS; 3045 *mappedbuffer = fh->nf_map; 3046 } 3047 3048 return; 3049} 3050 3051static void 3052NdisUnmapFile(filehandle) 3053 ndis_handle filehandle; 3054{ 3055 ndis_fh *fh; 3056 fh = (ndis_fh *)filehandle; 3057 3058 if (fh->nf_map == NULL) 3059 return; 3060 3061 if (fh->nf_type == NDIS_FH_TYPE_VFS) 3062 ExFreePool(fh->nf_map); 3063 fh->nf_map = NULL; 3064 3065 return; 3066} 3067 3068static void 3069NdisCloseFile(filehandle) 3070 ndis_handle filehandle; 3071{ 3072 struct thread *td = curthread; 3073 ndis_fh *fh; 3074 int vfslocked; 3075 struct vnode *vp; 3076 3077 if (filehandle == NULL) 3078 return; 3079 3080 fh = (ndis_fh *)filehandle; 3081 if (fh->nf_map != NULL) { 3082 if (fh->nf_type == NDIS_FH_TYPE_VFS) 3083 ExFreePool(fh->nf_map); 3084 fh->nf_map = NULL; 3085 } 3086 3087 if (fh->nf_vp == NULL) 3088 return; 3089 3090 if (fh->nf_type == NDIS_FH_TYPE_VFS) { 3091 vp = fh->nf_vp; 3092 vfslocked = VFS_LOCK_GIANT(vp->v_mount); 3093 vn_close(vp, FREAD, td->td_ucred, td); 3094 VFS_UNLOCK_GIANT(vfslocked); 3095 } 3096 3097 fh->nf_vp = NULL; 3098 free(fh->nf_name, M_DEVBUF); 3099 ExFreePool(fh); 3100 3101 return; 3102} 3103 3104static uint8_t 3105NdisSystemProcessorCount() 3106{ 3107 return(mp_ncpus); 3108} 3109 3110typedef void (*ndis_statusdone_handler)(ndis_handle); 3111typedef void (*ndis_status_handler)(ndis_handle, ndis_status, 3112 void *, uint32_t); 3113 3114static void 3115NdisMIndicateStatusComplete(adapter) 3116 ndis_handle adapter; 3117{ 3118 ndis_miniport_block *block; 3119 ndis_statusdone_handler statusdonefunc; 3120 3121 block = (ndis_miniport_block *)adapter; 3122 statusdonefunc = block->nmb_statusdone_func; 3123 3124 MSCALL1(statusdonefunc, adapter); 3125 return; 3126} 3127 3128static void 3129NdisMIndicateStatus(adapter, status, sbuf, slen) 3130 ndis_handle adapter; 3131 ndis_status status; 3132 void *sbuf; 3133 uint32_t slen; 3134{ 3135 ndis_miniport_block *block; 3136 ndis_status_handler statusfunc; 3137 3138 block = (ndis_miniport_block *)adapter; 3139 statusfunc = block->nmb_status_func; 3140 3141 MSCALL4(statusfunc, adapter, status, sbuf, slen); 3142 return; 3143} 3144 3145/* 3146 * The DDK documentation says that you should use IoQueueWorkItem() 3147 * instead of ExQueueWorkItem(). The problem is, IoQueueWorkItem() 3148 * is fundamentally incompatible with NdisScheduleWorkItem(), which 3149 * depends on the API semantics of ExQueueWorkItem(). In our world, 3150 * ExQueueWorkItem() is implemented on top of IoAllocateQueueItem() 3151 * anyway. 3152 * 3153 * There are actually three distinct APIs here. NdisScheduleWorkItem() 3154 * takes a pointer to an NDIS_WORK_ITEM. ExQueueWorkItem() takes a pointer 3155 * to a WORK_QUEUE_ITEM. And finally, IoQueueWorkItem() takes a pointer 3156 * to an opaque work item thingie which you get from IoAllocateWorkItem(). 3157 * An NDIS_WORK_ITEM is not the same as a WORK_QUEUE_ITEM. However, 3158 * the NDIS_WORK_ITEM has some opaque storage at the end of it, and we 3159 * (ab)use this storage as a WORK_QUEUE_ITEM, which is what we submit 3160 * to ExQueueWorkItem(). 3161 * 3162 * Got all that? (Sheesh.) 3163 */ 3164 3165ndis_status 3166NdisScheduleWorkItem(work) 3167 ndis_work_item *work; 3168{ 3169 work_queue_item *wqi; 3170 3171 wqi = (work_queue_item *)work->nwi_wraprsvd; 3172 ExInitializeWorkItem(wqi, 3173 (work_item_func)work->nwi_func, work->nwi_ctx); 3174 ExQueueWorkItem(wqi, WORKQUEUE_DELAYED); 3175 3176 return(NDIS_STATUS_SUCCESS); 3177} 3178 3179static void 3180NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen) 3181 ndis_packet *dpkt; 3182 uint32_t doff; 3183 uint32_t reqlen; 3184 ndis_packet *spkt; 3185 uint32_t soff; 3186 uint32_t *cpylen; 3187{ 3188 ndis_buffer *src, *dst; 3189 char *sptr, *dptr; 3190 int resid, copied, len, scnt, dcnt; 3191 3192 *cpylen = 0; 3193 3194 src = spkt->np_private.npp_head; 3195 dst = dpkt->np_private.npp_head; 3196 3197 sptr = MmGetMdlVirtualAddress(src); 3198 dptr = MmGetMdlVirtualAddress(dst); 3199 scnt = MmGetMdlByteCount(src); 3200 dcnt = MmGetMdlByteCount(dst); 3201 3202 while (soff) { 3203 if (MmGetMdlByteCount(src) > soff) { 3204 sptr += soff; 3205 scnt = MmGetMdlByteCount(src)- soff; 3206 break; 3207 } 3208 soff -= MmGetMdlByteCount(src); 3209 src = src->mdl_next; 3210 if (src == NULL) 3211 return; 3212 sptr = MmGetMdlVirtualAddress(src); 3213 } 3214 3215 while (doff) { 3216 if (MmGetMdlByteCount(dst) > doff) { 3217 dptr += doff; 3218 dcnt = MmGetMdlByteCount(dst) - doff; 3219 break; 3220 } 3221 doff -= MmGetMdlByteCount(dst); 3222 dst = dst->mdl_next; 3223 if (dst == NULL) 3224 return; 3225 dptr = MmGetMdlVirtualAddress(dst); 3226 } 3227 3228 resid = reqlen; 3229 copied = 0; 3230 3231 while(1) { 3232 if (resid < scnt) 3233 len = resid; 3234 else 3235 len = scnt; 3236 if (dcnt < len) 3237 len = dcnt; 3238 3239 bcopy(sptr, dptr, len); 3240 3241 copied += len; 3242 resid -= len; 3243 if (resid == 0) 3244 break; 3245 3246 dcnt -= len; 3247 if (dcnt == 0) { 3248 dst = dst->mdl_next; 3249 if (dst == NULL) 3250 break; 3251 dptr = MmGetMdlVirtualAddress(dst); 3252 dcnt = MmGetMdlByteCount(dst); 3253 } 3254 3255 scnt -= len; 3256 if (scnt == 0) { 3257 src = src->mdl_next; 3258 if (src == NULL) 3259 break; 3260 sptr = MmGetMdlVirtualAddress(src); 3261 scnt = MmGetMdlByteCount(src); 3262 } 3263 } 3264 3265 *cpylen = copied; 3266 return; 3267} 3268 3269static void 3270NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio) 3271 ndis_packet *dpkt; 3272 uint32_t doff; 3273 uint32_t reqlen; 3274 ndis_packet *spkt; 3275 uint32_t soff; 3276 uint32_t *cpylen; 3277 uint32_t prio; 3278{ 3279 NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen); 3280 return; 3281} 3282 3283static void 3284NdisIMCopySendPerPacketInfo(dpkt, spkt) 3285 ndis_packet *dpkt; 3286 ndis_packet *spkt; 3287{ 3288 memcpy(&dpkt->np_ext, &spkt->np_ext, sizeof(ndis_packet_extension)); 3289} 3290 3291static ndis_status 3292NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle) 3293 ndis_handle handle; 3294 unicode_string *devname; 3295 unicode_string *symname; 3296 driver_dispatch *majorfuncs[]; 3297 void **devobj; 3298 ndis_handle *devhandle; 3299{ 3300 uint32_t status; 3301 device_object *dobj; 3302 3303 status = IoCreateDevice(handle, 0, devname, 3304 FILE_DEVICE_UNKNOWN, 0, FALSE, &dobj); 3305 3306 if (status == STATUS_SUCCESS) { 3307 *devobj = dobj; 3308 *devhandle = dobj; 3309 } 3310 3311 return(status); 3312} 3313 3314static ndis_status 3315NdisMDeregisterDevice(handle) 3316 ndis_handle handle; 3317{ 3318 IoDeleteDevice(handle); 3319 return(NDIS_STATUS_SUCCESS); 3320} 3321 3322static ndis_status 3323NdisMQueryAdapterInstanceName(name, handle) 3324 unicode_string *name; 3325 ndis_handle handle; 3326{ 3327 ndis_miniport_block *block; 3328 device_t dev; 3329 ansi_string as; 3330 3331 block = (ndis_miniport_block *)handle; 3332 dev = block->nmb_physdeviceobj->do_devext; 3333 3334 RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev))); 3335 if (RtlAnsiStringToUnicodeString(name, &as, TRUE)) 3336 return(NDIS_STATUS_RESOURCES); 3337 3338 return(NDIS_STATUS_SUCCESS); 3339} 3340 3341static void 3342NdisMRegisterUnloadHandler(handle, func) 3343 ndis_handle handle; 3344 void *func; 3345{ 3346 return; 3347} 3348 3349static void 3350dummy() 3351{ 3352 printf ("NDIS dummy called...\n"); 3353 return; 3354} 3355 3356/* 3357 * Note: a couple of entries in this table specify the 3358 * number of arguments as "foo + 1". These are routines 3359 * that accept a 64-bit argument, passed by value. On 3360 * x86, these arguments consume two longwords on the stack, 3361 * so we lie and say there's one additional argument so 3362 * that the wrapping routines will do the right thing. 3363 */ 3364 3365image_patch_table ndis_functbl[] = { 3366 IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6), 3367 IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7), 3368 IMPORT_SFUNC(NdisIMCopySendPerPacketInfo, 2), 3369 IMPORT_SFUNC(NdisScheduleWorkItem, 1), 3370 IMPORT_SFUNC(NdisMIndicateStatusComplete, 1), 3371 IMPORT_SFUNC(NdisMIndicateStatus, 4), 3372 IMPORT_SFUNC(NdisSystemProcessorCount, 0), 3373 IMPORT_SFUNC(NdisUnchainBufferAtBack, 2), 3374 IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5), 3375 IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6), 3376 IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2), 3377 IMPORT_SFUNC(NdisMGetDeviceProperty, 6), 3378 IMPORT_SFUNC(NdisInitAnsiString, 2), 3379 IMPORT_SFUNC(NdisInitUnicodeString, 2), 3380 IMPORT_SFUNC(NdisWriteConfiguration, 4), 3381 IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2), 3382 IMPORT_SFUNC(NdisTerminateWrapper, 2), 3383 IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4), 3384 IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5), 3385 IMPORT_SFUNC(NdisMRemoveMiniport, 1), 3386 IMPORT_SFUNC(NdisInitializeString, 2), 3387 IMPORT_SFUNC(NdisFreeString, 1), 3388 IMPORT_SFUNC(NdisGetCurrentSystemTime, 1), 3389 IMPORT_SFUNC(NdisGetSystemUpTime, 1), 3390 IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3), 3391 IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4), 3392 IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3), 3393 IMPORT_SFUNC(NdisInterlockedInsertTailList, 3), 3394 IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2), 3395 IMPORT_SFUNC(NdisInitializeWrapper, 4), 3396 IMPORT_SFUNC(NdisMRegisterMiniport, 3), 3397 IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3), 3398 IMPORT_SFUNC(NdisAllocateMemory, 4 + 1), 3399 IMPORT_SFUNC(NdisMSetAttributesEx, 5), 3400 IMPORT_SFUNC(NdisCloseConfiguration, 1), 3401 IMPORT_SFUNC(NdisReadConfiguration, 5), 3402 IMPORT_SFUNC(NdisOpenConfiguration, 3), 3403 IMPORT_SFUNC(NdisAcquireSpinLock, 1), 3404 IMPORT_SFUNC(NdisReleaseSpinLock, 1), 3405 IMPORT_SFUNC(NdisDprAcquireSpinLock, 1), 3406 IMPORT_SFUNC(NdisDprReleaseSpinLock, 1), 3407 IMPORT_SFUNC(NdisAllocateSpinLock, 1), 3408 IMPORT_SFUNC(NdisInitializeReadWriteLock, 1), 3409 IMPORT_SFUNC(NdisAcquireReadWriteLock, 3), 3410 IMPORT_SFUNC(NdisReleaseReadWriteLock, 2), 3411 IMPORT_SFUNC(NdisFreeSpinLock, 1), 3412 IMPORT_SFUNC(NdisFreeMemory, 3), 3413 IMPORT_SFUNC(NdisReadPciSlotInformation, 5), 3414 IMPORT_SFUNC(NdisWritePciSlotInformation, 5), 3415 IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation, 3416 NdisReadPciSlotInformation, 5), 3417 IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation, 3418 NdisWritePciSlotInformation, 5), 3419 IMPORT_CFUNC(NdisWriteErrorLogEntry, 0), 3420 IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6), 3421 IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3), 3422 IMPORT_SFUNC(NdisMInitializeTimer, 4), 3423 IMPORT_SFUNC(NdisInitializeTimer, 3), 3424 IMPORT_SFUNC(NdisSetTimer, 2), 3425 IMPORT_SFUNC(NdisMCancelTimer, 2), 3426 IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2), 3427 IMPORT_SFUNC(NdisMSetPeriodicTimer, 2), 3428 IMPORT_SFUNC(NdisMQueryAdapterResources, 4), 3429 IMPORT_SFUNC(NdisMRegisterIoPortRange, 4), 3430 IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4), 3431 IMPORT_SFUNC(NdisReadNetworkAddress, 4), 3432 IMPORT_SFUNC(NdisQueryMapRegisterCount, 2), 3433 IMPORT_SFUNC(NdisMAllocateMapRegisters, 5), 3434 IMPORT_SFUNC(NdisMFreeMapRegisters, 1), 3435 IMPORT_SFUNC(NdisMAllocateSharedMemory, 5), 3436 IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1), 3437 IMPORT_SFUNC(NdisMUnmapIoSpace, 3), 3438 IMPORT_SFUNC(NdisGetCacheFillSize, 0), 3439 IMPORT_SFUNC(NdisMGetDmaAlignment, 1), 3440 IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3), 3441 IMPORT_SFUNC(NdisAllocatePacketPool, 4), 3442 IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5), 3443 IMPORT_SFUNC(NdisAllocatePacket, 3), 3444 IMPORT_SFUNC(NdisFreePacket, 1), 3445 IMPORT_SFUNC(NdisFreePacketPool, 1), 3446 IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3), 3447 IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1), 3448 IMPORT_SFUNC(NdisAllocateBufferPool, 3), 3449 IMPORT_SFUNC(NdisAllocateBuffer, 5), 3450 IMPORT_SFUNC(NdisQueryBuffer, 3), 3451 IMPORT_SFUNC(NdisQueryBufferSafe, 4), 3452 IMPORT_SFUNC(NdisBufferVirtualAddress, 1), 3453 IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2), 3454 IMPORT_SFUNC(NdisBufferLength, 1), 3455 IMPORT_SFUNC(NdisFreeBuffer, 1), 3456 IMPORT_SFUNC(NdisFreeBufferPool, 1), 3457 IMPORT_SFUNC(NdisInterlockedIncrement, 1), 3458 IMPORT_SFUNC(NdisInterlockedDecrement, 1), 3459 IMPORT_SFUNC(NdisInitializeEvent, 1), 3460 IMPORT_SFUNC(NdisSetEvent, 1), 3461 IMPORT_SFUNC(NdisResetEvent, 1), 3462 IMPORT_SFUNC(NdisWaitEvent, 2), 3463 IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2), 3464 IMPORT_SFUNC(NdisMPciAssignResources, 3), 3465 IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1), 3466 IMPORT_SFUNC(NdisMRegisterInterrupt, 7), 3467 IMPORT_SFUNC(NdisMDeregisterInterrupt, 1), 3468 IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3), 3469 IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1), 3470 IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1), 3471 IMPORT_SFUNC(NdisQueryBufferOffset, 3), 3472 IMPORT_SFUNC(NdisAdjustBufferLength, 2), 3473 IMPORT_SFUNC(NdisPacketPoolUsage, 1), 3474 IMPORT_SFUNC(NdisMSleep, 1), 3475 IMPORT_SFUNC(NdisUnchainBufferAtFront, 2), 3476 IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4), 3477 IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4), 3478 IMPORT_SFUNC(NdisOpenFile, 5 + 1), 3479 IMPORT_SFUNC(NdisMapFile, 3), 3480 IMPORT_SFUNC(NdisUnmapFile, 1), 3481 IMPORT_SFUNC(NdisCloseFile, 1), 3482 IMPORT_SFUNC(NdisMRegisterDevice, 6), 3483 IMPORT_SFUNC(NdisMDeregisterDevice, 1), 3484 IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2), 3485 IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2), 3486 IMPORT_SFUNC(ndis_timercall, 4), 3487 IMPORT_SFUNC(ndis_asyncmem_complete, 2), 3488 IMPORT_SFUNC(ndis_intr, 2), 3489 IMPORT_SFUNC(ndis_intrhand, 4), 3490 3491 /* 3492 * This last entry is a catch-all for any function we haven't 3493 * implemented yet. The PE import list patching routine will 3494 * use it for any function that doesn't have an explicit match 3495 * in this table. 3496 */ 3497 3498 { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL }, 3499 3500 /* End of list. */ 3501 3502 { NULL, NULL, NULL } 3503}; 3504