Sync usage with man page.
[netbsd-mini2440.git] / sys / compat / ndis / kern_ndis.c
blob100c117eba51f89199a943d1fa64a36d6eb34244
1 /*-
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 #ifdef __FreeBSD__
35 __FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.60.2.5 2005/04/01 17:14:20 wpaul Exp $");
36 #endif
37 #ifdef __NetBSD__
38 __KERNEL_RCSID(0, "$NetBSD: kern_ndis.c,v 1.20 2009/05/06 22:38:31 ad Exp $");
39 #endif
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/unistd.h>
44 #include <sys/types.h>
45 #include <sys/errno.h>
46 #include <sys/callout.h>
47 #include <sys/socket.h>
48 #include <sys/queue.h>
49 #include <sys/sysctl.h>
50 #include <sys/proc.h>
51 #include <sys/malloc.h>
52 #include <sys/lock.h>
53 #ifdef __FreeBSD__
54 #include <sys/mutex.h>
55 #endif
56 #include <sys/conf.h>
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
68 #ifdef __NetBSD__
69 #include <dev/pci/pcivar.h>
70 #include <dev/pci/pcireg.h>
71 #endif
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>
83 #include <net80211/ieee80211_var.h>
84 #include <net80211/ieee80211_ioctl.h>
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>
95 MODULE(MODULE_CLASS_MISC, ndis, NULL);
97 #define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
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 *);
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),
118 { NULL, NULL, NULL }
121 struct nd_head ndis_devhead;
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;
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 #ifdef __NetBSD__
138 int np_needs_wakeup;
139 #endif
142 static void ndis_return(void *);
143 static int ndis_create_kthreads(void);
144 static void ndis_destroy_kthreads(void);
145 static void ndis_stop_thread(int);
146 static int ndis_enlarge_thrqueue(int);
147 static int ndis_shrink_thrqueue(int);
148 //#ifdef NDIS_LKM
149 static void ndis_runq(void *);
150 //#endif
152 #ifdef __FreeBSD__
153 static struct mtx ndis_thr_mtx;
154 #else /* __NetBSD__ */
155 static struct simplelock ndis_thr_mtx;
156 #define THR_LOCK() do {old_ipl = splnet(); simple_lock(&ndis_thr_mtx);} while(0)
157 #define THR_UNLOCK() do {simple_unlock(&ndis_thr_mtx); splx(old_ipl);} while(0)
158 #endif
160 static struct mtx ndis_req_mtx;
161 static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo;
162 static struct ndisqhead ndis_itodo;
163 static struct ndisqhead ndis_free;
164 static int ndis_jobs = 32;
166 static struct ndisproc ndis_tproc;
167 static struct ndisproc ndis_iproc;
170 * This allows us to export our symbols to other modules.
171 * Note that we call ourselves 'ndisapi' to avoid a namespace
172 * collision with if_ndis.ko, which internally calls itself
173 * 'ndis.'
176 #ifdef __FreeBSD__
177 static int
178 ndis_modevent(module_t mod, int cmd, void *arg)
180 int error = 0;
181 image_patch_table *patch;
183 switch (cmd) {
184 case MOD_LOAD:
185 /* Initialize subsystems */
186 windrv_libinit();
187 hal_libinit();
188 ndis_libinit();
189 ntoskrnl_libinit();
190 #ifdef usbimplemented
191 usbd_libinit();
192 #endif
194 patch = kernndis_functbl;
195 while (patch->ipt_func != NULL) {
196 windrv_wrap((funcptr)patch->ipt_func,
197 (funcptr *)&patch->ipt_wrap);
198 patch++;
201 ndis_create_kthreads();
203 TAILQ_INIT(&ndis_devhead);
205 break;
206 case MOD_SHUTDOWN:
207 /* stop kthreads */
208 ndis_destroy_kthreads();
209 if (TAILQ_FIRST(&ndis_devhead) == NULL) {
210 /* Shut down subsystems */
211 hal_libfini();
212 ndis_libfini();
213 ntoskrnl_libfini();
214 #ifdef usbimplemented
215 usbd_libfini();
216 #endif
217 windrv_libfini();
219 patch = kernndis_functbl;
220 while (patch->ipt_func != NULL) {
221 windrv_unwrap(patch->ipt_wrap);
222 patch++;
225 break;
226 case MOD_UNLOAD:
227 /* stop kthreads */
228 ndis_destroy_kthreads();
230 /* Shut down subsystems */
231 hal_libfini();
232 ndis_libfini();
233 ntoskrnl_libfini();
234 usbd_libfini();
235 windrv_libfini();
237 patch = kernndis_functbl;
238 while (patch->ipt_func != NULL) {
239 windrv_unwrap(patch->ipt_wrap);
240 patch++;
243 break;
244 default:
245 error = EINVAL;
246 break;
249 return(error);
251 DEV_MODULE(ndisapi, ndis_modevent, NULL);
252 MODULE_VERSION(ndisapi, 1);
253 #endif
255 static int
256 ndis_modcmd(modcmd_t cmd, void *arg)
258 int error = 0;
259 image_patch_table *patch;
261 switch (cmd) {
262 case MODULE_CMD_INIT:
263 /* Initialize subsystems */
264 windrv_libinit();
265 hal_libinit();
266 ndis_libinit();
267 ntoskrnl_libinit();
268 #ifdef usbimplemented
269 usbd_libinit();
270 #endif
272 patch = kernndis_functbl;
273 while (patch->ipt_func != NULL) {
274 windrv_wrap((funcptr)patch->ipt_func,
275 (funcptr *)&patch->ipt_wrap);
276 patch++;
279 TAILQ_INIT(&ndis_devhead);
281 ndis_create_kthreads();
282 break;
284 case MODULE_CMD_FINI:
285 /* stop kthreads */
286 ndis_destroy_kthreads();
288 /* Shut down subsystems */
289 hal_libfini();
290 ndis_libfini();
291 ntoskrnl_libfini();
292 #ifdef usbimplemented
293 usbd_libfini();
294 #endif
295 windrv_libfini();
297 patch = kernndis_functbl;
298 while (patch->ipt_func != NULL) {
299 windrv_unwrap(patch->ipt_wrap);
300 patch++;
303 break;
305 default:
306 error = ENOTTY;
307 break;
310 return(error);
314 * We create two kthreads for the NDIS subsystem. One of them is a task
315 * queue for performing various odd jobs. The other is an swi thread
316 * reserved exclusively for running interrupt handlers. The reason we
317 * have our own task queue is that there are some cases where we may
318 * need to sleep for a significant amount of time, and if we were to
319 * use one of the taskqueue threads, we might delay the processing
320 * of other pending tasks which might need to run right away. We have
321 * a separate swi thread because we don't want our interrupt handling
322 * to be delayed either.
324 * By default there are 32 jobs available to start, and another 8
325 * are added to the free list each time a new device is created.
328 /* Just for testing this can be removed later */
329 struct ndis_req *_ndis_taskqueue_req;
330 struct ndis_req *_ndis_swi_req;
331 int calling_in_swi = FALSE;
332 int calling_in_tq = FALSE;
333 int num_swi = 0;
334 int num_tq = 0;
336 static void
337 ndis_runq(void *arg)
339 struct ndis_req *r = NULL, *die = NULL;
340 struct ndisproc *p;
341 #ifdef __NetBSD__
342 int old_ipl;
343 #endif
345 p = arg;
347 while (1) {
349 /* Protect against interrupts between checking if the queue is empty, and going to sleep
350 * to avoid a wakeup before sleep.
352 old_ipl = splnet();
353 /* Sleep, but preserve our original priority. */
354 if(STAILQ_EMPTY(p->np_q)) {
355 /* TODO: If we get an interrupt between checking if the queue is empty,
356 * TODO: and sleeping, then in the interrupt, an item could be placed
357 * TODO: on the queue, and we could be woken up before we sleep.
360 ndis_thsuspend(p->np_p, NULL, 0);
362 splx(old_ipl);
364 #ifdef __NetBSD__
365 p->np_needs_wakeup = FALSE;
366 #endif
368 /* Look for any jobs on the work queue. */
369 #ifdef __FreeBSD__
370 mtx_lock_spin(&ndis_thr_mtx);
371 #else /* __NetBSD__ */
372 THR_LOCK();
373 #endif
375 p->np_state = NDIS_PSTATE_RUNNING;
376 while(!STAILQ_EMPTY(p->np_q)/*STAILQ_FIRST(p->np_q) != NULL*/) {
377 r = STAILQ_FIRST(p->np_q);
378 STAILQ_REMOVE_HEAD(p->np_q, link);
380 /* for debugging */
382 if(p == &ndis_tproc) {
383 num_tq++;
384 _ndis_taskqueue_req = r;
385 r->area = 1;
386 } else if(p == &ndis_iproc) {
387 num_swi++;
388 _ndis_swi_req = r;
389 r->area = 2;
391 #ifdef __FreeBSD__
392 mtx_unlock_spin(&ndis_thr_mtx);
393 #else /* __NetBSD__ */
394 THR_UNLOCK();
395 #endif
396 /* Just for debugging */
398 if(p == &ndis_tproc) {
399 calling_in_tq = TRUE;
400 } else if(p == &ndis_iproc) {
401 calling_in_swi = TRUE;
404 /* Do the work. */
405 if (r->nr_func != NULL)
406 (*r->nr_func)(r->nr_arg);
408 /* Just for debugging */
409 if(p == &ndis_tproc) {
410 calling_in_tq = FALSE;
411 } else if(p == &ndis_iproc) {
412 calling_in_swi = FALSE;
415 #ifdef __FreeBSD__
416 mtx_lock_spin(&ndis_thr_mtx);
417 #else /* __NetBSD__ */
418 THR_LOCK();
419 #endif
421 /* Zeroing out the ndis_req is just for debugging */
422 //memset(r, 0, sizeof(struct ndis_req));
423 STAILQ_INSERT_HEAD(&ndis_free, r, link);
425 /* Check for a shutdown request */
426 if (r->nr_exit == TRUE)
427 die = r;
429 p->np_state = NDIS_PSTATE_SLEEPING;
431 #ifdef __FreeBSD__
432 mtx_unlock_spin(&ndis_thr_mtx);
433 #else /* __NetBSD__ */
434 THR_UNLOCK();
435 #endif
437 /* Bail if we were told to shut down. */
439 if (die != NULL)
440 break;
443 wakeup(die);
444 #ifdef __FreeBSD__
445 #if __FreeBSD_version < 502113
446 mtx_lock(&Giant);
447 #endif
448 #endif
449 if(p == &ndis_tproc) {
450 printf("taskqueue thread exiting!\n");
451 } else if(p == &ndis_iproc) {
452 printf("swi thread exiting!\n");
454 kthread_exit(0);
455 return; /* notreached */
458 /*static*/ int
459 ndis_create_kthreads(void)
461 struct ndis_req *r;
462 int i, error = 0;
464 printf("in ndis_create_kthreads\n");
466 #ifdef __FreeBSD__
467 mtx_init(&ndis_thr_mtx, "NDIS thread lock", NULL, MTX_SPIN);
468 #else /* __NetBSD__ */
469 simple_lock_init(&ndis_thr_mtx);
470 //lockinit(&ndis_thr_mtx, PWAIT, "NDIS thread lock", 0, 0);
471 #endif
472 mtx_init(&ndis_req_mtx, "NDIS request lock", MTX_NDIS_LOCK, MTX_DEF);
474 STAILQ_INIT(&ndis_ttodo);
475 STAILQ_INIT(&ndis_itodo);
476 STAILQ_INIT(&ndis_free);
478 for (i = 0; i < ndis_jobs; i++) {
479 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK|M_ZERO);
480 if (r == NULL) {
481 error = ENOMEM;
482 break;
484 STAILQ_INSERT_HEAD(&ndis_free, r, link);
487 if (error == 0) {
488 ndis_tproc.np_q = &ndis_ttodo;
489 ndis_tproc.np_state = NDIS_PSTATE_SLEEPING;
490 #ifdef __FreeBSD__
491 error = kthread_create(ndis_runq, &ndis_tproc,
492 &ndis_tproc.np_p, RFHIGHPID,
493 NDIS_KSTACK_PAGES, "ndis taskqueue");
494 #else /* __NetBSD__ */
495 error = ndis_kthread_create(ndis_runq, &ndis_tproc,
496 &ndis_tproc.np_p, ndis_tproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis taskqueue");
497 #endif
500 if (error == 0) {
501 ndis_iproc.np_q = &ndis_itodo;
502 ndis_iproc.np_state = NDIS_PSTATE_SLEEPING;
503 #ifdef __FreeBSD__
504 error = kthread_create(ndis_runq, &ndis_iproc,
505 &ndis_iproc.np_p, RFHIGHPID,
506 NDIS_KSTACK_PAGES, "ndis swi");
507 #else
508 error = ndis_kthread_create(ndis_runq, &ndis_iproc,
509 &ndis_iproc.np_p, ndis_iproc.np_stack, PAGE_SIZE*NDIS_KSTACK_PAGES, "ndis swi");
510 #endif
513 if (error) {
514 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
515 STAILQ_REMOVE_HEAD(&ndis_free, link);
516 free(r, M_DEVBUF);
518 return(error);
521 return(0);
524 static void
525 ndis_destroy_kthreads(void)
527 struct ndis_req *r;
529 /* Stop the threads. */
531 ndis_stop_thread(NDIS_TASKQUEUE);
532 ndis_stop_thread(NDIS_SWI);
534 /* Destroy request structures. */
536 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
537 STAILQ_REMOVE_HEAD(&ndis_free, link);
538 free(r, M_DEVBUF);
541 mtx_destroy(&ndis_req_mtx);
542 #ifndef __NetBSD__
543 mtx_destroy(&ndis_thr_mtx);
544 #endif
546 return;
549 static void
550 ndis_stop_thread(int t)
552 struct ndis_req *r;
553 struct ndisqhead *q;
554 struct proc *p;
555 #ifdef __NetBSD__
556 int old_ipl;
557 #endif
559 if (t == NDIS_TASKQUEUE) {
560 q = &ndis_ttodo;
561 p = ndis_tproc.np_p;
562 } else {
563 q = &ndis_itodo;
564 p = ndis_iproc.np_p;
567 /* Create and post a special 'exit' job. */
569 #ifdef __FreeBSD__
570 mtx_lock_spin(&ndis_thr_mtx);
571 #else /* __NetBSD__ */
572 THR_LOCK();
573 #endif
574 r = STAILQ_FIRST(&ndis_free);
575 STAILQ_REMOVE_HEAD(&ndis_free, link);
576 r->nr_func = NULL;
577 r->nr_arg = NULL;
578 r->nr_exit = TRUE;
579 r->area = 3;
580 STAILQ_INSERT_TAIL(q, r, link);
581 #ifdef __FreeBSD__
582 mtx_unlock_spin(&ndis_thr_mtx);
583 #else /* __NetBSD__ */
584 THR_UNLOCK();
585 #endif
587 ndis_thresume(p);
589 /* wait for thread exit */
591 #ifdef __FreeBSD__
592 tsleep(r, curthread->td_priority|PCATCH, "ndisthexit", hz * 60);
593 #else
594 tsleep(r, curlwp->l_priority|PCATCH, "ndisthexit", hz * 60);
595 #endif
597 /* Now empty the job list. */
598 #ifdef __FreeBSD__
599 mtx_lock_spin(&ndis_thr_mtx);
600 #else /* __NetBSD__ */
601 THR_LOCK();
602 #endif
603 while ((r = STAILQ_FIRST(q)) != NULL) {
604 STAILQ_REMOVE_HEAD(q, link);
605 STAILQ_INSERT_HEAD(&ndis_free, r, link);
608 #ifdef __FreeBSD__
609 mtx_unlock_spin(&ndis_thr_mtx);
610 #else /* __NetBSD__ */
611 THR_UNLOCK();
612 #endif
614 return;
617 static int
618 ndis_enlarge_thrqueue(int cnt)
620 struct ndis_req *r;
621 int i;
622 #ifdef __NetBSD__
623 int old_ipl;
624 #endif
626 for (i = 0; i < cnt; i++) {
627 r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
628 if (r == NULL)
629 return(ENOMEM);
630 #ifdef __FreeBSD__
631 mtx_lock_spin(&ndis_thr_mtx);
632 #else /* __NetBSD__ */
633 THR_LOCK();
634 #endif
635 STAILQ_INSERT_HEAD(&ndis_free, r, link);
636 ndis_jobs++;
637 #ifdef __FreeBSD__
638 mtx_unlock_spin(&ndis_thr_mtx);
639 #else /* __NetBSD__ */
640 THR_UNLOCK();
641 #endif
644 return(0);
647 static int
648 ndis_shrink_thrqueue(int cnt)
650 struct ndis_req *r;
651 int i;
652 #ifdef __NetBSD__
653 int old_ipl;
654 #endif
656 for (i = 0; i < cnt; i++) {
657 #ifdef __FreeBSD__
658 mtx_lock_spin(&ndis_thr_mtx);
659 #else /* __NetBSD__ */
660 THR_LOCK();
661 #endif
662 r = STAILQ_FIRST(&ndis_free);
663 if (r == NULL) {
664 #ifdef __FreeBSD__
665 mtx_unlock_spin(&ndis_thr_mtx);
666 #else /* __NetBSD__ */
667 THR_UNLOCK();
668 #endif
669 return(ENOMEM);
671 STAILQ_REMOVE_HEAD(&ndis_free, link);
672 ndis_jobs--;
673 #ifdef __FreeBSD__
674 mtx_unlock_spin(&ndis_thr_mtx);
675 #else /* __NetBSD__ */
676 THR_UNLOCK();
677 #endif
679 free(r, M_DEVBUF);
682 return(0);
686 ndis_unsched(void (*func)(void *), void *arg, int t)
688 struct ndis_req *r;
689 struct ndisqhead *q;
690 struct proc *p;
691 #ifdef __NetBSD__
692 int old_ipl;
693 #endif
695 if (t == NDIS_TASKQUEUE) {
696 q = &ndis_ttodo;
697 p = ndis_tproc.np_p;
698 } else {
699 q = &ndis_itodo;
700 p = ndis_iproc.np_p;
703 #ifdef __FreeBSD__
704 mtx_lock_spin(&ndis_thr_mtx);
705 #else /* __NetBSD__ */
706 THR_LOCK();
707 #endif
708 STAILQ_FOREACH(r, q, link) {
709 if (r->nr_func == func && r->nr_arg == arg) {
710 r->area = 4;
711 STAILQ_REMOVE(q, r, ndis_req, link);
712 STAILQ_INSERT_HEAD(&ndis_free, r, link);
713 #ifdef __FreeBSD__
714 mtx_unlock_spin(&ndis_thr_mtx);
715 #else /* __NetBSD__ */
716 THR_UNLOCK();
717 #endif
718 return(0);
721 #ifdef __FreeBSD__
722 mtx_unlock_spin(&ndis_thr_mtx);
723 #else /* __NetBSD__ */
724 THR_UNLOCK();
725 #endif
726 return(ENOENT);
729 /* just for testing */
730 struct ndis_req *ls_tq_req = NULL;
731 struct ndis_req *ls_swi_req = NULL;
734 ndis_sched(void (*func)(void *), void *arg, int t)
736 struct ndis_req *r;
737 struct ndisqhead *q;
738 struct proc *p;
739 int s;
740 #ifdef __NetBSD__
741 int old_ipl;
742 /* just for debugging */
743 struct ndis_req **ls;
744 //struct lwp *l = curlwp;
745 #endif
747 if (t == NDIS_TASKQUEUE) {
748 ls = &ls_tq_req;
749 q = &ndis_ttodo;
750 p = ndis_tproc.np_p;
751 } else {
752 ls = &ls_swi_req;
753 q = &ndis_itodo;
754 p = ndis_iproc.np_p;
757 #ifdef __FreeBSD__
758 mtx_lock_spin(&ndis_thr_mtx);
759 #else /* __NetBSD__ */
760 THR_LOCK();
761 #endif
764 * Check to see if an instance of this job is already
765 * pending. If so, don't bother queuing it again.
767 STAILQ_FOREACH(r, q, link) {
768 if (r->nr_func == func && r->nr_arg == arg) {
769 #ifdef __NetBSD__
770 if (t == NDIS_TASKQUEUE)
771 s = ndis_tproc.np_state;
772 else
773 s = ndis_iproc.np_state;
774 #endif
775 #ifdef __FreeBSD__
776 mtx_unlock_spin(&ndis_thr_mtx);
777 #else /* __NetBSD__ */
778 THR_UNLOCK();
779 #endif
780 #ifdef __NetBSD__
781 /* The swi thread seemed to be going to sleep, and not waking up
782 * again, so I thought I'd try this out...
784 if (s == NDIS_PSTATE_SLEEPING)
785 ndis_thresume(p);
786 #endif
787 return(0);
790 r = STAILQ_FIRST(&ndis_free);
791 if (r == NULL) {
792 #ifdef __FreeBSD__
793 mtx_unlock_spin(&ndis_thr_mtx);
794 #else /* __NetBSD__ */
795 THR_UNLOCK();
796 #endif
797 return(EAGAIN);
799 STAILQ_REMOVE_HEAD(&ndis_free, link);
800 #ifdef __NetBSD__
801 //memset(r, 0, sizeof(struct ndis_req));
802 #endif
803 *ls = r;
804 r->nr_func = func;
805 r->nr_arg = arg;
806 r->nr_exit = FALSE;
807 r->area = 5;
808 STAILQ_INSERT_TAIL(q, r, link);
809 if (t == NDIS_TASKQUEUE) {
810 s = ndis_tproc.np_state;
811 #ifdef __NetBSD__
812 ndis_tproc.np_needs_wakeup = TRUE;
813 #endif
814 } else {
815 s = ndis_iproc.np_state;
816 #ifdef __NetBSD__
817 ndis_iproc.np_needs_wakeup = TRUE;
818 #endif
821 #ifdef __FreeBSD__
822 mtx_unlock_spin(&ndis_thr_mtx);
823 #else /* __NetBSD__ */
824 THR_UNLOCK();
825 #endif
828 * Post the job, but only if the thread is actually blocked
829 * on its own suspend call. If a driver queues up a job with
830 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(),
831 * it may suspend there, and in that case we don't want to wake
832 * it up until KeWaitForObject() gets woken up on its own.
834 if (s == NDIS_PSTATE_SLEEPING) {
835 ndis_thresume(p);
838 return(0);
841 /* Try out writing my own version of ndis_sched() for NetBSD in which I just
842 * call the function instead of scheduling it. I know this isn't
843 * what's supposed to be done, but I've been having a lot of problems
844 * with the SWI and taskqueue threads, and just thought I'd give this
845 * a try.
848 /* I don't think this will work, because it means that DPC's will be
849 * called from the bottom half of the kernel, so they won't be able
850 * to sleep using KeWaitForSingleObject.
854 ndis_sched(void (*func)(void *), void *arg, int t)
856 if(func != NULL) {
857 (*func)(arg);
860 return 0;
865 ndis_thsuspend(p, m, timo)
866 struct proc *p;
867 #ifdef __FreeBSD__
868 struct mtx *m;
869 #else /* __NetBSD__*/
870 struct simplelock *m;
871 #endif
872 int timo;
874 int error;
876 #ifdef __FreeBSD__
877 if (m != NULL) {
878 error = msleep(&p->p_siglist, m,
879 curthread->td_priority, "ndissp", timo);
880 } else {
881 PROC_LOCK(p);
882 error = msleep(&p->p_siglist, &p->p_mtx,
883 curthread->td_priority|PDROP, "ndissp", timo);
885 #else
886 /* TODO: Why do they wait on &p->p_siglist? I noticed that in FreeBSD's
887 * src/sys/sys/proc.h there is some mention of p_siglist having to do with
888 * M:N threading.
890 if (m != NULL) {
891 //mtx_unlock(m);
892 error = ltsleep(&p->p_sigpend.sp_set, curlwp->l_priority,
893 "ndissp", timo, m);
894 //mtx_lock(m);
895 } else {
896 error = ltsleep(&p->p_sigpend.sp_set, curlwp->l_priority/*|PNORELOCK*/,
897 "ndissp", timo, 0 /*&p->p_lock*/);
900 #endif
902 return(error);
905 void
906 ndis_thresume(struct proc *p)
908 wakeup(&p->p_sigpend.sp_set);
910 return;
913 __stdcall static void
914 ndis_sendrsrcavail_func(ndis_handle adapter)
916 return;
919 __stdcall static void
920 ndis_status_func(ndis_handle adapter, ndis_status status, void *sbuf,
921 uint32_t slen)
923 ndis_miniport_block *block;
924 struct ndis_softc *sc;
925 struct ifnet *ifp;
927 block = adapter;
928 #ifdef __FreeBSD__
929 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
930 #else /* __NetBSD__ */
931 sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
932 #endif
934 #ifdef __FreeBSD__
935 ifp = &sc->arpcom.ac_if;
936 #else
937 ifp = &sc->arpcom.ec_if;
938 #endif
939 if (ifp->if_flags & IFF_DEBUG)
940 printf("%s: status: %x\n",
941 device_xname(sc->ndis_dev), status);
942 return;
945 __stdcall static void
946 ndis_statusdone_func(ndis_handle adapter)
948 ndis_miniport_block *block;
949 struct ndis_softc *sc;
950 struct ifnet *ifp;
952 block = adapter;
953 #ifdef __FreeBSD__
954 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
955 #else /* __NetBSD__ */
956 sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
957 #endif
959 #ifdef __FreeBSD__
960 ifp = &sc->arpcom.ac_if;
961 #else
962 ifp = &sc->arpcom.ec_if;
963 #endif
964 if (ifp->if_flags & IFF_DEBUG)
965 printf("%s: status complete\n",
966 device_xname(sc->ndis_dev));
967 return;
970 __stdcall static void
971 ndis_setdone_func(ndis_handle adapter, ndis_status status)
973 ndis_miniport_block *block;
974 block = adapter;
976 block->nmb_setstat = status;
977 wakeup(&block->nmb_setstat);
978 return;
981 __stdcall static void
982 ndis_getdone_func(ndis_handle adapter, ndis_status status)
984 ndis_miniport_block *block;
985 block = adapter;
987 block->nmb_getstat = status;
988 wakeup(&block->nmb_getstat);
989 return;
992 __stdcall static void
993 ndis_resetdone_func(ndis_handle adapter, ndis_status status,
994 uint8_t addressingreset)
996 ndis_miniport_block *block;
997 struct ndis_softc *sc;
998 struct ifnet *ifp;
1000 block = adapter;
1001 #ifdef __FreeBSD__
1002 sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1003 #else /* __NetBSD__ */
1004 sc = (struct ndis_softc *)block->nmb_physdeviceobj->pdo_sc;
1005 #endif
1007 #ifdef __FreeBSD__
1008 ifp = &sc->arpcom.ac_if;
1009 #else
1010 ifp = &sc->arpcom.ec_if;
1011 #endif
1013 if (ifp->if_flags & IFF_DEBUG)
1014 printf("%s: reset done...\n",
1015 device_xname(sc->ndis_dev));
1016 wakeup(sc);
1017 return;
1020 #ifdef __FreeBSD__
1021 /* FreeBSD version of ndis_create_sysctls() */
1023 ndis_create_sysctls(void *arg)
1025 struct ndis_softc *sc;
1026 ndis_cfg *vals;
1027 char buf[256];
1028 struct sysctl_oid *oidp;
1029 struct sysctl_ctx_entry *e;
1031 if (arg == NULL)
1032 return(EINVAL);
1034 sc = arg;
1035 vals = sc->ndis_regvals;
1037 TAILQ_INIT(&sc->ndis_cfglist_head);
1039 #if __FreeBSD_version < 502113
1040 /* Create the sysctl tree. */
1042 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
1043 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
1044 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
1045 device_get_desc(sc->ndis_dev));
1047 #endif
1048 /* Add the driver-specific registry keys. */
1050 vals = sc->ndis_regvals;
1051 while(1) {
1052 if (vals->nc_cfgkey == NULL)
1053 break;
1054 if (vals->nc_idx != sc->ndis_devidx) {
1055 vals++;
1056 continue;
1059 /* See if we already have a sysctl with this name */
1061 oidp = NULL;
1062 #if __FreeBSD_version < 502113
1063 TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
1064 #else
1065 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
1066 #endif
1067 oidp = e->entry;
1068 if (ndis_strcasecmp(oidp->oid_name,
1069 vals->nc_cfgkey) == 0)
1070 break;
1071 oidp = NULL;
1074 if (oidp != NULL) {
1075 vals++;
1076 continue;
1079 #if __FreeBSD_version < 502113
1080 SYSCTL_ADD_STRING(&sc->ndis_ctx,
1081 SYSCTL_CHILDREN(sc->ndis_tree),
1082 #else
1083 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
1084 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
1085 #endif
1086 OID_AUTO, vals->nc_cfgkey,
1087 CTLFLAG_RW, vals->nc_val,
1088 sizeof(vals->nc_val),
1089 vals->nc_cfgdesc);
1090 vals++;
1093 /* Now add a couple of builtin keys. */
1096 * Environment can be either Windows (0) or WindowsNT (1).
1097 * We qualify as the latter.
1099 ndis_add_sysctl(sc, "Environment",
1100 "Windows environment", "1", CTLFLAG_RD);
1102 /* NDIS version should be 5.1. */
1103 ndis_add_sysctl(sc, "NdisVersion",
1104 "NDIS API Version", "0x00050001", CTLFLAG_RD);
1106 /* Bus type (PCI, PCMCIA, etc...) */
1107 sprintf(buf, "%d", (int)sc->ndis_iftype);
1108 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
1110 if (sc->ndis_res_io != NULL) {
1111 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io));
1112 ndis_add_sysctl(sc, "IOBaseAddress",
1113 "Base I/O Address", buf, CTLFLAG_RD);
1116 if (sc->ndis_irq != NULL) {
1117 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq));
1118 ndis_add_sysctl(sc, "InterruptNumber",
1119 "Interrupt Number", buf, CTLFLAG_RD);
1122 return(0);
1124 #endif /* __FreeBSD__ */
1126 #ifdef __NetBSD__
1127 /* NetBSD version of ndis_create_sysctls() */
1129 ndis_create_sysctls(void *arg)
1131 struct ndis_softc *sc;
1132 ndis_cfg *vals;
1133 const struct sysctlnode *ndis_node;
1134 char buf[256];
1136 printf("in ndis_create_sysctls()\n");
1138 if (arg == NULL)
1139 return(EINVAL);
1141 sc = arg;
1142 vals = sc->ndis_regvals;
1144 TAILQ_INIT(&sc->ndis_cfglist_head);
1146 /* Create the sysctl tree. */
1147 sysctl_createv(&sc->sysctllog, 0, NULL, &ndis_node, CTLFLAG_READWRITE, CTLTYPE_NODE,
1148 device_xname(sc->ndis_dev), NULL, NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
1150 /* Store the number of the ndis mib */
1151 sc->ndis_sysctl_mib = ndis_node->sysctl_num;
1153 /* Add the driver-specific registry keys. */
1154 vals = sc->ndis_regvals;
1155 while(1) {
1156 if (vals->nc_cfgkey == NULL)
1157 break;
1158 if (vals->nc_idx != sc->ndis_devidx) {
1159 vals++;
1160 continue;
1163 /* See if we already have a sysctl with this name */
1164 /* TODO: Is something like this necessary in NetBSD? I'm guessing this
1165 TODO: is just checking if any of the information in the .inf file was
1166 TODO: already determined by FreeBSD's autoconfiguration which seems to
1167 TODO: add dev.XXX sysctl's beginning with %. (NetBSD dosen't seem to do this).
1170 /* TODO: use CTLFLAG_OWNDATA or not? */
1172 sysctl_createv(&sc->sysctllog, 0, NULL, NULL,
1173 CTLFLAG_READWRITE|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA, CTLTYPE_STRING,
1174 vals->nc_cfgkey, vals->nc_cfgdesc, NULL, 0, vals->nc_val, strlen(vals->nc_val),
1175 ndis_node->sysctl_num, CTL_CREATE, CTL_EOL);
1177 ndis_add_sysctl(sc, vals->nc_cfgkey,
1178 vals->nc_cfgdesc, vals->nc_val, CTLFLAG_READWRITE);
1180 vals++;
1181 } /* end while */
1183 /* Now add a couple of builtin keys. */
1186 * Environment can be either Windows (0) or WindowsNT (1).
1187 * We qualify as the latter.
1189 #ifdef __NetBSD__
1190 #define CTLFLAG_RD CTLFLAG_READONLY
1191 /* TODO: do we need something like rman_get_start? */
1192 #define rman_get_start(x) x
1193 #endif
1194 ndis_add_sysctl(sc, "Environment",
1195 "Windows environment", "1", CTLFLAG_RD);
1197 /* NDIS version should be 5.1. */
1198 ndis_add_sysctl(sc, "NdisVersion",
1199 /*"NDIS API Version"*/ "Version", "0x00050001", CTLFLAG_RD);
1201 /* Bus type (PCI, PCMCIA, etc...) */
1202 sprintf(buf, "%d", (int)sc->ndis_iftype);
1203 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
1205 if (sc->ndis_res_io != NULL) {
1206 sprintf(buf, "0x%lx", (long unsigned int)rman_get_start(sc->ndis_res_io));
1207 ndis_add_sysctl(sc, "IOBaseAddress",
1208 /*"Base I/O Address"*/ "Base I/O", buf, CTLFLAG_RD);
1211 if (sc->ndis_irq != NULL) {
1212 sprintf(buf, "%lu", (long unsigned int)rman_get_start(sc->ndis_irq));
1213 ndis_add_sysctl(sc, "InterruptNumber",
1214 "Interrupt Number", buf, CTLFLAG_RD);
1217 return(0);
1219 #endif /* __NetBSD__ */
1221 char *ndis_strdup(const char *src);
1223 char *ndis_strdup(const char *src)
1225 char *ret;
1227 ret = malloc(strlen(src), M_DEVBUF, M_NOWAIT|M_ZERO);
1228 if (ret == NULL) {
1229 printf("ndis_strdup failed\n");
1230 return(NULL);
1232 strcpy(ret, src);
1234 return ret;
1238 ndis_add_sysctl(void *arg, const char *key, const char *desc, const char *val, int flag)
1240 struct ndis_softc *sc;
1241 struct ndis_cfglist *cfg;
1242 char descstr[256];
1243 #ifdef __NetBSD__
1244 char newkey[MAX_SYSCTL_LEN+1];
1245 #endif
1247 sc = arg;
1249 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
1251 if (cfg == NULL)
1252 return(ENOMEM);
1254 /* I added this because NetBSD sysctl node names can't begin with
1255 * a digit.
1257 #ifdef __NetBSD__
1258 if(strlen(key) + strlen("ndis_") > MAX_SYSCTL_LEN) {
1259 panic("sysctl name too long: %s\n", key);
1261 strcpy(newkey, "ndis_");
1262 strcpy(newkey + strlen("ndis_"), key);
1263 key = newkey;
1264 #endif
1266 cfg->ndis_cfg.nc_cfgkey = ndis_strdup(key);
1268 if (desc == NULL) {
1269 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
1270 cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(descstr);
1271 } else
1272 cfg->ndis_cfg.nc_cfgdesc = ndis_strdup(desc);
1273 strcpy(cfg->ndis_cfg.nc_val, val);
1275 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
1277 #ifdef __FreeBSD__
1278 #if __FreeBSD_version < 502113
1279 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
1280 #else
1281 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
1282 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
1283 #endif
1284 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
1285 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
1286 cfg->ndis_cfg.nc_cfgdesc);
1287 #else /* __NetBSD__ */
1288 /* TODO: use CTLFLAG_OWNDATA or not? */
1289 sysctl_createv(&sc->sysctllog, 0, NULL, NULL, flag/*|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA*/, CTLTYPE_STRING,
1290 cfg->ndis_cfg.nc_cfgkey, cfg->ndis_cfg.nc_cfgdesc, NULL, 0, cfg->ndis_cfg.nc_val,
1291 strlen(cfg->ndis_cfg.nc_val), sc->ndis_sysctl_mib, CTL_CREATE, CTL_EOL);
1292 #endif
1293 return(0);
1297 ndis_flush_sysctls(void *arg)
1299 struct ndis_softc *sc;
1300 struct ndis_cfglist *cfg;
1302 sc = arg;
1304 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
1305 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
1306 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
1307 #ifdef __FreeBSD__
1308 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
1309 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
1310 #endif
1311 free(cfg, M_DEVBUF);
1314 return(0);
1317 static void
1318 ndis_return(void *arg)
1320 struct ndis_softc *sc;
1321 __stdcall ndis_return_handler returnfunc;
1322 ndis_handle adapter;
1323 ndis_packet *p;
1324 uint8_t irql = 0; /* XXX: gcc */
1326 p = arg;
1327 sc = p->np_softc;
1328 adapter = sc->ndis_block->nmb_miniportadapterctx;
1330 if (adapter == NULL)
1331 return;
1333 returnfunc = sc->ndis_chars->nmc_return_packet_func;
1335 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1336 MSCALL2(returnfunc, adapter, p);
1337 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1339 return;
1342 void
1343 #ifdef __FreeBSD__
1344 ndis_return_packet(buf, arg)
1345 void *buf; /* not used */
1346 void *arg;
1347 #else
1348 ndis_return_packet(struct mbuf *m, void *buf,
1349 size_t size, void *arg)
1350 #endif
1353 ndis_packet *p;
1355 if (arg == NULL)
1356 return;
1358 p = arg;
1360 /* Decrement refcount. */
1361 p->np_refcnt--;
1363 /* Release packet when refcount hits zero, otherwise return. */
1364 if (p->np_refcnt)
1365 return;
1367 ndis_sched(ndis_return, p, NDIS_TASKQUEUE);
1369 return;
1372 void
1373 ndis_free_bufs(ndis_buffer *b0)
1375 ndis_buffer *next;
1377 if (b0 == NULL)
1378 return;
1380 while(b0 != NULL) {
1381 next = b0->mdl_next;
1382 IoFreeMdl(b0);
1383 b0 = next;
1386 return;
1388 int in_reset = 0;
1389 void
1390 ndis_free_packet(ndis_packet *p)
1392 if (p == NULL)
1393 return;
1395 ndis_free_bufs(p->np_private.npp_head);
1396 NdisFreePacket(p);
1397 return;
1400 #ifdef __FreeBSD__
1402 ndis_convert_res(void *arg)
1404 struct ndis_softc *sc;
1405 ndis_resource_list *rl = NULL;
1406 cm_partial_resource_desc *prd = NULL;
1407 ndis_miniport_block *block;
1408 device_t dev;
1409 struct resource_list *brl;
1410 struct resource_list_entry *brle;
1411 #if __FreeBSD_version < 600022
1412 struct resource_list brl_rev;
1413 struct resource_list_entry *n;
1414 #endif
1415 int error = 0;
1417 sc = arg;
1418 block = sc->ndis_block;
1419 dev = sc->ndis_dev;
1421 #if __FreeBSD_version < 600022
1422 SLIST_INIT(&brl_rev);
1423 #endif
1424 rl = malloc(sizeof(ndis_resource_list) +
1425 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
1426 M_DEVBUF, M_NOWAIT|M_ZERO);
1428 if (rl == NULL)
1429 return(ENOMEM);
1431 rl->cprl_version = 5;
1432 rl->cprl_version = 1;
1433 rl->cprl_count = sc->ndis_rescnt;
1434 prd = rl->cprl_partial_descs;
1436 brl = BUS_GET_RESOURCE_LIST(dev, dev);
1438 if (brl != NULL) {
1440 #if __FreeBSD_version < 600022
1442 * We have a small problem. Some PCI devices have
1443 * multiple I/O ranges. Windows orders them starting
1444 * from lowest numbered BAR to highest. We discover
1445 * them in that order too, but insert them into a singly
1446 * linked list head first, which means when time comes
1447 * to traverse the list, we enumerate them in reverse
1448 * order. This screws up some drivers which expect the
1449 * BARs to be in ascending order so that they can choose
1450 * the "first" one as their register space. Unfortunately,
1451 * in order to fix this, we have to create our own
1452 * temporary list with the entries in reverse order.
1454 SLIST_FOREACH(brle, brl, link) {
1455 n = malloc(sizeof(struct resource_list_entry),
1456 M_TEMP, M_NOWAIT);
1457 if (n == NULL) {
1458 error = ENOMEM;
1459 goto bad;
1461 memcpy( (char *)n, (char *)brle,
1462 sizeof(struct resource_list_entry));
1463 SLIST_INSERT_HEAD(&brl_rev, n, link);
1466 SLIST_FOREACH(brle, &brl_rev, link) {
1467 #else
1468 STAILQ_FOREACH(brle, brl, link) {
1469 #endif
1470 switch (brle->type) {
1471 case SYS_RES_IOPORT:
1472 prd->cprd_type = CmResourceTypePort;
1473 prd->cprd_flags = CM_RESOURCE_PORT_IO;
1474 prd->cprd_sharedisp =
1475 CmResourceShareDeviceExclusive;
1476 prd->u.cprd_port.cprd_start.np_quad =
1477 brle->start;
1478 prd->u.cprd_port.cprd_len = brle->count;
1479 break;
1480 case SYS_RES_MEMORY:
1481 prd->cprd_type = CmResourceTypeMemory;
1482 prd->cprd_flags =
1483 CM_RESOURCE_MEMORY_READ_WRITE;
1484 prd->cprd_sharedisp =
1485 CmResourceShareDeviceExclusive;
1486 prd->u.cprd_port.cprd_start.np_quad =
1487 brle->start;
1488 prd->u.cprd_port.cprd_len = brle->count;
1489 break;
1490 case SYS_RES_IRQ:
1491 prd->cprd_type = CmResourceTypeInterrupt;
1492 prd->cprd_flags = 0;
1493 prd->cprd_sharedisp =
1494 CmResourceShareDeviceExclusive;
1495 prd->u.cprd_intr.cprd_level = brle->start;
1496 prd->u.cprd_intr.cprd_vector = brle->start;
1497 prd->u.cprd_intr.cprd_affinity = 0;
1498 break;
1499 default:
1500 break;
1502 prd++;
1506 block->nmb_rlist = rl;
1508 #if __FreeBSD_version < 600022
1509 bad:
1511 while (!SLIST_EMPTY(&brl_rev)) {
1512 n = SLIST_FIRST(&brl_rev);
1513 SLIST_REMOVE_HEAD(&brl_rev, link);
1514 free (n, M_TEMP);
1516 #endif
1518 return(error);
1520 #endif /* __FreeBSD__ */
1522 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
1523 * packet, it will hand it to us in the form of an ndis_packet,
1524 * which we need to convert to an mbuf that is then handed off
1525 * to the stack. Note: we configure the mbuf list so that it uses
1526 * the memory regions specified by the ndis_buffer structures in
1527 * the ndis_packet as external storage. In most cases, this will
1528 * point to a memory region allocated by the driver (either by
1529 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
1530 * the driver to handle free()ing this region for is, so we set up
1531 * a dummy no-op free handler for it.
1535 ndis_ptom(struct mbuf **m0, ndis_packet *p)
1537 struct mbuf *m, *prev = NULL;
1538 ndis_buffer *buf;
1539 ndis_packet_private *priv;
1540 uint32_t totlen = 0;
1542 if (p == NULL || m0 == NULL)
1543 return(EINVAL);
1545 priv = &p->np_private;
1546 buf = priv->npp_head;
1547 p->np_refcnt = 0;
1549 for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) {
1550 if (buf == priv->npp_head)
1551 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1552 else
1553 MGET(m, M_DONTWAIT, MT_DATA);
1554 if (m == NULL) {
1555 m_freem(*m0);
1556 *m0 = NULL;
1557 return(ENOBUFS);
1559 m->m_len = MmGetMdlByteCount(buf);
1560 m->m_data = MmGetMdlVirtualAddress(buf);
1561 #ifdef __FreeBSD__
1562 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
1563 p, 0, EXT_NDIS);
1564 #else
1565 MEXTADD(m, m->m_data, m->m_len, M_DEVBUF,
1566 ndis_return_packet, p);
1567 #endif
1568 p->np_refcnt++;
1569 totlen += m->m_len;
1570 if (m->m_flags & MT_HEADER)
1571 *m0 = m;
1572 else
1573 prev->m_next = m;
1574 prev = m;
1577 (*m0)->m_pkthdr.len = totlen;
1579 return(0);
1583 * Create an NDIS packet from an mbuf chain.
1584 * This is used mainly when transmitting packets, where we need
1585 * to turn an mbuf off an interface's send queue and transform it
1586 * into an NDIS packet which will be fed into the NDIS driver's
1587 * send routine.
1589 * NDIS packets consist of two parts: an ndis_packet structure,
1590 * which is vaguely analagous to the pkthdr portion of an mbuf,
1591 * and one or more ndis_buffer structures, which define the
1592 * actual memory segments in which the packet data resides.
1593 * We need to allocate one ndis_buffer for each mbuf in a chain,
1594 * plus one ndis_packet as the header.
1598 ndis_mtop(struct mbuf *m0, ndis_packet **p)
1600 struct mbuf *m;
1601 ndis_buffer *buf = NULL, *prev = NULL;
1602 ndis_packet_private *priv;
1604 if (p == NULL || *p == NULL || m0 == NULL)
1605 return(EINVAL);
1607 priv = &(*p)->np_private;
1608 priv->npp_totlen = m0->m_pkthdr.len;
1610 for (m = m0; m != NULL; m = m->m_next) {
1611 if (m->m_len == 0)
1612 continue;
1613 buf = IoAllocateMdl(m->m_data, m->m_len, FALSE, FALSE, NULL);
1614 if (buf == NULL) {
1615 ndis_free_packet(*p);
1616 *p = NULL;
1617 return(ENOMEM);
1620 if (priv->npp_head == NULL)
1621 priv->npp_head = buf;
1622 else
1623 prev->mdl_next = buf;
1624 prev = buf;
1627 priv->npp_tail = buf;
1629 return(0);
1633 ndis_get_supported_oids(void *arg, ndis_oid **oids, int *oidcnt)
1635 int len, rval;
1636 ndis_oid *o;
1638 if (arg == NULL || oids == NULL || oidcnt == NULL)
1639 return(EINVAL);
1640 len = 0;
1641 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
1643 o = malloc(len, M_DEVBUF, M_NOWAIT);
1644 if (o == NULL)
1645 return(ENOMEM);
1647 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
1649 if (rval) {
1650 free(o, M_DEVBUF);
1651 return(rval);
1654 *oids = o;
1655 *oidcnt = len / 4;
1657 return(0);
1661 ndis_set_info(void *arg, ndis_oid oid, void *buf, int *buflen)
1663 struct ndis_softc *sc;
1664 ndis_status rval;
1665 ndis_handle adapter;
1666 __stdcall ndis_setinfo_handler setfunc;
1667 uint32_t byteswritten = 0, bytesneeded = 0;
1668 int error;
1669 uint8_t irql = 0; /* XXX: gcc */
1670 #ifdef __NetBSD__
1671 int s;
1672 #endif
1675 * According to the NDIS spec, MiniportQueryInformation()
1676 * and MiniportSetInformation() requests are handled serially:
1677 * once one request has been issued, we must wait for it to
1678 * finish before allowing another request to proceed.
1681 sc = arg;
1683 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1685 if (sc->ndis_block->nmb_pendingreq != NULL)
1686 panic("ndis_set_info() called while other request pending");
1687 else
1688 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
1690 /* I added this lock because it was present in the FreeBSD-current sources */
1691 NDIS_LOCK(sc);
1693 setfunc = sc->ndis_chars->nmc_setinfo_func;
1694 adapter = sc->ndis_block->nmb_miniportadapterctx;
1696 if (adapter == NULL || setfunc == NULL) {
1697 sc->ndis_block->nmb_pendingreq = NULL;
1698 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1699 NDIS_UNLOCK(sc);
1700 return(ENXIO);
1703 NDIS_UNLOCK(sc);
1705 rval = MSCALL6(setfunc, adapter, oid, buf, *buflen,
1706 &byteswritten, &bytesneeded);
1708 sc->ndis_block->nmb_pendingreq = NULL;
1710 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1712 if (rval == NDIS_STATUS_PENDING) {
1713 mtx_lock(&ndis_req_mtx);
1714 #ifdef __FreeBSD__
1715 error = msleep(&sc->ndis_block->nmb_setstat,
1716 &ndis_req_mtx,
1717 curthread->td_priority|PDROP,
1718 "ndisset", 5 * hz);
1719 #else
1720 error = ltsleep(&sc->ndis_block->nmb_setstat,
1721 curlwp->l_priority|PNORELOCK,
1722 "ndisset", 5 * hz, 0);
1723 #endif
1724 rval = sc->ndis_block->nmb_setstat;
1725 #ifdef __NetBSD__
1726 mtx_unlock(&ndis_req_mtx);
1727 #endif
1731 if (byteswritten)
1732 *buflen = byteswritten;
1733 if (bytesneeded)
1734 *buflen = bytesneeded;
1736 if (rval == NDIS_STATUS_INVALID_LENGTH)
1737 return(ENOSPC);
1739 if (rval == NDIS_STATUS_INVALID_OID)
1740 return(EINVAL);
1742 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1743 rval == NDIS_STATUS_NOT_ACCEPTED)
1744 return(ENOTSUP);
1746 if (rval != NDIS_STATUS_SUCCESS)
1747 return(ENODEV);
1749 return(0);
1752 typedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
1755 ndis_send_packets(void *arg, ndis_packet **packets, int cnt)
1757 struct ndis_softc *sc;
1758 ndis_handle adapter;
1759 __stdcall ndis_sendmulti_handler sendfunc;
1760 __stdcall ndis_senddone_func senddonefunc;
1761 int i;
1762 ndis_packet *p;
1763 uint8_t irql = 0; /* XXX: gcc */
1765 sc = arg;
1766 adapter = sc->ndis_block->nmb_miniportadapterctx;
1767 if (adapter == NULL)
1768 return(ENXIO);
1769 sendfunc = sc->ndis_chars->nmc_sendmulti_func;
1770 senddonefunc = sc->ndis_block->nmb_senddone_func;
1772 if (NDIS_SERIALIZED(sc->ndis_block))
1773 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1775 MSCALL3(sendfunc, adapter, packets, cnt);
1777 for (i = 0; i < cnt; i++) {
1778 p = packets[i];
1780 * Either the driver already handed the packet to
1781 * ndis_txeof() due to a failure, or it wants to keep
1782 * it and release it asynchronously later. Skip to the
1783 * next one.
1785 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
1786 continue;
1787 MSCALL3(senddonefunc, sc->ndis_block, p, p->np_oob.npo_status);
1790 if (NDIS_SERIALIZED(sc->ndis_block))
1791 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1793 return(0);
1797 ndis_send_packet(void *arg, ndis_packet *packet)
1799 struct ndis_softc *sc;
1800 ndis_handle adapter;
1801 ndis_status status;
1802 __stdcall ndis_sendsingle_handler sendfunc;
1803 __stdcall ndis_senddone_func senddonefunc;
1804 uint8_t irql = 0; /* XXX: gcc */
1806 sc = arg;
1807 adapter = sc->ndis_block->nmb_miniportadapterctx;
1808 if (adapter == NULL)
1809 return(ENXIO);
1810 sendfunc = sc->ndis_chars->nmc_sendsingle_func;
1811 senddonefunc = sc->ndis_block->nmb_senddone_func;
1813 if (NDIS_SERIALIZED(sc->ndis_block))
1814 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1815 status = MSCALL3(sendfunc, adapter, packet,
1816 packet->np_private.npp_flags);
1818 if (status == NDIS_STATUS_PENDING) {
1819 if (NDIS_SERIALIZED(sc->ndis_block))
1820 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1821 return(0);
1824 MSCALL3(senddonefunc, sc->ndis_block, packet, status);
1826 if (NDIS_SERIALIZED(sc->ndis_block))
1827 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1829 return(0);
1833 ndis_init_dma(void *arg)
1835 struct ndis_softc *sc;
1836 int i, error = 0;
1838 sc = arg;
1840 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
1841 M_DEVBUF, M_NOWAIT|M_ZERO);
1843 if (sc->ndis_tmaps == NULL)
1844 return(ENOMEM);
1846 for (i = 0; i < sc->ndis_maxpkts; i++) {
1847 #ifdef __FreeBSD__
1848 error = bus_dmamap_create(sc->ndis_ttag, 0,
1849 &sc->ndis_tmaps[i]);
1850 #else
1852 bus_dmamap_create(sc->ndis_mtag, sizeof(bus_dmamap_t),
1853 1, sizeof(bus_dmamap_t), BUS_DMA_NOWAIT,
1854 0, &sc->ndis_mmaps[i]);
1856 bus_dmamap_create(sc->ndis_ttag, NDIS_MAXSEG * MCLBYTES,
1857 NDIS_MAXSEG, MCLBYTES, 0,
1858 BUS_DMA_NOWAIT, &sc->ndis_tmaps[i]);
1859 #endif
1860 if (error) {
1861 free(sc->ndis_tmaps, M_DEVBUF);
1862 return(ENODEV);
1866 return(0);
1870 ndis_destroy_dma(void *arg)
1872 struct ndis_softc *sc;
1873 struct mbuf *m;
1874 ndis_packet *p = NULL;
1875 int i;
1877 sc = arg;
1879 for (i = 0; i < sc->ndis_maxpkts; i++) {
1880 if (sc->ndis_txarray[i] != NULL) {
1881 p = sc->ndis_txarray[i];
1882 m = (struct mbuf *)p->np_rsvd[1];
1883 if (m != NULL)
1884 m_freem(m);
1885 ndis_free_packet(sc->ndis_txarray[i]);
1887 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
1890 free(sc->ndis_tmaps, M_DEVBUF);
1892 #ifdef __FreeBSD__
1893 bus_dma_tag_destroy(sc->ndis_ttag);
1894 #endif
1896 return(0);
1900 ndis_reset_nic(void *arg)
1902 struct ndis_softc *sc;
1903 ndis_handle adapter;
1904 __stdcall ndis_reset_handler resetfunc;
1905 uint8_t addressing_reset;
1906 struct ifnet *ifp;
1907 int rval;
1908 uint8_t irql = 0; /* XXX: gcc */
1910 sc = arg;
1911 #ifdef __FreeBSD__
1912 ifp = &sc->arpcom.ac_if;
1913 #else
1914 ifp = &sc->arpcom.ec_if;
1915 #endif
1917 adapter = sc->ndis_block->nmb_miniportadapterctx;
1918 resetfunc = sc->ndis_chars->nmc_reset_func;
1920 if (adapter == NULL || resetfunc == NULL)
1921 return(EIO);
1923 if (NDIS_SERIALIZED(sc->ndis_block))
1924 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
1926 rval = MSCALL2(resetfunc, &addressing_reset, adapter);
1928 if (NDIS_SERIALIZED(sc->ndis_block))
1929 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
1931 if (rval == NDIS_STATUS_PENDING) {
1932 mtx_lock(&ndis_req_mtx);
1933 #ifdef __FreeBSD__
1934 msleep(sc, &ndis_req_mtx,
1935 curthread->td_priority|PDROP, "ndisrst", 0);
1936 #else
1937 ltsleep(sc, curlwp->l_priority|PNORELOCK, "ndisrst", 0, 0);
1938 #endif
1941 return(0);
1945 ndis_halt_nic(void *arg)
1947 struct ndis_softc *sc;
1948 ndis_handle adapter;
1949 __stdcall ndis_halt_handler haltfunc;
1950 struct ifnet *ifp;
1951 #ifdef __NetBSD__
1952 int s;
1953 #endif
1955 sc = arg;
1956 #ifdef __FreeBSD__
1957 ifp = &sc->arpcom.ac_if;
1958 #else
1959 ifp = &sc->arpcom.ec_if;
1960 #endif
1962 NDIS_LOCK(sc);
1964 adapter = sc->ndis_block->nmb_miniportadapterctx;
1965 if (adapter == NULL) {
1966 NDIS_UNLOCK(sc);
1967 return(EIO);
1971 * The adapter context is only valid after the init
1972 * handler has been called, and is invalid once the
1973 * halt handler has been called.
1976 haltfunc = sc->ndis_chars->nmc_halt_func;
1978 NDIS_UNLOCK(sc);
1980 MSCALL1(haltfunc, adapter);
1982 NDIS_LOCK(sc);
1984 sc->ndis_block->nmb_miniportadapterctx = NULL;
1986 NDIS_UNLOCK(sc);
1988 return(0);
1992 ndis_shutdown_nic(void *arg)
1994 struct ndis_softc *sc;
1995 ndis_handle adapter;
1996 __stdcall ndis_shutdown_handler shutdownfunc;
1997 #ifdef __NetBSD__
1998 int s;
1999 #endif
2001 sc = arg;
2003 NDIS_LOCK(sc);
2005 adapter = sc->ndis_block->nmb_miniportadapterctx;
2006 shutdownfunc = sc->ndis_chars->nmc_shutdown_handler;
2008 NDIS_UNLOCK(sc);
2010 if (adapter == NULL || shutdownfunc == NULL)
2011 return(EIO);
2013 if (sc->ndis_chars->nmc_rsvd0 == NULL)
2014 MSCALL1(shutdownfunc, adapter);
2015 else
2016 MSCALL1(shutdownfunc, sc->ndis_chars->nmc_rsvd0);
2018 ndis_shrink_thrqueue(8);
2019 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
2021 return(0);
2025 ndis_init_nic(void *arg)
2027 struct ndis_softc *sc;
2028 ndis_miniport_block *block;
2029 __stdcall ndis_init_handler initfunc;
2030 ndis_status status, openstatus = 0;
2031 ndis_medium mediumarray[NdisMediumMax];
2032 uint32_t chosenmedium, i;
2033 #ifdef __NetBSD__
2034 int s;
2035 #endif
2037 if (arg == NULL)
2038 return(EINVAL);
2040 sc = arg;
2042 NDIS_LOCK(sc);
2044 block = sc->ndis_block;
2045 initfunc = sc->ndis_chars->nmc_init_func;
2047 NDIS_UNLOCK(sc);
2049 printf("sc->ndis_chars->nmc_version_major = %d\n\
2050 sc->ndis_chars->nmc_version_minor = %d\n",
2051 sc->ndis_chars->nmc_version_major,
2052 sc->ndis_chars->nmc_version_minor);
2054 for (i = 0; i < NdisMediumMax; i++)
2055 mediumarray[i] = i;
2057 status = MSCALL6(initfunc, &openstatus, &chosenmedium,
2058 mediumarray, NdisMediumMax, block, block);
2060 printf("status = %x", status);
2063 * If the init fails, blow away the other exported routines
2064 * we obtained from the driver so we can't call them later.
2065 * If the init failed, none of these will work.
2067 if (status != NDIS_STATUS_SUCCESS) {
2068 NDIS_LOCK(sc);
2070 sc->ndis_block->nmb_miniportadapterctx = NULL;
2072 NDIS_UNLOCK(sc);
2073 return(ENXIO);
2076 return(0);
2079 void
2080 ndis_enable_intr(void *arg)
2082 struct ndis_softc *sc;
2083 ndis_handle adapter;
2084 __stdcall ndis_enable_interrupts_handler intrenbfunc;
2086 sc = arg;
2087 adapter = sc->ndis_block->nmb_miniportadapterctx;
2088 intrenbfunc = sc->ndis_chars->nmc_enable_interrupts_func;
2089 if (adapter == NULL || intrenbfunc == NULL)
2090 return;
2091 MSCALL1(intrenbfunc, adapter);
2093 return;
2096 void
2097 ndis_disable_intr(void *arg)
2099 struct ndis_softc *sc;
2100 ndis_handle adapter;
2101 __stdcall ndis_disable_interrupts_handler intrdisfunc;
2103 sc = arg;
2104 adapter = sc->ndis_block->nmb_miniportadapterctx;
2105 intrdisfunc = sc->ndis_chars->nmc_disable_interrupts_func;
2106 if (adapter == NULL || intrdisfunc == NULL)
2107 return;
2109 MSCALL1(intrdisfunc, adapter);
2111 return;
2115 ndis_isr(void *arg, int *ourintr, int *callhandler)
2117 struct ndis_softc *sc;
2118 ndis_handle adapter;
2119 __stdcall ndis_isr_handler isrfunc;
2120 uint8_t accepted, queue;
2122 if (arg == NULL || ourintr == NULL || callhandler == NULL)
2123 return(EINVAL);
2125 sc = arg;
2126 adapter = sc->ndis_block->nmb_miniportadapterctx;
2127 isrfunc = sc->ndis_chars->nmc_isr_func;
2129 if (adapter == NULL || isrfunc == NULL)
2130 return(ENXIO);
2132 MSCALL3(isrfunc, &accepted, &queue, adapter);
2134 *ourintr = accepted;
2135 *callhandler = queue;
2137 return(0);
2140 __stdcall static void
2141 ndis_intrhand(kdpc *dpc, device_object *dobj,
2142 irp *ip, struct ndis_softc *sc)
2144 ndis_handle adapter;
2145 __stdcall ndis_interrupt_handler intrfunc;
2146 uint8_t irql = 0; /* XXX: gcc */
2148 adapter = sc->ndis_block->nmb_miniportadapterctx;
2149 intrfunc = sc->ndis_chars->nmc_interrupt_func;
2151 if (adapter == NULL || intrfunc == NULL)
2152 return;
2154 if (NDIS_SERIALIZED(sc->ndis_block))
2155 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
2157 MSCALL1(intrfunc, adapter);
2159 /* If there's a MiniportEnableInterrupt() routine, call it. */
2161 ndis_enable_intr(sc);
2163 if (NDIS_SERIALIZED(sc->ndis_block))
2164 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
2166 return;
2170 ndis_get_info(void *arg, ndis_oid oid, void *buf, int *buflen)
2172 struct ndis_softc *sc;
2173 ndis_status rval;
2174 ndis_handle adapter;
2175 __stdcall ndis_queryinfo_handler queryfunc;
2176 uint32_t byteswritten = 0, bytesneeded = 0;
2177 #ifdef __FreeBSD__
2178 int error;
2179 #endif
2180 uint8_t irql = 0; /* XXX: gcc */
2182 //printf("in ndis_get_info\n");
2184 sc = arg;
2185 KeAcquireSpinLock(&sc->ndis_block->nmb_lock, &irql);
2187 if (sc->ndis_block->nmb_pendingreq != NULL)
2188 panic("ndis_get_info() called while other request pending");
2189 else
2190 sc->ndis_block->nmb_pendingreq = (ndis_request *)sc;
2192 queryfunc = sc->ndis_chars->nmc_queryinfo_func;
2193 adapter = sc->ndis_block->nmb_miniportadapterctx;
2195 if (adapter == NULL || queryfunc == NULL) {
2196 sc->ndis_block->nmb_pendingreq = NULL;
2197 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
2198 return(ENXIO);
2201 rval = MSCALL6(queryfunc, adapter, oid, buf, *buflen,
2202 &byteswritten, &bytesneeded);
2204 sc->ndis_block->nmb_pendingreq = NULL;
2206 KeReleaseSpinLock(&sc->ndis_block->nmb_lock, irql);
2208 /* Wait for requests that block. */
2210 if (rval == NDIS_STATUS_PENDING) {
2211 mtx_lock(&ndis_req_mtx);
2212 #ifdef __FreeBSD__
2213 error = msleep(&sc->ndis_block->nmb_getstat,
2214 &ndis_req_mtx,
2215 curthread->td_priority|PDROP,
2216 "ndisget", 5 * hz);
2217 #else
2218 ltsleep(&sc->ndis_block->nmb_getstat,
2219 curlwp->l_priority|PNORELOCK, "ndisget", 5 * hz, 0);
2220 #endif
2221 rval = sc->ndis_block->nmb_getstat;
2224 if (byteswritten)
2225 *buflen = byteswritten;
2226 if (bytesneeded)
2227 *buflen = bytesneeded;
2229 if (rval == NDIS_STATUS_INVALID_LENGTH ||
2230 rval == NDIS_STATUS_BUFFER_TOO_SHORT)
2231 return(ENOSPC);
2233 if (rval == NDIS_STATUS_INVALID_OID)
2234 return(EINVAL);
2236 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
2237 rval == NDIS_STATUS_NOT_ACCEPTED)
2238 return(ENOTSUP);
2240 if (rval != NDIS_STATUS_SUCCESS)
2241 return(ENODEV);
2243 return(0);
2246 __stdcall uint32_t
2247 NdisAddDevice(driver_object *drv, device_object *pdo)
2249 device_object *fdo;
2250 ndis_miniport_block *block;
2251 struct ndis_softc *sc;
2252 uint32_t status;
2254 status = IoCreateDevice(drv, sizeof(ndis_miniport_block), NULL,
2255 FILE_DEVICE_UNKNOWN, 0, FALSE, &fdo);
2257 if (status != STATUS_SUCCESS)
2258 return(status);
2260 block = fdo->do_devext;
2261 block->nmb_deviceobj = fdo;
2262 block->nmb_physdeviceobj = pdo;
2263 block->nmb_nextdeviceobj = IoAttachDeviceToDeviceStack(fdo, pdo);
2264 KeInitializeSpinLock(&block->nmb_lock);
2266 #ifdef __NetBSD__
2267 /* NetBSD has a pointer to the callout object */
2268 block->nmb_wkupdpctimer.nt_ktimer.k_handle =
2269 malloc(sizeof(struct callout), M_DEVBUF, M_NOWAIT|M_ZERO);
2270 #endif
2273 * Stash pointers to the miniport block and miniport
2274 * characteristics info in the if_ndis softc so the
2275 * UNIX wrapper driver can get to them later.
2277 #ifdef __FreeBSD__
2278 sc = device_get_softc(pdo->do_devext);
2279 #else /* __NetBSD__ */
2280 sc = pdo->pdo_sc;
2281 fdo->fdo_sc = sc;
2282 #endif
2283 sc->ndis_block = block;
2284 sc->ndis_chars = IoGetDriverObjectExtension(drv, (void *)1);
2286 IoInitializeDpcRequest(fdo, kernndis_functbl[6].ipt_wrap);
2288 /* Finish up BSD-specific setup. */
2290 block->nmb_signature = (void *)0xcafebabe;
2291 block->nmb_status_func = kernndis_functbl[0].ipt_wrap;
2292 block->nmb_statusdone_func = kernndis_functbl[1].ipt_wrap;
2293 block->nmb_setdone_func = kernndis_functbl[2].ipt_wrap;
2294 block->nmb_querydone_func = kernndis_functbl[3].ipt_wrap;
2295 block->nmb_resetdone_func = kernndis_functbl[4].ipt_wrap;
2296 block->nmb_sendrsrc_func = kernndis_functbl[5].ipt_wrap;
2297 block->nmb_pendingreq = NULL;
2299 ndis_enlarge_thrqueue(8);
2301 TAILQ_INSERT_TAIL(&ndis_devhead, block, link);
2303 return (STATUS_SUCCESS);
2307 ndis_unload_driver(void *arg)
2309 struct ndis_softc *sc;
2310 device_object *fdo;
2312 sc = arg;
2314 if (sc->ndis_block->nmb_rlist != NULL)
2315 free(sc->ndis_block->nmb_rlist, M_DEVBUF);
2317 ndis_flush_sysctls(sc);
2319 ndis_shrink_thrqueue(8);
2320 TAILQ_REMOVE(&ndis_devhead, sc->ndis_block, link);
2322 fdo = sc->ndis_block->nmb_deviceobj;
2323 IoDetachDevice(sc->ndis_block->nmb_nextdeviceobj);
2324 IoDeleteDevice(fdo);
2326 return(0);