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