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