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