1 /*	$NetBSD: kern_ndis.c,v 1.26 2014/03/25 16:23:58 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2003
5  *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifdef __FreeBSD__
37 __FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.60.2.5 2005/04/01 17:14:20 wpaul Exp $");
38 #endif
39 #ifdef __NetBSD__
40 __KERNEL_RCSID(0, "$NetBSD: kern_ndis.c,v 1.26 2014/03/25 16:23:58 christos Exp $");
41 #endif
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/unistd.h>
46 #include <sys/types.h>
47 #include <sys/errno.h>
48 #include <sys/callout.h>
49 #include <sys/socket.h>
50 #include <sys/queue.h>
51 #include <sys/sysctl.h>
52 #include <sys/proc.h>
53 #include <sys/malloc.h>
54 #include <sys/lock.h>
55 #include <sys/mutex.h>
56 #include <sys/conf.h>
57 
58 #include <sys/kernel.h>
59 #include <sys/module.h>
60 #include <sys/mbuf.h>
61 #include <sys/kthread.h>
62 #include <sys/bus.h>
63 #ifdef __FreeBSD__
64 #include <machine/resource.h>
65 #include <sys/rman.h>
66 #endif
67 
68 #ifdef __NetBSD__
69 #include <dev/pci/pcivar.h>
70 #include <dev/pci/pcireg.h>
71 #endif
72 
73 #include <net/if.h>
74 #include <net/if_arp.h>
75 #ifdef __FreeBSD__
76 #include <net/ethernet.h>
77 #else
78 #include <net/if_ether.h>
79 #endif
80 #include <net/if_dl.h>
81 #include <net/if_media.h>
82 
83 #include <net80211/ieee80211_var.h>
84 #include <net80211/ieee80211_ioctl.h>
85 
86 #include <compat/ndis/pe_var.h>
87 #include <compat/ndis/resource_var.h>
88 #include <compat/ndis/ntoskrnl_var.h>
89 #include <compat/ndis/ndis_var.h>
90 #include <compat/ndis/hal_var.h>
91 #include <compat/ndis/cfg_var.h>
92 #include <compat/ndis/usbd_var.h>
93 #include <dev/if_ndis/if_ndisvar.h>
94 
95 MODULE(MODULE_CLASS_EXEC, ndis, NULL);
96 
97 #define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
98 
99 __stdcall static void ndis_status_func(ndis_handle, ndis_status,
100 	void *, uint32_t);
101 __stdcall static void ndis_statusdone_func(ndis_handle);
102 __stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
103 __stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
104 __stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
105 __stdcall static void ndis_sendrsrcavail_func(ndis_handle);
106 __stdcall static void ndis_intrhand(kdpc *, device_object *,
107 	irp *, struct ndis_softc *);
108 
109 static image_patch_table kernndis_functbl[] = {
110 	IMPORT_FUNC(ndis_status_func),
111 	IMPORT_FUNC(ndis_statusdone_func),
112 	IMPORT_FUNC(ndis_setdone_func),
113 	IMPORT_FUNC(ndis_getdone_func),
114 	IMPORT_FUNC(ndis_resetdone_func),
115 	IMPORT_FUNC(ndis_sendrsrcavail_func),
116 	IMPORT_FUNC(ndis_intrhand),
117 
118 	{ NULL, NULL, NULL }
119 };
120 
121 struct nd_head ndis_devhead;
122 
123 struct ndis_req {
124 	void			(*nr_func)(void *);
125 	void			*nr_arg;
126 	int			nr_exit;
127 	STAILQ_ENTRY(ndis_req)	link;
128 	/* just for debugging */
129 	int 			area;
130 };
131 
132 struct ndisproc {
133 	struct ndisqhead	*np_q;
134 	struct proc		*np_p;
135 	int			np_state;
136 	uint8_t			np_stack[PAGE_SIZE*NDIS_KSTACK_PAGES];
137 };
138 
139 static void ndis_return(void *);
140 static int ndis_create_kthreads(void);
141 static void ndis_destroy_kthreads(void);
142 static void ndis_stop_thread(int);
143 static int ndis_enlarge_thrqueue(int);
144 static int ndis_shrink_thrqueue(int);
145 //#ifdef NDIS_LKM
146 static void ndis_runq(void *);
147 //#endif
148 
149 #ifdef __FreeBSD__
150 static struct mtx ndis_thr_mtx;
151 #else /* __NetBSD__ */
152 static kmutex_t ndis_thr_mtx;
153 #endif
154 
155 static struct mtx ndis_req_mtx;
156 static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo;
157 static struct ndisqhead ndis_itodo;
158 static struct ndisqhead ndis_free;
159 static int ndis_jobs = 32;
160 
161 static struct ndisproc ndis_tproc;
162 static struct ndisproc ndis_iproc;
163 
164 /*
165  * This allows us to export our symbols to other modules.
166  * Note that we call ourselves 'ndisapi' to avoid a namespace
167  * collision with if_ndis.ko, which internally calls itself
168  * 'ndis.'
169  */
170 
171 #ifdef __FreeBSD__
172 static int
ndis_modevent(module_t mod,int cmd,void * arg)173 ndis_modevent(module_t mod, int cmd, void *arg)
174 {
175 	int			error = 0;
176 	image_patch_table	*patch;
177 
178 	switch (cmd) {
179 	case MOD_LOAD:
180 		/* Initialize subsystems */
181 		windrv_libinit();
182 		hal_libinit();
183 		ndis_libinit();
184 		ntoskrnl_libinit();
185 #ifdef usbimplemented
186 		usbd_libinit();
187 #endif
188 
189 		patch = kernndis_functbl;
190 		while (patch->ipt_func != NULL) {
191 			windrv_wrap((funcptr)patch->ipt_func,
192 			    (funcptr *)&patch->ipt_wrap);
193 			patch++;
194 		}
195 
196 		ndis_create_kthreads();
197 
198 		TAILQ_INIT(&ndis_devhead);
199 
200 		break;
201 	case MOD_SHUTDOWN:
202 		/* stop kthreads */
203 		ndis_destroy_kthreads();
204 		if (TAILQ_FIRST(&ndis_devhead) == NULL) {
205 			/* Shut down subsystems */
206 			hal_libfini();
207 			ndis_libfini();
208 			ntoskrnl_libfini();
209 #ifdef usbimplemented
210 			usbd_libfini();
211 #endif
212 			windrv_libfini();
213 
214 			patch = kernndis_functbl;
215 			while (patch->ipt_func != NULL) {
216 				windrv_unwrap(patch->ipt_wrap);
217 				patch++;
218 			}
219 		}
220 		break;
221 	case MOD_UNLOAD:
222 		/* stop kthreads */
223 		ndis_destroy_kthreads();
224 
225 		/* Shut down subsystems */
226 		hal_libfini();
227 		ndis_libfini();
228 		ntoskrnl_libfini();
229 		usbd_libfini();
230 		windrv_libfini();
231 
232 		patch = kernndis_functbl;
233 		while (patch->ipt_func != NULL) {
234 			windrv_unwrap(patch->ipt_wrap);
235 			patch++;
236 		}
237 
238 		break;
239 	default:
240 		error = EINVAL;
241 		break;
242 	}
243 
244 	return(error);
245 }
246 DEV_MODULE(ndisapi, ndis_modevent, NULL);
247 MODULE_VERSION(ndisapi, 1);
248 #endif
249 
250 static int
ndis_modcmd(modcmd_t cmd,void * arg)251 ndis_modcmd(modcmd_t cmd, void *arg)
252 {
253 	int			error = 0;
254 	image_patch_table	*patch;
255 
256 	switch (cmd) {
257 	case MODULE_CMD_INIT:
258 		/* Initialize subsystems */
259 		windrv_libinit();
260 		hal_libinit();
261 		ndis_libinit();
262 		ntoskrnl_libinit();
263 #ifdef usbimplemented
264 		usbd_libinit();
265 #endif
266 
267 		patch = kernndis_functbl;
268 		while (patch->ipt_func != NULL) {
269 			windrv_wrap((funcptr)patch->ipt_func,
270 			    (funcptr *)&patch->ipt_wrap);
271 			patch++;
272 		}
273 
274 		TAILQ_INIT(&ndis_devhead);
275 
276 		ndis_create_kthreads();
277 		break;
278 
279 	case MODULE_CMD_FINI:
280 		/* stop kthreads */
281 		ndis_destroy_kthreads();
282 
283 		/* Shut down subsystems */
284 		hal_libfini();
285 		ndis_libfini();
286 		ntoskrnl_libfini();
287 #ifdef usbimplemented
288 		usbd_libfini();
289 #endif
290 		windrv_libfini();
291 
292 		patch = kernndis_functbl;
293 		while (patch->ipt_func != NULL) {
294 			windrv_unwrap(patch->ipt_wrap);
295 			patch++;
296 		}
297 
298 		break;
299 
300 	default:
301 		error = ENOTTY;
302 		break;
303 	}
304 
305 	return(error);
306 }
307 
308 /*
309  * We create two kthreads for the NDIS subsystem. One of them is a task
310  * queue for performing various odd jobs. The other is an swi thread
311  * reserved exclusively for running interrupt handlers. The reason we
312  * have our own task queue is that there are some cases where we may
313  * need to sleep for a significant amount of time, and if we were to
314  * use one of the taskqueue threads, we might delay the processing
315  * of other pending tasks which might need to run right away. We have
316  * a separate swi thread because we don't want our interrupt handling
317  * to be delayed either.
318  *
319  * By default there are 32 jobs available to start, and another 8
320  * are added to the free list each time a new device is created.
321  */
322 
323 /* Just for testing this can be removed later */
324 struct ndis_req *_ndis_taskqueue_req;
325 struct ndis_req *_ndis_swi_req;
326 int calling_in_swi = FALSE;
327 int calling_in_tq  = FALSE;
328 int num_swi		 = 0;
329 int num_tq		 = 0;
330 
331 static void
ndis_runq(void * arg)332 ndis_runq(void *arg)
333 {
334 	struct ndis_req		*r = NULL, *die = NULL;
335 	struct ndisproc		*p;
336 
337 	p = arg;
338 
339 	for (;;) {
340 		mtx_lock_spin(&ndis_thr_mtx);
341 		ndis_thsuspend(p->np_p, &ndis_thr_mtx, 0);
342 
343 		/* Look for any jobs on the work queue. */
344 		p->np_state = NDIS_PSTATE_RUNNING;
345 		while (!STAILQ_EMPTY(p->np_q)) {
346 			r = STAILQ_FIRST(p->np_q);
347 			STAILQ_REMOVE_HEAD(p->np_q, link);
348 
349 			/* for debugging */
350 
351 			if(p == &ndis_tproc) {
352 				num_tq++;
353 				_ndis_taskqueue_req = r;
354 				r->area = 1;
355 			} else if(p == &ndis_iproc) {
356 				num_swi++;
357 				_ndis_swi_req = r;
358 				r->area = 2;
359 			}
360 			mtx_unlock_spin(&ndis_thr_mtx);
361 
362 			/* Just for debugging */
363 
364 			if(p == &ndis_tproc) {
365 				calling_in_tq = TRUE;
366 			} else if(p == &ndis_iproc) {
367 				calling_in_swi	   = TRUE;
368 			}
369 
370 			/* Do the work. */
371 			if (r->nr_func != NULL)
372 				(*r->nr_func)(r->nr_arg);
373 
374 			/* Just for debugging */
375 			if(p == &ndis_tproc) {
376 				calling_in_tq = FALSE;
377 			} else if(p == &ndis_iproc) {
378 				calling_in_swi	   = FALSE;
379 			}
380 
381 			mtx_lock_spin(&ndis_thr_mtx);
382 
383 			/* Zeroing out the ndis_req is just for debugging */
384 			//memset(r, 0, sizeof(struct ndis_req));
385 			STAILQ_INSERT_HEAD(&ndis_free, r, link);
386 
387 			/* Check for a shutdown request */
388 			if (r->nr_exit == TRUE)
389 				die = r;
390 		}
391 		p->np_state = NDIS_PSTATE_SLEEPING;
392 
393 		mtx_unlock_spin(&ndis_thr_mtx);
394 
395 		/* Bail if we were told to shut down. */
396 
397 		if (die != NULL)
398 			break;
399 	}
400 
401 	wakeup(die);
402 
403 	kthread_exit(0);
404 	/* NOTREACHED */
405 }
406 
407 /*static*/ int
ndis_create_kthreads(void)408 ndis_create_kthreads(void)
409 {
410 	struct ndis_req		*r;
411 	int			i, error = 0;
412 
413 #ifdef __FreeBSD__
414 	mtx_init(&ndis_thr_mtx, "NDIS thread lock", NULL, MTX_SPIN);
415 #else /* __NetBSD__ */
416 	mutex_init(&ndis_thr_mtx, MUTEX_DEFAULT, IPL_NET);
417 #endif
418 	mtx_init(&ndis_req_mtx, "NDIS request lock", MTX_NDIS_LOCK, MTX_DEF);
419 
420 	STAILQ_INIT(&ndis_ttodo);
421 	STAILQ_INIT(&ndis_itodo);
422 	STAILQ_INIT(&ndis_free);
423 
424 	for (i = 0; i < ndis_jobs; i++) {
425 		r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK|M_ZERO);
426 		if (r == NULL) {
427 			error = ENOMEM;
428 			break;
429 		}
430 		STAILQ_INSERT_HEAD(&ndis_free, r, link);
431 	}
432 
433 	if (error == 0) {
434 		ndis_tproc.np_q = &ndis_ttodo;
435 		ndis_tproc.np_state = NDIS_PSTATE_SLEEPING;
436 #ifdef __FreeBSD__
437 		error = kthread_create(ndis_runq, &ndis_tproc,
438 		    &ndis_tproc.np_p, RFHIGHPID,
439 		    NDIS_KSTACK_PAGES, "ndis taskqueue");
440 #else /* __NetBSD__ */
441 		error = ndis_kthread_create(ndis_runq, &ndis_tproc,
442 		    &ndis_tproc.np_p, ndis_tproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis taskqueue");
443 #endif
444 	}
445 
446 	if (error == 0) {
447 		ndis_iproc.np_q = &ndis_itodo;
448 		ndis_iproc.np_state = NDIS_PSTATE_SLEEPING;
449 #ifdef __FreeBSD__
450 		error = kthread_create(ndis_runq, &ndis_iproc,
451 		    &ndis_iproc.np_p, RFHIGHPID,
452 		    NDIS_KSTACK_PAGES, "ndis swi");
453 #else
454 		error = ndis_kthread_create(ndis_runq, &ndis_iproc,
455 		    &ndis_iproc.np_p, ndis_iproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis swi");
456 #endif
457 	}
458 
459 	if (error) {
460 		while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
461 			STAILQ_REMOVE_HEAD(&ndis_free, link);
462 			free(r, M_DEVBUF);
463 		}
464 		return(error);
465 	}
466 
467 	return(0);
468 }
469 
470 static void
ndis_destroy_kthreads(void)471 ndis_destroy_kthreads(void)
472 {
473 	struct ndis_req		*r;
474 
475 	/* Stop the threads. */
476 
477 	ndis_stop_thread(NDIS_TASKQUEUE);
478 	ndis_stop_thread(NDIS_SWI);
479 
480 	/* Destroy request structures. */
481 
482 	while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
483 		STAILQ_REMOVE_HEAD(&ndis_free, link);
484 		free(r, M_DEVBUF);
485 	}
486 
487 	mtx_destroy(&ndis_req_mtx);
488 	mtx_destroy(&ndis_thr_mtx);
489 
490 	return;
491 }
492 
493 static void
ndis_stop_thread(int t)494 ndis_stop_thread(int t)
495 {
496 	struct ndis_req		*r;
497 	struct ndisqhead	*q;
498 	struct proc		*p;
499 
500 	if (t == NDIS_TASKQUEUE) {
501 		q = &ndis_ttodo;
502 		p = ndis_tproc.np_p;
503 	} else {
504 		q = &ndis_itodo;
505 		p = ndis_iproc.np_p;
506 	}
507 
508 	/* Create and post a special 'exit' job. */
509 
510 	mtx_lock_spin(&ndis_thr_mtx);
511 
512 	r = STAILQ_FIRST(&ndis_free);
513 	STAILQ_REMOVE_HEAD(&ndis_free, link);
514 	r->nr_func = NULL;
515 	r->nr_arg = NULL;
516 	r->nr_exit = TRUE;
517 	r->area	   = 3;
518 	STAILQ_INSERT_TAIL(q, r, link);
519 	mtx_unlock_spin(&ndis_thr_mtx);
520 
521 	ndis_thresume(p);
522 
523 	/* Wait for thread exit */
524 	tsleep(r, PZERO | PCATCH, "ndisthexit", hz * 60);
525 
526 	/* Now empty the job list. */
527 	mtx_lock_spin(&ndis_thr_mtx);
528 	while ((r = STAILQ_FIRST(q)) != NULL) {
529 		STAILQ_REMOVE_HEAD(q, link);
530 		STAILQ_INSERT_HEAD(&ndis_free, r, link);
531 	}
532 	mtx_unlock_spin(&ndis_thr_mtx);
533 }
534 
535 static int
ndis_enlarge_thrqueue(int cnt)536 ndis_enlarge_thrqueue(int cnt)
537 {
538 	struct ndis_req		*r;
539 	int			i;
540 
541 	for (i = 0; i < cnt; i++) {
542 		r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
543 		if (r == NULL)
544 			return(ENOMEM);
545 
546 		mtx_lock_spin(&ndis_thr_mtx);
547 		STAILQ_INSERT_HEAD(&ndis_free, r, link);
548 		ndis_jobs++;
549 		mtx_unlock_spin(&ndis_thr_mtx);
550 	}
551 
552 	return(0);
553 }
554 
555 static int
ndis_shrink_thrqueue(int cnt)556 ndis_shrink_thrqueue(int cnt)
557 {
558 	struct ndis_req		*r;
559 	int			i;
560 
561 	for (i = 0; i < cnt; i++) {
562 		mtx_lock_spin(&ndis_thr_mtx);
563 		r = STAILQ_FIRST(&ndis_free);
564 		if (r == NULL) {
565 			mtx_unlock_spin(&ndis_thr_mtx);
566 			return(ENOMEM);
567 		}
568 		STAILQ_REMOVE_HEAD(&ndis_free, link);
569 		ndis_jobs--;
570 		mtx_unlock_spin(&ndis_thr_mtx);
571 		free(r, M_DEVBUF);
572 	}
573 
574 	return(0);
575 }
576 
577 int
ndis_unsched(void (* func)(void *),void * arg,int t)578 ndis_unsched(void (*func)(void *), void *arg, int t)
579 {
580 	struct ndis_req		*r;
581 	struct ndisqhead	*q;
582 
583 	if (t == NDIS_TASKQUEUE) {
584 		q = &ndis_ttodo;
585 	} else {
586 		q = &ndis_itodo;
587 	}
588 
589 	mtx_lock_spin(&ndis_thr_mtx);
590 	STAILQ_FOREACH(r, q, link) {
591 		if (r->nr_func == func && r->nr_arg == arg) {
592 			r->area = 4;
593 			STAILQ_REMOVE(q, r, ndis_req, link);
594 			STAILQ_INSERT_HEAD(&ndis_free, r, link);
595 			mtx_unlock_spin(&ndis_thr_mtx);
596 			return(0);
597 		}
598 	}
599 	mtx_unlock_spin(&ndis_thr_mtx);
600 
601 	return(ENOENT);
602 }
603 
604 /* just for testing */
605 struct ndis_req *ls_tq_req = NULL;
606 struct ndis_req *ls_swi_req = NULL;
607 
608 int
ndis_sched(void (* func)(void *),void * arg,int t)609 ndis_sched(void (*func)(void *), void *arg, int t)
610 {
611 	struct ndis_req		*r;
612 	struct ndisqhead	*q;
613 	struct proc		*p;
614 	int			s;
615 #ifdef __NetBSD__
616 	/* just for debugging */
617 	struct ndis_req		**ls;
618 	//struct lwp		*l = curlwp;
619 #endif
620 
621 	if (t == NDIS_TASKQUEUE) {
622 		ls = &ls_tq_req;
623 		q = &ndis_ttodo;
624 		p = ndis_tproc.np_p;
625 	} else {
626 		ls = &ls_swi_req;
627 		q = &ndis_itodo;
628 		p = ndis_iproc.np_p;
629 	}
630 
631 	mtx_lock_spin(&ndis_thr_mtx);
632 
633 	/*
634 	 * Check to see if an instance of this job is already
635 	 * pending. If so, don't bother queuing it again.
636 	 */
637 	STAILQ_FOREACH(r, q, link) {
638 		if (r->nr_func == func && r->nr_arg == arg) {
639 #ifdef __NetBSD__
640 			if (t == NDIS_TASKQUEUE)
641 				s = ndis_tproc.np_state;
642 			else
643 				s = ndis_iproc.np_state;
644 #endif
645 			mtx_unlock_spin(&ndis_thr_mtx);
646 #ifdef __NetBSD__
647 			/* The swi thread seemed to be going to sleep, and not waking up
648 			 * again, so I thought I'd try this out...
649 			 */
650 			if (s == NDIS_PSTATE_SLEEPING)
651 				ndis_thresume(p);
652 #endif
653 			return(0);
654 		}
655 	}
656 	r = STAILQ_FIRST(&ndis_free);
657 	if (r == NULL) {
658 		mtx_unlock_spin(&ndis_thr_mtx);
659 		return(EAGAIN);
660 	}
661 	STAILQ_REMOVE_HEAD(&ndis_free, link);
662 #ifdef __NetBSD__
663 	//memset(r, 0, sizeof(struct ndis_req));
664 #endif
665 	*ls = r;
666 	r->nr_func = func;
667 	r->nr_arg = arg;
668 	r->nr_exit = FALSE;
669 	r->area	   = 5;
670 	STAILQ_INSERT_TAIL(q, r, link);
671 	if (t == NDIS_TASKQUEUE) {
672 		s = ndis_tproc.np_state;
673 	} else {
674 		s = ndis_iproc.np_state;
675 	}
676 	mtx_unlock_spin(&ndis_thr_mtx);
677 
678 	/*
679 	 * Post the job, but only if the thread is actually blocked
680 	 * on its own suspend call. If a driver queues up a job with
681 	 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(),
682 	 * it may suspend there, and in that case we don't want to wake
683 	 * it up until KeWaitForObject() gets woken up on its own.
684 	 */
685 	if (s == NDIS_PSTATE_SLEEPING) {
686 		ndis_thresume(p);
687 	}
688 
689 	return(0);
690 }
691 
692 /* Try out writing my own version of ndis_sched() for NetBSD in which I just
693  * call the function instead of scheduling it.  I know this isn't
694  * what's supposed to be done, but I've been having a lot of problems
695  * with the SWI and taskqueue threads, and just thought I'd give this
696  * a try.
697  */
698 
699  /* I don't think this will work, because it means that DPC's will be
700   * called from the bottom half of the kernel, so they won't be able
701   * to sleep using KeWaitForSingleObject.
702   */
703  /*
704  int
705 ndis_sched(void (*func)(void *), void *arg, int t)
706 {
707 	if(func != NULL) {
708 		(*func)(arg);
709 	}
710 
711 	return 0;
712 }
713 */
714 
715 int
ndis_thsuspend(proc_t * p,kmutex_t * m,int timo)716 ndis_thsuspend(proc_t *p, kmutex_t *m, int timo)
717 {
718 
719 	return mtsleep(&p->p_sigpend.sp_set, PZERO,  "ndissp", timo, m);
720 }
721 
722 void
ndis_thresume(struct proc * p)723 ndis_thresume(struct proc *p)
724 {
725 
726 	wakeup(&p->p_sigpend.sp_set);
727 }
728 
729 __stdcall static void
ndis_sendrsrcavail_func(ndis_handle adapter)730 ndis_sendrsrcavail_func(ndis_handle adapter)
731 {
732 	return;
733 }
734 
735 __stdcall static void
ndis_status_func(ndis_handle adapter,ndis_status status,void * sbuf,uint32_t slen)736 ndis_status_func(ndis_handle adapter, ndis_status status, void *sbuf,
737     uint32_t slen)
738 {
739 	ndis_miniport_block	*block;
740 	struct ndis_softc	*sc;
741 	struct ifnet		*ifp;
742 
743 	block = adapter;
744 #ifdef __FreeBSD__
745 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
746 #else /* __NetBSD__ */
747 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
748 #endif
749 
750 #ifdef __FreeBSD__
751 	ifp = &sc->arpcom.ac_if;
752 #else
753 	ifp = &sc->arpcom.ec_if;
754 #endif
755 	if (ifp->if_flags & IFF_DEBUG)
756 		printf("%s: status: %x\n",
757 		       device_xname(sc->ndis_dev), status);
758 	return;
759 }
760 
761 __stdcall static void
ndis_statusdone_func(ndis_handle adapter)762 ndis_statusdone_func(ndis_handle adapter)
763 {
764 	ndis_miniport_block	*block;
765 	struct ndis_softc	*sc;
766 	struct ifnet		*ifp;
767 
768 	block = adapter;
769 #ifdef __FreeBSD__
770 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
771 #else /* __NetBSD__ */
772 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
773 #endif
774 
775 #ifdef __FreeBSD__
776 	ifp = &sc->arpcom.ac_if;
777 #else
778 	ifp = &sc->arpcom.ec_if;
779 #endif
780 	if (ifp->if_flags & IFF_DEBUG)
781 		printf("%s: status complete\n",
782 		       device_xname(sc->ndis_dev));
783 	return;
784 }
785 
786 __stdcall static void
ndis_setdone_func(ndis_handle adapter,ndis_status status)787 ndis_setdone_func(ndis_handle adapter, ndis_status status)
788 {
789 	ndis_miniport_block	*block;
790 	block = adapter;
791 
792 	block->nmb_setstat = status;
793 	wakeup(&block->nmb_setstat);
794 	return;
795 }
796 
797 __stdcall static void
ndis_getdone_func(ndis_handle adapter,ndis_status status)798 ndis_getdone_func(ndis_handle adapter, ndis_status status)
799 {
800 	ndis_miniport_block	*block;
801 	block = adapter;
802 
803 	block->nmb_getstat = status;
804 	wakeup(&block->nmb_getstat);
805 	return;
806 }
807 
808 __stdcall static void
ndis_resetdone_func(ndis_handle adapter,ndis_status status,uint8_t addressingreset)809 ndis_resetdone_func(ndis_handle adapter, ndis_status status,
810     uint8_t addressingreset)
811 {
812 	ndis_miniport_block	*block;
813 	struct ndis_softc	*sc;
814 	struct ifnet		*ifp;
815 
816 	block = adapter;
817 #ifdef __FreeBSD__
818 	sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
819 #else /* __NetBSD__ */
820 	sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
821 #endif
822 
823 #ifdef __FreeBSD__
824 	ifp = &sc->arpcom.ac_if;
825 #else
826 	ifp = &sc->arpcom.ec_if;
827 #endif
828 
829 	if (ifp->if_flags & IFF_DEBUG)
830 		printf("%s: reset done...\n",
831 		       device_xname(sc->ndis_dev));
832 	wakeup(sc);
833 	return;
834 }
835 
836 #ifdef __FreeBSD__
837 /* FreeBSD version of ndis_create_sysctls() */
838 int
ndis_create_sysctls(void * arg)839 ndis_create_sysctls(void *arg)
840 {
841 	struct ndis_softc	*sc;
842 	ndis_cfg		*vals;
843 	char			buf[256];
844 	struct sysctl_oid	*oidp;
845 	struct sysctl_ctx_entry	*e;
846 
847 	if (arg == NULL)
848 		return(EINVAL);
849 
850 	sc = arg;
851 	vals = sc->ndis_regvals;
852 
853 	TAILQ_INIT(&sc->ndis_cfglist_head);
854 
855 #if __FreeBSD_version < 502113
856 	/* Create the sysctl tree. */
857 
858 	sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
859 	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
860 	    device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
861 	    device_get_desc(sc->ndis_dev));
862 
863 #endif
864 	/* Add the driver-specific registry keys. */
865 
866 	vals = sc->ndis_regvals;
867 	while(1) {
868 		if (vals->nc_cfgkey == NULL)
869 			break;
870 		if (vals->nc_idx != sc->ndis_devidx) {
871 			vals++;
872 			continue;
873 		}
874 
875 		/* See if we already have a sysctl with this name */
876 
877 		oidp = NULL;
878 #if __FreeBSD_version < 502113
879 		TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
880 #else
881 		TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
882 #endif
883                 	oidp = e->entry;
884 			if (ndis_strcasecmp(oidp->oid_name,
885 			    vals->nc_cfgkey) == 0)
886 				break;
887 			oidp = NULL;
888 		}
889 
890 		if (oidp != NULL) {
891 			vals++;
892 			continue;
893 		}
894 
895 #if __FreeBSD_version < 502113
896 		SYSCTL_ADD_STRING(&sc->ndis_ctx,
897 		    SYSCTL_CHILDREN(sc->ndis_tree),
898 #else
899 		SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
900 		    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
901 #endif
902 		    OID_AUTO, vals->nc_cfgkey,
903 		    CTLFLAG_RW, vals->nc_val,
904 		    sizeof(vals->nc_val),
905 		    vals->nc_cfgdesc);
906 		vals++;
907 	}
908 
909 	/* Now add a couple of builtin keys. */
910 
911 	/*
912 	 * Environment can be either Windows (0) or WindowsNT (1).
913 	 * We qualify as the latter.
914 	 */
915 	ndis_add_sysctl(sc, "Environment",
916 	    "Windows environment", "1", CTLFLAG_RD);
917 
918 	/* NDIS version should be 5.1. */
919 	ndis_add_sysctl(sc, "NdisVersion",
920 	    "NDIS API Version", "0x00050001", CTLFLAG_RD);
921 
922 	/* Bus type (PCI, PCMCIA, etc...) */
923 	snprintf(buf, sizeof(buf), "%d", (int)sc->ndis_iftype);
924 	ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
925 
926 	if (sc->ndis_res_io != NULL) {
927 		snprintf(buf, sizeof(buf), "0x%lx",
928 		    rman_get_start(sc->ndis_res_io));
929 		ndis_add_sysctl(sc, "IOBaseAddress",
930 		    "Base I/O Address", buf, CTLFLAG_RD);
931 	}
932 
933 	if (sc->ndis_irq != NULL) {
934 		snprintf(buf, sizeof(buf), "%lu", rman_get_start(sc->ndis_irq));
935 		ndis_add_sysctl(sc, "InterruptNumber",
936 		    "Interrupt Number", buf, CTLFLAG_RD);
937 	}
938 
939 	return(0);
940 }
941 #endif /* __FreeBSD__ */
942 
943 #ifdef __NetBSD__
944 /* NetBSD version of ndis_create_sysctls() */
945 int
946 ndis_create_sysctls(void *arg)
947 {
948 	struct ndis_softc	*sc;
949 	ndis_cfg		*vals;
950 	const struct sysctlnode *ndis_node;
951 	char buf[256];
952 
953 	printf("in ndis_create_sysctls()\n");
954 
955 	if (arg == NULL)
956 		return(EINVAL);
957 
958 	sc = arg;
959 	vals = sc->ndis_regvals;
960 
961 	TAILQ_INIT(&sc->ndis_cfglist_head);
962 
963 	/* Create the sysctl tree. */
964 	sysctl_createv(&sc->sysctllog, 0, NULL, &ndis_node, CTLFLAG_READWRITE, CTLTYPE_NODE,
965 					device_xname(sc->ndis_dev), NULL, NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
966 
967 	/* Store the number of the ndis mib */
968 	sc->ndis_sysctl_mib = ndis_node->sysctl_num;
969 
970 	/* Add the driver-specific registry keys. */
971 	vals = sc->ndis_regvals;
972 	while(1) {
973 		if (vals->nc_cfgkey == NULL)
974 			break;
975 		if (vals->nc_idx != sc->ndis_devidx) {
976 			vals++;
977 			continue;
978 		}
979 
980 		/* See if we already have a sysctl with this name */
981 /* TODO: Is something like this necessary in NetBSD?  I'm guessing this
982    TODO: is just checking if any of the information in the .inf file was
983    TODO: already determined by FreeBSD's autoconfiguration which seems to
984    TODO: add dev.XXX sysctl's beginning with %.  (NetBSD dosen't seem to do this).
985 */
986 
987 /* TODO: use CTLFLAG_OWNDATA or not? */
988 		   /*
989 		sysctl_createv(&sc->sysctllog, 0, NULL, NULL,
990 						CTLFLAG_READWRITE|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA, CTLTYPE_STRING,
991 						vals->nc_cfgkey, vals->nc_cfgdesc, NULL, 0, vals->nc_val, strlen(vals->nc_val),
992 					    ndis_node->sysctl_num, CTL_CREATE, CTL_EOL);
993 		   */
994 		   ndis_add_sysctl(sc, vals->nc_cfgkey,
995 						   vals->nc_cfgdesc, vals->nc_val, CTLFLAG_READWRITE);
996 
997    		vals++;
998 	} /* end while */
999 
1000 		/* Now add a couple of builtin keys. */
1001 
1002 	/*
1003 	 * Environment can be either Windows (0) or WindowsNT (1).
1004 	 * We qualify as the latter.
1005 	 */
1006 #ifdef __NetBSD__
1007 #define CTLFLAG_RD CTLFLAG_READONLY
1008 /* TODO: do we need something like rman_get_start? */
1009 #define rman_get_start(x) x
1010 #endif
1011 		ndis_add_sysctl(sc, "Environment",
1012 						"Windows environment", "1", CTLFLAG_RD);
1013 
1014 		/* NDIS version should be 5.1. */
1015 		ndis_add_sysctl(sc, "NdisVersion",
1016 						/*"NDIS API Version"*/ "Version", "0x00050001", CTLFLAG_RD);
1017 
1018 		/* Bus type (PCI, PCMCIA, etc...) */
1019 		snprintf(buf, sizeof(buf), "%d", (int)sc->ndis_iftype);
1020 		ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
1021 
1022 		if (sc->ndis_res_io != NULL) {
1023 			snprintf(buf, sizeof(buf), "0x%lx",
1024 			    (long unsigned int)rman_get_start(sc->ndis_res_io));
1025 			ndis_add_sysctl(sc, "IOBaseAddress",
1026 							/*"Base I/O Address"*/ "Base I/O", buf, CTLFLAG_RD);
1027 		}
1028 
1029 		if (sc->ndis_irq != NULL) {
1030 			snprintf(buf, sizeof(buf), "%lu", (long unsigned int)rman_get_start(sc->ndis_irq));
1031 			ndis_add_sysctl(sc, "InterruptNumber",
1032 							"Interrupt Number", buf, CTLFLAG_RD);
1033 		}
1034 
1035 		return(0);
1036 }
1037 #endif /* __NetBSD__ */
1038 
1039 char *ndis_strdup(const char *src);
1040 
1041 char *ndis_strdup(const char *src)
1042 {
1043 	char *ret;
1044 
1045 	ret = malloc(strlen(src), M_DEVBUF, M_NOWAIT|M_ZERO);
1046 	if (ret == NULL) {
1047 		printf("ndis_strdup failed\n");
1048 		return(NULL);
1049 	}
1050 	strcpy(ret, src);
1051 
1052 	return ret;
1053 }
1054 
1055 int
1056 ndis_add_sysctl(void *arg, const char *key, const char *desc, const char *val, int flag)
1057 {
1058 	struct ndis_softc	*sc;
1059 	struct ndis_cfglist	*cfg;
1060 	char			descstr[256];
1061 #ifdef __NetBSD__
1062 	char newkey[MAX_SYSCTL_LEN+1];
1063 #endif
1064 
1065 	sc = arg;
1066 
1067 	cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
1068 
1069 	if (cfg == NULL)
1070 		return(ENOMEM);
1071 
1072 	/* I added this because NetBSD sysctl node names can't begin with
1073 	 * a digit.
1074 	 */
1075 #ifdef __NetBSD__
1076 	if(strlen(key) + strlen("ndis_") > MAX_SYSCTL_LEN) {
1077 		panic("sysctl name too long: %s\n", key);
1078 	}
1079 	strcpy(newkey, "ndis_");
1080 	strcpy(newkey + strlen("ndis_"), key);
1081 	key = newkey;
1082 #endif
1083 
1084 	cfg->ndis_cfg.nc_cfgkey = ndis_strdup(key);
1085 
1086 	if (desc == NULL) {
1087 		snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
1088 		cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(descstr);
1089 	} else
1090 		cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(desc);
1091 	strcpy(cfg->ndis_cfg.nc_val, val);
1092 
1093 	TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
1094 
1095 #ifdef __FreeBSD__
1096 #if __FreeBSD_version < 502113
1097 	SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
1098 #else
1099 	SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
1100 	    SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
1101 #endif
1102 	    OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
1103 	    cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
1104 	    cfg->ndis_cfg.nc_cfgdesc);
1105 #else /* __NetBSD__ */
1106 /* TODO: use CTLFLAG_OWNDATA or not? */
1107 	sysctl_createv(&sc->sysctllog, 0, NULL, NULL, flag/*|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA*/, CTLTYPE_STRING,
1108 					cfg->ndis_cfg.nc_cfgkey, cfg->ndis_cfg.nc_cfgdesc, NULL, 0, cfg->ndis_cfg.nc_val,
1109 					strlen(cfg->ndis_cfg.nc_val), sc->ndis_sysctl_mib, CTL_CREATE, CTL_EOL);
1110 #endif
1111 	return(0);
1112 }
1113 
1114 int
1115 ndis_flush_sysctls(void *arg)
1116 {
1117 	struct ndis_softc	*sc;
1118 	struct ndis_cfglist	*cfg;
1119 
1120 	sc = arg;
1121 
1122 	while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
1123 		cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
1124 		TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
1125 #ifdef __FreeBSD__
1126 		free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
1127 		free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
1128 #endif
1129 		free(cfg, M_DEVBUF);
1130 	}
1131 
1132 	return(0);
1133 }
1134 
1135 static void
1136 ndis_return(void *arg)
1137 {
1138 	struct ndis_softc	*sc;
1139 	__stdcall ndis_return_handler	returnfunc;
1140 	ndis_handle		adapter;
1141 	ndis_packet		*p;
1142 	uint8_t			irql = 0;	/* XXX: gcc */
1143 
1144 	p = arg;
1145 	sc = p->np_softc;
1146 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1147 
1148 	if (adapter == NULL)
1149 		return;
1150 
1151 	returnfunc = sc->ndis_chars->nmc_return_packet_func;
1152 
1153 	KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1154 	MSCALL2(returnfunc, adapter, p);
1155 	KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1156 
1157 	return;
1158 }
1159 
1160 void
1161 #ifdef __FreeBSD__
1162 ndis_return_packet(buf, arg)
1163 	void			*buf;	/* not used */
1164 	void			*arg;
1165 #else
1166 ndis_return_packet(struct mbuf *m, void *buf,
1167     size_t size, void *arg)
1168 #endif
1169 
1170 {
1171 	ndis_packet		*p;
1172 
1173 	if (arg == NULL)
1174 		return;
1175 
1176 	p = arg;
1177 
1178 	/* Decrement refcount. */
1179 	p->np_refcnt--;
1180 
1181 	/* Release packet when refcount hits zero, otherwise return. */
1182 	if (p->np_refcnt)
1183 		return;
1184 
1185 	ndis_sched(ndis_return, p, NDIS_TASKQUEUE);
1186 
1187 	return;
1188 }
1189 
1190 void
1191 ndis_free_bufs(ndis_buffer *b0)
1192 {
1193 	ndis_buffer		*next;
1194 
1195 	if (b0 == NULL)
1196 		return;
1197 
1198 	while(b0 != NULL) {
1199 		next = b0->mdl_next;
1200 		IoFreeMdl(b0);
1201 		b0 = next;
1202 	}
1203 
1204 	return;
1205 }
1206 int in_reset = 0;
1207 void
1208 ndis_free_packet(ndis_packet *p)
1209 {
1210 	if (p == NULL)
1211 		return;
1212 
1213 	ndis_free_bufs(p->np_private.npp_head);
1214 	NdisFreePacket(p);
1215 	return;
1216 }
1217 
1218 #ifdef __FreeBSD__
1219 int
1220 ndis_convert_res(void *arg)
1221 {
1222 	struct ndis_softc	*sc;
1223 	ndis_resource_list	*rl = NULL;
1224 	cm_partial_resource_desc	*prd = NULL;
1225 	ndis_miniport_block	*block;
1226 	device_t		dev;
1227 	struct resource_list	*brl;
1228 	struct resource_list_entry	*brle;
1229 #if __FreeBSD_version < 600022
1230 	struct resource_list	brl_rev;
1231 	struct resource_list_entry	*n;
1232 #endif
1233 	int 			error = 0;
1234 
1235 	sc = arg;
1236 	block = sc->ndis_block;
1237 	dev = sc->ndis_dev;
1238 
1239 #if __FreeBSD_version < 600022
1240 	SLIST_INIT(&brl_rev);
1241 #endif
1242 	rl = malloc(sizeof(ndis_resource_list) +
1243 	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
1244 	    M_DEVBUF, M_NOWAIT|M_ZERO);
1245 
1246 	if (rl == NULL)
1247 		return(ENOMEM);
1248 
1249 	rl->cprl_version = 5;
1250 	rl->cprl_version = 1;
1251 	rl->cprl_count = sc->ndis_rescnt;
1252 	prd = rl->cprl_partial_descs;
1253 
1254 	brl = BUS_GET_RESOURCE_LIST(dev, dev);
1255 
1256 	if (brl != NULL) {
1257 
1258 #if __FreeBSD_version < 600022
1259 		/*
1260 		 * We have a small problem. Some PCI devices have
1261 		 * multiple I/O ranges. Windows orders them starting
1262 		 * from lowest numbered BAR to highest. We discover
1263 		 * them in that order too, but insert them into a singly
1264 		 * linked list head first, which means when time comes
1265 		 * to traverse the list, we enumerate them in reverse
1266 		 * order. This screws up some drivers which expect the
1267 		 * BARs to be in ascending order so that they can choose
1268 		 * the "first" one as their register space. Unfortunately,
1269 		 * in order to fix this, we have to create our own
1270 		 * temporary list with the entries in reverse order.
1271 		 */
1272 		SLIST_FOREACH(brle, brl, link) {
1273 			n = malloc(sizeof(struct resource_list_entry),
1274 			    M_TEMP, M_NOWAIT);
1275 			if (n == NULL) {
1276 				error = ENOMEM;
1277 				goto bad;
1278 			}
1279 			memcpy( (char *)n, (char *)brle,
1280 			    sizeof(struct resource_list_entry));
1281 			SLIST_INSERT_HEAD(&brl_rev, n, link);
1282 		}
1283 
1284 		SLIST_FOREACH(brle, &brl_rev, link) {
1285 #else
1286 		STAILQ_FOREACH(brle, brl, link) {
1287 #endif
1288 			switch (brle->type) {
1289 			case SYS_RES_IOPORT:
1290 				prd->cprd_type = CmResourceTypePort;
1291 				prd->cprd_flags = CM_RESOURCE_PORT_IO;
1292 				prd->cprd_sharedisp =
1293 				    CmResourceShareDeviceExclusive;
1294 				prd->u.cprd_port.cprd_start.np_quad =
1295 				    brle->start;
1296 				prd->u.cprd_port.cprd_len = brle->count;
1297 				break;
1298 			case SYS_RES_MEMORY:
1299 				prd->cprd_type = CmResourceTypeMemory;
1300 				prd->cprd_flags =
1301 				    CM_RESOURCE_MEMORY_READ_WRITE;
1302 				prd->cprd_sharedisp =
1303 				    CmResourceShareDeviceExclusive;
1304 				prd->u.cprd_port.cprd_start.np_quad =
1305 				    brle->start;
1306 				prd->u.cprd_port.cprd_len = brle->count;
1307 				break;
1308 			case SYS_RES_IRQ:
1309 				prd->cprd_type = CmResourceTypeInterrupt;
1310 				prd->cprd_flags = 0;
1311 				prd->cprd_sharedisp =
1312 				    CmResourceShareDeviceExclusive;
1313 				prd->u.cprd_intr.cprd_level = brle->start;
1314 				prd->u.cprd_intr.cprd_vector = brle->start;
1315 				prd->u.cprd_intr.cprd_affinity = 0;
1316 				break;
1317 			default:
1318 				break;
1319 			}
1320 			prd++;
1321 		}
1322 	}
1323 
1324 	block->nmb_rlist = rl;
1325 
1326 #if __FreeBSD_version < 600022
1327 bad:
1328 
1329 	while (!SLIST_EMPTY(&brl_rev)) {
1330 		n = SLIST_FIRST(&brl_rev);
1331 		SLIST_REMOVE_HEAD(&brl_rev, link);
1332 		free (n, M_TEMP);
1333 	}
1334 #endif
1335 
1336 	return(error);
1337 }
1338 #endif /* __FreeBSD__ */
1339 /*
1340  * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
1341  * packet, it will hand it to us in the form of an ndis_packet,
1342  * which we need to convert to an mbuf that is then handed off
1343  * to the stack. Note: we configure the mbuf list so that it uses
1344  * the memory regions specified by the ndis_buffer structures in
1345  * the ndis_packet as external storage. In most cases, this will
1346  * point to a memory region allocated by the driver (either by
1347  * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
1348  * the driver to handle free()ing this region for is, so we set up
1349  * a dummy no-op free handler for it.
1350  */
1351 
1352 int
1353 ndis_ptom(struct mbuf **m0, ndis_packet *p)
1354 {
1355 	struct mbuf		*m, *prev = NULL;
1356 	ndis_buffer		*buf;
1357 	ndis_packet_private	*priv;
1358 	uint32_t		totlen = 0;
1359 
1360 	if (p == NULL || m0 == NULL)
1361 		return(EINVAL);
1362 
1363 	priv = &p->np_private;
1364 	buf = priv->npp_head;
1365 	p->np_refcnt = 0;
1366 
1367 	for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) {
1368 		if (buf == priv->npp_head)
1369 			MGETHDR(m, M_DONTWAIT, MT_HEADER);
1370 		else
1371 			MGET(m, M_DONTWAIT, MT_DATA);
1372 		if (m == NULL) {
1373 			m_freem(*m0);
1374 			*m0 = NULL;
1375 			return(ENOBUFS);
1376 		}
1377 		m->m_len = MmGetMdlByteCount(buf);
1378 		m->m_data = MmGetMdlVirtualAddress(buf);
1379 #ifdef __FreeBSD__
1380 		MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
1381 			p, 0, EXT_NDIS);
1382 #else
1383 		MEXTADD(m, m->m_data, m->m_len, M_DEVBUF,
1384 			ndis_return_packet, p);
1385 #endif
1386 		p->np_refcnt++;
1387 		totlen += m->m_len;
1388 		if (m->m_flags & MT_HEADER)
1389 			*m0 = m;
1390 		else
1391 			prev->m_next = m;
1392 		prev = m;
1393 	}
1394 
1395 	(*m0)->m_pkthdr.len = totlen;
1396 
1397 	return(0);
1398 }
1399 
1400 /*
1401  * Create an NDIS packet from an mbuf chain.
1402  * This is used mainly when transmitting packets, where we need
1403  * to turn an mbuf off an interface's send queue and transform it
1404  * into an NDIS packet which will be fed into the NDIS driver's
1405  * send routine.
1406  *
1407  * NDIS packets consist of two parts: an ndis_packet structure,
1408  * which is vaguely analagous to the pkthdr portion of an mbuf,
1409  * and one or more ndis_buffer structures, which define the
1410  * actual memory segments in which the packet data resides.
1411  * We need to allocate one ndis_buffer for each mbuf in a chain,
1412  * plus one ndis_packet as the header.
1413  */
1414 
1415 int
1416 ndis_mtop(struct mbuf *m0, ndis_packet **p)
1417 {
1418 	struct mbuf		*m;
1419 	ndis_buffer		*buf = NULL, *prev = NULL;
1420 	ndis_packet_private	*priv;
1421 
1422 	if (p == NULL || *p == NULL || m0 == NULL)
1423 		return(EINVAL);
1424 
1425 	priv = &(*p)->np_private;
1426 	priv->npp_totlen = m0->m_pkthdr.len;
1427 
1428 	for (m = m0; m != NULL; m = m->m_next) {
1429 		if (m->m_len == 0)
1430 			continue;
1431 		buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL);
1432 		if (buf == NULL) {
1433 			ndis_free_packet(*p);
1434 			*p = NULL;
1435 			return(ENOMEM);
1436 		}
1437 
1438 		if (priv->npp_head == NULL)
1439 			priv->npp_head = buf;
1440 		else
1441 			prev->mdl_next = buf;
1442 		prev = buf;
1443 	}
1444 
1445 	priv->npp_tail = buf;
1446 
1447 	return(0);
1448 }
1449 
1450 int
1451 ndis_get_supported_oids(void *arg, ndis_oid **oids, int *oidcnt)
1452 {
1453 	int			len, rval;
1454 	ndis_oid		*o;
1455 
1456 	if (arg == NULL || oids == NULL || oidcnt == NULL)
1457 		return(EINVAL);
1458 	len = 0;
1459 	ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
1460 
1461 	o = malloc(len, M_DEVBUF, M_NOWAIT);
1462 	if (o == NULL)
1463 		return(ENOMEM);
1464 
1465 	rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
1466 
1467 	if (rval) {
1468 		free(o, M_DEVBUF);
1469 		return(rval);
1470 	}
1471 
1472 	*oids = o;
1473 	*oidcnt = len / 4;
1474 
1475 	return(0);
1476 }
1477 
1478 int
1479 ndis_set_info(void *arg, ndis_oid oid, void *buf, int *buflen)
1480 {
1481 	struct ndis_softc	*sc;
1482 	ndis_status		rval;
1483 	ndis_handle		adapter;
1484 	__stdcall ndis_setinfo_handler	setfunc;
1485 	uint32_t		byteswritten = 0, bytesneeded = 0;
1486 	uint8_t			irql = 0;	/* XXX: gcc */
1487 
1488 	/*
1489 	 * According to the NDIS spec, MiniportQueryInformation()
1490 	 * and MiniportSetInformation() requests are handled serially:
1491 	 * once one request has been issued, we must wait for it to
1492  	 * finish before allowing another request to proceed.
1493 	 */
1494 
1495 	sc = arg;
1496 
1497 	KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1498 
1499 	if (sc->ndis_block->nmb_pendingreq != NULL)
1500 		panic("ndis_set_info() called while other request pending");
1501 	else
1502 		sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
1503 
1504 	/* I added this lock because it was present in the FreeBSD-current sources */
1505 	NDIS_LOCK(sc);
1506 
1507 	setfunc = sc->ndis_chars->nmc_setinfo_func;
1508 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1509 
1510 	if (adapter == NULL || setfunc == NULL) {
1511 		sc->ndis_block->nmb_pendingreq = NULL;
1512 		KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1513 		NDIS_UNLOCK(sc);
1514 		return(ENXIO);
1515 	}
1516 
1517 	NDIS_UNLOCK(sc);
1518 
1519 	rval = MSCALL6(setfunc, adapter, oid, buf, *buflen,
1520 	    &byteswritten, &bytesneeded);
1521 
1522 	sc->ndis_block->nmb_pendingreq = NULL;
1523 
1524 	KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1525 
1526 	if (rval == NDIS_STATUS_PENDING) {
1527 		mtx_lock(&ndis_req_mtx);
1528 		mtsleep(&sc->ndis_block->nmb_setstat, PZERO | PNORELOCK,
1529 		    "ndisset", 5 * hz, &ndis_req_mtx);
1530 		rval = sc->ndis_block->nmb_setstat;
1531 	}
1532 
1533 	if (byteswritten)
1534 		*buflen = byteswritten;
1535 	if (bytesneeded)
1536 		*buflen = bytesneeded;
1537 
1538 	if (rval == NDIS_STATUS_INVALID_LENGTH)
1539 		return(ENOSPC);
1540 
1541 	if (rval == NDIS_STATUS_INVALID_OID)
1542 		return(EINVAL);
1543 
1544 	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1545 	    rval == NDIS_STATUS_NOT_ACCEPTED)
1546 		return(ENOTSUP);
1547 
1548 	if (rval != NDIS_STATUS_SUCCESS)
1549 		return(ENODEV);
1550 
1551 	return(0);
1552 }
1553 
1554 typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
1555 
1556 int
1557 ndis_send_packets(void *arg, ndis_packet **packets, int cnt)
1558 {
1559 	struct ndis_softc	*sc;
1560 	ndis_handle		adapter;
1561 	__stdcall ndis_sendmulti_handler	sendfunc;
1562 	__stdcall ndis_senddone_func		senddonefunc;
1563 	int			i;
1564 	ndis_packet		*p;
1565 	uint8_t			irql = 0;	/* XXX: gcc */
1566 
1567 	sc = arg;
1568 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1569 	if (adapter == NULL)
1570 		return(ENXIO);
1571 	sendfunc = sc->ndis_chars->nmc_sendmulti_func;
1572 	senddonefunc = sc->ndis_block->nmb_senddone_func;
1573 
1574 	if (NDIS_SERIALIZED(sc->ndis_block))
1575 		KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1576 
1577 	MSCALL3(sendfunc, adapter, packets, cnt);
1578 
1579 	for (i = 0; i < cnt; i++) {
1580 		p = packets[i];
1581 		/*
1582 		 * Either the driver already handed the packet to
1583 		 * ndis_txeof() due to a failure, or it wants to keep
1584 		 * it and release it asynchronously later. Skip to the
1585 		 * next one.
1586 		 */
1587 		if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
1588 			continue;
1589 		MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status);
1590 	}
1591 
1592 	if (NDIS_SERIALIZED(sc->ndis_block))
1593 		KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1594 
1595 	return(0);
1596 }
1597 
1598 int
1599 ndis_send_packet(void *arg, ndis_packet *packet)
1600 {
1601 	struct ndis_softc	*sc;
1602 	ndis_handle		adapter;
1603 	ndis_status		status;
1604 	__stdcall ndis_sendsingle_handler	sendfunc;
1605 	__stdcall ndis_senddone_func		senddonefunc;
1606 	uint8_t			irql = 0;	/* XXX: gcc */
1607 
1608 	sc = arg;
1609 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1610 	if (adapter == NULL)
1611 		return(ENXIO);
1612 	sendfunc = sc->ndis_chars->nmc_sendsingle_func;
1613 	senddonefunc = sc->ndis_block->nmb_senddone_func;
1614 
1615 	if (NDIS_SERIALIZED(sc->ndis_block))
1616 		KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1617 	status = MSCALL3(sendfunc, adapter, packet,
1618 	    packet->np_private.npp_flags);
1619 
1620 	if (status == NDIS_STATUS_PENDING) {
1621 		if (NDIS_SERIALIZED(sc->ndis_block))
1622 			KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1623 		return(0);
1624 	}
1625 
1626 	MSCALL3(senddonefunc, sc->ndis_block, packet, status);
1627 
1628 	if (NDIS_SERIALIZED(sc->ndis_block))
1629 		KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1630 
1631 	return(0);
1632 }
1633 
1634 int
1635 ndis_init_dma(void *arg)
1636 {
1637 	struct ndis_softc	*sc;
1638 	int			i, error = 0;
1639 
1640 	sc = arg;
1641 
1642 	sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
1643 	    M_DEVBUF, M_NOWAIT|M_ZERO);
1644 
1645 	if (sc->ndis_tmaps == NULL)
1646 		return(ENOMEM);
1647 
1648 	for (i = 0; i < sc->ndis_maxpkts; i++) {
1649 #ifdef __FreeBSD__
1650 		error = bus_dmamap_create(sc->ndis_ttag, 0,
1651 		    &sc->ndis_tmaps[i]);
1652 #else
1653 		/*
1654 		bus_dmamap_create(sc->ndis_mtag, sizeof(bus_dmamap_t),
1655 				  1, sizeof(bus_dmamap_t), BUS_DMA_NOWAIT,
1656 				  0, &sc->ndis_mmaps[i]);
1657 		*/
1658 		bus_dmamap_create(sc->ndis_ttag, NDIS_MAXSEG * MCLBYTES,
1659 				  NDIS_MAXSEG, MCLBYTES, 0,
1660 				  BUS_DMA_NOWAIT, &sc->ndis_tmaps[i]);
1661 #endif
1662 		if (error) {
1663 			free(sc->ndis_tmaps, M_DEVBUF);
1664 			return(ENODEV);
1665 		}
1666 	}
1667 
1668 	return(0);
1669 }
1670 
1671 int
1672 ndis_destroy_dma(void *arg)
1673 {
1674 	struct ndis_softc	*sc;
1675 	struct mbuf		*m;
1676 	ndis_packet		*p = NULL;
1677 	int			i;
1678 
1679 	sc = arg;
1680 
1681 	for (i = 0; i < sc->ndis_maxpkts; i++) {
1682 		if (sc->ndis_txarray[i] != NULL) {
1683 			p = sc->ndis_txarray[i];
1684 			m = (struct mbuf *)p->np_rsvd[1];
1685 			if (m != NULL)
1686 				m_freem(m);
1687 			ndis_free_packet(sc->ndis_txarray[i]);
1688 		}
1689 		bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
1690 	}
1691 
1692 	free(sc->ndis_tmaps, M_DEVBUF);
1693 
1694 #ifdef __FreeBSD__
1695 	bus_dma_tag_destroy(sc->ndis_ttag);
1696 #endif
1697 
1698 	return(0);
1699 }
1700 
1701 int
1702 ndis_reset_nic(void *arg)
1703 {
1704 	struct ndis_softc	*sc;
1705 	ndis_handle		adapter;
1706 	__stdcall ndis_reset_handler	resetfunc;
1707 	uint8_t			addressing_reset;
1708 	int			rval;
1709 	uint8_t			irql = 0;	/* XXX: gcc */
1710 
1711 	sc = arg;
1712 
1713 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1714 	resetfunc = sc->ndis_chars->nmc_reset_func;
1715 
1716 	if (adapter == NULL || resetfunc == NULL)
1717 		return(EIO);
1718 
1719 	if (NDIS_SERIALIZED(sc->ndis_block))
1720 		KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1721 
1722 	rval = MSCALL2(resetfunc, &addressing_reset, adapter);
1723 
1724 	if (NDIS_SERIALIZED(sc->ndis_block))
1725 		KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1726 
1727 	if (rval == NDIS_STATUS_PENDING) {
1728 		mtsleep(sc, PZERO | PNORELOCK, "ndisrst", 0, &ndis_req_mtx);
1729 	}
1730 
1731 	return(0);
1732 }
1733 
1734 int
1735 ndis_halt_nic(void *arg)
1736 {
1737 	struct ndis_softc	*sc;
1738 	ndis_handle		adapter;
1739 	__stdcall ndis_halt_handler	haltfunc;
1740 
1741 	sc = arg;
1742 
1743 	NDIS_LOCK(sc);
1744 
1745 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1746 	if (adapter == NULL) {
1747 		NDIS_UNLOCK(sc);
1748 		return(EIO);
1749 	}
1750 
1751 	/*
1752 	 * The adapter context is only valid after the init
1753 	 * handler has been called, and is invalid once the
1754 	 * halt handler has been called.
1755 	 */
1756 
1757 	haltfunc = sc->ndis_chars->nmc_halt_func;
1758 
1759 	NDIS_UNLOCK(sc);
1760 
1761 	MSCALL1(haltfunc, adapter);
1762 
1763 	NDIS_LOCK(sc);
1764 
1765 	sc->ndis_block->nmb_miniportadapterctx = NULL;
1766 
1767 	NDIS_UNLOCK(sc);
1768 
1769 	return(0);
1770 }
1771 
1772 int
1773 ndis_shutdown_nic(void *arg)
1774 {
1775 	struct ndis_softc	*sc;
1776 	ndis_handle		adapter;
1777 	__stdcall ndis_shutdown_handler	shutdownfunc;
1778 
1779 	sc = arg;
1780 
1781 	NDIS_LOCK(sc);
1782 
1783 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1784 	shutdownfunc = sc->ndis_chars->nmc_shutdown_handler;
1785 
1786 	NDIS_UNLOCK(sc);
1787 
1788 	if (adapter == NULL || shutdownfunc == NULL)
1789 		return(EIO);
1790 
1791 	if (sc->ndis_chars->nmc_rsvd0 == NULL)
1792 		MSCALL1(shutdownfunc, adapter);
1793 	else
1794 		MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0);
1795 
1796 	ndis_shrink_thrqueue(8);
1797 	TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
1798 
1799 	return(0);
1800 }
1801 
1802 int
1803 ndis_init_nic(void *arg)
1804 {
1805 	struct ndis_softc	*sc;
1806 	ndis_miniport_block	*block;
1807         __stdcall ndis_init_handler	initfunc;
1808 	ndis_status		status, openstatus = 0;
1809 	ndis_medium		mediumarray[NdisMediumMax];
1810 	uint32_t		chosenmedium, i;
1811 
1812 	if (arg == NULL)
1813 		return(EINVAL);
1814 
1815 	sc = arg;
1816 
1817 	NDIS_LOCK(sc);
1818 
1819 	block = sc->ndis_block;
1820 	initfunc = sc->ndis_chars->nmc_init_func;
1821 
1822 	NDIS_UNLOCK(sc);
1823 
1824 	printf("sc->ndis_chars->nmc_version_major = %d\n\
1825 			sc->ndis_chars->nmc_version_minor = %d\n",
1826 			sc->ndis_chars->nmc_version_major,
1827 			sc->ndis_chars->nmc_version_minor);
1828 
1829 	for (i = 0; i < NdisMediumMax; i++)
1830 		mediumarray[i] = i;
1831 
1832         status = MSCALL6(initfunc, &openstatus, &chosenmedium,
1833             mediumarray, NdisMediumMax, block, block);
1834 
1835 	printf("status = %x", status);
1836 
1837 	/*
1838 	 * If the init fails, blow away the other exported routines
1839 	 * we obtained from the driver so we can't call them later.
1840 	 * If the init failed, none of these will work.
1841 	 */
1842 	if (status != NDIS_STATUS_SUCCESS) {
1843 		NDIS_LOCK(sc);
1844 
1845 		sc->ndis_block->nmb_miniportadapterctx = NULL;
1846 
1847 		NDIS_UNLOCK(sc);
1848 		return(ENXIO);
1849 	}
1850 
1851 	return(0);
1852 }
1853 
1854 void
1855 ndis_enable_intr(void *arg)
1856 {
1857 	struct ndis_softc	*sc;
1858 	ndis_handle		adapter;
1859 	__stdcall ndis_enable_interrupts_handler	intrenbfunc;
1860 
1861 	sc = arg;
1862 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1863 	intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func;
1864 	if (adapter == NULL || intrenbfunc == NULL)
1865 		return;
1866 	MSCALL1(intrenbfunc, adapter);
1867 
1868 	return;
1869 }
1870 
1871 void
1872 ndis_disable_intr(void *arg)
1873 {
1874 	struct ndis_softc	*sc;
1875 	ndis_handle		adapter;
1876 	__stdcall ndis_disable_interrupts_handler	intrdisfunc;
1877 
1878 	sc = arg;
1879 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1880 	intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func;
1881 	if (adapter == NULL || intrdisfunc == NULL)
1882 	    return;
1883 
1884 	MSCALL1(intrdisfunc, adapter);
1885 
1886 	return;
1887 }
1888 
1889 int
1890 ndis_isr(void *arg, int *ourintr, int *callhandler)
1891 {
1892 	struct ndis_softc	*sc;
1893 	ndis_handle		adapter;
1894 	__stdcall ndis_isr_handler	isrfunc;
1895 	uint8_t			accepted, queue;
1896 
1897 	if (arg == NULL || ourintr == NULL || callhandler == NULL)
1898 		return(EINVAL);
1899 
1900 	sc = arg;
1901 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1902 	isrfunc = sc->ndis_chars->nmc_isr_func;
1903 
1904 	if (adapter == NULL || isrfunc == NULL)
1905 		return(ENXIO);
1906 
1907 	MSCALL3(isrfunc, &accepted, &queue, adapter);
1908 
1909 	*ourintr = accepted;
1910 	*callhandler = queue;
1911 
1912 	return(0);
1913 }
1914 
1915 __stdcall static void
1916 ndis_intrhand(kdpc *dpc, device_object *dobj,
1917     irp *ip, struct ndis_softc *sc)
1918 {
1919 	ndis_handle		adapter;
1920 	__stdcall ndis_interrupt_handler	intrfunc;
1921 	uint8_t			irql = 0;	/* XXX: gcc */
1922 
1923 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1924 	intrfunc = sc->ndis_chars->nmc_interrupt_func;
1925 
1926 	if (adapter == NULL || intrfunc == NULL)
1927 		return;
1928 
1929 	if (NDIS_SERIALIZED(sc->ndis_block))
1930 		KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1931 
1932 	MSCALL1(intrfunc, adapter);
1933 
1934 	/* If there's a MiniportEnableInterrupt() routine, call it. */
1935 
1936 	ndis_enable_intr(sc);
1937 
1938 	if (NDIS_SERIALIZED(sc->ndis_block))
1939 		KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1940 
1941 	return;
1942 }
1943 
1944 int
1945 ndis_get_info(void *arg, ndis_oid oid, void *buf, int *buflen)
1946 {
1947 	struct ndis_softc	*sc;
1948 	ndis_status		rval;
1949 	ndis_handle		adapter;
1950 	__stdcall ndis_queryinfo_handler	queryfunc;
1951 	uint32_t		byteswritten = 0, bytesneeded = 0;
1952 #ifdef __FreeBSD__
1953 	int			error;
1954 #endif
1955 	uint8_t			irql = 0;	/* XXX: gcc */
1956 
1957 	//printf("in ndis_get_info\n");
1958 
1959 	sc = arg;
1960 	KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1961 
1962 	if (sc->ndis_block->nmb_pendingreq != NULL)
1963 		panic("ndis_get_info() called while other request pending");
1964 	else
1965 		sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
1966 
1967 	queryfunc = sc->ndis_chars->nmc_queryinfo_func;
1968 	adapter = sc->ndis_block->nmb_miniportadapterctx;
1969 
1970 	if (adapter == NULL || queryfunc == NULL) {
1971 		sc->ndis_block->nmb_pendingreq = NULL;
1972 		KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1973 		return(ENXIO);
1974 	}
1975 
1976 	rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen,
1977 	    &byteswritten, &bytesneeded);
1978 
1979 	sc->ndis_block->nmb_pendingreq = NULL;
1980 
1981 	KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1982 
1983 	/* Wait for requests that block. */
1984 
1985 	if (rval == NDIS_STATUS_PENDING) {
1986 		mtx_lock(&ndis_req_mtx);
1987 		mtsleep(&sc->ndis_block->nmb_getstat, PZERO | PNORELOCK,
1988 		    "ndisget", 5 * hz, &ndis_req_mtx);
1989 		rval = sc->ndis_block->nmb_getstat;
1990 	}
1991 
1992 	if (byteswritten)
1993 		*buflen = byteswritten;
1994 	if (bytesneeded)
1995 		*buflen = bytesneeded;
1996 
1997 	if (rval == NDIS_STATUS_INVALID_LENGTH ||
1998 	    rval == NDIS_STATUS_BUFFER_TOO_SHORT)
1999 		return(ENOSPC);
2000 
2001 	if (rval == NDIS_STATUS_INVALID_OID)
2002 		return(EINVAL);
2003 
2004 	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
2005 	    rval == NDIS_STATUS_NOT_ACCEPTED)
2006 		return(ENOTSUP);
2007 
2008 	if (rval != NDIS_STATUS_SUCCESS)
2009 		return(ENODEV);
2010 
2011 	return(0);
2012 }
2013 
2014 __stdcall uint32_t
2015 NdisAddDevice(driver_object *drv, device_object *pdo)
2016 {
2017 	device_object		*fdo;
2018 	ndis_miniport_block	*block;
2019 	struct ndis_softc	*sc;
2020 	uint32_t		status;
2021 
2022 	status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL,
2023 	    FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
2024 
2025 	if (status != STATUS_SUCCESS)
2026 		return(status);
2027 
2028 	block = fdo->do_devext;
2029 	block->nmb_deviceobj = fdo;
2030 	block->nmb_physdeviceobj = pdo;
2031 	block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo);
2032 	KeInitializeSpinLock(&block->nmb_lock);
2033 
2034 #ifdef __NetBSD__
2035 	/* NetBSD has a pointer to the callout object */
2036 	block->nmb_wkupdpctimer.nt_ktimer.k_handle =
2037 		malloc(sizeof(struct callout), M_DEVBUF, M_NOWAIT|M_ZERO);
2038 #endif
2039 
2040 	/*
2041 	 * Stash pointers to the miniport block and miniport
2042 	 * characteristics info in the if_ndis softc so the
2043 	 * UNIX wrapper driver can get to them later.
2044      */
2045 #ifdef __FreeBSD__
2046 	sc = device_get_softc(pdo->do_devext);
2047 #else /* __NetBSD__ */
2048 	sc = pdo->pdo_sc;
2049 	fdo->fdo_sc = sc;
2050 #endif
2051 	sc->ndis_block = block;
2052 	sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1);
2053 
2054 	IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap);
2055 
2056 	/* Finish up BSD-specific setup. */
2057 
2058 	block->nmb_signature = (void *)0xcafebabe;
2059 	block->nmb_status_func = kernndis_functbl[0].ipt_wrap;
2060 	block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap;
2061 	block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap;
2062 	block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap;
2063 	block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap;
2064 	block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap;
2065 	block->nmb_pendingreq = NULL;
2066 
2067 	ndis_enlarge_thrqueue(8);
2068 
2069 	TAILQ_INSERT_TAIL(&ndis_devhead, block, link);
2070 
2071 	return (STATUS_SUCCESS);
2072 }
2073 
2074 int
2075 ndis_unload_driver(void *arg)
2076 {
2077 	struct ndis_softc	*sc;
2078 	device_object		*fdo;
2079 
2080 	sc = arg;
2081 
2082 	if (sc->ndis_block->nmb_rlist != NULL)
2083 		free(sc->ndis_block->nmb_rlist, M_DEVBUF);
2084 
2085 	ndis_flush_sysctls(sc);
2086 
2087 	ndis_shrink_thrqueue(8);
2088 	TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
2089 
2090 	fdo = sc->ndis_block->nmb_deviceobj;
2091 	IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj);
2092 	IoDeleteDevice(fdo);
2093 
2094 	return(0);
2095 }
2096