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