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