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