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