kern_ndis.c revision 131953
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/kern_ndis.c 131953 2004-07-11 00:19:30Z 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; 113124697Swpaulstatic STAILQ_HEAD(ndisqhead, ndis_req) ndis_ttodo; 114124697Swpaulstruct ndisqhead ndis_itodo; 115124697Swpaulstruct ndisqhead ndis_free; 116124697Swpaulstatic int ndis_jobs = 32; 117124060Swpaul 118124724Swpaulstatic struct ndisproc ndis_tproc; 119124724Swpaulstatic struct ndisproc ndis_iproc; 120124697Swpaul 121123474Swpaul/* 122123474Swpaul * This allows us to export our symbols to other modules. 123123474Swpaul * Note that we call ourselves 'ndisapi' to avoid a namespace 124123474Swpaul * collision with if_ndis.ko, which internally calls itself 125123474Swpaul * 'ndis.' 126123474Swpaul */ 127123474Swpaulstatic int 128123474Swpaulndis_modevent(module_t mod, int cmd, void *arg) 129123474Swpaul{ 130124060Swpaul int error = 0; 131124060Swpaul 132124060Swpaul switch (cmd) { 133124060Swpaul case MOD_LOAD: 134124122Swpaul /* Initialize subsystems */ 135124122Swpaul ndis_libinit(); 136124122Swpaul ntoskrnl_libinit(); 137124122Swpaul 138124122Swpaul /* Initialize TX buffer UMA zone. */ 139124060Swpaul ndis_packet_zone = uma_zcreate("NDIS packet", 140124060Swpaul sizeof(ndis_packet), NULL, NULL, NULL, 141124060Swpaul NULL, UMA_ALIGN_PTR, 0); 142124060Swpaul ndis_buffer_zone = uma_zcreate("NDIS buffer", 143124060Swpaul sizeof(ndis_buffer), NULL, NULL, NULL, 144124060Swpaul NULL, UMA_ALIGN_PTR, 0); 145124697Swpaul 146124697Swpaul ndis_create_kthreads(); 147124697Swpaul 148125057Swpaul TAILQ_INIT(&ndis_devhead); 149125057Swpaul 150124060Swpaul break; 151124060Swpaul case MOD_SHUTDOWN: 152124697Swpaul /* stop kthreads */ 153124697Swpaul ndis_destroy_kthreads(); 154127311Swpaul if (TAILQ_FIRST(&ndis_devhead) == NULL) { 155125006Swpaul /* Shut down subsystems */ 156125006Swpaul ndis_libfini(); 157125006Swpaul ntoskrnl_libfini(); 158124697Swpaul 159125006Swpaul /* Remove zones */ 160125006Swpaul uma_zdestroy(ndis_packet_zone); 161125006Swpaul uma_zdestroy(ndis_buffer_zone); 162125006Swpaul } 163125006Swpaul break; 164125006Swpaul case MOD_UNLOAD: 165125006Swpaul /* stop kthreads */ 166125006Swpaul ndis_destroy_kthreads(); 167125006Swpaul 168124122Swpaul /* Shut down subsystems */ 169124122Swpaul ndis_libfini(); 170124122Swpaul ntoskrnl_libfini(); 171124122Swpaul 172124122Swpaul /* Remove zones */ 173124060Swpaul uma_zdestroy(ndis_packet_zone); 174124060Swpaul uma_zdestroy(ndis_buffer_zone); 175124060Swpaul break; 176124060Swpaul default: 177124060Swpaul error = EINVAL; 178124060Swpaul break; 179124060Swpaul } 180124060Swpaul 181124060Swpaul return(error); 182123474Swpaul} 183123474SwpaulDEV_MODULE(ndisapi, ndis_modevent, NULL); 184123474SwpaulMODULE_VERSION(ndisapi, 1); 185123474Swpaul 186124697Swpaul/* 187124697Swpaul * We create two kthreads for the NDIS subsystem. One of them is a task 188124697Swpaul * queue for performing various odd jobs. The other is an swi thread 189124697Swpaul * reserved exclusively for running interrupt handlers. The reason we 190124697Swpaul * have our own task queue is that there are some cases where we may 191124697Swpaul * need to sleep for a significant amount of time, and if we were to 192124697Swpaul * use one of the taskqueue threads, we might delay the processing 193124697Swpaul * of other pending tasks which might need to run right away. We have 194124697Swpaul * a separate swi thread because we don't want our interrupt handling 195124697Swpaul * to be delayed either. 196124697Swpaul * 197124697Swpaul * By default there are 32 jobs available to start, and another 8 198124697Swpaul * are added to the free list each time a new device is created. 199124697Swpaul */ 200123474Swpaul 201124697Swpaulstatic void 202124724Swpaulndis_runq(arg) 203124724Swpaul void *arg; 204124697Swpaul{ 205124697Swpaul struct ndis_req *r = NULL, *die = NULL; 206124724Swpaul struct ndisproc *p; 207124697Swpaul 208124724Swpaul p = arg; 209124724Swpaul 210124697Swpaul while (1) { 211124697Swpaul 212128229Swpaul /* Sleep, but preserve our original priority. */ 213128229Swpaul ndis_thsuspend(p->np_p, 0); 214128229Swpaul 215124697Swpaul /* Look for any jobs on the work queue. */ 216124697Swpaul 217128229Swpaul mtx_lock(&ndis_thr_mtx); 218125814Swpaul p->np_state = NDIS_PSTATE_RUNNING; 219124724Swpaul while(STAILQ_FIRST(p->np_q) != NULL) { 220124724Swpaul r = STAILQ_FIRST(p->np_q); 221124724Swpaul STAILQ_REMOVE_HEAD(p->np_q, link); 222128229Swpaul mtx_unlock(&ndis_thr_mtx); 223124697Swpaul 224124697Swpaul /* Do the work. */ 225124697Swpaul 226124724Swpaul if (r->nr_func != NULL) 227124724Swpaul (*r->nr_func)(r->nr_arg); 228124697Swpaul 229128229Swpaul mtx_lock(&ndis_thr_mtx); 230124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 231124697Swpaul 232124697Swpaul /* Check for a shutdown request */ 233124697Swpaul 234124724Swpaul if (r->nr_exit == TRUE) 235124697Swpaul die = r; 236124697Swpaul } 237125814Swpaul p->np_state = NDIS_PSTATE_SLEEPING; 238128229Swpaul mtx_unlock(&ndis_thr_mtx); 239124697Swpaul 240124697Swpaul /* Bail if we were told to shut down. */ 241124697Swpaul 242124697Swpaul if (die != NULL) 243124697Swpaul break; 244124697Swpaul } 245124697Swpaul 246124697Swpaul wakeup(die); 247130166Swpaul#if __FreeBSD_version < 502113 248130166Swpaul mtx_lock(&Giant); 249130166Swpaul#endif 250124697Swpaul kthread_exit(0); 251128229Swpaul return; /* notreached */ 252124697Swpaul} 253124697Swpaul 254124697Swpaulstatic int 255124697Swpaulndis_create_kthreads() 256124697Swpaul{ 257124697Swpaul struct ndis_req *r; 258124697Swpaul int i, error = 0; 259124697Swpaul 260128229Swpaul mtx_init(&ndis_thr_mtx, "NDIS thread lock", 261128229Swpaul MTX_NDIS_LOCK, MTX_DEF); 262128229Swpaul 263124697Swpaul STAILQ_INIT(&ndis_ttodo); 264124697Swpaul STAILQ_INIT(&ndis_itodo); 265124697Swpaul STAILQ_INIT(&ndis_free); 266124697Swpaul 267124697Swpaul for (i = 0; i < ndis_jobs; i++) { 268124697Swpaul r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 269124697Swpaul if (r == NULL) { 270124697Swpaul error = ENOMEM; 271124697Swpaul break; 272124697Swpaul } 273124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 274124697Swpaul } 275124697Swpaul 276124724Swpaul if (error == 0) { 277124724Swpaul ndis_tproc.np_q = &ndis_ttodo; 278125814Swpaul ndis_tproc.np_state = NDIS_PSTATE_SLEEPING; 279124724Swpaul error = kthread_create(ndis_runq, &ndis_tproc, 280127284Swpaul &ndis_tproc.np_p, RFHIGHPID, 281127284Swpaul NDIS_KSTACK_PAGES, "ndis taskqueue"); 282124724Swpaul } 283124697Swpaul 284124724Swpaul if (error == 0) { 285124724Swpaul ndis_iproc.np_q = &ndis_itodo; 286125814Swpaul ndis_iproc.np_state = NDIS_PSTATE_SLEEPING; 287124724Swpaul error = kthread_create(ndis_runq, &ndis_iproc, 288127284Swpaul &ndis_iproc.np_p, RFHIGHPID, 289127284Swpaul NDIS_KSTACK_PAGES, "ndis swi"); 290124724Swpaul } 291124697Swpaul 292124697Swpaul if (error) { 293124697Swpaul while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 294124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 295124697Swpaul free(r, M_DEVBUF); 296124697Swpaul } 297124697Swpaul return(error); 298124697Swpaul } 299124697Swpaul 300124697Swpaul return(0); 301124697Swpaul} 302124697Swpaul 303124697Swpaulstatic void 304124697Swpaulndis_destroy_kthreads() 305124697Swpaul{ 306124697Swpaul struct ndis_req *r; 307124697Swpaul 308124697Swpaul /* Stop the threads. */ 309124697Swpaul 310124697Swpaul ndis_stop_thread(NDIS_TASKQUEUE); 311124697Swpaul ndis_stop_thread(NDIS_SWI); 312124697Swpaul 313124697Swpaul /* Destroy request structures. */ 314124697Swpaul 315124697Swpaul while ((r = STAILQ_FIRST(&ndis_free)) != NULL) { 316124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 317124697Swpaul free(r, M_DEVBUF); 318124697Swpaul } 319124697Swpaul 320128229Swpaul mtx_destroy(&ndis_thr_mtx); 321128229Swpaul 322124697Swpaul return; 323124697Swpaul} 324124697Swpaul 325124697Swpaulstatic void 326124697Swpaulndis_stop_thread(t) 327124697Swpaul int t; 328124697Swpaul{ 329124697Swpaul struct ndis_req *r; 330124697Swpaul struct ndisqhead *q; 331124697Swpaul struct proc *p; 332124697Swpaul 333124697Swpaul if (t == NDIS_TASKQUEUE) { 334124697Swpaul q = &ndis_ttodo; 335124724Swpaul p = ndis_tproc.np_p; 336124697Swpaul } else { 337124697Swpaul q = &ndis_itodo; 338124724Swpaul p = ndis_iproc.np_p; 339124697Swpaul } 340124697Swpaul 341124697Swpaul /* Create and post a special 'exit' job. */ 342124697Swpaul 343128229Swpaul mtx_lock(&ndis_thr_mtx); 344124697Swpaul r = STAILQ_FIRST(&ndis_free); 345124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 346124724Swpaul r->nr_func = NULL; 347124724Swpaul r->nr_arg = NULL; 348124724Swpaul r->nr_exit = TRUE; 349124697Swpaul STAILQ_INSERT_TAIL(q, r, link); 350128229Swpaul mtx_unlock(&ndis_thr_mtx); 351124697Swpaul 352128229Swpaul ndis_thresume(p); 353124697Swpaul 354124697Swpaul /* wait for thread exit */ 355124697Swpaul 356128295Swpaul tsleep(r, curthread->td_priority|PCATCH, "ndisthexit", hz * 60); 357124697Swpaul 358124697Swpaul /* Now empty the job list. */ 359124697Swpaul 360128229Swpaul mtx_lock(&ndis_thr_mtx); 361124697Swpaul while ((r = STAILQ_FIRST(q)) != NULL) { 362124697Swpaul STAILQ_REMOVE_HEAD(q, link); 363124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 364124697Swpaul } 365128229Swpaul mtx_unlock(&ndis_thr_mtx); 366124697Swpaul 367124697Swpaul return; 368124697Swpaul} 369124697Swpaul 370124697Swpaulstatic int 371124697Swpaulndis_enlarge_thrqueue(cnt) 372124697Swpaul int cnt; 373124697Swpaul{ 374124697Swpaul struct ndis_req *r; 375124697Swpaul int i; 376124697Swpaul 377124697Swpaul for (i = 0; i < cnt; i++) { 378124697Swpaul r = malloc(sizeof(struct ndis_req), M_DEVBUF, M_WAITOK); 379124697Swpaul if (r == NULL) 380124697Swpaul return(ENOMEM); 381128229Swpaul mtx_lock(&ndis_thr_mtx); 382124697Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 383124697Swpaul ndis_jobs++; 384128229Swpaul mtx_unlock(&ndis_thr_mtx); 385124697Swpaul } 386124697Swpaul 387124697Swpaul return(0); 388124697Swpaul} 389124697Swpaul 390124697Swpaulstatic int 391124697Swpaulndis_shrink_thrqueue(cnt) 392124697Swpaul int cnt; 393124697Swpaul{ 394124697Swpaul struct ndis_req *r; 395124697Swpaul int i; 396124697Swpaul 397124697Swpaul for (i = 0; i < cnt; i++) { 398128229Swpaul mtx_lock(&ndis_thr_mtx); 399124697Swpaul r = STAILQ_FIRST(&ndis_free); 400124697Swpaul if (r == NULL) { 401128229Swpaul mtx_unlock(&ndis_thr_mtx); 402124697Swpaul return(ENOMEM); 403124697Swpaul } 404124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 405124697Swpaul ndis_jobs--; 406128229Swpaul mtx_unlock(&ndis_thr_mtx); 407124697Swpaul free(r, M_DEVBUF); 408124697Swpaul } 409124697Swpaul 410124697Swpaul return(0); 411124697Swpaul} 412124697Swpaul 413124697Swpaulint 414127393Swpaulndis_unsched(func, arg, t) 415127393Swpaul void (*func)(void *); 416127393Swpaul void *arg; 417127393Swpaul int t; 418127393Swpaul{ 419127393Swpaul struct ndis_req *r; 420127393Swpaul struct ndisqhead *q; 421127393Swpaul struct proc *p; 422127393Swpaul 423127393Swpaul if (t == NDIS_TASKQUEUE) { 424127393Swpaul q = &ndis_ttodo; 425127393Swpaul p = ndis_tproc.np_p; 426127393Swpaul } else { 427127393Swpaul q = &ndis_itodo; 428127393Swpaul p = ndis_iproc.np_p; 429127393Swpaul } 430127393Swpaul 431128229Swpaul mtx_lock(&ndis_thr_mtx); 432127393Swpaul STAILQ_FOREACH(r, q, link) { 433127393Swpaul if (r->nr_func == func && r->nr_arg == arg) { 434127393Swpaul STAILQ_REMOVE(q, r, ndis_req, link); 435127393Swpaul STAILQ_INSERT_HEAD(&ndis_free, r, link); 436128229Swpaul mtx_unlock(&ndis_thr_mtx); 437127393Swpaul return(0); 438127393Swpaul } 439127393Swpaul } 440127393Swpaul 441128229Swpaul mtx_unlock(&ndis_thr_mtx); 442127393Swpaul 443127393Swpaul return(ENOENT); 444127393Swpaul} 445127393Swpaul 446127393Swpaulint 447124697Swpaulndis_sched(func, arg, t) 448124697Swpaul void (*func)(void *); 449124697Swpaul void *arg; 450124697Swpaul int t; 451124697Swpaul{ 452124697Swpaul struct ndis_req *r; 453124697Swpaul struct ndisqhead *q; 454124697Swpaul struct proc *p; 455125814Swpaul int s; 456124697Swpaul 457124697Swpaul if (t == NDIS_TASKQUEUE) { 458124697Swpaul q = &ndis_ttodo; 459124724Swpaul p = ndis_tproc.np_p; 460124697Swpaul } else { 461124697Swpaul q = &ndis_itodo; 462124724Swpaul p = ndis_iproc.np_p; 463124697Swpaul } 464124697Swpaul 465128229Swpaul mtx_lock(&ndis_thr_mtx); 466124697Swpaul /* 467124697Swpaul * Check to see if an instance of this job is already 468124697Swpaul * pending. If so, don't bother queuing it again. 469124697Swpaul */ 470124697Swpaul STAILQ_FOREACH(r, q, link) { 471124724Swpaul if (r->nr_func == func && r->nr_arg == arg) { 472128229Swpaul mtx_unlock(&ndis_thr_mtx); 473124697Swpaul return(0); 474124697Swpaul } 475124697Swpaul } 476124697Swpaul r = STAILQ_FIRST(&ndis_free); 477124697Swpaul if (r == NULL) { 478128229Swpaul mtx_unlock(&ndis_thr_mtx); 479124697Swpaul return(EAGAIN); 480124697Swpaul } 481124697Swpaul STAILQ_REMOVE_HEAD(&ndis_free, link); 482124724Swpaul r->nr_func = func; 483124724Swpaul r->nr_arg = arg; 484124724Swpaul r->nr_exit = FALSE; 485124697Swpaul STAILQ_INSERT_TAIL(q, r, link); 486125814Swpaul if (t == NDIS_TASKQUEUE) 487125814Swpaul s = ndis_tproc.np_state; 488125814Swpaul else 489125814Swpaul s = ndis_iproc.np_state; 490128229Swpaul mtx_unlock(&ndis_thr_mtx); 491124697Swpaul 492125814Swpaul /* 493125814Swpaul * Post the job, but only if the thread is actually blocked 494125814Swpaul * on its own suspend call. If a driver queues up a job with 495125814Swpaul * NdisScheduleWorkItem() which happens to do a KeWaitForObject(), 496125814Swpaul * it may suspend there, and in that case we don't want to wake 497125814Swpaul * it up until KeWaitForObject() gets woken up on its own. 498125814Swpaul */ 499125814Swpaul if (s == NDIS_PSTATE_SLEEPING) 500128229Swpaul ndis_thresume(p); 501124697Swpaul 502124697Swpaul return(0); 503124697Swpaul} 504124697Swpaul 505128229Swpaulint 506128229Swpaulndis_thsuspend(p, timo) 507128229Swpaul struct proc *p; 508128229Swpaul int timo; 509128229Swpaul{ 510128229Swpaul int error; 511128229Swpaul 512128229Swpaul PROC_LOCK(p); 513128229Swpaul error = msleep(&p->p_siglist, &p->p_mtx, 514128229Swpaul curthread->td_priority|PDROP, "ndissp", timo); 515128229Swpaul return(error); 516128229Swpaul} 517128229Swpaul 518128229Swpaulvoid 519128229Swpaulndis_thresume(p) 520128229Swpaul struct proc *p; 521128229Swpaul{ 522128229Swpaul wakeup(&p->p_siglist); 523128229Swpaul return; 524128229Swpaul} 525128229Swpaul 526123474Swpaul__stdcall static void 527124100Swpaulndis_sendrsrcavail_func(adapter) 528124100Swpaul ndis_handle adapter; 529124100Swpaul{ 530124100Swpaul return; 531124100Swpaul} 532124100Swpaul 533124100Swpaul__stdcall static void 534123474Swpaulndis_status_func(adapter, status, sbuf, slen) 535123474Swpaul ndis_handle adapter; 536123474Swpaul ndis_status status; 537123474Swpaul void *sbuf; 538123474Swpaul uint32_t slen; 539123474Swpaul{ 540124060Swpaul ndis_miniport_block *block; 541124060Swpaul block = adapter; 542124060Swpaul 543124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 544124409Swpaul device_printf (block->nmb_dev, "status: %x\n", status); 545123474Swpaul return; 546123474Swpaul} 547123474Swpaul 548123474Swpaul__stdcall static void 549123474Swpaulndis_statusdone_func(adapter) 550123474Swpaul ndis_handle adapter; 551123474Swpaul{ 552124060Swpaul ndis_miniport_block *block; 553124060Swpaul block = adapter; 554124060Swpaul 555124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 556124409Swpaul device_printf (block->nmb_dev, "status complete\n"); 557123474Swpaul return; 558123474Swpaul} 559123474Swpaul 560123474Swpaul__stdcall static void 561123474Swpaulndis_setdone_func(adapter, status) 562123474Swpaul ndis_handle adapter; 563123474Swpaul ndis_status status; 564123474Swpaul{ 565123695Swpaul ndis_miniport_block *block; 566123695Swpaul block = adapter; 567123695Swpaul 568123695Swpaul block->nmb_setstat = status; 569123695Swpaul wakeup(&block->nmb_wkupdpctimer); 570123474Swpaul return; 571123474Swpaul} 572123474Swpaul 573123474Swpaul__stdcall static void 574123535Swpaulndis_getdone_func(adapter, status) 575123535Swpaul ndis_handle adapter; 576123535Swpaul ndis_status status; 577123535Swpaul{ 578123695Swpaul ndis_miniport_block *block; 579123695Swpaul block = adapter; 580123695Swpaul 581123695Swpaul block->nmb_getstat = status; 582123695Swpaul wakeup(&block->nmb_wkupdpctimer); 583123535Swpaul return; 584123535Swpaul} 585123535Swpaul 586123535Swpaul__stdcall static void 587123474Swpaulndis_resetdone_func(adapter, status, addressingreset) 588123474Swpaul ndis_handle adapter; 589123474Swpaul ndis_status status; 590123474Swpaul uint8_t addressingreset; 591123474Swpaul{ 592124060Swpaul ndis_miniport_block *block; 593124060Swpaul block = adapter; 594124060Swpaul 595124409Swpaul if (block->nmb_ifp->if_flags & IFF_DEBUG) 596124409Swpaul device_printf (block->nmb_dev, "reset done...\n"); 597127887Swpaul wakeup(block->nmb_ifp); 598123474Swpaul return; 599123474Swpaul} 600123474Swpaul 601123474Swpaulint 602123474Swpaulndis_create_sysctls(arg) 603123474Swpaul void *arg; 604123474Swpaul{ 605123474Swpaul struct ndis_softc *sc; 606123474Swpaul ndis_cfg *vals; 607123474Swpaul char buf[256]; 608123474Swpaul 609123474Swpaul if (arg == NULL) 610123474Swpaul return(EINVAL); 611123474Swpaul 612123474Swpaul sc = arg; 613123474Swpaul vals = sc->ndis_regvals; 614123474Swpaul 615123474Swpaul TAILQ_INIT(&sc->ndis_cfglist_head); 616123474Swpaul 617130097Sdes#if __FreeBSD_version < 502113 618123474Swpaul /* Create the sysctl tree. */ 619123474Swpaul 620123474Swpaul sc->ndis_tree = SYSCTL_ADD_NODE(&sc->ndis_ctx, 621123474Swpaul SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, 622123474Swpaul device_get_nameunit(sc->ndis_dev), CTLFLAG_RD, 0, 623123474Swpaul device_get_desc(sc->ndis_dev)); 624123474Swpaul 625130097Sdes#endif 626123474Swpaul /* Add the driver-specific registry keys. */ 627123474Swpaul 628123474Swpaul vals = sc->ndis_regvals; 629123474Swpaul while(1) { 630123474Swpaul if (vals->nc_cfgkey == NULL) 631123474Swpaul break; 632123620Swpaul if (vals->nc_idx != sc->ndis_devidx) { 633123620Swpaul vals++; 634123620Swpaul continue; 635123620Swpaul } 636130097Sdes#if __FreeBSD_version < 502113 637123474Swpaul SYSCTL_ADD_STRING(&sc->ndis_ctx, 638123474Swpaul SYSCTL_CHILDREN(sc->ndis_tree), 639130097Sdes#else 640130097Sdes SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 641130097Sdes SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 642130097Sdes#endif 643123474Swpaul OID_AUTO, vals->nc_cfgkey, 644123474Swpaul CTLFLAG_RW, vals->nc_val, 645123474Swpaul sizeof(vals->nc_val), 646123474Swpaul vals->nc_cfgdesc); 647123474Swpaul vals++; 648123474Swpaul } 649123474Swpaul 650123474Swpaul /* Now add a couple of builtin keys. */ 651123474Swpaul 652123474Swpaul /* 653123474Swpaul * Environment can be either Windows (0) or WindowsNT (1). 654123474Swpaul * We qualify as the latter. 655123474Swpaul */ 656123474Swpaul ndis_add_sysctl(sc, "Environment", 657123474Swpaul "Windows environment", "1", CTLFLAG_RD); 658123474Swpaul 659123474Swpaul /* NDIS version should be 5.1. */ 660123474Swpaul ndis_add_sysctl(sc, "NdisVersion", 661123474Swpaul "NDIS API Version", "0x00050001", CTLFLAG_RD); 662123474Swpaul 663123474Swpaul /* Bus type (PCI, PCMCIA, etc...) */ 664124272Swpaul sprintf(buf, "%d", (int)sc->ndis_iftype); 665123474Swpaul ndis_add_sysctl(sc, "BusType", "Bus Type", buf, CTLFLAG_RD); 666123474Swpaul 667123474Swpaul if (sc->ndis_res_io != NULL) { 668124272Swpaul sprintf(buf, "0x%lx", rman_get_start(sc->ndis_res_io)); 669123474Swpaul ndis_add_sysctl(sc, "IOBaseAddress", 670123474Swpaul "Base I/O Address", buf, CTLFLAG_RD); 671123474Swpaul } 672123474Swpaul 673123474Swpaul if (sc->ndis_irq != NULL) { 674124272Swpaul sprintf(buf, "%lu", rman_get_start(sc->ndis_irq)); 675123474Swpaul ndis_add_sysctl(sc, "InterruptNumber", 676123474Swpaul "Interrupt Number", buf, CTLFLAG_RD); 677123474Swpaul } 678123474Swpaul 679123474Swpaul return(0); 680123474Swpaul} 681123474Swpaul 682123474Swpaulint 683123474Swpaulndis_add_sysctl(arg, key, desc, val, flag) 684123474Swpaul void *arg; 685123474Swpaul char *key; 686123474Swpaul char *desc; 687123474Swpaul char *val; 688123474Swpaul int flag; 689123474Swpaul{ 690123474Swpaul struct ndis_softc *sc; 691123474Swpaul struct ndis_cfglist *cfg; 692123474Swpaul char descstr[256]; 693123474Swpaul 694123474Swpaul sc = arg; 695123474Swpaul 696123474Swpaul cfg = malloc(sizeof(struct ndis_cfglist), M_DEVBUF, M_NOWAIT|M_ZERO); 697123474Swpaul 698123474Swpaul if (cfg == NULL) 699123474Swpaul return(ENOMEM); 700123474Swpaul 701123474Swpaul cfg->ndis_cfg.nc_cfgkey = strdup(key, M_DEVBUF); 702123474Swpaul if (desc == NULL) { 703123474Swpaul snprintf(descstr, sizeof(descstr), "%s (dynamic)", key); 704123474Swpaul cfg->ndis_cfg.nc_cfgdesc = strdup(descstr, M_DEVBUF); 705123474Swpaul } else 706123474Swpaul cfg->ndis_cfg.nc_cfgdesc = strdup(desc, M_DEVBUF); 707123474Swpaul strcpy(cfg->ndis_cfg.nc_val, val); 708123474Swpaul 709123474Swpaul TAILQ_INSERT_TAIL(&sc->ndis_cfglist_head, cfg, link); 710123474Swpaul 711130097Sdes#if __FreeBSD_version < 502113 712123474Swpaul SYSCTL_ADD_STRING(&sc->ndis_ctx, SYSCTL_CHILDREN(sc->ndis_tree), 713130097Sdes#else 714130097Sdes SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->ndis_dev), 715130097Sdes SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ndis_dev)), 716130097Sdes#endif 717123474Swpaul OID_AUTO, cfg->ndis_cfg.nc_cfgkey, flag, 718123474Swpaul cfg->ndis_cfg.nc_val, sizeof(cfg->ndis_cfg.nc_val), 719123474Swpaul cfg->ndis_cfg.nc_cfgdesc); 720123474Swpaul 721123474Swpaul return(0); 722123474Swpaul} 723123474Swpaul 724123474Swpaulint 725123474Swpaulndis_flush_sysctls(arg) 726123474Swpaul void *arg; 727123474Swpaul{ 728123474Swpaul struct ndis_softc *sc; 729123474Swpaul struct ndis_cfglist *cfg; 730123474Swpaul 731123474Swpaul sc = arg; 732123474Swpaul 733123474Swpaul while (!TAILQ_EMPTY(&sc->ndis_cfglist_head)) { 734123474Swpaul cfg = TAILQ_FIRST(&sc->ndis_cfglist_head); 735123474Swpaul TAILQ_REMOVE(&sc->ndis_cfglist_head, cfg, link); 736123474Swpaul free(cfg->ndis_cfg.nc_cfgkey, M_DEVBUF); 737123474Swpaul free(cfg->ndis_cfg.nc_cfgdesc, M_DEVBUF); 738123474Swpaul free(cfg, M_DEVBUF); 739123474Swpaul } 740123474Swpaul 741123474Swpaul return(0); 742123474Swpaul} 743123474Swpaul 744128546Swpaulstatic void 745128546Swpaulndis_return(arg) 746123474Swpaul void *arg; 747123474Swpaul{ 748123474Swpaul struct ndis_softc *sc; 749128546Swpaul __stdcall ndis_return_handler returnfunc; 750123474Swpaul ndis_handle adapter; 751123535Swpaul ndis_packet *p; 752128229Swpaul uint8_t irql; 753123474Swpaul 754128546Swpaul p = arg; 755128546Swpaul sc = p->np_softc; 756128546Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 757128546Swpaul 758128546Swpaul if (adapter == NULL) 759128546Swpaul return; 760128546Swpaul 761128546Swpaul returnfunc = sc->ndis_chars.nmc_return_packet_func; 762128546Swpaul irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); 763128546Swpaul returnfunc(adapter, p); 764128546Swpaul FASTCALL1(hal_lower_irql, irql); 765128546Swpaul 766128546Swpaul return; 767128546Swpaul} 768128546Swpaul 769128546Swpaulvoid 770128546Swpaulndis_return_packet(buf, arg) 771128546Swpaul void *buf; /* not used */ 772128546Swpaul void *arg; 773128546Swpaul{ 774128546Swpaul ndis_packet *p; 775128546Swpaul 776123826Swpaul if (arg == NULL) 777123474Swpaul return; 778123474Swpaul 779123826Swpaul p = arg; 780123535Swpaul 781123535Swpaul /* Decrement refcount. */ 782123826Swpaul p->np_refcnt--; 783123535Swpaul 784123535Swpaul /* Release packet when refcount hits zero, otherwise return. */ 785123826Swpaul if (p->np_refcnt) 786123535Swpaul return; 787123536Swpaul 788128546Swpaul ndis_sched(ndis_return, p, NDIS_SWI); 789123858Swpaul 790123474Swpaul return; 791123474Swpaul} 792123474Swpaul 793123848Swpaulvoid 794123848Swpaulndis_free_bufs(b0) 795123848Swpaul ndis_buffer *b0; 796123848Swpaul{ 797123848Swpaul ndis_buffer *next; 798123848Swpaul 799123848Swpaul if (b0 == NULL) 800123848Swpaul return; 801123848Swpaul 802123848Swpaul while(b0 != NULL) { 803123848Swpaul next = b0->nb_next; 804124060Swpaul uma_zfree (ndis_buffer_zone, b0); 805123848Swpaul b0 = next; 806123848Swpaul } 807123848Swpaul 808123848Swpaul return; 809123848Swpaul} 810123848Swpaul 811123848Swpaulvoid 812123848Swpaulndis_free_packet(p) 813123848Swpaul ndis_packet *p; 814123848Swpaul{ 815123848Swpaul if (p == NULL) 816123848Swpaul return; 817123848Swpaul 818123848Swpaul ndis_free_bufs(p->np_private.npp_head); 819124060Swpaul uma_zfree(ndis_packet_zone, p); 820123848Swpaul 821123848Swpaul return; 822123848Swpaul} 823123848Swpaul 824123474Swpaulint 825123474Swpaulndis_convert_res(arg) 826123474Swpaul void *arg; 827123474Swpaul{ 828123474Swpaul struct ndis_softc *sc; 829123474Swpaul ndis_resource_list *rl = NULL; 830123474Swpaul cm_partial_resource_desc *prd = NULL; 831123474Swpaul ndis_miniport_block *block; 832123976Swpaul device_t dev; 833123976Swpaul struct resource_list *brl; 834127411Swpaul struct resource_list brl_rev; 835127411Swpaul struct resource_list_entry *brle, *n; 836127411Swpaul int error = 0; 837123474Swpaul 838123474Swpaul sc = arg; 839123474Swpaul block = &sc->ndis_block; 840123976Swpaul dev = sc->ndis_dev; 841123474Swpaul 842128012Swpaul SLIST_INIT(&brl_rev); 843128012Swpaul 844123474Swpaul rl = malloc(sizeof(ndis_resource_list) + 845123474Swpaul (sizeof(cm_partial_resource_desc) * (sc->ndis_rescnt - 1)), 846123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 847123474Swpaul 848123474Swpaul if (rl == NULL) 849123474Swpaul return(ENOMEM); 850123474Swpaul 851123474Swpaul rl->cprl_version = 5; 852123474Swpaul rl->cprl_version = 1; 853123474Swpaul rl->cprl_count = sc->ndis_rescnt; 854123474Swpaul prd = rl->cprl_partial_descs; 855123474Swpaul 856131953Swpaul brl = BUS_GET_RESOURCE_LIST(dev, dev); 857131953Swpaul 858123976Swpaul if (brl != NULL) { 859127411Swpaul 860127411Swpaul /* 861127411Swpaul * We have a small problem. Some PCI devices have 862127411Swpaul * multiple I/O ranges. Windows orders them starting 863127411Swpaul * from lowest numbered BAR to highest. We discover 864127411Swpaul * them in that order too, but insert them into a singly 865127411Swpaul * linked list head first, which means when time comes 866127411Swpaul * to traverse the list, we enumerate them in reverse 867127411Swpaul * order. This screws up some drivers which expect the 868127411Swpaul * BARs to be in ascending order so that they can choose 869127411Swpaul * the "first" one as their register space. Unfortunately, 870127411Swpaul * in order to fix this, we have to create our own 871127411Swpaul * temporary list with the entries in reverse order. 872127411Swpaul */ 873123976Swpaul SLIST_FOREACH(brle, brl, link) { 874127411Swpaul n = malloc(sizeof(struct resource_list_entry), 875127411Swpaul M_TEMP, M_NOWAIT); 876127411Swpaul if (n == NULL) { 877127411Swpaul error = ENOMEM; 878127411Swpaul goto bad; 879127411Swpaul } 880127411Swpaul bcopy((char *)brle, (char *)n, 881127411Swpaul sizeof(struct resource_list_entry)); 882127411Swpaul SLIST_INSERT_HEAD(&brl_rev, n, link); 883127411Swpaul } 884127411Swpaul 885127411Swpaul SLIST_FOREACH(brle, &brl_rev, link) { 886123976Swpaul switch (brle->type) { 887123976Swpaul case SYS_RES_IOPORT: 888123976Swpaul prd->cprd_type = CmResourceTypePort; 889127552Swpaul prd->cprd_flags = CM_RESOURCE_PORT_IO; 890127552Swpaul prd->cprd_sharedisp = 891127552Swpaul CmResourceShareDeviceExclusive; 892123976Swpaul prd->u.cprd_port.cprd_start.np_quad = 893123976Swpaul brle->start; 894123976Swpaul prd->u.cprd_port.cprd_len = brle->count; 895123976Swpaul break; 896123976Swpaul case SYS_RES_MEMORY: 897123976Swpaul prd->cprd_type = CmResourceTypeMemory; 898127552Swpaul prd->cprd_flags = 899127552Swpaul CM_RESOURCE_MEMORY_READ_WRITE; 900127552Swpaul prd->cprd_sharedisp = 901127552Swpaul CmResourceShareDeviceExclusive; 902123976Swpaul prd->u.cprd_port.cprd_start.np_quad = 903123976Swpaul brle->start; 904123976Swpaul prd->u.cprd_port.cprd_len = brle->count; 905123976Swpaul break; 906123976Swpaul case SYS_RES_IRQ: 907123976Swpaul prd->cprd_type = CmResourceTypeInterrupt; 908127552Swpaul prd->cprd_flags = 0; 909127552Swpaul prd->cprd_sharedisp = 910127552Swpaul CmResourceShareDeviceExclusive; 911123976Swpaul prd->u.cprd_intr.cprd_level = brle->start; 912123976Swpaul prd->u.cprd_intr.cprd_vector = brle->start; 913123976Swpaul prd->u.cprd_intr.cprd_affinity = 0; 914123976Swpaul break; 915123976Swpaul default: 916123976Swpaul break; 917123976Swpaul } 918123976Swpaul prd++; 919123976Swpaul } 920123474Swpaul } 921123474Swpaul 922123474Swpaul block->nmb_rlist = rl; 923123474Swpaul 924127411Swpaulbad: 925127411Swpaul 926127411Swpaul while (!SLIST_EMPTY(&brl_rev)) { 927127411Swpaul n = SLIST_FIRST(&brl_rev); 928127411Swpaul SLIST_REMOVE_HEAD(&brl_rev, link); 929127411Swpaul free (n, M_TEMP); 930127411Swpaul } 931127411Swpaul 932127411Swpaul return(error); 933123474Swpaul} 934123474Swpaul 935123474Swpaul/* 936123474Swpaul * Map an NDIS packet to an mbuf list. When an NDIS driver receives a 937123474Swpaul * packet, it will hand it to us in the form of an ndis_packet, 938123474Swpaul * which we need to convert to an mbuf that is then handed off 939123474Swpaul * to the stack. Note: we configure the mbuf list so that it uses 940123474Swpaul * the memory regions specified by the ndis_buffer structures in 941123474Swpaul * the ndis_packet as external storage. In most cases, this will 942123474Swpaul * point to a memory region allocated by the driver (either by 943123474Swpaul * ndis_malloc_withtag() or ndis_alloc_sharedmem()). We expect 944123474Swpaul * the driver to handle free()ing this region for is, so we set up 945123474Swpaul * a dummy no-op free handler for it. 946123474Swpaul */ 947123474Swpaul 948123474Swpaulint 949123474Swpaulndis_ptom(m0, p) 950123474Swpaul struct mbuf **m0; 951123474Swpaul ndis_packet *p; 952123474Swpaul{ 953123474Swpaul struct mbuf *m, *prev = NULL; 954123474Swpaul ndis_buffer *buf; 955123474Swpaul ndis_packet_private *priv; 956123474Swpaul uint32_t totlen = 0; 957123474Swpaul 958123474Swpaul if (p == NULL || m0 == NULL) 959123474Swpaul return(EINVAL); 960123474Swpaul 961123474Swpaul priv = &p->np_private; 962123474Swpaul buf = priv->npp_head; 963123826Swpaul p->np_refcnt = 0; 964123474Swpaul 965123474Swpaul for (buf = priv->npp_head; buf != NULL; buf = buf->nb_next) { 966123474Swpaul if (buf == priv->npp_head) 967123474Swpaul MGETHDR(m, M_DONTWAIT, MT_HEADER); 968123474Swpaul else 969123474Swpaul MGET(m, M_DONTWAIT, MT_DATA); 970123474Swpaul if (m == NULL) { 971123474Swpaul m_freem(*m0); 972123474Swpaul *m0 = NULL; 973123474Swpaul return(ENOBUFS); 974123474Swpaul } 975123757Swpaul m->m_len = buf->nb_bytecount; 976123757Swpaul m->m_data = MDL_VA(buf); 977123535Swpaul MEXTADD(m, m->m_data, m->m_len, ndis_return_packet, 978123826Swpaul p, 0, EXT_NDIS); 979123826Swpaul p->np_refcnt++; 980123474Swpaul totlen += m->m_len; 981123474Swpaul if (m->m_flags & MT_HEADER) 982123474Swpaul *m0 = m; 983123474Swpaul else 984123474Swpaul prev->m_next = m; 985123474Swpaul prev = m; 986123474Swpaul } 987123474Swpaul 988123474Swpaul (*m0)->m_pkthdr.len = totlen; 989123474Swpaul 990123474Swpaul return(0); 991123474Swpaul} 992123474Swpaul 993123474Swpaul/* 994123474Swpaul * Create an mbuf chain from an NDIS packet chain. 995123474Swpaul * This is used mainly when transmitting packets, where we need 996123474Swpaul * to turn an mbuf off an interface's send queue and transform it 997123474Swpaul * into an NDIS packet which will be fed into the NDIS driver's 998123474Swpaul * send routine. 999123474Swpaul * 1000123474Swpaul * NDIS packets consist of two parts: an ndis_packet structure, 1001123474Swpaul * which is vaguely analagous to the pkthdr portion of an mbuf, 1002123474Swpaul * and one or more ndis_buffer structures, which define the 1003123474Swpaul * actual memory segments in which the packet data resides. 1004123474Swpaul * We need to allocate one ndis_buffer for each mbuf in a chain, 1005123474Swpaul * plus one ndis_packet as the header. 1006123474Swpaul */ 1007123474Swpaul 1008123474Swpaulint 1009123474Swpaulndis_mtop(m0, p) 1010123474Swpaul struct mbuf *m0; 1011123474Swpaul ndis_packet **p; 1012123474Swpaul{ 1013123474Swpaul struct mbuf *m; 1014123474Swpaul ndis_buffer *buf = NULL, *prev = NULL; 1015123474Swpaul ndis_packet_private *priv; 1016123474Swpaul 1017123474Swpaul if (p == NULL || m0 == NULL) 1018123474Swpaul return(EINVAL); 1019123474Swpaul 1020123474Swpaul /* If caller didn't supply a packet, make one. */ 1021123474Swpaul if (*p == NULL) { 1022124060Swpaul *p = uma_zalloc(ndis_packet_zone, M_NOWAIT|M_ZERO); 1023123474Swpaul 1024123474Swpaul if (*p == NULL) 1025123474Swpaul return(ENOMEM); 1026123474Swpaul } 1027123474Swpaul 1028123474Swpaul priv = &(*p)->np_private; 1029123474Swpaul priv->npp_totlen = m0->m_pkthdr.len; 1030123474Swpaul priv->npp_packetooboffset = offsetof(ndis_packet, np_oob); 1031124278Swpaul priv->npp_ndispktflags = NDIS_PACKET_ALLOCATED_BY_NDIS; 1032123474Swpaul 1033123474Swpaul for (m = m0; m != NULL; m = m->m_next) { 1034123810Salfred if (m->m_len == 0) 1035123474Swpaul continue; 1036124060Swpaul buf = uma_zalloc(ndis_buffer_zone, M_NOWAIT | M_ZERO); 1037123474Swpaul if (buf == NULL) { 1038123474Swpaul ndis_free_packet(*p); 1039123474Swpaul *p = NULL; 1040123474Swpaul return(ENOMEM); 1041123474Swpaul } 1042123474Swpaul 1043123757Swpaul MDL_INIT(buf, m->m_data, m->m_len); 1044123474Swpaul if (priv->npp_head == NULL) 1045123474Swpaul priv->npp_head = buf; 1046123474Swpaul else 1047123474Swpaul prev->nb_next = buf; 1048123474Swpaul prev = buf; 1049123474Swpaul } 1050123474Swpaul 1051123474Swpaul priv->npp_tail = buf; 1052124060Swpaul priv->npp_totlen = m0->m_pkthdr.len; 1053123474Swpaul 1054123474Swpaul return(0); 1055123474Swpaul} 1056123474Swpaul 1057123474Swpaulint 1058123474Swpaulndis_get_supported_oids(arg, oids, oidcnt) 1059123474Swpaul void *arg; 1060123474Swpaul ndis_oid **oids; 1061123474Swpaul int *oidcnt; 1062123474Swpaul{ 1063123474Swpaul int len, rval; 1064123474Swpaul ndis_oid *o; 1065123474Swpaul 1066123474Swpaul if (arg == NULL || oids == NULL || oidcnt == NULL) 1067123474Swpaul return(EINVAL); 1068123474Swpaul len = 0; 1069123474Swpaul ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, NULL, &len); 1070123474Swpaul 1071123474Swpaul o = malloc(len, M_DEVBUF, M_NOWAIT); 1072123474Swpaul if (o == NULL) 1073123474Swpaul return(ENOMEM); 1074123474Swpaul 1075123474Swpaul rval = ndis_get_info(arg, OID_GEN_SUPPORTED_LIST, o, &len); 1076123474Swpaul 1077123474Swpaul if (rval) { 1078123474Swpaul free(o, M_DEVBUF); 1079123474Swpaul return(rval); 1080123474Swpaul } 1081123474Swpaul 1082123474Swpaul *oids = o; 1083123474Swpaul *oidcnt = len / 4; 1084123474Swpaul 1085123474Swpaul return(0); 1086123474Swpaul} 1087123474Swpaul 1088123474Swpaulint 1089123474Swpaulndis_set_info(arg, oid, buf, buflen) 1090123474Swpaul void *arg; 1091123474Swpaul ndis_oid oid; 1092123474Swpaul void *buf; 1093123474Swpaul int *buflen; 1094123474Swpaul{ 1095123474Swpaul struct ndis_softc *sc; 1096123474Swpaul ndis_status rval; 1097123474Swpaul ndis_handle adapter; 1098123474Swpaul __stdcall ndis_setinfo_handler setfunc; 1099123474Swpaul uint32_t byteswritten = 0, bytesneeded = 0; 1100123695Swpaul int error; 1101128229Swpaul uint8_t irql; 1102123474Swpaul 1103123474Swpaul sc = arg; 1104125718Swpaul NDIS_LOCK(sc); 1105123474Swpaul setfunc = sc->ndis_chars.nmc_setinfo_func; 1106123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1107125718Swpaul NDIS_UNLOCK(sc); 1108123474Swpaul 1109125718Swpaul if (adapter == NULL || setfunc == NULL) 1110125676Swpaul return(ENXIO); 1111125676Swpaul 1112128229Swpaul irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); 1113123474Swpaul rval = setfunc(adapter, oid, buf, *buflen, 1114123474Swpaul &byteswritten, &bytesneeded); 1115128229Swpaul FASTCALL1(hal_lower_irql, irql); 1116123474Swpaul 1117123695Swpaul if (rval == NDIS_STATUS_PENDING) { 1118127887Swpaul PROC_LOCK(curthread->td_proc); 1119127887Swpaul error = msleep(&sc->ndis_block.nmb_wkupdpctimer, 1120128229Swpaul &curthread->td_proc->p_mtx, 1121128229Swpaul curthread->td_priority|PDROP, 1122127887Swpaul "ndisset", 5 * hz); 1123123695Swpaul rval = sc->ndis_block.nmb_setstat; 1124123695Swpaul } 1125123695Swpaul 1126123474Swpaul if (byteswritten) 1127123474Swpaul *buflen = byteswritten; 1128123474Swpaul if (bytesneeded) 1129123474Swpaul *buflen = bytesneeded; 1130123474Swpaul 1131123474Swpaul if (rval == NDIS_STATUS_INVALID_LENGTH) 1132123474Swpaul return(ENOSPC); 1133123474Swpaul 1134123474Swpaul if (rval == NDIS_STATUS_INVALID_OID) 1135123474Swpaul return(EINVAL); 1136123474Swpaul 1137123474Swpaul if (rval == NDIS_STATUS_NOT_SUPPORTED || 1138123474Swpaul rval == NDIS_STATUS_NOT_ACCEPTED) 1139123474Swpaul return(ENOTSUP); 1140123474Swpaul 1141124809Swpaul if (rval != NDIS_STATUS_SUCCESS) 1142124809Swpaul return(ENODEV); 1143124809Swpaul 1144123474Swpaul return(0); 1145123474Swpaul} 1146123474Swpaul 1147124202Swpaultypedef void (*ndis_senddone_func)(ndis_handle, ndis_packet *, ndis_status); 1148124202Swpaul 1149123474Swpaulint 1150123474Swpaulndis_send_packets(arg, packets, cnt) 1151123474Swpaul void *arg; 1152123474Swpaul ndis_packet **packets; 1153123474Swpaul int cnt; 1154123474Swpaul{ 1155123474Swpaul struct ndis_softc *sc; 1156123474Swpaul ndis_handle adapter; 1157123474Swpaul __stdcall ndis_sendmulti_handler sendfunc; 1158124202Swpaul __stdcall ndis_senddone_func senddonefunc; 1159124202Swpaul int i; 1160123858Swpaul ndis_packet *p; 1161128229Swpaul uint8_t irql; 1162123474Swpaul 1163123474Swpaul sc = arg; 1164123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1165125718Swpaul if (adapter == NULL) 1166125718Swpaul return(ENXIO); 1167123474Swpaul sendfunc = sc->ndis_chars.nmc_sendmulti_func; 1168124202Swpaul senddonefunc = sc->ndis_block.nmb_senddone_func; 1169128229Swpaul irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); 1170123474Swpaul sendfunc(adapter, packets, cnt); 1171128229Swpaul FASTCALL1(hal_lower_irql, irql); 1172123474Swpaul 1173123858Swpaul for (i = 0; i < cnt; i++) { 1174123858Swpaul p = packets[i]; 1175124005Swpaul /* 1176124005Swpaul * Either the driver already handed the packet to 1177124005Swpaul * ndis_txeof() due to a failure, or it wants to keep 1178124005Swpaul * it and release it asynchronously later. Skip to the 1179124005Swpaul * next one. 1180124005Swpaul */ 1181124005Swpaul if (p == NULL || p->np_oob.npo_status == NDIS_STATUS_PENDING) 1182123858Swpaul continue; 1183124202Swpaul senddonefunc(&sc->ndis_block, p, p->np_oob.npo_status); 1184123858Swpaul } 1185123858Swpaul 1186123474Swpaul return(0); 1187123474Swpaul} 1188123474Swpaul 1189123474Swpaulint 1190125377Swpaulndis_send_packet(arg, packet) 1191125377Swpaul void *arg; 1192125377Swpaul ndis_packet *packet; 1193125377Swpaul{ 1194125377Swpaul struct ndis_softc *sc; 1195125377Swpaul ndis_handle adapter; 1196125377Swpaul ndis_status status; 1197125377Swpaul __stdcall ndis_sendsingle_handler sendfunc; 1198125377Swpaul __stdcall ndis_senddone_func senddonefunc; 1199128229Swpaul uint8_t irql; 1200125377Swpaul 1201125377Swpaul sc = arg; 1202125377Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1203125718Swpaul if (adapter == NULL) 1204125718Swpaul return(ENXIO); 1205125377Swpaul sendfunc = sc->ndis_chars.nmc_sendsingle_func; 1206125377Swpaul senddonefunc = sc->ndis_block.nmb_senddone_func; 1207125377Swpaul 1208128229Swpaul irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); 1209125377Swpaul status = sendfunc(adapter, packet, packet->np_private.npp_flags); 1210128229Swpaul FASTCALL1(hal_lower_irql, irql); 1211125377Swpaul 1212125377Swpaul if (status == NDIS_STATUS_PENDING) 1213125377Swpaul return(0); 1214125377Swpaul 1215125377Swpaul senddonefunc(&sc->ndis_block, packet, status); 1216125377Swpaul 1217125377Swpaul return(0); 1218125377Swpaul} 1219125377Swpaul 1220125377Swpaulint 1221123474Swpaulndis_init_dma(arg) 1222123474Swpaul void *arg; 1223123474Swpaul{ 1224123474Swpaul struct ndis_softc *sc; 1225123474Swpaul int i, error; 1226123474Swpaul 1227123474Swpaul sc = arg; 1228123474Swpaul 1229123474Swpaul sc->ndis_tmaps = malloc(sizeof(bus_dmamap_t) * sc->ndis_maxpkts, 1230123474Swpaul M_DEVBUF, M_NOWAIT|M_ZERO); 1231123474Swpaul 1232123474Swpaul if (sc->ndis_tmaps == NULL) 1233123474Swpaul return(ENOMEM); 1234123474Swpaul 1235123474Swpaul for (i = 0; i < sc->ndis_maxpkts; i++) { 1236123474Swpaul error = bus_dmamap_create(sc->ndis_ttag, 0, 1237123474Swpaul &sc->ndis_tmaps[i]); 1238123474Swpaul if (error) { 1239123474Swpaul free(sc->ndis_tmaps, M_DEVBUF); 1240123474Swpaul return(ENODEV); 1241123474Swpaul } 1242123474Swpaul } 1243123474Swpaul 1244123474Swpaul return(0); 1245123474Swpaul} 1246123474Swpaul 1247123474Swpaulint 1248123474Swpaulndis_destroy_dma(arg) 1249123474Swpaul void *arg; 1250123474Swpaul{ 1251123474Swpaul struct ndis_softc *sc; 1252123535Swpaul struct mbuf *m; 1253123535Swpaul ndis_packet *p = NULL; 1254123474Swpaul int i; 1255123474Swpaul 1256123474Swpaul sc = arg; 1257123474Swpaul 1258123474Swpaul for (i = 0; i < sc->ndis_maxpkts; i++) { 1259123535Swpaul if (sc->ndis_txarray[i] != NULL) { 1260123535Swpaul p = sc->ndis_txarray[i]; 1261123535Swpaul m = (struct mbuf *)p->np_rsvd[1]; 1262123535Swpaul if (m != NULL) 1263123535Swpaul m_freem(m); 1264123535Swpaul ndis_free_packet(sc->ndis_txarray[i]); 1265123535Swpaul } 1266123474Swpaul bus_dmamap_destroy(sc->ndis_ttag, sc->ndis_tmaps[i]); 1267123474Swpaul } 1268123474Swpaul 1269123474Swpaul free(sc->ndis_tmaps, M_DEVBUF); 1270123474Swpaul 1271123474Swpaul bus_dma_tag_destroy(sc->ndis_ttag); 1272123474Swpaul 1273123474Swpaul return(0); 1274123474Swpaul} 1275123474Swpaul 1276123474Swpaulint 1277123474Swpaulndis_reset_nic(arg) 1278123474Swpaul void *arg; 1279123474Swpaul{ 1280123474Swpaul struct ndis_softc *sc; 1281123474Swpaul ndis_handle adapter; 1282123474Swpaul __stdcall ndis_reset_handler resetfunc; 1283123474Swpaul uint8_t addressing_reset; 1284123474Swpaul struct ifnet *ifp; 1285127887Swpaul int rval; 1286128229Swpaul uint8_t irql; 1287123474Swpaul 1288123474Swpaul sc = arg; 1289123474Swpaul ifp = &sc->arpcom.ac_if; 1290125718Swpaul NDIS_LOCK(sc); 1291123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1292125718Swpaul resetfunc = sc->ndis_chars.nmc_reset_func; 1293125718Swpaul NDIS_UNLOCK(sc); 1294125718Swpaul if (adapter == NULL || resetfunc == NULL) 1295123474Swpaul return(EIO); 1296123474Swpaul 1297128229Swpaul irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); 1298127887Swpaul rval = resetfunc(&addressing_reset, adapter); 1299128229Swpaul FASTCALL1(hal_lower_irql, irql); 1300128229Swpaul 1301127887Swpaul if (rval == NDIS_STATUS_PENDING) { 1302127887Swpaul PROC_LOCK(curthread->td_proc); 1303127887Swpaul msleep(sc, &curthread->td_proc->p_mtx, 1304128229Swpaul curthread->td_priority|PDROP, "ndisrst", 0); 1305127887Swpaul } 1306123474Swpaul 1307123474Swpaul return(0); 1308123474Swpaul} 1309123474Swpaul 1310123474Swpaulint 1311123474Swpaulndis_halt_nic(arg) 1312123474Swpaul void *arg; 1313123474Swpaul{ 1314123474Swpaul struct ndis_softc *sc; 1315123474Swpaul ndis_handle adapter; 1316123474Swpaul __stdcall ndis_halt_handler haltfunc; 1317123474Swpaul struct ifnet *ifp; 1318123474Swpaul 1319123474Swpaul sc = arg; 1320123474Swpaul ifp = &sc->arpcom.ac_if; 1321125718Swpaul 1322125718Swpaul NDIS_LOCK(sc); 1323123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1324125718Swpaul if (adapter == NULL) { 1325125718Swpaul NDIS_UNLOCK(sc); 1326123474Swpaul return(EIO); 1327125718Swpaul } 1328123821Swpaul 1329123474Swpaul /* 1330123474Swpaul * The adapter context is only valid after the init 1331123474Swpaul * handler has been called, and is invalid once the 1332123474Swpaul * halt handler has been called. 1333123474Swpaul */ 1334123474Swpaul 1335125718Swpaul haltfunc = sc->ndis_chars.nmc_halt_func; 1336125718Swpaul NDIS_UNLOCK(sc); 1337125718Swpaul 1338125718Swpaul haltfunc(adapter); 1339125718Swpaul 1340125718Swpaul NDIS_LOCK(sc); 1341123474Swpaul sc->ndis_block.nmb_miniportadapterctx = NULL; 1342125718Swpaul NDIS_UNLOCK(sc); 1343123821Swpaul 1344123474Swpaul return(0); 1345123474Swpaul} 1346123474Swpaul 1347123474Swpaulint 1348123474Swpaulndis_shutdown_nic(arg) 1349123474Swpaul void *arg; 1350123474Swpaul{ 1351123474Swpaul struct ndis_softc *sc; 1352123474Swpaul ndis_handle adapter; 1353123474Swpaul __stdcall ndis_shutdown_handler shutdownfunc; 1354123474Swpaul 1355123474Swpaul sc = arg; 1356125718Swpaul NDIS_LOCK(sc); 1357123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1358125718Swpaul shutdownfunc = sc->ndis_chars.nmc_shutdown_handler; 1359125718Swpaul NDIS_UNLOCK(sc); 1360125718Swpaul if (adapter == NULL || shutdownfunc == NULL) 1361123474Swpaul return(EIO); 1362123474Swpaul 1363123485Swpaul if (sc->ndis_chars.nmc_rsvd0 == NULL) 1364123485Swpaul shutdownfunc(adapter); 1365123485Swpaul else 1366123485Swpaul shutdownfunc(sc->ndis_chars.nmc_rsvd0); 1367123474Swpaul 1368125006Swpaul ndis_shrink_thrqueue(8); 1369125057Swpaul TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1370125006Swpaul 1371123474Swpaul return(0); 1372123474Swpaul} 1373123474Swpaul 1374123474Swpaulint 1375123474Swpaulndis_init_nic(arg) 1376123474Swpaul void *arg; 1377123474Swpaul{ 1378123474Swpaul struct ndis_softc *sc; 1379123474Swpaul ndis_miniport_block *block; 1380123474Swpaul __stdcall ndis_init_handler initfunc; 1381123474Swpaul ndis_status status, openstatus = 0; 1382123474Swpaul ndis_medium mediumarray[NdisMediumMax]; 1383123474Swpaul uint32_t chosenmedium, i; 1384123474Swpaul 1385123474Swpaul if (arg == NULL) 1386123474Swpaul return(EINVAL); 1387123474Swpaul 1388123474Swpaul sc = arg; 1389125718Swpaul NDIS_LOCK(sc); 1390123474Swpaul block = &sc->ndis_block; 1391123474Swpaul initfunc = sc->ndis_chars.nmc_init_func; 1392125718Swpaul NDIS_UNLOCK(sc); 1393123474Swpaul 1394123821Swpaul TAILQ_INIT(&block->nmb_timerlist); 1395123821Swpaul 1396123474Swpaul for (i = 0; i < NdisMediumMax; i++) 1397123474Swpaul mediumarray[i] = i; 1398123474Swpaul 1399123474Swpaul status = initfunc(&openstatus, &chosenmedium, 1400123474Swpaul mediumarray, NdisMediumMax, block, block); 1401123474Swpaul 1402123474Swpaul /* 1403123474Swpaul * If the init fails, blow away the other exported routines 1404123474Swpaul * we obtained from the driver so we can't call them later. 1405123474Swpaul * If the init failed, none of these will work. 1406123474Swpaul */ 1407123474Swpaul if (status != NDIS_STATUS_SUCCESS) { 1408125718Swpaul NDIS_LOCK(sc); 1409125676Swpaul sc->ndis_block.nmb_miniportadapterctx = NULL; 1410125718Swpaul NDIS_UNLOCK(sc); 1411123474Swpaul return(ENXIO); 1412123474Swpaul } 1413123474Swpaul 1414123474Swpaul return(0); 1415123474Swpaul} 1416123474Swpaul 1417123474Swpaulvoid 1418123474Swpaulndis_enable_intr(arg) 1419123474Swpaul void *arg; 1420123474Swpaul{ 1421123474Swpaul struct ndis_softc *sc; 1422123474Swpaul ndis_handle adapter; 1423123474Swpaul __stdcall ndis_enable_interrupts_handler intrenbfunc; 1424123474Swpaul 1425123474Swpaul sc = arg; 1426123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1427123474Swpaul intrenbfunc = sc->ndis_chars.nmc_enable_interrupts_func; 1428125718Swpaul if (adapter == NULL || intrenbfunc == NULL) 1429123474Swpaul return; 1430123474Swpaul intrenbfunc(adapter); 1431123474Swpaul 1432123474Swpaul return; 1433123474Swpaul} 1434123474Swpaul 1435123474Swpaulvoid 1436123474Swpaulndis_disable_intr(arg) 1437123474Swpaul void *arg; 1438123474Swpaul{ 1439123474Swpaul struct ndis_softc *sc; 1440123474Swpaul ndis_handle adapter; 1441123474Swpaul __stdcall ndis_disable_interrupts_handler intrdisfunc; 1442123474Swpaul 1443123474Swpaul sc = arg; 1444125718Swpaul NDIS_LOCK(sc); 1445123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1446125718Swpaul intrdisfunc = sc->ndis_chars.nmc_disable_interrupts_func; 1447125718Swpaul NDIS_UNLOCK(sc); 1448126834Swpaul if (adapter == NULL || intrdisfunc == NULL) 1449123474Swpaul return; 1450123474Swpaul intrdisfunc(adapter); 1451123474Swpaul 1452123474Swpaul return; 1453123474Swpaul} 1454123474Swpaul 1455123474Swpaulint 1456123474Swpaulndis_isr(arg, ourintr, callhandler) 1457123474Swpaul void *arg; 1458123474Swpaul int *ourintr; 1459123474Swpaul int *callhandler; 1460123474Swpaul{ 1461123474Swpaul struct ndis_softc *sc; 1462123474Swpaul ndis_handle adapter; 1463123474Swpaul __stdcall ndis_isr_handler isrfunc; 1464123474Swpaul uint8_t accepted, queue; 1465123474Swpaul 1466123474Swpaul if (arg == NULL || ourintr == NULL || callhandler == NULL) 1467123474Swpaul return(EINVAL); 1468123474Swpaul 1469123474Swpaul sc = arg; 1470123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1471123474Swpaul isrfunc = sc->ndis_chars.nmc_isr_func; 1472125718Swpaul if (adapter == NULL || isrfunc == NULL) 1473125718Swpaul return(ENXIO); 1474125718Swpaul 1475123474Swpaul isrfunc(&accepted, &queue, adapter); 1476123474Swpaul *ourintr = accepted; 1477123474Swpaul *callhandler = queue; 1478123474Swpaul 1479123474Swpaul return(0); 1480123474Swpaul} 1481123474Swpaul 1482123474Swpaulint 1483123474Swpaulndis_intrhand(arg) 1484123474Swpaul void *arg; 1485123474Swpaul{ 1486123474Swpaul struct ndis_softc *sc; 1487123474Swpaul ndis_handle adapter; 1488123474Swpaul __stdcall ndis_interrupt_handler intrfunc; 1489123474Swpaul 1490123474Swpaul if (arg == NULL) 1491123474Swpaul return(EINVAL); 1492123474Swpaul 1493123474Swpaul sc = arg; 1494125718Swpaul NDIS_LOCK(sc); 1495123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1496123474Swpaul intrfunc = sc->ndis_chars.nmc_interrupt_func; 1497125718Swpaul NDIS_UNLOCK(sc); 1498125718Swpaul if (adapter == NULL || intrfunc == NULL) 1499125718Swpaul return(EINVAL); 1500125718Swpaul 1501123474Swpaul intrfunc(adapter); 1502123474Swpaul 1503123474Swpaul return(0); 1504123474Swpaul} 1505123474Swpaul 1506123474Swpaulint 1507123474Swpaulndis_get_info(arg, oid, buf, buflen) 1508123474Swpaul void *arg; 1509123474Swpaul ndis_oid oid; 1510123474Swpaul void *buf; 1511123474Swpaul int *buflen; 1512123474Swpaul{ 1513123474Swpaul struct ndis_softc *sc; 1514123474Swpaul ndis_status rval; 1515123474Swpaul ndis_handle adapter; 1516123474Swpaul __stdcall ndis_queryinfo_handler queryfunc; 1517123474Swpaul uint32_t byteswritten = 0, bytesneeded = 0; 1518123695Swpaul int error; 1519128229Swpaul uint8_t irql; 1520123474Swpaul 1521123474Swpaul sc = arg; 1522125718Swpaul NDIS_LOCK(sc); 1523123474Swpaul queryfunc = sc->ndis_chars.nmc_queryinfo_func; 1524123474Swpaul adapter = sc->ndis_block.nmb_miniportadapterctx; 1525125718Swpaul NDIS_UNLOCK(sc); 1526123474Swpaul 1527125718Swpaul if (adapter == NULL || queryfunc == NULL) 1528125676Swpaul return(ENXIO); 1529125676Swpaul 1530128229Swpaul irql = FASTCALL1(hal_raise_irql, DISPATCH_LEVEL); 1531123474Swpaul rval = queryfunc(adapter, oid, buf, *buflen, 1532123474Swpaul &byteswritten, &bytesneeded); 1533128229Swpaul FASTCALL1(hal_lower_irql, irql); 1534123474Swpaul 1535123695Swpaul /* Wait for requests that block. */ 1536123695Swpaul 1537123695Swpaul if (rval == NDIS_STATUS_PENDING) { 1538127887Swpaul PROC_LOCK(curthread->td_proc); 1539127887Swpaul error = msleep(&sc->ndis_block.nmb_wkupdpctimer, 1540128229Swpaul &curthread->td_proc->p_mtx, 1541128229Swpaul curthread->td_priority|PDROP, 1542127887Swpaul "ndisget", 5 * hz); 1543123695Swpaul rval = sc->ndis_block.nmb_getstat; 1544123695Swpaul } 1545123695Swpaul 1546123474Swpaul if (byteswritten) 1547123474Swpaul *buflen = byteswritten; 1548123474Swpaul if (bytesneeded) 1549123474Swpaul *buflen = bytesneeded; 1550123474Swpaul 1551123474Swpaul if (rval == NDIS_STATUS_INVALID_LENGTH || 1552123474Swpaul rval == NDIS_STATUS_BUFFER_TOO_SHORT) 1553123474Swpaul return(ENOSPC); 1554123474Swpaul 1555123474Swpaul if (rval == NDIS_STATUS_INVALID_OID) 1556123474Swpaul return(EINVAL); 1557123474Swpaul 1558123474Swpaul if (rval == NDIS_STATUS_NOT_SUPPORTED || 1559123474Swpaul rval == NDIS_STATUS_NOT_ACCEPTED) 1560123474Swpaul return(ENOTSUP); 1561123474Swpaul 1562124809Swpaul if (rval != NDIS_STATUS_SUCCESS) 1563124809Swpaul return(ENODEV); 1564124809Swpaul 1565123474Swpaul return(0); 1566123474Swpaul} 1567123474Swpaul 1568123474Swpaulint 1569123474Swpaulndis_unload_driver(arg) 1570123474Swpaul void *arg; 1571123474Swpaul{ 1572123474Swpaul struct ndis_softc *sc; 1573123474Swpaul 1574123474Swpaul sc = arg; 1575123474Swpaul 1576123474Swpaul free(sc->ndis_block.nmb_rlist, M_DEVBUF); 1577123474Swpaul 1578123474Swpaul ndis_flush_sysctls(sc); 1579123474Swpaul 1580124697Swpaul ndis_shrink_thrqueue(8); 1581125057Swpaul TAILQ_REMOVE(&ndis_devhead, &sc->ndis_block, link); 1582124697Swpaul 1583123474Swpaul return(0); 1584123474Swpaul} 1585123474Swpaul 1586127887Swpaul#define NDIS_LOADED htonl(0x42534F44) 1587124446Swpaul 1588123474Swpaulint 1589123474Swpaulndis_load_driver(img, arg) 1590123474Swpaul vm_offset_t img; 1591123474Swpaul void *arg; 1592123474Swpaul{ 1593123474Swpaul __stdcall driver_entry entry; 1594123474Swpaul image_optional_header opt_hdr; 1595123474Swpaul image_import_descriptor imp_desc; 1596123474Swpaul ndis_unicode_string dummystr; 1597123474Swpaul ndis_miniport_block *block; 1598123474Swpaul ndis_status status; 1599123474Swpaul int idx; 1600123474Swpaul uint32_t *ptr; 1601123474Swpaul struct ndis_softc *sc; 1602123474Swpaul 1603123474Swpaul sc = arg; 1604123474Swpaul 1605124446Swpaul /* 1606124446Swpaul * Only perform the relocation/linking phase once 1607124446Swpaul * since the binary image may be shared among multiple 1608124446Swpaul * device instances. 1609124446Swpaul */ 1610123474Swpaul 1611124446Swpaul ptr = (uint32_t *)(img + 8); 1612124446Swpaul if (*ptr != NDIS_LOADED) { 1613124446Swpaul /* Perform text relocation */ 1614124446Swpaul if (pe_relocate(img)) 1615124446Swpaul return(ENOEXEC); 1616123474Swpaul 1617124446Swpaul /* Dynamically link the NDIS.SYS routines -- required. */ 1618124446Swpaul if (pe_patch_imports(img, "NDIS", ndis_functbl)) 1619124446Swpaul return(ENOEXEC); 1620123474Swpaul 1621124446Swpaul /* Dynamically link the HAL.dll routines -- also required. */ 1622124446Swpaul if (pe_patch_imports(img, "HAL", hal_functbl)) 1623123474Swpaul return(ENOEXEC); 1624124446Swpaul 1625124446Swpaul /* Dynamically link ntoskrnl.exe -- optional. */ 1626124446Swpaul if (pe_get_import_descriptor(img, 1627124446Swpaul &imp_desc, "ntoskrnl") == 0) { 1628124446Swpaul if (pe_patch_imports(img, 1629124446Swpaul "ntoskrnl", ntoskrnl_functbl)) 1630124446Swpaul return(ENOEXEC); 1631124446Swpaul } 1632124446Swpaul *ptr = NDIS_LOADED; 1633123474Swpaul } 1634123474Swpaul 1635123474Swpaul /* Locate the driver entry point */ 1636123474Swpaul pe_get_optional_header(img, &opt_hdr); 1637123474Swpaul entry = (driver_entry)pe_translate_addr(img, opt_hdr.ioh_entryaddr); 1638123474Swpaul 1639125551Swpaul dummystr.nus_len = strlen(NDIS_DUMMY_PATH) * 2; 1640125551Swpaul dummystr.nus_maxlen = strlen(NDIS_DUMMY_PATH) * 2; 1641123474Swpaul dummystr.nus_buf = NULL; 1642123474Swpaul ndis_ascii_to_unicode(NDIS_DUMMY_PATH, &dummystr.nus_buf); 1643123474Swpaul 1644123474Swpaul /* 1645123474Swpaul * Now that we have the miniport driver characteristics, 1646123474Swpaul * create an NDIS block and call the init handler. 1647123474Swpaul * This will cause the driver to try to probe for 1648123474Swpaul * a device. 1649123474Swpaul */ 1650123474Swpaul 1651123474Swpaul block = &sc->ndis_block; 1652123474Swpaul 1653125551Swpaul ptr = (uint32_t *)block; 1654123474Swpaul for (idx = 0; idx < sizeof(ndis_miniport_block) / 4; idx++) { 1655123474Swpaul *ptr = idx | 0xdead0000; 1656123474Swpaul ptr++; 1657123474Swpaul } 1658123474Swpaul 1659123474Swpaul block->nmb_signature = (void *)0xcafebabe; 1660123474Swpaul block->nmb_setdone_func = ndis_setdone_func; 1661123535Swpaul block->nmb_querydone_func = ndis_getdone_func; 1662123474Swpaul block->nmb_status_func = ndis_status_func; 1663123474Swpaul block->nmb_statusdone_func = ndis_statusdone_func; 1664123474Swpaul block->nmb_resetdone_func = ndis_resetdone_func; 1665124100Swpaul block->nmb_sendrsrc_func = ndis_sendrsrcavail_func; 1666123474Swpaul 1667123474Swpaul block->nmb_ifp = &sc->arpcom.ac_if; 1668123474Swpaul block->nmb_dev = sc->ndis_dev; 1669124165Swpaul block->nmb_img = img; 1670125551Swpaul block->nmb_devobj.do_rsvd = block; 1671123474Swpaul 1672125551Swpaul /* 1673125551Swpaul * Now call the DriverEntry() routine. This will cause 1674125551Swpaul * a callout to the NdisInitializeWrapper() and 1675125551Swpaul * NdisMRegisterMiniport() routines. 1676125551Swpaul */ 1677125551Swpaul status = entry(&block->nmb_devobj, &dummystr); 1678125551Swpaul 1679125551Swpaul free (dummystr.nus_buf, M_DEVBUF); 1680125551Swpaul 1681125551Swpaul if (status != NDIS_STATUS_SUCCESS) 1682125551Swpaul return(ENODEV); 1683125551Swpaul 1684124697Swpaul ndis_enlarge_thrqueue(8); 1685124697Swpaul 1686125057Swpaul TAILQ_INSERT_TAIL(&ndis_devhead, block, link); 1687125006Swpaul 1688123474Swpaul return(0); 1689123474Swpaul} 1690