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