kern_ndis.c revision 124005
14910Swollman/* 24910Swollman * Copyright (c) 2003 34910Swollman * Bill Paul <wpaul@windriver.com>. All rights reserved. 44910Swollman * 530300Sjoerg * Redistribution and use in source and binary forms, with or without 625944Sjoerg * modification, are permitted provided that the following conditions 74910Swollman * are met: 825944Sjoerg * 1. Redistributions of source code must retain the above copyright 988534Sjoerg * notice, this list of conditions and the following disclaimer. 1025944Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 114910Swollman * notice, this list of conditions and the following disclaimer in the 124910Swollman * documentation and/or other materials provided with the distribution. 134910Swollman * 3. All advertising materials mentioning features or use of this software 144910Swollman * must display the following acknowledgement: 154910Swollman * This product includes software developed by Bill Paul. 164910Swollman * 4. Neither the name of the author nor the names of any co-contributors 174910Swollman * may be used to endorse or promote products derived from this software 1830300Sjoerg * without specific prior written permission. 1916288Sgpalmer * 2050477Speter * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 214910Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224910Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2340008Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 2440008Sjoerg * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2542065Sphk * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2632350Seivind * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2754263Sshin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2831742Seivind * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2940008Sjoerg * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 3031742Seivind * THE POSSIBILITY OF SUCH DAMAGE. 3140008Sjoerg */ 3240008Sjoerg 3340008Sjoerg#include <sys/cdefs.h> 3454263Sshin__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 124005 2003-12-30 21:33:26Z wpaul $"); 3540008Sjoerg 3640008Sjoerg#include <sys/param.h> 3740008Sjoerg#include <sys/types.h> 3840008Sjoerg#include <sys/errno.h> 394952Sbde#include <sys/callout.h> 404952Sbde#include <sys/socket.h> 4170199Sjhay#include <sys/queue.h> 4224204Sbde#include <sys/sysctl.h> 434910Swollman#include <sys/systm.h> 4425706Sjoerg#include <sys/malloc.h> 4542104Sphk#include <sys/lock.h> 4659604Sobrien#include <sys/mutex.h> 4742104Sphk#include <sys/conf.h> 4829024Sbde 494910Swollman#include <sys/kernel.h> 5040008Sjoerg#include <machine/bus.h> 5140008Sjoerg#include <machine/resource.h> 5240008Sjoerg#include <sys/bus.h> 5340008Sjoerg#include <sys/rman.h> 5430300Sjoerg 5540008Sjoerg#include <net/if.h> 564910Swollman#include <net/if_arp.h> 574910Swollman#include <net/ethernet.h> 584910Swollman#include <net/if_dl.h> 594910Swollman#include <net/if_media.h> 6042104Sphk 6188534Sjoerg#include <net80211/ieee80211_var.h> 6288534Sjoerg#include <net80211/ieee80211_ioctl.h> 6388534Sjoerg 6488534Sjoerg#include <dev/pccard/pccardvar.h> 654910Swollman#include "card_if.h" 6640008Sjoerg 6740008Sjoerg#include <compat/ndis/pe_var.h> 6840008Sjoerg#include <compat/ndis/resource_var.h> 6942104Sphk#include <compat/ndis/ndis_var.h> 7030300Sjoerg#include <compat/ndis/hal_var.h> 7130300Sjoerg#include <compat/ndis/ntoskrnl_var.h> 724910Swollman#include <compat/ndis/cfg_var.h> 734910Swollman#include <dev/if_ndis/if_ndisvar.h> 744910Swollman 7588705Sjoerg#define __stdcall __attribute__((__stdcall__)) 7688705Sjoerg#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 774910Swollman 784910Swollman__stdcall static void ndis_status_func(ndis_handle, ndis_status, 794910Swollman void *, uint32_t); 804910Swollman__stdcall static void ndis_statusdone_func(ndis_handle); 8188705Sjoerg__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 8288705Sjoerg__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 8388705Sjoerg__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 8488705Sjoerg 8588705Sjoerg/* 8688705Sjoerg * This allows us to export our symbols to other modules. 8711819Sjulian * Note that we call ourselves 'ndisapi' to avoid a namespace 8811819Sjulian * collision with if_ndis.ko, which internally calls itself 8911819Sjulian * 'ndis.' 9011819Sjulian */ 9111819Sjulianstatic int 924910Swollmanndis_modevent(module_t mod, int cmd, void *arg) 934910Swollman{ 944910Swollman return(0); 954910Swollman} 964910SwollmanDEV_MODULE(ndisapi, ndis_modevent, NULL); 974910SwollmanMODULE_VERSION(ndisapi, 1); 984910Swollman 9942065Sphk 10042064Sphk__stdcall static void 10142064Sphkndis_status_func(adapter, status, sbuf, slen) 10242104Sphk ndis_handle adapter; 10340008Sjoerg ndis_status status; 10442064Sphk void *sbuf; 10542064Sphk uint32_t slen; 10642104Sphk{ 10740008Sjoerg printf ("status: %x\n", status); 10842104Sphk return; 1094910Swollman} 1104910Swollman 11125944Sjoerg__stdcall static void 11225944Sjoergndis_statusdone_func(adapter) 11325944Sjoerg ndis_handle adapter; 11425955Sjoerg{ 11525944Sjoerg printf ("status complete\n"); 11625944Sjoerg return; 11725944Sjoerg} 11825955Sjoerg 11925955Sjoerg__stdcall static void 12025955Sjoergndis_setdone_func(adapter, status) 12130300Sjoerg ndis_handle adapter; 12230300Sjoerg ndis_status status; 12330300Sjoerg{ 12430300Sjoerg ndis_miniport_block *block; 12530300Sjoerg block = adapter; 12630300Sjoerg 12730300Sjoerg block->nmb_setstat = status; 12830300Sjoerg wakeup(&block->nmb_wkupdpctimer); 12930300Sjoerg return; 13025944Sjoerg} 13125944Sjoerg 13225955Sjoerg__stdcall static void 13325955Sjoergndis_getdone_func(adapter, status) 13445152Sphk ndis_handle adapter; 13525944Sjoerg ndis_status status; 13630300Sjoerg{ 13730300Sjoerg ndis_miniport_block *block; 13830300Sjoerg block = adapter; 13930300Sjoerg 14030300Sjoerg block->nmb_getstat = status; 14130300Sjoerg wakeup(&block->nmb_wkupdpctimer); 14288534Sjoerg return; 14388534Sjoerg} 14478064Sume 14530300Sjoerg__stdcall static void 14630300Sjoergndis_resetdone_func(adapter, status, addressingreset) 14730300Sjoerg ndis_handle adapter; 14830300Sjoerg ndis_status status; 14978064Sume uint8_t addressingreset; 1504910Swollman{ 15125944Sjoerg printf ("reset done...\n"); 15225944Sjoerg return; 15325944Sjoerg} 15425944Sjoerg 15525944Sjoerg#define NDIS_AM_RID 3 15625944Sjoerg 15725944Sjoergint 15825944Sjoergndis_alloc_amem(arg) 15925944Sjoerg void *arg; 16025944Sjoerg{ 16125944Sjoerg struct ndis_softc *sc; 1624910Swollman int error, rid; 16330300Sjoerg 16430300Sjoerg if (arg == NULL) 16530300Sjoerg return(EINVAL); 16630300Sjoerg 16730300Sjoerg sc = arg; 16830300Sjoerg rid = NDIS_AM_RID; 16930300Sjoerg sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY, 17030300Sjoerg &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE); 1714910Swollman 17225944Sjoerg if (sc->ndis_res_am == NULL) { 17325944Sjoerg printf("ndis%d: failed to allocate attribute memory\n", 17425944Sjoerg sc->ndis_unit); 1754910Swollman return(ENXIO); 17678064Sume } 17778064Sume 17878064Sume error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev), 17988534Sjoerg sc->ndis_dev, rid, 0, NULL); 18088534Sjoerg 18130300Sjoerg if (error) { 18230300Sjoerg printf("ndis%d: CARD_SET_MEMORY_OFFSET() returned 0x%x\n", 18330300Sjoerg sc->ndis_unit, error); 1844910Swollman return(error); 18530300Sjoerg } 18630300Sjoerg 18730300Sjoerg error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev), 18830300Sjoerg sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR); 18930300Sjoerg 19030300Sjoerg if (error) { 19130300Sjoerg printf("ndis%d: CARD_SET_RES_FLAGS() returned 0x%x\n", 19230300Sjoerg sc->ndis_unit, error); 19330300Sjoerg return(error); 19430300Sjoerg } 19530300Sjoerg 19630300Sjoerg return(0); 19730300Sjoerg} 19830300Sjoerg 19925944Sjoergint 20025944Sjoergndis_create_sysctls(arg) 20125944Sjoerg void *arg; 20225944Sjoerg{ 20325944Sjoerg struct ndis_softc *sc; 20425944Sjoerg ndis_cfg *vals; 20525944Sjoerg char buf[256]; 20625944Sjoerg 20725944Sjoerg if (arg == NULL) 20825944Sjoerg return(EINVAL); 20925944Sjoerg 21025944Sjoerg sc = arg; 2114910Swollman vals = sc->ndis_regvals; 21211189Sjkh 21311189Sjkh TAILQ_INIT(&sc->ndis_cfglist_head); 21411189Sjkh 215103842Salfred /* Create the sysctl tree. */ 2164910Swollman 2174910Swollman sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 2184910Swollman SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 21911189Sjkh device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 22011189Sjkh device_get_desc(sc->ndis_dev)); 22111189Sjkh 222103842Salfred /* Add the driver-specific registry keys. */ 2234910Swollman 2244910Swollman vals = sc->ndis_regvals; 2254910Swollman while(1) { 22611189Sjkh if (vals->nc_cfgkey == NULL) 22711189Sjkh break; 22811189Sjkh if (vals->nc_idx != sc->ndis_devidx) { 22911189Sjkh vals++; 23011189Sjkh continue; 23111189Sjkh } 232103842Salfred SYSCTL_ADD_STRING(&sc->ndis_ctx, 23388704Sjoerg SYSCTL_CHILDREN(sc->ndis_tree), 2344910Swollman OID_AUTO, vals->nc_cfgkey, 23525944Sjoerg CTLFLAG_RW, vals->nc_val, 23625944Sjoerg sizeof(vals->nc_val), 23725944Sjoerg vals->nc_cfgdesc); 23825944Sjoerg vals++; 23925944Sjoerg } 24025944Sjoerg 24125944Sjoerg /* Now add a couple of builtin keys. */ 24225944Sjoerg 24325944Sjoerg /* 24425944Sjoerg * Environment can be either Windows (0) or WindowsNT (1). 24525944Sjoerg * We qualify as the latter. 24625944Sjoerg */ 24725944Sjoerg ndis_add_sysctl(sc, "Environment", 24825944Sjoerg "Windows environment", "1", CTLFLAG_RD); 24925944Sjoerg 25025944Sjoerg /* NDIS version should be 5.1. */ 25125944Sjoerg ndis_add_sysctl(sc, "NdisVersion", 25225944Sjoerg "NDIS API Version", "0x00050001", CTLFLAG_RD); 25325944Sjoerg 25425944Sjoerg /* Bus type (PCI, PCMCIA, etc...) */ 25525944Sjoerg sprintf(buf, "%d\n", (int)sc->ndis_iftype); 25625944Sjoerg ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 25725944Sjoerg 25825944Sjoerg if (sc->ndis_res_io != NULL) { 25925944Sjoerg sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io)); 26025944Sjoerg ndis_add_sysctl(sc, "IOBaseAddress", 26125944Sjoerg "Base I/O Address", buf, CTLFLAG_RD); 26225944Sjoerg } 26325944Sjoerg 26425944Sjoerg if (sc->ndis_irq != NULL) { 26525944Sjoerg sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq)); 26625944Sjoerg ndis_add_sysctl(sc, "InterruptNumber", 26712820Sphk "Interrupt Number", buf, CTLFLAG_RD); 26842065Sphk } 26930300Sjoerg 27040008Sjoerg return(0); 2714910Swollman} 27242065Sphk 27340008Sjoergint 27440008Sjoergndis_add_sysctl(arg, key, desc, val, flag) 27540008Sjoerg void *arg; 27640008Sjoerg char *key; 27740008Sjoerg char *desc; 27840008Sjoerg char *val; 27940008Sjoerg int flag; 28088705Sjoerg{ 2814910Swollman struct ndis_softc *sc; 2824910Swollman struct ndis_cfglist *cfg; 2834910Swollman char descstr[256]; 2844910Swollman 2854910Swollman sc = arg; 28630300Sjoerg 28730300Sjoerg cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 2884910Swollman 28911189Sjkh if (cfg == NULL) 2904910Swollman return(ENOMEM); 2914910Swollman 2924910Swollman cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 2934910Swollman if (desc == NULL) { 29488705Sjoerg snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 2954910Swollman cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 29625944Sjoerg } else 29725944Sjoerg cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 29825944Sjoerg strcpy(cfg->ndis_cfg.nc_val, val); 29925944Sjoerg 30011189Sjkh TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 30130300Sjoerg 30225944Sjoerg SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 3034910Swollman OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 30425944Sjoerg cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 30525944Sjoerg cfg->ndis_cfg.nc_cfgdesc); 30625944Sjoerg 30725944Sjoerg return(0); 30825944Sjoerg} 30925944Sjoerg 31025944Sjoergint 31142104Sphkndis_flush_sysctls(arg) 31225944Sjoerg void *arg; 31325944Sjoerg{ 31430300Sjoerg struct ndis_softc *sc; 31542104Sphk struct ndis_cfglist *cfg; 31630300Sjoerg 31725944Sjoerg sc = arg; 31825944Sjoerg 31925944Sjoerg while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 32025944Sjoerg cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 32125944Sjoerg TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 32225944Sjoerg free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 32325944Sjoerg free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 32430300Sjoerg free(cfg, M_DEVBUF); 32530300Sjoerg } 32625944Sjoerg 32725944Sjoerg return(0); 32825944Sjoerg} 32925944Sjoerg 33025944Sjoergvoid 33125944Sjoergndis_return_packet(buf, arg) 33225944Sjoerg void *buf; /* not used */ 33325944Sjoerg void *arg; 33425944Sjoerg{ 33525944Sjoerg struct ndis_softc *sc; 33625944Sjoerg ndis_handle adapter; 33725944Sjoerg ndis_packet *p; 33825944Sjoerg __stdcall ndis_return_handler returnfunc; 33925944Sjoerg 34030300Sjoerg if (arg == NULL) 34130300Sjoerg return; 34225944Sjoerg 34325944Sjoerg p = arg; 34425944Sjoerg 34525944Sjoerg /* Decrement refcount. */ 34625944Sjoerg p->np_refcnt--; 34725944Sjoerg 34825944Sjoerg /* Release packet when refcount hits zero, otherwise return. */ 34925944Sjoerg if (p->np_refcnt) 35025944Sjoerg return; 35125944Sjoerg 35225944Sjoerg sc = p->np_softc; 35325944Sjoerg returnfunc = sc->ndis_chars.nmc_return_packet_func; 35425944Sjoerg adapter = sc->ndis_block.nmb_miniportadapterctx; 35525944Sjoerg if (returnfunc != NULL) 35625944Sjoerg returnfunc(adapter, p); 35725944Sjoerg 35878064Sume return; 35978064Sume} 36078064Sume 36178064Sumevoid 36278064Sumendis_free_bufs(b0) 36378064Sume ndis_buffer *b0; 36478064Sume{ 36578064Sume ndis_buffer *next; 36678064Sume 36778064Sume if (b0 == NULL) 36878064Sume return; 36978064Sume 37078064Sume while(b0 != NULL) { 37178064Sume next = b0->nb_next; 37278064Sume free (b0, M_DEVBUF); 37330300Sjoerg b0 = next; 37430300Sjoerg } 37530300Sjoerg 37630300Sjoerg return; 37730300Sjoerg} 37830300Sjoerg 37930300Sjoergvoid 38030300Sjoergndis_free_packet(p) 38130300Sjoerg ndis_packet *p; 38230300Sjoerg{ 38330300Sjoerg if (p == NULL) 38430300Sjoerg return; 38530300Sjoerg 38630300Sjoerg ndis_free_bufs(p->np_private.npp_head); 38730300Sjoerg free(p, M_DEVBUF); 38830300Sjoerg 38930300Sjoerg return; 39030300Sjoerg} 39130300Sjoerg 39230300Sjoergint 39325944Sjoergndis_convert_res(arg) 39430300Sjoerg void *arg; 39530300Sjoerg{ 39678064Sume struct ndis_softc *sc; 39778064Sume ndis_resource_list *rl = NULL; 39878064Sume cm_partial_resource_desc *prd = NULL; 39925944Sjoerg ndis_miniport_block *block; 40025944Sjoerg device_t dev; 40125944Sjoerg struct resource_list *brl; 40230300Sjoerg struct resource_list_entry *brle; 40338343Sbde 40430300Sjoerg sc = arg; 40530300Sjoerg block = &sc->ndis_block; 40630300Sjoerg dev = sc->ndis_dev; 40725944Sjoerg 40830300Sjoerg rl = malloc(sizeof(ndis_resource_list) + 40930300Sjoerg (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 41030300Sjoerg M_DEVBUF, M_NOWAIT|M_ZERO); 41125944Sjoerg 41225944Sjoerg if (rl == NULL) 41378064Sume return(ENOMEM); 41478064Sume 41578064Sume rl->cprl_version = 5; 41678064Sume rl->cprl_version = 1; 41778064Sume rl->cprl_count = sc->ndis_rescnt; 41878064Sume prd = rl->cprl_partial_descs; 41978064Sume 42078064Sume brl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 42178064Sume if (brl != NULL) { 42225944Sjoerg SLIST_FOREACH(brle, brl, link) { 42325944Sjoerg switch (brle->type) { 42433181Seivind case SYS_RES_IOPORT: 42525944Sjoerg prd->cprd_type = CmResourceTypePort; 42625944Sjoerg prd->u.cprd_port.cprd_start.np_quad = 42725944Sjoerg brle->start; 42825944Sjoerg prd->u.cprd_port.cprd_len = brle->count; 42925944Sjoerg break; 43025944Sjoerg case SYS_RES_MEMORY: 43125944Sjoerg prd->cprd_type = CmResourceTypeMemory; 43233181Seivind prd->u.cprd_port.cprd_start.np_quad = 43388709Sjoerg brle->start; 43488709Sjoerg prd->u.cprd_port.cprd_len = brle->count; 43588709Sjoerg break; 43688709Sjoerg case SYS_RES_IRQ: 43788709Sjoerg prd->cprd_type = CmResourceTypeInterrupt; 43888709Sjoerg prd->u.cprd_intr.cprd_level = brle->start; 43988709Sjoerg prd->u.cprd_intr.cprd_vector = brle->start; 44025944Sjoerg prd->u.cprd_intr.cprd_affinity = 0; 44125944Sjoerg break; 44225944Sjoerg default: 44325944Sjoerg break; 44425944Sjoerg } 44525944Sjoerg prd++; 44678064Sume } 44778064Sume } 44878064Sume 44978064Sume block->nmb_rlist = rl; 45078064Sume 45178064Sume return(0); 45278064Sume} 45378064Sume 45478064Sume/* 45578064Sume * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 45678064Sume * packet, it will hand it to us in the form of an ndis_packet, 45778064Sume * which we need to convert to an mbuf that is then handed off 45878064Sume * to the stack. Note: we configure the mbuf list so that it uses 45978064Sume * the memory regions specified by the ndis_buffer structures in 46033181Seivind * the ndis_packet as external storage. In most cases, this will 46130300Sjoerg * point to a memory region allocated by the driver (either by 46230300Sjoerg * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 46330300Sjoerg * the driver to handle free()ing this region for is, so we set up 46430300Sjoerg * a dummy no-op free handler for it. 46530300Sjoerg */ 46630300Sjoerg 46730300Sjoergint 46833181Seivindndis_ptom(m0, p) 46930300Sjoerg struct mbuf **m0; 47030300Sjoerg ndis_packet *p; 47130300Sjoerg{ 47230300Sjoerg struct mbuf *m, *prev = NULL; 47330300Sjoerg ndis_buffer *buf; 47430300Sjoerg ndis_packet_private *priv; 47530300Sjoerg uint32_t totlen = 0; 47633181Seivind 47725944Sjoerg if (p == NULL || m0 == NULL) 47825944Sjoerg return(EINVAL); 47978064Sume 48030300Sjoerg priv = &p->np_private; 48130300Sjoerg buf = priv->npp_head; 48225944Sjoerg p->np_refcnt = 0; 48325944Sjoerg 48470199Sjhay for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 48570199Sjhay if (buf == priv->npp_head) 48670199Sjhay MGETHDR(m, M_DONTWAIT, MT_HEADER); 48770199Sjhay else 48870199Sjhay MGET(m, M_DONTWAIT, MT_DATA); 48970199Sjhay if (m == NULL) { 49070199Sjhay m_freem(*m0); 49170199Sjhay *m0 = NULL; 49270199Sjhay return(ENOBUFS); 49370199Sjhay } 49470199Sjhay m->m_len = buf->nb_bytecount; 49570199Sjhay m->m_data = MDL_VA(buf); 49670199Sjhay MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 49770199Sjhay p, 0, EXT_NDIS); 49870199Sjhay p->np_refcnt++; 49970199Sjhay totlen += m->m_len; 50070199Sjhay if (m->m_flags & MT_HEADER) 50170199Sjhay *m0 = m; 50270199Sjhay else 50370199Sjhay prev->m_next = m; 50470199Sjhay prev = m; 50525944Sjoerg } 50670199Sjhay 50725944Sjoerg (*m0)->m_pkthdr.len = totlen; 5084910Swollman 5094910Swollman return(0); 5104910Swollman} 5114910Swollman 5124910Swollman/* 51325706Sjoerg * Create an mbuf chain from an NDIS packet chain. 51425706Sjoerg * This is used mainly when transmitting packets, where we need 5154910Swollman * to turn an mbuf off an interface's send queue and transform it 5164910Swollman * into an NDIS packet which will be fed into the NDIS driver's 5174910Swollman * send routine. 51825944Sjoerg * 51988700Sjoerg * NDIS packets consist of two parts: an ndis_packet structure, 52088700Sjoerg * which is vaguely analagous to the pkthdr portion of an mbuf, 52125944Sjoerg * and one or more ndis_buffer structures, which define the 5224910Swollman * actual memory segments in which the packet data resides. 5234910Swollman * We need to allocate one ndis_buffer for each mbuf in a chain, 5244910Swollman * plus one ndis_packet as the header. 5254910Swollman */ 5264910Swollman 5274910Swollmanint 5284910Swollmanndis_mtop(m0, p) 52925944Sjoerg struct mbuf *m0; 53025706Sjoerg ndis_packet **p; 53140008Sjoerg{ 53240008Sjoerg struct mbuf *m; 53325944Sjoerg ndis_buffer *buf = NULL, *prev = NULL; 53488700Sjoerg ndis_packet_private *priv; 53588700Sjoerg 53625944Sjoerg if (p == NULL || m0 == NULL) 53725944Sjoerg return(EINVAL); 5384910Swollman 5394910Swollman /* If caller didn't supply a packet, make one. */ 5404910Swollman if (*p == NULL) { 5414910Swollman *p = malloc(sizeof(ndis_packet), M_DEVBUF, M_NOWAIT|M_ZERO); 5424910Swollman 5434910Swollman if (*p == NULL) 5444910Swollman return(ENOMEM); 5454910Swollman } 5464910Swollman 5474910Swollman priv = &(*p)->np_private; 5484910Swollman priv->npp_totlen = m0->m_pkthdr.len; 54945152Sphk priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 55025944Sjoerg 55125706Sjoerg for (m = m0; m != NULL; m = m->m_next) { 55240008Sjoerg if (m->m_len == 0) 55325706Sjoerg continue; 55440008Sjoerg buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO); 55525706Sjoerg if (buf == NULL) { 55611189Sjkh ndis_free_packet(*p); 55711189Sjkh *p = NULL; 5584910Swollman return(ENOMEM); 5594910Swollman } 56025944Sjoerg 56125706Sjoerg MDL_INIT(buf, m->m_data, m->m_len); 56244145Sphk if (priv->npp_head == NULL) 56325706Sjoerg priv->npp_head = buf; 56440008Sjoerg else 56525706Sjoerg prev->nb_next = buf; 56644145Sphk prev = buf; 56744145Sphk } 56878064Sume 56944145Sphk priv->npp_tail = buf; 5704910Swollman 5714910Swollman return(0); 5724910Swollman} 57330300Sjoerg 5744910Swollmanint 5754910Swollmanndis_get_supported_oids(arg, oids, oidcnt) 57630300Sjoerg void *arg; 57730300Sjoerg ndis_oid **oids; 57830300Sjoerg int *oidcnt; 57930300Sjoerg{ 58030300Sjoerg int len, rval; 58130300Sjoerg ndis_oid *o; 58230300Sjoerg 58330300Sjoerg if (arg == NULL || oids == NULL || oidcnt == NULL) 58430300Sjoerg return(EINVAL); 58530300Sjoerg len = 0; 5864910Swollman ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 5874910Swollman 58825944Sjoerg o = malloc(len, M_DEVBUF, M_NOWAIT); 58930300Sjoerg if (o == NULL) 5904910Swollman return(ENOMEM); 5914910Swollman 5924910Swollman rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 59325944Sjoerg 5944910Swollman if (rval) { 5954910Swollman free(o, M_DEVBUF); 5964910Swollman return(rval); 59788577Sjoerg } 5984910Swollman 59988534Sjoerg *oids = o; 60088534Sjoerg *oidcnt = len / 4; 60188700Sjoerg 60288700Sjoerg return(0); 60388700Sjoerg} 60488700Sjoerg 60588700Sjoergint 60688700Sjoergndis_set_info(arg, oid, buf, buflen) 60788700Sjoerg void *arg; 60888700Sjoerg ndis_oid oid; 60988700Sjoerg void *buf; 61088700Sjoerg int *buflen; 61188534Sjoerg{ 61288700Sjoerg struct ndis_softc *sc; 61388700Sjoerg ndis_status rval; 61488700Sjoerg ndis_handle adapter; 61588700Sjoerg __stdcall ndis_setinfo_handler setfunc; 61688700Sjoerg uint32_t byteswritten = 0, bytesneeded = 0; 61788700Sjoerg struct timeval tv; 61888700Sjoerg int error; 61988700Sjoerg 62088700Sjoerg sc = arg; 62188700Sjoerg setfunc = sc->ndis_chars.nmc_setinfo_func; 62288700Sjoerg adapter = sc->ndis_block.nmb_miniportadapterctx; 62388700Sjoerg 62488700Sjoerg rval = setfunc(adapter, oid, buf, *buflen, 62588700Sjoerg &byteswritten, &bytesneeded); 62688534Sjoerg 62788534Sjoerg if (rval == NDIS_STATUS_PENDING) { 62888534Sjoerg tv.tv_sec = 60; 62988599Sjoerg tv.tv_usec = 0; 63088534Sjoerg error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 63188534Sjoerg PPAUSE|PCATCH, "ndisset", tvtohz(&tv)); 63288534Sjoerg rval = sc->ndis_block.nmb_setstat; 63388700Sjoerg } 63488700Sjoerg 63588700Sjoerg if (byteswritten) 63688700Sjoerg *buflen = byteswritten; 63788700Sjoerg if (bytesneeded) 63888700Sjoerg *buflen = bytesneeded; 63988700Sjoerg 64088700Sjoerg if (rval == NDIS_STATUS_INVALID_LENGTH) 64188700Sjoerg return(ENOSPC); 64288534Sjoerg 64388700Sjoerg if (rval == NDIS_STATUS_INVALID_OID) 64488534Sjoerg return(EINVAL); 64588534Sjoerg 64688534Sjoerg if (rval == NDIS_STATUS_NOT_SUPPORTED || 64788599Sjoerg rval == NDIS_STATUS_NOT_ACCEPTED) 64888534Sjoerg return(ENOTSUP); 64978064Sume 65088599Sjoerg return(0); 65188599Sjoerg} 65288599Sjoerg 65388599Sjoergint 65488599Sjoergndis_send_packets(arg, packets, cnt) 65588599Sjoerg void *arg; 65688599Sjoerg ndis_packet **packets; 65788599Sjoerg int cnt; 65888599Sjoerg{ 65988599Sjoerg struct ndis_softc *sc; 66088599Sjoerg ndis_handle adapter; 66188599Sjoerg __stdcall ndis_sendmulti_handler sendfunc; 66288599Sjoerg int i, idx; 66388599Sjoerg struct ifnet *ifp; 66488599Sjoerg struct mbuf *m; 66512495Speter ndis_packet *p; 66612495Speter 66712495Speter sc = arg; 66825944Sjoerg adapter = sc->ndis_block.nmb_miniportadapterctx; 66912495Speter sendfunc = sc->ndis_chars.nmc_sendmulti_func; 67012495Speter sendfunc(adapter, packets, cnt); 67112495Speter 67288577Sjoerg for (i = 0; i < cnt; i++) { 67312495Speter p = packets[i]; 67412495Speter /* 6754910Swollman * Either the driver already handed the packet to 6764910Swollman * ndis_txeof() due to a failure, or it wants to keep 6774910Swollman * it and release it asynchronously later. Skip to the 67825944Sjoerg * next one. 6794910Swollman */ 6804910Swollman if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 6814910Swollman continue; 68288577Sjoerg idx = p->np_txidx; 6834910Swollman m = p->np_m0; 6844910Swollman ifp = &sc->arpcom.ac_if; 6854910Swollman if (sc->ndis_sc) 6864910Swollman bus_dmamap_unload(sc->ndis_ttag, sc->ndis_tmaps[idx]); 6874910Swollman sc->ndis_txarray[idx] = NULL; 6884910Swollman sc->ndis_txpending++; 6894910Swollman m_freem(m); 69045152Sphk ndis_free_packet(p); 69125944Sjoerg if (p->np_oob.npo_status == NDIS_STATUS_SUCCESS) 69225706Sjoerg ifp->if_opackets++; 69340008Sjoerg else 69425706Sjoerg ifp->if_oerrors++; 69540008Sjoerg ifp->if_timer = 0; 69625706Sjoerg ifp->if_flags &= ~IFF_OACTIVE; 69711189Sjkh } 69811189Sjkh 6994910Swollman return(0); 7004910Swollman} 7014910Swollman 7024910Swollmanint 7034910Swollmanndis_init_dma(arg) 7044910Swollman void *arg; 7054910Swollman{ 7064910Swollman struct ndis_softc *sc; 7074910Swollman int i, error; 7084910Swollman 7094910Swollman sc = arg; 7104910Swollman 71188577Sjoerg sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 7124910Swollman M_DEVBUF, M_NOWAIT|M_ZERO); 7134910Swollman 71454263Sshin if (sc->ndis_tmaps == NULL) 71554263Sshin return(ENOMEM); 71654263Sshin 71754263Sshin for (i = 0; i < sc->ndis_maxpkts; i++) { 71888577Sjoerg error = bus_dmamap_create(sc->ndis_ttag, 0, 71954263Sshin &sc->ndis_tmaps[i]); 72054263Sshin if (error) { 72112495Speter free(sc->ndis_tmaps, M_DEVBUF); 72212495Speter return(ENODEV); 72312495Speter } 72412495Speter } 72588577Sjoerg 72612495Speter return(0); 72712495Speter} 7284910Swollman 7294910Swollmanint 7304910Swollmanndis_destroy_dma(arg) 7314910Swollman void *arg; 73288577Sjoerg{ 7334910Swollman struct ndis_softc *sc; 7344910Swollman struct mbuf *m; 7354910Swollman ndis_packet *p = NULL; 7364910Swollman int i; 73725944Sjoerg 73825944Sjoerg sc = arg; 73925944Sjoerg 74025944Sjoerg for (i = 0; i < sc->ndis_maxpkts; i++) { 74140008Sjoerg if (sc->ndis_txarray[i] != NULL) { 74225944Sjoerg p = sc->ndis_txarray[i]; 74340008Sjoerg m = (struct mbuf *)p->np_rsvd[1]; 74425944Sjoerg if (m != NULL) 74525944Sjoerg m_freem(m); 7464910Swollman ndis_free_packet(sc->ndis_txarray[i]); 7474910Swollman } 7484910Swollman bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 7494910Swollman } 7504910Swollman 7514910Swollman free(sc->ndis_tmaps, M_DEVBUF); 75269152Sjlemon 75325944Sjoerg bus_dma_tag_destroy(sc->ndis_ttag); 75440008Sjoerg 75540008Sjoerg return(0); 7564910Swollman} 7574910Swollman 75888577Sjoergint 75988577Sjoergndis_reset_nic(arg) 76088577Sjoerg void *arg; 76188577Sjoerg{ 76288577Sjoerg struct ndis_softc *sc; 76388577Sjoerg ndis_handle adapter; 76488577Sjoerg __stdcall ndis_reset_handler resetfunc; 7654910Swollman uint8_t addressing_reset; 7664910Swollman struct ifnet *ifp; 7674910Swollman 7684910Swollman sc = arg; 7694910Swollman ifp = &sc->arpcom.ac_if; 77012820Sphk adapter = sc->ndis_block.nmb_miniportadapterctx; 77125706Sjoerg if (adapter == NULL) 77225706Sjoerg return(EIO); 7734910Swollman resetfunc = sc->ndis_chars.nmc_reset_func; 7744910Swollman 7754910Swollman if (resetfunc == NULL) 77678064Sume return(EINVAL); 77725955Sjoerg 77888534Sjoerg resetfunc(&addressing_reset, adapter); 77942066Sphk 7804910Swollman return(0); 78125944Sjoerg} 78225944Sjoerg 78325944Sjoergint 78425944Sjoergndis_halt_nic(arg) 78588723Sjoerg void *arg; 78688723Sjoerg{ 78788723Sjoerg struct ndis_softc *sc; 7884910Swollman ndis_handle adapter; 7894910Swollman __stdcall ndis_halt_handler haltfunc; 7904910Swollman struct ifnet *ifp; 7914910Swollman struct ndis_timer_entry *ne; 7924910Swollman 79325944Sjoerg sc = arg; 79488723Sjoerg ifp = &sc->arpcom.ac_if; 79525944Sjoerg adapter = sc->ndis_block.nmb_miniportadapterctx; 79688723Sjoerg if (adapter == NULL) 79788723Sjoerg return(EIO); 79888723Sjoerg 79988723Sjoerg haltfunc = sc->ndis_chars.nmc_halt_func; 80088723Sjoerg 80188723Sjoerg if (haltfunc == NULL) 80288723Sjoerg return(EINVAL); 80388723Sjoerg 80488723Sjoerg haltfunc(adapter); 80588723Sjoerg 80688723Sjoerg /* 80788723Sjoerg * The adapter context is only valid after the init 80825944Sjoerg * handler has been called, and is invalid once the 80925944Sjoerg * halt handler has been called. 81025944Sjoerg */ 81125944Sjoerg 81225944Sjoerg sc->ndis_block.nmb_miniportadapterctx = NULL; 81325944Sjoerg 81425944Sjoerg /* Clobber all the timers in case the driver left one running. */ 81525944Sjoerg 81625944Sjoerg while (!TAILQ_EMPTY(&sc->ndis_block.nmb_timerlist)) { 81778134Sume ne = TAILQ_FIRST(&sc->ndis_block.nmb_timerlist); 8184910Swollman TAILQ_REMOVE(&sc->ndis_block.nmb_timerlist, ne, link); 81912436Speter callout_stop(&ne->nte_ch); 82040008Sjoerg free(ne, M_DEVBUF); 82112436Speter } 82212436Speter 8234910Swollman return(0); 82442104Sphk} 82542104Sphk 82642104Sphkint 82742104Sphkndis_shutdown_nic(arg) 82842104Sphk void *arg; 82942104Sphk{ 83042104Sphk struct ndis_softc *sc; 83142104Sphk ndis_handle adapter; 83242104Sphk __stdcall ndis_shutdown_handler shutdownfunc; 83370199Sjhay 83442104Sphk 83542104Sphk sc = arg; 83642104Sphk adapter = sc->ndis_block.nmb_miniportadapterctx; 83742104Sphk if (adapter == NULL) 83842104Sphk return(EIO); 83942104Sphk shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 84042104Sphk 84142104Sphk if (shutdownfunc == NULL) 84242104Sphk return(EINVAL); 84342104Sphk 84470199Sjhay if (sc->ndis_chars.nmc_rsvd0 == NULL) 84542104Sphk shutdownfunc(adapter); 84642104Sphk else 84742104Sphk shutdownfunc(sc->ndis_chars.nmc_rsvd0); 84842104Sphk 84969152Sjlemon return(0); 85041686Sphk} 85141686Sphk 85212436Speterint 85341686Sphkndis_init_nic(arg) 85441686Sphk void *arg; 85541686Sphk{ 85641686Sphk struct ndis_softc *sc; 85741686Sphk ndis_miniport_block *block; 85841686Sphk __stdcall ndis_init_handler initfunc; 85941686Sphk ndis_status status, openstatus = 0; 86041686Sphk ndis_medium mediumarray[NdisMediumMax]; 86188534Sjoerg uint32_t chosenmedium, i; 86288534Sjoerg 86388534Sjoerg if (arg == NULL) 86488534Sjoerg return(EINVAL); 86588534Sjoerg 86688534Sjoerg sc = arg; 86788599Sjoerg block = &sc->ndis_block; 86888534Sjoerg initfunc = sc->ndis_chars.nmc_init_func; 86988534Sjoerg 87088534Sjoerg TAILQ_INIT(&block->nmb_timerlist); 87188534Sjoerg 87288534Sjoerg for (i = 0; i < NdisMediumMax; i++) 87388534Sjoerg mediumarray[i] = i; 87488534Sjoerg 87588534Sjoerg status = initfunc(&openstatus, &chosenmedium, 87688534Sjoerg mediumarray, NdisMediumMax, block, block); 87788534Sjoerg 87888534Sjoerg /* 87988534Sjoerg * If the init fails, blow away the other exported routines 88088534Sjoerg * we obtained from the driver so we can't call them later. 88188534Sjoerg * If the init failed, none of these will work. 88288534Sjoerg */ 8834910Swollman if (status != NDIS_STATUS_SUCCESS) { 8844910Swollman bzero((char *)&sc->ndis_chars, 8854910Swollman sizeof(ndis_miniport_characteristics)); 88678064Sume return(ENXIO); 88778064Sume } 88878064Sume 88978064Sume return(0); 89078064Sume} 89178064Sume 8924910Swollmanvoid 8934910Swollmanndis_enable_intr(arg) 8944910Swollman void *arg; 8954910Swollman{ 8964910Swollman struct ndis_softc *sc; 89742066Sphk ndis_handle adapter; 89840008Sjoerg __stdcall ndis_enable_interrupts_handler intrenbfunc; 89940008Sjoerg 90025944Sjoerg sc = arg; 9014910Swollman adapter = sc->ndis_block.nmb_miniportadapterctx; 9024910Swollman if (adapter == NULL) 9034910Swollman return; 90440008Sjoerg intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 90540008Sjoerg if (intrenbfunc == NULL) 90640008Sjoerg return; 90740008Sjoerg intrenbfunc(adapter); 9084910Swollman 90945152Sphk return; 91028088Skjc} 9114910Swollman 9124910Swollmanvoid 9134910Swollmanndis_disable_intr(arg) 9144910Swollman void *arg; 9154910Swollman{ 9164910Swollman struct ndis_softc *sc; 9174910Swollman ndis_handle adapter; 9184910Swollman __stdcall ndis_disable_interrupts_handler intrdisfunc; 9194910Swollman 92045152Sphk sc = arg; 92111189Sjkh adapter = sc->ndis_block.nmb_miniportadapterctx; 92211189Sjkh if (adapter == NULL) 92325955Sjoerg return; 92425955Sjoerg intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 92525955Sjoerg if (intrdisfunc == NULL) 92625955Sjoerg return; 92725955Sjoerg intrdisfunc(adapter); 92825955Sjoerg 92925955Sjoerg return; 93025955Sjoerg} 93125955Sjoerg 93288534Sjoergint 93325955Sjoergndis_isr(arg, ourintr, callhandler) 93425955Sjoerg void *arg; 93511189Sjkh int *ourintr; 9364910Swollman int *callhandler; 9374910Swollman{ 93854263Sshin struct ndis_softc *sc; 93954263Sshin ndis_handle adapter; 94054263Sshin __stdcall ndis_isr_handler isrfunc; 94154263Sshin uint8_t accepted, queue; 94254263Sshin 94378064Sume if (arg == NULL || ourintr == NULL || callhandler == NULL) 94478064Sume return(EINVAL); 94578064Sume 94678064Sume sc = arg; 94778064Sume adapter = sc->ndis_block.nmb_miniportadapterctx; 94878064Sume isrfunc = sc->ndis_chars.nmc_isr_func; 94978064Sume isrfunc(&accepted, &queue, adapter); 95078064Sume *ourintr = accepted; 95178064Sume *callhandler = queue; 95278064Sume 95378064Sume return(0); 95478064Sume} 95554263Sshin 95654263Sshinint 95754263Sshinndis_intrhand(arg) 9584910Swollman void *arg; 9594910Swollman{ 96045152Sphk struct ndis_softc *sc; 9614910Swollman ndis_handle adapter; 9624910Swollman __stdcall ndis_interrupt_handler intrfunc; 9634910Swollman 96411819Sjulian if (arg == NULL) 96512495Speter return(EINVAL); 96645152Sphk 96712495Speter sc = arg; 96811819Sjulian adapter = sc->ndis_block.nmb_miniportadapterctx; 96911819Sjulian intrfunc = sc->ndis_chars.nmc_interrupt_func; 9704910Swollman intrfunc(adapter); 9714910Swollman 97225944Sjoerg return(0); 9734910Swollman} 9744910Swollman 9754910Swollmanint 9764910Swollmanndis_get_info(arg, oid, buf, buflen) 9774910Swollman void *arg; 9784910Swollman ndis_oid oid; 97988577Sjoerg void *buf; 9804910Swollman int *buflen; 98169152Sjlemon{ 98225944Sjoerg struct ndis_softc *sc; 98325955Sjoerg ndis_status rval; 9844910Swollman ndis_handle adapter; 98588577Sjoerg __stdcall ndis_queryinfo_handler queryfunc; 98688577Sjoerg uint32_t byteswritten = 0, bytesneeded = 0; 98788577Sjoerg struct timeval tv; 98888577Sjoerg int error; 98988577Sjoerg 99088577Sjoerg sc = arg; 99188577Sjoerg queryfunc = sc->ndis_chars.nmc_queryinfo_func; 9924910Swollman adapter = sc->ndis_block.nmb_miniportadapterctx; 9934910Swollman 9944910Swollman rval = queryfunc(adapter, oid, buf, *buflen, 99525706Sjoerg &byteswritten, &bytesneeded); 99625706Sjoerg 9974910Swollman /* Wait for requests that block. */ 9984910Swollman 9994910Swollman if (rval == NDIS_STATUS_PENDING) { 10004910Swollman tv.tv_sec = 60; 10014910Swollman tv.tv_usec = 0; 100242064Sphk error = tsleep(&sc->ndis_block.nmb_wkupdpctimer, 10034910Swollman PPAUSE|PCATCH, "ndisget", tvtohz(&tv)); 10044910Swollman rval = sc->ndis_block.nmb_getstat; 10054910Swollman } 10064910Swollman 10074910Swollman if (byteswritten) 100842064Sphk *buflen = byteswritten; 100942064Sphk if (bytesneeded) 10104910Swollman *buflen = bytesneeded; 10114910Swollman 101242104Sphk if (rval == NDIS_STATUS_INVALID_LENGTH || 101342064Sphk rval == NDIS_STATUS_BUFFER_TOO_SHORT) 101442104Sphk return(ENOSPC); 101570199Sjhay 101670199Sjhay if (rval == NDIS_STATUS_INVALID_OID) 101770199Sjhay return(EINVAL); 10184910Swollman 10194910Swollman if (rval == NDIS_STATUS_NOT_SUPPORTED || 102078064Sume rval == NDIS_STATUS_NOT_ACCEPTED) 102178064Sume return(ENOTSUP); 102225944Sjoerg 102325944Sjoerg return(0); 102425944Sjoerg} 102588716Sjoerg 102693818Sjhbint 102788716Sjoergndis_unload_driver(arg) 102893818Sjhb void *arg; 102988599Sjoerg{ 103088723Sjoerg struct ndis_softc *sc; 103188723Sjoerg 103288723Sjoerg sc = arg; 103388723Sjoerg 103488723Sjoerg free(sc->ndis_block.nmb_rlist, M_DEVBUF); 103588723Sjoerg 103688723Sjoerg ndis_flush_sysctls(sc); 103788599Sjoerg ndis_libfini(); 103888599Sjoerg ntoskrnl_libfini(); 103925944Sjoerg 104025944Sjoerg return(0); 104178064Sume} 104230300Sjoerg 104330300Sjoergint 10444910Swollmanndis_load_driver(img, arg) 10454910Swollman vm_offset_t img; 104630300Sjoerg void *arg; 104725706Sjoerg{ 10484910Swollman __stdcall driver_entry entry; 10494910Swollman image_optional_header opt_hdr; 105025944Sjoerg image_import_descriptor imp_desc; 10514910Swollman ndis_unicode_string dummystr; 10524910Swollman ndis_driver_object drv; 10534910Swollman ndis_miniport_block *block; 10544910Swollman ndis_status status; 10554910Swollman int idx; 10564910Swollman uint32_t *ptr; 10574910Swollman struct ndis_softc *sc; 10584910Swollman 10594910Swollman sc = arg; 10604910Swollman 106140008Sjoerg /* Perform text relocation */ 106225944Sjoerg if (pe_relocate(img)) 106325944Sjoerg return(ENOEXEC); 106440008Sjoerg 106540008Sjoerg /* Dynamically link the NDIS.SYS routines -- required. */ 106669152Sjlemon if (pe_patch_imports(img, "NDIS", ndis_functbl)) 106769152Sjlemon return(ENOEXEC); 10684910Swollman 10694910Swollman /* Dynamically link the HAL.dll routines -- also required. */ 10704910Swollman if (pe_patch_imports(img, "HAL", hal_functbl)) 10714910Swollman return(ENOEXEC); 10724910Swollman 107325706Sjoerg /* Dynamically link ntoskrnl.exe -- optional. */ 107425706Sjoerg if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) { 10754910Swollman if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl)) 10764910Swollman return(ENOEXEC); 10774910Swollman } 107825944Sjoerg 107925944Sjoerg /* Initialize subsystems */ 108026018Sjoerg ndis_libinit(); 10814910Swollman ntoskrnl_libinit(); 10824910Swollman 10834910Swollman /* Locate the driver entry point */ 108411189Sjkh pe_get_optional_header(img, &opt_hdr); 108511189Sjkh entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 108612820Sphk 108725706Sjoerg /* 108811189Sjkh * Now call the DriverEntry() routine. This will cause 108911189Sjkh * a callout to the NdisInitializeWrapper() and 109025944Sjoerg * NdisMRegisterMiniport() routines. 109111189Sjkh */ 109225944Sjoerg dummystr.nus_len = strlen(NDIS_DUMMY_PATH); 109326018Sjoerg dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH); 109426018Sjoerg dummystr.nus_buf = NULL; 109525944Sjoerg ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 109611189Sjkh drv.ndo_ifname = "ndis0"; 109711189Sjkh 109811189Sjkh status = entry(&drv, &dummystr); 109911189Sjkh 11004910Swollman free (dummystr.nus_buf, M_DEVBUF); 11014910Swollman 110225706Sjoerg if (status != NDIS_STATUS_SUCCESS) 110325706Sjoerg return(ENODEV); 11044910Swollman 11054910Swollman /* 11064910Swollman * Now that we have the miniport driver characteristics, 110725944Sjoerg * create an NDIS block and call the init handler. 11084910Swollman * This will cause the driver to try to probe for 110925944Sjoerg * a device. 111026018Sjoerg */ 111130300Sjoerg 111230300Sjoerg block = &sc->ndis_block; 111326018Sjoerg bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars, 111426018Sjoerg sizeof(ndis_miniport_characteristics)); 111526018Sjoerg 111626018Sjoerg /*block->nmb_signature = 0xcafebabe;*/ 111726018Sjoerg 111845152Sphk ptr = (uint32_t *)block; 111926018Sjoerg for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 112026018Sjoerg *ptr = idx | 0xdead0000; 112126018Sjoerg ptr++; 112226018Sjoerg } 112326018Sjoerg 112426018Sjoerg block->nmb_signature = (void *)0xcafebabe; 11254910Swollman block->nmb_setdone_func = ndis_setdone_func; 11264910Swollman block->nmb_querydone_func = ndis_getdone_func; 11274910Swollman block->nmb_status_func = ndis_status_func; 112830300Sjoerg block->nmb_statusdone_func = ndis_statusdone_func; 112930300Sjoerg block->nmb_resetdone_func = ndis_resetdone_func; 113030300Sjoerg 113130300Sjoerg block->nmb_ifp = &sc->arpcom.ac_if; 113230300Sjoerg block->nmb_dev = sc->ndis_dev; 113330300Sjoerg 113430300Sjoerg return(0); 113530300Sjoerg} 113630300Sjoerg