Set allow_memio to 1 if fetching the allow_memio hint fails. This
[dragonfly.git] / sys / emulation / ndis / subr_ndis.c
blob0d8ac36944ee7b51896e6c117429c609100f2336
1 /*
2 * Copyright (c) 2003
3 * Bill Paul <wpaul@windriver.com>. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
32 * $FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.62 2004/07/11 00:19:30 wpaul Exp $
33 * $DragonFly: src/sys/emulation/ndis/subr_ndis.c,v 1.19 2006/12/23 00:27:02 swildner Exp $
37 * This file implements a translation layer between the BSD networking
38 * infrasturcture and Windows(R) NDIS network driver modules. A Windows
39 * NDIS driver calls into several functions in the NDIS.SYS Windows
40 * kernel module and exports a table of functions designed to be called
41 * by the NDIS subsystem. Using the PE loader, we can patch our own
42 * versions of the NDIS routines into a given Windows driver module and
43 * convince the driver that it is in fact running on Windows.
45 * We provide a table of all our implemented NDIS routines which is patched
46 * into the driver object code. All our exported routines must use the
47 * _stdcall calling convention, since that's what the Windows object code
48 * expects.
51 #include <sys/ctype.h>
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/kernel.h>
55 #include <sys/types.h>
56 #include <sys/errno.h>
58 #include <sys/callout.h>
59 #include <sys/malloc.h>
60 #include <sys/lock.h>
61 #include <sys/socket.h>
62 #include <sys/sysctl.h>
63 #include <sys/queue.h>
64 #include <sys/proc.h>
65 #include <sys/filedesc.h>
66 #include <sys/nlookup.h>
67 #include <sys/fcntl.h>
68 #include <sys/vnode.h>
69 #include <sys/kthread.h>
70 #include <sys/bus.h>
71 #include <sys/rman.h>
73 #include <net/if.h>
74 #include <net/if_arp.h>
75 #include <net/ethernet.h>
76 #include <net/if_dl.h>
77 #include <net/if_media.h>
79 #include <machine/atomic.h>
80 #include <machine/stdarg.h>
82 #include <netproto/802_11/ieee80211_var.h>
83 #include <netproto/802_11/ieee80211_ioctl.h>
85 #include <bus/pci/pcireg.h>
86 #include <bus/pci/pcivar.h>
88 #include "regcall.h"
89 #include "pe_var.h"
90 #include "resource_var.h"
91 #include "ntoskrnl_var.h"
92 #include "hal_var.h"
93 #include "ndis_var.h"
94 #include "cfg_var.h"
95 #include <dev/netif/ndis/if_ndisvar.h>
97 #define FUNC void(*)(void)
99 static char ndis_filepath[MAXPATHLEN];
100 extern struct nd_head ndis_devhead;
102 SYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath,
103 MAXPATHLEN, "Path used by NdisOpenFile() to search for files");
105 __stdcall static void ndis_initwrap(ndis_handle *,
106 device_object *, void *, void *);
107 __stdcall static ndis_status ndis_register_miniport(ndis_handle,
108 ndis_miniport_characteristics *, int);
109 __stdcall static ndis_status ndis_malloc_withtag(void **, uint32_t, uint32_t);
110 __stdcall static ndis_status ndis_malloc(void **,
111 uint32_t, uint32_t, ndis_physaddr);
112 __stdcall static void ndis_free(void *, uint32_t, uint32_t);
113 __stdcall static ndis_status ndis_setattr_ex(ndis_handle, ndis_handle,
114 uint32_t, uint32_t, ndis_interface_type);
115 __stdcall static void ndis_open_cfg(ndis_status *, ndis_handle *, ndis_handle);
116 __stdcall static void ndis_open_cfgbyidx(ndis_status *, ndis_handle,
117 uint32_t, ndis_unicode_string *, ndis_handle *);
118 __stdcall static void ndis_open_cfgbyname(ndis_status *, ndis_handle,
119 ndis_unicode_string *, ndis_handle *);
120 static ndis_status ndis_encode_parm(ndis_miniport_block *,
121 struct sysctl_oid *, ndis_parm_type, ndis_config_parm **);
122 static ndis_status ndis_decode_parm(ndis_miniport_block *,
123 ndis_config_parm *, char *);
124 __stdcall static void ndis_read_cfg(ndis_status *, ndis_config_parm **,
125 ndis_handle, ndis_unicode_string *, ndis_parm_type);
126 __stdcall static void ndis_write_cfg(ndis_status *, ndis_handle,
127 ndis_unicode_string *, ndis_config_parm *);
128 __stdcall static void ndis_close_cfg(ndis_handle);
129 __stdcall static void ndis_create_lock(ndis_spin_lock *);
130 __stdcall static void ndis_destroy_lock(ndis_spin_lock *);
131 __stdcall static void ndis_lock(ndis_spin_lock *);
132 __stdcall static void ndis_unlock(ndis_spin_lock *);
133 __stdcall static void ndis_lock_dpr(ndis_spin_lock *);
134 __stdcall static void ndis_unlock_dpr(ndis_spin_lock *);
135 __stdcall static uint32_t ndis_read_pci(ndis_handle, uint32_t,
136 uint32_t, void *, uint32_t);
137 __stdcall static uint32_t ndis_write_pci(ndis_handle, uint32_t,
138 uint32_t, void *, uint32_t);
139 static void ndis_syslog(ndis_handle, ndis_error_code, uint32_t, ...);
140 static void ndis_map_cb(void *, bus_dma_segment_t *, int, int);
141 __stdcall static void ndis_vtophys_load(ndis_handle, ndis_buffer *,
142 uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *);
143 __stdcall static void ndis_vtophys_unload(ndis_handle, ndis_buffer *, uint32_t);
144 __stdcall static void ndis_create_timer(ndis_miniport_timer *, ndis_handle,
145 ndis_timer_function, void *);
146 __stdcall static void ndis_init_timer(ndis_timer *,
147 ndis_timer_function, void *);
148 __stdcall static void ndis_set_timer(ndis_timer *, uint32_t);
149 __stdcall static void ndis_set_periodic_timer(ndis_miniport_timer *, uint32_t);
150 __stdcall static void ndis_cancel_timer(ndis_timer *, uint8_t *);
151 __stdcall static void ndis_query_resources(ndis_status *, ndis_handle,
152 ndis_resource_list *, uint32_t *);
153 __stdcall static ndis_status ndis_register_ioport(void **,
154 ndis_handle, uint32_t, uint32_t);
155 __stdcall static void ndis_deregister_ioport(ndis_handle,
156 uint32_t, uint32_t, void *);
157 __stdcall static void ndis_read_netaddr(ndis_status *, void **,
158 uint32_t *, ndis_handle);
159 __stdcall static ndis_status ndis_mapreg_cnt(uint32_t, uint32_t *);
160 __stdcall static ndis_status ndis_alloc_mapreg(ndis_handle,
161 uint32_t, uint8_t, uint32_t, uint32_t);
162 __stdcall static void ndis_free_mapreg(ndis_handle);
163 static void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int);
164 __stdcall static void ndis_alloc_sharedmem(ndis_handle, uint32_t,
165 uint8_t, void **, ndis_physaddr *);
166 static void ndis_asyncmem_complete(void *);
167 __stdcall static ndis_status ndis_alloc_sharedmem_async(ndis_handle,
168 uint32_t, uint8_t, void *);
169 __stdcall static void ndis_free_sharedmem(ndis_handle, uint32_t,
170 uint8_t, void *, ndis_physaddr);
171 __stdcall static ndis_status ndis_map_iospace(void **, ndis_handle,
172 ndis_physaddr, uint32_t);
173 __stdcall static void ndis_unmap_iospace(ndis_handle, void *, uint32_t);
174 __stdcall static uint32_t ndis_cachefill(void);
175 __stdcall static uint32_t ndis_dma_align(ndis_handle);
176 __stdcall static ndis_status ndis_init_sc_dma(ndis_handle,
177 uint8_t, uint32_t);
178 __stdcall static void ndis_alloc_packetpool(ndis_status *,
179 ndis_handle *, uint32_t, uint32_t);
180 __stdcall static void ndis_ex_alloc_packetpool(ndis_status *,
181 ndis_handle *, uint32_t, uint32_t, uint32_t);
182 __stdcall static uint32_t ndis_packetpool_use(ndis_handle);
183 __stdcall static void ndis_free_packetpool(ndis_handle);
184 __stdcall static void ndis_alloc_packet(ndis_status *,
185 ndis_packet **, ndis_handle);
186 __stdcall static void ndis_release_packet(ndis_packet *);
187 __stdcall static void ndis_unchain_headbuf(ndis_packet *, ndis_buffer **);
188 __stdcall static void ndis_unchain_tailbuf(ndis_packet *, ndis_buffer **);
189 __stdcall static void ndis_alloc_bufpool(ndis_status *,
190 ndis_handle *, uint32_t);
191 __stdcall static void ndis_free_bufpool(ndis_handle);
192 __stdcall static void ndis_alloc_buf(ndis_status *, ndis_buffer **,
193 ndis_handle, void *, uint32_t);
194 __stdcall static void ndis_release_buf(ndis_buffer *);
195 __stdcall static uint32_t ndis_buflen(ndis_buffer *);
196 __stdcall static void ndis_query_buf(ndis_buffer *, void **, uint32_t *);
197 __stdcall static void ndis_query_buf_safe(ndis_buffer *, void **,
198 uint32_t *, uint32_t);
199 __stdcall static void *ndis_buf_vaddr(ndis_buffer *);
200 __stdcall static void *ndis_buf_vaddr_safe(ndis_buffer *, uint32_t);
201 __stdcall static void ndis_adjust_buflen(ndis_buffer *, int);
202 __stdcall static uint32_t ndis_interlock_inc(uint32_t *);
203 __stdcall static uint32_t ndis_interlock_dec(uint32_t *);
204 __stdcall static void ndis_init_event(ndis_event *);
205 __stdcall static void ndis_set_event(ndis_event *);
206 __stdcall static void ndis_reset_event(ndis_event *);
207 __stdcall static uint8_t ndis_wait_event(ndis_event *, uint32_t);
208 __stdcall static ndis_status ndis_unicode2ansi(ndis_ansi_string *,
209 ndis_unicode_string *);
210 __stdcall static ndis_status ndis_ansi2unicode(ndis_unicode_string *,
211 ndis_ansi_string *);
212 __stdcall static ndis_status ndis_assign_pcirsrc(ndis_handle,
213 uint32_t, ndis_resource_list **);
214 __stdcall static ndis_status ndis_register_intr(ndis_miniport_interrupt *,
215 ndis_handle, uint32_t, uint32_t, uint8_t,
216 uint8_t, ndis_interrupt_mode);
217 __stdcall static void ndis_deregister_intr(ndis_miniport_interrupt *);
218 __stdcall static void ndis_register_shutdown(ndis_handle, void *,
219 ndis_shutdown_handler);
220 __stdcall static void ndis_deregister_shutdown(ndis_handle);
221 __stdcall static uint32_t ndis_numpages(ndis_buffer *);
222 __stdcall static void ndis_buf_physpages(ndis_buffer *, uint32_t *);
223 __stdcall static void ndis_query_bufoffset(ndis_buffer *,
224 uint32_t *, uint32_t *);
225 __stdcall static void ndis_sleep(uint32_t);
226 __stdcall static uint32_t ndis_read_pccard_amem(ndis_handle,
227 uint32_t, void *, uint32_t);
228 __stdcall static uint32_t ndis_write_pccard_amem(ndis_handle,
229 uint32_t, void *, uint32_t);
230 __stdcall static list_entry *ndis_insert_head(list_entry *,
231 list_entry *, ndis_spin_lock *);
232 __stdcall static list_entry *ndis_remove_head(list_entry *,
233 ndis_spin_lock *);
234 __stdcall static list_entry *ndis_insert_tail(list_entry *,
235 list_entry *, ndis_spin_lock *);
236 __stdcall static uint8_t ndis_sync_with_intr(ndis_miniport_interrupt *,
237 void *, void *);
238 __stdcall static void ndis_time(uint64_t *);
239 __stdcall static void ndis_uptime(uint32_t *);
240 __stdcall static void ndis_init_string(ndis_unicode_string *, char *);
241 __stdcall static void ndis_init_ansi_string(ndis_ansi_string *, char *);
242 __stdcall static void ndis_init_unicode_string(ndis_unicode_string *,
243 uint16_t *);
244 __stdcall static void ndis_free_string(ndis_unicode_string *);
245 __stdcall static ndis_status ndis_remove_miniport(ndis_handle *);
246 __stdcall static void ndis_termwrap(ndis_handle, void *);
247 __stdcall static void ndis_get_devprop(ndis_handle, device_object **,
248 device_object **, device_object **, cm_resource_list *,
249 cm_resource_list *);
250 __stdcall static void ndis_firstbuf(ndis_packet *, ndis_buffer **,
251 void **, uint32_t *, uint32_t *);
252 __stdcall static void ndis_firstbuf_safe(ndis_packet *, ndis_buffer **,
253 void **, uint32_t *, uint32_t *, uint32_t);
254 __stdcall static void ndis_open_file(ndis_status *, ndis_handle *, uint32_t *,
255 ndis_unicode_string *, ndis_physaddr);
256 __stdcall static void ndis_map_file(ndis_status *, void **, ndis_handle);
257 __stdcall static void ndis_unmap_file(ndis_handle);
258 __stdcall static void ndis_close_file(ndis_handle);
259 __stdcall static u_int8_t ndis_cpu_cnt(void);
260 __stdcall static void ndis_ind_statusdone(ndis_handle);
261 __stdcall static void ndis_ind_status(ndis_handle, ndis_status,
262 void *, uint32_t);
263 static void ndis_workfunc(void *);
264 __stdcall static ndis_status ndis_sched_workitem(ndis_work_item *);
265 __stdcall static void ndis_pkt_to_pkt(ndis_packet *, uint32_t, uint32_t,
266 ndis_packet *, uint32_t, uint32_t *);
267 __stdcall static void ndis_pkt_to_pkt_safe(ndis_packet *, uint32_t, uint32_t,
268 ndis_packet *, uint32_t, uint32_t *, uint32_t);
269 __stdcall static ndis_status ndis_register_dev(ndis_handle,
270 ndis_unicode_string *, ndis_unicode_string *, driver_dispatch **,
271 void **, ndis_handle *);
272 __stdcall static ndis_status ndis_deregister_dev(ndis_handle);
273 __stdcall static ndis_status ndis_query_name(ndis_unicode_string *,
274 ndis_handle);
275 __stdcall static void ndis_register_unload(ndis_handle, void *);
276 __stdcall static void dummy(void);
279 * Some really old drivers do not properly check the return value
280 * from NdisAllocatePacket() and NdisAllocateBuffer() and will
281 * sometimes allocate few more buffers/packets that they originally
282 * requested when they created the pool. To prevent this from being
283 * a problem, we allocate a few extra buffers/packets beyond what
284 * the driver asks for. This #define controls how many.
286 #define NDIS_POOL_EXTRA 16
289 ndis_libinit(void)
291 strcpy(ndis_filepath, "/compat/ndis");
292 return(0);
296 ndis_libfini(void)
298 return(0);
302 * NDIS deals with strings in unicode format, so we have
303 * do deal with them that way too. For now, we only handle
304 * conversion between unicode and ASCII since that's all
305 * that device drivers care about.
309 ndis_ascii_to_unicode(char *ascii, uint16_t **unicode)
311 uint16_t *ustr;
312 int i;
314 if (*unicode == NULL)
315 *unicode = kmalloc(strlen(ascii) * 2, M_DEVBUF, M_WAITOK);
316 ustr = *unicode;
317 for (i = 0; i < strlen(ascii); i++) {
318 *ustr = (uint16_t)ascii[i];
319 ustr++;
322 return(0);
326 ndis_unicode_to_ascii(uint16_t *unicode, int ulen, char **ascii)
328 uint8_t *astr;
329 int i;
331 if (*ascii == NULL)
332 *ascii = kmalloc((ulen / 2) + 1, M_DEVBUF, M_WAITOK|M_ZERO);
333 astr = *ascii;
334 for (i = 0; i < ulen / 2; i++) {
335 *astr = (uint8_t)unicode[i];
336 astr++;
339 return(0);
342 __stdcall static void
343 ndis_initwrap(ndis_handle *wrapper, device_object *drv_obj, void *path,
344 void *unused)
346 ndis_miniport_block *block;
348 block = drv_obj->do_rsvd;
349 *wrapper = block;
351 return;
354 __stdcall static void
355 ndis_termwrap(ndis_handle handle, void *syspec)
357 return;
360 __stdcall static ndis_status
361 ndis_register_miniport(ndis_handle handle,
362 ndis_miniport_characteristics *characteristics,
363 int len)
365 ndis_miniport_block *block;
366 struct ndis_softc *sc;
368 block = (ndis_miniport_block *)handle;
369 sc = (struct ndis_softc *)block->nmb_ifp;
370 bcopy((char *)characteristics, (char *)&sc->ndis_chars,
371 sizeof(ndis_miniport_characteristics));
372 if (sc->ndis_chars.nmc_version_major < 5 ||
373 sc->ndis_chars.nmc_version_minor < 1) {
374 sc->ndis_chars.nmc_shutdown_handler = NULL;
375 sc->ndis_chars.nmc_canceltxpkts_handler = NULL;
376 sc->ndis_chars.nmc_pnpevent_handler = NULL;
379 return(NDIS_STATUS_SUCCESS);
382 __stdcall static ndis_status
383 ndis_malloc_withtag(void **vaddr, uint32_t len, uint32_t tag)
385 void *mem;
387 mem = kmalloc(len, M_DEVBUF, M_INTWAIT|M_NULLOK);
388 if (mem == NULL)
389 return(NDIS_STATUS_RESOURCES);
390 *vaddr = mem;
392 return(NDIS_STATUS_SUCCESS);
395 __stdcall static ndis_status
396 ndis_malloc(void **vaddr, uint32_t len, uint32_t flags,
397 ndis_physaddr highaddr)
399 void *mem;
401 mem = kmalloc(len, M_DEVBUF, M_INTWAIT|M_NULLOK);
402 if (mem == NULL)
403 return(NDIS_STATUS_RESOURCES);
404 *vaddr = mem;
406 return(NDIS_STATUS_SUCCESS);
409 __stdcall static void
410 ndis_free(void *vaddr, uint32_t len, uint32_t flags)
412 if (len == 0)
413 return;
414 kfree(vaddr, M_DEVBUF);
416 return;
419 __stdcall static ndis_status
420 ndis_setattr_ex(ndis_handle adapter_handle, ndis_handle adapter_ctx,
421 uint32_t hangsecs, uint32_t flags,
422 ndis_interface_type iftype)
424 ndis_miniport_block *block;
427 * Save the adapter context, we need it for calling
428 * the driver's internal functions.
430 block = (ndis_miniport_block *)adapter_handle;
431 block->nmb_miniportadapterctx = adapter_ctx;
432 block->nmb_checkforhangsecs = hangsecs;
433 block->nmb_flags = flags;
435 return(NDIS_STATUS_SUCCESS);
438 __stdcall static void
439 ndis_open_cfg(ndis_status *status, ndis_handle *cfg, ndis_handle wrapctx)
441 *cfg = wrapctx;
442 *status = NDIS_STATUS_SUCCESS;
443 return;
446 __stdcall static void
447 ndis_open_cfgbyname(ndis_status *status, ndis_handle cfg,
448 ndis_unicode_string *subkey, ndis_handle *subhandle)
450 *subhandle = cfg;
451 *status = NDIS_STATUS_SUCCESS;
452 return;
455 __stdcall static void
456 ndis_open_cfgbyidx(ndis_status *status, ndis_handle cfg, uint32_t idx,
457 ndis_unicode_string *subkey, ndis_handle *subhandle)
459 *status = NDIS_STATUS_FAILURE;
460 return;
463 static ndis_status
464 ndis_encode_parm(ndis_miniport_block *block, struct sysctl_oid *oid,
465 ndis_parm_type type, ndis_config_parm **parm)
467 uint16_t *unicode;
468 ndis_unicode_string *ustr;
469 int base = 0;
471 unicode = (uint16_t *)&block->nmb_dummybuf;
473 switch(type) {
474 case ndis_parm_string:
475 ndis_ascii_to_unicode((char *)oid->oid_arg1, &unicode);
476 (*parm)->ncp_type = ndis_parm_string;
477 ustr = &(*parm)->ncp_parmdata.ncp_stringdata;
478 ustr->nus_len = strlen((char *)oid->oid_arg1) * 2;
479 ustr->nus_buf = unicode;
480 break;
481 case ndis_parm_int:
482 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
483 base = 16;
484 else
485 base = 10;
486 (*parm)->ncp_type = ndis_parm_int;
487 (*parm)->ncp_parmdata.ncp_intdata =
488 strtol((char *)oid->oid_arg1, NULL, base);
489 break;
490 case ndis_parm_hexint:
491 if (strncmp((char *)oid->oid_arg1, "0x", 2) == 0)
492 base = 16;
493 else
494 base = 10;
495 (*parm)->ncp_type = ndis_parm_hexint;
496 (*parm)->ncp_parmdata.ncp_intdata =
497 strtoul((char *)oid->oid_arg1, NULL, base);
498 break;
499 default:
500 return(NDIS_STATUS_FAILURE);
501 break;
504 return(NDIS_STATUS_SUCCESS);
508 ndis_strcasecmp(const char *s1, const char *s2)
510 char a, b;
513 * In the kernel, toupper() is a macro. Have to be careful
514 * not to use pointer arithmetic when passing it arguments.
517 while(1) {
518 a = *s1;
519 b = *s2++;
520 if (toupper(a) != toupper(b))
521 break;
522 if (*s1++ == 0)
523 return(0);
526 return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
529 __stdcall static void
530 ndis_read_cfg(ndis_status *status, ndis_config_parm **parm, ndis_handle cfg,
531 ndis_unicode_string *key, ndis_parm_type type)
533 char *keystr = NULL;
534 uint16_t *unicode;
535 ndis_miniport_block *block;
536 struct ndis_softc *sc;
537 struct sysctl_oid *oidp;
538 struct sysctl_ctx_entry *e;
540 block = (ndis_miniport_block *)cfg;
541 sc = (struct ndis_softc *)block->nmb_ifp;
543 if (key->nus_len == 0 || key->nus_buf == NULL) {
544 *status = NDIS_STATUS_FAILURE;
545 return;
548 ndis_unicode_to_ascii(key->nus_buf, key->nus_len, &keystr);
550 *parm = &block->nmb_replyparm;
551 bzero((char *)&block->nmb_replyparm, sizeof(ndis_config_parm));
552 unicode = (uint16_t *)&block->nmb_dummybuf;
555 * See if registry key is already in a list of known keys
556 * included with the driver.
558 #if __FreeBSD_version < 502113
559 TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
560 #else
561 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
562 #endif
563 oidp = e->entry;
564 if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
565 if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) {
566 kfree(keystr, M_DEVBUF);
567 *status = NDIS_STATUS_FAILURE;
568 return;
570 *status = ndis_encode_parm(block, oidp, type, parm);
571 kfree(keystr, M_DEVBUF);
572 return;
577 * If the key didn't match, add it to the list of dynamically
578 * created ones. Sometimes, drivers refer to registry keys
579 * that aren't documented in their .INF files. These keys
580 * are supposed to be created by some sort of utility or
581 * control panel snap-in that comes with the driver software.
582 * Sometimes it's useful to be able to manipulate these.
583 * If the driver requests the key in the form of a string,
584 * make its default value an empty string, otherwise default
585 * it to "0".
588 if (type == ndis_parm_int || type == ndis_parm_hexint)
589 ndis_add_sysctl(sc, keystr, "(dynamic integer key)",
590 "UNSET", CTLFLAG_RW);
591 else
592 ndis_add_sysctl(sc, keystr, "(dynamic string key)",
593 "UNSET", CTLFLAG_RW);
595 kfree(keystr, M_DEVBUF);
596 *status = NDIS_STATUS_FAILURE;
597 return;
600 static ndis_status
601 ndis_decode_parm(ndis_miniport_block *block, ndis_config_parm *parm,
602 char *val)
604 ndis_unicode_string *ustr;
605 char *astr = NULL;
607 switch(parm->ncp_type) {
608 case ndis_parm_string:
609 ustr = &parm->ncp_parmdata.ncp_stringdata;
610 ndis_unicode_to_ascii(ustr->nus_buf, ustr->nus_len, &astr);
611 bcopy(astr, val, 254);
612 kfree(astr, M_DEVBUF);
613 break;
614 case ndis_parm_int:
615 ksprintf(val, "%d", parm->ncp_parmdata.ncp_intdata);
616 break;
617 case ndis_parm_hexint:
618 ksprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata);
619 break;
620 default:
621 return(NDIS_STATUS_FAILURE);
622 break;
624 return(NDIS_STATUS_SUCCESS);
627 __stdcall static void
628 ndis_write_cfg(ndis_status *status, ndis_handle cfg, ndis_unicode_string *key,
629 ndis_config_parm *parm)
631 char *keystr = NULL;
632 ndis_miniport_block *block;
633 struct ndis_softc *sc;
634 struct sysctl_oid *oidp;
635 struct sysctl_ctx_entry *e;
636 char val[256];
638 block = (ndis_miniport_block *)cfg;
639 sc = (struct ndis_softc *)block->nmb_ifp;
641 ndis_unicode_to_ascii(key->nus_buf, key->nus_len, &keystr);
643 /* Decode the parameter into a string. */
644 bzero(val, sizeof(val));
645 *status = ndis_decode_parm(block, parm, val);
646 if (*status != NDIS_STATUS_SUCCESS) {
647 kfree(keystr, M_DEVBUF);
648 return;
651 /* See if the key already exists. */
653 #if __FreeBSD_version < 502113
654 TAILQ_FOREACH(e, &sc->ndis_ctx, link) {
655 #else
656 TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) {
657 #endif
658 oidp = e->entry;
659 if (ndis_strcasecmp(oidp->oid_name, keystr) == 0) {
660 /* Found it, set the value. */
661 strcpy((char *)oidp->oid_arg1, val);
662 kfree(keystr, M_DEVBUF);
663 return;
667 /* Not found, add a new key with the specified value. */
668 ndis_add_sysctl(sc, keystr, "(dynamically set key)",
669 val, CTLFLAG_RW);
671 kfree(keystr, M_DEVBUF);
672 *status = NDIS_STATUS_SUCCESS;
673 return;
676 __stdcall static void
677 ndis_close_cfg(ndis_handle cfg)
679 return;
683 * Initialize a Windows spinlock.
685 __stdcall static void
686 ndis_create_lock(ndis_spin_lock *lock)
688 lock->nsl_spinlock = 0;
689 lock->nsl_kirql = 0;
691 return;
695 * Destroy a Windows spinlock. This is a no-op for now. There are two reasons
696 * for this. One is that it's sort of superfluous: we don't have to do anything
697 * special to deallocate the spinlock. The other is that there are some buggy
698 * drivers which call NdisFreeSpinLock() _after_ calling NdisFreeMemory() on
699 * the block of memory in which the spinlock resides. (Yes, ADMtek, I'm
700 * talking to you.)
702 __stdcall static void
703 ndis_destroy_lock(ndis_spin_lock *lock)
705 #ifdef notdef
706 lock->nsl_spinlock = 0;
707 lock->nsl_kirql = 0;
708 #endif
709 return;
713 * Acquire a spinlock from IRQL <= DISPATCH_LEVEL.
716 __stdcall static void
717 ndis_lock(ndis_spin_lock *lock)
719 lock->nsl_kirql = FASTCALL2(hal_lock,
720 &lock->nsl_spinlock, DISPATCH_LEVEL);
721 return;
725 * Release a spinlock from IRQL == DISPATCH_LEVEL.
728 __stdcall static void
729 ndis_unlock(ndis_spin_lock *lock)
731 FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
732 return;
736 * Acquire a spinlock when already running at IRQL == DISPATCH_LEVEL.
738 __stdcall static void
739 ndis_lock_dpr(ndis_spin_lock *lock)
741 FASTCALL1(ntoskrnl_lock_dpc, &lock->nsl_spinlock);
742 return;
746 * Release a spinlock without leaving IRQL == DISPATCH_LEVEL.
748 __stdcall static void
749 ndis_unlock_dpr(ndis_spin_lock *lock)
751 FASTCALL1(ntoskrnl_unlock_dpc, &lock->nsl_spinlock);
752 return;
755 __stdcall static uint32_t
756 ndis_read_pci(ndis_handle adapter, uint32_t slot, uint32_t offset,
757 void *buf, uint32_t len)
759 ndis_miniport_block *block;
760 int i;
761 char *dest;
763 block = (ndis_miniport_block *)adapter;
764 dest = buf;
765 if (block == NULL || block->nmb_dev == NULL)
766 return(0);
768 for (i = 0; i < len; i++)
769 dest[i] = pci_read_config(block->nmb_dev, i + offset, 1);
771 return(len);
774 __stdcall static uint32_t
775 ndis_write_pci(ndis_handle adapter, uint32_t slot, uint32_t offset,
776 void *buf, uint32_t len)
778 ndis_miniport_block *block;
779 int i;
780 char *dest;
782 block = (ndis_miniport_block *)adapter;
783 dest = buf;
785 if (block == NULL || block->nmb_dev == NULL)
786 return(0);
788 for (i = 0; i < len; i++)
789 pci_write_config(block->nmb_dev, i + offset, dest[i], 1);
791 return(len);
795 * The errorlog routine uses a variable argument list, so we
796 * have to declare it this way.
798 #define ERRMSGLEN 512
799 static void
800 ndis_syslog(ndis_handle adapter, ndis_error_code code,
801 uint32_t numerrors, ...)
803 ndis_miniport_block *block;
804 __va_list ap;
805 int i, error;
806 char *str = NULL, *ustr = NULL;
807 uint16_t flags;
808 char msgbuf[ERRMSGLEN];
811 block = (ndis_miniport_block *)adapter;
813 error = pe_get_message(block->nmb_img, code, &str, &i, &flags);
814 if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE) {
815 ustr = msgbuf;
816 ndis_unicode_to_ascii((uint16_t *)str,
817 ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr);
818 str = ustr;
820 device_printf (block->nmb_dev, "NDIS ERROR: %x (%s)\n", code,
821 str == NULL ? "unknown error" : str);
822 device_printf (block->nmb_dev, "NDIS NUMERRORS: %x\n", numerrors);
824 __va_start(ap, numerrors);
825 for (i = 0; i < numerrors; i++)
826 device_printf (block->nmb_dev, "argptr: %p\n",
827 __va_arg(ap, void *));
828 __va_end(ap);
830 return;
833 static void
834 ndis_map_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
836 struct ndis_map_arg *ctx;
837 int i;
839 if (error)
840 return;
842 ctx = arg;
844 for (i = 0; i < nseg; i++) {
845 ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr;
846 ctx->nma_fraglist[i].npu_len = segs[i].ds_len;
849 ctx->nma_cnt = nseg;
851 return;
854 __stdcall static void
855 ndis_vtophys_load(ndis_handle adapter, ndis_buffer *buf, uint32_t mapreg,
856 uint8_t writedev, ndis_paddr_unit *addrarray,
857 uint32_t *arraysize)
859 ndis_miniport_block *block;
860 struct ndis_softc *sc;
861 struct ndis_map_arg nma;
862 bus_dmamap_t map;
863 int error;
865 if (adapter == NULL)
866 return;
868 block = (ndis_miniport_block *)adapter;
869 sc = (struct ndis_softc *)(block->nmb_ifp);
871 if (mapreg > sc->ndis_mmapcnt)
872 return;
874 map = sc->ndis_mmaps[mapreg];
875 nma.nma_fraglist = addrarray;
877 error = bus_dmamap_load(sc->ndis_mtag, map,
878 MDL_VA(buf), buf->nb_bytecount, ndis_map_cb,
879 (void *)&nma, BUS_DMA_NOWAIT);
881 if (error)
882 return;
884 bus_dmamap_sync(sc->ndis_mtag, map,
885 writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD);
887 *arraysize = nma.nma_cnt;
889 return;
892 __stdcall static void
893 ndis_vtophys_unload(ndis_handle adapter, ndis_buffer *buf,
894 uint32_t mapreg)
896 ndis_miniport_block *block;
897 struct ndis_softc *sc;
898 bus_dmamap_t map;
900 if (adapter == NULL)
901 return;
903 block = (ndis_miniport_block *)adapter;
904 sc = (struct ndis_softc *)(block->nmb_ifp);
906 if (mapreg > sc->ndis_mmapcnt)
907 return;
909 map = sc->ndis_mmaps[mapreg];
911 bus_dmamap_sync(sc->ndis_mtag, map,
912 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
914 bus_dmamap_unload(sc->ndis_mtag, map);
916 return;
920 * This is an older pre-miniport timer init routine which doesn't
921 * accept a miniport context handle. The function context (ctx)
922 * is supposed to be a pointer to the adapter handle, which should
923 * have been handed to us via NdisSetAttributesEx(). We use this
924 * function context to track down the corresponding ndis_miniport_block
925 * structure. It's vital that we track down the miniport block structure,
926 * so if we can't do it, we panic. Note that we also play some games
927 * here by treating ndis_timer and ndis_miniport_timer as the same
928 * thing.
931 __stdcall static void
932 ndis_init_timer(ndis_timer *timer, ndis_timer_function func, void *ctx)
934 ntoskrnl_init_timer(&timer->nt_ktimer);
935 ntoskrnl_init_dpc(&timer->nt_kdpc, func, ctx);
937 return;
940 __stdcall static void
941 ndis_create_timer(ndis_miniport_timer *timer, ndis_handle handle,
942 ndis_timer_function func, void *ctx)
944 /* Save the funcptr and context */
946 timer->nmt_timerfunc = func;
947 timer->nmt_timerctx = ctx;
948 timer->nmt_block = handle;
950 ntoskrnl_init_timer(&timer->nmt_ktimer);
951 ntoskrnl_init_dpc(&timer->nmt_kdpc, func, ctx);
953 return;
957 * In Windows, there's both an NdisMSetTimer() and an NdisSetTimer(),
958 * but the former is just a macro wrapper around the latter.
960 __stdcall static void
961 ndis_set_timer(ndis_timer *timer, uint32_t msecs)
964 * KeSetTimer() wants the period in
965 * hundred nanosecond intervals.
967 ntoskrnl_set_timer(&timer->nt_ktimer,
968 ((int64_t)msecs * -10000), &timer->nt_kdpc);
970 return;
973 __stdcall static void
974 ndis_set_periodic_timer(ndis_miniport_timer *timer, uint32_t msecs)
976 ntoskrnl_set_timer_ex(&timer->nmt_ktimer,
977 ((int64_t)msecs * -10000), msecs, &timer->nmt_kdpc);
979 return;
983 * Technically, this is really NdisCancelTimer(), but we also
984 * (ab)use it for NdisMCancelTimer(), since in our implementation
985 * we don't need the extra info in the ndis_miniport_timer
986 * structure.
989 __stdcall static void
990 ndis_cancel_timer(ndis_timer *timer, uint8_t *cancelled)
992 *cancelled = ntoskrnl_cancel_timer(&timer->nt_ktimer);
994 return;
997 __stdcall static void
998 ndis_query_resources(ndis_status *status, ndis_handle adapter,
999 ndis_resource_list *list, uint32_t *buflen)
1001 ndis_miniport_block *block;
1002 struct ndis_softc *sc;
1003 int rsclen;
1005 block = (ndis_miniport_block *)adapter;
1006 sc = (struct ndis_softc *)block->nmb_ifp;
1008 rsclen = sizeof(ndis_resource_list) +
1009 (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1));
1010 if (*buflen < rsclen) {
1011 *buflen = rsclen;
1012 *status = NDIS_STATUS_INVALID_LENGTH;
1013 return;
1016 bcopy((char *)block->nmb_rlist, (char *)list, rsclen);
1017 *status = NDIS_STATUS_SUCCESS;
1018 return;
1021 __stdcall static ndis_status
1022 ndis_register_ioport(void **offset, ndis_handle adapter,
1023 uint32_t port, uint32_t numports)
1025 struct ndis_miniport_block *block;
1026 struct ndis_softc *sc;
1028 if (adapter == NULL)
1029 return(NDIS_STATUS_FAILURE);
1031 block = (ndis_miniport_block *)adapter;
1032 sc = (struct ndis_softc *)(block->nmb_ifp);
1034 if (sc->ndis_res_io == NULL)
1035 return(NDIS_STATUS_FAILURE);
1037 /* Don't let the device map more ports than we have. */
1038 if (rman_get_size(sc->ndis_res_io) < numports)
1039 return(NDIS_STATUS_INVALID_LENGTH);
1041 *offset = (void *)rman_get_start(sc->ndis_res_io);
1043 return(NDIS_STATUS_SUCCESS);
1046 __stdcall static void
1047 ndis_deregister_ioport(ndis_handle adapter, uint32_t port,
1048 uint32_t numports, void *offset)
1050 return;
1053 __stdcall static void
1054 ndis_read_netaddr(ndis_status *status, void **addr,
1055 uint32_t *addrlen, ndis_handle adapter)
1057 struct ndis_softc *sc;
1058 ndis_miniport_block *block;
1059 uint8_t empty[] = { 0, 0, 0, 0, 0, 0 };
1061 block = (ndis_miniport_block *)adapter;
1062 sc = (struct ndis_softc *)block->nmb_ifp;
1064 if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0)
1065 *status = NDIS_STATUS_FAILURE;
1066 else {
1067 *addr = sc->arpcom.ac_enaddr;
1068 *addrlen = ETHER_ADDR_LEN;
1069 *status = NDIS_STATUS_SUCCESS;
1072 return;
1075 __stdcall static ndis_status
1076 ndis_mapreg_cnt(uint32_t bustype, uint32_t *cnt)
1078 *cnt = 8192;
1079 return(NDIS_STATUS_SUCCESS);
1082 __stdcall static ndis_status
1083 ndis_alloc_mapreg(ndis_handle adapter, uint32_t dmachannel, uint8_t dmasize,
1084 uint32_t physmapneeded, uint32_t maxmap)
1086 struct ndis_softc *sc;
1087 ndis_miniport_block *block;
1088 int error, i, nseg = NDIS_MAXSEG;
1090 block = (ndis_miniport_block *)adapter;
1091 sc = (struct ndis_softc *)block->nmb_ifp;
1093 sc->ndis_mmaps = kmalloc(sizeof(bus_dmamap_t) * physmapneeded,
1094 M_DEVBUF, M_INTWAIT|M_ZERO);
1096 if (sc->ndis_mmaps == NULL)
1097 return(NDIS_STATUS_RESOURCES);
1099 error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1100 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1101 NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW,
1102 &sc->ndis_mtag);
1104 if (error) {
1105 kfree(sc->ndis_mmaps, M_DEVBUF);
1106 return(NDIS_STATUS_RESOURCES);
1109 for (i = 0; i < physmapneeded; i++)
1110 bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]);
1112 sc->ndis_mmapcnt = physmapneeded;
1114 return(NDIS_STATUS_SUCCESS);
1117 __stdcall static void
1118 ndis_free_mapreg(ndis_handle adapter)
1120 struct ndis_softc *sc;
1121 ndis_miniport_block *block;
1122 int i;
1124 block = (ndis_miniport_block *)adapter;
1125 sc = (struct ndis_softc *)block->nmb_ifp;
1127 for (i = 0; i < sc->ndis_mmapcnt; i++)
1128 bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]);
1130 kfree(sc->ndis_mmaps, M_DEVBUF);
1132 bus_dma_tag_destroy(sc->ndis_mtag);
1134 return;
1137 static void
1138 ndis_mapshared_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1140 ndis_physaddr *p;
1142 if (error || nseg > 1)
1143 return;
1145 p = arg;
1147 p->np_quad = segs[0].ds_addr;
1149 return;
1153 * This maps to bus_dmamem_alloc().
1155 __stdcall static void
1156 ndis_alloc_sharedmem(ndis_handle adapter, uint32_t len, uint8_t cached,
1157 void **vaddr, ndis_physaddr *paddr)
1159 ndis_miniport_block *block;
1160 struct ndis_softc *sc;
1161 struct ndis_shmem *sh;
1162 int error;
1164 if (adapter == NULL)
1165 return;
1167 block = (ndis_miniport_block *)adapter;
1168 sc = (struct ndis_softc *)(block->nmb_ifp);
1170 sh = kmalloc(sizeof(struct ndis_shmem), M_DEVBUF, M_INTWAIT|M_ZERO);
1171 if (sh == NULL)
1172 return;
1175 * When performing shared memory allocations, create a tag
1176 * with a lowaddr limit that restricts physical memory mappings
1177 * so that they all fall within the first 1GB of memory.
1178 * At least one device/driver combination (Linksys Instant
1179 * Wireless PCI Card V2.7, Broadcom 802.11b) seems to have
1180 * problems with performing DMA operations with physical
1181 * that lie above the 1GB mark. I don't know if this is a
1182 * hardware limitation or if the addresses are being truncated
1183 * within the driver, but this seems to be the only way to
1184 * make these cards work reliably in systems with more than
1185 * 1GB of physical memory.
1188 error = bus_dma_tag_create(sc->ndis_parent_tag, 64,
1189 0, NDIS_BUS_SPACE_SHARED_MAXADDR, BUS_SPACE_MAXADDR, NULL,
1190 NULL, len, 1, len, BUS_DMA_ALLOCNOW,
1191 &sh->ndis_stag);
1193 if (error) {
1194 kfree(sh, M_DEVBUF);
1195 return;
1198 error = bus_dmamem_alloc(sh->ndis_stag, vaddr,
1199 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap);
1201 if (error) {
1202 bus_dma_tag_destroy(sh->ndis_stag);
1203 kfree(sh, M_DEVBUF);
1204 return;
1207 error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr,
1208 len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT);
1210 if (error) {
1211 bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap);
1212 bus_dma_tag_destroy(sh->ndis_stag);
1213 kfree(sh, M_DEVBUF);
1214 return;
1217 sh->ndis_saddr = *vaddr;
1218 sh->ndis_next = sc->ndis_shlist;
1219 sc->ndis_shlist = sh;
1221 return;
1224 struct ndis_allocwork {
1225 ndis_handle na_adapter;
1226 uint32_t na_len;
1227 uint8_t na_cached;
1228 void *na_ctx;
1231 static void
1232 ndis_asyncmem_complete(void *arg)
1234 ndis_miniport_block *block;
1235 struct ndis_softc *sc;
1236 struct ndis_allocwork *w;
1237 void *vaddr;
1238 ndis_physaddr paddr;
1239 ndis_allocdone_handler donefunc;
1241 w = arg;
1242 block = (ndis_miniport_block *)w->na_adapter;
1243 sc = (struct ndis_softc *)(block->nmb_ifp);
1245 vaddr = NULL;
1246 paddr.np_quad = 0;
1248 donefunc = sc->ndis_chars.nmc_allocate_complete_func;
1249 ndis_alloc_sharedmem(w->na_adapter, w->na_len,
1250 w->na_cached, &vaddr, &paddr);
1251 donefunc(w->na_adapter, vaddr, &paddr, w->na_len, w->na_ctx);
1253 kfree(arg, M_DEVBUF);
1255 return;
1258 __stdcall static ndis_status
1259 ndis_alloc_sharedmem_async(ndis_handle adapter, uint32_t len,
1260 uint8_t cached, void *ctx)
1262 struct ndis_allocwork *w;
1264 if (adapter == NULL)
1265 return(NDIS_STATUS_FAILURE);
1267 w = kmalloc(sizeof(struct ndis_allocwork), M_TEMP, M_INTWAIT);
1269 if (w == NULL)
1270 return(NDIS_STATUS_FAILURE);
1272 w->na_adapter = adapter;
1273 w->na_cached = cached;
1274 w->na_len = len;
1275 w->na_ctx = ctx;
1278 * Pawn this work off on the SWI thread instead of the
1279 * taskqueue thread, because sometimes drivers will queue
1280 * up work items on the taskqueue thread that will block,
1281 * which would prevent the memory allocation from completing
1282 * when we need it.
1284 ndis_sched(ndis_asyncmem_complete, w, NDIS_SWI);
1286 return(NDIS_STATUS_PENDING);
1289 __stdcall static void
1290 ndis_free_sharedmem(ndis_handle adapter, uint32_t len, uint8_t cached,
1291 void *vaddr, ndis_physaddr paddr)
1293 ndis_miniport_block *block;
1294 struct ndis_softc *sc;
1295 struct ndis_shmem *sh, *prev;
1297 if (vaddr == NULL || adapter == NULL)
1298 return;
1300 block = (ndis_miniport_block *)adapter;
1301 sc = (struct ndis_softc *)(block->nmb_ifp);
1302 sh = prev = sc->ndis_shlist;
1304 while (sh) {
1305 if (sh->ndis_saddr == vaddr)
1306 break;
1307 prev = sh;
1308 sh = sh->ndis_next;
1311 bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap);
1312 bus_dmamem_free(sh->ndis_stag, vaddr, sh->ndis_smap);
1313 bus_dma_tag_destroy(sh->ndis_stag);
1315 if (sh == sc->ndis_shlist)
1316 sc->ndis_shlist = sh->ndis_next;
1317 else
1318 prev->ndis_next = sh->ndis_next;
1320 kfree(sh, M_DEVBUF);
1322 return;
1325 __stdcall static ndis_status
1326 ndis_map_iospace(void **vaddr, ndis_handle adapter, ndis_physaddr paddr,
1327 uint32_t len)
1329 ndis_miniport_block *block;
1330 struct ndis_softc *sc;
1332 if (adapter == NULL)
1333 return(NDIS_STATUS_FAILURE);
1335 block = (ndis_miniport_block *)adapter;
1336 sc = (struct ndis_softc *)(block->nmb_ifp);
1338 if (sc->ndis_res_mem != NULL &&
1339 paddr.np_quad == rman_get_start(sc->ndis_res_mem))
1340 *vaddr = (void *)rman_get_virtual(sc->ndis_res_mem);
1341 else if (sc->ndis_res_altmem != NULL &&
1342 paddr.np_quad == rman_get_start(sc->ndis_res_altmem))
1343 *vaddr = (void *)rman_get_virtual(sc->ndis_res_altmem);
1344 else if (sc->ndis_res_am != NULL &&
1345 paddr.np_quad == rman_get_start(sc->ndis_res_am))
1346 *vaddr = (void *)rman_get_virtual(sc->ndis_res_am);
1347 else
1348 return(NDIS_STATUS_FAILURE);
1350 return(NDIS_STATUS_SUCCESS);
1353 __stdcall static void
1354 ndis_unmap_iospace(ndis_handle adapter, void *vaddr, uint32_t len)
1356 return;
1359 __stdcall static uint32_t
1360 ndis_cachefill(void)
1362 return(128);
1365 __stdcall static uint32_t
1366 ndis_dma_align(ndis_handle handle)
1368 return(128);
1372 * NDIS has two methods for dealing with NICs that support DMA.
1373 * One is to just pass packets to the driver and let it call
1374 * NdisMStartBufferPhysicalMapping() to map each buffer in the packet
1375 * all by itself, and the other is to let the NDIS library handle the
1376 * buffer mapping internally, and hand the driver an already populated
1377 * scatter/gather fragment list. If the driver calls
1378 * NdisMInitializeScatterGatherDma(), it wants to use the latter
1379 * method.
1382 __stdcall static ndis_status
1383 ndis_init_sc_dma(ndis_handle adapter, uint8_t is64, uint32_t maxphysmap)
1385 struct ndis_softc *sc;
1386 ndis_miniport_block *block;
1387 int error;
1389 if (adapter == NULL)
1390 return(NDIS_STATUS_FAILURE);
1391 block = (ndis_miniport_block *)adapter;
1392 sc = (struct ndis_softc *)block->nmb_ifp;
1394 /* Don't do this twice. */
1395 if (sc->ndis_sc == 1)
1396 return(NDIS_STATUS_SUCCESS);
1398 error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0,
1399 BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1400 MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW,
1401 &sc->ndis_ttag);
1403 sc->ndis_sc = 1;
1405 return(NDIS_STATUS_SUCCESS);
1408 __stdcall static void
1409 ndis_alloc_packetpool(ndis_status *status, ndis_handle *pool,
1410 uint32_t descnum, uint32_t protrsvdlen)
1412 ndis_packet *cur;
1413 int i;
1415 *pool = kmalloc(sizeof(ndis_packet) *
1416 ((descnum + NDIS_POOL_EXTRA) + 1),
1417 M_DEVBUF, M_WAITOK|M_ZERO);
1418 cur = (ndis_packet *)*pool;
1419 cur->np_private.npp_flags = 0x1; /* mark the head of the list */
1420 cur->np_private.npp_totlen = 0; /* init deletetion flag */
1421 for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
1422 cur->np_private.npp_head = (ndis_handle)(cur + 1);
1423 cur++;
1426 *status = NDIS_STATUS_SUCCESS;
1427 return;
1430 __stdcall static void
1431 ndis_ex_alloc_packetpool(ndis_status *status, ndis_handle *pool,
1432 uint32_t descnum, uint32_t oflowdescnum,
1433 uint32_t protrsvdlen)
1435 return(ndis_alloc_packetpool(status, pool,
1436 descnum + oflowdescnum, protrsvdlen));
1439 __stdcall static uint32_t
1440 ndis_packetpool_use(ndis_handle pool)
1442 ndis_packet *head;
1444 head = (ndis_packet *)pool;
1446 return(head->np_private.npp_count);
1449 __stdcall static void
1450 ndis_free_packetpool(ndis_handle pool)
1452 ndis_packet *head;
1454 head = pool;
1456 /* Mark this pool as 'going away.' */
1458 head->np_private.npp_totlen = 1;
1460 /* If there are no buffers loaned out, destroy the pool. */
1462 if (head->np_private.npp_count == 0)
1463 kfree(pool, M_DEVBUF);
1464 else
1465 kprintf("NDIS: buggy driver deleting active packet pool!\n");
1467 return;
1470 __stdcall static void
1471 ndis_alloc_packet(ndis_status *status, ndis_packet **packet, ndis_handle pool)
1473 ndis_packet *head, *pkt;
1475 head = (ndis_packet *)pool;
1477 if (head->np_private.npp_flags != 0x1) {
1478 *status = NDIS_STATUS_FAILURE;
1479 return;
1483 * If this pool is marked as 'going away' don't allocate any
1484 * more packets out of it.
1487 if (head->np_private.npp_totlen) {
1488 *status = NDIS_STATUS_FAILURE;
1489 return;
1492 pkt = (ndis_packet *)head->np_private.npp_head;
1494 if (pkt == NULL) {
1495 *status = NDIS_STATUS_RESOURCES;
1496 return;
1499 head->np_private.npp_head = pkt->np_private.npp_head;
1501 pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL;
1502 /* Save pointer to the pool. */
1503 pkt->np_private.npp_pool = head;
1505 /* Set the oob offset pointer. Lots of things expect this. */
1506 pkt->np_private.npp_packetooboffset =
1507 offsetof(ndis_packet, np_oob);
1510 * We must initialize the packet flags correctly in order
1511 * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and
1512 * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() to work correctly.
1514 pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS;
1516 *packet = pkt;
1518 head->np_private.npp_count++;
1519 *status = NDIS_STATUS_SUCCESS;
1520 return;
1523 __stdcall static void
1524 ndis_release_packet(ndis_packet *packet)
1526 ndis_packet *head;
1528 if (packet == NULL || packet->np_private.npp_pool == NULL)
1529 return;
1531 head = packet->np_private.npp_pool;
1532 if (head->np_private.npp_flags != 0x1)
1533 return;
1535 packet->np_private.npp_head = head->np_private.npp_head;
1536 head->np_private.npp_head = (ndis_buffer *)packet;
1537 head->np_private.npp_count--;
1540 * If the pool has been marked for deletion and there are
1541 * no more packets outstanding, nuke the pool.
1544 if (head->np_private.npp_totlen && head->np_private.npp_count == 0)
1545 kfree(head, M_DEVBUF);
1547 return;
1550 __stdcall static void
1551 ndis_unchain_headbuf(ndis_packet *packet, ndis_buffer **buf)
1553 ndis_packet_private *priv;
1555 if (packet == NULL || buf == NULL)
1556 return;
1558 priv = &packet->np_private;
1560 priv->npp_validcounts = FALSE;
1562 if (priv->npp_head == priv->npp_tail) {
1563 *buf = priv->npp_head;
1564 priv->npp_head = priv->npp_tail = NULL;
1565 } else {
1566 *buf = priv->npp_head;
1567 priv->npp_head = (*buf)->nb_next;
1570 return;
1573 __stdcall static void
1574 ndis_unchain_tailbuf(ndis_packet *packet, ndis_buffer **buf)
1576 ndis_packet_private *priv;
1577 ndis_buffer *tmp;
1579 if (packet == NULL || buf == NULL)
1580 return;
1582 priv = &packet->np_private;
1584 priv->npp_validcounts = FALSE;
1586 if (priv->npp_head == priv->npp_tail) {
1587 *buf = priv->npp_head;
1588 priv->npp_head = priv->npp_tail = NULL;
1589 } else {
1590 *buf = priv->npp_tail;
1591 tmp = priv->npp_head;
1592 while (tmp->nb_next != priv->npp_tail)
1593 tmp = tmp->nb_next;
1594 priv->npp_tail = tmp;
1595 tmp->nb_next = NULL;
1598 return;
1602 * The NDIS "buffer" manipulation functions are somewhat misnamed.
1603 * They don't really allocate buffers: they allocate buffer mappings.
1604 * The idea is you reserve a chunk of DMA-able memory using
1605 * NdisMAllocateSharedMemory() and then use NdisAllocateBuffer()
1606 * to obtain the virtual address of the DMA-able region.
1607 * ndis_alloc_bufpool() is analagous to bus_dma_tag_create().
1610 __stdcall static void
1611 ndis_alloc_bufpool(ndis_status *status, ndis_handle *pool,
1612 uint32_t descnum)
1614 ndis_buffer *cur;
1615 int i;
1617 *pool = kmalloc(sizeof(ndis_buffer) *
1618 ((descnum + NDIS_POOL_EXTRA) + 1),
1619 M_DEVBUF, M_WAITOK|M_ZERO);
1620 cur = (ndis_buffer *)*pool;
1621 cur->nb_flags = 0x1; /* mark the head of the list */
1622 cur->nb_bytecount = 0; /* init usage count */
1623 cur->nb_byteoffset = 0; /* init deletetion flag */
1624 for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) {
1625 cur->nb_next = cur + 1;
1626 cur++;
1629 *status = NDIS_STATUS_SUCCESS;
1630 return;
1633 __stdcall static void
1634 ndis_free_bufpool(ndis_handle pool)
1636 ndis_buffer *head;
1638 head = pool;
1640 /* Mark this pool as 'going away.' */
1642 head->nb_byteoffset = 1;
1644 /* If there are no buffers loaned out, destroy the pool. */
1645 if (head->nb_bytecount == 0)
1646 kfree(pool, M_DEVBUF);
1647 else
1648 kprintf("NDIS: buggy driver deleting active buffer pool!\n");
1650 return;
1654 * This maps to a bus_dmamap_create() and bus_dmamap_load().
1656 __stdcall static void
1657 ndis_alloc_buf(ndis_status *status, ndis_buffer **buffer, ndis_handle pool,
1658 void *vaddr, uint32_t len)
1660 ndis_buffer *head, *buf;
1662 head = (ndis_buffer *)pool;
1663 if (head->nb_flags != 0x1) {
1664 *status = NDIS_STATUS_FAILURE;
1665 return;
1669 * If this pool is marked as 'going away' don't allocate any
1670 * more buffers out of it.
1673 if (head->nb_byteoffset) {
1674 *status = NDIS_STATUS_FAILURE;
1675 return;
1678 buf = head->nb_next;
1680 if (buf == NULL) {
1681 *status = NDIS_STATUS_RESOURCES;
1682 return;
1685 head->nb_next = buf->nb_next;
1687 /* Save pointer to the pool. */
1688 buf->nb_process = head;
1690 MDL_INIT(buf, vaddr, len);
1692 *buffer = buf;
1694 /* Increment count of busy buffers. */
1696 head->nb_bytecount++;
1698 *status = NDIS_STATUS_SUCCESS;
1699 return;
1702 __stdcall static void
1703 ndis_release_buf(ndis_buffer *buf)
1705 ndis_buffer *head;
1707 if (buf == NULL || buf->nb_process == NULL)
1708 return;
1710 head = buf->nb_process;
1712 if (head->nb_flags != 0x1)
1713 return;
1715 buf->nb_next = head->nb_next;
1716 head->nb_next = buf;
1718 /* Decrement count of busy buffers. */
1720 head->nb_bytecount--;
1723 * If the pool has been marked for deletion and there are
1724 * no more buffers outstanding, nuke the pool.
1727 if (head->nb_byteoffset && head->nb_bytecount == 0)
1728 kfree(head, M_DEVBUF);
1730 return;
1733 /* Aw c'mon. */
1735 __stdcall static uint32_t
1736 ndis_buflen(ndis_buffer *buf)
1738 return(buf->nb_bytecount);
1742 * Get the virtual address and length of a buffer.
1743 * Note: the vaddr argument is optional.
1746 __stdcall static void
1747 ndis_query_buf(ndis_buffer *buf, void **vaddr, uint32_t *len)
1749 if (vaddr != NULL)
1750 *vaddr = MDL_VA(buf);
1751 *len = buf->nb_bytecount;
1753 return;
1756 /* Same as above -- we don't care about the priority. */
1758 __stdcall static void
1759 ndis_query_buf_safe(ndis_buffer *buf, void **vaddr,
1760 uint32_t *len, uint32_t prio)
1762 if (vaddr != NULL)
1763 *vaddr = MDL_VA(buf);
1764 *len = buf->nb_bytecount;
1766 return;
1769 /* Damnit Microsoft!! How many ways can you do the same thing?! */
1771 __stdcall static void *
1772 ndis_buf_vaddr(ndis_buffer *buf)
1774 return(MDL_VA(buf));
1777 __stdcall static void *
1778 ndis_buf_vaddr_safe(ndis_buffer *buf, uint32_t prio)
1780 return(MDL_VA(buf));
1783 __stdcall static void
1784 ndis_adjust_buflen(ndis_buffer *buf, int len)
1786 buf->nb_bytecount = len;
1788 return;
1791 __stdcall static uint32_t
1792 ndis_interlock_inc(uint32_t *addend)
1794 atomic_add_long((u_long *)addend, 1);
1795 return(*addend);
1798 __stdcall static uint32_t
1799 ndis_interlock_dec(uint32_t *addend)
1801 atomic_subtract_long((u_long *)addend, 1);
1802 return(*addend);
1805 __stdcall static void
1806 ndis_init_event(ndis_event *event)
1809 * NDIS events are always notification
1810 * events, and should be initialized to the
1811 * not signaled state.
1814 ntoskrnl_init_event(&event->ne_event, EVENT_TYPE_NOTIFY, FALSE);
1815 return;
1818 __stdcall static void
1819 ndis_set_event(ndis_event *event)
1821 ntoskrnl_set_event(&event->ne_event, 0, 0);
1822 return;
1825 __stdcall static void
1826 ndis_reset_event(ndis_event *event)
1828 ntoskrnl_reset_event(&event->ne_event);
1829 return;
1832 __stdcall static uint8_t
1833 ndis_wait_event(ndis_event *event, uint32_t msecs)
1835 int64_t duetime;
1836 uint32_t rval;
1838 duetime = ((int64_t)msecs * -10000);
1840 rval = ntoskrnl_waitforobj((nt_dispatch_header *)event,
1841 0, 0, TRUE, msecs ? &duetime : NULL);
1843 if (rval == STATUS_TIMEOUT)
1844 return(FALSE);
1846 return(TRUE);
1849 __stdcall static ndis_status
1850 ndis_unicode2ansi(ndis_ansi_string *dstr, ndis_unicode_string *sstr)
1852 if (dstr == NULL || sstr == NULL)
1853 return(NDIS_STATUS_FAILURE);
1854 if (ndis_unicode_to_ascii(sstr->nus_buf,
1855 sstr->nus_len, &dstr->nas_buf))
1856 return(NDIS_STATUS_FAILURE);
1857 dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf);
1858 return (NDIS_STATUS_SUCCESS);
1861 __stdcall static ndis_status
1862 ndis_ansi2unicode(ndis_unicode_string *dstr, ndis_ansi_string *sstr)
1864 char *str;
1865 if (dstr == NULL || sstr == NULL)
1866 return(NDIS_STATUS_FAILURE);
1867 str = kmalloc(sstr->nas_len + 1, M_DEVBUF, M_WAITOK);
1868 strncpy(str, sstr->nas_buf, sstr->nas_len);
1869 *(str + sstr->nas_len) = '\0';
1870 if (ndis_ascii_to_unicode(str, &dstr->nus_buf)) {
1871 kfree(str, M_DEVBUF);
1872 return(NDIS_STATUS_FAILURE);
1874 dstr->nus_len = dstr->nus_maxlen = sstr->nas_len * 2;
1875 kfree(str, M_DEVBUF);
1876 return (NDIS_STATUS_SUCCESS);
1879 __stdcall static ndis_status
1880 ndis_assign_pcirsrc(ndis_handle adapter, uint32_t slot,
1881 ndis_resource_list **list)
1883 ndis_miniport_block *block;
1885 if (adapter == NULL || list == NULL)
1886 return (NDIS_STATUS_FAILURE);
1888 block = (ndis_miniport_block *)adapter;
1889 *list = block->nmb_rlist;
1891 return (NDIS_STATUS_SUCCESS);
1894 __stdcall static ndis_status
1895 ndis_register_intr(ndis_miniport_interrupt *intr, ndis_handle adapter,
1896 uint32_t ivec, uint32_t ilevel, uint8_t reqisr,
1897 uint8_t shared, ndis_interrupt_mode imode)
1899 ndis_miniport_block *block;
1901 block = adapter;
1903 intr->ni_block = adapter;
1904 intr->ni_isrreq = reqisr;
1905 intr->ni_shared = shared;
1906 block->nmb_interrupt = intr;
1907 return(NDIS_STATUS_SUCCESS);
1910 __stdcall static void
1911 ndis_deregister_intr(ndis_miniport_interrupt *intr)
1913 return;
1916 __stdcall static void
1917 ndis_register_shutdown(ndis_handle adapter, void *shutdownctx,
1918 ndis_shutdown_handler shutdownfunc)
1920 ndis_miniport_block *block;
1921 ndis_miniport_characteristics *chars;
1922 struct ndis_softc *sc;
1924 if (adapter == NULL)
1925 return;
1927 block = (ndis_miniport_block *)adapter;
1928 sc = (struct ndis_softc *)block->nmb_ifp;
1929 chars = &sc->ndis_chars;
1931 chars->nmc_shutdown_handler = shutdownfunc;
1932 chars->nmc_rsvd0 = shutdownctx;
1934 return;
1937 __stdcall static void
1938 ndis_deregister_shutdown(ndis_handle adapter)
1940 ndis_miniport_block *block;
1941 ndis_miniport_characteristics *chars;
1942 struct ndis_softc *sc;
1944 if (adapter == NULL)
1945 return;
1947 block = (ndis_miniport_block *)adapter;
1948 sc = (struct ndis_softc *)block->nmb_ifp;
1949 chars = &sc->ndis_chars;
1951 chars->nmc_shutdown_handler = NULL;
1952 chars->nmc_rsvd0 = NULL;
1954 return;
1957 __stdcall static uint32_t
1958 ndis_numpages(ndis_buffer *buf)
1960 if (buf == NULL)
1961 return(0);
1962 if (buf->nb_bytecount == 0)
1963 return(1);
1964 return(SPAN_PAGES(MDL_VA(buf), buf->nb_bytecount));
1967 __stdcall static void
1968 ndis_buf_physpages(ndis_buffer *buf, uint32_t *pages)
1970 if (buf == NULL)
1971 return;
1973 *pages = ndis_numpages(buf);
1974 return;
1977 __stdcall static void
1978 ndis_query_bufoffset(ndis_buffer *buf, uint32_t *off, uint32_t *len)
1980 if (buf == NULL)
1981 return;
1983 *off = buf->nb_byteoffset;
1984 *len = buf->nb_bytecount;
1986 return;
1989 __stdcall static void
1990 ndis_sleep(uint32_t usecs)
1992 struct timeval tv;
1994 tv.tv_sec = 0;
1995 tv.tv_usec = usecs;
1997 ndis_thsuspend(curthread, 1 + usecs * hz / 1000000);
1999 return;
2002 __stdcall static uint32_t
2003 ndis_read_pccard_amem(ndis_handle handle, uint32_t offset, void *buf,
2004 uint32_t len)
2006 struct ndis_softc *sc;
2007 ndis_miniport_block *block;
2008 bus_space_handle_t bh;
2009 bus_space_tag_t bt;
2010 char *dest;
2011 int i;
2013 if (handle == NULL)
2014 return(0);
2016 block = (ndis_miniport_block *)handle;
2017 sc = (struct ndis_softc *)block->nmb_ifp;
2018 dest = buf;
2020 bh = rman_get_bushandle(sc->ndis_res_am);
2021 bt = rman_get_bustag(sc->ndis_res_am);
2023 for (i = 0; i < len; i++)
2024 dest[i] = bus_space_read_1(bt, bh, (offset + i) * 2);
2026 return(i);
2029 __stdcall static uint32_t
2030 ndis_write_pccard_amem(ndis_handle handle, uint32_t offset, void *buf,
2031 uint32_t len)
2033 struct ndis_softc *sc;
2034 ndis_miniport_block *block;
2035 bus_space_handle_t bh;
2036 bus_space_tag_t bt;
2037 char *src;
2038 int i;
2040 if (handle == NULL)
2041 return(0);
2043 block = (ndis_miniport_block *)handle;
2044 sc = (struct ndis_softc *)block->nmb_ifp;
2045 src = buf;
2047 bh = rman_get_bushandle(sc->ndis_res_am);
2048 bt = rman_get_bustag(sc->ndis_res_am);
2050 for (i = 0; i < len; i++)
2051 bus_space_write_1(bt, bh, (offset + i) * 2, src[i]);
2053 return(i);
2056 __stdcall static list_entry *
2057 ndis_insert_head(list_entry *head, list_entry *entry, ndis_spin_lock *lock)
2059 list_entry *flink;
2061 lock->nsl_kirql = FASTCALL2(hal_lock,
2062 &lock->nsl_spinlock, DISPATCH_LEVEL);
2063 flink = head->nle_flink;
2064 entry->nle_flink = flink;
2065 entry->nle_blink = head;
2066 flink->nle_blink = entry;
2067 head->nle_flink = entry;
2068 FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
2070 return(flink);
2073 __stdcall static list_entry *
2074 ndis_remove_head(list_entry *head, ndis_spin_lock *lock)
2076 list_entry *flink;
2077 list_entry *entry;
2079 lock->nsl_kirql = FASTCALL2(hal_lock,
2080 &lock->nsl_spinlock, DISPATCH_LEVEL);
2081 entry = head->nle_flink;
2082 flink = entry->nle_flink;
2083 head->nle_flink = flink;
2084 flink->nle_blink = head;
2085 FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
2087 return(entry);
2090 __stdcall static list_entry *
2091 ndis_insert_tail(list_entry *head, list_entry *entry, ndis_spin_lock *lock)
2093 list_entry *blink;
2095 lock->nsl_kirql = FASTCALL2(hal_lock,
2096 &lock->nsl_spinlock, DISPATCH_LEVEL);
2097 blink = head->nle_blink;
2098 entry->nle_flink = head;
2099 entry->nle_blink = blink;
2100 blink->nle_flink = entry;
2101 head->nle_blink = entry;
2102 FASTCALL2(hal_unlock, &lock->nsl_spinlock, lock->nsl_kirql);
2104 return(blink);
2107 __stdcall static uint8_t
2108 ndis_sync_with_intr(ndis_miniport_interrupt *intr, void *syncfunc,
2109 void *syncctx)
2111 struct ndis_softc *sc;
2112 struct ifnet *ifp;
2113 __stdcall uint8_t (*sync)(void *);
2114 uint8_t rval;
2116 if (syncfunc == NULL || syncctx == NULL)
2117 return(0);
2119 sc = (struct ndis_softc *)intr->ni_block->nmb_ifp;
2120 ifp = &sc->arpcom.ac_if;
2121 sync = syncfunc;
2122 rval = sync(syncctx);
2124 return(rval);
2128 * Return the number of 100 nanosecond intervals since
2129 * January 1, 1601. (?!?!)
2131 __stdcall static void
2132 ndis_time(uint64_t *tval)
2134 struct timespec ts;
2136 nanotime(&ts);
2137 *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 +
2138 11644473600LL;
2140 return;
2144 * Return the number of milliseconds since the system booted.
2146 __stdcall static void
2147 ndis_uptime(uint32_t *tval)
2149 struct timespec ts;
2151 nanouptime(&ts);
2152 *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000;
2154 return;
2157 __stdcall static void
2158 ndis_init_string(ndis_unicode_string *dst, char *src)
2160 ndis_unicode_string *u;
2162 u = dst;
2163 u->nus_buf = NULL;
2164 if (ndis_ascii_to_unicode(src, &u->nus_buf))
2165 return;
2166 u->nus_len = u->nus_maxlen = strlen(src) * 2;
2167 return;
2170 __stdcall static void
2171 ndis_free_string(ndis_unicode_string *str)
2173 if (str == NULL)
2174 return;
2175 if (str->nus_buf != NULL)
2176 kfree(str->nus_buf, M_DEVBUF);
2177 kfree(str, M_DEVBUF);
2178 return;
2181 __stdcall static ndis_status
2182 ndis_remove_miniport(ndis_handle *adapter)
2184 return(NDIS_STATUS_SUCCESS);
2187 __stdcall static void
2188 ndis_init_ansi_string(ndis_ansi_string *dst, char *src)
2190 ndis_ansi_string *a;
2192 a = dst;
2193 if (a == NULL)
2194 return;
2195 if (src == NULL) {
2196 a->nas_len = a->nas_maxlen = 0;
2197 a->nas_buf = NULL;
2198 } else {
2199 a->nas_buf = src;
2200 a->nas_len = a->nas_maxlen = strlen(src);
2203 return;
2206 __stdcall static void
2207 ndis_init_unicode_string(ndis_unicode_string *dst, uint16_t *src)
2209 ndis_unicode_string *u;
2210 int i;
2212 u = dst;
2213 if (u == NULL)
2214 return;
2215 if (src == NULL) {
2216 u->nus_len = u->nus_maxlen = 0;
2217 u->nus_buf = NULL;
2218 } else {
2219 i = 0;
2220 while(src[i] != 0)
2221 i++;
2222 u->nus_buf = src;
2223 u->nus_len = u->nus_maxlen = i * 2;
2226 return;
2229 __stdcall static void
2230 ndis_get_devprop(ndis_handle adapter, device_object **phydevobj,
2231 device_object **funcdevobj, device_object **nextdevobj,
2232 cm_resource_list *resources, cm_resource_list *transresources)
2234 ndis_miniport_block *block;
2236 block = (ndis_miniport_block *)adapter;
2238 if (phydevobj != NULL)
2239 *phydevobj = &block->nmb_devobj;
2240 if (funcdevobj != NULL)
2241 *funcdevobj = &block->nmb_devobj;
2243 return;
2246 __stdcall static void
2247 ndis_firstbuf(ndis_packet *packet, ndis_buffer **buf, void **firstva,
2248 uint32_t *firstlen, uint32_t *totlen)
2250 ndis_buffer *tmp;
2252 tmp = packet->np_private.npp_head;
2253 *buf = tmp;
2254 if (tmp == NULL) {
2255 *firstva = NULL;
2256 *firstlen = *totlen = 0;
2257 } else {
2258 *firstva = MDL_VA(tmp);
2259 *firstlen = *totlen = tmp->nb_bytecount;
2260 for (tmp = tmp->nb_next; tmp != NULL; tmp = tmp->nb_next)
2261 *totlen += tmp->nb_bytecount;
2264 return;
2267 __stdcall static void
2268 ndis_firstbuf_safe(ndis_packet *packet, ndis_buffer **buf, void **firstva,
2269 uint32_t *firstlen, uint32_t *totlen, uint32_t prio)
2271 ndis_firstbuf(packet, buf, firstva, firstlen, totlen);
2274 /* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */
2275 __stdcall static void
2276 ndis_open_file(ndis_status *status, ndis_handle *filehandle, uint32_t *filelength,
2277 ndis_unicode_string *filename, ndis_physaddr highestaddr)
2279 char *afilename = NULL;
2280 struct nlookupdata nd;
2281 int error;
2282 struct vattr vat;
2283 struct vattr *vap = &vat;
2284 ndis_fh *fh;
2285 struct vnode *vp;
2286 char path[MAXPATHLEN];
2288 ndis_unicode_to_ascii(filename->nus_buf,
2289 filename->nus_len, &afilename);
2291 ksprintf(path, "%s/%s", ndis_filepath, afilename);
2292 kfree(afilename, M_DEVBUF);
2294 fh = kmalloc(sizeof(ndis_fh), M_TEMP, M_WAITOK);
2296 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW|NLC_LOCKVP);
2297 if (error == 0)
2298 error = vn_open(&nd, NULL, FREAD, 0);
2299 if (error) {
2300 *status = NDIS_STATUS_FILE_NOT_FOUND;
2301 kfree(fh, M_TEMP);
2302 kprintf("NDIS: open file %s failed: %d\n", path, error);
2303 goto done;
2306 vp = nd.nl_open_vp;
2307 nd.nl_open_vp = NULL;
2309 /* Get the file size. */
2310 VOP_GETATTR(vp, vap);
2311 vn_unlock(vp);
2313 fh->nf_vp = vp;
2314 fh->nf_map = NULL;
2315 *filehandle = fh;
2316 *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF;
2317 *status = NDIS_STATUS_SUCCESS;
2319 done:
2320 nlookup_done(&nd);
2321 return;
2324 __stdcall static void
2325 ndis_map_file(ndis_status *status, void **mappedbuffer, ndis_handle filehandle)
2327 ndis_fh *fh;
2328 int error, resid;
2330 if (filehandle == NULL) {
2331 *status = NDIS_STATUS_FAILURE;
2332 return;
2335 fh = (ndis_fh *)filehandle;
2337 if (fh->nf_vp == NULL) {
2338 *status = NDIS_STATUS_FAILURE;
2339 return;
2342 if (fh->nf_map != NULL) {
2343 *status = NDIS_STATUS_ALREADY_MAPPED;
2344 return;
2347 fh->nf_map = kmalloc(fh->nf_maplen, M_DEVBUF, M_WAITOK);
2349 error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0,
2350 UIO_SYSSPACE, 0, proc0.p_ucred, &resid);
2352 if (error)
2353 *status = NDIS_STATUS_FAILURE;
2354 else {
2355 *status = NDIS_STATUS_SUCCESS;
2356 *mappedbuffer = fh->nf_map;
2359 return;
2362 __stdcall static void
2363 ndis_unmap_file(ndis_handle filehandle)
2365 ndis_fh *fh;
2366 fh = (ndis_fh *)filehandle;
2368 if (fh->nf_map == NULL)
2369 return;
2370 kfree(fh->nf_map, M_DEVBUF);
2371 fh->nf_map = NULL;
2373 return;
2376 __stdcall static void
2377 ndis_close_file(ndis_handle filehandle)
2379 ndis_fh *fh;
2381 if (filehandle == NULL)
2382 return;
2384 fh = (ndis_fh *)filehandle;
2385 if (fh->nf_map != NULL) {
2386 kfree(fh->nf_map, M_DEVBUF);
2387 fh->nf_map = NULL;
2390 if (fh->nf_vp == NULL)
2391 return;
2393 vn_close(fh->nf_vp, FREAD);
2395 fh->nf_vp = NULL;
2396 kfree(fh, M_DEVBUF);
2398 return;
2401 __stdcall static uint8_t
2402 ndis_cpu_cnt(void)
2404 return(ncpus);
2407 typedef __stdcall void (*ndis_statusdone_handler)(ndis_handle);
2408 typedef __stdcall void (*ndis_status_handler)(ndis_handle, ndis_status,
2409 void *, uint32_t);
2411 __stdcall static void
2412 ndis_ind_statusdone(ndis_handle adapter)
2414 ndis_miniport_block *block;
2415 ndis_statusdone_handler statusdonefunc;
2417 block = (ndis_miniport_block *)adapter;
2418 statusdonefunc = block->nmb_statusdone_func;
2420 statusdonefunc(adapter);
2421 return;
2424 __stdcall static void
2425 ndis_ind_status(ndis_handle adapter, ndis_status status, void *sbuf,
2426 uint32_t slen)
2428 ndis_miniport_block *block;
2429 ndis_status_handler statusfunc;
2431 block = (ndis_miniport_block *)adapter;
2432 statusfunc = block->nmb_status_func;
2434 statusfunc(adapter, status, sbuf, slen);
2435 return;
2438 static void
2439 ndis_workfunc(void *ctx)
2441 ndis_work_item *work;
2442 ndis_proc workfunc;
2444 work = ctx;
2445 workfunc = work->nwi_func;
2446 workfunc(work, work->nwi_ctx);
2447 return;
2450 __stdcall static ndis_status
2451 ndis_sched_workitem(ndis_work_item *work)
2453 ndis_sched(ndis_workfunc, work, NDIS_TASKQUEUE);
2454 return(NDIS_STATUS_SUCCESS);
2457 __stdcall static void
2458 ndis_pkt_to_pkt(ndis_packet *dpkt, uint32_t doff, uint32_t reqlen,
2459 ndis_packet *spkt, uint32_t soff, uint32_t *cpylen)
2461 ndis_buffer *src, *dst;
2462 char *sptr, *dptr;
2463 int resid, copied, len, scnt, dcnt;
2465 *cpylen = 0;
2467 src = spkt->np_private.npp_head;
2468 dst = dpkt->np_private.npp_head;
2470 sptr = MDL_VA(src);
2471 dptr = MDL_VA(dst);
2472 scnt = src->nb_bytecount;
2473 dcnt = dst->nb_bytecount;
2475 while (soff) {
2476 if (src->nb_bytecount > soff) {
2477 sptr += soff;
2478 scnt = src->nb_bytecount - soff;
2479 break;
2481 soff -= src->nb_bytecount;
2482 src = src->nb_next;
2483 if (src == NULL)
2484 return;
2485 sptr = MDL_VA(src);
2488 while (doff) {
2489 if (dst->nb_bytecount > doff) {
2490 dptr += doff;
2491 dcnt = dst->nb_bytecount - doff;
2492 break;
2494 doff -= dst->nb_bytecount;
2495 dst = dst->nb_next;
2496 if (dst == NULL)
2497 return;
2498 dptr = MDL_VA(dst);
2501 resid = reqlen;
2502 copied = 0;
2504 while(1) {
2505 if (resid < scnt)
2506 len = resid;
2507 else
2508 len = scnt;
2509 if (dcnt < len)
2510 len = dcnt;
2512 bcopy(sptr, dptr, len);
2514 copied += len;
2515 resid -= len;
2516 if (resid == 0)
2517 break;
2519 dcnt -= len;
2520 if (dcnt == 0) {
2521 dst = dst->nb_next;
2522 if (dst == NULL)
2523 break;
2524 dptr = MDL_VA(dst);
2525 dcnt = dst->nb_bytecount;
2528 scnt -= len;
2529 if (scnt == 0) {
2530 src = src->nb_next;
2531 if (src == NULL)
2532 break;
2533 sptr = MDL_VA(src);
2534 scnt = src->nb_bytecount;
2538 *cpylen = copied;
2539 return;
2542 __stdcall static void
2543 ndis_pkt_to_pkt_safe(ndis_packet *dpkt, uint32_t doff, uint32_t reqlen,
2544 ndis_packet *spkt, uint32_t soff, uint32_t *cpylen,
2545 uint32_t prio)
2547 ndis_pkt_to_pkt(dpkt, doff, reqlen, spkt, soff, cpylen);
2548 return;
2551 __stdcall static ndis_status
2552 ndis_register_dev(ndis_handle handle, ndis_unicode_string *devname,
2553 ndis_unicode_string *symname, driver_dispatch **majorfuncs,
2554 void **devobj, ndis_handle *devhandle)
2556 ndis_miniport_block *block;
2558 block = (ndis_miniport_block *)handle;
2559 *devobj = &block->nmb_devobj;
2560 *devhandle = handle;
2562 return(NDIS_STATUS_SUCCESS);
2565 __stdcall static ndis_status
2566 ndis_deregister_dev(ndis_handle handle)
2568 return(NDIS_STATUS_SUCCESS);
2571 __stdcall static ndis_status
2572 ndis_query_name(ndis_unicode_string *name, ndis_handle handle)
2574 ndis_miniport_block *block;
2576 block = (ndis_miniport_block *)handle;
2577 ndis_ascii_to_unicode(__DECONST(char *,
2578 device_get_nameunit(block->nmb_dev)), &name->nus_buf);
2579 name->nus_len = strlen(device_get_nameunit(block->nmb_dev)) * 2;
2581 return(NDIS_STATUS_SUCCESS);
2584 __stdcall static void
2585 ndis_register_unload(ndis_handle handle, void *func)
2587 return;
2590 __stdcall static void
2591 dummy(void)
2593 kprintf ("NDIS dummy called...\n");
2594 return;
2597 image_patch_table ndis_functbl[] = {
2598 { "NdisCopyFromPacketToPacket", (FUNC)ndis_pkt_to_pkt },
2599 { "NdisCopyFromPacketToPacketSafe", (FUNC)ndis_pkt_to_pkt_safe },
2600 { "NdisScheduleWorkItem", (FUNC)ndis_sched_workitem },
2601 { "NdisMIndicateStatusComplete", (FUNC)ndis_ind_statusdone },
2602 { "NdisMIndicateStatus", (FUNC)ndis_ind_status },
2603 { "NdisSystemProcessorCount", (FUNC)ndis_cpu_cnt },
2604 { "NdisUnchainBufferAtBack", (FUNC)ndis_unchain_tailbuf, },
2605 { "NdisGetFirstBufferFromPacket", (FUNC)ndis_firstbuf },
2606 { "NdisGetFirstBufferFromPacketSafe", (FUNC)ndis_firstbuf_safe },
2607 { "NdisGetBufferPhysicalArraySize", (FUNC)ndis_buf_physpages },
2608 { "NdisMGetDeviceProperty", (FUNC)ndis_get_devprop },
2609 { "NdisInitAnsiString", (FUNC)ndis_init_ansi_string },
2610 { "NdisInitUnicodeString", (FUNC)ndis_init_unicode_string },
2611 { "NdisWriteConfiguration", (FUNC)ndis_write_cfg },
2612 { "NdisAnsiStringToUnicodeString", (FUNC)ndis_ansi2unicode },
2613 { "NdisTerminateWrapper", (FUNC)ndis_termwrap },
2614 { "NdisOpenConfigurationKeyByName", (FUNC)ndis_open_cfgbyname },
2615 { "NdisOpenConfigurationKeyByIndex", (FUNC)ndis_open_cfgbyidx },
2616 { "NdisMRemoveMiniport", (FUNC)ndis_remove_miniport },
2617 { "NdisInitializeString", (FUNC)ndis_init_string },
2618 { "NdisFreeString", (FUNC)ndis_free_string },
2619 { "NdisGetCurrentSystemTime", (FUNC)ndis_time },
2620 { "NdisGetSystemUpTime", (FUNC)ndis_uptime },
2621 { "NdisMSynchronizeWithInterrupt", (FUNC)ndis_sync_with_intr },
2622 { "NdisMAllocateSharedMemoryAsync", (FUNC)ndis_alloc_sharedmem_async },
2623 { "NdisInterlockedInsertHeadList", (FUNC)ndis_insert_head },
2624 { "NdisInterlockedInsertTailList", (FUNC)ndis_insert_tail },
2625 { "NdisInterlockedRemoveHeadList", (FUNC)ndis_remove_head },
2626 { "NdisInitializeWrapper", (FUNC)ndis_initwrap },
2627 { "NdisMRegisterMiniport", (FUNC)ndis_register_miniport },
2628 { "NdisAllocateMemoryWithTag", (FUNC)ndis_malloc_withtag },
2629 { "NdisAllocateMemory", (FUNC)ndis_malloc },
2630 { "NdisMSetAttributesEx", (FUNC)ndis_setattr_ex },
2631 { "NdisCloseConfiguration", (FUNC)ndis_close_cfg },
2632 { "NdisReadConfiguration", (FUNC)ndis_read_cfg },
2633 { "NdisOpenConfiguration", (FUNC)ndis_open_cfg },
2634 { "NdisAcquireSpinLock", (FUNC)ndis_lock },
2635 { "NdisReleaseSpinLock", (FUNC)ndis_unlock },
2636 { "NdisDprAcquireSpinLock", (FUNC)ndis_lock_dpr },
2637 { "NdisDprReleaseSpinLock", (FUNC)ndis_unlock_dpr },
2638 { "NdisAllocateSpinLock", (FUNC)ndis_create_lock },
2639 { "NdisFreeSpinLock", (FUNC)ndis_destroy_lock },
2640 { "NdisFreeMemory", (FUNC)ndis_free },
2641 { "NdisReadPciSlotInformation", (FUNC)ndis_read_pci },
2642 { "NdisWritePciSlotInformation",(FUNC)ndis_write_pci },
2643 { "NdisImmediateReadPciSlotInformation", (FUNC)ndis_read_pci },
2644 { "NdisImmediateWritePciSlotInformation", (FUNC)ndis_write_pci },
2645 { "NdisWriteErrorLogEntry", (FUNC)ndis_syslog },
2646 { "NdisMStartBufferPhysicalMapping", (FUNC)ndis_vtophys_load },
2647 { "NdisMCompleteBufferPhysicalMapping", (FUNC)ndis_vtophys_unload },
2648 { "NdisMInitializeTimer", (FUNC)ndis_create_timer },
2649 { "NdisInitializeTimer", (FUNC)ndis_init_timer },
2650 { "NdisSetTimer", (FUNC)ndis_set_timer },
2651 { "NdisMCancelTimer", (FUNC)ndis_cancel_timer },
2652 { "NdisCancelTimer", (FUNC)ndis_cancel_timer },
2653 { "NdisMSetPeriodicTimer", (FUNC)ndis_set_periodic_timer },
2654 { "NdisMQueryAdapterResources", (FUNC)ndis_query_resources },
2655 { "NdisMRegisterIoPortRange", (FUNC)ndis_register_ioport },
2656 { "NdisMDeregisterIoPortRange", (FUNC)ndis_deregister_ioport },
2657 { "NdisReadNetworkAddress", (FUNC)ndis_read_netaddr },
2658 { "NdisQueryMapRegisterCount", (FUNC)ndis_mapreg_cnt },
2659 { "NdisMAllocateMapRegisters", (FUNC)ndis_alloc_mapreg },
2660 { "NdisMFreeMapRegisters", (FUNC)ndis_free_mapreg },
2661 { "NdisMAllocateSharedMemory", (FUNC)ndis_alloc_sharedmem },
2662 { "NdisMMapIoSpace", (FUNC)ndis_map_iospace },
2663 { "NdisMUnmapIoSpace", (FUNC)ndis_unmap_iospace },
2664 { "NdisGetCacheFillSize", (FUNC)ndis_cachefill },
2665 { "NdisMGetDmaAlignment", (FUNC)ndis_dma_align },
2666 { "NdisMInitializeScatterGatherDma", (FUNC)ndis_init_sc_dma },
2667 { "NdisAllocatePacketPool", (FUNC)ndis_alloc_packetpool },
2668 { "NdisAllocatePacketPoolEx", (FUNC)ndis_ex_alloc_packetpool },
2669 { "NdisAllocatePacket", (FUNC)ndis_alloc_packet },
2670 { "NdisFreePacket", (FUNC)ndis_release_packet },
2671 { "NdisFreePacketPool", (FUNC)ndis_free_packetpool },
2672 { "NdisDprAllocatePacket", (FUNC)ndis_alloc_packet },
2673 { "NdisDprFreePacket", (FUNC)ndis_release_packet },
2674 { "NdisAllocateBufferPool", (FUNC)ndis_alloc_bufpool },
2675 { "NdisAllocateBuffer", (FUNC)ndis_alloc_buf },
2676 { "NdisQueryBuffer", (FUNC)ndis_query_buf },
2677 { "NdisQueryBufferSafe", (FUNC)ndis_query_buf_safe },
2678 { "NdisBufferVirtualAddress", (FUNC)ndis_buf_vaddr },
2679 { "NdisBufferVirtualAddressSafe", (FUNC)ndis_buf_vaddr_safe },
2680 { "NdisBufferLength", (FUNC)ndis_buflen },
2681 { "NdisFreeBuffer", (FUNC)ndis_release_buf },
2682 { "NdisFreeBufferPool", (FUNC)ndis_free_bufpool },
2683 { "NdisInterlockedIncrement", (FUNC)ndis_interlock_inc },
2684 { "NdisInterlockedDecrement", (FUNC)ndis_interlock_dec },
2685 { "NdisInitializeEvent", (FUNC)ndis_init_event },
2686 { "NdisSetEvent", (FUNC)ndis_set_event },
2687 { "NdisResetEvent", (FUNC)ndis_reset_event },
2688 { "NdisWaitEvent", (FUNC)ndis_wait_event },
2689 { "NdisUnicodeStringToAnsiString", (FUNC)ndis_unicode2ansi },
2690 { "NdisMPciAssignResources", (FUNC)ndis_assign_pcirsrc },
2691 { "NdisMFreeSharedMemory", (FUNC)ndis_free_sharedmem },
2692 { "NdisMRegisterInterrupt", (FUNC)ndis_register_intr },
2693 { "NdisMDeregisterInterrupt", (FUNC)ndis_deregister_intr },
2694 { "NdisMRegisterAdapterShutdownHandler", (FUNC)ndis_register_shutdown },
2695 { "NdisMDeregisterAdapterShutdownHandler", (FUNC)ndis_deregister_shutdown },
2696 { "NDIS_BUFFER_TO_SPAN_PAGES", (FUNC)ndis_numpages },
2697 { "NdisQueryBufferOffset", (FUNC)ndis_query_bufoffset },
2698 { "NdisAdjustBufferLength", (FUNC)ndis_adjust_buflen },
2699 { "NdisPacketPoolUsage", (FUNC)ndis_packetpool_use },
2700 { "NdisMSleep", (FUNC)ndis_sleep },
2701 { "NdisUnchainBufferAtFront", (FUNC)ndis_unchain_headbuf },
2702 { "NdisReadPcmciaAttributeMemory", (FUNC)ndis_read_pccard_amem },
2703 { "NdisWritePcmciaAttributeMemory", (FUNC)ndis_write_pccard_amem },
2704 { "NdisOpenFile", (FUNC)ndis_open_file },
2705 { "NdisMapFile", (FUNC)ndis_map_file },
2706 { "NdisUnmapFile", (FUNC)ndis_unmap_file },
2707 { "NdisCloseFile", (FUNC)ndis_close_file },
2708 { "NdisMRegisterDevice", (FUNC)ndis_register_dev },
2709 { "NdisMDeregisterDevice", (FUNC)ndis_deregister_dev },
2710 { "NdisMQueryAdapterInstanceName", (FUNC)ndis_query_name },
2711 { "NdisMRegisterUnloadHandler", (FUNC)ndis_register_unload },
2714 * This last entry is a catch-all for any function we haven't
2715 * implemented yet. The PE import list patching routine will
2716 * use it for any function that doesn't have an explicit match
2717 * in this table.
2720 { NULL, (FUNC)dummy },
2722 /* End of list. */
2724 { NULL, NULL },