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