Deleted Added
full compact
kern_ndis.c (124135) kern_ndis.c (124165)
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>
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__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 124135 2004-01-04 21:22:25Z wpaul $");
34__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 124165 2004-01-06 07:09:26Z wpaul $");
35
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/errno.h>
39#include <sys/callout.h>
40#include <sys/socket.h>
41#include <sys/queue.h>
42#include <sys/sysctl.h>
43#include <sys/systm.h>
44#include <sys/malloc.h>
45#include <sys/lock.h>
46#include <sys/mutex.h>
47#include <sys/conf.h>
48#include <sys/taskqueue.h>
49
50#include <sys/kernel.h>
51#include <machine/bus.h>
52#include <machine/resource.h>
53#include <sys/bus.h>
54#include <sys/rman.h>
55
56#include <vm/uma.h>
57
58#include <net/if.h>
59#include <net/if_arp.h>
60#include <net/ethernet.h>
61#include <net/if_dl.h>
62#include <net/if_media.h>
63
64#include <net80211/ieee80211_var.h>
65#include <net80211/ieee80211_ioctl.h>
66
67#include <dev/pccard/pccardvar.h>
68#include "card_if.h"
69
70#include <compat/ndis/pe_var.h>
71#include <compat/ndis/resource_var.h>
72#include <compat/ndis/ndis_var.h>
73#include <compat/ndis/hal_var.h>
74#include <compat/ndis/ntoskrnl_var.h>
75#include <compat/ndis/cfg_var.h>
76#include <dev/if_ndis/if_ndisvar.h>
77
78#define __stdcall __attribute__((__stdcall__))
79#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
80
81__stdcall static void ndis_status_func(ndis_handle, ndis_status,
82 void *, uint32_t);
83__stdcall static void ndis_statusdone_func(ndis_handle);
84__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
85__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
86__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
87__stdcall static void ndis_sendrsrcavail_func(ndis_handle);
88
89static uma_zone_t ndis_packet_zone, ndis_buffer_zone;
90
91/*
92 * This allows us to export our symbols to other modules.
93 * Note that we call ourselves 'ndisapi' to avoid a namespace
94 * collision with if_ndis.ko, which internally calls itself
95 * 'ndis.'
96 */
97static int
98ndis_modevent(module_t mod, int cmd, void *arg)
99{
100 int error = 0;
101
102 switch (cmd) {
103 case MOD_LOAD:
104 /* Initialize subsystems */
105 ndis_libinit();
106 ntoskrnl_libinit();
107
108 /* Initialize TX buffer UMA zone. */
109 ndis_packet_zone = uma_zcreate("NDIS packet",
110 sizeof(ndis_packet), NULL, NULL, NULL,
111 NULL, UMA_ALIGN_PTR, 0);
112 ndis_buffer_zone = uma_zcreate("NDIS buffer",
113 sizeof(ndis_buffer), NULL, NULL, NULL,
114 NULL, UMA_ALIGN_PTR, 0);
115 break;
116 case MOD_UNLOAD:
117 case MOD_SHUTDOWN:
118 /* Shut down subsystems */
119 ndis_libfini();
120 ntoskrnl_libfini();
121
122 /* Remove zones */
123 uma_zdestroy(ndis_packet_zone);
124 uma_zdestroy(ndis_buffer_zone);
125 break;
126 default:
127 error = EINVAL;
128 break;
129 }
130
131 return(error);
132}
133DEV_MODULE(ndisapi, ndis_modevent, NULL);
134MODULE_VERSION(ndisapi, 1);
135
136
137__stdcall static void
138ndis_sendrsrcavail_func(adapter)
139 ndis_handle adapter;
140{
141 return;
142}
143
144__stdcall static void
145ndis_status_func(adapter, status, sbuf, slen)
146 ndis_handle adapter;
147 ndis_status status;
148 void *sbuf;
149 uint32_t slen;
150{
151 ndis_miniport_block *block;
152 block = adapter;
153
154 device_printf (block->nmb_dev, "status: %x\n", status);
155 return;
156}
157
158__stdcall static void
159ndis_statusdone_func(adapter)
160 ndis_handle adapter;
161{
162 ndis_miniport_block *block;
163 block = adapter;
164
165 device_printf (block->nmb_dev, "status complete\n");
166 return;
167}
168
169__stdcall static void
170ndis_setdone_func(adapter, status)
171 ndis_handle adapter;
172 ndis_status status;
173{
174 ndis_miniport_block *block;
175 block = adapter;
176
177 block->nmb_setstat = status;
178 wakeup(&block->nmb_wkupdpctimer);
179 return;
180}
181
182__stdcall static void
183ndis_getdone_func(adapter, status)
184 ndis_handle adapter;
185 ndis_status status;
186{
187 ndis_miniport_block *block;
188 block = adapter;
189
190 block->nmb_getstat = status;
191 wakeup(&block->nmb_wkupdpctimer);
192 return;
193}
194
195__stdcall static void
196ndis_resetdone_func(adapter, status, addressingreset)
197 ndis_handle adapter;
198 ndis_status status;
199 uint8_t addressingreset;
200{
201 ndis_miniport_block *block;
202 block = adapter;
203
204 device_printf (block->nmb_dev, "reset done...\n");
205 return;
206}
207
208#define NDIS_AM_RID 3
209
210int
211ndis_alloc_amem(arg)
212 void *arg;
213{
214 struct ndis_softc *sc;
215 int error, rid;
216
217 if (arg == NULL)
218 return(EINVAL);
219
220 sc = arg;
221 rid = NDIS_AM_RID;
222 sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
223 &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
224
225 if (sc->ndis_res_am == NULL) {
226 device_printf(sc->ndis_dev,
227 "failed to allocate attribute memory\n");
228 return(ENXIO);
229 }
230
231 error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
232 sc->ndis_dev, rid, 0, NULL);
233
234 if (error) {
235 device_printf(sc->ndis_dev,
236 "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error);
237 return(error);
238 }
239
240 error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
241 sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
242
243 if (error) {
244 device_printf(sc->ndis_dev,
245 "CARD_SET_RES_FLAGS() returned 0x%x\n", error);
246 return(error);
247 }
248
249 return(0);
250}
251
252int
253ndis_create_sysctls(arg)
254 void *arg;
255{
256 struct ndis_softc *sc;
257 ndis_cfg *vals;
258 char buf[256];
259
260 if (arg == NULL)
261 return(EINVAL);
262
263 sc = arg;
264 vals = sc->ndis_regvals;
265
266 TAILQ_INIT(&sc->ndis_cfglist_head);
267
268 /* Create the sysctl tree. */
269
270 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
271 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
272 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
273 device_get_desc(sc->ndis_dev));
274
275 /* Add the driver-specific registry keys. */
276
277 vals = sc->ndis_regvals;
278 while(1) {
279 if (vals->nc_cfgkey == NULL)
280 break;
281 if (vals->nc_idx != sc->ndis_devidx) {
282 vals++;
283 continue;
284 }
285 SYSCTL_ADD_STRING(&sc->ndis_ctx,
286 SYSCTL_CHILDREN(sc->ndis_tree),
287 OID_AUTO, vals->nc_cfgkey,
288 CTLFLAG_RW, vals->nc_val,
289 sizeof(vals->nc_val),
290 vals->nc_cfgdesc);
291 vals++;
292 }
293
294 /* Now add a couple of builtin keys. */
295
296 /*
297 * Environment can be either Windows (0) or WindowsNT (1).
298 * We qualify as the latter.
299 */
300 ndis_add_sysctl(sc, "Environment",
301 "Windows environment", "1", CTLFLAG_RD);
302
303 /* NDIS version should be 5.1. */
304 ndis_add_sysctl(sc, "NdisVersion",
305 "NDIS API Version", "0x00050001", CTLFLAG_RD);
306
307 /* Bus type (PCI, PCMCIA, etc...) */
308 sprintf(buf, "%d\n", (int)sc->ndis_iftype);
309 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
310
311 if (sc->ndis_res_io != NULL) {
312 sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io));
313 ndis_add_sysctl(sc, "IOBaseAddress",
314 "Base I/O Address", buf, CTLFLAG_RD);
315 }
316
317 if (sc->ndis_irq != NULL) {
318 sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq));
319 ndis_add_sysctl(sc, "InterruptNumber",
320 "Interrupt Number", buf, CTLFLAG_RD);
321 }
322
323 return(0);
324}
325
326int
327ndis_add_sysctl(arg, key, desc, val, flag)
328 void *arg;
329 char *key;
330 char *desc;
331 char *val;
332 int flag;
333{
334 struct ndis_softc *sc;
335 struct ndis_cfglist *cfg;
336 char descstr[256];
337
338 sc = arg;
339
340 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
341
342 if (cfg == NULL)
343 return(ENOMEM);
344
345 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
346 if (desc == NULL) {
347 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
348 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
349 } else
350 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
351 strcpy(cfg->ndis_cfg.nc_val, val);
352
353 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
354
355 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
356 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
357 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
358 cfg->ndis_cfg.nc_cfgdesc);
359
360 return(0);
361}
362
363int
364ndis_flush_sysctls(arg)
365 void *arg;
366{
367 struct ndis_softc *sc;
368 struct ndis_cfglist *cfg;
369
370 sc = arg;
371
372 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
373 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
374 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
375 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
376 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
377 free(cfg, M_DEVBUF);
378 }
379
380 return(0);
381}
382
383void
384ndis_return_packet(buf, arg)
385 void *buf; /* not used */
386 void *arg;
387{
388 struct ndis_softc *sc;
389 ndis_handle adapter;
390 ndis_packet *p;
391 __stdcall ndis_return_handler returnfunc;
392
393 if (arg == NULL)
394 return;
395
396 p = arg;
397
398 /* Decrement refcount. */
399 p->np_refcnt--;
400
401 /* Release packet when refcount hits zero, otherwise return. */
402 if (p->np_refcnt)
403 return;
404
405 sc = p->np_softc;
406 returnfunc = sc->ndis_chars.nmc_return_packet_func;
407 adapter = sc->ndis_block.nmb_miniportadapterctx;
408 if (returnfunc != NULL)
409 returnfunc(adapter, p);
410
411 return;
412}
413
414void
415ndis_free_bufs(b0)
416 ndis_buffer *b0;
417{
418 ndis_buffer *next;
419
420 if (b0 == NULL)
421 return;
422
423 while(b0 != NULL) {
424 next = b0->nb_next;
425 uma_zfree (ndis_buffer_zone, b0);
426 b0 = next;
427 }
428
429 return;
430}
431
432void
433ndis_free_packet(p)
434 ndis_packet *p;
435{
436 if (p == NULL)
437 return;
438
439 ndis_free_bufs(p->np_private.npp_head);
440 uma_zfree(ndis_packet_zone, p);
441
442 return;
443}
444
445int
446ndis_convert_res(arg)
447 void *arg;
448{
449 struct ndis_softc *sc;
450 ndis_resource_list *rl = NULL;
451 cm_partial_resource_desc *prd = NULL;
452 ndis_miniport_block *block;
453 device_t dev;
454 struct resource_list *brl;
455 struct resource_list_entry *brle;
456
457 sc = arg;
458 block = &sc->ndis_block;
459 dev = sc->ndis_dev;
460
461 rl = malloc(sizeof(ndis_resource_list) +
462 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
463 M_DEVBUF, M_NOWAIT|M_ZERO);
464
465 if (rl == NULL)
466 return(ENOMEM);
467
468 rl->cprl_version = 5;
469 rl->cprl_version = 1;
470 rl->cprl_count = sc->ndis_rescnt;
471 prd = rl->cprl_partial_descs;
472
473 brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
474 if (brl != NULL) {
475 SLIST_FOREACH(brle, brl, link) {
476 switch (brle->type) {
477 case SYS_RES_IOPORT:
478 prd->cprd_type = CmResourceTypePort;
479 prd->u.cprd_port.cprd_start.np_quad =
480 brle->start;
481 prd->u.cprd_port.cprd_len = brle->count;
482 break;
483 case SYS_RES_MEMORY:
484 prd->cprd_type = CmResourceTypeMemory;
485 prd->u.cprd_port.cprd_start.np_quad =
486 brle->start;
487 prd->u.cprd_port.cprd_len = brle->count;
488 break;
489 case SYS_RES_IRQ:
490 prd->cprd_type = CmResourceTypeInterrupt;
491 prd->u.cprd_intr.cprd_level = brle->start;
492 prd->u.cprd_intr.cprd_vector = brle->start;
493 prd->u.cprd_intr.cprd_affinity = 0;
494 break;
495 default:
496 break;
497 }
498 prd++;
499 }
500 }
501
502 block->nmb_rlist = rl;
503
504 return(0);
505}
506
507/*
508 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
509 * packet, it will hand it to us in the form of an ndis_packet,
510 * which we need to convert to an mbuf that is then handed off
511 * to the stack. Note: we configure the mbuf list so that it uses
512 * the memory regions specified by the ndis_buffer structures in
513 * the ndis_packet as external storage. In most cases, this will
514 * point to a memory region allocated by the driver (either by
515 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
516 * the driver to handle free()ing this region for is, so we set up
517 * a dummy no-op free handler for it.
518 */
519
520int
521ndis_ptom(m0, p)
522 struct mbuf **m0;
523 ndis_packet *p;
524{
525 struct mbuf *m, *prev = NULL;
526 ndis_buffer *buf;
527 ndis_packet_private *priv;
528 uint32_t totlen = 0;
529
530 if (p == NULL || m0 == NULL)
531 return(EINVAL);
532
533 priv = &p->np_private;
534 buf = priv->npp_head;
535 p->np_refcnt = 0;
536
537 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
538 if (buf == priv->npp_head)
539 MGETHDR(m, M_DONTWAIT, MT_HEADER);
540 else
541 MGET(m, M_DONTWAIT, MT_DATA);
542 if (m == NULL) {
543 m_freem(*m0);
544 *m0 = NULL;
545 return(ENOBUFS);
546 }
547 m->m_len = buf->nb_bytecount;
548 m->m_data = MDL_VA(buf);
549 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
550 p, 0, EXT_NDIS);
551 p->np_refcnt++;
552 totlen += m->m_len;
553 if (m->m_flags & MT_HEADER)
554 *m0 = m;
555 else
556 prev->m_next = m;
557 prev = m;
558 }
559
560 (*m0)->m_pkthdr.len = totlen;
561
562 return(0);
563}
564
565/*
566 * Create an mbuf chain from an NDIS packet chain.
567 * This is used mainly when transmitting packets, where we need
568 * to turn an mbuf off an interface's send queue and transform it
569 * into an NDIS packet which will be fed into the NDIS driver's
570 * send routine.
571 *
572 * NDIS packets consist of two parts: an ndis_packet structure,
573 * which is vaguely analagous to the pkthdr portion of an mbuf,
574 * and one or more ndis_buffer structures, which define the
575 * actual memory segments in which the packet data resides.
576 * We need to allocate one ndis_buffer for each mbuf in a chain,
577 * plus one ndis_packet as the header.
578 */
579
580int
581ndis_mtop(m0, p)
582 struct mbuf *m0;
583 ndis_packet **p;
584{
585 struct mbuf *m;
586 ndis_buffer *buf = NULL, *prev = NULL;
587 ndis_packet_private *priv;
588
589 if (p == NULL || m0 == NULL)
590 return(EINVAL);
591
592 /* If caller didn't supply a packet, make one. */
593 if (*p == NULL) {
594 *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO);
595
596 if (*p == NULL)
597 return(ENOMEM);
598 }
599
600 priv = &(*p)->np_private;
601 priv->npp_totlen = m0->m_pkthdr.len;
602 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
603
604 for (m = m0; m != NULL; m = m->m_next) {
605 if (m->m_len == 0)
606 continue;
607 buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO);
608 if (buf == NULL) {
609 ndis_free_packet(*p);
610 *p = NULL;
611 return(ENOMEM);
612 }
613
614 MDL_INIT(buf, m->m_data, m->m_len);
615 if (priv->npp_head == NULL)
616 priv->npp_head = buf;
617 else
618 prev->nb_next = buf;
619 prev = buf;
620 }
621
622 priv->npp_tail = buf;
623 priv->npp_totlen = m0->m_pkthdr.len;
624
625 return(0);
626}
627
628int
629ndis_get_supported_oids(arg, oids, oidcnt)
630 void *arg;
631 ndis_oid **oids;
632 int *oidcnt;
633{
634 int len, rval;
635 ndis_oid *o;
636
637 if (arg == NULL || oids == NULL || oidcnt == NULL)
638 return(EINVAL);
639 len = 0;
640 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
641
642 o = malloc(len, M_DEVBUF, M_NOWAIT);
643 if (o == NULL)
644 return(ENOMEM);
645
646 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
647
648 if (rval) {
649 free(o, M_DEVBUF);
650 return(rval);
651 }
652
653 *oids = o;
654 *oidcnt = len / 4;
655
656 return(0);
657}
658
659int
660ndis_set_info(arg, oid, buf, buflen)
661 void *arg;
662 ndis_oid oid;
663 void *buf;
664 int *buflen;
665{
666 struct ndis_softc *sc;
667 ndis_status rval;
668 ndis_handle adapter;
669 __stdcall ndis_setinfo_handler setfunc;
670 uint32_t byteswritten = 0, bytesneeded = 0;
671 struct timeval tv;
672 int error;
673
674 sc = arg;
675 setfunc = sc->ndis_chars.nmc_setinfo_func;
676 adapter = sc->ndis_block.nmb_miniportadapterctx;
677
678 rval = setfunc(adapter, oid, buf, *buflen,
679 &byteswritten, &bytesneeded);
680
681 if (rval == NDIS_STATUS_PENDING) {
682 tv.tv_sec = 60;
683 tv.tv_usec = 0;
684 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
685 PPAUSE|PCATCH, "ndisset", tvtohz(&tv));
686 rval = sc->ndis_block.nmb_setstat;
687 }
688
689 if (byteswritten)
690 *buflen = byteswritten;
691 if (bytesneeded)
692 *buflen = bytesneeded;
693
694 if (rval == NDIS_STATUS_INVALID_LENGTH)
695 return(ENOSPC);
696
697 if (rval == NDIS_STATUS_INVALID_OID)
698 return(EINVAL);
699
700 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
701 rval == NDIS_STATUS_NOT_ACCEPTED)
702 return(ENOTSUP);
703
704 return(0);
705}
706
707int
708ndis_send_packets(arg, packets, cnt)
709 void *arg;
710 ndis_packet **packets;
711 int cnt;
712{
713 struct ndis_softc *sc;
714 ndis_handle adapter;
715 __stdcall ndis_sendmulti_handler sendfunc;
716 int i, idx;
717 struct ifnet *ifp;
718 struct mbuf *m;
719 ndis_packet *p;
720
721 sc = arg;
722 adapter = sc->ndis_block.nmb_miniportadapterctx;
723 sendfunc = sc->ndis_chars.nmc_sendmulti_func;
724 sendfunc(adapter, packets, cnt);
725
726 for (i = 0; i < cnt; i++) {
727 p = packets[i];
728 /*
729 * Either the driver already handed the packet to
730 * ndis_txeof() due to a failure, or it wants to keep
731 * it and release it asynchronously later. Skip to the
732 * next one.
733 */
734 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
735 continue;
736 idx = p->np_txidx;
737 m = p->np_m0;
738 ifp = &sc->arpcom.ac_if;
739 if (sc->ndis_sc)
740 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
741 sc->ndis_txarray[idx] = NULL;
742 sc->ndis_txpending++;
743 m_freem(m);
744 ndis_free_packet(p);
745 if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
746 ifp->if_opackets++;
747 else
748 ifp->if_oerrors++;
749 ifp->if_timer = 0;
750 ifp->if_flags &= ~IFF_OACTIVE;
751 }
752
753 return(0);
754}
755
756int
757ndis_init_dma(arg)
758 void *arg;
759{
760 struct ndis_softc *sc;
761 int i, error;
762
763 sc = arg;
764
765 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
766 M_DEVBUF, M_NOWAIT|M_ZERO);
767
768 if (sc->ndis_tmaps == NULL)
769 return(ENOMEM);
770
771 for (i = 0; i < sc->ndis_maxpkts; i++) {
772 error = bus_dmamap_create(sc->ndis_ttag, 0,
773 &sc->ndis_tmaps[i]);
774 if (error) {
775 free(sc->ndis_tmaps, M_DEVBUF);
776 return(ENODEV);
777 }
778 }
779
780 return(0);
781}
782
783int
784ndis_destroy_dma(arg)
785 void *arg;
786{
787 struct ndis_softc *sc;
788 struct mbuf *m;
789 ndis_packet *p = NULL;
790 int i;
791
792 sc = arg;
793
794 for (i = 0; i < sc->ndis_maxpkts; i++) {
795 if (sc->ndis_txarray[i] != NULL) {
796 p = sc->ndis_txarray[i];
797 m = (struct mbuf *)p->np_rsvd[1];
798 if (m != NULL)
799 m_freem(m);
800 ndis_free_packet(sc->ndis_txarray[i]);
801 }
802 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
803 }
804
805 free(sc->ndis_tmaps, M_DEVBUF);
806
807 bus_dma_tag_destroy(sc->ndis_ttag);
808
809 return(0);
810}
811
812int
813ndis_reset_nic(arg)
814 void *arg;
815{
816 struct ndis_softc *sc;
817 ndis_handle adapter;
818 __stdcall ndis_reset_handler resetfunc;
819 uint8_t addressing_reset;
820 struct ifnet *ifp;
821
822 sc = arg;
823 ifp = &sc->arpcom.ac_if;
824 adapter = sc->ndis_block.nmb_miniportadapterctx;
825 if (adapter == NULL)
826 return(EIO);
827 resetfunc = sc->ndis_chars.nmc_reset_func;
828
829 if (resetfunc == NULL)
830 return(EINVAL);
831
832 resetfunc(&addressing_reset, adapter);
833
834 return(0);
835}
836
837int
838ndis_halt_nic(arg)
839 void *arg;
840{
841 struct ndis_softc *sc;
842 ndis_handle adapter;
843 __stdcall ndis_halt_handler haltfunc;
844 struct ifnet *ifp;
845 struct ndis_timer_entry *ne;
846
847 sc = arg;
848 ifp = &sc->arpcom.ac_if;
849 adapter = sc->ndis_block.nmb_miniportadapterctx;
850 if (adapter == NULL)
851 return(EIO);
852
853 haltfunc = sc->ndis_chars.nmc_halt_func;
854
855 if (haltfunc == NULL)
856 return(EINVAL);
857
858 haltfunc(adapter);
859
860 /*
861 * The adapter context is only valid after the init
862 * handler has been called, and is invalid once the
863 * halt handler has been called.
864 */
865
866 sc->ndis_block.nmb_miniportadapterctx = NULL;
867
868 /* Clobber all the timers in case the driver left one running. */
869
870 while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) {
871 ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist);
872 TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link);
873 callout_stop(&ne->nte_ch);
874 free(ne, M_DEVBUF);
875 }
876
877 return(0);
878}
879
880int
881ndis_shutdown_nic(arg)
882 void *arg;
883{
884 struct ndis_softc *sc;
885 ndis_handle adapter;
886 __stdcall ndis_shutdown_handler shutdownfunc;
887
888
889 sc = arg;
890 adapter = sc->ndis_block.nmb_miniportadapterctx;
891 if (adapter == NULL)
892 return(EIO);
893 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
894
895 if (shutdownfunc == NULL)
896 return(EINVAL);
897
898 if (sc->ndis_chars.nmc_rsvd0 == NULL)
899 shutdownfunc(adapter);
900 else
901 shutdownfunc(sc->ndis_chars.nmc_rsvd0);
902
903 return(0);
904}
905
906int
907ndis_init_nic(arg)
908 void *arg;
909{
910 struct ndis_softc *sc;
911 ndis_miniport_block *block;
912 __stdcall ndis_init_handler initfunc;
913 ndis_status status, openstatus = 0;
914 ndis_medium mediumarray[NdisMediumMax];
915 uint32_t chosenmedium, i;
916
917 if (arg == NULL)
918 return(EINVAL);
919
920 sc = arg;
921 block = &sc->ndis_block;
922 initfunc = sc->ndis_chars.nmc_init_func;
923
924 TAILQ_INIT(&block->nmb_timerlist);
925
926 for (i = 0; i < NdisMediumMax; i++)
927 mediumarray[i] = i;
928
929 status = initfunc(&openstatus, &chosenmedium,
930 mediumarray, NdisMediumMax, block, block);
931
932 /*
933 * If the init fails, blow away the other exported routines
934 * we obtained from the driver so we can't call them later.
935 * If the init failed, none of these will work.
936 */
937 if (status != NDIS_STATUS_SUCCESS) {
938 bzero((char *)&sc->ndis_chars,
939 sizeof(ndis_miniport_characteristics));
940 return(ENXIO);
941 }
942
943 return(0);
944}
945
946void
947ndis_enable_intr(arg)
948 void *arg;
949{
950 struct ndis_softc *sc;
951 ndis_handle adapter;
952 __stdcall ndis_enable_interrupts_handler intrenbfunc;
953
954 sc = arg;
955 adapter = sc->ndis_block.nmb_miniportadapterctx;
956 if (adapter == NULL)
957 return;
958 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
959 if (intrenbfunc == NULL)
960 return;
961 intrenbfunc(adapter);
962
963 return;
964}
965
966void
967ndis_disable_intr(arg)
968 void *arg;
969{
970 struct ndis_softc *sc;
971 ndis_handle adapter;
972 __stdcall ndis_disable_interrupts_handler intrdisfunc;
973
974 sc = arg;
975 adapter = sc->ndis_block.nmb_miniportadapterctx;
976 if (adapter == NULL)
977 return;
978 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
979 if (intrdisfunc == NULL)
980 return;
981 intrdisfunc(adapter);
982
983 return;
984}
985
986int
987ndis_isr(arg, ourintr, callhandler)
988 void *arg;
989 int *ourintr;
990 int *callhandler;
991{
992 struct ndis_softc *sc;
993 ndis_handle adapter;
994 __stdcall ndis_isr_handler isrfunc;
995 uint8_t accepted, queue;
996
997 if (arg == NULL || ourintr == NULL || callhandler == NULL)
998 return(EINVAL);
999
1000 sc = arg;
1001 adapter = sc->ndis_block.nmb_miniportadapterctx;
1002 isrfunc = sc->ndis_chars.nmc_isr_func;
1003 isrfunc(&accepted, &queue, adapter);
1004 *ourintr = accepted;
1005 *callhandler = queue;
1006
1007 return(0);
1008}
1009
1010int
1011ndis_intrhand(arg)
1012 void *arg;
1013{
1014 struct ndis_softc *sc;
1015 ndis_handle adapter;
1016 __stdcall ndis_interrupt_handler intrfunc;
1017
1018 if (arg == NULL)
1019 return(EINVAL);
1020
1021 sc = arg;
1022 adapter = sc->ndis_block.nmb_miniportadapterctx;
1023 intrfunc = sc->ndis_chars.nmc_interrupt_func;
1024 intrfunc(adapter);
1025
1026 return(0);
1027}
1028
1029int
1030ndis_get_info(arg, oid, buf, buflen)
1031 void *arg;
1032 ndis_oid oid;
1033 void *buf;
1034 int *buflen;
1035{
1036 struct ndis_softc *sc;
1037 ndis_status rval;
1038 ndis_handle adapter;
1039 __stdcall ndis_queryinfo_handler queryfunc;
1040 uint32_t byteswritten = 0, bytesneeded = 0;
1041 struct timeval tv;
1042 int error;
1043
1044 sc = arg;
1045 queryfunc = sc->ndis_chars.nmc_queryinfo_func;
1046 adapter = sc->ndis_block.nmb_miniportadapterctx;
1047
1048 rval = queryfunc(adapter, oid, buf, *buflen,
1049 &byteswritten, &bytesneeded);
1050
1051 /* Wait for requests that block. */
1052
1053 if (rval == NDIS_STATUS_PENDING) {
1054 tv.tv_sec = 60;
1055 tv.tv_usec = 0;
1056 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
1057 PPAUSE|PCATCH, "ndisget", tvtohz(&tv));
1058 rval = sc->ndis_block.nmb_getstat;
1059 }
1060
1061 if (byteswritten)
1062 *buflen = byteswritten;
1063 if (bytesneeded)
1064 *buflen = bytesneeded;
1065
1066 if (rval == NDIS_STATUS_INVALID_LENGTH ||
1067 rval == NDIS_STATUS_BUFFER_TOO_SHORT)
1068 return(ENOSPC);
1069
1070 if (rval == NDIS_STATUS_INVALID_OID)
1071 return(EINVAL);
1072
1073 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1074 rval == NDIS_STATUS_NOT_ACCEPTED)
1075 return(ENOTSUP);
1076
1077 return(0);
1078}
1079
1080int
1081ndis_unload_driver(arg)
1082 void *arg;
1083{
1084 struct ndis_softc *sc;
1085
1086 sc = arg;
1087
1088 free(sc->ndis_block.nmb_rlist, M_DEVBUF);
1089
1090 ndis_flush_sysctls(sc);
1091
1092 return(0);
1093}
1094
1095int
1096ndis_load_driver(img, arg)
1097 vm_offset_t img;
1098 void *arg;
1099{
1100 __stdcall driver_entry entry;
1101 image_optional_header opt_hdr;
1102 image_import_descriptor imp_desc;
1103 ndis_unicode_string dummystr;
1104 ndis_driver_object drv;
1105 ndis_miniport_block *block;
1106 ndis_status status;
1107 int idx;
1108 uint32_t *ptr;
1109 struct ndis_softc *sc;
1110
1111 sc = arg;
1112
1113 /* Perform text relocation */
1114 if (pe_relocate(img))
1115 return(ENOEXEC);
1116
1117 /* Dynamically link the NDIS.SYS routines -- required. */
1118 if (pe_patch_imports(img, "NDIS", ndis_functbl))
1119 return(ENOEXEC);
1120
1121 /* Dynamically link the HAL.dll routines -- also required. */
1122 if (pe_patch_imports(img, "HAL", hal_functbl))
1123 return(ENOEXEC);
1124
1125 /* Dynamically link ntoskrnl.exe -- optional. */
1126 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
1127 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
1128 return(ENOEXEC);
1129 }
1130
1131 /* Locate the driver entry point */
1132 pe_get_optional_header(img, &opt_hdr);
1133 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
1134
1135 /*
1136 * Now call the DriverEntry() routine. This will cause
1137 * a callout to the NdisInitializeWrapper() and
1138 * NdisMRegisterMiniport() routines.
1139 */
1140 dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
1141 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
1142 dummystr.nus_buf = NULL;
1143 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
1144 drv.ndo_ifname = "ndis0";
1145
1146 status = entry(&drv, &dummystr);
1147
1148 free (dummystr.nus_buf, M_DEVBUF);
1149
1150 if (status != NDIS_STATUS_SUCCESS)
1151 return(ENODEV);
1152
1153 /*
1154 * Now that we have the miniport driver characteristics,
1155 * create an NDIS block and call the init handler.
1156 * This will cause the driver to try to probe for
1157 * a device.
1158 */
1159
1160 block = &sc->ndis_block;
1161 bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
1162 sizeof(ndis_miniport_characteristics));
1163
1164 /*block->nmb_signature = 0xcafebabe;*/
1165
1166 ptr = (uint32_t *)block;
1167 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
1168 *ptr = idx | 0xdead0000;
1169 ptr++;
1170 }
1171
1172 block->nmb_signature = (void *)0xcafebabe;
1173 block->nmb_setdone_func = ndis_setdone_func;
1174 block->nmb_querydone_func = ndis_getdone_func;
1175 block->nmb_status_func = ndis_status_func;
1176 block->nmb_statusdone_func = ndis_statusdone_func;
1177 block->nmb_resetdone_func = ndis_resetdone_func;
1178 block->nmb_sendrsrc_func = ndis_sendrsrcavail_func;
1179
1180 block->nmb_ifp = &sc->arpcom.ac_if;
1181 block->nmb_dev = sc->ndis_dev;
35
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/errno.h>
39#include <sys/callout.h>
40#include <sys/socket.h>
41#include <sys/queue.h>
42#include <sys/sysctl.h>
43#include <sys/systm.h>
44#include <sys/malloc.h>
45#include <sys/lock.h>
46#include <sys/mutex.h>
47#include <sys/conf.h>
48#include <sys/taskqueue.h>
49
50#include <sys/kernel.h>
51#include <machine/bus.h>
52#include <machine/resource.h>
53#include <sys/bus.h>
54#include <sys/rman.h>
55
56#include <vm/uma.h>
57
58#include <net/if.h>
59#include <net/if_arp.h>
60#include <net/ethernet.h>
61#include <net/if_dl.h>
62#include <net/if_media.h>
63
64#include <net80211/ieee80211_var.h>
65#include <net80211/ieee80211_ioctl.h>
66
67#include <dev/pccard/pccardvar.h>
68#include "card_if.h"
69
70#include <compat/ndis/pe_var.h>
71#include <compat/ndis/resource_var.h>
72#include <compat/ndis/ndis_var.h>
73#include <compat/ndis/hal_var.h>
74#include <compat/ndis/ntoskrnl_var.h>
75#include <compat/ndis/cfg_var.h>
76#include <dev/if_ndis/if_ndisvar.h>
77
78#define __stdcall __attribute__((__stdcall__))
79#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
80
81__stdcall static void ndis_status_func(ndis_handle, ndis_status,
82 void *, uint32_t);
83__stdcall static void ndis_statusdone_func(ndis_handle);
84__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
85__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
86__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
87__stdcall static void ndis_sendrsrcavail_func(ndis_handle);
88
89static uma_zone_t ndis_packet_zone, ndis_buffer_zone;
90
91/*
92 * This allows us to export our symbols to other modules.
93 * Note that we call ourselves 'ndisapi' to avoid a namespace
94 * collision with if_ndis.ko, which internally calls itself
95 * 'ndis.'
96 */
97static int
98ndis_modevent(module_t mod, int cmd, void *arg)
99{
100 int error = 0;
101
102 switch (cmd) {
103 case MOD_LOAD:
104 /* Initialize subsystems */
105 ndis_libinit();
106 ntoskrnl_libinit();
107
108 /* Initialize TX buffer UMA zone. */
109 ndis_packet_zone = uma_zcreate("NDIS packet",
110 sizeof(ndis_packet), NULL, NULL, NULL,
111 NULL, UMA_ALIGN_PTR, 0);
112 ndis_buffer_zone = uma_zcreate("NDIS buffer",
113 sizeof(ndis_buffer), NULL, NULL, NULL,
114 NULL, UMA_ALIGN_PTR, 0);
115 break;
116 case MOD_UNLOAD:
117 case MOD_SHUTDOWN:
118 /* Shut down subsystems */
119 ndis_libfini();
120 ntoskrnl_libfini();
121
122 /* Remove zones */
123 uma_zdestroy(ndis_packet_zone);
124 uma_zdestroy(ndis_buffer_zone);
125 break;
126 default:
127 error = EINVAL;
128 break;
129 }
130
131 return(error);
132}
133DEV_MODULE(ndisapi, ndis_modevent, NULL);
134MODULE_VERSION(ndisapi, 1);
135
136
137__stdcall static void
138ndis_sendrsrcavail_func(adapter)
139 ndis_handle adapter;
140{
141 return;
142}
143
144__stdcall static void
145ndis_status_func(adapter, status, sbuf, slen)
146 ndis_handle adapter;
147 ndis_status status;
148 void *sbuf;
149 uint32_t slen;
150{
151 ndis_miniport_block *block;
152 block = adapter;
153
154 device_printf (block->nmb_dev, "status: %x\n", status);
155 return;
156}
157
158__stdcall static void
159ndis_statusdone_func(adapter)
160 ndis_handle adapter;
161{
162 ndis_miniport_block *block;
163 block = adapter;
164
165 device_printf (block->nmb_dev, "status complete\n");
166 return;
167}
168
169__stdcall static void
170ndis_setdone_func(adapter, status)
171 ndis_handle adapter;
172 ndis_status status;
173{
174 ndis_miniport_block *block;
175 block = adapter;
176
177 block->nmb_setstat = status;
178 wakeup(&block->nmb_wkupdpctimer);
179 return;
180}
181
182__stdcall static void
183ndis_getdone_func(adapter, status)
184 ndis_handle adapter;
185 ndis_status status;
186{
187 ndis_miniport_block *block;
188 block = adapter;
189
190 block->nmb_getstat = status;
191 wakeup(&block->nmb_wkupdpctimer);
192 return;
193}
194
195__stdcall static void
196ndis_resetdone_func(adapter, status, addressingreset)
197 ndis_handle adapter;
198 ndis_status status;
199 uint8_t addressingreset;
200{
201 ndis_miniport_block *block;
202 block = adapter;
203
204 device_printf (block->nmb_dev, "reset done...\n");
205 return;
206}
207
208#define NDIS_AM_RID 3
209
210int
211ndis_alloc_amem(arg)
212 void *arg;
213{
214 struct ndis_softc *sc;
215 int error, rid;
216
217 if (arg == NULL)
218 return(EINVAL);
219
220 sc = arg;
221 rid = NDIS_AM_RID;
222 sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
223 &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
224
225 if (sc->ndis_res_am == NULL) {
226 device_printf(sc->ndis_dev,
227 "failed to allocate attribute memory\n");
228 return(ENXIO);
229 }
230
231 error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
232 sc->ndis_dev, rid, 0, NULL);
233
234 if (error) {
235 device_printf(sc->ndis_dev,
236 "CARD_SET_MEMORY_OFFSET() returned 0x%x\n", error);
237 return(error);
238 }
239
240 error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
241 sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
242
243 if (error) {
244 device_printf(sc->ndis_dev,
245 "CARD_SET_RES_FLAGS() returned 0x%x\n", error);
246 return(error);
247 }
248
249 return(0);
250}
251
252int
253ndis_create_sysctls(arg)
254 void *arg;
255{
256 struct ndis_softc *sc;
257 ndis_cfg *vals;
258 char buf[256];
259
260 if (arg == NULL)
261 return(EINVAL);
262
263 sc = arg;
264 vals = sc->ndis_regvals;
265
266 TAILQ_INIT(&sc->ndis_cfglist_head);
267
268 /* Create the sysctl tree. */
269
270 sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
271 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
272 device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
273 device_get_desc(sc->ndis_dev));
274
275 /* Add the driver-specific registry keys. */
276
277 vals = sc->ndis_regvals;
278 while(1) {
279 if (vals->nc_cfgkey == NULL)
280 break;
281 if (vals->nc_idx != sc->ndis_devidx) {
282 vals++;
283 continue;
284 }
285 SYSCTL_ADD_STRING(&sc->ndis_ctx,
286 SYSCTL_CHILDREN(sc->ndis_tree),
287 OID_AUTO, vals->nc_cfgkey,
288 CTLFLAG_RW, vals->nc_val,
289 sizeof(vals->nc_val),
290 vals->nc_cfgdesc);
291 vals++;
292 }
293
294 /* Now add a couple of builtin keys. */
295
296 /*
297 * Environment can be either Windows (0) or WindowsNT (1).
298 * We qualify as the latter.
299 */
300 ndis_add_sysctl(sc, "Environment",
301 "Windows environment", "1", CTLFLAG_RD);
302
303 /* NDIS version should be 5.1. */
304 ndis_add_sysctl(sc, "NdisVersion",
305 "NDIS API Version", "0x00050001", CTLFLAG_RD);
306
307 /* Bus type (PCI, PCMCIA, etc...) */
308 sprintf(buf, "%d\n", (int)sc->ndis_iftype);
309 ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
310
311 if (sc->ndis_res_io != NULL) {
312 sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io));
313 ndis_add_sysctl(sc, "IOBaseAddress",
314 "Base I/O Address", buf, CTLFLAG_RD);
315 }
316
317 if (sc->ndis_irq != NULL) {
318 sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq));
319 ndis_add_sysctl(sc, "InterruptNumber",
320 "Interrupt Number", buf, CTLFLAG_RD);
321 }
322
323 return(0);
324}
325
326int
327ndis_add_sysctl(arg, key, desc, val, flag)
328 void *arg;
329 char *key;
330 char *desc;
331 char *val;
332 int flag;
333{
334 struct ndis_softc *sc;
335 struct ndis_cfglist *cfg;
336 char descstr[256];
337
338 sc = arg;
339
340 cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
341
342 if (cfg == NULL)
343 return(ENOMEM);
344
345 cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
346 if (desc == NULL) {
347 snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
348 cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
349 } else
350 cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
351 strcpy(cfg->ndis_cfg.nc_val, val);
352
353 TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
354
355 SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
356 OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
357 cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
358 cfg->ndis_cfg.nc_cfgdesc);
359
360 return(0);
361}
362
363int
364ndis_flush_sysctls(arg)
365 void *arg;
366{
367 struct ndis_softc *sc;
368 struct ndis_cfglist *cfg;
369
370 sc = arg;
371
372 while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
373 cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
374 TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
375 free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
376 free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
377 free(cfg, M_DEVBUF);
378 }
379
380 return(0);
381}
382
383void
384ndis_return_packet(buf, arg)
385 void *buf; /* not used */
386 void *arg;
387{
388 struct ndis_softc *sc;
389 ndis_handle adapter;
390 ndis_packet *p;
391 __stdcall ndis_return_handler returnfunc;
392
393 if (arg == NULL)
394 return;
395
396 p = arg;
397
398 /* Decrement refcount. */
399 p->np_refcnt--;
400
401 /* Release packet when refcount hits zero, otherwise return. */
402 if (p->np_refcnt)
403 return;
404
405 sc = p->np_softc;
406 returnfunc = sc->ndis_chars.nmc_return_packet_func;
407 adapter = sc->ndis_block.nmb_miniportadapterctx;
408 if (returnfunc != NULL)
409 returnfunc(adapter, p);
410
411 return;
412}
413
414void
415ndis_free_bufs(b0)
416 ndis_buffer *b0;
417{
418 ndis_buffer *next;
419
420 if (b0 == NULL)
421 return;
422
423 while(b0 != NULL) {
424 next = b0->nb_next;
425 uma_zfree (ndis_buffer_zone, b0);
426 b0 = next;
427 }
428
429 return;
430}
431
432void
433ndis_free_packet(p)
434 ndis_packet *p;
435{
436 if (p == NULL)
437 return;
438
439 ndis_free_bufs(p->np_private.npp_head);
440 uma_zfree(ndis_packet_zone, p);
441
442 return;
443}
444
445int
446ndis_convert_res(arg)
447 void *arg;
448{
449 struct ndis_softc *sc;
450 ndis_resource_list *rl = NULL;
451 cm_partial_resource_desc *prd = NULL;
452 ndis_miniport_block *block;
453 device_t dev;
454 struct resource_list *brl;
455 struct resource_list_entry *brle;
456
457 sc = arg;
458 block = &sc->ndis_block;
459 dev = sc->ndis_dev;
460
461 rl = malloc(sizeof(ndis_resource_list) +
462 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
463 M_DEVBUF, M_NOWAIT|M_ZERO);
464
465 if (rl == NULL)
466 return(ENOMEM);
467
468 rl->cprl_version = 5;
469 rl->cprl_version = 1;
470 rl->cprl_count = sc->ndis_rescnt;
471 prd = rl->cprl_partial_descs;
472
473 brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
474 if (brl != NULL) {
475 SLIST_FOREACH(brle, brl, link) {
476 switch (brle->type) {
477 case SYS_RES_IOPORT:
478 prd->cprd_type = CmResourceTypePort;
479 prd->u.cprd_port.cprd_start.np_quad =
480 brle->start;
481 prd->u.cprd_port.cprd_len = brle->count;
482 break;
483 case SYS_RES_MEMORY:
484 prd->cprd_type = CmResourceTypeMemory;
485 prd->u.cprd_port.cprd_start.np_quad =
486 brle->start;
487 prd->u.cprd_port.cprd_len = brle->count;
488 break;
489 case SYS_RES_IRQ:
490 prd->cprd_type = CmResourceTypeInterrupt;
491 prd->u.cprd_intr.cprd_level = brle->start;
492 prd->u.cprd_intr.cprd_vector = brle->start;
493 prd->u.cprd_intr.cprd_affinity = 0;
494 break;
495 default:
496 break;
497 }
498 prd++;
499 }
500 }
501
502 block->nmb_rlist = rl;
503
504 return(0);
505}
506
507/*
508 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
509 * packet, it will hand it to us in the form of an ndis_packet,
510 * which we need to convert to an mbuf that is then handed off
511 * to the stack. Note: we configure the mbuf list so that it uses
512 * the memory regions specified by the ndis_buffer structures in
513 * the ndis_packet as external storage. In most cases, this will
514 * point to a memory region allocated by the driver (either by
515 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
516 * the driver to handle free()ing this region for is, so we set up
517 * a dummy no-op free handler for it.
518 */
519
520int
521ndis_ptom(m0, p)
522 struct mbuf **m0;
523 ndis_packet *p;
524{
525 struct mbuf *m, *prev = NULL;
526 ndis_buffer *buf;
527 ndis_packet_private *priv;
528 uint32_t totlen = 0;
529
530 if (p == NULL || m0 == NULL)
531 return(EINVAL);
532
533 priv = &p->np_private;
534 buf = priv->npp_head;
535 p->np_refcnt = 0;
536
537 for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
538 if (buf == priv->npp_head)
539 MGETHDR(m, M_DONTWAIT, MT_HEADER);
540 else
541 MGET(m, M_DONTWAIT, MT_DATA);
542 if (m == NULL) {
543 m_freem(*m0);
544 *m0 = NULL;
545 return(ENOBUFS);
546 }
547 m->m_len = buf->nb_bytecount;
548 m->m_data = MDL_VA(buf);
549 MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
550 p, 0, EXT_NDIS);
551 p->np_refcnt++;
552 totlen += m->m_len;
553 if (m->m_flags & MT_HEADER)
554 *m0 = m;
555 else
556 prev->m_next = m;
557 prev = m;
558 }
559
560 (*m0)->m_pkthdr.len = totlen;
561
562 return(0);
563}
564
565/*
566 * Create an mbuf chain from an NDIS packet chain.
567 * This is used mainly when transmitting packets, where we need
568 * to turn an mbuf off an interface's send queue and transform it
569 * into an NDIS packet which will be fed into the NDIS driver's
570 * send routine.
571 *
572 * NDIS packets consist of two parts: an ndis_packet structure,
573 * which is vaguely analagous to the pkthdr portion of an mbuf,
574 * and one or more ndis_buffer structures, which define the
575 * actual memory segments in which the packet data resides.
576 * We need to allocate one ndis_buffer for each mbuf in a chain,
577 * plus one ndis_packet as the header.
578 */
579
580int
581ndis_mtop(m0, p)
582 struct mbuf *m0;
583 ndis_packet **p;
584{
585 struct mbuf *m;
586 ndis_buffer *buf = NULL, *prev = NULL;
587 ndis_packet_private *priv;
588
589 if (p == NULL || m0 == NULL)
590 return(EINVAL);
591
592 /* If caller didn't supply a packet, make one. */
593 if (*p == NULL) {
594 *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO);
595
596 if (*p == NULL)
597 return(ENOMEM);
598 }
599
600 priv = &(*p)->np_private;
601 priv->npp_totlen = m0->m_pkthdr.len;
602 priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
603
604 for (m = m0; m != NULL; m = m->m_next) {
605 if (m->m_len == 0)
606 continue;
607 buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO);
608 if (buf == NULL) {
609 ndis_free_packet(*p);
610 *p = NULL;
611 return(ENOMEM);
612 }
613
614 MDL_INIT(buf, m->m_data, m->m_len);
615 if (priv->npp_head == NULL)
616 priv->npp_head = buf;
617 else
618 prev->nb_next = buf;
619 prev = buf;
620 }
621
622 priv->npp_tail = buf;
623 priv->npp_totlen = m0->m_pkthdr.len;
624
625 return(0);
626}
627
628int
629ndis_get_supported_oids(arg, oids, oidcnt)
630 void *arg;
631 ndis_oid **oids;
632 int *oidcnt;
633{
634 int len, rval;
635 ndis_oid *o;
636
637 if (arg == NULL || oids == NULL || oidcnt == NULL)
638 return(EINVAL);
639 len = 0;
640 ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
641
642 o = malloc(len, M_DEVBUF, M_NOWAIT);
643 if (o == NULL)
644 return(ENOMEM);
645
646 rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
647
648 if (rval) {
649 free(o, M_DEVBUF);
650 return(rval);
651 }
652
653 *oids = o;
654 *oidcnt = len / 4;
655
656 return(0);
657}
658
659int
660ndis_set_info(arg, oid, buf, buflen)
661 void *arg;
662 ndis_oid oid;
663 void *buf;
664 int *buflen;
665{
666 struct ndis_softc *sc;
667 ndis_status rval;
668 ndis_handle adapter;
669 __stdcall ndis_setinfo_handler setfunc;
670 uint32_t byteswritten = 0, bytesneeded = 0;
671 struct timeval tv;
672 int error;
673
674 sc = arg;
675 setfunc = sc->ndis_chars.nmc_setinfo_func;
676 adapter = sc->ndis_block.nmb_miniportadapterctx;
677
678 rval = setfunc(adapter, oid, buf, *buflen,
679 &byteswritten, &bytesneeded);
680
681 if (rval == NDIS_STATUS_PENDING) {
682 tv.tv_sec = 60;
683 tv.tv_usec = 0;
684 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
685 PPAUSE|PCATCH, "ndisset", tvtohz(&tv));
686 rval = sc->ndis_block.nmb_setstat;
687 }
688
689 if (byteswritten)
690 *buflen = byteswritten;
691 if (bytesneeded)
692 *buflen = bytesneeded;
693
694 if (rval == NDIS_STATUS_INVALID_LENGTH)
695 return(ENOSPC);
696
697 if (rval == NDIS_STATUS_INVALID_OID)
698 return(EINVAL);
699
700 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
701 rval == NDIS_STATUS_NOT_ACCEPTED)
702 return(ENOTSUP);
703
704 return(0);
705}
706
707int
708ndis_send_packets(arg, packets, cnt)
709 void *arg;
710 ndis_packet **packets;
711 int cnt;
712{
713 struct ndis_softc *sc;
714 ndis_handle adapter;
715 __stdcall ndis_sendmulti_handler sendfunc;
716 int i, idx;
717 struct ifnet *ifp;
718 struct mbuf *m;
719 ndis_packet *p;
720
721 sc = arg;
722 adapter = sc->ndis_block.nmb_miniportadapterctx;
723 sendfunc = sc->ndis_chars.nmc_sendmulti_func;
724 sendfunc(adapter, packets, cnt);
725
726 for (i = 0; i < cnt; i++) {
727 p = packets[i];
728 /*
729 * Either the driver already handed the packet to
730 * ndis_txeof() due to a failure, or it wants to keep
731 * it and release it asynchronously later. Skip to the
732 * next one.
733 */
734 if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING)
735 continue;
736 idx = p->np_txidx;
737 m = p->np_m0;
738 ifp = &sc->arpcom.ac_if;
739 if (sc->ndis_sc)
740 bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]);
741 sc->ndis_txarray[idx] = NULL;
742 sc->ndis_txpending++;
743 m_freem(m);
744 ndis_free_packet(p);
745 if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS)
746 ifp->if_opackets++;
747 else
748 ifp->if_oerrors++;
749 ifp->if_timer = 0;
750 ifp->if_flags &= ~IFF_OACTIVE;
751 }
752
753 return(0);
754}
755
756int
757ndis_init_dma(arg)
758 void *arg;
759{
760 struct ndis_softc *sc;
761 int i, error;
762
763 sc = arg;
764
765 sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
766 M_DEVBUF, M_NOWAIT|M_ZERO);
767
768 if (sc->ndis_tmaps == NULL)
769 return(ENOMEM);
770
771 for (i = 0; i < sc->ndis_maxpkts; i++) {
772 error = bus_dmamap_create(sc->ndis_ttag, 0,
773 &sc->ndis_tmaps[i]);
774 if (error) {
775 free(sc->ndis_tmaps, M_DEVBUF);
776 return(ENODEV);
777 }
778 }
779
780 return(0);
781}
782
783int
784ndis_destroy_dma(arg)
785 void *arg;
786{
787 struct ndis_softc *sc;
788 struct mbuf *m;
789 ndis_packet *p = NULL;
790 int i;
791
792 sc = arg;
793
794 for (i = 0; i < sc->ndis_maxpkts; i++) {
795 if (sc->ndis_txarray[i] != NULL) {
796 p = sc->ndis_txarray[i];
797 m = (struct mbuf *)p->np_rsvd[1];
798 if (m != NULL)
799 m_freem(m);
800 ndis_free_packet(sc->ndis_txarray[i]);
801 }
802 bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
803 }
804
805 free(sc->ndis_tmaps, M_DEVBUF);
806
807 bus_dma_tag_destroy(sc->ndis_ttag);
808
809 return(0);
810}
811
812int
813ndis_reset_nic(arg)
814 void *arg;
815{
816 struct ndis_softc *sc;
817 ndis_handle adapter;
818 __stdcall ndis_reset_handler resetfunc;
819 uint8_t addressing_reset;
820 struct ifnet *ifp;
821
822 sc = arg;
823 ifp = &sc->arpcom.ac_if;
824 adapter = sc->ndis_block.nmb_miniportadapterctx;
825 if (adapter == NULL)
826 return(EIO);
827 resetfunc = sc->ndis_chars.nmc_reset_func;
828
829 if (resetfunc == NULL)
830 return(EINVAL);
831
832 resetfunc(&addressing_reset, adapter);
833
834 return(0);
835}
836
837int
838ndis_halt_nic(arg)
839 void *arg;
840{
841 struct ndis_softc *sc;
842 ndis_handle adapter;
843 __stdcall ndis_halt_handler haltfunc;
844 struct ifnet *ifp;
845 struct ndis_timer_entry *ne;
846
847 sc = arg;
848 ifp = &sc->arpcom.ac_if;
849 adapter = sc->ndis_block.nmb_miniportadapterctx;
850 if (adapter == NULL)
851 return(EIO);
852
853 haltfunc = sc->ndis_chars.nmc_halt_func;
854
855 if (haltfunc == NULL)
856 return(EINVAL);
857
858 haltfunc(adapter);
859
860 /*
861 * The adapter context is only valid after the init
862 * handler has been called, and is invalid once the
863 * halt handler has been called.
864 */
865
866 sc->ndis_block.nmb_miniportadapterctx = NULL;
867
868 /* Clobber all the timers in case the driver left one running. */
869
870 while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) {
871 ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist);
872 TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link);
873 callout_stop(&ne->nte_ch);
874 free(ne, M_DEVBUF);
875 }
876
877 return(0);
878}
879
880int
881ndis_shutdown_nic(arg)
882 void *arg;
883{
884 struct ndis_softc *sc;
885 ndis_handle adapter;
886 __stdcall ndis_shutdown_handler shutdownfunc;
887
888
889 sc = arg;
890 adapter = sc->ndis_block.nmb_miniportadapterctx;
891 if (adapter == NULL)
892 return(EIO);
893 shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
894
895 if (shutdownfunc == NULL)
896 return(EINVAL);
897
898 if (sc->ndis_chars.nmc_rsvd0 == NULL)
899 shutdownfunc(adapter);
900 else
901 shutdownfunc(sc->ndis_chars.nmc_rsvd0);
902
903 return(0);
904}
905
906int
907ndis_init_nic(arg)
908 void *arg;
909{
910 struct ndis_softc *sc;
911 ndis_miniport_block *block;
912 __stdcall ndis_init_handler initfunc;
913 ndis_status status, openstatus = 0;
914 ndis_medium mediumarray[NdisMediumMax];
915 uint32_t chosenmedium, i;
916
917 if (arg == NULL)
918 return(EINVAL);
919
920 sc = arg;
921 block = &sc->ndis_block;
922 initfunc = sc->ndis_chars.nmc_init_func;
923
924 TAILQ_INIT(&block->nmb_timerlist);
925
926 for (i = 0; i < NdisMediumMax; i++)
927 mediumarray[i] = i;
928
929 status = initfunc(&openstatus, &chosenmedium,
930 mediumarray, NdisMediumMax, block, block);
931
932 /*
933 * If the init fails, blow away the other exported routines
934 * we obtained from the driver so we can't call them later.
935 * If the init failed, none of these will work.
936 */
937 if (status != NDIS_STATUS_SUCCESS) {
938 bzero((char *)&sc->ndis_chars,
939 sizeof(ndis_miniport_characteristics));
940 return(ENXIO);
941 }
942
943 return(0);
944}
945
946void
947ndis_enable_intr(arg)
948 void *arg;
949{
950 struct ndis_softc *sc;
951 ndis_handle adapter;
952 __stdcall ndis_enable_interrupts_handler intrenbfunc;
953
954 sc = arg;
955 adapter = sc->ndis_block.nmb_miniportadapterctx;
956 if (adapter == NULL)
957 return;
958 intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
959 if (intrenbfunc == NULL)
960 return;
961 intrenbfunc(adapter);
962
963 return;
964}
965
966void
967ndis_disable_intr(arg)
968 void *arg;
969{
970 struct ndis_softc *sc;
971 ndis_handle adapter;
972 __stdcall ndis_disable_interrupts_handler intrdisfunc;
973
974 sc = arg;
975 adapter = sc->ndis_block.nmb_miniportadapterctx;
976 if (adapter == NULL)
977 return;
978 intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
979 if (intrdisfunc == NULL)
980 return;
981 intrdisfunc(adapter);
982
983 return;
984}
985
986int
987ndis_isr(arg, ourintr, callhandler)
988 void *arg;
989 int *ourintr;
990 int *callhandler;
991{
992 struct ndis_softc *sc;
993 ndis_handle adapter;
994 __stdcall ndis_isr_handler isrfunc;
995 uint8_t accepted, queue;
996
997 if (arg == NULL || ourintr == NULL || callhandler == NULL)
998 return(EINVAL);
999
1000 sc = arg;
1001 adapter = sc->ndis_block.nmb_miniportadapterctx;
1002 isrfunc = sc->ndis_chars.nmc_isr_func;
1003 isrfunc(&accepted, &queue, adapter);
1004 *ourintr = accepted;
1005 *callhandler = queue;
1006
1007 return(0);
1008}
1009
1010int
1011ndis_intrhand(arg)
1012 void *arg;
1013{
1014 struct ndis_softc *sc;
1015 ndis_handle adapter;
1016 __stdcall ndis_interrupt_handler intrfunc;
1017
1018 if (arg == NULL)
1019 return(EINVAL);
1020
1021 sc = arg;
1022 adapter = sc->ndis_block.nmb_miniportadapterctx;
1023 intrfunc = sc->ndis_chars.nmc_interrupt_func;
1024 intrfunc(adapter);
1025
1026 return(0);
1027}
1028
1029int
1030ndis_get_info(arg, oid, buf, buflen)
1031 void *arg;
1032 ndis_oid oid;
1033 void *buf;
1034 int *buflen;
1035{
1036 struct ndis_softc *sc;
1037 ndis_status rval;
1038 ndis_handle adapter;
1039 __stdcall ndis_queryinfo_handler queryfunc;
1040 uint32_t byteswritten = 0, bytesneeded = 0;
1041 struct timeval tv;
1042 int error;
1043
1044 sc = arg;
1045 queryfunc = sc->ndis_chars.nmc_queryinfo_func;
1046 adapter = sc->ndis_block.nmb_miniportadapterctx;
1047
1048 rval = queryfunc(adapter, oid, buf, *buflen,
1049 &byteswritten, &bytesneeded);
1050
1051 /* Wait for requests that block. */
1052
1053 if (rval == NDIS_STATUS_PENDING) {
1054 tv.tv_sec = 60;
1055 tv.tv_usec = 0;
1056 error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
1057 PPAUSE|PCATCH, "ndisget", tvtohz(&tv));
1058 rval = sc->ndis_block.nmb_getstat;
1059 }
1060
1061 if (byteswritten)
1062 *buflen = byteswritten;
1063 if (bytesneeded)
1064 *buflen = bytesneeded;
1065
1066 if (rval == NDIS_STATUS_INVALID_LENGTH ||
1067 rval == NDIS_STATUS_BUFFER_TOO_SHORT)
1068 return(ENOSPC);
1069
1070 if (rval == NDIS_STATUS_INVALID_OID)
1071 return(EINVAL);
1072
1073 if (rval == NDIS_STATUS_NOT_SUPPORTED ||
1074 rval == NDIS_STATUS_NOT_ACCEPTED)
1075 return(ENOTSUP);
1076
1077 return(0);
1078}
1079
1080int
1081ndis_unload_driver(arg)
1082 void *arg;
1083{
1084 struct ndis_softc *sc;
1085
1086 sc = arg;
1087
1088 free(sc->ndis_block.nmb_rlist, M_DEVBUF);
1089
1090 ndis_flush_sysctls(sc);
1091
1092 return(0);
1093}
1094
1095int
1096ndis_load_driver(img, arg)
1097 vm_offset_t img;
1098 void *arg;
1099{
1100 __stdcall driver_entry entry;
1101 image_optional_header opt_hdr;
1102 image_import_descriptor imp_desc;
1103 ndis_unicode_string dummystr;
1104 ndis_driver_object drv;
1105 ndis_miniport_block *block;
1106 ndis_status status;
1107 int idx;
1108 uint32_t *ptr;
1109 struct ndis_softc *sc;
1110
1111 sc = arg;
1112
1113 /* Perform text relocation */
1114 if (pe_relocate(img))
1115 return(ENOEXEC);
1116
1117 /* Dynamically link the NDIS.SYS routines -- required. */
1118 if (pe_patch_imports(img, "NDIS", ndis_functbl))
1119 return(ENOEXEC);
1120
1121 /* Dynamically link the HAL.dll routines -- also required. */
1122 if (pe_patch_imports(img, "HAL", hal_functbl))
1123 return(ENOEXEC);
1124
1125 /* Dynamically link ntoskrnl.exe -- optional. */
1126 if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
1127 if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
1128 return(ENOEXEC);
1129 }
1130
1131 /* Locate the driver entry point */
1132 pe_get_optional_header(img, &opt_hdr);
1133 entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
1134
1135 /*
1136 * Now call the DriverEntry() routine. This will cause
1137 * a callout to the NdisInitializeWrapper() and
1138 * NdisMRegisterMiniport() routines.
1139 */
1140 dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
1141 dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
1142 dummystr.nus_buf = NULL;
1143 ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
1144 drv.ndo_ifname = "ndis0";
1145
1146 status = entry(&drv, &dummystr);
1147
1148 free (dummystr.nus_buf, M_DEVBUF);
1149
1150 if (status != NDIS_STATUS_SUCCESS)
1151 return(ENODEV);
1152
1153 /*
1154 * Now that we have the miniport driver characteristics,
1155 * create an NDIS block and call the init handler.
1156 * This will cause the driver to try to probe for
1157 * a device.
1158 */
1159
1160 block = &sc->ndis_block;
1161 bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
1162 sizeof(ndis_miniport_characteristics));
1163
1164 /*block->nmb_signature = 0xcafebabe;*/
1165
1166 ptr = (uint32_t *)block;
1167 for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
1168 *ptr = idx | 0xdead0000;
1169 ptr++;
1170 }
1171
1172 block->nmb_signature = (void *)0xcafebabe;
1173 block->nmb_setdone_func = ndis_setdone_func;
1174 block->nmb_querydone_func = ndis_getdone_func;
1175 block->nmb_status_func = ndis_status_func;
1176 block->nmb_statusdone_func = ndis_statusdone_func;
1177 block->nmb_resetdone_func = ndis_resetdone_func;
1178 block->nmb_sendrsrc_func = ndis_sendrsrcavail_func;
1179
1180 block->nmb_ifp = &sc->arpcom.ac_if;
1181 block->nmb_dev = sc->ndis_dev;
1182 block->nmb_img = img;
1182
1183 return(0);
1184}
1183
1184 return(0);
1185}