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