kern_ndis.c revision 123695
1123474Swpaul/*
2123474Swpaul * Copyright (c) 2003
3123474Swpaul *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4123474Swpaul *
5123474Swpaul * Redistribution and use in source and binary forms, with or without
6123474Swpaul * modification, are permitted provided that the following conditions
7123474Swpaul * are met:
8123474Swpaul * 1. Redistributions of source code must retain the above copyright
9123474Swpaul *    notice, this list of conditions and the following disclaimer.
10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright
11123474Swpaul *    notice, this list of conditions and the following disclaimer in the
12123474Swpaul *    documentation and/or other materials provided with the distribution.
13123474Swpaul * 3. All advertising materials mentioning features or use of this software
14123474Swpaul *    must display the following acknowledgement:
15123474Swpaul *	This product includes software developed by Bill Paul.
16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors
17123474Swpaul *    may be used to endorse or promote products derived from this software
18123474Swpaul *    without specific prior written permission.
19123474Swpaul *
20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23123474Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
31123474Swpaul */
32123474Swpaul
33123474Swpaul#include <sys/cdefs.h>
34123474Swpaul__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 123695 2003-12-21 00:00:08Z wpaul $");
35123474Swpaul
36123474Swpaul#include <sys/param.h>
37123474Swpaul#include <sys/types.h>
38123474Swpaul#include <sys/errno.h>
39123474Swpaul#include <sys/callout.h>
40123474Swpaul#include <sys/socket.h>
41123474Swpaul#include <sys/queue.h>
42123474Swpaul#include <sys/sysctl.h>
43123474Swpaul#include <sys/systm.h>
44123474Swpaul#include <sys/malloc.h>
45123474Swpaul#include <sys/lock.h>
46123474Swpaul#include <sys/mutex.h>
47123474Swpaul#include <sys/conf.h>
48123474Swpaul
49123474Swpaul#include <sys/kernel.h>
50123474Swpaul#include <machine/bus.h>
51123474Swpaul#include <machine/resource.h>
52123474Swpaul#include <sys/bus.h>
53123474Swpaul#include <sys/rman.h>
54123474Swpaul
55123474Swpaul#include <net/if.h>
56123474Swpaul#include <net/if_arp.h>
57123474Swpaul#include <net/ethernet.h>
58123474Swpaul#include <net/if_dl.h>
59123474Swpaul#include <net/if_media.h>
60123474Swpaul
61123695Swpaul#include <net80211/ieee80211_var.h>
62123695Swpaul#include <net80211/ieee80211_ioctl.h>
63123695Swpaul
64123474Swpaul#include <dev/pccard/pccardvar.h>
65123474Swpaul#include "card_if.h"
66123474Swpaul
67123474Swpaul#include <compat/ndis/pe_var.h>
68123474Swpaul#include <compat/ndis/resource_var.h>
69123474Swpaul#include <compat/ndis/ndis_var.h>
70123474Swpaul#include <compat/ndis/hal_var.h>
71123474Swpaul#include <compat/ndis/ntoskrnl_var.h>
72123474Swpaul#include <compat/ndis/cfg_var.h>
73123474Swpaul#include <dev/if_ndis/if_ndisvar.h>
74123474Swpaul
75123474Swpaul#define __stdcall __attribute__((__stdcall__))
76123474Swpaul#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
77123474Swpaul
78123474Swpaul__stdcall static void ndis_status_func(ndis_handle, ndis_status,
79123474Swpaul	void *, uint32_t);
80123474Swpaul__stdcall static void ndis_statusdone_func(ndis_handle);
81123474Swpaul__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
82123535Swpaul__stdcall static void ndis_getdone_func(ndis_handle, ndis_status);
83123474Swpaul__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
84123474Swpaul
85123474Swpaul/*
86123474Swpaul * This allows us to export our symbols to other modules.
87123474Swpaul * Note that we call ourselves 'ndisapi' to avoid a namespace
88123474Swpaul * collision with if_ndis.ko, which internally calls itself
89123474Swpaul * 'ndis.'
90123474Swpaul */
91123474Swpaulstatic int
92123474Swpaulndis_modevent(module_t mod, int cmd, void *arg)
93123474Swpaul{
94123474Swpaul	return(0);
95123474Swpaul}
96123474SwpaulDEV_MODULE(ndisapi, ndis_modevent, NULL);
97123474SwpaulMODULE_VERSION(ndisapi, 1);
98123474Swpaul
99123474Swpaul
100123474Swpaul__stdcall static void
101123474Swpaulndis_status_func(adapter, status, sbuf, slen)
102123474Swpaul	ndis_handle		adapter;
103123474Swpaul	ndis_status		status;
104123474Swpaul	void			*sbuf;
105123474Swpaul	uint32_t		slen;
106123474Swpaul{
107123474Swpaul	printf ("status: %x\n", status);
108123474Swpaul	return;
109123474Swpaul}
110123474Swpaul
111123474Swpaul__stdcall static void
112123474Swpaulndis_statusdone_func(adapter)
113123474Swpaul	ndis_handle		adapter;
114123474Swpaul{
115123474Swpaul	printf ("status complete\n");
116123474Swpaul	return;
117123474Swpaul}
118123474Swpaul
119123474Swpaul__stdcall static void
120123474Swpaulndis_setdone_func(adapter, status)
121123474Swpaul	ndis_handle		adapter;
122123474Swpaul	ndis_status		status;
123123474Swpaul{
124123695Swpaul	ndis_miniport_block	*block;
125123695Swpaul	block = adapter;
126123695Swpaul
127123695Swpaul	block->nmb_setstat = status;
128123695Swpaul	wakeup(&block->nmb_wkupdpctimer);
129123474Swpaul	return;
130123474Swpaul}
131123474Swpaul
132123474Swpaul__stdcall static void
133123535Swpaulndis_getdone_func(adapter, status)
134123535Swpaul	ndis_handle		adapter;
135123535Swpaul	ndis_status		status;
136123535Swpaul{
137123695Swpaul	ndis_miniport_block	*block;
138123695Swpaul	block = adapter;
139123695Swpaul
140123695Swpaul	block->nmb_getstat = status;
141123695Swpaul	wakeup(&block->nmb_wkupdpctimer);
142123535Swpaul	return;
143123535Swpaul}
144123535Swpaul
145123535Swpaul__stdcall static void
146123474Swpaulndis_resetdone_func(adapter, status, addressingreset)
147123474Swpaul	ndis_handle		adapter;
148123474Swpaul	ndis_status		status;
149123474Swpaul	uint8_t			addressingreset;
150123474Swpaul{
151123474Swpaul	printf ("reset done...\n");
152123474Swpaul	return;
153123474Swpaul}
154123474Swpaul
155123474Swpaul#define NDIS_AM_RID	3
156123474Swpaul
157123474Swpaulint
158123474Swpaulndis_alloc_amem(arg)
159123474Swpaul	void			*arg;
160123474Swpaul{
161123474Swpaul	struct ndis_softc	*sc;
162123474Swpaul	int			error, rid;
163123474Swpaul
164123474Swpaul	if (arg == NULL)
165123474Swpaul		return(EINVAL);
166123474Swpaul
167123474Swpaul	sc = arg;
168123474Swpaul	rid = NDIS_AM_RID;
169123474Swpaul	sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
170123474Swpaul	    &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
171123474Swpaul
172123474Swpaul	if (sc->ndis_res_am == NULL) {
173123474Swpaul		printf("ndis%d: failed to allocate attribute memory\n",
174123474Swpaul		    sc->ndis_unit);
175123474Swpaul		return(ENXIO);
176123474Swpaul	}
177123474Swpaul
178123474Swpaul	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
179123474Swpaul	    sc->ndis_dev, rid, 0, NULL);
180123474Swpaul
181123474Swpaul	if (error) {
182123474Swpaul		printf("ndis%d: CARD_SET_MEMORY_OFFSET() returned 0x%x\n",
183123474Swpaul		    sc->ndis_unit, error);
184123474Swpaul		return(error);
185123474Swpaul	}
186123474Swpaul
187123474Swpaul	error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
188123474Swpaul	    sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
189123474Swpaul
190123474Swpaul	if (error) {
191123474Swpaul		printf("ndis%d: CARD_SET_RES_FLAGS() returned 0x%x\n",
192123474Swpaul		    sc->ndis_unit, error);
193123474Swpaul		return(error);
194123474Swpaul	}
195123474Swpaul
196123474Swpaul	return(0);
197123474Swpaul}
198123474Swpaul
199123474Swpaulint
200123474Swpaulndis_create_sysctls(arg)
201123474Swpaul	void			*arg;
202123474Swpaul{
203123474Swpaul	struct ndis_softc	*sc;
204123474Swpaul	ndis_cfg		*vals;
205123474Swpaul	char			buf[256];
206123474Swpaul
207123474Swpaul	if (arg == NULL)
208123474Swpaul		return(EINVAL);
209123474Swpaul
210123474Swpaul	sc = arg;
211123474Swpaul	vals = sc->ndis_regvals;
212123474Swpaul
213123474Swpaul	TAILQ_INIT(&sc->ndis_cfglist_head);
214123474Swpaul
215123474Swpaul	/* Create the sysctl tree. */
216123474Swpaul
217123474Swpaul	sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
218123474Swpaul	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
219123474Swpaul	    device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
220123474Swpaul	    device_get_desc(sc->ndis_dev));
221123474Swpaul
222123474Swpaul	/* Add the driver-specific registry keys. */
223123474Swpaul
224123474Swpaul	vals = sc->ndis_regvals;
225123474Swpaul	while(1) {
226123474Swpaul		if (vals->nc_cfgkey == NULL)
227123474Swpaul			break;
228123620Swpaul		if (vals->nc_idx != sc->ndis_devidx) {
229123620Swpaul			vals++;
230123620Swpaul			continue;
231123620Swpaul		}
232123474Swpaul		SYSCTL_ADD_STRING(&sc->ndis_ctx,
233123474Swpaul		    SYSCTL_CHILDREN(sc->ndis_tree),
234123474Swpaul		    OID_AUTO, vals->nc_cfgkey,
235123474Swpaul		    CTLFLAG_RW, vals->nc_val,
236123474Swpaul		    sizeof(vals->nc_val),
237123474Swpaul		    vals->nc_cfgdesc);
238123474Swpaul		vals++;
239123474Swpaul	}
240123474Swpaul
241123474Swpaul	/* Now add a couple of builtin keys. */
242123474Swpaul
243123474Swpaul	/*
244123474Swpaul	 * Environment can be either Windows (0) or WindowsNT (1).
245123474Swpaul	 * We qualify as the latter.
246123474Swpaul	 */
247123474Swpaul	ndis_add_sysctl(sc, "Environment",
248123474Swpaul	    "Windows environment", "1", CTLFLAG_RD);
249123474Swpaul
250123474Swpaul	/* NDIS version should be 5.1. */
251123474Swpaul	ndis_add_sysctl(sc, "NdisVersion",
252123474Swpaul	    "NDIS API Version", "0x00050001", CTLFLAG_RD);
253123474Swpaul
254123474Swpaul	/* Bus type (PCI, PCMCIA, etc...) */
255123474Swpaul	sprintf(buf, "%d\n", (int)sc->ndis_iftype);
256123474Swpaul	ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
257123474Swpaul
258123474Swpaul	if (sc->ndis_res_io != NULL) {
259123474Swpaul		sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io));
260123474Swpaul		ndis_add_sysctl(sc, "IOBaseAddress",
261123474Swpaul		    "Base I/O Address", buf, CTLFLAG_RD);
262123474Swpaul	}
263123474Swpaul
264123474Swpaul	if (sc->ndis_irq != NULL) {
265123474Swpaul		sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq));
266123474Swpaul		ndis_add_sysctl(sc, "InterruptNumber",
267123474Swpaul		    "Interrupt Number", buf, CTLFLAG_RD);
268123474Swpaul	}
269123474Swpaul
270123474Swpaul	return(0);
271123474Swpaul}
272123474Swpaul
273123474Swpaulint
274123474Swpaulndis_add_sysctl(arg, key, desc, val, flag)
275123474Swpaul	void			*arg;
276123474Swpaul	char			*key;
277123474Swpaul	char			*desc;
278123474Swpaul	char			*val;
279123474Swpaul	int			flag;
280123474Swpaul{
281123474Swpaul	struct ndis_softc	*sc;
282123474Swpaul	struct ndis_cfglist	*cfg;
283123474Swpaul	char			descstr[256];
284123474Swpaul
285123474Swpaul	sc = arg;
286123474Swpaul
287123474Swpaul	cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
288123474Swpaul
289123474Swpaul	if (cfg == NULL)
290123474Swpaul		return(ENOMEM);
291123474Swpaul
292123474Swpaul	cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
293123474Swpaul	if (desc == NULL) {
294123474Swpaul		snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
295123474Swpaul		cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
296123474Swpaul	} else
297123474Swpaul		cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
298123474Swpaul	strcpy(cfg->ndis_cfg.nc_val, val);
299123474Swpaul
300123474Swpaul	TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
301123474Swpaul
302123474Swpaul	SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
303123474Swpaul	    OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
304123474Swpaul	    cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
305123474Swpaul	    cfg->ndis_cfg.nc_cfgdesc);
306123474Swpaul
307123474Swpaul	return(0);
308123474Swpaul}
309123474Swpaul
310123474Swpaulint
311123474Swpaulndis_flush_sysctls(arg)
312123474Swpaul	void			*arg;
313123474Swpaul{
314123474Swpaul	struct ndis_softc	*sc;
315123474Swpaul	struct ndis_cfglist	*cfg;
316123474Swpaul
317123474Swpaul	sc = arg;
318123474Swpaul
319123474Swpaul	while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
320123474Swpaul		cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
321123474Swpaul		TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
322123474Swpaul		free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
323123474Swpaul		free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
324123474Swpaul		free(cfg, M_DEVBUF);
325123474Swpaul	}
326123474Swpaul
327123474Swpaul	return(0);
328123474Swpaul}
329123474Swpaul
330123474Swpaulvoid
331123474Swpaulndis_return_packet(packet, arg)
332123474Swpaul	void			*packet;
333123474Swpaul	void			*arg;
334123474Swpaul{
335123474Swpaul	struct ndis_softc	*sc;
336123474Swpaul	ndis_handle		adapter;
337123535Swpaul	ndis_packet		*p;
338123474Swpaul	__stdcall ndis_return_handler	returnfunc;
339123474Swpaul
340123474Swpaul	if (arg == NULL || packet == NULL)
341123474Swpaul		return;
342123474Swpaul
343123535Swpaul	p = packet;
344123535Swpaul
345123535Swpaul	/* Decrement refcount. */
346123535Swpaul	p->np_private.npp_count--;
347123535Swpaul
348123535Swpaul	/* Release packet when refcount hits zero, otherwise return. */
349123535Swpaul	if (p->np_private.npp_count)
350123535Swpaul		return;
351123536Swpaul
352123474Swpaul	sc = arg;
353123474Swpaul	returnfunc = sc->ndis_chars.nmc_return_packet_func;
354123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
355123474Swpaul	if (returnfunc == NULL)
356123474Swpaul		ndis_free_packet((ndis_packet *)packet);
357123474Swpaul	else
358123474Swpaul		returnfunc(adapter, (ndis_packet *)packet);
359123474Swpaul	return;
360123474Swpaul}
361123474Swpaul
362123474Swpaulvoid
363123474Swpaulndis_free_bufs(b0)
364123474Swpaul	ndis_buffer		*b0;
365123474Swpaul{
366123474Swpaul	ndis_buffer		*next;
367123474Swpaul
368123474Swpaul	if (b0 == NULL)
369123474Swpaul		return;
370123474Swpaul
371123474Swpaul	while(b0 != NULL) {
372123474Swpaul		next = b0->nb_next;
373123474Swpaul		free (b0, M_DEVBUF);
374123474Swpaul		b0 = next;
375123474Swpaul	}
376123474Swpaul
377123474Swpaul	return;
378123474Swpaul}
379123474Swpaul
380123474Swpaulvoid
381123474Swpaulndis_free_packet(p)
382123474Swpaul	ndis_packet		*p;
383123474Swpaul{
384123474Swpaul	if (p == NULL)
385123474Swpaul		return;
386123474Swpaul
387123474Swpaul	ndis_free_bufs(p->np_private.npp_head);
388123474Swpaul	free(p, M_DEVBUF);
389123474Swpaul
390123474Swpaul	return;
391123474Swpaul}
392123474Swpaul
393123474Swpaulint
394123474Swpaulndis_convert_res(arg)
395123474Swpaul	void			*arg;
396123474Swpaul{
397123474Swpaul	struct ndis_softc	*sc;
398123474Swpaul	ndis_resource_list	*rl = NULL;
399123474Swpaul	cm_partial_resource_desc	*prd = NULL;
400123474Swpaul	ndis_miniport_block	*block;
401123474Swpaul
402123474Swpaul	sc = arg;
403123474Swpaul	block = &sc->ndis_block;
404123474Swpaul
405123474Swpaul	rl = malloc(sizeof(ndis_resource_list) +
406123474Swpaul	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
407123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
408123474Swpaul
409123474Swpaul	if (rl == NULL)
410123474Swpaul		return(ENOMEM);
411123474Swpaul
412123474Swpaul	rl->cprl_version = 5;
413123474Swpaul	rl->cprl_version = 1;
414123474Swpaul	rl->cprl_count = sc->ndis_rescnt;
415123474Swpaul
416123474Swpaul	prd = rl->cprl_partial_descs;
417123474Swpaul	if (sc->ndis_res_io) {
418123474Swpaul		prd->cprd_type = CmResourceTypePort;
419123474Swpaul		prd->u.cprd_port.cprd_start.np_quad =
420123474Swpaul		    rman_get_start(sc->ndis_res_io);
421123474Swpaul		prd->u.cprd_port.cprd_len =
422123474Swpaul		    rman_get_size(sc->ndis_res_io);
423123474Swpaul		prd++;
424123474Swpaul	}
425123474Swpaul
426123474Swpaul	if (sc->ndis_res_mem) {
427123474Swpaul		prd->cprd_type = CmResourceTypeMemory;
428123474Swpaul		prd->u.cprd_mem.cprd_start.np_quad =
429123474Swpaul		    rman_get_start(sc->ndis_res_mem);
430123474Swpaul		prd->u.cprd_mem.cprd_len =
431123474Swpaul		    rman_get_size(sc->ndis_res_mem);
432123474Swpaul		prd++;
433123474Swpaul	}
434123474Swpaul
435123474Swpaul	if (sc->ndis_irq) {
436123474Swpaul		prd->cprd_type = CmResourceTypeInterrupt;
437123474Swpaul		prd->u.cprd_intr.cprd_level =
438123474Swpaul		    rman_get_start(sc->ndis_irq);
439123474Swpaul		prd->u.cprd_intr.cprd_vector =
440123474Swpaul		    rman_get_start(sc->ndis_irq);
441123474Swpaul		prd->u.cprd_intr.cprd_affinity = 0;
442123474Swpaul	}
443123474Swpaul
444123474Swpaul	block->nmb_rlist = rl;
445123474Swpaul
446123474Swpaul	return(0);
447123474Swpaul}
448123474Swpaul
449123474Swpaul/*
450123474Swpaul * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
451123474Swpaul * packet, it will hand it to us in the form of an ndis_packet,
452123474Swpaul * which we need to convert to an mbuf that is then handed off
453123474Swpaul * to the stack. Note: we configure the mbuf list so that it uses
454123474Swpaul * the memory regions specified by the ndis_buffer structures in
455123474Swpaul * the ndis_packet as external storage. In most cases, this will
456123474Swpaul * point to a memory region allocated by the driver (either by
457123474Swpaul * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
458123474Swpaul * the driver to handle free()ing this region for is, so we set up
459123474Swpaul * a dummy no-op free handler for it.
460123474Swpaul */
461123474Swpaul
462123474Swpaulint
463123474Swpaulndis_ptom(m0, p)
464123474Swpaul	struct mbuf		**m0;
465123474Swpaul	ndis_packet		*p;
466123474Swpaul{
467123474Swpaul	struct mbuf		*m, *prev = NULL;
468123474Swpaul	ndis_buffer		*buf;
469123474Swpaul	ndis_packet_private	*priv;
470123474Swpaul	uint32_t		totlen = 0;
471123474Swpaul
472123474Swpaul	if (p == NULL || m0 == NULL)
473123474Swpaul		return(EINVAL);
474123474Swpaul
475123474Swpaul	priv = &p->np_private;
476123474Swpaul	buf = priv->npp_head;
477123535Swpaul	priv->npp_count = 0;
478123474Swpaul
479123474Swpaul	for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
480123474Swpaul		if (buf == priv->npp_head)
481123474Swpaul			MGETHDR(m, M_DONTWAIT, MT_HEADER);
482123474Swpaul		else
483123474Swpaul			MGET(m, M_DONTWAIT, MT_DATA);
484123474Swpaul		if (m == NULL) {
485123474Swpaul			m_freem(*m0);
486123474Swpaul			*m0 = NULL;
487123474Swpaul			return(ENOBUFS);
488123474Swpaul		}
489123488Swpaul		if (buf->nb_bytecount > buf->nb_size)
490123474Swpaul			m->m_len = buf->nb_size;
491123474Swpaul		else
492123474Swpaul			m->m_len = buf->nb_bytecount;
493123474Swpaul		m->m_data = buf->nb_mappedsystemva;
494123535Swpaul		MEXTADD(m, m->m_data, m->m_len, ndis_return_packet,
495123535Swpaul		    p->np_rsvd[0], 0, EXT_NDIS);
496123535Swpaul		m->m_ext.ext_buf = (void *)p; /* XXX */
497123535Swpaul		priv->npp_count++;
498123474Swpaul		totlen += m->m_len;
499123474Swpaul		if (m->m_flags & MT_HEADER)
500123474Swpaul			*m0 = m;
501123474Swpaul		else
502123474Swpaul			prev->m_next = m;
503123474Swpaul		prev = m;
504123474Swpaul	}
505123474Swpaul
506123474Swpaul	(*m0)->m_pkthdr.len = totlen;
507123474Swpaul
508123474Swpaul	return(0);
509123474Swpaul}
510123474Swpaul
511123474Swpaul/*
512123474Swpaul * Create an mbuf chain from an NDIS packet chain.
513123474Swpaul * This is used mainly when transmitting packets, where we need
514123474Swpaul * to turn an mbuf off an interface's send queue and transform it
515123474Swpaul * into an NDIS packet which will be fed into the NDIS driver's
516123474Swpaul * send routine.
517123474Swpaul *
518123474Swpaul * NDIS packets consist of two parts: an ndis_packet structure,
519123474Swpaul * which is vaguely analagous to the pkthdr portion of an mbuf,
520123474Swpaul * and one or more ndis_buffer structures, which define the
521123474Swpaul * actual memory segments in which the packet data resides.
522123474Swpaul * We need to allocate one ndis_buffer for each mbuf in a chain,
523123474Swpaul * plus one ndis_packet as the header.
524123474Swpaul */
525123474Swpaul
526123474Swpaulint
527123474Swpaulndis_mtop(m0, p)
528123474Swpaul	struct mbuf		*m0;
529123474Swpaul	ndis_packet		**p;
530123474Swpaul{
531123474Swpaul	struct mbuf		*m;
532123474Swpaul	ndis_buffer		*buf = NULL, *prev = NULL;
533123474Swpaul	ndis_packet_private	*priv;
534123474Swpaul
535123474Swpaul	if (p == NULL || m0 == NULL)
536123474Swpaul		return(EINVAL);
537123474Swpaul
538123474Swpaul	/* If caller didn't supply a packet, make one. */
539123474Swpaul	if (*p == NULL) {
540123474Swpaul		*p = malloc(sizeof(ndis_packet), M_DEVBUF, M_NOWAIT|M_ZERO);
541123474Swpaul
542123474Swpaul		if (*p == NULL)
543123474Swpaul			return(ENOMEM);
544123474Swpaul	}
545123474Swpaul
546123474Swpaul	priv = &(*p)->np_private;
547123474Swpaul	priv->npp_totlen = m0->m_pkthdr.len;
548123474Swpaul        priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
549123474Swpaul
550123474Swpaul	for (m = m0; m != NULL; m = m->m_next) {
551123474Swpaul		if (m->m_len == NULL)
552123474Swpaul			continue;
553123474Swpaul		buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO);
554123474Swpaul		if (buf == NULL) {
555123474Swpaul			ndis_free_packet(*p);
556123474Swpaul			*p = NULL;
557123474Swpaul			return(ENOMEM);
558123474Swpaul		}
559123474Swpaul
560123474Swpaul		buf->nb_bytecount = m->m_len;
561123474Swpaul		buf->nb_mappedsystemva = m->m_data;
562123474Swpaul		if (priv->npp_head == NULL)
563123474Swpaul			priv->npp_head = buf;
564123474Swpaul		else
565123474Swpaul			prev->nb_next = buf;
566123474Swpaul		prev = buf;
567123474Swpaul	}
568123474Swpaul
569123474Swpaul	priv->npp_tail = buf;
570123474Swpaul
571123474Swpaul	return(0);
572123474Swpaul}
573123474Swpaul
574123474Swpaulint
575123474Swpaulndis_get_supported_oids(arg, oids, oidcnt)
576123474Swpaul	void			*arg;
577123474Swpaul	ndis_oid		**oids;
578123474Swpaul	int			*oidcnt;
579123474Swpaul{
580123474Swpaul	int			len, rval;
581123474Swpaul	ndis_oid		*o;
582123474Swpaul
583123474Swpaul	if (arg == NULL || oids == NULL || oidcnt == NULL)
584123474Swpaul		return(EINVAL);
585123474Swpaul	len = 0;
586123474Swpaul	ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
587123474Swpaul
588123474Swpaul	o = malloc(len, M_DEVBUF, M_NOWAIT);
589123474Swpaul	if (o == NULL)
590123474Swpaul		return(ENOMEM);
591123474Swpaul
592123474Swpaul	rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
593123474Swpaul
594123474Swpaul	if (rval) {
595123474Swpaul		free(o, M_DEVBUF);
596123474Swpaul		return(rval);
597123474Swpaul	}
598123474Swpaul
599123474Swpaul	*oids = o;
600123474Swpaul	*oidcnt = len / 4;
601123474Swpaul
602123474Swpaul	return(0);
603123474Swpaul}
604123474Swpaul
605123474Swpaulint
606123474Swpaulndis_set_info(arg, oid, buf, buflen)
607123474Swpaul	void			*arg;
608123474Swpaul	ndis_oid		oid;
609123474Swpaul	void			*buf;
610123474Swpaul	int			*buflen;
611123474Swpaul{
612123474Swpaul	struct ndis_softc	*sc;
613123474Swpaul	ndis_status		rval;
614123474Swpaul	ndis_handle		adapter;
615123474Swpaul	__stdcall ndis_setinfo_handler	setfunc;
616123474Swpaul	uint32_t		byteswritten = 0, bytesneeded = 0;
617123695Swpaul	struct timeval		tv;
618123695Swpaul	int			error;
619123474Swpaul
620123474Swpaul	sc = arg;
621123474Swpaul	setfunc = sc->ndis_chars.nmc_setinfo_func;
622123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
623123474Swpaul
624123474Swpaul	rval = setfunc(adapter, oid, buf, *buflen,
625123474Swpaul	    &byteswritten, &bytesneeded);
626123474Swpaul
627123695Swpaul	if (rval == NDIS_STATUS_PENDING) {
628123695Swpaul		tv.tv_sec = 60;
629123695Swpaul		tv.tv_usec = 0;
630123695Swpaul		error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
631123695Swpaul		    PPAUSE|PCATCH, "ndis", tvtohz(&tv));
632123695Swpaul		rval = sc->ndis_block.nmb_setstat;
633123695Swpaul	}
634123695Swpaul
635123474Swpaul	if (byteswritten)
636123474Swpaul		*buflen = byteswritten;
637123474Swpaul	if (bytesneeded)
638123474Swpaul		*buflen = bytesneeded;
639123474Swpaul
640123474Swpaul	if (rval == NDIS_STATUS_INVALID_LENGTH)
641123474Swpaul		return(ENOSPC);
642123474Swpaul
643123474Swpaul	if (rval == NDIS_STATUS_INVALID_OID)
644123474Swpaul		return(EINVAL);
645123474Swpaul
646123474Swpaul	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
647123474Swpaul	    rval == NDIS_STATUS_NOT_ACCEPTED)
648123474Swpaul		return(ENOTSUP);
649123474Swpaul
650123474Swpaul	return(0);
651123474Swpaul}
652123474Swpaul
653123474Swpaulint
654123474Swpaulndis_send_packets(arg, packets, cnt)
655123474Swpaul	void			*arg;
656123474Swpaul	ndis_packet		**packets;
657123474Swpaul	int			cnt;
658123474Swpaul{
659123474Swpaul	struct ndis_softc	*sc;
660123474Swpaul	ndis_handle		adapter;
661123474Swpaul	__stdcall ndis_sendmulti_handler	sendfunc;
662123474Swpaul
663123474Swpaul	sc = arg;
664123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
665123474Swpaul	sendfunc = sc->ndis_chars.nmc_sendmulti_func;
666123474Swpaul	sendfunc(adapter, packets, cnt);
667123474Swpaul
668123474Swpaul	return(0);
669123474Swpaul}
670123474Swpaul
671123474Swpaulint
672123474Swpaulndis_init_dma(arg)
673123474Swpaul	void			*arg;
674123474Swpaul{
675123474Swpaul	struct ndis_softc	*sc;
676123474Swpaul	int			i, error;
677123474Swpaul
678123474Swpaul	sc = arg;
679123474Swpaul
680123474Swpaul	sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
681123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
682123474Swpaul
683123474Swpaul	if (sc->ndis_tmaps == NULL)
684123474Swpaul		return(ENOMEM);
685123474Swpaul
686123474Swpaul	for (i = 0; i < sc->ndis_maxpkts; i++) {
687123474Swpaul		error = bus_dmamap_create(sc->ndis_ttag, 0,
688123474Swpaul		    &sc->ndis_tmaps[i]);
689123474Swpaul		if (error) {
690123474Swpaul			free(sc->ndis_tmaps, M_DEVBUF);
691123474Swpaul			return(ENODEV);
692123474Swpaul		}
693123474Swpaul	}
694123474Swpaul
695123474Swpaul	return(0);
696123474Swpaul}
697123474Swpaul
698123474Swpaulint
699123474Swpaulndis_destroy_dma(arg)
700123474Swpaul	void			*arg;
701123474Swpaul{
702123474Swpaul	struct ndis_softc	*sc;
703123535Swpaul	struct mbuf		*m;
704123535Swpaul	ndis_packet		*p = NULL;
705123474Swpaul	int			i;
706123474Swpaul
707123474Swpaul	sc = arg;
708123474Swpaul
709123474Swpaul	for (i = 0; i < sc->ndis_maxpkts; i++) {
710123535Swpaul		if (sc->ndis_txarray[i] != NULL) {
711123535Swpaul			p = sc->ndis_txarray[i];
712123535Swpaul			m = (struct mbuf *)p->np_rsvd[1];
713123535Swpaul			if (m != NULL)
714123535Swpaul				m_freem(m);
715123535Swpaul			ndis_free_packet(sc->ndis_txarray[i]);
716123535Swpaul		}
717123474Swpaul		bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
718123474Swpaul	}
719123474Swpaul
720123474Swpaul	free(sc->ndis_tmaps, M_DEVBUF);
721123474Swpaul
722123474Swpaul	bus_dma_tag_destroy(sc->ndis_ttag);
723123474Swpaul
724123474Swpaul	return(0);
725123474Swpaul}
726123474Swpaul
727123474Swpaulint
728123474Swpaulndis_reset_nic(arg)
729123474Swpaul	void			*arg;
730123474Swpaul{
731123474Swpaul	struct ndis_softc	*sc;
732123474Swpaul	ndis_handle		adapter;
733123474Swpaul	__stdcall ndis_reset_handler	resetfunc;
734123474Swpaul	uint8_t			addressing_reset;
735123474Swpaul	struct ifnet		*ifp;
736123474Swpaul
737123474Swpaul	sc = arg;
738123474Swpaul	ifp = &sc->arpcom.ac_if;
739123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
740123474Swpaul	if (adapter == NULL)
741123474Swpaul		return(EIO);
742123474Swpaul	resetfunc = sc->ndis_chars.nmc_reset_func;
743123474Swpaul
744123474Swpaul	if (resetfunc == NULL)
745123474Swpaul		return(EINVAL);
746123474Swpaul
747123474Swpaul	resetfunc(&addressing_reset, adapter);
748123474Swpaul
749123474Swpaul	return(0);
750123474Swpaul}
751123474Swpaul
752123474Swpaulint
753123474Swpaulndis_halt_nic(arg)
754123474Swpaul	void			*arg;
755123474Swpaul{
756123474Swpaul	struct ndis_softc	*sc;
757123474Swpaul	ndis_handle		adapter;
758123474Swpaul	__stdcall ndis_halt_handler	haltfunc;
759123474Swpaul	struct ifnet		*ifp;
760123474Swpaul
761123474Swpaul	sc = arg;
762123474Swpaul	ifp = &sc->arpcom.ac_if;
763123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
764123474Swpaul	if (adapter == NULL)
765123474Swpaul		return(EIO);
766123474Swpaul	haltfunc = sc->ndis_chars.nmc_halt_func;
767123474Swpaul
768123474Swpaul	if (haltfunc == NULL)
769123474Swpaul		return(EINVAL);
770123474Swpaul
771123474Swpaul	haltfunc(adapter);
772123474Swpaul
773123474Swpaul	/*
774123474Swpaul	 * The adapter context is only valid after the init
775123474Swpaul	 * handler has been called, and is invalid once the
776123474Swpaul	 * halt handler has been called.
777123474Swpaul	 */
778123474Swpaul
779123474Swpaul	sc->ndis_block.nmb_miniportadapterctx = NULL;
780123474Swpaul
781123474Swpaul	return(0);
782123474Swpaul}
783123474Swpaul
784123474Swpaulint
785123474Swpaulndis_shutdown_nic(arg)
786123474Swpaul	void			*arg;
787123474Swpaul{
788123474Swpaul	struct ndis_softc	*sc;
789123474Swpaul	ndis_handle		adapter;
790123474Swpaul	__stdcall ndis_shutdown_handler	shutdownfunc;
791123474Swpaul
792123474Swpaul
793123474Swpaul	sc = arg;
794123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
795123474Swpaul	if (adapter == NULL)
796123474Swpaul		return(EIO);
797123474Swpaul	shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
798123474Swpaul
799123474Swpaul	if (shutdownfunc == NULL)
800123474Swpaul		return(EINVAL);
801123474Swpaul
802123485Swpaul	if (sc->ndis_chars.nmc_rsvd0 == NULL)
803123485Swpaul		shutdownfunc(adapter);
804123485Swpaul	else
805123485Swpaul		shutdownfunc(sc->ndis_chars.nmc_rsvd0);
806123474Swpaul
807123474Swpaul	return(0);
808123474Swpaul}
809123474Swpaul
810123474Swpaulint
811123474Swpaulndis_init_nic(arg)
812123474Swpaul	void			*arg;
813123474Swpaul{
814123474Swpaul	struct ndis_softc	*sc;
815123474Swpaul	ndis_miniport_block	*block;
816123474Swpaul        __stdcall ndis_init_handler	initfunc;
817123474Swpaul	ndis_status		status, openstatus = 0;
818123474Swpaul	ndis_medium		mediumarray[NdisMediumMax];
819123474Swpaul	uint32_t		chosenmedium, i;
820123474Swpaul
821123474Swpaul	if (arg == NULL)
822123474Swpaul		return(EINVAL);
823123474Swpaul
824123474Swpaul	sc = arg;
825123474Swpaul	block = &sc->ndis_block;
826123474Swpaul	initfunc = sc->ndis_chars.nmc_init_func;
827123474Swpaul
828123474Swpaul	for (i = 0; i < NdisMediumMax; i++)
829123474Swpaul		mediumarray[i] = i;
830123474Swpaul
831123474Swpaul        status = initfunc(&openstatus, &chosenmedium,
832123474Swpaul            mediumarray, NdisMediumMax, block, block);
833123474Swpaul
834123474Swpaul	/*
835123474Swpaul	 * If the init fails, blow away the other exported routines
836123474Swpaul	 * we obtained from the driver so we can't call them later.
837123474Swpaul	 * If the init failed, none of these will work.
838123474Swpaul	 */
839123474Swpaul	if (status != NDIS_STATUS_SUCCESS) {
840123474Swpaul		bzero((char *)&sc->ndis_chars,
841123474Swpaul		    sizeof(ndis_miniport_characteristics));
842123474Swpaul		return(ENXIO);
843123474Swpaul	}
844123474Swpaul
845123474Swpaul	return(0);
846123474Swpaul}
847123474Swpaul
848123474Swpaulvoid
849123474Swpaulndis_enable_intr(arg)
850123474Swpaul	void			*arg;
851123474Swpaul{
852123474Swpaul	struct ndis_softc	*sc;
853123474Swpaul	ndis_handle		adapter;
854123474Swpaul	__stdcall ndis_enable_interrupts_handler	intrenbfunc;
855123474Swpaul
856123474Swpaul	sc = arg;
857123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
858123474Swpaul	if (adapter == NULL)
859123474Swpaul	    return;
860123474Swpaul	intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
861123474Swpaul	if (intrenbfunc == NULL)
862123474Swpaul		return;
863123474Swpaul	intrenbfunc(adapter);
864123474Swpaul
865123474Swpaul	return;
866123474Swpaul}
867123474Swpaul
868123474Swpaulvoid
869123474Swpaulndis_disable_intr(arg)
870123474Swpaul	void			*arg;
871123474Swpaul{
872123474Swpaul	struct ndis_softc	*sc;
873123474Swpaul	ndis_handle		adapter;
874123474Swpaul	__stdcall ndis_disable_interrupts_handler	intrdisfunc;
875123474Swpaul
876123474Swpaul	sc = arg;
877123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
878123474Swpaul	if (adapter == NULL)
879123474Swpaul	    return;
880123474Swpaul	intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
881123474Swpaul	if (intrdisfunc == NULL)
882123474Swpaul		return;
883123474Swpaul	intrdisfunc(adapter);
884123474Swpaul
885123474Swpaul	return;
886123474Swpaul}
887123474Swpaul
888123474Swpaulint
889123474Swpaulndis_isr(arg, ourintr, callhandler)
890123474Swpaul	void			*arg;
891123474Swpaul	int			*ourintr;
892123474Swpaul	int			*callhandler;
893123474Swpaul{
894123474Swpaul	struct ndis_softc	*sc;
895123474Swpaul	ndis_handle		adapter;
896123474Swpaul	__stdcall ndis_isr_handler	isrfunc;
897123474Swpaul	uint8_t			accepted, queue;
898123474Swpaul
899123474Swpaul	if (arg == NULL || ourintr == NULL || callhandler == NULL)
900123474Swpaul		return(EINVAL);
901123474Swpaul
902123474Swpaul	sc = arg;
903123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
904123474Swpaul	isrfunc = sc->ndis_chars.nmc_isr_func;
905123474Swpaul	isrfunc(&accepted, &queue, adapter);
906123474Swpaul	*ourintr = accepted;
907123474Swpaul	*callhandler = queue;
908123474Swpaul
909123474Swpaul	return(0);
910123474Swpaul}
911123474Swpaul
912123474Swpaulint
913123474Swpaulndis_intrhand(arg)
914123474Swpaul	void			*arg;
915123474Swpaul{
916123474Swpaul	struct ndis_softc	*sc;
917123474Swpaul	ndis_handle		adapter;
918123474Swpaul	__stdcall ndis_interrupt_handler	intrfunc;
919123474Swpaul
920123474Swpaul	if (arg == NULL)
921123474Swpaul		return(EINVAL);
922123474Swpaul
923123474Swpaul	sc = arg;
924123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
925123474Swpaul	intrfunc = sc->ndis_chars.nmc_interrupt_func;
926123474Swpaul	intrfunc(adapter);
927123474Swpaul
928123474Swpaul	return(0);
929123474Swpaul}
930123474Swpaul
931123474Swpaulint
932123474Swpaulndis_get_info(arg, oid, buf, buflen)
933123474Swpaul	void			*arg;
934123474Swpaul	ndis_oid		oid;
935123474Swpaul	void			*buf;
936123474Swpaul	int			*buflen;
937123474Swpaul{
938123474Swpaul	struct ndis_softc	*sc;
939123474Swpaul	ndis_status		rval;
940123474Swpaul	ndis_handle		adapter;
941123474Swpaul	__stdcall ndis_queryinfo_handler	queryfunc;
942123474Swpaul	uint32_t		byteswritten = 0, bytesneeded = 0;
943123695Swpaul	struct timeval		tv;
944123695Swpaul	int			error;
945123474Swpaul
946123474Swpaul	sc = arg;
947123474Swpaul	queryfunc = sc->ndis_chars.nmc_queryinfo_func;
948123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
949123474Swpaul
950123474Swpaul	rval = queryfunc(adapter, oid, buf, *buflen,
951123474Swpaul	    &byteswritten, &bytesneeded);
952123474Swpaul
953123695Swpaul	/* Wait for requests that block. */
954123695Swpaul
955123695Swpaul	if (rval == NDIS_STATUS_PENDING) {
956123695Swpaul		tv.tv_sec = 60;
957123695Swpaul		tv.tv_usec = 0;
958123695Swpaul		error = tsleep(&sc->ndis_block.nmb_wkupdpctimer,
959123695Swpaul		    PPAUSE|PCATCH, "ndis", tvtohz(&tv));
960123695Swpaul		rval = sc->ndis_block.nmb_getstat;
961123695Swpaul	}
962123695Swpaul
963123474Swpaul	if (byteswritten)
964123474Swpaul		*buflen = byteswritten;
965123474Swpaul	if (bytesneeded)
966123474Swpaul		*buflen = bytesneeded;
967123474Swpaul
968123474Swpaul	if (rval == NDIS_STATUS_INVALID_LENGTH ||
969123474Swpaul	    rval == NDIS_STATUS_BUFFER_TOO_SHORT)
970123474Swpaul		return(ENOSPC);
971123474Swpaul
972123474Swpaul	if (rval == NDIS_STATUS_INVALID_OID)
973123474Swpaul		return(EINVAL);
974123474Swpaul
975123474Swpaul	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
976123474Swpaul	    rval == NDIS_STATUS_NOT_ACCEPTED)
977123474Swpaul		return(ENOTSUP);
978123474Swpaul
979123474Swpaul	return(0);
980123474Swpaul}
981123474Swpaul
982123474Swpaulint
983123474Swpaulndis_unload_driver(arg)
984123474Swpaul	void			*arg;
985123474Swpaul{
986123474Swpaul	struct ndis_softc	*sc;
987123474Swpaul
988123474Swpaul	sc = arg;
989123474Swpaul
990123474Swpaul	free(sc->ndis_block.nmb_rlist, M_DEVBUF);
991123474Swpaul
992123474Swpaul	ndis_flush_sysctls(sc);
993123474Swpaul	ndis_libfini();
994123474Swpaul	ntoskrnl_libfini();
995123474Swpaul
996123474Swpaul	return(0);
997123474Swpaul}
998123474Swpaul
999123474Swpaulint
1000123474Swpaulndis_load_driver(img, arg)
1001123474Swpaul	vm_offset_t		img;
1002123474Swpaul	void			*arg;
1003123474Swpaul{
1004123474Swpaul	__stdcall driver_entry	entry;
1005123474Swpaul	image_optional_header	opt_hdr;
1006123474Swpaul	image_import_descriptor imp_desc;
1007123474Swpaul	ndis_unicode_string	dummystr;
1008123474Swpaul	ndis_driver_object	drv;
1009123474Swpaul        ndis_miniport_block     *block;
1010123474Swpaul	ndis_status		status;
1011123474Swpaul	int			idx;
1012123474Swpaul	uint32_t		*ptr;
1013123474Swpaul	struct ndis_softc	*sc;
1014123474Swpaul
1015123474Swpaul	sc = arg;
1016123474Swpaul
1017123474Swpaul	/* Perform text relocation */
1018123474Swpaul	if (pe_relocate(img))
1019123474Swpaul		return(ENOEXEC);
1020123474Swpaul
1021123474Swpaul        /* Dynamically link the NDIS.SYS routines -- required. */
1022123474Swpaul	if (pe_patch_imports(img, "NDIS", ndis_functbl))
1023123474Swpaul		return(ENOEXEC);
1024123474Swpaul
1025123474Swpaul	/* Dynamically link the HAL.dll routines -- also required. */
1026123474Swpaul	if (pe_patch_imports(img, "HAL", hal_functbl))
1027123474Swpaul		return(ENOEXEC);
1028123474Swpaul
1029123474Swpaul	/* Dynamically link ntoskrnl.exe -- optional. */
1030123474Swpaul	if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
1031123474Swpaul		if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
1032123474Swpaul			return(ENOEXEC);
1033123474Swpaul	}
1034123474Swpaul
1035123474Swpaul	/* Initialize subsystems */
1036123474Swpaul	ndis_libinit();
1037123474Swpaul	ntoskrnl_libinit();
1038123474Swpaul
1039123474Swpaul        /* Locate the driver entry point */
1040123474Swpaul	pe_get_optional_header(img, &opt_hdr);
1041123474Swpaul	entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
1042123474Swpaul
1043123474Swpaul	/*
1044123474Swpaul	 * Now call the DriverEntry() routine. This will cause
1045123474Swpaul	 * a callout to the NdisInitializeWrapper() and
1046123474Swpaul	 * NdisMRegisterMiniport() routines.
1047123474Swpaul	 */
1048123474Swpaul	dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
1049123474Swpaul	dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
1050123474Swpaul	dummystr.nus_buf = NULL;
1051123474Swpaul	ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
1052123474Swpaul	drv.ndo_ifname = "ndis0";
1053123474Swpaul
1054123474Swpaul	status = entry(&drv, &dummystr);
1055123474Swpaul
1056123474Swpaul	free (dummystr.nus_buf, M_DEVBUF);
1057123474Swpaul
1058123474Swpaul	if (status != NDIS_STATUS_SUCCESS)
1059123474Swpaul		return(ENODEV);
1060123474Swpaul
1061123474Swpaul	/*
1062123474Swpaul	 * Now that we have the miniport driver characteristics,
1063123474Swpaul	 * create an NDIS block and call the init handler.
1064123474Swpaul	 * This will cause the driver to try to probe for
1065123474Swpaul	 * a device.
1066123474Swpaul	 */
1067123474Swpaul
1068123474Swpaul	block = &sc->ndis_block;
1069123474Swpaul	bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
1070123474Swpaul	    sizeof(ndis_miniport_characteristics));
1071123474Swpaul
1072123474Swpaul	/*block->nmb_signature = 0xcafebabe;*/
1073123474Swpaul
1074123474Swpaul		ptr = (uint32_t *)block;
1075123474Swpaul	for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
1076123474Swpaul		*ptr = idx | 0xdead0000;
1077123474Swpaul		ptr++;
1078123474Swpaul	}
1079123474Swpaul
1080123474Swpaul	block->nmb_signature = (void *)0xcafebabe;
1081123474Swpaul	block->nmb_setdone_func = ndis_setdone_func;
1082123535Swpaul	block->nmb_querydone_func = ndis_getdone_func;
1083123474Swpaul	block->nmb_status_func = ndis_status_func;
1084123474Swpaul	block->nmb_statusdone_func = ndis_statusdone_func;
1085123474Swpaul	block->nmb_resetdone_func = ndis_resetdone_func;
1086123474Swpaul
1087123474Swpaul	block->nmb_ifp = &sc->arpcom.ac_if;
1088123474Swpaul	block->nmb_dev = sc->ndis_dev;
1089123474Swpaul
1090123474Swpaul	return(0);
1091123474Swpaul}
1092