kern_ndis.c revision 124697
1123474Swpaul/*
2123474Swpaul * Copyright (c) 2003
3123474Swpaul *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4123474Swpaul *
5123474Swpaul * Redistribution and use in source and binary forms, with or without
6123474Swpaul * modification, are permitted provided that the following conditions
7123474Swpaul * are met:
8123474Swpaul * 1. Redistributions of source code must retain the above copyright
9123474Swpaul *    notice, this list of conditions and the following disclaimer.
10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright
11123474Swpaul *    notice, this list of conditions and the following disclaimer in the
12123474Swpaul *    documentation and/or other materials provided with the distribution.
13123474Swpaul * 3. All advertising materials mentioning features or use of this software
14123474Swpaul *    must display the following acknowledgement:
15123474Swpaul *	This product includes software developed by Bill Paul.
16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors
17123474Swpaul *    may be used to endorse or promote products derived from this software
18123474Swpaul *    without specific prior written permission.
19123474Swpaul *
20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23123474Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
31123474Swpaul */
32123474Swpaul
33123474Swpaul#include <sys/cdefs.h>
34123474Swpaul__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 124697 2004-01-18 22:57:11Z wpaul $");
35123474Swpaul
36123474Swpaul#include <sys/param.h>
37124697Swpaul#include <sys/systm.h>
38124697Swpaul#include <sys/unistd.h>
39123474Swpaul#include <sys/types.h>
40123474Swpaul#include <sys/errno.h>
41123474Swpaul#include <sys/callout.h>
42123474Swpaul#include <sys/socket.h>
43123474Swpaul#include <sys/queue.h>
44123474Swpaul#include <sys/sysctl.h>
45124697Swpaul#include <sys/proc.h>
46123474Swpaul#include <sys/malloc.h>
47123474Swpaul#include <sys/lock.h>
48123474Swpaul#include <sys/mutex.h>
49123474Swpaul#include <sys/conf.h>
50123474Swpaul
51123474Swpaul#include <sys/kernel.h>
52124697Swpaul#include <sys/kthread.h>
53123474Swpaul#include <machine/bus.h>
54123474Swpaul#include <machine/resource.h>
55123474Swpaul#include <sys/bus.h>
56123474Swpaul#include <sys/rman.h>
57123474Swpaul
58124060Swpaul#include <vm/uma.h>
59124060Swpaul
60123474Swpaul#include <net/if.h>
61123474Swpaul#include <net/if_arp.h>
62123474Swpaul#include <net/ethernet.h>
63123474Swpaul#include <net/if_dl.h>
64123474Swpaul#include <net/if_media.h>
65123474Swpaul
66123695Swpaul#include <net80211/ieee80211_var.h>
67123695Swpaul#include <net80211/ieee80211_ioctl.h>
68123695Swpaul
69123474Swpaul#include <dev/pccard/pccardvar.h>
70123474Swpaul#include "card_if.h"
71123474Swpaul
72123474Swpaul#include <compat/ndis/pe_var.h>
73123474Swpaul#include <compat/ndis/resource_var.h>
74123474Swpaul#include <compat/ndis/ndis_var.h>
75123474Swpaul#include <compat/ndis/hal_var.h>
76123474Swpaul#include <compat/ndis/ntoskrnl_var.h>
77123474Swpaul#include <compat/ndis/cfg_var.h>
78123474Swpaul#include <dev/if_ndis/if_ndisvar.h>
79123474Swpaul
80123474Swpaul#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
81123474Swpaul
82123474Swpaul__stdcall static void ndis_status_func(ndis_handle, ndis_status,
83123474Swpaul	void *, uint32_t);
84123474Swpaul__stdcall static void ndis_statusdone_func(ndis_handle);
85123474Swpaul__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
86123535Swpaul__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
87123474Swpaul__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
88124100Swpaul__stdcall static void ndis_sendrsrcavail_func(ndis_handle);
89123474Swpaul
90124697Swpaulstatic int ndis_create_kthreads(void);
91124697Swpaulstatic void ndis_destroy_kthreads(void);
92124697Swpaulstatic void ndis_stop_thread(int);
93124697Swpaulstatic int ndis_enlarge_thrqueue(int);
94124697Swpaulstatic int ndis_shrink_thrqueue(int);
95124697Swpaulstatic void ndis_runq(void *);
96124697Swpaulstatic void ndis_intq(void *);
97124697Swpaul
98124697Swpaulextern struct mtx_pool *ndis_mtxpool;
99124060Swpaulstatic uma_zone_t ndis_packet_zone, ndis_buffer_zone;
100124697Swpaulstruct mtx *ndis_thr_mtx;
101124697Swpaulstatic STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo;
102124697Swpaulstruct ndisqhead ndis_itodo;
103124697Swpaulstruct ndisqhead ndis_free;
104124697Swpaulstatic int ndis_jobs = 32;
105124697Swpaulstatic struct proc *ndis_tproc;
106124697Swpaulstatic struct proc *ndis_iproc;
107124060Swpaul
108124697Swpaulstruct ndis_req {
109124697Swpaul	void			(*ndis_func)(void *);
110124697Swpaul	void			*ndis_arg;
111124697Swpaul	int			ndis_exit;
112124697Swpaul	STAILQ_ENTRY(ndis_req)	link;
113124697Swpaul};
114124697Swpaul
115123474Swpaul/*
116123474Swpaul * This allows us to export our symbols to other modules.
117123474Swpaul * Note that we call ourselves 'ndisapi' to avoid a namespace
118123474Swpaul * collision with if_ndis.ko, which internally calls itself
119123474Swpaul * 'ndis.'
120123474Swpaul */
121123474Swpaulstatic int
122123474Swpaulndis_modevent(module_t mod, int cmd, void *arg)
123123474Swpaul{
124124060Swpaul	int			error = 0;
125124060Swpaul
126124060Swpaul	switch (cmd) {
127124060Swpaul	case MOD_LOAD:
128124122Swpaul		/* Initialize subsystems */
129124122Swpaul		ndis_libinit();
130124122Swpaul		ntoskrnl_libinit();
131124122Swpaul
132124122Swpaul		/* Initialize TX buffer UMA zone. */
133124060Swpaul		ndis_packet_zone = uma_zcreate("NDIS packet",
134124060Swpaul		    sizeof(ndis_packet), NULL, NULL, NULL,
135124060Swpaul		    NULL, UMA_ALIGN_PTR, 0);
136124060Swpaul		ndis_buffer_zone = uma_zcreate("NDIS buffer",
137124060Swpaul		    sizeof(ndis_buffer), NULL, NULL, NULL,
138124060Swpaul		    NULL, UMA_ALIGN_PTR, 0);
139124697Swpaul
140124697Swpaul		ndis_create_kthreads();
141124697Swpaul
142124060Swpaul		break;
143124060Swpaul	case MOD_UNLOAD:
144124060Swpaul	case MOD_SHUTDOWN:
145124697Swpaul		/* stop kthreads */
146124697Swpaul		ndis_destroy_kthreads();
147124697Swpaul
148124122Swpaul		/* Shut down subsystems */
149124122Swpaul		ndis_libfini();
150124122Swpaul		ntoskrnl_libfini();
151124122Swpaul
152124122Swpaul		/* Remove zones */
153124060Swpaul		uma_zdestroy(ndis_packet_zone);
154124060Swpaul		uma_zdestroy(ndis_buffer_zone);
155124060Swpaul		break;
156124060Swpaul	default:
157124060Swpaul		error = EINVAL;
158124060Swpaul		break;
159124060Swpaul	}
160124060Swpaul
161124060Swpaul	return(error);
162123474Swpaul}
163123474SwpaulDEV_MODULE(ndisapi, ndis_modevent, NULL);
164123474SwpaulMODULE_VERSION(ndisapi, 1);
165123474Swpaul
166124697Swpaul/*
167124697Swpaul * We create two kthreads for the NDIS subsystem. One of them is a task
168124697Swpaul * queue for performing various odd jobs. The other is an swi thread
169124697Swpaul * reserved exclusively for running interrupt handlers. The reason we
170124697Swpaul * have our own task queue is that there are some cases where we may
171124697Swpaul * need to sleep for a significant amount of time, and if we were to
172124697Swpaul * use one of the taskqueue threads, we might delay the processing
173124697Swpaul * of other pending tasks which might need to run right away. We have
174124697Swpaul * a separate swi thread because we don't want our interrupt handling
175124697Swpaul * to be delayed either.
176124697Swpaul *
177124697Swpaul * By default there are 32 jobs available to start, and another 8
178124697Swpaul * are added to the free list each time a new device is created.
179124697Swpaul */
180123474Swpaul
181124697Swpaulstatic void
182124697Swpaulndis_runq(dummy)
183124697Swpaul	void			*dummy;
184124697Swpaul{
185124697Swpaul	struct ndis_req		*r = NULL, *die = NULL;
186124697Swpaul
187124697Swpaul	while (1) {
188124697Swpaul		kthread_suspend(ndis_tproc, 0);
189124697Swpaul
190124697Swpaul		/* Look for any jobs on the work queue. */
191124697Swpaul
192124697Swpaul		mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
193124697Swpaul		while(STAILQ_FIRST(&ndis_ttodo) != NULL) {
194124697Swpaul			r = STAILQ_FIRST(&ndis_ttodo);
195124697Swpaul			STAILQ_REMOVE_HEAD(&ndis_ttodo, link);
196124697Swpaul			mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
197124697Swpaul
198124697Swpaul			/* Do the work. */
199124697Swpaul
200124697Swpaul			if (r->ndis_func != NULL)
201124697Swpaul				(*r->ndis_func)(r->ndis_arg);
202124697Swpaul
203124697Swpaul			mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
204124697Swpaul			STAILQ_INSERT_HEAD(&ndis_free, r, link);
205124697Swpaul
206124697Swpaul			/* Check for a shutdown request */
207124697Swpaul
208124697Swpaul			if (r->ndis_exit == TRUE)
209124697Swpaul				die = r;
210124697Swpaul		}
211124697Swpaul		mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
212124697Swpaul
213124697Swpaul		/* Bail if we were told to shut down. */
214124697Swpaul
215124697Swpaul		if (die != NULL)
216124697Swpaul			break;
217124697Swpaul	}
218124697Swpaul
219124697Swpaul	wakeup(die);
220124697Swpaul	mtx_lock(&Giant);
221124697Swpaul	kthread_exit(0);
222124697Swpaul}
223124697Swpaul
224124697Swpaulstatic void
225124697Swpaulndis_intq(dummy)
226124697Swpaul	void			*dummy;
227124697Swpaul{
228124697Swpaul	struct ndis_req		*r = NULL, *die = NULL;
229124697Swpaul
230124697Swpaul	while (1) {
231124697Swpaul		kthread_suspend(ndis_iproc, 0);
232124697Swpaul
233124697Swpaul		/* Look for any jobs on the work queue. */
234124697Swpaul
235124697Swpaul		mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
236124697Swpaul		while(STAILQ_FIRST(&ndis_itodo) != NULL) {
237124697Swpaul			r = STAILQ_FIRST(&ndis_itodo);
238124697Swpaul			STAILQ_REMOVE_HEAD(&ndis_itodo, link);
239124697Swpaul			mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
240124697Swpaul
241124697Swpaul			/* Do the work. */
242124697Swpaul
243124697Swpaul			if (r->ndis_func != NULL)
244124697Swpaul				(*r->ndis_func)(r->ndis_arg);
245124697Swpaul
246124697Swpaul			mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
247124697Swpaul			STAILQ_INSERT_HEAD(&ndis_free, r, link);
248124697Swpaul
249124697Swpaul			/* Check for a shutdown request */
250124697Swpaul
251124697Swpaul			if (r->ndis_exit == TRUE)
252124697Swpaul				die = r;
253124697Swpaul		}
254124697Swpaul		mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
255124697Swpaul
256124697Swpaul		/* Bail if this is an exit request. */
257124697Swpaul
258124697Swpaul		if (die != NULL)
259124697Swpaul			break;
260124697Swpaul	}
261124697Swpaul
262124697Swpaul	wakeup(die);
263124697Swpaul	mtx_lock(&Giant);
264124697Swpaul	kthread_exit(0);
265124697Swpaul}
266124697Swpaul
267124697Swpaulstatic int
268124697Swpaulndis_create_kthreads()
269124697Swpaul{
270124697Swpaul	struct ndis_req		*r;
271124697Swpaul	int			i, error = 0;
272124697Swpaul
273124697Swpaul	ndis_thr_mtx = mtx_pool_alloc(ndis_mtxpool);
274124697Swpaul	STAILQ_INIT(&ndis_ttodo);
275124697Swpaul	STAILQ_INIT(&ndis_itodo);
276124697Swpaul	STAILQ_INIT(&ndis_free);
277124697Swpaul
278124697Swpaul	for (i = 0; i < ndis_jobs; i++) {
279124697Swpaul		r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
280124697Swpaul		if (r == NULL) {
281124697Swpaul			error = ENOMEM;
282124697Swpaul			break;
283124697Swpaul		}
284124697Swpaul		STAILQ_INSERT_HEAD(&ndis_free, r, link);
285124697Swpaul	}
286124697Swpaul
287124697Swpaul	if (error == 0)
288124697Swpaul		error = kthread_create(ndis_runq, NULL,
289124697Swpaul		    &ndis_tproc, RFHIGHPID, 0, "ndis taskqueue");
290124697Swpaul
291124697Swpaul	if (error == 0)
292124697Swpaul		error = kthread_create(ndis_intq, NULL,
293124697Swpaul		    &ndis_iproc, RFHIGHPID, 0, "ndis swi");
294124697Swpaul
295124697Swpaul	if (error) {
296124697Swpaul		while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
297124697Swpaul			STAILQ_REMOVE_HEAD(&ndis_free, link);
298124697Swpaul			free(r, M_DEVBUF);
299124697Swpaul		}
300124697Swpaul		return(error);
301124697Swpaul	}
302124697Swpaul
303124697Swpaul	return(0);
304124697Swpaul}
305124697Swpaul
306124697Swpaulstatic void
307124697Swpaulndis_destroy_kthreads()
308124697Swpaul{
309124697Swpaul	struct ndis_req		*r;
310124697Swpaul
311124697Swpaul	/* Stop the threads. */
312124697Swpaul
313124697Swpaul	ndis_stop_thread(NDIS_TASKQUEUE);
314124697Swpaul	ndis_stop_thread(NDIS_SWI);
315124697Swpaul
316124697Swpaul	/* Destroy request structures. */
317124697Swpaul
318124697Swpaul	while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
319124697Swpaul		STAILQ_REMOVE_HEAD(&ndis_free, link);
320124697Swpaul		free(r, M_DEVBUF);
321124697Swpaul	}
322124697Swpaul
323124697Swpaul	return;
324124697Swpaul}
325124697Swpaul
326124697Swpaulstatic void
327124697Swpaulndis_stop_thread(t)
328124697Swpaul	int			t;
329124697Swpaul{
330124697Swpaul	struct ndis_req		*r;
331124697Swpaul	struct timeval		tv;
332124697Swpaul	struct ndisqhead	*q;
333124697Swpaul	struct proc		*p;
334124697Swpaul
335124697Swpaul	if (t == NDIS_TASKQUEUE) {
336124697Swpaul		q = &ndis_ttodo;
337124697Swpaul		p = ndis_tproc;
338124697Swpaul	} else {
339124697Swpaul		q = &ndis_itodo;
340124697Swpaul		p = ndis_iproc;
341124697Swpaul	}
342124697Swpaul
343124697Swpaul	/* Create and post a special 'exit' job. */
344124697Swpaul
345124697Swpaul	mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
346124697Swpaul	r = STAILQ_FIRST(&ndis_free);
347124697Swpaul	STAILQ_REMOVE_HEAD(&ndis_free, link);
348124697Swpaul	r->ndis_func = NULL;
349124697Swpaul	r->ndis_arg = NULL;
350124697Swpaul	r->ndis_exit = TRUE;
351124697Swpaul	STAILQ_INSERT_TAIL(q, r, link);
352124697Swpaul	mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
353124697Swpaul
354124697Swpaul	kthread_resume(p);
355124697Swpaul
356124697Swpaul	/* wait for thread exit */
357124697Swpaul
358124697Swpaul	tv.tv_sec = 60;
359124697Swpaul	tv.tv_usec = 0;
360124697Swpaul	tsleep(r, PPAUSE|PCATCH, "ndisthrexit", tvtohz(&tv));
361124697Swpaul
362124697Swpaul	/* Now empty the job list. */
363124697Swpaul
364124697Swpaul	mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
365124697Swpaul	while ((r = STAILQ_FIRST(q)) != NULL) {
366124697Swpaul		STAILQ_REMOVE_HEAD(q, link);
367124697Swpaul		STAILQ_INSERT_HEAD(&ndis_free, r, link);
368124697Swpaul	}
369124697Swpaul	mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
370124697Swpaul
371124697Swpaul	return;
372124697Swpaul}
373124697Swpaul
374124697Swpaulstatic int
375124697Swpaulndis_enlarge_thrqueue(cnt)
376124697Swpaul	int			cnt;
377124697Swpaul{
378124697Swpaul	struct ndis_req		*r;
379124697Swpaul	int			i;
380124697Swpaul
381124697Swpaul	for (i = 0; i < cnt; i++) {
382124697Swpaul		r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
383124697Swpaul		if (r == NULL)
384124697Swpaul			return(ENOMEM);
385124697Swpaul		mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
386124697Swpaul		STAILQ_INSERT_HEAD(&ndis_free, r, link);
387124697Swpaul		ndis_jobs++;
388124697Swpaul		mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
389124697Swpaul	}
390124697Swpaul
391124697Swpaul	return(0);
392124697Swpaul}
393124697Swpaul
394124697Swpaulstatic int
395124697Swpaulndis_shrink_thrqueue(cnt)
396124697Swpaul	int			cnt;
397124697Swpaul{
398124697Swpaul	struct ndis_req		*r;
399124697Swpaul	int			i;
400124697Swpaul
401124697Swpaul	for (i = 0; i < cnt; i++) {
402124697Swpaul		mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
403124697Swpaul		r = STAILQ_FIRST(&ndis_free);
404124697Swpaul		if (r == NULL) {
405124697Swpaul			mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
406124697Swpaul			return(ENOMEM);
407124697Swpaul		}
408124697Swpaul		STAILQ_REMOVE_HEAD(&ndis_free, link);
409124697Swpaul		ndis_jobs--;
410124697Swpaul		mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
411124697Swpaul		free(r, M_DEVBUF);
412124697Swpaul	}
413124697Swpaul
414124697Swpaul	return(0);
415124697Swpaul}
416124697Swpaul
417124697Swpaulint
418124697Swpaulndis_sched(func, arg, t)
419124697Swpaul	void			(*func)(void *);
420124697Swpaul	void			*arg;
421124697Swpaul	int			t;
422124697Swpaul{
423124697Swpaul	struct ndis_req		*r;
424124697Swpaul	struct ndisqhead	*q;
425124697Swpaul	struct proc		*p;
426124697Swpaul
427124697Swpaul	if (t == NDIS_TASKQUEUE) {
428124697Swpaul		q = &ndis_ttodo;
429124697Swpaul		p = ndis_tproc;
430124697Swpaul	} else {
431124697Swpaul		q = &ndis_itodo;
432124697Swpaul		p = ndis_iproc;
433124697Swpaul	}
434124697Swpaul
435124697Swpaul	mtx_pool_lock(ndis_mtxpool, ndis_thr_mtx);
436124697Swpaul	/*
437124697Swpaul	 * Check to see if an instance of this job is already
438124697Swpaul	 * pending. If so, don't bother queuing it again.
439124697Swpaul	 */
440124697Swpaul	STAILQ_FOREACH(r, q, link) {
441124697Swpaul		if (r->ndis_func == func && r->ndis_arg == arg) {
442124697Swpaul			mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
443124697Swpaul			return(0);
444124697Swpaul		}
445124697Swpaul	}
446124697Swpaul	r = STAILQ_FIRST(&ndis_free);
447124697Swpaul	if (r == NULL) {
448124697Swpaul		mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
449124697Swpaul		return(EAGAIN);
450124697Swpaul	}
451124697Swpaul	STAILQ_REMOVE_HEAD(&ndis_free, link);
452124697Swpaul	r->ndis_func = func;
453124697Swpaul	r->ndis_arg = arg;
454124697Swpaul	r->ndis_exit = FALSE;
455124697Swpaul	STAILQ_INSERT_TAIL(q, r, link);
456124697Swpaul	mtx_pool_unlock(ndis_mtxpool, ndis_thr_mtx);
457124697Swpaul
458124697Swpaul	/* Post the job. */
459124697Swpaul	kthread_resume(p);
460124697Swpaul
461124697Swpaul	return(0);
462124697Swpaul}
463124697Swpaul
464123474Swpaul__stdcall static void
465124100Swpaulndis_sendrsrcavail_func(adapter)
466124100Swpaul	ndis_handle		adapter;
467124100Swpaul{
468124100Swpaul	return;
469124100Swpaul}
470124100Swpaul
471124100Swpaul__stdcall static void
472123474Swpaulndis_status_func(adapter, status, sbuf, slen)
473123474Swpaul	ndis_handle		adapter;
474123474Swpaul	ndis_status		status;
475123474Swpaul	void			*sbuf;
476123474Swpaul	uint32_t		slen;
477123474Swpaul{
478124060Swpaul	ndis_miniport_block	*block;
479124060Swpaul	block = adapter;
480124060Swpaul
481124409Swpaul	if (block->nmb_ifp->if_flags & IFF_DEBUG)
482124409Swpaul		device_printf (block->nmb_dev, "status: %x\n", status);
483123474Swpaul	return;
484123474Swpaul}
485123474Swpaul
486123474Swpaul__stdcall static void
487123474Swpaulndis_statusdone_func(adapter)
488123474Swpaul	ndis_handle		adapter;
489123474Swpaul{
490124060Swpaul	ndis_miniport_block	*block;
491124060Swpaul	block = adapter;
492124060Swpaul
493124409Swpaul	if (block->nmb_ifp->if_flags & IFF_DEBUG)
494124409Swpaul		device_printf (block->nmb_dev, "status complete\n");
495123474Swpaul	return;
496123474Swpaul}
497123474Swpaul
498123474Swpaul__stdcall static void
499123474Swpaulndis_setdone_func(adapter, status)
500123474Swpaul	ndis_handle		adapter;
501123474Swpaul	ndis_status		status;
502123474Swpaul{
503123695Swpaul	ndis_miniport_block	*block;
504123695Swpaul	block = adapter;
505123695Swpaul
506123695Swpaul	block->nmb_setstat = status;
507123695Swpaul	wakeup(&block->nmb_wkupdpctimer);
508123474Swpaul	return;
509123474Swpaul}
510123474Swpaul
511123474Swpaul__stdcall static void
512123535Swpaulndis_getdone_func(adapter, status)
513123535Swpaul	ndis_handle		adapter;
514123535Swpaul	ndis_status		status;
515123535Swpaul{
516123695Swpaul	ndis_miniport_block	*block;
517123695Swpaul	block = adapter;
518123695Swpaul
519123695Swpaul	block->nmb_getstat = status;
520123695Swpaul	wakeup(&block->nmb_wkupdpctimer);
521123535Swpaul	return;
522123535Swpaul}
523123535Swpaul
524123535Swpaul__stdcall static void
525123474Swpaulndis_resetdone_func(adapter, status, addressingreset)
526123474Swpaul	ndis_handle		adapter;
527123474Swpaul	ndis_status		status;
528123474Swpaul	uint8_t			addressingreset;
529123474Swpaul{
530124060Swpaul	ndis_miniport_block	*block;
531124060Swpaul	block = adapter;
532124060Swpaul
533124409Swpaul	if (block->nmb_ifp->if_flags & IFF_DEBUG)
534124409Swpaul		device_printf (block->nmb_dev, "reset done...\n");
535123474Swpaul	return;
536123474Swpaul}
537123474Swpaul
538123474Swpaul#define NDIS_AM_RID	3
539123474Swpaul
540123474Swpaulint
541123474Swpaulndis_alloc_amem(arg)
542123474Swpaul	void			*arg;
543123474Swpaul{
544123474Swpaul	struct ndis_softc	*sc;
545123474Swpaul	int			error, rid;
546123474Swpaul
547123474Swpaul	if (arg == NULL)
548123474Swpaul		return(EINVAL);
549123474Swpaul
550123474Swpaul	sc = arg;
551123474Swpaul	rid = NDIS_AM_RID;
552123474Swpaul	sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
553123474Swpaul	    &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
554123474Swpaul
555123474Swpaul	if (sc->ndis_res_am == NULL) {
556124060Swpaul		device_printf(sc->ndis_dev,
557124060Swpaul		    "failed to allocate attribute memory\n");
558123474Swpaul		return(ENXIO);
559123474Swpaul	}
560123474Swpaul
561123474Swpaul	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
562123474Swpaul	    sc->ndis_dev, rid, 0, NULL);
563123474Swpaul
564123474Swpaul	if (error) {
565124060Swpaul		device_printf(sc->ndis_dev,
566124060Swpaul		    "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error);
567123474Swpaul		return(error);
568123474Swpaul	}
569123474Swpaul
570123474Swpaul	error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
571123474Swpaul	    sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
572123474Swpaul
573123474Swpaul	if (error) {
574124060Swpaul		device_printf(sc->ndis_dev,
575124060Swpaul		    "CARD_SET_RES_FLAGS() returned 0x%x\n", error);
576123474Swpaul		return(error);
577123474Swpaul	}
578123474Swpaul
579123474Swpaul	return(0);
580123474Swpaul}
581123474Swpaul
582123474Swpaulint
583123474Swpaulndis_create_sysctls(arg)
584123474Swpaul	void			*arg;
585123474Swpaul{
586123474Swpaul	struct ndis_softc	*sc;
587123474Swpaul	ndis_cfg		*vals;
588123474Swpaul	char			buf[256];
589123474Swpaul
590123474Swpaul	if (arg == NULL)
591123474Swpaul		return(EINVAL);
592123474Swpaul
593123474Swpaul	sc = arg;
594123474Swpaul	vals = sc->ndis_regvals;
595123474Swpaul
596123474Swpaul	TAILQ_INIT(&sc->ndis_cfglist_head);
597123474Swpaul
598123474Swpaul	/* Create the sysctl tree. */
599123474Swpaul
600123474Swpaul	sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
601123474Swpaul	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
602123474Swpaul	    device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
603123474Swpaul	    device_get_desc(sc->ndis_dev));
604123474Swpaul
605123474Swpaul	/* Add the driver-specific registry keys. */
606123474Swpaul
607123474Swpaul	vals = sc->ndis_regvals;
608123474Swpaul	while(1) {
609123474Swpaul		if (vals->nc_cfgkey == NULL)
610123474Swpaul			break;
611123620Swpaul		if (vals->nc_idx != sc->ndis_devidx) {
612123620Swpaul			vals++;
613123620Swpaul			continue;
614123620Swpaul		}
615123474Swpaul		SYSCTL_ADD_STRING(&sc->ndis_ctx,
616123474Swpaul		    SYSCTL_CHILDREN(sc->ndis_tree),
617123474Swpaul		    OID_AUTO, vals->nc_cfgkey,
618123474Swpaul		    CTLFLAG_RW, vals->nc_val,
619123474Swpaul		    sizeof(vals->nc_val),
620123474Swpaul		    vals->nc_cfgdesc);
621123474Swpaul		vals++;
622123474Swpaul	}
623123474Swpaul
624123474Swpaul	/* Now add a couple of builtin keys. */
625123474Swpaul
626123474Swpaul	/*
627123474Swpaul	 * Environment can be either Windows (0) or WindowsNT (1).
628123474Swpaul	 * We qualify as the latter.
629123474Swpaul	 */
630123474Swpaul	ndis_add_sysctl(sc, "Environment",
631123474Swpaul	    "Windows environment", "1", CTLFLAG_RD);
632123474Swpaul
633123474Swpaul	/* NDIS version should be 5.1. */
634123474Swpaul	ndis_add_sysctl(sc, "NdisVersion",
635123474Swpaul	    "NDIS API Version", "0x00050001", CTLFLAG_RD);
636123474Swpaul
637123474Swpaul	/* Bus type (PCI, PCMCIA, etc...) */
638124272Swpaul	sprintf(buf, "%d", (int)sc->ndis_iftype);
639123474Swpaul	ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
640123474Swpaul
641123474Swpaul	if (sc->ndis_res_io != NULL) {
642124272Swpaul		sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io));
643123474Swpaul		ndis_add_sysctl(sc, "IOBaseAddress",
644123474Swpaul		    "Base I/O Address", buf, CTLFLAG_RD);
645123474Swpaul	}
646123474Swpaul
647123474Swpaul	if (sc->ndis_irq != NULL) {
648124272Swpaul		sprintf(buf, "%lu", rman_get_start(sc->ndis_irq));
649123474Swpaul		ndis_add_sysctl(sc, "InterruptNumber",
650123474Swpaul		    "Interrupt Number", buf, CTLFLAG_RD);
651123474Swpaul	}
652123474Swpaul
653123474Swpaul	return(0);
654123474Swpaul}
655123474Swpaul
656123474Swpaulint
657123474Swpaulndis_add_sysctl(arg, key, desc, val, flag)
658123474Swpaul	void			*arg;
659123474Swpaul	char			*key;
660123474Swpaul	char			*desc;
661123474Swpaul	char			*val;
662123474Swpaul	int			flag;
663123474Swpaul{
664123474Swpaul	struct ndis_softc	*sc;
665123474Swpaul	struct ndis_cfglist	*cfg;
666123474Swpaul	char			descstr[256];
667123474Swpaul
668123474Swpaul	sc = arg;
669123474Swpaul
670123474Swpaul	cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
671123474Swpaul
672123474Swpaul	if (cfg == NULL)
673123474Swpaul		return(ENOMEM);
674123474Swpaul
675123474Swpaul	cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
676123474Swpaul	if (desc == NULL) {
677123474Swpaul		snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
678123474Swpaul		cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
679123474Swpaul	} else
680123474Swpaul		cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
681123474Swpaul	strcpy(cfg->ndis_cfg.nc_val, val);
682123474Swpaul
683123474Swpaul	TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
684123474Swpaul
685123474Swpaul	SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
686123474Swpaul	    OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
687123474Swpaul	    cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
688123474Swpaul	    cfg->ndis_cfg.nc_cfgdesc);
689123474Swpaul
690123474Swpaul	return(0);
691123474Swpaul}
692123474Swpaul
693123474Swpaulint
694123474Swpaulndis_flush_sysctls(arg)
695123474Swpaul	void			*arg;
696123474Swpaul{
697123474Swpaul	struct ndis_softc	*sc;
698123474Swpaul	struct ndis_cfglist	*cfg;
699123474Swpaul
700123474Swpaul	sc = arg;
701123474Swpaul
702123474Swpaul	while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
703123474Swpaul		cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
704123474Swpaul		TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
705123474Swpaul		free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
706123474Swpaul		free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
707123474Swpaul		free(cfg, M_DEVBUF);
708123474Swpaul	}
709123474Swpaul
710123474Swpaul	return(0);
711123474Swpaul}
712123474Swpaul
713123474Swpaulvoid
714123826Swpaulndis_return_packet(buf, arg)
715123826Swpaul	void			*buf;	/* not used */
716123474Swpaul	void			*arg;
717123474Swpaul{
718123474Swpaul	struct ndis_softc	*sc;
719123474Swpaul	ndis_handle		adapter;
720123535Swpaul	ndis_packet		*p;
721123474Swpaul	__stdcall ndis_return_handler	returnfunc;
722123474Swpaul
723123826Swpaul	if (arg == NULL)
724123474Swpaul		return;
725123474Swpaul
726123826Swpaul	p = arg;
727123535Swpaul
728123535Swpaul	/* Decrement refcount. */
729123826Swpaul	p->np_refcnt--;
730123535Swpaul
731123535Swpaul	/* Release packet when refcount hits zero, otherwise return. */
732123826Swpaul	if (p->np_refcnt)
733123535Swpaul		return;
734123536Swpaul
735123826Swpaul	sc = p->np_softc;
736123474Swpaul	returnfunc = sc->ndis_chars.nmc_return_packet_func;
737123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
738123858Swpaul	if (returnfunc != NULL)
739123826Swpaul		returnfunc(adapter, p);
740123858Swpaul
741123474Swpaul	return;
742123474Swpaul}
743123474Swpaul
744123848Swpaulvoid
745123848Swpaulndis_free_bufs(b0)
746123848Swpaul	ndis_buffer		*b0;
747123848Swpaul{
748123848Swpaul	ndis_buffer		*next;
749123848Swpaul
750123848Swpaul	if (b0 == NULL)
751123848Swpaul		return;
752123848Swpaul
753123848Swpaul	while(b0 != NULL) {
754123848Swpaul		next = b0->nb_next;
755124060Swpaul		uma_zfree (ndis_buffer_zone, b0);
756123848Swpaul		b0 = next;
757123848Swpaul	}
758123848Swpaul
759123848Swpaul	return;
760123848Swpaul}
761123848Swpaul
762123848Swpaulvoid
763123848Swpaulndis_free_packet(p)
764123848Swpaul	ndis_packet		*p;
765123848Swpaul{
766123848Swpaul	if (p == NULL)
767123848Swpaul		return;
768123848Swpaul
769123848Swpaul	ndis_free_bufs(p->np_private.npp_head);
770124060Swpaul	uma_zfree(ndis_packet_zone, p);
771123848Swpaul
772123848Swpaul	return;
773123848Swpaul}
774123848Swpaul
775123474Swpaulint
776123474Swpaulndis_convert_res(arg)
777123474Swpaul	void			*arg;
778123474Swpaul{
779123474Swpaul	struct ndis_softc	*sc;
780123474Swpaul	ndis_resource_list	*rl = NULL;
781123474Swpaul	cm_partial_resource_desc	*prd = NULL;
782123474Swpaul	ndis_miniport_block	*block;
783123976Swpaul	device_t		dev;
784123976Swpaul	struct resource_list	*brl;
785123976Swpaul	struct resource_list_entry	*brle;
786123474Swpaul
787123474Swpaul	sc = arg;
788123474Swpaul	block = &sc->ndis_block;
789123976Swpaul	dev = sc->ndis_dev;
790123474Swpaul
791123474Swpaul	rl = malloc(sizeof(ndis_resource_list) +
792123474Swpaul	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
793123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
794123474Swpaul
795123474Swpaul	if (rl == NULL)
796123474Swpaul		return(ENOMEM);
797123474Swpaul
798123474Swpaul	rl->cprl_version = 5;
799123474Swpaul	rl->cprl_version = 1;
800123474Swpaul	rl->cprl_count = sc->ndis_rescnt;
801123474Swpaul	prd = rl->cprl_partial_descs;
802123474Swpaul
803123976Swpaul	brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
804123976Swpaul	if (brl != NULL) {
805123976Swpaul		SLIST_FOREACH(brle, brl, link) {
806123976Swpaul			switch (brle->type) {
807123976Swpaul			case SYS_RES_IOPORT:
808123976Swpaul				prd->cprd_type = CmResourceTypePort;
809123976Swpaul				prd->u.cprd_port.cprd_start.np_quad =
810123976Swpaul				    brle->start;
811123976Swpaul				prd->u.cprd_port.cprd_len = brle->count;
812123976Swpaul				break;
813123976Swpaul			case SYS_RES_MEMORY:
814123976Swpaul				prd->cprd_type = CmResourceTypeMemory;
815123976Swpaul				prd->u.cprd_port.cprd_start.np_quad =
816123976Swpaul				    brle->start;
817123976Swpaul				prd->u.cprd_port.cprd_len = brle->count;
818123976Swpaul				break;
819123976Swpaul			case SYS_RES_IRQ:
820123976Swpaul				prd->cprd_type = CmResourceTypeInterrupt;
821123976Swpaul				prd->u.cprd_intr.cprd_level = brle->start;
822123976Swpaul				prd->u.cprd_intr.cprd_vector = brle->start;
823123976Swpaul				prd->u.cprd_intr.cprd_affinity = 0;
824123976Swpaul				break;
825123976Swpaul			default:
826123976Swpaul				break;
827123976Swpaul			}
828123976Swpaul			prd++;
829123976Swpaul		}
830123474Swpaul	}
831123474Swpaul
832123474Swpaul	block->nmb_rlist = rl;
833123474Swpaul
834123474Swpaul	return(0);
835123474Swpaul}
836123474Swpaul
837123474Swpaul/*
838123474Swpaul * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
839123474Swpaul * packet, it will hand it to us in the form of an ndis_packet,
840123474Swpaul * which we need to convert to an mbuf that is then handed off
841123474Swpaul * to the stack. Note: we configure the mbuf list so that it uses
842123474Swpaul * the memory regions specified by the ndis_buffer structures in
843123474Swpaul * the ndis_packet as external storage. In most cases, this will
844123474Swpaul * point to a memory region allocated by the driver (either by
845123474Swpaul * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
846123474Swpaul * the driver to handle free()ing this region for is, so we set up
847123474Swpaul * a dummy no-op free handler for it.
848123474Swpaul */
849123474Swpaul
850123474Swpaulint
851123474Swpaulndis_ptom(m0, p)
852123474Swpaul	struct mbuf		**m0;
853123474Swpaul	ndis_packet		*p;
854123474Swpaul{
855123474Swpaul	struct mbuf		*m, *prev = NULL;
856123474Swpaul	ndis_buffer		*buf;
857123474Swpaul	ndis_packet_private	*priv;
858123474Swpaul	uint32_t		totlen = 0;
859123474Swpaul
860123474Swpaul	if (p == NULL || m0 == NULL)
861123474Swpaul		return(EINVAL);
862123474Swpaul
863123474Swpaul	priv = &p->np_private;
864123474Swpaul	buf = priv->npp_head;
865123826Swpaul	p->np_refcnt = 0;
866123474Swpaul
867123474Swpaul	for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
868123474Swpaul		if (buf == priv->npp_head)
869123474Swpaul			MGETHDR(m, M_DONTWAIT, MT_HEADER);
870123474Swpaul		else
871123474Swpaul			MGET(m, M_DONTWAIT, MT_DATA);
872123474Swpaul		if (m == NULL) {
873123474Swpaul			m_freem(*m0);
874123474Swpaul			*m0 = NULL;
875123474Swpaul			return(ENOBUFS);
876123474Swpaul		}
877123757Swpaul		m->m_len = buf->nb_bytecount;
878123757Swpaul		m->m_data = MDL_VA(buf);
879123535Swpaul		MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
880123826Swpaul		    p, 0, EXT_NDIS);
881123826Swpaul		p->np_refcnt++;
882123474Swpaul		totlen += m->m_len;
883123474Swpaul		if (m->m_flags & MT_HEADER)
884123474Swpaul			*m0 = m;
885123474Swpaul		else
886123474Swpaul			prev->m_next = m;
887123474Swpaul		prev = m;
888123474Swpaul	}
889123474Swpaul
890123474Swpaul	(*m0)->m_pkthdr.len = totlen;
891123474Swpaul
892123474Swpaul	return(0);
893123474Swpaul}
894123474Swpaul
895123474Swpaul/*
896123474Swpaul * Create an mbuf chain from an NDIS packet chain.
897123474Swpaul * This is used mainly when transmitting packets, where we need
898123474Swpaul * to turn an mbuf off an interface's send queue and transform it
899123474Swpaul * into an NDIS packet which will be fed into the NDIS driver's
900123474Swpaul * send routine.
901123474Swpaul *
902123474Swpaul * NDIS packets consist of two parts: an ndis_packet structure,
903123474Swpaul * which is vaguely analagous to the pkthdr portion of an mbuf,
904123474Swpaul * and one or more ndis_buffer structures, which define the
905123474Swpaul * actual memory segments in which the packet data resides.
906123474Swpaul * We need to allocate one ndis_buffer for each mbuf in a chain,
907123474Swpaul * plus one ndis_packet as the header.
908123474Swpaul */
909123474Swpaul
910123474Swpaulint
911123474Swpaulndis_mtop(m0, p)
912123474Swpaul	struct mbuf		*m0;
913123474Swpaul	ndis_packet		**p;
914123474Swpaul{
915123474Swpaul	struct mbuf		*m;
916123474Swpaul	ndis_buffer		*buf = NULL, *prev = NULL;
917123474Swpaul	ndis_packet_private	*priv;
918123474Swpaul
919123474Swpaul	if (p == NULL || m0 == NULL)
920123474Swpaul		return(EINVAL);
921123474Swpaul
922123474Swpaul	/* If caller didn't supply a packet, make one. */
923123474Swpaul	if (*p == NULL) {
924124060Swpaul		*p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO);
925123474Swpaul
926123474Swpaul		if (*p == NULL)
927123474Swpaul			return(ENOMEM);
928123474Swpaul	}
929123474Swpaul
930123474Swpaul	priv = &(*p)->np_private;
931123474Swpaul	priv->npp_totlen = m0->m_pkthdr.len;
932123474Swpaul        priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
933124278Swpaul	priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
934123474Swpaul
935123474Swpaul	for (m = m0; m != NULL; m = m->m_next) {
936123810Salfred		if (m->m_len == 0)
937123474Swpaul			continue;
938124060Swpaul		buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO);
939123474Swpaul		if (buf == NULL) {
940123474Swpaul			ndis_free_packet(*p);
941123474Swpaul			*p = NULL;
942123474Swpaul			return(ENOMEM);
943123474Swpaul		}
944123474Swpaul
945123757Swpaul		MDL_INIT(buf, m->m_data, m->m_len);
946123474Swpaul		if (priv->npp_head == NULL)
947123474Swpaul			priv->npp_head = buf;
948123474Swpaul		else
949123474Swpaul			prev->nb_next = buf;
950123474Swpaul		prev = buf;
951123474Swpaul	}
952123474Swpaul
953123474Swpaul	priv->npp_tail = buf;
954124060Swpaul	priv->npp_totlen = m0->m_pkthdr.len;
955123474Swpaul
956123474Swpaul	return(0);
957123474Swpaul}
958123474Swpaul
959123474Swpaulint
960123474Swpaulndis_get_supported_oids(arg, oids, oidcnt)
961123474Swpaul	void			*arg;
962123474Swpaul	ndis_oid		**oids;
963123474Swpaul	int			*oidcnt;
964123474Swpaul{
965123474Swpaul	int			len, rval;
966123474Swpaul	ndis_oid		*o;
967123474Swpaul
968123474Swpaul	if (arg == NULL || oids == NULL || oidcnt == NULL)
969123474Swpaul		return(EINVAL);
970123474Swpaul	len = 0;
971123474Swpaul	ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
972123474Swpaul
973123474Swpaul	o = malloc(len, M_DEVBUF, M_NOWAIT);
974123474Swpaul	if (o == NULL)
975123474Swpaul		return(ENOMEM);
976123474Swpaul
977123474Swpaul	rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
978123474Swpaul
979123474Swpaul	if (rval) {
980123474Swpaul		free(o, M_DEVBUF);
981123474Swpaul		return(rval);
982123474Swpaul	}
983123474Swpaul
984123474Swpaul	*oids = o;
985123474Swpaul	*oidcnt = len / 4;
986123474Swpaul
987123474Swpaul	return(0);
988123474Swpaul}
989123474Swpaul
990123474Swpaulint
991123474Swpaulndis_set_info(arg, oid, buf, buflen)
992123474Swpaul	void			*arg;
993123474Swpaul	ndis_oid		oid;
994123474Swpaul	void			*buf;
995123474Swpaul	int			*buflen;
996123474Swpaul{
997123474Swpaul	struct ndis_softc	*sc;
998123474Swpaul	ndis_status		rval;
999123474Swpaul	ndis_handle		adapter;
1000123474Swpaul	__stdcall ndis_setinfo_handler	setfunc;
1001123474Swpaul	uint32_t		byteswritten = 0, bytesneeded = 0;
1002123695Swpaul	struct timeval		tv;
1003123695Swpaul	int			error;
1004123474Swpaul
1005123474Swpaul	sc = arg;
1006123474Swpaul	setfunc = sc->ndis_chars.nmc_setinfo_func;
1007123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1008123474Swpaul
1009123474Swpaul	rval = setfunc(adapter, oid, buf, *buflen,
1010123474Swpaul	    &byteswritten, &bytesneeded);
1011123474Swpaul
1012123695Swpaul	if (rval == NDIS_STATUS_PENDING) {
1013123695Swpaul		tv.tv_sec = 60;
1014123695Swpaul		tv.tv_usec = 0;
1015123695Swpaul		error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
1016123757Swpaul		    PPAUSE|PCATCH, "ndisset", tvtohz(&tv));
1017123695Swpaul		rval = sc->ndis_block.nmb_setstat;
1018123695Swpaul	}
1019123695Swpaul
1020123474Swpaul	if (byteswritten)
1021123474Swpaul		*buflen = byteswritten;
1022123474Swpaul	if (bytesneeded)
1023123474Swpaul		*buflen = bytesneeded;
1024123474Swpaul
1025123474Swpaul	if (rval == NDIS_STATUS_INVALID_LENGTH)
1026123474Swpaul		return(ENOSPC);
1027123474Swpaul
1028123474Swpaul	if (rval == NDIS_STATUS_INVALID_OID)
1029123474Swpaul		return(EINVAL);
1030123474Swpaul
1031123474Swpaul	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1032123474Swpaul	    rval == NDIS_STATUS_NOT_ACCEPTED)
1033123474Swpaul		return(ENOTSUP);
1034123474Swpaul
1035123474Swpaul	return(0);
1036123474Swpaul}
1037123474Swpaul
1038124202Swpaultypedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
1039124202Swpaul
1040123474Swpaulint
1041123474Swpaulndis_send_packets(arg, packets, cnt)
1042123474Swpaul	void			*arg;
1043123474Swpaul	ndis_packet		**packets;
1044123474Swpaul	int			cnt;
1045123474Swpaul{
1046123474Swpaul	struct ndis_softc	*sc;
1047123474Swpaul	ndis_handle		adapter;
1048123474Swpaul	__stdcall ndis_sendmulti_handler	sendfunc;
1049124202Swpaul	__stdcall ndis_senddone_func		senddonefunc;
1050124202Swpaul	int			i;
1051123858Swpaul	ndis_packet		*p;
1052123474Swpaul
1053123474Swpaul	sc = arg;
1054123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1055123474Swpaul	sendfunc = sc->ndis_chars.nmc_sendmulti_func;
1056124202Swpaul	senddonefunc = sc->ndis_block.nmb_senddone_func;
1057123474Swpaul	sendfunc(adapter, packets, cnt);
1058123474Swpaul
1059123858Swpaul	for (i = 0; i < cnt; i++) {
1060123858Swpaul		p = packets[i];
1061124005Swpaul		/*
1062124005Swpaul		 * Either the driver already handed the packet to
1063124005Swpaul		 * ndis_txeof() due to a failure, or it wants to keep
1064124005Swpaul		 * it and release it asynchronously later. Skip to the
1065124005Swpaul		 * next one.
1066124005Swpaul		 */
1067124005Swpaul		if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
1068123858Swpaul			continue;
1069124202Swpaul		senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status);
1070123858Swpaul	}
1071123858Swpaul
1072123474Swpaul	return(0);
1073123474Swpaul}
1074123474Swpaul
1075123474Swpaulint
1076123474Swpaulndis_init_dma(arg)
1077123474Swpaul	void			*arg;
1078123474Swpaul{
1079123474Swpaul	struct ndis_softc	*sc;
1080123474Swpaul	int			i, error;
1081123474Swpaul
1082123474Swpaul	sc = arg;
1083123474Swpaul
1084123474Swpaul	sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
1085123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
1086123474Swpaul
1087123474Swpaul	if (sc->ndis_tmaps == NULL)
1088123474Swpaul		return(ENOMEM);
1089123474Swpaul
1090123474Swpaul	for (i = 0; i < sc->ndis_maxpkts; i++) {
1091123474Swpaul		error = bus_dmamap_create(sc->ndis_ttag, 0,
1092123474Swpaul		    &sc->ndis_tmaps[i]);
1093123474Swpaul		if (error) {
1094123474Swpaul			free(sc->ndis_tmaps, M_DEVBUF);
1095123474Swpaul			return(ENODEV);
1096123474Swpaul		}
1097123474Swpaul	}
1098123474Swpaul
1099123474Swpaul	return(0);
1100123474Swpaul}
1101123474Swpaul
1102123474Swpaulint
1103123474Swpaulndis_destroy_dma(arg)
1104123474Swpaul	void			*arg;
1105123474Swpaul{
1106123474Swpaul	struct ndis_softc	*sc;
1107123535Swpaul	struct mbuf		*m;
1108123535Swpaul	ndis_packet		*p = NULL;
1109123474Swpaul	int			i;
1110123474Swpaul
1111123474Swpaul	sc = arg;
1112123474Swpaul
1113123474Swpaul	for (i = 0; i < sc->ndis_maxpkts; i++) {
1114123535Swpaul		if (sc->ndis_txarray[i] != NULL) {
1115123535Swpaul			p = sc->ndis_txarray[i];
1116123535Swpaul			m = (struct mbuf *)p->np_rsvd[1];
1117123535Swpaul			if (m != NULL)
1118123535Swpaul				m_freem(m);
1119123535Swpaul			ndis_free_packet(sc->ndis_txarray[i]);
1120123535Swpaul		}
1121123474Swpaul		bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
1122123474Swpaul	}
1123123474Swpaul
1124123474Swpaul	free(sc->ndis_tmaps, M_DEVBUF);
1125123474Swpaul
1126123474Swpaul	bus_dma_tag_destroy(sc->ndis_ttag);
1127123474Swpaul
1128123474Swpaul	return(0);
1129123474Swpaul}
1130123474Swpaul
1131123474Swpaulint
1132123474Swpaulndis_reset_nic(arg)
1133123474Swpaul	void			*arg;
1134123474Swpaul{
1135123474Swpaul	struct ndis_softc	*sc;
1136123474Swpaul	ndis_handle		adapter;
1137123474Swpaul	__stdcall ndis_reset_handler	resetfunc;
1138123474Swpaul	uint8_t			addressing_reset;
1139123474Swpaul	struct ifnet		*ifp;
1140123474Swpaul
1141123474Swpaul	sc = arg;
1142123474Swpaul	ifp = &sc->arpcom.ac_if;
1143123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1144123474Swpaul	if (adapter == NULL)
1145123474Swpaul		return(EIO);
1146123474Swpaul	resetfunc = sc->ndis_chars.nmc_reset_func;
1147123474Swpaul
1148123474Swpaul	if (resetfunc == NULL)
1149123474Swpaul		return(EINVAL);
1150123474Swpaul
1151123474Swpaul	resetfunc(&addressing_reset, adapter);
1152123474Swpaul
1153123474Swpaul	return(0);
1154123474Swpaul}
1155123474Swpaul
1156123474Swpaulint
1157123474Swpaulndis_halt_nic(arg)
1158123474Swpaul	void			*arg;
1159123474Swpaul{
1160123474Swpaul	struct ndis_softc	*sc;
1161123474Swpaul	ndis_handle		adapter;
1162123474Swpaul	__stdcall ndis_halt_handler	haltfunc;
1163123474Swpaul	struct ifnet		*ifp;
1164123821Swpaul	struct ndis_timer_entry	*ne;
1165123474Swpaul
1166123474Swpaul	sc = arg;
1167123474Swpaul	ifp = &sc->arpcom.ac_if;
1168123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1169123474Swpaul	if (adapter == NULL)
1170123474Swpaul		return(EIO);
1171123821Swpaul
1172123474Swpaul	haltfunc = sc->ndis_chars.nmc_halt_func;
1173123474Swpaul
1174123474Swpaul	if (haltfunc == NULL)
1175123474Swpaul		return(EINVAL);
1176123474Swpaul
1177123474Swpaul	haltfunc(adapter);
1178123474Swpaul
1179123474Swpaul	/*
1180123474Swpaul	 * The adapter context is only valid after the init
1181123474Swpaul	 * handler has been called, and is invalid once the
1182123474Swpaul	 * halt handler has been called.
1183123474Swpaul	 */
1184123474Swpaul
1185123474Swpaul	sc->ndis_block.nmb_miniportadapterctx = NULL;
1186123474Swpaul
1187123821Swpaul	/* Clobber all the timers in case the driver left one running. */
1188123821Swpaul
1189123821Swpaul	while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) {
1190123821Swpaul		ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist);
1191123821Swpaul		TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link);
1192123832Swpaul		callout_stop(&ne->nte_ch);
1193123821Swpaul		free(ne, M_DEVBUF);
1194123821Swpaul	}
1195123821Swpaul
1196123474Swpaul	return(0);
1197123474Swpaul}
1198123474Swpaul
1199123474Swpaulint
1200123474Swpaulndis_shutdown_nic(arg)
1201123474Swpaul	void			*arg;
1202123474Swpaul{
1203123474Swpaul	struct ndis_softc	*sc;
1204123474Swpaul	ndis_handle		adapter;
1205123474Swpaul	__stdcall ndis_shutdown_handler	shutdownfunc;
1206123474Swpaul
1207123474Swpaul
1208123474Swpaul	sc = arg;
1209123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1210123474Swpaul	if (adapter == NULL)
1211123474Swpaul		return(EIO);
1212123474Swpaul	shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
1213123474Swpaul
1214123474Swpaul	if (shutdownfunc == NULL)
1215123474Swpaul		return(EINVAL);
1216123474Swpaul
1217123485Swpaul	if (sc->ndis_chars.nmc_rsvd0 == NULL)
1218123485Swpaul		shutdownfunc(adapter);
1219123485Swpaul	else
1220123485Swpaul		shutdownfunc(sc->ndis_chars.nmc_rsvd0);
1221123474Swpaul
1222123474Swpaul	return(0);
1223123474Swpaul}
1224123474Swpaul
1225123474Swpaulint
1226123474Swpaulndis_init_nic(arg)
1227123474Swpaul	void			*arg;
1228123474Swpaul{
1229123474Swpaul	struct ndis_softc	*sc;
1230123474Swpaul	ndis_miniport_block	*block;
1231123474Swpaul        __stdcall ndis_init_handler	initfunc;
1232123474Swpaul	ndis_status		status, openstatus = 0;
1233123474Swpaul	ndis_medium		mediumarray[NdisMediumMax];
1234123474Swpaul	uint32_t		chosenmedium, i;
1235123474Swpaul
1236123474Swpaul	if (arg == NULL)
1237123474Swpaul		return(EINVAL);
1238123474Swpaul
1239123474Swpaul	sc = arg;
1240123474Swpaul	block = &sc->ndis_block;
1241123474Swpaul	initfunc = sc->ndis_chars.nmc_init_func;
1242123474Swpaul
1243123821Swpaul	TAILQ_INIT(&block->nmb_timerlist);
1244123821Swpaul
1245123474Swpaul	for (i = 0; i < NdisMediumMax; i++)
1246123474Swpaul		mediumarray[i] = i;
1247123474Swpaul
1248123474Swpaul        status = initfunc(&openstatus, &chosenmedium,
1249123474Swpaul            mediumarray, NdisMediumMax, block, block);
1250123474Swpaul
1251123474Swpaul	/*
1252123474Swpaul	 * If the init fails, blow away the other exported routines
1253123474Swpaul	 * we obtained from the driver so we can't call them later.
1254123474Swpaul	 * If the init failed, none of these will work.
1255123474Swpaul	 */
1256123474Swpaul	if (status != NDIS_STATUS_SUCCESS) {
1257123474Swpaul		bzero((char *)&sc->ndis_chars,
1258123474Swpaul		    sizeof(ndis_miniport_characteristics));
1259123474Swpaul		return(ENXIO);
1260123474Swpaul	}
1261123474Swpaul
1262123474Swpaul	return(0);
1263123474Swpaul}
1264123474Swpaul
1265123474Swpaulvoid
1266123474Swpaulndis_enable_intr(arg)
1267123474Swpaul	void			*arg;
1268123474Swpaul{
1269123474Swpaul	struct ndis_softc	*sc;
1270123474Swpaul	ndis_handle		adapter;
1271123474Swpaul	__stdcall ndis_enable_interrupts_handler	intrenbfunc;
1272123474Swpaul
1273123474Swpaul	sc = arg;
1274123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1275123474Swpaul	if (adapter == NULL)
1276123474Swpaul	    return;
1277123474Swpaul	intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
1278123474Swpaul	if (intrenbfunc == NULL)
1279123474Swpaul		return;
1280123474Swpaul	intrenbfunc(adapter);
1281123474Swpaul
1282123474Swpaul	return;
1283123474Swpaul}
1284123474Swpaul
1285123474Swpaulvoid
1286123474Swpaulndis_disable_intr(arg)
1287123474Swpaul	void			*arg;
1288123474Swpaul{
1289123474Swpaul	struct ndis_softc	*sc;
1290123474Swpaul	ndis_handle		adapter;
1291123474Swpaul	__stdcall ndis_disable_interrupts_handler	intrdisfunc;
1292123474Swpaul
1293123474Swpaul	sc = arg;
1294123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1295123474Swpaul	if (adapter == NULL)
1296123474Swpaul	    return;
1297123474Swpaul	intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
1298123474Swpaul	if (intrdisfunc == NULL)
1299123474Swpaul		return;
1300123474Swpaul	intrdisfunc(adapter);
1301123474Swpaul
1302123474Swpaul	return;
1303123474Swpaul}
1304123474Swpaul
1305123474Swpaulint
1306123474Swpaulndis_isr(arg, ourintr, callhandler)
1307123474Swpaul	void			*arg;
1308123474Swpaul	int			*ourintr;
1309123474Swpaul	int			*callhandler;
1310123474Swpaul{
1311123474Swpaul	struct ndis_softc	*sc;
1312123474Swpaul	ndis_handle		adapter;
1313123474Swpaul	__stdcall ndis_isr_handler	isrfunc;
1314123474Swpaul	uint8_t			accepted, queue;
1315123474Swpaul
1316123474Swpaul	if (arg == NULL || ourintr == NULL || callhandler == NULL)
1317123474Swpaul		return(EINVAL);
1318123474Swpaul
1319123474Swpaul	sc = arg;
1320123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1321123474Swpaul	isrfunc = sc->ndis_chars.nmc_isr_func;
1322123474Swpaul	isrfunc(&accepted, &queue, adapter);
1323123474Swpaul	*ourintr = accepted;
1324123474Swpaul	*callhandler = queue;
1325123474Swpaul
1326123474Swpaul	return(0);
1327123474Swpaul}
1328123474Swpaul
1329123474Swpaulint
1330123474Swpaulndis_intrhand(arg)
1331123474Swpaul	void			*arg;
1332123474Swpaul{
1333123474Swpaul	struct ndis_softc	*sc;
1334123474Swpaul	ndis_handle		adapter;
1335123474Swpaul	__stdcall ndis_interrupt_handler	intrfunc;
1336123474Swpaul
1337123474Swpaul	if (arg == NULL)
1338123474Swpaul		return(EINVAL);
1339123474Swpaul
1340123474Swpaul	sc = arg;
1341123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1342123474Swpaul	intrfunc = sc->ndis_chars.nmc_interrupt_func;
1343123474Swpaul	intrfunc(adapter);
1344123474Swpaul
1345123474Swpaul	return(0);
1346123474Swpaul}
1347123474Swpaul
1348123474Swpaulint
1349123474Swpaulndis_get_info(arg, oid, buf, buflen)
1350123474Swpaul	void			*arg;
1351123474Swpaul	ndis_oid		oid;
1352123474Swpaul	void			*buf;
1353123474Swpaul	int			*buflen;
1354123474Swpaul{
1355123474Swpaul	struct ndis_softc	*sc;
1356123474Swpaul	ndis_status		rval;
1357123474Swpaul	ndis_handle		adapter;
1358123474Swpaul	__stdcall ndis_queryinfo_handler	queryfunc;
1359123474Swpaul	uint32_t		byteswritten = 0, bytesneeded = 0;
1360123695Swpaul	struct timeval		tv;
1361123695Swpaul	int			error;
1362123474Swpaul
1363123474Swpaul	sc = arg;
1364123474Swpaul	queryfunc = sc->ndis_chars.nmc_queryinfo_func;
1365123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
1366123474Swpaul
1367123474Swpaul	rval = queryfunc(adapter, oid, buf, *buflen,
1368123474Swpaul	    &byteswritten, &bytesneeded);
1369123474Swpaul
1370123695Swpaul	/* Wait for requests that block. */
1371123695Swpaul
1372123695Swpaul	if (rval == NDIS_STATUS_PENDING) {
1373123695Swpaul		tv.tv_sec = 60;
1374123695Swpaul		tv.tv_usec = 0;
1375123695Swpaul		error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
1376123757Swpaul		    PPAUSE|PCATCH, "ndisget", tvtohz(&tv));
1377123695Swpaul		rval = sc->ndis_block.nmb_getstat;
1378123695Swpaul	}
1379123695Swpaul
1380123474Swpaul	if (byteswritten)
1381123474Swpaul		*buflen = byteswritten;
1382123474Swpaul	if (bytesneeded)
1383123474Swpaul		*buflen = bytesneeded;
1384123474Swpaul
1385123474Swpaul	if (rval == NDIS_STATUS_INVALID_LENGTH ||
1386123474Swpaul	    rval == NDIS_STATUS_BUFFER_TOO_SHORT)
1387123474Swpaul		return(ENOSPC);
1388123474Swpaul
1389123474Swpaul	if (rval == NDIS_STATUS_INVALID_OID)
1390123474Swpaul		return(EINVAL);
1391123474Swpaul
1392123474Swpaul	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1393123474Swpaul	    rval == NDIS_STATUS_NOT_ACCEPTED)
1394123474Swpaul		return(ENOTSUP);
1395123474Swpaul
1396123474Swpaul	return(0);
1397123474Swpaul}
1398123474Swpaul
1399123474Swpaulint
1400123474Swpaulndis_unload_driver(arg)
1401123474Swpaul	void			*arg;
1402123474Swpaul{
1403123474Swpaul	struct ndis_softc	*sc;
1404123474Swpaul
1405123474Swpaul	sc = arg;
1406123474Swpaul
1407123474Swpaul	free(sc->ndis_block.nmb_rlist, M_DEVBUF);
1408123474Swpaul
1409123474Swpaul	ndis_flush_sysctls(sc);
1410123474Swpaul
1411124697Swpaul	ndis_shrink_thrqueue(8);
1412124697Swpaul
1413123474Swpaul	return(0);
1414123474Swpaul}
1415123474Swpaul
1416124446Swpaul#define NDIS_LOADED		0x42534F44
1417124446Swpaul
1418123474Swpaulint
1419123474Swpaulndis_load_driver(img, arg)
1420123474Swpaul	vm_offset_t		img;
1421123474Swpaul	void			*arg;
1422123474Swpaul{
1423123474Swpaul	__stdcall driver_entry	entry;
1424123474Swpaul	image_optional_header	opt_hdr;
1425123474Swpaul	image_import_descriptor imp_desc;
1426123474Swpaul	ndis_unicode_string	dummystr;
1427123474Swpaul	ndis_driver_object	drv;
1428123474Swpaul        ndis_miniport_block     *block;
1429123474Swpaul	ndis_status		status;
1430123474Swpaul	int			idx;
1431123474Swpaul	uint32_t		*ptr;
1432123474Swpaul	struct ndis_softc	*sc;
1433123474Swpaul
1434123474Swpaul	sc = arg;
1435123474Swpaul
1436124446Swpaul	/*
1437124446Swpaul	 * Only perform the relocation/linking phase once
1438124446Swpaul	 * since the binary image may be shared among multiple
1439124446Swpaul	 * device instances.
1440124446Swpaul	 */
1441123474Swpaul
1442124446Swpaul	ptr = (uint32_t *)(img + 8);
1443124446Swpaul	if (*ptr != NDIS_LOADED) {
1444124446Swpaul		/* Perform text relocation */
1445124446Swpaul		if (pe_relocate(img))
1446124446Swpaul			return(ENOEXEC);
1447123474Swpaul
1448124446Swpaul		/* Dynamically link the NDIS.SYS routines -- required. */
1449124446Swpaul		if (pe_patch_imports(img, "NDIS", ndis_functbl))
1450124446Swpaul			return(ENOEXEC);
1451123474Swpaul
1452124446Swpaul		/* Dynamically link the HAL.dll routines -- also required. */
1453124446Swpaul		if (pe_patch_imports(img, "HAL", hal_functbl))
1454123474Swpaul			return(ENOEXEC);
1455124446Swpaul
1456124446Swpaul		/* Dynamically link ntoskrnl.exe -- optional. */
1457124446Swpaul		if (pe_get_import_descriptor(img,
1458124446Swpaul		    &imp_desc, "ntoskrnl") == 0) {
1459124446Swpaul			if (pe_patch_imports(img,
1460124446Swpaul			    "ntoskrnl", ntoskrnl_functbl))
1461124446Swpaul				return(ENOEXEC);
1462124446Swpaul		}
1463124446Swpaul		*ptr = NDIS_LOADED;
1464123474Swpaul	}
1465123474Swpaul
1466123474Swpaul        /* Locate the driver entry point */
1467123474Swpaul	pe_get_optional_header(img, &opt_hdr);
1468123474Swpaul	entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
1469123474Swpaul
1470123474Swpaul	/*
1471123474Swpaul	 * Now call the DriverEntry() routine. This will cause
1472123474Swpaul	 * a callout to the NdisInitializeWrapper() and
1473123474Swpaul	 * NdisMRegisterMiniport() routines.
1474123474Swpaul	 */
1475123474Swpaul	dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
1476123474Swpaul	dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
1477123474Swpaul	dummystr.nus_buf = NULL;
1478123474Swpaul	ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
1479123474Swpaul	drv.ndo_ifname = "ndis0";
1480123474Swpaul
1481123474Swpaul	status = entry(&drv, &dummystr);
1482123474Swpaul
1483123474Swpaul	free (dummystr.nus_buf, M_DEVBUF);
1484123474Swpaul
1485123474Swpaul	if (status != NDIS_STATUS_SUCCESS)
1486123474Swpaul		return(ENODEV);
1487123474Swpaul
1488123474Swpaul	/*
1489123474Swpaul	 * Now that we have the miniport driver characteristics,
1490123474Swpaul	 * create an NDIS block and call the init handler.
1491123474Swpaul	 * This will cause the driver to try to probe for
1492123474Swpaul	 * a device.
1493123474Swpaul	 */
1494123474Swpaul
1495123474Swpaul	block = &sc->ndis_block;
1496123474Swpaul	bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
1497123474Swpaul	    sizeof(ndis_miniport_characteristics));
1498123474Swpaul
1499123474Swpaul	/*block->nmb_signature = 0xcafebabe;*/
1500123474Swpaul
1501123474Swpaul		ptr = (uint32_t *)block;
1502123474Swpaul	for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
1503123474Swpaul		*ptr = idx | 0xdead0000;
1504123474Swpaul		ptr++;
1505123474Swpaul	}
1506123474Swpaul
1507123474Swpaul	block->nmb_signature = (void *)0xcafebabe;
1508123474Swpaul	block->nmb_setdone_func = ndis_setdone_func;
1509123535Swpaul	block->nmb_querydone_func = ndis_getdone_func;
1510123474Swpaul	block->nmb_status_func = ndis_status_func;
1511123474Swpaul	block->nmb_statusdone_func = ndis_statusdone_func;
1512123474Swpaul	block->nmb_resetdone_func = ndis_resetdone_func;
1513124100Swpaul	block->nmb_sendrsrc_func = ndis_sendrsrcavail_func;
1514123474Swpaul
1515123474Swpaul	block->nmb_ifp = &sc->arpcom.ac_if;
1516123474Swpaul	block->nmb_dev = sc->ndis_dev;
1517124165Swpaul	block->nmb_img = img;
1518123474Swpaul
1519124697Swpaul	ndis_enlarge_thrqueue(8);
1520124697Swpaul
1521123474Swpaul	return(0);
1522123474Swpaul}
1523