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