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