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