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