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