fe7c8eefc3
802.11b chipset work. This chip is present on the SMC2602W version 3 NIC, which is what was used for testing. This driver creates kernel threads (12 of them!) for various purposes, and required the following routines: PsCreateSystemThread() PsTerminateSystemThread() KeInitializeEvent() KeSetEvent() KeResetEvent() KeInitializeMutex() KeReleaseMutex() KeWaitForSingleObject() KeWaitForMultipleObjects() IoGetDeviceProperty() and several more. Also, this driver abuses the fact that NDIS events and timers are actually Windows events and timers, and uses NDIS events with KeWaitForSingleObject(). The NDIS event routines have been rewritten to interface with the ntoskrnl module. Many routines with incorrect prototypes have been cleaned up. Also, this driver puts jobs on the NDIS taskqueue (via NdisScheduleWorkItem()) which block on events, and this interferes with the operation of NdisMAllocateSharedMemoryAsync(), which was also being put on the NDIS taskqueue. To avoid the deadlock, NdisMAllocateSharedMemoryAsync() is now performed in the NDIS SWI thread instead. There's still room for some cleanups here, and I really should implement KeInitializeTimer() and friends.
449 lines
12 KiB
C
449 lines
12 KiB
C
/*
|
|
* Copyright (c) 2003
|
|
* Bill Paul <wpaul@windriver.com>. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Bill Paul.
|
|
* 4. Neither the name of the author nor the names of any co-contributors
|
|
* may be used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#ifndef _NTOSKRNL_VAR_H_
|
|
#define _NTOSKRNL_VAR_H_
|
|
|
|
/* Note: assumes x86 page size of 4K. */
|
|
#define PAGE_SHIFT 12
|
|
#define SPAN_PAGES(ptr, len) \
|
|
((uint32_t)((((uintptr_t)(ptr) & (PAGE_SIZE -1)) + \
|
|
(len) + (PAGE_SIZE - 1)) >> PAGE_SHIFT))
|
|
#define PAGE_ALIGN(ptr) \
|
|
((void *)((uintptr_t)(ptr) & ~(PAGE_SIZE - 1)))
|
|
#define BYTE_OFFSET(ptr) \
|
|
((uint32_t)((uintptr_t)(ptr) & (PAGE_SIZE - 1)))
|
|
#define MDL_INIT(b, baseva, len) \
|
|
(b)->nb_next = NULL; \
|
|
(b)->nb_size = (uint16_t)(sizeof(struct ndis_buffer) + \
|
|
(sizeof(uint32_t) * SPAN_PAGES((baseva), (len)))); \
|
|
(b)->nb_flags = 0; \
|
|
(b)->nb_startva = (void *)PAGE_ALIGN((baseva)); \
|
|
(b)->nb_byteoffset = BYTE_OFFSET((baseva)); \
|
|
(b)->nb_bytecount = (uint32_t)(len);
|
|
#define MDL_VA(b) \
|
|
((void *)((char *)((b)->nb_startva) + (b)->nb_byteoffset))
|
|
|
|
#define WDM_MAJOR 1
|
|
#define WDM_MINOR_WIN98 0x00
|
|
#define WDM_MINOR_WINME 0x05
|
|
#define WDM_MINOR_WIN2000 0x10
|
|
#define WDM_MINOR_WINXP 0x20
|
|
#define WDM_MINOR_WIN2003 0x30
|
|
|
|
/*-
|
|
* The ndis_kspin_lock type is called KSPIN_LOCK in MS-Windows.
|
|
* According to the Windows DDK header files, KSPIN_LOCK is defined like this:
|
|
* typedef ULONG_PTR KSPIN_LOCK;
|
|
*
|
|
* From basetsd.h (SDK, Feb. 2003):
|
|
* typedef [public] unsigned __int3264 ULONG_PTR, *PULONG_PTR;
|
|
* typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
|
|
* typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
|
|
*
|
|
* The keyword __int3264 specifies an integral type that has the following
|
|
* properties:
|
|
* + It is 32-bit on 32-bit platforms
|
|
* + It is 64-bit on 64-bit platforms
|
|
* + It is 32-bit on the wire for backward compatibility.
|
|
* It gets truncated on the sending side and extended appropriately
|
|
* (signed or unsigned) on the receiving side.
|
|
*
|
|
* Thus register_t seems the proper mapping onto FreeBSD for spin locks.
|
|
*/
|
|
|
|
typedef register_t kspin_lock;
|
|
|
|
struct slist_entry {
|
|
struct slist_entry *sl_next;
|
|
};
|
|
|
|
typedef struct slist_entry slist_entry;
|
|
|
|
union slist_header {
|
|
uint64_t slh_align;
|
|
struct {
|
|
struct slist_entry *slh_next;
|
|
uint16_t slh_depth;
|
|
uint16_t slh_seq;
|
|
} slh_list;
|
|
};
|
|
|
|
typedef union slist_header slist_header;
|
|
|
|
struct list_entry {
|
|
struct list_entry *nle_flink;
|
|
struct list_entry *nle_blink;
|
|
};
|
|
|
|
typedef struct list_entry list_entry;
|
|
|
|
#define INIT_LIST_HEAD(l) \
|
|
l->nle_flink = l->nle_blink = l
|
|
|
|
#define REMOVE_LIST_ENTRY(e) \
|
|
do { \
|
|
list_entry *b; \
|
|
list_entry *f; \
|
|
\
|
|
f = e->nle_flink; \
|
|
b = e->nle_blink; \
|
|
b->nle_flink = f; \
|
|
f->nle_blink = b; \
|
|
} while (0)
|
|
|
|
#define REMOVE_LIST_HEAD(l) \
|
|
do { \
|
|
list_entry *f; \
|
|
list_entry *e; \
|
|
\
|
|
e = l->nle_flink; \
|
|
f = e->nle_flink; \
|
|
l->nle_flink = f; \
|
|
f->nle_blink = l; \
|
|
} while (0)
|
|
|
|
#define REMOVE_LIST_TAIL(l) \
|
|
do { \
|
|
list_entry *b; \
|
|
list_entry *e; \
|
|
\
|
|
e = l->nle_blink; \
|
|
b = e->nle_blink; \
|
|
l->nle_blink = b; \
|
|
b->nle_flink = l; \
|
|
} while (0)
|
|
|
|
#define INSERT_LIST_TAIL(l, e) \
|
|
do { \
|
|
list_entry *b; \
|
|
\
|
|
b = l->nle_blink; \
|
|
e->nle_flink = l \
|
|
e->nle_blink = b; \
|
|
b->nle_flink = e; \
|
|
l->nle_blink = e; \
|
|
} while (0)
|
|
|
|
#define INSERT_LIST_HEAD(l, e) \
|
|
do { \
|
|
list_entry *f; \
|
|
\
|
|
f = l->nle_flink; \
|
|
e->nle_flink = f; \
|
|
e->nle_blink = l; \
|
|
f->nle_blink = e; \
|
|
l->nle_flink = e; \
|
|
} while (0)
|
|
|
|
struct nt_dispatch_header {
|
|
uint8_t dh_type;
|
|
uint8_t dh_abs;
|
|
uint8_t dh_size;
|
|
uint8_t dh_inserted;
|
|
uint32_t dh_sigstate;
|
|
list_entry dh_waitlisthead;
|
|
};
|
|
|
|
typedef struct nt_dispatch_header nt_dispatch_header;
|
|
|
|
#define OTYPE_EVENT 0
|
|
#define OTYPE_MUTEX 1
|
|
#define OTYPE_THREAD 2
|
|
#define OTYPE_TIMER 3
|
|
|
|
/* Windows dispatcher levels. */
|
|
|
|
#define PASSIVE_LEVEL 0
|
|
#define LOW_LEVEL 0
|
|
#define APC_LEVEL 1
|
|
#define DISPATCH_LEVEL 2
|
|
#define PROFILE_LEVEL 27
|
|
#define CLOCK1_LEVEL 28
|
|
#define CLOCK2_LEVEL 28
|
|
#define IPI_LEVEL 29
|
|
#define POWER_LEVEL 30
|
|
#define HIGH_LEVEL 31
|
|
|
|
#define SYNC_LEVEL_UP DISPATCH_LEVEL
|
|
#define SYNC_LEVEL_MP (IPI_LEVEL - 1)
|
|
|
|
struct nt_objref {
|
|
nt_dispatch_header no_dh;
|
|
void *no_obj;
|
|
TAILQ_ENTRY(nt_objref) link;
|
|
};
|
|
|
|
TAILQ_HEAD(nt_objref_head, nt_objref);
|
|
|
|
typedef struct nt_objref nt_objref;
|
|
|
|
#define EVENT_TYPE_NOTIFY 0
|
|
#define EVENT_TYPE_SYNC 1
|
|
|
|
struct ktimer {
|
|
nt_dispatch_header k_header;
|
|
uint64_t k_duetime;
|
|
list_entry k_timerlistentry;
|
|
void *k_dpc;
|
|
uint32_t k_period;
|
|
};
|
|
|
|
struct nt_kevent {
|
|
nt_dispatch_header k_header;
|
|
};
|
|
|
|
typedef struct nt_kevent nt_kevent;
|
|
|
|
/* Kernel defered procedure call (i.e. timer callback) */
|
|
|
|
struct kdpc;
|
|
typedef void (*kdpc_func)(struct kdpc *, void *, void *, void *);
|
|
|
|
struct kdpc {
|
|
uint16_t k_type;
|
|
uint8_t k_num;
|
|
uint8_t k_importance;
|
|
list_entry k_dpclistentry;
|
|
kdpc_func k_deferedfunc;
|
|
void *k_deferredctx;
|
|
void *k_sysarg1;
|
|
void *k_sysarg2;
|
|
uint32_t *k_lock;
|
|
};
|
|
|
|
/*
|
|
* Note: the acquisition count is BSD-specific. The Microsoft
|
|
* documentation says that mutexes can be acquired recursively
|
|
* by a given thread, but that you must release the mutex as
|
|
* many times as you acquired it before it will be set to the
|
|
* signalled state (i.e. before any other threads waiting on
|
|
* the object will be woken up). However the Windows KMUTANT
|
|
* structure has no field for keeping track of the number of
|
|
* acquisitions, so we need to add one ourselves. As long as
|
|
* driver code treats the mutex as opaque, we should be ok.
|
|
*/
|
|
struct kmutant {
|
|
nt_dispatch_header km_header;
|
|
list_entry km_listentry;
|
|
void *km_ownerthread;
|
|
uint8_t km_abandoned;
|
|
uint8_t km_apcdisable;
|
|
uint32_t km_acquirecnt;
|
|
};
|
|
|
|
typedef struct kmutant kmutant;
|
|
|
|
struct general_lookaside {
|
|
slist_header gl_listhead;
|
|
uint16_t gl_depth;
|
|
uint16_t gl_maxdepth;
|
|
uint32_t gl_totallocs;
|
|
union {
|
|
uint32_t gl_allocmisses;
|
|
uint32_t gl_allochits;
|
|
} u_a;
|
|
uint32_t gl_totalfrees;
|
|
union {
|
|
uint32_t gl_freemisses;
|
|
uint32_t gl_freehits;
|
|
} u_m;
|
|
uint32_t gl_type;
|
|
uint32_t gl_tag;
|
|
uint32_t gl_size;
|
|
void *gl_allocfunc;
|
|
void *gl_freefunc;
|
|
list_entry gl_listent;
|
|
uint32_t gl_lasttotallocs;
|
|
union {
|
|
uint32_t gl_lastallocmisses;
|
|
uint32_t gl_lastallochits;
|
|
} u_l;
|
|
uint32_t gl_rsvd[2];
|
|
};
|
|
|
|
typedef struct general_lookaside general_lookaside;
|
|
|
|
struct npaged_lookaside_list {
|
|
general_lookaside nll_l;
|
|
kspin_lock nll_obsoletelock;
|
|
};
|
|
|
|
typedef struct npaged_lookaside_list npaged_lookaside_list;
|
|
typedef struct npaged_lookaside_list paged_lookaside_list;
|
|
|
|
typedef void * (*lookaside_alloc_func)(uint32_t, size_t, uint32_t);
|
|
typedef void (*lookaside_free_func)(void *);
|
|
|
|
struct irp;
|
|
|
|
struct kdevice_qentry {
|
|
list_entry kqe_devlistent;
|
|
uint32_t kqe_sortkey;
|
|
uint8_t kqe_inserted;
|
|
};
|
|
|
|
typedef struct kdevice_qentry kdevice_qentry;
|
|
|
|
struct kdevice_queue {
|
|
uint16_t kq_type;
|
|
uint16_t kq_size;
|
|
list_entry kq_devlisthead;
|
|
kspin_lock kq_lock;
|
|
uint8_t kq_busy;
|
|
};
|
|
|
|
typedef struct kdevice_queue kdevice_queue;
|
|
|
|
struct wait_ctx_block {
|
|
kdevice_qentry wcb_waitqueue;
|
|
void *wcb_devfunc;
|
|
void *wcb_devctx;
|
|
uint32_t wcb_mapregcnt;
|
|
void *wcb_devobj;
|
|
void *wcb_curirp;
|
|
void *wcb_bufchaindpc;
|
|
};
|
|
|
|
typedef struct wait_ctx_block wait_ctx_block;
|
|
|
|
struct wait_block {
|
|
list_entry wb_waitlist;
|
|
void *wb_kthread;
|
|
nt_dispatch_header *wb_object;
|
|
struct wait_block *wb_next;
|
|
uint16_t wb_waitkey;
|
|
uint16_t wb_waittype;
|
|
};
|
|
|
|
typedef struct wait_block wait_block;
|
|
|
|
#define THREAD_WAIT_OBJECTS 3
|
|
#define MAX_WAIT_OBJECTS 64
|
|
|
|
#define WAITTYPE_ALL 0
|
|
#define WAITTYPE_ANY 1
|
|
|
|
struct thread_context {
|
|
void *tc_thrctx;
|
|
void *tc_thrfunc;
|
|
};
|
|
|
|
typedef struct thread_context thread_context;
|
|
|
|
struct device_object {
|
|
uint16_t do_type;
|
|
uint16_t do_size;
|
|
uint32_t do_refcnt;
|
|
struct device_object *do_drvobj;
|
|
struct device_object *do_nextdev;
|
|
struct device_object *do_attacheddev;
|
|
struct irp *do_currirp;
|
|
void *do_iotimer;
|
|
uint32_t do_flags;
|
|
uint32_t do_characteristics;
|
|
void *do_vpb;
|
|
void *do_devext;
|
|
uint8_t do_stacksize;
|
|
union {
|
|
list_entry do_listent;
|
|
wait_ctx_block do_wcb;
|
|
} queue;
|
|
uint32_t do_alignreq;
|
|
kdevice_queue do_devqueue;
|
|
struct kdpc do_dpc;
|
|
uint32_t do_activethreads;
|
|
void *do_securitydesc;
|
|
struct nt_kevent do_devlock;
|
|
uint16_t do_sectorsz;
|
|
uint16_t do_spare1;
|
|
void *do_devobj_ext;
|
|
void *do_rsvd;
|
|
};
|
|
|
|
typedef struct device_object device_object;
|
|
|
|
struct irp {
|
|
uint32_t i_dummy;
|
|
};
|
|
|
|
typedef struct irp irp;
|
|
|
|
typedef uint32_t (*driver_dispatch)(device_object *, irp *);
|
|
|
|
#define DEVPROP_DEVICE_DESCRIPTION 0x00000000
|
|
#define DEVPROP_HARDWARE_ID 0x00000001
|
|
#define DEVPROP_COMPATIBLE_IDS 0x00000002
|
|
#define DEVPROP_BOOTCONF 0x00000003
|
|
#define DEVPROP_BOOTCONF_TRANSLATED 0x00000004
|
|
#define DEVPROP_CLASS_NAME 0x00000005
|
|
#define DEVPROP_CLASS_GUID 0x00000006
|
|
#define DEVPROP_DRIVER_KEYNAME 0x00000007
|
|
#define DEVPROP_MANUFACTURER 0x00000008
|
|
#define DEVPROP_FRIENDLYNAME 0x00000009
|
|
#define DEVPROP_LOCATION_INFO 0x0000000A
|
|
#define DEVPROP_PHYSDEV_NAME 0x0000000B
|
|
#define DEVPROP_BUSTYPE_GUID 0x0000000C
|
|
#define DEVPROP_LEGACY_BUSTYPE 0x0000000D
|
|
#define DEVPROP_BUS_NUMBER 0x0000000E
|
|
#define DEVPROP_ENUMERATOR_NAME 0x0000000F
|
|
#define DEVPROP_ADDRESS 0x00000010
|
|
#define DEVPROP_UINUMBER 0x00000011
|
|
#define DEVPROP_INSTALL_STATE 0x00000012
|
|
#define DEVPROP_REMOVAL_POLICY 0x00000013
|
|
|
|
#define STATUS_SUCCESS 0x00000000
|
|
#define STATUS_USER_APC 0x000000C0
|
|
#define STATUS_KERNEL_APC 0x00000100
|
|
#define STATUS_ALERTED 0x00000101
|
|
#define STATUS_TIMEOUT 0x00000102
|
|
#define STATUS_INVALID_PARAMETER 0xC000000D
|
|
#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010
|
|
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
|
|
#define STATUS_MUTANT_NOT_OWNED 0xC0000046
|
|
#define STATUS_INVALID_PARAMETER_2 0xC00000F0
|
|
|
|
#define STATUS_WAIT_0 0x00000000
|
|
|
|
extern image_patch_table ntoskrnl_functbl[];
|
|
extern struct mtx *ntoskrnl_dispatchlock;
|
|
|
|
__BEGIN_DECLS
|
|
extern int ntoskrnl_libinit(void);
|
|
extern int ntoskrnl_libfini(void);
|
|
extern void ntoskrnl_wakeup(void *);
|
|
__END_DECLS
|
|
|
|
#endif /* _NTOSKRNL_VAR_H_ */
|