subr_ndis.c revision 144888
1139743Simp/*- 2123474Swpaul * Copyright (c) 2003 3123474Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4123474Swpaul * 5123474Swpaul * Redistribution and use in source and binary forms, with or without 6123474Swpaul * modification, are permitted provided that the following conditions 7123474Swpaul * are met: 8123474Swpaul * 1. Redistributions of source code must retain the above copyright 9123474Swpaul * notice, this list of conditions and the following disclaimer. 10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11123474Swpaul * notice, this list of conditions and the following disclaimer in the 12123474Swpaul * documentation and/or other materials provided with the distribution. 13123474Swpaul * 3. All advertising materials mentioning features or use of this software 14123474Swpaul * must display the following acknowledgement: 15123474Swpaul * This product includes software developed by Bill Paul. 16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17123474Swpaul * may be used to endorse or promote products derived from this software 18123474Swpaul * without specific prior written permission. 19123474Swpaul * 20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23123474Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31123474Swpaul */ 32123474Swpaul 33123474Swpaul#include <sys/cdefs.h> 34123474Swpaul__FBSDID("$FreeBSD: head/sys/compat/ndis/subr_ndis.c 144888 2005-04-11 02:02:35Z wpaul $"); 35123474Swpaul 36123474Swpaul/* 37123474Swpaul * This file implements a translation layer between the BSD networking 38123474Swpaul * infrasturcture and Windows(R) NDIS network driver modules. A Windows 39123474Swpaul * NDIS driver calls into several functions in the NDIS.SYS Windows 40123474Swpaul * kernel module and exports a table of functions designed to be called 41123474Swpaul * by the NDIS subsystem. Using the PE loader, we can patch our own 42123474Swpaul * versions of the NDIS routines into a given Windows driver module and 43123474Swpaul * convince the driver that it is in fact running on Windows. 44123474Swpaul * 45123474Swpaul * We provide a table of all our implemented NDIS routines which is patched 46123474Swpaul * into the driver object code. All our exported routines must use the 47123474Swpaul * _stdcall calling convention, since that's what the Windows object code 48123474Swpaul * expects. 49123474Swpaul */ 50123474Swpaul 51123474Swpaul 52129834Swpaul#include <sys/ctype.h> 53123474Swpaul#include <sys/param.h> 54123474Swpaul#include <sys/types.h> 55123474Swpaul#include <sys/errno.h> 56123474Swpaul 57123474Swpaul#include <sys/callout.h> 58123474Swpaul#include <sys/kernel.h> 59123474Swpaul#include <sys/systm.h> 60123474Swpaul#include <sys/malloc.h> 61123474Swpaul#include <sys/lock.h> 62123474Swpaul#include <sys/mutex.h> 63123474Swpaul#include <sys/socket.h> 64123474Swpaul#include <sys/sysctl.h> 65123504Swpaul#include <sys/timespec.h> 66123848Swpaul#include <sys/smp.h> 67124122Swpaul#include <sys/queue.h> 68124272Swpaul#include <sys/proc.h> 69125377Swpaul#include <sys/filedesc.h> 70124272Swpaul#include <sys/namei.h> 71124272Swpaul#include <sys/fcntl.h> 72124272Swpaul#include <sys/vnode.h> 73125551Swpaul#include <sys/kthread.h> 74132973Swpaul#include <sys/linker.h> 75132973Swpaul#include <sys/mount.h> 76132973Swpaul#include <sys/sysproto.h> 77123474Swpaul 78123474Swpaul#include <net/if.h> 79123474Swpaul#include <net/if_arp.h> 80123474Swpaul#include <net/ethernet.h> 81123474Swpaul#include <net/if_dl.h> 82123474Swpaul#include <net/if_media.h> 83123474Swpaul 84124203Swpaul#include <machine/atomic.h> 85123474Swpaul#include <machine/bus_memio.h> 86123474Swpaul#include <machine/bus_pio.h> 87123474Swpaul#include <machine/bus.h> 88123474Swpaul#include <machine/resource.h> 89123474Swpaul 90123474Swpaul#include <sys/bus.h> 91123474Swpaul#include <sys/rman.h> 92123474Swpaul 93123474Swpaul#include <machine/stdarg.h> 94123474Swpaul 95123695Swpaul#include <net80211/ieee80211_var.h> 96123695Swpaul#include <net80211/ieee80211_ioctl.h> 97123695Swpaul 98123474Swpaul#include <dev/pci/pcireg.h> 99123474Swpaul#include <dev/pci/pcivar.h> 100123474Swpaul 101123474Swpaul#include <compat/ndis/pe_var.h> 102123474Swpaul#include <compat/ndis/resource_var.h> 103123512Swpaul#include <compat/ndis/ntoskrnl_var.h> 104128229Swpaul#include <compat/ndis/hal_var.h> 105123474Swpaul#include <compat/ndis/ndis_var.h> 106123474Swpaul#include <compat/ndis/cfg_var.h> 107123474Swpaul#include <dev/if_ndis/if_ndisvar.h> 108123474Swpaul 109124272Swpaulstatic char ndis_filepath[MAXPATHLEN]; 110125057Swpaulextern struct nd_head ndis_devhead; 111123474Swpaul 112124272SwpaulSYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath, 113124272Swpaul MAXPATHLEN, "Path used by NdisOpenFile() to search for files"); 114124272Swpaul 115144888Swpaulstatic void NdisInitializeWrapper(ndis_handle *, 116141524Swpaul driver_object *, void *, void *); 117144888Swpaulstatic ndis_status NdisMRegisterMiniport(ndis_handle, 118123474Swpaul ndis_miniport_characteristics *, int); 119144888Swpaulstatic ndis_status NdisAllocateMemoryWithTag(void **, 120140751Swpaul uint32_t, uint32_t); 121144888Swpaulstatic ndis_status NdisAllocateMemory(void **, 122123474Swpaul uint32_t, uint32_t, ndis_physaddr); 123144888Swpaulstatic void NdisFreeMemory(void *, uint32_t, uint32_t); 124144888Swpaulstatic ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle, 125123474Swpaul uint32_t, uint32_t, ndis_interface_type); 126144888Swpaulstatic void NdisOpenConfiguration(ndis_status *, 127140751Swpaul ndis_handle *, ndis_handle); 128144888Swpaulstatic void NdisOpenConfigurationKeyByIndex(ndis_status *, 129140751Swpaul ndis_handle, uint32_t, ndis_unicode_string *, ndis_handle *); 130144888Swpaulstatic void NdisOpenConfigurationKeyByName(ndis_status *, 131140751Swpaul ndis_handle, ndis_unicode_string *, ndis_handle *); 132123474Swpaulstatic ndis_status ndis_encode_parm(ndis_miniport_block *, 133123474Swpaul struct sysctl_oid *, ndis_parm_type, ndis_config_parm **); 134123526Swpaulstatic ndis_status ndis_decode_parm(ndis_miniport_block *, 135123526Swpaul ndis_config_parm *, char *); 136144888Swpaulstatic void NdisReadConfiguration(ndis_status *, ndis_config_parm **, 137123474Swpaul ndis_handle, ndis_unicode_string *, ndis_parm_type); 138144888Swpaulstatic void NdisWriteConfiguration(ndis_status *, ndis_handle, 139123526Swpaul ndis_unicode_string *, ndis_config_parm *); 140144888Swpaulstatic void NdisCloseConfiguration(ndis_handle); 141144888Swpaulstatic void NdisAllocateSpinLock(ndis_spin_lock *); 142144888Swpaulstatic void NdisFreeSpinLock(ndis_spin_lock *); 143144888Swpaulstatic void NdisAcquireSpinLock(ndis_spin_lock *); 144144888Swpaulstatic void NdisReleaseSpinLock(ndis_spin_lock *); 145144888Swpaulstatic void NdisDprAcquireSpinLock(ndis_spin_lock *); 146144888Swpaulstatic void NdisDprReleaseSpinLock(ndis_spin_lock *); 147144888Swpaulstatic uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t, 148123474Swpaul uint32_t, void *, uint32_t); 149144888Swpaulstatic uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t, 150123474Swpaul uint32_t, void *, uint32_t); 151140751Swpaulstatic void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...); 152123474Swpaulstatic void ndis_map_cb(void *, bus_dma_segment_t *, int, int); 153144888Swpaulstatic void NdisMStartBufferPhysicalMapping(ndis_handle, 154140751Swpaul ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *); 155144888Swpaulstatic void NdisMCompleteBufferPhysicalMapping(ndis_handle, 156140751Swpaul ndis_buffer *, uint32_t); 157144888Swpaulstatic void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle, 158123474Swpaul ndis_timer_function, void *); 159144888Swpaulstatic void NdisInitializeTimer(ndis_timer *, 160125057Swpaul ndis_timer_function, void *); 161144888Swpaulstatic void NdisSetTimer(ndis_timer *, uint32_t); 162144888Swpaulstatic void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t); 163144888Swpaulstatic void NdisMCancelTimer(ndis_timer *, uint8_t *); 164144888Swpaulstatic void ndis_timercall(kdpc *, ndis_miniport_timer *, 165144174Swpaul void *, void *); 166144888Swpaulstatic void NdisMQueryAdapterResources(ndis_status *, ndis_handle, 167123474Swpaul ndis_resource_list *, uint32_t *); 168144888Swpaulstatic ndis_status NdisMRegisterIoPortRange(void **, 169123474Swpaul ndis_handle, uint32_t, uint32_t); 170144888Swpaulstatic void NdisMDeregisterIoPortRange(ndis_handle, 171123474Swpaul uint32_t, uint32_t, void *); 172144888Swpaulstatic void NdisReadNetworkAddress(ndis_status *, void **, 173123474Swpaul uint32_t *, ndis_handle); 174144888Swpaulstatic ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *); 175144888Swpaulstatic ndis_status NdisMAllocateMapRegisters(ndis_handle, 176123474Swpaul uint32_t, uint8_t, uint32_t, uint32_t); 177144888Swpaulstatic void NdisMFreeMapRegisters(ndis_handle); 178123474Swpaulstatic void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int); 179144888Swpaulstatic void NdisMAllocateSharedMemory(ndis_handle, uint32_t, 180123474Swpaul uint8_t, void **, ndis_physaddr *); 181125413Swpaulstatic void ndis_asyncmem_complete(void *); 182144888Swpaulstatic ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle, 183123474Swpaul uint32_t, uint8_t, void *); 184144888Swpaulstatic void NdisMFreeSharedMemory(ndis_handle, uint32_t, 185123474Swpaul uint8_t, void *, ndis_physaddr); 186144888Swpaulstatic ndis_status NdisMMapIoSpace(void **, ndis_handle, 187123474Swpaul ndis_physaddr, uint32_t); 188144888Swpaulstatic void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t); 189144888Swpaulstatic uint32_t NdisGetCacheFillSize(void); 190144888Swpaulstatic uint32_t NdisMGetDmaAlignment(ndis_handle); 191144888Swpaulstatic ndis_status NdisMInitializeScatterGatherDma(ndis_handle, 192123474Swpaul uint8_t, uint32_t); 193144888Swpaulstatic void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **); 194144888Swpaulstatic void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **); 195144888Swpaulstatic void NdisAllocateBufferPool(ndis_status *, 196123474Swpaul ndis_handle *, uint32_t); 197144888Swpaulstatic void NdisFreeBufferPool(ndis_handle); 198144888Swpaulstatic void NdisAllocateBuffer(ndis_status *, ndis_buffer **, 199123474Swpaul ndis_handle, void *, uint32_t); 200144888Swpaulstatic void NdisFreeBuffer(ndis_buffer *); 201144888Swpaulstatic uint32_t NdisBufferLength(ndis_buffer *); 202144888Swpaulstatic void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *); 203144888Swpaulstatic void NdisQueryBufferSafe(ndis_buffer *, void **, 204123474Swpaul uint32_t *, uint32_t); 205144888Swpaulstatic void *NdisBufferVirtualAddress(ndis_buffer *); 206144888Swpaulstatic void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t); 207144888Swpaulstatic void NdisAdjustBufferLength(ndis_buffer *, int); 208144888Swpaulstatic uint32_t NdisInterlockedIncrement(uint32_t *); 209144888Swpaulstatic uint32_t NdisInterlockedDecrement(uint32_t *); 210144888Swpaulstatic void NdisInitializeEvent(ndis_event *); 211144888Swpaulstatic void NdisSetEvent(ndis_event *); 212144888Swpaulstatic void NdisResetEvent(ndis_event *); 213144888Swpaulstatic uint8_t NdisWaitEvent(ndis_event *, uint32_t); 214144888Swpaulstatic ndis_status NdisUnicodeStringToAnsiString(ndis_ansi_string *, 215123474Swpaul ndis_unicode_string *); 216144888Swpaulstatic ndis_status 217140751Swpaul NdisAnsiStringToUnicodeString(ndis_unicode_string *, 218123526Swpaul ndis_ansi_string *); 219144888Swpaulstatic ndis_status NdisMPciAssignResources(ndis_handle, 220123474Swpaul uint32_t, ndis_resource_list **); 221144888Swpaulstatic ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *, 222123474Swpaul ndis_handle, uint32_t, uint32_t, uint8_t, 223123474Swpaul uint8_t, ndis_interrupt_mode); 224144888Swpaulstatic void NdisMDeregisterInterrupt(ndis_miniport_interrupt *); 225144888Swpaulstatic void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *, 226123474Swpaul ndis_shutdown_handler); 227144888Swpaulstatic void NdisMDeregisterAdapterShutdownHandler(ndis_handle); 228144888Swpaulstatic uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *); 229144888Swpaulstatic void NdisGetBufferPhysicalArraySize(ndis_buffer *, 230140751Swpaul uint32_t *); 231144888Swpaulstatic void NdisQueryBufferOffset(ndis_buffer *, 232123474Swpaul uint32_t *, uint32_t *); 233144888Swpaulstatic void NdisMSleep(uint32_t); 234144888Swpaulstatic uint32_t NdisReadPcmciaAttributeMemory(ndis_handle, 235123474Swpaul uint32_t, void *, uint32_t); 236144888Swpaulstatic uint32_t NdisWritePcmciaAttributeMemory(ndis_handle, 237123474Swpaul uint32_t, void *, uint32_t); 238144888Swpaulstatic list_entry *NdisInterlockedInsertHeadList(list_entry *, 239125551Swpaul list_entry *, ndis_spin_lock *); 240144888Swpaulstatic list_entry *NdisInterlockedRemoveHeadList(list_entry *, 241123474Swpaul ndis_spin_lock *); 242144888Swpaulstatic list_entry *NdisInterlockedInsertTailList(list_entry *, 243125551Swpaul list_entry *, ndis_spin_lock *); 244144888Swpaulstatic uint8_t 245140751Swpaul NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *, 246123474Swpaul void *, void *); 247144888Swpaulstatic void NdisGetCurrentSystemTime(uint64_t *); 248144888Swpaulstatic void NdisGetSystemUpTime(uint32_t *); 249144888Swpaulstatic void NdisInitializeString(ndis_unicode_string *, char *); 250144888Swpaulstatic void NdisInitAnsiString(ndis_ansi_string *, char *); 251144888Swpaulstatic void NdisInitUnicodeString(ndis_unicode_string *, 252123941Swpaul uint16_t *); 253144888Swpaulstatic void NdisFreeString(ndis_unicode_string *); 254144888Swpaulstatic ndis_status NdisMRemoveMiniport(ndis_handle *); 255144888Swpaulstatic void NdisTerminateWrapper(ndis_handle, void *); 256144888Swpaulstatic void NdisMGetDeviceProperty(ndis_handle, device_object **, 257125551Swpaul device_object **, device_object **, cm_resource_list *, 258125551Swpaul cm_resource_list *); 259144888Swpaulstatic void NdisGetFirstBufferFromPacket(ndis_packet *, 260140751Swpaul ndis_buffer **, void **, uint32_t *, uint32_t *); 261144888Swpaulstatic void NdisGetFirstBufferFromPacketSafe(ndis_packet *, 262140751Swpaul ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t); 263132973Swpaulstatic int ndis_find_sym(linker_file_t, char *, char *, caddr_t *); 264144888Swpaulstatic void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *, 265123822Swpaul ndis_unicode_string *, ndis_physaddr); 266144888Swpaulstatic void NdisMapFile(ndis_status *, void **, ndis_handle); 267144888Swpaulstatic void NdisUnmapFile(ndis_handle); 268144888Swpaulstatic void NdisCloseFile(ndis_handle); 269144888Swpaulstatic uint8_t NdisSystemProcessorCount(void); 270144888Swpaulstatic void NdisMIndicateStatusComplete(ndis_handle); 271144888Swpaulstatic void NdisMIndicateStatus(ndis_handle, ndis_status, 272124116Swpaul void *, uint32_t); 273124697Swpaulstatic void ndis_workfunc(void *); 274144402Swpaulstatic funcptr ndis_findwrap(funcptr); 275144888Swpaulstatic ndis_status NdisScheduleWorkItem(ndis_work_item *); 276144888Swpaulstatic void NdisCopyFromPacketToPacket(ndis_packet *, 277140751Swpaul uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *); 278144888Swpaulstatic void NdisCopyFromPacketToPacketSafe(ndis_packet *, 279140751Swpaul uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t); 280144888Swpaulstatic ndis_status NdisMRegisterDevice(ndis_handle, 281125551Swpaul ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **, 282125551Swpaul void **, ndis_handle *); 283144888Swpaulstatic ndis_status NdisMDeregisterDevice(ndis_handle); 284144888Swpaulstatic ndis_status 285140751Swpaul NdisMQueryAdapterInstanceName(ndis_unicode_string *, 286125551Swpaul ndis_handle); 287144888Swpaulstatic void NdisMRegisterUnloadHandler(ndis_handle, void *); 288144888Swpaulstatic void dummy(void); 289123474Swpaul 290124116Swpaul/* 291124116Swpaul * Some really old drivers do not properly check the return value 292124116Swpaul * from NdisAllocatePacket() and NdisAllocateBuffer() and will 293124116Swpaul * sometimes allocate few more buffers/packets that they originally 294124116Swpaul * requested when they created the pool. To prevent this from being 295124116Swpaul * a problem, we allocate a few extra buffers/packets beyond what 296124116Swpaul * the driver asks for. This #define controls how many. 297124116Swpaul */ 298124116Swpaul#define NDIS_POOL_EXTRA 16 299123474Swpaul 300123474Swpaulint 301123474Swpaulndis_libinit() 302123474Swpaul{ 303141963Swpaul image_patch_table *patch; 304141963Swpaul 305124272Swpaul strcpy(ndis_filepath, "/compat/ndis"); 306141963Swpaul 307141963Swpaul patch = ndis_functbl; 308141963Swpaul while (patch->ipt_func != NULL) { 309141963Swpaul windrv_wrap((funcptr)patch->ipt_func, 310144888Swpaul (funcptr *)&patch->ipt_wrap, 311144888Swpaul patch->ipt_argcnt, patch->ipt_ftype); 312141963Swpaul patch++; 313141963Swpaul } 314141963Swpaul 315123474Swpaul return(0); 316123474Swpaul} 317123474Swpaul 318123474Swpaulint 319123474Swpaulndis_libfini() 320123474Swpaul{ 321141963Swpaul image_patch_table *patch; 322141963Swpaul 323141963Swpaul patch = ndis_functbl; 324141963Swpaul while (patch->ipt_func != NULL) { 325141963Swpaul windrv_unwrap(patch->ipt_wrap); 326141963Swpaul patch++; 327141963Swpaul } 328141963Swpaul 329123474Swpaul return(0); 330123474Swpaul} 331123474Swpaul 332144402Swpaulstatic funcptr 333144402Swpaulndis_findwrap(func) 334144402Swpaul funcptr func; 335144402Swpaul{ 336144402Swpaul image_patch_table *patch; 337144402Swpaul 338144428Swpaul patch = ndis_functbl; 339144402Swpaul while (patch->ipt_func != NULL) { 340144402Swpaul if ((funcptr)patch->ipt_func == func) 341144402Swpaul return((funcptr)patch->ipt_wrap); 342144402Swpaul patch++; 343144402Swpaul } 344144402Swpaul 345144402Swpaul return(NULL); 346144402Swpaul} 347144402Swpaul 348123474Swpaul/* 349123474Swpaul * NDIS deals with strings in unicode format, so we have 350123474Swpaul * do deal with them that way too. For now, we only handle 351123474Swpaul * conversion between unicode and ASCII since that's all 352123474Swpaul * that device drivers care about. 353123474Swpaul */ 354123474Swpaul 355123474Swpaulint 356123474Swpaulndis_ascii_to_unicode(ascii, unicode) 357123474Swpaul char *ascii; 358123474Swpaul uint16_t **unicode; 359123474Swpaul{ 360123474Swpaul uint16_t *ustr; 361123474Swpaul int i; 362123474Swpaul 363123474Swpaul if (*unicode == NULL) 364144174Swpaul *unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_NOWAIT); 365123474Swpaul 366123474Swpaul if (*unicode == NULL) 367123474Swpaul return(ENOMEM); 368123474Swpaul ustr = *unicode; 369123474Swpaul for (i = 0; i < strlen(ascii); i++) { 370123474Swpaul *ustr = (uint16_t)ascii[i]; 371123474Swpaul ustr++; 372123474Swpaul } 373123474Swpaul 374123474Swpaul return(0); 375123474Swpaul} 376123474Swpaul 377123474Swpaulint 378123474Swpaulndis_unicode_to_ascii(unicode, ulen, ascii) 379123474Swpaul uint16_t *unicode; 380123474Swpaul int ulen; 381123474Swpaul char **ascii; 382123474Swpaul{ 383123474Swpaul uint8_t *astr; 384123474Swpaul int i; 385123474Swpaul 386123474Swpaul if (*ascii == NULL) 387144174Swpaul *ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_NOWAIT|M_ZERO); 388123474Swpaul if (*ascii == NULL) 389123474Swpaul return(ENOMEM); 390123474Swpaul astr = *ascii; 391124100Swpaul for (i = 0; i < ulen / 2; i++) { 392123474Swpaul *astr = (uint8_t)unicode[i]; 393123474Swpaul astr++; 394123474Swpaul } 395123474Swpaul 396123474Swpaul return(0); 397123474Swpaul} 398123474Swpaul 399141524Swpaul/* 400141524Swpaul * This routine does the messy Windows Driver Model device attachment 401141524Swpaul * stuff on behalf of NDIS drivers. We register our own AddDevice 402141524Swpaul * routine here 403141524Swpaul */ 404144888Swpaulstatic void 405141524SwpaulNdisInitializeWrapper(wrapper, drv, path, unused) 406125551Swpaul ndis_handle *wrapper; 407141524Swpaul driver_object *drv; 408123474Swpaul void *path; 409123474Swpaul void *unused; 410123474Swpaul{ 411141524Swpaul /* 412141524Swpaul * As of yet, I haven't come up with a compelling 413141524Swpaul * reason to define a private NDIS wrapper structure, 414141524Swpaul * so we use a pointer to the driver object as the 415141524Swpaul * wrapper handle. The driver object has the miniport 416141524Swpaul * characteristics struct for this driver hung off it 417141524Swpaul * via IoAllocateDriverObjectExtension(), and that's 418141524Swpaul * really all the private data we need. 419141524Swpaul */ 420123474Swpaul 421141524Swpaul *wrapper = drv; 422123474Swpaul 423141524Swpaul /* 424141524Swpaul * If this was really Windows, we'd be registering dispatch 425141524Swpaul * routines for the NDIS miniport module here, but we're 426141524Swpaul * not Windows so all we really need to do is set up an 427141524Swpaul * AddDevice function that'll be invoked when a new device 428141524Swpaul * instance appears. 429141524Swpaul */ 430141524Swpaul 431141524Swpaul drv->dro_driverext->dre_adddevicefunc = NdisAddDevice; 432141524Swpaul 433123474Swpaul return; 434123474Swpaul} 435123474Swpaul 436144888Swpaulstatic void 437140751SwpaulNdisTerminateWrapper(handle, syspec) 438123526Swpaul ndis_handle handle; 439123526Swpaul void *syspec; 440123526Swpaul{ 441141524Swpaul /* Nothing to see here, move along. */ 442123526Swpaul return; 443123526Swpaul} 444123526Swpaul 445144888Swpaulstatic ndis_status 446140751SwpaulNdisMRegisterMiniport(handle, characteristics, len) 447123474Swpaul ndis_handle handle; 448123474Swpaul ndis_miniport_characteristics *characteristics; 449123474Swpaul int len; 450123474Swpaul{ 451141524Swpaul ndis_miniport_characteristics *ch = NULL; 452141524Swpaul driver_object *drv; 453123474Swpaul 454141524Swpaul drv = (driver_object *)handle; 455141524Swpaul 456141524Swpaul /* 457141524Swpaul * We need to save the NDIS miniport characteristics 458141524Swpaul * somewhere. This data is per-driver, not per-device 459141524Swpaul * (all devices handled by the same driver have the 460141524Swpaul * same characteristics) so we hook it onto the driver 461141524Swpaul * object using IoAllocateDriverObjectExtension(). 462141524Swpaul * The extra extension info is automagically deleted when 463141524Swpaul * the driver is unloaded (see windrv_unload()). 464141524Swpaul */ 465141524Swpaul 466141524Swpaul if (IoAllocateDriverObjectExtension(drv, (void *)1, 467141524Swpaul sizeof(ndis_miniport_characteristics), (void **)&ch) != 468141524Swpaul STATUS_SUCCESS) 469141524Swpaul return(NDIS_STATUS_RESOURCES); 470141524Swpaul 471141524Swpaul bzero((char *)ch, sizeof(ndis_miniport_characteristics)); 472141524Swpaul 473141524Swpaul bcopy((char *)characteristics, (char *)ch, len); 474141524Swpaul 475141524Swpaul if (ch->nmc_version_major < 5 || ch->nmc_version_minor < 1) { 476141524Swpaul ch->nmc_shutdown_handler = NULL; 477141524Swpaul ch->nmc_canceltxpkts_handler = NULL; 478141524Swpaul ch->nmc_pnpevent_handler = NULL; 479125551Swpaul } 480125551Swpaul 481123474Swpaul return(NDIS_STATUS_SUCCESS); 482123474Swpaul} 483123474Swpaul 484144888Swpaulstatic ndis_status 485140751SwpaulNdisAllocateMemoryWithTag(vaddr, len, tag) 486123474Swpaul void **vaddr; 487123474Swpaul uint32_t len; 488123474Swpaul uint32_t tag; 489123474Swpaul{ 490123474Swpaul void *mem; 491123474Swpaul 492141963Swpaul 493141524Swpaul mem = ExAllocatePoolWithTag(NonPagedPool, len, tag); 494123474Swpaul if (mem == NULL) 495123474Swpaul return(NDIS_STATUS_RESOURCES); 496123474Swpaul *vaddr = mem; 497123474Swpaul 498123474Swpaul return(NDIS_STATUS_SUCCESS); 499123474Swpaul} 500123474Swpaul 501144888Swpaulstatic ndis_status 502140751SwpaulNdisAllocateMemory(vaddr, len, flags, highaddr) 503123474Swpaul void **vaddr; 504123474Swpaul uint32_t len; 505123474Swpaul uint32_t flags; 506123474Swpaul ndis_physaddr highaddr; 507123474Swpaul{ 508123474Swpaul void *mem; 509123474Swpaul 510141524Swpaul mem = ExAllocatePoolWithTag(NonPagedPool, len, 0); 511123474Swpaul if (mem == NULL) 512123474Swpaul return(NDIS_STATUS_RESOURCES); 513123474Swpaul *vaddr = mem; 514123474Swpaul 515123474Swpaul return(NDIS_STATUS_SUCCESS); 516123474Swpaul} 517123474Swpaul 518144888Swpaulstatic void 519140751SwpaulNdisFreeMemory(vaddr, len, flags) 520123474Swpaul void *vaddr; 521123474Swpaul uint32_t len; 522123474Swpaul uint32_t flags; 523123474Swpaul{ 524123474Swpaul if (len == 0) 525123474Swpaul return; 526125551Swpaul 527141524Swpaul ExFreePool(vaddr); 528141524Swpaul 529123474Swpaul return; 530123474Swpaul} 531123474Swpaul 532144888Swpaulstatic ndis_status 533140751SwpaulNdisMSetAttributesEx(adapter_handle, adapter_ctx, hangsecs, 534123474Swpaul flags, iftype) 535123474Swpaul ndis_handle adapter_handle; 536123474Swpaul ndis_handle adapter_ctx; 537123474Swpaul uint32_t hangsecs; 538123474Swpaul uint32_t flags; 539123474Swpaul ndis_interface_type iftype; 540123474Swpaul{ 541123474Swpaul ndis_miniport_block *block; 542123474Swpaul 543123474Swpaul /* 544123474Swpaul * Save the adapter context, we need it for calling 545123474Swpaul * the driver's internal functions. 546123474Swpaul */ 547123474Swpaul block = (ndis_miniport_block *)adapter_handle; 548123474Swpaul block->nmb_miniportadapterctx = adapter_ctx; 549123474Swpaul block->nmb_checkforhangsecs = hangsecs; 550126833Swpaul block->nmb_flags = flags; 551123474Swpaul 552123474Swpaul return(NDIS_STATUS_SUCCESS); 553123474Swpaul} 554123474Swpaul 555144888Swpaulstatic void 556140751SwpaulNdisOpenConfiguration(status, cfg, wrapctx) 557123474Swpaul ndis_status *status; 558123474Swpaul ndis_handle *cfg; 559123474Swpaul ndis_handle wrapctx; 560123474Swpaul{ 561141963Swpaul 562123474Swpaul *cfg = wrapctx; 563123474Swpaul *status = NDIS_STATUS_SUCCESS; 564141524Swpaul 565123474Swpaul return; 566123474Swpaul} 567123474Swpaul 568144888Swpaulstatic void 569140751SwpaulNdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle) 570123526Swpaul ndis_status *status; 571123526Swpaul ndis_handle cfg; 572123526Swpaul ndis_unicode_string *subkey; 573123526Swpaul ndis_handle *subhandle; 574123526Swpaul{ 575123526Swpaul *subhandle = cfg; 576123526Swpaul *status = NDIS_STATUS_SUCCESS; 577123526Swpaul return; 578123526Swpaul} 579123526Swpaul 580144888Swpaulstatic void 581140751SwpaulNdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle) 582123526Swpaul ndis_status *status; 583123526Swpaul ndis_handle cfg; 584123526Swpaul uint32_t idx; 585123526Swpaul ndis_unicode_string *subkey; 586123526Swpaul ndis_handle *subhandle; 587123526Swpaul{ 588123526Swpaul *status = NDIS_STATUS_FAILURE; 589123526Swpaul return; 590123526Swpaul} 591123526Swpaul 592123474Swpaulstatic ndis_status 593123474Swpaulndis_encode_parm(block, oid, type, parm) 594123474Swpaul ndis_miniport_block *block; 595123474Swpaul struct sysctl_oid *oid; 596123474Swpaul ndis_parm_type type; 597123474Swpaul ndis_config_parm **parm; 598123474Swpaul{ 599123474Swpaul uint16_t *unicode; 600123474Swpaul ndis_unicode_string *ustr; 601127248Swpaul int base = 0; 602123474Swpaul 603123474Swpaul unicode = (uint16_t *)&block->nmb_dummybuf; 604123474Swpaul 605123474Swpaul switch(type) { 606123474Swpaul case ndis_parm_string: 607123474Swpaul ndis_ascii_to_unicode((char *)oid->oid_arg1, &unicode); 608123474Swpaul (*parm)->ncp_type = ndis_parm_string; 609123474Swpaul ustr = &(*parm)->ncp_parmdata.ncp_stringdata; 610141524Swpaul ustr->us_len = strlen((char *)oid->oid_arg1) * 2; 611141524Swpaul ustr->us_buf = unicode; 612123474Swpaul break; 613123474Swpaul case ndis_parm_int: 614127248Swpaul if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0) 615127248Swpaul base = 16; 616127248Swpaul else 617127248Swpaul base = 10; 618123474Swpaul (*parm)->ncp_type = ndis_parm_int; 619123474Swpaul (*parm)->ncp_parmdata.ncp_intdata = 620127248Swpaul strtol((char *)oid->oid_arg1, NULL, base); 621123474Swpaul break; 622123474Swpaul case ndis_parm_hexint: 623127248Swpaul if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0) 624127248Swpaul base = 16; 625127248Swpaul else 626127248Swpaul base = 10; 627123474Swpaul (*parm)->ncp_type = ndis_parm_hexint; 628123474Swpaul (*parm)->ncp_parmdata.ncp_intdata = 629127248Swpaul strtoul((char *)oid->oid_arg1, NULL, base); 630123474Swpaul break; 631123474Swpaul default: 632123474Swpaul return(NDIS_STATUS_FAILURE); 633123474Swpaul break; 634123474Swpaul } 635123474Swpaul 636123474Swpaul return(NDIS_STATUS_SUCCESS); 637123474Swpaul} 638123474Swpaul 639131953Swpaulint 640131953Swpaulndis_strcasecmp(s1, s2) 641129834Swpaul const char *s1; 642129834Swpaul const char *s2; 643129834Swpaul{ 644130052Swpaul char a, b; 645129834Swpaul 646130052Swpaul /* 647130052Swpaul * In the kernel, toupper() is a macro. Have to be careful 648130052Swpaul * not to use pointer arithmetic when passing it arguments. 649130052Swpaul */ 650129834Swpaul 651130052Swpaul while(1) { 652130052Swpaul a = *s1; 653130052Swpaul b = *s2++; 654130052Swpaul if (toupper(a) != toupper(b)) 655130052Swpaul break; 656132973Swpaul if (*s1++ == '\0') 657130052Swpaul return(0); 658130052Swpaul } 659130052Swpaul 660130052Swpaul return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); 661129834Swpaul} 662129834Swpaul 663132973Swpaulint 664132973Swpaulndis_strncasecmp(s1, s2, n) 665132973Swpaul const char *s1; 666132973Swpaul const char *s2; 667132973Swpaul size_t n; 668132973Swpaul{ 669132973Swpaul char a, b; 670132973Swpaul 671132973Swpaul if (n != 0) { 672132973Swpaul do { 673132973Swpaul a = *s1; 674132973Swpaul b = *s2++; 675132973Swpaul if (toupper(a) != toupper(b)) 676132973Swpaul return (*(const unsigned char *)s1 - 677132973Swpaul *(const unsigned char *)(s2 - 1)); 678132973Swpaul if (*s1++ == '\0') 679132973Swpaul break; 680132973Swpaul } while (--n != 0); 681132973Swpaul } 682132973Swpaul 683132973Swpaul return(0); 684132973Swpaul} 685132973Swpaul 686144888Swpaulstatic void 687140751SwpaulNdisReadConfiguration(status, parm, cfg, key, type) 688123474Swpaul ndis_status *status; 689123474Swpaul ndis_config_parm **parm; 690123474Swpaul ndis_handle cfg; 691123474Swpaul ndis_unicode_string *key; 692123474Swpaul ndis_parm_type type; 693123474Swpaul{ 694123474Swpaul char *keystr = NULL; 695123474Swpaul uint16_t *unicode; 696123474Swpaul ndis_miniport_block *block; 697123474Swpaul struct ndis_softc *sc; 698123474Swpaul struct sysctl_oid *oidp; 699123474Swpaul struct sysctl_ctx_entry *e; 700123474Swpaul 701123474Swpaul block = (ndis_miniport_block *)cfg; 702141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 703123474Swpaul 704141524Swpaul if (key->us_len == 0 || key->us_buf == NULL) { 705124100Swpaul *status = NDIS_STATUS_FAILURE; 706124100Swpaul return; 707124100Swpaul } 708124100Swpaul 709141524Swpaul ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr); 710123474Swpaul *parm = &block->nmb_replyparm; 711123474Swpaul bzero((char *)&block->nmb_replyparm, sizeof(ndis_config_parm)); 712123474Swpaul unicode = (uint16_t *)&block->nmb_dummybuf; 713123474Swpaul 714123474Swpaul /* 715123474Swpaul * See if registry key is already in a list of known keys 716123474Swpaul * included with the driver. 717123474Swpaul */ 718130097Sdes#if __FreeBSD_version < 502113 719123474Swpaul TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 720130097Sdes#else 721130097Sdes TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 722130097Sdes#endif 723123474Swpaul oidp = e->entry; 724131953Swpaul if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) { 725123488Swpaul if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) { 726123488Swpaul free(keystr, M_DEVBUF); 727123488Swpaul *status = NDIS_STATUS_FAILURE; 728123488Swpaul return; 729123488Swpaul } 730123474Swpaul *status = ndis_encode_parm(block, oidp, type, parm); 731123474Swpaul free(keystr, M_DEVBUF); 732123474Swpaul return; 733123474Swpaul } 734123474Swpaul } 735123474Swpaul 736123474Swpaul /* 737123474Swpaul * If the key didn't match, add it to the list of dynamically 738123474Swpaul * created ones. Sometimes, drivers refer to registry keys 739123474Swpaul * that aren't documented in their .INF files. These keys 740123474Swpaul * are supposed to be created by some sort of utility or 741123474Swpaul * control panel snap-in that comes with the driver software. 742123474Swpaul * Sometimes it's useful to be able to manipulate these. 743123474Swpaul * If the driver requests the key in the form of a string, 744123474Swpaul * make its default value an empty string, otherwise default 745123474Swpaul * it to "0". 746123474Swpaul */ 747123474Swpaul 748123474Swpaul if (type == ndis_parm_int || type == ndis_parm_hexint) 749123488Swpaul ndis_add_sysctl(sc, keystr, "(dynamic integer key)", 750123488Swpaul "UNSET", CTLFLAG_RW); 751123474Swpaul else 752123488Swpaul ndis_add_sysctl(sc, keystr, "(dynamic string key)", 753123488Swpaul "UNSET", CTLFLAG_RW); 754123474Swpaul 755123474Swpaul free(keystr, M_DEVBUF); 756123474Swpaul *status = NDIS_STATUS_FAILURE; 757123474Swpaul return; 758123474Swpaul} 759123474Swpaul 760123526Swpaulstatic ndis_status 761123526Swpaulndis_decode_parm(block, parm, val) 762123526Swpaul ndis_miniport_block *block; 763123526Swpaul ndis_config_parm *parm; 764123526Swpaul char *val; 765123526Swpaul{ 766123526Swpaul ndis_unicode_string *ustr; 767124697Swpaul char *astr = NULL; 768123526Swpaul 769123526Swpaul switch(parm->ncp_type) { 770123526Swpaul case ndis_parm_string: 771123526Swpaul ustr = &parm->ncp_parmdata.ncp_stringdata; 772141524Swpaul ndis_unicode_to_ascii(ustr->us_buf, ustr->us_len, &astr); 773124697Swpaul bcopy(astr, val, 254); 774124697Swpaul free(astr, M_DEVBUF); 775123526Swpaul break; 776123526Swpaul case ndis_parm_int: 777124697Swpaul sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata); 778123526Swpaul break; 779123526Swpaul case ndis_parm_hexint: 780123526Swpaul sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata); 781123526Swpaul break; 782123526Swpaul default: 783123526Swpaul return(NDIS_STATUS_FAILURE); 784123526Swpaul break; 785123526Swpaul } 786123526Swpaul return(NDIS_STATUS_SUCCESS); 787123526Swpaul} 788123526Swpaul 789144888Swpaulstatic void 790140751SwpaulNdisWriteConfiguration(status, cfg, key, parm) 791123526Swpaul ndis_status *status; 792123526Swpaul ndis_handle cfg; 793123526Swpaul ndis_unicode_string *key; 794123526Swpaul ndis_config_parm *parm; 795123526Swpaul{ 796123526Swpaul char *keystr = NULL; 797123526Swpaul ndis_miniport_block *block; 798123526Swpaul struct ndis_softc *sc; 799123526Swpaul struct sysctl_oid *oidp; 800123526Swpaul struct sysctl_ctx_entry *e; 801123526Swpaul char val[256]; 802123526Swpaul 803123526Swpaul block = (ndis_miniport_block *)cfg; 804141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 805123526Swpaul 806141524Swpaul ndis_unicode_to_ascii(key->us_buf, key->us_len, &keystr); 807123526Swpaul 808123526Swpaul /* Decode the parameter into a string. */ 809124697Swpaul bzero(val, sizeof(val)); 810123526Swpaul *status = ndis_decode_parm(block, parm, val); 811123526Swpaul if (*status != NDIS_STATUS_SUCCESS) { 812123526Swpaul free(keystr, M_DEVBUF); 813123526Swpaul return; 814123526Swpaul } 815123526Swpaul 816123526Swpaul /* See if the key already exists. */ 817123526Swpaul 818130097Sdes#if __FreeBSD_version < 502113 819123526Swpaul TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 820130097Sdes#else 821130097Sdes TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 822130097Sdes#endif 823123526Swpaul oidp = e->entry; 824131953Swpaul if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) { 825123526Swpaul /* Found it, set the value. */ 826123526Swpaul strcpy((char *)oidp->oid_arg1, val); 827123526Swpaul free(keystr, M_DEVBUF); 828123526Swpaul return; 829123526Swpaul } 830123526Swpaul } 831123526Swpaul 832123526Swpaul /* Not found, add a new key with the specified value. */ 833123526Swpaul ndis_add_sysctl(sc, keystr, "(dynamically set key)", 834123526Swpaul val, CTLFLAG_RW); 835123526Swpaul 836123526Swpaul free(keystr, M_DEVBUF); 837123526Swpaul *status = NDIS_STATUS_SUCCESS; 838123526Swpaul return; 839123526Swpaul} 840123526Swpaul 841144888Swpaulstatic void 842140751SwpaulNdisCloseConfiguration(cfg) 843123474Swpaul ndis_handle cfg; 844123474Swpaul{ 845123474Swpaul return; 846123474Swpaul} 847123474Swpaul 848128229Swpaul/* 849128229Swpaul * Initialize a Windows spinlock. 850128229Swpaul */ 851144888Swpaulstatic void 852140751SwpaulNdisAllocateSpinLock(lock) 853123474Swpaul ndis_spin_lock *lock; 854123474Swpaul{ 855140751Swpaul KeInitializeSpinLock(&lock->nsl_spinlock); 856128229Swpaul lock->nsl_kirql = 0; 857128229Swpaul 858123474Swpaul return; 859123474Swpaul} 860123474Swpaul 861128229Swpaul/* 862128229Swpaul * Destroy a Windows spinlock. This is a no-op for now. There are two reasons 863128229Swpaul * for this. One is that it's sort of superfluous: we don't have to do anything 864128229Swpaul * special to deallocate the spinlock. The other is that there are some buggy 865128229Swpaul * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on 866128229Swpaul * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm 867128229Swpaul * talking to you.) 868128229Swpaul */ 869144888Swpaulstatic void 870140751SwpaulNdisFreeSpinLock(lock) 871123474Swpaul ndis_spin_lock *lock; 872123474Swpaul{ 873128229Swpaul#ifdef notdef 874140751Swpaul KeInitializeSpinLock(&lock->nsl_spinlock); 875128229Swpaul lock->nsl_kirql = 0; 876128229Swpaul#endif 877123474Swpaul return; 878123474Swpaul} 879123474Swpaul 880128229Swpaul/* 881128229Swpaul * Acquire a spinlock from IRQL <= DISPATCH_LEVEL. 882128229Swpaul */ 883128229Swpaul 884144888Swpaulstatic void 885140751SwpaulNdisAcquireSpinLock(lock) 886123474Swpaul ndis_spin_lock *lock; 887123474Swpaul{ 888140751Swpaul KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 889123474Swpaul return; 890123474Swpaul} 891123474Swpaul 892128229Swpaul/* 893128229Swpaul * Release a spinlock from IRQL == DISPATCH_LEVEL. 894128229Swpaul */ 895128229Swpaul 896144888Swpaulstatic void 897140751SwpaulNdisReleaseSpinLock(lock) 898123474Swpaul ndis_spin_lock *lock; 899123474Swpaul{ 900140751Swpaul KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 901123474Swpaul return; 902123474Swpaul} 903123474Swpaul 904128229Swpaul/* 905128229Swpaul * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL. 906128229Swpaul */ 907144888Swpaulstatic void 908140751SwpaulNdisDprAcquireSpinLock(lock) 909128229Swpaul ndis_spin_lock *lock; 910128229Swpaul{ 911144174Swpaul KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock); 912128229Swpaul return; 913128229Swpaul} 914128229Swpaul 915128229Swpaul/* 916128229Swpaul * Release a spinlock without leaving IRQL == DISPATCH_LEVEL. 917128229Swpaul */ 918144888Swpaulstatic void 919140751SwpaulNdisDprReleaseSpinLock(lock) 920128229Swpaul ndis_spin_lock *lock; 921128229Swpaul{ 922144174Swpaul KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock); 923128229Swpaul return; 924128229Swpaul} 925128229Swpaul 926144888Swpaulstatic uint32_t 927140751SwpaulNdisReadPciSlotInformation(adapter, slot, offset, buf, len) 928123474Swpaul ndis_handle adapter; 929123474Swpaul uint32_t slot; 930123474Swpaul uint32_t offset; 931123474Swpaul void *buf; 932123474Swpaul uint32_t len; 933123474Swpaul{ 934123474Swpaul ndis_miniport_block *block; 935123474Swpaul int i; 936123474Swpaul char *dest; 937141524Swpaul device_t dev; 938123474Swpaul 939123474Swpaul block = (ndis_miniport_block *)adapter; 940123474Swpaul dest = buf; 941141524Swpaul if (block == NULL) 942123474Swpaul return(0); 943123474Swpaul 944141524Swpaul dev = block->nmb_physdeviceobj->do_devext; 945144174Swpaul 946144174Swpaul /* 947144174Swpaul * I have a test system consisting of a Sun w2100z 948144174Swpaul * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g 949144174Swpaul * "Aries" miniPCI NIC. (The NIC is installed in the 950144174Swpaul * machine using a miniPCI to PCI bus adapter card.) 951144174Swpaul * When running in SMP mode, I found that 952144174Swpaul * performing a large number of consecutive calls to 953144174Swpaul * NdisReadPciSlotInformation() would result in a 954144174Swpaul * sudden system reset (or in some cases a freeze). 955144174Swpaul * My suspicion is that the multiple reads are somehow 956144174Swpaul * triggering a fatal PCI bus error that leads to a 957144174Swpaul * machine check. The 1us delay in the loop below 958144174Swpaul * seems to prevent this problem. 959144174Swpaul */ 960144174Swpaul 961144174Swpaul for (i = 0; i < len; i++) { 962144174Swpaul DELAY(1); 963141524Swpaul dest[i] = pci_read_config(dev, i + offset, 1); 964144174Swpaul } 965123474Swpaul 966123474Swpaul return(len); 967123474Swpaul} 968123474Swpaul 969144888Swpaulstatic uint32_t 970140751SwpaulNdisWritePciSlotInformation(adapter, slot, offset, buf, len) 971123474Swpaul ndis_handle adapter; 972123474Swpaul uint32_t slot; 973123474Swpaul uint32_t offset; 974123474Swpaul void *buf; 975123474Swpaul uint32_t len; 976123474Swpaul{ 977123474Swpaul ndis_miniport_block *block; 978123474Swpaul int i; 979123474Swpaul char *dest; 980141524Swpaul device_t dev; 981123474Swpaul 982123474Swpaul block = (ndis_miniport_block *)adapter; 983123474Swpaul dest = buf; 984123474Swpaul 985141524Swpaul if (block == NULL) 986123474Swpaul return(0); 987123474Swpaul 988141524Swpaul dev = block->nmb_physdeviceobj->do_devext; 989144174Swpaul for (i = 0; i < len; i++) { 990144174Swpaul DELAY(1); 991141524Swpaul pci_write_config(dev, i + offset, dest[i], 1); 992144174Swpaul } 993123474Swpaul 994123474Swpaul return(len); 995123474Swpaul} 996123474Swpaul 997123474Swpaul/* 998123474Swpaul * The errorlog routine uses a variable argument list, so we 999123474Swpaul * have to declare it this way. 1000123474Swpaul */ 1001124228Swpaul#define ERRMSGLEN 512 1002123474Swpaulstatic void 1003140751SwpaulNdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code, 1004123474Swpaul uint32_t numerrors, ...) 1005123474Swpaul{ 1006123474Swpaul ndis_miniport_block *block; 1007123474Swpaul va_list ap; 1008124173Swpaul int i, error; 1009124173Swpaul char *str = NULL, *ustr = NULL; 1010124173Swpaul uint16_t flags; 1011124228Swpaul char msgbuf[ERRMSGLEN]; 1012141524Swpaul device_t dev; 1013141963Swpaul driver_object *drv; 1014123474Swpaul 1015123474Swpaul block = (ndis_miniport_block *)adapter; 1016141524Swpaul dev = block->nmb_physdeviceobj->do_devext; 1017141963Swpaul drv = block->nmb_physdeviceobj->do_drvobj; 1018123474Swpaul 1019141963Swpaul error = pe_get_message((vm_offset_t)drv->dro_driverstart, 1020141963Swpaul code, &str, &i, &flags); 1021124173Swpaul if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE) { 1022124228Swpaul ustr = msgbuf; 1023124228Swpaul ndis_unicode_to_ascii((uint16_t *)str, 1024124228Swpaul ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr); 1025124173Swpaul str = ustr; 1026124173Swpaul } 1027141524Swpaul device_printf (dev, "NDIS ERROR: %x (%s)\n", code, 1028124165Swpaul str == NULL ? "unknown error" : str); 1029141524Swpaul device_printf (dev, "NDIS NUMERRORS: %x\n", numerrors); 1030123474Swpaul 1031123474Swpaul va_start(ap, numerrors); 1032123474Swpaul for (i = 0; i < numerrors; i++) 1033141524Swpaul device_printf (dev, "argptr: %p\n", 1034124060Swpaul va_arg(ap, void *)); 1035123474Swpaul va_end(ap); 1036123474Swpaul 1037123474Swpaul return; 1038123474Swpaul} 1039123474Swpaul 1040123474Swpaulstatic void 1041123474Swpaulndis_map_cb(arg, segs, nseg, error) 1042123474Swpaul void *arg; 1043123474Swpaul bus_dma_segment_t *segs; 1044123474Swpaul int nseg; 1045123474Swpaul int error; 1046123474Swpaul{ 1047123474Swpaul struct ndis_map_arg *ctx; 1048123474Swpaul int i; 1049123474Swpaul 1050123474Swpaul if (error) 1051123474Swpaul return; 1052123474Swpaul 1053123474Swpaul ctx = arg; 1054123474Swpaul 1055123474Swpaul for (i = 0; i < nseg; i++) { 1056123474Swpaul ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr; 1057123474Swpaul ctx->nma_fraglist[i].npu_len = segs[i].ds_len; 1058123474Swpaul } 1059123474Swpaul 1060123474Swpaul ctx->nma_cnt = nseg; 1061123474Swpaul 1062123474Swpaul return; 1063123474Swpaul} 1064123474Swpaul 1065144888Swpaulstatic void 1066140751SwpaulNdisMStartBufferPhysicalMapping(adapter, buf, mapreg, writedev, addrarray, arraysize) 1067123474Swpaul ndis_handle adapter; 1068123474Swpaul ndis_buffer *buf; 1069123474Swpaul uint32_t mapreg; 1070123474Swpaul uint8_t writedev; 1071123474Swpaul ndis_paddr_unit *addrarray; 1072123474Swpaul uint32_t *arraysize; 1073123474Swpaul{ 1074123474Swpaul ndis_miniport_block *block; 1075123474Swpaul struct ndis_softc *sc; 1076123474Swpaul struct ndis_map_arg nma; 1077123474Swpaul bus_dmamap_t map; 1078123474Swpaul int error; 1079123474Swpaul 1080123474Swpaul if (adapter == NULL) 1081123474Swpaul return; 1082123474Swpaul 1083123474Swpaul block = (ndis_miniport_block *)adapter; 1084141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1085123474Swpaul 1086123474Swpaul if (mapreg > sc->ndis_mmapcnt) 1087123474Swpaul return; 1088123474Swpaul 1089123474Swpaul map = sc->ndis_mmaps[mapreg]; 1090123474Swpaul nma.nma_fraglist = addrarray; 1091123474Swpaul 1092123474Swpaul error = bus_dmamap_load(sc->ndis_mtag, map, 1093140751Swpaul MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf), ndis_map_cb, 1094123474Swpaul (void *)&nma, BUS_DMA_NOWAIT); 1095123474Swpaul 1096123474Swpaul if (error) 1097123474Swpaul return; 1098123474Swpaul 1099123474Swpaul bus_dmamap_sync(sc->ndis_mtag, map, 1100123474Swpaul writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD); 1101123474Swpaul 1102123474Swpaul *arraysize = nma.nma_cnt; 1103123474Swpaul 1104123474Swpaul return; 1105123474Swpaul} 1106123474Swpaul 1107144888Swpaulstatic void 1108140751SwpaulNdisMCompleteBufferPhysicalMapping(adapter, buf, mapreg) 1109123474Swpaul ndis_handle adapter; 1110123474Swpaul ndis_buffer *buf; 1111123474Swpaul uint32_t mapreg; 1112123474Swpaul{ 1113123474Swpaul ndis_miniport_block *block; 1114123474Swpaul struct ndis_softc *sc; 1115123474Swpaul bus_dmamap_t map; 1116123474Swpaul 1117123474Swpaul if (adapter == NULL) 1118123474Swpaul return; 1119123474Swpaul 1120123474Swpaul block = (ndis_miniport_block *)adapter; 1121141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1122123474Swpaul 1123123474Swpaul if (mapreg > sc->ndis_mmapcnt) 1124123474Swpaul return; 1125123474Swpaul 1126123474Swpaul map = sc->ndis_mmaps[mapreg]; 1127123474Swpaul 1128123474Swpaul bus_dmamap_sync(sc->ndis_mtag, map, 1129123474Swpaul BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 1130123474Swpaul 1131123474Swpaul bus_dmamap_unload(sc->ndis_mtag, map); 1132123474Swpaul 1133123474Swpaul return; 1134123474Swpaul} 1135123474Swpaul 1136125057Swpaul/* 1137144174Swpaul * This is an older (?) timer init routine which doesn't 1138144174Swpaul * accept a miniport context handle. Serialized miniports should 1139144174Swpaul * never call this function. 1140125057Swpaul */ 1141125057Swpaul 1142144888Swpaulstatic void 1143140751SwpaulNdisInitializeTimer(timer, func, ctx) 1144125057Swpaul ndis_timer *timer; 1145125057Swpaul ndis_timer_function func; 1146125057Swpaul void *ctx; 1147125057Swpaul{ 1148140751Swpaul KeInitializeTimer(&timer->nt_ktimer); 1149140751Swpaul KeInitializeDpc(&timer->nt_kdpc, func, ctx); 1150125057Swpaul 1151125057Swpaul return; 1152125057Swpaul} 1153125057Swpaul 1154144888Swpaulstatic void 1155144174Swpaulndis_timercall(dpc, timer, sysarg1, sysarg2) 1156144174Swpaul kdpc *dpc; 1157144174Swpaul ndis_miniport_timer *timer; 1158144174Swpaul void *sysarg1; 1159144174Swpaul void *sysarg2; 1160144174Swpaul{ 1161144174Swpaul /* 1162144174Swpaul * Since we're called as a DPC, we should be running 1163144174Swpaul * at DISPATCH_LEVEL here. This means to acquire the 1164144174Swpaul * spinlock, we can use KeAcquireSpinLockAtDpcLevel() 1165144174Swpaul * rather than KeAcquireSpinLock(). 1166144174Swpaul */ 1167144174Swpaul if (NDIS_SERIALIZED(timer->nmt_block)) 1168144174Swpaul KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock); 1169144174Swpaul 1170144174Swpaul MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx, 1171144174Swpaul sysarg1, sysarg2); 1172144174Swpaul 1173144174Swpaul if (NDIS_SERIALIZED(timer->nmt_block)) 1174144174Swpaul KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock); 1175144174Swpaul 1176144174Swpaul return; 1177144174Swpaul} 1178144174Swpaul 1179144174Swpaul/* 1180144174Swpaul * For a long time I wondered why there were two NDIS timer initialization 1181144174Swpaul * routines, and why this one needed an NDIS_MINIPORT_TIMER and the 1182144174Swpaul * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout 1183144174Swpaul * function and context pointers separate from those in the DPC, which 1184144174Swpaul * allows for another level of indirection: when the timer fires, we 1185144174Swpaul * can have our own timer function invoked, and from there we can call 1186144174Swpaul * the driver's function. But why go to all that trouble? Then it hit 1187144174Swpaul * me: for serialized miniports, the timer callouts are not re-entrant. 1188144174Swpaul * By trapping the callouts and having access to the MiniportAdapterHandle, 1189144174Swpaul * we can protect the driver callouts by acquiring the NDIS serialization 1190144174Swpaul * lock. This is essential for allowing serialized miniports to work 1191144174Swpaul * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL 1192144174Swpaul * is enough to prevent other threads from pre-empting you, but with 1193144174Swpaul * SMP, you must acquire a lock as well, otherwise the other CPU is 1194144174Swpaul * free to clobber you. 1195144174Swpaul */ 1196144888Swpaulstatic void 1197140751SwpaulNdisMInitializeTimer(timer, handle, func, ctx) 1198123474Swpaul ndis_miniport_timer *timer; 1199127248Swpaul ndis_handle handle; 1200123474Swpaul ndis_timer_function func; 1201123474Swpaul void *ctx; 1202123474Swpaul{ 1203144174Swpaul /* Save the driver's funcptr and context */ 1204123474Swpaul 1205127248Swpaul timer->nmt_timerfunc = func; 1206127248Swpaul timer->nmt_timerctx = ctx; 1207127248Swpaul timer->nmt_block = handle; 1208123821Swpaul 1209144402Swpaul /* 1210144402Swpaul * Set up the timer so it will call our intermediate DPC. 1211144402Swpaul * Be sure to use the wrapped entry point, since 1212144402Swpaul * ntoskrnl_run_dpc() expects to invoke a function with 1213144402Swpaul * Microsoft calling conventions. 1214144402Swpaul */ 1215140751Swpaul KeInitializeTimer(&timer->nmt_ktimer); 1216144402Swpaul KeInitializeDpc(&timer->nmt_kdpc, 1217144402Swpaul ndis_findwrap((funcptr)ndis_timercall), timer); 1218123474Swpaul 1219123474Swpaul return; 1220123474Swpaul} 1221123474Swpaul 1222123474Swpaul/* 1223127248Swpaul * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(), 1224127248Swpaul * but the former is just a macro wrapper around the latter. 1225123474Swpaul */ 1226144888Swpaulstatic void 1227140751SwpaulNdisSetTimer(timer, msecs) 1228127248Swpaul ndis_timer *timer; 1229123474Swpaul uint32_t msecs; 1230123474Swpaul{ 1231127248Swpaul /* 1232127248Swpaul * KeSetTimer() wants the period in 1233127248Swpaul * hundred nanosecond intervals. 1234127248Swpaul */ 1235140751Swpaul KeSetTimer(&timer->nt_ktimer, 1236127248Swpaul ((int64_t)msecs * -10000), &timer->nt_kdpc); 1237123474Swpaul 1238123474Swpaul return; 1239123474Swpaul} 1240123474Swpaul 1241144888Swpaulstatic void 1242140751SwpaulNdisMSetPeriodicTimer(timer, msecs) 1243123474Swpaul ndis_miniport_timer *timer; 1244123474Swpaul uint32_t msecs; 1245123474Swpaul{ 1246140751Swpaul KeSetTimerEx(&timer->nmt_ktimer, 1247127248Swpaul ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc); 1248123474Swpaul 1249123474Swpaul return; 1250123474Swpaul} 1251123474Swpaul 1252127248Swpaul/* 1253127248Swpaul * Technically, this is really NdisCancelTimer(), but we also 1254127248Swpaul * (ab)use it for NdisMCancelTimer(), since in our implementation 1255127248Swpaul * we don't need the extra info in the ndis_miniport_timer 1256144174Swpaul * structure just to cancel a timer. 1257127248Swpaul */ 1258127248Swpaul 1259144888Swpaulstatic void 1260140751SwpaulNdisMCancelTimer(timer, cancelled) 1261127248Swpaul ndis_timer *timer; 1262123474Swpaul uint8_t *cancelled; 1263123474Swpaul{ 1264140751Swpaul *cancelled = KeCancelTimer(&timer->nt_ktimer); 1265123474Swpaul 1266123474Swpaul return; 1267123474Swpaul} 1268123474Swpaul 1269144888Swpaulstatic void 1270140751SwpaulNdisMQueryAdapterResources(status, adapter, list, buflen) 1271123474Swpaul ndis_status *status; 1272123474Swpaul ndis_handle adapter; 1273123474Swpaul ndis_resource_list *list; 1274123474Swpaul uint32_t *buflen; 1275123474Swpaul{ 1276123474Swpaul ndis_miniport_block *block; 1277123474Swpaul struct ndis_softc *sc; 1278124094Swpaul int rsclen; 1279123474Swpaul 1280123474Swpaul block = (ndis_miniport_block *)adapter; 1281141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1282124094Swpaul 1283124094Swpaul rsclen = sizeof(ndis_resource_list) + 1284123474Swpaul (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)); 1285124094Swpaul if (*buflen < rsclen) { 1286124094Swpaul *buflen = rsclen; 1287124094Swpaul *status = NDIS_STATUS_INVALID_LENGTH; 1288124094Swpaul return; 1289124094Swpaul } 1290123474Swpaul 1291127887Swpaul bcopy((char *)block->nmb_rlist, (char *)list, rsclen); 1292123474Swpaul *status = NDIS_STATUS_SUCCESS; 1293141963Swpaul 1294123474Swpaul return; 1295123474Swpaul} 1296123474Swpaul 1297144888Swpaulstatic ndis_status 1298140751SwpaulNdisMRegisterIoPortRange(offset, adapter, port, numports) 1299123474Swpaul void **offset; 1300123474Swpaul ndis_handle adapter; 1301123474Swpaul uint32_t port; 1302123474Swpaul uint32_t numports; 1303123474Swpaul{ 1304123474Swpaul struct ndis_miniport_block *block; 1305123474Swpaul struct ndis_softc *sc; 1306123474Swpaul 1307123474Swpaul if (adapter == NULL) 1308123474Swpaul return(NDIS_STATUS_FAILURE); 1309123474Swpaul 1310123474Swpaul block = (ndis_miniport_block *)adapter; 1311141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1312123474Swpaul 1313123474Swpaul if (sc->ndis_res_io == NULL) 1314123474Swpaul return(NDIS_STATUS_FAILURE); 1315123474Swpaul 1316124454Swpaul /* Don't let the device map more ports than we have. */ 1317124454Swpaul if (rman_get_size(sc->ndis_res_io) < numports) 1318123474Swpaul return(NDIS_STATUS_INVALID_LENGTH); 1319123474Swpaul 1320123474Swpaul *offset = (void *)rman_get_start(sc->ndis_res_io); 1321123474Swpaul 1322123474Swpaul return(NDIS_STATUS_SUCCESS); 1323123474Swpaul} 1324123474Swpaul 1325144888Swpaulstatic void 1326140751SwpaulNdisMDeregisterIoPortRange(adapter, port, numports, offset) 1327123474Swpaul ndis_handle adapter; 1328123474Swpaul uint32_t port; 1329123474Swpaul uint32_t numports; 1330123474Swpaul void *offset; 1331123474Swpaul{ 1332123474Swpaul return; 1333123474Swpaul} 1334123474Swpaul 1335144888Swpaulstatic void 1336140751SwpaulNdisReadNetworkAddress(status, addr, addrlen, adapter) 1337123474Swpaul ndis_status *status; 1338123474Swpaul void **addr; 1339123474Swpaul uint32_t *addrlen; 1340123474Swpaul ndis_handle adapter; 1341123474Swpaul{ 1342123474Swpaul struct ndis_softc *sc; 1343123474Swpaul ndis_miniport_block *block; 1344123474Swpaul uint8_t empty[] = { 0, 0, 0, 0, 0, 0 }; 1345123474Swpaul 1346123474Swpaul block = (ndis_miniport_block *)adapter; 1347141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1348123474Swpaul 1349123474Swpaul if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0) 1350123474Swpaul *status = NDIS_STATUS_FAILURE; 1351123474Swpaul else { 1352123474Swpaul *addr = sc->arpcom.ac_enaddr; 1353123474Swpaul *addrlen = ETHER_ADDR_LEN; 1354123474Swpaul *status = NDIS_STATUS_SUCCESS; 1355123474Swpaul } 1356123474Swpaul 1357123474Swpaul return; 1358123474Swpaul} 1359123474Swpaul 1360144888Swpaulstatic ndis_status 1361140751SwpaulNdisQueryMapRegisterCount(bustype, cnt) 1362123848Swpaul uint32_t bustype; 1363123848Swpaul uint32_t *cnt; 1364123848Swpaul{ 1365124097Swpaul *cnt = 8192; 1366123848Swpaul return(NDIS_STATUS_SUCCESS); 1367123848Swpaul} 1368123848Swpaul 1369144888Swpaulstatic ndis_status 1370140751SwpaulNdisMAllocateMapRegisters(adapter, dmachannel, dmasize, physmapneeded, maxmap) 1371123474Swpaul ndis_handle adapter; 1372123474Swpaul uint32_t dmachannel; 1373123474Swpaul uint8_t dmasize; 1374123474Swpaul uint32_t physmapneeded; 1375123474Swpaul uint32_t maxmap; 1376123474Swpaul{ 1377123474Swpaul struct ndis_softc *sc; 1378123474Swpaul ndis_miniport_block *block; 1379123474Swpaul int error, i, nseg = NDIS_MAXSEG; 1380123474Swpaul 1381123474Swpaul block = (ndis_miniport_block *)adapter; 1382141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1383123474Swpaul 1384123474Swpaul sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded, 1385123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1386123474Swpaul 1387123474Swpaul if (sc->ndis_mmaps == NULL) 1388123474Swpaul return(NDIS_STATUS_RESOURCES); 1389123474Swpaul 1390123474Swpaul error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1391123474Swpaul BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1392123474Swpaul NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW, 1393123474Swpaul NULL, NULL, &sc->ndis_mtag); 1394123474Swpaul 1395123474Swpaul if (error) { 1396123474Swpaul free(sc->ndis_mmaps, M_DEVBUF); 1397123474Swpaul return(NDIS_STATUS_RESOURCES); 1398123474Swpaul } 1399123474Swpaul 1400123474Swpaul for (i = 0; i < physmapneeded; i++) 1401123474Swpaul bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]); 1402123474Swpaul 1403123474Swpaul sc->ndis_mmapcnt = physmapneeded; 1404123474Swpaul 1405123474Swpaul return(NDIS_STATUS_SUCCESS); 1406123474Swpaul} 1407123474Swpaul 1408144888Swpaulstatic void 1409140751SwpaulNdisMFreeMapRegisters(adapter) 1410123474Swpaul ndis_handle adapter; 1411123474Swpaul{ 1412123474Swpaul struct ndis_softc *sc; 1413123474Swpaul ndis_miniport_block *block; 1414123474Swpaul int i; 1415123474Swpaul 1416123474Swpaul block = (ndis_miniport_block *)adapter; 1417141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1418123474Swpaul 1419123474Swpaul for (i = 0; i < sc->ndis_mmapcnt; i++) 1420123474Swpaul bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]); 1421123474Swpaul 1422123474Swpaul free(sc->ndis_mmaps, M_DEVBUF); 1423123474Swpaul 1424123474Swpaul bus_dma_tag_destroy(sc->ndis_mtag); 1425123474Swpaul 1426123474Swpaul return; 1427123474Swpaul} 1428123474Swpaul 1429123474Swpaulstatic void 1430123474Swpaulndis_mapshared_cb(arg, segs, nseg, error) 1431123474Swpaul void *arg; 1432123474Swpaul bus_dma_segment_t *segs; 1433123474Swpaul int nseg; 1434123474Swpaul int error; 1435123474Swpaul{ 1436123474Swpaul ndis_physaddr *p; 1437123474Swpaul 1438123474Swpaul if (error || nseg > 1) 1439123474Swpaul return; 1440123474Swpaul 1441123474Swpaul p = arg; 1442123474Swpaul 1443123474Swpaul p->np_quad = segs[0].ds_addr; 1444123474Swpaul 1445123474Swpaul return; 1446123474Swpaul} 1447123474Swpaul 1448123474Swpaul/* 1449123474Swpaul * This maps to bus_dmamem_alloc(). 1450123474Swpaul */ 1451144888Swpaulstatic void 1452140751SwpaulNdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr) 1453123474Swpaul ndis_handle adapter; 1454123474Swpaul uint32_t len; 1455123474Swpaul uint8_t cached; 1456123474Swpaul void **vaddr; 1457123474Swpaul ndis_physaddr *paddr; 1458123474Swpaul{ 1459123474Swpaul ndis_miniport_block *block; 1460123474Swpaul struct ndis_softc *sc; 1461123474Swpaul struct ndis_shmem *sh; 1462123474Swpaul int error; 1463123474Swpaul 1464123474Swpaul if (adapter == NULL) 1465123474Swpaul return; 1466123474Swpaul 1467123474Swpaul block = (ndis_miniport_block *)adapter; 1468141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1469123474Swpaul 1470123474Swpaul sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO); 1471123474Swpaul if (sh == NULL) 1472123474Swpaul return; 1473123474Swpaul 1474131750Swpaul /* 1475131750Swpaul * When performing shared memory allocations, create a tag 1476131750Swpaul * with a lowaddr limit that restricts physical memory mappings 1477131750Swpaul * so that they all fall within the first 1GB of memory. 1478131750Swpaul * At least one device/driver combination (Linksys Instant 1479131750Swpaul * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have 1480131750Swpaul * problems with performing DMA operations with physical 1481141963Swpaul * addresses that lie above the 1GB mark. I don't know if this 1482141963Swpaul * is a hardware limitation or if the addresses are being 1483141963Swpaul * truncated within the driver, but this seems to be the only 1484141963Swpaul * way to make these cards work reliably in systems with more 1485141963Swpaul * than 1GB of physical memory. 1486131750Swpaul */ 1487131750Swpaul 1488123474Swpaul error = bus_dma_tag_create(sc->ndis_parent_tag, 64, 1489131750Swpaul 0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL, 1490123474Swpaul NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL, 1491123474Swpaul &sh->ndis_stag); 1492123474Swpaul 1493123474Swpaul if (error) { 1494123474Swpaul free(sh, M_DEVBUF); 1495123474Swpaul return; 1496123474Swpaul } 1497123474Swpaul 1498123474Swpaul error = bus_dmamem_alloc(sh->ndis_stag, vaddr, 1499123474Swpaul BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap); 1500123474Swpaul 1501123474Swpaul if (error) { 1502123474Swpaul bus_dma_tag_destroy(sh->ndis_stag); 1503123474Swpaul free(sh, M_DEVBUF); 1504123474Swpaul return; 1505123474Swpaul } 1506123474Swpaul 1507123474Swpaul error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr, 1508123474Swpaul len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT); 1509123474Swpaul 1510123474Swpaul if (error) { 1511123474Swpaul bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap); 1512123474Swpaul bus_dma_tag_destroy(sh->ndis_stag); 1513123474Swpaul free(sh, M_DEVBUF); 1514123474Swpaul return; 1515123474Swpaul } 1516123474Swpaul 1517123474Swpaul sh->ndis_saddr = *vaddr; 1518123474Swpaul sh->ndis_next = sc->ndis_shlist; 1519123474Swpaul sc->ndis_shlist = sh; 1520123474Swpaul 1521123474Swpaul return; 1522123474Swpaul} 1523123474Swpaul 1524125413Swpaulstruct ndis_allocwork { 1525125413Swpaul ndis_handle na_adapter; 1526125413Swpaul uint32_t na_len; 1527125413Swpaul uint8_t na_cached; 1528125413Swpaul void *na_ctx; 1529125413Swpaul}; 1530125413Swpaul 1531125413Swpaulstatic void 1532125413Swpaulndis_asyncmem_complete(arg) 1533125413Swpaul void *arg; 1534123474Swpaul{ 1535123474Swpaul ndis_miniport_block *block; 1536123474Swpaul struct ndis_softc *sc; 1537125413Swpaul struct ndis_allocwork *w; 1538123474Swpaul void *vaddr; 1539123474Swpaul ndis_physaddr paddr; 1540144888Swpaul ndis_allocdone_handler donefunc; 1541123474Swpaul 1542125413Swpaul w = arg; 1543125413Swpaul block = (ndis_miniport_block *)w->na_adapter; 1544141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1545123474Swpaul 1546125413Swpaul vaddr = NULL; 1547125413Swpaul paddr.np_quad = 0; 1548125413Swpaul 1549141524Swpaul donefunc = sc->ndis_chars->nmc_allocate_complete_func; 1550140751Swpaul NdisMAllocateSharedMemory(w->na_adapter, w->na_len, 1551125413Swpaul w->na_cached, &vaddr, &paddr); 1552141963Swpaul MSCALL5(donefunc, w->na_adapter, vaddr, &paddr, w->na_len, w->na_ctx); 1553123474Swpaul 1554125551Swpaul free(arg, M_DEVBUF); 1555123474Swpaul 1556123474Swpaul return; 1557123474Swpaul} 1558123474Swpaul 1559144888Swpaulstatic ndis_status 1560140751SwpaulNdisMAllocateSharedMemoryAsync(adapter, len, cached, ctx) 1561125413Swpaul ndis_handle adapter; 1562125413Swpaul uint32_t len; 1563125413Swpaul uint8_t cached; 1564125413Swpaul void *ctx; 1565125413Swpaul{ 1566125413Swpaul struct ndis_allocwork *w; 1567125413Swpaul 1568125413Swpaul if (adapter == NULL) 1569125413Swpaul return(NDIS_STATUS_FAILURE); 1570125413Swpaul 1571125413Swpaul w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT); 1572125413Swpaul 1573125413Swpaul if (w == NULL) 1574125413Swpaul return(NDIS_STATUS_FAILURE); 1575125413Swpaul 1576125413Swpaul w->na_adapter = adapter; 1577125413Swpaul w->na_cached = cached; 1578125413Swpaul w->na_len = len; 1579125413Swpaul w->na_ctx = ctx; 1580125413Swpaul 1581125551Swpaul /* 1582125551Swpaul * Pawn this work off on the SWI thread instead of the 1583125551Swpaul * taskqueue thread, because sometimes drivers will queue 1584125551Swpaul * up work items on the taskqueue thread that will block, 1585125551Swpaul * which would prevent the memory allocation from completing 1586125551Swpaul * when we need it. 1587125551Swpaul */ 1588125551Swpaul ndis_sched(ndis_asyncmem_complete, w, NDIS_SWI); 1589125413Swpaul 1590125413Swpaul return(NDIS_STATUS_PENDING); 1591125413Swpaul} 1592125413Swpaul 1593144888Swpaulstatic void 1594140751SwpaulNdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr) 1595123474Swpaul ndis_handle adapter; 1596123474Swpaul uint32_t len; 1597123474Swpaul uint8_t cached; 1598123474Swpaul void *vaddr; 1599123474Swpaul ndis_physaddr paddr; 1600123474Swpaul{ 1601123474Swpaul ndis_miniport_block *block; 1602123474Swpaul struct ndis_softc *sc; 1603123474Swpaul struct ndis_shmem *sh, *prev; 1604123474Swpaul 1605123474Swpaul if (vaddr == NULL || adapter == NULL) 1606123474Swpaul return; 1607123474Swpaul 1608123474Swpaul block = (ndis_miniport_block *)adapter; 1609141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1610123474Swpaul sh = prev = sc->ndis_shlist; 1611123474Swpaul 1612144254Swpaul /* Sanity check: is list empty? */ 1613144254Swpaul 1614144254Swpaul if (sh == NULL) 1615144254Swpaul return; 1616144254Swpaul 1617123474Swpaul while (sh) { 1618123474Swpaul if (sh->ndis_saddr == vaddr) 1619123474Swpaul break; 1620123474Swpaul prev = sh; 1621123474Swpaul sh = sh->ndis_next; 1622123474Swpaul } 1623123474Swpaul 1624123474Swpaul bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap); 1625123474Swpaul bus_dmamem_free(sh->ndis_stag, vaddr, sh->ndis_smap); 1626123474Swpaul bus_dma_tag_destroy(sh->ndis_stag); 1627123474Swpaul 1628123474Swpaul if (sh == sc->ndis_shlist) 1629123474Swpaul sc->ndis_shlist = sh->ndis_next; 1630123474Swpaul else 1631123474Swpaul prev->ndis_next = sh->ndis_next; 1632123474Swpaul 1633123474Swpaul free(sh, M_DEVBUF); 1634123474Swpaul 1635123474Swpaul return; 1636123474Swpaul} 1637123474Swpaul 1638144888Swpaulstatic ndis_status 1639140751SwpaulNdisMMapIoSpace(vaddr, adapter, paddr, len) 1640123474Swpaul void **vaddr; 1641123474Swpaul ndis_handle adapter; 1642123474Swpaul ndis_physaddr paddr; 1643123474Swpaul uint32_t len; 1644123474Swpaul{ 1645123474Swpaul ndis_miniport_block *block; 1646123474Swpaul struct ndis_softc *sc; 1647123474Swpaul 1648123474Swpaul if (adapter == NULL) 1649123474Swpaul return(NDIS_STATUS_FAILURE); 1650123474Swpaul 1651123474Swpaul block = (ndis_miniport_block *)adapter; 1652141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1653123474Swpaul 1654125599Swpaul if (sc->ndis_res_mem != NULL && 1655125599Swpaul paddr.np_quad == rman_get_start(sc->ndis_res_mem)) 1656125598Swpaul *vaddr = (void *)rman_get_virtual(sc->ndis_res_mem); 1657125599Swpaul else if (sc->ndis_res_altmem != NULL && 1658125599Swpaul paddr.np_quad == rman_get_start(sc->ndis_res_altmem)) 1659125598Swpaul *vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem); 1660131953Swpaul else if (sc->ndis_res_am != NULL && 1661131953Swpaul paddr.np_quad == rman_get_start(sc->ndis_res_am)) 1662131953Swpaul *vaddr = (void *)rman_get_virtual(sc->ndis_res_am); 1663125598Swpaul else 1664123474Swpaul return(NDIS_STATUS_FAILURE); 1665123474Swpaul 1666123474Swpaul return(NDIS_STATUS_SUCCESS); 1667123474Swpaul} 1668123474Swpaul 1669144888Swpaulstatic void 1670140751SwpaulNdisMUnmapIoSpace(adapter, vaddr, len) 1671123474Swpaul ndis_handle adapter; 1672123474Swpaul void *vaddr; 1673123474Swpaul uint32_t len; 1674123474Swpaul{ 1675123474Swpaul return; 1676123474Swpaul} 1677123474Swpaul 1678144888Swpaulstatic uint32_t 1679140751SwpaulNdisGetCacheFillSize(void) 1680123474Swpaul{ 1681123474Swpaul return(128); 1682123474Swpaul} 1683123474Swpaul 1684144888Swpaulstatic uint32_t 1685140751SwpaulNdisMGetDmaAlignment(handle) 1686123474Swpaul ndis_handle handle; 1687123474Swpaul{ 1688123474Swpaul return(128); 1689123474Swpaul} 1690123474Swpaul 1691123474Swpaul/* 1692123474Swpaul * NDIS has two methods for dealing with NICs that support DMA. 1693123474Swpaul * One is to just pass packets to the driver and let it call 1694123474Swpaul * NdisMStartBufferPhysicalMapping() to map each buffer in the packet 1695123474Swpaul * all by itself, and the other is to let the NDIS library handle the 1696123474Swpaul * buffer mapping internally, and hand the driver an already populated 1697123474Swpaul * scatter/gather fragment list. If the driver calls 1698123474Swpaul * NdisMInitializeScatterGatherDma(), it wants to use the latter 1699123474Swpaul * method. 1700123474Swpaul */ 1701123474Swpaul 1702144888Swpaulstatic ndis_status 1703140751SwpaulNdisMInitializeScatterGatherDma(adapter, is64, maxphysmap) 1704123474Swpaul ndis_handle adapter; 1705123474Swpaul uint8_t is64; 1706123474Swpaul uint32_t maxphysmap; 1707123474Swpaul{ 1708123474Swpaul struct ndis_softc *sc; 1709123474Swpaul ndis_miniport_block *block; 1710123474Swpaul int error; 1711123474Swpaul 1712123474Swpaul if (adapter == NULL) 1713123474Swpaul return(NDIS_STATUS_FAILURE); 1714123474Swpaul block = (ndis_miniport_block *)adapter; 1715141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 1716123474Swpaul 1717123474Swpaul /* Don't do this twice. */ 1718123474Swpaul if (sc->ndis_sc == 1) 1719123474Swpaul return(NDIS_STATUS_SUCCESS); 1720123474Swpaul 1721123474Swpaul error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1722123474Swpaul BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 1723123474Swpaul MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW, 1724123474Swpaul NULL, NULL, &sc->ndis_ttag); 1725123474Swpaul 1726123474Swpaul sc->ndis_sc = 1; 1727123474Swpaul 1728123474Swpaul return(NDIS_STATUS_SUCCESS); 1729123474Swpaul} 1730123474Swpaul 1731144888Swpaulvoid 1732140751SwpaulNdisAllocatePacketPool(status, pool, descnum, protrsvdlen) 1733123474Swpaul ndis_status *status; 1734123474Swpaul ndis_handle *pool; 1735123474Swpaul uint32_t descnum; 1736123474Swpaul uint32_t protrsvdlen; 1737123474Swpaul{ 1738123474Swpaul ndis_packet *cur; 1739123474Swpaul int i; 1740123474Swpaul 1741141963Swpaul *pool = malloc((sizeof(ndis_packet) + protrsvdlen) * 1742124116Swpaul ((descnum + NDIS_POOL_EXTRA) + 1), 1743123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1744123474Swpaul 1745132980Swpaul if (*pool == NULL) { 1746123474Swpaul *status = NDIS_STATUS_RESOURCES; 1747123474Swpaul return; 1748123474Swpaul } 1749123474Swpaul 1750123474Swpaul cur = (ndis_packet *)*pool; 1751143086Swpaul KeInitializeSpinLock(&cur->np_lock); 1752123474Swpaul cur->np_private.npp_flags = 0x1; /* mark the head of the list */ 1753126568Swpaul cur->np_private.npp_totlen = 0; /* init deletetion flag */ 1754124116Swpaul for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) { 1755123474Swpaul cur->np_private.npp_head = (ndis_handle)(cur + 1); 1756123474Swpaul cur++; 1757123474Swpaul } 1758123474Swpaul 1759123474Swpaul *status = NDIS_STATUS_SUCCESS; 1760123474Swpaul return; 1761123474Swpaul} 1762123474Swpaul 1763144888Swpaulvoid 1764140751SwpaulNdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen) 1765123474Swpaul ndis_status *status; 1766123474Swpaul ndis_handle *pool; 1767123474Swpaul uint32_t descnum; 1768123474Swpaul uint32_t oflowdescnum; 1769123474Swpaul uint32_t protrsvdlen; 1770123474Swpaul{ 1771140751Swpaul return(NdisAllocatePacketPool(status, pool, 1772123474Swpaul descnum + oflowdescnum, protrsvdlen)); 1773123474Swpaul} 1774123474Swpaul 1775144888Swpauluint32_t 1776140751SwpaulNdisPacketPoolUsage(pool) 1777123474Swpaul ndis_handle pool; 1778123474Swpaul{ 1779123474Swpaul ndis_packet *head; 1780143086Swpaul uint8_t irql; 1781143086Swpaul uint32_t cnt; 1782123474Swpaul 1783123474Swpaul head = (ndis_packet *)pool; 1784143086Swpaul KeAcquireSpinLock(&head->np_lock, &irql); 1785143086Swpaul cnt = head->np_private.npp_count; 1786143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1787123474Swpaul 1788143086Swpaul return(cnt); 1789123474Swpaul} 1790123474Swpaul 1791144888Swpaulvoid 1792140751SwpaulNdisFreePacketPool(pool) 1793123474Swpaul ndis_handle pool; 1794123474Swpaul{ 1795126568Swpaul ndis_packet *head; 1796143086Swpaul uint8_t irql; 1797126568Swpaul 1798126568Swpaul head = pool; 1799126568Swpaul 1800126568Swpaul /* Mark this pool as 'going away.' */ 1801126568Swpaul 1802143086Swpaul KeAcquireSpinLock(&head->np_lock, &irql); 1803126568Swpaul head->np_private.npp_totlen = 1; 1804126568Swpaul 1805126568Swpaul /* If there are no buffers loaned out, destroy the pool. */ 1806126568Swpaul 1807143086Swpaul if (head->np_private.npp_count == 0) { 1808143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1809126568Swpaul free(pool, M_DEVBUF); 1810143086Swpaul } else { 1811126568Swpaul printf("NDIS: buggy driver deleting active packet pool!\n"); 1812143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1813143086Swpaul } 1814126568Swpaul 1815123474Swpaul return; 1816123474Swpaul} 1817123474Swpaul 1818144888Swpaulvoid 1819140751SwpaulNdisAllocatePacket(status, packet, pool) 1820123474Swpaul ndis_status *status; 1821123474Swpaul ndis_packet **packet; 1822123474Swpaul ndis_handle pool; 1823123474Swpaul{ 1824123474Swpaul ndis_packet *head, *pkt; 1825143086Swpaul uint8_t irql; 1826123474Swpaul 1827123474Swpaul head = (ndis_packet *)pool; 1828143086Swpaul KeAcquireSpinLock(&head->np_lock, &irql); 1829123474Swpaul 1830123474Swpaul if (head->np_private.npp_flags != 0x1) { 1831123474Swpaul *status = NDIS_STATUS_FAILURE; 1832143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1833123474Swpaul return; 1834123474Swpaul } 1835123474Swpaul 1836126568Swpaul /* 1837126568Swpaul * If this pool is marked as 'going away' don't allocate any 1838126568Swpaul * more packets out of it. 1839126568Swpaul */ 1840126568Swpaul 1841126568Swpaul if (head->np_private.npp_totlen) { 1842126568Swpaul *status = NDIS_STATUS_FAILURE; 1843143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1844126568Swpaul return; 1845126568Swpaul } 1846126568Swpaul 1847123474Swpaul pkt = (ndis_packet *)head->np_private.npp_head; 1848123474Swpaul 1849123474Swpaul if (pkt == NULL) { 1850123474Swpaul *status = NDIS_STATUS_RESOURCES; 1851143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1852123474Swpaul return; 1853123474Swpaul } 1854123474Swpaul 1855123474Swpaul head->np_private.npp_head = pkt->np_private.npp_head; 1856123474Swpaul 1857123474Swpaul pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL; 1858123474Swpaul /* Save pointer to the pool. */ 1859123474Swpaul pkt->np_private.npp_pool = head; 1860123474Swpaul 1861123474Swpaul /* Set the oob offset pointer. Lots of things expect this. */ 1862144888Swpaul pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob); 1863123474Swpaul 1864124278Swpaul /* 1865124278Swpaul * We must initialize the packet flags correctly in order 1866124278Swpaul * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and 1867141963Swpaul * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work 1868141963Swpaul * correctly. 1869124278Swpaul */ 1870124278Swpaul pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 1871144239Swpaul pkt->np_private.npp_validcounts = FALSE; 1872124278Swpaul 1873123474Swpaul *packet = pkt; 1874123474Swpaul 1875123474Swpaul head->np_private.npp_count++; 1876123474Swpaul *status = NDIS_STATUS_SUCCESS; 1877141963Swpaul 1878143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1879143086Swpaul 1880123474Swpaul return; 1881123474Swpaul} 1882123474Swpaul 1883144888Swpaulvoid 1884140751SwpaulNdisFreePacket(packet) 1885123474Swpaul ndis_packet *packet; 1886123474Swpaul{ 1887123474Swpaul ndis_packet *head; 1888143086Swpaul uint8_t irql; 1889123474Swpaul 1890123474Swpaul if (packet == NULL || packet->np_private.npp_pool == NULL) 1891123474Swpaul return; 1892123474Swpaul 1893123474Swpaul head = packet->np_private.npp_pool; 1894143086Swpaul KeAcquireSpinLock(&head->np_lock, &irql); 1895143086Swpaul 1896143086Swpaul if (head->np_private.npp_flags != 0x1) { 1897143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1898123474Swpaul return; 1899143086Swpaul } 1900123474Swpaul 1901123474Swpaul packet->np_private.npp_head = head->np_private.npp_head; 1902123474Swpaul head->np_private.npp_head = (ndis_buffer *)packet; 1903123474Swpaul head->np_private.npp_count--; 1904123474Swpaul 1905126568Swpaul /* 1906126568Swpaul * If the pool has been marked for deletion and there are 1907126568Swpaul * no more packets outstanding, nuke the pool. 1908126568Swpaul */ 1909126568Swpaul 1910143086Swpaul if (head->np_private.npp_totlen && head->np_private.npp_count == 0) { 1911143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1912126568Swpaul free(head, M_DEVBUF); 1913143086Swpaul } else 1914143086Swpaul KeReleaseSpinLock(&head->np_lock, irql); 1915126568Swpaul 1916123474Swpaul return; 1917123474Swpaul} 1918123474Swpaul 1919144888Swpaulstatic void 1920140751SwpaulNdisUnchainBufferAtFront(packet, buf) 1921123474Swpaul ndis_packet *packet; 1922123474Swpaul ndis_buffer **buf; 1923123474Swpaul{ 1924123474Swpaul ndis_packet_private *priv; 1925123474Swpaul 1926123474Swpaul if (packet == NULL || buf == NULL) 1927123474Swpaul return; 1928123474Swpaul 1929123474Swpaul priv = &packet->np_private; 1930123474Swpaul 1931123474Swpaul priv->npp_validcounts = FALSE; 1932123474Swpaul 1933123474Swpaul if (priv->npp_head == priv->npp_tail) { 1934123474Swpaul *buf = priv->npp_head; 1935123474Swpaul priv->npp_head = priv->npp_tail = NULL; 1936123474Swpaul } else { 1937123474Swpaul *buf = priv->npp_head; 1938140751Swpaul priv->npp_head = (*buf)->mdl_next; 1939123474Swpaul } 1940123474Swpaul 1941123474Swpaul return; 1942123474Swpaul} 1943123474Swpaul 1944144888Swpaulstatic void 1945140751SwpaulNdisUnchainBufferAtBack(packet, buf) 1946123721Swpaul ndis_packet *packet; 1947123721Swpaul ndis_buffer **buf; 1948123721Swpaul{ 1949123721Swpaul ndis_packet_private *priv; 1950123721Swpaul ndis_buffer *tmp; 1951123721Swpaul 1952123721Swpaul if (packet == NULL || buf == NULL) 1953123721Swpaul return; 1954123721Swpaul 1955123721Swpaul priv = &packet->np_private; 1956123721Swpaul 1957123721Swpaul priv->npp_validcounts = FALSE; 1958123721Swpaul 1959123721Swpaul if (priv->npp_head == priv->npp_tail) { 1960123721Swpaul *buf = priv->npp_head; 1961123721Swpaul priv->npp_head = priv->npp_tail = NULL; 1962123721Swpaul } else { 1963123721Swpaul *buf = priv->npp_tail; 1964123721Swpaul tmp = priv->npp_head; 1965140751Swpaul while (tmp->mdl_next != priv->npp_tail) 1966140751Swpaul tmp = tmp->mdl_next; 1967123721Swpaul priv->npp_tail = tmp; 1968140751Swpaul tmp->mdl_next = NULL; 1969123721Swpaul } 1970123721Swpaul 1971123721Swpaul return; 1972123721Swpaul} 1973123721Swpaul 1974123474Swpaul/* 1975141963Swpaul * The NDIS "buffer" is really an MDL (memory descriptor list) 1976141963Swpaul * which is used to describe a buffer in a way that allows it 1977141963Swpaul * to mapped into different contexts. We have to be careful how 1978141963Swpaul * we handle them: in some versions of Windows, the NdisFreeBuffer() 1979141963Swpaul * routine is an actual function in the NDIS API, but in others 1980141963Swpaul * it's just a macro wrapper around IoFreeMdl(). There's really 1981141963Swpaul * no way to use the 'descnum' parameter to count how many 1982141963Swpaul * "buffers" are allocated since in order to use IoFreeMdl() to 1983141963Swpaul * dispose of a buffer, we have to use IoAllocateMdl() to allocate 1984141963Swpaul * them, and IoAllocateMdl() just grabs them out of the heap. 1985123474Swpaul */ 1986123474Swpaul 1987144888Swpaulstatic void 1988140751SwpaulNdisAllocateBufferPool(status, pool, descnum) 1989123474Swpaul ndis_status *status; 1990123474Swpaul ndis_handle *pool; 1991123474Swpaul uint32_t descnum; 1992123474Swpaul{ 1993141963Swpaul /* 1994141963Swpaul * The only thing we can really do here is verify that descnum 1995141963Swpaul * is a reasonable value, but I really don't know what to check 1996141963Swpaul * it against. 1997141963Swpaul */ 1998123474Swpaul 1999141963Swpaul *pool = NonPagedPool; 2000123474Swpaul *status = NDIS_STATUS_SUCCESS; 2001123474Swpaul return; 2002123474Swpaul} 2003123474Swpaul 2004144888Swpaulstatic void 2005140751SwpaulNdisFreeBufferPool(pool) 2006123474Swpaul ndis_handle pool; 2007123474Swpaul{ 2008123474Swpaul return; 2009123474Swpaul} 2010123474Swpaul 2011144888Swpaulstatic void 2012140751SwpaulNdisAllocateBuffer(status, buffer, pool, vaddr, len) 2013123474Swpaul ndis_status *status; 2014123474Swpaul ndis_buffer **buffer; 2015123474Swpaul ndis_handle pool; 2016123474Swpaul void *vaddr; 2017123474Swpaul uint32_t len; 2018123474Swpaul{ 2019141963Swpaul ndis_buffer *buf; 2020123474Swpaul 2021141963Swpaul buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL); 2022123474Swpaul if (buf == NULL) { 2023123474Swpaul *status = NDIS_STATUS_RESOURCES; 2024123474Swpaul return; 2025123474Swpaul } 2026123474Swpaul 2027123474Swpaul *buffer = buf; 2028141963Swpaul *status = NDIS_STATUS_SUCCESS; 2029123474Swpaul 2030123474Swpaul return; 2031123474Swpaul} 2032123474Swpaul 2033144888Swpaulstatic void 2034140751SwpaulNdisFreeBuffer(buf) 2035123474Swpaul ndis_buffer *buf; 2036123474Swpaul{ 2037141963Swpaul IoFreeMdl(buf); 2038123474Swpaul return; 2039123474Swpaul} 2040123474Swpaul 2041124100Swpaul/* Aw c'mon. */ 2042124100Swpaul 2043144888Swpaulstatic uint32_t 2044140751SwpaulNdisBufferLength(buf) 2045124100Swpaul ndis_buffer *buf; 2046124100Swpaul{ 2047140751Swpaul return(MmGetMdlByteCount(buf)); 2048124100Swpaul} 2049124100Swpaul 2050123723Swpaul/* 2051123723Swpaul * Get the virtual address and length of a buffer. 2052123723Swpaul * Note: the vaddr argument is optional. 2053123723Swpaul */ 2054123474Swpaul 2055144888Swpaulstatic void 2056140751SwpaulNdisQueryBuffer(buf, vaddr, len) 2057123474Swpaul ndis_buffer *buf; 2058123474Swpaul void **vaddr; 2059123474Swpaul uint32_t *len; 2060123474Swpaul{ 2061123723Swpaul if (vaddr != NULL) 2062140751Swpaul *vaddr = MmGetMdlVirtualAddress(buf); 2063140751Swpaul *len = MmGetMdlByteCount(buf); 2064123474Swpaul 2065123474Swpaul return; 2066123474Swpaul} 2067123474Swpaul 2068123474Swpaul/* Same as above -- we don't care about the priority. */ 2069123474Swpaul 2070144888Swpaulstatic void 2071140751SwpaulNdisQueryBufferSafe(buf, vaddr, len, prio) 2072123474Swpaul ndis_buffer *buf; 2073123474Swpaul void **vaddr; 2074123474Swpaul uint32_t *len; 2075123474Swpaul uint32_t prio; 2076123474Swpaul{ 2077123723Swpaul if (vaddr != NULL) 2078140751Swpaul *vaddr = MmGetMdlVirtualAddress(buf); 2079140751Swpaul *len = MmGetMdlByteCount(buf); 2080123474Swpaul 2081123474Swpaul return; 2082123474Swpaul} 2083123474Swpaul 2084125069Swpaul/* Damnit Microsoft!! How many ways can you do the same thing?! */ 2085125069Swpaul 2086144888Swpaulstatic void * 2087140751SwpaulNdisBufferVirtualAddress(buf) 2088125069Swpaul ndis_buffer *buf; 2089125069Swpaul{ 2090140751Swpaul return(MmGetMdlVirtualAddress(buf)); 2091125069Swpaul} 2092125069Swpaul 2093144888Swpaulstatic void * 2094140751SwpaulNdisBufferVirtualAddressSafe(buf, prio) 2095125069Swpaul ndis_buffer *buf; 2096125069Swpaul uint32_t prio; 2097125069Swpaul{ 2098140751Swpaul return(MmGetMdlVirtualAddress(buf)); 2099125069Swpaul} 2100125069Swpaul 2101144888Swpaulstatic void 2102140751SwpaulNdisAdjustBufferLength(buf, len) 2103123474Swpaul ndis_buffer *buf; 2104123474Swpaul int len; 2105123474Swpaul{ 2106140751Swpaul MmGetMdlByteCount(buf) = len; 2107123474Swpaul 2108123474Swpaul return; 2109123474Swpaul} 2110123474Swpaul 2111144888Swpaulstatic uint32_t 2112140751SwpaulNdisInterlockedIncrement(addend) 2113123474Swpaul uint32_t *addend; 2114123474Swpaul{ 2115124203Swpaul atomic_add_long((u_long *)addend, 1); 2116123474Swpaul return(*addend); 2117123474Swpaul} 2118123474Swpaul 2119144888Swpaulstatic uint32_t 2120140751SwpaulNdisInterlockedDecrement(addend) 2121123474Swpaul uint32_t *addend; 2122123474Swpaul{ 2123124203Swpaul atomic_subtract_long((u_long *)addend, 1); 2124123474Swpaul return(*addend); 2125123474Swpaul} 2126123474Swpaul 2127144888Swpaulstatic void 2128140751SwpaulNdisInitializeEvent(event) 2129123474Swpaul ndis_event *event; 2130123474Swpaul{ 2131127248Swpaul /* 2132127411Swpaul * NDIS events are always notification 2133127248Swpaul * events, and should be initialized to the 2134127248Swpaul * not signaled state. 2135127248Swpaul */ 2136127248Swpaul 2137140751Swpaul KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE); 2138123474Swpaul return; 2139123474Swpaul} 2140123474Swpaul 2141144888Swpaulstatic void 2142140751SwpaulNdisSetEvent(event) 2143123474Swpaul ndis_event *event; 2144123474Swpaul{ 2145140751Swpaul KeSetEvent(&event->ne_event, 0, 0); 2146123474Swpaul return; 2147123474Swpaul} 2148123474Swpaul 2149144888Swpaulstatic void 2150140751SwpaulNdisResetEvent(event) 2151123474Swpaul ndis_event *event; 2152123474Swpaul{ 2153140751Swpaul KeResetEvent(&event->ne_event); 2154123474Swpaul return; 2155123474Swpaul} 2156123474Swpaul 2157144888Swpaulstatic uint8_t 2158140751SwpaulNdisWaitEvent(event, msecs) 2159123474Swpaul ndis_event *event; 2160123474Swpaul uint32_t msecs; 2161123474Swpaul{ 2162127248Swpaul int64_t duetime; 2163127248Swpaul uint32_t rval; 2164123474Swpaul 2165127248Swpaul duetime = ((int64_t)msecs * -10000); 2166125551Swpaul 2167140751Swpaul rval = KeWaitForSingleObject((nt_dispatch_header *)event, 2168127248Swpaul 0, 0, TRUE, msecs ? &duetime : NULL); 2169123474Swpaul 2170127248Swpaul if (rval == STATUS_TIMEOUT) 2171127248Swpaul return(FALSE); 2172125551Swpaul 2173127248Swpaul return(TRUE); 2174123474Swpaul} 2175123474Swpaul 2176144888Swpaulstatic ndis_status 2177140751SwpaulNdisUnicodeStringToAnsiString(dstr, sstr) 2178123526Swpaul ndis_ansi_string *dstr; 2179123526Swpaul ndis_unicode_string *sstr; 2180123474Swpaul{ 2181123526Swpaul if (dstr == NULL || sstr == NULL) 2182123526Swpaul return(NDIS_STATUS_FAILURE); 2183141524Swpaul if (ndis_unicode_to_ascii(sstr->us_buf, 2184141524Swpaul sstr->us_len, &dstr->nas_buf)) 2185123526Swpaul return(NDIS_STATUS_FAILURE); 2186123526Swpaul dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf); 2187123474Swpaul return (NDIS_STATUS_SUCCESS); 2188123474Swpaul} 2189123474Swpaul 2190144888Swpaulstatic ndis_status 2191140751SwpaulNdisAnsiStringToUnicodeString(dstr, sstr) 2192123526Swpaul ndis_unicode_string *dstr; 2193123526Swpaul ndis_ansi_string *sstr; 2194123526Swpaul{ 2195123526Swpaul char *str; 2196123526Swpaul if (dstr == NULL || sstr == NULL) 2197123526Swpaul return(NDIS_STATUS_FAILURE); 2198123526Swpaul str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT); 2199123526Swpaul if (str == NULL) 2200123526Swpaul return(NDIS_STATUS_FAILURE); 2201123526Swpaul strncpy(str, sstr->nas_buf, sstr->nas_len); 2202123526Swpaul *(str + sstr->nas_len) = '\0'; 2203141524Swpaul if (ndis_ascii_to_unicode(str, &dstr->us_buf)) { 2204123526Swpaul free(str, M_DEVBUF); 2205123526Swpaul return(NDIS_STATUS_FAILURE); 2206123526Swpaul } 2207141524Swpaul dstr->us_len = dstr->us_maxlen = sstr->nas_len * 2; 2208123526Swpaul free(str, M_DEVBUF); 2209123526Swpaul return (NDIS_STATUS_SUCCESS); 2210123526Swpaul} 2211123526Swpaul 2212144888Swpaulstatic ndis_status 2213140751SwpaulNdisMPciAssignResources(adapter, slot, list) 2214123474Swpaul ndis_handle adapter; 2215123474Swpaul uint32_t slot; 2216123474Swpaul ndis_resource_list **list; 2217123474Swpaul{ 2218123474Swpaul ndis_miniport_block *block; 2219123474Swpaul 2220123474Swpaul if (adapter == NULL || list == NULL) 2221123474Swpaul return (NDIS_STATUS_FAILURE); 2222123474Swpaul 2223123474Swpaul block = (ndis_miniport_block *)adapter; 2224123474Swpaul *list = block->nmb_rlist; 2225123474Swpaul 2226123474Swpaul return (NDIS_STATUS_SUCCESS); 2227123474Swpaul} 2228123474Swpaul 2229144888Swpaulstatic ndis_status 2230140751SwpaulNdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode) 2231123474Swpaul ndis_miniport_interrupt *intr; 2232123474Swpaul ndis_handle adapter; 2233123474Swpaul uint32_t ivec; 2234123474Swpaul uint32_t ilevel; 2235123474Swpaul uint8_t reqisr; 2236123474Swpaul uint8_t shared; 2237123474Swpaul ndis_interrupt_mode imode; 2238123474Swpaul{ 2239124165Swpaul ndis_miniport_block *block; 2240124165Swpaul 2241124165Swpaul block = adapter; 2242124165Swpaul 2243124135Swpaul intr->ni_block = adapter; 2244124165Swpaul intr->ni_isrreq = reqisr; 2245124165Swpaul intr->ni_shared = shared; 2246124165Swpaul block->nmb_interrupt = intr; 2247141524Swpaul 2248141963Swpaul KeInitializeSpinLock(&intr->ni_dpccountlock); 2249141963Swpaul 2250123474Swpaul return(NDIS_STATUS_SUCCESS); 2251123474Swpaul} 2252123474Swpaul 2253144888Swpaulstatic void 2254140751SwpaulNdisMDeregisterInterrupt(intr) 2255123474Swpaul ndis_miniport_interrupt *intr; 2256123474Swpaul{ 2257123474Swpaul return; 2258123474Swpaul} 2259123474Swpaul 2260144888Swpaulstatic void 2261140751SwpaulNdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc) 2262123474Swpaul ndis_handle adapter; 2263123474Swpaul void *shutdownctx; 2264123474Swpaul ndis_shutdown_handler shutdownfunc; 2265123474Swpaul{ 2266123474Swpaul ndis_miniport_block *block; 2267123474Swpaul ndis_miniport_characteristics *chars; 2268123474Swpaul struct ndis_softc *sc; 2269123474Swpaul 2270123474Swpaul if (adapter == NULL) 2271123474Swpaul return; 2272123474Swpaul 2273123474Swpaul block = (ndis_miniport_block *)adapter; 2274141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2275141524Swpaul chars = sc->ndis_chars; 2276123474Swpaul 2277123474Swpaul chars->nmc_shutdown_handler = shutdownfunc; 2278123474Swpaul chars->nmc_rsvd0 = shutdownctx; 2279123474Swpaul 2280123474Swpaul return; 2281123474Swpaul} 2282123474Swpaul 2283144888Swpaulstatic void 2284140751SwpaulNdisMDeregisterAdapterShutdownHandler(adapter) 2285123474Swpaul ndis_handle adapter; 2286123474Swpaul{ 2287123474Swpaul ndis_miniport_block *block; 2288123474Swpaul ndis_miniport_characteristics *chars; 2289123474Swpaul struct ndis_softc *sc; 2290123474Swpaul 2291123474Swpaul if (adapter == NULL) 2292123474Swpaul return; 2293123474Swpaul 2294123474Swpaul block = (ndis_miniport_block *)adapter; 2295141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2296141524Swpaul chars = sc->ndis_chars; 2297123474Swpaul 2298123474Swpaul chars->nmc_shutdown_handler = NULL; 2299123474Swpaul chars->nmc_rsvd0 = NULL; 2300123474Swpaul 2301123474Swpaul return; 2302123474Swpaul} 2303123474Swpaul 2304144888Swpaulstatic uint32_t 2305140751SwpaulNDIS_BUFFER_TO_SPAN_PAGES(buf) 2306123474Swpaul ndis_buffer *buf; 2307123474Swpaul{ 2308123757Swpaul if (buf == NULL) 2309123757Swpaul return(0); 2310140751Swpaul if (MmGetMdlByteCount(buf) == 0) 2311123512Swpaul return(1); 2312140751Swpaul return(SPAN_PAGES(MmGetMdlVirtualAddress(buf), 2313140751Swpaul MmGetMdlByteCount(buf))); 2314123474Swpaul} 2315123474Swpaul 2316144888Swpaulstatic void 2317140751SwpaulNdisGetBufferPhysicalArraySize(buf, pages) 2318123573Swpaul ndis_buffer *buf; 2319123573Swpaul uint32_t *pages; 2320123573Swpaul{ 2321123757Swpaul if (buf == NULL) 2322123757Swpaul return; 2323123757Swpaul 2324140751Swpaul *pages = NDIS_BUFFER_TO_SPAN_PAGES(buf); 2325123573Swpaul return; 2326123573Swpaul} 2327123573Swpaul 2328144888Swpaulstatic void 2329140751SwpaulNdisQueryBufferOffset(buf, off, len) 2330123474Swpaul ndis_buffer *buf; 2331123474Swpaul uint32_t *off; 2332123474Swpaul uint32_t *len; 2333123474Swpaul{ 2334123757Swpaul if (buf == NULL) 2335123757Swpaul return; 2336123757Swpaul 2337140751Swpaul *off = MmGetMdlByteOffset(buf); 2338140751Swpaul *len = MmGetMdlByteCount(buf); 2339123474Swpaul 2340123474Swpaul return; 2341123474Swpaul} 2342123474Swpaul 2343144888Swpaulstatic void 2344140751SwpaulNdisMSleep(usecs) 2345123474Swpaul uint32_t usecs; 2346123474Swpaul{ 2347123474Swpaul struct timeval tv; 2348123474Swpaul 2349123474Swpaul tv.tv_sec = 0; 2350123474Swpaul tv.tv_usec = usecs; 2351123474Swpaul 2352144174Swpaul ndis_thsuspend(curthread->td_proc, NULL, tvtohz(&tv)); 2353124100Swpaul 2354123474Swpaul return; 2355123474Swpaul} 2356123474Swpaul 2357144888Swpaulstatic uint32_t 2358140751SwpaulNdisReadPcmciaAttributeMemory(handle, offset, buf, len) 2359123474Swpaul ndis_handle handle; 2360123474Swpaul uint32_t offset; 2361123474Swpaul void *buf; 2362123474Swpaul uint32_t len; 2363123474Swpaul{ 2364123474Swpaul struct ndis_softc *sc; 2365123474Swpaul ndis_miniport_block *block; 2366123474Swpaul bus_space_handle_t bh; 2367123474Swpaul bus_space_tag_t bt; 2368123474Swpaul char *dest; 2369123474Swpaul int i; 2370123474Swpaul 2371123474Swpaul if (handle == NULL) 2372123474Swpaul return(0); 2373123474Swpaul 2374123474Swpaul block = (ndis_miniport_block *)handle; 2375141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2376123474Swpaul dest = buf; 2377123474Swpaul 2378123474Swpaul bh = rman_get_bushandle(sc->ndis_res_am); 2379123474Swpaul bt = rman_get_bustag(sc->ndis_res_am); 2380123474Swpaul 2381123474Swpaul for (i = 0; i < len; i++) 2382131953Swpaul dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2); 2383123474Swpaul 2384123474Swpaul return(i); 2385123474Swpaul} 2386123474Swpaul 2387144888Swpaulstatic uint32_t 2388140751SwpaulNdisWritePcmciaAttributeMemory(handle, offset, buf, len) 2389123474Swpaul ndis_handle handle; 2390123474Swpaul uint32_t offset; 2391123474Swpaul void *buf; 2392123474Swpaul uint32_t len; 2393123474Swpaul{ 2394123474Swpaul struct ndis_softc *sc; 2395123474Swpaul ndis_miniport_block *block; 2396123474Swpaul bus_space_handle_t bh; 2397123474Swpaul bus_space_tag_t bt; 2398123474Swpaul char *src; 2399123474Swpaul int i; 2400123474Swpaul 2401123474Swpaul if (handle == NULL) 2402123474Swpaul return(0); 2403123474Swpaul 2404123474Swpaul block = (ndis_miniport_block *)handle; 2405141524Swpaul sc = device_get_softc(block->nmb_physdeviceobj->do_devext); 2406123474Swpaul src = buf; 2407123474Swpaul 2408123474Swpaul bh = rman_get_bushandle(sc->ndis_res_am); 2409123474Swpaul bt = rman_get_bustag(sc->ndis_res_am); 2410123474Swpaul 2411123474Swpaul for (i = 0; i < len; i++) 2412131953Swpaul bus_space_write_1(bt, bh, (offset + i) * 2, src[i]); 2413123474Swpaul 2414123474Swpaul return(i); 2415123474Swpaul} 2416123474Swpaul 2417144888Swpaulstatic list_entry * 2418140751SwpaulNdisInterlockedInsertHeadList(head, entry, lock) 2419125551Swpaul list_entry *head; 2420125551Swpaul list_entry *entry; 2421123474Swpaul ndis_spin_lock *lock; 2422123474Swpaul{ 2423125551Swpaul list_entry *flink; 2424123474Swpaul 2425140751Swpaul KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2426123474Swpaul flink = head->nle_flink; 2427123474Swpaul entry->nle_flink = flink; 2428123474Swpaul entry->nle_blink = head; 2429123474Swpaul flink->nle_blink = entry; 2430123474Swpaul head->nle_flink = entry; 2431140751Swpaul KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2432123474Swpaul 2433123474Swpaul return(flink); 2434123474Swpaul} 2435123474Swpaul 2436144888Swpaulstatic list_entry * 2437140751SwpaulNdisInterlockedRemoveHeadList(head, lock) 2438125551Swpaul list_entry *head; 2439123474Swpaul ndis_spin_lock *lock; 2440123474Swpaul{ 2441125551Swpaul list_entry *flink; 2442125551Swpaul list_entry *entry; 2443123474Swpaul 2444140751Swpaul KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2445123474Swpaul entry = head->nle_flink; 2446123474Swpaul flink = entry->nle_flink; 2447123474Swpaul head->nle_flink = flink; 2448123474Swpaul flink->nle_blink = head; 2449140751Swpaul KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2450123474Swpaul 2451123474Swpaul return(entry); 2452123474Swpaul} 2453123474Swpaul 2454144888Swpaulstatic list_entry * 2455140751SwpaulNdisInterlockedInsertTailList(head, entry, lock) 2456125551Swpaul list_entry *head; 2457125551Swpaul list_entry *entry; 2458123474Swpaul ndis_spin_lock *lock; 2459123474Swpaul{ 2460125551Swpaul list_entry *blink; 2461123474Swpaul 2462140751Swpaul KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql); 2463123474Swpaul blink = head->nle_blink; 2464123474Swpaul entry->nle_flink = head; 2465123474Swpaul entry->nle_blink = blink; 2466123474Swpaul blink->nle_flink = entry; 2467123474Swpaul head->nle_blink = entry; 2468140751Swpaul KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql); 2469123474Swpaul 2470123474Swpaul return(blink); 2471123474Swpaul} 2472123474Swpaul 2473144888Swpaulstatic uint8_t 2474140751SwpaulNdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx) 2475123474Swpaul ndis_miniport_interrupt *intr; 2476123474Swpaul void *syncfunc; 2477123474Swpaul void *syncctx; 2478123474Swpaul{ 2479144888Swpaul uint8_t (*sync)(void *); 2480124135Swpaul uint8_t rval; 2481141963Swpaul uint8_t irql; 2482123474Swpaul 2483123474Swpaul if (syncfunc == NULL || syncctx == NULL) 2484123474Swpaul return(0); 2485123474Swpaul 2486123474Swpaul sync = syncfunc; 2487141963Swpaul KeAcquireSpinLock(&intr->ni_dpccountlock, &irql); 2488141963Swpaul rval = MSCALL1(sync, syncctx); 2489141963Swpaul KeReleaseSpinLock(&intr->ni_dpccountlock, irql); 2490124135Swpaul 2491124135Swpaul return(rval); 2492123474Swpaul} 2493123474Swpaul 2494123504Swpaul/* 2495123504Swpaul * Return the number of 100 nanosecond intervals since 2496123504Swpaul * January 1, 1601. (?!?!) 2497123504Swpaul */ 2498144888Swpaulstatic void 2499140751SwpaulNdisGetCurrentSystemTime(tval) 2500123504Swpaul uint64_t *tval; 2501123504Swpaul{ 2502123504Swpaul struct timespec ts; 2503123822Swpaul 2504123504Swpaul nanotime(&ts); 2505123822Swpaul *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 + 2506123822Swpaul 11644473600; 2507125551Swpaul 2508125551Swpaul return; 2509123504Swpaul} 2510123504Swpaul 2511123822Swpaul/* 2512123822Swpaul * Return the number of milliseconds since the system booted. 2513123822Swpaul */ 2514144888Swpaulstatic void 2515140751SwpaulNdisGetSystemUpTime(tval) 2516123822Swpaul uint32_t *tval; 2517123822Swpaul{ 2518144888Swpaul struct timespec ts; 2519144888Swpaul 2520144888Swpaul nanouptime(&ts); 2521144888Swpaul *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000; 2522123822Swpaul 2523125551Swpaul return; 2524123822Swpaul} 2525123822Swpaul 2526144888Swpaulstatic void 2527140751SwpaulNdisInitializeString(dst, src) 2528124100Swpaul ndis_unicode_string *dst; 2529123507Swpaul char *src; 2530123507Swpaul{ 2531123507Swpaul ndis_unicode_string *u; 2532123507Swpaul 2533124100Swpaul u = dst; 2534141524Swpaul u->us_buf = NULL; 2535141524Swpaul if (ndis_ascii_to_unicode(src, &u->us_buf)) 2536123507Swpaul return; 2537141524Swpaul u->us_len = u->us_maxlen = strlen(src) * 2; 2538123507Swpaul return; 2539123507Swpaul} 2540123507Swpaul 2541144888Swpaulstatic void 2542140751SwpaulNdisFreeString(str) 2543123507Swpaul ndis_unicode_string *str; 2544123507Swpaul{ 2545123507Swpaul if (str == NULL) 2546123507Swpaul return; 2547141524Swpaul if (str->us_buf != NULL) 2548141524Swpaul free(str->us_buf, M_DEVBUF); 2549123507Swpaul free(str, M_DEVBUF); 2550123507Swpaul return; 2551123507Swpaul} 2552123507Swpaul 2553144888Swpaulstatic ndis_status 2554140751SwpaulNdisMRemoveMiniport(adapter) 2555123507Swpaul ndis_handle *adapter; 2556123507Swpaul{ 2557123507Swpaul return(NDIS_STATUS_SUCCESS); 2558123507Swpaul} 2559123507Swpaul 2560144888Swpaulstatic void 2561140751SwpaulNdisInitAnsiString(dst, src) 2562123526Swpaul ndis_ansi_string *dst; 2563123526Swpaul char *src; 2564123526Swpaul{ 2565123526Swpaul ndis_ansi_string *a; 2566123526Swpaul 2567123526Swpaul a = dst; 2568123526Swpaul if (a == NULL) 2569123526Swpaul return; 2570123526Swpaul if (src == NULL) { 2571123526Swpaul a->nas_len = a->nas_maxlen = 0; 2572123526Swpaul a->nas_buf = NULL; 2573123526Swpaul } else { 2574123526Swpaul a->nas_buf = src; 2575123526Swpaul a->nas_len = a->nas_maxlen = strlen(src); 2576123526Swpaul } 2577123526Swpaul 2578123526Swpaul return; 2579123526Swpaul} 2580123526Swpaul 2581144888Swpaulstatic void 2582140751SwpaulNdisInitUnicodeString(dst, src) 2583123941Swpaul ndis_unicode_string *dst; 2584123941Swpaul uint16_t *src; 2585123941Swpaul{ 2586123941Swpaul ndis_unicode_string *u; 2587123941Swpaul int i; 2588123941Swpaul 2589123941Swpaul u = dst; 2590123941Swpaul if (u == NULL) 2591123941Swpaul return; 2592123941Swpaul if (src == NULL) { 2593141524Swpaul u->us_len = u->us_maxlen = 0; 2594141524Swpaul u->us_buf = NULL; 2595123941Swpaul } else { 2596123941Swpaul i = 0; 2597123941Swpaul while(src[i] != 0) 2598123941Swpaul i++; 2599141524Swpaul u->us_buf = src; 2600141524Swpaul u->us_len = u->us_maxlen = i * 2; 2601123941Swpaul } 2602123941Swpaul 2603123941Swpaul return; 2604123941Swpaul} 2605123941Swpaul 2606144888Swpaulstatic void NdisMGetDeviceProperty(adapter, phydevobj, 2607123526Swpaul funcdevobj, nextdevobj, resources, transresources) 2608123526Swpaul ndis_handle adapter; 2609125551Swpaul device_object **phydevobj; 2610125551Swpaul device_object **funcdevobj; 2611125551Swpaul device_object **nextdevobj; 2612123526Swpaul cm_resource_list *resources; 2613123526Swpaul cm_resource_list *transresources; 2614123526Swpaul{ 2615125551Swpaul ndis_miniport_block *block; 2616125551Swpaul 2617125551Swpaul block = (ndis_miniport_block *)adapter; 2618125551Swpaul 2619125551Swpaul if (phydevobj != NULL) 2620141524Swpaul *phydevobj = block->nmb_physdeviceobj; 2621125551Swpaul if (funcdevobj != NULL) 2622141524Swpaul *funcdevobj = block->nmb_deviceobj; 2623141524Swpaul if (nextdevobj != NULL) 2624141524Swpaul *nextdevobj = block->nmb_nextdeviceobj; 2625125551Swpaul 2626123526Swpaul return; 2627123526Swpaul} 2628123526Swpaul 2629144888Swpaulstatic void 2630140751SwpaulNdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen) 2631123721Swpaul ndis_packet *packet; 2632123721Swpaul ndis_buffer **buf; 2633123721Swpaul void **firstva; 2634123721Swpaul uint32_t *firstlen; 2635123721Swpaul uint32_t *totlen; 2636123721Swpaul{ 2637123721Swpaul ndis_buffer *tmp; 2638123721Swpaul 2639123721Swpaul tmp = packet->np_private.npp_head; 2640123721Swpaul *buf = tmp; 2641123721Swpaul if (tmp == NULL) { 2642123721Swpaul *firstva = NULL; 2643123721Swpaul *firstlen = *totlen = 0; 2644123721Swpaul } else { 2645140751Swpaul *firstva = MmGetMdlVirtualAddress(tmp); 2646140751Swpaul *firstlen = *totlen = MmGetMdlByteCount(tmp); 2647140751Swpaul for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next) 2648140751Swpaul *totlen += MmGetMdlByteCount(tmp); 2649123721Swpaul } 2650123721Swpaul 2651123721Swpaul return; 2652123721Swpaul} 2653123721Swpaul 2654144888Swpaulstatic void 2655140751SwpaulNdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio) 2656123721Swpaul ndis_packet *packet; 2657123721Swpaul ndis_buffer **buf; 2658123721Swpaul void **firstva; 2659123721Swpaul uint32_t *firstlen; 2660123721Swpaul uint32_t *totlen; 2661123721Swpaul uint32_t prio; 2662123721Swpaul{ 2663140751Swpaul NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen); 2664123721Swpaul} 2665123721Swpaul 2666132973Swpaulstatic int 2667132973Swpaulndis_find_sym(lf, filename, suffix, sym) 2668132973Swpaul linker_file_t lf; 2669132973Swpaul char *filename; 2670132973Swpaul char *suffix; 2671132973Swpaul caddr_t *sym; 2672132973Swpaul{ 2673143086Swpaul char *fullsym; 2674133876Swpaul char *suf; 2675132973Swpaul int i; 2676132973Swpaul 2677143086Swpaul fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2678143086Swpaul if (fullsym == NULL) 2679143086Swpaul return(ENOMEM); 2680143086Swpaul 2681143086Swpaul bzero(fullsym, MAXPATHLEN); 2682143086Swpaul strncpy(fullsym, filename, MAXPATHLEN); 2683143086Swpaul if (strlen(filename) < 4) { 2684143086Swpaul ExFreePool(fullsym); 2685133876Swpaul return(EINVAL); 2686143086Swpaul } 2687133876Swpaul 2688133876Swpaul /* If the filename has a .ko suffix, strip if off. */ 2689133876Swpaul suf = fullsym + (strlen(filename) - 3); 2690133876Swpaul if (strcmp(suf, ".ko") == 0) 2691133876Swpaul *suf = '\0'; 2692133876Swpaul 2693132973Swpaul for (i = 0; i < strlen(fullsym); i++) { 2694132973Swpaul if (fullsym[i] == '.') 2695132973Swpaul fullsym[i] = '_'; 2696132973Swpaul else 2697132973Swpaul fullsym[i] = tolower(fullsym[i]); 2698132973Swpaul } 2699132973Swpaul strcat(fullsym, suffix); 2700132973Swpaul *sym = linker_file_lookup_symbol(lf, fullsym, 0); 2701143086Swpaul ExFreePool(fullsym); 2702132973Swpaul if (*sym == 0) 2703132973Swpaul return(ENOENT); 2704132973Swpaul 2705132973Swpaul return(0); 2706132973Swpaul} 2707132973Swpaul 2708123822Swpaul/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ 2709144888Swpaulstatic void 2710140751SwpaulNdisOpenFile(status, filehandle, filelength, filename, highestaddr) 2711123822Swpaul ndis_status *status; 2712123822Swpaul ndis_handle *filehandle; 2713123822Swpaul uint32_t *filelength; 2714123822Swpaul ndis_unicode_string *filename; 2715123822Swpaul ndis_physaddr highestaddr; 2716123822Swpaul{ 2717123822Swpaul char *afilename = NULL; 2718124272Swpaul struct thread *td = curthread; 2719124272Swpaul struct nameidata nd; 2720124272Swpaul int flags, error; 2721124272Swpaul struct vattr vat; 2722124272Swpaul struct vattr *vap = &vat; 2723124272Swpaul ndis_fh *fh; 2724143086Swpaul char *path; 2725132973Swpaul linker_file_t head, lf; 2726132973Swpaul caddr_t kldstart, kldend; 2727123822Swpaul 2728141524Swpaul ndis_unicode_to_ascii(filename->us_buf, 2729141524Swpaul filename->us_len, &afilename); 2730124272Swpaul 2731143086Swpaul fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0); 2732124272Swpaul if (fh == NULL) { 2733124272Swpaul *status = NDIS_STATUS_RESOURCES; 2734124272Swpaul return; 2735124272Swpaul } 2736124272Swpaul 2737132973Swpaul /* 2738132973Swpaul * During system bootstrap, it's impossible to load files 2739132973Swpaul * from the rootfs since it's not mounted yet. We therefore 2740132973Swpaul * offer the possibility of opening files that have been 2741132973Swpaul * preloaded as modules instead. Both choices will work 2742132973Swpaul * when kldloading a module from multiuser, but only the 2743132973Swpaul * module option will work during bootstrap. The module 2744132973Swpaul * loading option works by using the ndiscvt(8) utility 2745132973Swpaul * to convert the arbitrary file into a .ko using objcopy(1). 2746132973Swpaul * This file will contain two special symbols: filename_start 2747132973Swpaul * and filename_end. All we have to do is traverse the KLD 2748132973Swpaul * list in search of those symbols and we've found the file 2749132973Swpaul * data. As an added bonus, ndiscvt(8) will also generate 2750132973Swpaul * a normal .o file which can be linked statically with 2751132973Swpaul * the kernel. This means that the symbols will actual reside 2752132973Swpaul * in the kernel's symbol table, but that doesn't matter to 2753132973Swpaul * us since the kernel appears to us as just another module. 2754132973Swpaul */ 2755132973Swpaul 2756132973Swpaul /* 2757132973Swpaul * This is an evil trick for getting the head of the linked 2758132973Swpaul * file list, which is not exported from kern_linker.o. It 2759132973Swpaul * happens that linker file #1 is always the kernel, and is 2760132973Swpaul * always the first element in the list. 2761132973Swpaul */ 2762132973Swpaul 2763132973Swpaul head = linker_find_file_by_id(1); 2764132973Swpaul for (lf = head; lf != NULL; lf = TAILQ_NEXT(lf, link)) { 2765132973Swpaul if (ndis_find_sym(lf, afilename, "_start", &kldstart)) 2766132973Swpaul continue; 2767132973Swpaul if (ndis_find_sym(lf, afilename, "_end", &kldend)) 2768132973Swpaul continue; 2769132973Swpaul fh->nf_vp = lf; 2770133880Swpaul fh->nf_map = NULL; 2771132973Swpaul fh->nf_type = NDIS_FH_TYPE_MODULE; 2772132973Swpaul *filelength = fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF; 2773132973Swpaul *filehandle = fh; 2774132973Swpaul free(afilename, M_DEVBUF); 2775132973Swpaul *status = NDIS_STATUS_SUCCESS; 2776132973Swpaul return; 2777132973Swpaul } 2778132973Swpaul 2779132973Swpaul if (TAILQ_EMPTY(&mountlist)) { 2780144256Swpaul ExFreePool(fh); 2781132973Swpaul *status = NDIS_STATUS_FILE_NOT_FOUND; 2782132973Swpaul printf("NDIS: could not find file %s in linker list\n", 2783132973Swpaul afilename); 2784132973Swpaul printf("NDIS: and no filesystems mounted yet, " 2785132973Swpaul "aborting NdisOpenFile()\n"); 2786132973Swpaul free(afilename, M_DEVBUF); 2787132973Swpaul return; 2788132973Swpaul } 2789132973Swpaul 2790143086Swpaul path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0); 2791143086Swpaul if (path == NULL) { 2792144256Swpaul ExFreePool(fh); 2793143086Swpaul *status = NDIS_STATUS_RESOURCES; 2794143086Swpaul return; 2795143086Swpaul } 2796143086Swpaul 2797143086Swpaul snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename); 2798132973Swpaul free(afilename, M_DEVBUF); 2799132973Swpaul 2800124272Swpaul mtx_lock(&Giant); 2801125377Swpaul 2802125377Swpaul /* Some threads don't have a current working directory. */ 2803125377Swpaul 2804125377Swpaul if (td->td_proc->p_fd->fd_rdir == NULL) 2805125377Swpaul td->td_proc->p_fd->fd_rdir = rootvnode; 2806125377Swpaul if (td->td_proc->p_fd->fd_cdir == NULL) 2807125377Swpaul td->td_proc->p_fd->fd_cdir = rootvnode; 2808125377Swpaul 2809124272Swpaul NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); 2810124272Swpaul 2811124272Swpaul flags = FREAD; 2812124272Swpaul error = vn_open(&nd, &flags, 0, -1); 2813124272Swpaul if (error) { 2814124272Swpaul mtx_unlock(&Giant); 2815124272Swpaul *status = NDIS_STATUS_FILE_NOT_FOUND; 2816143086Swpaul ExFreePool(fh); 2817127887Swpaul printf("NDIS: open file %s failed: %d\n", path, error); 2818143086Swpaul ExFreePool(path); 2819124272Swpaul return; 2820124272Swpaul } 2821124272Swpaul 2822143086Swpaul ExFreePool(path); 2823143086Swpaul 2824124272Swpaul NDFREE(&nd, NDF_ONLY_PNBUF); 2825124272Swpaul 2826124272Swpaul /* Get the file size. */ 2827131953Swpaul VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td); 2828124272Swpaul VOP_UNLOCK(nd.ni_vp, 0, td); 2829124272Swpaul mtx_unlock(&Giant); 2830124272Swpaul 2831124272Swpaul fh->nf_vp = nd.ni_vp; 2832124272Swpaul fh->nf_map = NULL; 2833132973Swpaul fh->nf_type = NDIS_FH_TYPE_VFS; 2834124272Swpaul *filehandle = fh; 2835124272Swpaul *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; 2836124272Swpaul *status = NDIS_STATUS_SUCCESS; 2837131953Swpaul 2838123822Swpaul return; 2839123822Swpaul} 2840123822Swpaul 2841144888Swpaulstatic void 2842140751SwpaulNdisMapFile(status, mappedbuffer, filehandle) 2843123822Swpaul ndis_status *status; 2844123822Swpaul void **mappedbuffer; 2845123822Swpaul ndis_handle filehandle; 2846123822Swpaul{ 2847124272Swpaul ndis_fh *fh; 2848124272Swpaul struct thread *td = curthread; 2849133876Swpaul linker_file_t lf; 2850133876Swpaul caddr_t kldstart; 2851124272Swpaul int error, resid; 2852123822Swpaul 2853124272Swpaul if (filehandle == NULL) { 2854124272Swpaul *status = NDIS_STATUS_FAILURE; 2855124272Swpaul return; 2856124272Swpaul } 2857124272Swpaul 2858124272Swpaul fh = (ndis_fh *)filehandle; 2859124272Swpaul 2860124272Swpaul if (fh->nf_vp == NULL) { 2861124272Swpaul *status = NDIS_STATUS_FAILURE; 2862124272Swpaul return; 2863124272Swpaul } 2864124272Swpaul 2865124272Swpaul if (fh->nf_map != NULL) { 2866124272Swpaul *status = NDIS_STATUS_ALREADY_MAPPED; 2867124272Swpaul return; 2868124272Swpaul } 2869124272Swpaul 2870132973Swpaul if (fh->nf_type == NDIS_FH_TYPE_MODULE) { 2871133876Swpaul lf = fh->nf_vp; 2872133876Swpaul if (ndis_find_sym(lf, lf->filename, "_start", &kldstart)) { 2873133876Swpaul *status = NDIS_STATUS_FAILURE; 2874133876Swpaul return; 2875133876Swpaul } 2876133876Swpaul fh->nf_map = kldstart; 2877132973Swpaul *status = NDIS_STATUS_SUCCESS; 2878132973Swpaul *mappedbuffer = fh->nf_map; 2879132973Swpaul return; 2880132973Swpaul } 2881132973Swpaul 2882143086Swpaul fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0); 2883124272Swpaul 2884124272Swpaul if (fh->nf_map == NULL) { 2885124272Swpaul *status = NDIS_STATUS_RESOURCES; 2886124272Swpaul return; 2887124272Swpaul } 2888124272Swpaul 2889124272Swpaul mtx_lock(&Giant); 2890124272Swpaul error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0, 2891124272Swpaul UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); 2892124272Swpaul mtx_unlock(&Giant); 2893124272Swpaul 2894124272Swpaul if (error) 2895124272Swpaul *status = NDIS_STATUS_FAILURE; 2896124272Swpaul else { 2897124272Swpaul *status = NDIS_STATUS_SUCCESS; 2898124272Swpaul *mappedbuffer = fh->nf_map; 2899124272Swpaul } 2900124272Swpaul 2901123822Swpaul return; 2902123822Swpaul} 2903123822Swpaul 2904144888Swpaulstatic void 2905140751SwpaulNdisUnmapFile(filehandle) 2906123822Swpaul ndis_handle filehandle; 2907123822Swpaul{ 2908124272Swpaul ndis_fh *fh; 2909124272Swpaul fh = (ndis_fh *)filehandle; 2910124272Swpaul 2911124272Swpaul if (fh->nf_map == NULL) 2912124272Swpaul return; 2913132973Swpaul 2914132973Swpaul if (fh->nf_type == NDIS_FH_TYPE_VFS) 2915143086Swpaul ExFreePool(fh->nf_map); 2916124272Swpaul fh->nf_map = NULL; 2917124272Swpaul 2918123822Swpaul return; 2919123822Swpaul} 2920123822Swpaul 2921144888Swpaulstatic void 2922140751SwpaulNdisCloseFile(filehandle) 2923123822Swpaul ndis_handle filehandle; 2924123822Swpaul{ 2925124272Swpaul struct thread *td = curthread; 2926124272Swpaul ndis_fh *fh; 2927124272Swpaul 2928124272Swpaul if (filehandle == NULL) 2929124272Swpaul return; 2930124272Swpaul 2931124272Swpaul fh = (ndis_fh *)filehandle; 2932124272Swpaul if (fh->nf_map != NULL) { 2933132973Swpaul if (fh->nf_type == NDIS_FH_TYPE_VFS) 2934143086Swpaul ExFreePool(fh->nf_map); 2935124272Swpaul fh->nf_map = NULL; 2936124272Swpaul } 2937124272Swpaul 2938124272Swpaul if (fh->nf_vp == NULL) 2939124272Swpaul return; 2940124272Swpaul 2941132973Swpaul if (fh->nf_type == NDIS_FH_TYPE_VFS) { 2942132973Swpaul mtx_lock(&Giant); 2943132973Swpaul vn_close(fh->nf_vp, FREAD, td->td_ucred, td); 2944132973Swpaul mtx_unlock(&Giant); 2945132973Swpaul } 2946124272Swpaul 2947124272Swpaul fh->nf_vp = NULL; 2948143086Swpaul ExFreePool(fh); 2949124272Swpaul 2950123822Swpaul return; 2951123822Swpaul} 2952123822Swpaul 2953144888Swpaulstatic uint8_t 2954140751SwpaulNdisSystemProcessorCount() 2955123848Swpaul{ 2956123848Swpaul return(mp_ncpus); 2957124509Swpaul} 2958123848Swpaul 2959124116Swpaultypedef void (*ndis_statusdone_handler)(ndis_handle); 2960124116Swpaultypedef void (*ndis_status_handler)(ndis_handle, ndis_status, 2961124116Swpaul void *, uint32_t); 2962124116Swpaul 2963144888Swpaulstatic void 2964140751SwpaulNdisMIndicateStatusComplete(adapter) 2965124116Swpaul ndis_handle adapter; 2966124116Swpaul{ 2967124116Swpaul ndis_miniport_block *block; 2968144888Swpaul ndis_statusdone_handler statusdonefunc; 2969124116Swpaul 2970124116Swpaul block = (ndis_miniport_block *)adapter; 2971124116Swpaul statusdonefunc = block->nmb_statusdone_func; 2972124116Swpaul 2973141963Swpaul MSCALL1(statusdonefunc, adapter); 2974124116Swpaul return; 2975124116Swpaul} 2976124116Swpaul 2977144888Swpaulstatic void 2978140751SwpaulNdisMIndicateStatus(adapter, status, sbuf, slen) 2979124116Swpaul ndis_handle adapter; 2980124116Swpaul ndis_status status; 2981124116Swpaul void *sbuf; 2982124116Swpaul uint32_t slen; 2983124116Swpaul{ 2984124116Swpaul ndis_miniport_block *block; 2985144888Swpaul ndis_status_handler statusfunc; 2986124116Swpaul 2987124116Swpaul block = (ndis_miniport_block *)adapter; 2988124116Swpaul statusfunc = block->nmb_status_func; 2989124116Swpaul 2990141963Swpaul MSCALL4(statusfunc, adapter, status, sbuf, slen); 2991124116Swpaul return; 2992124116Swpaul} 2993124116Swpaul 2994124122Swpaulstatic void 2995124697Swpaulndis_workfunc(ctx) 2996124122Swpaul void *ctx; 2997124122Swpaul{ 2998124122Swpaul ndis_work_item *work; 2999144888Swpaul ndis_proc workfunc; 3000124122Swpaul 3001124122Swpaul work = ctx; 3002140827Swpaul workfunc = work->nwi_func; 3003141963Swpaul MSCALL2(workfunc, work, work->nwi_ctx); 3004124122Swpaul return; 3005124122Swpaul} 3006124122Swpaul 3007144888Swpaulstatic ndis_status 3008140751SwpaulNdisScheduleWorkItem(work) 3009124122Swpaul ndis_work_item *work; 3010124122Swpaul{ 3011124697Swpaul ndis_sched(ndis_workfunc, work, NDIS_TASKQUEUE); 3012124122Swpaul return(NDIS_STATUS_SUCCESS); 3013124122Swpaul} 3014124122Swpaul 3015144888Swpaulstatic void 3016140751SwpaulNdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen) 3017124541Swpaul ndis_packet *dpkt; 3018124541Swpaul uint32_t doff; 3019124541Swpaul uint32_t reqlen; 3020124541Swpaul ndis_packet *spkt; 3021124541Swpaul uint32_t soff; 3022124541Swpaul uint32_t *cpylen; 3023124541Swpaul{ 3024124541Swpaul ndis_buffer *src, *dst; 3025124541Swpaul char *sptr, *dptr; 3026124541Swpaul int resid, copied, len, scnt, dcnt; 3027124541Swpaul 3028124541Swpaul *cpylen = 0; 3029124541Swpaul 3030124541Swpaul src = spkt->np_private.npp_head; 3031124541Swpaul dst = dpkt->np_private.npp_head; 3032124541Swpaul 3033140751Swpaul sptr = MmGetMdlVirtualAddress(src); 3034140751Swpaul dptr = MmGetMdlVirtualAddress(dst); 3035140751Swpaul scnt = MmGetMdlByteCount(src); 3036140751Swpaul dcnt = MmGetMdlByteCount(dst); 3037124541Swpaul 3038124541Swpaul while (soff) { 3039140751Swpaul if (MmGetMdlByteCount(src) > soff) { 3040124541Swpaul sptr += soff; 3041140751Swpaul scnt = MmGetMdlByteCount(src)- soff; 3042124541Swpaul break; 3043124541Swpaul } 3044140751Swpaul soff -= MmGetMdlByteCount(src); 3045140751Swpaul src = src->mdl_next; 3046124541Swpaul if (src == NULL) 3047124541Swpaul return; 3048140751Swpaul sptr = MmGetMdlVirtualAddress(src); 3049124541Swpaul } 3050124541Swpaul 3051124541Swpaul while (doff) { 3052140751Swpaul if (MmGetMdlByteCount(dst) > doff) { 3053124541Swpaul dptr += doff; 3054140751Swpaul dcnt = MmGetMdlByteCount(dst) - doff; 3055124541Swpaul break; 3056124541Swpaul } 3057140751Swpaul doff -= MmGetMdlByteCount(dst); 3058140751Swpaul dst = dst->mdl_next; 3059124541Swpaul if (dst == NULL) 3060124541Swpaul return; 3061140751Swpaul dptr = MmGetMdlVirtualAddress(dst); 3062124541Swpaul } 3063124541Swpaul 3064124541Swpaul resid = reqlen; 3065124541Swpaul copied = 0; 3066124541Swpaul 3067124541Swpaul while(1) { 3068124541Swpaul if (resid < scnt) 3069124541Swpaul len = resid; 3070124541Swpaul else 3071124541Swpaul len = scnt; 3072124541Swpaul if (dcnt < len) 3073124541Swpaul len = dcnt; 3074124541Swpaul 3075124541Swpaul bcopy(sptr, dptr, len); 3076124541Swpaul 3077124541Swpaul copied += len; 3078124541Swpaul resid -= len; 3079124541Swpaul if (resid == 0) 3080124541Swpaul break; 3081124541Swpaul 3082124541Swpaul dcnt -= len; 3083124541Swpaul if (dcnt == 0) { 3084140751Swpaul dst = dst->mdl_next; 3085124541Swpaul if (dst == NULL) 3086124541Swpaul break; 3087140751Swpaul dptr = MmGetMdlVirtualAddress(dst); 3088140751Swpaul dcnt = MmGetMdlByteCount(dst); 3089124541Swpaul } 3090124541Swpaul 3091124541Swpaul scnt -= len; 3092124541Swpaul if (scnt == 0) { 3093140751Swpaul src = src->mdl_next; 3094124541Swpaul if (src == NULL) 3095124541Swpaul break; 3096140751Swpaul sptr = MmGetMdlVirtualAddress(src); 3097140751Swpaul scnt = MmGetMdlByteCount(src); 3098124541Swpaul } 3099124541Swpaul } 3100124541Swpaul 3101124541Swpaul *cpylen = copied; 3102124541Swpaul return; 3103124541Swpaul} 3104124541Swpaul 3105144888Swpaulstatic void 3106140751SwpaulNdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio) 3107124541Swpaul ndis_packet *dpkt; 3108124541Swpaul uint32_t doff; 3109124541Swpaul uint32_t reqlen; 3110124541Swpaul ndis_packet *spkt; 3111124541Swpaul uint32_t soff; 3112124541Swpaul uint32_t *cpylen; 3113124541Swpaul uint32_t prio; 3114124541Swpaul{ 3115140751Swpaul NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen); 3116124541Swpaul return; 3117124541Swpaul} 3118124541Swpaul 3119144888Swpaulstatic ndis_status 3120140751SwpaulNdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle) 3121125551Swpaul ndis_handle handle; 3122125057Swpaul ndis_unicode_string *devname; 3123125057Swpaul ndis_unicode_string *symname; 3124125551Swpaul driver_dispatch *majorfuncs[]; 3125125551Swpaul void **devobj; 3126125551Swpaul ndis_handle *devhandle; 3127125057Swpaul{ 3128125551Swpaul ndis_miniport_block *block; 3129125551Swpaul 3130125551Swpaul block = (ndis_miniport_block *)handle; 3131141524Swpaul *devobj = block->nmb_deviceobj; 3132125551Swpaul *devhandle = handle; 3133125551Swpaul 3134125057Swpaul return(NDIS_STATUS_SUCCESS); 3135125057Swpaul} 3136125057Swpaul 3137144888Swpaulstatic ndis_status 3138140751SwpaulNdisMDeregisterDevice(handle) 3139125551Swpaul ndis_handle handle; 3140125057Swpaul{ 3141125057Swpaul return(NDIS_STATUS_SUCCESS); 3142125057Swpaul} 3143125057Swpaul 3144144888Swpaulstatic ndis_status 3145140751SwpaulNdisMQueryAdapterInstanceName(name, handle) 3146125551Swpaul ndis_unicode_string *name; 3147125551Swpaul ndis_handle handle; 3148125551Swpaul{ 3149125551Swpaul ndis_miniport_block *block; 3150141524Swpaul device_t dev; 3151125057Swpaul 3152125551Swpaul block = (ndis_miniport_block *)handle; 3153141524Swpaul dev = block->nmb_physdeviceobj->do_devext; 3154141524Swpaul 3155125551Swpaul ndis_ascii_to_unicode(__DECONST(char *, 3156141524Swpaul device_get_nameunit(dev)), &name->us_buf); 3157141524Swpaul name->us_len = strlen(device_get_nameunit(dev)) * 2; 3158125551Swpaul 3159125551Swpaul return(NDIS_STATUS_SUCCESS); 3160125551Swpaul} 3161125551Swpaul 3162144888Swpaulstatic void 3163140751SwpaulNdisMRegisterUnloadHandler(handle, func) 3164125551Swpaul ndis_handle handle; 3165125551Swpaul void *func; 3166125551Swpaul{ 3167125551Swpaul return; 3168125551Swpaul} 3169125551Swpaul 3170144888Swpaulstatic void 3171123474Swpauldummy() 3172123474Swpaul{ 3173123474Swpaul printf ("NDIS dummy called...\n"); 3174123474Swpaul return; 3175123474Swpaul} 3176123474Swpaul 3177144888Swpaul/* 3178144888Swpaul * Note: a couple of entries in this table specify the 3179144888Swpaul * number of arguments as "foo + 1". These are routines 3180144888Swpaul * that accept a 64-bit argument, passed by value. On 3181144888Swpaul * x86, these arguments consume two longwords on the stack, 3182144888Swpaul * so we lie and say there's one additional argument so 3183144888Swpaul * that the wrapping routines will do the right thing. 3184144888Swpaul */ 3185144888Swpaul 3186123474Swpaulimage_patch_table ndis_functbl[] = { 3187144888Swpaul IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6), 3188144888Swpaul IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7), 3189144888Swpaul IMPORT_SFUNC(NdisScheduleWorkItem, 1), 3190144888Swpaul IMPORT_SFUNC(NdisMIndicateStatusComplete, 1), 3191144888Swpaul IMPORT_SFUNC(NdisMIndicateStatus, 4), 3192144888Swpaul IMPORT_SFUNC(NdisSystemProcessorCount, 0), 3193144888Swpaul IMPORT_SFUNC(NdisUnchainBufferAtBack, 2), 3194144888Swpaul IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5), 3195144888Swpaul IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6), 3196144888Swpaul IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2), 3197144888Swpaul IMPORT_SFUNC(NdisMGetDeviceProperty, 6), 3198144888Swpaul IMPORT_SFUNC(NdisInitAnsiString, 2), 3199144888Swpaul IMPORT_SFUNC(NdisInitUnicodeString, 2), 3200144888Swpaul IMPORT_SFUNC(NdisWriteConfiguration, 4), 3201144888Swpaul IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2), 3202144888Swpaul IMPORT_SFUNC(NdisTerminateWrapper, 2), 3203144888Swpaul IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4), 3204144888Swpaul IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5), 3205144888Swpaul IMPORT_SFUNC(NdisMRemoveMiniport, 1), 3206144888Swpaul IMPORT_SFUNC(NdisInitializeString, 2), 3207144888Swpaul IMPORT_SFUNC(NdisFreeString, 1), 3208144888Swpaul IMPORT_SFUNC(NdisGetCurrentSystemTime, 1), 3209144888Swpaul IMPORT_SFUNC(NdisGetSystemUpTime, 1), 3210144888Swpaul IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3), 3211144888Swpaul IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4), 3212144888Swpaul IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3), 3213144888Swpaul IMPORT_SFUNC(NdisInterlockedInsertTailList, 3), 3214144888Swpaul IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2), 3215144888Swpaul IMPORT_SFUNC(NdisInitializeWrapper, 4), 3216144888Swpaul IMPORT_SFUNC(NdisMRegisterMiniport, 3), 3217144888Swpaul IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3), 3218144888Swpaul IMPORT_SFUNC(NdisAllocateMemory, 4 + 1), 3219144888Swpaul IMPORT_SFUNC(NdisMSetAttributesEx, 5), 3220144888Swpaul IMPORT_SFUNC(NdisCloseConfiguration, 1), 3221144888Swpaul IMPORT_SFUNC(NdisReadConfiguration, 5), 3222144888Swpaul IMPORT_SFUNC(NdisOpenConfiguration, 3), 3223144888Swpaul IMPORT_SFUNC(NdisAcquireSpinLock, 1), 3224144888Swpaul IMPORT_SFUNC(NdisReleaseSpinLock, 1), 3225144888Swpaul IMPORT_SFUNC(NdisDprAcquireSpinLock, 1), 3226144888Swpaul IMPORT_SFUNC(NdisDprReleaseSpinLock, 1), 3227144888Swpaul IMPORT_SFUNC(NdisAllocateSpinLock, 1), 3228144888Swpaul IMPORT_SFUNC(NdisFreeSpinLock, 1), 3229144888Swpaul IMPORT_SFUNC(NdisFreeMemory, 3), 3230144888Swpaul IMPORT_SFUNC(NdisReadPciSlotInformation, 5), 3231144888Swpaul IMPORT_SFUNC(NdisWritePciSlotInformation, 5), 3232144888Swpaul IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation, 3233144888Swpaul NdisReadPciSlotInformation, 5), 3234144888Swpaul IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation, 3235144888Swpaul NdisWritePciSlotInformation, 5), 3236144888Swpaul IMPORT_CFUNC(NdisWriteErrorLogEntry, 0), 3237144888Swpaul IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6), 3238144888Swpaul IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3), 3239144888Swpaul IMPORT_SFUNC(NdisMInitializeTimer, 4), 3240144888Swpaul IMPORT_SFUNC(NdisInitializeTimer, 3), 3241144888Swpaul IMPORT_SFUNC(NdisSetTimer, 2), 3242144888Swpaul IMPORT_SFUNC(NdisMCancelTimer, 2), 3243144888Swpaul IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2), 3244144888Swpaul IMPORT_SFUNC(NdisMSetPeriodicTimer, 2), 3245144888Swpaul IMPORT_SFUNC(NdisMQueryAdapterResources, 4), 3246144888Swpaul IMPORT_SFUNC(NdisMRegisterIoPortRange, 4), 3247144888Swpaul IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4), 3248144888Swpaul IMPORT_SFUNC(NdisReadNetworkAddress, 4), 3249144888Swpaul IMPORT_SFUNC(NdisQueryMapRegisterCount, 2), 3250144888Swpaul IMPORT_SFUNC(NdisMAllocateMapRegisters, 5), 3251144888Swpaul IMPORT_SFUNC(NdisMFreeMapRegisters, 1), 3252144888Swpaul IMPORT_SFUNC(NdisMAllocateSharedMemory, 5), 3253144888Swpaul IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1), 3254144888Swpaul IMPORT_SFUNC(NdisMUnmapIoSpace, 3), 3255144888Swpaul IMPORT_SFUNC(NdisGetCacheFillSize, 0), 3256144888Swpaul IMPORT_SFUNC(NdisMGetDmaAlignment, 1), 3257144888Swpaul IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3), 3258144888Swpaul IMPORT_SFUNC(NdisAllocatePacketPool, 4), 3259144888Swpaul IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5), 3260144888Swpaul IMPORT_SFUNC(NdisAllocatePacket, 3), 3261144888Swpaul IMPORT_SFUNC(NdisFreePacket, 1), 3262144888Swpaul IMPORT_SFUNC(NdisFreePacketPool, 1), 3263144888Swpaul IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3), 3264144888Swpaul IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1), 3265144888Swpaul IMPORT_SFUNC(NdisAllocateBufferPool, 3), 3266144888Swpaul IMPORT_SFUNC(NdisAllocateBuffer, 5), 3267144888Swpaul IMPORT_SFUNC(NdisQueryBuffer, 3), 3268144888Swpaul IMPORT_SFUNC(NdisQueryBufferSafe, 4), 3269144888Swpaul IMPORT_SFUNC(NdisBufferVirtualAddress, 1), 3270144888Swpaul IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2), 3271144888Swpaul IMPORT_SFUNC(NdisBufferLength, 1), 3272144888Swpaul IMPORT_SFUNC(NdisFreeBuffer, 1), 3273144888Swpaul IMPORT_SFUNC(NdisFreeBufferPool, 1), 3274144888Swpaul IMPORT_SFUNC(NdisInterlockedIncrement, 1), 3275144888Swpaul IMPORT_SFUNC(NdisInterlockedDecrement, 1), 3276144888Swpaul IMPORT_SFUNC(NdisInitializeEvent, 1), 3277144888Swpaul IMPORT_SFUNC(NdisSetEvent, 1), 3278144888Swpaul IMPORT_SFUNC(NdisResetEvent, 1), 3279144888Swpaul IMPORT_SFUNC(NdisWaitEvent, 2), 3280144888Swpaul IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2), 3281144888Swpaul IMPORT_SFUNC(NdisMPciAssignResources, 3), 3282144888Swpaul IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1), 3283144888Swpaul IMPORT_SFUNC(NdisMRegisterInterrupt, 7), 3284144888Swpaul IMPORT_SFUNC(NdisMDeregisterInterrupt, 1), 3285144888Swpaul IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3), 3286144888Swpaul IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1), 3287144888Swpaul IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1), 3288144888Swpaul IMPORT_SFUNC(NdisQueryBufferOffset, 3), 3289144888Swpaul IMPORT_SFUNC(NdisAdjustBufferLength, 2), 3290144888Swpaul IMPORT_SFUNC(NdisPacketPoolUsage, 1), 3291144888Swpaul IMPORT_SFUNC(NdisMSleep, 1), 3292144888Swpaul IMPORT_SFUNC(NdisUnchainBufferAtFront, 2), 3293144888Swpaul IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4), 3294144888Swpaul IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4), 3295144888Swpaul IMPORT_SFUNC(NdisOpenFile, 5 + 1), 3296144888Swpaul IMPORT_SFUNC(NdisMapFile, 3), 3297144888Swpaul IMPORT_SFUNC(NdisUnmapFile, 1), 3298144888Swpaul IMPORT_SFUNC(NdisCloseFile, 1), 3299144888Swpaul IMPORT_SFUNC(NdisMRegisterDevice, 6), 3300144888Swpaul IMPORT_SFUNC(NdisMDeregisterDevice, 1), 3301144888Swpaul IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2), 3302144888Swpaul IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2), 3303144888Swpaul IMPORT_SFUNC(ndis_timercall, 4), 3304123474Swpaul 3305123474Swpaul /* 3306123474Swpaul * This last entry is a catch-all for any function we haven't 3307123474Swpaul * implemented yet. The PE import list patching routine will 3308123474Swpaul * use it for any function that doesn't have an explicit match 3309123474Swpaul * in this table. 3310123474Swpaul */ 3311123474Swpaul 3312144888Swpaul { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_CDECL }, 3313123474Swpaul 3314123474Swpaul /* End of list. */ 3315123474Swpaul 3316141963Swpaul { NULL, NULL, NULL } 3317123474Swpaul}; 3318