3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.60.2.5 2005/04/01 17:14:20 wpaul Exp $");
38 __KERNEL_RCSID(0, "$NetBSD: kern_ndis.c,v 1.20 2009/05/06 22:38:31 ad Exp $");
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>
51 #include <sys/malloc.h>
54 #include <sys/mutex.h>
58 #include <sys/kernel.h>
59 #include <sys/module.h>
61 #include <sys/kthread.h>
64 #include <machine/resource.h>
69 #include <dev/pci/pcivar.h>
70 #include <dev/pci/pcireg.h>
74 #include <net/if_arp.h>
76 #include <net/ethernet.h>
78 #include <net/if_ether.h>
80 #include <net/if_dl.h>
81 #include <net/if_media.h>
83 #include <net80211/ieee80211_var.h>
84 #include <net80211/ieee80211_ioctl.h>
86 #include <compat/ndis/pe_var.h>
87 #include <compat/ndis/resource_var.h>
88 #include <compat/ndis/ntoskrnl_var.h>
89 #include <compat/ndis/ndis_var.h>
90 #include <compat/ndis/hal_var.h>
91 #include <compat/ndis/cfg_var.h>
92 #include <compat/ndis/usbd_var.h>
93 #include <dev/if_ndis/if_ndisvar.h>
95 MODULE(MODULE_CLASS_MISC
, ndis
, NULL
);
97 #define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
99 __stdcall
static void ndis_status_func(ndis_handle
, ndis_status
,
101 __stdcall
static void ndis_statusdone_func(ndis_handle
);
102 __stdcall
static void ndis_setdone_func(ndis_handle
, ndis_status
);
103 __stdcall
static void ndis_getdone_func(ndis_handle
, ndis_status
);
104 __stdcall
static void ndis_resetdone_func(ndis_handle
, ndis_status
, uint8_t);
105 __stdcall
static void ndis_sendrsrcavail_func(ndis_handle
);
106 __stdcall
static void ndis_intrhand(kdpc
*, device_object
*,
107 irp
*, struct ndis_softc
*);
109 static image_patch_table kernndis_functbl
[] = {
110 IMPORT_FUNC(ndis_status_func
),
111 IMPORT_FUNC(ndis_statusdone_func
),
112 IMPORT_FUNC(ndis_setdone_func
),
113 IMPORT_FUNC(ndis_getdone_func
),
114 IMPORT_FUNC(ndis_resetdone_func
),
115 IMPORT_FUNC(ndis_sendrsrcavail_func
),
116 IMPORT_FUNC(ndis_intrhand
),
121 struct nd_head ndis_devhead
;
124 void (*nr_func
)(void *);
127 STAILQ_ENTRY(ndis_req
) link
;
128 /* just for debugging */
133 struct ndisqhead
*np_q
;
136 uint8_t np_stack
[PAGE_SIZE
*NDIS_KSTACK_PAGES
];
142 static void ndis_return(void *);
143 static int ndis_create_kthreads(void);
144 static void ndis_destroy_kthreads(void);
145 static void ndis_stop_thread(int);
146 static int ndis_enlarge_thrqueue(int);
147 static int ndis_shrink_thrqueue(int);
149 static void ndis_runq(void *);
153 static struct mtx ndis_thr_mtx
;
154 #else /* __NetBSD__ */
155 static struct simplelock ndis_thr_mtx
;
156 #define THR_LOCK() do {old_ipl = splnet(); simple_lock(&ndis_thr_mtx);} while(0)
157 #define THR_UNLOCK() do {simple_unlock(&ndis_thr_mtx); splx(old_ipl);} while(0)
160 static struct mtx ndis_req_mtx
;
161 static STAILQ_HEAD(ndisqhead
, ndis_req
) ndis_ttodo
;
162 static struct ndisqhead ndis_itodo
;
163 static struct ndisqhead ndis_free
;
164 static int ndis_jobs
= 32;
166 static struct ndisproc ndis_tproc
;
167 static struct ndisproc ndis_iproc
;
170 * This allows us to export our symbols to other modules.
171 * Note that we call ourselves 'ndisapi' to avoid a namespace
172 * collision with if_ndis.ko, which internally calls itself
178 ndis_modevent(module_t mod
, int cmd
, void *arg
)
181 image_patch_table
*patch
;
185 /* Initialize subsystems */
190 #ifdef usbimplemented
194 patch
= kernndis_functbl
;
195 while (patch
->ipt_func
!= NULL
) {
196 windrv_wrap((funcptr
)patch
->ipt_func
,
197 (funcptr
*)&patch
->ipt_wrap
);
201 ndis_create_kthreads();
203 TAILQ_INIT(&ndis_devhead
);
208 ndis_destroy_kthreads();
209 if (TAILQ_FIRST(&ndis_devhead
) == NULL
) {
210 /* Shut down subsystems */
214 #ifdef usbimplemented
219 patch
= kernndis_functbl
;
220 while (patch
->ipt_func
!= NULL
) {
221 windrv_unwrap(patch
->ipt_wrap
);
228 ndis_destroy_kthreads();
230 /* Shut down subsystems */
237 patch
= kernndis_functbl
;
238 while (patch
->ipt_func
!= NULL
) {
239 windrv_unwrap(patch
->ipt_wrap
);
251 DEV_MODULE(ndisapi
, ndis_modevent
, NULL
);
252 MODULE_VERSION(ndisapi
, 1);
256 ndis_modcmd(modcmd_t cmd
, void *arg
)
259 image_patch_table
*patch
;
262 case MODULE_CMD_INIT
:
263 /* Initialize subsystems */
268 #ifdef usbimplemented
272 patch
= kernndis_functbl
;
273 while (patch
->ipt_func
!= NULL
) {
274 windrv_wrap((funcptr
)patch
->ipt_func
,
275 (funcptr
*)&patch
->ipt_wrap
);
279 TAILQ_INIT(&ndis_devhead
);
281 ndis_create_kthreads();
284 case MODULE_CMD_FINI
:
286 ndis_destroy_kthreads();
288 /* Shut down subsystems */
292 #ifdef usbimplemented
297 patch
= kernndis_functbl
;
298 while (patch
->ipt_func
!= NULL
) {
299 windrv_unwrap(patch
->ipt_wrap
);
314 * We create two kthreads for the NDIS subsystem. One of them is a task
315 * queue for performing various odd jobs. The other is an swi thread
316 * reserved exclusively for running interrupt handlers. The reason we
317 * have our own task queue is that there are some cases where we may
318 * need to sleep for a significant amount of time, and if we were to
319 * use one of the taskqueue threads, we might delay the processing
320 * of other pending tasks which might need to run right away. We have
321 * a separate swi thread because we don't want our interrupt handling
322 * to be delayed either.
324 * By default there are 32 jobs available to start, and another 8
325 * are added to the free list each time a new device is created.
328 /* Just for testing this can be removed later */
329 struct ndis_req
*_ndis_taskqueue_req
;
330 struct ndis_req
*_ndis_swi_req
;
331 int calling_in_swi
= FALSE
;
332 int calling_in_tq
= FALSE
;
339 struct ndis_req
*r
= NULL
, *die
= NULL
;
349 /* Protect against interrupts between checking if the queue is empty, and going to sleep
350 * to avoid a wakeup before sleep.
353 /* Sleep, but preserve our original priority. */
354 if(STAILQ_EMPTY(p
->np_q
)) {
355 /* TODO: If we get an interrupt between checking if the queue is empty,
356 * TODO: and sleeping, then in the interrupt, an item could be placed
357 * TODO: on the queue, and we could be woken up before we sleep.
360 ndis_thsuspend(p
->np_p
, NULL
, 0);
365 p
->np_needs_wakeup
= FALSE
;
368 /* Look for any jobs on the work queue. */
370 mtx_lock_spin(&ndis_thr_mtx
);
371 #else /* __NetBSD__ */
375 p
->np_state
= NDIS_PSTATE_RUNNING
;
376 while(!STAILQ_EMPTY(p
->np_q
)/*STAILQ_FIRST(p->np_q) != NULL*/) {
377 r
= STAILQ_FIRST(p
->np_q
);
378 STAILQ_REMOVE_HEAD(p
->np_q
, link
);
382 if(p
== &ndis_tproc
) {
384 _ndis_taskqueue_req
= r
;
386 } else if(p
== &ndis_iproc
) {
392 mtx_unlock_spin(&ndis_thr_mtx
);
393 #else /* __NetBSD__ */
396 /* Just for debugging */
398 if(p
== &ndis_tproc
) {
399 calling_in_tq
= TRUE
;
400 } else if(p
== &ndis_iproc
) {
401 calling_in_swi
= TRUE
;
405 if (r
->nr_func
!= NULL
)
406 (*r
->nr_func
)(r
->nr_arg
);
408 /* Just for debugging */
409 if(p
== &ndis_tproc
) {
410 calling_in_tq
= FALSE
;
411 } else if(p
== &ndis_iproc
) {
412 calling_in_swi
= FALSE
;
416 mtx_lock_spin(&ndis_thr_mtx
);
417 #else /* __NetBSD__ */
421 /* Zeroing out the ndis_req is just for debugging */
422 //memset(r, 0, sizeof(struct ndis_req));
423 STAILQ_INSERT_HEAD(&ndis_free
, r
, link
);
425 /* Check for a shutdown request */
426 if (r
->nr_exit
== TRUE
)
429 p
->np_state
= NDIS_PSTATE_SLEEPING
;
432 mtx_unlock_spin(&ndis_thr_mtx
);
433 #else /* __NetBSD__ */
437 /* Bail if we were told to shut down. */
445 #if __FreeBSD_version < 502113
449 if(p
== &ndis_tproc
) {
450 printf("taskqueue thread exiting!\n");
451 } else if(p
== &ndis_iproc
) {
452 printf("swi thread exiting!\n");
455 return; /* notreached */
459 ndis_create_kthreads(void)
464 printf("in ndis_create_kthreads\n");
467 mtx_init(&ndis_thr_mtx
, "NDIS thread lock", NULL
, MTX_SPIN
);
468 #else /* __NetBSD__ */
469 simple_lock_init(&ndis_thr_mtx
);
470 //lockinit(&ndis_thr_mtx, PWAIT, "NDIS thread lock", 0, 0);
472 mtx_init(&ndis_req_mtx
, "NDIS request lock", MTX_NDIS_LOCK
, MTX_DEF
);
474 STAILQ_INIT(&ndis_ttodo
);
475 STAILQ_INIT(&ndis_itodo
);
476 STAILQ_INIT(&ndis_free
);
478 for (i
= 0; i
< ndis_jobs
; i
++) {
479 r
= malloc(sizeof(struct ndis_req
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
484 STAILQ_INSERT_HEAD(&ndis_free
, r
, link
);
488 ndis_tproc
.np_q
= &ndis_ttodo
;
489 ndis_tproc
.np_state
= NDIS_PSTATE_SLEEPING
;
491 error
= kthread_create(ndis_runq
, &ndis_tproc
,
492 &ndis_tproc
.np_p
, RFHIGHPID
,
493 NDIS_KSTACK_PAGES
, "ndis taskqueue");
494 #else /* __NetBSD__ */
495 error
= ndis_kthread_create(ndis_runq
, &ndis_tproc
,
496 &ndis_tproc
.np_p
, ndis_tproc
.np_stack
, PAGE_SIZE
*NDIS_KSTACK_PAGES
, "ndis taskqueue");
501 ndis_iproc
.np_q
= &ndis_itodo
;
502 ndis_iproc
.np_state
= NDIS_PSTATE_SLEEPING
;
504 error
= kthread_create(ndis_runq
, &ndis_iproc
,
505 &ndis_iproc
.np_p
, RFHIGHPID
,
506 NDIS_KSTACK_PAGES
, "ndis swi");
508 error
= ndis_kthread_create(ndis_runq
, &ndis_iproc
,
509 &ndis_iproc
.np_p
, ndis_iproc
.np_stack
, PAGE_SIZE
*NDIS_KSTACK_PAGES
, "ndis swi");
514 while ((r
= STAILQ_FIRST(&ndis_free
)) != NULL
) {
515 STAILQ_REMOVE_HEAD(&ndis_free
, link
);
525 ndis_destroy_kthreads(void)
529 /* Stop the threads. */
531 ndis_stop_thread(NDIS_TASKQUEUE
);
532 ndis_stop_thread(NDIS_SWI
);
534 /* Destroy request structures. */
536 while ((r
= STAILQ_FIRST(&ndis_free
)) != NULL
) {
537 STAILQ_REMOVE_HEAD(&ndis_free
, link
);
541 mtx_destroy(&ndis_req_mtx
);
543 mtx_destroy(&ndis_thr_mtx
);
550 ndis_stop_thread(int t
)
559 if (t
== NDIS_TASKQUEUE
) {
567 /* Create and post a special 'exit' job. */
570 mtx_lock_spin(&ndis_thr_mtx
);
571 #else /* __NetBSD__ */
574 r
= STAILQ_FIRST(&ndis_free
);
575 STAILQ_REMOVE_HEAD(&ndis_free
, link
);
580 STAILQ_INSERT_TAIL(q
, r
, link
);
582 mtx_unlock_spin(&ndis_thr_mtx
);
583 #else /* __NetBSD__ */
589 /* wait for thread exit */
592 tsleep(r
, curthread
->td_priority
|PCATCH
, "ndisthexit", hz
* 60);
594 tsleep(r
, curlwp
->l_priority
|PCATCH
, "ndisthexit", hz
* 60);
597 /* Now empty the job list. */
599 mtx_lock_spin(&ndis_thr_mtx
);
600 #else /* __NetBSD__ */
603 while ((r
= STAILQ_FIRST(q
)) != NULL
) {
604 STAILQ_REMOVE_HEAD(q
, link
);
605 STAILQ_INSERT_HEAD(&ndis_free
, r
, link
);
609 mtx_unlock_spin(&ndis_thr_mtx
);
610 #else /* __NetBSD__ */
618 ndis_enlarge_thrqueue(int cnt
)
626 for (i
= 0; i
< cnt
; i
++) {
627 r
= malloc(sizeof(struct ndis_req
), M_DEVBUF
, M_WAITOK
);
631 mtx_lock_spin(&ndis_thr_mtx
);
632 #else /* __NetBSD__ */
635 STAILQ_INSERT_HEAD(&ndis_free
, r
, link
);
638 mtx_unlock_spin(&ndis_thr_mtx
);
639 #else /* __NetBSD__ */
648 ndis_shrink_thrqueue(int cnt
)
656 for (i
= 0; i
< cnt
; i
++) {
658 mtx_lock_spin(&ndis_thr_mtx
);
659 #else /* __NetBSD__ */
662 r
= STAILQ_FIRST(&ndis_free
);
665 mtx_unlock_spin(&ndis_thr_mtx
);
666 #else /* __NetBSD__ */
671 STAILQ_REMOVE_HEAD(&ndis_free
, link
);
674 mtx_unlock_spin(&ndis_thr_mtx
);
675 #else /* __NetBSD__ */
686 ndis_unsched(void (*func
)(void *), void *arg
, int t
)
695 if (t
== NDIS_TASKQUEUE
) {
704 mtx_lock_spin(&ndis_thr_mtx
);
705 #else /* __NetBSD__ */
708 STAILQ_FOREACH(r
, q
, link
) {
709 if (r
->nr_func
== func
&& r
->nr_arg
== arg
) {
711 STAILQ_REMOVE(q
, r
, ndis_req
, link
);
712 STAILQ_INSERT_HEAD(&ndis_free
, r
, link
);
714 mtx_unlock_spin(&ndis_thr_mtx
);
715 #else /* __NetBSD__ */
722 mtx_unlock_spin(&ndis_thr_mtx
);
723 #else /* __NetBSD__ */
729 /* just for testing */
730 struct ndis_req
*ls_tq_req
= NULL
;
731 struct ndis_req
*ls_swi_req
= NULL
;
734 ndis_sched(void (*func
)(void *), void *arg
, int t
)
742 /* just for debugging */
743 struct ndis_req
**ls
;
744 //struct lwp *l = curlwp;
747 if (t
== NDIS_TASKQUEUE
) {
758 mtx_lock_spin(&ndis_thr_mtx
);
759 #else /* __NetBSD__ */
764 * Check to see if an instance of this job is already
765 * pending. If so, don't bother queuing it again.
767 STAILQ_FOREACH(r
, q
, link
) {
768 if (r
->nr_func
== func
&& r
->nr_arg
== arg
) {
770 if (t
== NDIS_TASKQUEUE
)
771 s
= ndis_tproc
.np_state
;
773 s
= ndis_iproc
.np_state
;
776 mtx_unlock_spin(&ndis_thr_mtx
);
777 #else /* __NetBSD__ */
781 /* The swi thread seemed to be going to sleep, and not waking up
782 * again, so I thought I'd try this out...
784 if (s
== NDIS_PSTATE_SLEEPING
)
790 r
= STAILQ_FIRST(&ndis_free
);
793 mtx_unlock_spin(&ndis_thr_mtx
);
794 #else /* __NetBSD__ */
799 STAILQ_REMOVE_HEAD(&ndis_free
, link
);
801 //memset(r, 0, sizeof(struct ndis_req));
808 STAILQ_INSERT_TAIL(q
, r
, link
);
809 if (t
== NDIS_TASKQUEUE
) {
810 s
= ndis_tproc
.np_state
;
812 ndis_tproc
.np_needs_wakeup
= TRUE
;
815 s
= ndis_iproc
.np_state
;
817 ndis_iproc
.np_needs_wakeup
= TRUE
;
822 mtx_unlock_spin(&ndis_thr_mtx
);
823 #else /* __NetBSD__ */
828 * Post the job, but only if the thread is actually blocked
829 * on its own suspend call. If a driver queues up a job with
830 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(),
831 * it may suspend there, and in that case we don't want to wake
832 * it up until KeWaitForObject() gets woken up on its own.
834 if (s
== NDIS_PSTATE_SLEEPING
) {
841 /* Try out writing my own version of ndis_sched() for NetBSD in which I just
842 * call the function instead of scheduling it. I know this isn't
843 * what's supposed to be done, but I've been having a lot of problems
844 * with the SWI and taskqueue threads, and just thought I'd give this
848 /* I don't think this will work, because it means that DPC's will be
849 * called from the bottom half of the kernel, so they won't be able
850 * to sleep using KeWaitForSingleObject.
854 ndis_sched(void (*func)(void *), void *arg, int t)
865 ndis_thsuspend(p
, m
, timo
)
869 #else /* __NetBSD__*/
870 struct simplelock
*m
;
878 error
= msleep(&p
->p_siglist
, m
,
879 curthread
->td_priority
, "ndissp", timo
);
882 error
= msleep(&p
->p_siglist
, &p
->p_mtx
,
883 curthread
->td_priority
|PDROP
, "ndissp", timo
);
886 /* TODO: Why do they wait on &p->p_siglist? I noticed that in FreeBSD's
887 * src/sys/sys/proc.h there is some mention of p_siglist having to do with
892 error
= ltsleep(&p
->p_sigpend
.sp_set
, curlwp
->l_priority
,
896 error
= ltsleep(&p
->p_sigpend
.sp_set
, curlwp
->l_priority
/*|PNORELOCK*/,
897 "ndissp", timo
, 0 /*&p->p_lock*/);
906 ndis_thresume(struct proc
*p
)
908 wakeup(&p
->p_sigpend
.sp_set
);
913 __stdcall
static void
914 ndis_sendrsrcavail_func(ndis_handle adapter
)
919 __stdcall
static void
920 ndis_status_func(ndis_handle adapter
, ndis_status status
, void *sbuf
,
923 ndis_miniport_block
*block
;
924 struct ndis_softc
*sc
;
929 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
930 #else /* __NetBSD__ */
931 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
935 ifp
= &sc
->arpcom
.ac_if
;
937 ifp
= &sc
->arpcom
.ec_if
;
939 if (ifp
->if_flags
& IFF_DEBUG
)
940 printf("%s: status: %x\n",
941 device_xname(sc
->ndis_dev
), status
);
945 __stdcall
static void
946 ndis_statusdone_func(ndis_handle adapter
)
948 ndis_miniport_block
*block
;
949 struct ndis_softc
*sc
;
954 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
955 #else /* __NetBSD__ */
956 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
960 ifp
= &sc
->arpcom
.ac_if
;
962 ifp
= &sc
->arpcom
.ec_if
;
964 if (ifp
->if_flags
& IFF_DEBUG
)
965 printf("%s: status complete\n",
966 device_xname(sc
->ndis_dev
));
970 __stdcall
static void
971 ndis_setdone_func(ndis_handle adapter
, ndis_status status
)
973 ndis_miniport_block
*block
;
976 block
->nmb_setstat
= status
;
977 wakeup(&block
->nmb_setstat
);
981 __stdcall
static void
982 ndis_getdone_func(ndis_handle adapter
, ndis_status status
)
984 ndis_miniport_block
*block
;
987 block
->nmb_getstat
= status
;
988 wakeup(&block
->nmb_getstat
);
992 __stdcall
static void
993 ndis_resetdone_func(ndis_handle adapter
, ndis_status status
,
994 uint8_t addressingreset
)
996 ndis_miniport_block
*block
;
997 struct ndis_softc
*sc
;
1002 sc
= device_get_softc(block
->nmb_physdeviceobj
->do_devext
);
1003 #else /* __NetBSD__ */
1004 sc
= (struct ndis_softc
*)block
->nmb_physdeviceobj
->pdo_sc
;
1008 ifp
= &sc
->arpcom
.ac_if
;
1010 ifp
= &sc
->arpcom
.ec_if
;
1013 if (ifp
->if_flags
& IFF_DEBUG
)
1014 printf("%s: reset done...\n",
1015 device_xname(sc
->ndis_dev
));
1021 /* FreeBSD version of ndis_create_sysctls() */
1023 ndis_create_sysctls(void *arg
)
1025 struct ndis_softc
*sc
;
1028 struct sysctl_oid
*oidp
;
1029 struct sysctl_ctx_entry
*e
;
1035 vals
= sc
->ndis_regvals
;
1037 TAILQ_INIT(&sc
->ndis_cfglist_head
);
1039 #if __FreeBSD_version < 502113
1040 /* Create the sysctl tree. */
1042 sc
->ndis_tree
= SYSCTL_ADD_NODE(&sc
->ndis_ctx
,
1043 SYSCTL_STATIC_CHILDREN(_hw
), OID_AUTO
,
1044 device_get_nameunit(sc
->ndis_dev
), CTLFLAG_RD
, 0,
1045 device_get_desc(sc
->ndis_dev
));
1048 /* Add the driver-specific registry keys. */
1050 vals
= sc
->ndis_regvals
;
1052 if (vals
->nc_cfgkey
== NULL
)
1054 if (vals
->nc_idx
!= sc
->ndis_devidx
) {
1059 /* See if we already have a sysctl with this name */
1062 #if __FreeBSD_version < 502113
1063 TAILQ_FOREACH(e
, &sc
->ndis_ctx
, link
) {
1065 TAILQ_FOREACH(e
, device_get_sysctl_ctx(sc
->ndis_dev
), link
) {
1068 if (ndis_strcasecmp(oidp
->oid_name
,
1069 vals
->nc_cfgkey
) == 0)
1079 #if __FreeBSD_version < 502113
1080 SYSCTL_ADD_STRING(&sc
->ndis_ctx
,
1081 SYSCTL_CHILDREN(sc
->ndis_tree
),
1083 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc
->ndis_dev
),
1084 SYSCTL_CHILDREN(device_get_sysctl_tree(sc
->ndis_dev
)),
1086 OID_AUTO
, vals
->nc_cfgkey
,
1087 CTLFLAG_RW
, vals
->nc_val
,
1088 sizeof(vals
->nc_val
),
1093 /* Now add a couple of builtin keys. */
1096 * Environment can be either Windows (0) or WindowsNT (1).
1097 * We qualify as the latter.
1099 ndis_add_sysctl(sc
, "Environment",
1100 "Windows environment", "1", CTLFLAG_RD
);
1102 /* NDIS version should be 5.1. */
1103 ndis_add_sysctl(sc
, "NdisVersion",
1104 "NDIS API Version", "0x00050001", CTLFLAG_RD
);
1106 /* Bus type (PCI, PCMCIA, etc...) */
1107 sprintf(buf
, "%d", (int)sc
->ndis_iftype
);
1108 ndis_add_sysctl(sc
, "BusType", "Bus Type", buf
, CTLFLAG_RD
);
1110 if (sc
->ndis_res_io
!= NULL
) {
1111 sprintf(buf
, "0x%lx", rman_get_start(sc
->ndis_res_io
));
1112 ndis_add_sysctl(sc
, "IOBaseAddress",
1113 "Base I/O Address", buf
, CTLFLAG_RD
);
1116 if (sc
->ndis_irq
!= NULL
) {
1117 sprintf(buf
, "%lu", rman_get_start(sc
->ndis_irq
));
1118 ndis_add_sysctl(sc
, "InterruptNumber",
1119 "Interrupt Number", buf
, CTLFLAG_RD
);
1124 #endif /* __FreeBSD__ */
1127 /* NetBSD version of ndis_create_sysctls() */
1129 ndis_create_sysctls(void *arg
)
1131 struct ndis_softc
*sc
;
1133 const struct sysctlnode
*ndis_node
;
1136 printf("in ndis_create_sysctls()\n");
1142 vals
= sc
->ndis_regvals
;
1144 TAILQ_INIT(&sc
->ndis_cfglist_head
);
1146 /* Create the sysctl tree. */
1147 sysctl_createv(&sc
->sysctllog
, 0, NULL
, &ndis_node
, CTLFLAG_READWRITE
, CTLTYPE_NODE
,
1148 device_xname(sc
->ndis_dev
), NULL
, NULL
, 0, NULL
, 0, CTL_CREATE
, CTL_EOL
);
1150 /* Store the number of the ndis mib */
1151 sc
->ndis_sysctl_mib
= ndis_node
->sysctl_num
;
1153 /* Add the driver-specific registry keys. */
1154 vals
= sc
->ndis_regvals
;
1156 if (vals
->nc_cfgkey
== NULL
)
1158 if (vals
->nc_idx
!= sc
->ndis_devidx
) {
1163 /* See if we already have a sysctl with this name */
1164 /* TODO: Is something like this necessary in NetBSD? I'm guessing this
1165 TODO: is just checking if any of the information in the .inf file was
1166 TODO: already determined by FreeBSD's autoconfiguration which seems to
1167 TODO: add dev.XXX sysctl's beginning with %. (NetBSD dosen't seem to do this).
1170 /* TODO: use CTLFLAG_OWNDATA or not? */
1172 sysctl_createv(&sc->sysctllog, 0, NULL, NULL,
1173 CTLFLAG_READWRITE|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA, CTLTYPE_STRING,
1174 vals->nc_cfgkey, vals->nc_cfgdesc, NULL, 0, vals->nc_val, strlen(vals->nc_val),
1175 ndis_node->sysctl_num, CTL_CREATE, CTL_EOL);
1177 ndis_add_sysctl(sc
, vals
->nc_cfgkey
,
1178 vals
->nc_cfgdesc
, vals
->nc_val
, CTLFLAG_READWRITE
);
1183 /* Now add a couple of builtin keys. */
1186 * Environment can be either Windows (0) or WindowsNT (1).
1187 * We qualify as the latter.
1190 #define CTLFLAG_RD CTLFLAG_READONLY
1191 /* TODO: do we need something like rman_get_start? */
1192 #define rman_get_start(x) x
1194 ndis_add_sysctl(sc
, "Environment",
1195 "Windows environment", "1", CTLFLAG_RD
);
1197 /* NDIS version should be 5.1. */
1198 ndis_add_sysctl(sc
, "NdisVersion",
1199 /*"NDIS API Version"*/ "Version", "0x00050001", CTLFLAG_RD
);
1201 /* Bus type (PCI, PCMCIA, etc...) */
1202 sprintf(buf
, "%d", (int)sc
->ndis_iftype
);
1203 ndis_add_sysctl(sc
, "BusType", "Bus Type", buf
, CTLFLAG_RD
);
1205 if (sc
->ndis_res_io
!= NULL
) {
1206 sprintf(buf
, "0x%lx", (long unsigned int)rman_get_start(sc
->ndis_res_io
));
1207 ndis_add_sysctl(sc
, "IOBaseAddress",
1208 /*"Base I/O Address"*/ "Base I/O", buf
, CTLFLAG_RD
);
1211 if (sc
->ndis_irq
!= NULL
) {
1212 sprintf(buf
, "%lu", (long unsigned int)rman_get_start(sc
->ndis_irq
));
1213 ndis_add_sysctl(sc
, "InterruptNumber",
1214 "Interrupt Number", buf
, CTLFLAG_RD
);
1219 #endif /* __NetBSD__ */
1221 char *ndis_strdup(const char *src
);
1223 char *ndis_strdup(const char *src
)
1227 ret
= malloc(strlen(src
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1229 printf("ndis_strdup failed\n");
1238 ndis_add_sysctl(void *arg
, const char *key
, const char *desc
, const char *val
, int flag
)
1240 struct ndis_softc
*sc
;
1241 struct ndis_cfglist
*cfg
;
1244 char newkey
[MAX_SYSCTL_LEN
+1];
1249 cfg
= malloc(sizeof(struct ndis_cfglist
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1254 /* I added this because NetBSD sysctl node names can't begin with
1258 if(strlen(key
) + strlen("ndis_") > MAX_SYSCTL_LEN
) {
1259 panic("sysctl name too long: %s\n", key
);
1261 strcpy(newkey
, "ndis_");
1262 strcpy(newkey
+ strlen("ndis_"), key
);
1266 cfg
->ndis_cfg
.nc_cfgkey
= ndis_strdup(key
);
1269 snprintf(descstr
, sizeof(descstr
), "%s (dynamic)", key
);
1270 cfg
->ndis_cfg
.nc_cfgdesc
= ndis_strdup(descstr
);
1272 cfg
->ndis_cfg
.nc_cfgdesc
= ndis_strdup(desc
);
1273 strcpy(cfg
->ndis_cfg
.nc_val
, val
);
1275 TAILQ_INSERT_TAIL(&sc
->ndis_cfglist_head
, cfg
, link
);
1278 #if __FreeBSD_version < 502113
1279 SYSCTL_ADD_STRING(&sc
->ndis_ctx
, SYSCTL_CHILDREN(sc
->ndis_tree
),
1281 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc
->ndis_dev
),
1282 SYSCTL_CHILDREN(device_get_sysctl_tree(sc
->ndis_dev
)),
1284 OID_AUTO
, cfg
->ndis_cfg
.nc_cfgkey
, flag
,
1285 cfg
->ndis_cfg
.nc_val
, sizeof(cfg
->ndis_cfg
.nc_val
),
1286 cfg
->ndis_cfg
.nc_cfgdesc
);
1287 #else /* __NetBSD__ */
1288 /* TODO: use CTLFLAG_OWNDATA or not? */
1289 sysctl_createv(&sc
->sysctllog
, 0, NULL
, NULL
, flag
/*|CTLFLAG_OWNDESC|CTLFLAG_OWNDATA*/, CTLTYPE_STRING
,
1290 cfg
->ndis_cfg
.nc_cfgkey
, cfg
->ndis_cfg
.nc_cfgdesc
, NULL
, 0, cfg
->ndis_cfg
.nc_val
,
1291 strlen(cfg
->ndis_cfg
.nc_val
), sc
->ndis_sysctl_mib
, CTL_CREATE
, CTL_EOL
);
1297 ndis_flush_sysctls(void *arg
)
1299 struct ndis_softc
*sc
;
1300 struct ndis_cfglist
*cfg
;
1304 while (!TAILQ_EMPTY(&sc
->ndis_cfglist_head
)) {
1305 cfg
= TAILQ_FIRST(&sc
->ndis_cfglist_head
);
1306 TAILQ_REMOVE(&sc
->ndis_cfglist_head
, cfg
, link
);
1308 free(cfg
->ndis_cfg
.nc_cfgkey
, M_DEVBUF
);
1309 free(cfg
->ndis_cfg
.nc_cfgdesc
, M_DEVBUF
);
1311 free(cfg
, M_DEVBUF
);
1318 ndis_return(void *arg
)
1320 struct ndis_softc
*sc
;
1321 __stdcall ndis_return_handler returnfunc
;
1322 ndis_handle adapter
;
1324 uint8_t irql
= 0; /* XXX: gcc */
1328 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
1330 if (adapter
== NULL
)
1333 returnfunc
= sc
->ndis_chars
->nmc_return_packet_func
;
1335 KeAcquireSpinLock(&sc
->ndis_block
->nmb_lock
, &irql
);
1336 MSCALL2(returnfunc
, adapter
, p
);
1337 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
1344 ndis_return_packet(buf
, arg
)
1345 void *buf
; /* not used */
1348 ndis_return_packet(struct mbuf
*m
, void *buf
,
1349 size_t size
, void *arg
)
1360 /* Decrement refcount. */
1363 /* Release packet when refcount hits zero, otherwise return. */
1367 ndis_sched(ndis_return
, p
, NDIS_TASKQUEUE
);
1373 ndis_free_bufs(ndis_buffer
*b0
)
1381 next
= b0
->mdl_next
;
1390 ndis_free_packet(ndis_packet
*p
)
1395 ndis_free_bufs(p
->np_private
.npp_head
);
1402 ndis_convert_res(void *arg
)
1404 struct ndis_softc
*sc
;
1405 ndis_resource_list
*rl
= NULL
;
1406 cm_partial_resource_desc
*prd
= NULL
;
1407 ndis_miniport_block
*block
;
1409 struct resource_list
*brl
;
1410 struct resource_list_entry
*brle
;
1411 #if __FreeBSD_version < 600022
1412 struct resource_list brl_rev
;
1413 struct resource_list_entry
*n
;
1418 block
= sc
->ndis_block
;
1421 #if __FreeBSD_version < 600022
1422 SLIST_INIT(&brl_rev
);
1424 rl
= malloc(sizeof(ndis_resource_list
) +
1425 (sizeof(cm_partial_resource_desc
) * (sc
->ndis_rescnt
- 1)),
1426 M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1431 rl
->cprl_version
= 5;
1432 rl
->cprl_version
= 1;
1433 rl
->cprl_count
= sc
->ndis_rescnt
;
1434 prd
= rl
->cprl_partial_descs
;
1436 brl
= BUS_GET_RESOURCE_LIST(dev
, dev
);
1440 #if __FreeBSD_version < 600022
1442 * We have a small problem. Some PCI devices have
1443 * multiple I/O ranges. Windows orders them starting
1444 * from lowest numbered BAR to highest. We discover
1445 * them in that order too, but insert them into a singly
1446 * linked list head first, which means when time comes
1447 * to traverse the list, we enumerate them in reverse
1448 * order. This screws up some drivers which expect the
1449 * BARs to be in ascending order so that they can choose
1450 * the "first" one as their register space. Unfortunately,
1451 * in order to fix this, we have to create our own
1452 * temporary list with the entries in reverse order.
1454 SLIST_FOREACH(brle
, brl
, link
) {
1455 n
= malloc(sizeof(struct resource_list_entry
),
1461 memcpy( (char *)n
, (char *)brle
,
1462 sizeof(struct resource_list_entry
));
1463 SLIST_INSERT_HEAD(&brl_rev
, n
, link
);
1466 SLIST_FOREACH(brle
, &brl_rev
, link
) {
1468 STAILQ_FOREACH(brle
, brl
, link
) {
1470 switch (brle
->type
) {
1471 case SYS_RES_IOPORT
:
1472 prd
->cprd_type
= CmResourceTypePort
;
1473 prd
->cprd_flags
= CM_RESOURCE_PORT_IO
;
1474 prd
->cprd_sharedisp
=
1475 CmResourceShareDeviceExclusive
;
1476 prd
->u
.cprd_port
.cprd_start
.np_quad
=
1478 prd
->u
.cprd_port
.cprd_len
= brle
->count
;
1480 case SYS_RES_MEMORY
:
1481 prd
->cprd_type
= CmResourceTypeMemory
;
1483 CM_RESOURCE_MEMORY_READ_WRITE
;
1484 prd
->cprd_sharedisp
=
1485 CmResourceShareDeviceExclusive
;
1486 prd
->u
.cprd_port
.cprd_start
.np_quad
=
1488 prd
->u
.cprd_port
.cprd_len
= brle
->count
;
1491 prd
->cprd_type
= CmResourceTypeInterrupt
;
1492 prd
->cprd_flags
= 0;
1493 prd
->cprd_sharedisp
=
1494 CmResourceShareDeviceExclusive
;
1495 prd
->u
.cprd_intr
.cprd_level
= brle
->start
;
1496 prd
->u
.cprd_intr
.cprd_vector
= brle
->start
;
1497 prd
->u
.cprd_intr
.cprd_affinity
= 0;
1506 block
->nmb_rlist
= rl
;
1508 #if __FreeBSD_version < 600022
1511 while (!SLIST_EMPTY(&brl_rev
)) {
1512 n
= SLIST_FIRST(&brl_rev
);
1513 SLIST_REMOVE_HEAD(&brl_rev
, link
);
1520 #endif /* __FreeBSD__ */
1522 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
1523 * packet, it will hand it to us in the form of an ndis_packet,
1524 * which we need to convert to an mbuf that is then handed off
1525 * to the stack. Note: we configure the mbuf list so that it uses
1526 * the memory regions specified by the ndis_buffer structures in
1527 * the ndis_packet as external storage. In most cases, this will
1528 * point to a memory region allocated by the driver (either by
1529 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
1530 * the driver to handle free()ing this region for is, so we set up
1531 * a dummy no-op free handler for it.
1535 ndis_ptom(struct mbuf
**m0
, ndis_packet
*p
)
1537 struct mbuf
*m
, *prev
= NULL
;
1539 ndis_packet_private
*priv
;
1540 uint32_t totlen
= 0;
1542 if (p
== NULL
|| m0
== NULL
)
1545 priv
= &p
->np_private
;
1546 buf
= priv
->npp_head
;
1549 for (buf
= priv
->npp_head
; buf
!= NULL
; buf
= buf
->mdl_next
) {
1550 if (buf
== priv
->npp_head
)
1551 MGETHDR(m
, M_DONTWAIT
, MT_HEADER
);
1553 MGET(m
, M_DONTWAIT
, MT_DATA
);
1559 m
->m_len
= MmGetMdlByteCount(buf
);
1560 m
->m_data
= MmGetMdlVirtualAddress(buf
);
1562 MEXTADD(m
, m
->m_data
, m
->m_len
, ndis_return_packet
,
1565 MEXTADD(m
, m
->m_data
, m
->m_len
, M_DEVBUF
,
1566 ndis_return_packet
, p
);
1570 if (m
->m_flags
& MT_HEADER
)
1577 (*m0
)->m_pkthdr
.len
= totlen
;
1583 * Create an NDIS packet from an mbuf chain.
1584 * This is used mainly when transmitting packets, where we need
1585 * to turn an mbuf off an interface's send queue and transform it
1586 * into an NDIS packet which will be fed into the NDIS driver's
1589 * NDIS packets consist of two parts: an ndis_packet structure,
1590 * which is vaguely analagous to the pkthdr portion of an mbuf,
1591 * and one or more ndis_buffer structures, which define the
1592 * actual memory segments in which the packet data resides.
1593 * We need to allocate one ndis_buffer for each mbuf in a chain,
1594 * plus one ndis_packet as the header.
1598 ndis_mtop(struct mbuf
*m0
, ndis_packet
**p
)
1601 ndis_buffer
*buf
= NULL
, *prev
= NULL
;
1602 ndis_packet_private
*priv
;
1604 if (p
== NULL
|| *p
== NULL
|| m0
== NULL
)
1607 priv
= &(*p
)->np_private
;
1608 priv
->npp_totlen
= m0
->m_pkthdr
.len
;
1610 for (m
= m0
; m
!= NULL
; m
= m
->m_next
) {
1613 buf
= IoAllocateMdl(m
->m_data
, m
->m_len
, FALSE
, FALSE
, NULL
);
1615 ndis_free_packet(*p
);
1620 if (priv
->npp_head
== NULL
)
1621 priv
->npp_head
= buf
;
1623 prev
->mdl_next
= buf
;
1627 priv
->npp_tail
= buf
;
1633 ndis_get_supported_oids(void *arg
, ndis_oid
**oids
, int *oidcnt
)
1638 if (arg
== NULL
|| oids
== NULL
|| oidcnt
== NULL
)
1641 ndis_get_info(arg
, OID_GEN_SUPPORTED_LIST
, NULL
, &len
);
1643 o
= malloc(len
, M_DEVBUF
, M_NOWAIT
);
1647 rval
= ndis_get_info(arg
, OID_GEN_SUPPORTED_LIST
, o
, &len
);
1661 ndis_set_info(void *arg
, ndis_oid oid
, void *buf
, int *buflen
)
1663 struct ndis_softc
*sc
;
1665 ndis_handle adapter
;
1666 __stdcall ndis_setinfo_handler setfunc
;
1667 uint32_t byteswritten
= 0, bytesneeded
= 0;
1669 uint8_t irql
= 0; /* XXX: gcc */
1675 * According to the NDIS spec, MiniportQueryInformation()
1676 * and MiniportSetInformation() requests are handled serially:
1677 * once one request has been issued, we must wait for it to
1678 * finish before allowing another request to proceed.
1683 KeAcquireSpinLock(&sc
->ndis_block
->nmb_lock
, &irql
);
1685 if (sc
->ndis_block
->nmb_pendingreq
!= NULL
)
1686 panic("ndis_set_info() called while other request pending");
1688 sc
->ndis_block
->nmb_pendingreq
= (ndis_request
*)sc
;
1690 /* I added this lock because it was present in the FreeBSD-current sources */
1693 setfunc
= sc
->ndis_chars
->nmc_setinfo_func
;
1694 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
1696 if (adapter
== NULL
|| setfunc
== NULL
) {
1697 sc
->ndis_block
->nmb_pendingreq
= NULL
;
1698 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
1705 rval
= MSCALL6(setfunc
, adapter
, oid
, buf
, *buflen
,
1706 &byteswritten
, &bytesneeded
);
1708 sc
->ndis_block
->nmb_pendingreq
= NULL
;
1710 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
1712 if (rval
== NDIS_STATUS_PENDING
) {
1713 mtx_lock(&ndis_req_mtx
);
1715 error
= msleep(&sc
->ndis_block
->nmb_setstat
,
1717 curthread
->td_priority
|PDROP
,
1720 error
= ltsleep(&sc
->ndis_block
->nmb_setstat
,
1721 curlwp
->l_priority
|PNORELOCK
,
1722 "ndisset", 5 * hz
, 0);
1724 rval
= sc
->ndis_block
->nmb_setstat
;
1726 mtx_unlock(&ndis_req_mtx
);
1732 *buflen
= byteswritten
;
1734 *buflen
= bytesneeded
;
1736 if (rval
== NDIS_STATUS_INVALID_LENGTH
)
1739 if (rval
== NDIS_STATUS_INVALID_OID
)
1742 if (rval
== NDIS_STATUS_NOT_SUPPORTED
||
1743 rval
== NDIS_STATUS_NOT_ACCEPTED
)
1746 if (rval
!= NDIS_STATUS_SUCCESS
)
1752 typedef void (*ndis_senddone_func
)(ndis_handle
, ndis_packet
*, ndis_status
);
1755 ndis_send_packets(void *arg
, ndis_packet
**packets
, int cnt
)
1757 struct ndis_softc
*sc
;
1758 ndis_handle adapter
;
1759 __stdcall ndis_sendmulti_handler sendfunc
;
1760 __stdcall ndis_senddone_func senddonefunc
;
1763 uint8_t irql
= 0; /* XXX: gcc */
1766 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
1767 if (adapter
== NULL
)
1769 sendfunc
= sc
->ndis_chars
->nmc_sendmulti_func
;
1770 senddonefunc
= sc
->ndis_block
->nmb_senddone_func
;
1772 if (NDIS_SERIALIZED(sc
->ndis_block
))
1773 KeAcquireSpinLock(&sc
->ndis_block
->nmb_lock
, &irql
);
1775 MSCALL3(sendfunc
, adapter
, packets
, cnt
);
1777 for (i
= 0; i
< cnt
; i
++) {
1780 * Either the driver already handed the packet to
1781 * ndis_txeof() due to a failure, or it wants to keep
1782 * it and release it asynchronously later. Skip to the
1785 if (p
== NULL
|| p
->np_oob
.npo_status
== NDIS_STATUS_PENDING
)
1787 MSCALL3(senddonefunc
, sc
->ndis_block
, p
, p
->np_oob
.npo_status
);
1790 if (NDIS_SERIALIZED(sc
->ndis_block
))
1791 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
1797 ndis_send_packet(void *arg
, ndis_packet
*packet
)
1799 struct ndis_softc
*sc
;
1800 ndis_handle adapter
;
1802 __stdcall ndis_sendsingle_handler sendfunc
;
1803 __stdcall ndis_senddone_func senddonefunc
;
1804 uint8_t irql
= 0; /* XXX: gcc */
1807 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
1808 if (adapter
== NULL
)
1810 sendfunc
= sc
->ndis_chars
->nmc_sendsingle_func
;
1811 senddonefunc
= sc
->ndis_block
->nmb_senddone_func
;
1813 if (NDIS_SERIALIZED(sc
->ndis_block
))
1814 KeAcquireSpinLock(&sc
->ndis_block
->nmb_lock
, &irql
);
1815 status
= MSCALL3(sendfunc
, adapter
, packet
,
1816 packet
->np_private
.npp_flags
);
1818 if (status
== NDIS_STATUS_PENDING
) {
1819 if (NDIS_SERIALIZED(sc
->ndis_block
))
1820 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
1824 MSCALL3(senddonefunc
, sc
->ndis_block
, packet
, status
);
1826 if (NDIS_SERIALIZED(sc
->ndis_block
))
1827 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
1833 ndis_init_dma(void *arg
)
1835 struct ndis_softc
*sc
;
1840 sc
->ndis_tmaps
= malloc(sizeof(bus_dmamap_t
) * sc
->ndis_maxpkts
,
1841 M_DEVBUF
, M_NOWAIT
|M_ZERO
);
1843 if (sc
->ndis_tmaps
== NULL
)
1846 for (i
= 0; i
< sc
->ndis_maxpkts
; i
++) {
1848 error
= bus_dmamap_create(sc
->ndis_ttag
, 0,
1849 &sc
->ndis_tmaps
[i
]);
1852 bus_dmamap_create(sc->ndis_mtag, sizeof(bus_dmamap_t),
1853 1, sizeof(bus_dmamap_t), BUS_DMA_NOWAIT,
1854 0, &sc->ndis_mmaps[i]);
1856 bus_dmamap_create(sc
->ndis_ttag
, NDIS_MAXSEG
* MCLBYTES
,
1857 NDIS_MAXSEG
, MCLBYTES
, 0,
1858 BUS_DMA_NOWAIT
, &sc
->ndis_tmaps
[i
]);
1861 free(sc
->ndis_tmaps
, M_DEVBUF
);
1870 ndis_destroy_dma(void *arg
)
1872 struct ndis_softc
*sc
;
1874 ndis_packet
*p
= NULL
;
1879 for (i
= 0; i
< sc
->ndis_maxpkts
; i
++) {
1880 if (sc
->ndis_txarray
[i
] != NULL
) {
1881 p
= sc
->ndis_txarray
[i
];
1882 m
= (struct mbuf
*)p
->np_rsvd
[1];
1885 ndis_free_packet(sc
->ndis_txarray
[i
]);
1887 bus_dmamap_destroy(sc
->ndis_ttag
, sc
->ndis_tmaps
[i
]);
1890 free(sc
->ndis_tmaps
, M_DEVBUF
);
1893 bus_dma_tag_destroy(sc
->ndis_ttag
);
1900 ndis_reset_nic(void *arg
)
1902 struct ndis_softc
*sc
;
1903 ndis_handle adapter
;
1904 __stdcall ndis_reset_handler resetfunc
;
1905 uint8_t addressing_reset
;
1908 uint8_t irql
= 0; /* XXX: gcc */
1912 ifp
= &sc
->arpcom
.ac_if
;
1914 ifp
= &sc
->arpcom
.ec_if
;
1917 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
1918 resetfunc
= sc
->ndis_chars
->nmc_reset_func
;
1920 if (adapter
== NULL
|| resetfunc
== NULL
)
1923 if (NDIS_SERIALIZED(sc
->ndis_block
))
1924 KeAcquireSpinLock(&sc
->ndis_block
->nmb_lock
, &irql
);
1926 rval
= MSCALL2(resetfunc
, &addressing_reset
, adapter
);
1928 if (NDIS_SERIALIZED(sc
->ndis_block
))
1929 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
1931 if (rval
== NDIS_STATUS_PENDING
) {
1932 mtx_lock(&ndis_req_mtx
);
1934 msleep(sc
, &ndis_req_mtx
,
1935 curthread
->td_priority
|PDROP
, "ndisrst", 0);
1937 ltsleep(sc
, curlwp
->l_priority
|PNORELOCK
, "ndisrst", 0, 0);
1945 ndis_halt_nic(void *arg
)
1947 struct ndis_softc
*sc
;
1948 ndis_handle adapter
;
1949 __stdcall ndis_halt_handler haltfunc
;
1957 ifp
= &sc
->arpcom
.ac_if
;
1959 ifp
= &sc
->arpcom
.ec_if
;
1964 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
1965 if (adapter
== NULL
) {
1971 * The adapter context is only valid after the init
1972 * handler has been called, and is invalid once the
1973 * halt handler has been called.
1976 haltfunc
= sc
->ndis_chars
->nmc_halt_func
;
1980 MSCALL1(haltfunc
, adapter
);
1984 sc
->ndis_block
->nmb_miniportadapterctx
= NULL
;
1992 ndis_shutdown_nic(void *arg
)
1994 struct ndis_softc
*sc
;
1995 ndis_handle adapter
;
1996 __stdcall ndis_shutdown_handler shutdownfunc
;
2005 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
2006 shutdownfunc
= sc
->ndis_chars
->nmc_shutdown_handler
;
2010 if (adapter
== NULL
|| shutdownfunc
== NULL
)
2013 if (sc
->ndis_chars
->nmc_rsvd0
== NULL
)
2014 MSCALL1(shutdownfunc
, adapter
);
2016 MSCALL1(shutdownfunc
, sc
->ndis_chars
->nmc_rsvd0
);
2018 ndis_shrink_thrqueue(8);
2019 TAILQ_REMOVE(&ndis_devhead
, sc
->ndis_block
, link
);
2025 ndis_init_nic(void *arg
)
2027 struct ndis_softc
*sc
;
2028 ndis_miniport_block
*block
;
2029 __stdcall ndis_init_handler initfunc
;
2030 ndis_status status
, openstatus
= 0;
2031 ndis_medium mediumarray
[NdisMediumMax
];
2032 uint32_t chosenmedium
, i
;
2044 block
= sc
->ndis_block
;
2045 initfunc
= sc
->ndis_chars
->nmc_init_func
;
2049 printf("sc->ndis_chars->nmc_version_major = %d\n\
2050 sc->ndis_chars->nmc_version_minor = %d\n",
2051 sc
->ndis_chars
->nmc_version_major
,
2052 sc
->ndis_chars
->nmc_version_minor
);
2054 for (i
= 0; i
< NdisMediumMax
; i
++)
2057 status
= MSCALL6(initfunc
, &openstatus
, &chosenmedium
,
2058 mediumarray
, NdisMediumMax
, block
, block
);
2060 printf("status = %x", status
);
2063 * If the init fails, blow away the other exported routines
2064 * we obtained from the driver so we can't call them later.
2065 * If the init failed, none of these will work.
2067 if (status
!= NDIS_STATUS_SUCCESS
) {
2070 sc
->ndis_block
->nmb_miniportadapterctx
= NULL
;
2080 ndis_enable_intr(void *arg
)
2082 struct ndis_softc
*sc
;
2083 ndis_handle adapter
;
2084 __stdcall ndis_enable_interrupts_handler intrenbfunc
;
2087 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
2088 intrenbfunc
= sc
->ndis_chars
->nmc_enable_interrupts_func
;
2089 if (adapter
== NULL
|| intrenbfunc
== NULL
)
2091 MSCALL1(intrenbfunc
, adapter
);
2097 ndis_disable_intr(void *arg
)
2099 struct ndis_softc
*sc
;
2100 ndis_handle adapter
;
2101 __stdcall ndis_disable_interrupts_handler intrdisfunc
;
2104 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
2105 intrdisfunc
= sc
->ndis_chars
->nmc_disable_interrupts_func
;
2106 if (adapter
== NULL
|| intrdisfunc
== NULL
)
2109 MSCALL1(intrdisfunc
, adapter
);
2115 ndis_isr(void *arg
, int *ourintr
, int *callhandler
)
2117 struct ndis_softc
*sc
;
2118 ndis_handle adapter
;
2119 __stdcall ndis_isr_handler isrfunc
;
2120 uint8_t accepted
, queue
;
2122 if (arg
== NULL
|| ourintr
== NULL
|| callhandler
== NULL
)
2126 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
2127 isrfunc
= sc
->ndis_chars
->nmc_isr_func
;
2129 if (adapter
== NULL
|| isrfunc
== NULL
)
2132 MSCALL3(isrfunc
, &accepted
, &queue
, adapter
);
2134 *ourintr
= accepted
;
2135 *callhandler
= queue
;
2140 __stdcall
static void
2141 ndis_intrhand(kdpc
*dpc
, device_object
*dobj
,
2142 irp
*ip
, struct ndis_softc
*sc
)
2144 ndis_handle adapter
;
2145 __stdcall ndis_interrupt_handler intrfunc
;
2146 uint8_t irql
= 0; /* XXX: gcc */
2148 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
2149 intrfunc
= sc
->ndis_chars
->nmc_interrupt_func
;
2151 if (adapter
== NULL
|| intrfunc
== NULL
)
2154 if (NDIS_SERIALIZED(sc
->ndis_block
))
2155 KeAcquireSpinLock(&sc
->ndis_block
->nmb_lock
, &irql
);
2157 MSCALL1(intrfunc
, adapter
);
2159 /* If there's a MiniportEnableInterrupt() routine, call it. */
2161 ndis_enable_intr(sc
);
2163 if (NDIS_SERIALIZED(sc
->ndis_block
))
2164 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
2170 ndis_get_info(void *arg
, ndis_oid oid
, void *buf
, int *buflen
)
2172 struct ndis_softc
*sc
;
2174 ndis_handle adapter
;
2175 __stdcall ndis_queryinfo_handler queryfunc
;
2176 uint32_t byteswritten
= 0, bytesneeded
= 0;
2180 uint8_t irql
= 0; /* XXX: gcc */
2182 //printf("in ndis_get_info\n");
2185 KeAcquireSpinLock(&sc
->ndis_block
->nmb_lock
, &irql
);
2187 if (sc
->ndis_block
->nmb_pendingreq
!= NULL
)
2188 panic("ndis_get_info() called while other request pending");
2190 sc
->ndis_block
->nmb_pendingreq
= (ndis_request
*)sc
;
2192 queryfunc
= sc
->ndis_chars
->nmc_queryinfo_func
;
2193 adapter
= sc
->ndis_block
->nmb_miniportadapterctx
;
2195 if (adapter
== NULL
|| queryfunc
== NULL
) {
2196 sc
->ndis_block
->nmb_pendingreq
= NULL
;
2197 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
2201 rval
= MSCALL6(queryfunc
, adapter
, oid
, buf
, *buflen
,
2202 &byteswritten
, &bytesneeded
);
2204 sc
->ndis_block
->nmb_pendingreq
= NULL
;
2206 KeReleaseSpinLock(&sc
->ndis_block
->nmb_lock
, irql
);
2208 /* Wait for requests that block. */
2210 if (rval
== NDIS_STATUS_PENDING
) {
2211 mtx_lock(&ndis_req_mtx
);
2213 error
= msleep(&sc
->ndis_block
->nmb_getstat
,
2215 curthread
->td_priority
|PDROP
,
2218 ltsleep(&sc
->ndis_block
->nmb_getstat
,
2219 curlwp
->l_priority
|PNORELOCK
, "ndisget", 5 * hz
, 0);
2221 rval
= sc
->ndis_block
->nmb_getstat
;
2225 *buflen
= byteswritten
;
2227 *buflen
= bytesneeded
;
2229 if (rval
== NDIS_STATUS_INVALID_LENGTH
||
2230 rval
== NDIS_STATUS_BUFFER_TOO_SHORT
)
2233 if (rval
== NDIS_STATUS_INVALID_OID
)
2236 if (rval
== NDIS_STATUS_NOT_SUPPORTED
||
2237 rval
== NDIS_STATUS_NOT_ACCEPTED
)
2240 if (rval
!= NDIS_STATUS_SUCCESS
)
2247 NdisAddDevice(driver_object
*drv
, device_object
*pdo
)
2250 ndis_miniport_block
*block
;
2251 struct ndis_softc
*sc
;
2254 status
= IoCreateDevice(drv
, sizeof(ndis_miniport_block
), NULL
,
2255 FILE_DEVICE_UNKNOWN
, 0, FALSE
, &fdo
);
2257 if (status
!= STATUS_SUCCESS
)
2260 block
= fdo
->do_devext
;
2261 block
->nmb_deviceobj
= fdo
;
2262 block
->nmb_physdeviceobj
= pdo
;
2263 block
->nmb_nextdeviceobj
= IoAttachDeviceToDeviceStack(fdo
, pdo
);
2264 KeInitializeSpinLock(&block
->nmb_lock
);
2267 /* NetBSD has a pointer to the callout object */
2268 block
->nmb_wkupdpctimer
.nt_ktimer
.k_handle
=
2269 malloc(sizeof(struct callout
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
2273 * Stash pointers to the miniport block and miniport
2274 * characteristics info in the if_ndis softc so the
2275 * UNIX wrapper driver can get to them later.
2278 sc
= device_get_softc(pdo
->do_devext
);
2279 #else /* __NetBSD__ */
2283 sc
->ndis_block
= block
;
2284 sc
->ndis_chars
= IoGetDriverObjectExtension(drv
, (void *)1);
2286 IoInitializeDpcRequest(fdo
, kernndis_functbl
[6].ipt_wrap
);
2288 /* Finish up BSD-specific setup. */
2290 block
->nmb_signature
= (void *)0xcafebabe;
2291 block
->nmb_status_func
= kernndis_functbl
[0].ipt_wrap
;
2292 block
->nmb_statusdone_func
= kernndis_functbl
[1].ipt_wrap
;
2293 block
->nmb_setdone_func
= kernndis_functbl
[2].ipt_wrap
;
2294 block
->nmb_querydone_func
= kernndis_functbl
[3].ipt_wrap
;
2295 block
->nmb_resetdone_func
= kernndis_functbl
[4].ipt_wrap
;
2296 block
->nmb_sendrsrc_func
= kernndis_functbl
[5].ipt_wrap
;
2297 block
->nmb_pendingreq
= NULL
;
2299 ndis_enlarge_thrqueue(8);
2301 TAILQ_INSERT_TAIL(&ndis_devhead
, block
, link
);
2303 return (STATUS_SUCCESS
);
2307 ndis_unload_driver(void *arg
)
2309 struct ndis_softc
*sc
;
2314 if (sc
->ndis_block
->nmb_rlist
!= NULL
)
2315 free(sc
->ndis_block
->nmb_rlist
, M_DEVBUF
);
2317 ndis_flush_sysctls(sc
);
2319 ndis_shrink_thrqueue(8);
2320 TAILQ_REMOVE(&ndis_devhead
, sc
->ndis_block
, link
);
2322 fdo
= sc
->ndis_block
->nmb_deviceobj
;
2323 IoDetachDevice(sc
->ndis_block
->nmb_nextdeviceobj
);
2324 IoDeleteDevice(fdo
);