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