kern_ndis.c revision 140751
1139743Simp/*- 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/kern_ndis.c 140751 2005-01-24 18:18:12Z wpaul $"); 35123474Swpaul 36123474Swpaul#include <sys/param.h> 37124697Swpaul#include <sys/systm.h> 38124697Swpaul#include <sys/unistd.h> 39123474Swpaul#include <sys/types.h> 40123474Swpaul#include <sys/errno.h> 41123474Swpaul#include <sys/callout.h> 42123474Swpaul#include <sys/socket.h> 43123474Swpaul#include <sys/queue.h> 44123474Swpaul#include <sys/sysctl.h> 45124697Swpaul#include <sys/proc.h> 46123474Swpaul#include <sys/malloc.h> 47123474Swpaul#include <sys/lock.h> 48123474Swpaul#include <sys/mutex.h> 49123474Swpaul#include <sys/conf.h> 50123474Swpaul 51123474Swpaul#include <sys/kernel.h> 52129970Swpaul#include <sys/module.h> 53124697Swpaul#include <sys/kthread.h> 54123474Swpaul#include <machine/bus.h> 55123474Swpaul#include <machine/resource.h> 56123474Swpaul#include <sys/bus.h> 57123474Swpaul#include <sys/rman.h> 58123474Swpaul 59124060Swpaul#include <vm/uma.h> 60124060Swpaul 61123474Swpaul#include <net/if.h> 62123474Swpaul#include <net/if_arp.h> 63123474Swpaul#include <net/ethernet.h> 64123474Swpaul#include <net/if_dl.h> 65123474Swpaul#include <net/if_media.h> 66123474Swpaul 67123695Swpaul#include <net80211/ieee80211_var.h> 68123695Swpaul#include <net80211/ieee80211_ioctl.h> 69123695Swpaul 70123474Swpaul#include <compat/ndis/pe_var.h> 71123474Swpaul#include <compat/ndis/resource_var.h> 72125551Swpaul#include <compat/ndis/ntoskrnl_var.h> 73123474Swpaul#include <compat/ndis/ndis_var.h> 74123474Swpaul#include <compat/ndis/hal_var.h> 75123474Swpaul#include <compat/ndis/cfg_var.h> 76123474Swpaul#include <dev/if_ndis/if_ndisvar.h> 77123474Swpaul 78123474Swpaul#define NDIS_DUMMY_PATH "\\\\some\\bogus\\path" 79123474Swpaul 80123474Swpaul__stdcall static void ndis_status_func(ndis_handle, ndis_status, 81123474Swpaul void *, uint32_t); 82123474Swpaul__stdcall static void ndis_statusdone_func(ndis_handle); 83123474Swpaul__stdcall static void ndis_setdone_func(ndis_handle, ndis_status); 84123535Swpaul__stdcall static void ndis_getdone_func(ndis_handle, ndis_status); 85123474Swpaul__stdcall static void ndis_resetdone_func(ndis_handle, ndis_status, uint8_t); 86124100Swpaul__stdcall static void ndis_sendrsrcavail_func(ndis_handle); 87123474Swpaul 88125057Swpaulstruct nd_head ndis_devhead; 89125057Swpaul 90124724Swpaulstruct ndis_req { 91124724Swpaul void (*nr_func)(void *); 92124724Swpaul void *nr_arg; 93124724Swpaul int nr_exit; 94124724Swpaul STAILQ_ENTRY(ndis_req) link; 95124724Swpaul}; 96124724Swpaul 97124724Swpaulstruct ndisproc { 98124724Swpaul struct ndisqhead *np_q; 99124724Swpaul struct proc *np_p; 100125814Swpaul int np_state; 101124724Swpaul}; 102124724Swpaul 103128546Swpaulstatic void ndis_return(void *); 104124697Swpaulstatic int ndis_create_kthreads(void); 105124697Swpaulstatic void ndis_destroy_kthreads(void); 106124697Swpaulstatic void ndis_stop_thread(int); 107124697Swpaulstatic int ndis_enlarge_thrqueue(int); 108124697Swpaulstatic int ndis_shrink_thrqueue(int); 109124697Swpaulstatic void ndis_runq(void *); 110124697Swpaul 111124060Swpaulstatic uma_zone_t ndis_packet_zone, ndis_buffer_zone; 112128229Swpaulstruct mtx ndis_thr_mtx; 113140267Swpaulstruct mtx ndis_req_mtx; 114124697Swpaulstatic STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; 115124697Swpaulstruct ndisqhead ndis_itodo; 116124697Swpaulstruct ndisqhead ndis_free; 117124697Swpaulstatic int ndis_jobs = 32; 118124060Swpaul 119124724Swpaulstatic struct ndisproc ndis_tproc; 120124724Swpaulstatic struct ndisproc ndis_iproc; 121124697Swpaul 122123474Swpaul/* 123123474Swpaul * This allows us to export our symbols to other modules. 124123474Swpaul * Note that we call ourselves 'ndisapi' to avoid a namespace 125123474Swpaul * collision with if_ndis.ko, which internally calls itself 126123474Swpaul * 'ndis.' 127123474Swpaul */ 128123474Swpaulstatic int 129123474Swpaulndis_modevent(module_t mod, int cmd, void *arg) 130123474Swpaul{ 131124060Swpaul int error = 0; 132124060Swpaul 133124060Swpaul switch (cmd) { 134124060Swpaul case MOD_LOAD: 135124122Swpaul /* Initialize subsystems */ 136124122Swpaul ndis_libinit(); 137124122Swpaul ntoskrnl_libinit(); 138124122Swpaul 139124122Swpaul /* Initialize TX buffer UMA zone. */ 140124060Swpaul ndis_packet_zone = uma_zcreate("NDIS packet", 141124060Swpaul sizeof(ndis_packet), NULL, NULL, NULL, 142124060Swpaul NULL, UMA_ALIGN_PTR, 0); 143124060Swpaul ndis_buffer_zone = uma_zcreate("NDIS buffer", 144124060Swpaul sizeof(ndis_buffer), NULL, NULL, NULL, 145124060Swpaul NULL, UMA_ALIGN_PTR, 0); 146124697Swpaul 147124697Swpaul ndis_create_kthreads(); 148124697Swpaul 149125057Swpaul TAILQ_INIT(&ndis_devhead); 150125057Swpaul 151124060Swpaul break; 152124060Swpaul case MOD_SHUTDOWN: 153124697Swpaul /* stop kthreads */ 154124697Swpaul ndis_destroy_kthreads(); 155127311Swpaul if (TAILQ_FIRST(&ndis_devhead) == NULL) { 156125006Swpaul /* Shut down subsystems */ 157125006Swpaul ndis_libfini(); 158125006Swpaul ntoskrnl_libfini(); 159124697Swpaul 160125006Swpaul /* Remove zones */ 161125006Swpaul uma_zdestroy(ndis_packet_zone); 162125006Swpaul uma_zdestroy(ndis_buffer_zone); 163125006Swpaul } 164125006Swpaul break; 165125006Swpaul case MOD_UNLOAD: 166125006Swpaul /* stop kthreads */ 167125006Swpaul ndis_destroy_kthreads(); 168125006Swpaul 169124122Swpaul /* Shut down subsystems */ 170124122Swpaul ndis_libfini(); 171124122Swpaul ntoskrnl_libfini(); 172124122Swpaul 173124122Swpaul /* Remove zones */ 174124060Swpaul uma_zdestroy(ndis_packet_zone); 175124060Swpaul uma_zdestroy(ndis_buffer_zone); 176124060Swpaul break; 177124060Swpaul default: 178124060Swpaul error = EINVAL; 179124060Swpaul break; 180124060Swpaul } 181124060Swpaul 182124060Swpaul return(error); 183123474Swpaul} 184123474SwpaulDEV_MODULE(ndisapi, ndis_modevent, NULL); 185123474SwpaulMODULE_VERSION(ndisapi, 1); 186123474Swpaul 187124697Swpaul/* 188124697Swpaul * We create two kthreads for the NDIS subsystem. One of them is a task 189124697Swpaul * queue for performing various odd jobs. The other is an swi thread 190124697Swpaul * reserved exclusively for running interrupt handlers. The reason we 191124697Swpaul * have our own task queue is that there are some cases where we may 192124697Swpaul * need to sleep for a significant amount of time, and if we were to 193124697Swpaul * use one of the taskqueue threads, we might delay the processing 194124697Swpaul * of other pending tasks which might need to run right away. We have 195124697Swpaul * a separate swi thread because we don't want our interrupt handling 196124697Swpaul * to be delayed either. 197124697Swpaul * 198124697Swpaul * By default there are 32 jobs available to start, and another 8 199124697Swpaul * are added to the free list each time a new device is created. 200124697Swpaul */ 201123474Swpaul 202124697Swpaulstatic void 203124724Swpaulndis_runq(arg) 204124724Swpaul void *arg; 205124697Swpaul{ 206124697Swpaul struct ndis_req *r = NULL, *die = NULL; 207124724Swpaul struct ndisproc *p; 208124697Swpaul 209124724Swpaul p = arg; 210124724Swpaul 211124697Swpaul while (1) { 212124697Swpaul 213128229Swpaul /* Sleep, but preserve our original priority. */ 214128229Swpaul ndis_thsuspend(p->np_p, 0); 215128229Swpaul 216124697Swpaul /* Look for any jobs on the work queue. */ 217124697Swpaul 218128229Swpaul mtx_lock(&ndis_thr_mtx); 219125814Swpaul p->np_state = NDIS_PSTATE_RUNNING; 220124724Swpaul while(STAILQ_FIRST(p->np_q) != NULL) { 221124724Swpaul r = STAILQ_FIRST(p->np_q); 222124724Swpaul STAILQ_REMOVE_HEAD(p->np_q, link); 223128229Swpaul mtx_unlock(&ndis_thr_mtx); 224124697Swpaul 225124697Swpaul /* Do the work. */ 226124697Swpaul 227124724Swpaul if (r->nr_func != NULL) 228124724Swpaul (*r->nr_func)(r->nr_arg); 229124697Swpaul 230128229Swpaul mtx_lock(&ndis_thr_mtx); 231124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 232124697Swpaul 233124697Swpaul /* Check for a shutdown request */ 234124697Swpaul 235124724Swpaul if (r->nr_exit == TRUE) 236124697Swpaul die = r; 237124697Swpaul } 238125814Swpaul p->np_state = NDIS_PSTATE_SLEEPING; 239128229Swpaul mtx_unlock(&ndis_thr_mtx); 240124697Swpaul 241124697Swpaul /* Bail if we were told to shut down. */ 242124697Swpaul 243124697Swpaul if (die != NULL) 244124697Swpaul break; 245124697Swpaul } 246124697Swpaul 247124697Swpaul wakeup(die); 248130166Swpaul#if __FreeBSD_version < 502113 249130166Swpaul mtx_lock(&Giant); 250130166Swpaul#endif 251124697Swpaul kthread_exit(0); 252128229Swpaul return; /* notreached */ 253124697Swpaul} 254124697Swpaul 255124697Swpaulstatic int 256124697Swpaulndis_create_kthreads() 257124697Swpaul{ 258124697Swpaul struct ndis_req *r; 259124697Swpaul int i, error = 0; 260124697Swpaul 261128229Swpaul mtx_init(&ndis_thr_mtx, "NDIS thread lock", 262128229Swpaul MTX_NDIS_LOCK, MTX_DEF); 263140267Swpaul mtx_init(&ndis_req_mtx, "NDIS request lock", 264140267Swpaul MTX_NDIS_LOCK, MTX_DEF); 265128229Swpaul 266124697Swpaul STAILQ_INIT(&ndis_ttodo); 267124697Swpaul STAILQ_INIT(&ndis_itodo); 268124697Swpaul STAILQ_INIT(&ndis_free); 269124697Swpaul 270124697Swpaul for (i = 0; i < ndis_jobs; i++) { 271124697Swpaul r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 272124697Swpaul if (r == NULL) { 273124697Swpaul error = ENOMEM; 274124697Swpaul break; 275124697Swpaul } 276124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 277124697Swpaul } 278124697Swpaul 279124724Swpaul if (error == 0) { 280124724Swpaul ndis_tproc.np_q = &ndis_ttodo; 281125814Swpaul ndis_tproc.np_state = NDIS_PSTATE_SLEEPING; 282124724Swpaul error = kthread_create(ndis_runq, &ndis_tproc, 283127284Swpaul &ndis_tproc.np_p, RFHIGHPID, 284127284Swpaul NDIS_KSTACK_PAGES, "ndis taskqueue"); 285124724Swpaul } 286124697Swpaul 287124724Swpaul if (error == 0) { 288124724Swpaul ndis_iproc.np_q = &ndis_itodo; 289125814Swpaul ndis_iproc.np_state = NDIS_PSTATE_SLEEPING; 290124724Swpaul error = kthread_create(ndis_runq, &ndis_iproc, 291127284Swpaul &ndis_iproc.np_p, RFHIGHPID, 292127284Swpaul NDIS_KSTACK_PAGES, "ndis swi"); 293124724Swpaul } 294124697Swpaul 295124697Swpaul if (error) { 296124697Swpaul while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 297124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 298124697Swpaul free(r, M_DEVBUF); 299124697Swpaul } 300124697Swpaul return(error); 301124697Swpaul } 302124697Swpaul 303124697Swpaul return(0); 304124697Swpaul} 305124697Swpaul 306124697Swpaulstatic void 307124697Swpaulndis_destroy_kthreads() 308124697Swpaul{ 309124697Swpaul struct ndis_req *r; 310124697Swpaul 311124697Swpaul /* Stop the threads. */ 312124697Swpaul 313124697Swpaul ndis_stop_thread(NDIS_TASKQUEUE); 314124697Swpaul ndis_stop_thread(NDIS_SWI); 315124697Swpaul 316124697Swpaul /* Destroy request structures. */ 317124697Swpaul 318124697Swpaul while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 319124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 320124697Swpaul free(r, M_DEVBUF); 321124697Swpaul } 322124697Swpaul 323140267Swpaul mtx_destroy(&ndis_req_mtx); 324128229Swpaul mtx_destroy(&ndis_thr_mtx); 325128229Swpaul 326124697Swpaul return; 327124697Swpaul} 328124697Swpaul 329124697Swpaulstatic void 330124697Swpaulndis_stop_thread(t) 331124697Swpaul int t; 332124697Swpaul{ 333124697Swpaul struct ndis_req *r; 334124697Swpaul struct ndisqhead *q; 335124697Swpaul struct proc *p; 336124697Swpaul 337124697Swpaul if (t == NDIS_TASKQUEUE) { 338124697Swpaul q = &ndis_ttodo; 339124724Swpaul p = ndis_tproc.np_p; 340124697Swpaul } else { 341124697Swpaul q = &ndis_itodo; 342124724Swpaul p = ndis_iproc.np_p; 343124697Swpaul } 344124697Swpaul 345124697Swpaul /* Create and post a special 'exit' job. */ 346124697Swpaul 347128229Swpaul mtx_lock(&ndis_thr_mtx); 348124697Swpaul r = STAILQ_FIRST(&ndis_free); 349124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 350124724Swpaul r->nr_func = NULL; 351124724Swpaul r->nr_arg = NULL; 352124724Swpaul r->nr_exit = TRUE; 353124697Swpaul STAILQ_INSERT_TAIL(q, r, link); 354128229Swpaul mtx_unlock(&ndis_thr_mtx); 355124697Swpaul 356128229Swpaul ndis_thresume(p); 357124697Swpaul 358124697Swpaul /* wait for thread exit */ 359124697Swpaul 360128295Swpaul tsleep(r, curthread->td_priority|PCATCH, "ndisthexit", hz * 60); 361124697Swpaul 362124697Swpaul /* Now empty the job list. */ 363124697Swpaul 364128229Swpaul mtx_lock(&ndis_thr_mtx); 365124697Swpaul while ((r = STAILQ_FIRST(q)) != NULL) { 366124697Swpaul STAILQ_REMOVE_HEAD(q, link); 367124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 368124697Swpaul } 369128229Swpaul mtx_unlock(&ndis_thr_mtx); 370124697Swpaul 371124697Swpaul return; 372124697Swpaul} 373124697Swpaul 374124697Swpaulstatic int 375124697Swpaulndis_enlarge_thrqueue(cnt) 376124697Swpaul int cnt; 377124697Swpaul{ 378124697Swpaul struct ndis_req *r; 379124697Swpaul int i; 380124697Swpaul 381124697Swpaul for (i = 0; i < cnt; i++) { 382124697Swpaul r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 383124697Swpaul if (r == NULL) 384124697Swpaul return(ENOMEM); 385128229Swpaul mtx_lock(&ndis_thr_mtx); 386124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 387124697Swpaul ndis_jobs++; 388128229Swpaul mtx_unlock(&ndis_thr_mtx); 389124697Swpaul } 390124697Swpaul 391124697Swpaul return(0); 392124697Swpaul} 393124697Swpaul 394124697Swpaulstatic int 395124697Swpaulndis_shrink_thrqueue(cnt) 396124697Swpaul int cnt; 397124697Swpaul{ 398124697Swpaul struct ndis_req *r; 399124697Swpaul int i; 400124697Swpaul 401124697Swpaul for (i = 0; i < cnt; i++) { 402128229Swpaul mtx_lock(&ndis_thr_mtx); 403124697Swpaul r = STAILQ_FIRST(&ndis_free); 404124697Swpaul if (r == NULL) { 405128229Swpaul mtx_unlock(&ndis_thr_mtx); 406124697Swpaul return(ENOMEM); 407124697Swpaul } 408124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 409124697Swpaul ndis_jobs--; 410128229Swpaul mtx_unlock(&ndis_thr_mtx); 411124697Swpaul free(r, M_DEVBUF); 412124697Swpaul } 413124697Swpaul 414124697Swpaul return(0); 415124697Swpaul} 416124697Swpaul 417124697Swpaulint 418127393Swpaulndis_unsched(func, arg, t) 419127393Swpaul void (*func)(void *); 420127393Swpaul void *arg; 421127393Swpaul int t; 422127393Swpaul{ 423127393Swpaul struct ndis_req *r; 424127393Swpaul struct ndisqhead *q; 425127393Swpaul struct proc *p; 426127393Swpaul 427127393Swpaul if (t == NDIS_TASKQUEUE) { 428127393Swpaul q = &ndis_ttodo; 429127393Swpaul p = ndis_tproc.np_p; 430127393Swpaul } else { 431127393Swpaul q = &ndis_itodo; 432127393Swpaul p = ndis_iproc.np_p; 433127393Swpaul } 434127393Swpaul 435128229Swpaul mtx_lock(&ndis_thr_mtx); 436127393Swpaul STAILQ_FOREACH(r, q, link) { 437127393Swpaul if (r->nr_func == func && r->nr_arg == arg) { 438127393Swpaul STAILQ_REMOVE(q, r, ndis_req, link); 439127393Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 440128229Swpaul mtx_unlock(&ndis_thr_mtx); 441127393Swpaul return(0); 442127393Swpaul } 443127393Swpaul } 444127393Swpaul 445128229Swpaul mtx_unlock(&ndis_thr_mtx); 446127393Swpaul 447127393Swpaul return(ENOENT); 448127393Swpaul} 449127393Swpaul 450127393Swpaulint 451124697Swpaulndis_sched(func, arg, t) 452124697Swpaul void (*func)(void *); 453124697Swpaul void *arg; 454124697Swpaul int t; 455124697Swpaul{ 456124697Swpaul struct ndis_req *r; 457124697Swpaul struct ndisqhead *q; 458124697Swpaul struct proc *p; 459125814Swpaul int s; 460124697Swpaul 461124697Swpaul if (t == NDIS_TASKQUEUE) { 462124697Swpaul q = &ndis_ttodo; 463124724Swpaul p = ndis_tproc.np_p; 464124697Swpaul } else { 465124697Swpaul q = &ndis_itodo; 466124724Swpaul p = ndis_iproc.np_p; 467124697Swpaul } 468124697Swpaul 469128229Swpaul mtx_lock(&ndis_thr_mtx); 470124697Swpaul /* 471124697Swpaul * Check to see if an instance of this job is already 472124697Swpaul * pending. If so, don't bother queuing it again. 473124697Swpaul */ 474124697Swpaul STAILQ_FOREACH(r, q, link) { 475124724Swpaul if (r->nr_func == func && r->nr_arg == arg) { 476128229Swpaul mtx_unlock(&ndis_thr_mtx); 477124697Swpaul return(0); 478124697Swpaul } 479124697Swpaul } 480124697Swpaul r = STAILQ_FIRST(&ndis_free); 481124697Swpaul if (r == NULL) { 482128229Swpaul mtx_unlock(&ndis_thr_mtx); 483124697Swpaul return(EAGAIN); 484124697Swpaul } 485124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 486124724Swpaul r->nr_func = func; 487124724Swpaul r->nr_arg = arg; 488124724Swpaul r->nr_exit = FALSE; 489124697Swpaul STAILQ_INSERT_TAIL(q, r, link); 490125814Swpaul if (t == NDIS_TASKQUEUE) 491125814Swpaul s = ndis_tproc.np_state; 492125814Swpaul else 493125814Swpaul s = ndis_iproc.np_state; 494128229Swpaul mtx_unlock(&ndis_thr_mtx); 495124697Swpaul 496125814Swpaul /* 497125814Swpaul * Post the job, but only if the thread is actually blocked 498125814Swpaul * on its own suspend call. If a driver queues up a job with 499125814Swpaul * NdisScheduleWorkItem() which happens to do a KeWaitForObject(), 500125814Swpaul * it may suspend there, and in that case we don't want to wake 501125814Swpaul * it up until KeWaitForObject() gets woken up on its own. 502125814Swpaul */ 503125814Swpaul if (s == NDIS_PSTATE_SLEEPING) 504128229Swpaul ndis_thresume(p); 505124697Swpaul 506124697Swpaul return(0); 507124697Swpaul} 508124697Swpaul 509128229Swpaulint 510128229Swpaulndis_thsuspend(p, timo) 511128229Swpaul struct proc *p; 512128229Swpaul int timo; 513128229Swpaul{ 514128229Swpaul int error; 515128229Swpaul 516128229Swpaul PROC_LOCK(p); 517128229Swpaul error = msleep(&p->p_siglist, &p->p_mtx, 518128229Swpaul curthread->td_priority|PDROP, "ndissp", timo); 519128229Swpaul return(error); 520128229Swpaul} 521128229Swpaul 522128229Swpaulvoid 523128229Swpaulndis_thresume(p) 524128229Swpaul struct proc *p; 525128229Swpaul{ 526128229Swpaul wakeup(&p->p_siglist); 527128229Swpaul return; 528128229Swpaul} 529128229Swpaul 530123474Swpaul__stdcall static void 531124100Swpaulndis_sendrsrcavail_func(adapter) 532124100Swpaul ndis_handle adapter; 533124100Swpaul{ 534124100Swpaul return; 535124100Swpaul} 536124100Swpaul 537124100Swpaul__stdcall static void 538123474Swpaulndis_status_func(adapter, status, sbuf, slen) 539123474Swpaul ndis_handle adapter; 540123474Swpaul ndis_status status; 541123474Swpaul void *sbuf; 542123474Swpaul uint32_t slen; 543123474Swpaul{ 544124060Swpaul ndis_miniport_block *block; 545124060Swpaul block = adapter; 546124060Swpaul 547124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 548124409Swpaul device_printf (block->nmb_dev, "status: %x\n", status); 549123474Swpaul return; 550123474Swpaul} 551123474Swpaul 552123474Swpaul__stdcall static void 553123474Swpaulndis_statusdone_func(adapter) 554123474Swpaul ndis_handle adapter; 555123474Swpaul{ 556124060Swpaul ndis_miniport_block *block; 557124060Swpaul block = adapter; 558124060Swpaul 559124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 560124409Swpaul device_printf (block->nmb_dev, "status complete\n"); 561123474Swpaul return; 562123474Swpaul} 563123474Swpaul 564123474Swpaul__stdcall static void 565123474Swpaulndis_setdone_func(adapter, status) 566123474Swpaul ndis_handle adapter; 567123474Swpaul ndis_status status; 568123474Swpaul{ 569123695Swpaul ndis_miniport_block *block; 570123695Swpaul block = adapter; 571123695Swpaul 572123695Swpaul block->nmb_setstat = status; 573140267Swpaul wakeup(&block->nmb_setstat); 574123474Swpaul return; 575123474Swpaul} 576123474Swpaul 577123474Swpaul__stdcall static void 578123535Swpaulndis_getdone_func(adapter, status) 579123535Swpaul ndis_handle adapter; 580123535Swpaul ndis_status status; 581123535Swpaul{ 582123695Swpaul ndis_miniport_block *block; 583123695Swpaul block = adapter; 584123695Swpaul 585123695Swpaul block->nmb_getstat = status; 586140267Swpaul wakeup(&block->nmb_getstat); 587123535Swpaul return; 588123535Swpaul} 589123535Swpaul 590123535Swpaul__stdcall static void 591123474Swpaulndis_resetdone_func(adapter, status, addressingreset) 592123474Swpaul ndis_handle adapter; 593123474Swpaul ndis_status status; 594123474Swpaul uint8_t addressingreset; 595123474Swpaul{ 596124060Swpaul ndis_miniport_block *block; 597124060Swpaul block = adapter; 598124060Swpaul 599124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 600124409Swpaul device_printf (block->nmb_dev, "reset done...\n"); 601127887Swpaul wakeup(block->nmb_ifp); 602123474Swpaul return; 603123474Swpaul} 604123474Swpaul 605123474Swpaulint 606123474Swpaulndis_create_sysctls(arg) 607123474Swpaul void *arg; 608123474Swpaul{ 609123474Swpaul struct ndis_softc *sc; 610123474Swpaul ndis_cfg *vals; 611123474Swpaul char buf[256]; 612132973Swpaul struct sysctl_oid *oidp; 613132973Swpaul struct sysctl_ctx_entry *e; 614123474Swpaul 615123474Swpaul if (arg == NULL) 616123474Swpaul return(EINVAL); 617123474Swpaul 618123474Swpaul sc = arg; 619123474Swpaul vals = sc->ndis_regvals; 620123474Swpaul 621123474Swpaul TAILQ_INIT(&sc->ndis_cfglist_head); 622123474Swpaul 623130097Sdes#if __FreeBSD_version < 502113 624123474Swpaul /* Create the sysctl tree. */ 625123474Swpaul 626123474Swpaul sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 627123474Swpaul SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 628123474Swpaul device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 629123474Swpaul device_get_desc(sc->ndis_dev)); 630123474Swpaul 631130097Sdes#endif 632123474Swpaul /* Add the driver-specific registry keys. */ 633123474Swpaul 634123474Swpaul vals = sc->ndis_regvals; 635123474Swpaul while(1) { 636123474Swpaul if (vals->nc_cfgkey == NULL) 637123474Swpaul break; 638123620Swpaul if (vals->nc_idx != sc->ndis_devidx) { 639123620Swpaul vals++; 640123620Swpaul continue; 641123620Swpaul } 642132973Swpaul 643132973Swpaul /* See if we already have a sysctl with this name */ 644132973Swpaul 645132973Swpaul oidp = NULL; 646130097Sdes#if __FreeBSD_version < 502113 647132973Swpaul TAILQ_FOREACH(e, &sc->ndis_ctx, link) { 648132973Swpaul#else 649132973Swpaul TAILQ_FOREACH(e, device_get_sysctl_ctx(sc->ndis_dev), link) { 650132973Swpaul#endif 651132973Swpaul oidp = e->entry; 652132973Swpaul if (ndis_strcasecmp(oidp->oid_name, 653132973Swpaul vals->nc_cfgkey) == 0) 654132973Swpaul break; 655132973Swpaul oidp = NULL; 656132973Swpaul } 657132973Swpaul 658132973Swpaul if (oidp != NULL) { 659132973Swpaul vals++; 660132973Swpaul continue; 661132973Swpaul } 662132973Swpaul 663132973Swpaul#if __FreeBSD_version < 502113 664123474Swpaul SYSCTL_ADD_STRING(&sc->ndis_ctx, 665123474Swpaul SYSCTL_CHILDREN(sc->ndis_tree), 666130097Sdes#else 667130097Sdes SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 668130097Sdes SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 669130097Sdes#endif 670123474Swpaul OID_AUTO, vals->nc_cfgkey, 671123474Swpaul CTLFLAG_RW, vals->nc_val, 672123474Swpaul sizeof(vals->nc_val), 673123474Swpaul vals->nc_cfgdesc); 674123474Swpaul vals++; 675123474Swpaul } 676123474Swpaul 677123474Swpaul /* Now add a couple of builtin keys. */ 678123474Swpaul 679123474Swpaul /* 680123474Swpaul * Environment can be either Windows (0) or WindowsNT (1). 681123474Swpaul * We qualify as the latter. 682123474Swpaul */ 683123474Swpaul ndis_add_sysctl(sc, "Environment", 684123474Swpaul "Windows environment", "1", CTLFLAG_RD); 685123474Swpaul 686123474Swpaul /* NDIS version should be 5.1. */ 687123474Swpaul ndis_add_sysctl(sc, "NdisVersion", 688123474Swpaul "NDIS API Version", "0x00050001", CTLFLAG_RD); 689123474Swpaul 690123474Swpaul /* Bus type (PCI, PCMCIA, etc...) */ 691124272Swpaul sprintf(buf, "%d", (int)sc->ndis_iftype); 692123474Swpaul ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 693123474Swpaul 694123474Swpaul if (sc->ndis_res_io != NULL) { 695124272Swpaul sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 696123474Swpaul ndis_add_sysctl(sc, "IOBaseAddress", 697123474Swpaul "Base I/O Address", buf, CTLFLAG_RD); 698123474Swpaul } 699123474Swpaul 700123474Swpaul if (sc->ndis_irq != NULL) { 701124272Swpaul sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 702123474Swpaul ndis_add_sysctl(sc, "InterruptNumber", 703123474Swpaul "Interrupt Number", buf, CTLFLAG_RD); 704123474Swpaul } 705123474Swpaul 706123474Swpaul return(0); 707123474Swpaul} 708123474Swpaul 709123474Swpaulint 710123474Swpaulndis_add_sysctl(arg, key, desc, val, flag) 711123474Swpaul void *arg; 712123474Swpaul char *key; 713123474Swpaul char *desc; 714123474Swpaul char *val; 715123474Swpaul int flag; 716123474Swpaul{ 717123474Swpaul struct ndis_softc *sc; 718123474Swpaul struct ndis_cfglist *cfg; 719123474Swpaul char descstr[256]; 720123474Swpaul 721123474Swpaul sc = arg; 722123474Swpaul 723123474Swpaul cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 724123474Swpaul 725123474Swpaul if (cfg == NULL) 726123474Swpaul return(ENOMEM); 727123474Swpaul 728123474Swpaul cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 729123474Swpaul if (desc == NULL) { 730123474Swpaul snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 731123474Swpaul cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 732123474Swpaul } else 733123474Swpaul cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 734123474Swpaul strcpy(cfg->ndis_cfg.nc_val, val); 735123474Swpaul 736123474Swpaul TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 737123474Swpaul 738130097Sdes#if __FreeBSD_version < 502113 739123474Swpaul SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 740130097Sdes#else 741130097Sdes SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 742130097Sdes SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 743130097Sdes#endif 744123474Swpaul OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 745123474Swpaul cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 746123474Swpaul cfg->ndis_cfg.nc_cfgdesc); 747123474Swpaul 748123474Swpaul return(0); 749123474Swpaul} 750123474Swpaul 751123474Swpaulint 752123474Swpaulndis_flush_sysctls(arg) 753123474Swpaul void *arg; 754123474Swpaul{ 755123474Swpaul struct ndis_softc *sc; 756123474Swpaul struct ndis_cfglist *cfg; 757123474Swpaul 758123474Swpaul sc = arg; 759123474Swpaul 760123474Swpaul while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 761123474Swpaul cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 762123474Swpaul TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 763123474Swpaul free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 764123474Swpaul free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 765123474Swpaul free(cfg, M_DEVBUF); 766123474Swpaul } 767123474Swpaul 768123474Swpaul return(0); 769123474Swpaul} 770123474Swpaul 771128546Swpaulstatic void 772128546Swpaulndis_return(arg) 773123474Swpaul void *arg; 774123474Swpaul{ 775123474Swpaul struct ndis_softc *sc; 776128546Swpaul __stdcall ndis_return_handler returnfunc; 777123474Swpaul ndis_handle adapter; 778123535Swpaul ndis_packet *p; 779128229Swpaul uint8_t irql; 780123474Swpaul 781128546Swpaul p = arg; 782128546Swpaul sc = p->np_softc; 783128546Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 784128546Swpaul 785128546Swpaul if (adapter == NULL) 786128546Swpaul return; 787128546Swpaul 788128546Swpaul returnfunc = sc->ndis_chars.nmc_return_packet_func; 789140751Swpaul irql = KeRaiseIrql(DISPATCH_LEVEL); 790128546Swpaul returnfunc(adapter, p); 791140751Swpaul KeLowerIrql(irql); 792128546Swpaul 793128546Swpaul return; 794128546Swpaul} 795128546Swpaul 796128546Swpaulvoid 797128546Swpaulndis_return_packet(buf, arg) 798128546Swpaul void *buf; /* not used */ 799128546Swpaul void *arg; 800128546Swpaul{ 801128546Swpaul ndis_packet *p; 802128546Swpaul 803123826Swpaul if (arg == NULL) 804123474Swpaul return; 805123474Swpaul 806123826Swpaul p = arg; 807123535Swpaul 808123535Swpaul /* Decrement refcount. */ 809123826Swpaul p->np_refcnt--; 810123535Swpaul 811123535Swpaul /* Release packet when refcount hits zero, otherwise return. */ 812123826Swpaul if (p->np_refcnt) 813123535Swpaul return; 814123536Swpaul 815128546Swpaul ndis_sched(ndis_return, p, NDIS_SWI); 816123858Swpaul 817123474Swpaul return; 818123474Swpaul} 819123474Swpaul 820123848Swpaulvoid 821123848Swpaulndis_free_bufs(b0) 822123848Swpaul ndis_buffer *b0; 823123848Swpaul{ 824123848Swpaul ndis_buffer *next; 825123848Swpaul 826123848Swpaul if (b0 == NULL) 827123848Swpaul return; 828123848Swpaul 829123848Swpaul while(b0 != NULL) { 830140751Swpaul next = b0->mdl_next; 831124060Swpaul uma_zfree (ndis_buffer_zone, b0); 832123848Swpaul b0 = next; 833123848Swpaul } 834123848Swpaul 835123848Swpaul return; 836123848Swpaul} 837123848Swpaul 838123848Swpaulvoid 839123848Swpaulndis_free_packet(p) 840123848Swpaul ndis_packet *p; 841123848Swpaul{ 842123848Swpaul if (p == NULL) 843123848Swpaul return; 844123848Swpaul 845123848Swpaul ndis_free_bufs(p->np_private.npp_head); 846124060Swpaul uma_zfree(ndis_packet_zone, p); 847123848Swpaul 848123848Swpaul return; 849123848Swpaul} 850123848Swpaul 851123474Swpaulint 852123474Swpaulndis_convert_res(arg) 853123474Swpaul void *arg; 854123474Swpaul{ 855123474Swpaul struct ndis_softc *sc; 856123474Swpaul ndis_resource_list *rl = NULL; 857123474Swpaul cm_partial_resource_desc *prd = NULL; 858123474Swpaul ndis_miniport_block *block; 859123976Swpaul device_t dev; 860123976Swpaul struct resource_list *brl; 861127411Swpaul struct resource_list brl_rev; 862127411Swpaul struct resource_list_entry *brle, *n; 863127411Swpaul int error = 0; 864123474Swpaul 865123474Swpaul sc = arg; 866123474Swpaul block = &sc->ndis_block; 867123976Swpaul dev = sc->ndis_dev; 868123474Swpaul 869128012Swpaul SLIST_INIT(&brl_rev); 870128012Swpaul 871123474Swpaul rl = malloc(sizeof(ndis_resource_list) + 872123474Swpaul (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 873123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 874123474Swpaul 875123474Swpaul if (rl == NULL) 876123474Swpaul return(ENOMEM); 877123474Swpaul 878123474Swpaul rl->cprl_version = 5; 879123474Swpaul rl->cprl_version = 1; 880123474Swpaul rl->cprl_count = sc->ndis_rescnt; 881123474Swpaul prd = rl->cprl_partial_descs; 882123474Swpaul 883131953Swpaul brl = BUS_GET_RESOURCE_LIST(dev, dev); 884131953Swpaul 885123976Swpaul if (brl != NULL) { 886127411Swpaul 887127411Swpaul /* 888127411Swpaul * We have a small problem. Some PCI devices have 889127411Swpaul * multiple I/O ranges. Windows orders them starting 890127411Swpaul * from lowest numbered BAR to highest. We discover 891127411Swpaul * them in that order too, but insert them into a singly 892127411Swpaul * linked list head first, which means when time comes 893127411Swpaul * to traverse the list, we enumerate them in reverse 894127411Swpaul * order. This screws up some drivers which expect the 895127411Swpaul * BARs to be in ascending order so that they can choose 896127411Swpaul * the "first" one as their register space. Unfortunately, 897127411Swpaul * in order to fix this, we have to create our own 898127411Swpaul * temporary list with the entries in reverse order. 899127411Swpaul */ 900123976Swpaul SLIST_FOREACH(brle, brl, link) { 901127411Swpaul n = malloc(sizeof(struct resource_list_entry), 902127411Swpaul M_TEMP, M_NOWAIT); 903127411Swpaul if (n == NULL) { 904127411Swpaul error = ENOMEM; 905127411Swpaul goto bad; 906127411Swpaul } 907127411Swpaul bcopy((char *)brle, (char *)n, 908127411Swpaul sizeof(struct resource_list_entry)); 909127411Swpaul SLIST_INSERT_HEAD(&brl_rev, n, link); 910127411Swpaul } 911127411Swpaul 912127411Swpaul SLIST_FOREACH(brle, &brl_rev, link) { 913123976Swpaul switch (brle->type) { 914123976Swpaul case SYS_RES_IOPORT: 915123976Swpaul prd->cprd_type = CmResourceTypePort; 916127552Swpaul prd->cprd_flags = CM_RESOURCE_PORT_IO; 917127552Swpaul prd->cprd_sharedisp = 918127552Swpaul CmResourceShareDeviceExclusive; 919123976Swpaul prd->u.cprd_port.cprd_start.np_quad = 920123976Swpaul brle->start; 921123976Swpaul prd->u.cprd_port.cprd_len = brle->count; 922123976Swpaul break; 923123976Swpaul case SYS_RES_MEMORY: 924123976Swpaul prd->cprd_type = CmResourceTypeMemory; 925127552Swpaul prd->cprd_flags = 926127552Swpaul CM_RESOURCE_MEMORY_READ_WRITE; 927127552Swpaul prd->cprd_sharedisp = 928127552Swpaul CmResourceShareDeviceExclusive; 929123976Swpaul prd->u.cprd_port.cprd_start.np_quad = 930123976Swpaul brle->start; 931123976Swpaul prd->u.cprd_port.cprd_len = brle->count; 932123976Swpaul break; 933123976Swpaul case SYS_RES_IRQ: 934123976Swpaul prd->cprd_type = CmResourceTypeInterrupt; 935127552Swpaul prd->cprd_flags = 0; 936127552Swpaul prd->cprd_sharedisp = 937127552Swpaul CmResourceShareDeviceExclusive; 938123976Swpaul prd->u.cprd_intr.cprd_level = brle->start; 939123976Swpaul prd->u.cprd_intr.cprd_vector = brle->start; 940123976Swpaul prd->u.cprd_intr.cprd_affinity = 0; 941123976Swpaul break; 942123976Swpaul default: 943123976Swpaul break; 944123976Swpaul } 945123976Swpaul prd++; 946123976Swpaul } 947123474Swpaul } 948123474Swpaul 949123474Swpaul block->nmb_rlist = rl; 950123474Swpaul 951127411Swpaulbad: 952127411Swpaul 953127411Swpaul while (!SLIST_EMPTY(&brl_rev)) { 954127411Swpaul n = SLIST_FIRST(&brl_rev); 955127411Swpaul SLIST_REMOVE_HEAD(&brl_rev, link); 956127411Swpaul free (n, M_TEMP); 957127411Swpaul } 958127411Swpaul 959127411Swpaul return(error); 960123474Swpaul} 961123474Swpaul 962123474Swpaul/* 963123474Swpaul * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 964123474Swpaul * packet, it will hand it to us in the form of an ndis_packet, 965123474Swpaul * which we need to convert to an mbuf that is then handed off 966123474Swpaul * to the stack. Note: we configure the mbuf list so that it uses 967123474Swpaul * the memory regions specified by the ndis_buffer structures in 968123474Swpaul * the ndis_packet as external storage. In most cases, this will 969123474Swpaul * point to a memory region allocated by the driver (either by 970123474Swpaul * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 971123474Swpaul * the driver to handle free()ing this region for is, so we set up 972123474Swpaul * a dummy no-op free handler for it. 973123474Swpaul */ 974123474Swpaul 975123474Swpaulint 976123474Swpaulndis_ptom(m0, p) 977123474Swpaul struct mbuf **m0; 978123474Swpaul ndis_packet *p; 979123474Swpaul{ 980123474Swpaul struct mbuf *m, *prev = NULL; 981123474Swpaul ndis_buffer *buf; 982123474Swpaul ndis_packet_private *priv; 983123474Swpaul uint32_t totlen = 0; 984123474Swpaul 985123474Swpaul if (p == NULL || m0 == NULL) 986123474Swpaul return(EINVAL); 987123474Swpaul 988123474Swpaul priv = &p->np_private; 989123474Swpaul buf = priv->npp_head; 990123826Swpaul p->np_refcnt = 0; 991123474Swpaul 992140751Swpaul for (buf = priv->npp_head; buf != NULL; buf = buf->mdl_next) { 993123474Swpaul if (buf == priv->npp_head) 994123474Swpaul MGETHDR(m, M_DONTWAIT, MT_HEADER); 995123474Swpaul else 996123474Swpaul MGET(m, M_DONTWAIT, MT_DATA); 997123474Swpaul if (m == NULL) { 998123474Swpaul m_freem(*m0); 999123474Swpaul *m0 = NULL; 1000123474Swpaul return(ENOBUFS); 1001123474Swpaul } 1002140751Swpaul m->m_len = MmGetMdlByteCount(buf); 1003140751Swpaul m->m_data = MmGetMdlVirtualAddress(buf); 1004123535Swpaul MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 1005123826Swpaul p, 0, EXT_NDIS); 1006123826Swpaul p->np_refcnt++; 1007123474Swpaul totlen += m->m_len; 1008123474Swpaul if (m->m_flags & MT_HEADER) 1009123474Swpaul *m0 = m; 1010123474Swpaul else 1011123474Swpaul prev->m_next = m; 1012123474Swpaul prev = m; 1013123474Swpaul } 1014123474Swpaul 1015123474Swpaul (*m0)->m_pkthdr.len = totlen; 1016123474Swpaul 1017123474Swpaul return(0); 1018123474Swpaul} 1019123474Swpaul 1020123474Swpaul/* 1021123474Swpaul * Create an mbuf chain from an NDIS packet chain. 1022123474Swpaul * This is used mainly when transmitting packets, where we need 1023123474Swpaul * to turn an mbuf off an interface's send queue and transform it 1024123474Swpaul * into an NDIS packet which will be fed into the NDIS driver's 1025123474Swpaul * send routine. 1026123474Swpaul * 1027123474Swpaul * NDIS packets consist of two parts: an ndis_packet structure, 1028123474Swpaul * which is vaguely analagous to the pkthdr portion of an mbuf, 1029123474Swpaul * and one or more ndis_buffer structures, which define the 1030123474Swpaul * actual memory segments in which the packet data resides. 1031123474Swpaul * We need to allocate one ndis_buffer for each mbuf in a chain, 1032123474Swpaul * plus one ndis_packet as the header. 1033123474Swpaul */ 1034123474Swpaul 1035123474Swpaulint 1036123474Swpaulndis_mtop(m0, p) 1037123474Swpaul struct mbuf *m0; 1038123474Swpaul ndis_packet **p; 1039123474Swpaul{ 1040123474Swpaul struct mbuf *m; 1041123474Swpaul ndis_buffer *buf = NULL, *prev = NULL; 1042123474Swpaul ndis_packet_private *priv; 1043123474Swpaul 1044123474Swpaul if (p == NULL || m0 == NULL) 1045123474Swpaul return(EINVAL); 1046123474Swpaul 1047123474Swpaul /* If caller didn't supply a packet, make one. */ 1048123474Swpaul if (*p == NULL) { 1049124060Swpaul *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO); 1050123474Swpaul 1051123474Swpaul if (*p == NULL) 1052123474Swpaul return(ENOMEM); 1053123474Swpaul } 1054123474Swpaul 1055123474Swpaul priv = &(*p)->np_private; 1056123474Swpaul priv->npp_totlen = m0->m_pkthdr.len; 1057123474Swpaul priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 1058124278Swpaul priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 1059123474Swpaul 1060123474Swpaul for (m = m0; m != NULL; m = m->m_next) { 1061123810Salfred if (m->m_len == 0) 1062123474Swpaul continue; 1063124060Swpaul buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); 1064123474Swpaul if (buf == NULL) { 1065123474Swpaul ndis_free_packet(*p); 1066123474Swpaul *p = NULL; 1067123474Swpaul return(ENOMEM); 1068123474Swpaul } 1069123474Swpaul 1070140751Swpaul MmInitializeMdl(buf, m->m_data, m->m_len); 1071123474Swpaul if (priv->npp_head == NULL) 1072123474Swpaul priv->npp_head = buf; 1073123474Swpaul else 1074140751Swpaul prev->mdl_next = buf; 1075123474Swpaul prev = buf; 1076123474Swpaul } 1077123474Swpaul 1078123474Swpaul priv->npp_tail = buf; 1079124060Swpaul priv->npp_totlen = m0->m_pkthdr.len; 1080123474Swpaul 1081123474Swpaul return(0); 1082123474Swpaul} 1083123474Swpaul 1084123474Swpaulint 1085123474Swpaulndis_get_supported_oids(arg, oids, oidcnt) 1086123474Swpaul void *arg; 1087123474Swpaul ndis_oid **oids; 1088123474Swpaul int *oidcnt; 1089123474Swpaul{ 1090123474Swpaul int len, rval; 1091123474Swpaul ndis_oid *o; 1092123474Swpaul 1093123474Swpaul if (arg == NULL || oids == NULL || oidcnt == NULL) 1094123474Swpaul return(EINVAL); 1095123474Swpaul len = 0; 1096123474Swpaul ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 1097123474Swpaul 1098123474Swpaul o = malloc(len, M_DEVBUF, M_NOWAIT); 1099123474Swpaul if (o == NULL) 1100123474Swpaul return(ENOMEM); 1101123474Swpaul 1102123474Swpaul rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 1103123474Swpaul 1104123474Swpaul if (rval) { 1105123474Swpaul free(o, M_DEVBUF); 1106123474Swpaul return(rval); 1107123474Swpaul } 1108123474Swpaul 1109123474Swpaul *oids = o; 1110123474Swpaul *oidcnt = len / 4; 1111123474Swpaul 1112123474Swpaul return(0); 1113123474Swpaul} 1114123474Swpaul 1115123474Swpaulint 1116123474Swpaulndis_set_info(arg, oid, buf, buflen) 1117123474Swpaul void *arg; 1118123474Swpaul ndis_oid oid; 1119123474Swpaul void *buf; 1120123474Swpaul int *buflen; 1121123474Swpaul{ 1122123474Swpaul struct ndis_softc *sc; 1123123474Swpaul ndis_status rval; 1124123474Swpaul ndis_handle adapter; 1125123474Swpaul __stdcall ndis_setinfo_handler setfunc; 1126123474Swpaul uint32_t byteswritten = 0, bytesneeded = 0; 1127123695Swpaul int error; 1128128229Swpaul uint8_t irql; 1129123474Swpaul 1130123474Swpaul sc = arg; 1131125718Swpaul NDIS_LOCK(sc); 1132123474Swpaul setfunc = sc->ndis_chars.nmc_setinfo_func; 1133123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1134125718Swpaul NDIS_UNLOCK(sc); 1135123474Swpaul 1136125718Swpaul if (adapter == NULL || setfunc == NULL) 1137125676Swpaul return(ENXIO); 1138125676Swpaul 1139140751Swpaul KeAcquireSpinLock(&sc->ndis_block.nmb_lock, &irql); 1140123474Swpaul rval = setfunc(adapter, oid, buf, *buflen, 1141123474Swpaul &byteswritten, &bytesneeded); 1142140751Swpaul KeReleaseSpinLock(&sc->ndis_block.nmb_lock, irql); 1143123474Swpaul 1144123695Swpaul if (rval == NDIS_STATUS_PENDING) { 1145140267Swpaul mtx_lock(&ndis_req_mtx); 1146140267Swpaul error = msleep(&sc->ndis_block.nmb_setstat, 1147140267Swpaul &ndis_req_mtx, 1148128229Swpaul curthread->td_priority|PDROP, 1149127887Swpaul "ndisset", 5 * hz); 1150123695Swpaul rval = sc->ndis_block.nmb_setstat; 1151123695Swpaul } 1152123695Swpaul 1153123474Swpaul if (byteswritten) 1154123474Swpaul *buflen = byteswritten; 1155123474Swpaul if (bytesneeded) 1156123474Swpaul *buflen = bytesneeded; 1157123474Swpaul 1158123474Swpaul if (rval == NDIS_STATUS_INVALID_LENGTH) 1159123474Swpaul return(ENOSPC); 1160123474Swpaul 1161123474Swpaul if (rval == NDIS_STATUS_INVALID_OID) 1162123474Swpaul return(EINVAL); 1163123474Swpaul 1164123474Swpaul if (rval == NDIS_STATUS_NOT_SUPPORTED || 1165123474Swpaul rval == NDIS_STATUS_NOT_ACCEPTED) 1166123474Swpaul return(ENOTSUP); 1167123474Swpaul 1168124809Swpaul if (rval != NDIS_STATUS_SUCCESS) 1169124809Swpaul return(ENODEV); 1170124809Swpaul 1171123474Swpaul return(0); 1172123474Swpaul} 1173123474Swpaul 1174124202Swpaultypedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 1175124202Swpaul 1176123474Swpaulint 1177123474Swpaulndis_send_packets(arg, packets, cnt) 1178123474Swpaul void *arg; 1179123474Swpaul ndis_packet **packets; 1180123474Swpaul int cnt; 1181123474Swpaul{ 1182123474Swpaul struct ndis_softc *sc; 1183123474Swpaul ndis_handle adapter; 1184123474Swpaul __stdcall ndis_sendmulti_handler sendfunc; 1185124202Swpaul __stdcall ndis_senddone_func senddonefunc; 1186124202Swpaul int i; 1187123858Swpaul ndis_packet *p; 1188128229Swpaul uint8_t irql; 1189123474Swpaul 1190123474Swpaul sc = arg; 1191123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1192125718Swpaul if (adapter == NULL) 1193125718Swpaul return(ENXIO); 1194123474Swpaul sendfunc = sc->ndis_chars.nmc_sendmulti_func; 1195124202Swpaul senddonefunc = sc->ndis_block.nmb_senddone_func; 1196140751Swpaul irql = KeRaiseIrql(DISPATCH_LEVEL); 1197123474Swpaul sendfunc(adapter, packets, cnt); 1198140751Swpaul KeLowerIrql(irql); 1199123474Swpaul 1200123858Swpaul for (i = 0; i < cnt; i++) { 1201123858Swpaul p = packets[i]; 1202124005Swpaul /* 1203124005Swpaul * Either the driver already handed the packet to 1204124005Swpaul * ndis_txeof() due to a failure, or it wants to keep 1205124005Swpaul * it and release it asynchronously later. Skip to the 1206124005Swpaul * next one. 1207124005Swpaul */ 1208124005Swpaul if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 1209123858Swpaul continue; 1210124202Swpaul senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status); 1211123858Swpaul } 1212123858Swpaul 1213123474Swpaul return(0); 1214123474Swpaul} 1215123474Swpaul 1216123474Swpaulint 1217125377Swpaulndis_send_packet(arg, packet) 1218125377Swpaul void *arg; 1219125377Swpaul ndis_packet *packet; 1220125377Swpaul{ 1221125377Swpaul struct ndis_softc *sc; 1222125377Swpaul ndis_handle adapter; 1223125377Swpaul ndis_status status; 1224125377Swpaul __stdcall ndis_sendsingle_handler sendfunc; 1225125377Swpaul __stdcall ndis_senddone_func senddonefunc; 1226128229Swpaul uint8_t irql; 1227125377Swpaul 1228125377Swpaul sc = arg; 1229125377Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1230125718Swpaul if (adapter == NULL) 1231125718Swpaul return(ENXIO); 1232125377Swpaul sendfunc = sc->ndis_chars.nmc_sendsingle_func; 1233125377Swpaul senddonefunc = sc->ndis_block.nmb_senddone_func; 1234125377Swpaul 1235140751Swpaul irql = KeRaiseIrql(DISPATCH_LEVEL); 1236125377Swpaul status = sendfunc(adapter, packet, packet->np_private.npp_flags); 1237140751Swpaul KeLowerIrql(irql); 1238125377Swpaul 1239125377Swpaul if (status == NDIS_STATUS_PENDING) 1240125377Swpaul return(0); 1241125377Swpaul 1242125377Swpaul senddonefunc(&sc->ndis_block, packet, status); 1243125377Swpaul 1244125377Swpaul return(0); 1245125377Swpaul} 1246125377Swpaul 1247125377Swpaulint 1248123474Swpaulndis_init_dma(arg) 1249123474Swpaul void *arg; 1250123474Swpaul{ 1251123474Swpaul struct ndis_softc *sc; 1252123474Swpaul int i, error; 1253123474Swpaul 1254123474Swpaul sc = arg; 1255123474Swpaul 1256123474Swpaul sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1257123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1258123474Swpaul 1259123474Swpaul if (sc->ndis_tmaps == NULL) 1260123474Swpaul return(ENOMEM); 1261123474Swpaul 1262123474Swpaul for (i = 0; i < sc->ndis_maxpkts; i++) { 1263123474Swpaul error = bus_dmamap_create(sc->ndis_ttag, 0, 1264123474Swpaul &sc->ndis_tmaps[i]); 1265123474Swpaul if (error) { 1266123474Swpaul free(sc->ndis_tmaps, M_DEVBUF); 1267123474Swpaul return(ENODEV); 1268123474Swpaul } 1269123474Swpaul } 1270123474Swpaul 1271123474Swpaul return(0); 1272123474Swpaul} 1273123474Swpaul 1274123474Swpaulint 1275123474Swpaulndis_destroy_dma(arg) 1276123474Swpaul void *arg; 1277123474Swpaul{ 1278123474Swpaul struct ndis_softc *sc; 1279123535Swpaul struct mbuf *m; 1280123535Swpaul ndis_packet *p = NULL; 1281123474Swpaul int i; 1282123474Swpaul 1283123474Swpaul sc = arg; 1284123474Swpaul 1285123474Swpaul for (i = 0; i < sc->ndis_maxpkts; i++) { 1286123535Swpaul if (sc->ndis_txarray[i] != NULL) { 1287123535Swpaul p = sc->ndis_txarray[i]; 1288123535Swpaul m = (struct mbuf *)p->np_rsvd[1]; 1289123535Swpaul if (m != NULL) 1290123535Swpaul m_freem(m); 1291123535Swpaul ndis_free_packet(sc->ndis_txarray[i]); 1292123535Swpaul } 1293123474Swpaul bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1294123474Swpaul } 1295123474Swpaul 1296123474Swpaul free(sc->ndis_tmaps, M_DEVBUF); 1297123474Swpaul 1298123474Swpaul bus_dma_tag_destroy(sc->ndis_ttag); 1299123474Swpaul 1300123474Swpaul return(0); 1301123474Swpaul} 1302123474Swpaul 1303123474Swpaulint 1304123474Swpaulndis_reset_nic(arg) 1305123474Swpaul void *arg; 1306123474Swpaul{ 1307123474Swpaul struct ndis_softc *sc; 1308123474Swpaul ndis_handle adapter; 1309123474Swpaul __stdcall ndis_reset_handler resetfunc; 1310123474Swpaul uint8_t addressing_reset; 1311123474Swpaul struct ifnet *ifp; 1312127887Swpaul int rval; 1313128229Swpaul uint8_t irql; 1314123474Swpaul 1315123474Swpaul sc = arg; 1316123474Swpaul ifp = &sc->arpcom.ac_if; 1317125718Swpaul NDIS_LOCK(sc); 1318123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1319125718Swpaul resetfunc = sc->ndis_chars.nmc_reset_func; 1320125718Swpaul NDIS_UNLOCK(sc); 1321125718Swpaul if (adapter == NULL || resetfunc == NULL) 1322123474Swpaul return(EIO); 1323123474Swpaul 1324140751Swpaul irql = KeRaiseIrql(DISPATCH_LEVEL); 1325127887Swpaul rval = resetfunc(&addressing_reset, adapter); 1326140751Swpaul KeLowerIrql(irql); 1327128229Swpaul 1328127887Swpaul if (rval == NDIS_STATUS_PENDING) { 1329140267Swpaul mtx_lock(&ndis_req_mtx); 1330140267Swpaul msleep(sc, &ndis_req_mtx, 1331128229Swpaul curthread->td_priority|PDROP, "ndisrst", 0); 1332127887Swpaul } 1333123474Swpaul 1334123474Swpaul return(0); 1335123474Swpaul} 1336123474Swpaul 1337123474Swpaulint 1338123474Swpaulndis_halt_nic(arg) 1339123474Swpaul void *arg; 1340123474Swpaul{ 1341123474Swpaul struct ndis_softc *sc; 1342123474Swpaul ndis_handle adapter; 1343123474Swpaul __stdcall ndis_halt_handler haltfunc; 1344123474Swpaul struct ifnet *ifp; 1345123474Swpaul 1346123474Swpaul sc = arg; 1347123474Swpaul ifp = &sc->arpcom.ac_if; 1348125718Swpaul 1349125718Swpaul NDIS_LOCK(sc); 1350123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1351125718Swpaul if (adapter == NULL) { 1352125718Swpaul NDIS_UNLOCK(sc); 1353123474Swpaul return(EIO); 1354125718Swpaul } 1355123821Swpaul 1356123474Swpaul /* 1357123474Swpaul * The adapter context is only valid after the init 1358123474Swpaul * handler has been called, and is invalid once the 1359123474Swpaul * halt handler has been called. 1360123474Swpaul */ 1361123474Swpaul 1362125718Swpaul haltfunc = sc->ndis_chars.nmc_halt_func; 1363125718Swpaul NDIS_UNLOCK(sc); 1364125718Swpaul 1365125718Swpaul haltfunc(adapter); 1366125718Swpaul 1367125718Swpaul NDIS_LOCK(sc); 1368123474Swpaul sc->ndis_block.nmb_miniportadapterctx = NULL; 1369125718Swpaul NDIS_UNLOCK(sc); 1370123821Swpaul 1371123474Swpaul return(0); 1372123474Swpaul} 1373123474Swpaul 1374123474Swpaulint 1375123474Swpaulndis_shutdown_nic(arg) 1376123474Swpaul void *arg; 1377123474Swpaul{ 1378123474Swpaul struct ndis_softc *sc; 1379123474Swpaul ndis_handle adapter; 1380123474Swpaul __stdcall ndis_shutdown_handler shutdownfunc; 1381123474Swpaul 1382123474Swpaul sc = arg; 1383125718Swpaul NDIS_LOCK(sc); 1384123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1385125718Swpaul shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 1386125718Swpaul NDIS_UNLOCK(sc); 1387125718Swpaul if (adapter == NULL || shutdownfunc == NULL) 1388123474Swpaul return(EIO); 1389123474Swpaul 1390123485Swpaul if (sc->ndis_chars.nmc_rsvd0 == NULL) 1391123485Swpaul shutdownfunc(adapter); 1392123485Swpaul else 1393123485Swpaul shutdownfunc(sc->ndis_chars.nmc_rsvd0); 1394123474Swpaul 1395125006Swpaul ndis_shrink_thrqueue(8); 1396125057Swpaul TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1397125006Swpaul 1398123474Swpaul return(0); 1399123474Swpaul} 1400123474Swpaul 1401123474Swpaulint 1402123474Swpaulndis_init_nic(arg) 1403123474Swpaul void *arg; 1404123474Swpaul{ 1405123474Swpaul struct ndis_softc *sc; 1406123474Swpaul ndis_miniport_block *block; 1407123474Swpaul __stdcall ndis_init_handler initfunc; 1408123474Swpaul ndis_status status, openstatus = 0; 1409123474Swpaul ndis_medium mediumarray[NdisMediumMax]; 1410123474Swpaul uint32_t chosenmedium, i; 1411123474Swpaul 1412123474Swpaul if (arg == NULL) 1413123474Swpaul return(EINVAL); 1414123474Swpaul 1415123474Swpaul sc = arg; 1416125718Swpaul NDIS_LOCK(sc); 1417123474Swpaul block = &sc->ndis_block; 1418123474Swpaul initfunc = sc->ndis_chars.nmc_init_func; 1419125718Swpaul NDIS_UNLOCK(sc); 1420123474Swpaul 1421123821Swpaul TAILQ_INIT(&block->nmb_timerlist); 1422123821Swpaul 1423123474Swpaul for (i = 0; i < NdisMediumMax; i++) 1424123474Swpaul mediumarray[i] = i; 1425123474Swpaul 1426123474Swpaul status = initfunc(&openstatus, &chosenmedium, 1427123474Swpaul mediumarray, NdisMediumMax, block, block); 1428123474Swpaul 1429123474Swpaul /* 1430123474Swpaul * If the init fails, blow away the other exported routines 1431123474Swpaul * we obtained from the driver so we can't call them later. 1432123474Swpaul * If the init failed, none of these will work. 1433123474Swpaul */ 1434123474Swpaul if (status != NDIS_STATUS_SUCCESS) { 1435125718Swpaul NDIS_LOCK(sc); 1436125676Swpaul sc->ndis_block.nmb_miniportadapterctx = NULL; 1437125718Swpaul NDIS_UNLOCK(sc); 1438123474Swpaul return(ENXIO); 1439123474Swpaul } 1440123474Swpaul 1441123474Swpaul return(0); 1442123474Swpaul} 1443123474Swpaul 1444123474Swpaulvoid 1445123474Swpaulndis_enable_intr(arg) 1446123474Swpaul void *arg; 1447123474Swpaul{ 1448123474Swpaul struct ndis_softc *sc; 1449123474Swpaul ndis_handle adapter; 1450123474Swpaul __stdcall ndis_enable_interrupts_handler intrenbfunc; 1451123474Swpaul 1452123474Swpaul sc = arg; 1453123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1454123474Swpaul intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 1455125718Swpaul if (adapter == NULL || intrenbfunc == NULL) 1456123474Swpaul return; 1457123474Swpaul intrenbfunc(adapter); 1458123474Swpaul 1459123474Swpaul return; 1460123474Swpaul} 1461123474Swpaul 1462123474Swpaulvoid 1463123474Swpaulndis_disable_intr(arg) 1464123474Swpaul void *arg; 1465123474Swpaul{ 1466123474Swpaul struct ndis_softc *sc; 1467123474Swpaul ndis_handle adapter; 1468123474Swpaul __stdcall ndis_disable_interrupts_handler intrdisfunc; 1469123474Swpaul 1470123474Swpaul sc = arg; 1471125718Swpaul NDIS_LOCK(sc); 1472123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1473125718Swpaul intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 1474125718Swpaul NDIS_UNLOCK(sc); 1475126834Swpaul if (adapter == NULL || intrdisfunc == NULL) 1476123474Swpaul return; 1477123474Swpaul intrdisfunc(adapter); 1478123474Swpaul 1479123474Swpaul return; 1480123474Swpaul} 1481123474Swpaul 1482123474Swpaulint 1483123474Swpaulndis_isr(arg, ourintr, callhandler) 1484123474Swpaul void *arg; 1485123474Swpaul int *ourintr; 1486123474Swpaul int *callhandler; 1487123474Swpaul{ 1488123474Swpaul struct ndis_softc *sc; 1489123474Swpaul ndis_handle adapter; 1490123474Swpaul __stdcall ndis_isr_handler isrfunc; 1491123474Swpaul uint8_t accepted, queue; 1492123474Swpaul 1493123474Swpaul if (arg == NULL || ourintr == NULL || callhandler == NULL) 1494123474Swpaul return(EINVAL); 1495123474Swpaul 1496123474Swpaul sc = arg; 1497123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1498123474Swpaul isrfunc = sc->ndis_chars.nmc_isr_func; 1499125718Swpaul if (adapter == NULL || isrfunc == NULL) 1500125718Swpaul return(ENXIO); 1501125718Swpaul 1502123474Swpaul isrfunc(&accepted, &queue, adapter); 1503123474Swpaul *ourintr = accepted; 1504123474Swpaul *callhandler = queue; 1505123474Swpaul 1506123474Swpaul return(0); 1507123474Swpaul} 1508123474Swpaul 1509123474Swpaulint 1510123474Swpaulndis_intrhand(arg) 1511123474Swpaul void *arg; 1512123474Swpaul{ 1513123474Swpaul struct ndis_softc *sc; 1514123474Swpaul ndis_handle adapter; 1515123474Swpaul __stdcall ndis_interrupt_handler intrfunc; 1516123474Swpaul 1517123474Swpaul if (arg == NULL) 1518123474Swpaul return(EINVAL); 1519123474Swpaul 1520123474Swpaul sc = arg; 1521125718Swpaul NDIS_LOCK(sc); 1522123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1523123474Swpaul intrfunc = sc->ndis_chars.nmc_interrupt_func; 1524125718Swpaul NDIS_UNLOCK(sc); 1525125718Swpaul if (adapter == NULL || intrfunc == NULL) 1526125718Swpaul return(EINVAL); 1527125718Swpaul 1528123474Swpaul intrfunc(adapter); 1529123474Swpaul 1530123474Swpaul return(0); 1531123474Swpaul} 1532123474Swpaul 1533123474Swpaulint 1534123474Swpaulndis_get_info(arg, oid, buf, buflen) 1535123474Swpaul void *arg; 1536123474Swpaul ndis_oid oid; 1537123474Swpaul void *buf; 1538123474Swpaul int *buflen; 1539123474Swpaul{ 1540123474Swpaul struct ndis_softc *sc; 1541123474Swpaul ndis_status rval; 1542123474Swpaul ndis_handle adapter; 1543123474Swpaul __stdcall ndis_queryinfo_handler queryfunc; 1544123474Swpaul uint32_t byteswritten = 0, bytesneeded = 0; 1545123695Swpaul int error; 1546128229Swpaul uint8_t irql; 1547123474Swpaul 1548123474Swpaul sc = arg; 1549125718Swpaul NDIS_LOCK(sc); 1550123474Swpaul queryfunc = sc->ndis_chars.nmc_queryinfo_func; 1551123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1552125718Swpaul NDIS_UNLOCK(sc); 1553123474Swpaul 1554125718Swpaul if (adapter == NULL || queryfunc == NULL) 1555125676Swpaul return(ENXIO); 1556125676Swpaul 1557140751Swpaul KeAcquireSpinLock(&sc->ndis_block.nmb_lock, &irql); 1558123474Swpaul rval = queryfunc(adapter, oid, buf, *buflen, 1559123474Swpaul &byteswritten, &bytesneeded); 1560140751Swpaul KeReleaseSpinLock(&sc->ndis_block.nmb_lock, irql); 1561123474Swpaul 1562123695Swpaul /* Wait for requests that block. */ 1563123695Swpaul 1564123695Swpaul if (rval == NDIS_STATUS_PENDING) { 1565140267Swpaul mtx_lock(&ndis_req_mtx); 1566140267Swpaul error = msleep(&sc->ndis_block.nmb_getstat, 1567140267Swpaul &ndis_req_mtx, 1568128229Swpaul curthread->td_priority|PDROP, 1569127887Swpaul "ndisget", 5 * hz); 1570123695Swpaul rval = sc->ndis_block.nmb_getstat; 1571123695Swpaul } 1572123695Swpaul 1573123474Swpaul if (byteswritten) 1574123474Swpaul *buflen = byteswritten; 1575123474Swpaul if (bytesneeded) 1576123474Swpaul *buflen = bytesneeded; 1577123474Swpaul 1578123474Swpaul if (rval == NDIS_STATUS_INVALID_LENGTH || 1579123474Swpaul rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1580123474Swpaul return(ENOSPC); 1581123474Swpaul 1582123474Swpaul if (rval == NDIS_STATUS_INVALID_OID) 1583123474Swpaul return(EINVAL); 1584123474Swpaul 1585123474Swpaul if (rval == NDIS_STATUS_NOT_SUPPORTED || 1586123474Swpaul rval == NDIS_STATUS_NOT_ACCEPTED) 1587123474Swpaul return(ENOTSUP); 1588123474Swpaul 1589124809Swpaul if (rval != NDIS_STATUS_SUCCESS) 1590124809Swpaul return(ENODEV); 1591124809Swpaul 1592123474Swpaul return(0); 1593123474Swpaul} 1594123474Swpaul 1595123474Swpaulint 1596123474Swpaulndis_unload_driver(arg) 1597123474Swpaul void *arg; 1598123474Swpaul{ 1599123474Swpaul struct ndis_softc *sc; 1600123474Swpaul 1601123474Swpaul sc = arg; 1602123474Swpaul 1603123474Swpaul free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1604123474Swpaul 1605123474Swpaul ndis_flush_sysctls(sc); 1606123474Swpaul 1607124697Swpaul ndis_shrink_thrqueue(8); 1608125057Swpaul TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1609124697Swpaul 1610123474Swpaul return(0); 1611123474Swpaul} 1612123474Swpaul 1613127887Swpaul#define NDIS_LOADED htonl(0x42534F44) 1614124446Swpaul 1615123474Swpaulint 1616123474Swpaulndis_load_driver(img, arg) 1617123474Swpaul vm_offset_t img; 1618123474Swpaul void *arg; 1619123474Swpaul{ 1620133876Swpaul driver_entry entry; 1621123474Swpaul image_optional_header opt_hdr; 1622123474Swpaul image_import_descriptor imp_desc; 1623123474Swpaul ndis_unicode_string dummystr; 1624123474Swpaul ndis_miniport_block *block; 1625123474Swpaul ndis_status status; 1626123474Swpaul int idx; 1627123474Swpaul uint32_t *ptr; 1628123474Swpaul struct ndis_softc *sc; 1629123474Swpaul 1630123474Swpaul sc = arg; 1631123474Swpaul 1632124446Swpaul /* 1633124446Swpaul * Only perform the relocation/linking phase once 1634124446Swpaul * since the binary image may be shared among multiple 1635124446Swpaul * device instances. 1636124446Swpaul */ 1637123474Swpaul 1638124446Swpaul ptr = (uint32_t *)(img + 8); 1639124446Swpaul if (*ptr != NDIS_LOADED) { 1640124446Swpaul /* Perform text relocation */ 1641124446Swpaul if (pe_relocate(img)) 1642124446Swpaul return(ENOEXEC); 1643123474Swpaul 1644124446Swpaul /* Dynamically link the NDIS.SYS routines -- required. */ 1645124446Swpaul if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1646124446Swpaul return(ENOEXEC); 1647123474Swpaul 1648124446Swpaul /* Dynamically link the HAL.dll routines -- also required. */ 1649124446Swpaul if (pe_patch_imports(img, "HAL", hal_functbl)) 1650123474Swpaul return(ENOEXEC); 1651124446Swpaul 1652124446Swpaul /* Dynamically link ntoskrnl.exe -- optional. */ 1653124446Swpaul if (pe_get_import_descriptor(img, 1654124446Swpaul &imp_desc, "ntoskrnl") == 0) { 1655124446Swpaul if (pe_patch_imports(img, 1656124446Swpaul "ntoskrnl", ntoskrnl_functbl)) 1657124446Swpaul return(ENOEXEC); 1658124446Swpaul } 1659124446Swpaul *ptr = NDIS_LOADED; 1660123474Swpaul } 1661123474Swpaul 1662123474Swpaul /* Locate the driver entry point */ 1663123474Swpaul pe_get_optional_header(img, &opt_hdr); 1664123474Swpaul entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1665123474Swpaul 1666125551Swpaul dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2; 1667125551Swpaul dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2; 1668123474Swpaul dummystr.nus_buf = NULL; 1669123474Swpaul ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1670123474Swpaul 1671123474Swpaul /* 1672123474Swpaul * Now that we have the miniport driver characteristics, 1673123474Swpaul * create an NDIS block and call the init handler. 1674123474Swpaul * This will cause the driver to try to probe for 1675123474Swpaul * a device. 1676123474Swpaul */ 1677123474Swpaul 1678123474Swpaul block = &sc->ndis_block; 1679123474Swpaul 1680125551Swpaul ptr = (uint32_t *)block; 1681123474Swpaul for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1682123474Swpaul *ptr = idx | 0xdead0000; 1683123474Swpaul ptr++; 1684123474Swpaul } 1685123474Swpaul 1686123474Swpaul block->nmb_signature = (void *)0xcafebabe; 1687123474Swpaul block->nmb_setdone_func = ndis_setdone_func; 1688123535Swpaul block->nmb_querydone_func = ndis_getdone_func; 1689123474Swpaul block->nmb_status_func = ndis_status_func; 1690123474Swpaul block->nmb_statusdone_func = ndis_statusdone_func; 1691123474Swpaul block->nmb_resetdone_func = ndis_resetdone_func; 1692124100Swpaul block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; 1693123474Swpaul 1694123474Swpaul block->nmb_ifp = &sc->arpcom.ac_if; 1695123474Swpaul block->nmb_dev = sc->ndis_dev; 1696124165Swpaul block->nmb_img = img; 1697125551Swpaul block->nmb_devobj.do_rsvd = block; 1698123474Swpaul 1699125551Swpaul /* 1700125551Swpaul * Now call the DriverEntry() routine. This will cause 1701125551Swpaul * a callout to the NdisInitializeWrapper() and 1702125551Swpaul * NdisMRegisterMiniport() routines. 1703125551Swpaul */ 1704125551Swpaul status = entry(&block->nmb_devobj, &dummystr); 1705125551Swpaul 1706125551Swpaul free (dummystr.nus_buf, M_DEVBUF); 1707125551Swpaul 1708125551Swpaul if (status != NDIS_STATUS_SUCCESS) 1709125551Swpaul return(ENODEV); 1710125551Swpaul 1711124697Swpaul ndis_enlarge_thrqueue(8); 1712124697Swpaul 1713125057Swpaul TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1714140751Swpaul KeInitializeSpinLock(&block->nmb_lock); 1715125006Swpaul 1716123474Swpaul return(0); 1717123474Swpaul} 1718