subr_ndis.c revision 124165
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 124165 2004-01-06 07:09:26Z 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;
799	char			*str = NULL;
800
801	block = (ndis_miniport_block *)adapter;
802
803	pe_get_message(block->nmb_img, code, &str, &i);
804	device_printf (block->nmb_dev, "NDIS ERROR: %x (%s)\n", code,
805	    str == NULL ? "unknown error" : str);
806	device_printf (block->nmb_dev, "NDIS NUMERRORS: %x\n", numerrors);
807
808	va_start(ap, numerrors);
809	for (i = 0; i < numerrors; i++)
810		device_printf (block->nmb_dev, "argptr: %p\n",
811		    va_arg(ap, void *));
812	va_end(ap);
813
814	return;
815}
816
817static void
818ndis_map_cb(arg, segs, nseg, error)
819	void			*arg;
820	bus_dma_segment_t	*segs;
821	int			nseg;
822	int			error;
823{
824	struct ndis_map_arg	*ctx;
825	int			i;
826
827	if (error)
828		return;
829
830	ctx = arg;
831
832	for (i = 0; i < nseg; i++) {
833		ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr;
834		ctx->nma_fraglist[i].npu_len = segs[i].ds_len;
835	}
836
837	ctx->nma_cnt = nseg;
838
839	return;
840}
841
842__stdcall static void
843ndis_vtophys_load(adapter, buf, mapreg, writedev, addrarray, arraysize)
844	ndis_handle		adapter;
845	ndis_buffer		*buf;
846	uint32_t		mapreg;
847	uint8_t			writedev;
848	ndis_paddr_unit		*addrarray;
849	uint32_t		*arraysize;
850{
851	ndis_miniport_block	*block;
852	struct ndis_softc	*sc;
853	struct ndis_map_arg	nma;
854	bus_dmamap_t		map;
855	int			error;
856
857	if (adapter == NULL)
858		return;
859
860	block = (ndis_miniport_block *)adapter;
861	sc = (struct ndis_softc *)(block->nmb_ifp);
862
863	if (mapreg > sc->ndis_mmapcnt)
864		return;
865
866	map = sc->ndis_mmaps[mapreg];
867	nma.nma_fraglist = addrarray;
868
869	error = bus_dmamap_load(sc->ndis_mtag, map,
870	    MDL_VA(buf), buf->nb_bytecount, ndis_map_cb,
871	    (void *)&nma, BUS_DMA_NOWAIT);
872
873	if (error)
874		return;
875
876	bus_dmamap_sync(sc->ndis_mtag, map,
877	    writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
878
879	*arraysize = nma.nma_cnt;
880
881	return;
882}
883
884__stdcall static void
885ndis_vtophys_unload(adapter, buf, mapreg)
886	ndis_handle		adapter;
887	ndis_buffer		*buf;
888	uint32_t		mapreg;
889{
890	ndis_miniport_block	*block;
891	struct ndis_softc	*sc;
892	bus_dmamap_t		map;
893
894	if (adapter == NULL)
895		return;
896
897	block = (ndis_miniport_block *)adapter;
898	sc = (struct ndis_softc *)(block->nmb_ifp);
899
900	if (mapreg > sc->ndis_mmapcnt)
901		return;
902
903	map = sc->ndis_mmaps[mapreg];
904
905	bus_dmamap_sync(sc->ndis_mtag, map,
906	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
907
908	bus_dmamap_unload(sc->ndis_mtag, map);
909
910	return;
911}
912
913__stdcall static void
914ndis_create_timer(timer, handle, func, ctx)
915	ndis_miniport_timer	*timer;
916	ndis_handle		*handle;
917	ndis_timer_function	func;
918	void			*ctx;
919{
920	struct ndis_timer_entry	*ne = NULL;
921	ndis_miniport_block	*block;
922	block = (ndis_miniport_block *)handle;
923
924	ne = malloc(sizeof(struct ndis_timer_entry), M_DEVBUF, M_NOWAIT);
925	callout_init(&ne->nte_ch, CALLOUT_MPSAFE);
926	TAILQ_INSERT_TAIL(&block->nmb_timerlist, ne, link);
927	ne->nte_timer = timer;
928
929	timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
930	timer->nmt_dpc.nk_deferredctx = &ne->nte_ch;
931	timer->nmt_timerfunc = func;
932	timer->nmt_timerctx = ctx;
933
934	return;
935}
936
937/*
938 * The driver's timer callout is __stdcall function, so we need this
939 * intermediate step.
940 */
941
942static void
943ndis_timercall(arg)
944	void		*arg;
945{
946	ndis_miniport_timer	*timer;
947	__stdcall ndis_timer_function	timerfunc;
948
949	timer = arg;
950
951	timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
952	timerfunc = timer->nmt_timerfunc;
953	timerfunc(NULL, timer->nmt_timerctx, NULL, NULL);
954
955	return;
956}
957
958/*
959 * Windows specifies timeouts in milliseconds. We specify timeouts
960 * in hz. Trying to compute a tenth of a second based on hz is tricky.
961 * so we approximate. Note that we abuse the dpc portion of the
962 * miniport timer structure to hold the UNIX callout handle.
963 */
964__stdcall static void
965ndis_set_timer(timer, msecs)
966	ndis_miniport_timer	*timer;
967	uint32_t		msecs;
968{
969	struct callout		*ch;
970	struct timeval		tv;
971
972	tv.tv_sec = 0;
973	tv.tv_usec = msecs * 1000;
974
975	ch = timer->nmt_dpc.nk_deferredctx;
976	timer->nmt_dpc.nk_sysarg2 = ndis_timercall;
977	timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
978	callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
979
980	return;
981}
982
983static void
984ndis_tick(arg)
985	void			*arg;
986{
987	ndis_miniport_timer	*timer;
988	struct callout		*ch;
989	__stdcall ndis_timer_function	timerfunc;
990	struct timeval		tv;
991
992	timer = arg;
993
994	timer->nmt_ktimer.nk_header.dh_sigstate = FALSE;
995	timerfunc = timer->nmt_timerfunc;
996	timerfunc(NULL, timer->nmt_timerctx, NULL, NULL);
997
998	/* Automatically reload timer. */
999
1000	tv.tv_sec = 0;
1001	tv.tv_usec = timer->nmt_ktimer.nk_period * 1000;
1002	ch = timer->nmt_dpc.nk_deferredctx;
1003	timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
1004	timer->nmt_dpc.nk_sysarg2 = ndis_tick;
1005	callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
1006
1007	return;
1008}
1009
1010__stdcall static void
1011ndis_set_periodic_timer(timer, msecs)
1012	ndis_miniport_timer	*timer;
1013	uint32_t		msecs;
1014{
1015	struct callout		*ch;
1016	struct timeval		tv;
1017
1018	tv.tv_sec = 0;
1019	tv.tv_usec = msecs * 1000;
1020
1021	timer->nmt_ktimer.nk_period = msecs;
1022	ch = timer->nmt_dpc.nk_deferredctx;
1023	timer->nmt_dpc.nk_sysarg2 = ndis_tick;
1024	timer->nmt_ktimer.nk_header.dh_sigstate = TRUE;
1025	callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer);
1026
1027	return;
1028}
1029
1030__stdcall static void
1031ndis_cancel_timer(timer, cancelled)
1032	ndis_miniport_timer	*timer;
1033	uint8_t			*cancelled;
1034{
1035	struct callout		*ch;
1036
1037	if (timer == NULL)
1038		return;
1039	ch = timer->nmt_dpc.nk_deferredctx;
1040	if (ch == NULL)
1041		return;
1042	callout_stop(ch);
1043	*cancelled = timer->nmt_ktimer.nk_header.dh_sigstate;
1044
1045	return;
1046}
1047
1048__stdcall static void
1049ndis_query_resources(status, adapter, list, buflen)
1050	ndis_status		*status;
1051	ndis_handle		adapter;
1052	ndis_resource_list	*list;
1053	uint32_t		*buflen;
1054{
1055	ndis_miniport_block	*block;
1056	struct ndis_softc	*sc;
1057	int			rsclen;
1058
1059	block = (ndis_miniport_block *)adapter;
1060	sc = (struct ndis_softc *)block->nmb_ifp;
1061
1062	rsclen = sizeof(ndis_resource_list) +
1063	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1));
1064	if (*buflen < rsclen) {
1065		*buflen = rsclen;
1066		*status = NDIS_STATUS_INVALID_LENGTH;
1067		return;
1068	}
1069
1070	bcopy((char *)block->nmb_rlist, (char *)list, *buflen);
1071	*status = NDIS_STATUS_SUCCESS;
1072	return;
1073}
1074
1075__stdcall static ndis_status
1076ndis_register_ioport(offset, adapter, port, numports)
1077	void			**offset;
1078	ndis_handle		adapter;
1079	uint32_t		port;
1080	uint32_t		numports;
1081{
1082	struct ndis_miniport_block	*block;
1083	struct ndis_softc	*sc;
1084
1085	if (adapter == NULL)
1086		return(NDIS_STATUS_FAILURE);
1087
1088	block = (ndis_miniport_block *)adapter;
1089	sc = (struct ndis_softc *)(block->nmb_ifp);
1090
1091	if (sc->ndis_res_io == NULL)
1092		return(NDIS_STATUS_FAILURE);
1093
1094	if (rman_get_size(sc->ndis_res_io) != numports)
1095		return(NDIS_STATUS_INVALID_LENGTH);
1096
1097	*offset = (void *)rman_get_start(sc->ndis_res_io);
1098
1099	return(NDIS_STATUS_SUCCESS);
1100}
1101
1102__stdcall static void
1103ndis_deregister_ioport(adapter, port, numports, offset)
1104	ndis_handle		adapter;
1105	uint32_t		port;
1106	uint32_t		numports;
1107	void			*offset;
1108{
1109	return;
1110}
1111
1112__stdcall static void
1113ndis_read_netaddr(status, addr, addrlen, adapter)
1114	ndis_status		*status;
1115	void			**addr;
1116	uint32_t		*addrlen;
1117	ndis_handle		adapter;
1118{
1119	struct ndis_softc	*sc;
1120	ndis_miniport_block	*block;
1121	uint8_t			empty[] = { 0, 0, 0, 0, 0, 0 };
1122
1123	block = (ndis_miniport_block *)adapter;
1124	sc = (struct ndis_softc *)block->nmb_ifp;
1125
1126	if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0)
1127		*status = NDIS_STATUS_FAILURE;
1128	else {
1129		*addr = sc->arpcom.ac_enaddr;
1130		*addrlen = ETHER_ADDR_LEN;
1131		*status = NDIS_STATUS_SUCCESS;
1132	}
1133
1134	return;
1135}
1136
1137__stdcall static ndis_status
1138ndis_mapreg_cnt(bustype, cnt)
1139	uint32_t		bustype;
1140	uint32_t		*cnt;
1141{
1142	*cnt = 8192;
1143	return(NDIS_STATUS_SUCCESS);
1144}
1145
1146__stdcall static ndis_status
1147ndis_alloc_mapreg(adapter, dmachannel, dmasize, physmapneeded, maxmap)
1148	ndis_handle		adapter;
1149	uint32_t		dmachannel;
1150	uint8_t			dmasize;
1151	uint32_t		physmapneeded;
1152	uint32_t		maxmap;
1153{
1154	struct ndis_softc	*sc;
1155	ndis_miniport_block	*block;
1156	int			error, i, nseg = NDIS_MAXSEG;
1157
1158	block = (ndis_miniport_block *)adapter;
1159	sc = (struct ndis_softc *)block->nmb_ifp;
1160
1161	sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded,
1162	    M_DEVBUF, M_NOWAIT|M_ZERO);
1163
1164	if (sc->ndis_mmaps == NULL)
1165		return(NDIS_STATUS_RESOURCES);
1166
1167	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1168	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1169	    NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW,
1170	    NULL, NULL, &sc->ndis_mtag);
1171
1172	if (error) {
1173		free(sc->ndis_mmaps, M_DEVBUF);
1174		return(NDIS_STATUS_RESOURCES);
1175	}
1176
1177	for (i = 0; i < physmapneeded; i++)
1178		bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]);
1179
1180	sc->ndis_mmapcnt = physmapneeded;
1181
1182	return(NDIS_STATUS_SUCCESS);
1183}
1184
1185__stdcall static void
1186ndis_free_mapreg(adapter)
1187	ndis_handle		adapter;
1188{
1189	struct ndis_softc	*sc;
1190	ndis_miniport_block	*block;
1191	int			i;
1192
1193	block = (ndis_miniport_block *)adapter;
1194	sc = (struct ndis_softc *)block->nmb_ifp;
1195
1196	for (i = 0; i < sc->ndis_mmapcnt; i++)
1197		bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]);
1198
1199	free(sc->ndis_mmaps, M_DEVBUF);
1200
1201	bus_dma_tag_destroy(sc->ndis_mtag);
1202
1203	return;
1204}
1205
1206static void
1207ndis_mapshared_cb(arg, segs, nseg, error)
1208	void			*arg;
1209	bus_dma_segment_t	*segs;
1210	int			nseg;
1211	int			error;
1212{
1213	ndis_physaddr		*p;
1214
1215	if (error || nseg > 1)
1216		return;
1217
1218	p = arg;
1219
1220	p->np_quad = segs[0].ds_addr;
1221
1222	return;
1223}
1224
1225/*
1226 * This maps to bus_dmamem_alloc().
1227 */
1228__stdcall static void
1229ndis_alloc_sharedmem(adapter, len, cached, vaddr, paddr)
1230	ndis_handle		adapter;
1231	uint32_t		len;
1232	uint8_t			cached;
1233	void			**vaddr;
1234	ndis_physaddr		*paddr;
1235{
1236	ndis_miniport_block	*block;
1237	struct ndis_softc	*sc;
1238	struct ndis_shmem	*sh;
1239	int			error;
1240
1241	if (adapter == NULL)
1242		return;
1243
1244	block = (ndis_miniport_block *)adapter;
1245	sc = (struct ndis_softc *)(block->nmb_ifp);
1246
1247	sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO);
1248	if (sh == NULL)
1249		return;
1250
1251	error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
1252	    0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1253	    NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL,
1254	    &sh->ndis_stag);
1255
1256	if (error) {
1257		free(sh, M_DEVBUF);
1258		return;
1259	}
1260
1261	error = bus_dmamem_alloc(sh->ndis_stag, vaddr,
1262	    BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap);
1263
1264	if (error) {
1265		bus_dma_tag_destroy(sh->ndis_stag);
1266		free(sh, M_DEVBUF);
1267		return;
1268	}
1269
1270	error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr,
1271	    len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT);
1272
1273	if (error) {
1274		bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap);
1275		bus_dma_tag_destroy(sh->ndis_stag);
1276		free(sh, M_DEVBUF);
1277		return;
1278	}
1279
1280	sh->ndis_saddr = *vaddr;
1281	sh->ndis_next = sc->ndis_shlist;
1282	sc->ndis_shlist = sh;
1283
1284	return;
1285}
1286
1287__stdcall static void
1288ndis_alloc_sharedmem_async(adapter, len, cached, ctx)
1289	ndis_handle		adapter;
1290	uint32_t		len;
1291	uint8_t			cached;
1292	void			*ctx;
1293{
1294	ndis_miniport_block	*block;
1295	struct ndis_softc	*sc;
1296	void			*vaddr;
1297	ndis_physaddr		paddr;
1298	__stdcall ndis_allocdone_handler	donefunc;
1299
1300	if (adapter == NULL)
1301		return;
1302
1303	block = (ndis_miniport_block *)adapter;
1304	sc = (struct ndis_softc *)(block->nmb_ifp);
1305	donefunc = sc->ndis_chars.nmc_allocate_complete_func;
1306
1307	ndis_alloc_sharedmem(adapter, len, cached, &vaddr, &paddr);
1308	donefunc(adapter, vaddr, &paddr, len, ctx);
1309
1310	return;
1311}
1312
1313__stdcall static void
1314ndis_free_sharedmem(adapter, len, cached, vaddr, paddr)
1315	ndis_handle		adapter;
1316	uint32_t		len;
1317	uint8_t			cached;
1318	void			*vaddr;
1319	ndis_physaddr		paddr;
1320{
1321	ndis_miniport_block	*block;
1322	struct ndis_softc	*sc;
1323	struct ndis_shmem	*sh, *prev;
1324
1325	if (vaddr == NULL || adapter == NULL)
1326		return;
1327
1328	block = (ndis_miniport_block *)adapter;
1329	sc = (struct ndis_softc *)(block->nmb_ifp);
1330	sh = prev = sc->ndis_shlist;
1331
1332	while (sh) {
1333		if (sh->ndis_saddr == vaddr)
1334			break;
1335		prev = sh;
1336		sh = sh->ndis_next;
1337	}
1338
1339	bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1340	bus_dmamem_free(sh->ndis_stag, vaddr, sh->ndis_smap);
1341	bus_dma_tag_destroy(sh->ndis_stag);
1342
1343	if (sh == sc->ndis_shlist)
1344		sc->ndis_shlist = sh->ndis_next;
1345	else
1346		prev->ndis_next = sh->ndis_next;
1347
1348	free(sh, M_DEVBUF);
1349
1350	return;
1351}
1352
1353__stdcall static ndis_status
1354ndis_map_iospace(vaddr, adapter, paddr, len)
1355	void			**vaddr;
1356	ndis_handle		adapter;
1357	ndis_physaddr		paddr;
1358	uint32_t		len;
1359{
1360	ndis_miniport_block	*block;
1361	struct ndis_softc	*sc;
1362
1363	if (adapter == NULL)
1364		return(NDIS_STATUS_FAILURE);
1365
1366	block = (ndis_miniport_block *)adapter;
1367	sc = (struct ndis_softc *)(block->nmb_ifp);
1368
1369	if (sc->ndis_res_mem == NULL)
1370		return(NDIS_STATUS_FAILURE);
1371
1372	*vaddr = (void *)rman_get_virtual(sc->ndis_res_mem);
1373
1374	return(NDIS_STATUS_SUCCESS);
1375}
1376
1377__stdcall static void
1378ndis_unmap_iospace(adapter, vaddr, len)
1379	ndis_handle		adapter;
1380	void			*vaddr;
1381	uint32_t		len;
1382{
1383	return;
1384}
1385
1386__stdcall static uint32_t
1387ndis_cachefill(void)
1388{
1389	return(128);
1390}
1391
1392__stdcall static uint32_t
1393ndis_dma_align(handle)
1394	ndis_handle		handle;
1395{
1396	return(128);
1397}
1398
1399/*
1400 * NDIS has two methods for dealing with NICs that support DMA.
1401 * One is to just pass packets to the driver and let it call
1402 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
1403 * all by itself, and the other is to let the NDIS library handle the
1404 * buffer mapping internally, and hand the driver an already populated
1405 * scatter/gather fragment list. If the driver calls
1406 * NdisMInitializeScatterGatherDma(), it wants to use the latter
1407 * method.
1408 */
1409
1410__stdcall static ndis_status
1411ndis_init_sc_dma(adapter, is64, maxphysmap)
1412	ndis_handle		adapter;
1413	uint8_t			is64;
1414	uint32_t		maxphysmap;
1415{
1416	struct ndis_softc	*sc;
1417	ndis_miniport_block	*block;
1418	int			error;
1419
1420	if (adapter == NULL)
1421		return(NDIS_STATUS_FAILURE);
1422	block = (ndis_miniport_block *)adapter;
1423	sc = (struct ndis_softc *)block->nmb_ifp;
1424
1425	/* Don't do this twice. */
1426	if (sc->ndis_sc == 1)
1427		return(NDIS_STATUS_SUCCESS);
1428
1429	error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1430	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1431	    MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
1432	    NULL, NULL, &sc->ndis_ttag);
1433
1434	sc->ndis_sc = 1;
1435
1436	return(NDIS_STATUS_SUCCESS);
1437}
1438
1439__stdcall static void
1440ndis_alloc_packetpool(status, pool, descnum, protrsvdlen)
1441	ndis_status		*status;
1442	ndis_handle		*pool;
1443	uint32_t		descnum;
1444	uint32_t		protrsvdlen;
1445{
1446	ndis_packet		*cur;
1447	int			i;
1448
1449	*pool = malloc(sizeof(ndis_packet) *
1450	    ((descnum + NDIS_POOL_EXTRA) + 1),
1451	    M_DEVBUF, M_NOWAIT|M_ZERO);
1452
1453	if (pool == NULL) {
1454		*status = NDIS_STATUS_RESOURCES;
1455		return;
1456	}
1457
1458	cur = (ndis_packet *)*pool;
1459	cur->np_private.npp_flags = 0x1; /* mark the head of the list */
1460	for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
1461		cur->np_private.npp_head = (ndis_handle)(cur + 1);
1462		cur++;
1463	}
1464
1465	*status = NDIS_STATUS_SUCCESS;
1466	return;
1467}
1468
1469__stdcall static void
1470ndis_ex_alloc_packetpool(status, pool, descnum, oflowdescnum, protrsvdlen)
1471	ndis_status		*status;
1472	ndis_handle		*pool;
1473	uint32_t		descnum;
1474	uint32_t		oflowdescnum;
1475	uint32_t		protrsvdlen;
1476{
1477	return(ndis_alloc_packetpool(status, pool,
1478	    descnum + oflowdescnum, protrsvdlen));
1479}
1480
1481__stdcall static uint32_t
1482ndis_packetpool_use(pool)
1483	ndis_handle		pool;
1484{
1485	ndis_packet		*head;
1486
1487	head = (ndis_packet *)pool;
1488
1489	return(head->np_private.npp_count);
1490}
1491
1492__stdcall static void
1493ndis_free_packetpool(pool)
1494	ndis_handle		pool;
1495{
1496	free(pool, M_DEVBUF);
1497	return;
1498}
1499
1500__stdcall static void
1501ndis_alloc_packet(status, packet, pool)
1502	ndis_status		*status;
1503	ndis_packet		**packet;
1504	ndis_handle		pool;
1505{
1506	ndis_packet		*head, *pkt;
1507
1508	head = (ndis_packet *)pool;
1509
1510	if (head->np_private.npp_flags != 0x1) {
1511		*status = NDIS_STATUS_FAILURE;
1512		return;
1513	}
1514
1515	pkt = (ndis_packet *)head->np_private.npp_head;
1516
1517	if (pkt == NULL) {
1518		*status = NDIS_STATUS_RESOURCES;
1519		return;
1520	}
1521
1522	head->np_private.npp_head = pkt->np_private.npp_head;
1523
1524	pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL;
1525	/* Save pointer to the pool. */
1526	pkt->np_private.npp_pool = head;
1527
1528	/* Set the oob offset pointer. Lots of things expect this. */
1529	pkt->np_private.npp_packetooboffset =
1530	    offsetof(ndis_packet, np_oob);
1531
1532	*packet = pkt;
1533
1534	head->np_private.npp_count++;
1535	*status = NDIS_STATUS_SUCCESS;
1536	return;
1537}
1538
1539__stdcall static void
1540ndis_release_packet(packet)
1541	ndis_packet		*packet;
1542{
1543	ndis_packet		*head;
1544
1545	if (packet == NULL || packet->np_private.npp_pool == NULL)
1546		return;
1547
1548	head = packet->np_private.npp_pool;
1549	if (head->np_private.npp_flags != 0x1)
1550		return;
1551
1552	packet->np_private.npp_head = head->np_private.npp_head;
1553	head->np_private.npp_head = (ndis_buffer *)packet;
1554	head->np_private.npp_count--;
1555
1556	return;
1557}
1558
1559__stdcall static void
1560ndis_unchain_headbuf(packet, buf)
1561	ndis_packet		*packet;
1562	ndis_buffer		**buf;
1563{
1564	ndis_packet_private	*priv;
1565
1566	if (packet == NULL || buf == NULL)
1567		return;
1568
1569	priv = &packet->np_private;
1570
1571	priv->npp_validcounts = FALSE;
1572
1573	if (priv->npp_head == priv->npp_tail) {
1574		*buf = priv->npp_head;
1575		priv->npp_head = priv->npp_tail = NULL;
1576	} else {
1577		*buf = priv->npp_head;
1578		priv->npp_head = (*buf)->nb_next;
1579	}
1580
1581	return;
1582}
1583
1584__stdcall static void
1585ndis_unchain_tailbuf(packet, buf)
1586	ndis_packet		*packet;
1587	ndis_buffer		**buf;
1588{
1589	ndis_packet_private	*priv;
1590	ndis_buffer		*tmp;
1591
1592	if (packet == NULL || buf == NULL)
1593		return;
1594
1595	priv = &packet->np_private;
1596
1597	priv->npp_validcounts = FALSE;
1598
1599	if (priv->npp_head == priv->npp_tail) {
1600		*buf = priv->npp_head;
1601		priv->npp_head = priv->npp_tail = NULL;
1602	} else {
1603		*buf = priv->npp_tail;
1604		tmp = priv->npp_head;
1605		while (tmp->nb_next != priv->npp_tail)
1606			tmp = tmp->nb_next;
1607		priv->npp_tail = tmp;
1608		tmp->nb_next = NULL;
1609	}
1610
1611	return;
1612}
1613
1614/*
1615 * The NDIS "buffer" manipulation functions are somewhat misnamed.
1616 * They don't really allocate buffers: they allocate buffer mappings.
1617 * The idea is you reserve a chunk of DMA-able memory using
1618 * NdisMAllocateSharedMemory() and then use NdisAllocateBuffer()
1619 * to obtain the virtual address of the DMA-able region.
1620 * ndis_alloc_bufpool() is analagous to bus_dma_tag_create().
1621 */
1622
1623__stdcall static void
1624ndis_alloc_bufpool(status, pool, descnum)
1625	ndis_status		*status;
1626	ndis_handle		*pool;
1627	uint32_t		descnum;
1628{
1629	ndis_buffer		*cur;
1630	int			i;
1631
1632	*pool = malloc(sizeof(ndis_buffer) *
1633	    ((descnum + NDIS_POOL_EXTRA) + 1),
1634	    M_DEVBUF, M_NOWAIT|M_ZERO);
1635
1636	if (pool == NULL) {
1637		*status = NDIS_STATUS_RESOURCES;
1638		return;
1639	}
1640
1641	cur = (ndis_buffer *)*pool;
1642	cur->nb_flags = 0x1; /* mark the head of the list */
1643	for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
1644		cur->nb_next = cur + 1;
1645		cur++;
1646	}
1647
1648	*status = NDIS_STATUS_SUCCESS;
1649	return;
1650}
1651
1652__stdcall static void
1653ndis_free_bufpool(pool)
1654	ndis_handle		pool;
1655{
1656	free(pool, M_DEVBUF);
1657	return;
1658}
1659
1660/*
1661 * This maps to a bus_dmamap_create() and bus_dmamap_load().
1662 */
1663__stdcall static void
1664ndis_alloc_buf(status, buffer, pool, vaddr, len)
1665	ndis_status		*status;
1666	ndis_buffer		**buffer;
1667	ndis_handle		pool;
1668	void			*vaddr;
1669	uint32_t		len;
1670{
1671	ndis_buffer		*head, *buf;
1672
1673	head = (ndis_buffer *)pool;
1674	if (head->nb_flags != 0x1) {
1675		*status = NDIS_STATUS_FAILURE;
1676		return;
1677	}
1678
1679	buf = head->nb_next;
1680
1681	if (buf == NULL) {
1682		*status = NDIS_STATUS_RESOURCES;
1683		return;
1684	}
1685
1686	head->nb_next = buf->nb_next;
1687
1688	/* Save pointer to the pool. */
1689	buf->nb_process = head;
1690
1691	MDL_INIT(buf, vaddr, len);
1692
1693	*buffer = buf;
1694
1695	*status = NDIS_STATUS_SUCCESS;
1696	return;
1697}
1698
1699__stdcall static void
1700ndis_release_buf(buf)
1701	ndis_buffer		*buf;
1702{
1703	ndis_buffer		*head;
1704
1705	if (buf == NULL || buf->nb_process == NULL)
1706		return;
1707
1708	head = buf->nb_process;
1709
1710	if (head->nb_flags != 0x1)
1711		return;
1712
1713	buf->nb_next = head->nb_next;
1714	head->nb_next = buf;
1715
1716	return;
1717}
1718
1719/* Aw c'mon. */
1720
1721__stdcall static uint32_t
1722ndis_buflen(buf)
1723	ndis_buffer		*buf;
1724{
1725	return(buf->nb_bytecount);
1726}
1727
1728/*
1729 * Get the virtual address and length of a buffer.
1730 * Note: the vaddr argument is optional.
1731 */
1732
1733__stdcall static void
1734ndis_query_buf(buf, vaddr, len)
1735	ndis_buffer		*buf;
1736	void			**vaddr;
1737	uint32_t		*len;
1738{
1739	if (vaddr != NULL)
1740		*vaddr = MDL_VA(buf);
1741	*len = buf->nb_bytecount;
1742
1743	return;
1744}
1745
1746/* Same as above -- we don't care about the priority. */
1747
1748__stdcall static void
1749ndis_query_buf_safe(buf, vaddr, len, prio)
1750	ndis_buffer		*buf;
1751	void			**vaddr;
1752	uint32_t		*len;
1753	uint32_t		prio;
1754{
1755	if (vaddr != NULL)
1756		*vaddr = MDL_VA(buf);
1757	*len = buf->nb_bytecount;
1758
1759	return;
1760}
1761
1762__stdcall static void
1763ndis_adjust_buflen(buf, len)
1764	ndis_buffer		*buf;
1765	int			len;
1766{
1767	buf->nb_bytecount = len;
1768
1769	return;
1770}
1771
1772__stdcall static uint32_t
1773ndis_interlock_inc(addend)
1774	uint32_t		*addend;
1775{
1776	mtx_lock(&ndis_interlock);
1777	*addend++;
1778	mtx_unlock(&ndis_interlock);
1779	return(*addend);
1780}
1781
1782__stdcall static uint32_t
1783ndis_interlock_dec(addend)
1784	uint32_t		*addend;
1785{
1786	mtx_lock(&ndis_interlock);
1787	*addend--;
1788	mtx_unlock(&ndis_interlock);
1789	return(*addend);
1790}
1791
1792__stdcall static void
1793ndis_init_event(event)
1794	ndis_event		*event;
1795{
1796	event->ne_event.nk_header.dh_sigstate = FALSE;
1797	return;
1798}
1799
1800__stdcall static void
1801ndis_set_event(event)
1802	ndis_event		*event;
1803{
1804	event->ne_event.nk_header.dh_sigstate = TRUE;
1805	wakeup(event);
1806	return;
1807}
1808
1809__stdcall static void
1810ndis_reset_event(event)
1811	ndis_event		*event;
1812{
1813	event->ne_event.nk_header.dh_sigstate = FALSE;
1814	wakeup(event);
1815	return;
1816}
1817
1818__stdcall static uint8_t
1819ndis_wait_event(event, msecs)
1820	ndis_event		*event;
1821	uint32_t		msecs;
1822{
1823	int			error;
1824	struct timeval		tv;
1825
1826	if (event->ne_event.nk_header.dh_sigstate == TRUE)
1827		return(TRUE);
1828
1829	tv.tv_sec = 0;
1830	tv.tv_usec = msecs * 1000;
1831
1832	error = tsleep(event, PPAUSE|PCATCH, "ndis", tvtohz(&tv));
1833
1834	return(event->ne_event.nk_header.dh_sigstate);
1835}
1836
1837__stdcall static ndis_status
1838ndis_unicode2ansi(dstr, sstr)
1839	ndis_ansi_string	*dstr;
1840	ndis_unicode_string	*sstr;
1841{
1842	if (dstr == NULL || sstr == NULL)
1843		return(NDIS_STATUS_FAILURE);
1844	if (ndis_unicode_to_ascii(sstr->nus_buf,
1845	    sstr->nus_len, &dstr->nas_buf))
1846		return(NDIS_STATUS_FAILURE);
1847	dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf);
1848	return (NDIS_STATUS_SUCCESS);
1849}
1850
1851__stdcall static ndis_status
1852ndis_ansi2unicode(dstr, sstr)
1853	ndis_unicode_string	*dstr;
1854	ndis_ansi_string	*sstr;
1855{
1856	char			*str;
1857	if (dstr == NULL || sstr == NULL)
1858		return(NDIS_STATUS_FAILURE);
1859	str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT);
1860	if (str == NULL)
1861		return(NDIS_STATUS_FAILURE);
1862	strncpy(str, sstr->nas_buf, sstr->nas_len);
1863	*(str + sstr->nas_len) = '\0';
1864	if (ndis_ascii_to_unicode(str, &dstr->nus_buf)) {
1865		free(str, M_DEVBUF);
1866		return(NDIS_STATUS_FAILURE);
1867	}
1868	dstr->nus_len = dstr->nus_maxlen = sstr->nas_len * 2;
1869	free(str, M_DEVBUF);
1870	return (NDIS_STATUS_SUCCESS);
1871}
1872
1873__stdcall static ndis_status
1874ndis_assign_pcirsrc(adapter, slot, list)
1875	ndis_handle		adapter;
1876	uint32_t		slot;
1877	ndis_resource_list	**list;
1878{
1879	ndis_miniport_block	*block;
1880
1881	if (adapter == NULL || list == NULL)
1882		return (NDIS_STATUS_FAILURE);
1883
1884	block = (ndis_miniport_block *)adapter;
1885	*list = block->nmb_rlist;
1886
1887	return (NDIS_STATUS_SUCCESS);
1888}
1889
1890__stdcall static ndis_status
1891ndis_register_intr(intr, adapter, ivec, ilevel, reqisr, shared, imode)
1892	ndis_miniport_interrupt	*intr;
1893	ndis_handle		adapter;
1894	uint32_t		ivec;
1895	uint32_t		ilevel;
1896	uint8_t			reqisr;
1897	uint8_t			shared;
1898	ndis_interrupt_mode	imode;
1899{
1900	ndis_miniport_block	*block;
1901
1902	block = adapter;
1903
1904	intr->ni_block = adapter;
1905	intr->ni_isrreq = reqisr;
1906	intr->ni_shared = shared;
1907	block->nmb_interrupt = intr;
1908	return(NDIS_STATUS_SUCCESS);
1909}
1910
1911__stdcall static void
1912ndis_deregister_intr(intr)
1913	ndis_miniport_interrupt	*intr;
1914{
1915	return;
1916}
1917
1918__stdcall static void
1919ndis_register_shutdown(adapter, shutdownctx, shutdownfunc)
1920	ndis_handle		adapter;
1921	void			*shutdownctx;
1922	ndis_shutdown_handler	shutdownfunc;
1923{
1924	ndis_miniport_block	*block;
1925	ndis_miniport_characteristics *chars;
1926	struct ndis_softc	*sc;
1927
1928	if (adapter == NULL)
1929		return;
1930
1931	block = (ndis_miniport_block *)adapter;
1932	sc = (struct ndis_softc *)block->nmb_ifp;
1933	chars = &sc->ndis_chars;
1934
1935	chars->nmc_shutdown_handler = shutdownfunc;
1936	chars->nmc_rsvd0 = shutdownctx;
1937
1938	return;
1939}
1940
1941__stdcall static void
1942ndis_deregister_shutdown(adapter)
1943	ndis_handle		adapter;
1944{
1945	ndis_miniport_block	*block;
1946	ndis_miniport_characteristics *chars;
1947	struct ndis_softc	*sc;
1948
1949	if (adapter == NULL)
1950		return;
1951
1952	block = (ndis_miniport_block *)adapter;
1953	sc = (struct ndis_softc *)block->nmb_ifp;
1954	chars = &sc->ndis_chars;
1955
1956	chars->nmc_shutdown_handler = NULL;
1957	chars->nmc_rsvd0 = NULL;
1958
1959	return;
1960}
1961
1962__stdcall static uint32_t
1963ndis_numpages(buf)
1964	ndis_buffer		*buf;
1965{
1966	if (buf == NULL)
1967		return(0);
1968	if (buf->nb_bytecount == 0)
1969		return(1);
1970	return(SPAN_PAGES(MDL_VA(buf), buf->nb_bytecount));
1971}
1972
1973__stdcall static void
1974ndis_buf_physpages(buf, pages)
1975	ndis_buffer		*buf;
1976	uint32_t		*pages;
1977{
1978	if (buf == NULL)
1979		return;
1980
1981	*pages = ndis_numpages(buf);
1982	return;
1983}
1984
1985__stdcall static void
1986ndis_query_bufoffset(buf, off, len)
1987	ndis_buffer		*buf;
1988	uint32_t		*off;
1989	uint32_t		*len;
1990{
1991	if (buf == NULL)
1992		return;
1993
1994	*off = buf->nb_byteoffset;
1995	*len = buf->nb_bytecount;
1996
1997	return;
1998}
1999
2000__stdcall static void
2001ndis_sleep(usecs)
2002	uint32_t		usecs;
2003{
2004	struct timeval		tv;
2005	uint32_t		dummy;
2006
2007	tv.tv_sec = 0;
2008	tv.tv_usec = usecs;
2009
2010	tsleep(&dummy, PPAUSE|PCATCH, "ndis", tvtohz(&tv));
2011
2012	return;
2013}
2014
2015__stdcall static uint32_t
2016ndis_read_pccard_amem(handle, offset, buf, len)
2017	ndis_handle		handle;
2018	uint32_t		offset;
2019	void			*buf;
2020	uint32_t		len;
2021{
2022	struct ndis_softc	*sc;
2023	ndis_miniport_block	*block;
2024	bus_space_handle_t	bh;
2025	bus_space_tag_t		bt;
2026	char			*dest;
2027	int			i;
2028
2029	if (handle == NULL)
2030		return(0);
2031
2032	block = (ndis_miniport_block *)handle;
2033	sc = (struct ndis_softc *)block->nmb_ifp;
2034	dest = buf;
2035
2036	bh = rman_get_bushandle(sc->ndis_res_am);
2037	bt = rman_get_bustag(sc->ndis_res_am);
2038
2039	for (i = 0; i < len; i++)
2040		dest[i] = bus_space_read_1(bt, bh, (offset * 2) + (i * 2));
2041
2042	return(i);
2043}
2044
2045__stdcall static uint32_t
2046ndis_write_pccard_amem(handle, offset, buf, len)
2047	ndis_handle		handle;
2048	uint32_t		offset;
2049	void			*buf;
2050	uint32_t		len;
2051{
2052	struct ndis_softc	*sc;
2053	ndis_miniport_block	*block;
2054	bus_space_handle_t	bh;
2055	bus_space_tag_t		bt;
2056	char			*src;
2057	int			i;
2058
2059	if (handle == NULL)
2060		return(0);
2061
2062	block = (ndis_miniport_block *)handle;
2063	sc = (struct ndis_softc *)block->nmb_ifp;
2064	src = buf;
2065
2066	bh = rman_get_bushandle(sc->ndis_res_am);
2067	bt = rman_get_bustag(sc->ndis_res_am);
2068
2069	for (i = 0; i < len; i++)
2070		bus_space_write_1(bt, bh, (offset * 2) + (i * 2), src[i]);
2071
2072	return(i);
2073}
2074
2075__stdcall static ndis_list_entry *
2076ndis_insert_head(head, entry, lock)
2077	ndis_list_entry		*head;
2078	ndis_list_entry		*entry;
2079	ndis_spin_lock		*lock;
2080{
2081	ndis_list_entry		*flink;
2082
2083	mtx_lock_spin((struct mtx *)lock->nsl_spinlock);
2084	flink = head->nle_flink;
2085	entry->nle_flink = flink;
2086	entry->nle_blink = head;
2087	flink->nle_blink = entry;
2088	head->nle_flink = entry;
2089	mtx_unlock_spin((struct mtx *)lock->nsl_spinlock);
2090
2091	return(flink);
2092}
2093
2094__stdcall static ndis_list_entry *
2095ndis_remove_head(head, lock)
2096	ndis_list_entry		*head;
2097	ndis_spin_lock		*lock;
2098{
2099	ndis_list_entry		*flink;
2100	ndis_list_entry		*entry;
2101
2102	mtx_lock_spin((struct mtx *)lock->nsl_spinlock);
2103	entry = head->nle_flink;
2104	flink = entry->nle_flink;
2105	head->nle_flink = flink;
2106	flink->nle_blink = head;
2107	mtx_unlock_spin((struct mtx *)lock->nsl_spinlock);
2108
2109	return(entry);
2110}
2111
2112__stdcall static ndis_list_entry *
2113ndis_insert_tail(head, entry, lock)
2114	ndis_list_entry		*head;
2115	ndis_list_entry		*entry;
2116	ndis_spin_lock		*lock;
2117{
2118	ndis_list_entry		*blink;
2119
2120	mtx_lock_spin((struct mtx *)lock->nsl_spinlock);
2121	blink = head->nle_blink;
2122	entry->nle_flink = head;
2123	entry->nle_blink = blink;
2124	blink->nle_flink = entry;
2125	head->nle_blink = entry;
2126	mtx_unlock_spin((struct mtx *)lock->nsl_spinlock);
2127
2128	return(blink);
2129}
2130
2131__stdcall static uint8_t
2132ndis_sync_with_intr(intr, syncfunc, syncctx)
2133	ndis_miniport_interrupt	*intr;
2134	void			*syncfunc;
2135	void			*syncctx;
2136{
2137	struct ndis_softc	*sc;
2138	__stdcall uint8_t (*sync)(void *);
2139	uint8_t			rval;
2140
2141	if (syncfunc == NULL || syncctx == NULL)
2142		return(0);
2143
2144	sc = (struct ndis_softc *)intr->ni_block->nmb_ifp;
2145	sync = syncfunc;
2146	mtx_lock(&sc->ndis_intrmtx);
2147	rval = sync(syncctx);
2148	mtx_unlock(&sc->ndis_intrmtx);
2149
2150	return(rval);
2151}
2152
2153/*
2154 * Return the number of 100 nanosecond intervals since
2155 * January 1, 1601. (?!?!)
2156 */
2157__stdcall static void
2158ndis_time(tval)
2159	uint64_t		*tval;
2160{
2161	struct timespec		ts;
2162
2163	nanotime(&ts);
2164	*tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
2165	    11644473600;
2166}
2167
2168/*
2169 * Return the number of milliseconds since the system booted.
2170 */
2171__stdcall static void
2172ndis_uptime(tval)
2173	uint32_t		*tval;
2174{
2175	struct timespec		ts;
2176
2177	nanouptime(&ts);
2178	*tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
2179}
2180
2181__stdcall static void
2182ndis_init_string(dst, src)
2183	ndis_unicode_string	*dst;
2184	char			*src;
2185{
2186	ndis_unicode_string	*u;
2187
2188	u = dst;
2189	u->nus_buf = NULL;
2190	if (ndis_ascii_to_unicode(src, &u->nus_buf))
2191		return;
2192	u->nus_len = u->nus_maxlen = strlen(src) * 2;
2193	return;
2194}
2195
2196__stdcall static void
2197ndis_free_string(str)
2198	ndis_unicode_string	*str;
2199{
2200	if (str == NULL)
2201		return;
2202	if (str->nus_buf != NULL)
2203		free(str->nus_buf, M_DEVBUF);
2204	free(str, M_DEVBUF);
2205	return;
2206}
2207
2208__stdcall static ndis_status
2209ndis_remove_miniport(adapter)
2210	ndis_handle		*adapter;
2211{
2212	return(NDIS_STATUS_SUCCESS);
2213}
2214
2215__stdcall static void
2216ndis_init_ansi_string(dst, src)
2217	ndis_ansi_string	*dst;
2218	char			*src;
2219{
2220	ndis_ansi_string	*a;
2221
2222	a = dst;
2223	if (a == NULL)
2224		return;
2225	if (src == NULL) {
2226		a->nas_len = a->nas_maxlen = 0;
2227		a->nas_buf = NULL;
2228	} else {
2229		a->nas_buf = src;
2230		a->nas_len = a->nas_maxlen = strlen(src);
2231	}
2232
2233	return;
2234}
2235
2236__stdcall static void
2237ndis_init_unicode_string(dst, src)
2238	ndis_unicode_string	*dst;
2239	uint16_t		*src;
2240{
2241	ndis_unicode_string	*u;
2242	int			i;
2243
2244	u = dst;
2245	if (u == NULL)
2246		return;
2247	if (src == NULL) {
2248		u->nus_len = u->nus_maxlen = 0;
2249		u->nus_buf = NULL;
2250	} else {
2251		i = 0;
2252		while(src[i] != 0)
2253			i++;
2254		u->nus_buf = src;
2255		u->nus_len = u->nus_maxlen = i * 2;
2256	}
2257
2258	return;
2259}
2260
2261__stdcall static void ndis_get_devprop(adapter, phydevobj,
2262	funcdevobj, nextdevobj, resources, transresources)
2263	ndis_handle		adapter;
2264	void			*phydevobj;
2265	void			*funcdevobj;
2266	void			*nextdevobj;
2267	cm_resource_list	*resources;
2268	cm_resource_list	*transresources;
2269{
2270	return;
2271}
2272
2273__stdcall static void
2274ndis_firstbuf(packet, buf, firstva, firstlen, totlen)
2275	ndis_packet		*packet;
2276	ndis_buffer		**buf;
2277	void			**firstva;
2278	uint32_t		*firstlen;
2279	uint32_t		*totlen;
2280{
2281	ndis_buffer		*tmp;
2282
2283	tmp = packet->np_private.npp_head;
2284	*buf = tmp;
2285	if (tmp == NULL) {
2286		*firstva = NULL;
2287		*firstlen = *totlen = 0;
2288	} else {
2289		*firstva = MDL_VA(tmp);
2290		*firstlen = *totlen = tmp->nb_bytecount;
2291		for (tmp = tmp->nb_next; tmp != NULL; tmp = tmp->nb_next)
2292			*totlen += tmp->nb_bytecount;
2293	}
2294
2295	return;
2296}
2297
2298__stdcall static void
2299ndis_firstbuf_safe(packet, buf, firstva, firstlen, totlen, prio)
2300	ndis_packet		*packet;
2301	ndis_buffer		**buf;
2302	void			**firstva;
2303	uint32_t		*firstlen;
2304	uint32_t		*totlen;
2305	uint32_t		prio;
2306{
2307	ndis_firstbuf(packet, buf, firstva, firstlen, totlen);
2308}
2309
2310/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
2311__stdcall static void
2312ndis_open_file(status, filehandle, filelength, filename, highestaddr)
2313	ndis_status		*status;
2314	ndis_handle		*filehandle;
2315	uint32_t		*filelength;
2316	ndis_unicode_string	*filename;
2317	ndis_physaddr		highestaddr;
2318{
2319	char			*afilename = NULL;
2320
2321	ndis_unicode_to_ascii(filename->nus_buf, filename->nus_len, &afilename);
2322	printf("ndis_open_file(\"%s\", %ju)\n", afilename,
2323	    highestaddr.np_quad);
2324	free(afilename, M_DEVBUF);
2325	*status = NDIS_STATUS_FILE_NOT_FOUND;
2326	return;
2327}
2328
2329__stdcall static void
2330ndis_map_file(status, mappedbuffer, filehandle)
2331	ndis_status		*status;
2332	void			**mappedbuffer;
2333	ndis_handle		filehandle;
2334{
2335
2336	*status = NDIS_STATUS_ALREADY_MAPPED;
2337	return;
2338}
2339
2340__stdcall static void
2341ndis_unmap_file(filehandle)
2342	ndis_handle		filehandle;
2343{
2344	return;
2345}
2346
2347__stdcall static void
2348ndis_close_file(filehandle)
2349	ndis_handle		filehandle;
2350{
2351	return;
2352}
2353
2354__stdcall static uint8_t
2355ndis_cpu_cnt()
2356{
2357#ifdef SMP
2358	return(mp_ncpus);
2359#else
2360	return(1);
2361#endif
2362};
2363
2364typedef void (*ndis_statusdone_handler)(ndis_handle);
2365typedef void (*ndis_status_handler)(ndis_handle, ndis_status,
2366        void *, uint32_t);
2367
2368__stdcall static void
2369ndis_ind_statusdone(adapter)
2370	ndis_handle		adapter;
2371{
2372	ndis_miniport_block	*block;
2373	__stdcall ndis_statusdone_handler	statusdonefunc;
2374
2375	block = (ndis_miniport_block *)adapter;
2376	statusdonefunc = block->nmb_statusdone_func;
2377
2378	statusdonefunc(adapter);
2379	return;
2380}
2381
2382__stdcall static void
2383ndis_ind_status(adapter, status, sbuf, slen)
2384	ndis_handle		adapter;
2385	ndis_status		status;
2386	void			*sbuf;
2387	uint32_t		slen;
2388{
2389	ndis_miniport_block	*block;
2390	__stdcall ndis_status_handler	statusfunc;
2391
2392	block = (ndis_miniport_block *)adapter;
2393	statusfunc = block->nmb_status_func;
2394
2395	statusfunc(adapter, status, sbuf, slen);
2396	return;
2397}
2398
2399static void
2400ndis_workfunc(ctx, pending)
2401	void			*ctx;
2402	int			pending;
2403{
2404	ndis_work_item		*work;
2405	__stdcall ndis_proc	workfunc;
2406
2407	work = ctx;
2408	workfunc = work->nwi_func;
2409	workfunc(work, work->nwi_ctx);
2410	return;
2411}
2412
2413__stdcall static ndis_status
2414ndis_sched_workitem(work)
2415	ndis_work_item		*work;
2416{
2417	struct task		*t;
2418
2419	t = (struct task *)&work->nwi_wraprsvd;
2420	TASK_INIT(t, 0, ndis_workfunc, work);
2421	taskqueue_enqueue(taskqueue_swi, t);
2422	return(NDIS_STATUS_SUCCESS);
2423}
2424
2425__stdcall static void
2426dummy()
2427{
2428	printf ("NDIS dummy called...\n");
2429	return;
2430}
2431
2432image_patch_table ndis_functbl[] = {
2433	{ "NdisScheduleWorkItem",	(FUNC)ndis_sched_workitem },
2434	{ "NdisMIndicateStatusComplete", (FUNC)ndis_ind_statusdone },
2435	{ "NdisMIndicateStatus",	(FUNC)ndis_ind_status },
2436	{ "NdisSystemProcessorCount",	(FUNC)ndis_cpu_cnt },
2437	{ "NdisUnchainBufferAtBack",	(FUNC)ndis_unchain_tailbuf, },
2438	{ "NdisGetFirstBufferFromPacket", (FUNC)ndis_firstbuf },
2439	{ "NdisGetFirstBufferFromPacketSafe", (FUNC)ndis_firstbuf_safe },
2440	{ "NdisGetBufferPhysicalArraySize", (FUNC)ndis_buf_physpages },
2441	{ "NdisMGetDeviceProperty",	(FUNC)ndis_get_devprop },
2442	{ "NdisInitAnsiString",		(FUNC)ndis_init_ansi_string },
2443	{ "NdisInitUnicodeString",	(FUNC)ndis_init_unicode_string },
2444	{ "NdisWriteConfiguration",	(FUNC)ndis_write_cfg },
2445	{ "NdisAnsiStringToUnicodeString", (FUNC)ndis_ansi2unicode },
2446	{ "NdisTerminateWrapper",	(FUNC)ndis_termwrap },
2447	{ "NdisOpenConfigurationKeyByName", (FUNC)ndis_open_cfgbyname },
2448	{ "NdisOpenConfigurationKeyByIndex", (FUNC)ndis_open_cfgbyidx },
2449	{ "NdisMRemoveMiniport",	(FUNC)ndis_remove_miniport },
2450	{ "NdisInitializeString",	(FUNC)ndis_init_string },
2451	{ "NdisFreeString",		(FUNC)ndis_free_string },
2452	{ "NdisGetCurrentSystemTime",	(FUNC)ndis_time },
2453	{ "NdisGetSystemUpTime",	(FUNC)ndis_uptime },
2454	{ "NdisMSynchronizeWithInterrupt", (FUNC)ndis_sync_with_intr },
2455	{ "NdisMAllocateSharedMemoryAsync", (FUNC)ndis_alloc_sharedmem_async },
2456	{ "NdisInterlockedInsertHeadList", (FUNC)ndis_insert_head },
2457	{ "NdisInterlockedInsertTailList", (FUNC)ndis_insert_tail },
2458	{ "NdisInterlockedRemoveHeadList", (FUNC)ndis_remove_head },
2459	{ "NdisInitializeWrapper",	(FUNC)ndis_initwrap },
2460	{ "NdisMRegisterMiniport",	(FUNC)ndis_register_miniport },
2461	{ "NdisAllocateMemoryWithTag",	(FUNC)ndis_malloc_withtag },
2462	{ "NdisAllocateMemory",		(FUNC)ndis_malloc },
2463	{ "NdisMSetAttributesEx",	(FUNC)ndis_setattr_ex },
2464	{ "NdisCloseConfiguration",	(FUNC)ndis_close_cfg },
2465	{ "NdisReadConfiguration",	(FUNC)ndis_read_cfg },
2466	{ "NdisOpenConfiguration",	(FUNC)ndis_open_cfg },
2467	{ "NdisReleaseSpinLock",	(FUNC)ndis_unlock },
2468	{ "NdisDprAcquireSpinLock",	(FUNC)ndis_lock },
2469	{ "NdisDprReleaseSpinLock",	(FUNC)ndis_unlock },
2470	{ "NdisAcquireSpinLock",	(FUNC)ndis_lock },
2471	{ "NdisAllocateSpinLock",	(FUNC)ndis_create_lock },
2472	{ "NdisFreeSpinLock",		(FUNC)ndis_destroy_lock },
2473	{ "NdisFreeMemory",		(FUNC)ndis_free },
2474	{ "NdisReadPciSlotInformation",	(FUNC)ndis_read_pci },
2475	{ "NdisWritePciSlotInformation",(FUNC)ndis_write_pci },
2476	{ "NdisImmediateReadPciSlotInformation", (FUNC)ndis_read_pci },
2477	{ "NdisImmediateWritePciSlotInformation", (FUNC)ndis_write_pci },
2478	{ "NdisWriteErrorLogEntry",	(FUNC)ndis_syslog },
2479	{ "NdisMStartBufferPhysicalMapping", (FUNC)ndis_vtophys_load },
2480	{ "NdisMCompleteBufferPhysicalMapping", (FUNC)ndis_vtophys_unload },
2481	{ "NdisMInitializeTimer",	(FUNC)ndis_create_timer },
2482	{ "NdisSetTimer",		(FUNC)ndis_set_timer },
2483	{ "NdisMCancelTimer",		(FUNC)ndis_cancel_timer },
2484	{ "NdisMSetPeriodicTimer",	(FUNC)ndis_set_periodic_timer },
2485	{ "NdisMQueryAdapterResources",	(FUNC)ndis_query_resources },
2486	{ "NdisMRegisterIoPortRange",	(FUNC)ndis_register_ioport },
2487	{ "NdisMDeregisterIoPortRange",	(FUNC)ndis_deregister_ioport },
2488	{ "NdisReadNetworkAddress",	(FUNC)ndis_read_netaddr },
2489	{ "NdisQueryMapRegisterCount",	(FUNC)ndis_mapreg_cnt },
2490	{ "NdisMAllocateMapRegisters",	(FUNC)ndis_alloc_mapreg },
2491	{ "NdisMFreeMapRegisters",	(FUNC)ndis_free_mapreg },
2492	{ "NdisMAllocateSharedMemory",	(FUNC)ndis_alloc_sharedmem },
2493	{ "NdisMMapIoSpace",		(FUNC)ndis_map_iospace },
2494	{ "NdisMUnmapIoSpace",		(FUNC)ndis_unmap_iospace },
2495	{ "NdisGetCacheFillSize",	(FUNC)ndis_cachefill },
2496	{ "NdisMGetDmaAlignment",	(FUNC)ndis_dma_align },
2497	{ "NdisMInitializeScatterGatherDma", (FUNC)ndis_init_sc_dma },
2498	{ "NdisAllocatePacketPool",	(FUNC)ndis_alloc_packetpool },
2499	{ "NdisAllocatePacketPoolEx",	(FUNC)ndis_ex_alloc_packetpool },
2500	{ "NdisAllocatePacket",		(FUNC)ndis_alloc_packet },
2501	{ "NdisFreePacket",		(FUNC)ndis_release_packet },
2502	{ "NdisFreePacketPool",		(FUNC)ndis_free_packetpool },
2503	{ "NdisDprAllocatePacket",	(FUNC)ndis_alloc_packet },
2504	{ "NdisDprFreePacket",		(FUNC)ndis_release_packet },
2505	{ "NdisAllocateBufferPool",	(FUNC)ndis_alloc_bufpool },
2506	{ "NdisAllocateBuffer",		(FUNC)ndis_alloc_buf },
2507	{ "NdisQueryBuffer",		(FUNC)ndis_query_buf },
2508	{ "NdisQueryBufferSafe",	(FUNC)ndis_query_buf_safe },
2509	{ "NdisBufferLength",		(FUNC)ndis_buflen },
2510	{ "NdisFreeBuffer",		(FUNC)ndis_release_buf },
2511	{ "NdisFreeBufferPool",		(FUNC)ndis_free_bufpool },
2512	{ "NdisInterlockedIncrement",	(FUNC)ndis_interlock_inc },
2513	{ "NdisInterlockedDecrement",	(FUNC)ndis_interlock_dec },
2514	{ "NdisInitializeEvent",	(FUNC)ndis_init_event },
2515	{ "NdisSetEvent",		(FUNC)ndis_set_event },
2516	{ "NdisResetEvent",		(FUNC)ndis_reset_event },
2517	{ "NdisWaitEvent",		(FUNC)ndis_wait_event },
2518	{ "NdisUnicodeStringToAnsiString", (FUNC)ndis_unicode2ansi },
2519	{ "NdisMPciAssignResources",	(FUNC)ndis_assign_pcirsrc },
2520	{ "NdisMFreeSharedMemory",	(FUNC)ndis_free_sharedmem },
2521	{ "NdisMRegisterInterrupt",	(FUNC)ndis_register_intr },
2522	{ "NdisMDeregisterInterrupt",	(FUNC)ndis_deregister_intr },
2523	{ "NdisMRegisterAdapterShutdownHandler", (FUNC)ndis_register_shutdown },
2524	{ "NdisMDeregisterAdapterShutdownHandler", (FUNC)ndis_deregister_shutdown },
2525	{ "NDIS_BUFFER_TO_SPAN_PAGES",	(FUNC)ndis_numpages },
2526	{ "NdisQueryBufferOffset",	(FUNC)ndis_query_bufoffset },
2527	{ "NdisAdjustBufferLength",	(FUNC)ndis_adjust_buflen },
2528	{ "NdisPacketPoolUsage",	(FUNC)ndis_packetpool_use },
2529	{ "NdisMSleep",			(FUNC)ndis_sleep },
2530	{ "NdisUnchainBufferAtFront",	(FUNC)ndis_unchain_headbuf },
2531	{ "NdisReadPcmciaAttributeMemory", (FUNC)ndis_read_pccard_amem },
2532	{ "NdisWritePcmciaAttributeMemory", (FUNC)ndis_write_pccard_amem },
2533	{ "NdisOpenFile",		(FUNC)ndis_open_file },
2534	{ "NdisMapFile",		(FUNC)ndis_map_file },
2535	{ "NdisUnmapFile",		(FUNC)ndis_unmap_file },
2536	{ "NdisCloseFile",		(FUNC)ndis_close_file },
2537
2538	/*
2539	 * This last entry is a catch-all for any function we haven't
2540	 * implemented yet. The PE import list patching routine will
2541	 * use it for any function that doesn't have an explicit match
2542	 * in this table.
2543	 */
2544
2545	{ NULL, (FUNC)dummy },
2546
2547	/* End of list. */
2548
2549	{ NULL, NULL },
2550};
2551