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