subr_ndis.c revision 125069
1123474Swpaul/* 2123474Swpaul * Copyright (c) 2003 3123474Swpaul * Bill Paul <wpaul@windriver.com>. All rights reserved. 4123474Swpaul * 5123474Swpaul * Redistribution and use in source and binary forms, with or without 6123474Swpaul * modification, are permitted provided that the following conditions 7123474Swpaul * are met: 8123474Swpaul * 1. Redistributions of source code must retain the above copyright 9123474Swpaul * notice, this list of conditions and the following disclaimer. 10123474Swpaul * 2. Redistributions in binary form must reproduce the above copyright 11123474Swpaul * notice, this list of conditions and the following disclaimer in the 12123474Swpaul * documentation and/or other materials provided with the distribution. 13123474Swpaul * 3. All advertising materials mentioning features or use of this software 14123474Swpaul * must display the following acknowledgement: 15123474Swpaul * This product includes software developed by Bill Paul. 16123474Swpaul * 4. Neither the name of the author nor the names of any co-contributors 17123474Swpaul * may be used to endorse or promote products derived from this software 18123474Swpaul * without specific prior written permission. 19123474Swpaul * 20123474Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND 21123474Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22123474Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23123474Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD 24123474Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25123474Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26123474Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27123474Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28123474Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29123474Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30123474Swpaul * THE POSSIBILITY OF SUCH DAMAGE. 31123474Swpaul */ 32123474Swpaul 33123474Swpaul#include <sys/cdefs.h> 34123474Swpaul__FBSDID("$FreeBSD: head/sys/compat/ndis/subr_ndis.c 125069 2004-01-27 08:10:34Z wpaul $"); 35123474Swpaul 36123474Swpaul/* 37123474Swpaul * This file implements a translation layer between the BSD networking 38123474Swpaul * infrasturcture and Windows(R) NDIS network driver modules. A Windows 39123474Swpaul * NDIS driver calls into several functions in the NDIS.SYS Windows 40123474Swpaul * kernel module and exports a table of functions designed to be called 41123474Swpaul * by the NDIS subsystem. Using the PE loader, we can patch our own 42123474Swpaul * versions of the NDIS routines into a given Windows driver module and 43123474Swpaul * convince the driver that it is in fact running on Windows. 44123474Swpaul * 45123474Swpaul * We provide a table of all our implemented NDIS routines which is patched 46123474Swpaul * into the driver object code. All our exported routines must use the 47123474Swpaul * _stdcall calling convention, since that's what the Windows object code 48123474Swpaul * expects. 49123474Swpaul */ 50123474Swpaul 51123474Swpaul 52123474Swpaul#include <sys/param.h> 53123474Swpaul#include <sys/types.h> 54123474Swpaul#include <sys/errno.h> 55123474Swpaul 56123474Swpaul#include <sys/callout.h> 57123474Swpaul#include <sys/kernel.h> 58123474Swpaul#include <sys/systm.h> 59123474Swpaul#include <sys/malloc.h> 60123474Swpaul#include <sys/lock.h> 61123474Swpaul#include <sys/mutex.h> 62123474Swpaul#include <sys/socket.h> 63123474Swpaul#include <sys/sysctl.h> 64123504Swpaul#include <sys/timespec.h> 65123848Swpaul#include <sys/smp.h> 66124122Swpaul#include <sys/queue.h> 67124272Swpaul#include <sys/proc.h> 68124272Swpaul#include <sys/namei.h> 69124272Swpaul#include <sys/fcntl.h> 70124272Swpaul#include <sys/vnode.h> 71123474Swpaul 72123474Swpaul#include <net/if.h> 73123474Swpaul#include <net/if_arp.h> 74123474Swpaul#include <net/ethernet.h> 75123474Swpaul#include <net/if_dl.h> 76123474Swpaul#include <net/if_media.h> 77123474Swpaul 78124203Swpaul#include <machine/atomic.h> 79123474Swpaul#include <machine/bus_memio.h> 80123474Swpaul#include <machine/bus_pio.h> 81123474Swpaul#include <machine/bus.h> 82123474Swpaul#include <machine/resource.h> 83123474Swpaul 84123474Swpaul#include <sys/bus.h> 85123474Swpaul#include <sys/rman.h> 86123474Swpaul 87123474Swpaul#include <machine/stdarg.h> 88123474Swpaul 89123695Swpaul#include <net80211/ieee80211_var.h> 90123695Swpaul#include <net80211/ieee80211_ioctl.h> 91123695Swpaul 92123474Swpaul#include <dev/pci/pcireg.h> 93123474Swpaul#include <dev/pci/pcivar.h> 94123474Swpaul 95123474Swpaul#include <compat/ndis/pe_var.h> 96123474Swpaul#include <compat/ndis/resource_var.h> 97123512Swpaul#include <compat/ndis/ntoskrnl_var.h> 98123474Swpaul#include <compat/ndis/ndis_var.h> 99123474Swpaul#include <compat/ndis/cfg_var.h> 100123474Swpaul#include <dev/if_ndis/if_ndisvar.h> 101123474Swpaul 102123474Swpaul#define FUNC void(*)(void) 103123474Swpaul 104124409Swpaulstatic struct mtx *ndis_interlock; 105124272Swpaulstatic char ndis_filepath[MAXPATHLEN]; 106124409Swpaulstruct mtx_pool *ndis_mtxpool; 107125057Swpaulextern struct nd_head ndis_devhead; 108123474Swpaul 109124272SwpaulSYSCTL_STRING(_hw, OID_AUTO, ndis_filepath, CTLFLAG_RW, ndis_filepath, 110124272Swpaul MAXPATHLEN, "Path used by NdisOpenFile() to search for files"); 111124272Swpaul 112123474Swpaul__stdcall static void ndis_initwrap(ndis_handle, 113123474Swpaul ndis_driver_object *, void *, void *); 114123474Swpaul__stdcall static ndis_status ndis_register_miniport(ndis_handle, 115123474Swpaul ndis_miniport_characteristics *, int); 116123474Swpaul__stdcall static ndis_status ndis_malloc_withtag(void **, uint32_t, uint32_t); 117123474Swpaul__stdcall static ndis_status ndis_malloc(void **, 118123474Swpaul uint32_t, uint32_t, ndis_physaddr); 119123474Swpaul__stdcall static void ndis_free(void *, uint32_t, uint32_t); 120123474Swpaul__stdcall static ndis_status ndis_setattr_ex(ndis_handle, ndis_handle, 121123474Swpaul uint32_t, uint32_t, ndis_interface_type); 122123474Swpaul__stdcall static void ndis_open_cfg(ndis_status *, ndis_handle *, ndis_handle); 123123526Swpaul__stdcall static void ndis_open_cfgbyidx(ndis_status *, ndis_handle, 124123526Swpaul uint32_t, ndis_unicode_string *, ndis_handle *); 125123526Swpaul__stdcall static void ndis_open_cfgbyname(ndis_status *, ndis_handle, 126123526Swpaul ndis_unicode_string *, ndis_handle *); 127123474Swpaulstatic ndis_status ndis_encode_parm(ndis_miniport_block *, 128123474Swpaul struct sysctl_oid *, ndis_parm_type, ndis_config_parm **); 129123526Swpaulstatic ndis_status ndis_decode_parm(ndis_miniport_block *, 130123526Swpaul ndis_config_parm *, char *); 131123474Swpaul__stdcall static void ndis_read_cfg(ndis_status *, ndis_config_parm **, 132123474Swpaul ndis_handle, ndis_unicode_string *, ndis_parm_type); 133123526Swpaul__stdcall static void ndis_write_cfg(ndis_status *, ndis_handle, 134123526Swpaul ndis_unicode_string *, ndis_config_parm *); 135123474Swpaul__stdcall static void ndis_close_cfg(ndis_handle); 136123474Swpaul__stdcall static void ndis_create_lock(ndis_spin_lock *); 137123474Swpaul__stdcall static void ndis_destroy_lock(ndis_spin_lock *); 138123474Swpaul__stdcall static void ndis_lock(ndis_spin_lock *); 139123474Swpaul__stdcall static void ndis_unlock(ndis_spin_lock *); 140123474Swpaul__stdcall static uint32_t ndis_read_pci(ndis_handle, uint32_t, 141123474Swpaul uint32_t, void *, uint32_t); 142123474Swpaul__stdcall static uint32_t ndis_write_pci(ndis_handle, uint32_t, 143123474Swpaul uint32_t, void *, uint32_t); 144123474Swpaulstatic void ndis_syslog(ndis_handle, ndis_error_code, uint32_t, ...); 145123474Swpaulstatic void ndis_map_cb(void *, bus_dma_segment_t *, int, int); 146123474Swpaul__stdcall static void ndis_vtophys_load(ndis_handle, ndis_buffer *, 147123474Swpaul uint32_t, uint8_t, ndis_paddr_unit *, uint32_t *); 148123474Swpaul__stdcall static void ndis_vtophys_unload(ndis_handle, ndis_buffer *, uint32_t); 149123474Swpaul__stdcall static void ndis_create_timer(ndis_miniport_timer *, ndis_handle *, 150123474Swpaul ndis_timer_function, void *); 151125057Swpaul__stdcall static void ndis_init_timer(ndis_timer *, 152125057Swpaul ndis_timer_function, void *); 153123474Swpaulstatic void ndis_timercall(void *); 154123474Swpaul__stdcall static void ndis_set_timer(ndis_miniport_timer *, uint32_t); 155123474Swpaulstatic void ndis_tick(void *); 156123474Swpaul__stdcall static void ndis_set_periodic_timer(ndis_miniport_timer *, uint32_t); 157123474Swpaul__stdcall static void ndis_cancel_timer(ndis_miniport_timer *, uint8_t *); 158123474Swpaul__stdcall static void ndis_query_resources(ndis_status *, ndis_handle, 159123474Swpaul ndis_resource_list *, uint32_t *); 160123474Swpaul__stdcall static ndis_status ndis_register_ioport(void **, 161123474Swpaul ndis_handle, uint32_t, uint32_t); 162123474Swpaul__stdcall static void ndis_deregister_ioport(ndis_handle, 163123474Swpaul uint32_t, uint32_t, void *); 164123474Swpaul__stdcall static void ndis_read_netaddr(ndis_status *, void **, 165123474Swpaul uint32_t *, ndis_handle); 166123848Swpaul__stdcall static ndis_status ndis_mapreg_cnt(uint32_t, uint32_t *); 167123474Swpaul__stdcall static ndis_status ndis_alloc_mapreg(ndis_handle, 168123474Swpaul uint32_t, uint8_t, uint32_t, uint32_t); 169123474Swpaul__stdcall static void ndis_free_mapreg(ndis_handle); 170123474Swpaulstatic void ndis_mapshared_cb(void *, bus_dma_segment_t *, int, int); 171123474Swpaul__stdcall static void ndis_alloc_sharedmem(ndis_handle, uint32_t, 172123474Swpaul uint8_t, void **, ndis_physaddr *); 173123474Swpaul__stdcall static void ndis_alloc_sharedmem_async(ndis_handle, 174123474Swpaul uint32_t, uint8_t, void *); 175123474Swpaul__stdcall static void ndis_free_sharedmem(ndis_handle, uint32_t, 176123474Swpaul uint8_t, void *, ndis_physaddr); 177123474Swpaul__stdcall static ndis_status ndis_map_iospace(void **, ndis_handle, 178123474Swpaul ndis_physaddr, uint32_t); 179123474Swpaul__stdcall static void ndis_unmap_iospace(ndis_handle, void *, uint32_t); 180123474Swpaul__stdcall static uint32_t ndis_cachefill(void); 181123474Swpaul__stdcall static uint32_t ndis_dma_align(ndis_handle); 182123474Swpaul__stdcall static ndis_status ndis_init_sc_dma(ndis_handle, 183123474Swpaul uint8_t, uint32_t); 184123474Swpaul__stdcall static void ndis_alloc_packetpool(ndis_status *, 185123474Swpaul ndis_handle *, uint32_t, uint32_t); 186123474Swpaul__stdcall static void ndis_ex_alloc_packetpool(ndis_status *, 187123474Swpaul ndis_handle *, uint32_t, uint32_t, uint32_t); 188123474Swpaul__stdcall static uint32_t ndis_packetpool_use(ndis_handle); 189123474Swpaul__stdcall static void ndis_free_packetpool(ndis_handle); 190123474Swpaul__stdcall static void ndis_alloc_packet(ndis_status *, 191123474Swpaul ndis_packet **, ndis_handle); 192123474Swpaul__stdcall static void ndis_release_packet(ndis_packet *); 193123474Swpaul__stdcall static void ndis_unchain_headbuf(ndis_packet *, ndis_buffer **); 194123721Swpaul__stdcall static void ndis_unchain_tailbuf(ndis_packet *, ndis_buffer **); 195123474Swpaul__stdcall static void ndis_alloc_bufpool(ndis_status *, 196123474Swpaul ndis_handle *, uint32_t); 197123474Swpaul__stdcall static void ndis_free_bufpool(ndis_handle); 198123474Swpaul__stdcall static void ndis_alloc_buf(ndis_status *, ndis_buffer **, 199123474Swpaul ndis_handle, void *, uint32_t); 200123474Swpaul__stdcall static void ndis_release_buf(ndis_buffer *); 201124100Swpaul__stdcall static uint32_t ndis_buflen(ndis_buffer *); 202123474Swpaul__stdcall static void ndis_query_buf(ndis_buffer *, void **, uint32_t *); 203123474Swpaul__stdcall static void ndis_query_buf_safe(ndis_buffer *, void **, 204123474Swpaul uint32_t *, uint32_t); 205125069Swpaul__stdcall static void *ndis_buf_vaddr(ndis_buffer *); 206125069Swpaul__stdcall static void *ndis_buf_vaddr_safe(ndis_buffer *, uint32_t); 207123474Swpaul__stdcall static void ndis_adjust_buflen(ndis_buffer *, int); 208123474Swpaul__stdcall static uint32_t ndis_interlock_inc(uint32_t *); 209123474Swpaul__stdcall static uint32_t ndis_interlock_dec(uint32_t *); 210123474Swpaul__stdcall static void ndis_init_event(ndis_event *); 211123474Swpaul__stdcall static void ndis_set_event(ndis_event *); 212123474Swpaul__stdcall static void ndis_reset_event(ndis_event *); 213123474Swpaul__stdcall static uint8_t ndis_wait_event(ndis_event *, uint32_t); 214123474Swpaul__stdcall static ndis_status ndis_unicode2ansi(ndis_ansi_string *, 215123474Swpaul ndis_unicode_string *); 216123526Swpaul__stdcall static ndis_status ndis_ansi2unicode(ndis_unicode_string *, 217123526Swpaul ndis_ansi_string *); 218123474Swpaul__stdcall static ndis_status ndis_assign_pcirsrc(ndis_handle, 219123474Swpaul uint32_t, ndis_resource_list **); 220123474Swpaul__stdcall static ndis_status ndis_register_intr(ndis_miniport_interrupt *, 221123474Swpaul ndis_handle, uint32_t, uint32_t, uint8_t, 222123474Swpaul uint8_t, ndis_interrupt_mode); 223123474Swpaul__stdcall static void ndis_deregister_intr(ndis_miniport_interrupt *); 224123474Swpaul__stdcall static void ndis_register_shutdown(ndis_handle, void *, 225123474Swpaul ndis_shutdown_handler); 226123474Swpaul__stdcall static void ndis_deregister_shutdown(ndis_handle); 227123474Swpaul__stdcall static uint32_t ndis_numpages(ndis_buffer *); 228123573Swpaul__stdcall static void ndis_buf_physpages(ndis_buffer *, uint32_t *); 229123474Swpaul__stdcall static void ndis_query_bufoffset(ndis_buffer *, 230123474Swpaul uint32_t *, uint32_t *); 231123474Swpaul__stdcall static void ndis_sleep(uint32_t); 232123474Swpaul__stdcall static uint32_t ndis_read_pccard_amem(ndis_handle, 233123474Swpaul uint32_t, void *, uint32_t); 234123474Swpaul__stdcall static uint32_t ndis_write_pccard_amem(ndis_handle, 235123474Swpaul uint32_t, void *, uint32_t); 236123474Swpaul__stdcall static ndis_list_entry *ndis_insert_head(ndis_list_entry *, 237123474Swpaul ndis_list_entry *, ndis_spin_lock *); 238123474Swpaul__stdcall static ndis_list_entry *ndis_remove_head(ndis_list_entry *, 239123474Swpaul ndis_spin_lock *); 240123474Swpaul__stdcall static ndis_list_entry *ndis_insert_tail(ndis_list_entry *, 241123474Swpaul ndis_list_entry *, ndis_spin_lock *); 242123474Swpaul__stdcall static uint8_t ndis_sync_with_intr(ndis_miniport_interrupt *, 243123474Swpaul void *, void *); 244123504Swpaul__stdcall static void ndis_time(uint64_t *); 245123822Swpaul__stdcall static void ndis_uptime(uint32_t *); 246124100Swpaul__stdcall static void ndis_init_string(ndis_unicode_string *, char *); 247123526Swpaul__stdcall static void ndis_init_ansi_string(ndis_ansi_string *, char *); 248123941Swpaul__stdcall static void ndis_init_unicode_string(ndis_unicode_string *, 249123941Swpaul uint16_t *); 250123507Swpaul__stdcall static void ndis_free_string(ndis_unicode_string *); 251123507Swpaul__stdcall static ndis_status ndis_remove_miniport(ndis_handle *); 252123526Swpaul__stdcall static void ndis_termwrap(ndis_handle, void *); 253123526Swpaul__stdcall static void ndis_get_devprop(ndis_handle, void *, void *, 254123526Swpaul void *, cm_resource_list *, cm_resource_list *); 255123721Swpaul__stdcall static void ndis_firstbuf(ndis_packet *, ndis_buffer **, 256123721Swpaul void **, uint32_t *, uint32_t *); 257123721Swpaul__stdcall static void ndis_firstbuf_safe(ndis_packet *, ndis_buffer **, 258123721Swpaul void **, uint32_t *, uint32_t *, uint32_t); 259123822Swpaul__stdcall static void ndis_open_file(ndis_status *, ndis_handle *, uint32_t *, 260123822Swpaul ndis_unicode_string *, ndis_physaddr); 261123822Swpaul__stdcall static void ndis_map_file(ndis_status *, void **, ndis_handle); 262123822Swpaul__stdcall static void ndis_unmap_file(ndis_handle); 263123822Swpaul__stdcall static void ndis_close_file(ndis_handle); 264123848Swpaul__stdcall static u_int8_t ndis_cpu_cnt(void); 265124116Swpaul__stdcall static void ndis_ind_statusdone(ndis_handle); 266124116Swpaul__stdcall static void ndis_ind_status(ndis_handle, ndis_status, 267124116Swpaul void *, uint32_t); 268124697Swpaulstatic void ndis_workfunc(void *); 269124122Swpaul__stdcall static ndis_status ndis_sched_workitem(ndis_work_item *); 270124541Swpaul__stdcall static void ndis_pkt_to_pkt(ndis_packet *, uint32_t, uint32_t, 271124541Swpaul ndis_packet *, uint32_t, uint32_t *); 272124541Swpaul__stdcall static void ndis_pkt_to_pkt_safe(ndis_packet *, uint32_t, uint32_t, 273124541Swpaul ndis_packet *, uint32_t, uint32_t *, uint32_t); 274125057Swpaul__stdcall static ndis_status ndis_register_dev(ndis_handle *, 275125057Swpaul ndis_unicode_string *, ndis_unicode_string *, void *, 276125057Swpaul void *, ndis_handle **); 277125057Swpaul__stdcall static ndis_status ndis_deregister_dev(ndis_handle *); 278123474Swpaul__stdcall static void dummy(void); 279123474Swpaul 280124116Swpaul/* 281124116Swpaul * Some really old drivers do not properly check the return value 282124116Swpaul * from NdisAllocatePacket() and NdisAllocateBuffer() and will 283124116Swpaul * sometimes allocate few more buffers/packets that they originally 284124116Swpaul * requested when they created the pool. To prevent this from being 285124116Swpaul * a problem, we allocate a few extra buffers/packets beyond what 286124116Swpaul * the driver asks for. This #define controls how many. 287124116Swpaul */ 288124116Swpaul#define NDIS_POOL_EXTRA 16 289123474Swpaul 290123474Swpaulint 291123474Swpaulndis_libinit() 292123474Swpaul{ 293124272Swpaul strcpy(ndis_filepath, "/compat/ndis"); 294124409Swpaul ndis_mtxpool = mtx_pool_create("ndis mutex pool", 295124409Swpaul 1024, MTX_DEF | MTX_RECURSE | MTX_DUPOK);; 296124409Swpaul ndis_interlock = mtx_pool_alloc(ndis_mtxpool); 297123474Swpaul return(0); 298123474Swpaul} 299123474Swpaul 300123474Swpaulint 301123474Swpaulndis_libfini() 302123474Swpaul{ 303124409Swpaul mtx_pool_destroy(&ndis_mtxpool); 304123474Swpaul return(0); 305123474Swpaul} 306123474Swpaul 307123474Swpaul/* 308123474Swpaul * NDIS deals with strings in unicode format, so we have 309123474Swpaul * do deal with them that way too. For now, we only handle 310123474Swpaul * conversion between unicode and ASCII since that's all 311123474Swpaul * that device drivers care about. 312123474Swpaul */ 313123474Swpaul 314123474Swpaulint 315123474Swpaulndis_ascii_to_unicode(ascii, unicode) 316123474Swpaul char *ascii; 317123474Swpaul uint16_t **unicode; 318123474Swpaul{ 319123474Swpaul uint16_t *ustr; 320123474Swpaul int i; 321123474Swpaul 322123474Swpaul if (*unicode == NULL) 323123474Swpaul *unicode = malloc(strlen(ascii) * 2, M_DEVBUF, M_WAITOK); 324123474Swpaul 325123474Swpaul if (*unicode == NULL) 326123474Swpaul return(ENOMEM); 327123474Swpaul ustr = *unicode; 328123474Swpaul for (i = 0; i < strlen(ascii); i++) { 329123474Swpaul *ustr = (uint16_t)ascii[i]; 330123474Swpaul ustr++; 331123474Swpaul } 332123474Swpaul 333123474Swpaul return(0); 334123474Swpaul} 335123474Swpaul 336123474Swpaulint 337123474Swpaulndis_unicode_to_ascii(unicode, ulen, ascii) 338123474Swpaul uint16_t *unicode; 339123474Swpaul int ulen; 340123474Swpaul char **ascii; 341123474Swpaul{ 342123474Swpaul uint8_t *astr; 343123474Swpaul int i; 344123474Swpaul 345123474Swpaul if (*ascii == NULL) 346124100Swpaul *ascii = malloc((ulen / 2) + 1, M_DEVBUF, M_WAITOK|M_ZERO); 347123474Swpaul if (*ascii == NULL) 348123474Swpaul return(ENOMEM); 349123474Swpaul astr = *ascii; 350124100Swpaul for (i = 0; i < ulen / 2; i++) { 351123474Swpaul *astr = (uint8_t)unicode[i]; 352123474Swpaul astr++; 353123474Swpaul } 354123474Swpaul 355123474Swpaul return(0); 356123474Swpaul} 357123474Swpaul 358123474Swpaul__stdcall static void 359123474Swpaulndis_initwrap(wrapper, drv_obj, path, unused) 360123474Swpaul ndis_handle wrapper; 361123474Swpaul ndis_driver_object *drv_obj; 362123474Swpaul void *path; 363123474Swpaul void *unused; 364123474Swpaul{ 365123474Swpaul ndis_driver_object **drv; 366123474Swpaul 367123474Swpaul drv = wrapper; 368123474Swpaul *drv = drv_obj; 369123474Swpaul 370123474Swpaul return; 371123474Swpaul} 372123474Swpaul 373123526Swpaul__stdcall static void 374123526Swpaulndis_termwrap(handle, syspec) 375123526Swpaul ndis_handle handle; 376123526Swpaul void *syspec; 377123526Swpaul{ 378123526Swpaul return; 379123526Swpaul} 380123526Swpaul 381123474Swpaul__stdcall static ndis_status 382123474Swpaulndis_register_miniport(handle, characteristics, len) 383123474Swpaul ndis_handle handle; 384123474Swpaul ndis_miniport_characteristics *characteristics; 385123474Swpaul int len; 386123474Swpaul{ 387123474Swpaul ndis_driver_object *drv; 388123474Swpaul 389123474Swpaul drv = handle; 390123474Swpaul bcopy((char *)characteristics, (char *)&drv->ndo_chars, 391123474Swpaul sizeof(ndis_miniport_characteristics)); 392123474Swpaul return(NDIS_STATUS_SUCCESS); 393123474Swpaul} 394123474Swpaul 395123474Swpaul__stdcall static ndis_status 396123474Swpaulndis_malloc_withtag(vaddr, len, tag) 397123474Swpaul void **vaddr; 398123474Swpaul uint32_t len; 399123474Swpaul uint32_t tag; 400123474Swpaul{ 401123474Swpaul void *mem; 402123474Swpaul 403123474Swpaul mem = malloc(len, M_DEVBUF, M_NOWAIT); 404123474Swpaul if (mem == NULL) 405123474Swpaul return(NDIS_STATUS_RESOURCES); 406123474Swpaul *vaddr = mem; 407123474Swpaul 408123474Swpaul return(NDIS_STATUS_SUCCESS); 409123474Swpaul} 410123474Swpaul 411123474Swpaul__stdcall static ndis_status 412123474Swpaulndis_malloc(vaddr, len, flags, highaddr) 413123474Swpaul void **vaddr; 414123474Swpaul uint32_t len; 415123474Swpaul uint32_t flags; 416123474Swpaul ndis_physaddr highaddr; 417123474Swpaul{ 418123474Swpaul void *mem; 419123474Swpaul 420123474Swpaul mem = malloc(len, M_DEVBUF, M_NOWAIT); 421123474Swpaul if (mem == NULL) 422123474Swpaul return(NDIS_STATUS_RESOURCES); 423123474Swpaul *vaddr = mem; 424123474Swpaul 425123474Swpaul return(NDIS_STATUS_SUCCESS); 426123474Swpaul} 427123474Swpaul 428123474Swpaul__stdcall static void 429123474Swpaulndis_free(vaddr, len, flags) 430123474Swpaul void *vaddr; 431123474Swpaul uint32_t len; 432123474Swpaul uint32_t flags; 433123474Swpaul{ 434123474Swpaul if (len == 0) 435123474Swpaul return; 436123474Swpaul free(vaddr, M_DEVBUF); 437123474Swpaul return; 438123474Swpaul} 439123474Swpaul 440123474Swpaul__stdcall static ndis_status 441123474Swpaulndis_setattr_ex(adapter_handle, adapter_ctx, hangsecs, 442123474Swpaul flags, iftype) 443123474Swpaul ndis_handle adapter_handle; 444123474Swpaul ndis_handle adapter_ctx; 445123474Swpaul uint32_t hangsecs; 446123474Swpaul uint32_t flags; 447123474Swpaul ndis_interface_type iftype; 448123474Swpaul{ 449123474Swpaul ndis_miniport_block *block; 450123474Swpaul 451123474Swpaul /* 452123474Swpaul * Save the adapter context, we need it for calling 453123474Swpaul * the driver's internal functions. 454123474Swpaul */ 455123474Swpaul block = (ndis_miniport_block *)adapter_handle; 456123474Swpaul block->nmb_miniportadapterctx = adapter_ctx; 457123474Swpaul block->nmb_checkforhangsecs = hangsecs; 458123474Swpaul 459123474Swpaul return(NDIS_STATUS_SUCCESS); 460123474Swpaul} 461123474Swpaul 462123474Swpaul__stdcall static void 463123474Swpaulndis_open_cfg(status, cfg, wrapctx) 464123474Swpaul ndis_status *status; 465123474Swpaul ndis_handle *cfg; 466123474Swpaul ndis_handle wrapctx; 467123474Swpaul{ 468123474Swpaul *cfg = wrapctx; 469123474Swpaul *status = NDIS_STATUS_SUCCESS; 470123474Swpaul return; 471123474Swpaul} 472123474Swpaul 473123526Swpaul__stdcall static void 474123526Swpaulndis_open_cfgbyname(status, cfg, subkey, subhandle) 475123526Swpaul ndis_status *status; 476123526Swpaul ndis_handle cfg; 477123526Swpaul ndis_unicode_string *subkey; 478123526Swpaul ndis_handle *subhandle; 479123526Swpaul{ 480123526Swpaul *subhandle = cfg; 481123526Swpaul *status = NDIS_STATUS_SUCCESS; 482123526Swpaul return; 483123526Swpaul} 484123526Swpaul 485123526Swpaul__stdcall static void 486123526Swpaulndis_open_cfgbyidx(status, cfg, idx, subkey, subhandle) 487123526Swpaul ndis_status *status; 488123526Swpaul ndis_handle cfg; 489123526Swpaul uint32_t idx; 490123526Swpaul ndis_unicode_string *subkey; 491123526Swpaul ndis_handle *subhandle; 492123526Swpaul{ 493123526Swpaul *status = NDIS_STATUS_FAILURE; 494123526Swpaul return; 495123526Swpaul} 496123526Swpaul 497123474Swpaulstatic ndis_status 498123474Swpaulndis_encode_parm(block, oid, type, parm) 499123474Swpaul ndis_miniport_block *block; 500123474Swpaul struct sysctl_oid *oid; 501123474Swpaul ndis_parm_type type; 502123474Swpaul ndis_config_parm **parm; 503123474Swpaul{ 504123474Swpaul uint16_t *unicode; 505123474Swpaul ndis_unicode_string *ustr; 506123474Swpaul 507123474Swpaul unicode = (uint16_t *)&block->nmb_dummybuf; 508123474Swpaul 509123474Swpaul switch(type) { 510123474Swpaul case ndis_parm_string: 511123474Swpaul ndis_ascii_to_unicode((char *)oid->oid_arg1, &unicode); 512123474Swpaul (*parm)->ncp_type = ndis_parm_string; 513123474Swpaul ustr = &(*parm)->ncp_parmdata.ncp_stringdata; 514123474Swpaul ustr->nus_len = strlen((char *)oid->oid_arg1) * 2; 515123474Swpaul ustr->nus_buf = unicode; 516123474Swpaul break; 517123474Swpaul case ndis_parm_int: 518123474Swpaul (*parm)->ncp_type = ndis_parm_int; 519123474Swpaul (*parm)->ncp_parmdata.ncp_intdata = 520123474Swpaul strtol((char *)oid->oid_arg1, NULL, 10); 521123474Swpaul break; 522123474Swpaul case ndis_parm_hexint: 523123474Swpaul (*parm)->ncp_type = ndis_parm_hexint; 524123474Swpaul (*parm)->ncp_parmdata.ncp_intdata = 525123474Swpaul strtoul((char *)oid->oid_arg1, NULL, 16); 526123474Swpaul break; 527123474Swpaul default: 528123474Swpaul return(NDIS_STATUS_FAILURE); 529123474Swpaul break; 530123474Swpaul } 531123474Swpaul 532123474Swpaul return(NDIS_STATUS_SUCCESS); 533123474Swpaul} 534123474Swpaul 535123474Swpaul__stdcall static void 536123474Swpaulndis_read_cfg(status, parm, cfg, key, type) 537123474Swpaul ndis_status *status; 538123474Swpaul ndis_config_parm **parm; 539123474Swpaul ndis_handle cfg; 540123474Swpaul ndis_unicode_string *key; 541123474Swpaul ndis_parm_type type; 542123474Swpaul{ 543123474Swpaul char *keystr = NULL; 544123474Swpaul uint16_t *unicode; 545123474Swpaul ndis_miniport_block *block; 546123474Swpaul struct ndis_softc *sc; 547123474Swpaul struct sysctl_oid *oidp; 548123474Swpaul struct sysctl_ctx_entry *e; 549123474Swpaul 550123474Swpaul block = (ndis_miniport_block *)cfg; 551123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 552123474Swpaul 553124100Swpaul if (key->nus_len == 0 || key->nus_buf == NULL) { 554124100Swpaul *status = NDIS_STATUS_FAILURE; 555124100Swpaul return; 556124100Swpaul } 557124100Swpaul 558123474Swpaul ndis_unicode_to_ascii(key->nus_buf, key->nus_len, &keystr); 559123474Swpaul 560123474Swpaul *parm = &block->nmb_replyparm; 561123474Swpaul bzero((char *)&block->nmb_replyparm, sizeof(ndis_config_parm)); 562123474Swpaul unicode = (uint16_t *)&block->nmb_dummybuf; 563123474Swpaul 564123474Swpaul /* 565123474Swpaul * See if registry key is already in a list of known keys 566123474Swpaul * included with the driver. 567123474Swpaul */ 568123474Swpaul TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 569123474Swpaul oidp = e->entry; 570123474Swpaul if (strcmp(oidp->oid_name, keystr) == 0) { 571123488Swpaul if (strcmp((char *)oidp->oid_arg1, "UNSET") == 0) { 572123488Swpaul free(keystr, M_DEVBUF); 573123488Swpaul *status = NDIS_STATUS_FAILURE; 574123488Swpaul return; 575123488Swpaul } 576123474Swpaul *status = ndis_encode_parm(block, oidp, type, parm); 577123474Swpaul free(keystr, M_DEVBUF); 578123474Swpaul return; 579123474Swpaul } 580123474Swpaul } 581123474Swpaul 582123474Swpaul /* 583123474Swpaul * If the key didn't match, add it to the list of dynamically 584123474Swpaul * created ones. Sometimes, drivers refer to registry keys 585123474Swpaul * that aren't documented in their .INF files. These keys 586123474Swpaul * are supposed to be created by some sort of utility or 587123474Swpaul * control panel snap-in that comes with the driver software. 588123474Swpaul * Sometimes it's useful to be able to manipulate these. 589123474Swpaul * If the driver requests the key in the form of a string, 590123474Swpaul * make its default value an empty string, otherwise default 591123474Swpaul * it to "0". 592123474Swpaul */ 593123474Swpaul 594123474Swpaul if (type == ndis_parm_int || type == ndis_parm_hexint) 595123488Swpaul ndis_add_sysctl(sc, keystr, "(dynamic integer key)", 596123488Swpaul "UNSET", CTLFLAG_RW); 597123474Swpaul else 598123488Swpaul ndis_add_sysctl(sc, keystr, "(dynamic string key)", 599123488Swpaul "UNSET", CTLFLAG_RW); 600123474Swpaul 601123474Swpaul free(keystr, M_DEVBUF); 602123474Swpaul *status = NDIS_STATUS_FAILURE; 603123474Swpaul return; 604123474Swpaul} 605123474Swpaul 606123526Swpaulstatic ndis_status 607123526Swpaulndis_decode_parm(block, parm, val) 608123526Swpaul ndis_miniport_block *block; 609123526Swpaul ndis_config_parm *parm; 610123526Swpaul char *val; 611123526Swpaul{ 612123526Swpaul ndis_unicode_string *ustr; 613124697Swpaul char *astr = NULL; 614123526Swpaul 615123526Swpaul switch(parm->ncp_type) { 616123526Swpaul case ndis_parm_string: 617123526Swpaul ustr = &parm->ncp_parmdata.ncp_stringdata; 618124697Swpaul ndis_unicode_to_ascii(ustr->nus_buf, ustr->nus_len, &astr); 619124697Swpaul bcopy(astr, val, 254); 620124697Swpaul free(astr, M_DEVBUF); 621123526Swpaul break; 622123526Swpaul case ndis_parm_int: 623124697Swpaul sprintf(val, "%d", parm->ncp_parmdata.ncp_intdata); 624123526Swpaul break; 625123526Swpaul case ndis_parm_hexint: 626123526Swpaul sprintf(val, "%xu", parm->ncp_parmdata.ncp_intdata); 627123526Swpaul break; 628123526Swpaul default: 629123526Swpaul return(NDIS_STATUS_FAILURE); 630123526Swpaul break; 631123526Swpaul } 632123526Swpaul return(NDIS_STATUS_SUCCESS); 633123526Swpaul} 634123526Swpaul 635123474Swpaul__stdcall static void 636123526Swpaulndis_write_cfg(status, cfg, key, parm) 637123526Swpaul ndis_status *status; 638123526Swpaul ndis_handle cfg; 639123526Swpaul ndis_unicode_string *key; 640123526Swpaul ndis_config_parm *parm; 641123526Swpaul{ 642123526Swpaul char *keystr = NULL; 643123526Swpaul ndis_miniport_block *block; 644123526Swpaul struct ndis_softc *sc; 645123526Swpaul struct sysctl_oid *oidp; 646123526Swpaul struct sysctl_ctx_entry *e; 647123526Swpaul char val[256]; 648123526Swpaul 649123526Swpaul block = (ndis_miniport_block *)cfg; 650123526Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 651123526Swpaul 652123526Swpaul ndis_unicode_to_ascii(key->nus_buf, key->nus_len, &keystr); 653123526Swpaul 654123526Swpaul /* Decode the parameter into a string. */ 655124697Swpaul bzero(val, sizeof(val)); 656123526Swpaul *status = ndis_decode_parm(block, parm, val); 657123526Swpaul if (*status != NDIS_STATUS_SUCCESS) { 658123526Swpaul free(keystr, M_DEVBUF); 659123526Swpaul return; 660123526Swpaul } 661123526Swpaul 662123526Swpaul /* See if the key already exists. */ 663123526Swpaul 664123526Swpaul TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 665123526Swpaul oidp = e->entry; 666123526Swpaul if (strcmp(oidp->oid_name, keystr) == 0) { 667123526Swpaul /* Found it, set the value. */ 668123526Swpaul strcpy((char *)oidp->oid_arg1, val); 669123526Swpaul free(keystr, M_DEVBUF); 670123526Swpaul return; 671123526Swpaul } 672123526Swpaul } 673123526Swpaul 674123526Swpaul /* Not found, add a new key with the specified value. */ 675123526Swpaul ndis_add_sysctl(sc, keystr, "(dynamically set key)", 676123526Swpaul val, CTLFLAG_RW); 677123526Swpaul 678123526Swpaul free(keystr, M_DEVBUF); 679123526Swpaul *status = NDIS_STATUS_SUCCESS; 680123526Swpaul return; 681123526Swpaul} 682123526Swpaul 683123526Swpaul__stdcall static void 684123474Swpaulndis_close_cfg(cfg) 685123474Swpaul ndis_handle cfg; 686123474Swpaul{ 687123474Swpaul return; 688123474Swpaul} 689123474Swpaul 690123474Swpaul__stdcall static void 691123474Swpaulndis_create_lock(lock) 692123474Swpaul ndis_spin_lock *lock; 693123474Swpaul{ 694124409Swpaul lock->nsl_spinlock = (ndis_kspin_lock)mtx_pool_alloc(ndis_mtxpool); 695123474Swpaul return; 696123474Swpaul} 697123474Swpaul 698123474Swpaul__stdcall static void 699123474Swpaulndis_destroy_lock(lock) 700123474Swpaul ndis_spin_lock *lock; 701123474Swpaul{ 702124409Swpaul /* We use a mutex pool, so this is a no-op. */ 703123474Swpaul return; 704123474Swpaul} 705123474Swpaul 706123474Swpaul__stdcall static void 707123474Swpaulndis_lock(lock) 708123474Swpaul ndis_spin_lock *lock; 709123474Swpaul{ 710124409Swpaul mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 711123474Swpaul return; 712123474Swpaul} 713123474Swpaul 714123474Swpaul__stdcall static void 715123474Swpaulndis_unlock(lock) 716123474Swpaul ndis_spin_lock *lock; 717123474Swpaul{ 718124409Swpaul mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 719123474Swpaul return; 720123474Swpaul} 721123474Swpaul 722123474Swpaul__stdcall static uint32_t 723123474Swpaulndis_read_pci(adapter, slot, offset, buf, len) 724123474Swpaul ndis_handle adapter; 725123474Swpaul uint32_t slot; 726123474Swpaul uint32_t offset; 727123474Swpaul void *buf; 728123474Swpaul uint32_t len; 729123474Swpaul{ 730123474Swpaul ndis_miniport_block *block; 731123474Swpaul int i; 732123474Swpaul char *dest; 733123474Swpaul 734123474Swpaul block = (ndis_miniport_block *)adapter; 735123474Swpaul dest = buf; 736123474Swpaul if (block == NULL || block->nmb_dev == NULL) 737123474Swpaul return(0); 738123474Swpaul 739123474Swpaul for (i = 0; i < len; i++) 740123474Swpaul dest[i] = pci_read_config(block->nmb_dev, i + offset, 1); 741123474Swpaul 742123474Swpaul return(len); 743123474Swpaul} 744123474Swpaul 745123474Swpaul__stdcall static uint32_t 746123474Swpaulndis_write_pci(adapter, slot, offset, buf, len) 747123474Swpaul ndis_handle adapter; 748123474Swpaul uint32_t slot; 749123474Swpaul uint32_t offset; 750123474Swpaul void *buf; 751123474Swpaul uint32_t len; 752123474Swpaul{ 753123474Swpaul ndis_miniport_block *block; 754123474Swpaul int i; 755123474Swpaul char *dest; 756123474Swpaul 757123474Swpaul block = (ndis_miniport_block *)adapter; 758123474Swpaul dest = buf; 759123474Swpaul 760123474Swpaul if (block == NULL || block->nmb_dev == NULL) 761123474Swpaul return(0); 762123474Swpaul 763123474Swpaul for (i = 0; i < len; i++) 764123474Swpaul pci_write_config(block->nmb_dev, i + offset, dest[i], 1); 765123474Swpaul 766123474Swpaul return(len); 767123474Swpaul} 768123474Swpaul 769123474Swpaul/* 770123474Swpaul * The errorlog routine uses a variable argument list, so we 771123474Swpaul * have to declare it this way. 772123474Swpaul */ 773124228Swpaul#define ERRMSGLEN 512 774123474Swpaulstatic void 775123474Swpaulndis_syslog(ndis_handle adapter, ndis_error_code code, 776123474Swpaul uint32_t numerrors, ...) 777123474Swpaul{ 778123474Swpaul ndis_miniport_block *block; 779123474Swpaul va_list ap; 780124173Swpaul int i, error; 781124173Swpaul char *str = NULL, *ustr = NULL; 782124173Swpaul uint16_t flags; 783124228Swpaul char msgbuf[ERRMSGLEN]; 784123474Swpaul 785123474Swpaul block = (ndis_miniport_block *)adapter; 786123474Swpaul 787124173Swpaul error = pe_get_message(block->nmb_img, code, &str, &i, &flags); 788124173Swpaul if (error == 0 && flags & MESSAGE_RESOURCE_UNICODE) { 789124228Swpaul ustr = msgbuf; 790124228Swpaul ndis_unicode_to_ascii((uint16_t *)str, 791124228Swpaul ((i / 2)) > (ERRMSGLEN - 1) ? ERRMSGLEN : i, &ustr); 792124173Swpaul str = ustr; 793124173Swpaul } 794124165Swpaul device_printf (block->nmb_dev, "NDIS ERROR: %x (%s)\n", code, 795124165Swpaul str == NULL ? "unknown error" : str); 796124060Swpaul device_printf (block->nmb_dev, "NDIS NUMERRORS: %x\n", numerrors); 797123474Swpaul 798123474Swpaul va_start(ap, numerrors); 799123474Swpaul for (i = 0; i < numerrors; i++) 800124060Swpaul device_printf (block->nmb_dev, "argptr: %p\n", 801124060Swpaul va_arg(ap, void *)); 802123474Swpaul va_end(ap); 803123474Swpaul 804123474Swpaul return; 805123474Swpaul} 806123474Swpaul 807123474Swpaulstatic void 808123474Swpaulndis_map_cb(arg, segs, nseg, error) 809123474Swpaul void *arg; 810123474Swpaul bus_dma_segment_t *segs; 811123474Swpaul int nseg; 812123474Swpaul int error; 813123474Swpaul{ 814123474Swpaul struct ndis_map_arg *ctx; 815123474Swpaul int i; 816123474Swpaul 817123474Swpaul if (error) 818123474Swpaul return; 819123474Swpaul 820123474Swpaul ctx = arg; 821123474Swpaul 822123474Swpaul for (i = 0; i < nseg; i++) { 823123474Swpaul ctx->nma_fraglist[i].npu_physaddr.np_quad = segs[i].ds_addr; 824123474Swpaul ctx->nma_fraglist[i].npu_len = segs[i].ds_len; 825123474Swpaul } 826123474Swpaul 827123474Swpaul ctx->nma_cnt = nseg; 828123474Swpaul 829123474Swpaul return; 830123474Swpaul} 831123474Swpaul 832123474Swpaul__stdcall static void 833123474Swpaulndis_vtophys_load(adapter, buf, mapreg, writedev, addrarray, arraysize) 834123474Swpaul ndis_handle adapter; 835123474Swpaul ndis_buffer *buf; 836123474Swpaul uint32_t mapreg; 837123474Swpaul uint8_t writedev; 838123474Swpaul ndis_paddr_unit *addrarray; 839123474Swpaul uint32_t *arraysize; 840123474Swpaul{ 841123474Swpaul ndis_miniport_block *block; 842123474Swpaul struct ndis_softc *sc; 843123474Swpaul struct ndis_map_arg nma; 844123474Swpaul bus_dmamap_t map; 845123474Swpaul int error; 846123474Swpaul 847123474Swpaul if (adapter == NULL) 848123474Swpaul return; 849123474Swpaul 850123474Swpaul block = (ndis_miniport_block *)adapter; 851123474Swpaul sc = (struct ndis_softc *)(block->nmb_ifp); 852123474Swpaul 853123474Swpaul if (mapreg > sc->ndis_mmapcnt) 854123474Swpaul return; 855123474Swpaul 856123474Swpaul map = sc->ndis_mmaps[mapreg]; 857123474Swpaul nma.nma_fraglist = addrarray; 858123474Swpaul 859123474Swpaul error = bus_dmamap_load(sc->ndis_mtag, map, 860123757Swpaul MDL_VA(buf), buf->nb_bytecount, ndis_map_cb, 861123474Swpaul (void *)&nma, BUS_DMA_NOWAIT); 862123474Swpaul 863123474Swpaul if (error) 864123474Swpaul return; 865123474Swpaul 866123474Swpaul bus_dmamap_sync(sc->ndis_mtag, map, 867123474Swpaul writedev ? BUS_DMASYNC_PREWRITE : BUS_DMASYNC_PREREAD); 868123474Swpaul 869123474Swpaul *arraysize = nma.nma_cnt; 870123474Swpaul 871123474Swpaul return; 872123474Swpaul} 873123474Swpaul 874123474Swpaul__stdcall static void 875123474Swpaulndis_vtophys_unload(adapter, buf, mapreg) 876123474Swpaul ndis_handle adapter; 877123474Swpaul ndis_buffer *buf; 878123474Swpaul uint32_t mapreg; 879123474Swpaul{ 880123474Swpaul ndis_miniport_block *block; 881123474Swpaul struct ndis_softc *sc; 882123474Swpaul bus_dmamap_t map; 883123474Swpaul 884123474Swpaul if (adapter == NULL) 885123474Swpaul return; 886123474Swpaul 887123474Swpaul block = (ndis_miniport_block *)adapter; 888123474Swpaul sc = (struct ndis_softc *)(block->nmb_ifp); 889123474Swpaul 890123474Swpaul if (mapreg > sc->ndis_mmapcnt) 891123474Swpaul return; 892123474Swpaul 893123474Swpaul map = sc->ndis_mmaps[mapreg]; 894123474Swpaul 895123474Swpaul bus_dmamap_sync(sc->ndis_mtag, map, 896123474Swpaul BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); 897123474Swpaul 898123474Swpaul bus_dmamap_unload(sc->ndis_mtag, map); 899123474Swpaul 900123474Swpaul return; 901123474Swpaul} 902123474Swpaul 903125057Swpaul/* 904125057Swpaul * This is an older pre-miniport timer init routine which doesn't 905125057Swpaul * accept a miniport context handle. The function context (ctx) 906125057Swpaul * is supposed to be a pointer to the adapter handle, which should 907125057Swpaul * have been handed to us via NdisSetAttributesEx(). We use this 908125057Swpaul * function context to track down the corresponding ndis_miniport_block 909125057Swpaul * structure. It's vital that we track down the miniport block structure, 910125057Swpaul * so if we can't do it, we panic. Note that we also play some games 911125057Swpaul * here by treating ndis_timer and ndis_miniport_timer as the same 912125057Swpaul * thing. 913125057Swpaul */ 914125057Swpaul 915123474Swpaul__stdcall static void 916125057Swpaulndis_init_timer(timer, func, ctx) 917125057Swpaul ndis_timer *timer; 918125057Swpaul ndis_timer_function func; 919125057Swpaul void *ctx; 920125057Swpaul{ 921125057Swpaul struct ndis_timer_entry *ne = NULL; 922125057Swpaul ndis_miniport_block *block = NULL; 923125057Swpaul 924125057Swpaul TAILQ_FOREACH(block, &ndis_devhead, link) { 925125057Swpaul if (block->nmb_miniportadapterctx == ctx) 926125057Swpaul break; 927125057Swpaul } 928125057Swpaul 929125057Swpaul if (block->nmb_miniportadapterctx != ctx) 930125057Swpaul panic("NDIS driver timer context didn't " 931125057Swpaul "match any adapter contexts"); 932125057Swpaul 933125057Swpaul ne = malloc(sizeof(struct ndis_timer_entry), M_DEVBUF, M_NOWAIT); 934125057Swpaul callout_init(&ne->nte_ch, CALLOUT_MPSAFE); 935125057Swpaul TAILQ_INSERT_TAIL(&block->nmb_timerlist, ne, link); 936125057Swpaul ne->nte_timer = (ndis_miniport_timer *)timer; 937125057Swpaul 938125057Swpaul timer->nt_timer.nk_header.dh_sigstate = TRUE; 939125057Swpaul timer->nt_dpc.nk_sysarg1 = &ne->nte_ch; 940125057Swpaul timer->nt_dpc.nk_deferedfunc = (ndis_kdpc_func)func; 941125057Swpaul timer->nt_dpc.nk_deferredctx = ctx; 942125057Swpaul 943125057Swpaul return; 944125057Swpaul} 945125057Swpaul 946125057Swpaul__stdcall static void 947123474Swpaulndis_create_timer(timer, handle, func, ctx) 948123474Swpaul ndis_miniport_timer *timer; 949123474Swpaul ndis_handle *handle; 950123474Swpaul ndis_timer_function func; 951123474Swpaul void *ctx; 952123474Swpaul{ 953123821Swpaul struct ndis_timer_entry *ne = NULL; 954123821Swpaul ndis_miniport_block *block; 955123821Swpaul block = (ndis_miniport_block *)handle; 956123474Swpaul 957123821Swpaul ne = malloc(sizeof(struct ndis_timer_entry), M_DEVBUF, M_NOWAIT); 958123832Swpaul callout_init(&ne->nte_ch, CALLOUT_MPSAFE); 959123821Swpaul TAILQ_INSERT_TAIL(&block->nmb_timerlist, ne, link); 960123821Swpaul ne->nte_timer = timer; 961123821Swpaul 962123821Swpaul timer->nmt_ktimer.nk_header.dh_sigstate = TRUE; 963125057Swpaul timer->nmt_dpc.nk_sysarg1 = &ne->nte_ch; 964125057Swpaul timer->nmt_dpc.nk_deferedfunc = (ndis_kdpc_func)func; 965125057Swpaul timer->nmt_dpc.nk_deferredctx = ctx; 966123474Swpaul 967123474Swpaul return; 968123474Swpaul} 969123474Swpaul 970123474Swpaul/* 971123474Swpaul * The driver's timer callout is __stdcall function, so we need this 972123474Swpaul * intermediate step. 973123474Swpaul */ 974123474Swpaul 975123474Swpaulstatic void 976123474Swpaulndis_timercall(arg) 977123474Swpaul void *arg; 978123474Swpaul{ 979123474Swpaul ndis_miniport_timer *timer; 980123474Swpaul __stdcall ndis_timer_function timerfunc; 981123474Swpaul 982123474Swpaul timer = arg; 983123474Swpaul 984123821Swpaul timer->nmt_ktimer.nk_header.dh_sigstate = FALSE; 985125057Swpaul timerfunc = (ndis_timer_function)timer->nmt_dpc.nk_deferedfunc; 986125057Swpaul timerfunc(NULL, timer->nmt_dpc.nk_deferredctx, NULL, NULL); 987123474Swpaul 988123474Swpaul return; 989123474Swpaul} 990123474Swpaul 991123474Swpaul/* 992123474Swpaul * Windows specifies timeouts in milliseconds. We specify timeouts 993123474Swpaul * in hz. Trying to compute a tenth of a second based on hz is tricky. 994123474Swpaul * so we approximate. Note that we abuse the dpc portion of the 995123474Swpaul * miniport timer structure to hold the UNIX callout handle. 996123474Swpaul */ 997123474Swpaul__stdcall static void 998123474Swpaulndis_set_timer(timer, msecs) 999123474Swpaul ndis_miniport_timer *timer; 1000123474Swpaul uint32_t msecs; 1001123474Swpaul{ 1002123832Swpaul struct callout *ch; 1003123474Swpaul struct timeval tv; 1004123474Swpaul 1005123474Swpaul tv.tv_sec = 0; 1006123474Swpaul tv.tv_usec = msecs * 1000; 1007123474Swpaul 1008125057Swpaul ch = timer->nmt_dpc.nk_sysarg1; 1009123474Swpaul timer->nmt_dpc.nk_sysarg2 = ndis_timercall; 1010123821Swpaul timer->nmt_ktimer.nk_header.dh_sigstate = TRUE; 1011123832Swpaul callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer); 1012123474Swpaul 1013123474Swpaul return; 1014123474Swpaul} 1015123474Swpaul 1016123474Swpaulstatic void 1017123474Swpaulndis_tick(arg) 1018123474Swpaul void *arg; 1019123474Swpaul{ 1020123474Swpaul ndis_miniport_timer *timer; 1021123832Swpaul struct callout *ch; 1022123474Swpaul __stdcall ndis_timer_function timerfunc; 1023123474Swpaul struct timeval tv; 1024123474Swpaul 1025123474Swpaul timer = arg; 1026123474Swpaul 1027123821Swpaul timer->nmt_ktimer.nk_header.dh_sigstate = FALSE; 1028125057Swpaul timerfunc = (ndis_timer_function)timer->nmt_dpc.nk_deferedfunc; 1029125057Swpaul timerfunc(NULL, timer->nmt_dpc.nk_deferredctx, NULL, NULL); 1030123474Swpaul 1031123474Swpaul /* Automatically reload timer. */ 1032123474Swpaul 1033123474Swpaul tv.tv_sec = 0; 1034123474Swpaul tv.tv_usec = timer->nmt_ktimer.nk_period * 1000; 1035125057Swpaul ch = timer->nmt_dpc.nk_sysarg1; 1036123821Swpaul timer->nmt_ktimer.nk_header.dh_sigstate = TRUE; 1037123474Swpaul timer->nmt_dpc.nk_sysarg2 = ndis_tick; 1038123832Swpaul callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer); 1039123474Swpaul 1040123474Swpaul return; 1041123474Swpaul} 1042123474Swpaul 1043123474Swpaul__stdcall static void 1044123474Swpaulndis_set_periodic_timer(timer, msecs) 1045123474Swpaul ndis_miniport_timer *timer; 1046123474Swpaul uint32_t msecs; 1047123474Swpaul{ 1048123832Swpaul struct callout *ch; 1049123474Swpaul struct timeval tv; 1050123474Swpaul 1051123474Swpaul tv.tv_sec = 0; 1052123474Swpaul tv.tv_usec = msecs * 1000; 1053123474Swpaul 1054123474Swpaul timer->nmt_ktimer.nk_period = msecs; 1055125057Swpaul ch = timer->nmt_dpc.nk_sysarg1; 1056123474Swpaul timer->nmt_dpc.nk_sysarg2 = ndis_tick; 1057123821Swpaul timer->nmt_ktimer.nk_header.dh_sigstate = TRUE; 1058123832Swpaul callout_reset(ch, tvtohz(&tv), timer->nmt_dpc.nk_sysarg2, timer); 1059123474Swpaul 1060123474Swpaul return; 1061123474Swpaul} 1062123474Swpaul 1063123474Swpaul__stdcall static void 1064123474Swpaulndis_cancel_timer(timer, cancelled) 1065123474Swpaul ndis_miniport_timer *timer; 1066123474Swpaul uint8_t *cancelled; 1067123474Swpaul{ 1068123832Swpaul struct callout *ch; 1069123474Swpaul 1070124097Swpaul if (timer == NULL) 1071124097Swpaul return; 1072125057Swpaul ch = timer->nmt_dpc.nk_sysarg1; 1073124097Swpaul if (ch == NULL) 1074124097Swpaul return; 1075123832Swpaul callout_stop(ch); 1076123821Swpaul *cancelled = timer->nmt_ktimer.nk_header.dh_sigstate; 1077123474Swpaul 1078123474Swpaul return; 1079123474Swpaul} 1080123474Swpaul 1081123474Swpaul__stdcall static void 1082123474Swpaulndis_query_resources(status, adapter, list, buflen) 1083123474Swpaul ndis_status *status; 1084123474Swpaul ndis_handle adapter; 1085123474Swpaul ndis_resource_list *list; 1086123474Swpaul uint32_t *buflen; 1087123474Swpaul{ 1088123474Swpaul ndis_miniport_block *block; 1089123474Swpaul struct ndis_softc *sc; 1090124094Swpaul int rsclen; 1091123474Swpaul 1092123474Swpaul block = (ndis_miniport_block *)adapter; 1093123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 1094124094Swpaul 1095124094Swpaul rsclen = sizeof(ndis_resource_list) + 1096123474Swpaul (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)); 1097124094Swpaul if (*buflen < rsclen) { 1098124094Swpaul *buflen = rsclen; 1099124094Swpaul *status = NDIS_STATUS_INVALID_LENGTH; 1100124094Swpaul return; 1101124094Swpaul } 1102123474Swpaul 1103123474Swpaul bcopy((char *)block->nmb_rlist, (char *)list, *buflen); 1104123474Swpaul *status = NDIS_STATUS_SUCCESS; 1105123474Swpaul return; 1106123474Swpaul} 1107123474Swpaul 1108123474Swpaul__stdcall static ndis_status 1109123474Swpaulndis_register_ioport(offset, adapter, port, numports) 1110123474Swpaul void **offset; 1111123474Swpaul ndis_handle adapter; 1112123474Swpaul uint32_t port; 1113123474Swpaul uint32_t numports; 1114123474Swpaul{ 1115123474Swpaul struct ndis_miniport_block *block; 1116123474Swpaul struct ndis_softc *sc; 1117123474Swpaul 1118123474Swpaul if (adapter == NULL) 1119123474Swpaul return(NDIS_STATUS_FAILURE); 1120123474Swpaul 1121123474Swpaul block = (ndis_miniport_block *)adapter; 1122123474Swpaul sc = (struct ndis_softc *)(block->nmb_ifp); 1123123474Swpaul 1124123474Swpaul if (sc->ndis_res_io == NULL) 1125123474Swpaul return(NDIS_STATUS_FAILURE); 1126123474Swpaul 1127124454Swpaul /* Don't let the device map more ports than we have. */ 1128124454Swpaul if (rman_get_size(sc->ndis_res_io) < numports) 1129123474Swpaul return(NDIS_STATUS_INVALID_LENGTH); 1130123474Swpaul 1131123474Swpaul *offset = (void *)rman_get_start(sc->ndis_res_io); 1132123474Swpaul 1133123474Swpaul return(NDIS_STATUS_SUCCESS); 1134123474Swpaul} 1135123474Swpaul 1136123474Swpaul__stdcall static void 1137123474Swpaulndis_deregister_ioport(adapter, port, numports, offset) 1138123474Swpaul ndis_handle adapter; 1139123474Swpaul uint32_t port; 1140123474Swpaul uint32_t numports; 1141123474Swpaul void *offset; 1142123474Swpaul{ 1143123474Swpaul return; 1144123474Swpaul} 1145123474Swpaul 1146123474Swpaul__stdcall static void 1147123474Swpaulndis_read_netaddr(status, addr, addrlen, adapter) 1148123474Swpaul ndis_status *status; 1149123474Swpaul void **addr; 1150123474Swpaul uint32_t *addrlen; 1151123474Swpaul ndis_handle adapter; 1152123474Swpaul{ 1153123474Swpaul struct ndis_softc *sc; 1154123474Swpaul ndis_miniport_block *block; 1155123474Swpaul uint8_t empty[] = { 0, 0, 0, 0, 0, 0 }; 1156123474Swpaul 1157123474Swpaul block = (ndis_miniport_block *)adapter; 1158123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 1159123474Swpaul 1160123474Swpaul if (bcmp(sc->arpcom.ac_enaddr, empty, ETHER_ADDR_LEN) == 0) 1161123474Swpaul *status = NDIS_STATUS_FAILURE; 1162123474Swpaul else { 1163123474Swpaul *addr = sc->arpcom.ac_enaddr; 1164123474Swpaul *addrlen = ETHER_ADDR_LEN; 1165123474Swpaul *status = NDIS_STATUS_SUCCESS; 1166123474Swpaul } 1167123474Swpaul 1168123474Swpaul return; 1169123474Swpaul} 1170123474Swpaul 1171123474Swpaul__stdcall static ndis_status 1172123848Swpaulndis_mapreg_cnt(bustype, cnt) 1173123848Swpaul uint32_t bustype; 1174123848Swpaul uint32_t *cnt; 1175123848Swpaul{ 1176124097Swpaul *cnt = 8192; 1177123848Swpaul return(NDIS_STATUS_SUCCESS); 1178123848Swpaul} 1179123848Swpaul 1180123848Swpaul__stdcall static ndis_status 1181123474Swpaulndis_alloc_mapreg(adapter, dmachannel, dmasize, physmapneeded, maxmap) 1182123474Swpaul ndis_handle adapter; 1183123474Swpaul uint32_t dmachannel; 1184123474Swpaul uint8_t dmasize; 1185123474Swpaul uint32_t physmapneeded; 1186123474Swpaul uint32_t maxmap; 1187123474Swpaul{ 1188123474Swpaul struct ndis_softc *sc; 1189123474Swpaul ndis_miniport_block *block; 1190123474Swpaul int error, i, nseg = NDIS_MAXSEG; 1191123474Swpaul 1192123474Swpaul block = (ndis_miniport_block *)adapter; 1193123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 1194123474Swpaul 1195123474Swpaul sc->ndis_mmaps = malloc(sizeof(bus_dmamap_t) * physmapneeded, 1196123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1197123474Swpaul 1198123474Swpaul if (sc->ndis_mmaps == NULL) 1199123474Swpaul return(NDIS_STATUS_RESOURCES); 1200123474Swpaul 1201123474Swpaul error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1202123474Swpaul BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1203123474Swpaul NULL, maxmap * nseg, nseg, maxmap, BUS_DMA_ALLOCNOW, 1204123474Swpaul NULL, NULL, &sc->ndis_mtag); 1205123474Swpaul 1206123474Swpaul if (error) { 1207123474Swpaul free(sc->ndis_mmaps, M_DEVBUF); 1208123474Swpaul return(NDIS_STATUS_RESOURCES); 1209123474Swpaul } 1210123474Swpaul 1211123474Swpaul for (i = 0; i < physmapneeded; i++) 1212123474Swpaul bus_dmamap_create(sc->ndis_mtag, 0, &sc->ndis_mmaps[i]); 1213123474Swpaul 1214123474Swpaul sc->ndis_mmapcnt = physmapneeded; 1215123474Swpaul 1216123474Swpaul return(NDIS_STATUS_SUCCESS); 1217123474Swpaul} 1218123474Swpaul 1219123474Swpaul__stdcall static void 1220123474Swpaulndis_free_mapreg(adapter) 1221123474Swpaul ndis_handle adapter; 1222123474Swpaul{ 1223123474Swpaul struct ndis_softc *sc; 1224123474Swpaul ndis_miniport_block *block; 1225123474Swpaul int i; 1226123474Swpaul 1227123474Swpaul block = (ndis_miniport_block *)adapter; 1228123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 1229123474Swpaul 1230123474Swpaul for (i = 0; i < sc->ndis_mmapcnt; i++) 1231123474Swpaul bus_dmamap_destroy(sc->ndis_mtag, sc->ndis_mmaps[i]); 1232123474Swpaul 1233123474Swpaul free(sc->ndis_mmaps, M_DEVBUF); 1234123474Swpaul 1235123474Swpaul bus_dma_tag_destroy(sc->ndis_mtag); 1236123474Swpaul 1237123474Swpaul return; 1238123474Swpaul} 1239123474Swpaul 1240123474Swpaulstatic void 1241123474Swpaulndis_mapshared_cb(arg, segs, nseg, error) 1242123474Swpaul void *arg; 1243123474Swpaul bus_dma_segment_t *segs; 1244123474Swpaul int nseg; 1245123474Swpaul int error; 1246123474Swpaul{ 1247123474Swpaul ndis_physaddr *p; 1248123474Swpaul 1249123474Swpaul if (error || nseg > 1) 1250123474Swpaul return; 1251123474Swpaul 1252123474Swpaul p = arg; 1253123474Swpaul 1254123474Swpaul p->np_quad = segs[0].ds_addr; 1255123474Swpaul 1256123474Swpaul return; 1257123474Swpaul} 1258123474Swpaul 1259123474Swpaul/* 1260123474Swpaul * This maps to bus_dmamem_alloc(). 1261123474Swpaul */ 1262123474Swpaul__stdcall static void 1263123474Swpaulndis_alloc_sharedmem(adapter, len, cached, vaddr, paddr) 1264123474Swpaul ndis_handle adapter; 1265123474Swpaul uint32_t len; 1266123474Swpaul uint8_t cached; 1267123474Swpaul void **vaddr; 1268123474Swpaul ndis_physaddr *paddr; 1269123474Swpaul{ 1270123474Swpaul ndis_miniport_block *block; 1271123474Swpaul struct ndis_softc *sc; 1272123474Swpaul struct ndis_shmem *sh; 1273123474Swpaul int error; 1274123474Swpaul 1275123474Swpaul if (adapter == NULL) 1276123474Swpaul return; 1277123474Swpaul 1278123474Swpaul block = (ndis_miniport_block *)adapter; 1279123474Swpaul sc = (struct ndis_softc *)(block->nmb_ifp); 1280123474Swpaul 1281123474Swpaul sh = malloc(sizeof(struct ndis_shmem), M_DEVBUF, M_NOWAIT|M_ZERO); 1282123474Swpaul if (sh == NULL) 1283123474Swpaul return; 1284123474Swpaul 1285123474Swpaul error = bus_dma_tag_create(sc->ndis_parent_tag, 64, 1286123474Swpaul 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1287123474Swpaul NULL, len, 1, len, BUS_DMA_ALLOCNOW, NULL, NULL, 1288123474Swpaul &sh->ndis_stag); 1289123474Swpaul 1290123474Swpaul if (error) { 1291123474Swpaul free(sh, M_DEVBUF); 1292123474Swpaul return; 1293123474Swpaul } 1294123474Swpaul 1295123474Swpaul error = bus_dmamem_alloc(sh->ndis_stag, vaddr, 1296123474Swpaul BUS_DMA_NOWAIT | BUS_DMA_ZERO, &sh->ndis_smap); 1297123474Swpaul 1298123474Swpaul if (error) { 1299123474Swpaul bus_dma_tag_destroy(sh->ndis_stag); 1300123474Swpaul free(sh, M_DEVBUF); 1301123474Swpaul return; 1302123474Swpaul } 1303123474Swpaul 1304123474Swpaul error = bus_dmamap_load(sh->ndis_stag, sh->ndis_smap, *vaddr, 1305123474Swpaul len, ndis_mapshared_cb, (void *)paddr, BUS_DMA_NOWAIT); 1306123474Swpaul 1307123474Swpaul if (error) { 1308123474Swpaul bus_dmamem_free(sh->ndis_stag, *vaddr, sh->ndis_smap); 1309123474Swpaul bus_dma_tag_destroy(sh->ndis_stag); 1310123474Swpaul free(sh, M_DEVBUF); 1311123474Swpaul return; 1312123474Swpaul } 1313123474Swpaul 1314123474Swpaul sh->ndis_saddr = *vaddr; 1315123474Swpaul sh->ndis_next = sc->ndis_shlist; 1316123474Swpaul sc->ndis_shlist = sh; 1317123474Swpaul 1318123474Swpaul return; 1319123474Swpaul} 1320123474Swpaul 1321123474Swpaul__stdcall static void 1322123474Swpaulndis_alloc_sharedmem_async(adapter, len, cached, ctx) 1323123474Swpaul ndis_handle adapter; 1324123474Swpaul uint32_t len; 1325123474Swpaul uint8_t cached; 1326123474Swpaul void *ctx; 1327123474Swpaul{ 1328123474Swpaul ndis_miniport_block *block; 1329123474Swpaul struct ndis_softc *sc; 1330123474Swpaul void *vaddr; 1331123474Swpaul ndis_physaddr paddr; 1332123474Swpaul __stdcall ndis_allocdone_handler donefunc; 1333123474Swpaul 1334123474Swpaul if (adapter == NULL) 1335123474Swpaul return; 1336123474Swpaul 1337123474Swpaul block = (ndis_miniport_block *)adapter; 1338123474Swpaul sc = (struct ndis_softc *)(block->nmb_ifp); 1339123474Swpaul donefunc = sc->ndis_chars.nmc_allocate_complete_func; 1340123474Swpaul 1341123474Swpaul ndis_alloc_sharedmem(adapter, len, cached, &vaddr, &paddr); 1342123474Swpaul donefunc(adapter, vaddr, &paddr, len, ctx); 1343123474Swpaul 1344123474Swpaul return; 1345123474Swpaul} 1346123474Swpaul 1347123474Swpaul__stdcall static void 1348123474Swpaulndis_free_sharedmem(adapter, len, cached, vaddr, paddr) 1349123474Swpaul ndis_handle adapter; 1350123474Swpaul uint32_t len; 1351123474Swpaul uint8_t cached; 1352123474Swpaul void *vaddr; 1353123474Swpaul ndis_physaddr paddr; 1354123474Swpaul{ 1355123474Swpaul ndis_miniport_block *block; 1356123474Swpaul struct ndis_softc *sc; 1357123474Swpaul struct ndis_shmem *sh, *prev; 1358123474Swpaul 1359123474Swpaul if (vaddr == NULL || adapter == NULL) 1360123474Swpaul return; 1361123474Swpaul 1362123474Swpaul block = (ndis_miniport_block *)adapter; 1363123474Swpaul sc = (struct ndis_softc *)(block->nmb_ifp); 1364123474Swpaul sh = prev = sc->ndis_shlist; 1365123474Swpaul 1366123474Swpaul while (sh) { 1367123474Swpaul if (sh->ndis_saddr == vaddr) 1368123474Swpaul break; 1369123474Swpaul prev = sh; 1370123474Swpaul sh = sh->ndis_next; 1371123474Swpaul } 1372123474Swpaul 1373123474Swpaul bus_dmamap_unload(sh->ndis_stag, sh->ndis_smap); 1374123474Swpaul bus_dmamem_free(sh->ndis_stag, vaddr, sh->ndis_smap); 1375123474Swpaul bus_dma_tag_destroy(sh->ndis_stag); 1376123474Swpaul 1377123474Swpaul if (sh == sc->ndis_shlist) 1378123474Swpaul sc->ndis_shlist = sh->ndis_next; 1379123474Swpaul else 1380123474Swpaul prev->ndis_next = sh->ndis_next; 1381123474Swpaul 1382123474Swpaul free(sh, M_DEVBUF); 1383123474Swpaul 1384123474Swpaul return; 1385123474Swpaul} 1386123474Swpaul 1387123474Swpaul__stdcall static ndis_status 1388123474Swpaulndis_map_iospace(vaddr, adapter, paddr, len) 1389123474Swpaul void **vaddr; 1390123474Swpaul ndis_handle adapter; 1391123474Swpaul ndis_physaddr paddr; 1392123474Swpaul uint32_t len; 1393123474Swpaul{ 1394123474Swpaul ndis_miniport_block *block; 1395123474Swpaul struct ndis_softc *sc; 1396123474Swpaul 1397123474Swpaul if (adapter == NULL) 1398123474Swpaul return(NDIS_STATUS_FAILURE); 1399123474Swpaul 1400123474Swpaul block = (ndis_miniport_block *)adapter; 1401123474Swpaul sc = (struct ndis_softc *)(block->nmb_ifp); 1402123474Swpaul 1403123474Swpaul if (sc->ndis_res_mem == NULL) 1404123474Swpaul return(NDIS_STATUS_FAILURE); 1405123474Swpaul 1406123474Swpaul *vaddr = (void *)rman_get_virtual(sc->ndis_res_mem); 1407123474Swpaul 1408123474Swpaul return(NDIS_STATUS_SUCCESS); 1409123474Swpaul} 1410123474Swpaul 1411123474Swpaul__stdcall static void 1412123474Swpaulndis_unmap_iospace(adapter, vaddr, len) 1413123474Swpaul ndis_handle adapter; 1414123474Swpaul void *vaddr; 1415123474Swpaul uint32_t len; 1416123474Swpaul{ 1417123474Swpaul return; 1418123474Swpaul} 1419123474Swpaul 1420123474Swpaul__stdcall static uint32_t 1421123474Swpaulndis_cachefill(void) 1422123474Swpaul{ 1423123474Swpaul return(128); 1424123474Swpaul} 1425123474Swpaul 1426123474Swpaul__stdcall static uint32_t 1427123474Swpaulndis_dma_align(handle) 1428123474Swpaul ndis_handle handle; 1429123474Swpaul{ 1430123474Swpaul return(128); 1431123474Swpaul} 1432123474Swpaul 1433123474Swpaul/* 1434123474Swpaul * NDIS has two methods for dealing with NICs that support DMA. 1435123474Swpaul * One is to just pass packets to the driver and let it call 1436123474Swpaul * NdisMStartBufferPhysicalMapping() to map each buffer in the packet 1437123474Swpaul * all by itself, and the other is to let the NDIS library handle the 1438123474Swpaul * buffer mapping internally, and hand the driver an already populated 1439123474Swpaul * scatter/gather fragment list. If the driver calls 1440123474Swpaul * NdisMInitializeScatterGatherDma(), it wants to use the latter 1441123474Swpaul * method. 1442123474Swpaul */ 1443123474Swpaul 1444123474Swpaul__stdcall static ndis_status 1445123474Swpaulndis_init_sc_dma(adapter, is64, maxphysmap) 1446123474Swpaul ndis_handle adapter; 1447123474Swpaul uint8_t is64; 1448123474Swpaul uint32_t maxphysmap; 1449123474Swpaul{ 1450123474Swpaul struct ndis_softc *sc; 1451123474Swpaul ndis_miniport_block *block; 1452123474Swpaul int error; 1453123474Swpaul 1454123474Swpaul if (adapter == NULL) 1455123474Swpaul return(NDIS_STATUS_FAILURE); 1456123474Swpaul block = (ndis_miniport_block *)adapter; 1457123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 1458123474Swpaul 1459123474Swpaul /* Don't do this twice. */ 1460123474Swpaul if (sc->ndis_sc == 1) 1461123474Swpaul return(NDIS_STATUS_SUCCESS); 1462123474Swpaul 1463123474Swpaul error = bus_dma_tag_create(sc->ndis_parent_tag, ETHER_ALIGN, 0, 1464123474Swpaul BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 1465123474Swpaul MCLBYTES * NDIS_MAXSEG, NDIS_MAXSEG, MCLBYTES, BUS_DMA_ALLOCNOW, 1466123474Swpaul NULL, NULL, &sc->ndis_ttag); 1467123474Swpaul 1468123474Swpaul sc->ndis_sc = 1; 1469123474Swpaul 1470123474Swpaul return(NDIS_STATUS_SUCCESS); 1471123474Swpaul} 1472123474Swpaul 1473123474Swpaul__stdcall static void 1474123474Swpaulndis_alloc_packetpool(status, pool, descnum, protrsvdlen) 1475123474Swpaul ndis_status *status; 1476123474Swpaul ndis_handle *pool; 1477123474Swpaul uint32_t descnum; 1478123474Swpaul uint32_t protrsvdlen; 1479123474Swpaul{ 1480123474Swpaul ndis_packet *cur; 1481123474Swpaul int i; 1482123474Swpaul 1483124116Swpaul *pool = malloc(sizeof(ndis_packet) * 1484124116Swpaul ((descnum + NDIS_POOL_EXTRA) + 1), 1485123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1486123474Swpaul 1487123474Swpaul if (pool == NULL) { 1488123474Swpaul *status = NDIS_STATUS_RESOURCES; 1489123474Swpaul return; 1490123474Swpaul } 1491123474Swpaul 1492123474Swpaul cur = (ndis_packet *)*pool; 1493123474Swpaul cur->np_private.npp_flags = 0x1; /* mark the head of the list */ 1494124116Swpaul for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) { 1495123474Swpaul cur->np_private.npp_head = (ndis_handle)(cur + 1); 1496123474Swpaul cur++; 1497123474Swpaul } 1498123474Swpaul 1499123474Swpaul *status = NDIS_STATUS_SUCCESS; 1500123474Swpaul return; 1501123474Swpaul} 1502123474Swpaul 1503123474Swpaul__stdcall static void 1504123474Swpaulndis_ex_alloc_packetpool(status, pool, descnum, oflowdescnum, protrsvdlen) 1505123474Swpaul ndis_status *status; 1506123474Swpaul ndis_handle *pool; 1507123474Swpaul uint32_t descnum; 1508123474Swpaul uint32_t oflowdescnum; 1509123474Swpaul uint32_t protrsvdlen; 1510123474Swpaul{ 1511123474Swpaul return(ndis_alloc_packetpool(status, pool, 1512123474Swpaul descnum + oflowdescnum, protrsvdlen)); 1513123474Swpaul} 1514123474Swpaul 1515123474Swpaul__stdcall static uint32_t 1516123474Swpaulndis_packetpool_use(pool) 1517123474Swpaul ndis_handle pool; 1518123474Swpaul{ 1519123474Swpaul ndis_packet *head; 1520123474Swpaul 1521123474Swpaul head = (ndis_packet *)pool; 1522123474Swpaul 1523123474Swpaul return(head->np_private.npp_count); 1524123474Swpaul} 1525123474Swpaul 1526123474Swpaul__stdcall static void 1527123474Swpaulndis_free_packetpool(pool) 1528123474Swpaul ndis_handle pool; 1529123474Swpaul{ 1530123474Swpaul free(pool, M_DEVBUF); 1531123474Swpaul return; 1532123474Swpaul} 1533123474Swpaul 1534123474Swpaul__stdcall static void 1535123474Swpaulndis_alloc_packet(status, packet, pool) 1536123474Swpaul ndis_status *status; 1537123474Swpaul ndis_packet **packet; 1538123474Swpaul ndis_handle pool; 1539123474Swpaul{ 1540123474Swpaul ndis_packet *head, *pkt; 1541123474Swpaul 1542123474Swpaul head = (ndis_packet *)pool; 1543123474Swpaul 1544123474Swpaul if (head->np_private.npp_flags != 0x1) { 1545123474Swpaul *status = NDIS_STATUS_FAILURE; 1546123474Swpaul return; 1547123474Swpaul } 1548123474Swpaul 1549123474Swpaul pkt = (ndis_packet *)head->np_private.npp_head; 1550123474Swpaul 1551123474Swpaul if (pkt == NULL) { 1552123474Swpaul *status = NDIS_STATUS_RESOURCES; 1553123474Swpaul return; 1554123474Swpaul } 1555123474Swpaul 1556123474Swpaul head->np_private.npp_head = pkt->np_private.npp_head; 1557123474Swpaul 1558123474Swpaul pkt->np_private.npp_head = pkt->np_private.npp_tail = NULL; 1559123474Swpaul /* Save pointer to the pool. */ 1560123474Swpaul pkt->np_private.npp_pool = head; 1561123474Swpaul 1562123474Swpaul /* Set the oob offset pointer. Lots of things expect this. */ 1563123474Swpaul pkt->np_private.npp_packetooboffset = 1564123474Swpaul offsetof(ndis_packet, np_oob); 1565123474Swpaul 1566124278Swpaul /* 1567124278Swpaul * We must initialize the packet flags correctly in order 1568124278Swpaul * for the NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO() and 1569124278Swpaul * NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO() to work correctly. 1570124278Swpaul */ 1571124278Swpaul pkt->np_private.npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 1572124278Swpaul 1573123474Swpaul *packet = pkt; 1574123474Swpaul 1575123474Swpaul head->np_private.npp_count++; 1576123474Swpaul *status = NDIS_STATUS_SUCCESS; 1577123474Swpaul return; 1578123474Swpaul} 1579123474Swpaul 1580123848Swpaul__stdcall static void 1581123848Swpaulndis_release_packet(packet) 1582123474Swpaul ndis_packet *packet; 1583123474Swpaul{ 1584123474Swpaul ndis_packet *head; 1585123474Swpaul 1586123474Swpaul if (packet == NULL || packet->np_private.npp_pool == NULL) 1587123474Swpaul return; 1588123474Swpaul 1589123474Swpaul head = packet->np_private.npp_pool; 1590123474Swpaul if (head->np_private.npp_flags != 0x1) 1591123474Swpaul return; 1592123474Swpaul 1593123474Swpaul packet->np_private.npp_head = head->np_private.npp_head; 1594123474Swpaul head->np_private.npp_head = (ndis_buffer *)packet; 1595123474Swpaul head->np_private.npp_count--; 1596123474Swpaul 1597123474Swpaul return; 1598123474Swpaul} 1599123474Swpaul 1600123474Swpaul__stdcall static void 1601123474Swpaulndis_unchain_headbuf(packet, buf) 1602123474Swpaul ndis_packet *packet; 1603123474Swpaul ndis_buffer **buf; 1604123474Swpaul{ 1605123474Swpaul ndis_packet_private *priv; 1606123474Swpaul 1607123474Swpaul if (packet == NULL || buf == NULL) 1608123474Swpaul return; 1609123474Swpaul 1610123474Swpaul priv = &packet->np_private; 1611123474Swpaul 1612123474Swpaul priv->npp_validcounts = FALSE; 1613123474Swpaul 1614123474Swpaul if (priv->npp_head == priv->npp_tail) { 1615123474Swpaul *buf = priv->npp_head; 1616123474Swpaul priv->npp_head = priv->npp_tail = NULL; 1617123474Swpaul } else { 1618123474Swpaul *buf = priv->npp_head; 1619123474Swpaul priv->npp_head = (*buf)->nb_next; 1620123474Swpaul } 1621123474Swpaul 1622123474Swpaul return; 1623123474Swpaul} 1624123474Swpaul 1625123721Swpaul__stdcall static void 1626123721Swpaulndis_unchain_tailbuf(packet, buf) 1627123721Swpaul ndis_packet *packet; 1628123721Swpaul ndis_buffer **buf; 1629123721Swpaul{ 1630123721Swpaul ndis_packet_private *priv; 1631123721Swpaul ndis_buffer *tmp; 1632123721Swpaul 1633123721Swpaul if (packet == NULL || buf == NULL) 1634123721Swpaul return; 1635123721Swpaul 1636123721Swpaul priv = &packet->np_private; 1637123721Swpaul 1638123721Swpaul priv->npp_validcounts = FALSE; 1639123721Swpaul 1640123721Swpaul if (priv->npp_head == priv->npp_tail) { 1641123721Swpaul *buf = priv->npp_head; 1642123721Swpaul priv->npp_head = priv->npp_tail = NULL; 1643123721Swpaul } else { 1644123721Swpaul *buf = priv->npp_tail; 1645123721Swpaul tmp = priv->npp_head; 1646123721Swpaul while (tmp->nb_next != priv->npp_tail) 1647123721Swpaul tmp = tmp->nb_next; 1648123721Swpaul priv->npp_tail = tmp; 1649123721Swpaul tmp->nb_next = NULL; 1650123721Swpaul } 1651123721Swpaul 1652123721Swpaul return; 1653123721Swpaul} 1654123721Swpaul 1655123474Swpaul/* 1656123474Swpaul * The NDIS "buffer" manipulation functions are somewhat misnamed. 1657123474Swpaul * They don't really allocate buffers: they allocate buffer mappings. 1658123474Swpaul * The idea is you reserve a chunk of DMA-able memory using 1659123474Swpaul * NdisMAllocateSharedMemory() and then use NdisAllocateBuffer() 1660123474Swpaul * to obtain the virtual address of the DMA-able region. 1661123474Swpaul * ndis_alloc_bufpool() is analagous to bus_dma_tag_create(). 1662123474Swpaul */ 1663123474Swpaul 1664123474Swpaul__stdcall static void 1665123474Swpaulndis_alloc_bufpool(status, pool, descnum) 1666123474Swpaul ndis_status *status; 1667123474Swpaul ndis_handle *pool; 1668123474Swpaul uint32_t descnum; 1669123474Swpaul{ 1670123474Swpaul ndis_buffer *cur; 1671123474Swpaul int i; 1672123474Swpaul 1673124116Swpaul *pool = malloc(sizeof(ndis_buffer) * 1674124116Swpaul ((descnum + NDIS_POOL_EXTRA) + 1), 1675123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1676123474Swpaul 1677123474Swpaul if (pool == NULL) { 1678123474Swpaul *status = NDIS_STATUS_RESOURCES; 1679123474Swpaul return; 1680123474Swpaul } 1681123474Swpaul 1682123474Swpaul cur = (ndis_buffer *)*pool; 1683123474Swpaul cur->nb_flags = 0x1; /* mark the head of the list */ 1684124116Swpaul for (i = 0; i < (descnum + NDIS_POOL_EXTRA); i++) { 1685123474Swpaul cur->nb_next = cur + 1; 1686123474Swpaul cur++; 1687123474Swpaul } 1688123474Swpaul 1689123474Swpaul *status = NDIS_STATUS_SUCCESS; 1690123474Swpaul return; 1691123474Swpaul} 1692123474Swpaul 1693123474Swpaul__stdcall static void 1694123474Swpaulndis_free_bufpool(pool) 1695123474Swpaul ndis_handle pool; 1696123474Swpaul{ 1697123474Swpaul free(pool, M_DEVBUF); 1698123474Swpaul return; 1699123474Swpaul} 1700123474Swpaul 1701123474Swpaul/* 1702123474Swpaul * This maps to a bus_dmamap_create() and bus_dmamap_load(). 1703123474Swpaul */ 1704123474Swpaul__stdcall static void 1705123474Swpaulndis_alloc_buf(status, buffer, pool, vaddr, len) 1706123474Swpaul ndis_status *status; 1707123474Swpaul ndis_buffer **buffer; 1708123474Swpaul ndis_handle pool; 1709123474Swpaul void *vaddr; 1710123474Swpaul uint32_t len; 1711123474Swpaul{ 1712123474Swpaul ndis_buffer *head, *buf; 1713123474Swpaul 1714123474Swpaul head = (ndis_buffer *)pool; 1715123474Swpaul if (head->nb_flags != 0x1) { 1716123474Swpaul *status = NDIS_STATUS_FAILURE; 1717123474Swpaul return; 1718123474Swpaul } 1719123474Swpaul 1720123474Swpaul buf = head->nb_next; 1721123474Swpaul 1722123474Swpaul if (buf == NULL) { 1723123474Swpaul *status = NDIS_STATUS_RESOURCES; 1724123474Swpaul return; 1725123474Swpaul } 1726123474Swpaul 1727123474Swpaul head->nb_next = buf->nb_next; 1728123474Swpaul 1729123474Swpaul /* Save pointer to the pool. */ 1730123474Swpaul buf->nb_process = head; 1731123474Swpaul 1732123757Swpaul MDL_INIT(buf, vaddr, len); 1733123474Swpaul 1734123474Swpaul *buffer = buf; 1735123474Swpaul 1736123474Swpaul *status = NDIS_STATUS_SUCCESS; 1737123474Swpaul return; 1738123474Swpaul} 1739123474Swpaul 1740123848Swpaul__stdcall static void 1741123848Swpaulndis_release_buf(buf) 1742123474Swpaul ndis_buffer *buf; 1743123474Swpaul{ 1744123474Swpaul ndis_buffer *head; 1745123474Swpaul 1746123474Swpaul if (buf == NULL || buf->nb_process == NULL) 1747123474Swpaul return; 1748123474Swpaul 1749123474Swpaul head = buf->nb_process; 1750123474Swpaul 1751123474Swpaul if (head->nb_flags != 0x1) 1752123474Swpaul return; 1753123474Swpaul 1754123474Swpaul buf->nb_next = head->nb_next; 1755123474Swpaul head->nb_next = buf; 1756123474Swpaul 1757123474Swpaul return; 1758123474Swpaul} 1759123474Swpaul 1760124100Swpaul/* Aw c'mon. */ 1761124100Swpaul 1762124100Swpaul__stdcall static uint32_t 1763124100Swpaulndis_buflen(buf) 1764124100Swpaul ndis_buffer *buf; 1765124100Swpaul{ 1766124100Swpaul return(buf->nb_bytecount); 1767124100Swpaul} 1768124100Swpaul 1769123723Swpaul/* 1770123723Swpaul * Get the virtual address and length of a buffer. 1771123723Swpaul * Note: the vaddr argument is optional. 1772123723Swpaul */ 1773123474Swpaul 1774123474Swpaul__stdcall static void 1775123474Swpaulndis_query_buf(buf, vaddr, len) 1776123474Swpaul ndis_buffer *buf; 1777123474Swpaul void **vaddr; 1778123474Swpaul uint32_t *len; 1779123474Swpaul{ 1780123723Swpaul if (vaddr != NULL) 1781123757Swpaul *vaddr = MDL_VA(buf); 1782123474Swpaul *len = buf->nb_bytecount; 1783123474Swpaul 1784123474Swpaul return; 1785123474Swpaul} 1786123474Swpaul 1787123474Swpaul/* Same as above -- we don't care about the priority. */ 1788123474Swpaul 1789123474Swpaul__stdcall static void 1790123474Swpaulndis_query_buf_safe(buf, vaddr, len, prio) 1791123474Swpaul ndis_buffer *buf; 1792123474Swpaul void **vaddr; 1793123474Swpaul uint32_t *len; 1794123474Swpaul uint32_t prio; 1795123474Swpaul{ 1796123723Swpaul if (vaddr != NULL) 1797123757Swpaul *vaddr = MDL_VA(buf); 1798123474Swpaul *len = buf->nb_bytecount; 1799123474Swpaul 1800123474Swpaul return; 1801123474Swpaul} 1802123474Swpaul 1803125069Swpaul/* Damnit Microsoft!! How many ways can you do the same thing?! */ 1804125069Swpaul 1805125069Swpaul__stdcall static void * 1806125069Swpaulndis_buf_vaddr(buf) 1807125069Swpaul ndis_buffer *buf; 1808125069Swpaul{ 1809125069Swpaul return(MDL_VA(buf)); 1810125069Swpaul} 1811125069Swpaul 1812125069Swpaul__stdcall static void * 1813125069Swpaulndis_buf_vaddr_safe(buf, prio) 1814125069Swpaul ndis_buffer *buf; 1815125069Swpaul uint32_t prio; 1816125069Swpaul{ 1817125069Swpaul return(MDL_VA(buf)); 1818125069Swpaul} 1819125069Swpaul 1820123474Swpaul__stdcall static void 1821123474Swpaulndis_adjust_buflen(buf, len) 1822123474Swpaul ndis_buffer *buf; 1823123474Swpaul int len; 1824123474Swpaul{ 1825123474Swpaul buf->nb_bytecount = len; 1826123474Swpaul 1827123474Swpaul return; 1828123474Swpaul} 1829123474Swpaul 1830123474Swpaul__stdcall static uint32_t 1831123474Swpaulndis_interlock_inc(addend) 1832123474Swpaul uint32_t *addend; 1833123474Swpaul{ 1834124203Swpaul atomic_add_long((u_long *)addend, 1); 1835123474Swpaul return(*addend); 1836123474Swpaul} 1837123474Swpaul 1838123474Swpaul__stdcall static uint32_t 1839123474Swpaulndis_interlock_dec(addend) 1840123474Swpaul uint32_t *addend; 1841123474Swpaul{ 1842124203Swpaul atomic_subtract_long((u_long *)addend, 1); 1843123474Swpaul return(*addend); 1844123474Swpaul} 1845123474Swpaul 1846123474Swpaul__stdcall static void 1847123474Swpaulndis_init_event(event) 1848123474Swpaul ndis_event *event; 1849123474Swpaul{ 1850123474Swpaul event->ne_event.nk_header.dh_sigstate = FALSE; 1851123474Swpaul return; 1852123474Swpaul} 1853123474Swpaul 1854123474Swpaul__stdcall static void 1855123474Swpaulndis_set_event(event) 1856123474Swpaul ndis_event *event; 1857123474Swpaul{ 1858123474Swpaul event->ne_event.nk_header.dh_sigstate = TRUE; 1859123474Swpaul wakeup(event); 1860123474Swpaul return; 1861123474Swpaul} 1862123474Swpaul 1863123474Swpaul__stdcall static void 1864123474Swpaulndis_reset_event(event) 1865123474Swpaul ndis_event *event; 1866123474Swpaul{ 1867123474Swpaul event->ne_event.nk_header.dh_sigstate = FALSE; 1868123474Swpaul wakeup(event); 1869123474Swpaul return; 1870123474Swpaul} 1871123474Swpaul 1872123474Swpaul__stdcall static uint8_t 1873123474Swpaulndis_wait_event(event, msecs) 1874123474Swpaul ndis_event *event; 1875123474Swpaul uint32_t msecs; 1876123474Swpaul{ 1877123474Swpaul int error; 1878123474Swpaul struct timeval tv; 1879123474Swpaul 1880123474Swpaul if (event->ne_event.nk_header.dh_sigstate == TRUE) 1881123474Swpaul return(TRUE); 1882123474Swpaul 1883123474Swpaul tv.tv_sec = 0; 1884123474Swpaul tv.tv_usec = msecs * 1000; 1885123474Swpaul 1886123474Swpaul error = tsleep(event, PPAUSE|PCATCH, "ndis", tvtohz(&tv)); 1887123474Swpaul 1888123474Swpaul return(event->ne_event.nk_header.dh_sigstate); 1889123474Swpaul} 1890123474Swpaul 1891123474Swpaul__stdcall static ndis_status 1892123474Swpaulndis_unicode2ansi(dstr, sstr) 1893123526Swpaul ndis_ansi_string *dstr; 1894123526Swpaul ndis_unicode_string *sstr; 1895123474Swpaul{ 1896123526Swpaul if (dstr == NULL || sstr == NULL) 1897123526Swpaul return(NDIS_STATUS_FAILURE); 1898123526Swpaul if (ndis_unicode_to_ascii(sstr->nus_buf, 1899123526Swpaul sstr->nus_len, &dstr->nas_buf)) 1900123526Swpaul return(NDIS_STATUS_FAILURE); 1901123526Swpaul dstr->nas_len = dstr->nas_maxlen = strlen(dstr->nas_buf); 1902123474Swpaul return (NDIS_STATUS_SUCCESS); 1903123474Swpaul} 1904123474Swpaul 1905123474Swpaul__stdcall static ndis_status 1906123526Swpaulndis_ansi2unicode(dstr, sstr) 1907123526Swpaul ndis_unicode_string *dstr; 1908123526Swpaul ndis_ansi_string *sstr; 1909123526Swpaul{ 1910123526Swpaul char *str; 1911123526Swpaul if (dstr == NULL || sstr == NULL) 1912123526Swpaul return(NDIS_STATUS_FAILURE); 1913123526Swpaul str = malloc(sstr->nas_len + 1, M_DEVBUF, M_NOWAIT); 1914123526Swpaul if (str == NULL) 1915123526Swpaul return(NDIS_STATUS_FAILURE); 1916123526Swpaul strncpy(str, sstr->nas_buf, sstr->nas_len); 1917123526Swpaul *(str + sstr->nas_len) = '\0'; 1918123526Swpaul if (ndis_ascii_to_unicode(str, &dstr->nus_buf)) { 1919123526Swpaul free(str, M_DEVBUF); 1920123526Swpaul return(NDIS_STATUS_FAILURE); 1921123526Swpaul } 1922123526Swpaul dstr->nus_len = dstr->nus_maxlen = sstr->nas_len * 2; 1923123526Swpaul free(str, M_DEVBUF); 1924123526Swpaul return (NDIS_STATUS_SUCCESS); 1925123526Swpaul} 1926123526Swpaul 1927123526Swpaul__stdcall static ndis_status 1928123474Swpaulndis_assign_pcirsrc(adapter, slot, list) 1929123474Swpaul ndis_handle adapter; 1930123474Swpaul uint32_t slot; 1931123474Swpaul ndis_resource_list **list; 1932123474Swpaul{ 1933123474Swpaul ndis_miniport_block *block; 1934123474Swpaul 1935123474Swpaul if (adapter == NULL || list == NULL) 1936123474Swpaul return (NDIS_STATUS_FAILURE); 1937123474Swpaul 1938123474Swpaul block = (ndis_miniport_block *)adapter; 1939123474Swpaul *list = block->nmb_rlist; 1940123474Swpaul 1941123474Swpaul return (NDIS_STATUS_SUCCESS); 1942123474Swpaul} 1943123474Swpaul 1944123474Swpaul__stdcall static ndis_status 1945123474Swpaulndis_register_intr(intr, adapter, ivec, ilevel, reqisr, shared, imode) 1946123474Swpaul ndis_miniport_interrupt *intr; 1947123474Swpaul ndis_handle adapter; 1948123474Swpaul uint32_t ivec; 1949123474Swpaul uint32_t ilevel; 1950123474Swpaul uint8_t reqisr; 1951123474Swpaul uint8_t shared; 1952123474Swpaul ndis_interrupt_mode imode; 1953123474Swpaul{ 1954124165Swpaul ndis_miniport_block *block; 1955124165Swpaul 1956124165Swpaul block = adapter; 1957124165Swpaul 1958124135Swpaul intr->ni_block = adapter; 1959124165Swpaul intr->ni_isrreq = reqisr; 1960124165Swpaul intr->ni_shared = shared; 1961124165Swpaul block->nmb_interrupt = intr; 1962123474Swpaul return(NDIS_STATUS_SUCCESS); 1963123474Swpaul} 1964123474Swpaul 1965123474Swpaul__stdcall static void 1966123474Swpaulndis_deregister_intr(intr) 1967123474Swpaul ndis_miniport_interrupt *intr; 1968123474Swpaul{ 1969123474Swpaul return; 1970123474Swpaul} 1971123474Swpaul 1972123474Swpaul__stdcall static void 1973123474Swpaulndis_register_shutdown(adapter, shutdownctx, shutdownfunc) 1974123474Swpaul ndis_handle adapter; 1975123474Swpaul void *shutdownctx; 1976123474Swpaul ndis_shutdown_handler shutdownfunc; 1977123474Swpaul{ 1978123474Swpaul ndis_miniport_block *block; 1979123474Swpaul ndis_miniport_characteristics *chars; 1980123474Swpaul struct ndis_softc *sc; 1981123474Swpaul 1982123474Swpaul if (adapter == NULL) 1983123474Swpaul return; 1984123474Swpaul 1985123474Swpaul block = (ndis_miniport_block *)adapter; 1986123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 1987123474Swpaul chars = &sc->ndis_chars; 1988123474Swpaul 1989123474Swpaul chars->nmc_shutdown_handler = shutdownfunc; 1990123474Swpaul chars->nmc_rsvd0 = shutdownctx; 1991123474Swpaul 1992123474Swpaul return; 1993123474Swpaul} 1994123474Swpaul 1995123474Swpaul__stdcall static void 1996123474Swpaulndis_deregister_shutdown(adapter) 1997123474Swpaul ndis_handle adapter; 1998123474Swpaul{ 1999123474Swpaul ndis_miniport_block *block; 2000123474Swpaul ndis_miniport_characteristics *chars; 2001123474Swpaul struct ndis_softc *sc; 2002123474Swpaul 2003123474Swpaul if (adapter == NULL) 2004123474Swpaul return; 2005123474Swpaul 2006123474Swpaul block = (ndis_miniport_block *)adapter; 2007123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 2008123474Swpaul chars = &sc->ndis_chars; 2009123474Swpaul 2010123474Swpaul chars->nmc_shutdown_handler = NULL; 2011123474Swpaul chars->nmc_rsvd0 = NULL; 2012123474Swpaul 2013123474Swpaul return; 2014123474Swpaul} 2015123474Swpaul 2016123474Swpaul__stdcall static uint32_t 2017123474Swpaulndis_numpages(buf) 2018123474Swpaul ndis_buffer *buf; 2019123474Swpaul{ 2020123757Swpaul if (buf == NULL) 2021123757Swpaul return(0); 2022123512Swpaul if (buf->nb_bytecount == 0) 2023123512Swpaul return(1); 2024123757Swpaul return(SPAN_PAGES(MDL_VA(buf), buf->nb_bytecount)); 2025123474Swpaul} 2026123474Swpaul 2027123474Swpaul__stdcall static void 2028123573Swpaulndis_buf_physpages(buf, pages) 2029123573Swpaul ndis_buffer *buf; 2030123573Swpaul uint32_t *pages; 2031123573Swpaul{ 2032123757Swpaul if (buf == NULL) 2033123757Swpaul return; 2034123757Swpaul 2035123573Swpaul *pages = ndis_numpages(buf); 2036123573Swpaul return; 2037123573Swpaul} 2038123573Swpaul 2039123573Swpaul__stdcall static void 2040123474Swpaulndis_query_bufoffset(buf, off, len) 2041123474Swpaul ndis_buffer *buf; 2042123474Swpaul uint32_t *off; 2043123474Swpaul uint32_t *len; 2044123474Swpaul{ 2045123757Swpaul if (buf == NULL) 2046123757Swpaul return; 2047123757Swpaul 2048123757Swpaul *off = buf->nb_byteoffset; 2049123474Swpaul *len = buf->nb_bytecount; 2050123474Swpaul 2051123474Swpaul return; 2052123474Swpaul} 2053123474Swpaul 2054123474Swpaul__stdcall static void 2055123474Swpaulndis_sleep(usecs) 2056123474Swpaul uint32_t usecs; 2057123474Swpaul{ 2058123474Swpaul struct timeval tv; 2059123474Swpaul uint32_t dummy; 2060123474Swpaul 2061123474Swpaul tv.tv_sec = 0; 2062123474Swpaul tv.tv_usec = usecs; 2063123474Swpaul 2064123474Swpaul tsleep(&dummy, PPAUSE|PCATCH, "ndis", tvtohz(&tv)); 2065124100Swpaul 2066123474Swpaul return; 2067123474Swpaul} 2068123474Swpaul 2069123474Swpaul__stdcall static uint32_t 2070123474Swpaulndis_read_pccard_amem(handle, offset, buf, len) 2071123474Swpaul ndis_handle handle; 2072123474Swpaul uint32_t offset; 2073123474Swpaul void *buf; 2074123474Swpaul uint32_t len; 2075123474Swpaul{ 2076123474Swpaul struct ndis_softc *sc; 2077123474Swpaul ndis_miniport_block *block; 2078123474Swpaul bus_space_handle_t bh; 2079123474Swpaul bus_space_tag_t bt; 2080123474Swpaul char *dest; 2081123474Swpaul int i; 2082123474Swpaul 2083123474Swpaul if (handle == NULL) 2084123474Swpaul return(0); 2085123474Swpaul 2086123474Swpaul block = (ndis_miniport_block *)handle; 2087123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 2088123474Swpaul dest = buf; 2089123474Swpaul 2090123474Swpaul bh = rman_get_bushandle(sc->ndis_res_am); 2091123474Swpaul bt = rman_get_bustag(sc->ndis_res_am); 2092123474Swpaul 2093123474Swpaul for (i = 0; i < len; i++) 2094123474Swpaul dest[i] = bus_space_read_1(bt, bh, (offset * 2) + (i * 2)); 2095123474Swpaul 2096123474Swpaul return(i); 2097123474Swpaul} 2098123474Swpaul 2099123474Swpaul__stdcall static uint32_t 2100123474Swpaulndis_write_pccard_amem(handle, offset, buf, len) 2101123474Swpaul ndis_handle handle; 2102123474Swpaul uint32_t offset; 2103123474Swpaul void *buf; 2104123474Swpaul uint32_t len; 2105123474Swpaul{ 2106123474Swpaul struct ndis_softc *sc; 2107123474Swpaul ndis_miniport_block *block; 2108123474Swpaul bus_space_handle_t bh; 2109123474Swpaul bus_space_tag_t bt; 2110123474Swpaul char *src; 2111123474Swpaul int i; 2112123474Swpaul 2113123474Swpaul if (handle == NULL) 2114123474Swpaul return(0); 2115123474Swpaul 2116123474Swpaul block = (ndis_miniport_block *)handle; 2117123474Swpaul sc = (struct ndis_softc *)block->nmb_ifp; 2118123474Swpaul src = buf; 2119123474Swpaul 2120123474Swpaul bh = rman_get_bushandle(sc->ndis_res_am); 2121123474Swpaul bt = rman_get_bustag(sc->ndis_res_am); 2122123474Swpaul 2123123474Swpaul for (i = 0; i < len; i++) 2124123474Swpaul bus_space_write_1(bt, bh, (offset * 2) + (i * 2), src[i]); 2125123474Swpaul 2126123474Swpaul return(i); 2127123474Swpaul} 2128123474Swpaul 2129123474Swpaul__stdcall static ndis_list_entry * 2130123474Swpaulndis_insert_head(head, entry, lock) 2131123474Swpaul ndis_list_entry *head; 2132123474Swpaul ndis_list_entry *entry; 2133123474Swpaul ndis_spin_lock *lock; 2134123474Swpaul{ 2135123474Swpaul ndis_list_entry *flink; 2136123474Swpaul 2137124409Swpaul mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 2138123474Swpaul flink = head->nle_flink; 2139123474Swpaul entry->nle_flink = flink; 2140123474Swpaul entry->nle_blink = head; 2141123474Swpaul flink->nle_blink = entry; 2142123474Swpaul head->nle_flink = entry; 2143124409Swpaul mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 2144123474Swpaul 2145123474Swpaul return(flink); 2146123474Swpaul} 2147123474Swpaul 2148123474Swpaul__stdcall static ndis_list_entry * 2149123474Swpaulndis_remove_head(head, lock) 2150123474Swpaul ndis_list_entry *head; 2151123474Swpaul ndis_spin_lock *lock; 2152123474Swpaul{ 2153123474Swpaul ndis_list_entry *flink; 2154123474Swpaul ndis_list_entry *entry; 2155123474Swpaul 2156124409Swpaul mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 2157123474Swpaul entry = head->nle_flink; 2158123474Swpaul flink = entry->nle_flink; 2159123474Swpaul head->nle_flink = flink; 2160123474Swpaul flink->nle_blink = head; 2161124409Swpaul mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 2162123474Swpaul 2163123474Swpaul return(entry); 2164123474Swpaul} 2165123474Swpaul 2166123474Swpaul__stdcall static ndis_list_entry * 2167123474Swpaulndis_insert_tail(head, entry, lock) 2168123474Swpaul ndis_list_entry *head; 2169123474Swpaul ndis_list_entry *entry; 2170123474Swpaul ndis_spin_lock *lock; 2171123474Swpaul{ 2172123474Swpaul ndis_list_entry *blink; 2173123474Swpaul 2174124409Swpaul mtx_pool_lock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 2175123474Swpaul blink = head->nle_blink; 2176123474Swpaul entry->nle_flink = head; 2177123474Swpaul entry->nle_blink = blink; 2178123474Swpaul blink->nle_flink = entry; 2179123474Swpaul head->nle_blink = entry; 2180124409Swpaul mtx_pool_unlock(ndis_mtxpool, (struct mtx *)lock->nsl_spinlock); 2181123474Swpaul 2182123474Swpaul return(blink); 2183123474Swpaul} 2184123474Swpaul 2185123474Swpaul__stdcall static uint8_t 2186123474Swpaulndis_sync_with_intr(intr, syncfunc, syncctx) 2187123474Swpaul ndis_miniport_interrupt *intr; 2188123474Swpaul void *syncfunc; 2189123474Swpaul void *syncctx; 2190123474Swpaul{ 2191124135Swpaul struct ndis_softc *sc; 2192123474Swpaul __stdcall uint8_t (*sync)(void *); 2193124135Swpaul uint8_t rval; 2194123474Swpaul 2195123474Swpaul if (syncfunc == NULL || syncctx == NULL) 2196123474Swpaul return(0); 2197123474Swpaul 2198124135Swpaul sc = (struct ndis_softc *)intr->ni_block->nmb_ifp; 2199123474Swpaul sync = syncfunc; 2200124409Swpaul mtx_pool_lock(ndis_mtxpool, sc->ndis_intrmtx); 2201124135Swpaul rval = sync(syncctx); 2202124409Swpaul mtx_pool_unlock(ndis_mtxpool, sc->ndis_intrmtx); 2203124135Swpaul 2204124135Swpaul return(rval); 2205123474Swpaul} 2206123474Swpaul 2207123504Swpaul/* 2208123504Swpaul * Return the number of 100 nanosecond intervals since 2209123504Swpaul * January 1, 1601. (?!?!) 2210123504Swpaul */ 2211123474Swpaul__stdcall static void 2212123504Swpaulndis_time(tval) 2213123504Swpaul uint64_t *tval; 2214123504Swpaul{ 2215123504Swpaul struct timespec ts; 2216123822Swpaul 2217123504Swpaul nanotime(&ts); 2218123822Swpaul *tval = (uint64_t)ts.tv_nsec / 100 + (uint64_t)ts.tv_sec * 10000000 + 2219123822Swpaul 11644473600; 2220123504Swpaul} 2221123504Swpaul 2222123822Swpaul/* 2223123822Swpaul * Return the number of milliseconds since the system booted. 2224123822Swpaul */ 2225123504Swpaul__stdcall static void 2226123822Swpaulndis_uptime(tval) 2227123822Swpaul uint32_t *tval; 2228123822Swpaul{ 2229123822Swpaul struct timespec ts; 2230123822Swpaul 2231123822Swpaul nanouptime(&ts); 2232123822Swpaul *tval = ts.tv_nsec / 1000000 + ts.tv_sec * 1000; 2233123822Swpaul} 2234123822Swpaul 2235123822Swpaul__stdcall static void 2236123507Swpaulndis_init_string(dst, src) 2237124100Swpaul ndis_unicode_string *dst; 2238123507Swpaul char *src; 2239123507Swpaul{ 2240123507Swpaul ndis_unicode_string *u; 2241123507Swpaul 2242124100Swpaul u = dst; 2243124116Swpaul u->nus_buf = NULL; 2244124100Swpaul if (ndis_ascii_to_unicode(src, &u->nus_buf)) 2245123507Swpaul return; 2246123507Swpaul u->nus_len = u->nus_maxlen = strlen(src) * 2; 2247123507Swpaul return; 2248123507Swpaul} 2249123507Swpaul 2250123507Swpaul__stdcall static void 2251123507Swpaulndis_free_string(str) 2252123507Swpaul ndis_unicode_string *str; 2253123507Swpaul{ 2254123507Swpaul if (str == NULL) 2255123507Swpaul return; 2256123507Swpaul if (str->nus_buf != NULL) 2257123507Swpaul free(str->nus_buf, M_DEVBUF); 2258123507Swpaul free(str, M_DEVBUF); 2259123507Swpaul return; 2260123507Swpaul} 2261123507Swpaul 2262123507Swpaul__stdcall static ndis_status 2263123507Swpaulndis_remove_miniport(adapter) 2264123507Swpaul ndis_handle *adapter; 2265123507Swpaul{ 2266123507Swpaul return(NDIS_STATUS_SUCCESS); 2267123507Swpaul} 2268123507Swpaul 2269123507Swpaul__stdcall static void 2270123526Swpaulndis_init_ansi_string(dst, src) 2271123526Swpaul ndis_ansi_string *dst; 2272123526Swpaul char *src; 2273123526Swpaul{ 2274123526Swpaul ndis_ansi_string *a; 2275123526Swpaul 2276123526Swpaul a = dst; 2277123526Swpaul if (a == NULL) 2278123526Swpaul return; 2279123526Swpaul if (src == NULL) { 2280123526Swpaul a->nas_len = a->nas_maxlen = 0; 2281123526Swpaul a->nas_buf = NULL; 2282123526Swpaul } else { 2283123526Swpaul a->nas_buf = src; 2284123526Swpaul a->nas_len = a->nas_maxlen = strlen(src); 2285123526Swpaul } 2286123526Swpaul 2287123526Swpaul return; 2288123526Swpaul} 2289123526Swpaul 2290123941Swpaul__stdcall static void 2291123941Swpaulndis_init_unicode_string(dst, src) 2292123941Swpaul ndis_unicode_string *dst; 2293123941Swpaul uint16_t *src; 2294123941Swpaul{ 2295123941Swpaul ndis_unicode_string *u; 2296123941Swpaul int i; 2297123941Swpaul 2298123941Swpaul u = dst; 2299123941Swpaul if (u == NULL) 2300123941Swpaul return; 2301123941Swpaul if (src == NULL) { 2302123941Swpaul u->nus_len = u->nus_maxlen = 0; 2303123941Swpaul u->nus_buf = NULL; 2304123941Swpaul } else { 2305123941Swpaul i = 0; 2306123941Swpaul while(src[i] != 0) 2307123941Swpaul i++; 2308123941Swpaul u->nus_buf = src; 2309123941Swpaul u->nus_len = u->nus_maxlen = i * 2; 2310123941Swpaul } 2311123941Swpaul 2312123941Swpaul return; 2313123941Swpaul} 2314123941Swpaul 2315123526Swpaul__stdcall static void ndis_get_devprop(adapter, phydevobj, 2316123526Swpaul funcdevobj, nextdevobj, resources, transresources) 2317123526Swpaul ndis_handle adapter; 2318123526Swpaul void *phydevobj; 2319123526Swpaul void *funcdevobj; 2320123526Swpaul void *nextdevobj; 2321123526Swpaul cm_resource_list *resources; 2322123526Swpaul cm_resource_list *transresources; 2323123526Swpaul{ 2324123526Swpaul return; 2325123526Swpaul} 2326123526Swpaul 2327123526Swpaul__stdcall static void 2328123721Swpaulndis_firstbuf(packet, buf, firstva, firstlen, totlen) 2329123721Swpaul ndis_packet *packet; 2330123721Swpaul ndis_buffer **buf; 2331123721Swpaul void **firstva; 2332123721Swpaul uint32_t *firstlen; 2333123721Swpaul uint32_t *totlen; 2334123721Swpaul{ 2335123721Swpaul ndis_buffer *tmp; 2336123721Swpaul 2337123721Swpaul tmp = packet->np_private.npp_head; 2338123721Swpaul *buf = tmp; 2339123721Swpaul if (tmp == NULL) { 2340123721Swpaul *firstva = NULL; 2341123721Swpaul *firstlen = *totlen = 0; 2342123721Swpaul } else { 2343123757Swpaul *firstva = MDL_VA(tmp); 2344123721Swpaul *firstlen = *totlen = tmp->nb_bytecount; 2345123721Swpaul for (tmp = tmp->nb_next; tmp != NULL; tmp = tmp->nb_next) 2346123721Swpaul *totlen += tmp->nb_bytecount; 2347123721Swpaul } 2348123721Swpaul 2349123721Swpaul return; 2350123721Swpaul} 2351123721Swpaul 2352123721Swpaul__stdcall static void 2353123721Swpaulndis_firstbuf_safe(packet, buf, firstva, firstlen, totlen, prio) 2354123721Swpaul ndis_packet *packet; 2355123721Swpaul ndis_buffer **buf; 2356123721Swpaul void **firstva; 2357123721Swpaul uint32_t *firstlen; 2358123721Swpaul uint32_t *totlen; 2359123721Swpaul uint32_t prio; 2360123721Swpaul{ 2361123721Swpaul ndis_firstbuf(packet, buf, firstva, firstlen, totlen); 2362123721Swpaul} 2363123721Swpaul 2364123822Swpaul/* can also return NDIS_STATUS_RESOURCES/NDIS_STATUS_ERROR_READING_FILE */ 2365123721Swpaul__stdcall static void 2366123822Swpaulndis_open_file(status, filehandle, filelength, filename, highestaddr) 2367123822Swpaul ndis_status *status; 2368123822Swpaul ndis_handle *filehandle; 2369123822Swpaul uint32_t *filelength; 2370123822Swpaul ndis_unicode_string *filename; 2371123822Swpaul ndis_physaddr highestaddr; 2372123822Swpaul{ 2373123822Swpaul char *afilename = NULL; 2374124272Swpaul struct thread *td = curthread; 2375124272Swpaul struct nameidata nd; 2376124272Swpaul int flags, error; 2377124272Swpaul struct vattr vat; 2378124272Swpaul struct vattr *vap = &vat; 2379124272Swpaul ndis_fh *fh; 2380124272Swpaul char path[MAXPATHLEN]; 2381123822Swpaul 2382124272Swpaul ndis_unicode_to_ascii(filename->nus_buf, 2383124272Swpaul filename->nus_len, &afilename); 2384124272Swpaul 2385124272Swpaul sprintf(path, "%s/%s", ndis_filepath, afilename); 2386123822Swpaul free(afilename, M_DEVBUF); 2387124272Swpaul 2388124272Swpaul fh = malloc(sizeof(ndis_fh), M_TEMP, M_NOWAIT); 2389124272Swpaul if (fh == NULL) { 2390124272Swpaul *status = NDIS_STATUS_RESOURCES; 2391124272Swpaul return; 2392124272Swpaul } 2393124272Swpaul 2394124272Swpaul mtx_lock(&Giant); 2395124272Swpaul NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, path, td); 2396124272Swpaul 2397124272Swpaul flags = FREAD; 2398124272Swpaul error = vn_open(&nd, &flags, 0, -1); 2399124272Swpaul if (error) { 2400124272Swpaul mtx_unlock(&Giant); 2401124272Swpaul *status = NDIS_STATUS_FILE_NOT_FOUND; 2402124272Swpaul free(fh, M_TEMP); 2403124272Swpaul return; 2404124272Swpaul } 2405124272Swpaul 2406124272Swpaul NDFREE(&nd, NDF_ONLY_PNBUF); 2407124272Swpaul 2408124272Swpaul /* Get the file size. */ 2409124272Swpaul VOP_GETATTR(nd.ni_vp, vap, NOCRED, td); 2410124272Swpaul VOP_UNLOCK(nd.ni_vp, 0, td); 2411124272Swpaul mtx_unlock(&Giant); 2412124272Swpaul 2413124272Swpaul fh->nf_vp = nd.ni_vp; 2414124272Swpaul fh->nf_map = NULL; 2415124272Swpaul *filehandle = fh; 2416124272Swpaul *filelength = fh->nf_maplen = vap->va_size & 0xFFFFFFFF; 2417124272Swpaul *status = NDIS_STATUS_SUCCESS; 2418123822Swpaul return; 2419123822Swpaul} 2420123822Swpaul 2421123822Swpaul__stdcall static void 2422123822Swpaulndis_map_file(status, mappedbuffer, filehandle) 2423123822Swpaul ndis_status *status; 2424123822Swpaul void **mappedbuffer; 2425123822Swpaul ndis_handle filehandle; 2426123822Swpaul{ 2427124272Swpaul ndis_fh *fh; 2428124272Swpaul struct thread *td = curthread; 2429124272Swpaul int error, resid; 2430123822Swpaul 2431124272Swpaul if (filehandle == NULL) { 2432124272Swpaul *status = NDIS_STATUS_FAILURE; 2433124272Swpaul return; 2434124272Swpaul } 2435124272Swpaul 2436124272Swpaul fh = (ndis_fh *)filehandle; 2437124272Swpaul 2438124272Swpaul if (fh->nf_vp == NULL) { 2439124272Swpaul *status = NDIS_STATUS_FAILURE; 2440124272Swpaul return; 2441124272Swpaul } 2442124272Swpaul 2443124272Swpaul if (fh->nf_map != NULL) { 2444124272Swpaul *status = NDIS_STATUS_ALREADY_MAPPED; 2445124272Swpaul return; 2446124272Swpaul } 2447124272Swpaul 2448124272Swpaul fh->nf_map = malloc(fh->nf_maplen, M_DEVBUF, M_NOWAIT); 2449124272Swpaul 2450124272Swpaul if (fh->nf_map == NULL) { 2451124272Swpaul *status = NDIS_STATUS_RESOURCES; 2452124272Swpaul return; 2453124272Swpaul } 2454124272Swpaul 2455124272Swpaul mtx_lock(&Giant); 2456124272Swpaul error = vn_rdwr(UIO_READ, fh->nf_vp, fh->nf_map, fh->nf_maplen, 0, 2457124272Swpaul UIO_SYSSPACE, 0, td->td_ucred, NOCRED, &resid, td); 2458124272Swpaul mtx_unlock(&Giant); 2459124272Swpaul 2460124272Swpaul if (error) 2461124272Swpaul *status = NDIS_STATUS_FAILURE; 2462124272Swpaul else { 2463124272Swpaul *status = NDIS_STATUS_SUCCESS; 2464124272Swpaul *mappedbuffer = fh->nf_map; 2465124272Swpaul } 2466124272Swpaul 2467123822Swpaul return; 2468123822Swpaul} 2469123822Swpaul 2470123822Swpaul__stdcall static void 2471123822Swpaulndis_unmap_file(filehandle) 2472123822Swpaul ndis_handle filehandle; 2473123822Swpaul{ 2474124272Swpaul ndis_fh *fh; 2475124272Swpaul fh = (ndis_fh *)filehandle; 2476124272Swpaul 2477124272Swpaul if (fh->nf_map == NULL) 2478124272Swpaul return; 2479124272Swpaul free(fh->nf_map, M_DEVBUF); 2480124272Swpaul fh->nf_map = NULL; 2481124272Swpaul 2482123822Swpaul return; 2483123822Swpaul} 2484123822Swpaul 2485123822Swpaul__stdcall static void 2486123822Swpaulndis_close_file(filehandle) 2487123822Swpaul ndis_handle filehandle; 2488123822Swpaul{ 2489124272Swpaul struct thread *td = curthread; 2490124272Swpaul ndis_fh *fh; 2491124272Swpaul 2492124272Swpaul if (filehandle == NULL) 2493124272Swpaul return; 2494124272Swpaul 2495124272Swpaul fh = (ndis_fh *)filehandle; 2496124272Swpaul if (fh->nf_map != NULL) { 2497124272Swpaul free(fh->nf_map, M_DEVBUF); 2498124272Swpaul fh->nf_map = NULL; 2499124272Swpaul } 2500124272Swpaul 2501124272Swpaul if (fh->nf_vp == NULL) 2502124272Swpaul return; 2503124272Swpaul 2504124272Swpaul mtx_lock(&Giant); 2505124272Swpaul vn_close(fh->nf_vp, FREAD, td->td_ucred, td); 2506124272Swpaul mtx_unlock(&Giant); 2507124272Swpaul 2508124272Swpaul fh->nf_vp = NULL; 2509124272Swpaul free(fh, M_DEVBUF); 2510124272Swpaul 2511123822Swpaul return; 2512123822Swpaul} 2513123822Swpaul 2514123848Swpaul__stdcall static uint8_t 2515123848Swpaulndis_cpu_cnt() 2516123848Swpaul{ 2517123848Swpaul return(mp_ncpus); 2518124509Swpaul} 2519123848Swpaul 2520124116Swpaultypedef void (*ndis_statusdone_handler)(ndis_handle); 2521124116Swpaultypedef void (*ndis_status_handler)(ndis_handle, ndis_status, 2522124116Swpaul void *, uint32_t); 2523124116Swpaul 2524123822Swpaul__stdcall static void 2525124116Swpaulndis_ind_statusdone(adapter) 2526124116Swpaul ndis_handle adapter; 2527124116Swpaul{ 2528124116Swpaul ndis_miniport_block *block; 2529124116Swpaul __stdcall ndis_statusdone_handler statusdonefunc; 2530124116Swpaul 2531124116Swpaul block = (ndis_miniport_block *)adapter; 2532124116Swpaul statusdonefunc = block->nmb_statusdone_func; 2533124116Swpaul 2534124116Swpaul statusdonefunc(adapter); 2535124116Swpaul return; 2536124116Swpaul} 2537124116Swpaul 2538124116Swpaul__stdcall static void 2539124116Swpaulndis_ind_status(adapter, status, sbuf, slen) 2540124116Swpaul ndis_handle adapter; 2541124116Swpaul ndis_status status; 2542124116Swpaul void *sbuf; 2543124116Swpaul uint32_t slen; 2544124116Swpaul{ 2545124116Swpaul ndis_miniport_block *block; 2546124116Swpaul __stdcall ndis_status_handler statusfunc; 2547124116Swpaul 2548124116Swpaul block = (ndis_miniport_block *)adapter; 2549124116Swpaul statusfunc = block->nmb_status_func; 2550124116Swpaul 2551124116Swpaul statusfunc(adapter, status, sbuf, slen); 2552124116Swpaul return; 2553124116Swpaul} 2554124116Swpaul 2555124122Swpaulstatic void 2556124697Swpaulndis_workfunc(ctx) 2557124122Swpaul void *ctx; 2558124122Swpaul{ 2559124122Swpaul ndis_work_item *work; 2560124122Swpaul __stdcall ndis_proc workfunc; 2561124122Swpaul 2562124122Swpaul work = ctx; 2563124122Swpaul workfunc = work->nwi_func; 2564124122Swpaul workfunc(work, work->nwi_ctx); 2565124122Swpaul return; 2566124122Swpaul} 2567124122Swpaul 2568124122Swpaul__stdcall static ndis_status 2569124122Swpaulndis_sched_workitem(work) 2570124122Swpaul ndis_work_item *work; 2571124122Swpaul{ 2572124697Swpaul ndis_sched(ndis_workfunc, work, NDIS_TASKQUEUE); 2573124122Swpaul return(NDIS_STATUS_SUCCESS); 2574124122Swpaul} 2575124122Swpaul 2576124116Swpaul__stdcall static void 2577124541Swpaulndis_pkt_to_pkt(dpkt, doff, reqlen, spkt, soff, cpylen) 2578124541Swpaul ndis_packet *dpkt; 2579124541Swpaul uint32_t doff; 2580124541Swpaul uint32_t reqlen; 2581124541Swpaul ndis_packet *spkt; 2582124541Swpaul uint32_t soff; 2583124541Swpaul uint32_t *cpylen; 2584124541Swpaul{ 2585124541Swpaul ndis_buffer *src, *dst; 2586124541Swpaul char *sptr, *dptr; 2587124541Swpaul int resid, copied, len, scnt, dcnt; 2588124541Swpaul 2589124541Swpaul *cpylen = 0; 2590124541Swpaul 2591124541Swpaul src = spkt->np_private.npp_head; 2592124541Swpaul dst = dpkt->np_private.npp_head; 2593124541Swpaul 2594124541Swpaul sptr = MDL_VA(src); 2595124541Swpaul dptr = MDL_VA(dst); 2596124541Swpaul scnt = src->nb_bytecount; 2597124541Swpaul dcnt = dst->nb_bytecount; 2598124541Swpaul 2599124541Swpaul while (soff) { 2600124541Swpaul if (src->nb_bytecount > soff) { 2601124541Swpaul sptr += soff; 2602124541Swpaul scnt = src->nb_bytecount - soff; 2603124541Swpaul break; 2604124541Swpaul } 2605124541Swpaul soff -= src->nb_bytecount; 2606124541Swpaul src = src->nb_next; 2607124541Swpaul if (src == NULL) 2608124541Swpaul return; 2609124541Swpaul sptr = MDL_VA(src); 2610124541Swpaul } 2611124541Swpaul 2612124541Swpaul while (doff) { 2613124541Swpaul if (dst->nb_bytecount > doff) { 2614124541Swpaul dptr += doff; 2615124541Swpaul dcnt = dst->nb_bytecount - doff; 2616124541Swpaul break; 2617124541Swpaul } 2618124541Swpaul doff -= dst->nb_bytecount; 2619124541Swpaul dst = dst->nb_next; 2620124541Swpaul if (dst == NULL) 2621124541Swpaul return; 2622124541Swpaul dptr = MDL_VA(dst); 2623124541Swpaul } 2624124541Swpaul 2625124541Swpaul resid = reqlen; 2626124541Swpaul copied = 0; 2627124541Swpaul 2628124541Swpaul while(1) { 2629124541Swpaul if (resid < scnt) 2630124541Swpaul len = resid; 2631124541Swpaul else 2632124541Swpaul len = scnt; 2633124541Swpaul if (dcnt < len) 2634124541Swpaul len = dcnt; 2635124541Swpaul 2636124541Swpaul bcopy(sptr, dptr, len); 2637124541Swpaul 2638124541Swpaul copied += len; 2639124541Swpaul resid -= len; 2640124541Swpaul if (resid == 0) 2641124541Swpaul break; 2642124541Swpaul 2643124541Swpaul dcnt -= len; 2644124541Swpaul if (dcnt == 0) { 2645124541Swpaul dst = dst->nb_next; 2646124541Swpaul if (dst == NULL) 2647124541Swpaul break; 2648124541Swpaul dptr = MDL_VA(dst); 2649124541Swpaul dcnt = dst->nb_bytecount; 2650124541Swpaul } 2651124541Swpaul 2652124541Swpaul scnt -= len; 2653124541Swpaul if (scnt == 0) { 2654124541Swpaul src = src->nb_next; 2655124541Swpaul if (src == NULL) 2656124541Swpaul break; 2657124541Swpaul sptr = MDL_VA(src); 2658124541Swpaul scnt = src->nb_bytecount; 2659124541Swpaul } 2660124541Swpaul } 2661124541Swpaul 2662124541Swpaul *cpylen = copied; 2663124541Swpaul return; 2664124541Swpaul} 2665124541Swpaul 2666124541Swpaul__stdcall static void 2667124541Swpaulndis_pkt_to_pkt_safe(dpkt, doff, reqlen, spkt, soff, cpylen, prio) 2668124541Swpaul ndis_packet *dpkt; 2669124541Swpaul uint32_t doff; 2670124541Swpaul uint32_t reqlen; 2671124541Swpaul ndis_packet *spkt; 2672124541Swpaul uint32_t soff; 2673124541Swpaul uint32_t *cpylen; 2674124541Swpaul uint32_t prio; 2675124541Swpaul{ 2676124541Swpaul ndis_pkt_to_pkt(dpkt, doff, reqlen, spkt, soff, cpylen); 2677124541Swpaul return; 2678124541Swpaul} 2679124541Swpaul 2680125057Swpaul__stdcall static ndis_status 2681125057Swpaulndis_register_dev(handle, devname, symname, majorfuncs, devobj, devhandle) 2682125057Swpaul ndis_handle *handle; 2683125057Swpaul ndis_unicode_string *devname; 2684125057Swpaul ndis_unicode_string *symname; 2685125057Swpaul void *majorfuncs; 2686125057Swpaul void *devobj; 2687125057Swpaul ndis_handle **devhandle; 2688125057Swpaul{ 2689125057Swpaul return(NDIS_STATUS_SUCCESS); 2690125057Swpaul} 2691125057Swpaul 2692125057Swpaul__stdcall static ndis_status 2693125057Swpaulndis_deregister_dev(devhandle) 2694125057Swpaul ndis_handle *devhandle; 2695125057Swpaul{ 2696125057Swpaul return(NDIS_STATUS_SUCCESS); 2697125057Swpaul} 2698125057Swpaul 2699125057Swpaul 2700124541Swpaul__stdcall static void 2701123474Swpauldummy() 2702123474Swpaul{ 2703123474Swpaul printf ("NDIS dummy called...\n"); 2704123474Swpaul return; 2705123474Swpaul} 2706123474Swpaul 2707123474Swpaulimage_patch_table ndis_functbl[] = { 2708124541Swpaul { "NdisCopyFromPacketToPacket", (FUNC)ndis_pkt_to_pkt }, 2709124541Swpaul { "NdisCopyFromPacketToPacketSafe", (FUNC)ndis_pkt_to_pkt_safe }, 2710124122Swpaul { "NdisScheduleWorkItem", (FUNC)ndis_sched_workitem }, 2711124116Swpaul { "NdisMIndicateStatusComplete", (FUNC)ndis_ind_statusdone }, 2712124116Swpaul { "NdisMIndicateStatus", (FUNC)ndis_ind_status }, 2713123848Swpaul { "NdisSystemProcessorCount", (FUNC)ndis_cpu_cnt }, 2714123721Swpaul { "NdisUnchainBufferAtBack", (FUNC)ndis_unchain_tailbuf, }, 2715123721Swpaul { "NdisGetFirstBufferFromPacket", (FUNC)ndis_firstbuf }, 2716123721Swpaul { "NdisGetFirstBufferFromPacketSafe", (FUNC)ndis_firstbuf_safe }, 2717123573Swpaul { "NdisGetBufferPhysicalArraySize", (FUNC)ndis_buf_physpages }, 2718123526Swpaul { "NdisMGetDeviceProperty", (FUNC)ndis_get_devprop }, 2719123526Swpaul { "NdisInitAnsiString", (FUNC)ndis_init_ansi_string }, 2720123941Swpaul { "NdisInitUnicodeString", (FUNC)ndis_init_unicode_string }, 2721123526Swpaul { "NdisWriteConfiguration", (FUNC)ndis_write_cfg }, 2722123526Swpaul { "NdisAnsiStringToUnicodeString", (FUNC)ndis_ansi2unicode }, 2723123526Swpaul { "NdisTerminateWrapper", (FUNC)ndis_termwrap }, 2724123526Swpaul { "NdisOpenConfigurationKeyByName", (FUNC)ndis_open_cfgbyname }, 2725123526Swpaul { "NdisOpenConfigurationKeyByIndex", (FUNC)ndis_open_cfgbyidx }, 2726123507Swpaul { "NdisMRemoveMiniport", (FUNC)ndis_remove_miniport }, 2727123507Swpaul { "NdisInitializeString", (FUNC)ndis_init_string }, 2728123507Swpaul { "NdisFreeString", (FUNC)ndis_free_string }, 2729123504Swpaul { "NdisGetCurrentSystemTime", (FUNC)ndis_time }, 2730123822Swpaul { "NdisGetSystemUpTime", (FUNC)ndis_uptime }, 2731123474Swpaul { "NdisMSynchronizeWithInterrupt", (FUNC)ndis_sync_with_intr }, 2732123474Swpaul { "NdisMAllocateSharedMemoryAsync", (FUNC)ndis_alloc_sharedmem_async }, 2733123474Swpaul { "NdisInterlockedInsertHeadList", (FUNC)ndis_insert_head }, 2734123474Swpaul { "NdisInterlockedInsertTailList", (FUNC)ndis_insert_tail }, 2735123474Swpaul { "NdisInterlockedRemoveHeadList", (FUNC)ndis_remove_head }, 2736123474Swpaul { "NdisInitializeWrapper", (FUNC)ndis_initwrap }, 2737123474Swpaul { "NdisMRegisterMiniport", (FUNC)ndis_register_miniport }, 2738123474Swpaul { "NdisAllocateMemoryWithTag", (FUNC)ndis_malloc_withtag }, 2739123474Swpaul { "NdisAllocateMemory", (FUNC)ndis_malloc }, 2740123474Swpaul { "NdisMSetAttributesEx", (FUNC)ndis_setattr_ex }, 2741123474Swpaul { "NdisCloseConfiguration", (FUNC)ndis_close_cfg }, 2742123474Swpaul { "NdisReadConfiguration", (FUNC)ndis_read_cfg }, 2743123474Swpaul { "NdisOpenConfiguration", (FUNC)ndis_open_cfg }, 2744123474Swpaul { "NdisReleaseSpinLock", (FUNC)ndis_unlock }, 2745123474Swpaul { "NdisDprAcquireSpinLock", (FUNC)ndis_lock }, 2746123474Swpaul { "NdisDprReleaseSpinLock", (FUNC)ndis_unlock }, 2747123474Swpaul { "NdisAcquireSpinLock", (FUNC)ndis_lock }, 2748123474Swpaul { "NdisAllocateSpinLock", (FUNC)ndis_create_lock }, 2749123474Swpaul { "NdisFreeSpinLock", (FUNC)ndis_destroy_lock }, 2750123474Swpaul { "NdisFreeMemory", (FUNC)ndis_free }, 2751123474Swpaul { "NdisReadPciSlotInformation", (FUNC)ndis_read_pci }, 2752123474Swpaul { "NdisWritePciSlotInformation",(FUNC)ndis_write_pci }, 2753124100Swpaul { "NdisImmediateReadPciSlotInformation", (FUNC)ndis_read_pci }, 2754124100Swpaul { "NdisImmediateWritePciSlotInformation", (FUNC)ndis_write_pci }, 2755123474Swpaul { "NdisWriteErrorLogEntry", (FUNC)ndis_syslog }, 2756123474Swpaul { "NdisMStartBufferPhysicalMapping", (FUNC)ndis_vtophys_load }, 2757123474Swpaul { "NdisMCompleteBufferPhysicalMapping", (FUNC)ndis_vtophys_unload }, 2758123474Swpaul { "NdisMInitializeTimer", (FUNC)ndis_create_timer }, 2759125057Swpaul { "NdisInitializeTimer", (FUNC)ndis_init_timer }, 2760123474Swpaul { "NdisSetTimer", (FUNC)ndis_set_timer }, 2761123474Swpaul { "NdisMCancelTimer", (FUNC)ndis_cancel_timer }, 2762125057Swpaul { "NdisCancelTimer", (FUNC)ndis_cancel_timer }, 2763123474Swpaul { "NdisMSetPeriodicTimer", (FUNC)ndis_set_periodic_timer }, 2764123474Swpaul { "NdisMQueryAdapterResources", (FUNC)ndis_query_resources }, 2765123474Swpaul { "NdisMRegisterIoPortRange", (FUNC)ndis_register_ioport }, 2766123474Swpaul { "NdisMDeregisterIoPortRange", (FUNC)ndis_deregister_ioport }, 2767123474Swpaul { "NdisReadNetworkAddress", (FUNC)ndis_read_netaddr }, 2768123848Swpaul { "NdisQueryMapRegisterCount", (FUNC)ndis_mapreg_cnt }, 2769123474Swpaul { "NdisMAllocateMapRegisters", (FUNC)ndis_alloc_mapreg }, 2770123848Swpaul { "NdisMFreeMapRegisters", (FUNC)ndis_free_mapreg }, 2771123474Swpaul { "NdisMAllocateSharedMemory", (FUNC)ndis_alloc_sharedmem }, 2772123474Swpaul { "NdisMMapIoSpace", (FUNC)ndis_map_iospace }, 2773123474Swpaul { "NdisMUnmapIoSpace", (FUNC)ndis_unmap_iospace }, 2774123474Swpaul { "NdisGetCacheFillSize", (FUNC)ndis_cachefill }, 2775123474Swpaul { "NdisMGetDmaAlignment", (FUNC)ndis_dma_align }, 2776123474Swpaul { "NdisMInitializeScatterGatherDma", (FUNC)ndis_init_sc_dma }, 2777123474Swpaul { "NdisAllocatePacketPool", (FUNC)ndis_alloc_packetpool }, 2778123474Swpaul { "NdisAllocatePacketPoolEx", (FUNC)ndis_ex_alloc_packetpool }, 2779123474Swpaul { "NdisAllocatePacket", (FUNC)ndis_alloc_packet }, 2780123474Swpaul { "NdisFreePacket", (FUNC)ndis_release_packet }, 2781123474Swpaul { "NdisFreePacketPool", (FUNC)ndis_free_packetpool }, 2782124097Swpaul { "NdisDprAllocatePacket", (FUNC)ndis_alloc_packet }, 2783124097Swpaul { "NdisDprFreePacket", (FUNC)ndis_release_packet }, 2784123474Swpaul { "NdisAllocateBufferPool", (FUNC)ndis_alloc_bufpool }, 2785123474Swpaul { "NdisAllocateBuffer", (FUNC)ndis_alloc_buf }, 2786123474Swpaul { "NdisQueryBuffer", (FUNC)ndis_query_buf }, 2787123474Swpaul { "NdisQueryBufferSafe", (FUNC)ndis_query_buf_safe }, 2788125069Swpaul { "NdisBufferVirtualAddress", (FUNC)ndis_buf_vaddr }, 2789125069Swpaul { "NdisBufferVirtualAddressSafe", (FUNC)ndis_buf_vaddr_safe }, 2790124100Swpaul { "NdisBufferLength", (FUNC)ndis_buflen }, 2791123474Swpaul { "NdisFreeBuffer", (FUNC)ndis_release_buf }, 2792123474Swpaul { "NdisFreeBufferPool", (FUNC)ndis_free_bufpool }, 2793123474Swpaul { "NdisInterlockedIncrement", (FUNC)ndis_interlock_inc }, 2794123474Swpaul { "NdisInterlockedDecrement", (FUNC)ndis_interlock_dec }, 2795123474Swpaul { "NdisInitializeEvent", (FUNC)ndis_init_event }, 2796123474Swpaul { "NdisSetEvent", (FUNC)ndis_set_event }, 2797123474Swpaul { "NdisResetEvent", (FUNC)ndis_reset_event }, 2798123474Swpaul { "NdisWaitEvent", (FUNC)ndis_wait_event }, 2799123474Swpaul { "NdisUnicodeStringToAnsiString", (FUNC)ndis_unicode2ansi }, 2800123474Swpaul { "NdisMPciAssignResources", (FUNC)ndis_assign_pcirsrc }, 2801123474Swpaul { "NdisMFreeSharedMemory", (FUNC)ndis_free_sharedmem }, 2802123474Swpaul { "NdisMRegisterInterrupt", (FUNC)ndis_register_intr }, 2803123474Swpaul { "NdisMDeregisterInterrupt", (FUNC)ndis_deregister_intr }, 2804123474Swpaul { "NdisMRegisterAdapterShutdownHandler", (FUNC)ndis_register_shutdown }, 2805123474Swpaul { "NdisMDeregisterAdapterShutdownHandler", (FUNC)ndis_deregister_shutdown }, 2806123474Swpaul { "NDIS_BUFFER_TO_SPAN_PAGES", (FUNC)ndis_numpages }, 2807123474Swpaul { "NdisQueryBufferOffset", (FUNC)ndis_query_bufoffset }, 2808123474Swpaul { "NdisAdjustBufferLength", (FUNC)ndis_adjust_buflen }, 2809123474Swpaul { "NdisPacketPoolUsage", (FUNC)ndis_packetpool_use }, 2810123474Swpaul { "NdisMSleep", (FUNC)ndis_sleep }, 2811123474Swpaul { "NdisUnchainBufferAtFront", (FUNC)ndis_unchain_headbuf }, 2812123474Swpaul { "NdisReadPcmciaAttributeMemory", (FUNC)ndis_read_pccard_amem }, 2813123474Swpaul { "NdisWritePcmciaAttributeMemory", (FUNC)ndis_write_pccard_amem }, 2814123822Swpaul { "NdisOpenFile", (FUNC)ndis_open_file }, 2815123822Swpaul { "NdisMapFile", (FUNC)ndis_map_file }, 2816123822Swpaul { "NdisUnmapFile", (FUNC)ndis_unmap_file }, 2817123822Swpaul { "NdisCloseFile", (FUNC)ndis_close_file }, 2818125057Swpaul { "NdisMRegisterDevice", (FUNC)ndis_register_dev }, 2819125057Swpaul { "NdisMDeregisterDevice", (FUNC)ndis_deregister_dev }, 2820123474Swpaul 2821123474Swpaul /* 2822123474Swpaul * This last entry is a catch-all for any function we haven't 2823123474Swpaul * implemented yet. The PE import list patching routine will 2824123474Swpaul * use it for any function that doesn't have an explicit match 2825123474Swpaul * in this table. 2826123474Swpaul */ 2827123474Swpaul 2828123474Swpaul { NULL, (FUNC)dummy }, 2829123474Swpaul 2830123474Swpaul /* End of list. */ 2831123474Swpaul 2832123474Swpaul { NULL, NULL }, 2833123474Swpaul}; 2834