summaryrefslogtreecommitdiffstats
path: root/sys/compat/ndis/kern_ndis.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/ndis/kern_ndis.c')
-rw-r--r--sys/compat/ndis/kern_ndis.c1049
1 files changed, 1049 insertions, 0 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
new file mode 100644
index 0000000..b36831f
--- /dev/null
+++ b/sys/compat/ndis/kern_ndis.c
@@ -0,0 +1,1049 @@
+/*
+ * Copyright (c) 2003
+ * Bill Paul <wpaul@windriver.com>. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/callout.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/conf.h>
+
+#include <sys/kernel.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <dev/pccard/pccardvar.h>
+#include "card_if.h"
+
+#include <compat/ndis/pe_var.h>
+#include <compat/ndis/resource_var.h>
+#include <compat/ndis/ndis_var.h>
+#include <compat/ndis/hal_var.h>
+#include <compat/ndis/ntoskrnl_var.h>
+#include <compat/ndis/cfg_var.h>
+#include <dev/if_ndis/if_ndisvar.h>
+
+#define __stdcall __attribute__((__stdcall__))
+#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
+
+__stdcall static void ndis_status_func(ndis_handle, ndis_status,
+ void *, uint32_t);
+__stdcall static void ndis_statusdone_func(ndis_handle);
+__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
+__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
+
+/*
+ * This allows us to export our symbols to other modules.
+ * Note that we call ourselves 'ndisapi' to avoid a namespace
+ * collision with if_ndis.ko, which internally calls itself
+ * 'ndis.'
+ */
+static int
+ndis_modevent(module_t mod, int cmd, void *arg)
+{
+ return(0);
+}
+DEV_MODULE(ndisapi, ndis_modevent, NULL);
+MODULE_VERSION(ndisapi, 1);
+
+
+__stdcall static void
+ndis_status_func(adapter, status, sbuf, slen)
+ ndis_handle adapter;
+ ndis_status status;
+ void *sbuf;
+ uint32_t slen;
+{
+ printf ("status: %x\n", status);
+ return;
+}
+
+__stdcall static void
+ndis_statusdone_func(adapter)
+ ndis_handle adapter;
+{
+ printf ("status complete\n");
+ return;
+}
+
+__stdcall static void
+ndis_setdone_func(adapter, status)
+ ndis_handle adapter;
+ ndis_status status;
+{
+ printf ("Setup done... %x\n", status);
+ return;
+}
+
+__stdcall static void
+ndis_resetdone_func(adapter, status, addressingreset)
+ ndis_handle adapter;
+ ndis_status status;
+ uint8_t addressingreset;
+{
+ printf ("reset done...\n");
+ return;
+}
+
+#define NDIS_AM_RID 3
+
+int
+ndis_alloc_amem(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ int error, rid;
+
+ if (arg == NULL)
+ return(EINVAL);
+
+ sc = arg;
+ rid = NDIS_AM_RID;
+ sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
+ &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
+
+ if (sc->ndis_res_am == NULL) {
+ printf("ndis%d: failed to allocate attribute memory\n",
+ sc->ndis_unit);
+ return(ENXIO);
+ }
+
+ error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
+ sc->ndis_dev, rid, 0, NULL);
+
+ if (error) {
+ printf("ndis%d: CARD_SET_MEMORY_OFFSET() returned 0x%x\n",
+ sc->ndis_unit, error);
+ return(error);
+ }
+
+ error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
+ sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
+
+ if (error) {
+ printf("ndis%d: CARD_SET_RES_FLAGS() returned 0x%x\n",
+ sc->ndis_unit, error);
+ return(error);
+ }
+
+ return(0);
+}
+
+int
+ndis_create_sysctls(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_cfg *vals;
+ char buf[256];
+
+ if (arg == NULL)
+ return(EINVAL);
+
+ sc = arg;
+ vals = sc->ndis_regvals;
+
+ TAILQ_INIT(&sc->ndis_cfglist_head);
+
+ /* Create the sysctl tree. */
+
+ sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
+ SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
+ device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
+ device_get_desc(sc->ndis_dev));
+
+ /* Add the driver-specific registry keys. */
+
+ vals = sc->ndis_regvals;
+ while(1) {
+ if (vals->nc_cfgkey == NULL)
+ break;
+ SYSCTL_ADD_STRING(&sc->ndis_ctx,
+ SYSCTL_CHILDREN(sc->ndis_tree),
+ OID_AUTO, vals->nc_cfgkey,
+ CTLFLAG_RW, vals->nc_val,
+ sizeof(vals->nc_val),
+ vals->nc_cfgdesc);
+ vals++;
+ }
+
+ /* Now add a couple of builtin keys. */
+
+ /*
+ * Environment can be either Windows (0) or WindowsNT (1).
+ * We qualify as the latter.
+ */
+ ndis_add_sysctl(sc, "Environment",
+ "Windows environment", "1", CTLFLAG_RD);
+
+ /* NDIS version should be 5.1. */
+ ndis_add_sysctl(sc, "NdisVersion",
+ "NDIS API Version", "0x00050001", CTLFLAG_RD);
+
+ /* Bus type (PCI, PCMCIA, etc...) */
+ sprintf(buf, "%d\n", (int)sc->ndis_iftype);
+ ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
+
+ if (sc->ndis_res_io != NULL) {
+ sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io));
+ ndis_add_sysctl(sc, "IOBaseAddress",
+ "Base I/O Address", buf, CTLFLAG_RD);
+ }
+
+ if (sc->ndis_irq != NULL) {
+ sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq));
+ ndis_add_sysctl(sc, "InterruptNumber",
+ "Interrupt Number", buf, CTLFLAG_RD);
+ }
+
+ return(0);
+}
+
+int
+ndis_add_sysctl(arg, key, desc, val, flag)
+ void *arg;
+ char *key;
+ char *desc;
+ char *val;
+ int flag;
+{
+ struct ndis_softc *sc;
+ struct ndis_cfglist *cfg;
+ char descstr[256];
+
+ sc = arg;
+
+ cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
+
+ if (cfg == NULL)
+ return(ENOMEM);
+
+ cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
+ if (desc == NULL) {
+ snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
+ cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
+ } else
+ cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
+ strcpy(cfg->ndis_cfg.nc_val, val);
+
+ TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
+
+ SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
+ OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
+ cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
+ cfg->ndis_cfg.nc_cfgdesc);
+
+ return(0);
+}
+
+int
+ndis_flush_sysctls(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ struct ndis_cfglist *cfg;
+
+ sc = arg;
+
+ while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
+ cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
+ TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
+ free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
+ free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
+ free(cfg, M_DEVBUF);
+ }
+
+ return(0);
+}
+
+void
+ndis_return_packet(packet, arg)
+ void *packet;
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_return_handler returnfunc;
+
+ if (arg == NULL || packet == NULL)
+ return;
+
+ sc = arg;
+ returnfunc = sc->ndis_chars.nmc_return_packet_func;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ if (returnfunc == NULL)
+ ndis_free_packet((ndis_packet *)packet);
+ else
+ returnfunc(adapter, (ndis_packet *)packet);
+ return;
+}
+
+void
+ndis_free_bufs(b0)
+ ndis_buffer *b0;
+{
+ ndis_buffer *next;
+
+ if (b0 == NULL)
+ return;
+
+ while(b0 != NULL) {
+ next = b0->nb_next;
+ free (b0, M_DEVBUF);
+ b0 = next;
+ }
+
+ return;
+}
+
+void
+ndis_free_packet(p)
+ ndis_packet *p;
+{
+ if (p == NULL)
+ return;
+
+ ndis_free_bufs(p->np_private.npp_head);
+ free(p, M_DEVBUF);
+
+ return;
+}
+
+int
+ndis_convert_res(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_resource_list *rl = NULL;
+ cm_partial_resource_desc *prd = NULL;
+ ndis_miniport_block *block;
+
+ sc = arg;
+ block = &sc->ndis_block;
+
+ rl = malloc(sizeof(ndis_resource_list) +
+ (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
+ M_DEVBUF, M_NOWAIT|M_ZERO);
+
+ if (rl == NULL)
+ return(ENOMEM);
+
+ rl->cprl_version = 5;
+ rl->cprl_version = 1;
+ rl->cprl_count = sc->ndis_rescnt;
+
+ prd = rl->cprl_partial_descs;
+ if (sc->ndis_res_io) {
+ prd->cprd_type = CmResourceTypePort;
+ prd->u.cprd_port.cprd_start.np_quad =
+ rman_get_start(sc->ndis_res_io);
+ prd->u.cprd_port.cprd_len =
+ rman_get_size(sc->ndis_res_io);
+ prd++;
+ }
+
+ if (sc->ndis_res_mem) {
+ prd->cprd_type = CmResourceTypeMemory;
+ prd->u.cprd_mem.cprd_start.np_quad =
+ rman_get_start(sc->ndis_res_mem);
+ prd->u.cprd_mem.cprd_len =
+ rman_get_size(sc->ndis_res_mem);
+ prd++;
+ }
+
+ if (sc->ndis_irq) {
+ prd->cprd_type = CmResourceTypeInterrupt;
+ prd->u.cprd_intr.cprd_level =
+ rman_get_start(sc->ndis_irq);
+ prd->u.cprd_intr.cprd_vector =
+ rman_get_start(sc->ndis_irq);
+ prd->u.cprd_intr.cprd_affinity = 0;
+ }
+
+ block->nmb_rlist = rl;
+
+ return(0);
+}
+
+/*
+ * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
+ * packet, it will hand it to us in the form of an ndis_packet,
+ * which we need to convert to an mbuf that is then handed off
+ * to the stack. Note: we configure the mbuf list so that it uses
+ * the memory regions specified by the ndis_buffer structures in
+ * the ndis_packet as external storage. In most cases, this will
+ * point to a memory region allocated by the driver (either by
+ * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
+ * the driver to handle free()ing this region for is, so we set up
+ * a dummy no-op free handler for it.
+ */
+
+int
+ndis_ptom(m0, p)
+ struct mbuf **m0;
+ ndis_packet *p;
+{
+ struct mbuf *m, *prev = NULL;
+ ndis_buffer *buf;
+ ndis_packet_private *priv;
+ uint32_t totlen = 0;
+
+ if (p == NULL || m0 == NULL)
+ return(EINVAL);
+
+ priv = &p->np_private;
+ buf = priv->npp_head;
+
+ for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
+ if (buf == priv->npp_head)
+ MGETHDR(m, M_DONTWAIT, MT_HEADER);
+ else
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ m_freem(*m0);
+ *m0 = NULL;
+ return(ENOBUFS);
+ }
+
+ /*
+ * Note: there's some hackery going on here. We want
+ * to mate the mbufs to the buffers in the NDIS packet,
+ * but we don't mark the mbufs with the M_EXT flag to
+ * indicate external storage. This is because we don't
+ * want anything special done to free the buffers.
+ * Depending on the circumstances, the caller may want
+ * the entire packet to be released, buffers and all,
+ * by calling ndis_return_packet(), or ndis_free_packet().
+ * We leave it up to the caller to do the MEXTADD() to
+ * set up the free mechanism in the first mbuf of the
+ * chain.
+ */
+ if (buf->nb_size)
+ m->m_len = buf->nb_size;
+ else
+ m->m_len = buf->nb_bytecount;
+ m->m_data = buf->nb_mappedsystemva;
+ totlen += m->m_len;
+ if (m->m_flags & MT_HEADER)
+ *m0 = m;
+ else
+ prev->m_next = m;
+ prev = m;
+ }
+
+ (*m0)->m_pkthdr.len = totlen;
+
+ return(0);
+}
+
+/*
+ * Create an mbuf chain from an NDIS packet chain.
+ * This is used mainly when transmitting packets, where we need
+ * to turn an mbuf off an interface's send queue and transform it
+ * into an NDIS packet which will be fed into the NDIS driver's
+ * send routine.
+ *
+ * NDIS packets consist of two parts: an ndis_packet structure,
+ * which is vaguely analagous to the pkthdr portion of an mbuf,
+ * and one or more ndis_buffer structures, which define the
+ * actual memory segments in which the packet data resides.
+ * We need to allocate one ndis_buffer for each mbuf in a chain,
+ * plus one ndis_packet as the header.
+ */
+
+int
+ndis_mtop(m0, p)
+ struct mbuf *m0;
+ ndis_packet **p;
+{
+ struct mbuf *m;
+ ndis_buffer *buf = NULL, *prev = NULL;
+ ndis_packet_private *priv;
+
+ if (p == NULL || m0 == NULL)
+ return(EINVAL);
+
+ /* If caller didn't supply a packet, make one. */
+ if (*p == NULL) {
+ *p = malloc(sizeof(ndis_packet), M_DEVBUF, M_NOWAIT|M_ZERO);
+
+ if (*p == NULL)
+ return(ENOMEM);
+ }
+
+ priv = &(*p)->np_private;
+ priv->npp_totlen = m0->m_pkthdr.len;
+ priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
+
+ for (m = m0; m != NULL; m = m->m_next) {
+ if (m->m_len == NULL)
+ continue;
+
+ buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if (buf == NULL) {
+ ndis_free_packet(*p);
+ *p = NULL;
+ return(ENOMEM);
+ }
+
+ buf->nb_bytecount = m->m_len;
+ buf->nb_mappedsystemva = m->m_data;
+ if (priv->npp_head == NULL)
+ priv->npp_head = buf;
+ else
+ prev->nb_next = buf;
+ prev = buf;
+ }
+
+ priv->npp_tail = buf;
+
+ return(0);
+}
+
+int
+ndis_get_supported_oids(arg, oids, oidcnt)
+ void *arg;
+ ndis_oid **oids;
+ int *oidcnt;
+{
+ int len, rval;
+ ndis_oid *o;
+
+ if (arg == NULL || oids == NULL || oidcnt == NULL)
+ return(EINVAL);
+ len = 0;
+ ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
+
+ o = malloc(len, M_DEVBUF, M_NOWAIT);
+ if (o == NULL)
+ return(ENOMEM);
+
+ rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
+
+ if (rval) {
+ free(o, M_DEVBUF);
+ return(rval);
+ }
+
+ *oids = o;
+ *oidcnt = len / 4;
+
+ return(0);
+}
+
+int
+ndis_set_info(arg, oid, buf, buflen)
+ void *arg;
+ ndis_oid oid;
+ void *buf;
+ int *buflen;
+{
+ struct ndis_softc *sc;
+ ndis_status rval;
+ ndis_handle adapter;
+ __stdcall ndis_setinfo_handler setfunc;
+ uint32_t byteswritten = 0, bytesneeded = 0;
+
+ sc = arg;
+ setfunc = sc->ndis_chars.nmc_setinfo_func;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+
+ rval = setfunc(adapter, oid, buf, *buflen,
+ &byteswritten, &bytesneeded);
+
+ if (byteswritten)
+ *buflen = byteswritten;
+ if (bytesneeded)
+ *buflen = bytesneeded;
+
+ if (rval == NDIS_STATUS_INVALID_LENGTH)
+ return(ENOSPC);
+
+ if (rval == NDIS_STATUS_INVALID_OID)
+ return(EINVAL);
+
+ if (rval == NDIS_STATUS_NOT_SUPPORTED ||
+ rval == NDIS_STATUS_NOT_ACCEPTED)
+ return(ENOTSUP);
+
+ if (rval == NDIS_STATUS_PENDING)
+ return(EAGAIN);
+
+ return(0);
+}
+
+int
+ndis_send_packets(arg, packets, cnt)
+ void *arg;
+ ndis_packet **packets;
+ int cnt;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_sendmulti_handler sendfunc;
+
+ sc = arg;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ sendfunc = sc->ndis_chars.nmc_sendmulti_func;
+ sendfunc(adapter, packets, cnt);
+
+ return(0);
+}
+
+int
+ndis_init_dma(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ int i, error;
+
+ sc = arg;
+
+ sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
+ M_DEVBUF, M_NOWAIT|M_ZERO);
+
+ if (sc->ndis_tmaps == NULL)
+ return(ENOMEM);
+
+ sc->ndis_mbufs = malloc(sizeof(struct mbuf) * sc->ndis_maxpkts,
+ M_DEVBUF, M_NOWAIT|M_ZERO);
+
+ if (sc->ndis_mbufs == NULL) {
+ free(sc->ndis_tmaps, M_DEVBUF);
+ return(ENOMEM);
+ }
+
+ for (i = 0; i < sc->ndis_maxpkts; i++) {
+ error = bus_dmamap_create(sc->ndis_ttag, 0,
+ &sc->ndis_tmaps[i]);
+ if (error) {
+ free(sc->ndis_tmaps, M_DEVBUF);
+ free(sc->ndis_mbufs, M_DEVBUF);
+ return(ENODEV);
+ }
+ }
+
+ return(0);
+}
+
+int
+ndis_destroy_dma(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ int i;
+
+ sc = arg;
+
+ for (i = 0; i < sc->ndis_maxpkts; i++) {
+ if (sc->ndis_mbufs[i] != NULL)
+ m_freem(sc->ndis_mbufs[i]);
+ bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
+ }
+
+ free(sc->ndis_tmaps, M_DEVBUF);
+ free(sc->ndis_mbufs, M_DEVBUF);
+
+ bus_dma_tag_destroy(sc->ndis_ttag);
+
+ return(0);
+}
+
+int
+ndis_reset_nic(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_reset_handler resetfunc;
+ uint8_t addressing_reset;
+ struct ifnet *ifp;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ if (adapter == NULL)
+ return(EIO);
+ resetfunc = sc->ndis_chars.nmc_reset_func;
+
+ if (resetfunc == NULL)
+ return(EINVAL);
+
+ resetfunc(&addressing_reset, adapter);
+
+ return(0);
+}
+
+int
+ndis_halt_nic(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_halt_handler haltfunc;
+ struct ifnet *ifp;
+
+ sc = arg;
+ ifp = &sc->arpcom.ac_if;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ if (adapter == NULL)
+ return(EIO);
+ haltfunc = sc->ndis_chars.nmc_halt_func;
+
+ if (haltfunc == NULL)
+ return(EINVAL);
+
+ haltfunc(adapter);
+
+ /*
+ * The adapter context is only valid after the init
+ * handler has been called, and is invalid once the
+ * halt handler has been called.
+ */
+
+ sc->ndis_block.nmb_miniportadapterctx = NULL;
+
+ return(0);
+}
+
+int
+ndis_shutdown_nic(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_shutdown_handler shutdownfunc;
+
+
+ sc = arg;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ if (adapter == NULL)
+ return(EIO);
+ shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
+
+ if (shutdownfunc == NULL)
+ return(EINVAL);
+
+ shutdownfunc(sc->ndis_chars.nmc_rsvd0);
+
+ return(0);
+}
+
+int
+ndis_init_nic(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_miniport_block *block;
+ __stdcall ndis_init_handler initfunc;
+ ndis_status status, openstatus = 0;
+ ndis_medium mediumarray[NdisMediumMax];
+ uint32_t chosenmedium, i;
+
+ if (arg == NULL)
+ return(EINVAL);
+
+ sc = arg;
+ block = &sc->ndis_block;
+ initfunc = sc->ndis_chars.nmc_init_func;
+
+ for (i = 0; i < NdisMediumMax; i++)
+ mediumarray[i] = i;
+
+ status = initfunc(&openstatus, &chosenmedium,
+ mediumarray, NdisMediumMax, block, block);
+
+ /*
+ * If the init fails, blow away the other exported routines
+ * we obtained from the driver so we can't call them later.
+ * If the init failed, none of these will work.
+ */
+ if (status != NDIS_STATUS_SUCCESS) {
+ bzero((char *)&sc->ndis_chars,
+ sizeof(ndis_miniport_characteristics));
+ return(ENXIO);
+ }
+
+ return(0);
+}
+
+void
+ndis_enable_intr(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_enable_interrupts_handler intrenbfunc;
+
+ sc = arg;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ if (adapter == NULL)
+ return;
+ intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
+ if (intrenbfunc == NULL)
+ return;
+ intrenbfunc(adapter);
+
+ return;
+}
+
+void
+ndis_disable_intr(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_disable_interrupts_handler intrdisfunc;
+
+ sc = arg;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ if (adapter == NULL)
+ return;
+ intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
+ if (intrdisfunc == NULL)
+ return;
+ intrdisfunc(adapter);
+
+ return;
+}
+
+int
+ndis_isr(arg, ourintr, callhandler)
+ void *arg;
+ int *ourintr;
+ int *callhandler;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_isr_handler isrfunc;
+ uint8_t accepted, queue;
+
+ if (arg == NULL || ourintr == NULL || callhandler == NULL)
+ return(EINVAL);
+
+ sc = arg;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ isrfunc = sc->ndis_chars.nmc_isr_func;
+ isrfunc(&accepted, &queue, adapter);
+ *ourintr = accepted;
+ *callhandler = queue;
+
+ return(0);
+}
+
+int
+ndis_intrhand(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ __stdcall ndis_interrupt_handler intrfunc;
+
+ if (arg == NULL)
+ return(EINVAL);
+
+ sc = arg;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+ intrfunc = sc->ndis_chars.nmc_interrupt_func;
+ intrfunc(adapter);
+
+ return(0);
+}
+
+int
+ndis_get_info(arg, oid, buf, buflen)
+ void *arg;
+ ndis_oid oid;
+ void *buf;
+ int *buflen;
+{
+ struct ndis_softc *sc;
+ ndis_status rval;
+ ndis_handle adapter;
+ __stdcall ndis_queryinfo_handler queryfunc;
+ uint32_t byteswritten = 0, bytesneeded = 0;
+
+ sc = arg;
+ queryfunc = sc->ndis_chars.nmc_queryinfo_func;
+ adapter = sc->ndis_block.nmb_miniportadapterctx;
+
+ rval = queryfunc(adapter, oid, buf, *buflen,
+ &byteswritten, &bytesneeded);
+
+ if (byteswritten)
+ *buflen = byteswritten;
+ if (bytesneeded)
+ *buflen = bytesneeded;
+
+ if (rval == NDIS_STATUS_INVALID_LENGTH ||
+ rval == NDIS_STATUS_BUFFER_TOO_SHORT)
+ return(ENOSPC);
+
+ if (rval == NDIS_STATUS_INVALID_OID)
+ return(EINVAL);
+
+ if (rval == NDIS_STATUS_NOT_SUPPORTED ||
+ rval == NDIS_STATUS_NOT_ACCEPTED)
+ return(ENOTSUP);
+
+ if (rval == NDIS_STATUS_PENDING)
+ return(EAGAIN);
+
+ return(0);
+}
+
+int
+ndis_unload_driver(arg)
+ void *arg;
+{
+ struct ndis_softc *sc;
+
+ sc = arg;
+
+ free(sc->ndis_block.nmb_rlist, M_DEVBUF);
+
+ ndis_flush_sysctls(sc);
+ ndis_libfini();
+ ntoskrnl_libfini();
+
+ return(0);
+}
+
+int
+ndis_load_driver(img, arg)
+ vm_offset_t img;
+ void *arg;
+{
+ __stdcall driver_entry entry;
+ image_optional_header opt_hdr;
+ image_import_descriptor imp_desc;
+ ndis_unicode_string dummystr;
+ ndis_driver_object drv;
+ ndis_miniport_block *block;
+ ndis_status status;
+ int idx;
+ uint32_t *ptr;
+ struct ndis_softc *sc;
+
+ sc = arg;
+
+ /* Perform text relocation */
+ if (pe_relocate(img))
+ return(ENOEXEC);
+
+ /* Dynamically link the NDIS.SYS routines -- required. */
+ if (pe_patch_imports(img, "NDIS", ndis_functbl))
+ return(ENOEXEC);
+
+ /* Dynamically link the HAL.dll routines -- also required. */
+ if (pe_patch_imports(img, "HAL", hal_functbl))
+ return(ENOEXEC);
+
+ /* Dynamically link ntoskrnl.exe -- optional. */
+ if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
+ if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
+ return(ENOEXEC);
+ }
+
+ /* Initialize subsystems */
+ ndis_libinit();
+ ntoskrnl_libinit();
+
+ /* Locate the driver entry point */
+ pe_get_optional_header(img, &opt_hdr);
+ entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
+
+ /*
+ * Now call the DriverEntry() routine. This will cause
+ * a callout to the NdisInitializeWrapper() and
+ * NdisMRegisterMiniport() routines.
+ */
+ dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
+ dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
+ dummystr.nus_buf = NULL;
+ ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
+ drv.ndo_ifname = "ndis0";
+
+ status = entry(&drv, &dummystr);
+
+ free (dummystr.nus_buf, M_DEVBUF);
+
+ if (status != NDIS_STATUS_SUCCESS)
+ return(ENODEV);
+
+ /*
+ * Now that we have the miniport driver characteristics,
+ * create an NDIS block and call the init handler.
+ * This will cause the driver to try to probe for
+ * a device.
+ */
+
+ block = &sc->ndis_block;
+ bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
+ sizeof(ndis_miniport_characteristics));
+
+ /*block->nmb_signature = 0xcafebabe;*/
+
+ ptr = (uint32_t *)block;
+ for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
+ *ptr = idx | 0xdead0000;
+ ptr++;
+ }
+
+ block->nmb_signature = (void *)0xcafebabe;
+ block->nmb_setdone_func = ndis_setdone_func;
+ block->nmb_status_func = ndis_status_func;
+ block->nmb_statusdone_func = ndis_statusdone_func;
+ block->nmb_resetdone_func = ndis_resetdone_func;
+
+ block->nmb_ifp = &sc->arpcom.ac_if;
+ block->nmb_dev = sc->ndis_dev;
+
+ return(0);
+}
OpenPOWER on IntegriCloud