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$");
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.h>
86123474Swpaul#include <machine/resource.h>
87123474Swpaul
88123474Swpaul#include <sys/bus.h>
89123474Swpaul#include <sys/rman.h>
90123474Swpaul
91123474Swpaul#include <machine/stdarg.h>
92123474Swpaul
93123695Swpaul#include <net80211/ieee80211_var.h>
94123695Swpaul#include <net80211/ieee80211_ioctl.h>
95123695Swpaul
96123474Swpaul#include <dev/pci/pcireg.h>
97123474Swpaul#include <dev/pci/pcivar.h>
98189488Sweongyo#include <dev/usb/usb.h>
99194677Sthompsa#include <dev/usb/usbdi.h>
100123474Swpaul
101123474Swpaul#include <compat/ndis/pe_var.h>
102145485Swpaul#include <compat/ndis/cfg_var.h>
103123474Swpaul#include <compat/ndis/resource_var.h>
104123512Swpaul#include <compat/ndis/ntoskrnl_var.h>
105128229Swpaul#include <compat/ndis/hal_var.h>
106123474Swpaul#include <compat/ndis/ndis_var.h>
107123474Swpaul#include <dev/if_ndis/if_ndisvar.h>
108123474Swpaul
109151207Swpaul#include <vm/vm.h>
110151207Swpaul#include <vm/vm_param.h>
111151207Swpaul#include <vm/pmap.h>
112151207Swpaul#include <vm/uma.h>
113151207Swpaul#include <vm/vm_kern.h>
114151207Swpaul#include <vm/vm_map.h>
115151207Swpaul
116124272Swpaulstatic char ndis_filepath[MAXPATHLEN];
117123474Swpaul
118124272SwpaulSYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
119189488Sweongyo    MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
120124272Swpaul
121144888Swpaulstatic void NdisInitializeWrapper(ndis_handle *,
122141524Swpaul	driver_object *, void *, void *);
123144888Swpaulstatic ndis_status NdisMRegisterMiniport(ndis_handle,
124123474Swpaul	ndis_miniport_characteristics *, int);
125144888Swpaulstatic ndis_status NdisAllocateMemoryWithTag(void **,
126140751Swpaul	uint32_t, uint32_t);
127144888Swpaulstatic ndis_status NdisAllocateMemory(void **,
128123474Swpaul	uint32_t, uint32_t, ndis_physaddr);
129144888Swpaulstatic void NdisFreeMemory(void *, uint32_t, uint32_t);
130144888Swpaulstatic ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle,
131123474Swpaul	uint32_t, uint32_t, ndis_interface_type);
132144888Swpaulstatic void NdisOpenConfiguration(ndis_status *,
133140751Swpaul	ndis_handle *, ndis_handle);
134144888Swpaulstatic void NdisOpenConfigurationKeyByIndex(ndis_status *,
135151207Swpaul	ndis_handle, uint32_t, unicode_string *, ndis_handle *);
136144888Swpaulstatic void NdisOpenConfigurationKeyByName(ndis_status *,
137151207Swpaul	ndis_handle, unicode_string *, ndis_handle *);
138123474Swpaulstatic ndis_status ndis_encode_parm(ndis_miniport_block *,
139123474Swpaul	struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
140123526Swpaulstatic ndis_status ndis_decode_parm(ndis_miniport_block *,
141123526Swpaul	ndis_config_parm *, char *);
142144888Swpaulstatic void NdisReadConfiguration(ndis_status *, ndis_config_parm **,
143151207Swpaul	ndis_handle, unicode_string *, ndis_parm_type);
144144888Swpaulstatic void NdisWriteConfiguration(ndis_status *, ndis_handle,
145151207Swpaul	unicode_string *, ndis_config_parm *);
146144888Swpaulstatic void NdisCloseConfiguration(ndis_handle);
147144888Swpaulstatic void NdisAllocateSpinLock(ndis_spin_lock *);
148144888Swpaulstatic void NdisFreeSpinLock(ndis_spin_lock *);
149144888Swpaulstatic void NdisAcquireSpinLock(ndis_spin_lock *);
150144888Swpaulstatic void NdisReleaseSpinLock(ndis_spin_lock *);
151144888Swpaulstatic void NdisDprAcquireSpinLock(ndis_spin_lock *);
152144888Swpaulstatic void NdisDprReleaseSpinLock(ndis_spin_lock *);
153145895Swpaulstatic void NdisInitializeReadWriteLock(ndis_rw_lock *);
154145895Swpaulstatic void NdisAcquireReadWriteLock(ndis_rw_lock *,
155145895Swpaul	uint8_t, ndis_lock_state *);
156145895Swpaulstatic void NdisReleaseReadWriteLock(ndis_rw_lock *, ndis_lock_state *);
157144888Swpaulstatic uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t,
158123474Swpaul	uint32_t, void *, uint32_t);
159144888Swpaulstatic uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t,
160123474Swpaul	uint32_t, void *, uint32_t);
161140751Swpaulstatic void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...);
162123474Swpaulstatic void ndis_map_cb(void *, bus_dma_segment_t *, int, int);
163144888Swpaulstatic void NdisMStartBufferPhysicalMapping(ndis_handle,
164140751Swpaul	ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *);
165144888Swpaulstatic void NdisMCompleteBufferPhysicalMapping(ndis_handle,
166140751Swpaul	ndis_buffer *, uint32_t);
167144888Swpaulstatic void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle,
168123474Swpaul	ndis_timer_function, void *);
169144888Swpaulstatic void NdisInitializeTimer(ndis_timer *,
170125057Swpaul	ndis_timer_function, void *);
171144888Swpaulstatic void NdisSetTimer(ndis_timer *, uint32_t);
172144888Swpaulstatic void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t);
173144888Swpaulstatic void NdisMCancelTimer(ndis_timer *, uint8_t *);
174144888Swpaulstatic void ndis_timercall(kdpc *, ndis_miniport_timer *,
175144174Swpaul	void *, void *);
176144888Swpaulstatic void NdisMQueryAdapterResources(ndis_status *, ndis_handle,
177123474Swpaul	ndis_resource_list *, uint32_t *);
178144888Swpaulstatic ndis_status NdisMRegisterIoPortRange(void **,
179123474Swpaul	ndis_handle, uint32_t, uint32_t);
180144888Swpaulstatic void NdisMDeregisterIoPortRange(ndis_handle,
181123474Swpaul	uint32_t, uint32_t, void *);
182144888Swpaulstatic void NdisReadNetworkAddress(ndis_status *, void **,
183123474Swpaul	uint32_t *, ndis_handle);
184144888Swpaulstatic ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *);
185144888Swpaulstatic ndis_status NdisMAllocateMapRegisters(ndis_handle,
186123474Swpaul	uint32_t, uint8_t, uint32_t, uint32_t);
187144888Swpaulstatic void NdisMFreeMapRegisters(ndis_handle);
188123474Swpaulstatic void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int);
189144888Swpaulstatic void NdisMAllocateSharedMemory(ndis_handle, uint32_t,
190123474Swpaul	uint8_t, void **, ndis_physaddr *);
191145895Swpaulstatic void ndis_asyncmem_complete(device_object *, void *);
192144888Swpaulstatic ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle,
193123474Swpaul	uint32_t, uint8_t, void *);
194144888Swpaulstatic void NdisMFreeSharedMemory(ndis_handle, uint32_t,
195123474Swpaul	uint8_t, void *, ndis_physaddr);
196144888Swpaulstatic ndis_status NdisMMapIoSpace(void **, ndis_handle,
197123474Swpaul	ndis_physaddr, uint32_t);
198144888Swpaulstatic void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t);
199144888Swpaulstatic uint32_t NdisGetCacheFillSize(void);
200216242Sbschmidtstatic void *NdisGetRoutineAddress(unicode_string *);
201144888Swpaulstatic uint32_t NdisMGetDmaAlignment(ndis_handle);
202144888Swpaulstatic ndis_status NdisMInitializeScatterGatherDma(ndis_handle,
203123474Swpaul	uint8_t, uint32_t);
204144888Swpaulstatic void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **);
205144888Swpaulstatic void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **);
206144888Swpaulstatic void NdisAllocateBufferPool(ndis_status *,
207123474Swpaul	ndis_handle *, uint32_t);
208144888Swpaulstatic void NdisFreeBufferPool(ndis_handle);
209144888Swpaulstatic void NdisAllocateBuffer(ndis_status *, ndis_buffer **,
210123474Swpaul	ndis_handle, void *, uint32_t);
211144888Swpaulstatic void NdisFreeBuffer(ndis_buffer *);
212144888Swpaulstatic uint32_t NdisBufferLength(ndis_buffer *);
213144888Swpaulstatic void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *);
214144888Swpaulstatic void NdisQueryBufferSafe(ndis_buffer *, void **,
215123474Swpaul	uint32_t *, uint32_t);
216144888Swpaulstatic void *NdisBufferVirtualAddress(ndis_buffer *);
217144888Swpaulstatic void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t);
218144888Swpaulstatic void NdisAdjustBufferLength(ndis_buffer *, int);
219144888Swpaulstatic uint32_t NdisInterlockedIncrement(uint32_t *);
220144888Swpaulstatic uint32_t NdisInterlockedDecrement(uint32_t *);
221144888Swpaulstatic void NdisInitializeEvent(ndis_event *);
222144888Swpaulstatic void NdisSetEvent(ndis_event *);
223144888Swpaulstatic void NdisResetEvent(ndis_event *);
224144888Swpaulstatic uint8_t NdisWaitEvent(ndis_event *, uint32_t);
225151207Swpaulstatic ndis_status NdisUnicodeStringToAnsiString(ansi_string *,
226151207Swpaul	unicode_string *);
227144888Swpaulstatic ndis_status
228151207Swpaul	NdisAnsiStringToUnicodeString(unicode_string *, ansi_string *);
229144888Swpaulstatic ndis_status NdisMPciAssignResources(ndis_handle,
230123474Swpaul	uint32_t, ndis_resource_list **);
231144888Swpaulstatic ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *,
232123474Swpaul	ndis_handle, uint32_t, uint32_t, uint8_t,
233123474Swpaul	uint8_t, ndis_interrupt_mode);
234144888Swpaulstatic void NdisMDeregisterInterrupt(ndis_miniport_interrupt *);
235144888Swpaulstatic void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *,
236123474Swpaul	ndis_shutdown_handler);
237144888Swpaulstatic void NdisMDeregisterAdapterShutdownHandler(ndis_handle);
238144888Swpaulstatic uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *);
239144888Swpaulstatic void NdisGetBufferPhysicalArraySize(ndis_buffer *,
240140751Swpaul	uint32_t *);
241144888Swpaulstatic void NdisQueryBufferOffset(ndis_buffer *,
242123474Swpaul	uint32_t *, uint32_t *);
243144888Swpaulstatic uint32_t NdisReadPcmciaAttributeMemory(ndis_handle,
244123474Swpaul	uint32_t, void *, uint32_t);
245144888Swpaulstatic uint32_t NdisWritePcmciaAttributeMemory(ndis_handle,
246123474Swpaul	uint32_t, void *, uint32_t);
247144888Swpaulstatic list_entry *NdisInterlockedInsertHeadList(list_entry *,
248125551Swpaul	list_entry *, ndis_spin_lock *);
249144888Swpaulstatic list_entry *NdisInterlockedRemoveHeadList(list_entry *,
250123474Swpaul	ndis_spin_lock *);
251144888Swpaulstatic list_entry *NdisInterlockedInsertTailList(list_entry *,
252125551Swpaul	list_entry *, ndis_spin_lock *);
253144888Swpaulstatic uint8_t
254140751Swpaul	NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *,
255123474Swpaul	void *, void *);
256144888Swpaulstatic void NdisGetCurrentSystemTime(uint64_t *);
257144888Swpaulstatic void NdisGetSystemUpTime(uint32_t *);
258215779Sbschmidtstatic uint32_t NdisGetVersion(void);
259151207Swpaulstatic void NdisInitializeString(unicode_string *, char *);
260151207Swpaulstatic void NdisInitAnsiString(ansi_string *, char *);
261151207Swpaulstatic void NdisInitUnicodeString(unicode_string *, uint16_t *);
262151207Swpaulstatic void NdisFreeString(unicode_string *);
263144888Swpaulstatic ndis_status NdisMRemoveMiniport(ndis_handle *);
264144888Swpaulstatic void NdisTerminateWrapper(ndis_handle, void *);
265144888Swpaulstatic void NdisMGetDeviceProperty(ndis_handle, device_object **,
266125551Swpaul	device_object **, device_object **, cm_resource_list *,
267125551Swpaul	cm_resource_list *);
268144888Swpaulstatic void NdisGetFirstBufferFromPacket(ndis_packet *,
269140751Swpaul	ndis_buffer **, void **, uint32_t *, uint32_t *);
270144888Swpaulstatic void NdisGetFirstBufferFromPacketSafe(ndis_packet *,
271140751Swpaul	ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t);
272132973Swpaulstatic int ndis_find_sym(linker_file_t, char *, char *, caddr_t *);
273144888Swpaulstatic void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *,
274151207Swpaul	unicode_string *, ndis_physaddr);
275144888Swpaulstatic void NdisMapFile(ndis_status *, void **, ndis_handle);
276144888Swpaulstatic void NdisUnmapFile(ndis_handle);
277144888Swpaulstatic void NdisCloseFile(ndis_handle);
278144888Swpaulstatic uint8_t NdisSystemProcessorCount(void);
279215779Sbschmidtstatic void NdisGetCurrentProcessorCounts(uint32_t *, uint32_t *, uint32_t *);
280144888Swpaulstatic void NdisMIndicateStatusComplete(ndis_handle);
281144888Swpaulstatic void NdisMIndicateStatus(ndis_handle, ndis_status,
282189488Sweongyo    void *, uint32_t);
283152626Swpaulstatic uint8_t ndis_intr(kinterrupt *, void *);
284151207Swpaulstatic void ndis_intrhand(kdpc *, ndis_miniport_interrupt *, void *, void *);
285144402Swpaulstatic funcptr ndis_findwrap(funcptr);
286144888Swpaulstatic void NdisCopyFromPacketToPacket(ndis_packet *,
287140751Swpaul	uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *);
288144888Swpaulstatic void NdisCopyFromPacketToPacketSafe(ndis_packet *,
289140751Swpaul	uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t);
290174240Sthompsastatic void NdisIMCopySendPerPacketInfo(ndis_packet *, ndis_packet *);
291144888Swpaulstatic ndis_status NdisMRegisterDevice(ndis_handle,
292151207Swpaul	unicode_string *, unicode_string *, driver_dispatch **,
293125551Swpaul	void **, ndis_handle *);
294144888Swpaulstatic ndis_status NdisMDeregisterDevice(ndis_handle);
295144888Swpaulstatic ndis_status
296151207Swpaul	NdisMQueryAdapterInstanceName(unicode_string *, ndis_handle);
297144888Swpaulstatic void NdisMRegisterUnloadHandler(ndis_handle, void *);
298144888Swpaulstatic void dummy(void);
299123474Swpaul
300124116Swpaul/*
301124116Swpaul * Some really old drivers do not properly check the return value
302124116Swpaul * from NdisAllocatePacket() and NdisAllocateBuffer() and will
303124116Swpaul * sometimes allocate few more buffers/packets that they originally
304124116Swpaul * requested when they created the pool. To prevent this from being
305124116Swpaul * a problem, we allocate a few extra buffers/packets beyond what
306124116Swpaul * the driver asks for. This #define controls how many.
307124116Swpaul */
308124116Swpaul#define NDIS_POOL_EXTRA		16
309123474Swpaul
310123474Swpaulint
311123474Swpaulndis_libinit()
312123474Swpaul{
313141963Swpaul	image_patch_table	*patch;
314141963Swpaul
315124272Swpaul	strcpy(ndis_filepath, "/compat/ndis");
316141963Swpaul
317141963Swpaul	patch = ndis_functbl;
318141963Swpaul	while (patch->ipt_func != NULL) {
319141963Swpaul		windrv_wrap((funcptr)patch->ipt_func,
320144888Swpaul		    (funcptr *)&patch->ipt_wrap,
321144888Swpaul		    patch->ipt_argcnt, patch->ipt_ftype);
322141963Swpaul		patch++;
323141963Swpaul	}
324141963Swpaul
325198786Srpaulo	return (0);
326123474Swpaul}
327123474Swpaul
328123474Swpaulint
329123474Swpaulndis_libfini()
330123474Swpaul{
331141963Swpaul	image_patch_table	*patch;
332141963Swpaul
333141963Swpaul	patch = ndis_functbl;
334141963Swpaul	while (patch->ipt_func != NULL) {
335141963Swpaul		windrv_unwrap(patch->ipt_wrap);
336141963Swpaul		patch++;
337141963Swpaul	}
338141963Swpaul
339198786Srpaulo	return (0);
340123474Swpaul}
341123474Swpaul
342144402Swpaulstatic funcptr
343144402Swpaulndis_findwrap(func)
344144402Swpaul	funcptr			func;
345144402Swpaul{
346144402Swpaul	image_patch_table	*patch;
347144402Swpaul
348144428Swpaul	patch = ndis_functbl;
349144402Swpaul	while (patch->ipt_func != NULL) {
350144402Swpaul		if ((funcptr)patch->ipt_func == func)
351198786Srpaulo			return ((funcptr)patch->ipt_wrap);
352144402Swpaul		patch++;
353144402Swpaul	}
354144402Swpaul
355198786Srpaulo	return (NULL);
356144402Swpaul}
357144402Swpaul
358123474Swpaul/*
359141524Swpaul * This routine does the messy Windows Driver Model device attachment
360141524Swpaul * stuff on behalf of NDIS drivers. We register our own AddDevice
361141524Swpaul * routine here
362141524Swpaul */
363144888Swpaulstatic void
364141524SwpaulNdisInitializeWrapper(wrapper, drv, path, unused)
365125551Swpaul	ndis_handle		*wrapper;
366141524Swpaul	driver_object		*drv;
367123474Swpaul	void			*path;
368123474Swpaul	void			*unused;
369123474Swpaul{
370141524Swpaul	/*
371141524Swpaul	 * As of yet, I haven't come up with a compelling
372141524Swpaul	 * reason to define a private NDIS wrapper structure,
373141524Swpaul	 * so we use a pointer to the driver object as the
374141524Swpaul	 * wrapper handle. The driver object has the miniport
375141524Swpaul	 * characteristics struct for this driver hung off it
376141524Swpaul	 * via IoAllocateDriverObjectExtension(), and that's
377141524Swpaul	 * really all the private data we need.
378141524Swpaul	 */
379123474Swpaul
380141524Swpaul	*wrapper = drv;
381123474Swpaul
382141524Swpaul	/*
383141524Swpaul	 * If this was really Windows, we'd be registering dispatch
384141524Swpaul	 * routines for the NDIS miniport module here, but we're
385141524Swpaul	 * not Windows so all we really need to do is set up an
386141524Swpaul	 * AddDevice function that'll be invoked when a new device
387141524Swpaul	 * instance appears.
388141524Swpaul	 */
389141524Swpaul
390141524Swpaul	drv->dro_driverext->dre_adddevicefunc = NdisAddDevice;
391123474Swpaul}
392123474Swpaul
393144888Swpaulstatic void
394140751SwpaulNdisTerminateWrapper(handle, syspec)
395123526Swpaul	ndis_handle		handle;
396123526Swpaul	void			*syspec;
397123526Swpaul{
398141524Swpaul	/* Nothing to see here, move along. */
399123526Swpaul}
400123526Swpaul
401144888Swpaulstatic ndis_status
402140751SwpaulNdisMRegisterMiniport(handle, characteristics, len)
403123474Swpaul	ndis_handle		handle;
404123474Swpaul	ndis_miniport_characteristics *characteristics;
405123474Swpaul	int			len;
406123474Swpaul{
407141524Swpaul	ndis_miniport_characteristics	*ch = NULL;
408141524Swpaul	driver_object		*drv;
409123474Swpaul
410141524Swpaul	drv = (driver_object *)handle;
411141524Swpaul
412141524Swpaul	/*
413141524Swpaul	 * We need to save the NDIS miniport characteristics
414141524Swpaul	 * somewhere. This data is per-driver, not per-device
415141524Swpaul	 * (all devices handled by the same driver have the
416141524Swpaul	 * same characteristics) so we hook it onto the driver
417141524Swpaul	 * object using IoAllocateDriverObjectExtension().
418141524Swpaul	 * The extra extension info is automagically deleted when
419141524Swpaul	 * the driver is unloaded (see windrv_unload()).
420141524Swpaul	 */
421141524Swpaul
422141524Swpaul	if (IoAllocateDriverObjectExtension(drv, (void *)1,
423141524Swpaul	    sizeof(ndis_miniport_characteristics), (void **)&ch) !=
424151207Swpaul	    STATUS_SUCCESS) {
425198786Srpaulo		return (NDIS_STATUS_RESOURCES);
426151207Swpaul	}
427141524Swpaul
428141524Swpaul	bzero((char *)ch, sizeof(ndis_miniport_characteristics));
429141524Swpaul
430141524Swpaul	bcopy((char *)characteristics, (char *)ch, len);
431141524Swpaul
432141524Swpaul	if (ch->nmc_version_major < 5 || ch->nmc_version_minor < 1) {
433141524Swpaul		ch->nmc_shutdown_handler = NULL;
434141524Swpaul		ch->nmc_canceltxpkts_handler = NULL;
435141524Swpaul		ch->nmc_pnpevent_handler = NULL;
436125551Swpaul	}
437125551Swpaul
438198786Srpaulo	return (NDIS_STATUS_SUCCESS);
439123474Swpaul}
440123474Swpaul
441144888Swpaulstatic ndis_status
442140751SwpaulNdisAllocateMemoryWithTag(vaddr, len, tag)
443123474Swpaul	void			**vaddr;
444123474Swpaul	uint32_t		len;
445123474Swpaul	uint32_t		tag;
446123474Swpaul{
447123474Swpaul	void			*mem;
448123474Swpaul
449141524Swpaul	mem = ExAllocatePoolWithTag(NonPagedPool, len, tag);
450151207Swpaul	if (mem == NULL) {
451198786Srpaulo		return (NDIS_STATUS_RESOURCES);
452151207Swpaul	}
453123474Swpaul	*vaddr = mem;
454123474Swpaul
455198786Srpaulo	return (NDIS_STATUS_SUCCESS);
456123474Swpaul}
457123474Swpaul
458144888Swpaulstatic ndis_status
459140751SwpaulNdisAllocateMemory(vaddr, len, flags, highaddr)
460123474Swpaul	void			**vaddr;
461123474Swpaul	uint32_t		len;
462123474Swpaul	uint32_t		flags;
463123474Swpaul	ndis_physaddr		highaddr;
464123474Swpaul{
465123474Swpaul	void			*mem;
466123474Swpaul
467141524Swpaul	mem = ExAllocatePoolWithTag(NonPagedPool, len, 0);
468123474Swpaul	if (mem == NULL)
469198786Srpaulo		return (NDIS_STATUS_RESOURCES);
470123474Swpaul	*vaddr = mem;
471123474Swpaul
472198786Srpaulo	return (NDIS_STATUS_SUCCESS);
473123474Swpaul}
474123474Swpaul
475144888Swpaulstatic void
476140751SwpaulNdisFreeMemory(vaddr, len, flags)
477123474Swpaul	void			*vaddr;
478123474Swpaul	uint32_t		len;
479123474Swpaul	uint32_t		flags;
480123474Swpaul{
481123474Swpaul	if (len == 0)
482123474Swpaul		return;
483125551Swpaul
484141524Swpaul	ExFreePool(vaddr);
485123474Swpaul}
486123474Swpaul
487144888Swpaulstatic ndis_status
488140751SwpaulNdisMSetAttributesEx(adapter_handle, adapter_ctx, hangsecs,
489123474Swpaul			flags, iftype)
490123474Swpaul	ndis_handle			adapter_handle;
491123474Swpaul	ndis_handle			adapter_ctx;
492123474Swpaul	uint32_t			hangsecs;
493123474Swpaul	uint32_t			flags;
494123474Swpaul	ndis_interface_type		iftype;
495123474Swpaul{
496123474Swpaul	ndis_miniport_block		*block;
497123474Swpaul
498123474Swpaul	/*
499123474Swpaul	 * Save the adapter context, we need it for calling
500123474Swpaul	 * the driver's internal functions.
501123474Swpaul	 */
502123474Swpaul	block = (ndis_miniport_block *)adapter_handle;
503123474Swpaul	block->nmb_miniportadapterctx = adapter_ctx;
504123474Swpaul	block->nmb_checkforhangsecs = hangsecs;
505126833Swpaul	block->nmb_flags = flags;
506123474Swpaul
507198786Srpaulo	return (NDIS_STATUS_SUCCESS);
508123474Swpaul}
509123474Swpaul
510144888Swpaulstatic void
511140751SwpaulNdisOpenConfiguration(status, cfg, wrapctx)
512123474Swpaul	ndis_status		*status;
513123474Swpaul	ndis_handle		*cfg;
514123474Swpaul	ndis_handle		wrapctx;
515123474Swpaul{
516123474Swpaul	*cfg = wrapctx;
517123474Swpaul	*status = NDIS_STATUS_SUCCESS;
518123474Swpaul}
519123474Swpaul
520144888Swpaulstatic void
521140751SwpaulNdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle)
522123526Swpaul	ndis_status		*status;
523123526Swpaul	ndis_handle		cfg;
524151207Swpaul	unicode_string		*subkey;
525123526Swpaul	ndis_handle		*subhandle;
526123526Swpaul{
527123526Swpaul	*subhandle = cfg;
528123526Swpaul	*status = NDIS_STATUS_SUCCESS;
529123526Swpaul}
530123526Swpaul
531144888Swpaulstatic void
532140751SwpaulNdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle)
533123526Swpaul	ndis_status		*status;
534123526Swpaul	ndis_handle		cfg;
535123526Swpaul	uint32_t		idx;
536151207Swpaul	unicode_string		*subkey;
537123526Swpaul	ndis_handle		*subhandle;
538123526Swpaul{
539123526Swpaul	*status = NDIS_STATUS_FAILURE;
540123526Swpaul}
541123526Swpaul
542123474Swpaulstatic ndis_status
543123474Swpaulndis_encode_parm(block, oid, type, parm)
544123474Swpaul	ndis_miniport_block	*block;
545189488Sweongyo	struct sysctl_oid	*oid;
546123474Swpaul	ndis_parm_type		type;
547123474Swpaul	ndis_config_parm	**parm;
548123474Swpaul{
549151207Swpaul	ndis_config_parm	*p;
550151207Swpaul	ndis_parmlist_entry	*np;
551151207Swpaul	unicode_string		*us;
552151207Swpaul	ansi_string		as;
553127248Swpaul	int			base = 0;
554151207Swpaul	uint32_t		val;
555151207Swpaul	char			tmp[32];
556123474Swpaul
557151207Swpaul	np = ExAllocatePoolWithTag(NonPagedPool,
558151207Swpaul	    sizeof(ndis_parmlist_entry), 0);
559151207Swpaul	if (np == NULL)
560198786Srpaulo		return (NDIS_STATUS_RESOURCES);
561151207Swpaul	InsertHeadList((&block->nmb_parmlist), (&np->np_list));
562151207Swpaul	*parm = p = &np->np_parm;
563123474Swpaul
564123474Swpaul	switch(type) {
565123474Swpaul	case ndis_parm_string:
566151207Swpaul		/* See if this might be a number. */
567151207Swpaul		val = strtoul((char *)oid->oid_arg1, NULL, 10);
568151207Swpaul		us = &p->ncp_parmdata.ncp_stringdata;
569151207Swpaul		p->ncp_type = ndis_parm_string;
570151207Swpaul		if (val) {
571151207Swpaul			snprintf(tmp, 32, "%x", val);
572151207Swpaul			RtlInitAnsiString(&as, tmp);
573151207Swpaul		} else {
574151207Swpaul			RtlInitAnsiString(&as, (char *)oid->oid_arg1);
575151207Swpaul		}
576151207Swpaul
577151207Swpaul		if (RtlAnsiStringToUnicodeString(us, &as, TRUE)) {
578151207Swpaul			ExFreePool(np);
579198786Srpaulo			return (NDIS_STATUS_RESOURCES);
580151207Swpaul		}
581123474Swpaul		break;
582123474Swpaul	case ndis_parm_int:
583127248Swpaul		if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
584127248Swpaul			base = 16;
585127248Swpaul		else
586127248Swpaul			base = 10;
587151207Swpaul		p->ncp_type = ndis_parm_int;
588151207Swpaul		p->ncp_parmdata.ncp_intdata =
589127248Swpaul		    strtol((char *)oid->oid_arg1, NULL, base);
590123474Swpaul		break;
591123474Swpaul	case ndis_parm_hexint:
592151207Swpaul#ifdef notdef
593127248Swpaul		if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
594127248Swpaul			base = 16;
595127248Swpaul		else
596127248Swpaul			base = 10;
597151207Swpaul#endif
598151207Swpaul		base = 16;
599151207Swpaul		p->ncp_type = ndis_parm_hexint;
600151207Swpaul		p->ncp_parmdata.ncp_intdata =
601127248Swpaul		    strtoul((char *)oid->oid_arg1, NULL, base);
602123474Swpaul		break;
603123474Swpaul	default:
604198786Srpaulo		return (NDIS_STATUS_FAILURE);
605123474Swpaul		break;
606123474Swpaul	}
607123474Swpaul
608198786Srpaulo	return (NDIS_STATUS_SUCCESS);
609123474Swpaul}
610123474Swpaul
611144888Swpaulstatic void
612140751SwpaulNdisReadConfiguration(status, parm, cfg, key, type)
613123474Swpaul	ndis_status		*status;
614123474Swpaul	ndis_config_parm	**parm;
615123474Swpaul	ndis_handle		cfg;
616151207Swpaul	unicode_string		*key;
617123474Swpaul	ndis_parm_type		type;
618123474Swpaul{
619123474Swpaul	char			*keystr = NULL;
620123474Swpaul	ndis_miniport_block	*block;
621123474Swpaul	struct ndis_softc	*sc;
622189488Sweongyo	struct sysctl_oid	*oidp;
623123474Swpaul	struct sysctl_ctx_entry	*e;
624151207Swpaul	ansi_string		as;
625123474Swpaul
626123474Swpaul	block = (ndis_miniport_block *)cfg;
627141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
628123474Swpaul
629141524Swpaul	if (key->us_len == 0 || key->us_buf == NULL) {
630124100Swpaul		*status = NDIS_STATUS_FAILURE;
631124100Swpaul		return;
632124100Swpaul	}
633124100Swpaul
634151207Swpaul	if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
635151207Swpaul		*status = NDIS_STATUS_RESOURCES;
636151207Swpaul		return;
637151207Swpaul	}
638123474Swpaul
639151207Swpaul	keystr = as.as_buf;
640151207Swpaul
641123474Swpaul	/*
642123474Swpaul	 * See if registry key is already in a list of known keys
643123474Swpaul	 * included with the driver.
644123474Swpaul	 */
645130097Sdes	TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
646123474Swpaul		oidp = e->entry;
647168421Spjd		if (strcasecmp(oidp->oid_name, keystr) == 0) {
648123488Swpaul			if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
649151207Swpaul				RtlFreeAnsiString(&as);
650123488Swpaul				*status = NDIS_STATUS_FAILURE;
651123488Swpaul				return;
652123488Swpaul			}
653151207Swpaul
654123474Swpaul			*status = ndis_encode_parm(block, oidp, type, parm);
655151207Swpaul			RtlFreeAnsiString(&as);
656123474Swpaul			return;
657123474Swpaul		}
658123474Swpaul	}
659123474Swpaul
660123474Swpaul	/*
661123474Swpaul	 * If the key didn't match, add it to the list of dynamically
662123474Swpaul	 * created ones. Sometimes, drivers refer to registry keys
663123474Swpaul	 * that aren't documented in their .INF files. These keys
664123474Swpaul	 * are supposed to be created by some sort of utility or
665123474Swpaul	 * control panel snap-in that comes with the driver software.
666123474Swpaul	 * Sometimes it's useful to be able to manipulate these.
667123474Swpaul	 * If the driver requests the key in the form of a string,
668123474Swpaul	 * make its default value an empty string, otherwise default
669123474Swpaul	 * it to "0".
670123474Swpaul	 */
671123474Swpaul
672123474Swpaul	if (type == ndis_parm_int || type == ndis_parm_hexint)
673123488Swpaul		ndis_add_sysctl(sc, keystr, "(dynamic integer key)",
674123488Swpaul		    "UNSET", CTLFLAG_RW);
675123474Swpaul	else
676123488Swpaul		ndis_add_sysctl(sc, keystr, "(dynamic string key)",
677123488Swpaul		    "UNSET", CTLFLAG_RW);
678123474Swpaul
679151207Swpaul	RtlFreeAnsiString(&as);
680123474Swpaul	*status = NDIS_STATUS_FAILURE;
681123474Swpaul}
682123474Swpaul
683123526Swpaulstatic ndis_status
684123526Swpaulndis_decode_parm(block, parm, val)
685123526Swpaul	ndis_miniport_block	*block;
686123526Swpaul	ndis_config_parm	*parm;
687123526Swpaul	char			*val;
688123526Swpaul{
689151207Swpaul	unicode_string		*ustr;
690151207Swpaul	ansi_string		as;
691123526Swpaul
692123526Swpaul	switch(parm->ncp_type) {
693123526Swpaul	case ndis_parm_string:
694123526Swpaul		ustr = &parm->ncp_parmdata.ncp_stringdata;
695151207Swpaul		if (RtlUnicodeStringToAnsiString(&as, ustr, TRUE))
696198786Srpaulo			return (NDIS_STATUS_RESOURCES);
697151207Swpaul		bcopy(as.as_buf, val, as.as_len);
698151207Swpaul		RtlFreeAnsiString(&as);
699123526Swpaul		break;
700123526Swpaul	case ndis_parm_int:
701124697Swpaul		sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata);
702123526Swpaul		break;
703123526Swpaul	case ndis_parm_hexint:
704123526Swpaul		sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata);
705123526Swpaul		break;
706123526Swpaul	default:
707198786Srpaulo		return (NDIS_STATUS_FAILURE);
708123526Swpaul		break;
709123526Swpaul	}
710198786Srpaulo	return (NDIS_STATUS_SUCCESS);
711123526Swpaul}
712123526Swpaul
713144888Swpaulstatic void
714140751SwpaulNdisWriteConfiguration(status, cfg, key, parm)
715123526Swpaul	ndis_status		*status;
716123526Swpaul	ndis_handle		cfg;
717151207Swpaul	unicode_string		*key;
718123526Swpaul	ndis_config_parm	*parm;
719123526Swpaul{
720151207Swpaul	ansi_string		as;
721123526Swpaul	char			*keystr = NULL;
722123526Swpaul	ndis_miniport_block	*block;
723123526Swpaul	struct ndis_softc	*sc;
724189488Sweongyo	struct sysctl_oid	*oidp;
725123526Swpaul	struct sysctl_ctx_entry	*e;
726123526Swpaul	char			val[256];
727123526Swpaul
728123526Swpaul	block = (ndis_miniport_block *)cfg;
729141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
730123526Swpaul
731151207Swpaul	if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
732151207Swpaul		*status = NDIS_STATUS_RESOURCES;
733151207Swpaul		return;
734151207Swpaul	}
735123526Swpaul
736151207Swpaul	keystr = as.as_buf;
737151207Swpaul
738123526Swpaul	/* Decode the parameter into a string. */
739124697Swpaul	bzero(val, sizeof(val));
740123526Swpaul	*status = ndis_decode_parm(block, parm, val);
741123526Swpaul	if (*status != NDIS_STATUS_SUCCESS) {
742151207Swpaul		RtlFreeAnsiString(&as);
743123526Swpaul		return;
744123526Swpaul	}
745123526Swpaul
746123526Swpaul	/* See if the key already exists. */
747123526Swpaul
748130097Sdes	TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
749123526Swpaul		oidp = e->entry;
750168421Spjd		if (strcasecmp(oidp->oid_name, keystr) == 0) {
751123526Swpaul			/* Found it, set the value. */
752123526Swpaul			strcpy((char *)oidp->oid_arg1, val);
753151207Swpaul			RtlFreeAnsiString(&as);
754123526Swpaul			return;
755123526Swpaul		}
756123526Swpaul	}
757123526Swpaul
758123526Swpaul	/* Not found, add a new key with the specified value. */
759123526Swpaul	ndis_add_sysctl(sc, keystr, "(dynamically set key)",
760123526Swpaul		    val, CTLFLAG_RW);
761123526Swpaul
762151207Swpaul	RtlFreeAnsiString(&as);
763123526Swpaul	*status = NDIS_STATUS_SUCCESS;
764123526Swpaul}
765123526Swpaul
766144888Swpaulstatic void
767140751SwpaulNdisCloseConfiguration(cfg)
768123474Swpaul	ndis_handle		cfg;
769123474Swpaul{
770151207Swpaul	list_entry		*e;
771151207Swpaul	ndis_parmlist_entry	*pe;
772151207Swpaul	ndis_miniport_block	*block;
773151207Swpaul	ndis_config_parm	*p;
774151207Swpaul
775151207Swpaul	block = (ndis_miniport_block *)cfg;
776151207Swpaul
777151207Swpaul	while (!IsListEmpty(&block->nmb_parmlist)) {
778189488Sweongyo		e = RemoveHeadList(&block->nmb_parmlist);
779189488Sweongyo		pe = CONTAINING_RECORD(e, ndis_parmlist_entry, np_list);
780151207Swpaul		p = &pe->np_parm;
781151207Swpaul		if (p->ncp_type == ndis_parm_string)
782151207Swpaul			RtlFreeUnicodeString(&p->ncp_parmdata.ncp_stringdata);
783151207Swpaul		ExFreePool(e);
784151207Swpaul	}
785123474Swpaul}
786123474Swpaul
787128229Swpaul/*
788128229Swpaul * Initialize a Windows spinlock.
789128229Swpaul */
790144888Swpaulstatic void
791140751SwpaulNdisAllocateSpinLock(lock)
792123474Swpaul	ndis_spin_lock		*lock;
793123474Swpaul{
794140751Swpaul	KeInitializeSpinLock(&lock->nsl_spinlock);
795128229Swpaul	lock->nsl_kirql = 0;
796123474Swpaul}
797123474Swpaul
798128229Swpaul/*
799128229Swpaul * Destroy a Windows spinlock. This is a no-op for now. There are two reasons
800128229Swpaul * for this. One is that it's sort of superfluous: we don't have to do anything
801128229Swpaul * special to deallocate the spinlock. The other is that there are some buggy
802128229Swpaul * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on
803128229Swpaul * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm
804128229Swpaul * talking to you.)
805128229Swpaul */
806144888Swpaulstatic void
807140751SwpaulNdisFreeSpinLock(lock)
808123474Swpaul	ndis_spin_lock		*lock;
809123474Swpaul{
810128229Swpaul#ifdef notdef
811140751Swpaul	KeInitializeSpinLock(&lock->nsl_spinlock);
812128229Swpaul	lock->nsl_kirql = 0;
813128229Swpaul#endif
814123474Swpaul}
815123474Swpaul
816128229Swpaul/*
817128229Swpaul * Acquire a spinlock from IRQL <= DISPATCH_LEVEL.
818128229Swpaul */
819128229Swpaul
820144888Swpaulstatic void
821140751SwpaulNdisAcquireSpinLock(lock)
822123474Swpaul	ndis_spin_lock		*lock;
823123474Swpaul{
824140751Swpaul	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
825123474Swpaul}
826123474Swpaul
827128229Swpaul/*
828128229Swpaul * Release a spinlock from IRQL == DISPATCH_LEVEL.
829128229Swpaul */
830128229Swpaul
831144888Swpaulstatic void
832140751SwpaulNdisReleaseSpinLock(lock)
833123474Swpaul	ndis_spin_lock		*lock;
834123474Swpaul{
835140751Swpaul	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
836123474Swpaul}
837123474Swpaul
838128229Swpaul/*
839128229Swpaul * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL.
840128229Swpaul */
841144888Swpaulstatic void
842140751SwpaulNdisDprAcquireSpinLock(lock)
843128229Swpaul	ndis_spin_lock		*lock;
844128229Swpaul{
845144174Swpaul	KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock);
846128229Swpaul}
847128229Swpaul
848128229Swpaul/*
849128229Swpaul * Release a spinlock without leaving IRQL == DISPATCH_LEVEL.
850128229Swpaul */
851144888Swpaulstatic void
852140751SwpaulNdisDprReleaseSpinLock(lock)
853128229Swpaul	ndis_spin_lock		*lock;
854128229Swpaul{
855144174Swpaul	KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock);
856128229Swpaul}
857128229Swpaul
858145895Swpaulstatic void
859145895SwpaulNdisInitializeReadWriteLock(lock)
860145895Swpaul	ndis_rw_lock		*lock;
861145895Swpaul{
862145895Swpaul	KeInitializeSpinLock(&lock->nrl_spinlock);
863145895Swpaul	bzero((char *)&lock->nrl_rsvd, sizeof(lock->nrl_rsvd));
864145895Swpaul}
865145895Swpaul
866145895Swpaulstatic void
867189004SrdivackyNdisAcquireReadWriteLock(ndis_rw_lock *lock, uint8_t writeacc,
868189004Srdivacky    ndis_lock_state *state)
869145895Swpaul{
870145895Swpaul	if (writeacc == TRUE) {
871145895Swpaul		KeAcquireSpinLock(&lock->nrl_spinlock, &state->nls_oldirql);
872145895Swpaul		lock->nrl_rsvd[0]++;
873145895Swpaul	} else
874145895Swpaul		lock->nrl_rsvd[1]++;
875145895Swpaul}
876145895Swpaul
877145895Swpaulstatic void
878145895SwpaulNdisReleaseReadWriteLock(lock, state)
879145895Swpaul	ndis_rw_lock		*lock;
880145895Swpaul	ndis_lock_state		*state;
881145895Swpaul{
882145895Swpaul	if (lock->nrl_rsvd[0]) {
883145895Swpaul		lock->nrl_rsvd[0]--;
884145895Swpaul		KeReleaseSpinLock(&lock->nrl_spinlock, state->nls_oldirql);
885145895Swpaul	} else
886145895Swpaul		lock->nrl_rsvd[1]--;
887145895Swpaul}
888145895Swpaul
889144888Swpaulstatic uint32_t
890140751SwpaulNdisReadPciSlotInformation(adapter, slot, offset, buf, len)
891123474Swpaul	ndis_handle		adapter;
892123474Swpaul	uint32_t		slot;
893123474Swpaul	uint32_t		offset;
894123474Swpaul	void			*buf;
895123474Swpaul	uint32_t		len;
896123474Swpaul{
897123474Swpaul	ndis_miniport_block	*block;
898123474Swpaul	int			i;
899123474Swpaul	char			*dest;
900141524Swpaul	device_t		dev;
901123474Swpaul
902123474Swpaul	block = (ndis_miniport_block *)adapter;
903123474Swpaul	dest = buf;
904141524Swpaul	if (block == NULL)
905198786Srpaulo		return (0);
906123474Swpaul
907141524Swpaul	dev = block->nmb_physdeviceobj->do_devext;
908144174Swpaul
909144174Swpaul	/*
910144174Swpaul	 * I have a test system consisting of a Sun w2100z
911144174Swpaul	 * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g
912144174Swpaul	 * "Aries" miniPCI NIC. (The NIC is installed in the
913144174Swpaul	 * machine using a miniPCI to PCI bus adapter card.)
914144174Swpaul	 * When running in SMP mode, I found that
915144174Swpaul	 * performing a large number of consecutive calls to
916144174Swpaul	 * NdisReadPciSlotInformation() would result in a
917144174Swpaul	 * sudden system reset (or in some cases a freeze).
918144174Swpaul	 * My suspicion is that the multiple reads are somehow
919144174Swpaul	 * triggering a fatal PCI bus error that leads to a
920144174Swpaul	 * machine check. The 1us delay in the loop below
921144174Swpaul	 * seems to prevent this problem.
922144174Swpaul	 */
923144174Swpaul
924144174Swpaul	for (i = 0; i < len; i++) {
925144174Swpaul		DELAY(1);
926141524Swpaul		dest[i] = pci_read_config(dev, i + offset, 1);
927144174Swpaul	}
928123474Swpaul
929198786Srpaulo	return (len);
930123474Swpaul}
931123474Swpaul
932144888Swpaulstatic uint32_t
933140751SwpaulNdisWritePciSlotInformation(adapter, slot, offset, buf, len)
934123474Swpaul	ndis_handle		adapter;
935123474Swpaul	uint32_t		slot;
936123474Swpaul	uint32_t		offset;
937123474Swpaul	void			*buf;
938123474Swpaul	uint32_t		len;
939123474Swpaul{
940123474Swpaul	ndis_miniport_block	*block;
941123474Swpaul	int			i;
942123474Swpaul	char			*dest;
943141524Swpaul	device_t		dev;
944123474Swpaul
945123474Swpaul	block = (ndis_miniport_block *)adapter;
946123474Swpaul	dest = buf;
947123474Swpaul
948141524Swpaul	if (block == NULL)
949198786Srpaulo		return (0);
950123474Swpaul
951141524Swpaul	dev = block->nmb_physdeviceobj->do_devext;
952144174Swpaul	for (i = 0; i < len; i++) {
953144174Swpaul		DELAY(1);
954141524Swpaul		pci_write_config(dev, i + offset, dest[i], 1);
955144174Swpaul	}
956123474Swpaul
957198786Srpaulo	return (len);
958123474Swpaul}
959123474Swpaul
960123474Swpaul/*
961123474Swpaul * The errorlog routine uses a variable argument list, so we
962123474Swpaul * have to declare it this way.
963123474Swpaul */
964151207Swpaul
965124228Swpaul#define ERRMSGLEN 512
966123474Swpaulstatic void
967140751SwpaulNdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
968123474Swpaul	uint32_t numerrors, ...)
969123474Swpaul{
970123474Swpaul	ndis_miniport_block	*block;
971123474Swpaul	va_list			ap;
972124173Swpaul	int			i, error;
973151207Swpaul	char			*str = NULL;
974124173Swpaul	uint16_t		flags;
975141524Swpaul	device_t		dev;
976141963Swpaul	driver_object		*drv;
977145895Swpaul	struct ndis_softc	*sc;
978145895Swpaul	struct ifnet		*ifp;
979151207Swpaul	unicode_string		us;
980151606Swpaul	ansi_string		as = { 0, 0, NULL };
981123474Swpaul
982123474Swpaul	block = (ndis_miniport_block *)adapter;
983141524Swpaul	dev = block->nmb_physdeviceobj->do_devext;
984145485Swpaul	drv = block->nmb_deviceobj->do_drvobj;
985145895Swpaul	sc = device_get_softc(dev);
986147256Sbrooks	ifp = sc->ifp;
987123474Swpaul
988179720Sweongyo	if (ifp != NULL && ifp->if_flags & IFF_DEBUG) {
989151977Swpaul		error = pe_get_message((vm_offset_t)drv->dro_driverstart,
990151977Swpaul		    code, &str, &i, &flags);
991151977Swpaul		if (error == 0) {
992151977Swpaul			if (flags & MESSAGE_RESOURCE_UNICODE) {
993151977Swpaul				RtlInitUnicodeString(&us, (uint16_t *)str);
994151977Swpaul				if (RtlUnicodeStringToAnsiString(&as,
995151977Swpaul				    &us, TRUE) == STATUS_SUCCESS)
996151977Swpaul					str = as.as_buf;
997151977Swpaul				else
998151977Swpaul					str = NULL;
999151977Swpaul			}
1000151977Swpaul		}
1001151977Swpaul	}
1002145895Swpaul
1003198786Srpaulo	device_printf(dev, "NDIS ERROR: %x (%s)\n", code,
1004124165Swpaul	    str == NULL ? "unknown error" : str);
1005123474Swpaul
1006179720Sweongyo	if (ifp != NULL && ifp->if_flags & IFF_DEBUG) {
1007198786Srpaulo		device_printf(dev, "NDIS NUMERRORS: %x\n", numerrors);
1008145895Swpaul		va_start(ap, numerrors);
1009145895Swpaul		for (i = 0; i < numerrors; i++)
1010198786Srpaulo			device_printf(dev, "argptr: %p\n",
1011145895Swpaul			    va_arg(ap, void *));
1012145895Swpaul		va_end(ap);
1013145895Swpaul	}
1014123474Swpaul
1015151606Swpaul	if (as.as_len)
1016151207Swpaul		RtlFreeAnsiString(&as);
1017123474Swpaul}
1018123474Swpaul
1019123474Swpaulstatic void
1020123474Swpaulndis_map_cb(arg, segs, nseg, error)
1021123474Swpaul	void			*arg;
1022123474Swpaul	bus_dma_segment_t	*segs;
1023123474Swpaul	int			nseg;
1024123474Swpaul	int			error;
1025123474Swpaul{
1026123474Swpaul	struct ndis_map_arg	*ctx;
1027123474Swpaul	int			i;
1028123474Swpaul
1029123474Swpaul	if (error)
1030123474Swpaul		return;
1031123474Swpaul
1032123474Swpaul	ctx = arg;
1033123474Swpaul
1034123474Swpaul	for (i = 0; i < nseg; i++) {
1035123474Swpaul		ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr;
1036123474Swpaul		ctx->nma_fraglist[i].npu_len = segs[i].ds_len;
1037123474Swpaul	}
1038123474Swpaul
1039123474Swpaul	ctx->nma_cnt = nseg;
1040123474Swpaul}
1041123474Swpaul
1042144888Swpaulstatic void
1043189004SrdivackyNdisMStartBufferPhysicalMapping(ndis_handle adapter, ndis_buffer *buf,
1044189004Srdivacky    uint32_t mapreg, uint8_t writedev, ndis_paddr_unit *addrarray,
1045189004Srdivacky    uint32_t *arraysize)
1046123474Swpaul{
1047123474Swpaul	ndis_miniport_block	*block;
1048123474Swpaul	struct ndis_softc	*sc;
1049123474Swpaul	struct ndis_map_arg	nma;
1050123474Swpaul	bus_dmamap_t		map;
1051123474Swpaul	int			error;
1052123474Swpaul
1053123474Swpaul	if (adapter == NULL)
1054123474Swpaul		return;
1055123474Swpaul
1056123474Swpaul	block = (ndis_miniport_block *)adapter;
1057141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1058123474Swpaul
1059123474Swpaul	if (mapreg > sc->ndis_mmapcnt)
1060123474Swpaul		return;
1061123474Swpaul
1062123474Swpaul	map = sc->ndis_mmaps[mapreg];
1063123474Swpaul	nma.nma_fraglist = addrarray;
1064123474Swpaul
1065123474Swpaul	error = bus_dmamap_load(sc->ndis_mtag, map,
1066140751Swpaul	    MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf), ndis_map_cb,
1067123474Swpaul	    (void *)&nma, BUS_DMA_NOWAIT);
1068123474Swpaul
1069123474Swpaul	if (error)
1070123474Swpaul		return;
1071123474Swpaul
1072123474Swpaul	bus_dmamap_sync(sc->ndis_mtag, map,
1073123474Swpaul	    writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
1074123474Swpaul
1075123474Swpaul	*arraysize = nma.nma_cnt;
1076123474Swpaul}
1077123474Swpaul
1078144888Swpaulstatic void
1079140751SwpaulNdisMCompleteBufferPhysicalMapping(adapter, buf, mapreg)
1080123474Swpaul	ndis_handle		adapter;
1081123474Swpaul	ndis_buffer		*buf;
1082123474Swpaul	uint32_t		mapreg;
1083123474Swpaul{
1084123474Swpaul	ndis_miniport_block	*block;
1085123474Swpaul	struct ndis_softc	*sc;
1086123474Swpaul	bus_dmamap_t		map;
1087123474Swpaul
1088123474Swpaul	if (adapter == NULL)
1089123474Swpaul		return;
1090123474Swpaul
1091123474Swpaul	block = (ndis_miniport_block *)adapter;
1092141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1093123474Swpaul
1094123474Swpaul	if (mapreg > sc->ndis_mmapcnt)
1095123474Swpaul		return;
1096123474Swpaul
1097123474Swpaul	map = sc->ndis_mmaps[mapreg];
1098123474Swpaul
1099123474Swpaul	bus_dmamap_sync(sc->ndis_mtag, map,
1100123474Swpaul	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1101123474Swpaul
1102123474Swpaul	bus_dmamap_unload(sc->ndis_mtag, map);
1103123474Swpaul}
1104123474Swpaul
1105125057Swpaul/*
1106144174Swpaul * This is an older (?) timer init routine which doesn't
1107144174Swpaul * accept a miniport context handle. Serialized miniports should
1108144174Swpaul * never call this function.
1109125057Swpaul */
1110125057Swpaul
1111144888Swpaulstatic void
1112140751SwpaulNdisInitializeTimer(timer, func, ctx)
1113125057Swpaul	ndis_timer		*timer;
1114125057Swpaul	ndis_timer_function	func;
1115125057Swpaul	void			*ctx;
1116125057Swpaul{
1117140751Swpaul	KeInitializeTimer(&timer->nt_ktimer);
1118140751Swpaul	KeInitializeDpc(&timer->nt_kdpc, func, ctx);
1119145895Swpaul	KeSetImportanceDpc(&timer->nt_kdpc, KDPC_IMPORTANCE_LOW);
1120125057Swpaul}
1121125057Swpaul
1122144888Swpaulstatic void
1123144174Swpaulndis_timercall(dpc, timer, sysarg1, sysarg2)
1124144174Swpaul	kdpc			*dpc;
1125144174Swpaul	ndis_miniport_timer	*timer;
1126144174Swpaul	void			*sysarg1;
1127144174Swpaul	void			*sysarg2;
1128144174Swpaul{
1129144174Swpaul	/*
1130144174Swpaul	 * Since we're called as a DPC, we should be running
1131144174Swpaul	 * at DISPATCH_LEVEL here. This means to acquire the
1132144174Swpaul	 * spinlock, we can use KeAcquireSpinLockAtDpcLevel()
1133144174Swpaul	 * rather than KeAcquireSpinLock().
1134144174Swpaul	 */
1135144174Swpaul	if (NDIS_SERIALIZED(timer->nmt_block))
1136144174Swpaul		KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock);
1137144174Swpaul
1138144174Swpaul	MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx,
1139144174Swpaul	    sysarg1, sysarg2);
1140144174Swpaul
1141144174Swpaul	if (NDIS_SERIALIZED(timer->nmt_block))
1142144174Swpaul		KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock);
1143144174Swpaul}
1144144174Swpaul
1145144174Swpaul/*
1146144174Swpaul * For a long time I wondered why there were two NDIS timer initialization
1147144174Swpaul * routines, and why this one needed an NDIS_MINIPORT_TIMER and the
1148144174Swpaul * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout
1149144174Swpaul * function and context pointers separate from those in the DPC, which
1150144174Swpaul * allows for another level of indirection: when the timer fires, we
1151144174Swpaul * can have our own timer function invoked, and from there we can call
1152144174Swpaul * the driver's function. But why go to all that trouble? Then it hit
1153144174Swpaul * me: for serialized miniports, the timer callouts are not re-entrant.
1154144174Swpaul * By trapping the callouts and having access to the MiniportAdapterHandle,
1155144174Swpaul * we can protect the driver callouts by acquiring the NDIS serialization
1156144174Swpaul * lock. This is essential for allowing serialized miniports to work
1157144174Swpaul * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL
1158144174Swpaul * is enough to prevent other threads from pre-empting you, but with
1159144174Swpaul * SMP, you must acquire a lock as well, otherwise the other CPU is
1160144174Swpaul * free to clobber you.
1161144174Swpaul */
1162144888Swpaulstatic void
1163140751SwpaulNdisMInitializeTimer(timer, handle, func, ctx)
1164123474Swpaul	ndis_miniport_timer	*timer;
1165127248Swpaul	ndis_handle		handle;
1166123474Swpaul	ndis_timer_function	func;
1167123474Swpaul	void			*ctx;
1168123474Swpaul{
1169186507Sweongyo	ndis_miniport_block	*block;
1170186507Sweongyo	struct ndis_softc	*sc;
1171186507Sweongyo
1172186507Sweongyo	block = (ndis_miniport_block *)handle;
1173186507Sweongyo	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1174186507Sweongyo
1175144174Swpaul	/* Save the driver's funcptr and context */
1176123474Swpaul
1177127248Swpaul	timer->nmt_timerfunc = func;
1178127248Swpaul	timer->nmt_timerctx = ctx;
1179127248Swpaul	timer->nmt_block = handle;
1180123821Swpaul
1181144402Swpaul	/*
1182144402Swpaul	 * Set up the timer so it will call our intermediate DPC.
1183144402Swpaul	 * Be sure to use the wrapped entry point, since
1184144402Swpaul	 * ntoskrnl_run_dpc() expects to invoke a function with
1185144402Swpaul	 * Microsoft calling conventions.
1186144402Swpaul	 */
1187140751Swpaul	KeInitializeTimer(&timer->nmt_ktimer);
1188144402Swpaul	KeInitializeDpc(&timer->nmt_kdpc,
1189144402Swpaul	    ndis_findwrap((funcptr)ndis_timercall), timer);
1190145895Swpaul	timer->nmt_ktimer.k_dpc = &timer->nmt_kdpc;
1191123474Swpaul}
1192123474Swpaul
1193123474Swpaul/*
1194127248Swpaul * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(),
1195127248Swpaul * but the former is just a macro wrapper around the latter.
1196123474Swpaul */
1197144888Swpaulstatic void
1198140751SwpaulNdisSetTimer(timer, msecs)
1199127248Swpaul	ndis_timer		*timer;
1200123474Swpaul	uint32_t		msecs;
1201123474Swpaul{
1202127248Swpaul	/*
1203127248Swpaul	 * KeSetTimer() wants the period in
1204127248Swpaul	 * hundred nanosecond intervals.
1205127248Swpaul	 */
1206140751Swpaul	KeSetTimer(&timer->nt_ktimer,
1207127248Swpaul	    ((int64_t)msecs * -10000), &timer->nt_kdpc);
1208123474Swpaul}
1209123474Swpaul
1210144888Swpaulstatic void
1211140751SwpaulNdisMSetPeriodicTimer(timer, msecs)
1212123474Swpaul	ndis_miniport_timer	*timer;
1213123474Swpaul	uint32_t		msecs;
1214123474Swpaul{
1215140751Swpaul	KeSetTimerEx(&timer->nmt_ktimer,
1216127248Swpaul	    ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc);
1217123474Swpaul}
1218123474Swpaul
1219127248Swpaul/*
1220127248Swpaul * Technically, this is really NdisCancelTimer(), but we also
1221127248Swpaul * (ab)use it for NdisMCancelTimer(), since in our implementation
1222127248Swpaul * we don't need the extra info in the ndis_miniport_timer
1223144174Swpaul * structure just to cancel a timer.
1224127248Swpaul */
1225127248Swpaul
1226144888Swpaulstatic void
1227140751SwpaulNdisMCancelTimer(timer, cancelled)
1228127248Swpaul	ndis_timer		*timer;
1229123474Swpaul	uint8_t			*cancelled;
1230123474Swpaul{
1231186507Sweongyo
1232140751Swpaul	*cancelled = KeCancelTimer(&timer->nt_ktimer);
1233123474Swpaul}
1234123474Swpaul
1235144888Swpaulstatic void
1236140751SwpaulNdisMQueryAdapterResources(status, adapter, list, buflen)
1237123474Swpaul	ndis_status		*status;
1238123474Swpaul	ndis_handle		adapter;
1239123474Swpaul	ndis_resource_list	*list;
1240123474Swpaul	uint32_t		*buflen;
1241123474Swpaul{
1242123474Swpaul	ndis_miniport_block	*block;
1243123474Swpaul	struct ndis_softc	*sc;
1244198819Srpaulo	int			rsclen;
1245123474Swpaul
1246123474Swpaul	block = (ndis_miniport_block *)adapter;
1247141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1248124094Swpaul
1249124094Swpaul	rsclen = sizeof(ndis_resource_list) +
1250123474Swpaul	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1));
1251124094Swpaul	if (*buflen < rsclen) {
1252124094Swpaul		*buflen = rsclen;
1253124094Swpaul		*status = NDIS_STATUS_INVALID_LENGTH;
1254124094Swpaul		return;
1255124094Swpaul	}
1256123474Swpaul
1257127887Swpaul	bcopy((char *)block->nmb_rlist, (char *)list, rsclen);
1258123474Swpaul	*status = NDIS_STATUS_SUCCESS;
1259123474Swpaul}
1260123474Swpaul
1261144888Swpaulstatic ndis_status
1262140751SwpaulNdisMRegisterIoPortRange(offset, adapter, port, numports)
1263123474Swpaul	void			**offset;
1264123474Swpaul	ndis_handle		adapter;
1265123474Swpaul	uint32_t		port;
1266123474Swpaul	uint32_t		numports;
1267123474Swpaul{
1268123474Swpaul	struct ndis_miniport_block	*block;
1269123474Swpaul	struct ndis_softc	*sc;
1270123474Swpaul
1271123474Swpaul	if (adapter == NULL)
1272198786Srpaulo		return (NDIS_STATUS_FAILURE);
1273123474Swpaul
1274123474Swpaul	block = (ndis_miniport_block *)adapter;
1275141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1276123474Swpaul
1277123474Swpaul	if (sc->ndis_res_io == NULL)
1278198786Srpaulo		return (NDIS_STATUS_FAILURE);
1279123474Swpaul
1280124454Swpaul	/* Don't let the device map more ports than we have. */
1281124454Swpaul	if (rman_get_size(sc->ndis_res_io) < numports)
1282198786Srpaulo		return (NDIS_STATUS_INVALID_LENGTH);
1283123474Swpaul
1284123474Swpaul	*offset = (void *)rman_get_start(sc->ndis_res_io);
1285123474Swpaul
1286198786Srpaulo	return (NDIS_STATUS_SUCCESS);
1287123474Swpaul}
1288123474Swpaul
1289144888Swpaulstatic void
1290140751SwpaulNdisMDeregisterIoPortRange(adapter, port, numports, offset)
1291123474Swpaul	ndis_handle		adapter;
1292123474Swpaul	uint32_t		port;
1293123474Swpaul	uint32_t		numports;
1294123474Swpaul	void			*offset;
1295123474Swpaul{
1296123474Swpaul}
1297123474Swpaul
1298144888Swpaulstatic void
1299140751SwpaulNdisReadNetworkAddress(status, addr, addrlen, adapter)
1300123474Swpaul	ndis_status		*status;
1301123474Swpaul	void			**addr;
1302123474Swpaul	uint32_t		*addrlen;
1303123474Swpaul	ndis_handle		adapter;
1304123474Swpaul{
1305123474Swpaul	struct ndis_softc	*sc;
1306123474Swpaul	ndis_miniport_block	*block;
1307123474Swpaul	uint8_t			empty[] = { 0, 0, 0, 0, 0, 0 };
1308123474Swpaul
1309123474Swpaul	block = (ndis_miniport_block *)adapter;
1310141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1311179009Sweongyo	if (sc->ifp == NULL) {
1312179009Sweongyo		*status = NDIS_STATUS_FAILURE;
1313179009Sweongyo		return;
1314179009Sweongyo	}
1315123474Swpaul
1316152423Sru	if (sc->ifp->if_addr == NULL ||
1317152423Sru	    bcmp(IF_LLADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0)
1318123474Swpaul		*status = NDIS_STATUS_FAILURE;
1319123474Swpaul	else {
1320152315Sru		*addr = IF_LLADDR(sc->ifp);
1321123474Swpaul		*addrlen = ETHER_ADDR_LEN;
1322123474Swpaul		*status = NDIS_STATUS_SUCCESS;
1323123474Swpaul	}
1324123474Swpaul}
1325123474Swpaul
1326144888Swpaulstatic ndis_status
1327140751SwpaulNdisQueryMapRegisterCount(bustype, cnt)
1328123848Swpaul	uint32_t		bustype;
1329123848Swpaul	uint32_t		*cnt;
1330123848Swpaul{
1331124097Swpaul	*cnt = 8192;
1332198786Srpaulo	return (NDIS_STATUS_SUCCESS);
1333123848Swpaul}
1334123848Swpaul
1335144888Swpaulstatic ndis_status
1336189004SrdivackyNdisMAllocateMapRegisters(ndis_handle adapter, uint32_t dmachannel,
1337189004Srdivacky    uint8_t dmasize, uint32_t physmapneeded, uint32_t maxmap)
1338123474Swpaul{
1339123474Swpaul	struct ndis_softc	*sc;
1340123474Swpaul	ndis_miniport_block	*block;
1341123474Swpaul	int			error, i, nseg = NDIS_MAXSEG;
1342123474Swpaul
1343123474Swpaul	block = (ndis_miniport_block *)adapter;
1344141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1345123474Swpaul
1346123474Swpaul	sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded,
1347123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
1348123474Swpaul
1349123474Swpaul	if (sc->ndis_mmaps == NULL)
1350198786Srpaulo		return (NDIS_STATUS_RESOURCES);
1351123474Swpaul
1352123474Swpaul	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1353123474Swpaul	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1354123474Swpaul	    NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW,
1355123474Swpaul	    NULL, NULL, &sc->ndis_mtag);
1356123474Swpaul
1357123474Swpaul	if (error) {
1358123474Swpaul		free(sc->ndis_mmaps, M_DEVBUF);
1359198786Srpaulo		return (NDIS_STATUS_RESOURCES);
1360123474Swpaul	}
1361123474Swpaul
1362123474Swpaul	for (i = 0; i < physmapneeded; i++)
1363123474Swpaul		bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]);
1364123474Swpaul
1365123474Swpaul	sc->ndis_mmapcnt = physmapneeded;
1366123474Swpaul
1367198786Srpaulo	return (NDIS_STATUS_SUCCESS);
1368123474Swpaul}
1369123474Swpaul
1370144888Swpaulstatic void
1371140751SwpaulNdisMFreeMapRegisters(adapter)
1372123474Swpaul	ndis_handle		adapter;
1373123474Swpaul{
1374123474Swpaul	struct ndis_softc	*sc;
1375123474Swpaul	ndis_miniport_block	*block;
1376123474Swpaul	int			i;
1377123474Swpaul
1378123474Swpaul	block = (ndis_miniport_block *)adapter;
1379141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1380123474Swpaul
1381123474Swpaul	for (i = 0; i < sc->ndis_mmapcnt; i++)
1382123474Swpaul		bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]);
1383123474Swpaul
1384123474Swpaul	free(sc->ndis_mmaps, M_DEVBUF);
1385123474Swpaul
1386123474Swpaul	bus_dma_tag_destroy(sc->ndis_mtag);
1387123474Swpaul}
1388123474Swpaul
1389123474Swpaulstatic void
1390123474Swpaulndis_mapshared_cb(arg, segs, nseg, error)
1391123474Swpaul	void			*arg;
1392123474Swpaul	bus_dma_segment_t	*segs;
1393123474Swpaul	int			nseg;
1394123474Swpaul	int			error;
1395123474Swpaul{
1396123474Swpaul	ndis_physaddr		*p;
1397123474Swpaul
1398123474Swpaul	if (error || nseg > 1)
1399123474Swpaul		return;
1400123474Swpaul
1401123474Swpaul	p = arg;
1402123474Swpaul
1403123474Swpaul	p->np_quad = segs[0].ds_addr;
1404123474Swpaul}
1405123474Swpaul
1406123474Swpaul/*
1407123474Swpaul * This maps to bus_dmamem_alloc().
1408123474Swpaul */
1409145895Swpaul
1410144888Swpaulstatic void
1411189004SrdivackyNdisMAllocateSharedMemory(ndis_handle adapter, uint32_t len, uint8_t cached,
1412189004Srdivacky    void **vaddr, ndis_physaddr *paddr)
1413123474Swpaul{
1414123474Swpaul	ndis_miniport_block	*block;
1415123474Swpaul	struct ndis_softc	*sc;
1416123474Swpaul	struct ndis_shmem	*sh;
1417123474Swpaul	int			error;
1418123474Swpaul
1419123474Swpaul	if (adapter == NULL)
1420123474Swpaul		return;
1421123474Swpaul
1422123474Swpaul	block = (ndis_miniport_block *)adapter;
1423141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1424123474Swpaul
1425123474Swpaul	sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO);
1426123474Swpaul	if (sh == NULL)
1427123474Swpaul		return;
1428123474Swpaul
1429151207Swpaul	InitializeListHead(&sh->ndis_list);
1430151207Swpaul
1431131750Swpaul	/*
1432131750Swpaul	 * When performing shared memory allocations, create a tag
1433131750Swpaul	 * with a lowaddr limit that restricts physical memory mappings
1434131750Swpaul	 * so that they all fall within the first 1GB of memory.
1435131750Swpaul	 * At least one device/driver combination (Linksys Instant
1436131750Swpaul	 * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
1437131750Swpaul	 * problems with performing DMA operations with physical
1438141963Swpaul	 * addresses that lie above the 1GB mark. I don't know if this
1439141963Swpaul	 * is a hardware limitation or if the addresses are being
1440141963Swpaul	 * truncated within the driver, but this seems to be the only
1441141963Swpaul	 * way to make these cards work reliably in systems with more
1442141963Swpaul	 * than 1GB of physical memory.
1443131750Swpaul	 */
1444131750Swpaul
1445123474Swpaul	error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
1446131750Swpaul	    0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL,
1447123474Swpaul	    NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL,
1448123474Swpaul	    &sh->ndis_stag);
1449123474Swpaul
1450123474Swpaul	if (error) {
1451123474Swpaul		free(sh, M_DEVBUF);
1452123474Swpaul		return;
1453123474Swpaul	}
1454123474Swpaul
1455123474Swpaul	error = bus_dmamem_alloc(sh->ndis_stag, vaddr,
1456123474Swpaul	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap);
1457123474Swpaul
1458123474Swpaul	if (error) {
1459123474Swpaul		bus_dma_tag_destroy(sh->ndis_stag);
1460123474Swpaul		free(sh, M_DEVBUF);
1461123474Swpaul		return;
1462123474Swpaul	}
1463123474Swpaul
1464123474Swpaul	error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr,
1465123474Swpaul	    len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT);
1466123474Swpaul
1467123474Swpaul	if (error) {
1468123474Swpaul		bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap);
1469123474Swpaul		bus_dma_tag_destroy(sh->ndis_stag);
1470123474Swpaul		free(sh, M_DEVBUF);
1471123474Swpaul		return;
1472123474Swpaul	}
1473123474Swpaul
1474145895Swpaul	/*
1475145895Swpaul	 * Save the physical address along with the source address.
1476145895Swpaul	 * The AirGo MIMO driver will call NdisMFreeSharedMemory()
1477145895Swpaul	 * with a bogus virtual address sometimes, but with a valid
1478145895Swpaul	 * physical address. To keep this from causing trouble, we
1479145895Swpaul	 * use the physical address to as a sanity check in case
1480145895Swpaul	 * searching based on the virtual address fails.
1481145895Swpaul	 */
1482145895Swpaul
1483151207Swpaul	NDIS_LOCK(sc);
1484145895Swpaul	sh->ndis_paddr.np_quad = paddr->np_quad;
1485123474Swpaul	sh->ndis_saddr = *vaddr;
1486151207Swpaul	InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list));
1487151207Swpaul	NDIS_UNLOCK(sc);
1488123474Swpaul}
1489123474Swpaul
1490125413Swpaulstruct ndis_allocwork {
1491125413Swpaul	uint32_t		na_len;
1492125413Swpaul	uint8_t			na_cached;
1493125413Swpaul	void			*na_ctx;
1494145895Swpaul	io_workitem		*na_iw;
1495125413Swpaul};
1496125413Swpaul
1497125413Swpaulstatic void
1498145895Swpaulndis_asyncmem_complete(dobj, arg)
1499145895Swpaul	device_object		*dobj;
1500125413Swpaul	void			*arg;
1501123474Swpaul{
1502123474Swpaul	ndis_miniport_block	*block;
1503123474Swpaul	struct ndis_softc	*sc;
1504125413Swpaul	struct ndis_allocwork	*w;
1505123474Swpaul	void			*vaddr;
1506123474Swpaul	ndis_physaddr		paddr;
1507144888Swpaul	ndis_allocdone_handler	donefunc;
1508123474Swpaul
1509125413Swpaul	w = arg;
1510145895Swpaul	block = (ndis_miniport_block *)dobj->do_devext;
1511141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1512123474Swpaul
1513125413Swpaul	vaddr = NULL;
1514125413Swpaul	paddr.np_quad = 0;
1515125413Swpaul
1516141524Swpaul	donefunc = sc->ndis_chars->nmc_allocate_complete_func;
1517145895Swpaul	NdisMAllocateSharedMemory(block, w->na_len,
1518125413Swpaul	    w->na_cached, &vaddr, &paddr);
1519145895Swpaul	MSCALL5(donefunc, block, vaddr, &paddr, w->na_len, w->na_ctx);
1520123474Swpaul
1521145895Swpaul	IoFreeWorkItem(w->na_iw);
1522145895Swpaul	free(w, M_DEVBUF);
1523123474Swpaul}
1524123474Swpaul
1525144888Swpaulstatic ndis_status
1526189004SrdivackyNdisMAllocateSharedMemoryAsync(ndis_handle adapter, uint32_t len,
1527189004Srdivacky    uint8_t cached, void *ctx)
1528125413Swpaul{
1529145895Swpaul	ndis_miniport_block	*block;
1530125413Swpaul	struct ndis_allocwork	*w;
1531145895Swpaul	io_workitem		*iw;
1532145895Swpaul	io_workitem_func	ifw;
1533125413Swpaul
1534125413Swpaul	if (adapter == NULL)
1535198786Srpaulo		return (NDIS_STATUS_FAILURE);
1536125413Swpaul
1537145895Swpaul	block = adapter;
1538145895Swpaul
1539145895Swpaul	iw = IoAllocateWorkItem(block->nmb_deviceobj);
1540145895Swpaul	if (iw == NULL)
1541198786Srpaulo		return (NDIS_STATUS_FAILURE);
1542145895Swpaul
1543125413Swpaul	w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT);
1544125413Swpaul
1545125413Swpaul	if (w == NULL)
1546198786Srpaulo		return (NDIS_STATUS_FAILURE);
1547125413Swpaul
1548125413Swpaul	w->na_cached = cached;
1549125413Swpaul	w->na_len = len;
1550125413Swpaul	w->na_ctx = ctx;
1551146273Swpaul	w->na_iw = iw;
1552125413Swpaul
1553145895Swpaul	ifw = (io_workitem_func)ndis_findwrap((funcptr)ndis_asyncmem_complete);
1554145895Swpaul	IoQueueWorkItem(iw, ifw, WORKQUEUE_DELAYED, w);
1555125413Swpaul
1556198786Srpaulo	return (NDIS_STATUS_PENDING);
1557125413Swpaul}
1558125413Swpaul
1559144888Swpaulstatic void
1560189004SrdivackyNdisMFreeSharedMemory(ndis_handle adapter, uint32_t len, uint8_t cached,
1561189004Srdivacky    void *vaddr, ndis_physaddr paddr)
1562123474Swpaul{
1563123474Swpaul	ndis_miniport_block	*block;
1564123474Swpaul	struct ndis_softc	*sc;
1565151207Swpaul	struct ndis_shmem	*sh = NULL;
1566151207Swpaul	list_entry		*l;
1567123474Swpaul
1568123474Swpaul	if (vaddr == NULL || adapter == NULL)
1569123474Swpaul		return;
1570123474Swpaul
1571123474Swpaul	block = (ndis_miniport_block *)adapter;
1572141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1573123474Swpaul
1574144254Swpaul	/* Sanity check: is list empty? */
1575144254Swpaul
1576151207Swpaul	if (IsListEmpty(&sc->ndis_shlist))
1577144254Swpaul		return;
1578144254Swpaul
1579151207Swpaul	NDIS_LOCK(sc);
1580151207Swpaul	l = sc->ndis_shlist.nle_flink;
1581151207Swpaul	while (l != &sc->ndis_shlist) {
1582151207Swpaul		sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list);
1583123474Swpaul		if (sh->ndis_saddr == vaddr)
1584123474Swpaul			break;
1585145895Swpaul		/*
1586189488Sweongyo		 * Check the physaddr too, just in case the driver lied
1587145895Swpaul		 * about the virtual address.
1588145895Swpaul		 */
1589145895Swpaul		if (sh->ndis_paddr.np_quad == paddr.np_quad)
1590145895Swpaul			break;
1591151207Swpaul		l = l->nle_flink;
1592123474Swpaul	}
1593123474Swpaul
1594145895Swpaul	if (sh == NULL) {
1595151207Swpaul		NDIS_UNLOCK(sc);
1596145895Swpaul		printf("NDIS: buggy driver tried to free "
1597145906Swpaul		    "invalid shared memory: vaddr: %p paddr: 0x%jx\n",
1598145935Swpaul		    vaddr, (uintmax_t)paddr.np_quad);
1599145895Swpaul		return;
1600145895Swpaul	}
1601145895Swpaul
1602151207Swpaul	RemoveEntryList(&sh->ndis_list);
1603151207Swpaul
1604151207Swpaul	NDIS_UNLOCK(sc);
1605151207Swpaul
1606123474Swpaul	bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1607145895Swpaul	bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap);
1608123474Swpaul	bus_dma_tag_destroy(sh->ndis_stag);
1609123474Swpaul
1610123474Swpaul	free(sh, M_DEVBUF);
1611123474Swpaul}
1612123474Swpaul
1613144888Swpaulstatic ndis_status
1614140751SwpaulNdisMMapIoSpace(vaddr, adapter, paddr, len)
1615123474Swpaul	void			**vaddr;
1616123474Swpaul	ndis_handle		adapter;
1617123474Swpaul	ndis_physaddr		paddr;
1618123474Swpaul	uint32_t		len;
1619123474Swpaul{
1620123474Swpaul	if (adapter == NULL)
1621198786Srpaulo		return (NDIS_STATUS_FAILURE);
1622123474Swpaul
1623151691Swpaul	*vaddr = MmMapIoSpace(paddr.np_quad, len, 0);
1624123474Swpaul
1625151691Swpaul	if (*vaddr == NULL)
1626198786Srpaulo		return (NDIS_STATUS_FAILURE);
1627123474Swpaul
1628198786Srpaulo	return (NDIS_STATUS_SUCCESS);
1629123474Swpaul}
1630123474Swpaul
1631144888Swpaulstatic void
1632140751SwpaulNdisMUnmapIoSpace(adapter, vaddr, len)
1633123474Swpaul	ndis_handle		adapter;
1634123474Swpaul	void			*vaddr;
1635123474Swpaul	uint32_t		len;
1636123474Swpaul{
1637151691Swpaul	MmUnmapIoSpace(vaddr, len);
1638123474Swpaul}
1639123474Swpaul
1640144888Swpaulstatic uint32_t
1641140751SwpaulNdisGetCacheFillSize(void)
1642123474Swpaul{
1643198786Srpaulo	return (128);
1644123474Swpaul}
1645123474Swpaul
1646216242Sbschmidtstatic void *
1647216242SbschmidtNdisGetRoutineAddress(ustr)
1648216242Sbschmidt	unicode_string		*ustr;
1649216242Sbschmidt{
1650216242Sbschmidt	ansi_string		astr;
1651216242Sbschmidt
1652216242Sbschmidt	if (RtlUnicodeStringToAnsiString(&astr, ustr, TRUE))
1653216242Sbschmidt		return (NULL);
1654216242Sbschmidt	return (ndis_get_routine_address(ndis_functbl, astr.as_buf));
1655216242Sbschmidt}
1656216242Sbschmidt
1657144888Swpaulstatic uint32_t
1658140751SwpaulNdisMGetDmaAlignment(handle)
1659123474Swpaul	ndis_handle		handle;
1660123474Swpaul{
1661198786Srpaulo	return (16);
1662123474Swpaul}
1663123474Swpaul
1664123474Swpaul/*
1665123474Swpaul * NDIS has two methods for dealing with NICs that support DMA.
1666123474Swpaul * One is to just pass packets to the driver and let it call
1667123474Swpaul * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
1668123474Swpaul * all by itself, and the other is to let the NDIS library handle the
1669123474Swpaul * buffer mapping internally, and hand the driver an already populated
1670123474Swpaul * scatter/gather fragment list. If the driver calls
1671123474Swpaul * NdisMInitializeScatterGatherDma(), it wants to use the latter
1672123474Swpaul * method.
1673123474Swpaul */
1674123474Swpaul
1675144888Swpaulstatic ndis_status
1676189004SrdivackyNdisMInitializeScatterGatherDma(ndis_handle adapter, uint8_t is64,
1677189004Srdivacky    uint32_t maxphysmap)
1678123474Swpaul{
1679123474Swpaul	struct ndis_softc	*sc;
1680123474Swpaul	ndis_miniport_block	*block;
1681123474Swpaul	int			error;
1682123474Swpaul
1683123474Swpaul	if (adapter == NULL)
1684198786Srpaulo		return (NDIS_STATUS_FAILURE);
1685123474Swpaul	block = (ndis_miniport_block *)adapter;
1686141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1687123474Swpaul
1688123474Swpaul	/* Don't do this twice. */
1689123474Swpaul	if (sc->ndis_sc == 1)
1690198786Srpaulo		return (NDIS_STATUS_SUCCESS);
1691123474Swpaul
1692123474Swpaul	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1693123474Swpaul	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1694123474Swpaul	    MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
1695123474Swpaul	    NULL, NULL, &sc->ndis_ttag);
1696123474Swpaul
1697123474Swpaul	sc->ndis_sc = 1;
1698123474Swpaul
1699198786Srpaulo	return (NDIS_STATUS_SUCCESS);
1700123474Swpaul}
1701123474Swpaul
1702144888Swpaulvoid
1703140751SwpaulNdisAllocatePacketPool(status, pool, descnum, protrsvdlen)
1704123474Swpaul	ndis_status		*status;
1705123474Swpaul	ndis_handle		*pool;
1706123474Swpaul	uint32_t		descnum;
1707123474Swpaul	uint32_t		protrsvdlen;
1708123474Swpaul{
1709151451Swpaul	ndis_packet_pool	*p;
1710151451Swpaul	ndis_packet		*packets;
1711123474Swpaul	int			i;
1712123474Swpaul
1713151451Swpaul	p = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_packet_pool), 0);
1714151451Swpaul	if (p == NULL) {
1715123474Swpaul		*status = NDIS_STATUS_RESOURCES;
1716123474Swpaul		return;
1717123474Swpaul	}
1718123474Swpaul
1719151451Swpaul	p->np_cnt = descnum + NDIS_POOL_EXTRA;
1720151451Swpaul	p->np_protrsvd = protrsvdlen;
1721151451Swpaul	p->np_len = sizeof(ndis_packet) + protrsvdlen;
1722151451Swpaul
1723151451Swpaul	packets = ExAllocatePoolWithTag(NonPagedPool, p->np_cnt *
1724151451Swpaul	    p->np_len, 0);
1725151451Swpaul
1726151451Swpaul
1727151451Swpaul	if (packets == NULL) {
1728151451Swpaul		ExFreePool(p);
1729151451Swpaul		*status = NDIS_STATUS_RESOURCES;
1730151451Swpaul		return;
1731123474Swpaul	}
1732123474Swpaul
1733151451Swpaul	p->np_pktmem = packets;
1734151451Swpaul
1735151451Swpaul	for (i = 0; i < p->np_cnt; i++)
1736151451Swpaul		InterlockedPushEntrySList(&p->np_head,
1737151451Swpaul		    (struct slist_entry *)&packets[i]);
1738151451Swpaul
1739151451Swpaul#ifdef NDIS_DEBUG_PACKETS
1740151451Swpaul	p->np_dead = 0;
1741151451Swpaul	KeInitializeSpinLock(&p->np_lock);
1742189488Sweongyo	KeInitializeEvent(&p->np_event, EVENT_TYPE_NOTIFY, TRUE);
1743151451Swpaul#endif
1744151451Swpaul
1745151451Swpaul	*pool = p;
1746123474Swpaul	*status = NDIS_STATUS_SUCCESS;
1747123474Swpaul}
1748123474Swpaul
1749144888Swpaulvoid
1750140751SwpaulNdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen)
1751123474Swpaul	ndis_status		*status;
1752123474Swpaul	ndis_handle		*pool;
1753123474Swpaul	uint32_t		descnum;
1754123474Swpaul	uint32_t		oflowdescnum;
1755123474Swpaul	uint32_t		protrsvdlen;
1756123474Swpaul{
1757198786Srpaulo	return (NdisAllocatePacketPool(status, pool,
1758123474Swpaul	    descnum + oflowdescnum, protrsvdlen));
1759123474Swpaul}
1760123474Swpaul
1761144888Swpauluint32_t
1762140751SwpaulNdisPacketPoolUsage(pool)
1763123474Swpaul	ndis_handle		pool;
1764123474Swpaul{
1765151451Swpaul	ndis_packet_pool	*p;
1766123474Swpaul
1767151451Swpaul	p = (ndis_packet_pool *)pool;
1768198786Srpaulo	return (p->np_cnt - ExQueryDepthSList(&p->np_head));
1769123474Swpaul}
1770123474Swpaul
1771144888Swpaulvoid
1772140751SwpaulNdisFreePacketPool(pool)
1773123474Swpaul	ndis_handle		pool;
1774123474Swpaul{
1775151451Swpaul	ndis_packet_pool	*p;
1776151451Swpaul	int			usage;
1777189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1778143086Swpaul	uint8_t			irql;
1779151451Swpaul#endif
1780126568Swpaul
1781151451Swpaul	p = (ndis_packet_pool *)pool;
1782126568Swpaul
1783189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1784151451Swpaul	KeAcquireSpinLock(&p->np_lock, &irql);
1785151451Swpaul#endif
1786126568Swpaul
1787151451Swpaul	usage = NdisPacketPoolUsage(pool);
1788126568Swpaul
1789189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1790151451Swpaul	if (usage) {
1791151451Swpaul		p->np_dead = 1;
1792151451Swpaul		KeResetEvent(&p->np_event);
1793151451Swpaul		KeReleaseSpinLock(&p->np_lock, irql);
1794151451Swpaul		KeWaitForSingleObject(&p->np_event, 0, 0, FALSE, NULL);
1795151451Swpaul	} else
1796151451Swpaul		KeReleaseSpinLock(&p->np_lock, irql);
1797151451Swpaul#endif
1798126568Swpaul
1799151451Swpaul	ExFreePool(p->np_pktmem);
1800151451Swpaul	ExFreePool(p);
1801123474Swpaul}
1802123474Swpaul
1803144888Swpaulvoid
1804140751SwpaulNdisAllocatePacket(status, packet, pool)
1805123474Swpaul	ndis_status		*status;
1806123474Swpaul	ndis_packet		**packet;
1807123474Swpaul	ndis_handle		pool;
1808123474Swpaul{
1809151451Swpaul	ndis_packet_pool	*p;
1810151451Swpaul	ndis_packet		*pkt;
1811189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1812143086Swpaul	uint8_t			irql;
1813151451Swpaul#endif
1814123474Swpaul
1815151451Swpaul	p = (ndis_packet_pool *)pool;
1816123474Swpaul
1817189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1818151451Swpaul	KeAcquireSpinLock(&p->np_lock, &irql);
1819151451Swpaul	if (p->np_dead) {
1820151451Swpaul		KeReleaseSpinLock(&p->np_lock, irql);
1821151451Swpaul		printf("NDIS: tried to allocate packet from dead pool %p\n",
1822151451Swpaul		    pool);
1823151451Swpaul		*status = NDIS_STATUS_RESOURCES;
1824123474Swpaul		return;
1825123474Swpaul	}
1826151451Swpaul#endif
1827123474Swpaul
1828151451Swpaul	pkt = (ndis_packet *)InterlockedPopEntrySList(&p->np_head);
1829126568Swpaul
1830189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1831151451Swpaul	KeReleaseSpinLock(&p->np_lock, irql);
1832151451Swpaul#endif
1833126568Swpaul
1834123474Swpaul	if (pkt == NULL) {
1835123474Swpaul		*status = NDIS_STATUS_RESOURCES;
1836123474Swpaul		return;
1837123474Swpaul	}
1838123474Swpaul
1839123474Swpaul
1840151451Swpaul	bzero((char *)pkt, sizeof(ndis_packet));
1841151451Swpaul
1842123474Swpaul	/* Save pointer to the pool. */
1843151451Swpaul	pkt->np_private.npp_pool = pool;
1844123474Swpaul
1845123474Swpaul	/* Set the oob offset pointer. Lots of things expect this. */
1846144888Swpaul	pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob);
1847123474Swpaul
1848124278Swpaul	/*
1849124278Swpaul	 * We must initialize the packet flags correctly in order
1850124278Swpaul	 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
1851141963Swpaul	 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work
1852189488Sweongyo	 * correctly.
1853124278Swpaul	 */
1854124278Swpaul	pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
1855144239Swpaul	pkt->np_private.npp_validcounts = FALSE;
1856124278Swpaul
1857123474Swpaul	*packet = pkt;
1858123474Swpaul
1859123474Swpaul	*status = NDIS_STATUS_SUCCESS;
1860123474Swpaul}
1861123474Swpaul
1862144888Swpaulvoid
1863140751SwpaulNdisFreePacket(packet)
1864123474Swpaul	ndis_packet		*packet;
1865123474Swpaul{
1866151451Swpaul	ndis_packet_pool	*p;
1867189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1868143086Swpaul	uint8_t			irql;
1869151451Swpaul#endif
1870123474Swpaul
1871151451Swpaul	p = (ndis_packet_pool *)packet->np_private.npp_pool;
1872123474Swpaul
1873189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1874151451Swpaul	KeAcquireSpinLock(&p->np_lock, &irql);
1875151451Swpaul#endif
1876143086Swpaul
1877151451Swpaul	InterlockedPushEntrySList(&p->np_head, (slist_entry *)packet);
1878151451Swpaul
1879189488Sweongyo#ifdef NDIS_DEBUG_PACKETS
1880151451Swpaul	if (p->np_dead) {
1881151451Swpaul		if (ExQueryDepthSList(&p->np_head) == p->np_cnt)
1882151451Swpaul			KeSetEvent(&p->np_event, IO_NO_INCREMENT, FALSE);
1883143086Swpaul	}
1884151451Swpaul	KeReleaseSpinLock(&p->np_lock, irql);
1885151451Swpaul#endif
1886123474Swpaul}
1887123474Swpaul
1888144888Swpaulstatic void
1889140751SwpaulNdisUnchainBufferAtFront(packet, buf)
1890123474Swpaul	ndis_packet		*packet;
1891123474Swpaul	ndis_buffer		**buf;
1892123474Swpaul{
1893123474Swpaul	ndis_packet_private	*priv;
1894123474Swpaul
1895123474Swpaul	if (packet == NULL || buf == NULL)
1896123474Swpaul		return;
1897123474Swpaul
1898123474Swpaul	priv = &packet->np_private;
1899123474Swpaul
1900123474Swpaul	priv->npp_validcounts = FALSE;
1901123474Swpaul
1902123474Swpaul	if (priv->npp_head == priv->npp_tail) {
1903123474Swpaul		*buf = priv->npp_head;
1904123474Swpaul		priv->npp_head = priv->npp_tail = NULL;
1905123474Swpaul	} else {
1906123474Swpaul		*buf = priv->npp_head;
1907140751Swpaul		priv->npp_head = (*buf)->mdl_next;
1908123474Swpaul	}
1909123474Swpaul}
1910123474Swpaul
1911144888Swpaulstatic void
1912140751SwpaulNdisUnchainBufferAtBack(packet, buf)
1913123721Swpaul	ndis_packet		*packet;
1914123721Swpaul	ndis_buffer		**buf;
1915123721Swpaul{
1916123721Swpaul	ndis_packet_private	*priv;
1917123721Swpaul	ndis_buffer		*tmp;
1918123721Swpaul
1919123721Swpaul	if (packet == NULL || buf == NULL)
1920123721Swpaul		return;
1921123721Swpaul
1922123721Swpaul	priv = &packet->np_private;
1923123721Swpaul
1924123721Swpaul	priv->npp_validcounts = FALSE;
1925123721Swpaul
1926123721Swpaul	if (priv->npp_head == priv->npp_tail) {
1927123721Swpaul		*buf = priv->npp_head;
1928123721Swpaul		priv->npp_head = priv->npp_tail = NULL;
1929123721Swpaul	} else {
1930123721Swpaul		*buf = priv->npp_tail;
1931123721Swpaul		tmp = priv->npp_head;
1932140751Swpaul		while (tmp->mdl_next != priv->npp_tail)
1933140751Swpaul			tmp = tmp->mdl_next;
1934123721Swpaul		priv->npp_tail = tmp;
1935140751Swpaul		tmp->mdl_next = NULL;
1936123721Swpaul	}
1937123721Swpaul}
1938123721Swpaul
1939123474Swpaul/*
1940141963Swpaul * The NDIS "buffer" is really an MDL (memory descriptor list)
1941141963Swpaul * which is used to describe a buffer in a way that allows it
1942141963Swpaul * to mapped into different contexts. We have to be careful how
1943141963Swpaul * we handle them: in some versions of Windows, the NdisFreeBuffer()
1944141963Swpaul * routine is an actual function in the NDIS API, but in others
1945141963Swpaul * it's just a macro wrapper around IoFreeMdl(). There's really
1946141963Swpaul * no way to use the 'descnum' parameter to count how many
1947141963Swpaul * "buffers" are allocated since in order to use IoFreeMdl() to
1948141963Swpaul * dispose of a buffer, we have to use IoAllocateMdl() to allocate
1949141963Swpaul * them, and IoAllocateMdl() just grabs them out of the heap.
1950123474Swpaul */
1951123474Swpaul
1952144888Swpaulstatic void
1953140751SwpaulNdisAllocateBufferPool(status, pool, descnum)
1954123474Swpaul	ndis_status		*status;
1955123474Swpaul	ndis_handle		*pool;
1956123474Swpaul	uint32_t		descnum;
1957123474Swpaul{
1958151207Swpaul
1959141963Swpaul	/*
1960141963Swpaul	 * The only thing we can really do here is verify that descnum
1961141963Swpaul	 * is a reasonable value, but I really don't know what to check
1962141963Swpaul	 * it against.
1963141963Swpaul	 */
1964123474Swpaul
1965141963Swpaul	*pool = NonPagedPool;
1966123474Swpaul	*status = NDIS_STATUS_SUCCESS;
1967123474Swpaul}
1968123474Swpaul
1969144888Swpaulstatic void
1970140751SwpaulNdisFreeBufferPool(pool)
1971123474Swpaul	ndis_handle		pool;
1972123474Swpaul{
1973123474Swpaul}
1974123474Swpaul
1975144888Swpaulstatic void
1976140751SwpaulNdisAllocateBuffer(status, buffer, pool, vaddr, len)
1977123474Swpaul	ndis_status		*status;
1978123474Swpaul	ndis_buffer		**buffer;
1979123474Swpaul	ndis_handle		pool;
1980123474Swpaul	void			*vaddr;
1981123474Swpaul	uint32_t		len;
1982123474Swpaul{
1983141963Swpaul	ndis_buffer		*buf;
1984123474Swpaul
1985141963Swpaul	buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL);
1986123474Swpaul	if (buf == NULL) {
1987123474Swpaul		*status = NDIS_STATUS_RESOURCES;
1988123474Swpaul		return;
1989123474Swpaul	}
1990123474Swpaul
1991151207Swpaul	MmBuildMdlForNonPagedPool(buf);
1992151207Swpaul
1993123474Swpaul	*buffer = buf;
1994141963Swpaul	*status = NDIS_STATUS_SUCCESS;
1995123474Swpaul}
1996123474Swpaul
1997144888Swpaulstatic void
1998140751SwpaulNdisFreeBuffer(buf)
1999123474Swpaul	ndis_buffer		*buf;
2000123474Swpaul{
2001141963Swpaul	IoFreeMdl(buf);
2002123474Swpaul}
2003123474Swpaul
2004124100Swpaul/* Aw c'mon. */
2005124100Swpaul
2006144888Swpaulstatic uint32_t
2007140751SwpaulNdisBufferLength(buf)
2008124100Swpaul	ndis_buffer		*buf;
2009124100Swpaul{
2010198786Srpaulo	return (MmGetMdlByteCount(buf));
2011124100Swpaul}
2012124100Swpaul
2013123723Swpaul/*
2014123723Swpaul * Get the virtual address and length of a buffer.
2015123723Swpaul * Note: the vaddr argument is optional.
2016123723Swpaul */
2017123474Swpaul
2018144888Swpaulstatic void
2019140751SwpaulNdisQueryBuffer(buf, vaddr, len)
2020123474Swpaul	ndis_buffer		*buf;
2021123474Swpaul	void			**vaddr;
2022123474Swpaul	uint32_t		*len;
2023123474Swpaul{
2024123723Swpaul	if (vaddr != NULL)
2025140751Swpaul		*vaddr = MmGetMdlVirtualAddress(buf);
2026140751Swpaul	*len = MmGetMdlByteCount(buf);
2027123474Swpaul}
2028123474Swpaul
2029123474Swpaul/* Same as above -- we don't care about the priority. */
2030123474Swpaul
2031144888Swpaulstatic void
2032140751SwpaulNdisQueryBufferSafe(buf, vaddr, len, prio)
2033123474Swpaul	ndis_buffer		*buf;
2034123474Swpaul	void			**vaddr;
2035123474Swpaul	uint32_t		*len;
2036123474Swpaul	uint32_t		prio;
2037123474Swpaul{
2038123723Swpaul	if (vaddr != NULL)
2039140751Swpaul		*vaddr = MmGetMdlVirtualAddress(buf);
2040140751Swpaul	*len = MmGetMdlByteCount(buf);
2041123474Swpaul}
2042123474Swpaul
2043125069Swpaul/* Damnit Microsoft!! How many ways can you do the same thing?! */
2044125069Swpaul
2045144888Swpaulstatic void *
2046140751SwpaulNdisBufferVirtualAddress(buf)
2047125069Swpaul	ndis_buffer		*buf;
2048125069Swpaul{
2049198786Srpaulo	return (MmGetMdlVirtualAddress(buf));
2050125069Swpaul}
2051125069Swpaul
2052144888Swpaulstatic void *
2053140751SwpaulNdisBufferVirtualAddressSafe(buf, prio)
2054125069Swpaul	ndis_buffer		*buf;
2055125069Swpaul	uint32_t		prio;
2056125069Swpaul{
2057198786Srpaulo	return (MmGetMdlVirtualAddress(buf));
2058125069Swpaul}
2059125069Swpaul
2060144888Swpaulstatic void
2061140751SwpaulNdisAdjustBufferLength(buf, len)
2062123474Swpaul	ndis_buffer		*buf;
2063123474Swpaul	int			len;
2064123474Swpaul{
2065140751Swpaul	MmGetMdlByteCount(buf) = len;
2066123474Swpaul}
2067123474Swpaul
2068144888Swpaulstatic uint32_t
2069140751SwpaulNdisInterlockedIncrement(addend)
2070123474Swpaul	uint32_t		*addend;
2071123474Swpaul{
2072124203Swpaul	atomic_add_long((u_long *)addend, 1);
2073198786Srpaulo	return (*addend);
2074123474Swpaul}
2075123474Swpaul
2076144888Swpaulstatic uint32_t
2077140751SwpaulNdisInterlockedDecrement(addend)
2078123474Swpaul	uint32_t		*addend;
2079123474Swpaul{
2080124203Swpaul	atomic_subtract_long((u_long *)addend, 1);
2081198786Srpaulo	return (*addend);
2082123474Swpaul}
2083123474Swpaul
2084215779Sbschmidtstatic uint32_t
2085215779SbschmidtNdisGetVersion(void)
2086215779Sbschmidt{
2087215779Sbschmidt	return (0x00050001);
2088215779Sbschmidt}
2089215779Sbschmidt
2090144888Swpaulstatic void
2091140751SwpaulNdisInitializeEvent(event)
2092123474Swpaul	ndis_event		*event;
2093123474Swpaul{
2094127248Swpaul	/*
2095127411Swpaul	 * NDIS events are always notification
2096127248Swpaul	 * events, and should be initialized to the
2097127248Swpaul	 * not signaled state.
2098127248Swpaul	 */
2099140751Swpaul	KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE);
2100123474Swpaul}
2101123474Swpaul
2102144888Swpaulstatic void
2103140751SwpaulNdisSetEvent(event)
2104123474Swpaul	ndis_event		*event;
2105123474Swpaul{
2106151451Swpaul	KeSetEvent(&event->ne_event, IO_NO_INCREMENT, FALSE);
2107123474Swpaul}
2108123474Swpaul
2109144888Swpaulstatic void
2110140751SwpaulNdisResetEvent(event)
2111123474Swpaul	ndis_event		*event;
2112123474Swpaul{
2113140751Swpaul	KeResetEvent(&event->ne_event);
2114123474Swpaul}
2115123474Swpaul
2116144888Swpaulstatic uint8_t
2117140751SwpaulNdisWaitEvent(event, msecs)
2118123474Swpaul	ndis_event		*event;
2119123474Swpaul	uint32_t		msecs;
2120123474Swpaul{
2121127248Swpaul	int64_t			duetime;
2122127248Swpaul	uint32_t		rval;
2123123474Swpaul
2124127248Swpaul	duetime = ((int64_t)msecs * -10000);
2125151451Swpaul	rval = KeWaitForSingleObject(event,
2126145895Swpaul	    0, 0, TRUE, msecs ? & duetime : NULL);
2127123474Swpaul
2128127248Swpaul	if (rval == STATUS_TIMEOUT)
2129198786Srpaulo		return (FALSE);
2130125551Swpaul
2131198786Srpaulo	return (TRUE);
2132123474Swpaul}
2133123474Swpaul
2134144888Swpaulstatic ndis_status
2135140751SwpaulNdisUnicodeStringToAnsiString(dstr, sstr)
2136151207Swpaul	ansi_string		*dstr;
2137151207Swpaul	unicode_string		*sstr;
2138123474Swpaul{
2139151207Swpaul	uint32_t		rval;
2140151207Swpaul
2141151207Swpaul	rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE);
2142151207Swpaul
2143151207Swpaul	if (rval == STATUS_INSUFFICIENT_RESOURCES)
2144198786Srpaulo		return (NDIS_STATUS_RESOURCES);
2145151207Swpaul	if (rval)
2146198786Srpaulo		return (NDIS_STATUS_FAILURE);
2147151207Swpaul
2148123474Swpaul	return (NDIS_STATUS_SUCCESS);
2149123474Swpaul}
2150123474Swpaul
2151144888Swpaulstatic ndis_status
2152140751SwpaulNdisAnsiStringToUnicodeString(dstr, sstr)
2153151207Swpaul	unicode_string		*dstr;
2154151207Swpaul	ansi_string		*sstr;
2155123526Swpaul{
2156151207Swpaul	uint32_t		rval;
2157151207Swpaul
2158151207Swpaul	rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE);
2159151207Swpaul
2160151207Swpaul	if (rval == STATUS_INSUFFICIENT_RESOURCES)
2161198786Srpaulo		return (NDIS_STATUS_RESOURCES);
2162151207Swpaul	if (rval)
2163198786Srpaulo		return (NDIS_STATUS_FAILURE);
2164151207Swpaul
2165123526Swpaul	return (NDIS_STATUS_SUCCESS);
2166123526Swpaul}
2167123526Swpaul
2168144888Swpaulstatic ndis_status
2169140751SwpaulNdisMPciAssignResources(adapter, slot, list)
2170123474Swpaul	ndis_handle		adapter;
2171123474Swpaul	uint32_t		slot;
2172123474Swpaul	ndis_resource_list	**list;
2173123474Swpaul{
2174123474Swpaul	ndis_miniport_block	*block;
2175123474Swpaul
2176123474Swpaul	if (adapter == NULL || list == NULL)
2177123474Swpaul		return (NDIS_STATUS_FAILURE);
2178123474Swpaul
2179123474Swpaul	block = (ndis_miniport_block *)adapter;
2180123474Swpaul	*list = block->nmb_rlist;
2181123474Swpaul
2182123474Swpaul	return (NDIS_STATUS_SUCCESS);
2183123474Swpaul}
2184123474Swpaul
2185152626Swpaulstatic uint8_t
2186152626Swpaulndis_intr(iobj, arg)
2187152626Swpaul	kinterrupt		*iobj;
2188189488Sweongyo	void			*arg;
2189151207Swpaul{
2190151207Swpaul	struct ndis_softc	*sc;
2191152626Swpaul	uint8_t			is_our_intr = FALSE;
2192151207Swpaul	int			call_isr = 0;
2193151207Swpaul	ndis_miniport_interrupt	*intr;
2194151207Swpaul
2195151207Swpaul	sc = arg;
2196151207Swpaul	intr = sc->ndis_block->nmb_interrupt;
2197151207Swpaul
2198151207Swpaul	if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL)
2199198786Srpaulo		return (FALSE);
2200151207Swpaul
2201151207Swpaul	if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
2202151977Swpaul		MSCALL3(intr->ni_isrfunc, &is_our_intr, &call_isr,
2203151977Swpaul		    sc->ndis_block->nmb_miniportadapterctx);
2204151207Swpaul	else {
2205151977Swpaul		MSCALL1(sc->ndis_chars->nmc_disable_interrupts_func,
2206151977Swpaul		    sc->ndis_block->nmb_miniportadapterctx);
2207151207Swpaul		call_isr = 1;
2208151207Swpaul	}
2209151207Swpaul
2210152626Swpaul	if (call_isr)
2211151207Swpaul		IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
2212151207Swpaul
2213198786Srpaulo	return (is_our_intr);
2214151207Swpaul}
2215151207Swpaul
2216151207Swpaulstatic void
2217151207Swpaulndis_intrhand(dpc, intr, sysarg1, sysarg2)
2218151207Swpaul	kdpc			*dpc;
2219151207Swpaul	ndis_miniport_interrupt	*intr;
2220151207Swpaul	void			*sysarg1;
2221151207Swpaul	void			*sysarg2;
2222151207Swpaul{
2223151207Swpaul	struct ndis_softc	*sc;
2224151207Swpaul	ndis_miniport_block	*block;
2225189488Sweongyo	ndis_handle             adapter;
2226151207Swpaul
2227151207Swpaul	block = intr->ni_block;
2228189488Sweongyo	adapter = block->nmb_miniportadapterctx;
2229151207Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2230151207Swpaul
2231189488Sweongyo	if (NDIS_SERIALIZED(sc->ndis_block))
2232189488Sweongyo		KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
2233151207Swpaul
2234189488Sweongyo	MSCALL1(intr->ni_dpcfunc, adapter);
2235151207Swpaul
2236189488Sweongyo	/* If there's a MiniportEnableInterrupt() routine, call it. */
2237151207Swpaul
2238151977Swpaul	if (sc->ndis_chars->nmc_enable_interrupts_func != NULL)
2239151977Swpaul		MSCALL1(sc->ndis_chars->nmc_enable_interrupts_func, adapter);
2240151207Swpaul
2241189488Sweongyo	if (NDIS_SERIALIZED(sc->ndis_block))
2242189488Sweongyo		KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
2243151207Swpaul
2244151207Swpaul	/*
2245151207Swpaul	 * Set the completion event if we've drained all
2246151207Swpaul	 * pending interrupts.
2247151207Swpaul	 */
2248151207Swpaul
2249151207Swpaul	KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
2250151207Swpaul	intr->ni_dpccnt--;
2251151207Swpaul	if (intr->ni_dpccnt == 0)
2252151207Swpaul		KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE);
2253151207Swpaul	KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
2254151207Swpaul}
2255151207Swpaul
2256144888Swpaulstatic ndis_status
2257189004SrdivackyNdisMRegisterInterrupt(ndis_miniport_interrupt *intr, ndis_handle adapter,
2258189004Srdivacky    uint32_t ivec, uint32_t ilevel, uint8_t reqisr, uint8_t shared,
2259189004Srdivacky    ndis_interrupt_mode imode)
2260123474Swpaul{
2261124165Swpaul	ndis_miniport_block	*block;
2262151207Swpaul	ndis_miniport_characteristics *ch;
2263151207Swpaul	struct ndis_softc	*sc;
2264151207Swpaul	int			error;
2265124165Swpaul
2266124165Swpaul	block = adapter;
2267151207Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2268151207Swpaul	ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj,
2269151207Swpaul	    (void *)1);
2270124165Swpaul
2271151207Swpaul	intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool,
2272151207Swpaul	    sizeof(struct mtx), 0);
2273151207Swpaul	if (intr->ni_rsvd == NULL)
2274198786Srpaulo		return (NDIS_STATUS_RESOURCES);
2275151207Swpaul
2276124135Swpaul	intr->ni_block = adapter;
2277124165Swpaul	intr->ni_isrreq = reqisr;
2278124165Swpaul	intr->ni_shared = shared;
2279151207Swpaul	intr->ni_dpccnt = 0;
2280151977Swpaul	intr->ni_isrfunc = ch->nmc_isr_func;
2281151977Swpaul	intr->ni_dpcfunc = ch->nmc_interrupt_func;
2282151207Swpaul
2283189488Sweongyo	KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE);
2284189488Sweongyo	KeInitializeDpc(&intr->ni_dpc,
2285151207Swpaul	    ndis_findwrap((funcptr)ndis_intrhand), intr);
2286189488Sweongyo	KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW);
2287151207Swpaul
2288151207Swpaul	error = IoConnectInterrupt(&intr->ni_introbj,
2289151207Swpaul	    ndis_findwrap((funcptr)ndis_intr), sc, NULL,
2290151207Swpaul	    ivec, ilevel, 0, imode, shared, 0, FALSE);
2291151207Swpaul
2292151207Swpaul	if (error != STATUS_SUCCESS)
2293198786Srpaulo		return (NDIS_STATUS_FAILURE);
2294151207Swpaul
2295124165Swpaul	block->nmb_interrupt = intr;
2296141524Swpaul
2297198786Srpaulo	return (NDIS_STATUS_SUCCESS);
2298189488Sweongyo}
2299123474Swpaul
2300144888Swpaulstatic void
2301140751SwpaulNdisMDeregisterInterrupt(intr)
2302123474Swpaul	ndis_miniport_interrupt	*intr;
2303123474Swpaul{
2304151207Swpaul	ndis_miniport_block	*block;
2305151207Swpaul	uint8_t			irql;
2306151207Swpaul
2307151207Swpaul	block = intr->ni_block;
2308151207Swpaul
2309151207Swpaul	/* Should really be KeSynchronizeExecution() */
2310151207Swpaul
2311151207Swpaul	KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql);
2312151207Swpaul	block->nmb_interrupt = NULL;
2313151207Swpaul	KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql);
2314151207Swpaul/*
2315151207Swpaul	KeFlushQueuedDpcs();
2316151207Swpaul*/
2317151207Swpaul	/* Disconnect our ISR */
2318151207Swpaul
2319151207Swpaul	IoDisconnectInterrupt(intr->ni_introbj);
2320151207Swpaul
2321151451Swpaul	KeWaitForSingleObject(&intr->ni_dpcevt, 0, 0, FALSE, NULL);
2322151207Swpaul	KeResetEvent(&intr->ni_dpcevt);
2323123474Swpaul}
2324123474Swpaul
2325144888Swpaulstatic void
2326140751SwpaulNdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc)
2327123474Swpaul	ndis_handle		adapter;
2328123474Swpaul	void			*shutdownctx;
2329123474Swpaul	ndis_shutdown_handler	shutdownfunc;
2330123474Swpaul{
2331123474Swpaul	ndis_miniport_block	*block;
2332123474Swpaul	ndis_miniport_characteristics *chars;
2333123474Swpaul	struct ndis_softc	*sc;
2334123474Swpaul
2335123474Swpaul	if (adapter == NULL)
2336123474Swpaul		return;
2337123474Swpaul
2338123474Swpaul	block = (ndis_miniport_block *)adapter;
2339141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2340141524Swpaul	chars = sc->ndis_chars;
2341123474Swpaul
2342123474Swpaul	chars->nmc_shutdown_handler = shutdownfunc;
2343123474Swpaul	chars->nmc_rsvd0 = shutdownctx;
2344123474Swpaul}
2345123474Swpaul
2346144888Swpaulstatic void
2347140751SwpaulNdisMDeregisterAdapterShutdownHandler(adapter)
2348123474Swpaul	ndis_handle		adapter;
2349123474Swpaul{
2350123474Swpaul	ndis_miniport_block	*block;
2351123474Swpaul	ndis_miniport_characteristics *chars;
2352123474Swpaul	struct ndis_softc	*sc;
2353123474Swpaul
2354123474Swpaul	if (adapter == NULL)
2355123474Swpaul		return;
2356123474Swpaul
2357123474Swpaul	block = (ndis_miniport_block *)adapter;
2358141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2359141524Swpaul	chars = sc->ndis_chars;
2360123474Swpaul
2361123474Swpaul	chars->nmc_shutdown_handler = NULL;
2362123474Swpaul	chars->nmc_rsvd0 = NULL;
2363123474Swpaul}
2364123474Swpaul
2365144888Swpaulstatic uint32_t
2366140751SwpaulNDIS_BUFFER_TO_SPAN_PAGES(buf)
2367123474Swpaul	ndis_buffer		*buf;
2368123474Swpaul{
2369123757Swpaul	if (buf == NULL)
2370198786Srpaulo		return (0);
2371140751Swpaul	if (MmGetMdlByteCount(buf) == 0)
2372198786Srpaulo		return (1);
2373198786Srpaulo	return (SPAN_PAGES(MmGetMdlVirtualAddress(buf),
2374140751Swpaul	    MmGetMdlByteCount(buf)));
2375123474Swpaul}
2376123474Swpaul
2377144888Swpaulstatic void
2378140751SwpaulNdisGetBufferPhysicalArraySize(buf, pages)
2379123573Swpaul	ndis_buffer		*buf;
2380123573Swpaul	uint32_t		*pages;
2381123573Swpaul{
2382123757Swpaul	if (buf == NULL)
2383123757Swpaul		return;
2384123757Swpaul
2385140751Swpaul	*pages = NDIS_BUFFER_TO_SPAN_PAGES(buf);
2386123573Swpaul}
2387123573Swpaul
2388144888Swpaulstatic void
2389140751SwpaulNdisQueryBufferOffset(buf, off, len)
2390123474Swpaul	ndis_buffer		*buf;
2391123474Swpaul	uint32_t		*off;
2392123474Swpaul	uint32_t		*len;
2393123474Swpaul{
2394123757Swpaul	if (buf == NULL)
2395123757Swpaul		return;
2396123757Swpaul
2397140751Swpaul	*off = MmGetMdlByteOffset(buf);
2398140751Swpaul	*len = MmGetMdlByteCount(buf);
2399123474Swpaul}
2400123474Swpaul
2401151451Swpaulvoid
2402140751SwpaulNdisMSleep(usecs)
2403123474Swpaul	uint32_t		usecs;
2404123474Swpaul{
2405151207Swpaul	ktimer			timer;
2406123474Swpaul
2407145485Swpaul	/*
2408145485Swpaul	 * During system bootstrap, (i.e. cold == 1), we aren't
2409151207Swpaul	 * allowed to sleep, so we have to do a hard DELAY()
2410151207Swpaul	 * instead.
2411145485Swpaul	 */
2412123474Swpaul
2413151207Swpaul	if (cold)
2414145485Swpaul		DELAY(usecs);
2415151207Swpaul	else {
2416151207Swpaul		KeInitializeTimer(&timer);
2417151207Swpaul		KeSetTimer(&timer, ((int64_t)usecs * -10), NULL);
2418151451Swpaul		KeWaitForSingleObject(&timer, 0, 0, FALSE, NULL);
2419151207Swpaul	}
2420123474Swpaul}
2421123474Swpaul
2422144888Swpaulstatic uint32_t
2423140751SwpaulNdisReadPcmciaAttributeMemory(handle, offset, buf, len)
2424123474Swpaul	ndis_handle		handle;
2425123474Swpaul	uint32_t		offset;
2426123474Swpaul	void			*buf;
2427123474Swpaul	uint32_t		len;
2428123474Swpaul{
2429123474Swpaul	struct ndis_softc	*sc;
2430123474Swpaul	ndis_miniport_block	*block;
2431123474Swpaul	bus_space_handle_t	bh;
2432123474Swpaul	bus_space_tag_t		bt;
2433123474Swpaul	char			*dest;
2434123474Swpaul	int			i;
2435123474Swpaul
2436123474Swpaul	if (handle == NULL)
2437198786Srpaulo		return (0);
2438123474Swpaul
2439123474Swpaul	block = (ndis_miniport_block *)handle;
2440141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2441123474Swpaul	dest = buf;
2442123474Swpaul
2443123474Swpaul	bh = rman_get_bushandle(sc->ndis_res_am);
2444123474Swpaul	bt = rman_get_bustag(sc->ndis_res_am);
2445123474Swpaul
2446123474Swpaul	for (i = 0; i < len; i++)
2447131953Swpaul		dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2);
2448123474Swpaul
2449198786Srpaulo	return (i);
2450123474Swpaul}
2451123474Swpaul
2452144888Swpaulstatic uint32_t
2453140751SwpaulNdisWritePcmciaAttributeMemory(handle, offset, buf, len)
2454123474Swpaul	ndis_handle		handle;
2455123474Swpaul	uint32_t		offset;
2456123474Swpaul	void			*buf;
2457123474Swpaul	uint32_t		len;
2458123474Swpaul{
2459123474Swpaul	struct ndis_softc	*sc;
2460123474Swpaul	ndis_miniport_block	*block;
2461123474Swpaul	bus_space_handle_t	bh;
2462123474Swpaul	bus_space_tag_t		bt;
2463123474Swpaul	char			*src;
2464123474Swpaul	int			i;
2465123474Swpaul
2466123474Swpaul	if (handle == NULL)
2467198786Srpaulo		return (0);
2468123474Swpaul
2469123474Swpaul	block = (ndis_miniport_block *)handle;
2470141524Swpaul	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2471123474Swpaul	src = buf;
2472123474Swpaul
2473123474Swpaul	bh = rman_get_bushandle(sc->ndis_res_am);
2474123474Swpaul	bt = rman_get_bustag(sc->ndis_res_am);
2475123474Swpaul
2476123474Swpaul	for (i = 0; i < len; i++)
2477131953Swpaul		bus_space_write_1(bt, bh, (offset + i) * 2, src[i]);
2478123474Swpaul
2479198786Srpaulo	return (i);
2480123474Swpaul}
2481123474Swpaul
2482144888Swpaulstatic list_entry *
2483140751SwpaulNdisInterlockedInsertHeadList(head, entry, lock)
2484125551Swpaul	list_entry		*head;
2485125551Swpaul	list_entry		*entry;
2486123474Swpaul	ndis_spin_lock		*lock;
2487123474Swpaul{
2488125551Swpaul	list_entry		*flink;
2489123474Swpaul
2490140751Swpaul	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2491123474Swpaul	flink = head->nle_flink;
2492123474Swpaul	entry->nle_flink = flink;
2493123474Swpaul	entry->nle_blink = head;
2494123474Swpaul	flink->nle_blink = entry;
2495123474Swpaul	head->nle_flink = entry;
2496140751Swpaul	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2497123474Swpaul
2498198786Srpaulo	return (flink);
2499123474Swpaul}
2500123474Swpaul
2501144888Swpaulstatic list_entry *
2502140751SwpaulNdisInterlockedRemoveHeadList(head, lock)
2503125551Swpaul	list_entry		*head;
2504123474Swpaul	ndis_spin_lock		*lock;
2505123474Swpaul{
2506125551Swpaul	list_entry		*flink;
2507125551Swpaul	list_entry		*entry;
2508123474Swpaul
2509140751Swpaul	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2510123474Swpaul	entry = head->nle_flink;
2511123474Swpaul	flink = entry->nle_flink;
2512123474Swpaul	head->nle_flink = flink;
2513123474Swpaul	flink->nle_blink = head;
2514140751Swpaul	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2515123474Swpaul
2516198786Srpaulo	return (entry);
2517123474Swpaul}
2518123474Swpaul
2519144888Swpaulstatic list_entry *
2520140751SwpaulNdisInterlockedInsertTailList(head, entry, lock)
2521125551Swpaul	list_entry		*head;
2522125551Swpaul	list_entry		*entry;
2523123474Swpaul	ndis_spin_lock		*lock;
2524123474Swpaul{
2525125551Swpaul	list_entry		*blink;
2526123474Swpaul
2527140751Swpaul	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2528123474Swpaul	blink = head->nle_blink;
2529123474Swpaul	entry->nle_flink = head;
2530123474Swpaul	entry->nle_blink = blink;
2531123474Swpaul	blink->nle_flink = entry;
2532123474Swpaul	head->nle_blink = entry;
2533140751Swpaul	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2534123474Swpaul
2535198786Srpaulo	return (blink);
2536123474Swpaul}
2537123474Swpaul
2538144888Swpaulstatic uint8_t
2539140751SwpaulNdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx)
2540123474Swpaul	ndis_miniport_interrupt	*intr;
2541123474Swpaul	void			*syncfunc;
2542123474Swpaul	void			*syncctx;
2543123474Swpaul{
2544198786Srpaulo	return (KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx));
2545123474Swpaul}
2546123474Swpaul
2547144888Swpaulstatic void
2548140751SwpaulNdisGetCurrentSystemTime(tval)
2549123504Swpaul	uint64_t		*tval;
2550123504Swpaul{
2551174150Sthompsa	ntoskrnl_time(tval);
2552123504Swpaul}
2553123504Swpaul
2554123822Swpaul/*
2555123822Swpaul * Return the number of milliseconds since the system booted.
2556123822Swpaul */
2557144888Swpaulstatic void
2558140751SwpaulNdisGetSystemUpTime(tval)
2559123822Swpaul	uint32_t		*tval;
2560123822Swpaul{
2561144888Swpaul	struct timespec		ts;
2562189488Sweongyo
2563144888Swpaul	nanouptime(&ts);
2564144888Swpaul	*tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
2565123822Swpaul}
2566123822Swpaul
2567144888Swpaulstatic void
2568140751SwpaulNdisInitializeString(dst, src)
2569151207Swpaul	unicode_string		*dst;
2570123507Swpaul	char			*src;
2571123507Swpaul{
2572151207Swpaul	ansi_string		as;
2573151207Swpaul	RtlInitAnsiString(&as, src);
2574151207Swpaul	RtlAnsiStringToUnicodeString(dst, &as, TRUE);
2575123507Swpaul}
2576123507Swpaul
2577144888Swpaulstatic void
2578140751SwpaulNdisFreeString(str)
2579151207Swpaul	unicode_string		*str;
2580123507Swpaul{
2581151207Swpaul	RtlFreeUnicodeString(str);
2582123507Swpaul}
2583123507Swpaul
2584144888Swpaulstatic ndis_status
2585140751SwpaulNdisMRemoveMiniport(adapter)
2586123507Swpaul	ndis_handle		*adapter;
2587123507Swpaul{
2588198786Srpaulo	return (NDIS_STATUS_SUCCESS);
2589123507Swpaul}
2590123507Swpaul
2591144888Swpaulstatic void
2592140751SwpaulNdisInitAnsiString(dst, src)
2593151207Swpaul	ansi_string		*dst;
2594123526Swpaul	char			*src;
2595123526Swpaul{
2596151207Swpaul	RtlInitAnsiString(dst, src);
2597123526Swpaul}
2598123526Swpaul
2599144888Swpaulstatic void
2600140751SwpaulNdisInitUnicodeString(dst, src)
2601151207Swpaul	unicode_string		*dst;
2602123941Swpaul	uint16_t		*src;
2603123941Swpaul{
2604151207Swpaul	RtlInitUnicodeString(dst, src);
2605123941Swpaul}
2606123941Swpaul
2607144888Swpaulstatic void NdisMGetDeviceProperty(adapter, phydevobj,
2608123526Swpaul	funcdevobj, nextdevobj, resources, transresources)
2609123526Swpaul	ndis_handle		adapter;
2610125551Swpaul	device_object		**phydevobj;
2611125551Swpaul	device_object		**funcdevobj;
2612125551Swpaul	device_object		**nextdevobj;
2613123526Swpaul	cm_resource_list	*resources;
2614123526Swpaul	cm_resource_list	*transresources;
2615123526Swpaul{
2616125551Swpaul	ndis_miniport_block	*block;
2617125551Swpaul
2618125551Swpaul	block = (ndis_miniport_block *)adapter;
2619125551Swpaul
2620125551Swpaul	if (phydevobj != NULL)
2621141524Swpaul		*phydevobj = block->nmb_physdeviceobj;
2622125551Swpaul	if (funcdevobj != NULL)
2623141524Swpaul		*funcdevobj = block->nmb_deviceobj;
2624141524Swpaul	if (nextdevobj != NULL)
2625141524Swpaul		*nextdevobj = block->nmb_nextdeviceobj;
2626123526Swpaul}
2627123526Swpaul
2628144888Swpaulstatic void
2629140751SwpaulNdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen)
2630123721Swpaul	ndis_packet		*packet;
2631123721Swpaul	ndis_buffer		**buf;
2632123721Swpaul	void			**firstva;
2633123721Swpaul	uint32_t		*firstlen;
2634123721Swpaul	uint32_t		*totlen;
2635123721Swpaul{
2636123721Swpaul	ndis_buffer		*tmp;
2637123721Swpaul
2638123721Swpaul	tmp = packet->np_private.npp_head;
2639123721Swpaul	*buf = tmp;
2640123721Swpaul	if (tmp == NULL) {
2641123721Swpaul		*firstva = NULL;
2642123721Swpaul		*firstlen = *totlen = 0;
2643123721Swpaul	} else {
2644140751Swpaul		*firstva = MmGetMdlVirtualAddress(tmp);
2645140751Swpaul		*firstlen = *totlen = MmGetMdlByteCount(tmp);
2646140751Swpaul		for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next)
2647140751Swpaul			*totlen += MmGetMdlByteCount(tmp);
2648123721Swpaul	}
2649123721Swpaul}
2650123721Swpaul
2651144888Swpaulstatic void
2652140751SwpaulNdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio)
2653123721Swpaul	ndis_packet		*packet;
2654123721Swpaul	ndis_buffer		**buf;
2655123721Swpaul	void			**firstva;
2656123721Swpaul	uint32_t		*firstlen;
2657123721Swpaul	uint32_t		*totlen;
2658123721Swpaul	uint32_t		prio;
2659123721Swpaul{
2660140751Swpaul	NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen);
2661123721Swpaul}
2662123721Swpaul
2663132973Swpaulstatic int
2664132973Swpaulndis_find_sym(lf, filename, suffix, sym)
2665132973Swpaul	linker_file_t		lf;
2666132973Swpaul	char			*filename;
2667132973Swpaul	char			*suffix;
2668132973Swpaul	caddr_t			*sym;
2669132973Swpaul{
2670143086Swpaul	char			*fullsym;
2671133876Swpaul	char			*suf;
2672132973Swpaul	int			i;
2673132973Swpaul
2674143086Swpaul	fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2675143086Swpaul	if (fullsym == NULL)
2676198786Srpaulo		return (ENOMEM);
2677143086Swpaul
2678143086Swpaul	bzero(fullsym, MAXPATHLEN);
2679143086Swpaul	strncpy(fullsym, filename, MAXPATHLEN);
2680143086Swpaul	if (strlen(filename) < 4) {
2681143086Swpaul		ExFreePool(fullsym);
2682198786Srpaulo		return (EINVAL);
2683143086Swpaul	}
2684133876Swpaul
2685133876Swpaul	/* If the filename has a .ko suffix, strip if off. */
2686133876Swpaul	suf = fullsym + (strlen(filename) - 3);
2687133876Swpaul	if (strcmp(suf, ".ko") == 0)
2688133876Swpaul		*suf = '\0';
2689133876Swpaul
2690132973Swpaul	for (i = 0; i < strlen(fullsym); i++) {
2691132973Swpaul		if (fullsym[i] == '.')
2692132973Swpaul			fullsym[i] = '_';
2693132973Swpaul		else
2694132973Swpaul			fullsym[i] = tolower(fullsym[i]);
2695132973Swpaul	}
2696132973Swpaul	strcat(fullsym, suffix);
2697132973Swpaul	*sym = linker_file_lookup_symbol(lf, fullsym, 0);
2698143086Swpaul	ExFreePool(fullsym);
2699132973Swpaul	if (*sym == 0)
2700198786Srpaulo		return (ENOENT);
2701132973Swpaul
2702198786Srpaulo	return (0);
2703132973Swpaul}
2704132973Swpaul
2705159797Sjhbstruct ndis_checkmodule {
2706159797Sjhb	char	*afilename;
2707159797Sjhb	ndis_fh	*fh;
2708159797Sjhb};
2709159797Sjhb
2710159797Sjhb/*
2711159797Sjhb * See if a single module contains the symbols for a specified file.
2712159797Sjhb */
2713159797Sjhbstatic int
2714159797SjhbNdisCheckModule(linker_file_t lf, void *context)
2715159797Sjhb{
2716159797Sjhb	struct ndis_checkmodule *nc;
2717159797Sjhb	caddr_t			kldstart, kldend;
2718159797Sjhb
2719159797Sjhb	nc = (struct ndis_checkmodule *)context;
2720159797Sjhb	if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart))
2721159797Sjhb		return (0);
2722159797Sjhb	if (ndis_find_sym(lf, nc->afilename, "_end", &kldend))
2723159797Sjhb		return (0);
2724159797Sjhb	nc->fh->nf_vp = lf;
2725159797Sjhb	nc->fh->nf_map = NULL;
2726159797Sjhb	nc->fh->nf_type = NDIS_FH_TYPE_MODULE;
2727159797Sjhb	nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF;
2728159797Sjhb	return (1);
2729159797Sjhb}
2730159797Sjhb
2731123822Swpaul/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
2732144888Swpaulstatic void
2733140751SwpaulNdisOpenFile(status, filehandle, filelength, filename, highestaddr)
2734123822Swpaul	ndis_status		*status;
2735123822Swpaul	ndis_handle		*filehandle;
2736123822Swpaul	uint32_t		*filelength;
2737151207Swpaul	unicode_string		*filename;
2738123822Swpaul	ndis_physaddr		highestaddr;
2739123822Swpaul{
2740151207Swpaul	ansi_string		as;
2741123822Swpaul	char			*afilename = NULL;
2742124272Swpaul	struct thread		*td = curthread;
2743124272Swpaul	struct nameidata	nd;
2744159808Sjhb	int			flags, error, vfslocked;
2745124272Swpaul	struct vattr		vat;
2746124272Swpaul	struct vattr		*vap = &vat;
2747124272Swpaul	ndis_fh			*fh;
2748143086Swpaul	char			*path;
2749159797Sjhb	struct ndis_checkmodule	nc;
2750123822Swpaul
2751151207Swpaul	if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) {
2752151207Swpaul		*status = NDIS_STATUS_RESOURCES;
2753151207Swpaul		return;
2754151207Swpaul	}
2755124272Swpaul
2756151207Swpaul	afilename = strdup(as.as_buf, M_DEVBUF);
2757151207Swpaul	RtlFreeAnsiString(&as);
2758151207Swpaul
2759143086Swpaul	fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0);
2760124272Swpaul	if (fh == NULL) {
2761145895Swpaul		free(afilename, M_DEVBUF);
2762124272Swpaul		*status = NDIS_STATUS_RESOURCES;
2763124272Swpaul		return;
2764124272Swpaul	}
2765124272Swpaul
2766145895Swpaul	fh->nf_name = afilename;
2767145895Swpaul
2768132973Swpaul	/*
2769132973Swpaul	 * During system bootstrap, it's impossible to load files
2770132973Swpaul	 * from the rootfs since it's not mounted yet. We therefore
2771132973Swpaul	 * offer the possibility of opening files that have been
2772132973Swpaul	 * preloaded as modules instead. Both choices will work
2773132973Swpaul	 * when kldloading a module from multiuser, but only the
2774132973Swpaul	 * module option will work during bootstrap. The module
2775132973Swpaul	 * loading option works by using the ndiscvt(8) utility
2776132973Swpaul	 * to convert the arbitrary file into a .ko using objcopy(1).
2777132973Swpaul	 * This file will contain two special symbols: filename_start
2778132973Swpaul	 * and filename_end. All we have to do is traverse the KLD
2779132973Swpaul	 * list in search of those symbols and we've found the file
2780132973Swpaul	 * data. As an added bonus, ndiscvt(8) will also generate
2781132973Swpaul	 * a normal .o file which can be linked statically with
2782132973Swpaul	 * the kernel. This means that the symbols will actual reside
2783132973Swpaul	 * in the kernel's symbol table, but that doesn't matter to
2784132973Swpaul	 * us since the kernel appears to us as just another module.
2785132973Swpaul	 */
2786132973Swpaul
2787159797Sjhb	nc.afilename = afilename;
2788159797Sjhb	nc.fh = fh;
2789159797Sjhb	if (linker_file_foreach(NdisCheckModule, &nc)) {
2790159797Sjhb		*filelength = fh->nf_maplen;
2791132973Swpaul		*filehandle = fh;
2792132973Swpaul		*status = NDIS_STATUS_SUCCESS;
2793132973Swpaul		return;
2794132973Swpaul	}
2795132973Swpaul
2796132973Swpaul	if (TAILQ_EMPTY(&mountlist)) {
2797144256Swpaul		ExFreePool(fh);
2798132973Swpaul		*status = NDIS_STATUS_FILE_NOT_FOUND;
2799132973Swpaul		printf("NDIS: could not find file %s in linker list\n",
2800132973Swpaul		    afilename);
2801132973Swpaul		printf("NDIS: and no filesystems mounted yet, "
2802132973Swpaul		    "aborting NdisOpenFile()\n");
2803132973Swpaul		free(afilename, M_DEVBUF);
2804132973Swpaul		return;
2805132973Swpaul	}
2806132973Swpaul
2807143086Swpaul	path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2808143086Swpaul	if (path == NULL) {
2809144256Swpaul		ExFreePool(fh);
2810145895Swpaul		free(afilename, M_DEVBUF);
2811143086Swpaul		*status = NDIS_STATUS_RESOURCES;
2812143086Swpaul		return;
2813143086Swpaul	}
2814143086Swpaul
2815143086Swpaul	snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename);
2816132973Swpaul
2817125377Swpaul	/* Some threads don't have a current working directory. */
2818125377Swpaul
2819125377Swpaul	if (td->td_proc->p_fd->fd_rdir == NULL)
2820125377Swpaul		td->td_proc->p_fd->fd_rdir = rootvnode;
2821125377Swpaul	if (td->td_proc->p_fd->fd_cdir == NULL)
2822125377Swpaul		td->td_proc->p_fd->fd_cdir = rootvnode;
2823125377Swpaul
2824159808Sjhb	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, path, td);
2825124272Swpaul
2826124272Swpaul	flags = FREAD;
2827170152Skib	error = vn_open(&nd, &flags, 0, NULL);
2828124272Swpaul	if (error) {
2829124272Swpaul		*status = NDIS_STATUS_FILE_NOT_FOUND;
2830143086Swpaul		ExFreePool(fh);
2831127887Swpaul		printf("NDIS: open file %s failed: %d\n", path, error);
2832143086Swpaul		ExFreePool(path);
2833145895Swpaul		free(afilename, M_DEVBUF);
2834124272Swpaul		return;
2835124272Swpaul	}
2836159808Sjhb	vfslocked = NDHASGIANT(&nd);
2837124272Swpaul
2838143086Swpaul	ExFreePool(path);
2839143086Swpaul
2840124272Swpaul	NDFREE(&nd, NDF_ONLY_PNBUF);
2841124272Swpaul
2842124272Swpaul	/* Get the file size. */
2843182371Sattilio	VOP_GETATTR(nd.ni_vp, vap, td->td_ucred);
2844175294Sattilio	VOP_UNLOCK(nd.ni_vp, 0);
2845159808Sjhb	VFS_UNLOCK_GIANT(vfslocked);
2846124272Swpaul
2847124272Swpaul	fh->nf_vp = nd.ni_vp;
2848124272Swpaul	fh->nf_map = NULL;
2849132973Swpaul	fh->nf_type = NDIS_FH_TYPE_VFS;
2850124272Swpaul	*filehandle = fh;
2851124272Swpaul	*filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
2852124272Swpaul	*status = NDIS_STATUS_SUCCESS;
2853123822Swpaul}
2854123822Swpaul
2855144888Swpaulstatic void
2856140751SwpaulNdisMapFile(status, mappedbuffer, filehandle)
2857123822Swpaul	ndis_status		*status;
2858123822Swpaul	void			**mappedbuffer;
2859123822Swpaul	ndis_handle		filehandle;
2860123822Swpaul{
2861124272Swpaul	ndis_fh			*fh;
2862124272Swpaul	struct thread		*td = curthread;
2863133876Swpaul	linker_file_t		lf;
2864133876Swpaul	caddr_t			kldstart;
2865233353Skib	int			error, vfslocked;
2866233353Skib	ssize_t			resid;
2867159808Sjhb	struct vnode		*vp;
2868123822Swpaul
2869124272Swpaul	if (filehandle == NULL) {
2870124272Swpaul		*status = NDIS_STATUS_FAILURE;
2871124272Swpaul		return;
2872124272Swpaul	}
2873124272Swpaul
2874124272Swpaul	fh = (ndis_fh *)filehandle;
2875124272Swpaul
2876124272Swpaul	if (fh->nf_vp == NULL) {
2877124272Swpaul		*status = NDIS_STATUS_FAILURE;
2878124272Swpaul		return;
2879124272Swpaul	}
2880124272Swpaul
2881124272Swpaul	if (fh->nf_map != NULL) {
2882124272Swpaul		*status = NDIS_STATUS_ALREADY_MAPPED;
2883124272Swpaul		return;
2884124272Swpaul	}
2885124272Swpaul
2886132973Swpaul	if (fh->nf_type == NDIS_FH_TYPE_MODULE) {
2887133876Swpaul		lf = fh->nf_vp;
2888145895Swpaul		if (ndis_find_sym(lf, fh->nf_name, "_start", &kldstart)) {
2889133876Swpaul			*status = NDIS_STATUS_FAILURE;
2890133876Swpaul			return;
2891133876Swpaul		}
2892133876Swpaul		fh->nf_map = kldstart;
2893132973Swpaul		*status = NDIS_STATUS_SUCCESS;
2894132973Swpaul		*mappedbuffer = fh->nf_map;
2895132973Swpaul		return;
2896132973Swpaul	}
2897132973Swpaul
2898143086Swpaul	fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0);
2899124272Swpaul
2900124272Swpaul	if (fh->nf_map == NULL) {
2901124272Swpaul		*status = NDIS_STATUS_RESOURCES;
2902124272Swpaul		return;
2903124272Swpaul	}
2904124272Swpaul
2905159808Sjhb	vp = fh->nf_vp;
2906159808Sjhb	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
2907159808Sjhb	error = vn_rdwr(UIO_READ, vp, fh->nf_map, fh->nf_maplen, 0,
2908124272Swpaul	    UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td);
2909159808Sjhb	VFS_UNLOCK_GIANT(vfslocked);
2910124272Swpaul
2911124272Swpaul	if (error)
2912124272Swpaul		*status = NDIS_STATUS_FAILURE;
2913124272Swpaul	else {
2914124272Swpaul		*status = NDIS_STATUS_SUCCESS;
2915124272Swpaul		*mappedbuffer = fh->nf_map;
2916124272Swpaul	}
2917123822Swpaul}
2918123822Swpaul
2919144888Swpaulstatic void
2920140751SwpaulNdisUnmapFile(filehandle)
2921123822Swpaul	ndis_handle		filehandle;
2922123822Swpaul{
2923124272Swpaul	ndis_fh			*fh;
2924124272Swpaul	fh = (ndis_fh *)filehandle;
2925124272Swpaul
2926124272Swpaul	if (fh->nf_map == NULL)
2927124272Swpaul		return;
2928132973Swpaul
2929132973Swpaul	if (fh->nf_type == NDIS_FH_TYPE_VFS)
2930143086Swpaul		ExFreePool(fh->nf_map);
2931124272Swpaul	fh->nf_map = NULL;
2932123822Swpaul}
2933123822Swpaul
2934144888Swpaulstatic void
2935140751SwpaulNdisCloseFile(filehandle)
2936123822Swpaul	ndis_handle		filehandle;
2937123822Swpaul{
2938124272Swpaul	struct thread		*td = curthread;
2939124272Swpaul	ndis_fh			*fh;
2940159808Sjhb	int			vfslocked;
2941159808Sjhb	struct vnode		*vp;
2942124272Swpaul
2943124272Swpaul	if (filehandle == NULL)
2944124272Swpaul		return;
2945124272Swpaul
2946124272Swpaul	fh = (ndis_fh *)filehandle;
2947124272Swpaul	if (fh->nf_map != NULL) {
2948132973Swpaul		if (fh->nf_type == NDIS_FH_TYPE_VFS)
2949143086Swpaul			ExFreePool(fh->nf_map);
2950124272Swpaul		fh->nf_map = NULL;
2951124272Swpaul	}
2952124272Swpaul
2953124272Swpaul	if (fh->nf_vp == NULL)
2954124272Swpaul		return;
2955124272Swpaul
2956132973Swpaul	if (fh->nf_type == NDIS_FH_TYPE_VFS) {
2957159808Sjhb		vp = fh->nf_vp;
2958159808Sjhb		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
2959159808Sjhb		vn_close(vp, FREAD, td->td_ucred, td);
2960159808Sjhb		VFS_UNLOCK_GIANT(vfslocked);
2961132973Swpaul	}
2962124272Swpaul
2963124272Swpaul	fh->nf_vp = NULL;
2964145895Swpaul	free(fh->nf_name, M_DEVBUF);
2965143086Swpaul	ExFreePool(fh);
2966123822Swpaul}
2967123822Swpaul
2968144888Swpaulstatic uint8_t
2969140751SwpaulNdisSystemProcessorCount()
2970123848Swpaul{
2971198786Srpaulo	return (mp_ncpus);
2972124509Swpaul}
2973123848Swpaul
2974215779Sbschmidtstatic void
2975215779SbschmidtNdisGetCurrentProcessorCounts(idle_count, kernel_and_user, index)
2976215779Sbschmidt	uint32_t		*idle_count;
2977215779Sbschmidt	uint32_t		*kernel_and_user;
2978215779Sbschmidt	uint32_t		*index;
2979215779Sbschmidt{
2980215779Sbschmidt	struct pcpu		*pcpu;
2981215779Sbschmidt
2982215779Sbschmidt	pcpu = pcpu_find(curthread->td_oncpu);
2983215779Sbschmidt	*index = pcpu->pc_cpuid;
2984215779Sbschmidt	*idle_count = pcpu->pc_cp_time[CP_IDLE];
2985215779Sbschmidt	*kernel_and_user = pcpu->pc_cp_time[CP_INTR];
2986215779Sbschmidt}
2987215779Sbschmidt
2988124116Swpaultypedef void (*ndis_statusdone_handler)(ndis_handle);
2989124116Swpaultypedef void (*ndis_status_handler)(ndis_handle, ndis_status,
2990189488Sweongyo    void *, uint32_t);
2991124116Swpaul
2992144888Swpaulstatic void
2993140751SwpaulNdisMIndicateStatusComplete(adapter)
2994124116Swpaul	ndis_handle		adapter;
2995124116Swpaul{
2996124116Swpaul	ndis_miniport_block	*block;
2997144888Swpaul	ndis_statusdone_handler	statusdonefunc;
2998124116Swpaul
2999124116Swpaul	block = (ndis_miniport_block *)adapter;
3000124116Swpaul	statusdonefunc = block->nmb_statusdone_func;
3001124116Swpaul
3002141963Swpaul	MSCALL1(statusdonefunc, adapter);
3003124116Swpaul}
3004124116Swpaul
3005144888Swpaulstatic void
3006140751SwpaulNdisMIndicateStatus(adapter, status, sbuf, slen)
3007124116Swpaul	ndis_handle		adapter;
3008124116Swpaul	ndis_status		status;
3009124116Swpaul	void			*sbuf;
3010124116Swpaul	uint32_t		slen;
3011124116Swpaul{
3012124116Swpaul	ndis_miniport_block	*block;
3013144888Swpaul	ndis_status_handler	statusfunc;
3014124116Swpaul
3015124116Swpaul	block = (ndis_miniport_block *)adapter;
3016124116Swpaul	statusfunc = block->nmb_status_func;
3017124116Swpaul
3018141963Swpaul	MSCALL4(statusfunc, adapter, status, sbuf, slen);
3019124116Swpaul}
3020124116Swpaul
3021145895Swpaul/*
3022145895Swpaul * The DDK documentation says that you should use IoQueueWorkItem()
3023145895Swpaul * instead of ExQueueWorkItem(). The problem is, IoQueueWorkItem()
3024145895Swpaul * is fundamentally incompatible with NdisScheduleWorkItem(), which
3025145895Swpaul * depends on the API semantics of ExQueueWorkItem(). In our world,
3026145895Swpaul * ExQueueWorkItem() is implemented on top of IoAllocateQueueItem()
3027145895Swpaul * anyway.
3028146273Swpaul *
3029146273Swpaul * There are actually three distinct APIs here. NdisScheduleWorkItem()
3030146273Swpaul * takes a pointer to an NDIS_WORK_ITEM. ExQueueWorkItem() takes a pointer
3031146273Swpaul * to a WORK_QUEUE_ITEM. And finally, IoQueueWorkItem() takes a pointer
3032146273Swpaul * to an opaque work item thingie which you get from IoAllocateWorkItem().
3033146273Swpaul * An NDIS_WORK_ITEM is not the same as a WORK_QUEUE_ITEM. However,
3034146273Swpaul * the NDIS_WORK_ITEM has some opaque storage at the end of it, and we
3035146273Swpaul * (ab)use this storage as a WORK_QUEUE_ITEM, which is what we submit
3036146273Swpaul * to ExQueueWorkItem().
3037146273Swpaul *
3038146273Swpaul * Got all that? (Sheesh.)
3039145895Swpaul */
3040124122Swpaul
3041145895Swpaulndis_status
3042140751SwpaulNdisScheduleWorkItem(work)
3043124122Swpaul	ndis_work_item		*work;
3044124122Swpaul{
3045146273Swpaul	work_queue_item		*wqi;
3046146273Swpaul
3047146273Swpaul	wqi = (work_queue_item *)work->nwi_wraprsvd;
3048146273Swpaul	ExInitializeWorkItem(wqi,
3049146273Swpaul	    (work_item_func)work->nwi_func, work->nwi_ctx);
3050146273Swpaul	ExQueueWorkItem(wqi, WORKQUEUE_DELAYED);
3051151207Swpaul
3052198786Srpaulo	return (NDIS_STATUS_SUCCESS);
3053124122Swpaul}
3054124122Swpaul
3055144888Swpaulstatic void
3056140751SwpaulNdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen)
3057124541Swpaul	ndis_packet		*dpkt;
3058124541Swpaul	uint32_t		doff;
3059124541Swpaul	uint32_t		reqlen;
3060124541Swpaul	ndis_packet		*spkt;
3061124541Swpaul	uint32_t		soff;
3062124541Swpaul	uint32_t		*cpylen;
3063124541Swpaul{
3064124541Swpaul	ndis_buffer		*src, *dst;
3065124541Swpaul	char			*sptr, *dptr;
3066124541Swpaul	int			resid, copied, len, scnt, dcnt;
3067124541Swpaul
3068124541Swpaul	*cpylen = 0;
3069124541Swpaul
3070124541Swpaul	src = spkt->np_private.npp_head;
3071124541Swpaul	dst = dpkt->np_private.npp_head;
3072124541Swpaul
3073140751Swpaul	sptr = MmGetMdlVirtualAddress(src);
3074140751Swpaul	dptr = MmGetMdlVirtualAddress(dst);
3075140751Swpaul	scnt = MmGetMdlByteCount(src);
3076140751Swpaul	dcnt = MmGetMdlByteCount(dst);
3077124541Swpaul
3078124541Swpaul	while (soff) {
3079140751Swpaul		if (MmGetMdlByteCount(src) > soff) {
3080124541Swpaul			sptr += soff;
3081140751Swpaul			scnt = MmGetMdlByteCount(src)- soff;
3082124541Swpaul			break;
3083124541Swpaul		}
3084140751Swpaul		soff -= MmGetMdlByteCount(src);
3085140751Swpaul		src = src->mdl_next;
3086124541Swpaul		if (src == NULL)
3087124541Swpaul			return;
3088140751Swpaul		sptr = MmGetMdlVirtualAddress(src);
3089124541Swpaul	}
3090124541Swpaul
3091124541Swpaul	while (doff) {
3092140751Swpaul		if (MmGetMdlByteCount(dst) > doff) {
3093124541Swpaul			dptr += doff;
3094140751Swpaul			dcnt = MmGetMdlByteCount(dst) - doff;
3095124541Swpaul			break;
3096124541Swpaul		}
3097140751Swpaul		doff -= MmGetMdlByteCount(dst);
3098140751Swpaul		dst = dst->mdl_next;
3099124541Swpaul		if (dst == NULL)
3100124541Swpaul			return;
3101140751Swpaul		dptr = MmGetMdlVirtualAddress(dst);
3102124541Swpaul	}
3103124541Swpaul
3104124541Swpaul	resid = reqlen;
3105124541Swpaul	copied = 0;
3106124541Swpaul
3107124541Swpaul	while(1) {
3108124541Swpaul		if (resid < scnt)
3109124541Swpaul			len = resid;
3110124541Swpaul		else
3111124541Swpaul			len = scnt;
3112124541Swpaul		if (dcnt < len)
3113124541Swpaul			len = dcnt;
3114124541Swpaul
3115124541Swpaul		bcopy(sptr, dptr, len);
3116124541Swpaul
3117124541Swpaul		copied += len;
3118124541Swpaul		resid -= len;
3119124541Swpaul		if (resid == 0)
3120124541Swpaul			break;
3121124541Swpaul
3122124541Swpaul		dcnt -= len;
3123124541Swpaul		if (dcnt == 0) {
3124140751Swpaul			dst = dst->mdl_next;
3125124541Swpaul			if (dst == NULL)
3126124541Swpaul				break;
3127140751Swpaul			dptr = MmGetMdlVirtualAddress(dst);
3128140751Swpaul			dcnt = MmGetMdlByteCount(dst);
3129124541Swpaul		}
3130124541Swpaul
3131124541Swpaul		scnt -= len;
3132124541Swpaul		if (scnt == 0) {
3133140751Swpaul			src = src->mdl_next;
3134124541Swpaul			if (src == NULL)
3135124541Swpaul				break;
3136140751Swpaul			sptr = MmGetMdlVirtualAddress(src);
3137140751Swpaul			scnt = MmGetMdlByteCount(src);
3138124541Swpaul		}
3139124541Swpaul	}
3140124541Swpaul
3141124541Swpaul	*cpylen = copied;
3142124541Swpaul}
3143124541Swpaul
3144144888Swpaulstatic void
3145140751SwpaulNdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
3146124541Swpaul	ndis_packet		*dpkt;
3147124541Swpaul	uint32_t		doff;
3148124541Swpaul	uint32_t		reqlen;
3149124541Swpaul	ndis_packet		*spkt;
3150124541Swpaul	uint32_t		soff;
3151124541Swpaul	uint32_t		*cpylen;
3152124541Swpaul	uint32_t		prio;
3153124541Swpaul{
3154140751Swpaul	NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen);
3155124541Swpaul}
3156124541Swpaul
3157174240Sthompsastatic void
3158174240SthompsaNdisIMCopySendPerPacketInfo(dpkt, spkt)
3159174240Sthompsa	ndis_packet		*dpkt;
3160174240Sthompsa	ndis_packet		*spkt;
3161174240Sthompsa{
3162174240Sthompsa	memcpy(&dpkt->np_ext, &spkt->np_ext, sizeof(ndis_packet_extension));
3163174240Sthompsa}
3164174240Sthompsa
3165144888Swpaulstatic ndis_status
3166140751SwpaulNdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle)
3167125551Swpaul	ndis_handle		handle;
3168151207Swpaul	unicode_string		*devname;
3169151207Swpaul	unicode_string		*symname;
3170125551Swpaul	driver_dispatch		*majorfuncs[];
3171125551Swpaul	void			**devobj;
3172125551Swpaul	ndis_handle		*devhandle;
3173125057Swpaul{
3174146364Swpaul	uint32_t		status;
3175146364Swpaul	device_object		*dobj;
3176125551Swpaul
3177146364Swpaul	status = IoCreateDevice(handle, 0, devname,
3178146364Swpaul	    FILE_DEVICE_UNKNOWN, 0, FALSE, &dobj);
3179125551Swpaul
3180146364Swpaul	if (status == STATUS_SUCCESS) {
3181146364Swpaul		*devobj = dobj;
3182146364Swpaul		*devhandle = dobj;
3183146364Swpaul	}
3184146364Swpaul
3185198786Srpaulo	return (status);
3186125057Swpaul}
3187125057Swpaul
3188144888Swpaulstatic ndis_status
3189140751SwpaulNdisMDeregisterDevice(handle)
3190125551Swpaul	ndis_handle		handle;
3191125057Swpaul{
3192146364Swpaul	IoDeleteDevice(handle);
3193198786Srpaulo	return (NDIS_STATUS_SUCCESS);
3194125057Swpaul}
3195125057Swpaul
3196144888Swpaulstatic ndis_status
3197140751SwpaulNdisMQueryAdapterInstanceName(name, handle)
3198151207Swpaul	unicode_string		*name;
3199125551Swpaul	ndis_handle		handle;
3200125551Swpaul{
3201125551Swpaul	ndis_miniport_block	*block;
3202141524Swpaul	device_t		dev;
3203151207Swpaul	ansi_string		as;
3204125057Swpaul
3205125551Swpaul	block = (ndis_miniport_block *)handle;
3206141524Swpaul	dev = block->nmb_physdeviceobj->do_devext;
3207141524Swpaul
3208151207Swpaul	RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev)));
3209151207Swpaul	if (RtlAnsiStringToUnicodeString(name, &as, TRUE))
3210198786Srpaulo		return (NDIS_STATUS_RESOURCES);
3211125551Swpaul
3212198786Srpaulo	return (NDIS_STATUS_SUCCESS);
3213125551Swpaul}
3214125551Swpaul
3215144888Swpaulstatic void
3216140751SwpaulNdisMRegisterUnloadHandler(handle, func)
3217125551Swpaul	ndis_handle		handle;
3218125551Swpaul	void			*func;
3219125551Swpaul{
3220125551Swpaul}
3221125551Swpaul
3222144888Swpaulstatic void
3223123474Swpauldummy()
3224123474Swpaul{
3225198786Srpaulo	printf("NDIS dummy called...\n");
3226123474Swpaul}
3227123474Swpaul
3228144888Swpaul/*
3229144888Swpaul * Note: a couple of entries in this table specify the
3230144888Swpaul * number of arguments as "foo + 1". These are routines
3231144888Swpaul * that accept a 64-bit argument, passed by value. On
3232144888Swpaul * x86, these arguments consume two longwords on the stack,
3233144888Swpaul * so we lie and say there's one additional argument so
3234144888Swpaul * that the wrapping routines will do the right thing.
3235144888Swpaul */
3236144888Swpaul
3237123474Swpaulimage_patch_table ndis_functbl[] = {
3238144888Swpaul	IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6),
3239144888Swpaul	IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7),
3240174240Sthompsa	IMPORT_SFUNC(NdisIMCopySendPerPacketInfo, 2),
3241144888Swpaul	IMPORT_SFUNC(NdisScheduleWorkItem, 1),
3242144888Swpaul	IMPORT_SFUNC(NdisMIndicateStatusComplete, 1),
3243144888Swpaul	IMPORT_SFUNC(NdisMIndicateStatus, 4),
3244144888Swpaul	IMPORT_SFUNC(NdisSystemProcessorCount, 0),
3245215779Sbschmidt	IMPORT_SFUNC(NdisGetCurrentProcessorCounts, 3),
3246144888Swpaul	IMPORT_SFUNC(NdisUnchainBufferAtBack, 2),
3247144888Swpaul	IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5),
3248144888Swpaul	IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6),
3249144888Swpaul	IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2),
3250144888Swpaul	IMPORT_SFUNC(NdisMGetDeviceProperty, 6),
3251144888Swpaul	IMPORT_SFUNC(NdisInitAnsiString, 2),
3252144888Swpaul	IMPORT_SFUNC(NdisInitUnicodeString, 2),
3253144888Swpaul	IMPORT_SFUNC(NdisWriteConfiguration, 4),
3254144888Swpaul	IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2),
3255144888Swpaul	IMPORT_SFUNC(NdisTerminateWrapper, 2),
3256144888Swpaul	IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4),
3257144888Swpaul	IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5),
3258144888Swpaul	IMPORT_SFUNC(NdisMRemoveMiniport, 1),
3259189488Sweongyo	IMPORT_SFUNC(NdisInitializeString, 2),
3260189488Sweongyo	IMPORT_SFUNC(NdisFreeString, 1),
3261144888Swpaul	IMPORT_SFUNC(NdisGetCurrentSystemTime, 1),
3262216242Sbschmidt	IMPORT_SFUNC(NdisGetRoutineAddress, 1),
3263144888Swpaul	IMPORT_SFUNC(NdisGetSystemUpTime, 1),
3264215779Sbschmidt	IMPORT_SFUNC(NdisGetVersion, 0),
3265144888Swpaul	IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3),
3266144888Swpaul	IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4),
3267144888Swpaul	IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3),
3268144888Swpaul	IMPORT_SFUNC(NdisInterlockedInsertTailList, 3),
3269144888Swpaul	IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2),
3270144888Swpaul	IMPORT_SFUNC(NdisInitializeWrapper, 4),
3271144888Swpaul	IMPORT_SFUNC(NdisMRegisterMiniport, 3),
3272144888Swpaul	IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3),
3273144888Swpaul	IMPORT_SFUNC(NdisAllocateMemory, 4 + 1),
3274144888Swpaul	IMPORT_SFUNC(NdisMSetAttributesEx, 5),
3275144888Swpaul	IMPORT_SFUNC(NdisCloseConfiguration, 1),
3276144888Swpaul	IMPORT_SFUNC(NdisReadConfiguration, 5),
3277144888Swpaul	IMPORT_SFUNC(NdisOpenConfiguration, 3),
3278144888Swpaul	IMPORT_SFUNC(NdisAcquireSpinLock, 1),
3279144888Swpaul	IMPORT_SFUNC(NdisReleaseSpinLock, 1),
3280144888Swpaul	IMPORT_SFUNC(NdisDprAcquireSpinLock, 1),
3281144888Swpaul	IMPORT_SFUNC(NdisDprReleaseSpinLock, 1),
3282144888Swpaul	IMPORT_SFUNC(NdisAllocateSpinLock, 1),
3283145895Swpaul	IMPORT_SFUNC(NdisInitializeReadWriteLock, 1),
3284145895Swpaul	IMPORT_SFUNC(NdisAcquireReadWriteLock, 3),
3285145895Swpaul	IMPORT_SFUNC(NdisReleaseReadWriteLock, 2),
3286144888Swpaul	IMPORT_SFUNC(NdisFreeSpinLock, 1),
3287144888Swpaul	IMPORT_SFUNC(NdisFreeMemory, 3),
3288144888Swpaul	IMPORT_SFUNC(NdisReadPciSlotInformation, 5),
3289144888Swpaul	IMPORT_SFUNC(NdisWritePciSlotInformation, 5),
3290144888Swpaul	IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation,
3291144888Swpaul	    NdisReadPciSlotInformation, 5),
3292144888Swpaul	IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation,
3293144888Swpaul	    NdisWritePciSlotInformation, 5),
3294144888Swpaul	IMPORT_CFUNC(NdisWriteErrorLogEntry, 0),
3295144888Swpaul	IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6),
3296144888Swpaul	IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3),
3297144888Swpaul	IMPORT_SFUNC(NdisMInitializeTimer, 4),
3298144888Swpaul	IMPORT_SFUNC(NdisInitializeTimer, 3),
3299144888Swpaul	IMPORT_SFUNC(NdisSetTimer, 2),
3300144888Swpaul	IMPORT_SFUNC(NdisMCancelTimer, 2),
3301144888Swpaul	IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2),
3302144888Swpaul	IMPORT_SFUNC(NdisMSetPeriodicTimer, 2),
3303144888Swpaul	IMPORT_SFUNC(NdisMQueryAdapterResources, 4),
3304144888Swpaul	IMPORT_SFUNC(NdisMRegisterIoPortRange, 4),
3305144888Swpaul	IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4),
3306144888Swpaul	IMPORT_SFUNC(NdisReadNetworkAddress, 4),
3307144888Swpaul	IMPORT_SFUNC(NdisQueryMapRegisterCount, 2),
3308144888Swpaul	IMPORT_SFUNC(NdisMAllocateMapRegisters, 5),
3309144888Swpaul	IMPORT_SFUNC(NdisMFreeMapRegisters, 1),
3310144888Swpaul	IMPORT_SFUNC(NdisMAllocateSharedMemory, 5),
3311144888Swpaul	IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1),
3312144888Swpaul	IMPORT_SFUNC(NdisMUnmapIoSpace, 3),
3313144888Swpaul	IMPORT_SFUNC(NdisGetCacheFillSize, 0),
3314144888Swpaul	IMPORT_SFUNC(NdisMGetDmaAlignment, 1),
3315144888Swpaul	IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3),
3316144888Swpaul	IMPORT_SFUNC(NdisAllocatePacketPool, 4),
3317144888Swpaul	IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5),
3318144888Swpaul	IMPORT_SFUNC(NdisAllocatePacket, 3),
3319144888Swpaul	IMPORT_SFUNC(NdisFreePacket, 1),
3320144888Swpaul	IMPORT_SFUNC(NdisFreePacketPool, 1),
3321144888Swpaul	IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3),
3322144888Swpaul	IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1),
3323144888Swpaul	IMPORT_SFUNC(NdisAllocateBufferPool, 3),
3324144888Swpaul	IMPORT_SFUNC(NdisAllocateBuffer, 5),
3325144888Swpaul	IMPORT_SFUNC(NdisQueryBuffer, 3),
3326144888Swpaul	IMPORT_SFUNC(NdisQueryBufferSafe, 4),
3327144888Swpaul	IMPORT_SFUNC(NdisBufferVirtualAddress, 1),
3328144888Swpaul	IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2),
3329144888Swpaul	IMPORT_SFUNC(NdisBufferLength, 1),
3330144888Swpaul	IMPORT_SFUNC(NdisFreeBuffer, 1),
3331144888Swpaul	IMPORT_SFUNC(NdisFreeBufferPool, 1),
3332144888Swpaul	IMPORT_SFUNC(NdisInterlockedIncrement, 1),
3333144888Swpaul	IMPORT_SFUNC(NdisInterlockedDecrement, 1),
3334144888Swpaul	IMPORT_SFUNC(NdisInitializeEvent, 1),
3335144888Swpaul	IMPORT_SFUNC(NdisSetEvent, 1),
3336144888Swpaul	IMPORT_SFUNC(NdisResetEvent, 1),
3337144888Swpaul	IMPORT_SFUNC(NdisWaitEvent, 2),
3338144888Swpaul	IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2),
3339144888Swpaul	IMPORT_SFUNC(NdisMPciAssignResources, 3),
3340144888Swpaul	IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1),
3341144888Swpaul	IMPORT_SFUNC(NdisMRegisterInterrupt, 7),
3342144888Swpaul	IMPORT_SFUNC(NdisMDeregisterInterrupt, 1),
3343144888Swpaul	IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3),
3344144888Swpaul	IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1),
3345144888Swpaul	IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1),
3346144888Swpaul	IMPORT_SFUNC(NdisQueryBufferOffset, 3),
3347144888Swpaul	IMPORT_SFUNC(NdisAdjustBufferLength, 2),
3348144888Swpaul	IMPORT_SFUNC(NdisPacketPoolUsage, 1),
3349144888Swpaul	IMPORT_SFUNC(NdisMSleep, 1),
3350144888Swpaul	IMPORT_SFUNC(NdisUnchainBufferAtFront, 2),
3351144888Swpaul	IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4),
3352144888Swpaul	IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4),
3353144888Swpaul	IMPORT_SFUNC(NdisOpenFile, 5 + 1),
3354144888Swpaul	IMPORT_SFUNC(NdisMapFile, 3),
3355144888Swpaul	IMPORT_SFUNC(NdisUnmapFile, 1),
3356144888Swpaul	IMPORT_SFUNC(NdisCloseFile, 1),
3357144888Swpaul	IMPORT_SFUNC(NdisMRegisterDevice, 6),
3358144888Swpaul	IMPORT_SFUNC(NdisMDeregisterDevice, 1),
3359144888Swpaul	IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2),
3360144888Swpaul	IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2),
3361144888Swpaul	IMPORT_SFUNC(ndis_timercall, 4),
3362145895Swpaul	IMPORT_SFUNC(ndis_asyncmem_complete, 2),
3363152626Swpaul	IMPORT_SFUNC(ndis_intr, 2),
3364151207Swpaul	IMPORT_SFUNC(ndis_intrhand, 4),
3365123474Swpaul
3366123474Swpaul	/*
3367123474Swpaul	 * This last entry is a catch-all for any function we haven't
3368123474Swpaul	 * implemented yet. The PE import list patching routine will
3369123474Swpaul	 * use it for any function that doesn't have an explicit match
3370123474Swpaul	 * in this table.
3371123474Swpaul	 */
3372123474Swpaul
3373145895Swpaul	{ NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
3374123474Swpaul
3375123474Swpaul	/* End of list. */
3376123474Swpaul
3377141963Swpaul	{ NULL, NULL, NULL }
3378123474Swpaul};
3379