kern_ndis.c revision 123485
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 123485 2003-12-12 05:27:58Z 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
61123474Swpaul#include <dev/pccard/pccardvar.h>
62123474Swpaul#include "card_if.h"
63123474Swpaul
64123474Swpaul#include <compat/ndis/pe_var.h>
65123474Swpaul#include <compat/ndis/resource_var.h>
66123474Swpaul#include <compat/ndis/ndis_var.h>
67123474Swpaul#include <compat/ndis/hal_var.h>
68123474Swpaul#include <compat/ndis/ntoskrnl_var.h>
69123474Swpaul#include <compat/ndis/cfg_var.h>
70123474Swpaul#include <dev/if_ndis/if_ndisvar.h>
71123474Swpaul
72123474Swpaul#define __stdcall __attribute__((__stdcall__))
73123474Swpaul#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
74123474Swpaul
75123474Swpaul__stdcall static void ndis_status_func(ndis_handle, ndis_status,
76123474Swpaul	void *, uint32_t);
77123474Swpaul__stdcall static void ndis_statusdone_func(ndis_handle);
78123474Swpaul__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
79123474Swpaul__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
80123474Swpaul
81123474Swpaul/*
82123474Swpaul * This allows us to export our symbols to other modules.
83123474Swpaul * Note that we call ourselves 'ndisapi' to avoid a namespace
84123474Swpaul * collision with if_ndis.ko, which internally calls itself
85123474Swpaul * 'ndis.'
86123474Swpaul */
87123474Swpaulstatic int
88123474Swpaulndis_modevent(module_t mod, int cmd, void *arg)
89123474Swpaul{
90123474Swpaul	return(0);
91123474Swpaul}
92123474SwpaulDEV_MODULE(ndisapi, ndis_modevent, NULL);
93123474SwpaulMODULE_VERSION(ndisapi, 1);
94123474Swpaul
95123474Swpaul
96123474Swpaul__stdcall static void
97123474Swpaulndis_status_func(adapter, status, sbuf, slen)
98123474Swpaul	ndis_handle		adapter;
99123474Swpaul	ndis_status		status;
100123474Swpaul	void			*sbuf;
101123474Swpaul	uint32_t		slen;
102123474Swpaul{
103123474Swpaul	printf ("status: %x\n", status);
104123474Swpaul	return;
105123474Swpaul}
106123474Swpaul
107123474Swpaul__stdcall static void
108123474Swpaulndis_statusdone_func(adapter)
109123474Swpaul	ndis_handle		adapter;
110123474Swpaul{
111123474Swpaul	printf ("status complete\n");
112123474Swpaul	return;
113123474Swpaul}
114123474Swpaul
115123474Swpaul__stdcall static void
116123474Swpaulndis_setdone_func(adapter, status)
117123474Swpaul	ndis_handle		adapter;
118123474Swpaul	ndis_status		status;
119123474Swpaul{
120123474Swpaul	printf ("Setup done... %x\n", status);
121123474Swpaul	return;
122123474Swpaul}
123123474Swpaul
124123474Swpaul__stdcall static void
125123474Swpaulndis_resetdone_func(adapter, status, addressingreset)
126123474Swpaul	ndis_handle		adapter;
127123474Swpaul	ndis_status		status;
128123474Swpaul	uint8_t			addressingreset;
129123474Swpaul{
130123474Swpaul	printf ("reset done...\n");
131123474Swpaul	return;
132123474Swpaul}
133123474Swpaul
134123474Swpaul#define NDIS_AM_RID	3
135123474Swpaul
136123474Swpaulint
137123474Swpaulndis_alloc_amem(arg)
138123474Swpaul	void			*arg;
139123474Swpaul{
140123474Swpaul	struct ndis_softc	*sc;
141123474Swpaul	int			error, rid;
142123474Swpaul
143123474Swpaul	if (arg == NULL)
144123474Swpaul		return(EINVAL);
145123474Swpaul
146123474Swpaul	sc = arg;
147123474Swpaul	rid = NDIS_AM_RID;
148123474Swpaul	sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
149123474Swpaul	    &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
150123474Swpaul
151123474Swpaul	if (sc->ndis_res_am == NULL) {
152123474Swpaul		printf("ndis%d: failed to allocate attribute memory\n",
153123474Swpaul		    sc->ndis_unit);
154123474Swpaul		return(ENXIO);
155123474Swpaul	}
156123474Swpaul
157123474Swpaul	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
158123474Swpaul	    sc->ndis_dev, rid, 0, NULL);
159123474Swpaul
160123474Swpaul	if (error) {
161123474Swpaul		printf("ndis%d: CARD_SET_MEMORY_OFFSET() returned 0x%x\n",
162123474Swpaul		    sc->ndis_unit, error);
163123474Swpaul		return(error);
164123474Swpaul	}
165123474Swpaul
166123474Swpaul	error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
167123474Swpaul	    sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
168123474Swpaul
169123474Swpaul	if (error) {
170123474Swpaul		printf("ndis%d: CARD_SET_RES_FLAGS() returned 0x%x\n",
171123474Swpaul		    sc->ndis_unit, error);
172123474Swpaul		return(error);
173123474Swpaul	}
174123474Swpaul
175123474Swpaul	return(0);
176123474Swpaul}
177123474Swpaul
178123474Swpaulint
179123474Swpaulndis_create_sysctls(arg)
180123474Swpaul	void			*arg;
181123474Swpaul{
182123474Swpaul	struct ndis_softc	*sc;
183123474Swpaul	ndis_cfg		*vals;
184123474Swpaul	char			buf[256];
185123474Swpaul
186123474Swpaul	if (arg == NULL)
187123474Swpaul		return(EINVAL);
188123474Swpaul
189123474Swpaul	sc = arg;
190123474Swpaul	vals = sc->ndis_regvals;
191123474Swpaul
192123474Swpaul	TAILQ_INIT(&sc->ndis_cfglist_head);
193123474Swpaul
194123474Swpaul	/* Create the sysctl tree. */
195123474Swpaul
196123474Swpaul	sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
197123474Swpaul	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
198123474Swpaul	    device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
199123474Swpaul	    device_get_desc(sc->ndis_dev));
200123474Swpaul
201123474Swpaul	/* Add the driver-specific registry keys. */
202123474Swpaul
203123474Swpaul	vals = sc->ndis_regvals;
204123474Swpaul	while(1) {
205123474Swpaul		if (vals->nc_cfgkey == NULL)
206123474Swpaul			break;
207123474Swpaul		SYSCTL_ADD_STRING(&sc->ndis_ctx,
208123474Swpaul		    SYSCTL_CHILDREN(sc->ndis_tree),
209123474Swpaul		    OID_AUTO, vals->nc_cfgkey,
210123474Swpaul		    CTLFLAG_RW, vals->nc_val,
211123474Swpaul		    sizeof(vals->nc_val),
212123474Swpaul		    vals->nc_cfgdesc);
213123474Swpaul		vals++;
214123474Swpaul	}
215123474Swpaul
216123474Swpaul	/* Now add a couple of builtin keys. */
217123474Swpaul
218123474Swpaul	/*
219123474Swpaul	 * Environment can be either Windows (0) or WindowsNT (1).
220123474Swpaul	 * We qualify as the latter.
221123474Swpaul	 */
222123474Swpaul	ndis_add_sysctl(sc, "Environment",
223123474Swpaul	    "Windows environment", "1", CTLFLAG_RD);
224123474Swpaul
225123474Swpaul	/* NDIS version should be 5.1. */
226123474Swpaul	ndis_add_sysctl(sc, "NdisVersion",
227123474Swpaul	    "NDIS API Version", "0x00050001", CTLFLAG_RD);
228123474Swpaul
229123474Swpaul	/* Bus type (PCI, PCMCIA, etc...) */
230123474Swpaul	sprintf(buf, "%d\n", (int)sc->ndis_iftype);
231123474Swpaul	ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
232123474Swpaul
233123474Swpaul	if (sc->ndis_res_io != NULL) {
234123474Swpaul		sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io));
235123474Swpaul		ndis_add_sysctl(sc, "IOBaseAddress",
236123474Swpaul		    "Base I/O Address", buf, CTLFLAG_RD);
237123474Swpaul	}
238123474Swpaul
239123474Swpaul	if (sc->ndis_irq != NULL) {
240123474Swpaul		sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq));
241123474Swpaul		ndis_add_sysctl(sc, "InterruptNumber",
242123474Swpaul		    "Interrupt Number", buf, CTLFLAG_RD);
243123474Swpaul	}
244123474Swpaul
245123474Swpaul	return(0);
246123474Swpaul}
247123474Swpaul
248123474Swpaulint
249123474Swpaulndis_add_sysctl(arg, key, desc, val, flag)
250123474Swpaul	void			*arg;
251123474Swpaul	char			*key;
252123474Swpaul	char			*desc;
253123474Swpaul	char			*val;
254123474Swpaul	int			flag;
255123474Swpaul{
256123474Swpaul	struct ndis_softc	*sc;
257123474Swpaul	struct ndis_cfglist	*cfg;
258123474Swpaul	char			descstr[256];
259123474Swpaul
260123474Swpaul	sc = arg;
261123474Swpaul
262123474Swpaul	cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
263123474Swpaul
264123474Swpaul	if (cfg == NULL)
265123474Swpaul		return(ENOMEM);
266123474Swpaul
267123474Swpaul	cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
268123474Swpaul	if (desc == NULL) {
269123474Swpaul		snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
270123474Swpaul		cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
271123474Swpaul	} else
272123474Swpaul		cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
273123474Swpaul	strcpy(cfg->ndis_cfg.nc_val, val);
274123474Swpaul
275123474Swpaul	TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
276123474Swpaul
277123474Swpaul	SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
278123474Swpaul	    OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
279123474Swpaul	    cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
280123474Swpaul	    cfg->ndis_cfg.nc_cfgdesc);
281123474Swpaul
282123474Swpaul	return(0);
283123474Swpaul}
284123474Swpaul
285123474Swpaulint
286123474Swpaulndis_flush_sysctls(arg)
287123474Swpaul	void			*arg;
288123474Swpaul{
289123474Swpaul	struct ndis_softc	*sc;
290123474Swpaul	struct ndis_cfglist	*cfg;
291123474Swpaul
292123474Swpaul	sc = arg;
293123474Swpaul
294123474Swpaul	while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
295123474Swpaul		cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
296123474Swpaul		TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
297123474Swpaul		free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
298123474Swpaul		free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
299123474Swpaul		free(cfg, M_DEVBUF);
300123474Swpaul	}
301123474Swpaul
302123474Swpaul	return(0);
303123474Swpaul}
304123474Swpaul
305123474Swpaulvoid
306123474Swpaulndis_return_packet(packet, arg)
307123474Swpaul	void			*packet;
308123474Swpaul	void			*arg;
309123474Swpaul{
310123474Swpaul	struct ndis_softc	*sc;
311123474Swpaul	ndis_handle		adapter;
312123474Swpaul	__stdcall ndis_return_handler	returnfunc;
313123474Swpaul
314123474Swpaul	if (arg == NULL || packet == NULL)
315123474Swpaul		return;
316123474Swpaul
317123474Swpaul	sc = arg;
318123474Swpaul	returnfunc = sc->ndis_chars.nmc_return_packet_func;
319123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
320123474Swpaul	if (returnfunc == NULL)
321123474Swpaul		ndis_free_packet((ndis_packet *)packet);
322123474Swpaul	else
323123474Swpaul		returnfunc(adapter, (ndis_packet *)packet);
324123474Swpaul	return;
325123474Swpaul}
326123474Swpaul
327123474Swpaulvoid
328123474Swpaulndis_free_bufs(b0)
329123474Swpaul	ndis_buffer		*b0;
330123474Swpaul{
331123474Swpaul	ndis_buffer		*next;
332123474Swpaul
333123474Swpaul	if (b0 == NULL)
334123474Swpaul		return;
335123474Swpaul
336123474Swpaul	while(b0 != NULL) {
337123474Swpaul		next = b0->nb_next;
338123474Swpaul		free (b0, M_DEVBUF);
339123474Swpaul		b0 = next;
340123474Swpaul	}
341123474Swpaul
342123474Swpaul	return;
343123474Swpaul}
344123474Swpaul
345123474Swpaulvoid
346123474Swpaulndis_free_packet(p)
347123474Swpaul	ndis_packet		*p;
348123474Swpaul{
349123474Swpaul	if (p == NULL)
350123474Swpaul		return;
351123474Swpaul
352123474Swpaul	ndis_free_bufs(p->np_private.npp_head);
353123474Swpaul	free(p, M_DEVBUF);
354123474Swpaul
355123474Swpaul	return;
356123474Swpaul}
357123474Swpaul
358123474Swpaulint
359123474Swpaulndis_convert_res(arg)
360123474Swpaul	void			*arg;
361123474Swpaul{
362123474Swpaul	struct ndis_softc	*sc;
363123474Swpaul	ndis_resource_list	*rl = NULL;
364123474Swpaul	cm_partial_resource_desc	*prd = NULL;
365123474Swpaul	ndis_miniport_block	*block;
366123474Swpaul
367123474Swpaul	sc = arg;
368123474Swpaul	block = &sc->ndis_block;
369123474Swpaul
370123474Swpaul	rl = malloc(sizeof(ndis_resource_list) +
371123474Swpaul	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
372123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
373123474Swpaul
374123474Swpaul	if (rl == NULL)
375123474Swpaul		return(ENOMEM);
376123474Swpaul
377123474Swpaul	rl->cprl_version = 5;
378123474Swpaul	rl->cprl_version = 1;
379123474Swpaul	rl->cprl_count = sc->ndis_rescnt;
380123474Swpaul
381123474Swpaul	prd = rl->cprl_partial_descs;
382123474Swpaul	if (sc->ndis_res_io) {
383123474Swpaul		prd->cprd_type = CmResourceTypePort;
384123474Swpaul		prd->u.cprd_port.cprd_start.np_quad =
385123474Swpaul		    rman_get_start(sc->ndis_res_io);
386123474Swpaul		prd->u.cprd_port.cprd_len =
387123474Swpaul		    rman_get_size(sc->ndis_res_io);
388123474Swpaul		prd++;
389123474Swpaul	}
390123474Swpaul
391123474Swpaul	if (sc->ndis_res_mem) {
392123474Swpaul		prd->cprd_type = CmResourceTypeMemory;
393123474Swpaul		prd->u.cprd_mem.cprd_start.np_quad =
394123474Swpaul		    rman_get_start(sc->ndis_res_mem);
395123474Swpaul		prd->u.cprd_mem.cprd_len =
396123474Swpaul		    rman_get_size(sc->ndis_res_mem);
397123474Swpaul		prd++;
398123474Swpaul	}
399123474Swpaul
400123474Swpaul	if (sc->ndis_irq) {
401123474Swpaul		prd->cprd_type = CmResourceTypeInterrupt;
402123474Swpaul		prd->u.cprd_intr.cprd_level =
403123474Swpaul		    rman_get_start(sc->ndis_irq);
404123474Swpaul		prd->u.cprd_intr.cprd_vector =
405123474Swpaul		    rman_get_start(sc->ndis_irq);
406123474Swpaul		prd->u.cprd_intr.cprd_affinity = 0;
407123474Swpaul	}
408123474Swpaul
409123474Swpaul	block->nmb_rlist = rl;
410123474Swpaul
411123474Swpaul	return(0);
412123474Swpaul}
413123474Swpaul
414123474Swpaul/*
415123474Swpaul * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
416123474Swpaul * packet, it will hand it to us in the form of an ndis_packet,
417123474Swpaul * which we need to convert to an mbuf that is then handed off
418123474Swpaul * to the stack. Note: we configure the mbuf list so that it uses
419123474Swpaul * the memory regions specified by the ndis_buffer structures in
420123474Swpaul * the ndis_packet as external storage. In most cases, this will
421123474Swpaul * point to a memory region allocated by the driver (either by
422123474Swpaul * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
423123474Swpaul * the driver to handle free()ing this region for is, so we set up
424123474Swpaul * a dummy no-op free handler for it.
425123474Swpaul */
426123474Swpaul
427123474Swpaulint
428123474Swpaulndis_ptom(m0, p)
429123474Swpaul	struct mbuf		**m0;
430123474Swpaul	ndis_packet		*p;
431123474Swpaul{
432123474Swpaul	struct mbuf		*m, *prev = NULL;
433123474Swpaul	ndis_buffer		*buf;
434123474Swpaul	ndis_packet_private	*priv;
435123474Swpaul	uint32_t		totlen = 0;
436123474Swpaul
437123474Swpaul	if (p == NULL || m0 == NULL)
438123474Swpaul		return(EINVAL);
439123474Swpaul
440123474Swpaul	priv = &p->np_private;
441123474Swpaul	buf = priv->npp_head;
442123474Swpaul
443123474Swpaul	for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
444123474Swpaul		if (buf == priv->npp_head)
445123474Swpaul			MGETHDR(m, M_DONTWAIT, MT_HEADER);
446123474Swpaul		else
447123474Swpaul			MGET(m, M_DONTWAIT, MT_DATA);
448123474Swpaul		if (m == NULL) {
449123474Swpaul			m_freem(*m0);
450123474Swpaul			*m0 = NULL;
451123474Swpaul			return(ENOBUFS);
452123474Swpaul		}
453123474Swpaul
454123474Swpaul		/*
455123474Swpaul		 * Note: there's some hackery going on here. We want
456123474Swpaul		 * to mate the mbufs to the buffers in the NDIS packet,
457123474Swpaul		 * but we don't mark the mbufs with the M_EXT flag to
458123474Swpaul		 * indicate external storage. This is because we don't
459123474Swpaul		 * want anything special done to free the buffers.
460123474Swpaul		 * Depending on the circumstances, the caller may want
461123474Swpaul		 * the entire packet to be released, buffers and all,
462123474Swpaul		 * by calling ndis_return_packet(), or ndis_free_packet().
463123474Swpaul		 * We leave it up to the caller to do the MEXTADD() to
464123474Swpaul		 * set up the free mechanism in the first mbuf of the
465123474Swpaul		 * chain.
466123474Swpaul		 */
467123474Swpaul		if (buf->nb_size)
468123474Swpaul			m->m_len = buf->nb_size;
469123474Swpaul		else
470123474Swpaul			m->m_len = buf->nb_bytecount;
471123474Swpaul		m->m_data = buf->nb_mappedsystemva;
472123474Swpaul		totlen += m->m_len;
473123474Swpaul		if (m->m_flags & MT_HEADER)
474123474Swpaul			*m0 = m;
475123474Swpaul		else
476123474Swpaul			prev->m_next = m;
477123474Swpaul		prev = m;
478123474Swpaul	}
479123474Swpaul
480123474Swpaul	(*m0)->m_pkthdr.len = totlen;
481123474Swpaul
482123474Swpaul	return(0);
483123474Swpaul}
484123474Swpaul
485123474Swpaul/*
486123474Swpaul * Create an mbuf chain from an NDIS packet chain.
487123474Swpaul * This is used mainly when transmitting packets, where we need
488123474Swpaul * to turn an mbuf off an interface's send queue and transform it
489123474Swpaul * into an NDIS packet which will be fed into the NDIS driver's
490123474Swpaul * send routine.
491123474Swpaul *
492123474Swpaul * NDIS packets consist of two parts: an ndis_packet structure,
493123474Swpaul * which is vaguely analagous to the pkthdr portion of an mbuf,
494123474Swpaul * and one or more ndis_buffer structures, which define the
495123474Swpaul * actual memory segments in which the packet data resides.
496123474Swpaul * We need to allocate one ndis_buffer for each mbuf in a chain,
497123474Swpaul * plus one ndis_packet as the header.
498123474Swpaul */
499123474Swpaul
500123474Swpaulint
501123474Swpaulndis_mtop(m0, p)
502123474Swpaul	struct mbuf		*m0;
503123474Swpaul	ndis_packet		**p;
504123474Swpaul{
505123474Swpaul	struct mbuf		*m;
506123474Swpaul	ndis_buffer		*buf = NULL, *prev = NULL;
507123474Swpaul	ndis_packet_private	*priv;
508123474Swpaul
509123474Swpaul	if (p == NULL || m0 == NULL)
510123474Swpaul		return(EINVAL);
511123474Swpaul
512123474Swpaul	/* If caller didn't supply a packet, make one. */
513123474Swpaul	if (*p == NULL) {
514123474Swpaul		*p = malloc(sizeof(ndis_packet), M_DEVBUF, M_NOWAIT|M_ZERO);
515123474Swpaul
516123474Swpaul		if (*p == NULL)
517123474Swpaul			return(ENOMEM);
518123474Swpaul	}
519123474Swpaul
520123474Swpaul	priv = &(*p)->np_private;
521123474Swpaul	priv->npp_totlen = m0->m_pkthdr.len;
522123474Swpaul        priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
523123474Swpaul
524123474Swpaul	for (m = m0; m != NULL; m = m->m_next) {
525123474Swpaul		if (m->m_len == NULL)
526123474Swpaul			continue;
527123474Swpaul
528123474Swpaul		buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO);
529123474Swpaul		if (buf == NULL) {
530123474Swpaul			ndis_free_packet(*p);
531123474Swpaul			*p = NULL;
532123474Swpaul			return(ENOMEM);
533123474Swpaul		}
534123474Swpaul
535123474Swpaul		buf->nb_bytecount = m->m_len;
536123474Swpaul		buf->nb_mappedsystemva = m->m_data;
537123474Swpaul		if (priv->npp_head == NULL)
538123474Swpaul			priv->npp_head = buf;
539123474Swpaul		else
540123474Swpaul			prev->nb_next = buf;
541123474Swpaul		prev = buf;
542123474Swpaul	}
543123474Swpaul
544123474Swpaul	priv->npp_tail = buf;
545123474Swpaul
546123474Swpaul	return(0);
547123474Swpaul}
548123474Swpaul
549123474Swpaulint
550123474Swpaulndis_get_supported_oids(arg, oids, oidcnt)
551123474Swpaul	void			*arg;
552123474Swpaul	ndis_oid		**oids;
553123474Swpaul	int			*oidcnt;
554123474Swpaul{
555123474Swpaul	int			len, rval;
556123474Swpaul	ndis_oid		*o;
557123474Swpaul
558123474Swpaul	if (arg == NULL || oids == NULL || oidcnt == NULL)
559123474Swpaul		return(EINVAL);
560123474Swpaul	len = 0;
561123474Swpaul	ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
562123474Swpaul
563123474Swpaul	o = malloc(len, M_DEVBUF, M_NOWAIT);
564123474Swpaul	if (o == NULL)
565123474Swpaul		return(ENOMEM);
566123474Swpaul
567123474Swpaul	rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
568123474Swpaul
569123474Swpaul	if (rval) {
570123474Swpaul		free(o, M_DEVBUF);
571123474Swpaul		return(rval);
572123474Swpaul	}
573123474Swpaul
574123474Swpaul	*oids = o;
575123474Swpaul	*oidcnt = len / 4;
576123474Swpaul
577123474Swpaul	return(0);
578123474Swpaul}
579123474Swpaul
580123474Swpaulint
581123474Swpaulndis_set_info(arg, oid, buf, buflen)
582123474Swpaul	void			*arg;
583123474Swpaul	ndis_oid		oid;
584123474Swpaul	void			*buf;
585123474Swpaul	int			*buflen;
586123474Swpaul{
587123474Swpaul	struct ndis_softc	*sc;
588123474Swpaul	ndis_status		rval;
589123474Swpaul	ndis_handle		adapter;
590123474Swpaul	__stdcall ndis_setinfo_handler	setfunc;
591123474Swpaul	uint32_t		byteswritten = 0, bytesneeded = 0;
592123474Swpaul
593123474Swpaul	sc = arg;
594123474Swpaul	setfunc = sc->ndis_chars.nmc_setinfo_func;
595123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
596123474Swpaul
597123474Swpaul	rval = setfunc(adapter, oid, buf, *buflen,
598123474Swpaul	    &byteswritten, &bytesneeded);
599123474Swpaul
600123474Swpaul	if (byteswritten)
601123474Swpaul		*buflen = byteswritten;
602123474Swpaul	if (bytesneeded)
603123474Swpaul		*buflen = bytesneeded;
604123474Swpaul
605123474Swpaul	if (rval == NDIS_STATUS_INVALID_LENGTH)
606123474Swpaul		return(ENOSPC);
607123474Swpaul
608123474Swpaul	if (rval == NDIS_STATUS_INVALID_OID)
609123474Swpaul		return(EINVAL);
610123474Swpaul
611123474Swpaul	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
612123474Swpaul	    rval == NDIS_STATUS_NOT_ACCEPTED)
613123474Swpaul		return(ENOTSUP);
614123474Swpaul
615123474Swpaul	if (rval == NDIS_STATUS_PENDING)
616123474Swpaul		return(EAGAIN);
617123474Swpaul
618123474Swpaul	return(0);
619123474Swpaul}
620123474Swpaul
621123474Swpaulint
622123474Swpaulndis_send_packets(arg, packets, cnt)
623123474Swpaul	void			*arg;
624123474Swpaul	ndis_packet		**packets;
625123474Swpaul	int			cnt;
626123474Swpaul{
627123474Swpaul	struct ndis_softc	*sc;
628123474Swpaul	ndis_handle		adapter;
629123474Swpaul	__stdcall ndis_sendmulti_handler	sendfunc;
630123474Swpaul
631123474Swpaul	sc = arg;
632123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
633123474Swpaul	sendfunc = sc->ndis_chars.nmc_sendmulti_func;
634123474Swpaul	sendfunc(adapter, packets, cnt);
635123474Swpaul
636123474Swpaul	return(0);
637123474Swpaul}
638123474Swpaul
639123474Swpaulint
640123474Swpaulndis_init_dma(arg)
641123474Swpaul	void			*arg;
642123474Swpaul{
643123474Swpaul	struct ndis_softc	*sc;
644123474Swpaul	int			i, error;
645123474Swpaul
646123474Swpaul	sc = arg;
647123474Swpaul
648123474Swpaul	sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
649123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
650123474Swpaul
651123474Swpaul	if (sc->ndis_tmaps == NULL)
652123474Swpaul		return(ENOMEM);
653123474Swpaul
654123474Swpaul	sc->ndis_mbufs = malloc(sizeof(struct mbuf) * sc->ndis_maxpkts,
655123474Swpaul	    M_DEVBUF, M_NOWAIT|M_ZERO);
656123474Swpaul
657123474Swpaul	if (sc->ndis_mbufs == NULL) {
658123474Swpaul		free(sc->ndis_tmaps, M_DEVBUF);
659123474Swpaul		return(ENOMEM);
660123474Swpaul	}
661123474Swpaul
662123474Swpaul	for (i = 0; i < sc->ndis_maxpkts; i++) {
663123474Swpaul		error = bus_dmamap_create(sc->ndis_ttag, 0,
664123474Swpaul		    &sc->ndis_tmaps[i]);
665123474Swpaul		if (error) {
666123474Swpaul			free(sc->ndis_tmaps, M_DEVBUF);
667123474Swpaul			free(sc->ndis_mbufs, M_DEVBUF);
668123474Swpaul			return(ENODEV);
669123474Swpaul		}
670123474Swpaul	}
671123474Swpaul
672123474Swpaul	return(0);
673123474Swpaul}
674123474Swpaul
675123474Swpaulint
676123474Swpaulndis_destroy_dma(arg)
677123474Swpaul	void			*arg;
678123474Swpaul{
679123474Swpaul	struct ndis_softc	*sc;
680123474Swpaul	int			i;
681123474Swpaul
682123474Swpaul	sc = arg;
683123474Swpaul
684123474Swpaul	for (i = 0; i < sc->ndis_maxpkts; i++) {
685123474Swpaul		if (sc->ndis_mbufs[i] != NULL)
686123474Swpaul			m_freem(sc->ndis_mbufs[i]);
687123474Swpaul		bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
688123474Swpaul	}
689123474Swpaul
690123474Swpaul	free(sc->ndis_tmaps, M_DEVBUF);
691123474Swpaul	free(sc->ndis_mbufs, M_DEVBUF);
692123474Swpaul
693123474Swpaul	bus_dma_tag_destroy(sc->ndis_ttag);
694123474Swpaul
695123474Swpaul	return(0);
696123474Swpaul}
697123474Swpaul
698123474Swpaulint
699123474Swpaulndis_reset_nic(arg)
700123474Swpaul	void			*arg;
701123474Swpaul{
702123474Swpaul	struct ndis_softc	*sc;
703123474Swpaul	ndis_handle		adapter;
704123474Swpaul	__stdcall ndis_reset_handler	resetfunc;
705123474Swpaul	uint8_t			addressing_reset;
706123474Swpaul	struct ifnet		*ifp;
707123474Swpaul
708123474Swpaul	sc = arg;
709123474Swpaul	ifp = &sc->arpcom.ac_if;
710123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
711123474Swpaul	if (adapter == NULL)
712123474Swpaul		return(EIO);
713123474Swpaul	resetfunc = sc->ndis_chars.nmc_reset_func;
714123474Swpaul
715123474Swpaul	if (resetfunc == NULL)
716123474Swpaul		return(EINVAL);
717123474Swpaul
718123474Swpaul	resetfunc(&addressing_reset, adapter);
719123474Swpaul
720123474Swpaul	return(0);
721123474Swpaul}
722123474Swpaul
723123474Swpaulint
724123474Swpaulndis_halt_nic(arg)
725123474Swpaul	void			*arg;
726123474Swpaul{
727123474Swpaul	struct ndis_softc	*sc;
728123474Swpaul	ndis_handle		adapter;
729123474Swpaul	__stdcall ndis_halt_handler	haltfunc;
730123474Swpaul	struct ifnet		*ifp;
731123474Swpaul
732123474Swpaul	sc = arg;
733123474Swpaul	ifp = &sc->arpcom.ac_if;
734123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
735123474Swpaul	if (adapter == NULL)
736123474Swpaul		return(EIO);
737123474Swpaul	haltfunc = sc->ndis_chars.nmc_halt_func;
738123474Swpaul
739123474Swpaul	if (haltfunc == NULL)
740123474Swpaul		return(EINVAL);
741123474Swpaul
742123474Swpaul	haltfunc(adapter);
743123474Swpaul
744123474Swpaul	/*
745123474Swpaul	 * The adapter context is only valid after the init
746123474Swpaul	 * handler has been called, and is invalid once the
747123474Swpaul	 * halt handler has been called.
748123474Swpaul	 */
749123474Swpaul
750123474Swpaul	sc->ndis_block.nmb_miniportadapterctx = NULL;
751123474Swpaul
752123474Swpaul	return(0);
753123474Swpaul}
754123474Swpaul
755123474Swpaulint
756123474Swpaulndis_shutdown_nic(arg)
757123474Swpaul	void			*arg;
758123474Swpaul{
759123474Swpaul	struct ndis_softc	*sc;
760123474Swpaul	ndis_handle		adapter;
761123474Swpaul	__stdcall ndis_shutdown_handler	shutdownfunc;
762123474Swpaul
763123474Swpaul
764123474Swpaul	sc = arg;
765123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
766123474Swpaul	if (adapter == NULL)
767123474Swpaul		return(EIO);
768123474Swpaul	shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
769123474Swpaul
770123474Swpaul	if (shutdownfunc == NULL)
771123474Swpaul		return(EINVAL);
772123474Swpaul
773123485Swpaul	if (sc->ndis_chars.nmc_rsvd0 == NULL)
774123485Swpaul		shutdownfunc(adapter);
775123485Swpaul	else
776123485Swpaul		shutdownfunc(sc->ndis_chars.nmc_rsvd0);
777123474Swpaul
778123474Swpaul	return(0);
779123474Swpaul}
780123474Swpaul
781123474Swpaulint
782123474Swpaulndis_init_nic(arg)
783123474Swpaul	void			*arg;
784123474Swpaul{
785123474Swpaul	struct ndis_softc	*sc;
786123474Swpaul	ndis_miniport_block	*block;
787123474Swpaul        __stdcall ndis_init_handler	initfunc;
788123474Swpaul	ndis_status		status, openstatus = 0;
789123474Swpaul	ndis_medium		mediumarray[NdisMediumMax];
790123474Swpaul	uint32_t		chosenmedium, i;
791123474Swpaul
792123474Swpaul	if (arg == NULL)
793123474Swpaul		return(EINVAL);
794123474Swpaul
795123474Swpaul	sc = arg;
796123474Swpaul	block = &sc->ndis_block;
797123474Swpaul	initfunc = sc->ndis_chars.nmc_init_func;
798123474Swpaul
799123474Swpaul	for (i = 0; i < NdisMediumMax; i++)
800123474Swpaul		mediumarray[i] = i;
801123474Swpaul
802123474Swpaul        status = initfunc(&openstatus, &chosenmedium,
803123474Swpaul            mediumarray, NdisMediumMax, block, block);
804123474Swpaul
805123474Swpaul	/*
806123474Swpaul	 * If the init fails, blow away the other exported routines
807123474Swpaul	 * we obtained from the driver so we can't call them later.
808123474Swpaul	 * If the init failed, none of these will work.
809123474Swpaul	 */
810123474Swpaul	if (status != NDIS_STATUS_SUCCESS) {
811123474Swpaul		bzero((char *)&sc->ndis_chars,
812123474Swpaul		    sizeof(ndis_miniport_characteristics));
813123474Swpaul		return(ENXIO);
814123474Swpaul	}
815123474Swpaul
816123474Swpaul	return(0);
817123474Swpaul}
818123474Swpaul
819123474Swpaulvoid
820123474Swpaulndis_enable_intr(arg)
821123474Swpaul	void			*arg;
822123474Swpaul{
823123474Swpaul	struct ndis_softc	*sc;
824123474Swpaul	ndis_handle		adapter;
825123474Swpaul	__stdcall ndis_enable_interrupts_handler	intrenbfunc;
826123474Swpaul
827123474Swpaul	sc = arg;
828123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
829123474Swpaul	if (adapter == NULL)
830123474Swpaul	    return;
831123474Swpaul	intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
832123474Swpaul	if (intrenbfunc == NULL)
833123474Swpaul		return;
834123474Swpaul	intrenbfunc(adapter);
835123474Swpaul
836123474Swpaul	return;
837123474Swpaul}
838123474Swpaul
839123474Swpaulvoid
840123474Swpaulndis_disable_intr(arg)
841123474Swpaul	void			*arg;
842123474Swpaul{
843123474Swpaul	struct ndis_softc	*sc;
844123474Swpaul	ndis_handle		adapter;
845123474Swpaul	__stdcall ndis_disable_interrupts_handler	intrdisfunc;
846123474Swpaul
847123474Swpaul	sc = arg;
848123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
849123474Swpaul	if (adapter == NULL)
850123474Swpaul	    return;
851123474Swpaul	intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
852123474Swpaul	if (intrdisfunc == NULL)
853123474Swpaul		return;
854123474Swpaul	intrdisfunc(adapter);
855123474Swpaul
856123474Swpaul	return;
857123474Swpaul}
858123474Swpaul
859123474Swpaulint
860123474Swpaulndis_isr(arg, ourintr, callhandler)
861123474Swpaul	void			*arg;
862123474Swpaul	int			*ourintr;
863123474Swpaul	int			*callhandler;
864123474Swpaul{
865123474Swpaul	struct ndis_softc	*sc;
866123474Swpaul	ndis_handle		adapter;
867123474Swpaul	__stdcall ndis_isr_handler	isrfunc;
868123474Swpaul	uint8_t			accepted, queue;
869123474Swpaul
870123474Swpaul	if (arg == NULL || ourintr == NULL || callhandler == NULL)
871123474Swpaul		return(EINVAL);
872123474Swpaul
873123474Swpaul	sc = arg;
874123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
875123474Swpaul	isrfunc = sc->ndis_chars.nmc_isr_func;
876123474Swpaul	isrfunc(&accepted, &queue, adapter);
877123474Swpaul	*ourintr = accepted;
878123474Swpaul	*callhandler = queue;
879123474Swpaul
880123474Swpaul	return(0);
881123474Swpaul}
882123474Swpaul
883123474Swpaulint
884123474Swpaulndis_intrhand(arg)
885123474Swpaul	void			*arg;
886123474Swpaul{
887123474Swpaul	struct ndis_softc	*sc;
888123474Swpaul	ndis_handle		adapter;
889123474Swpaul	__stdcall ndis_interrupt_handler	intrfunc;
890123474Swpaul
891123474Swpaul	if (arg == NULL)
892123474Swpaul		return(EINVAL);
893123474Swpaul
894123474Swpaul	sc = arg;
895123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
896123474Swpaul	intrfunc = sc->ndis_chars.nmc_interrupt_func;
897123474Swpaul	intrfunc(adapter);
898123474Swpaul
899123474Swpaul	return(0);
900123474Swpaul}
901123474Swpaul
902123474Swpaulint
903123474Swpaulndis_get_info(arg, oid, buf, buflen)
904123474Swpaul	void			*arg;
905123474Swpaul	ndis_oid		oid;
906123474Swpaul	void			*buf;
907123474Swpaul	int			*buflen;
908123474Swpaul{
909123474Swpaul	struct ndis_softc	*sc;
910123474Swpaul	ndis_status		rval;
911123474Swpaul	ndis_handle		adapter;
912123474Swpaul	__stdcall ndis_queryinfo_handler	queryfunc;
913123474Swpaul	uint32_t		byteswritten = 0, bytesneeded = 0;
914123474Swpaul
915123474Swpaul	sc = arg;
916123474Swpaul	queryfunc = sc->ndis_chars.nmc_queryinfo_func;
917123474Swpaul	adapter = sc->ndis_block.nmb_miniportadapterctx;
918123474Swpaul
919123474Swpaul	rval = queryfunc(adapter, oid, buf, *buflen,
920123474Swpaul	    &byteswritten, &bytesneeded);
921123474Swpaul
922123474Swpaul	if (byteswritten)
923123474Swpaul		*buflen = byteswritten;
924123474Swpaul	if (bytesneeded)
925123474Swpaul		*buflen = bytesneeded;
926123474Swpaul
927123474Swpaul	if (rval == NDIS_STATUS_INVALID_LENGTH ||
928123474Swpaul	    rval == NDIS_STATUS_BUFFER_TOO_SHORT)
929123474Swpaul		return(ENOSPC);
930123474Swpaul
931123474Swpaul	if (rval == NDIS_STATUS_INVALID_OID)
932123474Swpaul		return(EINVAL);
933123474Swpaul
934123474Swpaul	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
935123474Swpaul	    rval == NDIS_STATUS_NOT_ACCEPTED)
936123474Swpaul		return(ENOTSUP);
937123474Swpaul
938123474Swpaul	if (rval == NDIS_STATUS_PENDING)
939123474Swpaul		return(EAGAIN);
940123474Swpaul
941123474Swpaul	return(0);
942123474Swpaul}
943123474Swpaul
944123474Swpaulint
945123474Swpaulndis_unload_driver(arg)
946123474Swpaul	void			*arg;
947123474Swpaul{
948123474Swpaul	struct ndis_softc	*sc;
949123474Swpaul
950123474Swpaul	sc = arg;
951123474Swpaul
952123474Swpaul	free(sc->ndis_block.nmb_rlist, M_DEVBUF);
953123474Swpaul
954123474Swpaul	ndis_flush_sysctls(sc);
955123474Swpaul	ndis_libfini();
956123474Swpaul	ntoskrnl_libfini();
957123474Swpaul
958123474Swpaul	return(0);
959123474Swpaul}
960123474Swpaul
961123474Swpaulint
962123474Swpaulndis_load_driver(img, arg)
963123474Swpaul	vm_offset_t		img;
964123474Swpaul	void			*arg;
965123474Swpaul{
966123474Swpaul	__stdcall driver_entry	entry;
967123474Swpaul	image_optional_header	opt_hdr;
968123474Swpaul	image_import_descriptor imp_desc;
969123474Swpaul	ndis_unicode_string	dummystr;
970123474Swpaul	ndis_driver_object	drv;
971123474Swpaul        ndis_miniport_block     *block;
972123474Swpaul	ndis_status		status;
973123474Swpaul	int			idx;
974123474Swpaul	uint32_t		*ptr;
975123474Swpaul	struct ndis_softc	*sc;
976123474Swpaul
977123474Swpaul	sc = arg;
978123474Swpaul
979123474Swpaul	/* Perform text relocation */
980123474Swpaul	if (pe_relocate(img))
981123474Swpaul		return(ENOEXEC);
982123474Swpaul
983123474Swpaul        /* Dynamically link the NDIS.SYS routines -- required. */
984123474Swpaul	if (pe_patch_imports(img, "NDIS", ndis_functbl))
985123474Swpaul		return(ENOEXEC);
986123474Swpaul
987123474Swpaul	/* Dynamically link the HAL.dll routines -- also required. */
988123474Swpaul	if (pe_patch_imports(img, "HAL", hal_functbl))
989123474Swpaul		return(ENOEXEC);
990123474Swpaul
991123474Swpaul	/* Dynamically link ntoskrnl.exe -- optional. */
992123474Swpaul	if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
993123474Swpaul		if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
994123474Swpaul			return(ENOEXEC);
995123474Swpaul	}
996123474Swpaul
997123474Swpaul	/* Initialize subsystems */
998123474Swpaul	ndis_libinit();
999123474Swpaul	ntoskrnl_libinit();
1000123474Swpaul
1001123474Swpaul        /* Locate the driver entry point */
1002123474Swpaul	pe_get_optional_header(img, &opt_hdr);
1003123474Swpaul	entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
1004123474Swpaul
1005123474Swpaul	/*
1006123474Swpaul	 * Now call the DriverEntry() routine. This will cause
1007123474Swpaul	 * a callout to the NdisInitializeWrapper() and
1008123474Swpaul	 * NdisMRegisterMiniport() routines.
1009123474Swpaul	 */
1010123474Swpaul	dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
1011123474Swpaul	dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
1012123474Swpaul	dummystr.nus_buf = NULL;
1013123474Swpaul	ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
1014123474Swpaul	drv.ndo_ifname = "ndis0";
1015123474Swpaul
1016123474Swpaul	status = entry(&drv, &dummystr);
1017123474Swpaul
1018123474Swpaul	free (dummystr.nus_buf, M_DEVBUF);
1019123474Swpaul
1020123474Swpaul	if (status != NDIS_STATUS_SUCCESS)
1021123474Swpaul		return(ENODEV);
1022123474Swpaul
1023123474Swpaul	/*
1024123474Swpaul	 * Now that we have the miniport driver characteristics,
1025123474Swpaul	 * create an NDIS block and call the init handler.
1026123474Swpaul	 * This will cause the driver to try to probe for
1027123474Swpaul	 * a device.
1028123474Swpaul	 */
1029123474Swpaul
1030123474Swpaul	block = &sc->ndis_block;
1031123474Swpaul	bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
1032123474Swpaul	    sizeof(ndis_miniport_characteristics));
1033123474Swpaul
1034123474Swpaul	/*block->nmb_signature = 0xcafebabe;*/
1035123474Swpaul
1036123474Swpaul		ptr = (uint32_t *)block;
1037123474Swpaul	for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
1038123474Swpaul		*ptr = idx | 0xdead0000;
1039123474Swpaul		ptr++;
1040123474Swpaul	}
1041123474Swpaul
1042123474Swpaul	block->nmb_signature = (void *)0xcafebabe;
1043123474Swpaul	block->nmb_setdone_func = ndis_setdone_func;
1044123474Swpaul	block->nmb_status_func = ndis_status_func;
1045123474Swpaul	block->nmb_statusdone_func = ndis_statusdone_func;
1046123474Swpaul	block->nmb_resetdone_func = ndis_resetdone_func;
1047123474Swpaul
1048123474Swpaul	block->nmb_ifp = &sc->arpcom.ac_if;
1049123474Swpaul	block->nmb_dev = sc->ndis_dev;
1050123474Swpaul
1051123474Swpaul	return(0);
1052123474Swpaul}
1053