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