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