kern_ndis.c revision 123474
1/*
2 * Copyright (c) 2003
3 *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/compat/ndis/kern_ndis.c 123474 2003-12-11 22:34:37Z wpaul $");
35
36#include <sys/param.h>
37#include <sys/types.h>
38#include <sys/errno.h>
39#include <sys/callout.h>
40#include <sys/socket.h>
41#include <sys/queue.h>
42#include <sys/sysctl.h>
43#include <sys/systm.h>
44#include <sys/malloc.h>
45#include <sys/lock.h>
46#include <sys/mutex.h>
47#include <sys/conf.h>
48
49#include <sys/kernel.h>
50#include <machine/bus.h>
51#include <machine/resource.h>
52#include <sys/bus.h>
53#include <sys/rman.h>
54
55#include <net/if.h>
56#include <net/if_arp.h>
57#include <net/ethernet.h>
58#include <net/if_dl.h>
59#include <net/if_media.h>
60
61#include <dev/pccard/pccardvar.h>
62#include "card_if.h"
63
64#include <compat/ndis/pe_var.h>
65#include <compat/ndis/resource_var.h>
66#include <compat/ndis/ndis_var.h>
67#include <compat/ndis/hal_var.h>
68#include <compat/ndis/ntoskrnl_var.h>
69#include <compat/ndis/cfg_var.h>
70#include <dev/if_ndis/if_ndisvar.h>
71
72#define __stdcall __attribute__((__stdcall__))
73#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path"
74
75__stdcall static void ndis_status_func(ndis_handle, ndis_status,
76	void *, uint32_t);
77__stdcall static void ndis_statusdone_func(ndis_handle);
78__stdcall static void ndis_setdone_func(ndis_handle, ndis_status);
79__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t);
80
81/*
82 * This allows us to export our symbols to other modules.
83 * Note that we call ourselves 'ndisapi' to avoid a namespace
84 * collision with if_ndis.ko, which internally calls itself
85 * 'ndis.'
86 */
87static int
88ndis_modevent(module_t mod, int cmd, void *arg)
89{
90	return(0);
91}
92DEV_MODULE(ndisapi, ndis_modevent, NULL);
93MODULE_VERSION(ndisapi, 1);
94
95
96__stdcall static void
97ndis_status_func(adapter, status, sbuf, slen)
98	ndis_handle		adapter;
99	ndis_status		status;
100	void			*sbuf;
101	uint32_t		slen;
102{
103	printf ("status: %x\n", status);
104	return;
105}
106
107__stdcall static void
108ndis_statusdone_func(adapter)
109	ndis_handle		adapter;
110{
111	printf ("status complete\n");
112	return;
113}
114
115__stdcall static void
116ndis_setdone_func(adapter, status)
117	ndis_handle		adapter;
118	ndis_status		status;
119{
120	printf ("Setup done... %x\n", status);
121	return;
122}
123
124__stdcall static void
125ndis_resetdone_func(adapter, status, addressingreset)
126	ndis_handle		adapter;
127	ndis_status		status;
128	uint8_t			addressingreset;
129{
130	printf ("reset done...\n");
131	return;
132}
133
134#define NDIS_AM_RID	3
135
136int
137ndis_alloc_amem(arg)
138	void			*arg;
139{
140	struct ndis_softc	*sc;
141	int			error, rid;
142
143	if (arg == NULL)
144		return(EINVAL);
145
146	sc = arg;
147	rid = NDIS_AM_RID;
148	sc->ndis_res_am = bus_alloc_resource(sc->ndis_dev, SYS_RES_MEMORY,
149	    &rid, 0UL, ~0UL, 0x1000, RF_ACTIVE);
150
151	if (sc->ndis_res_am == NULL) {
152		printf("ndis%d: failed to allocate attribute memory\n",
153		    sc->ndis_unit);
154		return(ENXIO);
155	}
156
157	error = CARD_SET_MEMORY_OFFSET(device_get_parent(sc->ndis_dev),
158	    sc->ndis_dev, rid, 0, NULL);
159
160	if (error) {
161		printf("ndis%d: CARD_SET_MEMORY_OFFSET() returned 0x%x\n",
162		    sc->ndis_unit, error);
163		return(error);
164	}
165
166	error = CARD_SET_RES_FLAGS(device_get_parent(sc->ndis_dev),
167	    sc->ndis_dev, SYS_RES_MEMORY, rid, PCCARD_A_MEM_ATTR);
168
169	if (error) {
170		printf("ndis%d: CARD_SET_RES_FLAGS() returned 0x%x\n",
171		    sc->ndis_unit, error);
172		return(error);
173	}
174
175	return(0);
176}
177
178int
179ndis_create_sysctls(arg)
180	void			*arg;
181{
182	struct ndis_softc	*sc;
183	ndis_cfg		*vals;
184	char			buf[256];
185
186	if (arg == NULL)
187		return(EINVAL);
188
189	sc = arg;
190	vals = sc->ndis_regvals;
191
192	TAILQ_INIT(&sc->ndis_cfglist_head);
193
194	/* Create the sysctl tree. */
195
196	sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx,
197	    SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
198	    device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0,
199	    device_get_desc(sc->ndis_dev));
200
201	/* Add the driver-specific registry keys. */
202
203	vals = sc->ndis_regvals;
204	while(1) {
205		if (vals->nc_cfgkey == NULL)
206			break;
207		SYSCTL_ADD_STRING(&sc->ndis_ctx,
208		    SYSCTL_CHILDREN(sc->ndis_tree),
209		    OID_AUTO, vals->nc_cfgkey,
210		    CTLFLAG_RW, vals->nc_val,
211		    sizeof(vals->nc_val),
212		    vals->nc_cfgdesc);
213		vals++;
214	}
215
216	/* Now add a couple of builtin keys. */
217
218	/*
219	 * Environment can be either Windows (0) or WindowsNT (1).
220	 * We qualify as the latter.
221	 */
222	ndis_add_sysctl(sc, "Environment",
223	    "Windows environment", "1", CTLFLAG_RD);
224
225	/* NDIS version should be 5.1. */
226	ndis_add_sysctl(sc, "NdisVersion",
227	    "NDIS API Version", "0x00050001", CTLFLAG_RD);
228
229	/* Bus type (PCI, PCMCIA, etc...) */
230	sprintf(buf, "%d\n", (int)sc->ndis_iftype);
231	ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD);
232
233	if (sc->ndis_res_io != NULL) {
234		sprintf(buf, "0x%lx\n", rman_get_start(sc->ndis_res_io));
235		ndis_add_sysctl(sc, "IOBaseAddress",
236		    "Base I/O Address", buf, CTLFLAG_RD);
237	}
238
239	if (sc->ndis_irq != NULL) {
240		sprintf(buf, "%lu\n", rman_get_start(sc->ndis_irq));
241		ndis_add_sysctl(sc, "InterruptNumber",
242		    "Interrupt Number", buf, CTLFLAG_RD);
243	}
244
245	return(0);
246}
247
248int
249ndis_add_sysctl(arg, key, desc, val, flag)
250	void			*arg;
251	char			*key;
252	char			*desc;
253	char			*val;
254	int			flag;
255{
256	struct ndis_softc	*sc;
257	struct ndis_cfglist	*cfg;
258	char			descstr[256];
259
260	sc = arg;
261
262	cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO);
263
264	if (cfg == NULL)
265		return(ENOMEM);
266
267	cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF);
268	if (desc == NULL) {
269		snprintf(descstr, sizeof(descstr), "%s (dynamic)", key);
270		cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF);
271	} else
272		cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF);
273	strcpy(cfg->ndis_cfg.nc_val, val);
274
275	TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link);
276
277	SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree),
278	    OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag,
279	    cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val),
280	    cfg->ndis_cfg.nc_cfgdesc);
281
282	return(0);
283}
284
285int
286ndis_flush_sysctls(arg)
287	void			*arg;
288{
289	struct ndis_softc	*sc;
290	struct ndis_cfglist	*cfg;
291
292	sc = arg;
293
294	while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) {
295		cfg = TAILQ_FIRST(&sc->ndis_cfglist_head);
296		TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link);
297		free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF);
298		free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF);
299		free(cfg, M_DEVBUF);
300	}
301
302	return(0);
303}
304
305void
306ndis_return_packet(packet, arg)
307	void			*packet;
308	void			*arg;
309{
310	struct ndis_softc	*sc;
311	ndis_handle		adapter;
312	__stdcall ndis_return_handler	returnfunc;
313
314	if (arg == NULL || packet == NULL)
315		return;
316
317	sc = arg;
318	returnfunc = sc->ndis_chars.nmc_return_packet_func;
319	adapter = sc->ndis_block.nmb_miniportadapterctx;
320	if (returnfunc == NULL)
321		ndis_free_packet((ndis_packet *)packet);
322	else
323		returnfunc(adapter, (ndis_packet *)packet);
324	return;
325}
326
327void
328ndis_free_bufs(b0)
329	ndis_buffer		*b0;
330{
331	ndis_buffer		*next;
332
333	if (b0 == NULL)
334		return;
335
336	while(b0 != NULL) {
337		next = b0->nb_next;
338		free (b0, M_DEVBUF);
339		b0 = next;
340	}
341
342	return;
343}
344
345void
346ndis_free_packet(p)
347	ndis_packet		*p;
348{
349	if (p == NULL)
350		return;
351
352	ndis_free_bufs(p->np_private.npp_head);
353	free(p, M_DEVBUF);
354
355	return;
356}
357
358int
359ndis_convert_res(arg)
360	void			*arg;
361{
362	struct ndis_softc	*sc;
363	ndis_resource_list	*rl = NULL;
364	cm_partial_resource_desc	*prd = NULL;
365	ndis_miniport_block	*block;
366
367	sc = arg;
368	block = &sc->ndis_block;
369
370	rl = malloc(sizeof(ndis_resource_list) +
371	    (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)),
372	    M_DEVBUF, M_NOWAIT|M_ZERO);
373
374	if (rl == NULL)
375		return(ENOMEM);
376
377	rl->cprl_version = 5;
378	rl->cprl_version = 1;
379	rl->cprl_count = sc->ndis_rescnt;
380
381	prd = rl->cprl_partial_descs;
382	if (sc->ndis_res_io) {
383		prd->cprd_type = CmResourceTypePort;
384		prd->u.cprd_port.cprd_start.np_quad =
385		    rman_get_start(sc->ndis_res_io);
386		prd->u.cprd_port.cprd_len =
387		    rman_get_size(sc->ndis_res_io);
388		prd++;
389	}
390
391	if (sc->ndis_res_mem) {
392		prd->cprd_type = CmResourceTypeMemory;
393		prd->u.cprd_mem.cprd_start.np_quad =
394		    rman_get_start(sc->ndis_res_mem);
395		prd->u.cprd_mem.cprd_len =
396		    rman_get_size(sc->ndis_res_mem);
397		prd++;
398	}
399
400	if (sc->ndis_irq) {
401		prd->cprd_type = CmResourceTypeInterrupt;
402		prd->u.cprd_intr.cprd_level =
403		    rman_get_start(sc->ndis_irq);
404		prd->u.cprd_intr.cprd_vector =
405		    rman_get_start(sc->ndis_irq);
406		prd->u.cprd_intr.cprd_affinity = 0;
407	}
408
409	block->nmb_rlist = rl;
410
411	return(0);
412}
413
414/*
415 * Map an NDIS packet to an mbuf list. When an NDIS driver receives a
416 * packet, it will hand it to us in the form of an ndis_packet,
417 * which we need to convert to an mbuf that is then handed off
418 * to the stack. Note: we configure the mbuf list so that it uses
419 * the memory regions specified by the ndis_buffer structures in
420 * the ndis_packet as external storage. In most cases, this will
421 * point to a memory region allocated by the driver (either by
422 * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect
423 * the driver to handle free()ing this region for is, so we set up
424 * a dummy no-op free handler for it.
425 */
426
427int
428ndis_ptom(m0, p)
429	struct mbuf		**m0;
430	ndis_packet		*p;
431{
432	struct mbuf		*m, *prev = NULL;
433	ndis_buffer		*buf;
434	ndis_packet_private	*priv;
435	uint32_t		totlen = 0;
436
437	if (p == NULL || m0 == NULL)
438		return(EINVAL);
439
440	priv = &p->np_private;
441	buf = priv->npp_head;
442
443	for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) {
444		if (buf == priv->npp_head)
445			MGETHDR(m, M_DONTWAIT, MT_HEADER);
446		else
447			MGET(m, M_DONTWAIT, MT_DATA);
448		if (m == NULL) {
449			m_freem(*m0);
450			*m0 = NULL;
451			return(ENOBUFS);
452		}
453
454		/*
455		 * Note: there's some hackery going on here. We want
456		 * to mate the mbufs to the buffers in the NDIS packet,
457		 * but we don't mark the mbufs with the M_EXT flag to
458		 * indicate external storage. This is because we don't
459		 * want anything special done to free the buffers.
460		 * Depending on the circumstances, the caller may want
461		 * the entire packet to be released, buffers and all,
462		 * by calling ndis_return_packet(), or ndis_free_packet().
463		 * We leave it up to the caller to do the MEXTADD() to
464		 * set up the free mechanism in the first mbuf of the
465		 * chain.
466		 */
467		if (buf->nb_size)
468			m->m_len = buf->nb_size;
469		else
470			m->m_len = buf->nb_bytecount;
471		m->m_data = buf->nb_mappedsystemva;
472		totlen += m->m_len;
473		if (m->m_flags & MT_HEADER)
474			*m0 = m;
475		else
476			prev->m_next = m;
477		prev = m;
478	}
479
480	(*m0)->m_pkthdr.len = totlen;
481
482	return(0);
483}
484
485/*
486 * Create an mbuf chain from an NDIS packet chain.
487 * This is used mainly when transmitting packets, where we need
488 * to turn an mbuf off an interface's send queue and transform it
489 * into an NDIS packet which will be fed into the NDIS driver's
490 * send routine.
491 *
492 * NDIS packets consist of two parts: an ndis_packet structure,
493 * which is vaguely analagous to the pkthdr portion of an mbuf,
494 * and one or more ndis_buffer structures, which define the
495 * actual memory segments in which the packet data resides.
496 * We need to allocate one ndis_buffer for each mbuf in a chain,
497 * plus one ndis_packet as the header.
498 */
499
500int
501ndis_mtop(m0, p)
502	struct mbuf		*m0;
503	ndis_packet		**p;
504{
505	struct mbuf		*m;
506	ndis_buffer		*buf = NULL, *prev = NULL;
507	ndis_packet_private	*priv;
508
509	if (p == NULL || m0 == NULL)
510		return(EINVAL);
511
512	/* If caller didn't supply a packet, make one. */
513	if (*p == NULL) {
514		*p = malloc(sizeof(ndis_packet), M_DEVBUF, M_NOWAIT|M_ZERO);
515
516		if (*p == NULL)
517			return(ENOMEM);
518	}
519
520	priv = &(*p)->np_private;
521	priv->npp_totlen = m0->m_pkthdr.len;
522        priv->npp_packetooboffset = offsetof(ndis_packet, np_oob);
523
524	for (m = m0; m != NULL; m = m->m_next) {
525		if (m->m_len == NULL)
526			continue;
527
528		buf = malloc(sizeof(ndis_buffer), M_DEVBUF, M_NOWAIT|M_ZERO);
529		if (buf == NULL) {
530			ndis_free_packet(*p);
531			*p = NULL;
532			return(ENOMEM);
533		}
534
535		buf->nb_bytecount = m->m_len;
536		buf->nb_mappedsystemva = m->m_data;
537		if (priv->npp_head == NULL)
538			priv->npp_head = buf;
539		else
540			prev->nb_next = buf;
541		prev = buf;
542	}
543
544	priv->npp_tail = buf;
545
546	return(0);
547}
548
549int
550ndis_get_supported_oids(arg, oids, oidcnt)
551	void			*arg;
552	ndis_oid		**oids;
553	int			*oidcnt;
554{
555	int			len, rval;
556	ndis_oid		*o;
557
558	if (arg == NULL || oids == NULL || oidcnt == NULL)
559		return(EINVAL);
560	len = 0;
561	ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len);
562
563	o = malloc(len, M_DEVBUF, M_NOWAIT);
564	if (o == NULL)
565		return(ENOMEM);
566
567	rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len);
568
569	if (rval) {
570		free(o, M_DEVBUF);
571		return(rval);
572	}
573
574	*oids = o;
575	*oidcnt = len / 4;
576
577	return(0);
578}
579
580int
581ndis_set_info(arg, oid, buf, buflen)
582	void			*arg;
583	ndis_oid		oid;
584	void			*buf;
585	int			*buflen;
586{
587	struct ndis_softc	*sc;
588	ndis_status		rval;
589	ndis_handle		adapter;
590	__stdcall ndis_setinfo_handler	setfunc;
591	uint32_t		byteswritten = 0, bytesneeded = 0;
592
593	sc = arg;
594	setfunc = sc->ndis_chars.nmc_setinfo_func;
595	adapter = sc->ndis_block.nmb_miniportadapterctx;
596
597	rval = setfunc(adapter, oid, buf, *buflen,
598	    &byteswritten, &bytesneeded);
599
600	if (byteswritten)
601		*buflen = byteswritten;
602	if (bytesneeded)
603		*buflen = bytesneeded;
604
605	if (rval == NDIS_STATUS_INVALID_LENGTH)
606		return(ENOSPC);
607
608	if (rval == NDIS_STATUS_INVALID_OID)
609		return(EINVAL);
610
611	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
612	    rval == NDIS_STATUS_NOT_ACCEPTED)
613		return(ENOTSUP);
614
615	if (rval == NDIS_STATUS_PENDING)
616		return(EAGAIN);
617
618	return(0);
619}
620
621int
622ndis_send_packets(arg, packets, cnt)
623	void			*arg;
624	ndis_packet		**packets;
625	int			cnt;
626{
627	struct ndis_softc	*sc;
628	ndis_handle		adapter;
629	__stdcall ndis_sendmulti_handler	sendfunc;
630
631	sc = arg;
632	adapter = sc->ndis_block.nmb_miniportadapterctx;
633	sendfunc = sc->ndis_chars.nmc_sendmulti_func;
634	sendfunc(adapter, packets, cnt);
635
636	return(0);
637}
638
639int
640ndis_init_dma(arg)
641	void			*arg;
642{
643	struct ndis_softc	*sc;
644	int			i, error;
645
646	sc = arg;
647
648	sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts,
649	    M_DEVBUF, M_NOWAIT|M_ZERO);
650
651	if (sc->ndis_tmaps == NULL)
652		return(ENOMEM);
653
654	sc->ndis_mbufs = malloc(sizeof(struct mbuf) * sc->ndis_maxpkts,
655	    M_DEVBUF, M_NOWAIT|M_ZERO);
656
657	if (sc->ndis_mbufs == NULL) {
658		free(sc->ndis_tmaps, M_DEVBUF);
659		return(ENOMEM);
660	}
661
662	for (i = 0; i < sc->ndis_maxpkts; i++) {
663		error = bus_dmamap_create(sc->ndis_ttag, 0,
664		    &sc->ndis_tmaps[i]);
665		if (error) {
666			free(sc->ndis_tmaps, M_DEVBUF);
667			free(sc->ndis_mbufs, M_DEVBUF);
668			return(ENODEV);
669		}
670	}
671
672	return(0);
673}
674
675int
676ndis_destroy_dma(arg)
677	void			*arg;
678{
679	struct ndis_softc	*sc;
680	int			i;
681
682	sc = arg;
683
684	for (i = 0; i < sc->ndis_maxpkts; i++) {
685		if (sc->ndis_mbufs[i] != NULL)
686			m_freem(sc->ndis_mbufs[i]);
687		bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]);
688	}
689
690	free(sc->ndis_tmaps, M_DEVBUF);
691	free(sc->ndis_mbufs, M_DEVBUF);
692
693	bus_dma_tag_destroy(sc->ndis_ttag);
694
695	return(0);
696}
697
698int
699ndis_reset_nic(arg)
700	void			*arg;
701{
702	struct ndis_softc	*sc;
703	ndis_handle		adapter;
704	__stdcall ndis_reset_handler	resetfunc;
705	uint8_t			addressing_reset;
706	struct ifnet		*ifp;
707
708	sc = arg;
709	ifp = &sc->arpcom.ac_if;
710	adapter = sc->ndis_block.nmb_miniportadapterctx;
711	if (adapter == NULL)
712		return(EIO);
713	resetfunc = sc->ndis_chars.nmc_reset_func;
714
715	if (resetfunc == NULL)
716		return(EINVAL);
717
718	resetfunc(&addressing_reset, adapter);
719
720	return(0);
721}
722
723int
724ndis_halt_nic(arg)
725	void			*arg;
726{
727	struct ndis_softc	*sc;
728	ndis_handle		adapter;
729	__stdcall ndis_halt_handler	haltfunc;
730	struct ifnet		*ifp;
731
732	sc = arg;
733	ifp = &sc->arpcom.ac_if;
734	adapter = sc->ndis_block.nmb_miniportadapterctx;
735	if (adapter == NULL)
736		return(EIO);
737	haltfunc = sc->ndis_chars.nmc_halt_func;
738
739	if (haltfunc == NULL)
740		return(EINVAL);
741
742	haltfunc(adapter);
743
744	/*
745	 * The adapter context is only valid after the init
746	 * handler has been called, and is invalid once the
747	 * halt handler has been called.
748	 */
749
750	sc->ndis_block.nmb_miniportadapterctx = NULL;
751
752	return(0);
753}
754
755int
756ndis_shutdown_nic(arg)
757	void			*arg;
758{
759	struct ndis_softc	*sc;
760	ndis_handle		adapter;
761	__stdcall ndis_shutdown_handler	shutdownfunc;
762
763
764	sc = arg;
765	adapter = sc->ndis_block.nmb_miniportadapterctx;
766	if (adapter == NULL)
767		return(EIO);
768	shutdownfunc = sc->ndis_chars.nmc_shutdown_handler;
769
770	if (shutdownfunc == NULL)
771		return(EINVAL);
772
773	shutdownfunc(sc->ndis_chars.nmc_rsvd0);
774
775	return(0);
776}
777
778int
779ndis_init_nic(arg)
780	void			*arg;
781{
782	struct ndis_softc	*sc;
783	ndis_miniport_block	*block;
784        __stdcall ndis_init_handler	initfunc;
785	ndis_status		status, openstatus = 0;
786	ndis_medium		mediumarray[NdisMediumMax];
787	uint32_t		chosenmedium, i;
788
789	if (arg == NULL)
790		return(EINVAL);
791
792	sc = arg;
793	block = &sc->ndis_block;
794	initfunc = sc->ndis_chars.nmc_init_func;
795
796	for (i = 0; i < NdisMediumMax; i++)
797		mediumarray[i] = i;
798
799        status = initfunc(&openstatus, &chosenmedium,
800            mediumarray, NdisMediumMax, block, block);
801
802	/*
803	 * If the init fails, blow away the other exported routines
804	 * we obtained from the driver so we can't call them later.
805	 * If the init failed, none of these will work.
806	 */
807	if (status != NDIS_STATUS_SUCCESS) {
808		bzero((char *)&sc->ndis_chars,
809		    sizeof(ndis_miniport_characteristics));
810		return(ENXIO);
811	}
812
813	return(0);
814}
815
816void
817ndis_enable_intr(arg)
818	void			*arg;
819{
820	struct ndis_softc	*sc;
821	ndis_handle		adapter;
822	__stdcall ndis_enable_interrupts_handler	intrenbfunc;
823
824	sc = arg;
825	adapter = sc->ndis_block.nmb_miniportadapterctx;
826	if (adapter == NULL)
827	    return;
828	intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func;
829	if (intrenbfunc == NULL)
830		return;
831	intrenbfunc(adapter);
832
833	return;
834}
835
836void
837ndis_disable_intr(arg)
838	void			*arg;
839{
840	struct ndis_softc	*sc;
841	ndis_handle		adapter;
842	__stdcall ndis_disable_interrupts_handler	intrdisfunc;
843
844	sc = arg;
845	adapter = sc->ndis_block.nmb_miniportadapterctx;
846	if (adapter == NULL)
847	    return;
848	intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func;
849	if (intrdisfunc == NULL)
850		return;
851	intrdisfunc(adapter);
852
853	return;
854}
855
856int
857ndis_isr(arg, ourintr, callhandler)
858	void			*arg;
859	int			*ourintr;
860	int			*callhandler;
861{
862	struct ndis_softc	*sc;
863	ndis_handle		adapter;
864	__stdcall ndis_isr_handler	isrfunc;
865	uint8_t			accepted, queue;
866
867	if (arg == NULL || ourintr == NULL || callhandler == NULL)
868		return(EINVAL);
869
870	sc = arg;
871	adapter = sc->ndis_block.nmb_miniportadapterctx;
872	isrfunc = sc->ndis_chars.nmc_isr_func;
873	isrfunc(&accepted, &queue, adapter);
874	*ourintr = accepted;
875	*callhandler = queue;
876
877	return(0);
878}
879
880int
881ndis_intrhand(arg)
882	void			*arg;
883{
884	struct ndis_softc	*sc;
885	ndis_handle		adapter;
886	__stdcall ndis_interrupt_handler	intrfunc;
887
888	if (arg == NULL)
889		return(EINVAL);
890
891	sc = arg;
892	adapter = sc->ndis_block.nmb_miniportadapterctx;
893	intrfunc = sc->ndis_chars.nmc_interrupt_func;
894	intrfunc(adapter);
895
896	return(0);
897}
898
899int
900ndis_get_info(arg, oid, buf, buflen)
901	void			*arg;
902	ndis_oid		oid;
903	void			*buf;
904	int			*buflen;
905{
906	struct ndis_softc	*sc;
907	ndis_status		rval;
908	ndis_handle		adapter;
909	__stdcall ndis_queryinfo_handler	queryfunc;
910	uint32_t		byteswritten = 0, bytesneeded = 0;
911
912	sc = arg;
913	queryfunc = sc->ndis_chars.nmc_queryinfo_func;
914	adapter = sc->ndis_block.nmb_miniportadapterctx;
915
916	rval = queryfunc(adapter, oid, buf, *buflen,
917	    &byteswritten, &bytesneeded);
918
919	if (byteswritten)
920		*buflen = byteswritten;
921	if (bytesneeded)
922		*buflen = bytesneeded;
923
924	if (rval == NDIS_STATUS_INVALID_LENGTH ||
925	    rval == NDIS_STATUS_BUFFER_TOO_SHORT)
926		return(ENOSPC);
927
928	if (rval == NDIS_STATUS_INVALID_OID)
929		return(EINVAL);
930
931	if (rval == NDIS_STATUS_NOT_SUPPORTED ||
932	    rval == NDIS_STATUS_NOT_ACCEPTED)
933		return(ENOTSUP);
934
935	if (rval == NDIS_STATUS_PENDING)
936		return(EAGAIN);
937
938	return(0);
939}
940
941int
942ndis_unload_driver(arg)
943	void			*arg;
944{
945	struct ndis_softc	*sc;
946
947	sc = arg;
948
949	free(sc->ndis_block.nmb_rlist, M_DEVBUF);
950
951	ndis_flush_sysctls(sc);
952	ndis_libfini();
953	ntoskrnl_libfini();
954
955	return(0);
956}
957
958int
959ndis_load_driver(img, arg)
960	vm_offset_t		img;
961	void			*arg;
962{
963	__stdcall driver_entry	entry;
964	image_optional_header	opt_hdr;
965	image_import_descriptor imp_desc;
966	ndis_unicode_string	dummystr;
967	ndis_driver_object	drv;
968        ndis_miniport_block     *block;
969	ndis_status		status;
970	int			idx;
971	uint32_t		*ptr;
972	struct ndis_softc	*sc;
973
974	sc = arg;
975
976	/* Perform text relocation */
977	if (pe_relocate(img))
978		return(ENOEXEC);
979
980        /* Dynamically link the NDIS.SYS routines -- required. */
981	if (pe_patch_imports(img, "NDIS", ndis_functbl))
982		return(ENOEXEC);
983
984	/* Dynamically link the HAL.dll routines -- also required. */
985	if (pe_patch_imports(img, "HAL", hal_functbl))
986		return(ENOEXEC);
987
988	/* Dynamically link ntoskrnl.exe -- optional. */
989	if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
990		if (pe_patch_imports(img, "ntoskrnl", ntoskrnl_functbl))
991			return(ENOEXEC);
992	}
993
994	/* Initialize subsystems */
995	ndis_libinit();
996	ntoskrnl_libinit();
997
998        /* Locate the driver entry point */
999	pe_get_optional_header(img, &opt_hdr);
1000	entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr);
1001
1002	/*
1003	 * Now call the DriverEntry() routine. This will cause
1004	 * a callout to the NdisInitializeWrapper() and
1005	 * NdisMRegisterMiniport() routines.
1006	 */
1007	dummystr.nus_len = strlen(NDIS_DUMMY_PATH);
1008	dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH);
1009	dummystr.nus_buf = NULL;
1010	ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf);
1011	drv.ndo_ifname = "ndis0";
1012
1013	status = entry(&drv, &dummystr);
1014
1015	free (dummystr.nus_buf, M_DEVBUF);
1016
1017	if (status != NDIS_STATUS_SUCCESS)
1018		return(ENODEV);
1019
1020	/*
1021	 * Now that we have the miniport driver characteristics,
1022	 * create an NDIS block and call the init handler.
1023	 * This will cause the driver to try to probe for
1024	 * a device.
1025	 */
1026
1027	block = &sc->ndis_block;
1028	bcopy((char *)&drv.ndo_chars, (char *)&sc->ndis_chars,
1029	    sizeof(ndis_miniport_characteristics));
1030
1031	/*block->nmb_signature = 0xcafebabe;*/
1032
1033		ptr = (uint32_t *)block;
1034	for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) {
1035		*ptr = idx | 0xdead0000;
1036		ptr++;
1037	}
1038
1039	block->nmb_signature = (void *)0xcafebabe;
1040	block->nmb_setdone_func = ndis_setdone_func;
1041	block->nmb_status_func = ndis_status_func;
1042	block->nmb_statusdone_func = ndis_statusdone_func;
1043	block->nmb_resetdone_func = ndis_resetdone_func;
1044
1045	block->nmb_ifp = &sc->arpcom.ac_if;
1046	block->nmb_dev = sc->ndis_dev;
1047
1048	return(0);
1049}
1050