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