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