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