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