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