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