Do a major clean-up of the BUSDMA architecture. A large number of
[dragonfly.git] / sys / emulation / ndis / kern_ndis.c
CommitLineData
60d6dac1
MD
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 * $FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.57 2004/07/11 00:19:30 wpaul Exp $
1f7ab7c9 33 * $DragonFly: src/sys/emulation/ndis/kern_ndis.c,v 1.13 2006/10/25 20:56:02 dillon Exp $
60d6dac1
MD
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/unistd.h>
39#include <sys/types.h>
40#include <sys/errno.h>
41#include <sys/callout.h>
42#include <sys/socket.h>
43#include <sys/queue.h>
44#include <sys/sysctl.h>
45#include <sys/proc.h>
46#include <sys/malloc.h>
47#include <sys/lock.h>
48#include <sys/conf.h>
49
50#include <sys/kernel.h>
51#include <sys/module.h>
52#include <sys/kthread.h>
60d6dac1
MD
53#include <sys/bus.h>
54#include <sys/rman.h>
55
56#include <net/if.h>
57#include <net/if_arp.h>
58#include <net/ethernet.h>
59#include <net/if_dl.h>
60#include <net/if_media.h>
61
62#include <netproto/802_11/ieee80211_var.h>
63#include <netproto/802_11/ieee80211_ioctl.h>
64
65#include "regcall.h"
66#include "pe_var.h"
67#include "resource_var.h"
68#include "ntoskrnl_var.h"
69#include "ndis_var.h"
70#include "hal_var.h"
71#include "cfg_var.h"
72#include <dev/netif/ndis/if_ndisvar.h>
73
74#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
75
76__stdcall static void ndis_status_func(ndis_handle, ndis_status,
77 void *, uint32_t);
78__stdcall static void ndis_statusdone_func(ndis_handle);
79__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
80__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
81__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
82__stdcall static void ndis_sendrsrcavail_func(ndis_handle);
83
84struct nd_head ndis_devhead;
85
86struct ndis_req {
87 void (*nr_func)(void *);
88 void *nr_arg;
89 int nr_exit;
90 STAILQ_ENTRY(ndis_req) link;
91};
92
93struct ndisproc {
94 struct ndisqhead *np_q;
95 struct thread *np_td;
96 int np_state;
97};
98
99static void ndis_return(void *);
100static int ndis_create_kthreads(void);
101static void ndis_destroy_kthreads(void);
102static void ndis_stop_thread(int);
103static int ndis_enlarge_thrqueue(int);
104static int ndis_shrink_thrqueue(int);
105static void ndis_runq(void *);
106
107static MALLOC_DEFINE(M_NDIS_PACKET, "ndis_packet", "ndis packet slosh");
108static MALLOC_DEFINE(M_NDIS_BUFFER, "ndis_buffer", "ndis buffer slosh");
109struct lwkt_token ndis_thr_token;
110static STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo;
111struct ndisqhead ndis_itodo;
112struct ndisqhead ndis_free;
113static int ndis_jobs = 32;
114
115static struct ndisproc ndis_tproc;
116static struct ndisproc ndis_iproc;
117
118/*
119 * This allows us to export our symbols to other modules.
120 * Note that we call ourselves 'ndisapi' to avoid a namespace
121 * collision with if_ndis.ko, which internally calls itself
122 * 'ndis.'
123 */
124static int
125ndis_modevent(module_t mod, int cmd, void *arg)
126{
127 int error = 0;
128
129 switch (cmd) {
130 case MOD_LOAD:
131 /* Initialize subsystems */
132 ndis_libinit();
133 ntoskrnl_libinit();
134
135 /* Initialize TX buffer UMA zone. */
136 ndis_create_kthreads();
137
138 TAILQ_INIT(&ndis_devhead);
139
140 break;
141 case MOD_SHUTDOWN:
142 /* stop kthreads */
143 ndis_destroy_kthreads();
144 if (TAILQ_FIRST(&ndis_devhead) == NULL) {
145 /* Shut down subsystems */
146 ndis_libfini();
147 ntoskrnl_libfini();
148
149 /* Remove zones */
150#if 0 /* YYY */
151 malloc_uninit(M_NDIS_PACKET);
152 malloc_uninit(M_NDIS_BUFFER);
153#endif
154 }
155 break;
156 case MOD_UNLOAD:
157 /* stop kthreads */
158 ndis_destroy_kthreads();
159
160 /* Shut down subsystems */
161 ndis_libfini();
162 ntoskrnl_libfini();
163
164 /* Remove zones */
165#if 0 /* YYY */
166 malloc_uninit(M_NDIS_PACKET);
167 malloc_uninit(M_NDIS_BUFFER);
168#endif
169 break;
170 default:
171 error = EINVAL;
172 break;
173 }
174
175 return(error);
176}
177DEV_MODULE(ndisapi, ndis_modevent, NULL);
178MODULE_VERSION(ndisapi, 1);
179
180/*
181 * We create two kthreads for the NDIS subsystem. One of them is a task
182 * queue for performing various odd jobs. The other is an swi thread
183 * reserved exclusively for running interrupt handlers. The reason we
184 * have our own task queue is that there are some cases where we may
185 * need to sleep for a significant amount of time, and if we were to
186 * use one of the taskqueue threads, we might delay the processing
187 * of other pending tasks which might need to run right away. We have
188 * a separate swi thread because we don't want our interrupt handling
189 * to be delayed either.
190 *
191 * By default there are 32 jobs available to start, and another 8
192 * are added to the free list each time a new device is created.
193 */
194
195static void
2da2a8af 196ndis_runq(void *arg)
60d6dac1
MD
197{
198 struct ndis_req *r = NULL, *die = NULL;
199 struct ndisproc *p;
200 struct lwkt_tokref tokref;
201
202 p = arg;
203
204 while (1) {
205
206 /* Sleep, but preserve our original priority. */
207 ndis_thsuspend(p->np_td, 0);
208
209 /* Look for any jobs on the work queue. */
210
211 lwkt_gettoken(&tokref, &ndis_thr_token);
212 p->np_state = NDIS_PSTATE_RUNNING;
213 while(STAILQ_FIRST(p->np_q) != NULL) {
214 r = STAILQ_FIRST(p->np_q);
215 STAILQ_REMOVE_HEAD(p->np_q, link);
216 lwkt_reltoken(&tokref);
217
218 /* Do the work. */
219
220 if (r->nr_func != NULL)
221 (*r->nr_func)(r->nr_arg);
222
223 lwkt_gettoken(&tokref, &ndis_thr_token);
224 STAILQ_INSERT_HEAD(&ndis_free, r, link);
225
226 /* Check for a shutdown request */
227
228 if (r->nr_exit == TRUE)
229 die = r;
230 }
231 p->np_state = NDIS_PSTATE_SLEEPING;
232 lwkt_reltoken(&tokref);
233
234 /* Bail if we were told to shut down. */
235
236 if (die != NULL)
237 break;
238 }
239
240 wakeup(die);
241 kthread_exit();
242}
243
244static int
2da2a8af 245ndis_create_kthreads(void)
60d6dac1
MD
246{
247 struct ndis_req *r;
248 int i, error = 0;
249
250 lwkt_token_init(&ndis_thr_token);
251
252 STAILQ_INIT(&ndis_ttodo);
253 STAILQ_INIT(&ndis_itodo);
254 STAILQ_INIT(&ndis_free);
255
256 for (i = 0; i < ndis_jobs; i++) {
efda3bd0 257 r = kmalloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
60d6dac1
MD
258 STAILQ_INSERT_HEAD(&ndis_free, r, link);
259 }
260
261 if (error == 0) {
262 ndis_tproc.np_q = &ndis_ttodo;
263 ndis_tproc.np_state = NDIS_PSTATE_SLEEPING;
264 error = kthread_create_stk(ndis_runq, &ndis_tproc,
265 &ndis_tproc.np_td, NDIS_KSTACK_PAGES * PAGE_SIZE,
266 "ndis taskqueue");
267 }
268
269 if (error == 0) {
270 ndis_iproc.np_q = &ndis_itodo;
271 ndis_iproc.np_state = NDIS_PSTATE_SLEEPING;
272 error = kthread_create_stk(ndis_runq, &ndis_iproc,
273 &ndis_iproc.np_td, NDIS_KSTACK_PAGES * PAGE_SIZE,
274 "ndis swi");
275 }
276
277 if (error) {
278 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
279 STAILQ_REMOVE_HEAD(&ndis_free, link);
efda3bd0 280 kfree(r, M_DEVBUF);
60d6dac1
MD
281 }
282 return(error);
283 }
284
285 return(0);
286}
287
288static void
2da2a8af 289ndis_destroy_kthreads(void)
60d6dac1
MD
290{
291 struct ndis_req *r;
292
293 /* Stop the threads. */
294
295 ndis_stop_thread(NDIS_TASKQUEUE);
296 ndis_stop_thread(NDIS_SWI);
297
298 /* Destroy request structures. */
299
300 while ((r = STAILQ_FIRST(&ndis_free)) != NULL) {
301 STAILQ_REMOVE_HEAD(&ndis_free, link);
efda3bd0 302 kfree(r, M_DEVBUF);
60d6dac1
MD
303 }
304
305 lwkt_token_uninit(&ndis_thr_token);
306
307 return;
308}
309
310static void
2da2a8af 311ndis_stop_thread(int t)
60d6dac1
MD
312{
313 struct ndis_req *r;
314 struct ndisqhead *q;
315 thread_t td;
316 struct lwkt_tokref tokref;
317
318 if (t == NDIS_TASKQUEUE) {
319 q = &ndis_ttodo;
320 td = ndis_tproc.np_td;
321 } else {
322 q = &ndis_itodo;
323 td = ndis_iproc.np_td;
324 }
325
326 /* Create and post a special 'exit' job. */
327
328 lwkt_gettoken(&tokref, &ndis_thr_token);
329 r = STAILQ_FIRST(&ndis_free);
330 STAILQ_REMOVE_HEAD(&ndis_free, link);
331 r->nr_func = NULL;
332 r->nr_arg = NULL;
333 r->nr_exit = TRUE;
334 STAILQ_INSERT_TAIL(q, r, link);
335 lwkt_reltoken(&tokref);
336
337 ndis_thresume(td);
338
339 /* wait for thread exit */
340
341 tsleep(r, PCATCH, "ndisthexit", hz * 60);
342
343 /* Now empty the job list. */
344
345 lwkt_gettoken(&tokref, &ndis_thr_token);
346 while ((r = STAILQ_FIRST(q)) != NULL) {
347 STAILQ_REMOVE_HEAD(q, link);
348 STAILQ_INSERT_HEAD(&ndis_free, r, link);
349 }
350 lwkt_reltoken(&tokref);
351
352 return;
353}
354
355static int
2da2a8af 356ndis_enlarge_thrqueue(int cnt)
60d6dac1
MD
357{
358 struct ndis_req *r;
359 int i;
360 struct lwkt_tokref tokref;
361
362 for (i = 0; i < cnt; i++) {
efda3bd0 363 r = kmalloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK);
60d6dac1
MD
364 lwkt_gettoken(&tokref, &ndis_thr_token);
365 STAILQ_INSERT_HEAD(&ndis_free, r, link);
366 ndis_jobs++;
367 lwkt_reltoken(&tokref);
368 }
369
370 return(0);
371}
372
373static int
2da2a8af 374ndis_shrink_thrqueue(int cnt)
60d6dac1
MD
375{
376 struct ndis_req *r;
377 int i;
378 struct lwkt_tokref tokref;
379
380 for (i = 0; i < cnt; i++) {
381 lwkt_gettoken(&tokref, &ndis_thr_token);
382 r = STAILQ_FIRST(&ndis_free);
383 if (r == NULL) {
384 lwkt_reltoken(&tokref);
385 return(ENOMEM);
386 }
387 STAILQ_REMOVE_HEAD(&ndis_free, link);
388 ndis_jobs--;
389 lwkt_reltoken(&tokref);
efda3bd0 390 kfree(r, M_DEVBUF);
60d6dac1
MD
391 }
392
393 return(0);
394}
395
396int
2da2a8af 397ndis_unsched(void (*func)(void *), void *arg, int t)
60d6dac1
MD
398{
399 struct ndis_req *r;
400 struct ndisqhead *q;
401 thread_t td;
402 struct lwkt_tokref tokref;
403
404 if (t == NDIS_TASKQUEUE) {
405 q = &ndis_ttodo;
406 td = ndis_tproc.np_td;
407 } else {
408 q = &ndis_itodo;
409 td = ndis_iproc.np_td;
410 }
411
412 lwkt_gettoken(&tokref, &ndis_thr_token);
413 STAILQ_FOREACH(r, q, link) {
414 if (r->nr_func == func && r->nr_arg == arg) {
415 STAILQ_REMOVE(q, r, ndis_req, link);
416 STAILQ_INSERT_HEAD(&ndis_free, r, link);
417 lwkt_reltoken(&tokref);
418 return(0);
419 }
420 }
421
422 lwkt_reltoken(&tokref);
423
424 return(ENOENT);
425}
426
427int
2da2a8af 428ndis_sched(void (*func)(void *), void *arg, int t)
60d6dac1
MD
429{
430 struct ndis_req *r;
431 struct ndisqhead *q;
432 thread_t td;
433 int s;
434 struct lwkt_tokref tokref;
435
436 if (t == NDIS_TASKQUEUE) {
437 q = &ndis_ttodo;
438 td = ndis_tproc.np_td;
439 } else {
440 q = &ndis_itodo;
441 td = ndis_iproc.np_td;
442 }
443
444 lwkt_gettoken(&tokref, &ndis_thr_token);
445 /*
446 * Check to see if an instance of this job is already
447 * pending. If so, don't bother queuing it again.
448 */
449 STAILQ_FOREACH(r, q, link) {
450 if (r->nr_func == func && r->nr_arg == arg) {
451 lwkt_reltoken(&tokref);
452 return(0);
453 }
454 }
455 r = STAILQ_FIRST(&ndis_free);
456 if (r == NULL) {
457 lwkt_reltoken(&tokref);
458 return(EAGAIN);
459 }
460 STAILQ_REMOVE_HEAD(&ndis_free, link);
461 r->nr_func = func;
462 r->nr_arg = arg;
463 r->nr_exit = FALSE;
464 STAILQ_INSERT_TAIL(q, r, link);
465 if (t == NDIS_TASKQUEUE)
466 s = ndis_tproc.np_state;
467 else
468 s = ndis_iproc.np_state;
469 lwkt_reltoken(&tokref);
470
471 /*
472 * Post the job, but only if the thread is actually blocked
473 * on its own suspend call. If a driver queues up a job with
474 * NdisScheduleWorkItem() which happens to do a KeWaitForObject(),
475 * it may suspend there, and in that case we don't want to wake
476 * it up until KeWaitForObject() gets woken up on its own.
477 */
478 if (s == NDIS_PSTATE_SLEEPING)
479 ndis_thresume(td);
480
481 return(0);
482}
483
484int
2da2a8af 485ndis_thsuspend(thread_t td, int timo)
60d6dac1
MD
486{
487 int error;
488
489 error = tsleep(td, 0, "ndissp", timo);
490 return(error);
491}
492
493void
2da2a8af 494ndis_thresume(struct thread *td)
60d6dac1
MD
495{
496 wakeup(td);
497}
498
499__stdcall static void
2da2a8af 500ndis_sendrsrcavail_func(ndis_handle adapter)
60d6dac1
MD
501{
502 return;
503}
504
505__stdcall static void
2da2a8af
SW
506ndis_status_func(ndis_handle adapter, ndis_status status, void *sbuf,
507 uint32_t slen)
60d6dac1
MD
508{
509 ndis_miniport_block *block;
510 block = adapter;
511
512 if (block->nmb_ifp->if_flags & IFF_DEBUG)
513 device_printf (block->nmb_dev, "status: %x\n", status);
514 return;
515}
516
517__stdcall static void
2da2a8af 518ndis_statusdone_func(ndis_handle adapter)
60d6dac1
MD
519{
520 ndis_miniport_block *block;
521 block = adapter;
522
523 if (block->nmb_ifp->if_flags & IFF_DEBUG)
524 device_printf (block->nmb_dev, "status complete\n");
525 return;
526}
527
528__stdcall static void
2da2a8af 529ndis_setdone_func(ndis_handle adapter, ndis_status status)
60d6dac1
MD
530{
531 ndis_miniport_block *block;
532 block = adapter;
533
534 block->nmb_setstat = status;
535 wakeup(&block->nmb_wkupdpctimer);
536 return;
537}
538
539__stdcall static void
2da2a8af 540ndis_getdone_func(ndis_handle adapter, ndis_status status)
60d6dac1
MD
541{
542 ndis_miniport_block *block;
543 block = adapter;
544
545 block->nmb_getstat = status;
546 wakeup(&block->nmb_wkupdpctimer);
547 return;
548}
549
550__stdcall static void
2da2a8af
SW
551ndis_resetdone_func(ndis_handle adapter, ndis_status status,
552 uint8_t addressingreset)
60d6dac1
MD
553{
554 ndis_miniport_block *block;
555 block = adapter;
556
557 if (block->nmb_ifp->if_flags & IFF_DEBUG)
558 device_printf (block->nmb_dev, "reset done...\n");
559 wakeup(block->nmb_ifp);
560 return;
561}
562
563int
2da2a8af 564ndis_create_sysctls(void *arg)
60d6dac1
MD
565{
566 struct ndis_softc *sc;
567 ndis_cfg *vals;
568 char buf[256];
569
570 if (arg == NULL)
571 return(EINVAL);
572
573 sc = arg;
574 vals = sc->ndis_regvals;
575
576 TAILQ_INIT(&sc->ndis_cfglist_head);
577
578#if __FreeBSD_version < 502113
579 /* Create the sysctl tree. */
580
581 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
582 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
583 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
584 device_get_desc(sc->ndis_dev));
585
586#endif
587 /* Add the driver-specific registry keys. */
588
589 vals = sc->ndis_regvals;
590 while(1) {
591 if (vals->nc_cfgkey == NULL)
592 break;
593 if (vals->nc_idx != sc->ndis_devidx) {
594 vals++;
595 continue;
596 }
597#if 1
598 SYSCTL_ADD_STRING(&sc->ndis_ctx,
599 SYSCTL_CHILDREN(sc->ndis_tree),
600 OID_AUTO, vals->nc_cfgkey,
601 CTLFLAG_RW, vals->nc_val,
602 sizeof(vals->nc_val),
603 vals->nc_cfgdesc);
604#else
605 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
606 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
607 OID_AUTO, vals->nc_cfgkey,
608 CTLFLAG_RW, vals->nc_val,
609 sizeof(vals->nc_val),
610 vals->nc_cfgdesc);
611#endif
612 vals++;
613 }
614
615 /* Now add a couple of builtin keys. */
616
617 /*
618 * Environment can be either Windows (0) or WindowsNT (1).
619 * We qualify as the latter.
620 */
621 ndis_add_sysctl(sc, "Environment",
622 "Windows environment", "1", CTLFLAG_RD);
623
624 /* NDIS version should be 5.1. */
625 ndis_add_sysctl(sc, "NdisVersion",
626 "NDIS API Version", "0x00050001", CTLFLAG_RD);
627
628 /* Bus type (PCI, PCMCIA, etc...) */
629 sprintf(buf, "%d", (int)sc->ndis_iftype);
630 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
631
632 if (sc->ndis_res_io != NULL) {
633 sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io));
634 ndis_add_sysctl(sc, "IOBaseAddress",
635 "Base I/O Address", buf, CTLFLAG_RD);
636 }
637
638 if (sc->ndis_irq != NULL) {
639 sprintf(buf, "%lu", rman_get_start(sc->ndis_irq));
640 ndis_add_sysctl(sc, "InterruptNumber",
641 "Interrupt Number", buf, CTLFLAG_RD);
642 }
643
644 return(0);
645}
646
647int
2da2a8af 648ndis_add_sysctl(void *arg, char *key, char *desc, char *val, int flag)
60d6dac1
MD
649{
650 struct ndis_softc *sc;
651 struct ndis_cfglist *cfg;
652 char descstr[256];
653
654 sc = arg;
655
efda3bd0 656 cfg = kmalloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_WAITOK|M_ZERO);
59302080 657 cfg->ndis_cfg.nc_cfgkey = kstrdup(key, M_DEVBUF);
60d6dac1
MD
658 if (desc == NULL) {
659 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
59302080 660 cfg->ndis_cfg.nc_cfgdesc = kstrdup(descstr, M_DEVBUF);
60d6dac1 661 } else
59302080 662 cfg->ndis_cfg.nc_cfgdesc = kstrdup(desc, M_DEVBUF);
60d6dac1
MD
663 strcpy(cfg->ndis_cfg.nc_val, val);
664
665 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
666
667#if 1
668 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
669 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
670 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
671 cfg->ndis_cfg.nc_cfgdesc);
672#else
673 SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev),
674 SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)),
675 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
676 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
677 cfg->ndis_cfg.nc_cfgdesc);
678#endif
679
680 return(0);
681}
682
683int
2da2a8af 684ndis_flush_sysctls(void *arg)
60d6dac1
MD
685{
686 struct ndis_softc *sc;
687 struct ndis_cfglist *cfg;
688
689 sc = arg;
690
691 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
692 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
693 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
efda3bd0
MD
694 kfree(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
695 kfree(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
696 kfree(cfg, M_DEVBUF);
60d6dac1
MD
697 }
698
699 return(0);
700}
701
702static void
2da2a8af 703ndis_return(void *arg)
60d6dac1
MD
704{
705 struct ndis_softc *sc;
385c8bc5 706 ndis_return_handler returnfunc;
60d6dac1
MD
707 ndis_handle adapter;
708 ndis_packet *p;
709 uint8_t irql;
710
711 p = arg;
712 sc = p->np_softc;
713 adapter = sc->ndis_block.nmb_miniportadapterctx;
714
715 if (adapter == NULL)
716 return;
717
718 returnfunc = sc->ndis_chars.nmc_return_packet_func;
719 irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
720 returnfunc(adapter, p);
721 FASTCALL1(hal_lower_irql, irql);
722
723 return;
724}
725
726static void
727ndis_extref_packet(void *arg)
728{
729 ndis_packet *p = arg;
730
731 ++p->np_refcnt;
732}
733
734static void
735ndis_extfree_packet(void *arg)
736{
737 ndis_packet *p = arg;
738
739 if (p == NULL)
740 return;
741
742 /* Decrement refcount. */
743 p->np_refcnt--;
744
745 /* Release packet when refcount hits zero, otherwise return. */
746 if (p->np_refcnt)
747 return;
748
749 ndis_sched(ndis_return, p, NDIS_SWI);
750
751 return;
752}
753
754void
755ndis_return_packet(struct ndis_softc *sc, ndis_packet *p)
756{
757 ndis_extfree_packet(p);
758}
759
760void
2da2a8af 761ndis_free_bufs(ndis_buffer *b0)
60d6dac1
MD
762{
763 ndis_buffer *next;
764
765 if (b0 == NULL)
766 return;
767
768 while(b0 != NULL) {
769 next = b0->nb_next;
efda3bd0 770 kfree(b0, M_NDIS_BUFFER);
60d6dac1
MD
771 b0 = next;
772 }
773
774 return;
775}
776
777void
2da2a8af 778ndis_free_packet(ndis_packet *p)
60d6dac1
MD
779{
780 if (p == NULL)
781 return;
782
783 ndis_free_bufs(p->np_private.npp_head);
efda3bd0 784 kfree(p, M_NDIS_PACKET);
60d6dac1
MD
785
786 return;
787}
788
789int
2da2a8af 790ndis_convert_res(void *arg)
60d6dac1
MD
791{
792 struct ndis_softc *sc;
793 ndis_resource_list *rl = NULL;
794 cm_partial_resource_desc *prd = NULL;
795 ndis_miniport_block *block;
796 device_t dev;
797 struct resource_list *brl;
798 struct resource_list brl_rev;
799 struct resource_list_entry *brle, *n;
800 int error = 0;
801
802 sc = arg;
803 block = &sc->ndis_block;
804 dev = sc->ndis_dev;
805
806 SLIST_INIT(&brl_rev);
807
77652cad 808 rl = kmalloc(sizeof(ndis_resource_list) +
60d6dac1 809 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
6147a8af 810 M_DEVBUF, M_WAITOK|M_NULLOK|M_ZERO);
60d6dac1
MD
811
812 if (rl == NULL)
813 return(ENOMEM);
814
815 rl->cprl_version = 5;
816 rl->cprl_version = 1;
817 rl->cprl_count = sc->ndis_rescnt;
818 prd = rl->cprl_partial_descs;
819
820 brl = BUS_GET_RESOURCE_LIST(dev, dev);
821
822 if (brl != NULL) {
823
824 /*
825 * We have a small problem. Some PCI devices have
826 * multiple I/O ranges. Windows orders them starting
827 * from lowest numbered BAR to highest. We discover
828 * them in that order too, but insert them into a singly
829 * linked list head first, which means when time comes
830 * to traverse the list, we enumerate them in reverse
831 * order. This screws up some drivers which expect the
832 * BARs to be in ascending order so that they can choose
833 * the "first" one as their register space. Unfortunately,
834 * in order to fix this, we have to create our own
835 * temporary list with the entries in reverse order.
836 */
837 SLIST_FOREACH(brle, brl, link) {
77652cad 838 n = kmalloc(sizeof(struct resource_list_entry),
6147a8af 839 M_TEMP, M_WAITOK|M_NULLOK);
60d6dac1
MD
840 if (n == NULL) {
841 error = ENOMEM;
842 goto bad;
843 }
844 bcopy((char *)brle, (char *)n,
845 sizeof(struct resource_list_entry));
846 SLIST_INSERT_HEAD(&brl_rev, n, link);
847 }
848
849 SLIST_FOREACH(brle, &brl_rev, link) {
850 switch (brle->type) {
851 case SYS_RES_IOPORT:
852 prd->cprd_type = CmResourceTypePort;
853 prd->cprd_flags = CM_RESOURCE_PORT_IO;
854 prd->cprd_sharedisp =
855 CmResourceShareDeviceExclusive;
856 prd->u.cprd_port.cprd_start.np_quad =
857 brle->start;
858 prd->u.cprd_port.cprd_len = brle->count;
859 break;
860 case SYS_RES_MEMORY:
861 prd->cprd_type = CmResourceTypeMemory;
862 prd->cprd_flags =
863 CM_RESOURCE_MEMORY_READ_WRITE;
864 prd->cprd_sharedisp =
865 CmResourceShareDeviceExclusive;
866 prd->u.cprd_port.cprd_start.np_quad =
867 brle->start;
868 prd->u.cprd_port.cprd_len = brle->count;
869 break;
870 case SYS_RES_IRQ:
871 prd->cprd_type = CmResourceTypeInterrupt;
872 prd->cprd_flags = 0;
873 prd->cprd_sharedisp =
874 CmResourceShareDeviceExclusive;
875 prd->u.cprd_intr.cprd_level = brle->start;
876 prd->u.cprd_intr.cprd_vector = brle->start;
877 prd->u.cprd_intr.cprd_affinity = 0;
878 break;
879 default:
880 break;
881 }
882 prd++;
883 }
884 }
885
886 block->nmb_rlist = rl;
887
888bad:
889
890 while (!SLIST_EMPTY(&brl_rev)) {
891 n = SLIST_FIRST(&brl_rev);
892 SLIST_REMOVE_HEAD(&brl_rev, link);
efda3bd0 893 kfree (n, M_TEMP);
60d6dac1
MD
894 }
895
896 return(error);
897}
898
899/*
900 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
901 * packet, it will hand it to us in the form of an ndis_packet,
902 * which we need to convert to an mbuf that is then handed off
903 * to the stack. Note: we configure the mbuf list so that it uses
904 * the memory regions specified by the ndis_buffer structures in
905 * the ndis_packet as external storage. In most cases, this will
906 * point to a memory region allocated by the driver (either by
907 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
908 * the driver to handle free()ing this region for is, so we set up
909 * a dummy no-op free handler for it.
910 */
911
912int
2da2a8af 913ndis_ptom(struct mbuf **m0, ndis_packet *p)
60d6dac1
MD
914{
915 struct mbuf *m, *prev = NULL;
916 ndis_buffer *buf;
917 ndis_packet_private *priv;
918 uint32_t totlen = 0;
919
920 if (p == NULL || m0 == NULL)
921 return(EINVAL);
922
923 priv = &p->np_private;
924 buf = priv->npp_head;
925 p->np_refcnt = 0;
926
927 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
928 if (buf == priv->npp_head)
929 MGETHDR(m, MB_DONTWAIT, MT_HEADER);
930 else
931 MGET(m, MB_DONTWAIT, MT_DATA);
932 if (m == NULL) {
933 m_freem(*m0);
934 *m0 = NULL;
935 return(ENOBUFS);
936 }
937 m->m_len = buf->nb_bytecount;
938 m->m_data = MDL_VA(buf);
b542cd49
JS
939 m->m_ext.ext_free = ndis_extfree_packet;
940 m->m_ext.ext_ref = ndis_extref_packet;
60d6dac1
MD
941 m->m_ext.ext_arg = p;
942 m->m_ext.ext_buf = m->m_data;
943 m->m_ext.ext_size = m->m_len;
944 m->m_flags |= M_EXT;
945#if 0
946 MEXTADD(m, m->m_data, m->m_len, ndis_free_packet,
947 p, 0, EXT_NDIS);
948#endif
949 p->np_refcnt++;
950 totlen += m->m_len;
6c46447a 951 if (m->m_flags & M_PKTHDR)
60d6dac1
MD
952 *m0 = m;
953 else
954 prev->m_next = m;
955 prev = m;
956 }
957
958 (*m0)->m_pkthdr.len = totlen;
959
960 return(0);
961}
962
963/*
964 * Create an mbuf chain from an NDIS packet chain.
965 * This is used mainly when transmitting packets, where we need
966 * to turn an mbuf off an interface's send queue and transform it
967 * into an NDIS packet which will be fed into the NDIS driver's
968 * send routine.
969 *
970 * NDIS packets consist of two parts: an ndis_packet structure,
971 * which is vaguely analagous to the pkthdr portion of an mbuf,
972 * and one or more ndis_buffer structures, which define the
973 * actual memory segments in which the packet data resides.
974 * We need to allocate one ndis_buffer for each mbuf in a chain,
975 * plus one ndis_packet as the header.
976 */
977
978int
2da2a8af 979ndis_mtop(struct mbuf *m0, ndis_packet **p)
60d6dac1
MD
980{
981 struct mbuf *m;
982 ndis_buffer *buf = NULL, *prev = NULL;
983 ndis_packet_private *priv;
984
985 if (p == NULL || m0 == NULL)
986 return(EINVAL);
987
988 /* If caller didn't supply a packet, make one. */
989 if (*p == NULL) {
efda3bd0 990 *p = kmalloc(sizeof(ndis_packet), M_NDIS_PACKET, M_NOWAIT|M_ZERO);
60d6dac1
MD
991 if (*p == NULL)
992 return(ENOMEM);
993 }
994
995 priv = &(*p)->np_private;
996 priv->npp_totlen = m0->m_pkthdr.len;
997 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
998 priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
999
1000 for (m = m0; m != NULL; m = m->m_next) {
1001 if (m->m_len == 0)
1002 continue;
efda3bd0 1003 buf = kmalloc(sizeof(ndis_buffer), M_NDIS_BUFFER, M_NOWAIT|M_ZERO);
60d6dac1
MD
1004 if (buf == NULL) {
1005 ndis_free_packet(*p);
1006 *p = NULL;
1007 return(ENOMEM);
1008 }
1009
1010 MDL_INIT(buf, m->m_data, m->m_len);
1011 if (priv->npp_head == NULL)
1012 priv->npp_head = buf;
1013 else
1014 prev->nb_next = buf;
1015 prev = buf;
1016 }
1017
1018 priv->npp_tail = buf;
1019 priv->npp_totlen = m0->m_pkthdr.len;
1020
1021 return(0);
1022}
1023
1024int
2da2a8af 1025ndis_get_supported_oids(void *arg, ndis_oid **oids, int *oidcnt)
60d6dac1
MD
1026{
1027 int len, rval;
1028 ndis_oid *o;
1029
1030 if (arg == NULL || oids == NULL || oidcnt == NULL)
1031 return(EINVAL);
1032 len = 0;
1033 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
1034
efda3bd0 1035 o = kmalloc(len, M_DEVBUF, M_WAITOK);
60d6dac1
MD
1036
1037 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
1038
1039 if (rval) {
efda3bd0 1040 kfree(o, M_DEVBUF);
60d6dac1
MD
1041 return(rval);
1042 }
1043
1044 *oids = o;
1045 *oidcnt = len / 4;
1046
1047 return(0);
1048}
1049
1050int
2da2a8af 1051ndis_set_info(void *arg, ndis_oid oid, void *buf, int *buflen)
60d6dac1
MD
1052{
1053 struct ndis_softc *sc;
1054 ndis_status rval;
1055 ndis_handle adapter;
385c8bc5 1056 ndis_setinfo_handler setfunc;
60d6dac1
MD
1057 uint32_t byteswritten = 0, bytesneeded = 0;
1058 int error;
1059 uint8_t irql;
60d6dac1
MD
1060
1061 sc = arg;
60d6dac1
MD
1062 setfunc = sc->ndis_chars.nmc_setinfo_func;
1063 adapter = sc->ndis_block.nmb_miniportadapterctx;
60d6dac1
MD
1064
1065 if (adapter == NULL || setfunc == NULL)
1066 return(ENXIO);
1067
1068 irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
1069 rval = setfunc(adapter, oid, buf, *buflen,
1070 &byteswritten, &bytesneeded);
1071 FASTCALL1(hal_lower_irql, irql);
1072
1073 if (rval == NDIS_STATUS_PENDING) {
1074 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
1075 0, "ndisset", 5 * hz);
1076 rval = sc->ndis_block.nmb_setstat;
1077 }
1078
1079 if (byteswritten)
1080 *buflen = byteswritten;
1081 if (bytesneeded)
1082 *buflen = bytesneeded;
1083
1084 if (rval == NDIS_STATUS_INVALID_LENGTH)
1085 return(ENOSPC);
1086
1087 if (rval == NDIS_STATUS_INVALID_OID)
1088 return(EINVAL);
1089
1090 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1091 rval == NDIS_STATUS_NOT_ACCEPTED)
1092 return(ENOTSUP);
1093
1094 if (rval != NDIS_STATUS_SUCCESS)
1095 return(ENODEV);
1096
1097 return(0);
1098}
1099
385c8bc5 1100typedef __stdcall void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status);
60d6dac1
MD
1101
1102int
2da2a8af 1103ndis_send_packets(void *arg, ndis_packet **packets, int cnt)
60d6dac1
MD
1104{
1105 struct ndis_softc *sc;
1106 ndis_handle adapter;
385c8bc5
MD
1107 ndis_sendmulti_handler sendfunc;
1108 ndis_senddone_func senddonefunc;
60d6dac1
MD
1109 int i;
1110 ndis_packet *p;
1111 uint8_t irql;
1112
1113 sc = arg;
1114 adapter = sc->ndis_block.nmb_miniportadapterctx;
1115 if (adapter == NULL)
1116 return(ENXIO);
1117 sendfunc = sc->ndis_chars.nmc_sendmulti_func;
1118 senddonefunc = sc->ndis_block.nmb_senddone_func;
1119 irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
1120 sendfunc(adapter, packets, cnt);
1121 FASTCALL1(hal_lower_irql, irql);
1122
1123 for (i = 0; i < cnt; i++) {
1124 p = packets[i];
1125 /*
1126 * Either the driver already handed the packet to
1127 * ndis_txeof() due to a failure, or it wants to keep
1128 * it and release it asynchronously later. Skip to the
1129 * next one.
1130 */
1131 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
1132 continue;
1133 senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status);
1134 }
1135
1136 return(0);
1137}
1138
1139int
2da2a8af 1140ndis_send_packet(void *arg, ndis_packet *packet)
60d6dac1
MD
1141{
1142 struct ndis_softc *sc;
1143 ndis_handle adapter;
1144 ndis_status status;
385c8bc5
MD
1145 ndis_sendsingle_handler sendfunc;
1146 ndis_senddone_func senddonefunc;
60d6dac1
MD
1147 uint8_t irql;
1148
1149 sc = arg;
1150 adapter = sc->ndis_block.nmb_miniportadapterctx;
1151 if (adapter == NULL)
1152 return(ENXIO);
1153 sendfunc = sc->ndis_chars.nmc_sendsingle_func;
1154 senddonefunc = sc->ndis_block.nmb_senddone_func;
1155
1156 irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
1157 status = sendfunc(adapter, packet, packet->np_private.npp_flags);
1158 FASTCALL1(hal_lower_irql, irql);
1159
1160 if (status == NDIS_STATUS_PENDING)
1161 return(0);
1162
1163 senddonefunc(&sc->ndis_block, packet, status);
1164
1165 return(0);
1166}
1167
1168int
2da2a8af 1169ndis_init_dma(void *arg)
60d6dac1
MD
1170{
1171 struct ndis_softc *sc;
1172 int i, error;
1173
1174 sc = arg;
1175
77652cad 1176 sc->ndis_tmaps = kmalloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
6147a8af 1177 M_DEVBUF, M_WAITOK|M_ZERO);
60d6dac1 1178
60d6dac1
MD
1179 for (i = 0; i < sc->ndis_maxpkts; i++) {
1180 error = bus_dmamap_create(sc->ndis_ttag, 0,
1181 &sc->ndis_tmaps[i]);
1182 if (error) {
efda3bd0 1183 kfree(sc->ndis_tmaps, M_DEVBUF);
60d6dac1
MD
1184 return(ENODEV);
1185 }
1186 }
1187
1188 return(0);
1189}
1190
1191int
2da2a8af 1192ndis_destroy_dma(void *arg)
60d6dac1
MD
1193{
1194 struct ndis_softc *sc;
1195 struct mbuf *m;
1196 ndis_packet *p = NULL;
1197 int i;
1198
1199 sc = arg;
1200
1201 for (i = 0; i < sc->ndis_maxpkts; i++) {
1202 if (sc->ndis_txarray[i] != NULL) {
1203 p = sc->ndis_txarray[i];
1204 m = (struct mbuf *)p->np_rsvd[1];
1205 if (m != NULL)
1206 m_freem(m);
1207 ndis_free_packet(sc->ndis_txarray[i]);
1208 }
1209 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
1210 }
6147a8af 1211 if (sc->ndis_tmaps)
efda3bd0 1212 kfree(sc->ndis_tmaps, M_DEVBUF);
60d6dac1
MD
1213 bus_dma_tag_destroy(sc->ndis_ttag);
1214
1215 return(0);
1216}
1217
1218int
2da2a8af 1219ndis_reset_nic(void *arg)
60d6dac1
MD
1220{
1221 struct ndis_softc *sc;
1222 ndis_handle adapter;
385c8bc5 1223 ndis_reset_handler resetfunc;
60d6dac1 1224 uint8_t addressing_reset;
60d6dac1
MD
1225 int rval;
1226 uint8_t irql;
60d6dac1
MD
1227
1228 sc = arg;
60d6dac1
MD
1229 adapter = sc->ndis_block.nmb_miniportadapterctx;
1230 resetfunc = sc->ndis_chars.nmc_reset_func;
60d6dac1
MD
1231 if (adapter == NULL || resetfunc == NULL)
1232 return(EIO);
1233
1234 irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
1235 rval = resetfunc(&addressing_reset, adapter);
1236 FASTCALL1(hal_lower_irql, irql);
1237
1238 if (rval == NDIS_STATUS_PENDING) {
1239 tsleep(sc, 0, "ndisrst", 0);
1240 }
1241
1242 return(0);
1243}
1244
1245int
2da2a8af 1246ndis_halt_nic(void *arg)
60d6dac1
MD
1247{
1248 struct ndis_softc *sc;
1249 ndis_handle adapter;
385c8bc5 1250 ndis_halt_handler haltfunc;
60d6dac1
MD
1251
1252 sc = arg;
60d6dac1 1253
60d6dac1
MD
1254 adapter = sc->ndis_block.nmb_miniportadapterctx;
1255 if (adapter == NULL) {
60d6dac1
MD
1256 return(EIO);
1257 }
1258
1259 /*
1260 * The adapter context is only valid after the init
1261 * handler has been called, and is invalid once the
1262 * halt handler has been called.
1263 */
1264
1265 haltfunc = sc->ndis_chars.nmc_halt_func;
60d6dac1
MD
1266
1267 haltfunc(adapter);
1268
60d6dac1 1269 sc->ndis_block.nmb_miniportadapterctx = NULL;
60d6dac1
MD
1270
1271 return(0);
1272}
1273
1274int
2da2a8af 1275ndis_shutdown_nic(void *arg)
60d6dac1
MD
1276{
1277 struct ndis_softc *sc;
1278 ndis_handle adapter;
385c8bc5 1279 ndis_shutdown_handler shutdownfunc;
60d6dac1
MD
1280
1281 sc = arg;
60d6dac1
MD
1282 adapter = sc->ndis_block.nmb_miniportadapterctx;
1283 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
60d6dac1
MD
1284 if (adapter == NULL || shutdownfunc == NULL)
1285 return(EIO);
1286
1287 if (sc->ndis_chars.nmc_rsvd0 == NULL)
1288 shutdownfunc(adapter);
1289 else
1290 shutdownfunc(sc->ndis_chars.nmc_rsvd0);
1291
1292 ndis_shrink_thrqueue(8);
1293 TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link);
1294
1295 return(0);
1296}
1297
1298int
2da2a8af 1299ndis_init_nic(void *arg)
60d6dac1
MD
1300{
1301 struct ndis_softc *sc;
1302 ndis_miniport_block *block;
385c8bc5 1303 ndis_init_handler initfunc;
60d6dac1
MD
1304 ndis_status status, openstatus = 0;
1305 ndis_medium mediumarray[NdisMediumMax];
1306 uint32_t chosenmedium, i;
60d6dac1
MD
1307
1308 if (arg == NULL)
1309 return(EINVAL);
1310
1311 sc = arg;
60d6dac1
MD
1312 block = &sc->ndis_block;
1313 initfunc = sc->ndis_chars.nmc_init_func;
60d6dac1
MD
1314
1315 TAILQ_INIT(&block->nmb_timerlist);
1316
1317 for (i = 0; i < NdisMediumMax; i++)
1318 mediumarray[i] = i;
1319
1320 status = initfunc(&openstatus, &chosenmedium,
1321 mediumarray, NdisMediumMax, block, block);
1322
1323 /*
1324 * If the init fails, blow away the other exported routines
1325 * we obtained from the driver so we can't call them later.
1326 * If the init failed, none of these will work.
1327 */
1328 if (status != NDIS_STATUS_SUCCESS) {
60d6dac1 1329 sc->ndis_block.nmb_miniportadapterctx = NULL;
60d6dac1
MD
1330 return(ENXIO);
1331 }
1332
1333 return(0);
1334}
1335
1336void
2da2a8af 1337ndis_enable_intr(void *arg)
60d6dac1
MD
1338{
1339 struct ndis_softc *sc;
1340 ndis_handle adapter;
385c8bc5 1341 ndis_enable_interrupts_handler intrenbfunc;
60d6dac1
MD
1342
1343 sc = arg;
1344 adapter = sc->ndis_block.nmb_miniportadapterctx;
1345 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
1346 if (adapter == NULL || intrenbfunc == NULL)
1347 return;
1348 intrenbfunc(adapter);
1349
1350 return;
1351}
1352
1353void
2da2a8af 1354ndis_disable_intr(void *arg)
60d6dac1
MD
1355{
1356 struct ndis_softc *sc;
1357 ndis_handle adapter;
385c8bc5 1358 ndis_disable_interrupts_handler intrdisfunc;
60d6dac1
MD
1359
1360 sc = arg;
60d6dac1
MD
1361 adapter = sc->ndis_block.nmb_miniportadapterctx;
1362 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
60d6dac1
MD
1363 if (adapter == NULL || intrdisfunc == NULL)
1364 return;
1365 intrdisfunc(adapter);
1366
1367 return;
1368}
1369
1370int
2da2a8af 1371ndis_isr(void *arg, int *ourintr, int *callhandler)
60d6dac1
MD
1372{
1373 struct ndis_softc *sc;
1374 ndis_handle adapter;
385c8bc5 1375 ndis_isr_handler isrfunc;
60d6dac1
MD
1376 uint8_t accepted, queue;
1377
1378 if (arg == NULL || ourintr == NULL || callhandler == NULL)
1379 return(EINVAL);
1380
1381 sc = arg;
1382 adapter = sc->ndis_block.nmb_miniportadapterctx;
1383 isrfunc = sc->ndis_chars.nmc_isr_func;
1384 if (adapter == NULL || isrfunc == NULL)
1385 return(ENXIO);
1386
1387 isrfunc(&accepted, &queue, adapter);
1388 *ourintr = accepted;
1389 *callhandler = queue;
1390
1391 return(0);
1392}
1393
1394int
2da2a8af 1395ndis_intrhand(void *arg)
60d6dac1
MD
1396{
1397 struct ndis_softc *sc;
1398 ndis_handle adapter;
385c8bc5 1399 ndis_interrupt_handler intrfunc;
60d6dac1
MD
1400
1401 if (arg == NULL)
1402 return(EINVAL);
1403
1404 sc = arg;
60d6dac1
MD
1405 adapter = sc->ndis_block.nmb_miniportadapterctx;
1406 intrfunc = sc->ndis_chars.nmc_interrupt_func;
60d6dac1
MD
1407 if (adapter == NULL || intrfunc == NULL)
1408 return(EINVAL);
1409
1410 intrfunc(adapter);
1411
1412 return(0);
1413}
1414
1415int
2da2a8af 1416ndis_get_info(void *arg, ndis_oid oid, void *buf, int *buflen)
60d6dac1
MD
1417{
1418 struct ndis_softc *sc;
1419 ndis_status rval;
1420 ndis_handle adapter;
1421 ndis_queryinfo_handler queryfunc;
1422 uint32_t byteswritten = 0, bytesneeded = 0;
1423 int error;
1424 uint8_t irql;
60d6dac1
MD
1425
1426 sc = arg;
60d6dac1
MD
1427 queryfunc = sc->ndis_chars.nmc_queryinfo_func;
1428 adapter = sc->ndis_block.nmb_miniportadapterctx;
60d6dac1
MD
1429
1430 if (adapter == NULL || queryfunc == NULL)
1431 return(ENXIO);
1432
1433 irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL);
1434 rval = queryfunc(adapter, oid, buf, *buflen,
1435 &byteswritten, &bytesneeded);
1436 FASTCALL1(hal_lower_irql, irql);
1437
1438 /* Wait for requests that block. */
1439
1440 if (rval == NDIS_STATUS_PENDING) {
1441 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
1442 0, "ndisget", 5 * hz);
1443 rval = sc->ndis_block.nmb_getstat;
1444 }
1445
1446 if (byteswritten)
1447 *buflen = byteswritten;
1448 if (bytesneeded)
1449 *buflen = bytesneeded;
1450
1451 if (rval == NDIS_STATUS_INVALID_LENGTH ||
1452 rval == NDIS_STATUS_BUFFER_TOO_SHORT)
1453 return(ENOSPC);
1454
1455 if (rval == NDIS_STATUS_INVALID_OID)
1456 return(EINVAL);
1457
1458 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1459 rval == NDIS_STATUS_NOT_ACCEPTED)
1460 return(ENOTSUP);
1461
1462 if (rval != NDIS_STATUS_SUCCESS)
1463 return(ENODEV);
1464
1465 return(0);
1466}
1467
1468int
2da2a8af 1469ndis_unload_driver(void *arg)
60d6dac1
MD
1470{
1471 struct ndis_softc *sc;
1472
1473 sc = arg;
1474
efda3bd0 1475 kfree(sc->ndis_block.nmb_rlist, M_DEVBUF);
60d6dac1
MD
1476
1477 ndis_flush_sysctls(sc);
1478
1479 ndis_shrink_thrqueue(8);
1480 TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link);
1481
1482 return(0);
1483}
1484
1485#define NDIS_LOADED htonl(0x42534F44)
1486
1487int
2da2a8af 1488ndis_load_driver(vm_offset_t img, void *arg)
60d6dac1 1489{
385c8bc5 1490 driver_entry entry;
60d6dac1
MD
1491 image_optional_header opt_hdr;
1492 image_import_descriptor imp_desc;
1493 ndis_unicode_string dummystr;
1494 ndis_miniport_block *block;
1495 ndis_status status;
1496 int idx;
1497 uint32_t *ptr;
1498 struct ndis_softc *sc;
1499
1500 sc = arg;
1501
1502 /*
1503 * Only perform the relocation/linking phase once
1504 * since the binary image may be shared among multiple
1505 * device instances.
1506 */
1507
1508 ptr = (uint32_t *)(img + 8);
1509 if (*ptr != NDIS_LOADED) {
1510 /* Perform text relocation */
1511 if (pe_relocate(img))
1512 return(ENOEXEC);
1513
1514 /* Dynamically link the NDIS.SYS routines -- required. */
1515 if (pe_patch_imports(img, "NDIS", ndis_functbl))
1516 return(ENOEXEC);
1517
1518 /* Dynamically link the HAL.dll routines -- also required. */
1519 if (pe_patch_imports(img, "HAL", hal_functbl))
1520 return(ENOEXEC);
1521
1522 /* Dynamically link ntoskrnl.exe -- optional. */
1523 if (pe_get_import_descriptor(img,
1524 &imp_desc, "ntoskrnl") == 0) {
1525 if (pe_patch_imports(img,
1526 "ntoskrnl", ntoskrnl_functbl))
1527 return(ENOEXEC);
1528 }
1529 *ptr = NDIS_LOADED;
1530 }
1531
1532 /* Locate the driver entry point */
1533 pe_get_optional_header(img, &opt_hdr);
1534 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
1535
1536 dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2;
1537 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2;
1538 dummystr.nus_buf = NULL;
1539 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
1540
1541 /*
1542 * Now that we have the miniport driver characteristics,
1543 * create an NDIS block and call the init handler.
1544 * This will cause the driver to try to probe for
1545 * a device.
1546 */
1547
1548 block = &sc->ndis_block;
1549
1550 ptr = (uint32_t *)block;
1551 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
1552 *ptr = idx | 0xdead0000;
1553 ptr++;
1554 }
1555
1556 block->nmb_signature = (void *)0xcafebabe;
1557 block->nmb_setdone_func = ndis_setdone_func;
1558 block->nmb_querydone_func = ndis_getdone_func;
1559 block->nmb_status_func = ndis_status_func;
1560 block->nmb_statusdone_func = ndis_statusdone_func;
1561 block->nmb_resetdone_func = ndis_resetdone_func;
1562 block->nmb_sendrsrc_func = ndis_sendrsrcavail_func;
1563
1564 block->nmb_ifp = &sc->arpcom.ac_if;
1565 block->nmb_dev = sc->ndis_dev;
1566 block->nmb_img = img;
1567 block->nmb_devobj.do_rsvd = block;
1568
1569 /*
1570 * Now call the DriverEntry() routine. This will cause
1571 * a callout to the NdisInitializeWrapper() and
1572 * NdisMRegisterMiniport() routines.
1573 */
1574 status = entry(&block->nmb_devobj, &dummystr);
1575
efda3bd0 1576 kfree (dummystr.nus_buf, M_DEVBUF);
60d6dac1
MD
1577
1578 if (status != NDIS_STATUS_SUCCESS)
1579 return(ENODEV);
1580
1581 ndis_enlarge_thrqueue(8);
1582
1583 TAILQ_INSERT_TAIL(&ndis_devhead, block, link);
1584
1585 return(0);
1586}
1587