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