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