Equivalent to: FreeBSD rev 1.82
[dragonfly.git] / sys / emulation / ndis / subr_ndis.c
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  * $FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.62 2004/07/11 00:19:30 wpaul Exp $
33  * $DragonFly: src/sys/emulation/ndis/subr_ndis.c,v 1.8 2004/11/17 18:59:21 dillon Exp $
34  */
35
36 /*
37  * This file implements a translation layer between the BSD networking
38  * infrasturcture and Windows(R) NDIS network driver modules. A Windows
39  * NDIS driver calls into several functions in the NDIS.SYS Windows
40  * kernel module and exports a table of functions designed to be called
41  * by the NDIS subsystem. Using the PE loader, we can patch our own
42  * versions of the NDIS routines into a given Windows driver module and
43  * convince the driver that it is in fact running on Windows.
44  *
45  * We provide a table of all our implemented NDIS routines which is patched
46  * into the driver object code. All our exported routines must use the
47  * _stdcall calling convention, since that's what the Windows object code
48  * expects.
49  */
50
51
52 #include <sys/ctype.h>
53 #include <sys/param.h>
54 #include <sys/types.h>
55 #include <sys/errno.h>
56
57 #include <sys/callout.h>
58 #include <sys/kernel.h>
59 #include <sys/systm.h>
60 #include <sys/malloc.h>
61 #include <sys/lock.h>
62 #include <sys/socket.h>
63 #include <sys/sysctl.h>
64 #include <sys/queue.h>
65 #include <sys/proc.h>
66 #include <sys/filedesc.h>
67 #include <sys/nlookup.h>
68 #include <sys/fcntl.h>
69 #include <sys/vnode.h>
70 #include <sys/kthread.h>
71
72 #include <net/if.h>
73 #include <net/if_arp.h>
74 #include <net/ethernet.h>
75 #include <net/if_dl.h>
76 #include <net/if_media.h>
77
78 #include <machine/atomic.h>
79 #include <machine/bus_memio.h>
80 #include <machine/bus_pio.h>
81 #include <machine/bus.h>
82 #include <machine/resource.h>
83
84 #include <sys/bus.h>
85 #include <sys/rman.h>
86
87 #include <machine/stdarg.h>
88
89 #include <netproto/802_11/ieee80211_var.h>
90 #include <netproto/802_11/ieee80211_ioctl.h>
91
92 #include <bus/pci/pcireg.h>
93 #include <bus/pci/pcivar.h>
94
95 #include "regcall.h"
96 #include "pe_var.h"
97 #include "resource_var.h"
98 #include "ntoskrnl_var.h"
99 #include "hal_var.h"
100 #include "ndis_var.h"
101 #include "cfg_var.h"
102 #include <dev/netif/ndis/if_ndisvar.h>
103
104 #define FUNC void(*)(void)
105
106 static char ndis_filepath[MAXPATHLEN];
107 extern struct nd_head ndis_devhead;
108
109 SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
110         MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
111
112 __stdcall static void ndis_initwrap(ndis_handle *,
113         device_object *, void *, void *);
114 __stdcall static ndis_status ndis_register_miniport(ndis_handle,
115         ndis_miniport_characteristics *, int);
116 __stdcall static ndis_status ndis_malloc_withtag(void **, uint32_t, uint32_t);
117 __stdcall static ndis_status ndis_malloc(void **,
118         uint32_t, uint32_t, ndis_physaddr);
119 __stdcall static void ndis_free(void *, uint32_t, uint32_t);
120 __stdcall static ndis_status ndis_setattr_ex(ndis_handle, ndis_handle,
121         uint32_t, uint32_t, ndis_interface_type);
122 __stdcall static void ndis_open_cfg(ndis_status *, ndis_handle *, ndis_handle);
123 __stdcall static void ndis_open_cfgbyidx(ndis_status *, ndis_handle,
124         uint32_t, ndis_unicode_string *, ndis_handle *);
125 __stdcall static void ndis_open_cfgbyname(ndis_status *, ndis_handle,
126         ndis_unicode_string *, ndis_handle *);
127 static ndis_status ndis_encode_parm(ndis_miniport_block *,
128         struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
129 static ndis_status ndis_decode_parm(ndis_miniport_block *,
130         ndis_config_parm *, char *);
131 __stdcall static void ndis_read_cfg(ndis_status *, ndis_config_parm **,
132         ndis_handle, ndis_unicode_string *, ndis_parm_type);
133 __stdcall static void ndis_write_cfg(ndis_status *, ndis_handle,
134         ndis_unicode_string *, ndis_config_parm *);
135 __stdcall static void ndis_close_cfg(ndis_handle);
136 __stdcall static void ndis_create_lock(ndis_spin_lock *);
137 __stdcall static void ndis_destroy_lock(ndis_spin_lock *);
138 __stdcall static void ndis_lock(ndis_spin_lock *);
139 __stdcall static void ndis_unlock(ndis_spin_lock *);
140 __stdcall static void ndis_lock_dpr(ndis_spin_lock *);
141 __stdcall static void ndis_unlock_dpr(ndis_spin_lock *);
142 __stdcall static uint32_t ndis_read_pci(ndis_handle, uint32_t,
143         uint32_t, void *, uint32_t);
144 __stdcall static uint32_t ndis_write_pci(ndis_handle, uint32_t,
145         uint32_t, void *, uint32_t);
146 static void ndis_syslog(ndis_handle, ndis_error_code, uint32_t, ...);
147 static void ndis_map_cb(void *, bus_dma_segment_t *, int, int);
148 __stdcall static void ndis_vtophys_load(ndis_handle, ndis_buffer *,
149         uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *);
150 __stdcall static void ndis_vtophys_unload(ndis_handle, ndis_buffer *, uint32_t);
151 __stdcall static void ndis_create_timer(ndis_miniport_timer *, ndis_handle,
152         ndis_timer_function, void *);
153 __stdcall static void ndis_init_timer(ndis_timer *,
154         ndis_timer_function, void *);
155 __stdcall static void ndis_set_timer(ndis_timer *, uint32_t);
156 __stdcall static void ndis_set_periodic_timer(ndis_miniport_timer *, uint32_t);
157 __stdcall static void ndis_cancel_timer(ndis_timer *, uint8_t *);
158 __stdcall static void ndis_query_resources(ndis_status *, ndis_handle,
159         ndis_resource_list *, uint32_t *);
160 __stdcall static ndis_status ndis_register_ioport(void **,
161         ndis_handle, uint32_t, uint32_t);
162 __stdcall static void ndis_deregister_ioport(ndis_handle,
163         uint32_t, uint32_t, void *);
164 __stdcall static void ndis_read_netaddr(ndis_status *, void **,
165         uint32_t *, ndis_handle);
166 __stdcall static ndis_status ndis_mapreg_cnt(uint32_t, uint32_t *);
167 __stdcall static ndis_status ndis_alloc_mapreg(ndis_handle,
168         uint32_t, uint8_t, uint32_t, uint32_t);
169 __stdcall static void ndis_free_mapreg(ndis_handle);
170 static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int);
171 __stdcall static void ndis_alloc_sharedmem(ndis_handle, uint32_t,
172         uint8_t, void **, ndis_physaddr *);
173 static void ndis_asyncmem_complete(void *);
174 __stdcall static ndis_status ndis_alloc_sharedmem_async(ndis_handle,
175         uint32_t, uint8_t, void *);
176 __stdcall static void ndis_free_sharedmem(ndis_handle, uint32_t,
177         uint8_t, void *, ndis_physaddr);
178 __stdcall static ndis_status ndis_map_iospace(void **, ndis_handle,
179         ndis_physaddr, uint32_t);
180 __stdcall static void ndis_unmap_iospace(ndis_handle, void *, uint32_t);
181 __stdcall static uint32_t ndis_cachefill(void);
182 __stdcall static uint32_t ndis_dma_align(ndis_handle);
183 __stdcall static ndis_status ndis_init_sc_dma(ndis_handle,
184         uint8_t, uint32_t);
185 __stdcall static void ndis_alloc_packetpool(ndis_status *,
186         ndis_handle *, uint32_t, uint32_t);
187 __stdcall static void ndis_ex_alloc_packetpool(ndis_status *,
188         ndis_handle *, uint32_t, uint32_t, uint32_t);
189 __stdcall static uint32_t ndis_packetpool_use(ndis_handle);
190 __stdcall static void ndis_free_packetpool(ndis_handle);
191 __stdcall static void ndis_alloc_packet(ndis_status *,
192         ndis_packet **, ndis_handle);
193 __stdcall static void ndis_release_packet(ndis_packet *);
194 __stdcall static void ndis_unchain_headbuf(ndis_packet *, ndis_buffer **);
195 __stdcall static void ndis_unchain_tailbuf(ndis_packet *, ndis_buffer **);
196 __stdcall static void ndis_alloc_bufpool(ndis_status *,
197         ndis_handle *, uint32_t);
198 __stdcall static void ndis_free_bufpool(ndis_handle);
199 __stdcall static void ndis_alloc_buf(ndis_status *, ndis_buffer **,
200         ndis_handle, void *, uint32_t);
201 __stdcall static void ndis_release_buf(ndis_buffer *);
202 __stdcall static uint32_t ndis_buflen(ndis_buffer *);
203 __stdcall static void ndis_query_buf(ndis_buffer *, void **, uint32_t *);
204 __stdcall static void ndis_query_buf_safe(ndis_buffer *, void **,
205         uint32_t *, uint32_t);
206 __stdcall static void *ndis_buf_vaddr(ndis_buffer *);
207 __stdcall static void *ndis_buf_vaddr_safe(ndis_buffer *, uint32_t);
208 __stdcall static void ndis_adjust_buflen(ndis_buffer *, int);
209 __stdcall static uint32_t ndis_interlock_inc(uint32_t *);
210 __stdcall static uint32_t ndis_interlock_dec(uint32_t *);
211 __stdcall static void ndis_init_event(ndis_event *);
212 __stdcall static void ndis_set_event(ndis_event *);
213 __stdcall static void ndis_reset_event(ndis_event *);
214 __stdcall static uint8_t ndis_wait_event(ndis_event *, uint32_t);
215 __stdcall static ndis_status ndis_unicode2ansi(ndis_ansi_string *,
216         ndis_unicode_string *);
217 __stdcall static ndis_status ndis_ansi2unicode(ndis_unicode_string *,
218         ndis_ansi_string *);
219 __stdcall static ndis_status ndis_assign_pcirsrc(ndis_handle,
220         uint32_t, ndis_resource_list **);
221 __stdcall static ndis_status ndis_register_intr(ndis_miniport_interrupt *,
222         ndis_handle, uint32_t, uint32_t, uint8_t,
223         uint8_t, ndis_interrupt_mode);
224 __stdcall static void ndis_deregister_intr(ndis_miniport_interrupt *);
225 __stdcall static void ndis_register_shutdown(ndis_handle, void *,
226         ndis_shutdown_handler);
227 __stdcall static void ndis_deregister_shutdown(ndis_handle);
228 __stdcall static uint32_t ndis_numpages(ndis_buffer *);
229 __stdcall static void ndis_buf_physpages(ndis_buffer *, uint32_t *);
230 __stdcall static void ndis_query_bufoffset(ndis_buffer *,
231         uint32_t *, uint32_t *);
232 __stdcall static void ndis_sleep(uint32_t);
233 __stdcall static uint32_t ndis_read_pccard_amem(ndis_handle,
234         uint32_t, void *, uint32_t);
235 __stdcall static uint32_t ndis_write_pccard_amem(ndis_handle,
236         uint32_t, void *, uint32_t);
237 __stdcall static list_entry *ndis_insert_head(list_entry *,
238         list_entry *, ndis_spin_lock *);
239 __stdcall static list_entry *ndis_remove_head(list_entry *,
240         ndis_spin_lock *);
241 __stdcall static list_entry *ndis_insert_tail(list_entry *,
242         list_entry *, ndis_spin_lock *);
243 __stdcall static uint8_t ndis_sync_with_intr(ndis_miniport_interrupt *,
244         void *, void *);
245 __stdcall static void ndis_time(uint64_t *);
246 __stdcall static void ndis_uptime(uint32_t *);
247 __stdcall static void ndis_init_string(ndis_unicode_string *, char *);
248 __stdcall static void ndis_init_ansi_string(ndis_ansi_string *, char *);
249 __stdcall static void ndis_init_unicode_string(ndis_unicode_string *,
250         uint16_t *);
251 __stdcall static void ndis_free_string(ndis_unicode_string *);
252 __stdcall static ndis_status ndis_remove_miniport(ndis_handle *);
253 __stdcall static void ndis_termwrap(ndis_handle, void *);
254 __stdcall static void ndis_get_devprop(ndis_handle, device_object **,
255         device_object **, device_object **, cm_resource_list *,
256         cm_resource_list *);
257 __stdcall static void ndis_firstbuf(ndis_packet *, ndis_buffer **,
258         void **, uint32_t *, uint32_t *);
259 __stdcall static void ndis_firstbuf_safe(ndis_packet *, ndis_buffer **,
260         void **, uint32_t *, uint32_t *, uint32_t);
261 __stdcall static void ndis_open_file(ndis_status *, ndis_handle *, uint32_t *,
262         ndis_unicode_string *, ndis_physaddr);
263 __stdcall static void ndis_map_file(ndis_status *, void **, ndis_handle);
264 __stdcall static void ndis_unmap_file(ndis_handle);
265 __stdcall static void ndis_close_file(ndis_handle);
266 __stdcall static u_int8_t ndis_cpu_cnt(void);
267 __stdcall static void ndis_ind_statusdone(ndis_handle);
268 __stdcall static void ndis_ind_status(ndis_handle, ndis_status,
269         void *, uint32_t);
270 static void ndis_workfunc(void *);
271 __stdcall static ndis_status ndis_sched_workitem(ndis_work_item *);
272 __stdcall static void ndis_pkt_to_pkt(ndis_packet *, uint32_t, uint32_t,
273         ndis_packet *, uint32_t, uint32_t *);
274 __stdcall static void ndis_pkt_to_pkt_safe(ndis_packet *, uint32_t, uint32_t,
275         ndis_packet *, uint32_t, uint32_t *, uint32_t);
276 __stdcall static ndis_status ndis_register_dev(ndis_handle,
277         ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **,
278         void **, ndis_handle *);
279 __stdcall static ndis_status ndis_deregister_dev(ndis_handle);
280 __stdcall static ndis_status ndis_query_name(ndis_unicode_string *,
281         ndis_handle);
282 __stdcall static void ndis_register_unload(ndis_handle, void *);
283 __stdcall static void dummy(void);
284
285 /*
286  * Some really old drivers do not properly check the return value
287  * from NdisAllocatePacket() and NdisAllocateBuffer() and will
288  * sometimes allocate few more buffers/packets that they originally
289  * requested when they created the pool. To prevent this from being
290  * a problem, we allocate a few extra buffers/packets beyond what
291  * the driver asks for. This #define controls how many.
292  */
293 #define NDIS_POOL_EXTRA         16
294
295 int
296 ndis_libinit()
297 {
298         strcpy(ndis_filepath, "/compat/ndis");
299         return(0);
300 }
301
302 int
303 ndis_libfini()
304 {
305         return(0);
306 }
307
308 /*
309  * NDIS deals with strings in unicode format, so we have
310  * do deal with them that way too. For now, we only handle
311  * conversion between unicode and ASCII since that's all
312  * that device drivers care about.
313  */
314
315 int
316 ndis_ascii_to_unicode(ascii, unicode)
317         char                    *ascii;
318         uint16_t                **unicode;
319 {
320         uint16_t                *ustr;
321         int                     i;
322
323         if (*unicode == NULL)
324                 *unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_WAITOK);
325         ustr = *unicode;
326         for (i = 0; i < strlen(ascii); i++) {
327                 *ustr = (uint16_t)ascii[i];
328                 ustr++;
329         }
330
331         return(0);
332 }
333
334 int
335 ndis_unicode_to_ascii(unicode, ulen, ascii)
336         uint16_t                *unicode;
337         int                     ulen;
338         char                    **ascii;
339 {
340         uint8_t                 *astr;
341         int                     i;
342
343         if (*ascii == NULL)
344                 *ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_WAITOK|M_ZERO);
345         astr = *ascii;
346         for (i = 0; i < ulen / 2; i++) {
347                 *astr = (uint8_t)unicode[i];
348                 astr++;
349         }
350
351         return(0);
352 }
353
354 __stdcall static void
355 ndis_initwrap(wrapper, drv_obj, path, unused)
356         ndis_handle             *wrapper;
357         device_object           *drv_obj;
358         void                    *path;
359         void                    *unused;
360 {
361         ndis_miniport_block     *block;
362
363         block = drv_obj->do_rsvd;
364         *wrapper = block;
365
366         return;
367 }
368
369 __stdcall static void
370 ndis_termwrap(handle, syspec)
371         ndis_handle             handle;
372         void                    *syspec;
373 {
374         return;
375 }
376
377 __stdcall static ndis_status
378 ndis_register_miniport(handle, characteristics, len)
379         ndis_handle             handle;
380         ndis_miniport_characteristics *characteristics;
381         int                     len;
382 {
383         ndis_miniport_block     *block;
384         struct ndis_softc       *sc;
385
386         block = (ndis_miniport_block *)handle;
387         sc = (struct ndis_softc *)block->nmb_ifp;
388         bcopy((char *)characteristics, (char *)&sc->ndis_chars,
389             sizeof(ndis_miniport_characteristics));
390         if (sc->ndis_chars.nmc_version_major < 5 ||
391             sc->ndis_chars.nmc_version_minor < 1) {
392                 sc->ndis_chars.nmc_shutdown_handler = NULL;
393                 sc->ndis_chars.nmc_canceltxpkts_handler = NULL;
394                 sc->ndis_chars.nmc_pnpevent_handler = NULL;
395         }
396
397         return(NDIS_STATUS_SUCCESS);
398 }
399
400 __stdcall static ndis_status
401 ndis_malloc_withtag(vaddr, len, tag)
402         void                    **vaddr;
403         uint32_t                len;
404         uint32_t                tag;
405 {
406         void                    *mem;
407
408         mem = malloc(len, M_DEVBUF, M_INTWAIT|M_NULLOK);
409         if (mem == NULL)
410                 return(NDIS_STATUS_RESOURCES);
411         *vaddr = mem;
412
413         return(NDIS_STATUS_SUCCESS);
414 }
415
416 __stdcall static ndis_status
417 ndis_malloc(vaddr, len, flags, highaddr)
418         void                    **vaddr;
419         uint32_t                len;
420         uint32_t                flags;
421         ndis_physaddr           highaddr;
422 {
423         void                    *mem;
424
425         mem = malloc(len, M_DEVBUF, M_INTWAIT|M_NULLOK);
426         if (mem == NULL)
427                 return(NDIS_STATUS_RESOURCES);
428         *vaddr = mem;
429
430         return(NDIS_STATUS_SUCCESS);
431 }
432
433 __stdcall static void
434 ndis_free(vaddr, len, flags)
435         void                    *vaddr;
436         uint32_t                len;
437         uint32_t                flags;
438 {
439         if (len == 0)
440                 return;
441         free(vaddr, M_DEVBUF);
442
443         return;
444 }
445
446 __stdcall static ndis_status
447 ndis_setattr_ex(adapter_handle, adapter_ctx, hangsecs,
448                         flags, iftype)
449         ndis_handle                     adapter_handle;
450         ndis_handle                     adapter_ctx;
451         uint32_t                        hangsecs;
452         uint32_t                        flags;
453         ndis_interface_type             iftype;
454 {
455         ndis_miniport_block             *block;
456
457         /*
458          * Save the adapter context, we need it for calling
459          * the driver's internal functions.
460          */
461         block = (ndis_miniport_block *)adapter_handle;
462         block->nmb_miniportadapterctx = adapter_ctx;
463         block->nmb_checkforhangsecs = hangsecs;
464         block->nmb_flags = flags;
465
466         return(NDIS_STATUS_SUCCESS);
467 }
468
469 __stdcall static void
470 ndis_open_cfg(status, cfg, wrapctx)
471         ndis_status             *status;
472         ndis_handle             *cfg;
473         ndis_handle             wrapctx;
474 {
475         *cfg = wrapctx;
476         *status = NDIS_STATUS_SUCCESS;
477         return;
478 }
479
480 __stdcall static void
481 ndis_open_cfgbyname(status, cfg, subkey, subhandle)
482         ndis_status             *status;
483         ndis_handle             cfg;
484         ndis_unicode_string     *subkey;
485         ndis_handle             *subhandle;
486 {
487         *subhandle = cfg;
488         *status = NDIS_STATUS_SUCCESS;
489         return;
490 }
491
492 __stdcall static void
493 ndis_open_cfgbyidx(status, cfg, idx, subkey, subhandle)
494         ndis_status             *status;
495         ndis_handle             cfg;
496         uint32_t                idx;
497         ndis_unicode_string     *subkey;
498         ndis_handle             *subhandle;
499 {
500         *status = NDIS_STATUS_FAILURE;
501         return;
502 }
503
504 static ndis_status
505 ndis_encode_parm(block, oid, type, parm)
506         ndis_miniport_block     *block;
507         struct sysctl_oid       *oid;
508         ndis_parm_type          type;
509         ndis_config_parm        **parm;
510 {
511         uint16_t                *unicode;
512         ndis_unicode_string     *ustr;
513         int                     base = 0;
514
515         unicode = (uint16_t *)&block->nmb_dummybuf;
516
517         switch(type) {
518         case ndis_parm_string:
519                 ndis_ascii_to_unicode((char *)oid->oid_arg1, &unicode);
520                 (*parm)->ncp_type = ndis_parm_string;
521                 ustr = &(*parm)->ncp_parmdata.ncp_stringdata;
522                 ustr->nus_len = strlen((char *)oid->oid_arg1) * 2;
523                 ustr->nus_buf = unicode;
524                 break;
525         case ndis_parm_int:
526                 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
527                         base = 16;
528                 else
529                         base = 10;
530                 (*parm)->ncp_type = ndis_parm_int;
531                 (*parm)->ncp_parmdata.ncp_intdata =
532                     strtol((char *)oid->oid_arg1, NULL, base);
533                 break;
534         case ndis_parm_hexint:
535                 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
536                         base = 16;
537                 else
538                         base = 10;
539                 (*parm)->ncp_type = ndis_parm_hexint;
540                 (*parm)->ncp_parmdata.ncp_intdata =
541                     strtoul((char *)oid->oid_arg1, NULL, base);
542                 break;
543         default:
544                 return(NDIS_STATUS_FAILURE);
545                 break;
546         }
547
548         return(NDIS_STATUS_SUCCESS);
549 }
550
551 int
552 ndis_strcasecmp(s1, s2)
553         const char              *s1;
554         const char              *s2;
555 {
556         char                    a, b;
557
558         /*
559          * In the kernel, toupper() is a macro. Have to be careful
560          * not to use pointer arithmetic when passing it arguments.
561          */
562
563         while(1) {
564                 a = *s1;
565                 b = *s2++;
566                 if (toupper(a) != toupper(b))
567                         break;
568                 if (*s1++ == 0)
569                         return(0);
570         }
571
572         return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
573 }
574
575 __stdcall static void
576 ndis_read_cfg(status, parm, cfg, key, type)
577         ndis_status             *status;
578         ndis_config_parm        **parm;
579         ndis_handle             cfg;
580         ndis_unicode_string     *key;
581         ndis_parm_type          type;
582 {
583         char                    *keystr = NULL;
584         uint16_t                *unicode;
585         ndis_miniport_block     *block;
586         struct ndis_softc       *sc;
587         struct sysctl_oid       *oidp;
588         struct sysctl_ctx_entry *e;
589
590         block = (ndis_miniport_block *)cfg;
591         sc = (struct ndis_softc *)block->nmb_ifp;
592
593         if (key->nus_len == 0 || key->nus_buf == NULL) {
594                 *status = NDIS_STATUS_FAILURE;
595                 return;
596         }
597
598         ndis_unicode_to_ascii(key->nus_buf, key->nus_len, &keystr);
599
600         *parm = &block->nmb_replyparm;
601         bzero((char *)&block->nmb_replyparm, sizeof(ndis_config_parm));
602         unicode = (uint16_t *)&block->nmb_dummybuf;
603
604         /*
605          * See if registry key is already in a list of known keys
606          * included with the driver.
607          */
608 #if __FreeBSD_version < 502113
609         TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
610 #else
611         TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
612 #endif
613                 oidp = e->entry;
614                 if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
615                         if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
616                                 free(keystr, M_DEVBUF);
617                                 *status = NDIS_STATUS_FAILURE;
618                                 return;
619                         }
620                         *status = ndis_encode_parm(block, oidp, type, parm);
621                         free(keystr, M_DEVBUF);
622                         return;
623                 }
624         }
625
626         /*
627          * If the key didn't match, add it to the list of dynamically
628          * created ones. Sometimes, drivers refer to registry keys
629          * that aren't documented in their .INF files. These keys
630          * are supposed to be created by some sort of utility or
631          * control panel snap-in that comes with the driver software.
632          * Sometimes it's useful to be able to manipulate these.
633          * If the driver requests the key in the form of a string,
634          * make its default value an empty string, otherwise default
635          * it to "0".
636          */
637
638         if (type == ndis_parm_int || type == ndis_parm_hexint)
639                 ndis_add_sysctl(sc, keystr, "(dynamic integer key)",
640                     "UNSET", CTLFLAG_RW);
641         else
642                 ndis_add_sysctl(sc, keystr, "(dynamic string key)",
643                     "UNSET", CTLFLAG_RW);
644
645         free(keystr, M_DEVBUF);
646         *status = NDIS_STATUS_FAILURE;
647         return;
648 }
649
650 static ndis_status
651 ndis_decode_parm(block, parm, val)
652         ndis_miniport_block     *block;
653         ndis_config_parm        *parm;
654         char                    *val;
655 {
656         ndis_unicode_string     *ustr;
657         char                    *astr = NULL;
658
659         switch(parm->ncp_type) {
660         case ndis_parm_string:
661                 ustr = &parm->ncp_parmdata.ncp_stringdata;
662                 ndis_unicode_to_ascii(ustr->nus_buf, ustr->nus_len, &astr);
663                 bcopy(astr, val, 254);
664                 free(astr, M_DEVBUF);
665                 break;
666         case ndis_parm_int:
667                 sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata);
668                 break;
669         case ndis_parm_hexint:
670                 sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata);
671                 break;
672         default:
673                 return(NDIS_STATUS_FAILURE);
674                 break;
675         }
676         return(NDIS_STATUS_SUCCESS);
677 }
678
679 __stdcall static void
680 ndis_write_cfg(status, cfg, key, parm)
681         ndis_status             *status;
682         ndis_handle             cfg;
683         ndis_unicode_string     *key;
684         ndis_config_parm        *parm;
685 {
686         char                    *keystr = NULL;
687         ndis_miniport_block     *block;
688         struct ndis_softc       *sc;
689         struct sysctl_oid       *oidp;
690         struct sysctl_ctx_entry *e;
691         char                    val[256];
692
693         block = (ndis_miniport_block *)cfg;
694         sc = (struct ndis_softc *)block->nmb_ifp;
695
696         ndis_unicode_to_ascii(key->nus_buf, key->nus_len, &keystr);
697
698         /* Decode the parameter into a string. */
699         bzero(val, sizeof(val));
700         *status = ndis_decode_parm(block, parm, val);
701         if (*status != NDIS_STATUS_SUCCESS) {
702                 free(keystr, M_DEVBUF);
703                 return;
704         }
705
706         /* See if the key already exists. */
707
708 #if __FreeBSD_version < 502113
709         TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
710 #else
711         TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
712 #endif
713                 oidp = e->entry;
714                 if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
715                         /* Found it, set the value. */
716                         strcpy((char *)oidp->oid_arg1, val);
717                         free(keystr, M_DEVBUF);
718                         return;
719                 }
720         }
721
722         /* Not found, add a new key with the specified value. */
723         ndis_add_sysctl(sc, keystr, "(dynamically set key)",
724                     val, CTLFLAG_RW);
725
726         free(keystr, M_DEVBUF);
727         *status = NDIS_STATUS_SUCCESS;
728         return;
729 }
730
731 __stdcall static void
732 ndis_close_cfg(cfg)
733         ndis_handle             cfg;
734 {
735         return;
736 }
737
738 /*
739  * Initialize a Windows spinlock.
740  */
741 __stdcall static void
742 ndis_create_lock(lock)
743         ndis_spin_lock          *lock;
744 {
745         lock->nsl_spinlock = 0;
746         lock->nsl_kirql = 0;
747
748         return;
749 }
750
751 /*
752  * Destroy a Windows spinlock. This is a no-op for now. There are two reasons
753  * for this. One is that it's sort of superfluous: we don't have to do anything
754  * special to deallocate the spinlock. The other is that there are some buggy
755  * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on
756  * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm
757  * talking to you.)
758  */
759 __stdcall static void
760 ndis_destroy_lock(lock)
761         ndis_spin_lock          *lock;
762 {
763 #ifdef notdef
764         lock->nsl_spinlock = 0;
765         lock->nsl_kirql = 0;
766 #endif
767         return;
768 }
769
770 /*
771  * Acquire a spinlock from IRQL <= DISPATCH_LEVEL.
772  */
773
774 __stdcall static void
775 ndis_lock(lock)
776         ndis_spin_lock          *lock;
777 {
778         lock->nsl_kirql = FASTCALL2(hal_lock,
779             &lock->nsl_spinlock, DISPATCH_LEVEL);
780         return;
781 }
782
783 /*
784  * Release a spinlock from IRQL == DISPATCH_LEVEL.
785  */
786
787 __stdcall static void
788 ndis_unlock(lock)
789         ndis_spin_lock          *lock;
790 {
791         FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
792         return;
793 }
794
795 /*
796  * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL.
797  */
798 __stdcall static void
799 ndis_lock_dpr(lock)
800         ndis_spin_lock          *lock;
801 {
802         FASTCALL1(ntoskrnl_lock_dpc, &lock->nsl_spinlock);
803         return;
804 }
805
806 /*
807  * Release a spinlock without leaving IRQL == DISPATCH_LEVEL.
808  */
809 __stdcall static void
810 ndis_unlock_dpr(lock)
811         ndis_spin_lock          *lock;
812 {
813         FASTCALL1(ntoskrnl_unlock_dpc, &lock->nsl_spinlock);
814         return;
815 }
816
817 __stdcall static uint32_t
818 ndis_read_pci(adapter, slot, offset, buf, len)
819         ndis_handle             adapter;
820         uint32_t                slot;
821         uint32_t                offset;
822         void                    *buf;
823         uint32_t                len;
824 {
825         ndis_miniport_block     *block;
826         int                     i;
827         char                    *dest;
828
829         block = (ndis_miniport_block *)adapter;
830         dest = buf;
831         if (block == NULL || block->nmb_dev == NULL)
832                 return(0);
833
834         for (i = 0; i < len; i++)
835                 dest[i] = pci_read_config(block->nmb_dev, i + offset, 1);
836
837         return(len);
838 }
839
840 __stdcall static uint32_t
841 ndis_write_pci(adapter, slot, offset, buf, len)
842         ndis_handle             adapter;
843         uint32_t                slot;
844         uint32_t                offset;
845         void                    *buf;
846         uint32_t                len;
847 {
848         ndis_miniport_block     *block;
849         int                     i;
850         char                    *dest;
851
852         block = (ndis_miniport_block *)adapter;
853         dest = buf;
854
855         if (block == NULL || block->nmb_dev == NULL)
856                 return(0);
857
858         for (i = 0; i < len; i++)
859                 pci_write_config(block->nmb_dev, i + offset, dest[i], 1);
860
861         return(len);
862 }
863
864 /*
865  * The errorlog routine uses a variable argument list, so we
866  * have to declare it this way.
867  */
868 #define ERRMSGLEN 512
869 static void
870 ndis_syslog(ndis_handle adapter, ndis_error_code code,
871         uint32_t numerrors, ...)
872 {
873         ndis_miniport_block     *block;
874         __va_list               ap;
875         int                     i, error;
876         char                    *str = NULL, *ustr = NULL;
877         uint16_t                flags;
878         char                    msgbuf[ERRMSGLEN];
879
880
881         block = (ndis_miniport_block *)adapter;
882
883         error = pe_get_message(block->nmb_img, code, &str, &i, &flags);
884         if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE) {
885                 ustr = msgbuf;
886                 ndis_unicode_to_ascii((uint16_t *)str,
887                     ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr);
888                 str = ustr;
889         }
890         device_printf (block->nmb_dev, "NDIS ERROR: %x (%s)\n", code,
891             str == NULL ? "unknown error" : str);
892         device_printf (block->nmb_dev, "NDIS NUMERRORS: %x\n", numerrors);
893
894         __va_start(ap, numerrors);
895         for (i = 0; i < numerrors; i++)
896                 device_printf (block->nmb_dev, "argptr: %p\n",
897                     __va_arg(ap, void *));
898         __va_end(ap);
899
900         return;
901 }
902
903 static void
904 ndis_map_cb(arg, segs, nseg, error)
905         void                    *arg;
906         bus_dma_segment_t       *segs;
907         int                     nseg;
908         int                     error;
909 {
910         struct ndis_map_arg     *ctx;
911         int                     i;
912
913         if (error)
914                 return;
915
916         ctx = arg;
917
918         for (i = 0; i < nseg; i++) {
919                 ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr;
920                 ctx->nma_fraglist[i].npu_len = segs[i].ds_len;
921         }
922
923         ctx->nma_cnt = nseg;
924
925         return;
926 }
927
928 __stdcall static void
929 ndis_vtophys_load(adapter, buf, mapreg, writedev, addrarray, arraysize)
930         ndis_handle             adapter;
931         ndis_buffer             *buf;
932         uint32_t                mapreg;
933         uint8_t                 writedev;
934         ndis_paddr_unit         *addrarray;
935         uint32_t                *arraysize;
936 {
937         ndis_miniport_block     *block;
938         struct ndis_softc       *sc;
939         struct ndis_map_arg     nma;
940         bus_dmamap_t            map;
941         int                     error;
942
943         if (adapter == NULL)
944                 return;
945
946         block = (ndis_miniport_block *)adapter;
947         sc = (struct ndis_softc *)(block->nmb_ifp);
948
949         if (mapreg > sc->ndis_mmapcnt)
950                 return;
951
952         map = sc->ndis_mmaps[mapreg];
953         nma.nma_fraglist = addrarray;
954
955         error = bus_dmamap_load(sc->ndis_mtag, map,
956             MDL_VA(buf), buf->nb_bytecount, ndis_map_cb,
957             (void *)&nma, BUS_DMA_NOWAIT);
958
959         if (error)
960                 return;
961
962         bus_dmamap_sync(sc->ndis_mtag, map,
963             writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
964
965         *arraysize = nma.nma_cnt;
966
967         return;
968 }
969
970 __stdcall static void
971 ndis_vtophys_unload(adapter, buf, mapreg)
972         ndis_handle             adapter;
973         ndis_buffer             *buf;
974         uint32_t                mapreg;
975 {
976         ndis_miniport_block     *block;
977         struct ndis_softc       *sc;
978         bus_dmamap_t            map;
979
980         if (adapter == NULL)
981                 return;
982
983         block = (ndis_miniport_block *)adapter;
984         sc = (struct ndis_softc *)(block->nmb_ifp);
985
986         if (mapreg > sc->ndis_mmapcnt)
987                 return;
988
989         map = sc->ndis_mmaps[mapreg];
990
991         bus_dmamap_sync(sc->ndis_mtag, map,
992             BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
993
994         bus_dmamap_unload(sc->ndis_mtag, map);
995
996         return;
997 }
998
999 /*
1000  * This is an older pre-miniport timer init routine which doesn't
1001  * accept a miniport context handle. The function context (ctx)
1002  * is supposed to be a pointer to the adapter handle, which should
1003  * have been handed to us via NdisSetAttributesEx(). We use this
1004  * function context to track down the corresponding ndis_miniport_block
1005  * structure. It's vital that we track down the miniport block structure,
1006  * so if we can't do it, we panic. Note that we also play some games
1007  * here by treating ndis_timer and ndis_miniport_timer as the same
1008  * thing.
1009  */
1010
1011 __stdcall static void
1012 ndis_init_timer(timer, func, ctx)
1013         ndis_timer              *timer;
1014         ndis_timer_function     func;
1015         void                    *ctx;
1016 {
1017         ntoskrnl_init_timer(&timer->nt_ktimer);
1018         ntoskrnl_init_dpc(&timer->nt_kdpc, func, ctx);
1019
1020         return;
1021 }
1022
1023 __stdcall static void
1024 ndis_create_timer(timer, handle, func, ctx)
1025         ndis_miniport_timer     *timer;
1026         ndis_handle             handle;
1027         ndis_timer_function     func;
1028         void                    *ctx;
1029 {
1030         /* Save the funcptr and context */
1031
1032         timer->nmt_timerfunc = func;
1033         timer->nmt_timerctx = ctx;
1034         timer->nmt_block = handle;
1035
1036         ntoskrnl_init_timer(&timer->nmt_ktimer);
1037         ntoskrnl_init_dpc(&timer->nmt_kdpc, func, ctx);
1038
1039         return;
1040 }
1041
1042 /*
1043  * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(),
1044  * but the former is just a macro wrapper around the latter.
1045  */
1046 __stdcall static void
1047 ndis_set_timer(timer, msecs)
1048         ndis_timer              *timer;
1049         uint32_t                msecs;
1050 {
1051         /*
1052          * KeSetTimer() wants the period in
1053          * hundred nanosecond intervals.
1054          */
1055         ntoskrnl_set_timer(&timer->nt_ktimer,
1056             ((int64_t)msecs * -10000), &timer->nt_kdpc);
1057
1058         return;
1059 }
1060
1061 __stdcall static void
1062 ndis_set_periodic_timer(timer, msecs)
1063         ndis_miniport_timer     *timer;
1064         uint32_t                msecs;
1065 {
1066         ntoskrnl_set_timer_ex(&timer->nmt_ktimer,
1067             ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc);
1068
1069         return;
1070 }
1071
1072 /*
1073  * Technically, this is really NdisCancelTimer(), but we also
1074  * (ab)use it for NdisMCancelTimer(), since in our implementation
1075  * we don't need the extra info in the ndis_miniport_timer
1076  * structure.
1077  */
1078
1079 __stdcall static void
1080 ndis_cancel_timer(timer, cancelled)
1081         ndis_timer              *timer;
1082         uint8_t                 *cancelled;
1083 {
1084         *cancelled = ntoskrnl_cancel_timer(&timer->nt_ktimer);
1085
1086         return;
1087 }
1088
1089 __stdcall static void
1090 ndis_query_resources(status, adapter, list, buflen)
1091         ndis_status             *status;
1092         ndis_handle             adapter;
1093         ndis_resource_list      *list;
1094         uint32_t                *buflen;
1095 {
1096         ndis_miniport_block     *block;
1097         struct ndis_softc       *sc;
1098         int                     rsclen;
1099
1100         block = (ndis_miniport_block *)adapter;
1101         sc = (struct ndis_softc *)block->nmb_ifp;
1102
1103         rsclen = sizeof(ndis_resource_list) +
1104             (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1));
1105         if (*buflen < rsclen) {
1106                 *buflen = rsclen;
1107                 *status = NDIS_STATUS_INVALID_LENGTH;
1108                 return;
1109         }
1110
1111         bcopy((char *)block->nmb_rlist, (char *)list, rsclen);
1112         *status = NDIS_STATUS_SUCCESS;
1113         return;
1114 }
1115
1116 __stdcall static ndis_status
1117 ndis_register_ioport(offset, adapter, port, numports)
1118         void                    **offset;
1119         ndis_handle             adapter;
1120         uint32_t                port;
1121         uint32_t                numports;
1122 {
1123         struct ndis_miniport_block      *block;
1124         struct ndis_softc       *sc;
1125
1126         if (adapter == NULL)
1127                 return(NDIS_STATUS_FAILURE);
1128
1129         block = (ndis_miniport_block *)adapter;
1130         sc = (struct ndis_softc *)(block->nmb_ifp);
1131
1132         if (sc->ndis_res_io == NULL)
1133                 return(NDIS_STATUS_FAILURE);
1134
1135         /* Don't let the device map more ports than we have. */
1136         if (rman_get_size(sc->ndis_res_io) < numports)
1137                 return(NDIS_STATUS_INVALID_LENGTH);
1138
1139         *offset = (void *)rman_get_start(sc->ndis_res_io);
1140
1141         return(NDIS_STATUS_SUCCESS);
1142 }
1143
1144 __stdcall static void
1145 ndis_deregister_ioport(adapter, port, numports, offset)
1146         ndis_handle             adapter;
1147         uint32_t                port;
1148         uint32_t                numports;
1149         void                    *offset;
1150 {
1151         return;
1152 }
1153
1154 __stdcall static void
1155 ndis_read_netaddr(status, addr, addrlen, adapter)
1156         ndis_status             *status;
1157         void                    **addr;
1158         uint32_t                *addrlen;
1159         ndis_handle             adapter;
1160 {
1161         struct ndis_softc       *sc;
1162         ndis_miniport_block     *block;
1163         uint8_t                 empty[] = { 0, 0, 0, 0, 0, 0 };
1164
1165         block = (ndis_miniport_block *)adapter;
1166         sc = (struct ndis_softc *)block->nmb_ifp;
1167
1168         if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0)
1169                 *status = NDIS_STATUS_FAILURE;
1170         else {
1171                 *addr = sc->arpcom.ac_enaddr;
1172                 *addrlen = ETHER_ADDR_LEN;
1173                 *status = NDIS_STATUS_SUCCESS;
1174         }
1175
1176         return;
1177 }
1178
1179 __stdcall static ndis_status
1180 ndis_mapreg_cnt(bustype, cnt)
1181         uint32_t                bustype;
1182         uint32_t                *cnt;
1183 {
1184         *cnt = 8192;
1185         return(NDIS_STATUS_SUCCESS);
1186 }
1187
1188 __stdcall static ndis_status
1189 ndis_alloc_mapreg(adapter, dmachannel, dmasize, physmapneeded, maxmap)
1190         ndis_handle             adapter;
1191         uint32_t                dmachannel;
1192         uint8_t                 dmasize;
1193         uint32_t                physmapneeded;
1194         uint32_t                maxmap;
1195 {
1196         struct ndis_softc       *sc;
1197         ndis_miniport_block     *block;
1198         int                     error, i, nseg = NDIS_MAXSEG;
1199
1200         block = (ndis_miniport_block *)adapter;
1201         sc = (struct ndis_softc *)block->nmb_ifp;
1202
1203         sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded,
1204             M_DEVBUF, M_INTWAIT|M_ZERO);
1205
1206         if (sc->ndis_mmaps == NULL)
1207                 return(NDIS_STATUS_RESOURCES);
1208
1209         error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1210             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1211             NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW,
1212             &sc->ndis_mtag);
1213
1214         if (error) {
1215                 free(sc->ndis_mmaps, M_DEVBUF);
1216                 return(NDIS_STATUS_RESOURCES);
1217         }
1218
1219         for (i = 0; i < physmapneeded; i++)
1220                 bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]);
1221
1222         sc->ndis_mmapcnt = physmapneeded;
1223
1224         return(NDIS_STATUS_SUCCESS);
1225 }
1226
1227 __stdcall static void
1228 ndis_free_mapreg(adapter)
1229         ndis_handle             adapter;
1230 {
1231         struct ndis_softc       *sc;
1232         ndis_miniport_block     *block;
1233         int                     i;
1234
1235         block = (ndis_miniport_block *)adapter;
1236         sc = (struct ndis_softc *)block->nmb_ifp;
1237
1238         for (i = 0; i < sc->ndis_mmapcnt; i++)
1239                 bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]);
1240
1241         free(sc->ndis_mmaps, M_DEVBUF);
1242
1243         bus_dma_tag_destroy(sc->ndis_mtag);
1244
1245         return;
1246 }
1247
1248 static void
1249 ndis_mapshared_cb(arg, segs, nseg, error)
1250         void                    *arg;
1251         bus_dma_segment_t       *segs;
1252         int                     nseg;
1253         int                     error;
1254 {
1255         ndis_physaddr           *p;
1256
1257         if (error || nseg > 1)
1258                 return;
1259
1260         p = arg;
1261
1262         p->np_quad = segs[0].ds_addr;
1263
1264         return;
1265 }
1266
1267 /*
1268  * This maps to bus_dmamem_alloc().
1269  */
1270 __stdcall static void
1271 ndis_alloc_sharedmem(adapter, len, cached, vaddr, paddr)
1272         ndis_handle             adapter;
1273         uint32_t                len;
1274         uint8_t                 cached;
1275         void                    **vaddr;
1276         ndis_physaddr           *paddr;
1277 {
1278         ndis_miniport_block     *block;
1279         struct ndis_softc       *sc;
1280         struct ndis_shmem       *sh;
1281         int                     error;
1282
1283         if (adapter == NULL)
1284                 return;
1285
1286         block = (ndis_miniport_block *)adapter;
1287         sc = (struct ndis_softc *)(block->nmb_ifp);
1288
1289         sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_INTWAIT|M_ZERO);
1290         if (sh == NULL)
1291                 return;
1292
1293         /*
1294          * When performing shared memory allocations, create a tag
1295          * with a lowaddr limit that restricts physical memory mappings
1296          * so that they all fall within the first 1GB of memory.
1297          * At least one device/driver combination (Linksys Instant
1298          * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
1299          * problems with performing DMA operations with physical
1300          * that lie above the 1GB mark. I don't know if this is a
1301          * hardware limitation or if the addresses are being truncated
1302          * within the driver, but this seems to be the only way to
1303          * make these cards work reliably in systems with more than
1304          * 1GB of physical memory.
1305          */
1306
1307         error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
1308             0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL,
1309             NULL, len, 1, len, BUS_DMA_ALLOCNOW, 
1310             &sh->ndis_stag);
1311
1312         if (error) {
1313                 free(sh, M_DEVBUF);
1314                 return;
1315         }
1316
1317         error = bus_dmamem_alloc(sh->ndis_stag, vaddr,
1318             BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap);
1319
1320         if (error) {
1321                 bus_dma_tag_destroy(sh->ndis_stag);
1322                 free(sh, M_DEVBUF);
1323                 return;
1324         }
1325
1326         error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr,
1327             len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT);
1328
1329         if (error) {
1330                 bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap);
1331                 bus_dma_tag_destroy(sh->ndis_stag);
1332                 free(sh, M_DEVBUF);
1333                 return;
1334         }
1335
1336         sh->ndis_saddr = *vaddr;
1337         sh->ndis_next = sc->ndis_shlist;
1338         sc->ndis_shlist = sh;
1339
1340         return;
1341 }
1342
1343 struct ndis_allocwork {
1344         ndis_handle             na_adapter;
1345         uint32_t                na_len;
1346         uint8_t                 na_cached;
1347         void                    *na_ctx;
1348 };
1349
1350 static void
1351 ndis_asyncmem_complete(arg)
1352         void                    *arg;
1353 {
1354         ndis_miniport_block     *block;
1355         struct ndis_softc       *sc;
1356         struct ndis_allocwork   *w;
1357         void                    *vaddr;
1358         ndis_physaddr           paddr;
1359         ndis_allocdone_handler  donefunc;
1360
1361         w = arg;
1362         block = (ndis_miniport_block *)w->na_adapter;
1363         sc = (struct ndis_softc *)(block->nmb_ifp);
1364
1365         vaddr = NULL;
1366         paddr.np_quad = 0;
1367
1368         donefunc = sc->ndis_chars.nmc_allocate_complete_func;
1369         ndis_alloc_sharedmem(w->na_adapter, w->na_len,
1370             w->na_cached, &vaddr, &paddr);
1371         donefunc(w->na_adapter, vaddr, &paddr, w->na_len, w->na_ctx);
1372
1373         free(arg, M_DEVBUF);
1374
1375         return;
1376 }
1377
1378 __stdcall static ndis_status
1379 ndis_alloc_sharedmem_async(adapter, len, cached, ctx)
1380         ndis_handle             adapter;
1381         uint32_t                len;
1382         uint8_t                 cached;
1383         void                    *ctx;
1384 {
1385         struct ndis_allocwork   *w;
1386
1387         if (adapter == NULL)
1388                 return(NDIS_STATUS_FAILURE);
1389
1390         w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_INTWAIT);
1391
1392         if (w == NULL)
1393                 return(NDIS_STATUS_FAILURE);
1394
1395         w->na_adapter = adapter;
1396         w->na_cached = cached;
1397         w->na_len = len;
1398         w->na_ctx = ctx;
1399
1400         /*
1401          * Pawn this work off on the SWI thread instead of the
1402          * taskqueue thread, because sometimes drivers will queue
1403          * up work items on the taskqueue thread that will block,
1404          * which would prevent the memory allocation from completing
1405          * when we need it.
1406          */
1407         ndis_sched(ndis_asyncmem_complete, w, NDIS_SWI);
1408
1409         return(NDIS_STATUS_PENDING);
1410 }
1411
1412 __stdcall static void
1413 ndis_free_sharedmem(adapter, len, cached, vaddr, paddr)
1414         ndis_handle             adapter;
1415         uint32_t                len;
1416         uint8_t                 cached;
1417         void                    *vaddr;
1418         ndis_physaddr           paddr;
1419 {
1420         ndis_miniport_block     *block;
1421         struct ndis_softc       *sc;
1422         struct ndis_shmem       *sh, *prev;
1423
1424         if (vaddr == NULL || adapter == NULL)
1425                 return;
1426
1427         block = (ndis_miniport_block *)adapter;
1428         sc = (struct ndis_softc *)(block->nmb_ifp);
1429         sh = prev = sc->ndis_shlist;
1430
1431         while (sh) {
1432                 if (sh->ndis_saddr == vaddr)
1433                         break;
1434                 prev = sh;
1435                 sh = sh->ndis_next;
1436         }
1437
1438         bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1439         bus_dmamem_free(sh->ndis_stag, vaddr, sh->ndis_smap);
1440         bus_dma_tag_destroy(sh->ndis_stag);
1441
1442         if (sh == sc->ndis_shlist)
1443                 sc->ndis_shlist = sh->ndis_next;
1444         else
1445                 prev->ndis_next = sh->ndis_next;
1446
1447         free(sh, M_DEVBUF);
1448
1449         return;
1450 }
1451
1452 __stdcall static ndis_status
1453 ndis_map_iospace(vaddr, adapter, paddr, len)
1454         void                    **vaddr;
1455         ndis_handle             adapter;
1456         ndis_physaddr           paddr;
1457         uint32_t                len;
1458 {
1459         ndis_miniport_block     *block;
1460         struct ndis_softc       *sc;
1461
1462         if (adapter == NULL)
1463                 return(NDIS_STATUS_FAILURE);
1464
1465         block = (ndis_miniport_block *)adapter;
1466         sc = (struct ndis_softc *)(block->nmb_ifp);
1467
1468         if (sc->ndis_res_mem != NULL &&
1469             paddr.np_quad == rman_get_start(sc->ndis_res_mem))
1470                 *vaddr = (void *)rman_get_virtual(sc->ndis_res_mem);
1471         else if (sc->ndis_res_altmem != NULL &&
1472              paddr.np_quad == rman_get_start(sc->ndis_res_altmem))
1473                 *vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem);
1474         else if (sc->ndis_res_am != NULL &&
1475              paddr.np_quad == rman_get_start(sc->ndis_res_am))
1476                 *vaddr = (void *)rman_get_virtual(sc->ndis_res_am);
1477         else
1478                 return(NDIS_STATUS_FAILURE);
1479
1480         return(NDIS_STATUS_SUCCESS);
1481 }
1482
1483 __stdcall static void
1484 ndis_unmap_iospace(adapter, vaddr, len)
1485         ndis_handle             adapter;
1486         void                    *vaddr;
1487         uint32_t                len;
1488 {
1489         return;
1490 }
1491
1492 __stdcall static uint32_t
1493 ndis_cachefill(void)
1494 {
1495         return(128);
1496 }
1497
1498 __stdcall static uint32_t
1499 ndis_dma_align(handle)
1500         ndis_handle             handle;
1501 {
1502         return(128);
1503 }
1504
1505 /*
1506  * NDIS has two methods for dealing with NICs that support DMA.
1507  * One is to just pass packets to the driver and let it call
1508  * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
1509  * all by itself, and the other is to let the NDIS library handle the
1510  * buffer mapping internally, and hand the driver an already populated
1511  * scatter/gather fragment list. If the driver calls
1512  * NdisMInitializeScatterGatherDma(), it wants to use the latter
1513  * method.
1514  */
1515
1516 __stdcall static ndis_status
1517 ndis_init_sc_dma(adapter, is64, maxphysmap)
1518         ndis_handle             adapter;
1519         uint8_t                 is64;
1520         uint32_t                maxphysmap;
1521 {
1522         struct ndis_softc       *sc;
1523         ndis_miniport_block     *block;
1524         int                     error;
1525
1526         if (adapter == NULL)
1527                 return(NDIS_STATUS_FAILURE);
1528         block = (ndis_miniport_block *)adapter;
1529         sc = (struct ndis_softc *)block->nmb_ifp;
1530
1531         /* Don't do this twice. */
1532         if (sc->ndis_sc == 1)
1533                 return(NDIS_STATUS_SUCCESS);
1534
1535         error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1536             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1537             MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
1538             &sc->ndis_ttag);
1539
1540         sc->ndis_sc = 1;
1541
1542         return(NDIS_STATUS_SUCCESS);
1543 }
1544
1545 __stdcall static void
1546 ndis_alloc_packetpool(status, pool, descnum, protrsvdlen)
1547         ndis_status             *status;
1548         ndis_handle             *pool;
1549         uint32_t                descnum;
1550         uint32_t                protrsvdlen;
1551 {
1552         ndis_packet             *cur;
1553         int                     i;
1554
1555         *pool = malloc(sizeof(ndis_packet) *
1556             ((descnum + NDIS_POOL_EXTRA) + 1),
1557             M_DEVBUF, M_WAITOK|M_ZERO);
1558         cur = (ndis_packet *)*pool;
1559         cur->np_private.npp_flags = 0x1; /* mark the head of the list */
1560         cur->np_private.npp_totlen = 0; /* init deletetion flag */
1561         for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
1562                 cur->np_private.npp_head = (ndis_handle)(cur + 1);
1563                 cur++;
1564         }
1565
1566         *status = NDIS_STATUS_SUCCESS;
1567         return;
1568 }
1569
1570 __stdcall static void
1571 ndis_ex_alloc_packetpool(status, pool, descnum, oflowdescnum, protrsvdlen)
1572         ndis_status             *status;
1573         ndis_handle             *pool;
1574         uint32_t                descnum;
1575         uint32_t                oflowdescnum;
1576         uint32_t                protrsvdlen;
1577 {
1578         return(ndis_alloc_packetpool(status, pool,
1579             descnum + oflowdescnum, protrsvdlen));
1580 }
1581
1582 __stdcall static uint32_t
1583 ndis_packetpool_use(pool)
1584         ndis_handle             pool;
1585 {
1586         ndis_packet             *head;
1587
1588         head = (ndis_packet *)pool;
1589
1590         return(head->np_private.npp_count);
1591 }
1592
1593 __stdcall static void
1594 ndis_free_packetpool(pool)
1595         ndis_handle             pool;
1596 {
1597         ndis_packet             *head;
1598
1599         head = pool;
1600
1601         /* Mark this pool as 'going away.' */
1602
1603         head->np_private.npp_totlen = 1;
1604
1605         /* If there are no buffers loaned out, destroy the pool. */
1606
1607         if (head->np_private.npp_count == 0)
1608                 free(pool, M_DEVBUF);
1609         else
1610                 printf("NDIS: buggy driver deleting active packet pool!\n");
1611
1612         return;
1613 }
1614
1615 __stdcall static void
1616 ndis_alloc_packet(status, packet, pool)
1617         ndis_status             *status;
1618         ndis_packet             **packet;
1619         ndis_handle             pool;
1620 {
1621         ndis_packet             *head, *pkt;
1622
1623         head = (ndis_packet *)pool;
1624
1625         if (head->np_private.npp_flags != 0x1) {
1626                 *status = NDIS_STATUS_FAILURE;
1627                 return;
1628         }
1629
1630         /*
1631          * If this pool is marked as 'going away' don't allocate any
1632          * more packets out of it.
1633          */
1634
1635         if (head->np_private.npp_totlen) {
1636                 *status = NDIS_STATUS_FAILURE;
1637                 return;
1638         }
1639
1640         pkt = (ndis_packet *)head->np_private.npp_head;
1641
1642         if (pkt == NULL) {
1643                 *status = NDIS_STATUS_RESOURCES;
1644                 return;
1645         }
1646
1647         head->np_private.npp_head = pkt->np_private.npp_head;
1648
1649         pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL;
1650         /* Save pointer to the pool. */
1651         pkt->np_private.npp_pool = head;
1652
1653         /* Set the oob offset pointer. Lots of things expect this. */
1654         pkt->np_private.npp_packetooboffset =
1655             offsetof(ndis_packet, np_oob);
1656
1657         /*
1658          * We must initialize the packet flags correctly in order
1659          * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
1660          * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() to work correctly.
1661          */
1662         pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
1663
1664         *packet = pkt;
1665
1666         head->np_private.npp_count++;
1667         *status = NDIS_STATUS_SUCCESS;
1668         return;
1669 }
1670
1671 __stdcall static void
1672 ndis_release_packet(packet)
1673         ndis_packet             *packet;
1674 {
1675         ndis_packet             *head;
1676
1677         if (packet == NULL || packet->np_private.npp_pool == NULL)
1678                 return;
1679
1680         head = packet->np_private.npp_pool;
1681         if (head->np_private.npp_flags != 0x1)
1682                 return;
1683
1684         packet->np_private.npp_head = head->np_private.npp_head;
1685         head->np_private.npp_head = (ndis_buffer *)packet;
1686         head->np_private.npp_count--;
1687
1688         /*
1689          * If the pool has been marked for deletion and there are
1690          * no more packets outstanding, nuke the pool.
1691          */
1692
1693         if (head->np_private.npp_totlen && head->np_private.npp_count == 0)
1694                 free(head, M_DEVBUF);
1695
1696         return;
1697 }
1698
1699 __stdcall static void
1700 ndis_unchain_headbuf(packet, buf)
1701         ndis_packet             *packet;
1702         ndis_buffer             **buf;
1703 {
1704         ndis_packet_private     *priv;
1705
1706         if (packet == NULL || buf == NULL)
1707                 return;
1708
1709         priv = &packet->np_private;
1710
1711         priv->npp_validcounts = FALSE;
1712
1713         if (priv->npp_head == priv->npp_tail) {
1714                 *buf = priv->npp_head;
1715                 priv->npp_head = priv->npp_tail = NULL;
1716         } else {
1717                 *buf = priv->npp_head;
1718                 priv->npp_head = (*buf)->nb_next;
1719         }
1720
1721         return;
1722 }
1723
1724 __stdcall static void
1725 ndis_unchain_tailbuf(packet, buf)
1726         ndis_packet             *packet;
1727         ndis_buffer             **buf;
1728 {
1729         ndis_packet_private     *priv;
1730         ndis_buffer             *tmp;
1731
1732         if (packet == NULL || buf == NULL)
1733                 return;
1734
1735         priv = &packet->np_private;
1736
1737         priv->npp_validcounts = FALSE;
1738
1739         if (priv->npp_head == priv->npp_tail) {
1740                 *buf = priv->npp_head;
1741                 priv->npp_head = priv->npp_tail = NULL;
1742         } else {
1743                 *buf = priv->npp_tail;
1744                 tmp = priv->npp_head;
1745                 while (tmp->nb_next != priv->npp_tail)
1746                         tmp = tmp->nb_next;
1747                 priv->npp_tail = tmp;
1748                 tmp->nb_next = NULL;
1749         }
1750
1751         return;
1752 }
1753
1754 /*
1755  * The NDIS "buffer" manipulation functions are somewhat misnamed.
1756  * They don't really allocate buffers: they allocate buffer mappings.
1757  * The idea is you reserve a chunk of DMA-able memory using
1758  * NdisMAllocateSharedMemory() and then use NdisAllocateBuffer()
1759  * to obtain the virtual address of the DMA-able region.
1760  * ndis_alloc_bufpool() is analagous to bus_dma_tag_create().
1761  */
1762
1763 __stdcall static void
1764 ndis_alloc_bufpool(status, pool, descnum)
1765         ndis_status             *status;
1766         ndis_handle             *pool;
1767         uint32_t                descnum;
1768 {
1769         ndis_buffer             *cur;
1770         int                     i;
1771
1772         *pool = malloc(sizeof(ndis_buffer) *
1773             ((descnum + NDIS_POOL_EXTRA) + 1),
1774             M_DEVBUF, M_WAITOK|M_ZERO);
1775         cur = (ndis_buffer *)*pool;
1776         cur->nb_flags = 0x1; /* mark the head of the list */
1777         cur->nb_bytecount = 0; /* init usage count */
1778         cur->nb_byteoffset = 0; /* init deletetion flag */
1779         for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
1780                 cur->nb_next = cur + 1;
1781                 cur++;
1782         }
1783
1784         *status = NDIS_STATUS_SUCCESS;
1785         return;
1786 }
1787
1788 __stdcall static void
1789 ndis_free_bufpool(pool)
1790         ndis_handle             pool;
1791 {
1792         ndis_buffer             *head;
1793
1794         head = pool;
1795
1796         /* Mark this pool as 'going away.' */
1797
1798         head->nb_byteoffset = 1;
1799
1800         /* If there are no buffers loaned out, destroy the pool. */
1801         if (head->nb_bytecount == 0)
1802                 free(pool, M_DEVBUF);
1803         else
1804                 printf("NDIS: buggy driver deleting active buffer pool!\n");
1805
1806         return;
1807 }
1808
1809 /*
1810  * This maps to a bus_dmamap_create() and bus_dmamap_load().
1811  */
1812 __stdcall static void
1813 ndis_alloc_buf(status, buffer, pool, vaddr, len)
1814         ndis_status             *status;
1815         ndis_buffer             **buffer;
1816         ndis_handle             pool;
1817         void                    *vaddr;
1818         uint32_t                len;
1819 {
1820         ndis_buffer             *head, *buf;
1821
1822         head = (ndis_buffer *)pool;
1823         if (head->nb_flags != 0x1) {
1824                 *status = NDIS_STATUS_FAILURE;
1825                 return;
1826         }
1827
1828         /*
1829          * If this pool is marked as 'going away' don't allocate any
1830          * more buffers out of it.
1831          */
1832
1833         if (head->nb_byteoffset) {
1834                 *status = NDIS_STATUS_FAILURE;
1835                 return;
1836         }
1837
1838         buf = head->nb_next;
1839
1840         if (buf == NULL) {
1841                 *status = NDIS_STATUS_RESOURCES;
1842                 return;
1843         }
1844
1845         head->nb_next = buf->nb_next;
1846
1847         /* Save pointer to the pool. */
1848         buf->nb_process = head;
1849
1850         MDL_INIT(buf, vaddr, len);
1851
1852         *buffer = buf;
1853
1854         /* Increment count of busy buffers. */
1855
1856         head->nb_bytecount++;
1857
1858         *status = NDIS_STATUS_SUCCESS;
1859         return;
1860 }
1861
1862 __stdcall static void
1863 ndis_release_buf(buf)
1864         ndis_buffer             *buf;
1865 {
1866         ndis_buffer             *head;
1867
1868         if (buf == NULL || buf->nb_process == NULL)
1869                 return;
1870
1871         head = buf->nb_process;
1872
1873         if (head->nb_flags != 0x1)
1874                 return;
1875
1876         buf->nb_next = head->nb_next;
1877         head->nb_next = buf;
1878
1879         /* Decrement count of busy buffers. */
1880
1881         head->nb_bytecount--;
1882
1883         /*
1884          * If the pool has been marked for deletion and there are
1885          * no more buffers outstanding, nuke the pool.
1886          */
1887
1888         if (head->nb_byteoffset && head->nb_bytecount == 0)
1889                 free(head, M_DEVBUF);
1890
1891         return;
1892 }
1893
1894 /* Aw c'mon. */
1895
1896 __stdcall static uint32_t
1897 ndis_buflen(buf)
1898         ndis_buffer             *buf;
1899 {
1900         return(buf->nb_bytecount);
1901 }
1902
1903 /*
1904  * Get the virtual address and length of a buffer.
1905  * Note: the vaddr argument is optional.
1906  */
1907
1908 __stdcall static void
1909 ndis_query_buf(buf, vaddr, len)
1910         ndis_buffer             *buf;
1911         void                    **vaddr;
1912         uint32_t                *len;
1913 {
1914         if (vaddr != NULL)
1915                 *vaddr = MDL_VA(buf);
1916         *len = buf->nb_bytecount;
1917
1918         return;
1919 }
1920
1921 /* Same as above -- we don't care about the priority. */
1922
1923 __stdcall static void
1924 ndis_query_buf_safe(buf, vaddr, len, prio)
1925         ndis_buffer             *buf;
1926         void                    **vaddr;
1927         uint32_t                *len;
1928         uint32_t                prio;
1929 {
1930         if (vaddr != NULL)
1931                 *vaddr = MDL_VA(buf);
1932         *len = buf->nb_bytecount;
1933
1934         return;
1935 }
1936
1937 /* Damnit Microsoft!! How many ways can you do the same thing?! */
1938
1939 __stdcall static void *
1940 ndis_buf_vaddr(buf)
1941         ndis_buffer             *buf;
1942 {
1943         return(MDL_VA(buf));
1944 }
1945
1946 __stdcall static void *
1947 ndis_buf_vaddr_safe(buf, prio)
1948         ndis_buffer             *buf;
1949         uint32_t                prio;
1950 {
1951         return(MDL_VA(buf));
1952 }
1953
1954 __stdcall static void
1955 ndis_adjust_buflen(buf, len)
1956         ndis_buffer             *buf;
1957         int                     len;
1958 {
1959         buf->nb_bytecount = len;
1960
1961         return;
1962 }
1963
1964 __stdcall static uint32_t
1965 ndis_interlock_inc(addend)
1966         uint32_t                *addend;
1967 {
1968         atomic_add_long((u_long *)addend, 1);
1969         return(*addend);
1970 }
1971
1972 __stdcall static uint32_t
1973 ndis_interlock_dec(addend)
1974         uint32_t                *addend;
1975 {
1976         atomic_subtract_long((u_long *)addend, 1);
1977         return(*addend);
1978 }
1979
1980 __stdcall static void
1981 ndis_init_event(event)
1982         ndis_event              *event;
1983 {
1984         /*
1985          * NDIS events are always notification
1986          * events, and should be initialized to the
1987          * not signaled state.
1988          */
1989  
1990         ntoskrnl_init_event(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE);
1991         return;
1992 }
1993
1994 __stdcall static void
1995 ndis_set_event(event)
1996         ndis_event              *event;
1997 {
1998         ntoskrnl_set_event(&event->ne_event, 0, 0);
1999         return;
2000 }
2001
2002 __stdcall static void
2003 ndis_reset_event(event)
2004         ndis_event              *event;
2005 {
2006         ntoskrnl_reset_event(&event->ne_event);
2007         return;
2008 }
2009
2010 __stdcall static uint8_t
2011 ndis_wait_event(event, msecs)
2012         ndis_event              *event;
2013         uint32_t                msecs;
2014 {
2015         int64_t                 duetime;
2016         uint32_t                rval;
2017
2018         duetime = ((int64_t)msecs * -10000);
2019
2020         rval = ntoskrnl_waitforobj((nt_dispatch_header *)event,
2021             0, 0, TRUE, msecs ? &duetime : NULL);
2022
2023         if (rval == STATUS_TIMEOUT)
2024                 return(FALSE);
2025
2026         return(TRUE);
2027 }
2028
2029 __stdcall static ndis_status
2030 ndis_unicode2ansi(dstr, sstr)
2031         ndis_ansi_string        *dstr;
2032         ndis_unicode_string     *sstr;
2033 {
2034         if (dstr == NULL || sstr == NULL)
2035                 return(NDIS_STATUS_FAILURE);
2036         if (ndis_unicode_to_ascii(sstr->nus_buf,
2037             sstr->nus_len, &dstr->nas_buf))
2038                 return(NDIS_STATUS_FAILURE);
2039         dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf);
2040         return (NDIS_STATUS_SUCCESS);
2041 }
2042
2043 __stdcall static ndis_status
2044 ndis_ansi2unicode(dstr, sstr)
2045         ndis_unicode_string     *dstr;
2046         ndis_ansi_string        *sstr;
2047 {
2048         char                    *str;
2049         if (dstr == NULL || sstr == NULL)
2050                 return(NDIS_STATUS_FAILURE);
2051         str = malloc(sstr->nas_len + 1, M_DEVBUF, M_WAITOK);
2052         strncpy(str, sstr->nas_buf, sstr->nas_len);
2053         *(str + sstr->nas_len) = '\0';
2054         if (ndis_ascii_to_unicode(str, &dstr->nus_buf)) {
2055                 free(str, M_DEVBUF);
2056                 return(NDIS_STATUS_FAILURE);
2057         }
2058         dstr->nus_len = dstr->nus_maxlen = sstr->nas_len * 2;
2059         free(str, M_DEVBUF);
2060         return (NDIS_STATUS_SUCCESS);
2061 }
2062
2063 __stdcall static ndis_status
2064 ndis_assign_pcirsrc(adapter, slot, list)
2065         ndis_handle             adapter;
2066         uint32_t                slot;
2067         ndis_resource_list      **list;
2068 {
2069         ndis_miniport_block     *block;
2070
2071         if (adapter == NULL || list == NULL)
2072                 return (NDIS_STATUS_FAILURE);
2073
2074         block = (ndis_miniport_block *)adapter;
2075         *list = block->nmb_rlist;
2076
2077         return (NDIS_STATUS_SUCCESS);
2078 }
2079
2080 __stdcall static ndis_status
2081 ndis_register_intr(intr, adapter, ivec, ilevel, reqisr, shared, imode)
2082         ndis_miniport_interrupt *intr;
2083         ndis_handle             adapter;
2084         uint32_t                ivec;
2085         uint32_t                ilevel;
2086         uint8_t                 reqisr;
2087         uint8_t                 shared;
2088         ndis_interrupt_mode     imode;
2089 {
2090         ndis_miniport_block     *block;
2091
2092         block = adapter;
2093
2094         intr->ni_block = adapter;
2095         intr->ni_isrreq = reqisr;
2096         intr->ni_shared = shared;
2097         block->nmb_interrupt = intr;
2098         return(NDIS_STATUS_SUCCESS);
2099 }       
2100
2101 __stdcall static void
2102 ndis_deregister_intr(intr)
2103         ndis_miniport_interrupt *intr;
2104 {
2105         return;
2106 }
2107
2108 __stdcall static void
2109 ndis_register_shutdown(adapter, shutdownctx, shutdownfunc)
2110         ndis_handle             adapter;
2111         void                    *shutdownctx;
2112         ndis_shutdown_handler   shutdownfunc;
2113 {
2114         ndis_miniport_block     *block;
2115         ndis_miniport_characteristics *chars;
2116         struct ndis_softc       *sc;
2117
2118         if (adapter == NULL)
2119                 return;
2120
2121         block = (ndis_miniport_block *)adapter;
2122         sc = (struct ndis_softc *)block->nmb_ifp;
2123         chars = &sc->ndis_chars;
2124
2125         chars->nmc_shutdown_handler = shutdownfunc;
2126         chars->nmc_rsvd0 = shutdownctx;
2127
2128         return;
2129 }
2130
2131 __stdcall static void
2132 ndis_deregister_shutdown(adapter)
2133         ndis_handle             adapter;
2134 {
2135         ndis_miniport_block     *block;
2136         ndis_miniport_characteristics *chars;
2137         struct ndis_softc       *sc;
2138
2139         if (adapter == NULL)
2140                 return;
2141
2142         block = (ndis_miniport_block *)adapter;
2143         sc = (struct ndis_softc *)block->nmb_ifp;
2144         chars = &sc->ndis_chars;
2145
2146         chars->nmc_shutdown_handler = NULL;
2147         chars->nmc_rsvd0 = NULL;
2148
2149         return;
2150 }
2151
2152 __stdcall static uint32_t
2153 ndis_numpages(buf)
2154         ndis_buffer             *buf;
2155 {
2156         if (buf == NULL)
2157                 return(0);
2158         if (buf->nb_bytecount == 0)
2159                 return(1);
2160         return(SPAN_PAGES(MDL_VA(buf), buf->nb_bytecount));
2161 }
2162
2163 __stdcall static void
2164 ndis_buf_physpages(buf, pages)
2165         ndis_buffer             *buf;
2166         uint32_t                *pages;
2167 {
2168         if (buf == NULL)
2169                 return;
2170
2171         *pages = ndis_numpages(buf);
2172         return;
2173 }
2174
2175 __stdcall static void
2176 ndis_query_bufoffset(buf, off, len)
2177         ndis_buffer             *buf;
2178         uint32_t                *off;
2179         uint32_t                *len;
2180 {
2181         if (buf == NULL)
2182                 return;
2183
2184         *off = buf->nb_byteoffset;
2185         *len = buf->nb_bytecount;
2186
2187         return;
2188 }
2189
2190 __stdcall static void
2191 ndis_sleep(usecs)
2192         uint32_t                usecs;
2193 {
2194         struct timeval          tv;
2195
2196         tv.tv_sec = 0;
2197         tv.tv_usec = usecs;
2198
2199         ndis_thsuspend(curthread, 1 + usecs * hz / 1000000);
2200
2201         return;
2202 }
2203
2204 __stdcall static uint32_t
2205 ndis_read_pccard_amem(handle, offset, buf, len)
2206         ndis_handle             handle;
2207         uint32_t                offset;
2208         void                    *buf;
2209         uint32_t                len;
2210 {
2211         struct ndis_softc       *sc;
2212         ndis_miniport_block     *block;
2213         bus_space_handle_t      bh;
2214         bus_space_tag_t         bt;
2215         char                    *dest;
2216         int                     i;
2217
2218         if (handle == NULL)
2219                 return(0);
2220
2221         block = (ndis_miniport_block *)handle;
2222         sc = (struct ndis_softc *)block->nmb_ifp;
2223         dest = buf;
2224
2225         bh = rman_get_bushandle(sc->ndis_res_am);
2226         bt = rman_get_bustag(sc->ndis_res_am);
2227
2228         for (i = 0; i < len; i++)
2229                 dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2);
2230
2231         return(i);
2232 }
2233
2234 __stdcall static uint32_t
2235 ndis_write_pccard_amem(handle, offset, buf, len)
2236         ndis_handle             handle;
2237         uint32_t                offset;
2238         void                    *buf;
2239         uint32_t                len;
2240 {
2241         struct ndis_softc       *sc;
2242         ndis_miniport_block     *block;
2243         bus_space_handle_t      bh;
2244         bus_space_tag_t         bt;
2245         char                    *src;
2246         int                     i;
2247
2248         if (handle == NULL)
2249                 return(0);
2250
2251         block = (ndis_miniport_block *)handle;
2252         sc = (struct ndis_softc *)block->nmb_ifp;
2253         src = buf;
2254
2255         bh = rman_get_bushandle(sc->ndis_res_am);
2256         bt = rman_get_bustag(sc->ndis_res_am);
2257
2258         for (i = 0; i < len; i++)
2259                 bus_space_write_1(bt, bh, (offset + i) * 2, src[i]);
2260
2261         return(i);
2262 }
2263
2264 __stdcall static list_entry *
2265 ndis_insert_head(head, entry, lock)
2266         list_entry              *head;
2267         list_entry              *entry;
2268         ndis_spin_lock          *lock;
2269 {
2270         list_entry              *flink;
2271
2272         lock->nsl_kirql = FASTCALL2(hal_lock,
2273             &lock->nsl_spinlock, DISPATCH_LEVEL);
2274         flink = head->nle_flink;
2275         entry->nle_flink = flink;
2276         entry->nle_blink = head;
2277         flink->nle_blink = entry;
2278         head->nle_flink = entry;
2279         FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
2280
2281         return(flink);
2282 }
2283
2284 __stdcall static list_entry *
2285 ndis_remove_head(head, lock)
2286         list_entry              *head;
2287         ndis_spin_lock          *lock;
2288 {
2289         list_entry              *flink;
2290         list_entry              *entry;
2291
2292         lock->nsl_kirql = FASTCALL2(hal_lock,
2293             &lock->nsl_spinlock, DISPATCH_LEVEL);
2294         entry = head->nle_flink;
2295         flink = entry->nle_flink;
2296         head->nle_flink = flink;
2297         flink->nle_blink = head;
2298         FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
2299
2300         return(entry);
2301 }
2302
2303 __stdcall static list_entry *
2304 ndis_insert_tail(head, entry, lock)
2305         list_entry              *head;
2306         list_entry              *entry;
2307         ndis_spin_lock          *lock;
2308 {
2309         list_entry              *blink;
2310
2311         lock->nsl_kirql = FASTCALL2(hal_lock,
2312             &lock->nsl_spinlock, DISPATCH_LEVEL);
2313         blink = head->nle_blink;
2314         entry->nle_flink = head;
2315         entry->nle_blink = blink;
2316         blink->nle_flink = entry;
2317         head->nle_blink = entry;
2318         FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
2319
2320         return(blink);
2321 }
2322
2323 __stdcall static uint8_t
2324 ndis_sync_with_intr(intr, syncfunc, syncctx)
2325         ndis_miniport_interrupt *intr;
2326         void                    *syncfunc;
2327         void                    *syncctx;
2328 {
2329         struct ndis_softc       *sc;
2330         __stdcall uint8_t (*sync)(void *);
2331         uint8_t                 rval;
2332         NDIS_LOCK_INFO;
2333
2334         if (syncfunc == NULL || syncctx == NULL)
2335                 return(0);
2336
2337         sc = (struct ndis_softc *)intr->ni_block->nmb_ifp;
2338         sync = syncfunc;
2339         NDIS_INTRLOCK(sc);
2340         rval = sync(syncctx);
2341         NDIS_INTRUNLOCK(sc);
2342
2343         return(rval);
2344 }
2345
2346 /*
2347  * Return the number of 100 nanosecond intervals since
2348  * January 1, 1601. (?!?!)
2349  */
2350 __stdcall static void
2351 ndis_time(tval)
2352         uint64_t                *tval;
2353 {
2354         struct timespec         ts;
2355
2356         nanotime(&ts);
2357         *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
2358             11644473600LL;
2359
2360         return;
2361 }
2362
2363 /*
2364  * Return the number of milliseconds since the system booted.
2365  */
2366 __stdcall static void
2367 ndis_uptime(tval)
2368         uint32_t                *tval;
2369 {
2370         struct timespec         ts;
2371
2372         nanouptime(&ts);
2373         *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
2374
2375         return;
2376 }
2377
2378 __stdcall static void
2379 ndis_init_string(dst, src)
2380         ndis_unicode_string     *dst;
2381         char                    *src;
2382 {
2383         ndis_unicode_string     *u;
2384
2385         u = dst;
2386         u->nus_buf = NULL;
2387         if (ndis_ascii_to_unicode(src, &u->nus_buf))
2388                 return;
2389         u->nus_len = u->nus_maxlen = strlen(src) * 2;
2390         return;
2391 }
2392
2393 __stdcall static void
2394 ndis_free_string(str)
2395         ndis_unicode_string     *str;
2396 {
2397         if (str == NULL)
2398                 return;
2399         if (str->nus_buf != NULL)
2400                 free(str->nus_buf, M_DEVBUF);
2401         free(str, M_DEVBUF);
2402         return;
2403 }
2404
2405 __stdcall static ndis_status
2406 ndis_remove_miniport(adapter)
2407         ndis_handle             *adapter;
2408 {
2409         return(NDIS_STATUS_SUCCESS);
2410 }
2411
2412 __stdcall static void
2413 ndis_init_ansi_string(dst, src)
2414         ndis_ansi_string        *dst;
2415         char                    *src;
2416 {
2417         ndis_ansi_string        *a;
2418
2419         a = dst;
2420         if (a == NULL)
2421                 return;
2422         if (src == NULL) {
2423                 a->nas_len = a->nas_maxlen = 0;
2424                 a->nas_buf = NULL;
2425         } else {
2426                 a->nas_buf = src;
2427                 a->nas_len = a->nas_maxlen = strlen(src);
2428         }
2429
2430         return;
2431 }
2432
2433 __stdcall static void
2434 ndis_init_unicode_string(dst, src)
2435         ndis_unicode_string     *dst;
2436         uint16_t                *src;
2437 {
2438         ndis_unicode_string     *u;
2439         int                     i;
2440
2441         u = dst;
2442         if (u == NULL)
2443                 return;
2444         if (src == NULL) {
2445                 u->nus_len = u->nus_maxlen = 0;
2446                 u->nus_buf = NULL;
2447         } else {
2448                 i = 0;
2449                 while(src[i] != 0)
2450                         i++;
2451                 u->nus_buf = src;
2452                 u->nus_len = u->nus_maxlen = i * 2;
2453         }
2454
2455         return;
2456 }
2457
2458 __stdcall static void ndis_get_devprop(adapter, phydevobj,
2459         funcdevobj, nextdevobj, resources, transresources)
2460         ndis_handle             adapter;
2461         device_object           **phydevobj;
2462         device_object           **funcdevobj;
2463         device_object           **nextdevobj;
2464         cm_resource_list        *resources;
2465         cm_resource_list        *transresources;
2466 {
2467         ndis_miniport_block     *block;
2468
2469         block = (ndis_miniport_block *)adapter;
2470
2471         if (phydevobj != NULL)
2472                 *phydevobj = &block->nmb_devobj;
2473         if (funcdevobj != NULL)
2474                 *funcdevobj = &block->nmb_devobj;
2475
2476         return;
2477 }
2478
2479 __stdcall static void
2480 ndis_firstbuf(packet, buf, firstva, firstlen, totlen)
2481         ndis_packet             *packet;
2482         ndis_buffer             **buf;
2483         void                    **firstva;
2484         uint32_t                *firstlen;
2485         uint32_t                *totlen;
2486 {
2487         ndis_buffer             *tmp;
2488
2489         tmp = packet->np_private.npp_head;
2490         *buf = tmp;
2491         if (tmp == NULL) {
2492                 *firstva = NULL;
2493                 *firstlen = *totlen = 0;
2494         } else {
2495                 *firstva = MDL_VA(tmp);
2496                 *firstlen = *totlen = tmp->nb_bytecount;
2497                 for (tmp = tmp->nb_next; tmp != NULL; tmp = tmp->nb_next)
2498                         *totlen += tmp->nb_bytecount;
2499         }
2500
2501         return;
2502 }
2503
2504 __stdcall static void
2505 ndis_firstbuf_safe(packet, buf, firstva, firstlen, totlen, prio)
2506         ndis_packet             *packet;
2507         ndis_buffer             **buf;
2508         void                    **firstva;
2509         uint32_t                *firstlen;
2510         uint32_t                *totlen;
2511         uint32_t                prio;
2512 {
2513         ndis_firstbuf(packet, buf, firstva, firstlen, totlen);
2514 }
2515
2516 /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
2517 __stdcall static void
2518 ndis_open_file(status, filehandle, filelength, filename, highestaddr)
2519         ndis_status             *status;
2520         ndis_handle             *filehandle;
2521         uint32_t                *filelength;
2522         ndis_unicode_string     *filename;
2523         ndis_physaddr           highestaddr;
2524 {
2525         char                    *afilename = NULL;
2526         struct thread           *td = curthread;
2527         struct nlookupdata      nd;
2528         int                     error;
2529         struct vattr            vat;
2530         struct vattr            *vap = &vat;
2531         ndis_fh                 *fh;
2532         struct vnode            *vp;
2533         char                    path[MAXPATHLEN];
2534
2535         ndis_unicode_to_ascii(filename->nus_buf,
2536             filename->nus_len, &afilename);
2537
2538         sprintf(path, "%s/%s", ndis_filepath, afilename);
2539         free(afilename, M_DEVBUF);
2540
2541         fh = malloc(sizeof(ndis_fh), M_TEMP, M_WAITOK);
2542
2543         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
2544         if (error == 0)
2545                 error = vn_open(&nd, NULL, FREAD, 0);
2546         if (error) {
2547                 *status = NDIS_STATUS_FILE_NOT_FOUND;
2548                 free(fh, M_TEMP);
2549                 printf("NDIS: open file %s failed: %d\n", path, error);
2550                 goto done;
2551         }
2552
2553         vp = nd.nl_open_vp;
2554         nd.nl_open_vp = NULL;
2555
2556         /* Get the file size. */
2557         VOP_GETATTR(vp, vap, td);
2558         VOP_UNLOCK(vp, 0, td);
2559
2560         fh->nf_vp = vp;
2561         fh->nf_map = NULL;
2562         *filehandle = fh;
2563         *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
2564         *status = NDIS_STATUS_SUCCESS;
2565
2566 done:
2567         nlookup_done(&nd);
2568         return;
2569 }
2570
2571 __stdcall static void
2572 ndis_map_file(status, mappedbuffer, filehandle)
2573         ndis_status             *status;
2574         void                    **mappedbuffer;
2575         ndis_handle             filehandle;
2576 {
2577         ndis_fh                 *fh;
2578         struct thread           *td = curthread;
2579         int                     error, resid;
2580
2581         if (filehandle == NULL) {
2582                 *status = NDIS_STATUS_FAILURE;
2583                 return;
2584         }
2585
2586         fh = (ndis_fh *)filehandle;
2587
2588         if (fh->nf_vp == NULL) {
2589                 *status = NDIS_STATUS_FAILURE;
2590                 return;
2591         }
2592
2593         if (fh->nf_map != NULL) {
2594                 *status = NDIS_STATUS_ALREADY_MAPPED;
2595                 return;
2596         }
2597
2598         fh->nf_map = malloc(fh->nf_maplen, M_DEVBUF, M_WAITOK);
2599
2600         error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0,
2601             UIO_SYSSPACE, 0, proc0.p_ucred, &resid, td);
2602
2603         if (error)
2604                 *status = NDIS_STATUS_FAILURE;
2605         else {
2606                 *status = NDIS_STATUS_SUCCESS;
2607                 *mappedbuffer = fh->nf_map;
2608         }
2609
2610         return;
2611 }
2612
2613 __stdcall static void
2614 ndis_unmap_file(filehandle)
2615         ndis_handle             filehandle;
2616 {
2617         ndis_fh                 *fh;
2618         fh = (ndis_fh *)filehandle;
2619
2620         if (fh->nf_map == NULL)
2621                 return;
2622         free(fh->nf_map, M_DEVBUF);
2623         fh->nf_map = NULL;
2624
2625         return;
2626 }
2627
2628 __stdcall static void
2629 ndis_close_file(filehandle)
2630         ndis_handle             filehandle;
2631 {
2632         struct thread           *td = curthread;
2633         ndis_fh                 *fh;
2634
2635         if (filehandle == NULL)
2636                 return;
2637
2638         fh = (ndis_fh *)filehandle;
2639         if (fh->nf_map != NULL) {
2640                 free(fh->nf_map, M_DEVBUF);
2641                 fh->nf_map = NULL;
2642         }
2643
2644         if (fh->nf_vp == NULL)
2645                 return;
2646
2647         vn_close(fh->nf_vp, FREAD, td);
2648
2649         fh->nf_vp = NULL;
2650         free(fh, M_DEVBUF);
2651
2652         return;
2653 }
2654
2655 __stdcall static uint8_t
2656 ndis_cpu_cnt()
2657 {
2658         return(ncpus);
2659 }
2660
2661 typedef __stdcall void (*ndis_statusdone_handler)(ndis_handle);
2662 typedef __stdcall void (*ndis_status_handler)(ndis_handle, ndis_status,
2663         void *, uint32_t);
2664
2665 __stdcall static void
2666 ndis_ind_statusdone(adapter)
2667         ndis_handle             adapter;
2668 {
2669         ndis_miniport_block     *block;
2670         ndis_statusdone_handler statusdonefunc;
2671
2672         block = (ndis_miniport_block *)adapter;
2673         statusdonefunc = block->nmb_statusdone_func;
2674
2675         statusdonefunc(adapter);
2676         return;
2677 }
2678
2679 __stdcall static void
2680 ndis_ind_status(adapter, status, sbuf, slen)
2681         ndis_handle             adapter;
2682         ndis_status             status;
2683         void                    *sbuf;
2684         uint32_t                slen;
2685 {
2686         ndis_miniport_block     *block;
2687         ndis_status_handler     statusfunc;
2688
2689         block = (ndis_miniport_block *)adapter;
2690         statusfunc = block->nmb_status_func;
2691
2692         statusfunc(adapter, status, sbuf, slen);
2693         return;
2694 }
2695
2696 static void
2697 ndis_workfunc(ctx)
2698         void                    *ctx;
2699 {
2700         ndis_work_item          *work;
2701         ndis_proc               workfunc;
2702
2703         work = ctx;
2704         workfunc = work->nwi_func;
2705         workfunc(work, work->nwi_ctx);
2706         return;
2707 }
2708
2709 __stdcall static ndis_status
2710 ndis_sched_workitem(work)
2711         ndis_work_item          *work;
2712 {
2713         ndis_sched(ndis_workfunc, work, NDIS_TASKQUEUE);
2714         return(NDIS_STATUS_SUCCESS);
2715 }
2716
2717 __stdcall static void
2718 ndis_pkt_to_pkt(dpkt, doff, reqlen, spkt, soff, cpylen)
2719         ndis_packet             *dpkt;
2720         uint32_t                doff;
2721         uint32_t                reqlen;
2722         ndis_packet             *spkt;
2723         uint32_t                soff;
2724         uint32_t                *cpylen;
2725 {
2726         ndis_buffer             *src, *dst;
2727         char                    *sptr, *dptr;
2728         int                     resid, copied, len, scnt, dcnt;
2729
2730         *cpylen = 0;
2731
2732         src = spkt->np_private.npp_head;
2733         dst = dpkt->np_private.npp_head;
2734
2735         sptr = MDL_VA(src);
2736         dptr = MDL_VA(dst);
2737         scnt = src->nb_bytecount;
2738         dcnt = dst->nb_bytecount;
2739
2740         while (soff) {
2741                 if (src->nb_bytecount > soff) {
2742                         sptr += soff;
2743                         scnt = src->nb_bytecount - soff;
2744                         break;
2745                 }
2746                 soff -= src->nb_bytecount;
2747                 src = src->nb_next;
2748                 if (src == NULL)
2749                         return;
2750                 sptr = MDL_VA(src);
2751         }
2752
2753         while (doff) {
2754                 if (dst->nb_bytecount > doff) {
2755                         dptr += doff;
2756                         dcnt = dst->nb_bytecount - doff;
2757                         break;
2758                 }
2759                 doff -= dst->nb_bytecount;
2760                 dst = dst->nb_next;
2761                 if (dst == NULL)
2762                         return;
2763                 dptr = MDL_VA(dst);
2764         }
2765
2766         resid = reqlen;
2767         copied = 0;
2768
2769         while(1) {
2770                 if (resid < scnt)
2771                         len = resid;
2772                 else
2773                         len = scnt;
2774                 if (dcnt < len)
2775                         len = dcnt;
2776
2777                 bcopy(sptr, dptr, len);
2778
2779                 copied += len;
2780                 resid -= len;
2781                 if (resid == 0)
2782                         break;
2783
2784                 dcnt -= len;
2785                 if (dcnt == 0) {
2786                         dst = dst->nb_next;
2787                         if (dst == NULL)
2788                                 break;
2789                         dptr = MDL_VA(dst);
2790                         dcnt = dst->nb_bytecount;
2791                 }
2792
2793                 scnt -= len;
2794                 if (scnt == 0) {
2795                         src = src->nb_next;
2796                         if (src == NULL)
2797                                 break;
2798                         sptr = MDL_VA(src);
2799                         scnt = src->nb_bytecount;
2800                 }
2801         }
2802
2803         *cpylen = copied;
2804         return;
2805 }
2806
2807 __stdcall static void
2808 ndis_pkt_to_pkt_safe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
2809         ndis_packet             *dpkt;
2810         uint32_t                doff;
2811         uint32_t                reqlen;
2812         ndis_packet             *spkt;
2813         uint32_t                soff;
2814         uint32_t                *cpylen;
2815         uint32_t                prio;
2816 {
2817         ndis_pkt_to_pkt(dpkt, doff, reqlen, spkt, soff, cpylen);
2818         return;
2819 }
2820
2821 __stdcall static ndis_status
2822 ndis_register_dev(handle, devname, symname, majorfuncs, devobj, devhandle)
2823         ndis_handle             handle;
2824         ndis_unicode_string     *devname;
2825         ndis_unicode_string     *symname;
2826         driver_dispatch         *majorfuncs[];
2827         void                    **devobj;
2828         ndis_handle             *devhandle;
2829 {
2830         ndis_miniport_block     *block;
2831
2832         block = (ndis_miniport_block *)handle;
2833         *devobj = &block->nmb_devobj;
2834         *devhandle = handle;
2835
2836         return(NDIS_STATUS_SUCCESS);
2837 }
2838
2839 __stdcall static ndis_status
2840 ndis_deregister_dev(handle)
2841         ndis_handle             handle;
2842 {
2843         return(NDIS_STATUS_SUCCESS);
2844 }
2845
2846 __stdcall static ndis_status
2847 ndis_query_name(name, handle)
2848         ndis_unicode_string     *name;
2849         ndis_handle             handle;
2850 {
2851         ndis_miniport_block     *block;
2852
2853         block = (ndis_miniport_block *)handle;
2854         ndis_ascii_to_unicode(__DECONST(char *,
2855             device_get_nameunit(block->nmb_dev)), &name->nus_buf);
2856         name->nus_len = strlen(device_get_nameunit(block->nmb_dev)) * 2;
2857
2858         return(NDIS_STATUS_SUCCESS);
2859 }
2860
2861 __stdcall static void
2862 ndis_register_unload(handle, func)
2863         ndis_handle             handle;
2864         void                    *func;
2865 {
2866         return;
2867 }
2868
2869 __stdcall static void
2870 dummy()
2871 {
2872         printf ("NDIS dummy called...\n");
2873         return;
2874 }
2875
2876 image_patch_table ndis_functbl[] = {
2877         { "NdisCopyFromPacketToPacket", (FUNC)ndis_pkt_to_pkt },
2878         { "NdisCopyFromPacketToPacketSafe", (FUNC)ndis_pkt_to_pkt_safe },
2879         { "NdisScheduleWorkItem",       (FUNC)ndis_sched_workitem },
2880         { "NdisMIndicateStatusComplete", (FUNC)ndis_ind_statusdone },
2881         { "NdisMIndicateStatus",        (FUNC)ndis_ind_status },
2882         { "NdisSystemProcessorCount",   (FUNC)ndis_cpu_cnt },
2883         { "NdisUnchainBufferAtBack",    (FUNC)ndis_unchain_tailbuf, },
2884         { "NdisGetFirstBufferFromPacket", (FUNC)ndis_firstbuf },
2885         { "NdisGetFirstBufferFromPacketSafe", (FUNC)ndis_firstbuf_safe },
2886         { "NdisGetBufferPhysicalArraySize", (FUNC)ndis_buf_physpages },
2887         { "NdisMGetDeviceProperty",     (FUNC)ndis_get_devprop },
2888         { "NdisInitAnsiString",         (FUNC)ndis_init_ansi_string },
2889         { "NdisInitUnicodeString",      (FUNC)ndis_init_unicode_string },
2890         { "NdisWriteConfiguration",     (FUNC)ndis_write_cfg },
2891         { "NdisAnsiStringToUnicodeString", (FUNC)ndis_ansi2unicode },
2892         { "NdisTerminateWrapper",       (FUNC)ndis_termwrap },
2893         { "NdisOpenConfigurationKeyByName", (FUNC)ndis_open_cfgbyname },
2894         { "NdisOpenConfigurationKeyByIndex", (FUNC)ndis_open_cfgbyidx },
2895         { "NdisMRemoveMiniport",        (FUNC)ndis_remove_miniport },
2896         { "NdisInitializeString",       (FUNC)ndis_init_string },       
2897         { "NdisFreeString",             (FUNC)ndis_free_string },       
2898         { "NdisGetCurrentSystemTime",   (FUNC)ndis_time },
2899         { "NdisGetSystemUpTime",        (FUNC)ndis_uptime },
2900         { "NdisMSynchronizeWithInterrupt", (FUNC)ndis_sync_with_intr },
2901         { "NdisMAllocateSharedMemoryAsync", (FUNC)ndis_alloc_sharedmem_async },
2902         { "NdisInterlockedInsertHeadList", (FUNC)ndis_insert_head },
2903         { "NdisInterlockedInsertTailList", (FUNC)ndis_insert_tail },
2904         { "NdisInterlockedRemoveHeadList", (FUNC)ndis_remove_head },
2905         { "NdisInitializeWrapper",      (FUNC)ndis_initwrap },
2906         { "NdisMRegisterMiniport",      (FUNC)ndis_register_miniport },
2907         { "NdisAllocateMemoryWithTag",  (FUNC)ndis_malloc_withtag },
2908         { "NdisAllocateMemory",         (FUNC)ndis_malloc },
2909         { "NdisMSetAttributesEx",       (FUNC)ndis_setattr_ex },
2910         { "NdisCloseConfiguration",     (FUNC)ndis_close_cfg },
2911         { "NdisReadConfiguration",      (FUNC)ndis_read_cfg },
2912         { "NdisOpenConfiguration",      (FUNC)ndis_open_cfg },
2913         { "NdisAcquireSpinLock",        (FUNC)ndis_lock },
2914         { "NdisReleaseSpinLock",        (FUNC)ndis_unlock },
2915         { "NdisDprAcquireSpinLock",     (FUNC)ndis_lock_dpr },
2916         { "NdisDprReleaseSpinLock",     (FUNC)ndis_unlock_dpr },
2917         { "NdisAllocateSpinLock",       (FUNC)ndis_create_lock },
2918         { "NdisFreeSpinLock",           (FUNC)ndis_destroy_lock },
2919         { "NdisFreeMemory",             (FUNC)ndis_free },
2920         { "NdisReadPciSlotInformation", (FUNC)ndis_read_pci },
2921         { "NdisWritePciSlotInformation",(FUNC)ndis_write_pci },
2922         { "NdisImmediateReadPciSlotInformation", (FUNC)ndis_read_pci },
2923         { "NdisImmediateWritePciSlotInformation", (FUNC)ndis_write_pci },
2924         { "NdisWriteErrorLogEntry",     (FUNC)ndis_syslog },
2925         { "NdisMStartBufferPhysicalMapping", (FUNC)ndis_vtophys_load },
2926         { "NdisMCompleteBufferPhysicalMapping", (FUNC)ndis_vtophys_unload },
2927         { "NdisMInitializeTimer",       (FUNC)ndis_create_timer },
2928         { "NdisInitializeTimer",        (FUNC)ndis_init_timer },
2929         { "NdisSetTimer",               (FUNC)ndis_set_timer },
2930         { "NdisMCancelTimer",           (FUNC)ndis_cancel_timer },
2931         { "NdisCancelTimer",            (FUNC)ndis_cancel_timer },
2932         { "NdisMSetPeriodicTimer",      (FUNC)ndis_set_periodic_timer },
2933         { "NdisMQueryAdapterResources", (FUNC)ndis_query_resources },
2934         { "NdisMRegisterIoPortRange",   (FUNC)ndis_register_ioport },
2935         { "NdisMDeregisterIoPortRange", (FUNC)ndis_deregister_ioport },
2936         { "NdisReadNetworkAddress",     (FUNC)ndis_read_netaddr },
2937         { "NdisQueryMapRegisterCount",  (FUNC)ndis_mapreg_cnt },
2938         { "NdisMAllocateMapRegisters",  (FUNC)ndis_alloc_mapreg },
2939         { "NdisMFreeMapRegisters",      (FUNC)ndis_free_mapreg },
2940         { "NdisMAllocateSharedMemory",  (FUNC)ndis_alloc_sharedmem },
2941         { "NdisMMapIoSpace",            (FUNC)ndis_map_iospace },
2942         { "NdisMUnmapIoSpace",          (FUNC)ndis_unmap_iospace },
2943         { "NdisGetCacheFillSize",       (FUNC)ndis_cachefill },
2944         { "NdisMGetDmaAlignment",       (FUNC)ndis_dma_align },
2945         { "NdisMInitializeScatterGatherDma", (FUNC)ndis_init_sc_dma },
2946         { "NdisAllocatePacketPool",     (FUNC)ndis_alloc_packetpool },
2947         { "NdisAllocatePacketPoolEx",   (FUNC)ndis_ex_alloc_packetpool },
2948         { "NdisAllocatePacket",         (FUNC)ndis_alloc_packet },
2949         { "NdisFreePacket",             (FUNC)ndis_release_packet },
2950         { "NdisFreePacketPool",         (FUNC)ndis_free_packetpool },
2951         { "NdisDprAllocatePacket",      (FUNC)ndis_alloc_packet },
2952         { "NdisDprFreePacket",          (FUNC)ndis_release_packet },
2953         { "NdisAllocateBufferPool",     (FUNC)ndis_alloc_bufpool },
2954         { "NdisAllocateBuffer",         (FUNC)ndis_alloc_buf },
2955         { "NdisQueryBuffer",            (FUNC)ndis_query_buf },
2956         { "NdisQueryBufferSafe",        (FUNC)ndis_query_buf_safe },
2957         { "NdisBufferVirtualAddress",   (FUNC)ndis_buf_vaddr },
2958         { "NdisBufferVirtualAddressSafe", (FUNC)ndis_buf_vaddr_safe },
2959         { "NdisBufferLength",           (FUNC)ndis_buflen },
2960         { "NdisFreeBuffer",             (FUNC)ndis_release_buf },
2961         { "NdisFreeBufferPool",         (FUNC)ndis_free_bufpool },
2962         { "NdisInterlockedIncrement",   (FUNC)ndis_interlock_inc },
2963         { "NdisInterlockedDecrement",   (FUNC)ndis_interlock_dec },
2964         { "NdisInitializeEvent",        (FUNC)ndis_init_event },
2965         { "NdisSetEvent",               (FUNC)ndis_set_event },
2966         { "NdisResetEvent",             (FUNC)ndis_reset_event },
2967         { "NdisWaitEvent",              (FUNC)ndis_wait_event },
2968         { "NdisUnicodeStringToAnsiString", (FUNC)ndis_unicode2ansi },
2969         { "NdisMPciAssignResources",    (FUNC)ndis_assign_pcirsrc },
2970         { "NdisMFreeSharedMemory",      (FUNC)ndis_free_sharedmem },
2971         { "NdisMRegisterInterrupt",     (FUNC)ndis_register_intr },
2972         { "NdisMDeregisterInterrupt",   (FUNC)ndis_deregister_intr },
2973         { "NdisMRegisterAdapterShutdownHandler", (FUNC)ndis_register_shutdown },
2974         { "NdisMDeregisterAdapterShutdownHandler", (FUNC)ndis_deregister_shutdown },
2975         { "NDIS_BUFFER_TO_SPAN_PAGES",  (FUNC)ndis_numpages },
2976         { "NdisQueryBufferOffset",      (FUNC)ndis_query_bufoffset },
2977         { "NdisAdjustBufferLength",     (FUNC)ndis_adjust_buflen },
2978         { "NdisPacketPoolUsage",        (FUNC)ndis_packetpool_use },
2979         { "NdisMSleep",                 (FUNC)ndis_sleep },
2980         { "NdisUnchainBufferAtFront",   (FUNC)ndis_unchain_headbuf },
2981         { "NdisReadPcmciaAttributeMemory", (FUNC)ndis_read_pccard_amem },
2982         { "NdisWritePcmciaAttributeMemory", (FUNC)ndis_write_pccard_amem },
2983         { "NdisOpenFile",               (FUNC)ndis_open_file },
2984         { "NdisMapFile",                (FUNC)ndis_map_file },
2985         { "NdisUnmapFile",              (FUNC)ndis_unmap_file },
2986         { "NdisCloseFile",              (FUNC)ndis_close_file },
2987         { "NdisMRegisterDevice",        (FUNC)ndis_register_dev },
2988         { "NdisMDeregisterDevice",      (FUNC)ndis_deregister_dev },
2989         { "NdisMQueryAdapterInstanceName", (FUNC)ndis_query_name },
2990         { "NdisMRegisterUnloadHandler", (FUNC)ndis_register_unload },
2991
2992         /*
2993          * This last entry is a catch-all for any function we haven't
2994          * implemented yet. The PE import list patching routine will
2995          * use it for any function that doesn't have an explicit match
2996          * in this table.
2997          */
2998
2999         { NULL, (FUNC)dummy },
3000
3001         /* End of list. */
3002
3003         { NULL, NULL },
3004 };