subr_ndis.c revision 145895
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 145895 2005-05-05 03:56:09Z 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
1662	ifw = (io_workitem_func)ndis_findwrap((funcptr)ndis_asyncmem_complete);
1663	IoQueueWorkItem(iw, ifw, WORKQUEUE_DELAYED, w);
1664
1665	return(NDIS_STATUS_PENDING);
1666}
1667
1668static void
1669NdisMFreeSharedMemory(adapter, len, cached, vaddr, paddr)
1670	ndis_handle		adapter;
1671	uint32_t		len;
1672	uint8_t			cached;
1673	void			*vaddr;
1674	ndis_physaddr		paddr;
1675{
1676	ndis_miniport_block	*block;
1677	struct ndis_softc	*sc;
1678	struct ndis_shmem	*sh, *prev;
1679	int			checks = 0;
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		checks++;
1695		if (sh->ndis_saddr == vaddr)
1696			break;
1697		/*
1698	 	 * Check the physaddr too, just in case the driver lied
1699		 * about the virtual address.
1700		 */
1701		if (sh->ndis_paddr.np_quad == paddr.np_quad)
1702			break;
1703		prev = sh;
1704		sh = sh->ndis_next;
1705	}
1706
1707	if (sh == NULL) {
1708		printf("NDIS: buggy driver tried to free "
1709		    "invalid shared memory: vaddr: %p paddr: 0x%qx\n",
1710		    vaddr, paddr.np_quad);
1711		return;
1712	}
1713
1714	bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1715	bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap);
1716	bus_dma_tag_destroy(sh->ndis_stag);
1717
1718	if (sh == sc->ndis_shlist)
1719		sc->ndis_shlist = sh->ndis_next;
1720	else
1721		prev->ndis_next = sh->ndis_next;
1722
1723	free(sh, M_DEVBUF);
1724
1725	return;
1726}
1727
1728static ndis_status
1729NdisMMapIoSpace(vaddr, adapter, paddr, len)
1730	void			**vaddr;
1731	ndis_handle		adapter;
1732	ndis_physaddr		paddr;
1733	uint32_t		len;
1734{
1735	ndis_miniport_block	*block;
1736	struct ndis_softc	*sc;
1737
1738	if (adapter == NULL)
1739		return(NDIS_STATUS_FAILURE);
1740
1741	block = (ndis_miniport_block *)adapter;
1742	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1743
1744	if (sc->ndis_res_mem != NULL &&
1745	    paddr.np_quad == rman_get_start(sc->ndis_res_mem))
1746		*vaddr = (void *)rman_get_virtual(sc->ndis_res_mem);
1747	else if (sc->ndis_res_altmem != NULL &&
1748	     paddr.np_quad == rman_get_start(sc->ndis_res_altmem))
1749		*vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem);
1750	else if (sc->ndis_res_am != NULL &&
1751	     paddr.np_quad == rman_get_start(sc->ndis_res_am))
1752		*vaddr = (void *)rman_get_virtual(sc->ndis_res_am);
1753	else
1754		return(NDIS_STATUS_FAILURE);
1755
1756	return(NDIS_STATUS_SUCCESS);
1757}
1758
1759static void
1760NdisMUnmapIoSpace(adapter, vaddr, len)
1761	ndis_handle		adapter;
1762	void			*vaddr;
1763	uint32_t		len;
1764{
1765	return;
1766}
1767
1768static uint32_t
1769NdisGetCacheFillSize(void)
1770{
1771	return(128);
1772}
1773
1774static uint32_t
1775NdisMGetDmaAlignment(handle)
1776	ndis_handle		handle;
1777{
1778	return(16);
1779}
1780
1781/*
1782 * NDIS has two methods for dealing with NICs that support DMA.
1783 * One is to just pass packets to the driver and let it call
1784 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
1785 * all by itself, and the other is to let the NDIS library handle the
1786 * buffer mapping internally, and hand the driver an already populated
1787 * scatter/gather fragment list. If the driver calls
1788 * NdisMInitializeScatterGatherDma(), it wants to use the latter
1789 * method.
1790 */
1791
1792static ndis_status
1793NdisMInitializeScatterGatherDma(adapter, is64, maxphysmap)
1794	ndis_handle		adapter;
1795	uint8_t			is64;
1796	uint32_t		maxphysmap;
1797{
1798	struct ndis_softc	*sc;
1799	ndis_miniport_block	*block;
1800	int			error;
1801
1802	if (adapter == NULL)
1803		return(NDIS_STATUS_FAILURE);
1804	block = (ndis_miniport_block *)adapter;
1805	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1806
1807	/* Don't do this twice. */
1808	if (sc->ndis_sc == 1)
1809		return(NDIS_STATUS_SUCCESS);
1810
1811	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1812	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1813	    MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
1814	    NULL, NULL, &sc->ndis_ttag);
1815
1816	sc->ndis_sc = 1;
1817
1818	return(NDIS_STATUS_SUCCESS);
1819}
1820
1821void
1822NdisAllocatePacketPool(status, pool, descnum, protrsvdlen)
1823	ndis_status		*status;
1824	ndis_handle		*pool;
1825	uint32_t		descnum;
1826	uint32_t		protrsvdlen;
1827{
1828	ndis_packet		*cur;
1829	int			i;
1830
1831	*pool = malloc((sizeof(ndis_packet) + protrsvdlen) *
1832	    ((descnum + NDIS_POOL_EXTRA) + 1),
1833	    M_DEVBUF, M_NOWAIT|M_ZERO);
1834
1835	if (*pool == NULL) {
1836		*status = NDIS_STATUS_RESOURCES;
1837		return;
1838	}
1839
1840	cur = (ndis_packet *)*pool;
1841	KeInitializeSpinLock(&cur->np_lock);
1842	cur->np_private.npp_flags = 0x1; /* mark the head of the list */
1843	cur->np_private.npp_totlen = 0; /* init deletetion flag */
1844	for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
1845		cur->np_private.npp_head = (ndis_handle)(cur + 1);
1846		cur++;
1847	}
1848
1849	*status = NDIS_STATUS_SUCCESS;
1850	return;
1851}
1852
1853void
1854NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen)
1855	ndis_status		*status;
1856	ndis_handle		*pool;
1857	uint32_t		descnum;
1858	uint32_t		oflowdescnum;
1859	uint32_t		protrsvdlen;
1860{
1861	return(NdisAllocatePacketPool(status, pool,
1862	    descnum + oflowdescnum, protrsvdlen));
1863}
1864
1865uint32_t
1866NdisPacketPoolUsage(pool)
1867	ndis_handle		pool;
1868{
1869	ndis_packet		*head;
1870	uint8_t			irql;
1871	uint32_t		cnt;
1872
1873	head = (ndis_packet *)pool;
1874	KeAcquireSpinLock(&head->np_lock, &irql);
1875	cnt = head->np_private.npp_count;
1876	KeReleaseSpinLock(&head->np_lock, irql);
1877
1878	return(cnt);
1879}
1880
1881void
1882NdisFreePacketPool(pool)
1883	ndis_handle		pool;
1884{
1885	ndis_packet		*head;
1886	uint8_t			irql;
1887
1888	head = pool;
1889
1890	/* Mark this pool as 'going away.' */
1891
1892	KeAcquireSpinLock(&head->np_lock, &irql);
1893	head->np_private.npp_totlen = 1;
1894
1895	/* If there are no buffers loaned out, destroy the pool. */
1896
1897	if (head->np_private.npp_count == 0) {
1898		KeReleaseSpinLock(&head->np_lock, irql);
1899		free(pool, M_DEVBUF);
1900	} else {
1901		printf("NDIS: buggy driver deleting active packet pool!\n");
1902		KeReleaseSpinLock(&head->np_lock, irql);
1903	}
1904
1905	return;
1906}
1907
1908void
1909NdisAllocatePacket(status, packet, pool)
1910	ndis_status		*status;
1911	ndis_packet		**packet;
1912	ndis_handle		pool;
1913{
1914	ndis_packet		*head, *pkt;
1915	uint8_t			irql;
1916
1917	head = (ndis_packet *)pool;
1918	KeAcquireSpinLock(&head->np_lock, &irql);
1919
1920	if (head->np_private.npp_flags != 0x1) {
1921		*status = NDIS_STATUS_FAILURE;
1922		KeReleaseSpinLock(&head->np_lock, irql);
1923		return;
1924	}
1925
1926	/*
1927	 * If this pool is marked as 'going away' don't allocate any
1928	 * more packets out of it.
1929	 */
1930
1931	if (head->np_private.npp_totlen) {
1932		*status = NDIS_STATUS_FAILURE;
1933		KeReleaseSpinLock(&head->np_lock, irql);
1934		return;
1935	}
1936
1937	pkt = (ndis_packet *)head->np_private.npp_head;
1938
1939	if (pkt == NULL) {
1940		*status = NDIS_STATUS_RESOURCES;
1941		KeReleaseSpinLock(&head->np_lock, irql);
1942		return;
1943	}
1944
1945	head->np_private.npp_head = pkt->np_private.npp_head;
1946
1947	pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL;
1948	/* Save pointer to the pool. */
1949	pkt->np_private.npp_pool = head;
1950
1951	/* Set the oob offset pointer. Lots of things expect this. */
1952	pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob);
1953
1954	/*
1955	 * We must initialize the packet flags correctly in order
1956	 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
1957	 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work
1958         * correctly.
1959	 */
1960	pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
1961	pkt->np_private.npp_validcounts = FALSE;
1962
1963	*packet = pkt;
1964
1965	head->np_private.npp_count++;
1966	*status = NDIS_STATUS_SUCCESS;
1967
1968	KeReleaseSpinLock(&head->np_lock, irql);
1969
1970	return;
1971}
1972
1973void
1974NdisFreePacket(packet)
1975	ndis_packet		*packet;
1976{
1977	ndis_packet		*head;
1978	uint8_t			irql;
1979
1980	if (packet == NULL || packet->np_private.npp_pool == NULL)
1981		return;
1982
1983	head = packet->np_private.npp_pool;
1984	KeAcquireSpinLock(&head->np_lock, &irql);
1985
1986	if (head->np_private.npp_flags != 0x1) {
1987		KeReleaseSpinLock(&head->np_lock, irql);
1988		return;
1989	}
1990
1991	packet->np_private.npp_head = head->np_private.npp_head;
1992	head->np_private.npp_head = (ndis_buffer *)packet;
1993	head->np_private.npp_count--;
1994
1995	/*
1996	 * If the pool has been marked for deletion and there are
1997	 * no more packets outstanding, nuke the pool.
1998	 */
1999
2000	if (head->np_private.npp_totlen && head->np_private.npp_count == 0) {
2001		KeReleaseSpinLock(&head->np_lock, irql);
2002		free(head, M_DEVBUF);
2003	} else
2004		KeReleaseSpinLock(&head->np_lock, irql);
2005
2006	return;
2007}
2008
2009static void
2010NdisUnchainBufferAtFront(packet, buf)
2011	ndis_packet		*packet;
2012	ndis_buffer		**buf;
2013{
2014	ndis_packet_private	*priv;
2015
2016	if (packet == NULL || buf == NULL)
2017		return;
2018
2019	priv = &packet->np_private;
2020
2021	priv->npp_validcounts = FALSE;
2022
2023	if (priv->npp_head == priv->npp_tail) {
2024		*buf = priv->npp_head;
2025		priv->npp_head = priv->npp_tail = NULL;
2026	} else {
2027		*buf = priv->npp_head;
2028		priv->npp_head = (*buf)->mdl_next;
2029	}
2030
2031	return;
2032}
2033
2034static void
2035NdisUnchainBufferAtBack(packet, buf)
2036	ndis_packet		*packet;
2037	ndis_buffer		**buf;
2038{
2039	ndis_packet_private	*priv;
2040	ndis_buffer		*tmp;
2041
2042	if (packet == NULL || buf == NULL)
2043		return;
2044
2045	priv = &packet->np_private;
2046
2047	priv->npp_validcounts = FALSE;
2048
2049	if (priv->npp_head == priv->npp_tail) {
2050		*buf = priv->npp_head;
2051		priv->npp_head = priv->npp_tail = NULL;
2052	} else {
2053		*buf = priv->npp_tail;
2054		tmp = priv->npp_head;
2055		while (tmp->mdl_next != priv->npp_tail)
2056			tmp = tmp->mdl_next;
2057		priv->npp_tail = tmp;
2058		tmp->mdl_next = NULL;
2059	}
2060
2061	return;
2062}
2063
2064/*
2065 * The NDIS "buffer" is really an MDL (memory descriptor list)
2066 * which is used to describe a buffer in a way that allows it
2067 * to mapped into different contexts. We have to be careful how
2068 * we handle them: in some versions of Windows, the NdisFreeBuffer()
2069 * routine is an actual function in the NDIS API, but in others
2070 * it's just a macro wrapper around IoFreeMdl(). There's really
2071 * no way to use the 'descnum' parameter to count how many
2072 * "buffers" are allocated since in order to use IoFreeMdl() to
2073 * dispose of a buffer, we have to use IoAllocateMdl() to allocate
2074 * them, and IoAllocateMdl() just grabs them out of the heap.
2075 */
2076
2077static void
2078NdisAllocateBufferPool(status, pool, descnum)
2079	ndis_status		*status;
2080	ndis_handle		*pool;
2081	uint32_t		descnum;
2082{
2083	/*
2084	 * The only thing we can really do here is verify that descnum
2085	 * is a reasonable value, but I really don't know what to check
2086	 * it against.
2087	 */
2088
2089	*pool = NonPagedPool;
2090	*status = NDIS_STATUS_SUCCESS;
2091	return;
2092}
2093
2094static void
2095NdisFreeBufferPool(pool)
2096	ndis_handle		pool;
2097{
2098	return;
2099}
2100
2101static void
2102NdisAllocateBuffer(status, buffer, pool, vaddr, len)
2103	ndis_status		*status;
2104	ndis_buffer		**buffer;
2105	ndis_handle		pool;
2106	void			*vaddr;
2107	uint32_t		len;
2108{
2109	ndis_buffer		*buf;
2110
2111	buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL);
2112	if (buf == NULL) {
2113		*status = NDIS_STATUS_RESOURCES;
2114		return;
2115	}
2116
2117	*buffer = buf;
2118	*status = NDIS_STATUS_SUCCESS;
2119
2120	return;
2121}
2122
2123static void
2124NdisFreeBuffer(buf)
2125	ndis_buffer		*buf;
2126{
2127	IoFreeMdl(buf);
2128	return;
2129}
2130
2131/* Aw c'mon. */
2132
2133static uint32_t
2134NdisBufferLength(buf)
2135	ndis_buffer		*buf;
2136{
2137	return(MmGetMdlByteCount(buf));
2138}
2139
2140/*
2141 * Get the virtual address and length of a buffer.
2142 * Note: the vaddr argument is optional.
2143 */
2144
2145static void
2146NdisQueryBuffer(buf, vaddr, len)
2147	ndis_buffer		*buf;
2148	void			**vaddr;
2149	uint32_t		*len;
2150{
2151	if (vaddr != NULL)
2152		*vaddr = MmGetMdlVirtualAddress(buf);
2153	*len = MmGetMdlByteCount(buf);
2154
2155	return;
2156}
2157
2158/* Same as above -- we don't care about the priority. */
2159
2160static void
2161NdisQueryBufferSafe(buf, vaddr, len, prio)
2162	ndis_buffer		*buf;
2163	void			**vaddr;
2164	uint32_t		*len;
2165	uint32_t		prio;
2166{
2167	if (vaddr != NULL)
2168		*vaddr = MmGetMdlVirtualAddress(buf);
2169	*len = MmGetMdlByteCount(buf);
2170
2171	return;
2172}
2173
2174/* Damnit Microsoft!! How many ways can you do the same thing?! */
2175
2176static void *
2177NdisBufferVirtualAddress(buf)
2178	ndis_buffer		*buf;
2179{
2180	return(MmGetMdlVirtualAddress(buf));
2181}
2182
2183static void *
2184NdisBufferVirtualAddressSafe(buf, prio)
2185	ndis_buffer		*buf;
2186	uint32_t		prio;
2187{
2188	return(MmGetMdlVirtualAddress(buf));
2189}
2190
2191static void
2192NdisAdjustBufferLength(buf, len)
2193	ndis_buffer		*buf;
2194	int			len;
2195{
2196	MmGetMdlByteCount(buf) = len;
2197
2198	return;
2199}
2200
2201static uint32_t
2202NdisInterlockedIncrement(addend)
2203	uint32_t		*addend;
2204{
2205	atomic_add_long((u_long *)addend, 1);
2206	return(*addend);
2207}
2208
2209static uint32_t
2210NdisInterlockedDecrement(addend)
2211	uint32_t		*addend;
2212{
2213	atomic_subtract_long((u_long *)addend, 1);
2214	return(*addend);
2215}
2216
2217static void
2218NdisInitializeEvent(event)
2219	ndis_event		*event;
2220{
2221	/*
2222	 * NDIS events are always notification
2223	 * events, and should be initialized to the
2224	 * not signaled state.
2225	 */
2226	KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE);
2227	return;
2228}
2229
2230static void
2231NdisSetEvent(event)
2232	ndis_event		*event;
2233{
2234	KeSetEvent(&event->ne_event, 0, 0);
2235	return;
2236}
2237
2238static void
2239NdisResetEvent(event)
2240	ndis_event		*event;
2241{
2242	KeResetEvent(&event->ne_event);
2243	return;
2244}
2245
2246static uint8_t
2247NdisWaitEvent(event, msecs)
2248	ndis_event		*event;
2249	uint32_t		msecs;
2250{
2251	int64_t			duetime;
2252	uint32_t		rval;
2253
2254	duetime = ((int64_t)msecs * -10000);
2255	rval = KeWaitForSingleObject((nt_dispatch_header *)event,
2256	    0, 0, TRUE, msecs ? & duetime : NULL);
2257
2258	if (rval == STATUS_TIMEOUT)
2259		return(FALSE);
2260
2261	return(TRUE);
2262}
2263
2264static ndis_status
2265NdisUnicodeStringToAnsiString(dstr, sstr)
2266	ndis_ansi_string	*dstr;
2267	ndis_unicode_string	*sstr;
2268{
2269	if (dstr == NULL || sstr == NULL)
2270		return(NDIS_STATUS_FAILURE);
2271	if (ndis_unicode_to_ascii(sstr->us_buf,
2272	    sstr->us_len, &dstr->nas_buf))
2273		return(NDIS_STATUS_FAILURE);
2274	dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf);
2275	return (NDIS_STATUS_SUCCESS);
2276}
2277
2278static ndis_status
2279NdisAnsiStringToUnicodeString(dstr, sstr)
2280	ndis_unicode_string	*dstr;
2281	ndis_ansi_string	*sstr;
2282{
2283	char			*str;
2284	if (dstr == NULL || sstr == NULL)
2285		return(NDIS_STATUS_FAILURE);
2286	str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT);
2287	if (str == NULL)
2288		return(NDIS_STATUS_FAILURE);
2289	strncpy(str, sstr->nas_buf, sstr->nas_len);
2290	*(str + sstr->nas_len) = '\0';
2291	if (ndis_ascii_to_unicode(str, &dstr->us_buf)) {
2292		free(str, M_DEVBUF);
2293		return(NDIS_STATUS_FAILURE);
2294	}
2295	dstr->us_len = dstr->us_maxlen = sstr->nas_len * 2;
2296	free(str, M_DEVBUF);
2297	return (NDIS_STATUS_SUCCESS);
2298}
2299
2300static ndis_status
2301NdisMPciAssignResources(adapter, slot, list)
2302	ndis_handle		adapter;
2303	uint32_t		slot;
2304	ndis_resource_list	**list;
2305{
2306	ndis_miniport_block	*block;
2307
2308	if (adapter == NULL || list == NULL)
2309		return (NDIS_STATUS_FAILURE);
2310
2311	block = (ndis_miniport_block *)adapter;
2312	*list = block->nmb_rlist;
2313
2314	return (NDIS_STATUS_SUCCESS);
2315}
2316
2317static ndis_status
2318NdisMRegisterInterrupt(intr, adapter, ivec, ilevel, reqisr, shared, imode)
2319	ndis_miniport_interrupt	*intr;
2320	ndis_handle		adapter;
2321	uint32_t		ivec;
2322	uint32_t		ilevel;
2323	uint8_t			reqisr;
2324	uint8_t			shared;
2325	ndis_interrupt_mode	imode;
2326{
2327	ndis_miniport_block	*block;
2328
2329	block = adapter;
2330
2331	intr->ni_block = adapter;
2332	intr->ni_isrreq = reqisr;
2333	intr->ni_shared = shared;
2334	block->nmb_interrupt = intr;
2335
2336	KeInitializeSpinLock(&intr->ni_dpccountlock);
2337
2338	return(NDIS_STATUS_SUCCESS);
2339}
2340
2341static void
2342NdisMDeregisterInterrupt(intr)
2343	ndis_miniport_interrupt	*intr;
2344{
2345	return;
2346}
2347
2348static void
2349NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc)
2350	ndis_handle		adapter;
2351	void			*shutdownctx;
2352	ndis_shutdown_handler	shutdownfunc;
2353{
2354	ndis_miniport_block	*block;
2355	ndis_miniport_characteristics *chars;
2356	struct ndis_softc	*sc;
2357
2358	if (adapter == NULL)
2359		return;
2360
2361	block = (ndis_miniport_block *)adapter;
2362	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2363	chars = sc->ndis_chars;
2364
2365	chars->nmc_shutdown_handler = shutdownfunc;
2366	chars->nmc_rsvd0 = shutdownctx;
2367
2368	return;
2369}
2370
2371static void
2372NdisMDeregisterAdapterShutdownHandler(adapter)
2373	ndis_handle		adapter;
2374{
2375	ndis_miniport_block	*block;
2376	ndis_miniport_characteristics *chars;
2377	struct ndis_softc	*sc;
2378
2379	if (adapter == NULL)
2380		return;
2381
2382	block = (ndis_miniport_block *)adapter;
2383	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2384	chars = sc->ndis_chars;
2385
2386	chars->nmc_shutdown_handler = NULL;
2387	chars->nmc_rsvd0 = NULL;
2388
2389	return;
2390}
2391
2392static uint32_t
2393NDIS_BUFFER_TO_SPAN_PAGES(buf)
2394	ndis_buffer		*buf;
2395{
2396	if (buf == NULL)
2397		return(0);
2398	if (MmGetMdlByteCount(buf) == 0)
2399		return(1);
2400	return(SPAN_PAGES(MmGetMdlVirtualAddress(buf),
2401	    MmGetMdlByteCount(buf)));
2402}
2403
2404static void
2405NdisGetBufferPhysicalArraySize(buf, pages)
2406	ndis_buffer		*buf;
2407	uint32_t		*pages;
2408{
2409	if (buf == NULL)
2410		return;
2411
2412	*pages = NDIS_BUFFER_TO_SPAN_PAGES(buf);
2413	return;
2414}
2415
2416static void
2417NdisQueryBufferOffset(buf, off, len)
2418	ndis_buffer		*buf;
2419	uint32_t		*off;
2420	uint32_t		*len;
2421{
2422	if (buf == NULL)
2423		return;
2424
2425	*off = MmGetMdlByteOffset(buf);
2426	*len = MmGetMdlByteCount(buf);
2427
2428	return;
2429}
2430
2431static void
2432NdisMSleep(usecs)
2433	uint32_t		usecs;
2434{
2435	struct timeval		tv;
2436
2437	/*
2438	 * During system bootstrap, (i.e. cold == 1), we aren't
2439	 * allowed to msleep(), so calling ndis_thsuspend() here
2440	 * will return 0, and we won't actually have delayed. This
2441	 * is a problem because some drivers expect NdisMSleep()
2442	 * to always wait, and might fail if the expected delay
2443	 * period does not in fact elapse. As a workaround, if the
2444	 * attempt to sleep delay fails, we do a hard DELAY() instead.
2445	 */
2446	tv.tv_sec = 0;
2447	tv.tv_usec = usecs;
2448
2449	if (ndis_thsuspend(curthread->td_proc, NULL, tvtohz(&tv)) == 0)
2450		DELAY(usecs);
2451
2452	return;
2453}
2454
2455static uint32_t
2456NdisReadPcmciaAttributeMemory(handle, offset, buf, len)
2457	ndis_handle		handle;
2458	uint32_t		offset;
2459	void			*buf;
2460	uint32_t		len;
2461{
2462	struct ndis_softc	*sc;
2463	ndis_miniport_block	*block;
2464	bus_space_handle_t	bh;
2465	bus_space_tag_t		bt;
2466	char			*dest;
2467	int			i;
2468
2469	if (handle == NULL)
2470		return(0);
2471
2472	block = (ndis_miniport_block *)handle;
2473	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2474	dest = buf;
2475
2476	bh = rman_get_bushandle(sc->ndis_res_am);
2477	bt = rman_get_bustag(sc->ndis_res_am);
2478
2479	for (i = 0; i < len; i++)
2480		dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2);
2481
2482	return(i);
2483}
2484
2485static uint32_t
2486NdisWritePcmciaAttributeMemory(handle, offset, buf, len)
2487	ndis_handle		handle;
2488	uint32_t		offset;
2489	void			*buf;
2490	uint32_t		len;
2491{
2492	struct ndis_softc	*sc;
2493	ndis_miniport_block	*block;
2494	bus_space_handle_t	bh;
2495	bus_space_tag_t		bt;
2496	char			*src;
2497	int			i;
2498
2499	if (handle == NULL)
2500		return(0);
2501
2502	block = (ndis_miniport_block *)handle;
2503	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2504	src = buf;
2505
2506	bh = rman_get_bushandle(sc->ndis_res_am);
2507	bt = rman_get_bustag(sc->ndis_res_am);
2508
2509	for (i = 0; i < len; i++)
2510		bus_space_write_1(bt, bh, (offset + i) * 2, src[i]);
2511
2512	return(i);
2513}
2514
2515static list_entry *
2516NdisInterlockedInsertHeadList(head, entry, lock)
2517	list_entry		*head;
2518	list_entry		*entry;
2519	ndis_spin_lock		*lock;
2520{
2521	list_entry		*flink;
2522
2523	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2524	flink = head->nle_flink;
2525	entry->nle_flink = flink;
2526	entry->nle_blink = head;
2527	flink->nle_blink = entry;
2528	head->nle_flink = entry;
2529	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2530
2531	return(flink);
2532}
2533
2534static list_entry *
2535NdisInterlockedRemoveHeadList(head, lock)
2536	list_entry		*head;
2537	ndis_spin_lock		*lock;
2538{
2539	list_entry		*flink;
2540	list_entry		*entry;
2541
2542	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2543	entry = head->nle_flink;
2544	flink = entry->nle_flink;
2545	head->nle_flink = flink;
2546	flink->nle_blink = head;
2547	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2548
2549	return(entry);
2550}
2551
2552static list_entry *
2553NdisInterlockedInsertTailList(head, entry, lock)
2554	list_entry		*head;
2555	list_entry		*entry;
2556	ndis_spin_lock		*lock;
2557{
2558	list_entry		*blink;
2559
2560	KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2561	blink = head->nle_blink;
2562	entry->nle_flink = head;
2563	entry->nle_blink = blink;
2564	blink->nle_flink = entry;
2565	head->nle_blink = entry;
2566	KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2567
2568	return(blink);
2569}
2570
2571static uint8_t
2572NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx)
2573	ndis_miniport_interrupt	*intr;
2574	void			*syncfunc;
2575	void			*syncctx;
2576{
2577	uint8_t (*sync)(void *);
2578	uint8_t			rval;
2579	uint8_t			irql;
2580
2581	if (syncfunc == NULL || syncctx == NULL)
2582		return(0);
2583
2584	sync = syncfunc;
2585	KeAcquireSpinLock(&intr->ni_dpccountlock, &irql);
2586	rval = MSCALL1(sync, syncctx);
2587	KeReleaseSpinLock(&intr->ni_dpccountlock, irql);
2588
2589	return(rval);
2590}
2591
2592/*
2593 * Return the number of 100 nanosecond intervals since
2594 * January 1, 1601. (?!?!)
2595 */
2596static void
2597NdisGetCurrentSystemTime(tval)
2598	uint64_t		*tval;
2599{
2600	struct timespec		ts;
2601
2602	nanotime(&ts);
2603	*tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
2604	    11644473600;
2605
2606	return;
2607}
2608
2609/*
2610 * Return the number of milliseconds since the system booted.
2611 */
2612static void
2613NdisGetSystemUpTime(tval)
2614	uint32_t		*tval;
2615{
2616	struct timespec		ts;
2617
2618	nanouptime(&ts);
2619	*tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
2620
2621	return;
2622}
2623
2624static void
2625NdisInitializeString(dst, src)
2626	ndis_unicode_string	*dst;
2627	char			*src;
2628{
2629	ndis_unicode_string	*u;
2630
2631	u = dst;
2632	u->us_buf = NULL;
2633	if (ndis_ascii_to_unicode(src, &u->us_buf))
2634		return;
2635	u->us_len = u->us_maxlen = strlen(src) * 2;
2636	return;
2637}
2638
2639static void
2640NdisFreeString(str)
2641	ndis_unicode_string	*str;
2642{
2643	if (str == NULL)
2644		return;
2645	if (str->us_buf != NULL)
2646		free(str->us_buf, M_DEVBUF);
2647	free(str, M_DEVBUF);
2648	return;
2649}
2650
2651static ndis_status
2652NdisMRemoveMiniport(adapter)
2653	ndis_handle		*adapter;
2654{
2655	return(NDIS_STATUS_SUCCESS);
2656}
2657
2658static void
2659NdisInitAnsiString(dst, src)
2660	ndis_ansi_string	*dst;
2661	char			*src;
2662{
2663	ndis_ansi_string	*a;
2664
2665	a = dst;
2666	if (a == NULL)
2667		return;
2668	if (src == NULL) {
2669		a->nas_len = a->nas_maxlen = 0;
2670		a->nas_buf = NULL;
2671	} else {
2672		a->nas_buf = src;
2673		a->nas_len = a->nas_maxlen = strlen(src);
2674	}
2675
2676	return;
2677}
2678
2679static void
2680NdisInitUnicodeString(dst, src)
2681	ndis_unicode_string	*dst;
2682	uint16_t		*src;
2683{
2684	ndis_unicode_string	*u;
2685	int			i;
2686
2687	u = dst;
2688	if (u == NULL)
2689		return;
2690	if (src == NULL) {
2691		u->us_len = u->us_maxlen = 0;
2692		u->us_buf = NULL;
2693	} else {
2694		i = 0;
2695		while(src[i] != 0)
2696			i++;
2697		u->us_buf = src;
2698		u->us_len = u->us_maxlen = i * 2;
2699	}
2700
2701	return;
2702}
2703
2704static void NdisMGetDeviceProperty(adapter, phydevobj,
2705	funcdevobj, nextdevobj, resources, transresources)
2706	ndis_handle		adapter;
2707	device_object		**phydevobj;
2708	device_object		**funcdevobj;
2709	device_object		**nextdevobj;
2710	cm_resource_list	*resources;
2711	cm_resource_list	*transresources;
2712{
2713	ndis_miniport_block	*block;
2714
2715	block = (ndis_miniport_block *)adapter;
2716
2717	if (phydevobj != NULL)
2718		*phydevobj = block->nmb_physdeviceobj;
2719	if (funcdevobj != NULL)
2720		*funcdevobj = block->nmb_deviceobj;
2721	if (nextdevobj != NULL)
2722		*nextdevobj = block->nmb_nextdeviceobj;
2723
2724	return;
2725}
2726
2727static void
2728NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen)
2729	ndis_packet		*packet;
2730	ndis_buffer		**buf;
2731	void			**firstva;
2732	uint32_t		*firstlen;
2733	uint32_t		*totlen;
2734{
2735	ndis_buffer		*tmp;
2736
2737	tmp = packet->np_private.npp_head;
2738	*buf = tmp;
2739	if (tmp == NULL) {
2740		*firstva = NULL;
2741		*firstlen = *totlen = 0;
2742	} else {
2743		*firstva = MmGetMdlVirtualAddress(tmp);
2744		*firstlen = *totlen = MmGetMdlByteCount(tmp);
2745		for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next)
2746			*totlen += MmGetMdlByteCount(tmp);
2747	}
2748
2749	return;
2750}
2751
2752static void
2753NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio)
2754	ndis_packet		*packet;
2755	ndis_buffer		**buf;
2756	void			**firstva;
2757	uint32_t		*firstlen;
2758	uint32_t		*totlen;
2759	uint32_t		prio;
2760{
2761	NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen);
2762}
2763
2764static int
2765ndis_find_sym(lf, filename, suffix, sym)
2766	linker_file_t		lf;
2767	char			*filename;
2768	char			*suffix;
2769	caddr_t			*sym;
2770{
2771	char			*fullsym;
2772	char			*suf;
2773	int			i;
2774
2775	fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2776	if (fullsym == NULL)
2777		return(ENOMEM);
2778
2779	bzero(fullsym, MAXPATHLEN);
2780	strncpy(fullsym, filename, MAXPATHLEN);
2781	if (strlen(filename) < 4) {
2782		ExFreePool(fullsym);
2783		return(EINVAL);
2784	}
2785
2786	/* If the filename has a .ko suffix, strip if off. */
2787	suf = fullsym + (strlen(filename) - 3);
2788	if (strcmp(suf, ".ko") == 0)
2789		*suf = '\0';
2790
2791	for (i = 0; i < strlen(fullsym); i++) {
2792		if (fullsym[i] == '.')
2793			fullsym[i] = '_';
2794		else
2795			fullsym[i] = tolower(fullsym[i]);
2796	}
2797	strcat(fullsym, suffix);
2798	*sym = linker_file_lookup_symbol(lf, fullsym, 0);
2799	ExFreePool(fullsym);
2800	if (*sym == 0)
2801		return(ENOENT);
2802
2803	return(0);
2804}
2805
2806/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
2807static void
2808NdisOpenFile(status, filehandle, filelength, filename, highestaddr)
2809	ndis_status		*status;
2810	ndis_handle		*filehandle;
2811	uint32_t		*filelength;
2812	ndis_unicode_string	*filename;
2813	ndis_physaddr		highestaddr;
2814{
2815	char			*afilename = NULL;
2816	struct thread		*td = curthread;
2817	struct nameidata	nd;
2818	int			flags, error;
2819	struct vattr		vat;
2820	struct vattr		*vap = &vat;
2821	ndis_fh			*fh;
2822	char			*path;
2823	linker_file_t		head, lf;
2824	caddr_t			kldstart, kldend;
2825
2826	ndis_unicode_to_ascii(filename->us_buf,
2827	    filename->us_len, &afilename);
2828
2829	fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0);
2830	if (fh == NULL) {
2831		free(afilename, M_DEVBUF);
2832		*status = NDIS_STATUS_RESOURCES;
2833		return;
2834	}
2835
2836	fh->nf_name = afilename;
2837
2838	/*
2839	 * During system bootstrap, it's impossible to load files
2840	 * from the rootfs since it's not mounted yet. We therefore
2841	 * offer the possibility of opening files that have been
2842	 * preloaded as modules instead. Both choices will work
2843	 * when kldloading a module from multiuser, but only the
2844	 * module option will work during bootstrap. The module
2845	 * loading option works by using the ndiscvt(8) utility
2846	 * to convert the arbitrary file into a .ko using objcopy(1).
2847	 * This file will contain two special symbols: filename_start
2848	 * and filename_end. All we have to do is traverse the KLD
2849	 * list in search of those symbols and we've found the file
2850	 * data. As an added bonus, ndiscvt(8) will also generate
2851	 * a normal .o file which can be linked statically with
2852	 * the kernel. This means that the symbols will actual reside
2853	 * in the kernel's symbol table, but that doesn't matter to
2854	 * us since the kernel appears to us as just another module.
2855	 */
2856
2857	/*
2858	 * This is an evil trick for getting the head of the linked
2859	 * file list, which is not exported from kern_linker.o. It
2860	 * happens that linker file #1 is always the kernel, and is
2861	 * always the first element in the list.
2862	 */
2863
2864	head = linker_find_file_by_id(1);
2865	for (lf = head; lf != NULL; lf = TAILQ_NEXT(lf, link)) {
2866		if (ndis_find_sym(lf, afilename, "_start", &kldstart))
2867			continue;
2868		if (ndis_find_sym(lf, afilename, "_end", &kldend))
2869			continue;
2870		fh->nf_vp = lf;
2871		fh->nf_map = NULL;
2872		fh->nf_type = NDIS_FH_TYPE_MODULE;
2873		*filelength = fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF;
2874		*filehandle = fh;
2875		*status = NDIS_STATUS_SUCCESS;
2876		return;
2877	}
2878
2879	if (TAILQ_EMPTY(&mountlist)) {
2880		ExFreePool(fh);
2881		*status = NDIS_STATUS_FILE_NOT_FOUND;
2882		printf("NDIS: could not find file %s in linker list\n",
2883		    afilename);
2884		printf("NDIS: and no filesystems mounted yet, "
2885		    "aborting NdisOpenFile()\n");
2886		free(afilename, M_DEVBUF);
2887		return;
2888	}
2889
2890	path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2891	if (path == NULL) {
2892		ExFreePool(fh);
2893		free(afilename, M_DEVBUF);
2894		*status = NDIS_STATUS_RESOURCES;
2895		return;
2896	}
2897
2898	snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename);
2899	free(afilename, M_DEVBUF);
2900
2901	mtx_lock(&Giant);
2902
2903	/* Some threads don't have a current working directory. */
2904
2905	if (td->td_proc->p_fd->fd_rdir == NULL)
2906		td->td_proc->p_fd->fd_rdir = rootvnode;
2907	if (td->td_proc->p_fd->fd_cdir == NULL)
2908		td->td_proc->p_fd->fd_cdir = rootvnode;
2909
2910	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
2911
2912	flags = FREAD;
2913	error = vn_open(&nd, &flags, 0, -1);
2914	if (error) {
2915		mtx_unlock(&Giant);
2916		*status = NDIS_STATUS_FILE_NOT_FOUND;
2917		ExFreePool(fh);
2918		printf("NDIS: open file %s failed: %d\n", path, error);
2919		ExFreePool(path);
2920		free(afilename, M_DEVBUF);
2921		return;
2922	}
2923
2924	ExFreePool(path);
2925
2926	NDFREE(&nd, NDF_ONLY_PNBUF);
2927
2928	/* Get the file size. */
2929	VOP_GETATTR(nd.ni_vp, vap, td->td_ucred, td);
2930	VOP_UNLOCK(nd.ni_vp, 0, td);
2931	mtx_unlock(&Giant);
2932
2933	fh->nf_vp = nd.ni_vp;
2934	fh->nf_map = NULL;
2935	fh->nf_type = NDIS_FH_TYPE_VFS;
2936	*filehandle = fh;
2937	*filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
2938	*status = NDIS_STATUS_SUCCESS;
2939
2940	return;
2941}
2942
2943static void
2944NdisMapFile(status, mappedbuffer, filehandle)
2945	ndis_status		*status;
2946	void			**mappedbuffer;
2947	ndis_handle		filehandle;
2948{
2949	ndis_fh			*fh;
2950	struct thread		*td = curthread;
2951	linker_file_t		lf;
2952	caddr_t			kldstart;
2953	int			error, resid;
2954
2955	if (filehandle == NULL) {
2956		*status = NDIS_STATUS_FAILURE;
2957		return;
2958	}
2959
2960	fh = (ndis_fh *)filehandle;
2961
2962	if (fh->nf_vp == NULL) {
2963		*status = NDIS_STATUS_FAILURE;
2964		return;
2965	}
2966
2967	if (fh->nf_map != NULL) {
2968		*status = NDIS_STATUS_ALREADY_MAPPED;
2969		return;
2970	}
2971
2972	if (fh->nf_type == NDIS_FH_TYPE_MODULE) {
2973		lf = fh->nf_vp;
2974		if (ndis_find_sym(lf, fh->nf_name, "_start", &kldstart)) {
2975			*status = NDIS_STATUS_FAILURE;
2976			return;
2977		}
2978		fh->nf_map = kldstart;
2979		*status = NDIS_STATUS_SUCCESS;
2980		*mappedbuffer = fh->nf_map;
2981		return;
2982	}
2983
2984	fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0);
2985
2986	if (fh->nf_map == NULL) {
2987		*status = NDIS_STATUS_RESOURCES;
2988		return;
2989	}
2990
2991	mtx_lock(&Giant);
2992	error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0,
2993	    UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td);
2994	mtx_unlock(&Giant);
2995
2996	if (error)
2997		*status = NDIS_STATUS_FAILURE;
2998	else {
2999		*status = NDIS_STATUS_SUCCESS;
3000		*mappedbuffer = fh->nf_map;
3001	}
3002
3003	return;
3004}
3005
3006static void
3007NdisUnmapFile(filehandle)
3008	ndis_handle		filehandle;
3009{
3010	ndis_fh			*fh;
3011	fh = (ndis_fh *)filehandle;
3012
3013	if (fh->nf_map == NULL)
3014		return;
3015
3016	if (fh->nf_type == NDIS_FH_TYPE_VFS)
3017		ExFreePool(fh->nf_map);
3018	fh->nf_map = NULL;
3019
3020	return;
3021}
3022
3023static void
3024NdisCloseFile(filehandle)
3025	ndis_handle		filehandle;
3026{
3027	struct thread		*td = curthread;
3028	ndis_fh			*fh;
3029
3030	if (filehandle == NULL)
3031		return;
3032
3033	fh = (ndis_fh *)filehandle;
3034	if (fh->nf_map != NULL) {
3035		if (fh->nf_type == NDIS_FH_TYPE_VFS)
3036			ExFreePool(fh->nf_map);
3037		fh->nf_map = NULL;
3038	}
3039
3040	if (fh->nf_vp == NULL)
3041		return;
3042
3043	if (fh->nf_type == NDIS_FH_TYPE_VFS) {
3044		mtx_lock(&Giant);
3045		vn_close(fh->nf_vp, FREAD, td->td_ucred, td);
3046		mtx_unlock(&Giant);
3047	}
3048
3049	fh->nf_vp = NULL;
3050	free(fh->nf_name, M_DEVBUF);
3051	ExFreePool(fh);
3052
3053	return;
3054}
3055
3056static uint8_t
3057NdisSystemProcessorCount()
3058{
3059	return(mp_ncpus);
3060}
3061
3062typedef void (*ndis_statusdone_handler)(ndis_handle);
3063typedef void (*ndis_status_handler)(ndis_handle, ndis_status,
3064        void *, uint32_t);
3065
3066static void
3067NdisMIndicateStatusComplete(adapter)
3068	ndis_handle		adapter;
3069{
3070	ndis_miniport_block	*block;
3071	ndis_statusdone_handler	statusdonefunc;
3072
3073	block = (ndis_miniport_block *)adapter;
3074	statusdonefunc = block->nmb_statusdone_func;
3075
3076	MSCALL1(statusdonefunc, adapter);
3077	return;
3078}
3079
3080static void
3081NdisMIndicateStatus(adapter, status, sbuf, slen)
3082	ndis_handle		adapter;
3083	ndis_status		status;
3084	void			*sbuf;
3085	uint32_t		slen;
3086{
3087	ndis_miniport_block	*block;
3088	ndis_status_handler	statusfunc;
3089
3090	block = (ndis_miniport_block *)adapter;
3091	statusfunc = block->nmb_status_func;
3092
3093	MSCALL4(statusfunc, adapter, status, sbuf, slen);
3094	return;
3095}
3096
3097/*
3098 * The DDK documentation says that you should use IoQueueWorkItem()
3099 * instead of ExQueueWorkItem(). The problem is, IoQueueWorkItem()
3100 * is fundamentally incompatible with NdisScheduleWorkItem(), which
3101 * depends on the API semantics of ExQueueWorkItem(). In our world,
3102 * ExQueueWorkItem() is implemented on top of IoAllocateQueueItem()
3103 * anyway.
3104 */
3105
3106ndis_status
3107NdisScheduleWorkItem(work)
3108	ndis_work_item		*work;
3109{
3110	ExQueueWorkItem(work, WORKQUEUE_DELAYED);
3111	return(NDIS_STATUS_SUCCESS);
3112}
3113
3114static void
3115NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen)
3116	ndis_packet		*dpkt;
3117	uint32_t		doff;
3118	uint32_t		reqlen;
3119	ndis_packet		*spkt;
3120	uint32_t		soff;
3121	uint32_t		*cpylen;
3122{
3123	ndis_buffer		*src, *dst;
3124	char			*sptr, *dptr;
3125	int			resid, copied, len, scnt, dcnt;
3126
3127	*cpylen = 0;
3128
3129	src = spkt->np_private.npp_head;
3130	dst = dpkt->np_private.npp_head;
3131
3132	sptr = MmGetMdlVirtualAddress(src);
3133	dptr = MmGetMdlVirtualAddress(dst);
3134	scnt = MmGetMdlByteCount(src);
3135	dcnt = MmGetMdlByteCount(dst);
3136
3137	while (soff) {
3138		if (MmGetMdlByteCount(src) > soff) {
3139			sptr += soff;
3140			scnt = MmGetMdlByteCount(src)- soff;
3141			break;
3142		}
3143		soff -= MmGetMdlByteCount(src);
3144		src = src->mdl_next;
3145		if (src == NULL)
3146			return;
3147		sptr = MmGetMdlVirtualAddress(src);
3148	}
3149
3150	while (doff) {
3151		if (MmGetMdlByteCount(dst) > doff) {
3152			dptr += doff;
3153			dcnt = MmGetMdlByteCount(dst) - doff;
3154			break;
3155		}
3156		doff -= MmGetMdlByteCount(dst);
3157		dst = dst->mdl_next;
3158		if (dst == NULL)
3159			return;
3160		dptr = MmGetMdlVirtualAddress(dst);
3161	}
3162
3163	resid = reqlen;
3164	copied = 0;
3165
3166	while(1) {
3167		if (resid < scnt)
3168			len = resid;
3169		else
3170			len = scnt;
3171		if (dcnt < len)
3172			len = dcnt;
3173
3174		bcopy(sptr, dptr, len);
3175
3176		copied += len;
3177		resid -= len;
3178		if (resid == 0)
3179			break;
3180
3181		dcnt -= len;
3182		if (dcnt == 0) {
3183			dst = dst->mdl_next;
3184			if (dst == NULL)
3185				break;
3186			dptr = MmGetMdlVirtualAddress(dst);
3187			dcnt = MmGetMdlByteCount(dst);
3188		}
3189
3190		scnt -= len;
3191		if (scnt == 0) {
3192			src = src->mdl_next;
3193			if (src == NULL)
3194				break;
3195			sptr = MmGetMdlVirtualAddress(src);
3196			scnt = MmGetMdlByteCount(src);
3197		}
3198	}
3199
3200	*cpylen = copied;
3201	return;
3202}
3203
3204static void
3205NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
3206	ndis_packet		*dpkt;
3207	uint32_t		doff;
3208	uint32_t		reqlen;
3209	ndis_packet		*spkt;
3210	uint32_t		soff;
3211	uint32_t		*cpylen;
3212	uint32_t		prio;
3213{
3214	NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen);
3215	return;
3216}
3217
3218static ndis_status
3219NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle)
3220	ndis_handle		handle;
3221	ndis_unicode_string	*devname;
3222	ndis_unicode_string	*symname;
3223	driver_dispatch		*majorfuncs[];
3224	void			**devobj;
3225	ndis_handle		*devhandle;
3226{
3227	ndis_miniport_block	*block;
3228
3229	block = (ndis_miniport_block *)handle;
3230	*devobj = block->nmb_deviceobj;
3231	*devhandle = handle;
3232
3233	return(NDIS_STATUS_SUCCESS);
3234}
3235
3236static ndis_status
3237NdisMDeregisterDevice(handle)
3238	ndis_handle		handle;
3239{
3240	return(NDIS_STATUS_SUCCESS);
3241}
3242
3243static ndis_status
3244NdisMQueryAdapterInstanceName(name, handle)
3245	ndis_unicode_string	*name;
3246	ndis_handle		handle;
3247{
3248	ndis_miniport_block	*block;
3249	device_t		dev;
3250
3251	block = (ndis_miniport_block *)handle;
3252	dev = block->nmb_physdeviceobj->do_devext;
3253
3254	ndis_ascii_to_unicode(__DECONST(char *,
3255	    device_get_nameunit(dev)), &name->us_buf);
3256	name->us_len = strlen(device_get_nameunit(dev)) * 2;
3257
3258	return(NDIS_STATUS_SUCCESS);
3259}
3260
3261static void
3262NdisMRegisterUnloadHandler(handle, func)
3263	ndis_handle		handle;
3264	void			*func;
3265{
3266	return;
3267}
3268
3269static void
3270dummy()
3271{
3272	printf ("NDIS dummy called...\n");
3273	return;
3274}
3275
3276/*
3277 * Note: a couple of entries in this table specify the
3278 * number of arguments as "foo + 1". These are routines
3279 * that accept a 64-bit argument, passed by value. On
3280 * x86, these arguments consume two longwords on the stack,
3281 * so we lie and say there's one additional argument so
3282 * that the wrapping routines will do the right thing.
3283 */
3284
3285image_patch_table ndis_functbl[] = {
3286	IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6),
3287	IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7),
3288	IMPORT_SFUNC(NdisScheduleWorkItem, 1),
3289	IMPORT_SFUNC(NdisMIndicateStatusComplete, 1),
3290	IMPORT_SFUNC(NdisMIndicateStatus, 4),
3291	IMPORT_SFUNC(NdisSystemProcessorCount, 0),
3292	IMPORT_SFUNC(NdisUnchainBufferAtBack, 2),
3293	IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5),
3294	IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6),
3295	IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2),
3296	IMPORT_SFUNC(NdisMGetDeviceProperty, 6),
3297	IMPORT_SFUNC(NdisInitAnsiString, 2),
3298	IMPORT_SFUNC(NdisInitUnicodeString, 2),
3299	IMPORT_SFUNC(NdisWriteConfiguration, 4),
3300	IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2),
3301	IMPORT_SFUNC(NdisTerminateWrapper, 2),
3302	IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4),
3303	IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5),
3304	IMPORT_SFUNC(NdisMRemoveMiniport, 1),
3305	IMPORT_SFUNC(NdisInitializeString, 2),
3306	IMPORT_SFUNC(NdisFreeString, 1),
3307	IMPORT_SFUNC(NdisGetCurrentSystemTime, 1),
3308	IMPORT_SFUNC(NdisGetSystemUpTime, 1),
3309	IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3),
3310	IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4),
3311	IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3),
3312	IMPORT_SFUNC(NdisInterlockedInsertTailList, 3),
3313	IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2),
3314	IMPORT_SFUNC(NdisInitializeWrapper, 4),
3315	IMPORT_SFUNC(NdisMRegisterMiniport, 3),
3316	IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3),
3317	IMPORT_SFUNC(NdisAllocateMemory, 4 + 1),
3318	IMPORT_SFUNC(NdisMSetAttributesEx, 5),
3319	IMPORT_SFUNC(NdisCloseConfiguration, 1),
3320	IMPORT_SFUNC(NdisReadConfiguration, 5),
3321	IMPORT_SFUNC(NdisOpenConfiguration, 3),
3322	IMPORT_SFUNC(NdisAcquireSpinLock, 1),
3323	IMPORT_SFUNC(NdisReleaseSpinLock, 1),
3324	IMPORT_SFUNC(NdisDprAcquireSpinLock, 1),
3325	IMPORT_SFUNC(NdisDprReleaseSpinLock, 1),
3326	IMPORT_SFUNC(NdisAllocateSpinLock, 1),
3327	IMPORT_SFUNC(NdisInitializeReadWriteLock, 1),
3328	IMPORT_SFUNC(NdisAcquireReadWriteLock, 3),
3329	IMPORT_SFUNC(NdisReleaseReadWriteLock, 2),
3330	IMPORT_SFUNC(NdisFreeSpinLock, 1),
3331	IMPORT_SFUNC(NdisFreeMemory, 3),
3332	IMPORT_SFUNC(NdisReadPciSlotInformation, 5),
3333	IMPORT_SFUNC(NdisWritePciSlotInformation, 5),
3334	IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation,
3335	    NdisReadPciSlotInformation, 5),
3336	IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation,
3337	    NdisWritePciSlotInformation, 5),
3338	IMPORT_CFUNC(NdisWriteErrorLogEntry, 0),
3339	IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6),
3340	IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3),
3341	IMPORT_SFUNC(NdisMInitializeTimer, 4),
3342	IMPORT_SFUNC(NdisInitializeTimer, 3),
3343	IMPORT_SFUNC(NdisSetTimer, 2),
3344	IMPORT_SFUNC(NdisMCancelTimer, 2),
3345	IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2),
3346	IMPORT_SFUNC(NdisMSetPeriodicTimer, 2),
3347	IMPORT_SFUNC(NdisMQueryAdapterResources, 4),
3348	IMPORT_SFUNC(NdisMRegisterIoPortRange, 4),
3349	IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4),
3350	IMPORT_SFUNC(NdisReadNetworkAddress, 4),
3351	IMPORT_SFUNC(NdisQueryMapRegisterCount, 2),
3352	IMPORT_SFUNC(NdisMAllocateMapRegisters, 5),
3353	IMPORT_SFUNC(NdisMFreeMapRegisters, 1),
3354	IMPORT_SFUNC(NdisMAllocateSharedMemory, 5),
3355	IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1),
3356	IMPORT_SFUNC(NdisMUnmapIoSpace, 3),
3357	IMPORT_SFUNC(NdisGetCacheFillSize, 0),
3358	IMPORT_SFUNC(NdisMGetDmaAlignment, 1),
3359	IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3),
3360	IMPORT_SFUNC(NdisAllocatePacketPool, 4),
3361	IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5),
3362	IMPORT_SFUNC(NdisAllocatePacket, 3),
3363	IMPORT_SFUNC(NdisFreePacket, 1),
3364	IMPORT_SFUNC(NdisFreePacketPool, 1),
3365	IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3),
3366	IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1),
3367	IMPORT_SFUNC(NdisAllocateBufferPool, 3),
3368	IMPORT_SFUNC(NdisAllocateBuffer, 5),
3369	IMPORT_SFUNC(NdisQueryBuffer, 3),
3370	IMPORT_SFUNC(NdisQueryBufferSafe, 4),
3371	IMPORT_SFUNC(NdisBufferVirtualAddress, 1),
3372	IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2),
3373	IMPORT_SFUNC(NdisBufferLength, 1),
3374	IMPORT_SFUNC(NdisFreeBuffer, 1),
3375	IMPORT_SFUNC(NdisFreeBufferPool, 1),
3376	IMPORT_SFUNC(NdisInterlockedIncrement, 1),
3377	IMPORT_SFUNC(NdisInterlockedDecrement, 1),
3378	IMPORT_SFUNC(NdisInitializeEvent, 1),
3379	IMPORT_SFUNC(NdisSetEvent, 1),
3380	IMPORT_SFUNC(NdisResetEvent, 1),
3381	IMPORT_SFUNC(NdisWaitEvent, 2),
3382	IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2),
3383	IMPORT_SFUNC(NdisMPciAssignResources, 3),
3384	IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1),
3385	IMPORT_SFUNC(NdisMRegisterInterrupt, 7),
3386	IMPORT_SFUNC(NdisMDeregisterInterrupt, 1),
3387	IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3),
3388	IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1),
3389	IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1),
3390	IMPORT_SFUNC(NdisQueryBufferOffset, 3),
3391	IMPORT_SFUNC(NdisAdjustBufferLength, 2),
3392	IMPORT_SFUNC(NdisPacketPoolUsage, 1),
3393	IMPORT_SFUNC(NdisMSleep, 1),
3394	IMPORT_SFUNC(NdisUnchainBufferAtFront, 2),
3395	IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4),
3396	IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4),
3397	IMPORT_SFUNC(NdisOpenFile, 5 + 1),
3398	IMPORT_SFUNC(NdisMapFile, 3),
3399	IMPORT_SFUNC(NdisUnmapFile, 1),
3400	IMPORT_SFUNC(NdisCloseFile, 1),
3401	IMPORT_SFUNC(NdisMRegisterDevice, 6),
3402	IMPORT_SFUNC(NdisMDeregisterDevice, 1),
3403	IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2),
3404	IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2),
3405	IMPORT_SFUNC(ndis_timercall, 4),
3406	IMPORT_SFUNC(ndis_asyncmem_complete, 2),
3407
3408	/*
3409	 * This last entry is a catch-all for any function we haven't
3410	 * implemented yet. The PE import list patching routine will
3411	 * use it for any function that doesn't have an explicit match
3412	 * in this table.
3413	 */
3414
3415	{ NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
3416
3417	/* End of list. */
3418
3419	{ NULL, NULL, NULL }
3420};
3421