]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/compat/ndis/subr_ndis.c
sysctl(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sys / compat / ndis / subr_ndis.c
1 /*-
2  * SPDX-License-Identifier: BSD-4-Clause
3  *
4  * Copyright (c) 2003
5  *      Bill Paul <wpaul@windriver.com>.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by Bill Paul.
18  * 4. Neither the name of the author nor the names of any co-contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /*
39  * This file implements a translation layer between the BSD networking
40  * infrasturcture and Windows(R) NDIS network driver modules. A Windows
41  * NDIS driver calls into several functions in the NDIS.SYS Windows
42  * kernel module and exports a table of functions designed to be called
43  * by the NDIS subsystem. Using the PE loader, we can patch our own
44  * versions of the NDIS routines into a given Windows driver module and
45  * convince the driver that it is in fact running on Windows.
46  *
47  * We provide a table of all our implemented NDIS routines which is patched
48  * into the driver object code. All our exported routines must use the
49  * _stdcall calling convention, since that's what the Windows object code
50  * expects.
51  */
52
53 #include <sys/ctype.h>
54 #include <sys/param.h>
55 #include <sys/types.h>
56 #include <sys/errno.h>
57
58 #include <sys/callout.h>
59 #include <sys/kernel.h>
60 #include <sys/systm.h>
61 #include <sys/malloc.h>
62 #include <sys/lock.h>
63 #include <sys/mutex.h>
64 #include <sys/socket.h>
65 #include <sys/sysctl.h>
66 #include <sys/timespec.h>
67 #include <sys/smp.h>
68 #include <sys/queue.h>
69 #include <sys/proc.h>
70 #include <sys/filedesc.h>
71 #include <sys/namei.h>
72 #include <sys/fcntl.h>
73 #include <sys/vnode.h>
74 #include <sys/kthread.h>
75 #include <sys/linker.h>
76 #include <sys/mount.h>
77 #include <sys/sysproto.h>
78
79 #include <net/if.h>
80 #include <net/if_var.h>
81 #include <net/if_arp.h>
82 #include <net/ethernet.h>
83 #include <net/if_dl.h>
84 #include <net/if_media.h>
85
86 #include <machine/atomic.h>
87 #include <machine/bus.h>
88 #include <machine/resource.h>
89
90 #include <sys/bus.h>
91 #include <sys/rman.h>
92
93 #include <machine/stdarg.h>
94
95 #include <net80211/ieee80211_var.h>
96 #include <net80211/ieee80211_ioctl.h>
97
98 #include <dev/pci/pcireg.h>
99 #include <dev/pci/pcivar.h>
100 #include <dev/usb/usb.h>
101 #include <dev/usb/usbdi.h>
102
103 #include <compat/ndis/pe_var.h>
104 #include <compat/ndis/cfg_var.h>
105 #include <compat/ndis/resource_var.h>
106 #include <compat/ndis/ntoskrnl_var.h>
107 #include <compat/ndis/hal_var.h>
108 #include <compat/ndis/ndis_var.h>
109 #include <dev/if_ndis/if_ndisvar.h>
110
111 #include <vm/vm.h>
112 #include <vm/vm_param.h>
113 #include <vm/pmap.h>
114 #include <vm/uma.h>
115 #include <vm/vm_kern.h>
116 #include <vm/vm_map.h>
117
118 static char ndis_filepath[MAXPATHLEN];
119
120 SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
121     MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
122
123 static void NdisInitializeWrapper(ndis_handle *,
124         driver_object *, void *, void *);
125 static ndis_status NdisMRegisterMiniport(ndis_handle,
126         ndis_miniport_characteristics *, int);
127 static ndis_status NdisAllocateMemoryWithTag(void **,
128         uint32_t, uint32_t);
129 static ndis_status NdisAllocateMemory(void **,
130         uint32_t, uint32_t, ndis_physaddr);
131 static void NdisFreeMemory(void *, uint32_t, uint32_t);
132 static ndis_status NdisMSetAttributesEx(ndis_handle, ndis_handle,
133         uint32_t, uint32_t, ndis_interface_type);
134 static void NdisOpenConfiguration(ndis_status *,
135         ndis_handle *, ndis_handle);
136 static void NdisOpenConfigurationKeyByIndex(ndis_status *,
137         ndis_handle, uint32_t, unicode_string *, ndis_handle *);
138 static void NdisOpenConfigurationKeyByName(ndis_status *,
139         ndis_handle, unicode_string *, ndis_handle *);
140 static ndis_status ndis_encode_parm(ndis_miniport_block *,
141         struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
142 static ndis_status ndis_decode_parm(ndis_miniport_block *,
143         ndis_config_parm *, char *);
144 static void NdisReadConfiguration(ndis_status *, ndis_config_parm **,
145         ndis_handle, unicode_string *, ndis_parm_type);
146 static void NdisWriteConfiguration(ndis_status *, ndis_handle,
147         unicode_string *, ndis_config_parm *);
148 static void NdisCloseConfiguration(ndis_handle);
149 static void NdisAllocateSpinLock(ndis_spin_lock *);
150 static void NdisFreeSpinLock(ndis_spin_lock *);
151 static void NdisAcquireSpinLock(ndis_spin_lock *);
152 static void NdisReleaseSpinLock(ndis_spin_lock *);
153 static void NdisDprAcquireSpinLock(ndis_spin_lock *);
154 static void NdisDprReleaseSpinLock(ndis_spin_lock *);
155 static void NdisInitializeReadWriteLock(ndis_rw_lock *);
156 static void NdisAcquireReadWriteLock(ndis_rw_lock *,
157         uint8_t, ndis_lock_state *);
158 static void NdisReleaseReadWriteLock(ndis_rw_lock *, ndis_lock_state *);
159 static uint32_t NdisReadPciSlotInformation(ndis_handle, uint32_t,
160         uint32_t, void *, uint32_t);
161 static uint32_t NdisWritePciSlotInformation(ndis_handle, uint32_t,
162         uint32_t, void *, uint32_t);
163 static void NdisWriteErrorLogEntry(ndis_handle, ndis_error_code, uint32_t, ...);
164 static void ndis_map_cb(void *, bus_dma_segment_t *, int, int);
165 static void NdisMStartBufferPhysicalMapping(ndis_handle,
166         ndis_buffer *, uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *);
167 static void NdisMCompleteBufferPhysicalMapping(ndis_handle,
168         ndis_buffer *, uint32_t);
169 static void NdisMInitializeTimer(ndis_miniport_timer *, ndis_handle,
170         ndis_timer_function, void *);
171 static void NdisInitializeTimer(ndis_timer *,
172         ndis_timer_function, void *);
173 static void NdisSetTimer(ndis_timer *, uint32_t);
174 static void NdisMSetPeriodicTimer(ndis_miniport_timer *, uint32_t);
175 static void NdisMCancelTimer(ndis_timer *, uint8_t *);
176 static void ndis_timercall(kdpc *, ndis_miniport_timer *,
177         void *, void *);
178 static void NdisMQueryAdapterResources(ndis_status *, ndis_handle,
179         ndis_resource_list *, uint32_t *);
180 static ndis_status NdisMRegisterIoPortRange(void **,
181         ndis_handle, uint32_t, uint32_t);
182 static void NdisMDeregisterIoPortRange(ndis_handle,
183         uint32_t, uint32_t, void *);
184 static void NdisReadNetworkAddress(ndis_status *, void **,
185         uint32_t *, ndis_handle);
186 static ndis_status NdisQueryMapRegisterCount(uint32_t, uint32_t *);
187 static ndis_status NdisMAllocateMapRegisters(ndis_handle,
188         uint32_t, uint8_t, uint32_t, uint32_t);
189 static void NdisMFreeMapRegisters(ndis_handle);
190 static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int);
191 static void NdisMAllocateSharedMemory(ndis_handle, uint32_t,
192         uint8_t, void **, ndis_physaddr *);
193 static void ndis_asyncmem_complete(device_object *, void *);
194 static ndis_status NdisMAllocateSharedMemoryAsync(ndis_handle,
195         uint32_t, uint8_t, void *);
196 static void NdisMFreeSharedMemory(ndis_handle, uint32_t,
197         uint8_t, void *, ndis_physaddr);
198 static ndis_status NdisMMapIoSpace(void **, ndis_handle,
199         ndis_physaddr, uint32_t);
200 static void NdisMUnmapIoSpace(ndis_handle, void *, uint32_t);
201 static uint32_t NdisGetCacheFillSize(void);
202 static void *NdisGetRoutineAddress(unicode_string *);
203 static uint32_t NdisMGetDmaAlignment(ndis_handle);
204 static ndis_status NdisMInitializeScatterGatherDma(ndis_handle,
205         uint8_t, uint32_t);
206 static void NdisUnchainBufferAtFront(ndis_packet *, ndis_buffer **);
207 static void NdisUnchainBufferAtBack(ndis_packet *, ndis_buffer **);
208 static void NdisAllocateBufferPool(ndis_status *,
209         ndis_handle *, uint32_t);
210 static void NdisFreeBufferPool(ndis_handle);
211 static void NdisAllocateBuffer(ndis_status *, ndis_buffer **,
212         ndis_handle, void *, uint32_t);
213 static void NdisFreeBuffer(ndis_buffer *);
214 static uint32_t NdisBufferLength(ndis_buffer *);
215 static void NdisQueryBuffer(ndis_buffer *, void **, uint32_t *);
216 static void NdisQueryBufferSafe(ndis_buffer *, void **,
217         uint32_t *, uint32_t);
218 static void *NdisBufferVirtualAddress(ndis_buffer *);
219 static void *NdisBufferVirtualAddressSafe(ndis_buffer *, uint32_t);
220 static void NdisAdjustBufferLength(ndis_buffer *, int);
221 static uint32_t NdisInterlockedIncrement(uint32_t *);
222 static uint32_t NdisInterlockedDecrement(uint32_t *);
223 static void NdisInitializeEvent(ndis_event *);
224 static void NdisSetEvent(ndis_event *);
225 static void NdisResetEvent(ndis_event *);
226 static uint8_t NdisWaitEvent(ndis_event *, uint32_t);
227 static ndis_status NdisUnicodeStringToAnsiString(ansi_string *,
228         unicode_string *);
229 static ndis_status
230         NdisAnsiStringToUnicodeString(unicode_string *, ansi_string *);
231 static ndis_status NdisMPciAssignResources(ndis_handle,
232         uint32_t, ndis_resource_list **);
233 static ndis_status NdisMRegisterInterrupt(ndis_miniport_interrupt *,
234         ndis_handle, uint32_t, uint32_t, uint8_t,
235         uint8_t, ndis_interrupt_mode);
236 static void NdisMDeregisterInterrupt(ndis_miniport_interrupt *);
237 static void NdisMRegisterAdapterShutdownHandler(ndis_handle, void *,
238         ndis_shutdown_handler);
239 static void NdisMDeregisterAdapterShutdownHandler(ndis_handle);
240 static uint32_t NDIS_BUFFER_TO_SPAN_PAGES(ndis_buffer *);
241 static void NdisGetBufferPhysicalArraySize(ndis_buffer *,
242         uint32_t *);
243 static void NdisQueryBufferOffset(ndis_buffer *,
244         uint32_t *, uint32_t *);
245 static uint32_t NdisReadPcmciaAttributeMemory(ndis_handle,
246         uint32_t, void *, uint32_t);
247 static uint32_t NdisWritePcmciaAttributeMemory(ndis_handle,
248         uint32_t, void *, uint32_t);
249 static list_entry *NdisInterlockedInsertHeadList(list_entry *,
250         list_entry *, ndis_spin_lock *);
251 static list_entry *NdisInterlockedRemoveHeadList(list_entry *,
252         ndis_spin_lock *);
253 static list_entry *NdisInterlockedInsertTailList(list_entry *,
254         list_entry *, ndis_spin_lock *);
255 static uint8_t
256         NdisMSynchronizeWithInterrupt(ndis_miniport_interrupt *,
257         void *, void *);
258 static void NdisGetCurrentSystemTime(uint64_t *);
259 static void NdisGetSystemUpTime(uint32_t *);
260 static uint32_t NdisGetVersion(void);
261 static void NdisInitializeString(unicode_string *, char *);
262 static void NdisInitAnsiString(ansi_string *, char *);
263 static void NdisInitUnicodeString(unicode_string *, uint16_t *);
264 static void NdisFreeString(unicode_string *);
265 static ndis_status NdisMRemoveMiniport(ndis_handle *);
266 static void NdisTerminateWrapper(ndis_handle, void *);
267 static void NdisMGetDeviceProperty(ndis_handle, device_object **,
268         device_object **, device_object **, cm_resource_list *,
269         cm_resource_list *);
270 static void NdisGetFirstBufferFromPacket(ndis_packet *,
271         ndis_buffer **, void **, uint32_t *, uint32_t *);
272 static void NdisGetFirstBufferFromPacketSafe(ndis_packet *,
273         ndis_buffer **, void **, uint32_t *, uint32_t *, uint32_t);
274 static int ndis_find_sym(linker_file_t, char *, char *, caddr_t *);
275 static void NdisOpenFile(ndis_status *, ndis_handle *, uint32_t *,
276         unicode_string *, ndis_physaddr);
277 static void NdisMapFile(ndis_status *, void **, ndis_handle);
278 static void NdisUnmapFile(ndis_handle);
279 static void NdisCloseFile(ndis_handle);
280 static uint8_t NdisSystemProcessorCount(void);
281 static void NdisGetCurrentProcessorCounts(uint32_t *, uint32_t *, uint32_t *);
282 static void NdisMIndicateStatusComplete(ndis_handle);
283 static void NdisMIndicateStatus(ndis_handle, ndis_status,
284     void *, uint32_t);
285 static uint8_t ndis_intr(kinterrupt *, void *);
286 static void ndis_intrhand(kdpc *, ndis_miniport_interrupt *, void *, void *);
287 static funcptr ndis_findwrap(funcptr);
288 static void NdisCopyFromPacketToPacket(ndis_packet *,
289         uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *);
290 static void NdisCopyFromPacketToPacketSafe(ndis_packet *,
291         uint32_t, uint32_t, ndis_packet *, uint32_t, uint32_t *, uint32_t);
292 static void NdisIMCopySendPerPacketInfo(ndis_packet *, ndis_packet *);
293 static ndis_status NdisMRegisterDevice(ndis_handle,
294         unicode_string *, unicode_string *, driver_dispatch **,
295         void **, ndis_handle *);
296 static ndis_status NdisMDeregisterDevice(ndis_handle);
297 static ndis_status
298         NdisMQueryAdapterInstanceName(unicode_string *, ndis_handle);
299 static void NdisMRegisterUnloadHandler(ndis_handle, void *);
300 static void dummy(void);
301
302 /*
303  * Some really old drivers do not properly check the return value
304  * from NdisAllocatePacket() and NdisAllocateBuffer() and will
305  * sometimes allocate few more buffers/packets that they originally
306  * requested when they created the pool. To prevent this from being
307  * a problem, we allocate a few extra buffers/packets beyond what
308  * the driver asks for. This #define controls how many.
309  */
310 #define NDIS_POOL_EXTRA         16
311
312 int
313 ndis_libinit()
314 {
315         image_patch_table       *patch;
316
317         strcpy(ndis_filepath, "/compat/ndis");
318
319         patch = ndis_functbl;
320         while (patch->ipt_func != NULL) {
321                 windrv_wrap((funcptr)patch->ipt_func,
322                     (funcptr *)&patch->ipt_wrap,
323                     patch->ipt_argcnt, patch->ipt_ftype);
324                 patch++;
325         }
326
327         return (0);
328 }
329
330 int
331 ndis_libfini()
332 {
333         image_patch_table       *patch;
334
335         patch = ndis_functbl;
336         while (patch->ipt_func != NULL) {
337                 windrv_unwrap(patch->ipt_wrap);
338                 patch++;
339         }
340
341         return (0);
342 }
343
344 static funcptr
345 ndis_findwrap(func)
346         funcptr                 func;
347 {
348         image_patch_table       *patch;
349
350         patch = ndis_functbl;
351         while (patch->ipt_func != NULL) {
352                 if ((funcptr)patch->ipt_func == func)
353                         return ((funcptr)patch->ipt_wrap);
354                 patch++;
355         }
356
357         return (NULL);
358 }
359
360 /*
361  * This routine does the messy Windows Driver Model device attachment
362  * stuff on behalf of NDIS drivers. We register our own AddDevice
363  * routine here
364  */
365 static void
366 NdisInitializeWrapper(wrapper, drv, path, unused)
367         ndis_handle             *wrapper;
368         driver_object           *drv;
369         void                    *path;
370         void                    *unused;
371 {
372         /*
373          * As of yet, I haven't come up with a compelling
374          * reason to define a private NDIS wrapper structure,
375          * so we use a pointer to the driver object as the
376          * wrapper handle. The driver object has the miniport
377          * characteristics struct for this driver hung off it
378          * via IoAllocateDriverObjectExtension(), and that's
379          * really all the private data we need.
380          */
381
382         *wrapper = drv;
383
384         /*
385          * If this was really Windows, we'd be registering dispatch
386          * routines for the NDIS miniport module here, but we're
387          * not Windows so all we really need to do is set up an
388          * AddDevice function that'll be invoked when a new device
389          * instance appears.
390          */
391
392         drv->dro_driverext->dre_adddevicefunc = NdisAddDevice;
393 }
394
395 static void
396 NdisTerminateWrapper(handle, syspec)
397         ndis_handle             handle;
398         void                    *syspec;
399 {
400         /* Nothing to see here, move along. */
401 }
402
403 static ndis_status
404 NdisMRegisterMiniport(handle, characteristics, len)
405         ndis_handle             handle;
406         ndis_miniport_characteristics *characteristics;
407         int                     len;
408 {
409         ndis_miniport_characteristics   *ch = NULL;
410         driver_object           *drv;
411
412         drv = (driver_object *)handle;
413
414         /*
415          * We need to save the NDIS miniport characteristics
416          * somewhere. This data is per-driver, not per-device
417          * (all devices handled by the same driver have the
418          * same characteristics) so we hook it onto the driver
419          * object using IoAllocateDriverObjectExtension().
420          * The extra extension info is automagically deleted when
421          * the driver is unloaded (see windrv_unload()).
422          */
423
424         if (IoAllocateDriverObjectExtension(drv, (void *)1,
425             sizeof(ndis_miniport_characteristics), (void **)&ch) !=
426             STATUS_SUCCESS) {
427                 return (NDIS_STATUS_RESOURCES);
428         }
429
430         bzero((char *)ch, sizeof(ndis_miniport_characteristics));
431
432         bcopy((char *)characteristics, (char *)ch, len);
433
434         if (ch->nmc_version_major < 5 || ch->nmc_version_minor < 1) {
435                 ch->nmc_shutdown_handler = NULL;
436                 ch->nmc_canceltxpkts_handler = NULL;
437                 ch->nmc_pnpevent_handler = NULL;
438         }
439
440         return (NDIS_STATUS_SUCCESS);
441 }
442
443 static ndis_status
444 NdisAllocateMemoryWithTag(vaddr, len, tag)
445         void                    **vaddr;
446         uint32_t                len;
447         uint32_t                tag;
448 {
449         void                    *mem;
450
451         mem = ExAllocatePoolWithTag(NonPagedPool, len, tag);
452         if (mem == NULL) {
453                 return (NDIS_STATUS_RESOURCES);
454         }
455         *vaddr = mem;
456
457         return (NDIS_STATUS_SUCCESS);
458 }
459
460 static ndis_status
461 NdisAllocateMemory(vaddr, len, flags, highaddr)
462         void                    **vaddr;
463         uint32_t                len;
464         uint32_t                flags;
465         ndis_physaddr           highaddr;
466 {
467         void                    *mem;
468
469         mem = ExAllocatePoolWithTag(NonPagedPool, len, 0);
470         if (mem == NULL)
471                 return (NDIS_STATUS_RESOURCES);
472         *vaddr = mem;
473
474         return (NDIS_STATUS_SUCCESS);
475 }
476
477 static void
478 NdisFreeMemory(vaddr, len, flags)
479         void                    *vaddr;
480         uint32_t                len;
481         uint32_t                flags;
482 {
483         if (len == 0)
484                 return;
485
486         ExFreePool(vaddr);
487 }
488
489 static ndis_status
490 NdisMSetAttributesEx(adapter_handle, adapter_ctx, hangsecs,
491                         flags, iftype)
492         ndis_handle                     adapter_handle;
493         ndis_handle                     adapter_ctx;
494         uint32_t                        hangsecs;
495         uint32_t                        flags;
496         ndis_interface_type             iftype;
497 {
498         ndis_miniport_block             *block;
499
500         /*
501          * Save the adapter context, we need it for calling
502          * the driver's internal functions.
503          */
504         block = (ndis_miniport_block *)adapter_handle;
505         block->nmb_miniportadapterctx = adapter_ctx;
506         block->nmb_checkforhangsecs = hangsecs;
507         block->nmb_flags = flags;
508
509         return (NDIS_STATUS_SUCCESS);
510 }
511
512 static void
513 NdisOpenConfiguration(status, cfg, wrapctx)
514         ndis_status             *status;
515         ndis_handle             *cfg;
516         ndis_handle             wrapctx;
517 {
518         *cfg = wrapctx;
519         *status = NDIS_STATUS_SUCCESS;
520 }
521
522 static void
523 NdisOpenConfigurationKeyByName(status, cfg, subkey, subhandle)
524         ndis_status             *status;
525         ndis_handle             cfg;
526         unicode_string          *subkey;
527         ndis_handle             *subhandle;
528 {
529         *subhandle = cfg;
530         *status = NDIS_STATUS_SUCCESS;
531 }
532
533 static void
534 NdisOpenConfigurationKeyByIndex(status, cfg, idx, subkey, subhandle)
535         ndis_status             *status;
536         ndis_handle             cfg;
537         uint32_t                idx;
538         unicode_string          *subkey;
539         ndis_handle             *subhandle;
540 {
541         *status = NDIS_STATUS_FAILURE;
542 }
543
544 static ndis_status
545 ndis_encode_parm(block, oid, type, parm)
546         ndis_miniport_block     *block;
547         struct sysctl_oid       *oid;
548         ndis_parm_type          type;
549         ndis_config_parm        **parm;
550 {
551         ndis_config_parm        *p;
552         ndis_parmlist_entry     *np;
553         unicode_string          *us;
554         ansi_string             as;
555         int                     base = 0;
556         uint32_t                val;
557         char                    tmp[32];
558
559         np = ExAllocatePoolWithTag(NonPagedPool,
560             sizeof(ndis_parmlist_entry), 0);
561         if (np == NULL)
562                 return (NDIS_STATUS_RESOURCES);
563         InsertHeadList((&block->nmb_parmlist), (&np->np_list));
564         *parm = p = &np->np_parm;
565
566         switch(type) {
567         case ndis_parm_string:
568                 /* See if this might be a number. */
569                 val = strtoul((char *)oid->oid_arg1, NULL, 10);
570                 us = &p->ncp_parmdata.ncp_stringdata;
571                 p->ncp_type = ndis_parm_string;
572                 if (val) {
573                         snprintf(tmp, 32, "%x", val);
574                         RtlInitAnsiString(&as, tmp);
575                 } else {
576                         RtlInitAnsiString(&as, (char *)oid->oid_arg1);
577                 }
578
579                 if (RtlAnsiStringToUnicodeString(us, &as, TRUE)) {
580                         ExFreePool(np);
581                         return (NDIS_STATUS_RESOURCES);
582                 }
583                 break;
584         case ndis_parm_int:
585                 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
586                         base = 16;
587                 else
588                         base = 10;
589                 p->ncp_type = ndis_parm_int;
590                 p->ncp_parmdata.ncp_intdata =
591                     strtol((char *)oid->oid_arg1, NULL, base);
592                 break;
593         case ndis_parm_hexint:
594 #ifdef notdef
595                 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
596                         base = 16;
597                 else
598                         base = 10;
599 #endif
600                 base = 16;
601                 p->ncp_type = ndis_parm_hexint;
602                 p->ncp_parmdata.ncp_intdata =
603                     strtoul((char *)oid->oid_arg1, NULL, base);
604                 break;
605         default:
606                 return (NDIS_STATUS_FAILURE);
607                 break;
608         }
609
610         return (NDIS_STATUS_SUCCESS);
611 }
612
613 static void
614 NdisReadConfiguration(status, parm, cfg, key, type)
615         ndis_status             *status;
616         ndis_config_parm        **parm;
617         ndis_handle             cfg;
618         unicode_string          *key;
619         ndis_parm_type          type;
620 {
621         char                    *keystr = NULL;
622         ndis_miniport_block     *block;
623         struct ndis_softc       *sc;
624         struct sysctl_oid       *oidp;
625         struct sysctl_ctx_entry *e;
626         ansi_string             as;
627
628         block = (ndis_miniport_block *)cfg;
629         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
630         /*
631         device_printf(sc->ndis_dev, "NdisReadConfiguration sc=%p\n", sc);
632         */
633
634         if (key->us_len == 0 || key->us_buf == NULL) {
635                 *status = NDIS_STATUS_FAILURE;
636                 return;
637         }
638
639         if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
640                 *status = NDIS_STATUS_RESOURCES;
641                 return;
642         }
643
644         keystr = as.as_buf;
645
646         /*
647          * See if registry key is already in a list of known keys
648          * included with the driver.
649          */
650         TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
651                 oidp = e->entry;
652                 if (strcasecmp(oidp->oid_name, keystr) == 0) {
653                         if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
654                                 RtlFreeAnsiString(&as);
655                                 *status = NDIS_STATUS_FAILURE;
656                                 return;
657                         }
658
659                         *status = ndis_encode_parm(block, oidp, type, parm);
660                         RtlFreeAnsiString(&as);
661                         return;
662                 }
663         }
664
665         /*
666          * If the key didn't match, add it to the list of dynamically
667          * created ones. Sometimes, drivers refer to registry keys
668          * that aren't documented in their .INF files. These keys
669          * are supposed to be created by some sort of utility or
670          * control panel snap-in that comes with the driver software.
671          * Sometimes it's useful to be able to manipulate these.
672          * If the driver requests the key in the form of a string,
673          * make its default value an empty string, otherwise default
674          * it to "0".
675          */
676
677         if (type == ndis_parm_int || type == ndis_parm_hexint)
678                 ndis_add_sysctl(sc, keystr, "(dynamic integer key)",
679                     "UNSET", CTLFLAG_RW);
680         else
681                 ndis_add_sysctl(sc, keystr, "(dynamic string key)",
682                     "UNSET", CTLFLAG_RW);
683
684         RtlFreeAnsiString(&as);
685         *status = NDIS_STATUS_FAILURE;
686 }
687
688 static ndis_status
689 ndis_decode_parm(block, parm, val)
690         ndis_miniport_block     *block;
691         ndis_config_parm        *parm;
692         char                    *val;
693 {
694         unicode_string          *ustr;
695         ansi_string             as;
696
697         switch(parm->ncp_type) {
698         case ndis_parm_string:
699                 ustr = &parm->ncp_parmdata.ncp_stringdata;
700                 if (RtlUnicodeStringToAnsiString(&as, ustr, TRUE))
701                         return (NDIS_STATUS_RESOURCES);
702                 bcopy(as.as_buf, val, as.as_len);
703                 RtlFreeAnsiString(&as);
704                 break;
705         case ndis_parm_int:
706                 sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata);
707                 break;
708         case ndis_parm_hexint:
709                 sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata);
710                 break;
711         default:
712                 return (NDIS_STATUS_FAILURE);
713                 break;
714         }
715         return (NDIS_STATUS_SUCCESS);
716 }
717
718 static void
719 NdisWriteConfiguration(status, cfg, key, parm)
720         ndis_status             *status;
721         ndis_handle             cfg;
722         unicode_string          *key;
723         ndis_config_parm        *parm;
724 {
725         ansi_string             as;
726         char                    *keystr = NULL;
727         ndis_miniport_block     *block;
728         struct ndis_softc       *sc;
729         struct sysctl_oid       *oidp;
730         struct sysctl_ctx_entry *e;
731         char                    val[256];
732
733         block = (ndis_miniport_block *)cfg;
734         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
735
736         if (RtlUnicodeStringToAnsiString(&as, key, TRUE)) {
737                 *status = NDIS_STATUS_RESOURCES;
738                 return;
739         }
740
741         keystr = as.as_buf;
742
743         /* Decode the parameter into a string. */
744         bzero(val, sizeof(val));
745         *status = ndis_decode_parm(block, parm, val);
746         if (*status != NDIS_STATUS_SUCCESS) {
747                 RtlFreeAnsiString(&as);
748                 return;
749         }
750
751         /* See if the key already exists. */
752
753         TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
754                 oidp = e->entry;
755                 if (strcasecmp(oidp->oid_name, keystr) == 0) {
756                         /* Found it, set the value. */
757                         strcpy((char *)oidp->oid_arg1, val);
758                         RtlFreeAnsiString(&as);
759                         return;
760                 }
761         }
762
763         /* Not found, add a new key with the specified value. */
764         ndis_add_sysctl(sc, keystr, "(dynamically set key)",
765                     val, CTLFLAG_RW);
766
767         RtlFreeAnsiString(&as);
768         *status = NDIS_STATUS_SUCCESS;
769 }
770
771 static void
772 NdisCloseConfiguration(cfg)
773         ndis_handle             cfg;
774 {
775         list_entry              *e;
776         ndis_parmlist_entry     *pe;
777         ndis_miniport_block     *block;
778         ndis_config_parm        *p;
779
780         block = (ndis_miniport_block *)cfg;
781
782         while (!IsListEmpty(&block->nmb_parmlist)) {
783                 e = RemoveHeadList(&block->nmb_parmlist);
784                 pe = CONTAINING_RECORD(e, ndis_parmlist_entry, np_list);
785                 p = &pe->np_parm;
786                 if (p->ncp_type == ndis_parm_string)
787                         RtlFreeUnicodeString(&p->ncp_parmdata.ncp_stringdata);
788                 ExFreePool(e);
789         }
790 }
791
792 /*
793  * Initialize a Windows spinlock.
794  */
795 static void
796 NdisAllocateSpinLock(lock)
797         ndis_spin_lock          *lock;
798 {
799         KeInitializeSpinLock(&lock->nsl_spinlock);
800         lock->nsl_kirql = 0;
801 }
802
803 /*
804  * Destroy a Windows spinlock. This is a no-op for now. There are two reasons
805  * for this. One is that it's sort of superfluous: we don't have to do anything
806  * special to deallocate the spinlock. The other is that there are some buggy
807  * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on
808  * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm
809  * talking to you.)
810  */
811 static void
812 NdisFreeSpinLock(lock)
813         ndis_spin_lock          *lock;
814 {
815 #ifdef notdef
816         KeInitializeSpinLock(&lock->nsl_spinlock);
817         lock->nsl_kirql = 0;
818 #endif
819 }
820
821 /*
822  * Acquire a spinlock from IRQL <= DISPATCH_LEVEL.
823  */
824
825 static void
826 NdisAcquireSpinLock(lock)
827         ndis_spin_lock          *lock;
828 {
829         KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
830 }
831
832 /*
833  * Release a spinlock from IRQL == DISPATCH_LEVEL.
834  */
835
836 static void
837 NdisReleaseSpinLock(lock)
838         ndis_spin_lock          *lock;
839 {
840         KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
841 }
842
843 /*
844  * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL.
845  */
846 static void
847 NdisDprAcquireSpinLock(lock)
848         ndis_spin_lock          *lock;
849 {
850         KeAcquireSpinLockAtDpcLevel(&lock->nsl_spinlock);
851 }
852
853 /*
854  * Release a spinlock without leaving IRQL == DISPATCH_LEVEL.
855  */
856 static void
857 NdisDprReleaseSpinLock(lock)
858         ndis_spin_lock          *lock;
859 {
860         KeReleaseSpinLockFromDpcLevel(&lock->nsl_spinlock);
861 }
862
863 static void
864 NdisInitializeReadWriteLock(lock)
865         ndis_rw_lock            *lock;
866 {
867         KeInitializeSpinLock(&lock->nrl_spinlock);
868         bzero((char *)&lock->nrl_rsvd, sizeof(lock->nrl_rsvd));
869 }
870
871 static void
872 NdisAcquireReadWriteLock(ndis_rw_lock *lock, uint8_t writeacc,
873     ndis_lock_state *state)
874 {
875         if (writeacc == TRUE) {
876                 KeAcquireSpinLock(&lock->nrl_spinlock, &state->nls_oldirql);
877                 lock->nrl_rsvd[0]++;
878         } else
879                 lock->nrl_rsvd[1]++;
880 }
881
882 static void
883 NdisReleaseReadWriteLock(lock, state)
884         ndis_rw_lock            *lock;
885         ndis_lock_state         *state;
886 {
887         if (lock->nrl_rsvd[0]) {
888                 lock->nrl_rsvd[0]--;
889                 KeReleaseSpinLock(&lock->nrl_spinlock, state->nls_oldirql);
890         } else
891                 lock->nrl_rsvd[1]--;
892 }
893
894 static uint32_t
895 NdisReadPciSlotInformation(adapter, slot, offset, buf, len)
896         ndis_handle             adapter;
897         uint32_t                slot;
898         uint32_t                offset;
899         void                    *buf;
900         uint32_t                len;
901 {
902         ndis_miniport_block     *block;
903         uint32_t                i;
904         char                    *dest;
905         device_t                dev;
906
907         block = (ndis_miniport_block *)adapter;
908         dest = buf;
909         if (block == NULL)
910                 return (0);
911
912         dev = block->nmb_physdeviceobj->do_devext;
913
914         /*
915          * I have a test system consisting of a Sun w2100z
916          * dual 2.4Ghz Opteron machine and an Atheros 802.11a/b/g
917          * "Aries" miniPCI NIC. (The NIC is installed in the
918          * machine using a miniPCI to PCI bus adapter card.)
919          * When running in SMP mode, I found that
920          * performing a large number of consecutive calls to
921          * NdisReadPciSlotInformation() would result in a
922          * sudden system reset (or in some cases a freeze).
923          * My suspicion is that the multiple reads are somehow
924          * triggering a fatal PCI bus error that leads to a
925          * machine check. The 1us delay in the loop below
926          * seems to prevent this problem.
927          */
928
929         for (i = 0; i < len; i++) {
930                 DELAY(1);
931                 dest[i] = pci_read_config(dev, i + offset, 1);
932         }
933
934         return (len);
935 }
936
937 static uint32_t
938 NdisWritePciSlotInformation(adapter, slot, offset, buf, len)
939         ndis_handle             adapter;
940         uint32_t                slot;
941         uint32_t                offset;
942         void                    *buf;
943         uint32_t                len;
944 {
945         ndis_miniport_block     *block;
946         uint32_t                i;
947         char                    *dest;
948         device_t                dev;
949
950         block = (ndis_miniport_block *)adapter;
951         dest = buf;
952
953         if (block == NULL)
954                 return (0);
955
956         dev = block->nmb_physdeviceobj->do_devext;
957         for (i = 0; i < len; i++) {
958                 DELAY(1);
959                 pci_write_config(dev, i + offset, dest[i], 1);
960         }
961
962         return (len);
963 }
964
965 /*
966  * The errorlog routine uses a variable argument list, so we
967  * have to declare it this way.
968  */
969
970 #define ERRMSGLEN 512
971 static void
972 NdisWriteErrorLogEntry(ndis_handle adapter, ndis_error_code code,
973         uint32_t numerrors, ...)
974 {
975         ndis_miniport_block     *block;
976         va_list                 ap;
977         int                     i, error;
978         char                    *str = NULL;
979         uint16_t                flags;
980         device_t                dev;
981         driver_object           *drv;
982         struct ndis_softc       *sc;
983         struct ifnet            *ifp;
984         unicode_string          us;
985         ansi_string             as = { 0, 0, NULL };
986
987         block = (ndis_miniport_block *)adapter;
988         dev = block->nmb_physdeviceobj->do_devext;
989         drv = block->nmb_deviceobj->do_drvobj;
990         sc = device_get_softc(dev);
991         ifp = NDISUSB_GET_IFNET(sc);
992
993         if (ifp != NULL && ifp->if_flags & IFF_DEBUG) {
994                 error = pe_get_message((vm_offset_t)drv->dro_driverstart,
995                     code, &str, &i, &flags);
996                 if (error == 0) {
997                         if (flags & MESSAGE_RESOURCE_UNICODE) {
998                                 RtlInitUnicodeString(&us, (uint16_t *)str);
999                                 if (RtlUnicodeStringToAnsiString(&as,
1000                                     &us, TRUE) == STATUS_SUCCESS)
1001                                         str = as.as_buf;
1002                                 else
1003                                         str = NULL;
1004                         }
1005                 }
1006         }
1007
1008         device_printf(dev, "NDIS ERROR: %x (%s)\n", code,
1009             str == NULL ? "unknown error" : str);
1010
1011         if (ifp != NULL && ifp->if_flags & IFF_DEBUG) {
1012                 device_printf(dev, "NDIS NUMERRORS: %x\n", numerrors);
1013                 va_start(ap, numerrors);
1014                 for (i = 0; i < numerrors; i++)
1015                         device_printf(dev, "argptr: %p\n",
1016                             va_arg(ap, void *));
1017                 va_end(ap);
1018         }
1019
1020         if (as.as_len)
1021                 RtlFreeAnsiString(&as);
1022 }
1023
1024 static void
1025 ndis_map_cb(arg, segs, nseg, error)
1026         void                    *arg;
1027         bus_dma_segment_t       *segs;
1028         int                     nseg;
1029         int                     error;
1030 {
1031         struct ndis_map_arg     *ctx;
1032         int                     i;
1033
1034         if (error)
1035                 return;
1036
1037         ctx = arg;
1038
1039         for (i = 0; i < nseg; i++) {
1040                 ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr;
1041                 ctx->nma_fraglist[i].npu_len = segs[i].ds_len;
1042         }
1043
1044         ctx->nma_cnt = nseg;
1045 }
1046
1047 static void
1048 NdisMStartBufferPhysicalMapping(ndis_handle adapter, ndis_buffer *buf,
1049     uint32_t mapreg, uint8_t writedev, ndis_paddr_unit *addrarray,
1050     uint32_t *arraysize)
1051 {
1052         ndis_miniport_block     *block;
1053         struct ndis_softc       *sc;
1054         struct ndis_map_arg     nma;
1055         bus_dmamap_t            map;
1056         int                     error;
1057
1058         if (adapter == NULL)
1059                 return;
1060
1061         block = (ndis_miniport_block *)adapter;
1062         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1063
1064         if (mapreg > sc->ndis_mmapcnt)
1065                 return;
1066
1067         map = sc->ndis_mmaps[mapreg];
1068         nma.nma_fraglist = addrarray;
1069
1070         error = bus_dmamap_load(sc->ndis_mtag, map,
1071             MmGetMdlVirtualAddress(buf), MmGetMdlByteCount(buf), ndis_map_cb,
1072             (void *)&nma, BUS_DMA_NOWAIT);
1073
1074         if (error)
1075                 return;
1076
1077         bus_dmamap_sync(sc->ndis_mtag, map,
1078             writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
1079
1080         *arraysize = nma.nma_cnt;
1081 }
1082
1083 static void
1084 NdisMCompleteBufferPhysicalMapping(adapter, buf, mapreg)
1085         ndis_handle             adapter;
1086         ndis_buffer             *buf;
1087         uint32_t                mapreg;
1088 {
1089         ndis_miniport_block     *block;
1090         struct ndis_softc       *sc;
1091         bus_dmamap_t            map;
1092
1093         if (adapter == NULL)
1094                 return;
1095
1096         block = (ndis_miniport_block *)adapter;
1097         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1098
1099         if (mapreg > sc->ndis_mmapcnt)
1100                 return;
1101
1102         map = sc->ndis_mmaps[mapreg];
1103
1104         bus_dmamap_sync(sc->ndis_mtag, map,
1105             BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1106
1107         bus_dmamap_unload(sc->ndis_mtag, map);
1108 }
1109
1110 /*
1111  * This is an older (?) timer init routine which doesn't
1112  * accept a miniport context handle. Serialized miniports should
1113  * never call this function.
1114  */
1115
1116 static void
1117 NdisInitializeTimer(timer, func, ctx)
1118         ndis_timer              *timer;
1119         ndis_timer_function     func;
1120         void                    *ctx;
1121 {
1122         KeInitializeTimer(&timer->nt_ktimer);
1123         KeInitializeDpc(&timer->nt_kdpc, func, ctx);
1124         KeSetImportanceDpc(&timer->nt_kdpc, KDPC_IMPORTANCE_LOW);
1125 }
1126
1127 static void
1128 ndis_timercall(dpc, timer, sysarg1, sysarg2)
1129         kdpc                    *dpc;
1130         ndis_miniport_timer     *timer;
1131         void                    *sysarg1;
1132         void                    *sysarg2;
1133 {
1134         /*
1135          * Since we're called as a DPC, we should be running
1136          * at DISPATCH_LEVEL here. This means to acquire the
1137          * spinlock, we can use KeAcquireSpinLockAtDpcLevel()
1138          * rather than KeAcquireSpinLock().
1139          */
1140         if (NDIS_SERIALIZED(timer->nmt_block))
1141                 KeAcquireSpinLockAtDpcLevel(&timer->nmt_block->nmb_lock);
1142
1143         MSCALL4(timer->nmt_timerfunc, dpc, timer->nmt_timerctx,
1144             sysarg1, sysarg2);
1145
1146         if (NDIS_SERIALIZED(timer->nmt_block))
1147                 KeReleaseSpinLockFromDpcLevel(&timer->nmt_block->nmb_lock);
1148 }
1149
1150 /*
1151  * For a long time I wondered why there were two NDIS timer initialization
1152  * routines, and why this one needed an NDIS_MINIPORT_TIMER and the
1153  * MiniportAdapterHandle. The NDIS_MINIPORT_TIMER has its own callout
1154  * function and context pointers separate from those in the DPC, which
1155  * allows for another level of indirection: when the timer fires, we
1156  * can have our own timer function invoked, and from there we can call
1157  * the driver's function. But why go to all that trouble? Then it hit
1158  * me: for serialized miniports, the timer callouts are not re-entrant.
1159  * By trapping the callouts and having access to the MiniportAdapterHandle,
1160  * we can protect the driver callouts by acquiring the NDIS serialization
1161  * lock. This is essential for allowing serialized miniports to work
1162  * correctly on SMP systems. On UP hosts, setting IRQL to DISPATCH_LEVEL
1163  * is enough to prevent other threads from pre-empting you, but with
1164  * SMP, you must acquire a lock as well, otherwise the other CPU is
1165  * free to clobber you.
1166  */
1167 static void
1168 NdisMInitializeTimer(timer, handle, func, ctx)
1169         ndis_miniport_timer     *timer;
1170         ndis_handle             handle;
1171         ndis_timer_function     func;
1172         void                    *ctx;
1173 {
1174         ndis_miniport_block     *block;
1175         struct ndis_softc       *sc;
1176
1177         block = (ndis_miniport_block *)handle;
1178         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1179
1180         /* Save the driver's funcptr and context */
1181
1182         timer->nmt_timerfunc = func;
1183         timer->nmt_timerctx = ctx;
1184         timer->nmt_block = handle;
1185
1186         /*
1187          * Set up the timer so it will call our intermediate DPC.
1188          * Be sure to use the wrapped entry point, since
1189          * ntoskrnl_run_dpc() expects to invoke a function with
1190          * Microsoft calling conventions.
1191          */
1192         KeInitializeTimer(&timer->nmt_ktimer);
1193         KeInitializeDpc(&timer->nmt_kdpc,
1194             ndis_findwrap((funcptr)ndis_timercall), timer);
1195         timer->nmt_ktimer.k_dpc = &timer->nmt_kdpc;
1196 }
1197
1198 /*
1199  * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(),
1200  * but the former is just a macro wrapper around the latter.
1201  */
1202 static void
1203 NdisSetTimer(timer, msecs)
1204         ndis_timer              *timer;
1205         uint32_t                msecs;
1206 {
1207         /*
1208          * KeSetTimer() wants the period in
1209          * hundred nanosecond intervals.
1210          */
1211         KeSetTimer(&timer->nt_ktimer,
1212             ((int64_t)msecs * -10000), &timer->nt_kdpc);
1213 }
1214
1215 static void
1216 NdisMSetPeriodicTimer(timer, msecs)
1217         ndis_miniport_timer     *timer;
1218         uint32_t                msecs;
1219 {
1220         KeSetTimerEx(&timer->nmt_ktimer,
1221             ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc);
1222 }
1223
1224 /*
1225  * Technically, this is really NdisCancelTimer(), but we also
1226  * (ab)use it for NdisMCancelTimer(), since in our implementation
1227  * we don't need the extra info in the ndis_miniport_timer
1228  * structure just to cancel a timer.
1229  */
1230
1231 static void
1232 NdisMCancelTimer(timer, cancelled)
1233         ndis_timer              *timer;
1234         uint8_t                 *cancelled;
1235 {
1236
1237         *cancelled = KeCancelTimer(&timer->nt_ktimer);
1238 }
1239
1240 static void
1241 NdisMQueryAdapterResources(status, adapter, list, buflen)
1242         ndis_status             *status;
1243         ndis_handle             adapter;
1244         ndis_resource_list      *list;
1245         uint32_t                *buflen;
1246 {
1247         ndis_miniport_block     *block;
1248         struct ndis_softc       *sc;
1249         int                     rsclen;
1250
1251         block = (ndis_miniport_block *)adapter;
1252         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1253
1254         rsclen = sizeof(ndis_resource_list) +
1255             (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1));
1256         if (*buflen < rsclen) {
1257                 *buflen = rsclen;
1258                 *status = NDIS_STATUS_INVALID_LENGTH;
1259                 return;
1260         }
1261
1262         bcopy((char *)block->nmb_rlist, (char *)list, rsclen);
1263         *status = NDIS_STATUS_SUCCESS;
1264 }
1265
1266 static ndis_status
1267 NdisMRegisterIoPortRange(offset, adapter, port, numports)
1268         void                    **offset;
1269         ndis_handle             adapter;
1270         uint32_t                port;
1271         uint32_t                numports;
1272 {
1273         struct ndis_miniport_block      *block;
1274         struct ndis_softc       *sc;
1275
1276         if (adapter == NULL)
1277                 return (NDIS_STATUS_FAILURE);
1278
1279         block = (ndis_miniport_block *)adapter;
1280         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1281
1282         if (sc->ndis_res_io == NULL)
1283                 return (NDIS_STATUS_FAILURE);
1284
1285         /* Don't let the device map more ports than we have. */
1286         if (rman_get_size(sc->ndis_res_io) < numports)
1287                 return (NDIS_STATUS_INVALID_LENGTH);
1288
1289         *offset = (void *)(uintptr_t)rman_get_start(sc->ndis_res_io);
1290
1291         return (NDIS_STATUS_SUCCESS);
1292 }
1293
1294 static void
1295 NdisMDeregisterIoPortRange(adapter, port, numports, offset)
1296         ndis_handle             adapter;
1297         uint32_t                port;
1298         uint32_t                numports;
1299         void                    *offset;
1300 {
1301 }
1302
1303 static void
1304 NdisReadNetworkAddress(status, addr, addrlen, adapter)
1305         ndis_status             *status;
1306         void                    **addr;
1307         uint32_t                *addrlen;
1308         ndis_handle             adapter;
1309 {
1310         struct ndis_softc       *sc;
1311         struct ifnet            *ifp;
1312         ndis_miniport_block     *block;
1313         uint8_t                 empty[] = { 0, 0, 0, 0, 0, 0 };
1314
1315         block = (ndis_miniport_block *)adapter;
1316         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1317         ifp = NDISUSB_GET_IFNET(sc);
1318         if (ifp == NULL) {
1319                 *status = NDIS_STATUS_FAILURE;
1320                 return;
1321         }
1322
1323         if (ifp->if_addr == NULL ||
1324             bcmp(IF_LLADDR(sc->ifp), empty, ETHER_ADDR_LEN) == 0)
1325                 *status = NDIS_STATUS_FAILURE;
1326         else {
1327                 *addr = IF_LLADDR(sc->ifp);
1328                 *addrlen = ETHER_ADDR_LEN;
1329                 *status = NDIS_STATUS_SUCCESS;
1330         }
1331 }
1332
1333 static ndis_status
1334 NdisQueryMapRegisterCount(bustype, cnt)
1335         uint32_t                bustype;
1336         uint32_t                *cnt;
1337 {
1338         *cnt = 8192;
1339         return (NDIS_STATUS_SUCCESS);
1340 }
1341
1342 static ndis_status
1343 NdisMAllocateMapRegisters(ndis_handle adapter, uint32_t dmachannel,
1344     uint8_t dmasize, uint32_t physmapneeded, uint32_t maxmap)
1345 {
1346         struct ndis_softc       *sc;
1347         ndis_miniport_block     *block;
1348         int                     error, i, nseg = NDIS_MAXSEG;
1349
1350         block = (ndis_miniport_block *)adapter;
1351         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1352
1353         sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded,
1354             M_DEVBUF, M_NOWAIT|M_ZERO);
1355
1356         if (sc->ndis_mmaps == NULL)
1357                 return (NDIS_STATUS_RESOURCES);
1358
1359         error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1360             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1361             NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW,
1362             NULL, NULL, &sc->ndis_mtag);
1363
1364         if (error) {
1365                 free(sc->ndis_mmaps, M_DEVBUF);
1366                 return (NDIS_STATUS_RESOURCES);
1367         }
1368
1369         for (i = 0; i < physmapneeded; i++)
1370                 bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]);
1371
1372         sc->ndis_mmapcnt = physmapneeded;
1373
1374         return (NDIS_STATUS_SUCCESS);
1375 }
1376
1377 static void
1378 NdisMFreeMapRegisters(adapter)
1379         ndis_handle             adapter;
1380 {
1381         struct ndis_softc       *sc;
1382         ndis_miniport_block     *block;
1383         int                     i;
1384
1385         block = (ndis_miniport_block *)adapter;
1386         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1387
1388         for (i = 0; i < sc->ndis_mmapcnt; i++)
1389                 bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]);
1390
1391         free(sc->ndis_mmaps, M_DEVBUF);
1392
1393         bus_dma_tag_destroy(sc->ndis_mtag);
1394 }
1395
1396 static void
1397 ndis_mapshared_cb(arg, segs, nseg, error)
1398         void                    *arg;
1399         bus_dma_segment_t       *segs;
1400         int                     nseg;
1401         int                     error;
1402 {
1403         ndis_physaddr           *p;
1404
1405         if (error || nseg > 1)
1406                 return;
1407
1408         p = arg;
1409
1410         p->np_quad = segs[0].ds_addr;
1411 }
1412
1413 /*
1414  * This maps to bus_dmamem_alloc().
1415  */
1416
1417 static void
1418 NdisMAllocateSharedMemory(ndis_handle adapter, uint32_t len, uint8_t cached,
1419     void **vaddr, ndis_physaddr *paddr)
1420 {
1421         ndis_miniport_block     *block;
1422         struct ndis_softc       *sc;
1423         struct ndis_shmem       *sh;
1424         int                     error;
1425
1426         if (adapter == NULL)
1427                 return;
1428
1429         block = (ndis_miniport_block *)adapter;
1430         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1431
1432         sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO);
1433         if (sh == NULL)
1434                 return;
1435
1436         InitializeListHead(&sh->ndis_list);
1437
1438         /*
1439          * When performing shared memory allocations, create a tag
1440          * with a lowaddr limit that restricts physical memory mappings
1441          * so that they all fall within the first 1GB of memory.
1442          * At least one device/driver combination (Linksys Instant
1443          * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
1444          * problems with performing DMA operations with physical
1445          * addresses that lie above the 1GB mark. I don't know if this
1446          * is a hardware limitation or if the addresses are being
1447          * truncated within the driver, but this seems to be the only
1448          * way to make these cards work reliably in systems with more
1449          * than 1GB of physical memory.
1450          */
1451
1452         error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
1453             0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL,
1454             NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL,
1455             &sh->ndis_stag);
1456
1457         if (error) {
1458                 free(sh, M_DEVBUF);
1459                 return;
1460         }
1461
1462         error = bus_dmamem_alloc(sh->ndis_stag, vaddr,
1463             BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap);
1464
1465         if (error) {
1466                 bus_dma_tag_destroy(sh->ndis_stag);
1467                 free(sh, M_DEVBUF);
1468                 return;
1469         }
1470
1471         error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr,
1472             len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT);
1473
1474         if (error) {
1475                 bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap);
1476                 bus_dma_tag_destroy(sh->ndis_stag);
1477                 free(sh, M_DEVBUF);
1478                 return;
1479         }
1480
1481         /*
1482          * Save the physical address along with the source address.
1483          * The AirGo MIMO driver will call NdisMFreeSharedMemory()
1484          * with a bogus virtual address sometimes, but with a valid
1485          * physical address. To keep this from causing trouble, we
1486          * use the physical address to as a sanity check in case
1487          * searching based on the virtual address fails.
1488          */
1489
1490         NDIS_LOCK(sc);
1491         sh->ndis_paddr.np_quad = paddr->np_quad;
1492         sh->ndis_saddr = *vaddr;
1493         InsertHeadList((&sc->ndis_shlist), (&sh->ndis_list));
1494         NDIS_UNLOCK(sc);
1495 }
1496
1497 struct ndis_allocwork {
1498         uint32_t                na_len;
1499         uint8_t                 na_cached;
1500         void                    *na_ctx;
1501         io_workitem             *na_iw;
1502 };
1503
1504 static void
1505 ndis_asyncmem_complete(dobj, arg)
1506         device_object           *dobj;
1507         void                    *arg;
1508 {
1509         ndis_miniport_block     *block;
1510         struct ndis_softc       *sc;
1511         struct ndis_allocwork   *w;
1512         void                    *vaddr;
1513         ndis_physaddr           paddr;
1514         ndis_allocdone_handler  donefunc;
1515
1516         w = arg;
1517         block = (ndis_miniport_block *)dobj->do_devext;
1518         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1519
1520         vaddr = NULL;
1521         paddr.np_quad = 0;
1522
1523         donefunc = sc->ndis_chars->nmc_allocate_complete_func;
1524         NdisMAllocateSharedMemory(block, w->na_len,
1525             w->na_cached, &vaddr, &paddr);
1526         MSCALL5(donefunc, block, vaddr, &paddr, w->na_len, w->na_ctx);
1527
1528         IoFreeWorkItem(w->na_iw);
1529         free(w, M_DEVBUF);
1530 }
1531
1532 static ndis_status
1533 NdisMAllocateSharedMemoryAsync(ndis_handle adapter, uint32_t len,
1534     uint8_t cached, void *ctx)
1535 {
1536         ndis_miniport_block     *block;
1537         struct ndis_allocwork   *w;
1538         io_workitem             *iw;
1539         io_workitem_func        ifw;
1540
1541         if (adapter == NULL)
1542                 return (NDIS_STATUS_FAILURE);
1543
1544         block = adapter;
1545
1546         iw = IoAllocateWorkItem(block->nmb_deviceobj);
1547         if (iw == NULL)
1548                 return (NDIS_STATUS_FAILURE);
1549
1550         w = malloc(sizeof(struct ndis_allocwork), M_TEMP, M_NOWAIT);
1551
1552         if (w == NULL)
1553                 return (NDIS_STATUS_FAILURE);
1554
1555         w->na_cached = cached;
1556         w->na_len = len;
1557         w->na_ctx = ctx;
1558         w->na_iw = iw;
1559
1560         ifw = (io_workitem_func)ndis_findwrap((funcptr)ndis_asyncmem_complete);
1561         IoQueueWorkItem(iw, ifw, WORKQUEUE_DELAYED, w);
1562
1563         return (NDIS_STATUS_PENDING);
1564 }
1565
1566 static void
1567 NdisMFreeSharedMemory(ndis_handle adapter, uint32_t len, uint8_t cached,
1568     void *vaddr, ndis_physaddr paddr)
1569 {
1570         ndis_miniport_block     *block;
1571         struct ndis_softc       *sc;
1572         struct ndis_shmem       *sh = NULL;
1573         list_entry              *l;
1574
1575         if (vaddr == NULL || adapter == NULL)
1576                 return;
1577
1578         block = (ndis_miniport_block *)adapter;
1579         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1580
1581         /* Sanity check: is list empty? */
1582
1583         if (IsListEmpty(&sc->ndis_shlist))
1584                 return;
1585
1586         NDIS_LOCK(sc);
1587         l = sc->ndis_shlist.nle_flink;
1588         while (l != &sc->ndis_shlist) {
1589                 sh = CONTAINING_RECORD(l, struct ndis_shmem, ndis_list);
1590                 if (sh->ndis_saddr == vaddr)
1591                         break;
1592                 /*
1593                  * Check the physaddr too, just in case the driver lied
1594                  * about the virtual address.
1595                  */
1596                 if (sh->ndis_paddr.np_quad == paddr.np_quad)
1597                         break;
1598                 l = l->nle_flink;
1599         }
1600
1601         if (sh == NULL) {
1602                 NDIS_UNLOCK(sc);
1603                 printf("NDIS: buggy driver tried to free "
1604                     "invalid shared memory: vaddr: %p paddr: 0x%jx\n",
1605                     vaddr, (uintmax_t)paddr.np_quad);
1606                 return;
1607         }
1608
1609         RemoveEntryList(&sh->ndis_list);
1610
1611         NDIS_UNLOCK(sc);
1612
1613         bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1614         bus_dmamem_free(sh->ndis_stag, sh->ndis_saddr, sh->ndis_smap);
1615         bus_dma_tag_destroy(sh->ndis_stag);
1616
1617         free(sh, M_DEVBUF);
1618 }
1619
1620 static ndis_status
1621 NdisMMapIoSpace(vaddr, adapter, paddr, len)
1622         void                    **vaddr;
1623         ndis_handle             adapter;
1624         ndis_physaddr           paddr;
1625         uint32_t                len;
1626 {
1627         if (adapter == NULL)
1628                 return (NDIS_STATUS_FAILURE);
1629
1630         *vaddr = MmMapIoSpace(paddr.np_quad, len, 0);
1631
1632         if (*vaddr == NULL)
1633                 return (NDIS_STATUS_FAILURE);
1634
1635         return (NDIS_STATUS_SUCCESS);
1636 }
1637
1638 static void
1639 NdisMUnmapIoSpace(adapter, vaddr, len)
1640         ndis_handle             adapter;
1641         void                    *vaddr;
1642         uint32_t                len;
1643 {
1644         MmUnmapIoSpace(vaddr, len);
1645 }
1646
1647 static uint32_t
1648 NdisGetCacheFillSize(void)
1649 {
1650         return (128);
1651 }
1652
1653 static void *
1654 NdisGetRoutineAddress(ustr)
1655         unicode_string          *ustr;
1656 {
1657         ansi_string             astr;
1658
1659         if (RtlUnicodeStringToAnsiString(&astr, ustr, TRUE))
1660                 return (NULL);
1661         return (ndis_get_routine_address(ndis_functbl, astr.as_buf));
1662 }
1663
1664 static uint32_t
1665 NdisMGetDmaAlignment(handle)
1666         ndis_handle             handle;
1667 {
1668         return (16);
1669 }
1670
1671 /*
1672  * NDIS has two methods for dealing with NICs that support DMA.
1673  * One is to just pass packets to the driver and let it call
1674  * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
1675  * all by itself, and the other is to let the NDIS library handle the
1676  * buffer mapping internally, and hand the driver an already populated
1677  * scatter/gather fragment list. If the driver calls
1678  * NdisMInitializeScatterGatherDma(), it wants to use the latter
1679  * method.
1680  */
1681
1682 static ndis_status
1683 NdisMInitializeScatterGatherDma(ndis_handle adapter, uint8_t is64,
1684     uint32_t maxphysmap)
1685 {
1686         struct ndis_softc       *sc;
1687         ndis_miniport_block     *block;
1688         int                     error;
1689
1690         if (adapter == NULL)
1691                 return (NDIS_STATUS_FAILURE);
1692         block = (ndis_miniport_block *)adapter;
1693         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
1694
1695         /* Don't do this twice. */
1696         if (sc->ndis_sc == 1)
1697                 return (NDIS_STATUS_SUCCESS);
1698
1699         error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1700             BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1701             MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
1702             NULL, NULL, &sc->ndis_ttag);
1703
1704         sc->ndis_sc = 1;
1705
1706         return (NDIS_STATUS_SUCCESS);
1707 }
1708
1709 void
1710 NdisAllocatePacketPool(status, pool, descnum, protrsvdlen)
1711         ndis_status             *status;
1712         ndis_handle             *pool;
1713         uint32_t                descnum;
1714         uint32_t                protrsvdlen;
1715 {
1716         ndis_packet_pool        *p;
1717         ndis_packet             *packets;
1718         int                     i;
1719
1720         p = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_packet_pool), 0);
1721         if (p == NULL) {
1722                 *status = NDIS_STATUS_RESOURCES;
1723                 return;
1724         }
1725
1726         p->np_cnt = descnum + NDIS_POOL_EXTRA;
1727         p->np_protrsvd = protrsvdlen;
1728         p->np_len = sizeof(ndis_packet) + protrsvdlen;
1729
1730         packets = ExAllocatePoolWithTag(NonPagedPool, p->np_cnt *
1731             p->np_len, 0);
1732
1733         if (packets == NULL) {
1734                 ExFreePool(p);
1735                 *status = NDIS_STATUS_RESOURCES;
1736                 return;
1737         }
1738
1739         p->np_pktmem = packets;
1740
1741         for (i = 0; i < p->np_cnt; i++)
1742                 InterlockedPushEntrySList(&p->np_head,
1743                     (struct slist_entry *)&packets[i]);
1744
1745 #ifdef NDIS_DEBUG_PACKETS 
1746         p->np_dead = 0; 
1747         KeInitializeSpinLock(&p->np_lock);
1748         KeInitializeEvent(&p->np_event, EVENT_TYPE_NOTIFY, TRUE);
1749 #endif
1750
1751         *pool = p; 
1752         *status = NDIS_STATUS_SUCCESS;
1753 }
1754
1755 void
1756 NdisAllocatePacketPoolEx(status, pool, descnum, oflowdescnum, protrsvdlen)
1757         ndis_status             *status;
1758         ndis_handle             *pool;
1759         uint32_t                descnum;
1760         uint32_t                oflowdescnum;
1761         uint32_t                protrsvdlen;
1762 {
1763         return (NdisAllocatePacketPool(status, pool,
1764             descnum + oflowdescnum, protrsvdlen));
1765 }
1766
1767 uint32_t
1768 NdisPacketPoolUsage(pool)
1769         ndis_handle             pool;
1770 {
1771         ndis_packet_pool        *p;
1772
1773         p = (ndis_packet_pool *)pool;
1774         return (p->np_cnt - ExQueryDepthSList(&p->np_head));
1775 }
1776
1777 void
1778 NdisFreePacketPool(pool)
1779         ndis_handle             pool;
1780 {
1781         ndis_packet_pool        *p;
1782         int                     usage;
1783 #ifdef NDIS_DEBUG_PACKETS
1784         uint8_t                 irql;
1785 #endif
1786
1787         p = (ndis_packet_pool *)pool;
1788
1789 #ifdef NDIS_DEBUG_PACKETS
1790         KeAcquireSpinLock(&p->np_lock, &irql);
1791 #endif
1792
1793         usage = NdisPacketPoolUsage(pool);
1794
1795 #ifdef NDIS_DEBUG_PACKETS
1796         if (usage) {
1797                 p->np_dead = 1;
1798                 KeResetEvent(&p->np_event);
1799                 KeReleaseSpinLock(&p->np_lock, irql);
1800                 KeWaitForSingleObject(&p->np_event, 0, 0, FALSE, NULL);
1801         } else
1802                 KeReleaseSpinLock(&p->np_lock, irql);
1803 #endif
1804
1805         ExFreePool(p->np_pktmem);
1806         ExFreePool(p);
1807 }
1808
1809 void
1810 NdisAllocatePacket(status, packet, pool)
1811         ndis_status             *status;
1812         ndis_packet             **packet;
1813         ndis_handle             pool;
1814 {
1815         ndis_packet_pool        *p;
1816         ndis_packet             *pkt;
1817 #ifdef NDIS_DEBUG_PACKETS
1818         uint8_t                 irql;
1819 #endif
1820
1821         p = (ndis_packet_pool *)pool;
1822
1823 #ifdef NDIS_DEBUG_PACKETS
1824         KeAcquireSpinLock(&p->np_lock, &irql);
1825         if (p->np_dead) {
1826                 KeReleaseSpinLock(&p->np_lock, irql);
1827                 printf("NDIS: tried to allocate packet from dead pool %p\n",
1828                     pool);
1829                 *status = NDIS_STATUS_RESOURCES;
1830                 return;
1831         }
1832 #endif
1833
1834         pkt = (ndis_packet *)InterlockedPopEntrySList(&p->np_head);
1835
1836 #ifdef NDIS_DEBUG_PACKETS
1837         KeReleaseSpinLock(&p->np_lock, irql);
1838 #endif
1839
1840         if (pkt == NULL) {
1841                 *status = NDIS_STATUS_RESOURCES;
1842                 return;
1843         }
1844
1845         bzero((char *)pkt, sizeof(ndis_packet));
1846
1847         /* Save pointer to the pool. */
1848         pkt->np_private.npp_pool = pool;
1849
1850         /* Set the oob offset pointer. Lots of things expect this. */
1851         pkt->np_private.npp_packetooboffset = offsetof(ndis_packet, np_oob);
1852
1853         /*
1854          * We must initialize the packet flags correctly in order
1855          * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
1856          * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() macros to work
1857          * correctly.
1858          */
1859         pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
1860         pkt->np_private.npp_validcounts = FALSE;
1861
1862         *packet = pkt;
1863
1864         *status = NDIS_STATUS_SUCCESS;
1865 }
1866
1867 void
1868 NdisFreePacket(packet)
1869         ndis_packet             *packet;
1870 {
1871         ndis_packet_pool        *p;
1872 #ifdef NDIS_DEBUG_PACKETS
1873         uint8_t                 irql;
1874 #endif
1875
1876         p = (ndis_packet_pool *)packet->np_private.npp_pool;
1877
1878 #ifdef NDIS_DEBUG_PACKETS
1879         KeAcquireSpinLock(&p->np_lock, &irql);
1880 #endif
1881
1882         InterlockedPushEntrySList(&p->np_head, (slist_entry *)packet);
1883
1884 #ifdef NDIS_DEBUG_PACKETS
1885         if (p->np_dead) {
1886                 if (ExQueryDepthSList(&p->np_head) == p->np_cnt)
1887                         KeSetEvent(&p->np_event, IO_NO_INCREMENT, FALSE);
1888         }
1889         KeReleaseSpinLock(&p->np_lock, irql);
1890 #endif
1891 }
1892
1893 static void
1894 NdisUnchainBufferAtFront(packet, buf)
1895         ndis_packet             *packet;
1896         ndis_buffer             **buf;
1897 {
1898         ndis_packet_private     *priv;
1899
1900         if (packet == NULL || buf == NULL)
1901                 return;
1902
1903         priv = &packet->np_private;
1904
1905         priv->npp_validcounts = FALSE;
1906
1907         if (priv->npp_head == priv->npp_tail) {
1908                 *buf = priv->npp_head;
1909                 priv->npp_head = priv->npp_tail = NULL;
1910         } else {
1911                 *buf = priv->npp_head;
1912                 priv->npp_head = (*buf)->mdl_next;
1913         }
1914 }
1915
1916 static void
1917 NdisUnchainBufferAtBack(packet, buf)
1918         ndis_packet             *packet;
1919         ndis_buffer             **buf;
1920 {
1921         ndis_packet_private     *priv;
1922         ndis_buffer             *tmp;
1923
1924         if (packet == NULL || buf == NULL)
1925                 return;
1926
1927         priv = &packet->np_private;
1928
1929         priv->npp_validcounts = FALSE;
1930
1931         if (priv->npp_head == priv->npp_tail) {
1932                 *buf = priv->npp_head;
1933                 priv->npp_head = priv->npp_tail = NULL;
1934         } else {
1935                 *buf = priv->npp_tail;
1936                 tmp = priv->npp_head;
1937                 while (tmp->mdl_next != priv->npp_tail)
1938                         tmp = tmp->mdl_next;
1939                 priv->npp_tail = tmp;
1940                 tmp->mdl_next = NULL;
1941         }
1942 }
1943
1944 /*
1945  * The NDIS "buffer" is really an MDL (memory descriptor list)
1946  * which is used to describe a buffer in a way that allows it
1947  * to mapped into different contexts. We have to be careful how
1948  * we handle them: in some versions of Windows, the NdisFreeBuffer()
1949  * routine is an actual function in the NDIS API, but in others
1950  * it's just a macro wrapper around IoFreeMdl(). There's really
1951  * no way to use the 'descnum' parameter to count how many
1952  * "buffers" are allocated since in order to use IoFreeMdl() to
1953  * dispose of a buffer, we have to use IoAllocateMdl() to allocate
1954  * them, and IoAllocateMdl() just grabs them out of the heap.
1955  */
1956
1957 static void
1958 NdisAllocateBufferPool(status, pool, descnum)
1959         ndis_status             *status;
1960         ndis_handle             *pool;
1961         uint32_t                descnum;
1962 {
1963
1964         /*
1965          * The only thing we can really do here is verify that descnum
1966          * is a reasonable value, but I really don't know what to check
1967          * it against.
1968          */
1969
1970         *pool = NonPagedPool;
1971         *status = NDIS_STATUS_SUCCESS;
1972 }
1973
1974 static void
1975 NdisFreeBufferPool(pool)
1976         ndis_handle             pool;
1977 {
1978 }
1979
1980 static void
1981 NdisAllocateBuffer(status, buffer, pool, vaddr, len)
1982         ndis_status             *status;
1983         ndis_buffer             **buffer;
1984         ndis_handle             pool;
1985         void                    *vaddr;
1986         uint32_t                len;
1987 {
1988         ndis_buffer             *buf;
1989
1990         buf = IoAllocateMdl(vaddr, len, FALSE, FALSE, NULL);
1991         if (buf == NULL) {
1992                 *status = NDIS_STATUS_RESOURCES;
1993                 return;
1994         }
1995
1996         MmBuildMdlForNonPagedPool(buf);
1997
1998         *buffer = buf;
1999         *status = NDIS_STATUS_SUCCESS;
2000 }
2001
2002 static void
2003 NdisFreeBuffer(buf)
2004         ndis_buffer             *buf;
2005 {
2006         IoFreeMdl(buf);
2007 }
2008
2009 /* Aw c'mon. */
2010
2011 static uint32_t
2012 NdisBufferLength(buf)
2013         ndis_buffer             *buf;
2014 {
2015         return (MmGetMdlByteCount(buf));
2016 }
2017
2018 /*
2019  * Get the virtual address and length of a buffer.
2020  * Note: the vaddr argument is optional.
2021  */
2022
2023 static void
2024 NdisQueryBuffer(buf, vaddr, len)
2025         ndis_buffer             *buf;
2026         void                    **vaddr;
2027         uint32_t                *len;
2028 {
2029         if (vaddr != NULL)
2030                 *vaddr = MmGetMdlVirtualAddress(buf);
2031         *len = MmGetMdlByteCount(buf);
2032 }
2033
2034 /* Same as above -- we don't care about the priority. */
2035
2036 static void
2037 NdisQueryBufferSafe(buf, vaddr, len, prio)
2038         ndis_buffer             *buf;
2039         void                    **vaddr;
2040         uint32_t                *len;
2041         uint32_t                prio;
2042 {
2043         if (vaddr != NULL)
2044                 *vaddr = MmGetMdlVirtualAddress(buf);
2045         *len = MmGetMdlByteCount(buf);
2046 }
2047
2048 /* Damnit Microsoft!! How many ways can you do the same thing?! */
2049
2050 static void *
2051 NdisBufferVirtualAddress(buf)
2052         ndis_buffer             *buf;
2053 {
2054         return (MmGetMdlVirtualAddress(buf));
2055 }
2056
2057 static void *
2058 NdisBufferVirtualAddressSafe(buf, prio)
2059         ndis_buffer             *buf;
2060         uint32_t                prio;
2061 {
2062         return (MmGetMdlVirtualAddress(buf));
2063 }
2064
2065 static void
2066 NdisAdjustBufferLength(buf, len)
2067         ndis_buffer             *buf;
2068         int                     len;
2069 {
2070         MmGetMdlByteCount(buf) = len;
2071 }
2072
2073 static uint32_t
2074 NdisInterlockedIncrement(addend)
2075         uint32_t                *addend;
2076 {
2077         atomic_add_long((u_long *)addend, 1);
2078         return (*addend);
2079 }
2080
2081 static uint32_t
2082 NdisInterlockedDecrement(addend)
2083         uint32_t                *addend;
2084 {
2085         atomic_subtract_long((u_long *)addend, 1);
2086         return (*addend);
2087 }
2088
2089 static uint32_t
2090 NdisGetVersion(void)
2091 {
2092         return (0x00050001);
2093 }
2094
2095 static void
2096 NdisInitializeEvent(event)
2097         ndis_event              *event;
2098 {
2099         /*
2100          * NDIS events are always notification
2101          * events, and should be initialized to the
2102          * not signaled state.
2103          */
2104         KeInitializeEvent(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE);
2105 }
2106
2107 static void
2108 NdisSetEvent(event)
2109         ndis_event              *event;
2110 {
2111         KeSetEvent(&event->ne_event, IO_NO_INCREMENT, FALSE);
2112 }
2113
2114 static void
2115 NdisResetEvent(event)
2116         ndis_event              *event;
2117 {
2118         KeResetEvent(&event->ne_event);
2119 }
2120
2121 static uint8_t
2122 NdisWaitEvent(event, msecs)
2123         ndis_event              *event;
2124         uint32_t                msecs;
2125 {
2126         int64_t                 duetime;
2127         uint32_t                rval;
2128
2129         duetime = ((int64_t)msecs * -10000);
2130         rval = KeWaitForSingleObject(event,
2131             0, 0, TRUE, msecs ? & duetime : NULL);
2132
2133         if (rval == STATUS_TIMEOUT)
2134                 return (FALSE);
2135
2136         return (TRUE);
2137 }
2138
2139 static ndis_status
2140 NdisUnicodeStringToAnsiString(dstr, sstr)
2141         ansi_string             *dstr;
2142         unicode_string          *sstr;
2143 {
2144         uint32_t                rval;
2145
2146         rval = RtlUnicodeStringToAnsiString(dstr, sstr, FALSE);
2147
2148         if (rval == STATUS_INSUFFICIENT_RESOURCES)
2149                 return (NDIS_STATUS_RESOURCES);
2150         if (rval)
2151                 return (NDIS_STATUS_FAILURE);
2152
2153         return (NDIS_STATUS_SUCCESS);
2154 }
2155
2156 static ndis_status
2157 NdisAnsiStringToUnicodeString(dstr, sstr)
2158         unicode_string          *dstr;
2159         ansi_string             *sstr;
2160 {
2161         uint32_t                rval;
2162
2163         rval = RtlAnsiStringToUnicodeString(dstr, sstr, FALSE);
2164
2165         if (rval == STATUS_INSUFFICIENT_RESOURCES)
2166                 return (NDIS_STATUS_RESOURCES);
2167         if (rval)
2168                 return (NDIS_STATUS_FAILURE);
2169
2170         return (NDIS_STATUS_SUCCESS);
2171 }
2172
2173 static ndis_status
2174 NdisMPciAssignResources(adapter, slot, list)
2175         ndis_handle             adapter;
2176         uint32_t                slot;
2177         ndis_resource_list      **list;
2178 {
2179         ndis_miniport_block     *block;
2180
2181         if (adapter == NULL || list == NULL)
2182                 return (NDIS_STATUS_FAILURE);
2183
2184         block = (ndis_miniport_block *)adapter;
2185         *list = block->nmb_rlist;
2186
2187         return (NDIS_STATUS_SUCCESS);
2188 }
2189
2190 static uint8_t
2191 ndis_intr(iobj, arg)
2192         kinterrupt              *iobj;
2193         void                    *arg;
2194 {
2195         struct ndis_softc       *sc;
2196         uint8_t                 is_our_intr = FALSE;
2197         int                     call_isr = 0;
2198         ndis_miniport_interrupt *intr;
2199
2200         sc = arg;
2201         intr = sc->ndis_block->nmb_interrupt;
2202
2203         if (intr == NULL || sc->ndis_block->nmb_miniportadapterctx == NULL)
2204                 return (FALSE);
2205
2206         if (sc->ndis_block->nmb_interrupt->ni_isrreq == TRUE)
2207                 MSCALL3(intr->ni_isrfunc, &is_our_intr, &call_isr,
2208                     sc->ndis_block->nmb_miniportadapterctx);
2209         else {
2210                 MSCALL1(sc->ndis_chars->nmc_disable_interrupts_func,
2211                     sc->ndis_block->nmb_miniportadapterctx);
2212                 call_isr = 1;
2213         }
2214
2215         if (call_isr)
2216                 IoRequestDpc(sc->ndis_block->nmb_deviceobj, NULL, sc);
2217
2218         return (is_our_intr);
2219 }
2220
2221 static void
2222 ndis_intrhand(dpc, intr, sysarg1, sysarg2)
2223         kdpc                    *dpc;
2224         ndis_miniport_interrupt *intr;
2225         void                    *sysarg1;
2226         void                    *sysarg2;
2227 {
2228         struct ndis_softc       *sc;
2229         ndis_miniport_block     *block;
2230         ndis_handle             adapter;
2231
2232         block = intr->ni_block;
2233         adapter = block->nmb_miniportadapterctx;
2234         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2235
2236         if (NDIS_SERIALIZED(sc->ndis_block))
2237                 KeAcquireSpinLockAtDpcLevel(&block->nmb_lock);
2238
2239         MSCALL1(intr->ni_dpcfunc, adapter);
2240
2241         /* If there's a MiniportEnableInterrupt() routine, call it. */
2242
2243         if (sc->ndis_chars->nmc_enable_interrupts_func != NULL)
2244                 MSCALL1(sc->ndis_chars->nmc_enable_interrupts_func, adapter);
2245
2246         if (NDIS_SERIALIZED(sc->ndis_block))
2247                 KeReleaseSpinLockFromDpcLevel(&block->nmb_lock);
2248
2249         /*
2250          * Set the completion event if we've drained all
2251          * pending interrupts.
2252          */
2253
2254         KeAcquireSpinLockAtDpcLevel(&intr->ni_dpccountlock);
2255         intr->ni_dpccnt--;
2256         if (intr->ni_dpccnt == 0)
2257                 KeSetEvent(&intr->ni_dpcevt, IO_NO_INCREMENT, FALSE);
2258         KeReleaseSpinLockFromDpcLevel(&intr->ni_dpccountlock);
2259 }
2260
2261 static ndis_status
2262 NdisMRegisterInterrupt(ndis_miniport_interrupt *intr, ndis_handle adapter,
2263     uint32_t ivec, uint32_t ilevel, uint8_t reqisr, uint8_t shared,
2264     ndis_interrupt_mode imode)
2265 {
2266         ndis_miniport_block     *block;
2267         ndis_miniport_characteristics *ch;
2268         struct ndis_softc       *sc;
2269         int                     error;
2270
2271         block = adapter;
2272         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2273         ch = IoGetDriverObjectExtension(block->nmb_deviceobj->do_drvobj,
2274             (void *)1);
2275
2276         intr->ni_rsvd = ExAllocatePoolWithTag(NonPagedPool,
2277             sizeof(struct mtx), 0);
2278         if (intr->ni_rsvd == NULL)
2279                 return (NDIS_STATUS_RESOURCES);
2280
2281         intr->ni_block = adapter;
2282         intr->ni_isrreq = reqisr;
2283         intr->ni_shared = shared;
2284         intr->ni_dpccnt = 0;
2285         intr->ni_isrfunc = ch->nmc_isr_func;
2286         intr->ni_dpcfunc = ch->nmc_interrupt_func;
2287
2288         KeInitializeEvent(&intr->ni_dpcevt, EVENT_TYPE_NOTIFY, TRUE);
2289         KeInitializeDpc(&intr->ni_dpc,
2290             ndis_findwrap((funcptr)ndis_intrhand), intr);
2291         KeSetImportanceDpc(&intr->ni_dpc, KDPC_IMPORTANCE_LOW);
2292
2293         error = IoConnectInterrupt(&intr->ni_introbj,
2294             ndis_findwrap((funcptr)ndis_intr), sc, NULL,
2295             ivec, ilevel, 0, imode, shared, 0, FALSE);
2296
2297         if (error != STATUS_SUCCESS)
2298                 return (NDIS_STATUS_FAILURE);
2299
2300         block->nmb_interrupt = intr;
2301
2302         return (NDIS_STATUS_SUCCESS);
2303 }
2304
2305 static void
2306 NdisMDeregisterInterrupt(intr)
2307         ndis_miniport_interrupt *intr;
2308 {
2309         ndis_miniport_block     *block;
2310         uint8_t                 irql;
2311
2312         block = intr->ni_block;
2313
2314         /* Should really be KeSynchronizeExecution() */
2315
2316         KeAcquireSpinLock(intr->ni_introbj->ki_lock, &irql);
2317         block->nmb_interrupt = NULL;
2318         KeReleaseSpinLock(intr->ni_introbj->ki_lock, irql);
2319 /*
2320         KeFlushQueuedDpcs();
2321 */
2322         /* Disconnect our ISR */
2323
2324         IoDisconnectInterrupt(intr->ni_introbj);
2325
2326         KeWaitForSingleObject(&intr->ni_dpcevt, 0, 0, FALSE, NULL);
2327         KeResetEvent(&intr->ni_dpcevt);
2328 }
2329
2330 static void
2331 NdisMRegisterAdapterShutdownHandler(adapter, shutdownctx, shutdownfunc)
2332         ndis_handle             adapter;
2333         void                    *shutdownctx;
2334         ndis_shutdown_handler   shutdownfunc;
2335 {
2336         ndis_miniport_block     *block;
2337         ndis_miniport_characteristics *chars;
2338         struct ndis_softc       *sc;
2339
2340         if (adapter == NULL)
2341                 return;
2342
2343         block = (ndis_miniport_block *)adapter;
2344         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2345         chars = sc->ndis_chars;
2346
2347         chars->nmc_shutdown_handler = shutdownfunc;
2348         chars->nmc_rsvd0 = shutdownctx;
2349 }
2350
2351 static void
2352 NdisMDeregisterAdapterShutdownHandler(adapter)
2353         ndis_handle             adapter;
2354 {
2355         ndis_miniport_block     *block;
2356         ndis_miniport_characteristics *chars;
2357         struct ndis_softc       *sc;
2358
2359         if (adapter == NULL)
2360                 return;
2361
2362         block = (ndis_miniport_block *)adapter;
2363         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2364         chars = sc->ndis_chars;
2365
2366         chars->nmc_shutdown_handler = NULL;
2367         chars->nmc_rsvd0 = NULL;
2368 }
2369
2370 static uint32_t
2371 NDIS_BUFFER_TO_SPAN_PAGES(buf)
2372         ndis_buffer             *buf;
2373 {
2374         if (buf == NULL)
2375                 return (0);
2376         if (MmGetMdlByteCount(buf) == 0)
2377                 return (1);
2378         return (SPAN_PAGES(MmGetMdlVirtualAddress(buf),
2379             MmGetMdlByteCount(buf)));
2380 }
2381
2382 static void
2383 NdisGetBufferPhysicalArraySize(buf, pages)
2384         ndis_buffer             *buf;
2385         uint32_t                *pages;
2386 {
2387         if (buf == NULL)
2388                 return;
2389
2390         *pages = NDIS_BUFFER_TO_SPAN_PAGES(buf);
2391 }
2392
2393 static void
2394 NdisQueryBufferOffset(buf, off, len)
2395         ndis_buffer             *buf;
2396         uint32_t                *off;
2397         uint32_t                *len;
2398 {
2399         if (buf == NULL)
2400                 return;
2401
2402         *off = MmGetMdlByteOffset(buf);
2403         *len = MmGetMdlByteCount(buf);
2404 }
2405
2406 void
2407 NdisMSleep(usecs)
2408         uint32_t                usecs;
2409 {
2410         ktimer                  timer;
2411
2412         /*
2413          * During system bootstrap, (i.e. cold == 1), we aren't
2414          * allowed to sleep, so we have to do a hard DELAY()
2415          * instead.
2416          */
2417
2418         if (cold)
2419                 DELAY(usecs);
2420         else {
2421                 KeInitializeTimer(&timer);
2422                 KeSetTimer(&timer, ((int64_t)usecs * -10), NULL);
2423                 KeWaitForSingleObject(&timer, 0, 0, FALSE, NULL);
2424         }
2425 }
2426
2427 static uint32_t
2428 NdisReadPcmciaAttributeMemory(handle, offset, buf, len)
2429         ndis_handle             handle;
2430         uint32_t                offset;
2431         void                    *buf;
2432         uint32_t                len;
2433 {
2434         struct ndis_softc       *sc;
2435         ndis_miniport_block     *block;
2436         bus_space_handle_t      bh;
2437         bus_space_tag_t         bt;
2438         char                    *dest;
2439         uint32_t                i;
2440
2441         if (handle == NULL)
2442                 return (0);
2443
2444         block = (ndis_miniport_block *)handle;
2445         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2446         dest = buf;
2447
2448         bh = rman_get_bushandle(sc->ndis_res_am);
2449         bt = rman_get_bustag(sc->ndis_res_am);
2450
2451         for (i = 0; i < len; i++)
2452                 dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2);
2453
2454         return (i);
2455 }
2456
2457 static uint32_t
2458 NdisWritePcmciaAttributeMemory(handle, offset, buf, len)
2459         ndis_handle             handle;
2460         uint32_t                offset;
2461         void                    *buf;
2462         uint32_t                len;
2463 {
2464         struct ndis_softc       *sc;
2465         ndis_miniport_block     *block;
2466         bus_space_handle_t      bh;
2467         bus_space_tag_t         bt;
2468         char                    *src;
2469         uint32_t                i;
2470
2471         if (handle == NULL)
2472                 return (0);
2473
2474         block = (ndis_miniport_block *)handle;
2475         sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
2476         src = buf;
2477
2478         bh = rman_get_bushandle(sc->ndis_res_am);
2479         bt = rman_get_bustag(sc->ndis_res_am);
2480
2481         for (i = 0; i < len; i++)
2482                 bus_space_write_1(bt, bh, (offset + i) * 2, src[i]);
2483
2484         return (i);
2485 }
2486
2487 static list_entry *
2488 NdisInterlockedInsertHeadList(head, entry, lock)
2489         list_entry              *head;
2490         list_entry              *entry;
2491         ndis_spin_lock          *lock;
2492 {
2493         list_entry              *flink;
2494
2495         KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2496         flink = head->nle_flink;
2497         entry->nle_flink = flink;
2498         entry->nle_blink = head;
2499         flink->nle_blink = entry;
2500         head->nle_flink = entry;
2501         KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2502
2503         return (flink);
2504 }
2505
2506 static list_entry *
2507 NdisInterlockedRemoveHeadList(head, lock)
2508         list_entry              *head;
2509         ndis_spin_lock          *lock;
2510 {
2511         list_entry              *flink;
2512         list_entry              *entry;
2513
2514         KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2515         entry = head->nle_flink;
2516         flink = entry->nle_flink;
2517         head->nle_flink = flink;
2518         flink->nle_blink = head;
2519         KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2520
2521         return (entry);
2522 }
2523
2524 static list_entry *
2525 NdisInterlockedInsertTailList(head, entry, lock)
2526         list_entry              *head;
2527         list_entry              *entry;
2528         ndis_spin_lock          *lock;
2529 {
2530         list_entry              *blink;
2531
2532         KeAcquireSpinLock(&lock->nsl_spinlock, &lock->nsl_kirql);
2533         blink = head->nle_blink;
2534         entry->nle_flink = head;
2535         entry->nle_blink = blink;
2536         blink->nle_flink = entry;
2537         head->nle_blink = entry;
2538         KeReleaseSpinLock(&lock->nsl_spinlock, lock->nsl_kirql);
2539
2540         return (blink);
2541 }
2542
2543 static uint8_t
2544 NdisMSynchronizeWithInterrupt(intr, syncfunc, syncctx)
2545         ndis_miniport_interrupt *intr;
2546         void                    *syncfunc;
2547         void                    *syncctx;
2548 {
2549         return (KeSynchronizeExecution(intr->ni_introbj, syncfunc, syncctx));
2550 }
2551
2552 static void
2553 NdisGetCurrentSystemTime(tval)
2554         uint64_t                *tval;
2555 {
2556         ntoskrnl_time(tval);
2557 }
2558
2559 /*
2560  * Return the number of milliseconds since the system booted.
2561  */
2562 static void
2563 NdisGetSystemUpTime(tval)
2564         uint32_t                *tval;
2565 {
2566         struct timespec         ts;
2567
2568         nanouptime(&ts);
2569         *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
2570 }
2571
2572 static void
2573 NdisInitializeString(dst, src)
2574         unicode_string          *dst;
2575         char                    *src;
2576 {
2577         ansi_string             as;
2578         RtlInitAnsiString(&as, src);
2579         RtlAnsiStringToUnicodeString(dst, &as, TRUE);
2580 }
2581
2582 static void
2583 NdisFreeString(str)
2584         unicode_string          *str;
2585 {
2586         RtlFreeUnicodeString(str);
2587 }
2588
2589 static ndis_status
2590 NdisMRemoveMiniport(adapter)
2591         ndis_handle             *adapter;
2592 {
2593         return (NDIS_STATUS_SUCCESS);
2594 }
2595
2596 static void
2597 NdisInitAnsiString(dst, src)
2598         ansi_string             *dst;
2599         char                    *src;
2600 {
2601         RtlInitAnsiString(dst, src);
2602 }
2603
2604 static void
2605 NdisInitUnicodeString(dst, src)
2606         unicode_string          *dst;
2607         uint16_t                *src;
2608 {
2609         RtlInitUnicodeString(dst, src);
2610 }
2611
2612 static void NdisMGetDeviceProperty(adapter, phydevobj,
2613         funcdevobj, nextdevobj, resources, transresources)
2614         ndis_handle             adapter;
2615         device_object           **phydevobj;
2616         device_object           **funcdevobj;
2617         device_object           **nextdevobj;
2618         cm_resource_list        *resources;
2619         cm_resource_list        *transresources;
2620 {
2621         ndis_miniport_block     *block;
2622
2623         block = (ndis_miniport_block *)adapter;
2624
2625         if (phydevobj != NULL)
2626                 *phydevobj = block->nmb_physdeviceobj;
2627         if (funcdevobj != NULL)
2628                 *funcdevobj = block->nmb_deviceobj;
2629         if (nextdevobj != NULL)
2630                 *nextdevobj = block->nmb_nextdeviceobj;
2631 }
2632
2633 static void
2634 NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen)
2635         ndis_packet             *packet;
2636         ndis_buffer             **buf;
2637         void                    **firstva;
2638         uint32_t                *firstlen;
2639         uint32_t                *totlen;
2640 {
2641         ndis_buffer             *tmp;
2642
2643         tmp = packet->np_private.npp_head;
2644         *buf = tmp;
2645         if (tmp == NULL) {
2646                 *firstva = NULL;
2647                 *firstlen = *totlen = 0;
2648         } else {
2649                 *firstva = MmGetMdlVirtualAddress(tmp);
2650                 *firstlen = *totlen = MmGetMdlByteCount(tmp);
2651                 for (tmp = tmp->mdl_next; tmp != NULL; tmp = tmp->mdl_next)
2652                         *totlen += MmGetMdlByteCount(tmp);
2653         }
2654 }
2655
2656 static void
2657 NdisGetFirstBufferFromPacketSafe(packet, buf, firstva, firstlen, totlen, prio)
2658         ndis_packet             *packet;
2659         ndis_buffer             **buf;
2660         void                    **firstva;
2661         uint32_t                *firstlen;
2662         uint32_t                *totlen;
2663         uint32_t                prio;
2664 {
2665         NdisGetFirstBufferFromPacket(packet, buf, firstva, firstlen, totlen);
2666 }
2667
2668 static int
2669 ndis_find_sym(lf, filename, suffix, sym)
2670         linker_file_t           lf;
2671         char                    *filename;
2672         char                    *suffix;
2673         caddr_t                 *sym;
2674 {
2675         char                    *fullsym;
2676         char                    *suf;
2677         u_int                   i;
2678
2679         fullsym = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2680         if (fullsym == NULL)
2681                 return (ENOMEM);
2682
2683         bzero(fullsym, MAXPATHLEN);
2684         strncpy(fullsym, filename, MAXPATHLEN);
2685         if (strlen(filename) < 4) {
2686                 ExFreePool(fullsym);
2687                 return (EINVAL);
2688         }
2689
2690         /* If the filename has a .ko suffix, strip if off. */
2691         suf = fullsym + (strlen(filename) - 3);
2692         if (strcmp(suf, ".ko") == 0)
2693                 *suf = '\0';
2694
2695         for (i = 0; i < strlen(fullsym); i++) {
2696                 if (fullsym[i] == '.')
2697                         fullsym[i] = '_';
2698                 else
2699                         fullsym[i] = tolower(fullsym[i]);
2700         }
2701         strcat(fullsym, suffix);
2702         *sym = linker_file_lookup_symbol(lf, fullsym, 0);
2703         ExFreePool(fullsym);
2704         if (*sym == 0)
2705                 return (ENOENT);
2706
2707         return (0);
2708 }
2709
2710 struct ndis_checkmodule {
2711         char    *afilename;
2712         ndis_fh *fh;
2713 };
2714
2715 /*
2716  * See if a single module contains the symbols for a specified file.
2717  */
2718 static int
2719 NdisCheckModule(linker_file_t lf, void *context)
2720 {
2721         struct ndis_checkmodule *nc;
2722         caddr_t                 kldstart, kldend;
2723
2724         nc = (struct ndis_checkmodule *)context;
2725         if (ndis_find_sym(lf, nc->afilename, "_start", &kldstart))
2726                 return (0);
2727         if (ndis_find_sym(lf, nc->afilename, "_end", &kldend))
2728                 return (0);
2729         nc->fh->nf_vp = lf;
2730         nc->fh->nf_map = NULL;
2731         nc->fh->nf_type = NDIS_FH_TYPE_MODULE;
2732         nc->fh->nf_maplen = (kldend - kldstart) & 0xFFFFFFFF;
2733         return (1);
2734 }
2735
2736 /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
2737 static void
2738 NdisOpenFile(status, filehandle, filelength, filename, highestaddr)
2739         ndis_status             *status;
2740         ndis_handle             *filehandle;
2741         uint32_t                *filelength;
2742         unicode_string          *filename;
2743         ndis_physaddr           highestaddr;
2744 {
2745         ansi_string             as;
2746         char                    *afilename = NULL;
2747         struct thread           *td = curthread;
2748         struct nameidata        nd;
2749         int                     flags, error;
2750         struct vattr            vat;
2751         struct vattr            *vap = &vat;
2752         ndis_fh                 *fh;
2753         char                    *path;
2754         struct ndis_checkmodule nc;
2755
2756         if (RtlUnicodeStringToAnsiString(&as, filename, TRUE)) {
2757                 *status = NDIS_STATUS_RESOURCES;
2758                 return;
2759         }
2760
2761         afilename = strdup(as.as_buf, M_DEVBUF);
2762         RtlFreeAnsiString(&as);
2763
2764         fh = ExAllocatePoolWithTag(NonPagedPool, sizeof(ndis_fh), 0);
2765         if (fh == NULL) {
2766                 free(afilename, M_DEVBUF);
2767                 *status = NDIS_STATUS_RESOURCES;
2768                 return;
2769         }
2770
2771         fh->nf_name = afilename;
2772
2773         /*
2774          * During system bootstrap, it's impossible to load files
2775          * from the rootfs since it's not mounted yet. We therefore
2776          * offer the possibility of opening files that have been
2777          * preloaded as modules instead. Both choices will work
2778          * when kldloading a module from multiuser, but only the
2779          * module option will work during bootstrap. The module
2780          * loading option works by using the ndiscvt(8) utility
2781          * to convert the arbitrary file into a .ko using objcopy(1).
2782          * This file will contain two special symbols: filename_start
2783          * and filename_end. All we have to do is traverse the KLD
2784          * list in search of those symbols and we've found the file
2785          * data. As an added bonus, ndiscvt(8) will also generate
2786          * a normal .o file which can be linked statically with
2787          * the kernel. This means that the symbols will actual reside
2788          * in the kernel's symbol table, but that doesn't matter to
2789          * us since the kernel appears to us as just another module.
2790          */
2791
2792         nc.afilename = afilename;
2793         nc.fh = fh;
2794         if (linker_file_foreach(NdisCheckModule, &nc)) {
2795                 *filelength = fh->nf_maplen;
2796                 *filehandle = fh;
2797                 *status = NDIS_STATUS_SUCCESS;
2798                 return;
2799         }
2800
2801         if (TAILQ_EMPTY(&mountlist)) {
2802                 ExFreePool(fh);
2803                 *status = NDIS_STATUS_FILE_NOT_FOUND;
2804                 printf("NDIS: could not find file %s in linker list\n",
2805                     afilename);
2806                 printf("NDIS: and no filesystems mounted yet, "
2807                     "aborting NdisOpenFile()\n");
2808                 free(afilename, M_DEVBUF);
2809                 return;
2810         }
2811
2812         path = ExAllocatePoolWithTag(NonPagedPool, MAXPATHLEN, 0);
2813         if (path == NULL) {
2814                 ExFreePool(fh);
2815                 free(afilename, M_DEVBUF);
2816                 *status = NDIS_STATUS_RESOURCES;
2817                 return;
2818         }
2819
2820         snprintf(path, MAXPATHLEN, "%s/%s", ndis_filepath, afilename);
2821
2822         /* Some threads don't have a current working directory. */
2823
2824         pwd_ensure_dirs();
2825
2826         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td);
2827
2828         flags = FREAD;
2829         error = vn_open(&nd, &flags, 0, NULL);
2830         if (error) {
2831                 *status = NDIS_STATUS_FILE_NOT_FOUND;
2832                 ExFreePool(fh);
2833                 printf("NDIS: open file %s failed: %d\n", path, error);
2834                 ExFreePool(path);
2835                 free(afilename, M_DEVBUF);
2836                 return;
2837         }
2838
2839         ExFreePool(path);
2840
2841         NDFREE(&nd, NDF_ONLY_PNBUF);
2842
2843         /* Get the file size. */
2844         VOP_GETATTR(nd.ni_vp, vap, td->td_ucred);
2845         VOP_UNLOCK(nd.ni_vp);
2846
2847         fh->nf_vp = nd.ni_vp;
2848         fh->nf_map = NULL;
2849         fh->nf_type = NDIS_FH_TYPE_VFS;
2850         *filehandle = fh;
2851         *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
2852         *status = NDIS_STATUS_SUCCESS;
2853 }
2854
2855 static void
2856 NdisMapFile(status, mappedbuffer, filehandle)
2857         ndis_status             *status;
2858         void                    **mappedbuffer;
2859         ndis_handle             filehandle;
2860 {
2861         ndis_fh                 *fh;
2862         struct thread           *td = curthread;
2863         linker_file_t           lf;
2864         caddr_t                 kldstart;
2865         int                     error;
2866         ssize_t                 resid;
2867         struct vnode            *vp;
2868
2869         if (filehandle == NULL) {
2870                 *status = NDIS_STATUS_FAILURE;
2871                 return;
2872         }
2873
2874         fh = (ndis_fh *)filehandle;
2875
2876         if (fh->nf_vp == NULL) {
2877                 *status = NDIS_STATUS_FAILURE;
2878                 return;
2879         }
2880
2881         if (fh->nf_map != NULL) {
2882                 *status = NDIS_STATUS_ALREADY_MAPPED;
2883                 return;
2884         }
2885
2886         if (fh->nf_type == NDIS_FH_TYPE_MODULE) {
2887                 lf = fh->nf_vp;
2888                 if (ndis_find_sym(lf, fh->nf_name, "_start", &kldstart)) {
2889                         *status = NDIS_STATUS_FAILURE;
2890                         return;
2891                 }
2892                 fh->nf_map = kldstart;
2893                 *status = NDIS_STATUS_SUCCESS;
2894                 *mappedbuffer = fh->nf_map;
2895                 return;
2896         }
2897
2898         fh->nf_map = ExAllocatePoolWithTag(NonPagedPool, fh->nf_maplen, 0);
2899
2900         if (fh->nf_map == NULL) {
2901                 *status = NDIS_STATUS_RESOURCES;
2902                 return;
2903         }
2904
2905         vp = fh->nf_vp;
2906         error = vn_rdwr(UIO_READ, vp, fh->nf_map, fh->nf_maplen, 0,
2907             UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td);
2908
2909         if (error)
2910                 *status = NDIS_STATUS_FAILURE;
2911         else {
2912                 *status = NDIS_STATUS_SUCCESS;
2913                 *mappedbuffer = fh->nf_map;
2914         }
2915 }
2916
2917 static void
2918 NdisUnmapFile(filehandle)
2919         ndis_handle             filehandle;
2920 {
2921         ndis_fh                 *fh;
2922         fh = (ndis_fh *)filehandle;
2923
2924         if (fh->nf_map == NULL)
2925                 return;
2926
2927         if (fh->nf_type == NDIS_FH_TYPE_VFS)
2928                 ExFreePool(fh->nf_map);
2929         fh->nf_map = NULL;
2930 }
2931
2932 static void
2933 NdisCloseFile(filehandle)
2934         ndis_handle             filehandle;
2935 {
2936         struct thread           *td = curthread;
2937         ndis_fh                 *fh;
2938         struct vnode            *vp;
2939
2940         if (filehandle == NULL)
2941                 return;
2942
2943         fh = (ndis_fh *)filehandle;
2944         if (fh->nf_map != NULL) {
2945                 if (fh->nf_type == NDIS_FH_TYPE_VFS)
2946                         ExFreePool(fh->nf_map);
2947                 fh->nf_map = NULL;
2948         }
2949
2950         if (fh->nf_vp == NULL)
2951                 return;
2952
2953         if (fh->nf_type == NDIS_FH_TYPE_VFS) {
2954                 vp = fh->nf_vp;
2955                 vn_close(vp, FREAD, td->td_ucred, td);
2956         }
2957
2958         fh->nf_vp = NULL;
2959         free(fh->nf_name, M_DEVBUF);
2960         ExFreePool(fh);
2961 }
2962
2963 static uint8_t
2964 NdisSystemProcessorCount()
2965 {
2966         return (mp_ncpus);
2967 }
2968
2969 static void
2970 NdisGetCurrentProcessorCounts(idle_count, kernel_and_user, index)
2971         uint32_t                *idle_count;
2972         uint32_t                *kernel_and_user;
2973         uint32_t                *index;
2974 {
2975         struct pcpu             *pcpu;
2976
2977         pcpu = pcpu_find(curthread->td_oncpu);
2978         *index = pcpu->pc_cpuid;
2979         *idle_count = pcpu->pc_cp_time[CP_IDLE];
2980         *kernel_and_user = pcpu->pc_cp_time[CP_INTR];
2981 }
2982
2983 typedef void (*ndis_statusdone_handler)(ndis_handle);
2984 typedef void (*ndis_status_handler)(ndis_handle, ndis_status,
2985     void *, uint32_t);
2986
2987 static void
2988 NdisMIndicateStatusComplete(adapter)
2989         ndis_handle             adapter;
2990 {
2991         ndis_miniport_block     *block;
2992         ndis_statusdone_handler statusdonefunc;
2993
2994         block = (ndis_miniport_block *)adapter;
2995         statusdonefunc = block->nmb_statusdone_func;
2996
2997         MSCALL1(statusdonefunc, adapter);
2998 }
2999
3000 static void
3001 NdisMIndicateStatus(adapter, status, sbuf, slen)
3002         ndis_handle             adapter;
3003         ndis_status             status;
3004         void                    *sbuf;
3005         uint32_t                slen;
3006 {
3007         ndis_miniport_block     *block;
3008         ndis_status_handler     statusfunc;
3009
3010         block = (ndis_miniport_block *)adapter;
3011         statusfunc = block->nmb_status_func;
3012
3013         MSCALL4(statusfunc, adapter, status, sbuf, slen);
3014 }
3015
3016 /*
3017  * The DDK documentation says that you should use IoQueueWorkItem()
3018  * instead of ExQueueWorkItem(). The problem is, IoQueueWorkItem()
3019  * is fundamentally incompatible with NdisScheduleWorkItem(), which
3020  * depends on the API semantics of ExQueueWorkItem(). In our world,
3021  * ExQueueWorkItem() is implemented on top of IoAllocateQueueItem()
3022  * anyway.
3023  *
3024  * There are actually three distinct APIs here. NdisScheduleWorkItem()
3025  * takes a pointer to an NDIS_WORK_ITEM. ExQueueWorkItem() takes a pointer
3026  * to a WORK_QUEUE_ITEM. And finally, IoQueueWorkItem() takes a pointer
3027  * to an opaque work item thingie which you get from IoAllocateWorkItem().
3028  * An NDIS_WORK_ITEM is not the same as a WORK_QUEUE_ITEM. However,
3029  * the NDIS_WORK_ITEM has some opaque storage at the end of it, and we
3030  * (ab)use this storage as a WORK_QUEUE_ITEM, which is what we submit
3031  * to ExQueueWorkItem().
3032  *
3033  * Got all that? (Sheesh.)
3034  */
3035
3036 ndis_status
3037 NdisScheduleWorkItem(work)
3038         ndis_work_item          *work;
3039 {
3040         work_queue_item         *wqi;
3041
3042         wqi = (work_queue_item *)work->nwi_wraprsvd;
3043         ExInitializeWorkItem(wqi,
3044             (work_item_func)work->nwi_func, work->nwi_ctx);
3045         ExQueueWorkItem(wqi, WORKQUEUE_DELAYED);
3046
3047         return (NDIS_STATUS_SUCCESS);
3048 }
3049
3050 static void
3051 NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen)
3052         ndis_packet             *dpkt;
3053         uint32_t                doff;
3054         uint32_t                reqlen;
3055         ndis_packet             *spkt;
3056         uint32_t                soff;
3057         uint32_t                *cpylen;
3058 {
3059         ndis_buffer             *src, *dst;
3060         char                    *sptr, *dptr;
3061         int                     resid, copied, len, scnt, dcnt;
3062
3063         *cpylen = 0;
3064
3065         src = spkt->np_private.npp_head;
3066         dst = dpkt->np_private.npp_head;
3067
3068         sptr = MmGetMdlVirtualAddress(src);
3069         dptr = MmGetMdlVirtualAddress(dst);
3070         scnt = MmGetMdlByteCount(src);
3071         dcnt = MmGetMdlByteCount(dst);
3072
3073         while (soff) {
3074                 if (MmGetMdlByteCount(src) > soff) {
3075                         sptr += soff;
3076                         scnt = MmGetMdlByteCount(src)- soff;
3077                         break;
3078                 }
3079                 soff -= MmGetMdlByteCount(src);
3080                 src = src->mdl_next;
3081                 if (src == NULL)
3082                         return;
3083                 sptr = MmGetMdlVirtualAddress(src);
3084         }
3085
3086         while (doff) {
3087                 if (MmGetMdlByteCount(dst) > doff) {
3088                         dptr += doff;
3089                         dcnt = MmGetMdlByteCount(dst) - doff;
3090                         break;
3091                 }
3092                 doff -= MmGetMdlByteCount(dst);
3093                 dst = dst->mdl_next;
3094                 if (dst == NULL)
3095                         return;
3096                 dptr = MmGetMdlVirtualAddress(dst);
3097         }
3098
3099         resid = reqlen;
3100         copied = 0;
3101
3102         while(1) {
3103                 if (resid < scnt)
3104                         len = resid;
3105                 else
3106                         len = scnt;
3107                 if (dcnt < len)
3108                         len = dcnt;
3109
3110                 bcopy(sptr, dptr, len);
3111
3112                 copied += len;
3113                 resid -= len;
3114                 if (resid == 0)
3115                         break;
3116
3117                 dcnt -= len;
3118                 if (dcnt == 0) {
3119                         dst = dst->mdl_next;
3120                         if (dst == NULL)
3121                                 break;
3122                         dptr = MmGetMdlVirtualAddress(dst);
3123                         dcnt = MmGetMdlByteCount(dst);
3124                 }
3125
3126                 scnt -= len;
3127                 if (scnt == 0) {
3128                         src = src->mdl_next;
3129                         if (src == NULL)
3130                                 break;
3131                         sptr = MmGetMdlVirtualAddress(src);
3132                         scnt = MmGetMdlByteCount(src);
3133                 }
3134         }
3135
3136         *cpylen = copied;
3137 }
3138
3139 static void
3140 NdisCopyFromPacketToPacketSafe(dpkt, doff, reqlen, spkt, soff, cpylen, prio)
3141         ndis_packet             *dpkt;
3142         uint32_t                doff;
3143         uint32_t                reqlen;
3144         ndis_packet             *spkt;
3145         uint32_t                soff;
3146         uint32_t                *cpylen;
3147         uint32_t                prio;
3148 {
3149         NdisCopyFromPacketToPacket(dpkt, doff, reqlen, spkt, soff, cpylen);
3150 }
3151
3152 static void
3153 NdisIMCopySendPerPacketInfo(dpkt, spkt)
3154         ndis_packet             *dpkt;
3155         ndis_packet             *spkt;
3156 {
3157         memcpy(&dpkt->np_ext, &spkt->np_ext, sizeof(ndis_packet_extension));
3158 }
3159
3160 static ndis_status
3161 NdisMRegisterDevice(handle, devname, symname, majorfuncs, devobj, devhandle)
3162         ndis_handle             handle;
3163         unicode_string          *devname;
3164         unicode_string          *symname;
3165         driver_dispatch         *majorfuncs[];
3166         void                    **devobj;
3167         ndis_handle             *devhandle;
3168 {
3169         uint32_t                status;
3170         device_object           *dobj;
3171
3172         status = IoCreateDevice(handle, 0, devname,
3173             FILE_DEVICE_UNKNOWN, 0, FALSE, &dobj);
3174
3175         if (status == STATUS_SUCCESS) {
3176                 *devobj = dobj;
3177                 *devhandle = dobj;
3178         }
3179
3180         return (status);
3181 }
3182
3183 static ndis_status
3184 NdisMDeregisterDevice(handle)
3185         ndis_handle             handle;
3186 {
3187         IoDeleteDevice(handle);
3188         return (NDIS_STATUS_SUCCESS);
3189 }
3190
3191 static ndis_status
3192 NdisMQueryAdapterInstanceName(name, handle)
3193         unicode_string          *name;
3194         ndis_handle             handle;
3195 {
3196         ndis_miniport_block     *block;
3197         device_t                dev;
3198         ansi_string             as;
3199
3200         block = (ndis_miniport_block *)handle;
3201         dev = block->nmb_physdeviceobj->do_devext;
3202
3203         RtlInitAnsiString(&as, __DECONST(char *, device_get_nameunit(dev)));
3204         if (RtlAnsiStringToUnicodeString(name, &as, TRUE))
3205                 return (NDIS_STATUS_RESOURCES);
3206
3207         return (NDIS_STATUS_SUCCESS);
3208 }
3209
3210 static void
3211 NdisMRegisterUnloadHandler(handle, func)
3212         ndis_handle             handle;
3213         void                    *func;
3214 {
3215 }
3216
3217 static void
3218 dummy()
3219 {
3220         printf("NDIS dummy called...\n");
3221 }
3222
3223 /*
3224  * Note: a couple of entries in this table specify the
3225  * number of arguments as "foo + 1". These are routines
3226  * that accept a 64-bit argument, passed by value. On
3227  * x86, these arguments consume two longwords on the stack,
3228  * so we lie and say there's one additional argument so
3229  * that the wrapping routines will do the right thing.
3230  */
3231
3232 image_patch_table ndis_functbl[] = {
3233         IMPORT_SFUNC(NdisCopyFromPacketToPacket, 6),
3234         IMPORT_SFUNC(NdisCopyFromPacketToPacketSafe, 7),
3235         IMPORT_SFUNC(NdisIMCopySendPerPacketInfo, 2),
3236         IMPORT_SFUNC(NdisScheduleWorkItem, 1),
3237         IMPORT_SFUNC(NdisMIndicateStatusComplete, 1),
3238         IMPORT_SFUNC(NdisMIndicateStatus, 4),
3239         IMPORT_SFUNC(NdisSystemProcessorCount, 0),
3240         IMPORT_SFUNC(NdisGetCurrentProcessorCounts, 3),
3241         IMPORT_SFUNC(NdisUnchainBufferAtBack, 2),
3242         IMPORT_SFUNC(NdisGetFirstBufferFromPacket, 5),
3243         IMPORT_SFUNC(NdisGetFirstBufferFromPacketSafe, 6),
3244         IMPORT_SFUNC(NdisGetBufferPhysicalArraySize, 2),
3245         IMPORT_SFUNC(NdisMGetDeviceProperty, 6),
3246         IMPORT_SFUNC(NdisInitAnsiString, 2),
3247         IMPORT_SFUNC(NdisInitUnicodeString, 2),
3248         IMPORT_SFUNC(NdisWriteConfiguration, 4),
3249         IMPORT_SFUNC(NdisAnsiStringToUnicodeString, 2),
3250         IMPORT_SFUNC(NdisTerminateWrapper, 2),
3251         IMPORT_SFUNC(NdisOpenConfigurationKeyByName, 4),
3252         IMPORT_SFUNC(NdisOpenConfigurationKeyByIndex, 5),
3253         IMPORT_SFUNC(NdisMRemoveMiniport, 1),
3254         IMPORT_SFUNC(NdisInitializeString, 2),
3255         IMPORT_SFUNC(NdisFreeString, 1),
3256         IMPORT_SFUNC(NdisGetCurrentSystemTime, 1),
3257         IMPORT_SFUNC(NdisGetRoutineAddress, 1),
3258         IMPORT_SFUNC(NdisGetSystemUpTime, 1),
3259         IMPORT_SFUNC(NdisGetVersion, 0),
3260         IMPORT_SFUNC(NdisMSynchronizeWithInterrupt, 3),
3261         IMPORT_SFUNC(NdisMAllocateSharedMemoryAsync, 4),
3262         IMPORT_SFUNC(NdisInterlockedInsertHeadList, 3),
3263         IMPORT_SFUNC(NdisInterlockedInsertTailList, 3),
3264         IMPORT_SFUNC(NdisInterlockedRemoveHeadList, 2),
3265         IMPORT_SFUNC(NdisInitializeWrapper, 4),
3266         IMPORT_SFUNC(NdisMRegisterMiniport, 3),
3267         IMPORT_SFUNC(NdisAllocateMemoryWithTag, 3),
3268         IMPORT_SFUNC(NdisAllocateMemory, 4 + 1),
3269         IMPORT_SFUNC(NdisMSetAttributesEx, 5),
3270         IMPORT_SFUNC(NdisCloseConfiguration, 1),
3271         IMPORT_SFUNC(NdisReadConfiguration, 5),
3272         IMPORT_SFUNC(NdisOpenConfiguration, 3),
3273         IMPORT_SFUNC(NdisAcquireSpinLock, 1),
3274         IMPORT_SFUNC(NdisReleaseSpinLock, 1),
3275         IMPORT_SFUNC(NdisDprAcquireSpinLock, 1),
3276         IMPORT_SFUNC(NdisDprReleaseSpinLock, 1),
3277         IMPORT_SFUNC(NdisAllocateSpinLock, 1),
3278         IMPORT_SFUNC(NdisInitializeReadWriteLock, 1),
3279         IMPORT_SFUNC(NdisAcquireReadWriteLock, 3),
3280         IMPORT_SFUNC(NdisReleaseReadWriteLock, 2),
3281         IMPORT_SFUNC(NdisFreeSpinLock, 1),
3282         IMPORT_SFUNC(NdisFreeMemory, 3),
3283         IMPORT_SFUNC(NdisReadPciSlotInformation, 5),
3284         IMPORT_SFUNC(NdisWritePciSlotInformation, 5),
3285         IMPORT_SFUNC_MAP(NdisImmediateReadPciSlotInformation,
3286             NdisReadPciSlotInformation, 5),
3287         IMPORT_SFUNC_MAP(NdisImmediateWritePciSlotInformation,
3288             NdisWritePciSlotInformation, 5),
3289         IMPORT_CFUNC(NdisWriteErrorLogEntry, 0),
3290         IMPORT_SFUNC(NdisMStartBufferPhysicalMapping, 6),
3291         IMPORT_SFUNC(NdisMCompleteBufferPhysicalMapping, 3),
3292         IMPORT_SFUNC(NdisMInitializeTimer, 4),
3293         IMPORT_SFUNC(NdisInitializeTimer, 3),
3294         IMPORT_SFUNC(NdisSetTimer, 2),
3295         IMPORT_SFUNC(NdisMCancelTimer, 2),
3296         IMPORT_SFUNC_MAP(NdisCancelTimer, NdisMCancelTimer, 2),
3297         IMPORT_SFUNC(NdisMSetPeriodicTimer, 2),
3298         IMPORT_SFUNC(NdisMQueryAdapterResources, 4),
3299         IMPORT_SFUNC(NdisMRegisterIoPortRange, 4),
3300         IMPORT_SFUNC(NdisMDeregisterIoPortRange, 4),
3301         IMPORT_SFUNC(NdisReadNetworkAddress, 4),
3302         IMPORT_SFUNC(NdisQueryMapRegisterCount, 2),
3303         IMPORT_SFUNC(NdisMAllocateMapRegisters, 5),
3304         IMPORT_SFUNC(NdisMFreeMapRegisters, 1),
3305         IMPORT_SFUNC(NdisMAllocateSharedMemory, 5),
3306         IMPORT_SFUNC(NdisMMapIoSpace, 4 + 1),
3307         IMPORT_SFUNC(NdisMUnmapIoSpace, 3),
3308         IMPORT_SFUNC(NdisGetCacheFillSize, 0),
3309         IMPORT_SFUNC(NdisMGetDmaAlignment, 1),
3310         IMPORT_SFUNC(NdisMInitializeScatterGatherDma, 3),
3311         IMPORT_SFUNC(NdisAllocatePacketPool, 4),
3312         IMPORT_SFUNC(NdisAllocatePacketPoolEx, 5),
3313         IMPORT_SFUNC(NdisAllocatePacket, 3),
3314         IMPORT_SFUNC(NdisFreePacket, 1),
3315         IMPORT_SFUNC(NdisFreePacketPool, 1),
3316         IMPORT_SFUNC_MAP(NdisDprAllocatePacket, NdisAllocatePacket, 3),
3317         IMPORT_SFUNC_MAP(NdisDprFreePacket, NdisFreePacket, 1),
3318         IMPORT_SFUNC(NdisAllocateBufferPool, 3),
3319         IMPORT_SFUNC(NdisAllocateBuffer, 5),
3320         IMPORT_SFUNC(NdisQueryBuffer, 3),
3321         IMPORT_SFUNC(NdisQueryBufferSafe, 4),
3322         IMPORT_SFUNC(NdisBufferVirtualAddress, 1),
3323         IMPORT_SFUNC(NdisBufferVirtualAddressSafe, 2),
3324         IMPORT_SFUNC(NdisBufferLength, 1),
3325         IMPORT_SFUNC(NdisFreeBuffer, 1),
3326         IMPORT_SFUNC(NdisFreeBufferPool, 1),
3327         IMPORT_SFUNC(NdisInterlockedIncrement, 1),
3328         IMPORT_SFUNC(NdisInterlockedDecrement, 1),
3329         IMPORT_SFUNC(NdisInitializeEvent, 1),
3330         IMPORT_SFUNC(NdisSetEvent, 1),
3331         IMPORT_SFUNC(NdisResetEvent, 1),
3332         IMPORT_SFUNC(NdisWaitEvent, 2),
3333         IMPORT_SFUNC(NdisUnicodeStringToAnsiString, 2),
3334         IMPORT_SFUNC(NdisMPciAssignResources, 3),
3335         IMPORT_SFUNC(NdisMFreeSharedMemory, 5 + 1),
3336         IMPORT_SFUNC(NdisMRegisterInterrupt, 7),
3337         IMPORT_SFUNC(NdisMDeregisterInterrupt, 1),
3338         IMPORT_SFUNC(NdisMRegisterAdapterShutdownHandler, 3),
3339         IMPORT_SFUNC(NdisMDeregisterAdapterShutdownHandler, 1),
3340         IMPORT_SFUNC(NDIS_BUFFER_TO_SPAN_PAGES, 1),
3341         IMPORT_SFUNC(NdisQueryBufferOffset, 3),
3342         IMPORT_SFUNC(NdisAdjustBufferLength, 2),
3343         IMPORT_SFUNC(NdisPacketPoolUsage, 1),
3344         IMPORT_SFUNC(NdisMSleep, 1),
3345         IMPORT_SFUNC(NdisUnchainBufferAtFront, 2),
3346         IMPORT_SFUNC(NdisReadPcmciaAttributeMemory, 4),
3347         IMPORT_SFUNC(NdisWritePcmciaAttributeMemory, 4),
3348         IMPORT_SFUNC(NdisOpenFile, 5 + 1),
3349         IMPORT_SFUNC(NdisMapFile, 3),
3350         IMPORT_SFUNC(NdisUnmapFile, 1),
3351         IMPORT_SFUNC(NdisCloseFile, 1),
3352         IMPORT_SFUNC(NdisMRegisterDevice, 6),
3353         IMPORT_SFUNC(NdisMDeregisterDevice, 1),
3354         IMPORT_SFUNC(NdisMQueryAdapterInstanceName, 2),
3355         IMPORT_SFUNC(NdisMRegisterUnloadHandler, 2),
3356         IMPORT_SFUNC(ndis_timercall, 4),
3357         IMPORT_SFUNC(ndis_asyncmem_complete, 2),
3358         IMPORT_SFUNC(ndis_intr, 2),
3359         IMPORT_SFUNC(ndis_intrhand, 4),
3360
3361         /*
3362          * This last entry is a catch-all for any function we haven't
3363          * implemented yet. The PE import list patching routine will
3364          * use it for any function that doesn't have an explicit match
3365          * in this table.
3366          */
3367
3368         { NULL, (FUNC)dummy, NULL, 0, WINDRV_WRAP_STDCALL },
3369
3370         /* End of list. */
3371         { NULL, NULL, NULL }
3372 };