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