subr_ndis.c revision 175294
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 175294 2008-01-13 14:44:15Z attilio $");
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->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->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
1364#ifdef IFP2ENADDR
1365	if (bcmp(IFP2ENADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0)
1366#elif __FreeBSD_version >= 700000
1367	if (sc->ifp->if_addr == NULL ||
1368	    bcmp(IF_LLADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0)
1369#else
1370	if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0)
1371#endif
1372		*status = NDIS_STATUS_FAILURE;
1373	else {
1374#ifdef IFP2ENADDR
1375		*addr = IFP2ENADDR(sc->ifp);
1376#elif __FreeBSD_version >= 700000
1377		*addr = IF_LLADDR(sc->ifp);
1378#else
1379		*addr = sc->arpcom.ac_enaddr;
1380#endif
1381		*addrlen = ETHER_ADDR_LEN;
1382		*status = NDIS_STATUS_SUCCESS;
1383	}
1384
1385	return;
1386}
1387
1388static ndis_status
1389NdisQueryMapRegisterCount(bustype, cnt)
1390	uint32_t		bustype;
1391	uint32_t		*cnt;
1392{
1393	*cnt = 8192;
1394	return(NDIS_STATUS_SUCCESS);
1395}
1396
1397static ndis_status
1398NdisMAllocateMapRegisters(adapter, dmachannel, dmasize, physmapneeded, maxmap)
1399	ndis_handle		adapter;
1400	uint32_t		dmachannel;
1401	uint8_t			dmasize;
1402	uint32_t		physmapneeded;
1403	uint32_t		maxmap;
1404{
1405	struct ndis_softc	*sc;
1406	ndis_miniport_block	*block;
1407	int			error, i, nseg = NDIS_MAXSEG;
1408
1409	block = (ndis_miniport_block *)adapter;
1410	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1411
1412	sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded,
1413	    M_DEVBUF, M_NOWAIT|M_ZERO);
1414
1415	if (sc->ndis_mmaps == NULL)
1416		return(NDIS_STATUS_RESOURCES);
1417
1418	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1419	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1420	    NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW,
1421	    NULL, NULL, &sc->ndis_mtag);
1422
1423	if (error) {
1424		free(sc->ndis_mmaps, M_DEVBUF);
1425		return(NDIS_STATUS_RESOURCES);
1426	}
1427
1428	for (i = 0; i < physmapneeded; i++)
1429		bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]);
1430
1431	sc->ndis_mmapcnt = physmapneeded;
1432
1433	return(NDIS_STATUS_SUCCESS);
1434}
1435
1436static void
1437NdisMFreeMapRegisters(adapter)
1438	ndis_handle		adapter;
1439{
1440	struct ndis_softc	*sc;
1441	ndis_miniport_block	*block;
1442	int			i;
1443
1444	block = (ndis_miniport_block *)adapter;
1445	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1446
1447	for (i = 0; i < sc->ndis_mmapcnt; i++)
1448		bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]);
1449
1450	free(sc->ndis_mmaps, M_DEVBUF);
1451
1452	bus_dma_tag_destroy(sc->ndis_mtag);
1453
1454	return;
1455}
1456
1457static void
1458ndis_mapshared_cb(arg, segs, nseg, error)
1459	void			*arg;
1460	bus_dma_segment_t	*segs;
1461	int			nseg;
1462	int			error;
1463{
1464	ndis_physaddr		*p;
1465
1466	if (error || nseg > 1)
1467		return;
1468
1469	p = arg;
1470
1471	p->np_quad = segs[0].ds_addr;
1472
1473	return;
1474}
1475
1476/*
1477 * This maps to bus_dmamem_alloc().
1478 */
1479
1480static void
1481NdisMAllocateSharedMemory(adapter, len, cached, vaddr, paddr)
1482	ndis_handle		adapter;
1483	uint32_t		len;
1484	uint8_t			cached;
1485	void			**vaddr;
1486	ndis_physaddr		*paddr;
1487{
1488	ndis_miniport_block	*block;
1489	struct ndis_softc	*sc;
1490	struct ndis_shmem	*sh;
1491	int			error;
1492
1493	if (adapter == NULL)
1494		return;
1495
1496	block = (ndis_miniport_block *)adapter;
1497	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1498
1499	sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO);
1500	if (sh == NULL)
1501		return;
1502
1503	InitializeListHead(&sh->ndis_list);
1504
1505	/*
1506	 * When performing shared memory allocations, create a tag
1507	 * with a lowaddr limit that restricts physical memory mappings
1508	 * so that they all fall within the first 1GB of memory.
1509	 * At least one device/driver combination (Linksys Instant
1510	 * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
1511	 * problems with performing DMA operations with physical
1512	 * addresses that lie above the 1GB mark. I don't know if this
1513	 * is a hardware limitation or if the addresses are being
1514	 * truncated within the driver, but this seems to be the only
1515	 * way to make these cards work reliably in systems with more
1516	 * than 1GB of physical memory.
1517	 */
1518
1519	error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
1520	    0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL,
1521	    NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL,
1522	    &sh->ndis_stag);
1523
1524	if (error) {
1525		free(sh, M_DEVBUF);
1526		return;
1527	}
1528
1529	error = bus_dmamem_alloc(sh->ndis_stag, vaddr,
1530	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap);
1531
1532	if (error) {
1533		bus_dma_tag_destroy(sh->ndis_stag);
1534		free(sh, M_DEVBUF);
1535		return;
1536	}
1537
1538	error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr,
1539	    len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT);
1540
1541	if (error) {
1542		bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap);
1543		bus_dma_tag_destroy(sh->ndis_stag);
1544		free(sh, M_DEVBUF);
1545		return;
1546	}
1547
1548	/*
1549	 * Save the physical address along with the source address.
1550	 * The AirGo MIMO driver will call NdisMFreeSharedMemory()
1551	 * with a bogus virtual address sometimes, but with a valid
1552	 * physical address. To keep this from causing trouble, we
1553	 * use the physical address to as a sanity check in case
1554	 * searching based on the virtual address fails.
1555	 */
1556
1557	NDIS_LOCK(sc);
1558	sh->ndis_paddr.np_quad = paddr->np_quad;
1559	sh->ndis_saddr = *vaddr;
1560	InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list));
1561	NDIS_UNLOCK(sc);
1562
1563	return;
1564}
1565
1566struct ndis_allocwork {
1567	uint32_t		na_len;
1568	uint8_t			na_cached;
1569	void			*na_ctx;
1570	io_workitem		*na_iw;
1571};
1572
1573static void
1574ndis_asyncmem_complete(dobj, arg)
1575	device_object		*dobj;
1576	void			*arg;
1577{
1578	ndis_miniport_block	*block;
1579	struct ndis_softc	*sc;
1580	struct ndis_allocwork	*w;
1581	void			*vaddr;
1582	ndis_physaddr		paddr;
1583	ndis_allocdone_handler	donefunc;
1584
1585	w = arg;
1586	block = (ndis_miniport_block *)dobj->do_devext;
1587	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1588
1589	vaddr = NULL;
1590	paddr.np_quad = 0;
1591
1592	donefunc = sc->ndis_chars->nmc_allocate_complete_func;
1593	NdisMAllocateSharedMemory(block, w->na_len,
1594	    w->na_cached, &vaddr, &paddr);
1595	MSCALL5(donefunc, block, vaddr, &paddr, w->na_len, w->na_ctx);
1596
1597	IoFreeWorkItem(w->na_iw);
1598	free(w, M_DEVBUF);
1599
1600	return;
1601}
1602
1603static ndis_status
1604NdisMAllocateSharedMemoryAsync(adapter, len, cached, ctx)
1605	ndis_handle		adapter;
1606	uint32_t		len;
1607	uint8_t			cached;
1608	void			*ctx;
1609{
1610	ndis_miniport_block	*block;
1611	struct ndis_allocwork	*w;
1612	io_workitem		*iw;
1613	io_workitem_func	ifw;
1614
1615	if (adapter == NULL)
1616		return(NDIS_STATUS_FAILURE);
1617
1618	block = adapter;
1619
1620	iw = IoAllocateWorkItem(block->nmb_deviceobj);
1621	if (iw == NULL)
1622		return(NDIS_STATUS_FAILURE);
1623
1624	w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT);
1625
1626	if (w == NULL)
1627		return(NDIS_STATUS_FAILURE);
1628
1629	w->na_cached = cached;
1630	w->na_len = len;
1631	w->na_ctx = ctx;
1632	w->na_iw = iw;
1633
1634	ifw = (io_workitem_func)ndis_findwrap((funcptr)ndis_asyncmem_complete);
1635	IoQueueWorkItem(iw, ifw, WORKQUEUE_DELAYED, w);
1636
1637	return(NDIS_STATUS_PENDING);
1638}
1639
1640static void
1641NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr)
1642	ndis_handle		adapter;
1643	uint32_t		len;
1644	uint8_t			cached;
1645	void			*vaddr;
1646	ndis_physaddr		paddr;
1647{
1648	ndis_miniport_block	*block;
1649	struct ndis_softc	*sc;
1650	struct ndis_shmem	*sh = NULL;
1651	list_entry		*l;
1652
1653	if (vaddr == NULL || adapter == NULL)
1654		return;
1655
1656	block = (ndis_miniport_block *)adapter;
1657	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1658
1659	/* Sanity check: is list empty? */
1660
1661	if (IsListEmpty(&sc->ndis_shlist))
1662		return;
1663
1664	NDIS_LOCK(sc);
1665	l = sc->ndis_shlist.nle_flink;
1666	while (l != &sc->ndis_shlist) {
1667		sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list);
1668		if (sh->ndis_saddr == vaddr)
1669			break;
1670		/*
1671	 	 * Check the physaddr too, just in case the driver lied
1672		 * about the virtual address.
1673		 */
1674		if (sh->ndis_paddr.np_quad == paddr.np_quad)
1675			break;
1676		l = l->nle_flink;
1677	}
1678
1679	if (sh == NULL) {
1680		NDIS_UNLOCK(sc);
1681		printf("NDIS: buggy driver tried to free "
1682		    "invalid shared memory: vaddr: %p paddr: 0x%jx\n",
1683		    vaddr, (uintmax_t)paddr.np_quad);
1684		return;
1685	}
1686
1687	RemoveEntryList(&sh->ndis_list);
1688
1689	NDIS_UNLOCK(sc);
1690
1691	bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1692	bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap);
1693	bus_dma_tag_destroy(sh->ndis_stag);
1694
1695	free(sh, M_DEVBUF);
1696
1697	return;
1698}
1699
1700static ndis_status
1701NdisMMapIoSpace(vaddr, adapter, paddr, len)
1702	void			**vaddr;
1703	ndis_handle		adapter;
1704	ndis_physaddr		paddr;
1705	uint32_t		len;
1706{
1707	if (adapter == NULL)
1708		return(NDIS_STATUS_FAILURE);
1709
1710	*vaddr = MmMapIoSpace(paddr.np_quad, len, 0);
1711
1712	if (*vaddr == NULL)
1713		return(NDIS_STATUS_FAILURE);
1714
1715	return(NDIS_STATUS_SUCCESS);
1716}
1717
1718static void
1719NdisMUnmapIoSpace(adapter, vaddr, len)
1720	ndis_handle		adapter;
1721	void			*vaddr;
1722	uint32_t		len;
1723{
1724	MmUnmapIoSpace(vaddr, len);
1725	return;
1726}
1727
1728static uint32_t
1729NdisGetCacheFillSize(void)
1730{
1731	return(128);
1732}
1733
1734static uint32_t
1735NdisMGetDmaAlignment(handle)
1736	ndis_handle		handle;
1737{
1738	return(16);
1739}
1740
1741/*
1742 * NDIS has two methods for dealing with NICs that support DMA.
1743 * One is to just pass packets to the driver and let it call
1744 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
1745 * all by itself, and the other is to let the NDIS library handle the
1746 * buffer mapping internally, and hand the driver an already populated
1747 * scatter/gather fragment list. If the driver calls
1748 * NdisMInitializeScatterGatherDma(), it wants to use the latter
1749 * method.
1750 */
1751
1752static ndis_status
1753NdisMInitializeScatterGatherDma(adapter, is64, maxphysmap)
1754	ndis_handle		adapter;
1755	uint8_t			is64;
1756	uint32_t		maxphysmap;
1757{
1758	struct ndis_softc	*sc;
1759	ndis_miniport_block	*block;
1760	int			error;
1761
1762	if (adapter == NULL)
1763		return(NDIS_STATUS_FAILURE);
1764	block = (ndis_miniport_block *)adapter;
1765	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1766
1767	/* Don't do this twice. */
1768	if (sc->ndis_sc == 1)
1769		return(NDIS_STATUS_SUCCESS);
1770
1771	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1772	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1773	    MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
1774	    NULL, NULL, &sc->ndis_ttag);
1775
1776	sc->ndis_sc = 1;
1777
1778	return(NDIS_STATUS_SUCCESS);
1779}
1780
1781void
1782NdisAllocatePacketPool(status, pool, descnum, protrsvdlen)
1783	ndis_status		*status;
1784	ndis_handle		*pool;
1785	uint32_t		descnum;
1786	uint32_t		protrsvdlen;
1787{
1788	ndis_packet_pool	*p;
1789	ndis_packet		*packets;
1790	int			i;
1791
1792	p = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_packet_pool), 0);
1793	if (p == NULL) {
1794		*status = NDIS_STATUS_RESOURCES;
1795		return;
1796	}
1797
1798	p->np_cnt = descnum + NDIS_POOL_EXTRA;
1799	p->np_protrsvd = protrsvdlen;
1800	p->np_len = sizeof(ndis_packet) + protrsvdlen;
1801
1802	packets = ExAllocatePoolWithTag(NonPagedPool, p->np_cnt *
1803	    p->np_len, 0);
1804
1805
1806	if (packets == NULL) {
1807		ExFreePool(p);
1808		*status = NDIS_STATUS_RESOURCES;
1809		return;
1810	}
1811
1812	p->np_pktmem = packets;
1813
1814	for (i = 0; i < p->np_cnt; i++)
1815		InterlockedPushEntrySList(&p->np_head,
1816		    (struct slist_entry *)&packets[i]);
1817
1818#ifdef NDIS_DEBUG_PACKETS
1819	p->np_dead = 0;
1820	KeInitializeSpinLock(&p->np_lock);
1821        KeInitializeEvent(&p->np_event, EVENT_TYPE_NOTIFY, TRUE);
1822#endif
1823
1824	*pool = p;
1825	*status = NDIS_STATUS_SUCCESS;
1826	return;
1827}
1828
1829void
1830NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen)
1831	ndis_status		*status;
1832	ndis_handle		*pool;
1833	uint32_t		descnum;
1834	uint32_t		oflowdescnum;
1835	uint32_t		protrsvdlen;
1836{
1837	return(NdisAllocatePacketPool(status, pool,
1838	    descnum + oflowdescnum, protrsvdlen));
1839}
1840
1841uint32_t
1842NdisPacketPoolUsage(pool)
1843	ndis_handle		pool;
1844{
1845	ndis_packet_pool	*p;
1846
1847	p = (ndis_packet_pool *)pool;
1848	return(p->np_cnt - ExQueryDepthSList(&p->np_head));
1849}
1850
1851void
1852NdisFreePacketPool(pool)
1853	ndis_handle		pool;
1854{
1855	ndis_packet_pool	*p;
1856	int			usage;
1857#ifdef NDIS_DEBUG_PACKETS
1858	uint8_t			irql;
1859#endif
1860
1861	p = (ndis_packet_pool *)pool;
1862
1863#ifdef NDIS_DEBUG_PACKETS
1864	KeAcquireSpinLock(&p->np_lock, &irql);
1865#endif
1866
1867	usage = NdisPacketPoolUsage(pool);
1868
1869#ifdef NDIS_DEBUG_PACKETS
1870	if (usage) {
1871		p->np_dead = 1;
1872		KeResetEvent(&p->np_event);
1873		KeReleaseSpinLock(&p->np_lock, irql);
1874		KeWaitForSingleObject(&p->np_event, 0, 0, FALSE, NULL);
1875	} else
1876		KeReleaseSpinLock(&p->np_lock, irql);
1877#endif
1878
1879	ExFreePool(p->np_pktmem);
1880	ExFreePool(p);
1881
1882	return;
1883}
1884
1885void
1886NdisAllocatePacket(status, packet, pool)
1887	ndis_status		*status;
1888	ndis_packet		**packet;
1889	ndis_handle		pool;
1890{
1891	ndis_packet_pool	*p;
1892	ndis_packet		*pkt;
1893#ifdef NDIS_DEBUG_PACKETS
1894	uint8_t			irql;
1895#endif
1896
1897	p = (ndis_packet_pool *)pool;
1898
1899#ifdef NDIS_DEBUG_PACKETS
1900	KeAcquireSpinLock(&p->np_lock, &irql);
1901	if (p->np_dead) {
1902		KeReleaseSpinLock(&p->np_lock, irql);
1903		printf("NDIS: tried to allocate packet from dead pool %p\n",
1904		    pool);
1905		*status = NDIS_STATUS_RESOURCES;
1906		return;
1907	}
1908#endif
1909
1910	pkt = (ndis_packet *)InterlockedPopEntrySList(&p->np_head);
1911
1912#ifdef NDIS_DEBUG_PACKETS
1913	KeReleaseSpinLock(&p->np_lock, irql);
1914#endif
1915
1916	if (pkt == NULL) {
1917		*status = NDIS_STATUS_RESOURCES;
1918		return;
1919	}
1920
1921
1922	bzero((char *)pkt, sizeof(ndis_packet));
1923
1924	/* Save pointer to the pool. */
1925	pkt->np_private.npp_pool = pool;
1926
1927	/* Set the oob offset pointer. Lots of things expect this. */
1928	pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob);
1929
1930	/*
1931	 * We must initialize the packet flags correctly in order
1932	 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
1933	 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work
1934         * correctly.
1935	 */
1936	pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
1937	pkt->np_private.npp_validcounts = FALSE;
1938
1939	*packet = pkt;
1940
1941	*status = NDIS_STATUS_SUCCESS;
1942
1943	return;
1944}
1945
1946void
1947NdisFreePacket(packet)
1948	ndis_packet		*packet;
1949{
1950	ndis_packet_pool	*p;
1951#ifdef NDIS_DEBUG_PACKETS
1952	uint8_t			irql;
1953#endif
1954
1955	p = (ndis_packet_pool *)packet->np_private.npp_pool;
1956
1957#ifdef NDIS_DEBUG_PACKETS
1958	KeAcquireSpinLock(&p->np_lock, &irql);
1959#endif
1960
1961	InterlockedPushEntrySList(&p->np_head, (slist_entry *)packet);
1962
1963#ifdef NDIS_DEBUG_PACKETS
1964	if (p->np_dead) {
1965		if (ExQueryDepthSList(&p->np_head) == p->np_cnt)
1966			KeSetEvent(&p->np_event, IO_NO_INCREMENT, FALSE);
1967	}
1968	KeReleaseSpinLock(&p->np_lock, irql);
1969#endif
1970
1971	return;
1972}
1973
1974static void
1975NdisUnchainBufferAtFront(packet, buf)
1976	ndis_packet		*packet;
1977	ndis_buffer		**buf;
1978{
1979	ndis_packet_private	*priv;
1980
1981	if (packet == NULL || buf == NULL)
1982		return;
1983
1984	priv = &packet->np_private;
1985
1986	priv->npp_validcounts = FALSE;
1987
1988	if (priv->npp_head == priv->npp_tail) {
1989		*buf = priv->npp_head;
1990		priv->npp_head = priv->npp_tail = NULL;
1991	} else {
1992		*buf = priv->npp_head;
1993		priv->npp_head = (*buf)->mdl_next;
1994	}
1995
1996	return;
1997}
1998
1999static void
2000NdisUnchainBufferAtBack(packet, buf)
2001	ndis_packet		*packet;
2002	ndis_buffer		**buf;
2003{
2004	ndis_packet_private	*priv;
2005	ndis_buffer		*tmp;
2006
2007	if (packet == NULL || buf == NULL)
2008		return;
2009
2010	priv = &packet->np_private;
2011
2012	priv->npp_validcounts = FALSE;
2013
2014	if (priv->npp_head == priv->npp_tail) {
2015		*buf = priv->npp_head;
2016		priv->npp_head = priv->npp_tail = NULL;
2017	} else {
2018		*buf = priv->npp_tail;
2019		tmp = priv->npp_head;
2020		while (tmp->mdl_next != priv->npp_tail)
2021			tmp = tmp->mdl_next;
2022		priv->npp_tail = tmp;
2023		tmp->mdl_next = NULL;
2024	}
2025
2026	return;
2027}
2028
2029/*
2030 * The NDIS "buffer" is really an MDL (memory descriptor list)
2031 * which is used to describe a buffer in a way that allows it
2032 * to mapped into different contexts. We have to be careful how
2033 * we handle them: in some versions of Windows, the NdisFreeBuffer()
2034 * routine is an actual function in the NDIS API, but in others
2035 * it's just a macro wrapper around IoFreeMdl(). There's really
2036 * no way to use the 'descnum' parameter to count how many
2037 * "buffers" are allocated since in order to use IoFreeMdl() to
2038 * dispose of a buffer, we have to use IoAllocateMdl() to allocate
2039 * them, and IoAllocateMdl() just grabs them out of the heap.
2040 */
2041
2042static void
2043NdisAllocateBufferPool(status, pool, descnum)
2044	ndis_status		*status;
2045	ndis_handle		*pool;
2046	uint32_t		descnum;
2047{
2048
2049	/*
2050	 * The only thing we can really do here is verify that descnum
2051	 * is a reasonable value, but I really don't know what to check
2052	 * it against.
2053	 */
2054
2055	*pool = NonPagedPool;
2056	*status = NDIS_STATUS_SUCCESS;
2057	return;
2058}
2059
2060static void
2061NdisFreeBufferPool(pool)
2062	ndis_handle		pool;
2063{
2064	return;
2065}
2066
2067static void
2068NdisAllocateBuffer(status, buffer, pool, vaddr, len)
2069	ndis_status		*status;
2070	ndis_buffer		**buffer;
2071	ndis_handle		pool;
2072	void			*vaddr;
2073	uint32_t		len;
2074{
2075	ndis_buffer		*buf;
2076
2077	buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL);
2078	if (buf == NULL) {
2079		*status = NDIS_STATUS_RESOURCES;
2080		return;
2081	}
2082
2083	MmBuildMdlForNonPagedPool(buf);
2084
2085	*buffer = buf;
2086	*status = NDIS_STATUS_SUCCESS;
2087
2088	return;
2089}
2090
2091static void
2092NdisFreeBuffer(buf)
2093	ndis_buffer		*buf;
2094{
2095	IoFreeMdl(buf);
2096	return;
2097}
2098
2099/* Aw c'mon. */
2100
2101static uint32_t
2102NdisBufferLength(buf)
2103	ndis_buffer		*buf;
2104{
2105	return(MmGetMdlByteCount(buf));
2106}
2107
2108/*
2109 * Get the virtual address and length of a buffer.
2110 * Note: the vaddr argument is optional.
2111 */
2112
2113static void
2114NdisQueryBuffer(buf, vaddr, len)
2115	ndis_buffer		*buf;
2116	void			**vaddr;
2117	uint32_t		*len;
2118{
2119	if (vaddr != NULL)
2120		*vaddr = MmGetMdlVirtualAddress(buf);
2121	*len = MmGetMdlByteCount(buf);
2122
2123	return;
2124}
2125
2126/* Same as above -- we don't care about the priority. */
2127
2128static void
2129NdisQueryBufferSafe(buf, vaddr, len, prio)
2130	ndis_buffer		*buf;
2131	void			**vaddr;
2132	uint32_t		*len;
2133	uint32_t		prio;
2134{
2135	if (vaddr != NULL)
2136		*vaddr = MmGetMdlVirtualAddress(buf);
2137	*len = MmGetMdlByteCount(buf);
2138
2139	return;
2140}
2141
2142/* Damnit Microsoft!! How many ways can you do the same thing?! */
2143
2144static void *
2145NdisBufferVirtualAddress(buf)
2146	ndis_buffer		*buf;
2147{
2148	return(MmGetMdlVirtualAddress(buf));
2149}
2150
2151static void *
2152NdisBufferVirtualAddressSafe(buf, prio)
2153	ndis_buffer		*buf;
2154	uint32_t		prio;
2155{
2156	return(MmGetMdlVirtualAddress(buf));
2157}
2158
2159static void
2160NdisAdjustBufferLength(buf, len)
2161	ndis_buffer		*buf;
2162	int			len;
2163{
2164	MmGetMdlByteCount(buf) = len;
2165
2166	return;
2167}
2168
2169static uint32_t
2170NdisInterlockedIncrement(addend)
2171	uint32_t		*addend;
2172{
2173	atomic_add_long((u_long *)addend, 1);
2174	return(*addend);
2175}
2176
2177static uint32_t
2178NdisInterlockedDecrement(addend)
2179	uint32_t		*addend;
2180{
2181	atomic_subtract_long((u_long *)addend, 1);
2182	return(*addend);
2183}
2184
2185static void
2186NdisInitializeEvent(event)
2187	ndis_event		*event;
2188{
2189	/*
2190	 * NDIS events are always notification
2191	 * events, and should be initialized to the
2192	 * not signaled state.
2193	 */
2194	KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE);
2195	return;
2196}
2197
2198static void
2199NdisSetEvent(event)
2200	ndis_event		*event;
2201{
2202	KeSetEvent(&event->ne_event, IO_NO_INCREMENT, FALSE);
2203	return;
2204}
2205
2206static void
2207NdisResetEvent(event)
2208	ndis_event		*event;
2209{
2210	KeResetEvent(&event->ne_event);
2211	return;
2212}
2213
2214static uint8_t
2215NdisWaitEvent(event, msecs)
2216	ndis_event		*event;
2217	uint32_t		msecs;
2218{
2219	int64_t			duetime;
2220	uint32_t		rval;
2221
2222	duetime = ((int64_t)msecs * -10000);
2223	rval = KeWaitForSingleObject(event,
2224	    0, 0, TRUE, msecs ? & duetime : NULL);
2225
2226	if (rval == STATUS_TIMEOUT)
2227		return(FALSE);
2228
2229	return(TRUE);
2230}
2231
2232static ndis_status
2233NdisUnicodeStringToAnsiString(dstr, sstr)
2234	ansi_string		*dstr;
2235	unicode_string		*sstr;
2236{
2237	uint32_t		rval;
2238
2239	rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE);
2240
2241	if (rval == STATUS_INSUFFICIENT_RESOURCES)
2242		return(NDIS_STATUS_RESOURCES);
2243	if (rval)
2244		return(NDIS_STATUS_FAILURE);
2245
2246	return (NDIS_STATUS_SUCCESS);
2247}
2248
2249static ndis_status
2250NdisAnsiStringToUnicodeString(dstr, sstr)
2251	unicode_string		*dstr;
2252	ansi_string		*sstr;
2253{
2254	uint32_t		rval;
2255
2256	rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE);
2257
2258	if (rval == STATUS_INSUFFICIENT_RESOURCES)
2259		return(NDIS_STATUS_RESOURCES);
2260	if (rval)
2261		return(NDIS_STATUS_FAILURE);
2262
2263	return (NDIS_STATUS_SUCCESS);
2264}
2265
2266static ndis_status
2267NdisMPciAssignResources(adapter, slot, list)
2268	ndis_handle		adapter;
2269	uint32_t		slot;
2270	ndis_resource_list	**list;
2271{
2272	ndis_miniport_block	*block;
2273
2274	if (adapter == NULL || list == NULL)
2275		return (NDIS_STATUS_FAILURE);
2276
2277	block = (ndis_miniport_block *)adapter;
2278	*list = block->nmb_rlist;
2279
2280	return (NDIS_STATUS_SUCCESS);
2281}
2282
2283static uint8_t
2284ndis_intr(iobj, arg)
2285	kinterrupt		*iobj;
2286        void                    *arg;
2287{
2288	struct ndis_softc	*sc;
2289	uint8_t			is_our_intr = FALSE;
2290	int			call_isr = 0;
2291	ndis_miniport_interrupt	*intr;
2292
2293	sc = arg;
2294	intr = sc->ndis_block->nmb_interrupt;
2295
2296	if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL)
2297		return(FALSE);
2298
2299	if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
2300		MSCALL3(intr->ni_isrfunc, &is_our_intr, &call_isr,
2301		    sc->ndis_block->nmb_miniportadapterctx);
2302	else {
2303		MSCALL1(sc->ndis_chars->nmc_disable_interrupts_func,
2304		    sc->ndis_block->nmb_miniportadapterctx);
2305		call_isr = 1;
2306	}
2307
2308	if (call_isr)
2309		IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
2310
2311	return(is_our_intr);
2312}
2313
2314static void
2315ndis_intrhand(dpc, intr, sysarg1, sysarg2)
2316	kdpc			*dpc;
2317	ndis_miniport_interrupt	*intr;
2318	void			*sysarg1;
2319	void			*sysarg2;
2320{
2321	struct ndis_softc	*sc;
2322	ndis_miniport_block	*block;
2323        ndis_handle             adapter;
2324
2325	block = intr->ni_block;
2326        adapter = block->nmb_miniportadapterctx;
2327	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2328
2329        if (NDIS_SERIALIZED(sc->ndis_block))
2330                KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
2331
2332        MSCALL1(intr->ni_dpcfunc, adapter);
2333
2334        /* If there's a MiniportEnableInterrupt() routine, call it. */
2335
2336	if (sc->ndis_chars->nmc_enable_interrupts_func != NULL)
2337		MSCALL1(sc->ndis_chars->nmc_enable_interrupts_func, adapter);
2338
2339        if (NDIS_SERIALIZED(sc->ndis_block))
2340                KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
2341
2342	/*
2343	 * Set the completion event if we've drained all
2344	 * pending interrupts.
2345	 */
2346
2347	KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
2348	intr->ni_dpccnt--;
2349	if (intr->ni_dpccnt == 0)
2350		KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE);
2351	KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
2352
2353        return;
2354}
2355
2356static ndis_status
2357NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode)
2358	ndis_miniport_interrupt	*intr;
2359	ndis_handle		adapter;
2360	uint32_t		ivec;
2361	uint32_t		ilevel;
2362	uint8_t			reqisr;
2363	uint8_t			shared;
2364	ndis_interrupt_mode	imode;
2365{
2366	ndis_miniport_block	*block;
2367	ndis_miniport_characteristics *ch;
2368	struct ndis_softc	*sc;
2369	int			error;
2370
2371	block = adapter;
2372	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2373	ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj,
2374	    (void *)1);
2375
2376	intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool,
2377	    sizeof(struct mtx), 0);
2378	if (intr->ni_rsvd == NULL)
2379		return(NDIS_STATUS_RESOURCES);
2380
2381	intr->ni_block = adapter;
2382	intr->ni_isrreq = reqisr;
2383	intr->ni_shared = shared;
2384	intr->ni_dpccnt = 0;
2385	intr->ni_isrfunc = ch->nmc_isr_func;
2386	intr->ni_dpcfunc = ch->nmc_interrupt_func;
2387
2388        KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE);
2389        KeInitializeDpc(&intr->ni_dpc,
2390	    ndis_findwrap((funcptr)ndis_intrhand), intr);
2391        KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW);
2392
2393	error = IoConnectInterrupt(&intr->ni_introbj,
2394	    ndis_findwrap((funcptr)ndis_intr), sc, NULL,
2395	    ivec, ilevel, 0, imode, shared, 0, FALSE);
2396
2397	if (error != STATUS_SUCCESS)
2398		return(NDIS_STATUS_FAILURE);
2399
2400	block->nmb_interrupt = intr;
2401
2402	return(NDIS_STATUS_SUCCESS);
2403}
2404
2405static void
2406NdisMDeregisterInterrupt(intr)
2407	ndis_miniport_interrupt	*intr;
2408{
2409	ndis_miniport_block	*block;
2410	struct ndis_softc	*sc;
2411	uint8_t			irql;
2412
2413	block = intr->ni_block;
2414	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2415
2416	/* Should really be KeSynchronizeExecution() */
2417
2418	KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql);
2419	block->nmb_interrupt = NULL;
2420	KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql);
2421/*
2422	KeFlushQueuedDpcs();
2423*/
2424	/* Disconnect our ISR */
2425
2426	IoDisconnectInterrupt(intr->ni_introbj);
2427
2428	KeWaitForSingleObject(&intr->ni_dpcevt, 0, 0, FALSE, NULL);
2429	KeResetEvent(&intr->ni_dpcevt);
2430
2431	return;
2432}
2433
2434static void
2435NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc)
2436	ndis_handle		adapter;
2437	void			*shutdownctx;
2438	ndis_shutdown_handler	shutdownfunc;
2439{
2440	ndis_miniport_block	*block;
2441	ndis_miniport_characteristics *chars;
2442	struct ndis_softc	*sc;
2443
2444	if (adapter == NULL)
2445		return;
2446
2447	block = (ndis_miniport_block *)adapter;
2448	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2449	chars = sc->ndis_chars;
2450
2451	chars->nmc_shutdown_handler = shutdownfunc;
2452	chars->nmc_rsvd0 = shutdownctx;
2453
2454	return;
2455}
2456
2457static void
2458NdisMDeregisterAdapterShutdownHandler(adapter)
2459	ndis_handle		adapter;
2460{
2461	ndis_miniport_block	*block;
2462	ndis_miniport_characteristics *chars;
2463	struct ndis_softc	*sc;
2464
2465	if (adapter == NULL)
2466		return;
2467
2468	block = (ndis_miniport_block *)adapter;
2469	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2470	chars = sc->ndis_chars;
2471
2472	chars->nmc_shutdown_handler = NULL;
2473	chars->nmc_rsvd0 = NULL;
2474
2475	return;
2476}
2477
2478static uint32_t
2479NDIS_BUFFER_TO_SPAN_PAGES(buf)
2480	ndis_buffer		*buf;
2481{
2482	if (buf == NULL)
2483		return(0);
2484	if (MmGetMdlByteCount(buf) == 0)
2485		return(1);
2486	return(SPAN_PAGES(MmGetMdlVirtualAddress(buf),
2487	    MmGetMdlByteCount(buf)));
2488}
2489
2490static void
2491NdisGetBufferPhysicalArraySize(buf, pages)
2492	ndis_buffer		*buf;
2493	uint32_t		*pages;
2494{
2495	if (buf == NULL)
2496		return;
2497
2498	*pages = NDIS_BUFFER_TO_SPAN_PAGES(buf);
2499	return;
2500}
2501
2502static void
2503NdisQueryBufferOffset(buf, off, len)
2504	ndis_buffer		*buf;
2505	uint32_t		*off;
2506	uint32_t		*len;
2507{
2508	if (buf == NULL)
2509		return;
2510
2511	*off = MmGetMdlByteOffset(buf);
2512	*len = MmGetMdlByteCount(buf);
2513
2514	return;
2515}
2516
2517void
2518NdisMSleep(usecs)
2519	uint32_t		usecs;
2520{
2521	ktimer			timer;
2522
2523	/*
2524	 * During system bootstrap, (i.e. cold == 1), we aren't
2525	 * allowed to sleep, so we have to do a hard DELAY()
2526	 * instead.
2527	 */
2528
2529	if (cold)
2530		DELAY(usecs);
2531	else {
2532		KeInitializeTimer(&timer);
2533		KeSetTimer(&timer, ((int64_t)usecs * -10), NULL);
2534		KeWaitForSingleObject(&timer, 0, 0, FALSE, NULL);
2535	}
2536
2537	return;
2538}
2539
2540static uint32_t
2541NdisReadPcmciaAttributeMemory(handle, offset, buf, len)
2542	ndis_handle		handle;
2543	uint32_t		offset;
2544	void			*buf;
2545	uint32_t		len;
2546{
2547	struct ndis_softc	*sc;
2548	ndis_miniport_block	*block;
2549	bus_space_handle_t	bh;
2550	bus_space_tag_t		bt;
2551	char			*dest;
2552	int			i;
2553
2554	if (handle == NULL)
2555		return(0);
2556
2557	block = (ndis_miniport_block *)handle;
2558	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2559	dest = buf;
2560
2561	bh = rman_get_bushandle(sc->ndis_res_am);
2562	bt = rman_get_bustag(sc->ndis_res_am);
2563
2564	for (i = 0; i < len; i++)
2565		dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2);
2566
2567	return(i);
2568}
2569
2570static uint32_t
2571NdisWritePcmciaAttributeMemory(handle, offset, buf, len)
2572	ndis_handle		handle;
2573	uint32_t		offset;
2574	void			*buf;
2575	uint32_t		len;
2576{
2577	struct ndis_softc	*sc;
2578	ndis_miniport_block	*block;
2579	bus_space_handle_t	bh;
2580	bus_space_tag_t		bt;
2581	char			*src;
2582	int			i;
2583
2584	if (handle == NULL)
2585		return(0);
2586
2587	block = (ndis_miniport_block *)handle;
2588	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2589	src = buf;
2590
2591	bh = rman_get_bushandle(sc->ndis_res_am);
2592	bt = rman_get_bustag(sc->ndis_res_am);
2593
2594	for (i = 0; i < len; i++)
2595		bus_space_write_1(bt, bh, (offset + i) * 2, src[i]);
2596
2597	return(i);
2598}
2599
2600static list_entry *
2601NdisInterlockedInsertHeadList(head, entry, lock)
2602	list_entry		*head;
2603	list_entry		*entry;
2604	ndis_spin_lock		*lock;
2605{
2606	list_entry		*flink;
2607
2608	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2609	flink = head->nle_flink;
2610	entry->nle_flink = flink;
2611	entry->nle_blink = head;
2612	flink->nle_blink = entry;
2613	head->nle_flink = entry;
2614	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2615
2616	return(flink);
2617}
2618
2619static list_entry *
2620NdisInterlockedRemoveHeadList(head, lock)
2621	list_entry		*head;
2622	ndis_spin_lock		*lock;
2623{
2624	list_entry		*flink;
2625	list_entry		*entry;
2626
2627	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2628	entry = head->nle_flink;
2629	flink = entry->nle_flink;
2630	head->nle_flink = flink;
2631	flink->nle_blink = head;
2632	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2633
2634	return(entry);
2635}
2636
2637static list_entry *
2638NdisInterlockedInsertTailList(head, entry, lock)
2639	list_entry		*head;
2640	list_entry		*entry;
2641	ndis_spin_lock		*lock;
2642{
2643	list_entry		*blink;
2644
2645	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2646	blink = head->nle_blink;
2647	entry->nle_flink = head;
2648	entry->nle_blink = blink;
2649	blink->nle_flink = entry;
2650	head->nle_blink = entry;
2651	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2652
2653	return(blink);
2654}
2655
2656static uint8_t
2657NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx)
2658	ndis_miniport_interrupt	*intr;
2659	void			*syncfunc;
2660	void			*syncctx;
2661{
2662	return(KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx));
2663}
2664
2665static void
2666NdisGetCurrentSystemTime(tval)
2667	uint64_t		*tval;
2668{
2669	ntoskrnl_time(tval);
2670	return;
2671}
2672
2673/*
2674 * Return the number of milliseconds since the system booted.
2675 */
2676static void
2677NdisGetSystemUpTime(tval)
2678	uint32_t		*tval;
2679{
2680	struct timespec		ts;
2681
2682	nanouptime(&ts);
2683	*tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
2684
2685	return;
2686}
2687
2688static void
2689NdisInitializeString(dst, src)
2690	unicode_string		*dst;
2691	char			*src;
2692{
2693	ansi_string		as;
2694	RtlInitAnsiString(&as, src);
2695	RtlAnsiStringToUnicodeString(dst, &as, TRUE);
2696	return;
2697}
2698
2699static void
2700NdisFreeString(str)
2701	unicode_string		*str;
2702{
2703	RtlFreeUnicodeString(str);
2704	return;
2705}
2706
2707static ndis_status
2708NdisMRemoveMiniport(adapter)
2709	ndis_handle		*adapter;
2710{
2711	return(NDIS_STATUS_SUCCESS);
2712}
2713
2714static void
2715NdisInitAnsiString(dst, src)
2716	ansi_string		*dst;
2717	char			*src;
2718{
2719	RtlInitAnsiString(dst, src);
2720	return;
2721}
2722
2723static void
2724NdisInitUnicodeString(dst, src)
2725	unicode_string		*dst;
2726	uint16_t		*src;
2727{
2728	RtlInitUnicodeString(dst, src);
2729	return;
2730}
2731
2732static void NdisMGetDeviceProperty(adapter, phydevobj,
2733	funcdevobj, nextdevobj, resources, transresources)
2734	ndis_handle		adapter;
2735	device_object		**phydevobj;
2736	device_object		**funcdevobj;
2737	device_object		**nextdevobj;
2738	cm_resource_list	*resources;
2739	cm_resource_list	*transresources;
2740{
2741	ndis_miniport_block	*block;
2742
2743	block = (ndis_miniport_block *)adapter;
2744
2745	if (phydevobj != NULL)
2746		*phydevobj = block->nmb_physdeviceobj;
2747	if (funcdevobj != NULL)
2748		*funcdevobj = block->nmb_deviceobj;
2749	if (nextdevobj != NULL)
2750		*nextdevobj = block->nmb_nextdeviceobj;
2751
2752	return;
2753}
2754
2755static void
2756NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen)
2757	ndis_packet		*packet;
2758	ndis_buffer		**buf;
2759	void			**firstva;
2760	uint32_t		*firstlen;
2761	uint32_t		*totlen;
2762{
2763	ndis_buffer		*tmp;
2764
2765	tmp = packet->np_private.npp_head;
2766	*buf = tmp;
2767	if (tmp == NULL) {
2768		*firstva = NULL;
2769		*firstlen = *totlen = 0;
2770	} else {
2771		*firstva = MmGetMdlVirtualAddress(tmp);
2772		*firstlen = *totlen = MmGetMdlByteCount(tmp);
2773		for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next)
2774			*totlen += MmGetMdlByteCount(tmp);
2775	}
2776
2777	return;
2778}
2779
2780static void
2781NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio)
2782	ndis_packet		*packet;
2783	ndis_buffer		**buf;
2784	void			**firstva;
2785	uint32_t		*firstlen;
2786	uint32_t		*totlen;
2787	uint32_t		prio;
2788{
2789	NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen);
2790}
2791
2792static int
2793ndis_find_sym(lf, filename, suffix, sym)
2794	linker_file_t		lf;
2795	char			*filename;
2796	char			*suffix;
2797	caddr_t			*sym;
2798{
2799	char			*fullsym;
2800	char			*suf;
2801	int			i;
2802
2803	fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2804	if (fullsym == NULL)
2805		return(ENOMEM);
2806
2807	bzero(fullsym, MAXPATHLEN);
2808	strncpy(fullsym, filename, MAXPATHLEN);
2809	if (strlen(filename) < 4) {
2810		ExFreePool(fullsym);
2811		return(EINVAL);
2812	}
2813
2814	/* If the filename has a .ko suffix, strip if off. */
2815	suf = fullsym + (strlen(filename) - 3);
2816	if (strcmp(suf, ".ko") == 0)
2817		*suf = '\0';
2818
2819	for (i = 0; i < strlen(fullsym); i++) {
2820		if (fullsym[i] == '.')
2821			fullsym[i] = '_';
2822		else
2823			fullsym[i] = tolower(fullsym[i]);
2824	}
2825	strcat(fullsym, suffix);
2826	*sym = linker_file_lookup_symbol(lf, fullsym, 0);
2827	ExFreePool(fullsym);
2828	if (*sym == 0)
2829		return(ENOENT);
2830
2831	return(0);
2832}
2833
2834struct ndis_checkmodule {
2835	char	*afilename;
2836	ndis_fh	*fh;
2837};
2838
2839/*
2840 * See if a single module contains the symbols for a specified file.
2841 */
2842static int
2843NdisCheckModule(linker_file_t lf, void *context)
2844{
2845	struct ndis_checkmodule *nc;
2846	caddr_t			kldstart, kldend;
2847
2848	nc = (struct ndis_checkmodule *)context;
2849	if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart))
2850		return (0);
2851	if (ndis_find_sym(lf, nc->afilename, "_end", &kldend))
2852		return (0);
2853	nc->fh->nf_vp = lf;
2854	nc->fh->nf_map = NULL;
2855	nc->fh->nf_type = NDIS_FH_TYPE_MODULE;
2856	nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF;
2857	return (1);
2858}
2859
2860/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
2861static void
2862NdisOpenFile(status, filehandle, filelength, filename, highestaddr)
2863	ndis_status		*status;
2864	ndis_handle		*filehandle;
2865	uint32_t		*filelength;
2866	unicode_string		*filename;
2867	ndis_physaddr		highestaddr;
2868{
2869	ansi_string		as;
2870	char			*afilename = NULL;
2871	struct thread		*td = curthread;
2872	struct nameidata	nd;
2873	int			flags, error, vfslocked;
2874	struct vattr		vat;
2875	struct vattr		*vap = &vat;
2876	ndis_fh			*fh;
2877	char			*path;
2878	struct ndis_checkmodule	nc;
2879
2880	if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) {
2881		*status = NDIS_STATUS_RESOURCES;
2882		return;
2883	}
2884
2885	afilename = strdup(as.as_buf, M_DEVBUF);
2886	RtlFreeAnsiString(&as);
2887
2888	fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0);
2889	if (fh == NULL) {
2890		free(afilename, M_DEVBUF);
2891		*status = NDIS_STATUS_RESOURCES;
2892		return;
2893	}
2894
2895	fh->nf_name = afilename;
2896
2897	/*
2898	 * During system bootstrap, it's impossible to load files
2899	 * from the rootfs since it's not mounted yet. We therefore
2900	 * offer the possibility of opening files that have been
2901	 * preloaded as modules instead. Both choices will work
2902	 * when kldloading a module from multiuser, but only the
2903	 * module option will work during bootstrap. The module
2904	 * loading option works by using the ndiscvt(8) utility
2905	 * to convert the arbitrary file into a .ko using objcopy(1).
2906	 * This file will contain two special symbols: filename_start
2907	 * and filename_end. All we have to do is traverse the KLD
2908	 * list in search of those symbols and we've found the file
2909	 * data. As an added bonus, ndiscvt(8) will also generate
2910	 * a normal .o file which can be linked statically with
2911	 * the kernel. This means that the symbols will actual reside
2912	 * in the kernel's symbol table, but that doesn't matter to
2913	 * us since the kernel appears to us as just another module.
2914	 */
2915
2916	nc.afilename = afilename;
2917	nc.fh = fh;
2918	if (linker_file_foreach(NdisCheckModule, &nc)) {
2919		*filelength = fh->nf_maplen;
2920		*filehandle = fh;
2921		*status = NDIS_STATUS_SUCCESS;
2922		return;
2923	}
2924
2925	if (TAILQ_EMPTY(&mountlist)) {
2926		ExFreePool(fh);
2927		*status = NDIS_STATUS_FILE_NOT_FOUND;
2928		printf("NDIS: could not find file %s in linker list\n",
2929		    afilename);
2930		printf("NDIS: and no filesystems mounted yet, "
2931		    "aborting NdisOpenFile()\n");
2932		free(afilename, M_DEVBUF);
2933		return;
2934	}
2935
2936	path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2937	if (path == NULL) {
2938		ExFreePool(fh);
2939		free(afilename, M_DEVBUF);
2940		*status = NDIS_STATUS_RESOURCES;
2941		return;
2942	}
2943
2944	snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename);
2945
2946	/* Some threads don't have a current working directory. */
2947
2948	if (td->td_proc->p_fd->fd_rdir == NULL)
2949		td->td_proc->p_fd->fd_rdir = rootvnode;
2950	if (td->td_proc->p_fd->fd_cdir == NULL)
2951		td->td_proc->p_fd->fd_cdir = rootvnode;
2952
2953	NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE, UIO_SYSSPACE, path, td);
2954
2955	flags = FREAD;
2956	error = vn_open(&nd, &flags, 0, NULL);
2957	if (error) {
2958		*status = NDIS_STATUS_FILE_NOT_FOUND;
2959		ExFreePool(fh);
2960		printf("NDIS: open file %s failed: %d\n", path, error);
2961		ExFreePool(path);
2962		free(afilename, M_DEVBUF);
2963		return;
2964	}
2965	vfslocked = NDHASGIANT(&nd);
2966
2967	ExFreePool(path);
2968
2969	NDFREE(&nd, NDF_ONLY_PNBUF);
2970
2971	/* Get the file size. */
2972	VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
2973	VOP_UNLOCK(nd.ni_vp, 0);
2974	VFS_UNLOCK_GIANT(vfslocked);
2975
2976	fh->nf_vp = nd.ni_vp;
2977	fh->nf_map = NULL;
2978	fh->nf_type = NDIS_FH_TYPE_VFS;
2979	*filehandle = fh;
2980	*filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
2981	*status = NDIS_STATUS_SUCCESS;
2982
2983	return;
2984}
2985
2986static void
2987NdisMapFile(status, mappedbuffer, filehandle)
2988	ndis_status		*status;
2989	void			**mappedbuffer;
2990	ndis_handle		filehandle;
2991{
2992	ndis_fh			*fh;
2993	struct thread		*td = curthread;
2994	linker_file_t		lf;
2995	caddr_t			kldstart;
2996	int			error, resid, vfslocked;
2997	struct vnode		*vp;
2998
2999	if (filehandle == NULL) {
3000		*status = NDIS_STATUS_FAILURE;
3001		return;
3002	}
3003
3004	fh = (ndis_fh *)filehandle;
3005
3006	if (fh->nf_vp == NULL) {
3007		*status = NDIS_STATUS_FAILURE;
3008		return;
3009	}
3010
3011	if (fh->nf_map != NULL) {
3012		*status = NDIS_STATUS_ALREADY_MAPPED;
3013		return;
3014	}
3015
3016	if (fh->nf_type == NDIS_FH_TYPE_MODULE) {
3017		lf = fh->nf_vp;
3018		if (ndis_find_sym(lf, fh->nf_name, "_start", &kldstart)) {
3019			*status = NDIS_STATUS_FAILURE;
3020			return;
3021		}
3022		fh->nf_map = kldstart;
3023		*status = NDIS_STATUS_SUCCESS;
3024		*mappedbuffer = fh->nf_map;
3025		return;
3026	}
3027
3028	fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0);
3029
3030	if (fh->nf_map == NULL) {
3031		*status = NDIS_STATUS_RESOURCES;
3032		return;
3033	}
3034
3035	vp = fh->nf_vp;
3036	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
3037	error = vn_rdwr(UIO_READ, vp, fh->nf_map, fh->nf_maplen, 0,
3038	    UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td);
3039	VFS_UNLOCK_GIANT(vfslocked);
3040
3041	if (error)
3042		*status = NDIS_STATUS_FAILURE;
3043	else {
3044		*status = NDIS_STATUS_SUCCESS;
3045		*mappedbuffer = fh->nf_map;
3046	}
3047
3048	return;
3049}
3050
3051static void
3052NdisUnmapFile(filehandle)
3053	ndis_handle		filehandle;
3054{
3055	ndis_fh			*fh;
3056	fh = (ndis_fh *)filehandle;
3057
3058	if (fh->nf_map == NULL)
3059		return;
3060
3061	if (fh->nf_type == NDIS_FH_TYPE_VFS)
3062		ExFreePool(fh->nf_map);
3063	fh->nf_map = NULL;
3064
3065	return;
3066}
3067
3068static void
3069NdisCloseFile(filehandle)
3070	ndis_handle		filehandle;
3071{
3072	struct thread		*td = curthread;
3073	ndis_fh			*fh;
3074	int			vfslocked;
3075	struct vnode		*vp;
3076
3077	if (filehandle == NULL)
3078		return;
3079
3080	fh = (ndis_fh *)filehandle;
3081	if (fh->nf_map != NULL) {
3082		if (fh->nf_type == NDIS_FH_TYPE_VFS)
3083			ExFreePool(fh->nf_map);
3084		fh->nf_map = NULL;
3085	}
3086
3087	if (fh->nf_vp == NULL)
3088		return;
3089
3090	if (fh->nf_type == NDIS_FH_TYPE_VFS) {
3091		vp = fh->nf_vp;
3092		vfslocked = VFS_LOCK_GIANT(vp->v_mount);
3093		vn_close(vp, FREAD, td->td_ucred, td);
3094		VFS_UNLOCK_GIANT(vfslocked);
3095	}
3096
3097	fh->nf_vp = NULL;
3098	free(fh->nf_name, M_DEVBUF);
3099	ExFreePool(fh);
3100
3101	return;
3102}
3103
3104static uint8_t
3105NdisSystemProcessorCount()
3106{
3107	return(mp_ncpus);
3108}
3109
3110typedef void (*ndis_statusdone_handler)(ndis_handle);
3111typedef void (*ndis_status_handler)(ndis_handle, ndis_status,
3112        void *, uint32_t);
3113
3114static void
3115NdisMIndicateStatusComplete(adapter)
3116	ndis_handle		adapter;
3117{
3118	ndis_miniport_block	*block;
3119	ndis_statusdone_handler	statusdonefunc;
3120
3121	block = (ndis_miniport_block *)adapter;
3122	statusdonefunc = block->nmb_statusdone_func;
3123
3124	MSCALL1(statusdonefunc, adapter);
3125	return;
3126}
3127
3128static void
3129NdisMIndicateStatus(adapter, status, sbuf, slen)
3130	ndis_handle		adapter;
3131	ndis_status		status;
3132	void			*sbuf;
3133	uint32_t		slen;
3134{
3135	ndis_miniport_block	*block;
3136	ndis_status_handler	statusfunc;
3137
3138	block = (ndis_miniport_block *)adapter;
3139	statusfunc = block->nmb_status_func;
3140
3141	MSCALL4(statusfunc, adapter, status, sbuf, slen);
3142	return;
3143}
3144
3145/*
3146 * The DDK documentation says that you should use IoQueueWorkItem()
3147 * instead of ExQueueWorkItem(). The problem is, IoQueueWorkItem()
3148 * is fundamentally incompatible with NdisScheduleWorkItem(), which
3149 * depends on the API semantics of ExQueueWorkItem(). In our world,
3150 * ExQueueWorkItem() is implemented on top of IoAllocateQueueItem()
3151 * anyway.
3152 *
3153 * There are actually three distinct APIs here. NdisScheduleWorkItem()
3154 * takes a pointer to an NDIS_WORK_ITEM. ExQueueWorkItem() takes a pointer
3155 * to a WORK_QUEUE_ITEM. And finally, IoQueueWorkItem() takes a pointer
3156 * to an opaque work item thingie which you get from IoAllocateWorkItem().
3157 * An NDIS_WORK_ITEM is not the same as a WORK_QUEUE_ITEM. However,
3158 * the NDIS_WORK_ITEM has some opaque storage at the end of it, and we
3159 * (ab)use this storage as a WORK_QUEUE_ITEM, which is what we submit
3160 * to ExQueueWorkItem().
3161 *
3162 * Got all that? (Sheesh.)
3163 */
3164
3165ndis_status
3166NdisScheduleWorkItem(work)
3167	ndis_work_item		*work;
3168{
3169	work_queue_item		*wqi;
3170
3171	wqi = (work_queue_item *)work->nwi_wraprsvd;
3172	ExInitializeWorkItem(wqi,
3173	    (work_item_func)work->nwi_func, work->nwi_ctx);
3174	ExQueueWorkItem(wqi, WORKQUEUE_DELAYED);
3175
3176	return(NDIS_STATUS_SUCCESS);
3177}
3178
3179static void
3180NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen)
3181	ndis_packet		*dpkt;
3182	uint32_t		doff;
3183	uint32_t		reqlen;
3184	ndis_packet		*spkt;
3185	uint32_t		soff;
3186	uint32_t		*cpylen;
3187{
3188	ndis_buffer		*src, *dst;
3189	char			*sptr, *dptr;
3190	int			resid, copied, len, scnt, dcnt;
3191
3192	*cpylen = 0;
3193
3194	src = spkt->np_private.npp_head;
3195	dst = dpkt->np_private.npp_head;
3196
3197	sptr = MmGetMdlVirtualAddress(src);
3198	dptr = MmGetMdlVirtualAddress(dst);
3199	scnt = MmGetMdlByteCount(src);
3200	dcnt = MmGetMdlByteCount(dst);
3201
3202	while (soff) {
3203		if (MmGetMdlByteCount(src) > soff) {
3204			sptr += soff;
3205			scnt = MmGetMdlByteCount(src)- soff;
3206			break;
3207		}
3208		soff -= MmGetMdlByteCount(src);
3209		src = src->mdl_next;
3210		if (src == NULL)
3211			return;
3212		sptr = MmGetMdlVirtualAddress(src);
3213	}
3214
3215	while (doff) {
3216		if (MmGetMdlByteCount(dst) > doff) {
3217			dptr += doff;
3218			dcnt = MmGetMdlByteCount(dst) - doff;
3219			break;
3220		}
3221		doff -= MmGetMdlByteCount(dst);
3222		dst = dst->mdl_next;
3223		if (dst == NULL)
3224			return;
3225		dptr = MmGetMdlVirtualAddress(dst);
3226	}
3227
3228	resid = reqlen;
3229	copied = 0;
3230
3231	while(1) {
3232		if (resid < scnt)
3233			len = resid;
3234		else
3235			len = scnt;
3236		if (dcnt < len)
3237			len = dcnt;
3238
3239		bcopy(sptr, dptr, len);
3240
3241		copied += len;
3242		resid -= len;
3243		if (resid == 0)
3244			break;
3245
3246		dcnt -= len;
3247		if (dcnt == 0) {
3248			dst = dst->mdl_next;
3249			if (dst == NULL)
3250				break;
3251			dptr = MmGetMdlVirtualAddress(dst);
3252			dcnt = MmGetMdlByteCount(dst);
3253		}
3254
3255		scnt -= len;
3256		if (scnt == 0) {
3257			src = src->mdl_next;
3258			if (src == NULL)
3259				break;
3260			sptr = MmGetMdlVirtualAddress(src);
3261			scnt = MmGetMdlByteCount(src);
3262		}
3263	}
3264
3265	*cpylen = copied;
3266	return;
3267}
3268
3269static void
3270NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
3271	ndis_packet		*dpkt;
3272	uint32_t		doff;
3273	uint32_t		reqlen;
3274	ndis_packet		*spkt;
3275	uint32_t		soff;
3276	uint32_t		*cpylen;
3277	uint32_t		prio;
3278{
3279	NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen);
3280	return;
3281}
3282
3283static void
3284NdisIMCopySendPerPacketInfo(dpkt, spkt)
3285	ndis_packet		*dpkt;
3286	ndis_packet		*spkt;
3287{
3288	memcpy(&dpkt->np_ext, &spkt->np_ext, sizeof(ndis_packet_extension));
3289}
3290
3291static ndis_status
3292NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle)
3293	ndis_handle		handle;
3294	unicode_string		*devname;
3295	unicode_string		*symname;
3296	driver_dispatch		*majorfuncs[];
3297	void			**devobj;
3298	ndis_handle		*devhandle;
3299{
3300	uint32_t		status;
3301	device_object		*dobj;
3302
3303	status = IoCreateDevice(handle, 0, devname,
3304	    FILE_DEVICE_UNKNOWN, 0, FALSE, &dobj);
3305
3306	if (status == STATUS_SUCCESS) {
3307		*devobj = dobj;
3308		*devhandle = dobj;
3309	}
3310
3311	return(status);
3312}
3313
3314static ndis_status
3315NdisMDeregisterDevice(handle)
3316	ndis_handle		handle;
3317{
3318	IoDeleteDevice(handle);
3319	return(NDIS_STATUS_SUCCESS);
3320}
3321
3322static ndis_status
3323NdisMQueryAdapterInstanceName(name, handle)
3324	unicode_string		*name;
3325	ndis_handle		handle;
3326{
3327	ndis_miniport_block	*block;
3328	device_t		dev;
3329	ansi_string		as;
3330
3331	block = (ndis_miniport_block *)handle;
3332	dev = block->nmb_physdeviceobj->do_devext;
3333
3334	RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev)));
3335	if (RtlAnsiStringToUnicodeString(name, &as, TRUE))
3336		return(NDIS_STATUS_RESOURCES);
3337
3338	return(NDIS_STATUS_SUCCESS);
3339}
3340
3341static void
3342NdisMRegisterUnloadHandler(handle, func)
3343	ndis_handle		handle;
3344	void			*func;
3345{
3346	return;
3347}
3348
3349static void
3350dummy()
3351{
3352	printf ("NDIS dummy called...\n");
3353	return;
3354}
3355
3356/*
3357 * Note: a couple of entries in this table specify the
3358 * number of arguments as "foo + 1". These are routines
3359 * that accept a 64-bit argument, passed by value. On
3360 * x86, these arguments consume two longwords on the stack,
3361 * so we lie and say there's one additional argument so
3362 * that the wrapping routines will do the right thing.
3363 */
3364
3365image_patch_table ndis_functbl[] = {
3366	IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6),
3367	IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7),
3368	IMPORT_SFUNC(NdisIMCopySendPerPacketInfo, 2),
3369	IMPORT_SFUNC(NdisScheduleWorkItem, 1),
3370	IMPORT_SFUNC(NdisMIndicateStatusComplete, 1),
3371	IMPORT_SFUNC(NdisMIndicateStatus, 4),
3372	IMPORT_SFUNC(NdisSystemProcessorCount, 0),
3373	IMPORT_SFUNC(NdisUnchainBufferAtBack, 2),
3374	IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5),
3375	IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6),
3376	IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2),
3377	IMPORT_SFUNC(NdisMGetDeviceProperty, 6),
3378	IMPORT_SFUNC(NdisInitAnsiString, 2),
3379	IMPORT_SFUNC(NdisInitUnicodeString, 2),
3380	IMPORT_SFUNC(NdisWriteConfiguration, 4),
3381	IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2),
3382	IMPORT_SFUNC(NdisTerminateWrapper, 2),
3383	IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4),
3384	IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5),
3385	IMPORT_SFUNC(NdisMRemoveMiniport, 1),
3386	IMPORT_SFUNC(NdisInitializeString, 2),
3387	IMPORT_SFUNC(NdisFreeString, 1),
3388	IMPORT_SFUNC(NdisGetCurrentSystemTime, 1),
3389	IMPORT_SFUNC(NdisGetSystemUpTime, 1),
3390	IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3),
3391	IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4),
3392	IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3),
3393	IMPORT_SFUNC(NdisInterlockedInsertTailList, 3),
3394	IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2),
3395	IMPORT_SFUNC(NdisInitializeWrapper, 4),
3396	IMPORT_SFUNC(NdisMRegisterMiniport, 3),
3397	IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3),
3398	IMPORT_SFUNC(NdisAllocateMemory, 4 + 1),
3399	IMPORT_SFUNC(NdisMSetAttributesEx, 5),
3400	IMPORT_SFUNC(NdisCloseConfiguration, 1),
3401	IMPORT_SFUNC(NdisReadConfiguration, 5),
3402	IMPORT_SFUNC(NdisOpenConfiguration, 3),
3403	IMPORT_SFUNC(NdisAcquireSpinLock, 1),
3404	IMPORT_SFUNC(NdisReleaseSpinLock, 1),
3405	IMPORT_SFUNC(NdisDprAcquireSpinLock, 1),
3406	IMPORT_SFUNC(NdisDprReleaseSpinLock, 1),
3407	IMPORT_SFUNC(NdisAllocateSpinLock, 1),
3408	IMPORT_SFUNC(NdisInitializeReadWriteLock, 1),
3409	IMPORT_SFUNC(NdisAcquireReadWriteLock, 3),
3410	IMPORT_SFUNC(NdisReleaseReadWriteLock, 2),
3411	IMPORT_SFUNC(NdisFreeSpinLock, 1),
3412	IMPORT_SFUNC(NdisFreeMemory, 3),
3413	IMPORT_SFUNC(NdisReadPciSlotInformation, 5),
3414	IMPORT_SFUNC(NdisWritePciSlotInformation, 5),
3415	IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation,
3416	    NdisReadPciSlotInformation, 5),
3417	IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation,
3418	    NdisWritePciSlotInformation, 5),
3419	IMPORT_CFUNC(NdisWriteErrorLogEntry, 0),
3420	IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6),
3421	IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3),
3422	IMPORT_SFUNC(NdisMInitializeTimer, 4),
3423	IMPORT_SFUNC(NdisInitializeTimer, 3),
3424	IMPORT_SFUNC(NdisSetTimer, 2),
3425	IMPORT_SFUNC(NdisMCancelTimer, 2),
3426	IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2),
3427	IMPORT_SFUNC(NdisMSetPeriodicTimer, 2),
3428	IMPORT_SFUNC(NdisMQueryAdapterResources, 4),
3429	IMPORT_SFUNC(NdisMRegisterIoPortRange, 4),
3430	IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4),
3431	IMPORT_SFUNC(NdisReadNetworkAddress, 4),
3432	IMPORT_SFUNC(NdisQueryMapRegisterCount, 2),
3433	IMPORT_SFUNC(NdisMAllocateMapRegisters, 5),
3434	IMPORT_SFUNC(NdisMFreeMapRegisters, 1),
3435	IMPORT_SFUNC(NdisMAllocateSharedMemory, 5),
3436	IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1),
3437	IMPORT_SFUNC(NdisMUnmapIoSpace, 3),
3438	IMPORT_SFUNC(NdisGetCacheFillSize, 0),
3439	IMPORT_SFUNC(NdisMGetDmaAlignment, 1),
3440	IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3),
3441	IMPORT_SFUNC(NdisAllocatePacketPool, 4),
3442	IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5),
3443	IMPORT_SFUNC(NdisAllocatePacket, 3),
3444	IMPORT_SFUNC(NdisFreePacket, 1),
3445	IMPORT_SFUNC(NdisFreePacketPool, 1),
3446	IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3),
3447	IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1),
3448	IMPORT_SFUNC(NdisAllocateBufferPool, 3),
3449	IMPORT_SFUNC(NdisAllocateBuffer, 5),
3450	IMPORT_SFUNC(NdisQueryBuffer, 3),
3451	IMPORT_SFUNC(NdisQueryBufferSafe, 4),
3452	IMPORT_SFUNC(NdisBufferVirtualAddress, 1),
3453	IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2),
3454	IMPORT_SFUNC(NdisBufferLength, 1),
3455	IMPORT_SFUNC(NdisFreeBuffer, 1),
3456	IMPORT_SFUNC(NdisFreeBufferPool, 1),
3457	IMPORT_SFUNC(NdisInterlockedIncrement, 1),
3458	IMPORT_SFUNC(NdisInterlockedDecrement, 1),
3459	IMPORT_SFUNC(NdisInitializeEvent, 1),
3460	IMPORT_SFUNC(NdisSetEvent, 1),
3461	IMPORT_SFUNC(NdisResetEvent, 1),
3462	IMPORT_SFUNC(NdisWaitEvent, 2),
3463	IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2),
3464	IMPORT_SFUNC(NdisMPciAssignResources, 3),
3465	IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1),
3466	IMPORT_SFUNC(NdisMRegisterInterrupt, 7),
3467	IMPORT_SFUNC(NdisMDeregisterInterrupt, 1),
3468	IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3),
3469	IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1),
3470	IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1),
3471	IMPORT_SFUNC(NdisQueryBufferOffset, 3),
3472	IMPORT_SFUNC(NdisAdjustBufferLength, 2),
3473	IMPORT_SFUNC(NdisPacketPoolUsage, 1),
3474	IMPORT_SFUNC(NdisMSleep, 1),
3475	IMPORT_SFUNC(NdisUnchainBufferAtFront, 2),
3476	IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4),
3477	IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4),
3478	IMPORT_SFUNC(NdisOpenFile, 5 + 1),
3479	IMPORT_SFUNC(NdisMapFile, 3),
3480	IMPORT_SFUNC(NdisUnmapFile, 1),
3481	IMPORT_SFUNC(NdisCloseFile, 1),
3482	IMPORT_SFUNC(NdisMRegisterDevice, 6),
3483	IMPORT_SFUNC(NdisMDeregisterDevice, 1),
3484	IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2),
3485	IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2),
3486	IMPORT_SFUNC(ndis_timercall, 4),
3487	IMPORT_SFUNC(ndis_asyncmem_complete, 2),
3488	IMPORT_SFUNC(ndis_intr, 2),
3489	IMPORT_SFUNC(ndis_intrhand, 4),
3490
3491	/*
3492	 * This last entry is a catch-all for any function we haven't
3493	 * implemented yet. The PE import list patching routine will
3494	 * use it for any function that doesn't have an explicit match
3495	 * in this table.
3496	 */
3497
3498	{ NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
3499
3500	/* End of list. */
3501
3502	{ NULL, NULL, NULL }
3503};
3504