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