summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/ndis/kern_ndis.c29
-rw-r--r--sys/compat/ndis/kern_windrv.c11
-rw-r--r--sys/compat/ndis/ndis_var.h3
-rw-r--r--sys/compat/ndis/ntoskrnl_var.h30
-rw-r--r--sys/compat/ndis/subr_ndis.c77
-rw-r--r--sys/compat/ndis/subr_ntoskrnl.c119
-rw-r--r--sys/compat/ndis/subr_usbd.c1091
-rw-r--r--sys/compat/ndis/usbd_var.h172
8 files changed, 1490 insertions, 42 deletions
diff --git a/sys/compat/ndis/kern_ndis.c b/sys/compat/ndis/kern_ndis.c
index 2c7d037..98ac538 100644
--- a/sys/compat/ndis/kern_ndis.c
+++ b/sys/compat/ndis/kern_ndis.c
@@ -65,6 +65,9 @@ __FBSDID("$FreeBSD$");
#include <net80211/ieee80211_var.h>
#include <net80211/ieee80211_ioctl.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
#include <compat/ndis/pe_var.h>
#include <compat/ndis/cfg_var.h>
#include <compat/ndis/resource_var.h>
@@ -144,7 +147,6 @@ ndis_modevent(module_t mod, int cmd, void *arg)
}
TAILQ_INIT(&ndis_devhead);
-
break;
case MOD_SHUTDOWN:
if (TAILQ_FIRST(&ndis_devhead) == NULL) {
@@ -1199,6 +1201,31 @@ ndis_shutdown_nic(arg)
}
int
+ndis_pnpevent_nic(arg, type)
+ void *arg;
+ int type;
+{
+ struct ndis_softc *sc;
+ ndis_handle adapter;
+ ndis_pnpevent_handler pnpeventfunc;
+
+ sc = arg;
+ NDIS_LOCK(sc);
+ adapter = sc->ndis_block->nmb_miniportadapterctx;
+ pnpeventfunc = sc->ndis_chars->nmc_pnpevent_handler;
+ NDIS_UNLOCK(sc);
+ if (adapter == NULL || pnpeventfunc == NULL)
+ return(EIO);
+
+ if (sc->ndis_chars->nmc_rsvd0 == NULL)
+ MSCALL4(pnpeventfunc, adapter, type, NULL, 0);
+ else
+ MSCALL4(pnpeventfunc, sc->ndis_chars->nmc_rsvd0, type, NULL, 0);
+
+ return (0);
+}
+
+int
ndis_init_nic(arg)
void *arg;
{
diff --git a/sys/compat/ndis/kern_windrv.c b/sys/compat/ndis/kern_windrv.c
index 00d8e8d..021bea6 100644
--- a/sys/compat/ndis/kern_windrv.c
+++ b/sys/compat/ndis/kern_windrv.c
@@ -56,6 +56,9 @@ __FBSDID("$FreeBSD$");
#include <machine/segments.h>
#endif
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
#include <compat/ndis/pe_var.h>
#include <compat/ndis/cfg_var.h>
#include <compat/ndis/resource_var.h>
@@ -349,9 +352,11 @@ windrv_load(mod, img, len, bustype, devlist, regvals)
if (pe_patch_imports(img, "NDIS", ndis_functbl))
return(ENOEXEC);
- /* Dynamically link the HAL.dll routines -- also required. */
- if (pe_patch_imports(img, "HAL", hal_functbl))
- return(ENOEXEC);
+ /* Dynamically link the HAL.dll routines -- optional. */
+ if (pe_get_import_descriptor(img, &imp_desc, "HAL") == 0) {
+ if (pe_patch_imports(img, "HAL", hal_functbl))
+ return(ENOEXEC);
+ }
/* Dynamically link ntoskrnl.exe -- optional. */
if (pe_get_import_descriptor(img, &imp_desc, "ntoskrnl") == 0) {
diff --git a/sys/compat/ndis/ndis_var.h b/sys/compat/ndis/ndis_var.h
index bef4f2e..6608f0c 100644
--- a/sys/compat/ndis/ndis_var.h
+++ b/sys/compat/ndis/ndis_var.h
@@ -1658,6 +1658,7 @@ typedef void (*ndis_return_handler)(ndis_handle, ndis_packet *);
typedef void (*ndis_enable_interrupts_handler)(ndis_handle);
typedef void (*ndis_disable_interrupts_handler)(ndis_handle);
typedef void (*ndis_shutdown_handler)(void *);
+typedef void (*ndis_pnpevent_handler)(void *, int, void *, uint32_t);
typedef void (*ndis_allocdone_handler)(ndis_handle, void *,
ndis_physaddr *, uint32_t, void *);
typedef uint8_t (*ndis_checkforhang_handler)(ndis_handle);
@@ -1739,6 +1740,7 @@ extern void ndis_free_bufs(ndis_buffer *);
extern int ndis_reset_nic(void *);
extern int ndis_halt_nic(void *);
extern int ndis_shutdown_nic(void *);
+extern int ndis_pnpevent_nic(void *, int);
extern int ndis_init_nic(void *);
extern void ndis_return_packet(void *, void *);
extern int ndis_init_dma(void *);
@@ -1759,6 +1761,7 @@ extern void NdisAllocatePacket(ndis_status *,
extern void NdisFreePacket(ndis_packet *);
extern ndis_status NdisScheduleWorkItem(ndis_work_item *);
extern void NdisMSleep(uint32_t);
+extern void ndis_cancel_timerlist(void);
__END_DECLS
#endif /* _NDIS_VAR_H_ */
diff --git a/sys/compat/ndis/ntoskrnl_var.h b/sys/compat/ndis/ntoskrnl_var.h
index 3c0fe58..73e01c4 100644
--- a/sys/compat/ndis/ntoskrnl_var.h
+++ b/sys/compat/ndis/ntoskrnl_var.h
@@ -536,6 +536,11 @@ typedef struct wait_block wait_block;
#define WAITKEY_VALID 0x8000
+/* kthread priority */
+#define LOW_PRIORITY 0
+#define LOW_REALTIME_PRIORITY 16
+#define HIGH_PRIORITY 31
+
struct thread_context {
void *tc_thrctx;
void *tc_thrfunc;
@@ -989,7 +994,13 @@ struct irp {
} s2;
void *irp_fileobj;
} irp_overlay;
- kapc irp_apc;
+ union {
+ kapc irp_apc;
+ struct {
+ void *irp_xfer;
+ void *irp_dev;
+ } irp_usb;
+ } irp_misc;
void *irp_compkey;
} irp_tail;
};
@@ -997,6 +1008,9 @@ struct irp {
#define irp_csl s2.u2.irp_csl
#define irp_pkttype s2.u2.irp_pkttype
+#define IRP_NDIS_DEV(irp) (irp)->irp_tail.irp_misc.irp_usb.irp_dev
+#define IRP_NDISUSB_XFER(irp) (irp)->irp_tail.irp_misc.irp_usb.irp_xfer
+
typedef struct irp irp;
#define InterlockedExchangePointer(dst, val) \
@@ -1009,6 +1023,10 @@ typedef struct irp irp;
(cancel_func)InterlockedExchangePointer( \
(void *)&(ip)->irp_cancelfunc, (void *)(func))
+#define IoSetCancelValue(irp, val) \
+ (u_long)InterlockedExchangePointer( \
+ (void *)&(ip)->irp_cancel, (void *)(val))
+
#define IoGetCurrentIrpStackLocation(irp) \
(irp)->irp_tail.irp_overlay.irp_csl
@@ -1035,6 +1053,8 @@ typedef struct irp irp;
#define IoMarkIrpPending(irp) \
IoGetCurrentIrpStackLocation(irp)->isl_ctl |= SL_PENDING_RETURNED
+#define IoUnmarkIrpPending(irp) \
+ IoGetCurrentIrpStackLocation(irp)->isl_ctl &= ~SL_PENDING_RETURNED
#define IoCopyCurrentIrpStackLocationToNext(irp) \
do { \
@@ -1191,14 +1211,21 @@ typedef struct driver_object driver_object;
#define STATUS_ALERTED 0x00000101
#define STATUS_TIMEOUT 0x00000102
#define STATUS_PENDING 0x00000103
+#define STATUS_FAILURE 0xC0000001
+#define STATUS_NOT_IMPLEMENTED 0xC0000002
#define STATUS_INVALID_PARAMETER 0xC000000D
#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010
#define STATUS_MORE_PROCESSING_REQUIRED 0xC0000016
+#define STATUS_NO_MEMORY 0xC0000017
#define STATUS_BUFFER_TOO_SMALL 0xC0000023
#define STATUS_MUTANT_NOT_OWNED 0xC0000046
+#define STATUS_NOT_SUPPORTED 0xC00000BB
#define STATUS_INVALID_PARAMETER_2 0xC00000F0
#define STATUS_INSUFFICIENT_RESOURCES 0xC000009A
+#define STATUS_DEVICE_NOT_CONNECTED 0xC000009D
+#define STATUS_CANCELLED 0xC0000120
#define STATUS_NOT_FOUND 0xC0000225
+#define STATUS_DEVICE_REMOVED 0xC00002B6
#define STATUS_WAIT_0 0x00000000
@@ -1365,6 +1392,7 @@ extern void ExFreePool(void *);
extern uint32_t IoConnectInterrupt(kinterrupt **, void *, void *,
kspin_lock *, uint32_t, uint8_t, uint8_t, uint8_t, uint8_t,
uint32_t, uint8_t);
+extern uint8_t MmIsAddressValid(void *);
extern void *MmMapIoSpace(uint64_t, uint32_t, uint32_t);
extern void MmUnmapIoSpace(void *, size_t);
extern void MmBuildMdlForNonPagedPool(mdl *);
diff --git a/sys/compat/ndis/subr_ndis.c b/sys/compat/ndis/subr_ndis.c
index e0f1f99..ac9d8da 100644
--- a/sys/compat/ndis/subr_ndis.c
+++ b/sys/compat/ndis/subr_ndis.c
@@ -95,6 +95,8 @@ __FBSDID("$FreeBSD$");
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
#include <compat/ndis/pe_var.h>
#include <compat/ndis/cfg_var.h>
@@ -302,6 +304,15 @@ static void dummy(void);
*/
#define NDIS_POOL_EXTRA 16
+struct ktimer_list {
+ ktimer *kl_timer;
+ list_entry kl_next;
+};
+
+static struct list_entry ndis_timerlist;
+static kspin_lock ndis_timerlock;
+static int ndis_isusbdev;
+
int
ndis_libinit()
{
@@ -317,6 +328,9 @@ ndis_libinit()
patch++;
}
+ KeInitializeSpinLock(&ndis_timerlock);
+ InitializeListHead(&ndis_timerlist);
+
return(0);
}
@@ -1215,6 +1229,16 @@ NdisMInitializeTimer(timer, handle, func, ctx)
ndis_timer_function func;
void *ctx;
{
+ ndis_miniport_block *block;
+ struct ktimer_list *kl;
+ struct ndis_softc *sc;
+ uint8_t irql;
+
+ block = (ndis_miniport_block *)handle;
+ sc = device_get_softc(block->nmb_physdeviceobj->do_devext);
+ if (sc->ndis_iftype == PNPBus && ndis_isusbdev == 0)
+ ndis_isusbdev = 1;
+
/* Save the driver's funcptr and context */
timer->nmt_timerfunc = func;
@@ -1232,7 +1256,38 @@ NdisMInitializeTimer(timer, handle, func, ctx)
ndis_findwrap((funcptr)ndis_timercall), timer);
timer->nmt_ktimer.k_dpc = &timer->nmt_kdpc;
- return;
+ if (ndis_isusbdev == 1) {
+ kl = (struct ktimer_list *)malloc(sizeof(*kl), M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (kl == NULL)
+ panic("out of memory"); /* no way to report errors */
+
+ kl->kl_timer = &timer->nmt_ktimer;
+ KeAcquireSpinLock(&ndis_timerlock, &irql);
+ InsertHeadList((&ndis_timerlist), (&kl->kl_next));
+ KeReleaseSpinLock(&ndis_timerlock, irql);
+ }
+}
+
+void
+ndis_cancel_timerlist(void)
+{
+ list_entry *l;
+ struct ktimer_list *kl;
+ uint8_t cancelled, irql;
+
+ KeAcquireSpinLock(&ndis_timerlock, &irql);
+
+ while(!IsListEmpty(&ndis_timerlist)) {
+ l = RemoveHeadList(&ndis_timerlist);
+ kl = CONTAINING_RECORD(l, struct ktimer_list, kl_next);
+ KeReleaseSpinLock(&ndis_timerlock, irql);
+ cancelled = KeCancelTimer(kl->kl_timer);
+ free(kl, M_DEVBUF);
+ KeAcquireSpinLock(&ndis_timerlock, &irql);
+ }
+
+ KeReleaseSpinLock(&ndis_timerlock, irql);
}
/*
@@ -1277,6 +1332,26 @@ NdisMCancelTimer(timer, cancelled)
ndis_timer *timer;
uint8_t *cancelled;
{
+ list_entry *l;
+ struct ktimer_list *kl;
+ uint8_t irql;
+
+ if (ndis_isusbdev == 1) {
+ KeAcquireSpinLock(&ndis_timerlock, &irql);
+ l = ndis_timerlist.nle_flink;
+ while(l != &ndis_timerlist) {
+ kl = CONTAINING_RECORD(l, struct ktimer_list, kl_next);
+ if (kl->kl_timer == &timer->nt_ktimer) {
+ RemoveEntryList((&kl->kl_next));
+ l = l->nle_flink;
+ free(kl, M_DEVBUF);
+ continue;
+ }
+ l = l->nle_flink;
+ }
+ KeReleaseSpinLock(&ndis_timerlock, irql);
+ }
+
*cancelled = KeCancelTimer(&timer->nt_ktimer);
return;
}
diff --git a/sys/compat/ndis/subr_ntoskrnl.c b/sys/compat/ndis/subr_ntoskrnl.c
index d18d22b..1651c3f 100644
--- a/sys/compat/ndis/subr_ntoskrnl.c
+++ b/sys/compat/ndis/subr_ntoskrnl.c
@@ -207,7 +207,6 @@ static void *MmMapLockedPages(mdl *, uint8_t);
static void *MmMapLockedPagesSpecifyCache(mdl *,
uint8_t, uint32_t, void *, uint32_t, uint32_t);
static void MmUnmapLockedPages(void *, mdl *);
-static uint8_t MmIsAddressValid(void *);
static device_t ntoskrnl_finddev(device_t, uint64_t, struct resource **);
static void RtlZeroMemory(void *, size_t);
static void RtlCopyMemory(void *, const void *, size_t);
@@ -251,6 +250,8 @@ static funcptr ntoskrnl_findwrap(funcptr);
static uint32_t DbgPrint(char *, ...);
static void DbgBreakPoint(void);
static void KeBugCheckEx(uint32_t, u_long, u_long, u_long, u_long);
+static int32_t KeDelayExecutionThread(uint8_t, uint8_t, int64_t *);
+static int32_t KeSetPriorityThread(struct thread *, int32_t);
static void dummy(void);
static struct mtx ntoskrnl_dispatchlock;
@@ -1143,16 +1144,18 @@ uint8_t
IoCancelIrp(irp *ip)
{
cancel_func cfunc;
+ uint8_t cancelirql;
- IoAcquireCancelSpinLock(&ip->irp_cancelirql);
+ IoAcquireCancelSpinLock(&cancelirql);
cfunc = IoSetCancelRoutine(ip, NULL);
ip->irp_cancel = TRUE;
- if (ip->irp_cancelfunc == NULL) {
- IoReleaseCancelSpinLock(ip->irp_cancelirql);
+ if (cfunc == NULL) {
+ IoReleaseCancelSpinLock(cancelirql);
return(FALSE);
}
+ ip->irp_cancelirql = cancelirql;
MSCALL2(cfunc, IoGetCurrentIrpStackLocation(ip)->isl_devobj, ip);
- return(TRUE);
+ return (uint8_t)IoSetCancelValue(ip, TRUE);
}
uint32_t
@@ -1186,24 +1189,27 @@ IofCompleteRequest(ip, prioboost)
irp *ip;
uint8_t prioboost;
{
- uint32_t i;
uint32_t status;
device_object *dobj;
io_stack_location *sl;
completion_func cf;
- ip->irp_pendingreturned =
- IoGetCurrentIrpStackLocation(ip)->isl_ctl & SL_PENDING_RETURNED;
- sl = (io_stack_location *)(ip + 1);
+ KASSERT(ip->irp_iostat.isb_status != STATUS_PENDING,
+ ("incorrect IRP(%p) status (STATUS_PENDING)", ip));
+
+ sl = IoGetCurrentIrpStackLocation(ip);
+ IoSkipCurrentIrpStackLocation(ip);
+
+ do {
+ if (sl->isl_ctl & SL_PENDING_RETURNED)
+ ip->irp_pendingreturned = TRUE;
- for (i = ip->irp_currentstackloc; i < (uint32_t)ip->irp_stackcnt; i++) {
- if (ip->irp_currentstackloc < ip->irp_stackcnt - 1) {
- IoSkipCurrentIrpStackLocation(ip);
+ if (ip->irp_currentstackloc != (ip->irp_stackcnt + 1))
dobj = IoGetCurrentIrpStackLocation(ip)->isl_devobj;
- } else
+ else
dobj = NULL;
- if (sl[i].isl_completionfunc != NULL &&
+ if (sl->isl_completionfunc != NULL &&
((ip->irp_iostat.isb_status == STATUS_SUCCESS &&
sl->isl_ctl & SL_INVOKE_ON_SUCCESS) ||
(ip->irp_iostat.isb_status != STATUS_SUCCESS &&
@@ -1214,12 +1220,16 @@ IofCompleteRequest(ip, prioboost)
status = MSCALL3(cf, dobj, ip, sl->isl_completionctx);
if (status == STATUS_MORE_PROCESSING_REQUIRED)
return;
+ } else {
+ if ((ip->irp_currentstackloc <= ip->irp_stackcnt) &&
+ (ip->irp_pendingreturned == TRUE))
+ IoMarkIrpPending(ip);
}
- if (IoGetCurrentIrpStackLocation(ip)->isl_ctl &
- SL_PENDING_RETURNED)
- ip->irp_pendingreturned = TRUE;
- }
+ /* move to the next. */
+ IoSkipCurrentIrpStackLocation(ip);
+ sl++;
+ } while (ip->irp_currentstackloc <= (ip->irp_stackcnt + 1));
/* Handle any associated IRPs. */
@@ -2672,7 +2682,7 @@ MmUnmapLockedPages(vaddr, buf)
* here, but it doesn't.
*/
-static uint8_t
+uint8_t
MmIsAddressValid(vaddr)
void *vaddr;
{
@@ -4258,6 +4268,73 @@ KeReadStateTimer(timer)
return(timer->k_header.dh_sigstate);
}
+static int32_t
+KeDelayExecutionThread(wait_mode, alertable, interval)
+ uint8_t wait_mode;
+ uint8_t alertable;
+ int64_t *interval;
+{
+ ktimer timer;
+
+ if (wait_mode != 0)
+ panic("invalid wait_mode %d", wait_mode);
+
+ KeInitializeTimer(&timer);
+ KeSetTimer(&timer, *interval, NULL);
+ KeWaitForSingleObject(&timer, 0, 0, alertable, NULL);
+
+ return STATUS_SUCCESS;
+}
+
+static uint64_t
+KeQueryInterruptTime(void)
+{
+ int ticks;
+ struct timeval tv;
+
+ getmicrouptime(&tv);
+
+ ticks = tvtohz(&tv);
+
+ return ticks * ((10000000 + hz - 1) / hz);
+}
+
+static struct thread *
+KeGetCurrentThread(void)
+{
+
+ return curthread;
+}
+
+static int32_t
+KeSetPriorityThread(td, pri)
+ struct thread *td;
+ int32_t pri;
+{
+ int32_t old;
+
+ if (td == NULL)
+ return LOW_REALTIME_PRIORITY;
+
+ if (td->td_priority <= PRI_MIN_KERN)
+ old = HIGH_PRIORITY;
+ else if (td->td_priority >= PRI_MAX_KERN)
+ old = LOW_PRIORITY;
+ else
+ old = LOW_REALTIME_PRIORITY;
+
+ thread_lock(td);
+ if (pri == HIGH_PRIORITY)
+ sched_prio(td, PRI_MIN_KERN);
+ if (pri == LOW_REALTIME_PRIORITY)
+ sched_prio(td, PRI_MIN_KERN + (PRI_MAX_KERN - PRI_MIN_KERN) / 2);
+ if (pri == LOW_PRIORITY)
+ sched_prio(td, PRI_MAX_KERN);
+ thread_unlock(td);
+
+ return old;
+}
+
static void
dummy()
{
@@ -4441,6 +4518,10 @@ image_patch_table ntoskrnl_functbl[] = {
IMPORT_CFUNC(WmiTraceMessage, 0),
IMPORT_SFUNC(KeQuerySystemTime, 1),
IMPORT_CFUNC(KeTickCount, 0),
+ IMPORT_SFUNC(KeDelayExecutionThread, 3),
+ IMPORT_SFUNC(KeQueryInterruptTime, 0),
+ IMPORT_SFUNC(KeGetCurrentThread, 0),
+ IMPORT_SFUNC(KeSetPriorityThread, 2),
/*
* This last entry is a catch-all for any function we haven't
diff --git a/sys/compat/ndis/subr_usbd.c b/sys/compat/ndis/subr_usbd.c
index 3aa322e..0c47c1b 100644
--- a/sys/compat/ndis/subr_usbd.c
+++ b/sys/compat/ndis/subr_usbd.c
@@ -45,10 +45,24 @@ __FBSDID("$FreeBSD$");
#include <sys/module.h>
#include <sys/conf.h>
#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <machine/bus.h>
#include <sys/bus.h>
#include <sys/queue.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_quirks.h>
+#include "usbdevs.h"
+
#include <compat/ndis/pe_var.h>
#include <compat/ndis/cfg_var.h>
#include <compat/ndis/resource_var.h>
@@ -56,18 +70,64 @@ __FBSDID("$FreeBSD$");
#include <compat/ndis/ndis_var.h>
#include <compat/ndis/hal_var.h>
#include <compat/ndis/usbd_var.h>
+#include <dev/if_ndis/if_ndisvar.h>
static driver_object usbd_driver;
-static uint32_t usbd_iodispatch(device_object *, irp *);
+static int32_t usbd_func_bulkintr(irp *);
+static int32_t usbd_func_vendorclass(irp *);
+static int32_t usbd_func_selconf(irp *);
+static int32_t usbd_func_getdesc(irp *);
+static usbd_status usbd_get_desc_ndis(usbd_device_handle, int, int, int,
+ void *, int *);
+static union usbd_urb *usbd_geturb(irp *);
+static usbd_status usbd_init_ndispipe(irp *, usb_endpoint_descriptor_t *);
+static usbd_xfer_handle usbd_init_ndisxfer(irp *, usb_endpoint_descriptor_t *,
+ void *, uint32_t);
+static int32_t usbd_iodispatch(device_object *, irp *);
+static int32_t usbd_ioinvalid(device_object *, irp *);
+static int32_t usbd_pnp(device_object *, irp *);
+static int32_t usbd_power(device_object *, irp *);
+static void usbd_irpcancel(device_object *, irp *);
+static void usbd_irpcancel_cb(void *);
+static int32_t usbd_submit_urb(irp *);
+static int32_t usbd_urb2nt(int32_t);
+static void usbd_xfereof(usbd_xfer_handle, usbd_private_handle,
+ usbd_status);
+static void usbd_xferadd(usbd_xfer_handle, usbd_private_handle,
+ usbd_status);
+static void usbd_xfertask(device_object *, void *);
+static void dummy(void);
-static void USBD_GetUSBDIVersion(usbd_version_info *);
-static void dummy(void);
+static union usbd_urb *USBD_CreateConfigurationRequestEx(
+ usb_config_descriptor_t *,
+ struct usbd_interface_list_entry *);
+static union usbd_urb *USBD_CreateConfigurationRequest(
+ usb_config_descriptor_t *,
+ uint16_t *);
+static void USBD_GetUSBDIVersion(usbd_version_info *);
+static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptorEx(
+ usb_config_descriptor_t *, void *, int32_t, int32_t,
+ int32_t, int32_t, int32_t);
+static usb_interface_descriptor_t *USBD_ParseConfigurationDescriptor(
+ usb_config_descriptor_t *, uint8_t, uint8_t);
+
+/*
+ * We need to wrap these functions because these need `context switch' from
+ * Windows to UNIX before it's called.
+ */
+static funcptr usbd_iodispatch_wrap;
+static funcptr usbd_ioinvalid_wrap;
+static funcptr usbd_pnp_wrap;
+static funcptr usbd_power_wrap;
+static funcptr usbd_irpcancel_wrap;
+static funcptr usbd_xfertask_wrap;
int
usbd_libinit(void)
{
image_patch_table *patch;
+ int i;
patch = usbd_functbl;
while (patch->ipt_func != NULL) {
@@ -77,14 +137,36 @@ usbd_libinit(void)
patch++;
}
+ windrv_wrap((funcptr)usbd_ioinvalid,
+ (funcptr *)&usbd_ioinvalid_wrap, 2, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)usbd_iodispatch,
+ (funcptr *)&usbd_iodispatch_wrap, 2, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)usbd_pnp,
+ (funcptr *)&usbd_pnp_wrap, 2, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)usbd_power,
+ (funcptr *)&usbd_power_wrap, 2, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)usbd_irpcancel,
+ (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)usbd_xfertask,
+ (funcptr *)&usbd_xfertask_wrap, 2, WINDRV_WRAP_STDCALL);
+
/* Create a fake USB driver instance. */
windrv_bus_attach(&usbd_driver, "USB Bus");
/* Set up our dipatch routine. */
+ for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
+ usbd_driver.dro_dispatch[i] =
+ (driver_dispatch)usbd_ioinvalid_wrap;
usbd_driver.dro_dispatch[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
- (driver_dispatch)usbd_iodispatch;
+ (driver_dispatch)usbd_iodispatch_wrap;
+ usbd_driver.dro_dispatch[IRP_MJ_DEVICE_CONTROL] =
+ (driver_dispatch)usbd_iodispatch_wrap;
+ usbd_driver.dro_dispatch[IRP_MJ_POWER] =
+ (driver_dispatch)usbd_power_wrap;
+ usbd_driver.dro_dispatch[IRP_MJ_PNP] =
+ (driver_dispatch)usbd_pnp_wrap;
return(0);
}
@@ -100,17 +182,949 @@ usbd_libfini(void)
patch++;
}
+ windrv_unwrap(usbd_ioinvalid_wrap);
+ windrv_unwrap(usbd_iodispatch_wrap);
+ windrv_unwrap(usbd_pnp_wrap);
+ windrv_unwrap(usbd_power_wrap);
+ windrv_unwrap(usbd_irpcancel_wrap);
+ windrv_unwrap(usbd_xfertask_wrap);
+
free(usbd_driver.dro_drivername.us_buf, M_DEVBUF);
return(0);
}
-static uint32_t
+static int32_t
usbd_iodispatch(dobj, ip)
device_object *dobj;
irp *ip;
{
- return(0);
+ device_t dev = dobj->do_devext;
+ int32_t status;
+ struct io_stack_location *irp_sl;
+
+ irp_sl = IoGetCurrentIrpStackLocation(ip);
+ switch (irp_sl->isl_parameters.isl_ioctl.isl_iocode) {
+ case IOCTL_INTERNAL_USB_SUBMIT_URB:
+ IRP_NDIS_DEV(ip) = dev;
+
+ status = usbd_submit_urb(ip);
+ break;
+ default:
+ device_printf(dev, "ioctl 0x%x isn't supported\n",
+ irp_sl->isl_parameters.isl_ioctl.isl_iocode);
+ status = USBD_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (status == USBD_STATUS_PENDING)
+ return (STATUS_PENDING);
+
+ ip->irp_iostat.isb_status = usbd_urb2nt(status);
+ if (status != USBD_STATUS_SUCCESS)
+ ip->irp_iostat.isb_info = 0;
+ return (ip->irp_iostat.isb_status);
+}
+
+static int32_t
+usbd_ioinvalid(dobj, ip)
+ device_object *dobj;
+ irp *ip;
+{
+ device_t dev = dobj->do_devext;
+ struct io_stack_location *irp_sl;
+
+ irp_sl = IoGetCurrentIrpStackLocation(ip);
+ device_printf(dev, "invalid I/O dispatch %d:%d\n", irp_sl->isl_major,
+ irp_sl->isl_minor);
+
+ ip->irp_iostat.isb_status = STATUS_FAILURE;
+ ip->irp_iostat.isb_info = 0;
+
+ IoCompleteRequest(ip, IO_NO_INCREMENT);
+
+ return (STATUS_FAILURE);
+}
+
+static int32_t
+usbd_pnp(dobj, ip)
+ device_object *dobj;
+ irp *ip;
+{
+ device_t dev = dobj->do_devext;
+ struct io_stack_location *irp_sl;
+
+ irp_sl = IoGetCurrentIrpStackLocation(ip);
+ device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
+ __func__, irp_sl->isl_major, irp_sl->isl_minor);
+
+ ip->irp_iostat.isb_status = STATUS_FAILURE;
+ ip->irp_iostat.isb_info = 0;
+
+ IoCompleteRequest(ip, IO_NO_INCREMENT);
+
+ return (STATUS_FAILURE);
+}
+
+static int32_t
+usbd_power(dobj, ip)
+ device_object *dobj;
+ irp *ip;
+{
+ device_t dev = dobj->do_devext;
+ struct io_stack_location *irp_sl;
+
+ irp_sl = IoGetCurrentIrpStackLocation(ip);
+ device_printf(dev, "%s: unsupported I/O dispatch %d:%d\n",
+ __func__, irp_sl->isl_major, irp_sl->isl_minor);
+
+ ip->irp_iostat.isb_status = STATUS_FAILURE;
+ ip->irp_iostat.isb_info = 0;
+
+ IoCompleteRequest(ip, IO_NO_INCREMENT);
+
+ return (STATUS_FAILURE);
+}
+
+/* Convert USBD_STATUS to NTSTATUS */
+static int32_t
+usbd_urb2nt(status)
+ int32_t status;
+{
+
+ switch (status) {
+ case USBD_STATUS_SUCCESS:
+ return (STATUS_SUCCESS);
+ case USBD_STATUS_DEVICE_GONE:
+ return (STATUS_DEVICE_NOT_CONNECTED);
+ case USBD_STATUS_PENDING:
+ return (STATUS_PENDING);
+ case USBD_STATUS_NOT_SUPPORTED:
+ return (STATUS_NOT_IMPLEMENTED);
+ case USBD_STATUS_NO_MEMORY:
+ return (STATUS_NO_MEMORY);
+ case USBD_STATUS_REQUEST_FAILED:
+ return (STATUS_NOT_SUPPORTED);
+ case USBD_STATUS_CANCELED:
+ return (STATUS_CANCELLED);
+ default:
+ break;
+ }
+
+ return (STATUS_FAILURE);
+}
+
+/* Convert FreeBSD's usbd_status to USBD_STATUS */
+static int32_t
+usbd_usb2urb(int status)
+{
+
+ switch (status) {
+ case USBD_NORMAL_COMPLETION:
+ return (USBD_STATUS_SUCCESS);
+ case USBD_IN_PROGRESS:
+ return (USBD_STATUS_PENDING);
+ case USBD_TIMEOUT:
+ return (USBD_STATUS_TIMEOUT);
+ case USBD_SHORT_XFER:
+ return (USBD_STATUS_ERROR_SHORT_TRANSFER);
+ case USBD_IOERROR:
+ return (USBD_STATUS_XACT_ERROR);
+ case USBD_NOMEM:
+ return (USBD_STATUS_NO_MEMORY);
+ case USBD_INVAL:
+ return (USBD_STATUS_REQUEST_FAILED);
+ case USBD_NOT_STARTED:
+ case USBD_TOO_DEEP:
+ case USBD_NO_POWER:
+ return (USBD_STATUS_DEVICE_GONE);
+ case USBD_CANCELLED:
+ return (USBD_STATUS_CANCELED);
+ default:
+ break;
+ }
+
+ return (USBD_STATUS_NOT_SUPPORTED);
+}
+
+static union usbd_urb *
+usbd_geturb(ip)
+ irp *ip;
+{
+ struct io_stack_location *irp_sl;
+
+ irp_sl = IoGetCurrentIrpStackLocation(ip);
+
+ return (irp_sl->isl_parameters.isl_others.isl_arg1);
+}
+
+static int32_t
+usbd_submit_urb(ip)
+ irp *ip;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ int32_t status;
+ union usbd_urb *urb;
+
+ urb = usbd_geturb(ip);
+ /*
+ * In a case of URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
+ * USBD_URB_STATUS(urb) would be set at callback functions like
+ * usbd_intr() or usbd_xfereof().
+ */
+ switch (urb->uu_hdr.uuh_func) {
+ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+ status = usbd_func_bulkintr(ip);
+ if (status != USBD_STATUS_SUCCESS &&
+ status != USBD_STATUS_PENDING)
+ USBD_URB_STATUS(urb) = status;
+ break;
+ case URB_FUNCTION_VENDOR_DEVICE:
+ case URB_FUNCTION_VENDOR_INTERFACE:
+ case URB_FUNCTION_VENDOR_ENDPOINT:
+ case URB_FUNCTION_VENDOR_OTHER:
+ case URB_FUNCTION_CLASS_DEVICE:
+ case URB_FUNCTION_CLASS_INTERFACE:
+ case URB_FUNCTION_CLASS_ENDPOINT:
+ case URB_FUNCTION_CLASS_OTHER:
+ status = usbd_func_vendorclass(ip);
+ USBD_URB_STATUS(urb) = status;
+ break;
+ case URB_FUNCTION_SELECT_CONFIGURATION:
+ status = usbd_func_selconf(ip);
+ USBD_URB_STATUS(urb) = status;
+ break;
+ case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
+ status = usbd_func_getdesc(ip);
+ USBD_URB_STATUS(urb) = status;
+ break;
+ default:
+ device_printf(dev, "func 0x%x isn't supported\n",
+ urb->uu_hdr.uuh_func);
+ USBD_URB_STATUS(urb) = status = USBD_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return (status);
+}
+
+static int32_t
+usbd_func_getdesc(ip)
+ irp *ip;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ int actlen, i;
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct usbd_urb_control_descriptor_request *ctldesc;
+ uint32_t len;
+ union usbd_urb *urb;
+ usb_config_descriptor_t cd, *cdp;
+ usbd_status status;
+
+ mtx_lock(&Giant);
+
+ urb = usbd_geturb(ip);
+ ctldesc = &urb->uu_ctldesc;
+ if (ctldesc->ucd_desctype == UDESC_CONFIG) {
+ /* Get the short config descriptor. */
+ status = usbd_get_config_desc(uaa->device, ctldesc->ucd_idx,
+ &cd);
+ if (status != USBD_NORMAL_COMPLETION) {
+ ctldesc->ucd_trans_buflen = 0;
+ mtx_unlock(&Giant);
+ return usbd_usb2urb(status);
+ }
+ /* Get the full descriptor. Try a few times for slow devices. */
+ len = MIN(ctldesc->ucd_trans_buflen, UGETW(cd.wTotalLength));
+ for (i = 0; i < 3; i++) {
+ status = usbd_get_desc_ndis(uaa->device,
+ ctldesc->ucd_desctype, ctldesc->ucd_idx,
+ len, ctldesc->ucd_trans_buf, &actlen);
+ if (status == USBD_NORMAL_COMPLETION)
+ break;
+ usbd_delay_ms(uaa->device, 200);
+ }
+ if (status != USBD_NORMAL_COMPLETION) {
+ ctldesc->ucd_trans_buflen = 0;
+ mtx_unlock(&Giant);
+ return usbd_usb2urb(status);
+ }
+
+ cdp = (usb_config_descriptor_t *)ctldesc->ucd_trans_buf;
+ if (cdp->bDescriptorType != UDESC_CONFIG) {
+ device_printf(dev, "bad desc %d\n",
+ cdp->bDescriptorType);
+ status = USBD_INVAL;
+ }
+ } else if (ctldesc->ucd_desctype == UDESC_STRING) {
+ /* Try a few times for slow devices. */
+ for (i = 0; i < 3; i++) {
+ status = usbd_get_string_desc(uaa->device,
+ (UDESC_STRING << 8) + ctldesc->ucd_idx,
+ ctldesc->ucd_langid, ctldesc->ucd_trans_buf,
+ &actlen);
+ if (actlen > ctldesc->ucd_trans_buflen)
+ panic("small string buffer for UDESC_STRING");
+ if (status == USBD_NORMAL_COMPLETION)
+ break;
+ usbd_delay_ms(uaa->device, 200);
+ }
+ } else
+ status = usbd_get_desc_ndis(uaa->device, ctldesc->ucd_desctype,
+ ctldesc->ucd_idx, ctldesc->ucd_trans_buflen,
+ ctldesc->ucd_trans_buf, &actlen);
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ ctldesc->ucd_trans_buflen = 0;
+ mtx_unlock(&Giant);
+ return usbd_usb2urb(status);
+ }
+
+ ctldesc->ucd_trans_buflen = actlen;
+ ip->irp_iostat.isb_info = actlen;
+
+ mtx_unlock(&Giant);
+
+ return (USBD_STATUS_SUCCESS);
+}
+
+/*
+ * FIXME: at USB1, not USB2, framework, there's no a interface to get `actlen'.
+ * However, we need it!!!
+ */
+static usbd_status
+usbd_get_desc_ndis(usbd_device_handle dev, int type, int index, int len,
+ void *desc, int *actlen)
+{
+ usb_device_request_t req;
+
+ req.bmRequestType = UT_READ_DEVICE;
+ req.bRequest = UR_GET_DESCRIPTOR;
+ USETW2(req.wValue, type, index);
+ USETW(req.wIndex, 0);
+ USETW(req.wLength, len);
+ return usbd_do_request_flags_pipe(dev, dev->default_pipe, &req, desc,
+ 0, actlen, USBD_DEFAULT_TIMEOUT);
+}
+
+static int32_t
+usbd_func_selconf(ip)
+ irp *ip;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ int i, j;
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct usbd_interface_information *intf;
+ struct usbd_pipe_information *pipe;
+ struct usbd_urb_select_configuration *selconf;
+ union usbd_urb *urb;
+ usb_config_descriptor_t *conf;
+ usb_endpoint_descriptor_t *edesc;
+ usbd_device_handle udev = uaa->device;
+ usbd_interface_handle iface;
+ usbd_status ret;
+
+ urb = usbd_geturb(ip);
+
+ selconf = &urb->uu_selconf;
+ conf = selconf->usc_conf;
+ if (conf == NULL) {
+ device_printf(dev, "select configuration is NULL\n");
+ return usbd_usb2urb(USBD_NORMAL_COMPLETION);
+ }
+
+ if (conf->bConfigurationValue > NDISUSB_CONFIG_NO)
+ device_printf(dev, "warning: config_no is larger than default");
+
+ intf = &selconf->usc_intf;
+ for (i = 0; i < conf->bNumInterface && intf->uii_len > 0; i++) {
+ ret = usbd_device2interface_handle(uaa->device,
+ intf->uii_intfnum, &iface);
+ if (ret != USBD_NORMAL_COMPLETION) {
+ device_printf(dev,
+ "getting interface handle failed: %s\n",
+ usbd_errstr(ret));
+ return usbd_usb2urb(ret);
+ }
+
+ ret = usbd_set_interface(iface, intf->uii_altset);
+ if (ret != USBD_NORMAL_COMPLETION && ret != USBD_IN_USE) {
+ device_printf(dev,
+ "setting alternate interface failed: %s\n",
+ usbd_errstr(ret));
+ return usbd_usb2urb(ret);
+ }
+
+ for (j = 0; j < iface->idesc->bNumEndpoints; j++) {
+ if (j >= intf->uii_numeps) {
+ device_printf(dev,
+ "endpoint %d and above are ignored",
+ intf->uii_numeps);
+ break;
+ }
+ edesc = iface->endpoints[j].edesc;
+ pipe = &intf->uii_pipes[j];
+ pipe->upi_handle = edesc;
+ pipe->upi_epaddr = edesc->bEndpointAddress;
+ pipe->upi_maxpktsize = UGETW(edesc->wMaxPacketSize);
+ pipe->upi_type = UE_GET_XFERTYPE(edesc->bmAttributes);
+ if (pipe->upi_type != UE_INTERRUPT)
+ continue;
+
+ /* XXX we're following linux USB's interval policy. */
+ if (udev->speed == USB_SPEED_LOW)
+ pipe->upi_interval = edesc->bInterval + 5;
+ else if (udev->speed == USB_SPEED_FULL)
+ pipe->upi_interval = edesc->bInterval;
+ else {
+ int k0 = 0, k1 = 1;
+ do {
+ k1 = k1 * 2;
+ k0 = k0 + 1;
+ } while (k1 < edesc->bInterval);
+ pipe->upi_interval = k0;
+ }
+ }
+
+ intf = (struct usbd_interface_information *)(((char *)intf) +
+ intf->uii_len);
+ }
+
+ return USBD_STATUS_SUCCESS;
+}
+
+static int32_t
+usbd_func_vendorclass(ip)
+ irp *ip;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct usbd_urb_vendor_or_class_request *vcreq;
+ uint8_t type = 0;
+ union usbd_urb *urb;
+ usb_device_request_t req;
+ usbd_status status;
+
+ urb = usbd_geturb(ip);
+ vcreq = &urb->uu_vcreq;
+
+ switch (urb->uu_hdr.uuh_func) {
+ case URB_FUNCTION_CLASS_DEVICE:
+ type = UT_CLASS | UT_DEVICE;
+ break;
+ case URB_FUNCTION_CLASS_INTERFACE:
+ type = UT_CLASS | UT_INTERFACE;
+ break;
+ case URB_FUNCTION_CLASS_OTHER:
+ type = UT_CLASS | UT_OTHER;
+ break;
+ case URB_FUNCTION_CLASS_ENDPOINT:
+ type = UT_CLASS | UT_ENDPOINT;
+ break;
+ case URB_FUNCTION_VENDOR_DEVICE:
+ type = UT_VENDOR | UT_DEVICE;
+ break;
+ case URB_FUNCTION_VENDOR_INTERFACE:
+ type = UT_VENDOR | UT_INTERFACE;
+ break;
+ case URB_FUNCTION_VENDOR_OTHER:
+ type = UT_VENDOR | UT_OTHER;
+ break;
+ case URB_FUNCTION_VENDOR_ENDPOINT:
+ type = UT_VENDOR | UT_ENDPOINT;
+ break;
+ default:
+ /* never reach. */
+ break;
+ }
+
+ type |= (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) ?
+ UT_READ : UT_WRITE;
+ type |= vcreq->uvc_reserved1;
+
+ req.bmRequestType = type;
+ req.bRequest = vcreq->uvc_req;
+ USETW(req.wIndex, vcreq->uvc_idx);
+ USETW(req.wValue, vcreq->uvc_value);
+ USETW(req.wLength, vcreq->uvc_trans_buflen);
+
+ if (vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN) {
+ mtx_lock(&Giant);
+ status = usbd_do_request(uaa->device, &req,
+ vcreq->uvc_trans_buf);
+ mtx_unlock(&Giant);
+ } else
+ status = usbd_do_request_async(uaa->device, &req,
+ vcreq->uvc_trans_buf);
+
+ return usbd_usb2urb(status);
+}
+
+static usbd_status
+usbd_init_ndispipe(ip, ep)
+ irp *ip;
+ usb_endpoint_descriptor_t *ep;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ struct ndis_softc *sc = device_get_softc(dev);
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ usbd_interface_handle iface;
+ usbd_status status;
+
+ status = usbd_device2interface_handle(uaa->device, NDISUSB_IFACE_INDEX,
+ &iface);
+ if (status != USBD_NORMAL_COMPLETION) {
+ device_printf(dev, "could not get interface handle\n");
+ return (status);
+ }
+
+ switch (UE_GET_XFERTYPE(ep->bmAttributes)) {
+ case UE_BULK:
+ if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
+ /* RX (bulk IN) */
+ if (sc->ndisusb_ep[NDISUSB_ENDPT_BIN] != NULL)
+ return (USBD_NORMAL_COMPLETION);
+
+ status = usbd_open_pipe(iface, ep->bEndpointAddress,
+ USBD_EXCLUSIVE_USE,
+ &sc->ndisusb_ep[NDISUSB_ENDPT_BIN]);
+ break;
+ }
+
+ /* TX (bulk OUT) */
+ if (sc->ndisusb_ep[NDISUSB_ENDPT_BOUT] != NULL)
+ return (USBD_NORMAL_COMPLETION);
+
+ status = usbd_open_pipe(iface, ep->bEndpointAddress,
+ USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_BOUT]);
+ break;
+ case UE_INTERRUPT:
+ if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
+ /* Interrupt IN. */
+ if (sc->ndisusb_ep[NDISUSB_ENDPT_IIN] != NULL)
+ return (USBD_NORMAL_COMPLETION);
+
+ status = usbd_open_pipe(iface, ep->bEndpointAddress,
+ USBD_EXCLUSIVE_USE,
+ &sc->ndisusb_ep[NDISUSB_ENDPT_IIN]);
+ break;
+ }
+
+ /* Interrupt OUT. */
+ if (sc->ndisusb_ep[NDISUSB_ENDPT_IOUT] != NULL)
+ return (USBD_NORMAL_COMPLETION);
+
+ status = usbd_open_pipe(iface, ep->bEndpointAddress,
+ USBD_EXCLUSIVE_USE, &sc->ndisusb_ep[NDISUSB_ENDPT_IOUT]);
+ break;
+ default:
+ device_printf(dev, "can't handle xfertype 0x%x\n",
+ UE_GET_XFERTYPE(ep->bmAttributes));
+ return (USBD_INVAL);
+ }
+
+ if (status != USBD_NORMAL_COMPLETION)
+ device_printf(dev, "open pipe failed: (0x%x) %s\n",
+ ep->bEndpointAddress, usbd_errstr(status));
+
+ return (status);
+}
+
+static void
+usbd_irpcancel_cb(priv)
+ void *priv;
+{
+ struct ndisusb_cancel *nc = priv;
+ struct ndis_softc *sc = device_get_softc(nc->dev);
+ usbd_status status;
+ usbd_xfer_handle xfer = nc->xfer;
+
+ if (sc->ndisusb_status & NDISUSB_STATUS_DETACH)
+ goto exit;
+
+ status = usbd_abort_pipe(xfer->pipe);
+ if (status != USBD_NORMAL_COMPLETION)
+ device_printf(nc->dev, "can't be canceld");
+exit:
+ free(nc, M_USBDEV);
+}
+
+static void
+usbd_irpcancel(dobj, ip)
+ device_object *dobj;
+ irp *ip;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ struct ndisusb_cancel *nc;
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+
+ if (IRP_NDISUSB_XFER(ip) == NULL) {
+ ip->irp_cancel = TRUE;
+ IoReleaseCancelSpinLock(ip->irp_cancelirql);
+ return;
+ }
+
+ /*
+ * XXX Since we're under DISPATCH_LEVEL during calling usbd_irpcancel(),
+ * we can't sleep at all. However, currently FreeBSD's USB stack
+ * requires a sleep to abort a transfer. It's inevitable! so it causes
+ * serveral fatal problems (e.g. kernel hangups or crashes). I think
+ * that there are no ways to make this reliable. In this implementation,
+ * I used usb_add_task() but it's not a perfect method to solve this
+ * because of as follows: NDIS drivers would expect that IRP's
+ * completely canceld when usbd_irpcancel() is returned but we need
+ * a sleep to do it. During canceling XFERs, usbd_intr() would be
+ * called with a status, USBD_CANCELLED.
+ */
+ nc = malloc(sizeof(struct ndisusb_cancel), M_USBDEV, M_NOWAIT | M_ZERO);
+ if (nc == NULL) {
+ ip->irp_cancel = FALSE;
+ IoReleaseCancelSpinLock(ip->irp_cancelirql);
+ return;
+ }
+
+ nc->dev = dev;
+ nc->xfer = IRP_NDISUSB_XFER(ip);
+ usb_init_task(&nc->task, usbd_irpcancel_cb, nc);
+
+ IRP_NDISUSB_XFER(ip) = NULL;
+ usb_add_task(uaa->device, &nc->task, USB_TASKQ_DRIVER);
+
+ ip->irp_cancel = TRUE;
+ IoReleaseCancelSpinLock(ip->irp_cancelirql);
+}
+
+static usbd_xfer_handle
+usbd_init_ndisxfer(ip, ep, buf, buflen)
+ irp *ip;
+ usb_endpoint_descriptor_t *ep;
+ void *buf;
+ uint32_t buflen;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ usbd_xfer_handle xfer;
+
+ xfer = usbd_alloc_xfer(uaa->device);
+ if (xfer == NULL)
+ return (NULL);
+
+ if (buf != NULL && MmIsAddressValid(buf) == FALSE && buflen > 0) {
+ xfer->buffer = usbd_alloc_buffer(xfer, buflen);
+ if (xfer->buffer == NULL)
+ return (NULL);
+
+ if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_OUT)
+ memcpy(xfer->buffer, buf, buflen);
+ } else
+ xfer->buffer = buf;
+
+ xfer->length = buflen;
+
+ IoAcquireCancelSpinLock(&ip->irp_cancelirql);
+ IRP_NDISUSB_XFER(ip) = xfer;
+ ip->irp_cancelfunc = (cancel_func)usbd_irpcancel_wrap;
+ IoReleaseCancelSpinLock(ip->irp_cancelirql);
+
+ return (xfer);
+}
+
+static void
+usbd_xferadd(xfer, priv, status)
+ usbd_xfer_handle xfer;
+ usbd_private_handle priv;
+ usbd_status status;
+{
+ irp *ip = priv;
+ device_t dev = IRP_NDIS_DEV(ip);
+ struct ndis_softc *sc = device_get_softc(dev);
+ struct ndisusb_xfer *nx;
+ uint8_t irql;
+
+ nx = malloc(sizeof(struct ndisusb_xfer), M_USBDEV, M_NOWAIT | M_ZERO);
+ if (nx == NULL) {
+ device_printf(dev, "out of memory");
+ return;
+ }
+ nx->nx_xfer = xfer;
+ nx->nx_priv = priv;
+ nx->nx_status = status;
+
+ KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
+ InsertTailList((&sc->ndisusb_xferlist), (&nx->nx_xferlist));
+ KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
+
+ IoQueueWorkItem(sc->ndisusb_xferitem,
+ (io_workitem_func)usbd_xfertask_wrap, WORKQUEUE_CRITICAL, sc);
+}
+
+static void
+usbd_xfereof(xfer, priv, status)
+ usbd_xfer_handle xfer;
+ usbd_private_handle priv;
+ usbd_status status;
+{
+
+ usbd_xferadd(xfer, priv, status);
+}
+
+static void
+usbd_xfertask(dobj, arg)
+ device_object *dobj;
+ void *arg;
+{
+ int error;
+ irp *ip;
+ device_t dev;
+ list_entry *l;
+ struct ndis_softc *sc = arg;
+ struct ndisusb_xfer *nx;
+ struct usbd_urb_bulk_or_intr_transfer *ubi;
+ uint8_t irql;
+ union usbd_urb *urb;
+ usbd_private_handle priv;
+ usbd_status status;
+ usbd_xfer_handle xfer;
+
+ dev = sc->ndis_dev;
+
+ if (IsListEmpty(&sc->ndisusb_xferlist))
+ return;
+
+ KeAcquireSpinLock(&sc->ndisusb_xferlock, &irql);
+ l = sc->ndisusb_xferlist.nle_flink;
+ while (l != &sc->ndisusb_xferlist) {
+ nx = CONTAINING_RECORD(l, struct ndisusb_xfer, nx_xferlist);
+ xfer = nx->nx_xfer;
+ priv = nx->nx_priv;
+ status = nx->nx_status;
+ error = 0;
+ ip = priv;
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ if (status == USBD_NOT_STARTED) {
+ error = 1;
+ goto next;
+ }
+ if (status == USBD_STALLED)
+ usbd_clear_endpoint_stall_async(xfer->pipe);
+ /*
+ * NB: just for notice. We must handle error cases also
+ * because if we just return without notifying to the
+ * NDIS driver the driver never knows about that there
+ * was a error. This can cause a lot of problems like
+ * system hangs.
+ */
+ device_printf(dev, "usb xfer warning (%s)\n",
+ usbd_errstr(status));
+ }
+
+ urb = usbd_geturb(ip);
+
+ KASSERT(urb->uu_hdr.uuh_func ==
+ URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER,
+ ("function(%d) isn't for bulk or interrupt",
+ urb->uu_hdr.uuh_func));
+
+ IoAcquireCancelSpinLock(&ip->irp_cancelirql);
+
+ ip->irp_cancelfunc = NULL;
+ IRP_NDISUSB_XFER(ip) = NULL;
+
+ switch (status) {
+ case USBD_NORMAL_COMPLETION:
+ ubi = &urb->uu_bulkintr;
+ ubi->ubi_trans_buflen = xfer->actlen;
+ if (ubi->ubi_trans_flags & USBD_TRANSFER_DIRECTION_IN)
+ memcpy(ubi->ubi_trans_buf, xfer->buffer,
+ xfer->actlen);
+
+ ip->irp_iostat.isb_info = xfer->actlen;
+ ip->irp_iostat.isb_status = STATUS_SUCCESS;
+ USBD_URB_STATUS(urb) = USBD_STATUS_SUCCESS;
+ break;
+ case USBD_CANCELLED:
+ ip->irp_iostat.isb_info = 0;
+ ip->irp_iostat.isb_status = STATUS_CANCELLED;
+ USBD_URB_STATUS(urb) = USBD_STATUS_CANCELED;
+ break;
+ default:
+ ip->irp_iostat.isb_info = 0;
+ USBD_URB_STATUS(urb) = usbd_usb2urb(status);
+ ip->irp_iostat.isb_status =
+ usbd_urb2nt(USBD_URB_STATUS(urb));
+ break;
+ }
+
+ IoReleaseCancelSpinLock(ip->irp_cancelirql);
+next:
+ l = l->nle_flink;
+ RemoveEntryList(&nx->nx_xferlist);
+ usbd_free_xfer(nx->nx_xfer);
+ free(nx, M_USBDEV);
+ if (error)
+ continue;
+ /* NB: call after cleaning */
+ IoCompleteRequest(ip, IO_NO_INCREMENT);
+ }
+ KeReleaseSpinLock(&sc->ndisusb_xferlock, irql);
+}
+
+static int32_t
+usbd_func_bulkintr(ip)
+ irp *ip;
+{
+ device_t dev = IRP_NDIS_DEV(ip);
+ struct ndis_softc *sc = device_get_softc(dev);
+ struct usbd_urb_bulk_or_intr_transfer *ubi;
+ union usbd_urb *urb;
+ usb_endpoint_descriptor_t *ep;
+ usbd_status status;
+ usbd_xfer_handle xfer;
+
+ urb = usbd_geturb(ip);
+ ubi = &urb->uu_bulkintr;
+ ep = ubi->ubi_epdesc;
+ if (ep == NULL)
+ return (USBD_STATUS_INVALID_PIPE_HANDLE);
+
+ status = usbd_init_ndispipe(ip, ep);
+ if (status != USBD_NORMAL_COMPLETION)
+ return usbd_usb2urb(status);
+
+ xfer = usbd_init_ndisxfer(ip, ep, ubi->ubi_trans_buf,
+ ubi->ubi_trans_buflen);
+ if (xfer == NULL) {
+ device_printf(IRP_NDIS_DEV(ip), "can't allocate xfer\n");
+ return (USBD_STATUS_NO_MEMORY);
+ }
+
+ if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN) {
+ xfer->flags |= USBD_SHORT_XFER_OK;
+ if (!(ubi->ubi_trans_flags & USBD_SHORT_TRANSFER_OK))
+ xfer->flags &= ~USBD_SHORT_XFER_OK;
+ }
+
+ if (UE_GET_XFERTYPE(ep->bmAttributes) == UE_BULK) {
+ if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
+ /* RX (bulk IN) */
+ usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_BIN],
+ ip, xfer->buffer, xfer->length, xfer->flags,
+ USBD_NO_TIMEOUT, usbd_xfereof);
+ else {
+ /* TX (bulk OUT) */
+ xfer->flags |= USBD_NO_COPY;
+
+ usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_BOUT],
+ ip, xfer->buffer, xfer->length, xfer->flags,
+ NDISUSB_TX_TIMEOUT, usbd_xfereof);
+ }
+ } else {
+ if (UE_GET_DIR(ep->bEndpointAddress) == UE_DIR_IN)
+ /* Interrupt IN */
+ usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_IIN],
+ ip, xfer->buffer, xfer->length, xfer->flags,
+ USBD_NO_TIMEOUT, usbd_xfereof);
+ else
+ /* Interrupt OUT */
+ usbd_setup_xfer(xfer, sc->ndisusb_ep[NDISUSB_ENDPT_IOUT],
+ ip, xfer->buffer, xfer->length, xfer->flags,
+ NDISUSB_INTR_TIMEOUT, usbd_xfereof);
+ }
+
+ /* we've done to setup xfer. Let's transfer it. */
+ ip->irp_iostat.isb_status = STATUS_PENDING;
+ ip->irp_iostat.isb_info = 0;
+ USBD_URB_STATUS(urb) = USBD_STATUS_PENDING;
+ IoMarkIrpPending(ip);
+
+ status = usbd_transfer(xfer);
+ if (status == USBD_IN_PROGRESS)
+ return (USBD_STATUS_PENDING);
+
+ usbd_free_xfer(xfer);
+ IRP_NDISUSB_XFER(ip) = NULL;
+ IoUnmarkIrpPending(ip);
+ USBD_URB_STATUS(urb) = usbd_usb2urb(status);
+
+ return USBD_URB_STATUS(urb);
+}
+
+static union usbd_urb *
+USBD_CreateConfigurationRequest(conf, len)
+ usb_config_descriptor_t *conf;
+ uint16_t *len;
+{
+ struct usbd_interface_list_entry list[2];
+ union usbd_urb *urb;
+
+ bzero(list, sizeof(struct usbd_interface_list_entry) * 2);
+ list[0].uil_intfdesc = USBD_ParseConfigurationDescriptorEx(conf, conf,
+ -1, -1, -1, -1, -1);
+ urb = USBD_CreateConfigurationRequestEx(conf, list);
+ if (urb == NULL)
+ return NULL;
+
+ *len = urb->uu_selconf.usc_hdr.uuh_len;
+ return urb;
+}
+
+static union usbd_urb *
+USBD_CreateConfigurationRequestEx(conf, list)
+ usb_config_descriptor_t *conf;
+ struct usbd_interface_list_entry *list;
+{
+ int i, j, size;
+ struct usbd_interface_information *intf;
+ struct usbd_pipe_information *pipe;
+ struct usbd_urb_select_configuration *selconf;
+ usb_interface_descriptor_t *desc;
+
+ for (i = 0, size = 0; i < conf->bNumInterface; i++) {
+ j = list[i].uil_intfdesc->bNumEndpoints;
+ size = size + sizeof(struct usbd_interface_information) +
+ sizeof(struct usbd_pipe_information) * (j - 1);
+ }
+ size += sizeof(struct usbd_urb_select_configuration) -
+ sizeof(struct usbd_interface_information);
+
+ selconf = ExAllocatePoolWithTag(NonPagedPool, size, 0);
+ if (selconf == NULL)
+ return NULL;
+ selconf->usc_hdr.uuh_func = URB_FUNCTION_SELECT_CONFIGURATION;
+ selconf->usc_hdr.uuh_len = size;
+ selconf->usc_handle = conf;
+ selconf->usc_conf = conf;
+
+ intf = &selconf->usc_intf;
+ for (i = 0; i < conf->bNumInterface; i++) {
+ if (list[i].uil_intfdesc == NULL)
+ break;
+
+ list[i].uil_intf = intf;
+ desc = list[i].uil_intfdesc;
+
+ intf->uii_len = sizeof(struct usbd_interface_information) +
+ (desc->bNumEndpoints - 1) *
+ sizeof(struct usbd_pipe_information);
+ intf->uii_intfnum = desc->bInterfaceNumber;
+ intf->uii_altset = desc->bAlternateSetting;
+ intf->uii_intfclass = desc->bInterfaceClass;
+ intf->uii_intfsubclass = desc->bInterfaceSubClass;
+ intf->uii_intfproto = desc->bInterfaceProtocol;
+ intf->uii_handle = desc;
+ intf->uii_numeps = desc->bNumEndpoints;
+
+ pipe = &intf->uii_pipes[0];
+ for (j = 0; j < intf->uii_numeps; j++)
+ pipe[j].upi_maxtxsize =
+ USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE;
+
+ intf = (struct usbd_interface_information *)((char *)intf +
+ intf->uii_len);
+ }
+
+ return ((union usbd_urb *)selconf);
}
static void
@@ -125,6 +1139,52 @@ USBD_GetUSBDIVersion(ui)
return;
}
+static usb_interface_descriptor_t *
+USBD_ParseConfigurationDescriptor(conf, intfnum, altset)
+ usb_config_descriptor_t *conf;
+ uint8_t intfnum;
+ uint8_t altset;
+{
+ return USBD_ParseConfigurationDescriptorEx(conf, conf, intfnum, altset,
+ -1, -1, -1);
+}
+
+static usb_interface_descriptor_t *
+USBD_ParseConfigurationDescriptorEx(conf, start, intfnum,
+ altset, intfclass, intfsubclass, intfproto)
+ usb_config_descriptor_t *conf;
+ void *start;
+ int32_t intfnum;
+ int32_t altset;
+ int32_t intfclass;
+ int32_t intfsubclass;
+ int32_t intfproto;
+{
+ char *pos;
+ usb_interface_descriptor_t *desc;
+
+ for (pos = start; pos < ((char *)conf + UGETW(conf->wTotalLength));
+ pos += desc->bLength) {
+ desc = (usb_interface_descriptor_t *)pos;
+ if (desc->bDescriptorType != UDESC_INTERFACE)
+ continue;
+ if (!(intfnum == -1 || desc->bInterfaceNumber == intfnum))
+ continue;
+ if (!(altset == -1 || desc->bAlternateSetting == altset))
+ continue;
+ if (!(intfclass == -1 || desc->bInterfaceClass == intfclass))
+ continue;
+ if (!(intfsubclass == -1 ||
+ desc->bInterfaceSubClass == intfsubclass))
+ continue;
+ if (!(intfproto == -1 || desc->bInterfaceProtocol == intfproto))
+ continue;
+ return (desc);
+ }
+
+ return (NULL);
+}
+
static void
dummy(void)
{
@@ -133,14 +1193,15 @@ dummy(void)
}
image_patch_table usbd_functbl[] = {
- IMPORT_SFUNC(USBD_GetUSBDIVersion, 0),
- IMPORT_SFUNC(usbd_iodispatch, 2),
-#ifdef notyet
- IMPORT_FUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
- USBD_ParseConfigurationDescriptorEx),
- IMPORT_FUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
- USBD_CreateConfigurationRequestEx),
-#endif
+ IMPORT_SFUNC(USBD_CreateConfigurationRequest, 2),
+ IMPORT_SFUNC(USBD_CreateConfigurationRequestEx, 2),
+ IMPORT_SFUNC_MAP(_USBD_CreateConfigurationRequestEx@8,
+ USBD_CreateConfigurationRequestEx, 2),
+ IMPORT_SFUNC(USBD_GetUSBDIVersion, 1),
+ IMPORT_SFUNC(USBD_ParseConfigurationDescriptor, 3),
+ IMPORT_SFUNC(USBD_ParseConfigurationDescriptorEx, 7),
+ IMPORT_SFUNC_MAP(_USBD_ParseConfigurationDescriptorEx@28,
+ USBD_ParseConfigurationDescriptorEx, 7),
/*
* This last entry is a catch-all for any function we haven't
@@ -156,3 +1217,5 @@ image_patch_table usbd_functbl[] = {
{ NULL, NULL, NULL }
};
+MODULE_DEPEND(ndis, usb, 1, 1, 1);
+
diff --git a/sys/compat/ndis/usbd_var.h b/sys/compat/ndis/usbd_var.h
index 8c9f2b3..59009a7 100644
--- a/sys/compat/ndis/usbd_var.h
+++ b/sys/compat/ndis/usbd_var.h
@@ -35,9 +35,168 @@
#ifndef _USBD_VAR_H_
#define _USBD_VAR_H_
-#define USBDI_VERSION 0x00000500
-#define USB_VER_1_1 0x00000110
-#define USB_VER_2_0 0x00000200
+#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003
+
+#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000
+#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009
+#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B
+#define URB_FUNCTION_VENDOR_DEVICE 0x0017
+#define URB_FUNCTION_VENDOR_INTERFACE 0x0018
+#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019
+#define URB_FUNCTION_CLASS_DEVICE 0x001A
+#define URB_FUNCTION_CLASS_INTERFACE 0x001B
+#define URB_FUNCTION_CLASS_ENDPOINT 0x001C
+#define URB_FUNCTION_CLASS_OTHER 0x001F
+#define URB_FUNCTION_VENDOR_OTHER 0x0020
+
+#define USBD_STATUS_SUCCESS 0x00000000
+#define USBD_STATUS_CANCELED 0x00010000
+#define USBD_STATUS_PENDING 0x40000000
+#define USBD_STATUS_NO_MEMORY 0x80000100
+#define USBD_STATUS_REQUEST_FAILED 0x80000500
+#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600
+#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900
+#define USBD_STATUS_CRC 0xC0000001
+#define USBD_STATUS_BTSTUFF 0xC0000002
+#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003
+#define USBD_STATUS_STALL_PID 0xC0000004
+#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005
+#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006
+#define USBD_STATUS_UNEXPECTED_PID 0xC0000007
+#define USBD_STATUS_DATA_OVERRUN 0xC0000008
+#define USBD_STATUS_DATA_UNDERRUN 0xC0000009
+#define USBD_STATUS_RESERVED1 0xC000000A
+#define USBD_STATUS_RESERVED2 0xC000000B
+#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C
+#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D
+#define USBD_STATUS_NOT_ACCESSED 0xC000000F
+#define USBD_STATUS_FIFO 0xC0000010
+#define USBD_STATUS_XACT_ERROR 0xC0000011
+#define USBD_STATUS_BABBLE_DETECTED 0xC0000012
+#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013
+#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00
+#define USBD_STATUS_TIMEOUT 0xC0006000
+#define USBD_STATUS_DEVICE_GONE 0xC0007000
+
+struct usbd_urb_header {
+ uint16_t uuh_len;
+ uint16_t uuh_func;
+ int32_t uuh_status;
+ void *uuh_handle;
+ uint32_t uuh_flags;
+};
+
+enum usbd_pipe_type {
+ UsbdPipeTypeControl = UE_CONTROL,
+ UsbdPipeTypeIsochronous = UE_ISOCHRONOUS,
+ UsbdPipeTypeBulk = UE_BULK,
+ UsbdPipeTypeInterrupt = UE_INTERRUPT
+};
+
+struct usbd_pipe_information {
+ uint16_t upi_maxpktsize;
+ uint8_t upi_epaddr;
+ uint8_t upi_interval;
+ enum usbd_pipe_type upi_type;
+ usb_endpoint_descriptor_t *upi_handle;
+ uint32_t upi_maxtxsize;
+#define USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE PAGE_SIZE
+ uint32_t upi_flags;
+};
+
+struct usbd_interface_information {
+ uint16_t uii_len;
+ uint8_t uii_intfnum;
+ uint8_t uii_altset;
+ uint8_t uii_intfclass;
+ uint8_t uii_intfsubclass;
+ uint8_t uii_intfproto;
+ uint8_t uii_reserved;
+ void *uii_handle;
+ uint32_t uii_numeps;
+ struct usbd_pipe_information uii_pipes[1];
+};
+
+struct usbd_urb_select_interface {
+ struct usbd_urb_header usi_hdr;
+ void *usi_handle;
+ struct usbd_interface_information uusi_intf;
+};
+
+struct usbd_urb_select_configuration {
+ struct usbd_urb_header usc_hdr;
+ usb_config_descriptor_t *usc_conf;
+ void *usc_handle;
+ struct usbd_interface_information usc_intf;
+};
+
+struct usbd_hcd_area {
+ void *reserved8[8];
+};
+
+struct usbd_urb_bulk_or_intr_transfer {
+ struct usbd_urb_header ubi_hdr;
+ usb_endpoint_descriptor_t *ubi_epdesc;
+ uint32_t ubi_trans_flags;
+#define USBD_SHORT_TRANSFER_OK 0x00000002
+ uint32_t ubi_trans_buflen;
+ void *ubi_trans_buf;
+ struct mdl *ubi_mdl;
+ union usbd_urb *ubi_urblink;
+ struct usbd_hcd_area ubi_hca;
+};
+
+struct usbd_urb_control_descriptor_request {
+ struct usbd_urb_header ucd_hdr;
+ void *ucd_reserved0;
+ uint32_t ucd_reserved1;
+ uint32_t ucd_trans_buflen;
+ void *ucd_trans_buf;
+ struct mdl *ucd_mdl;
+ union nt_urb *ucd_urblink;
+ struct usbd_hcd_area ucd_hca;
+ uint16_t ucd_reserved2;
+ uint8_t ucd_idx;
+ uint8_t ucd_desctype;
+ uint16_t ucd_langid;
+ uint16_t ucd_reserved3;
+};
+
+struct usbd_urb_vendor_or_class_request {
+ struct usbd_urb_header uvc_hdr;
+ void *uvc_reserved0;
+ uint32_t uvc_trans_flags;
+#define USBD_TRANSFER_DIRECTION_IN 1
+ uint32_t uvc_trans_buflen;
+ void *uvc_trans_buf;
+ struct mdl *uvc_mdl;
+ union nt_urb *uvc_urblink;
+ struct usbd_hcd_area uvc_hca;
+ uint8_t uvc_reserved1;
+ uint8_t uvc_req;
+ uint16_t uvc_value;
+ uint16_t uvc_idx;
+ uint16_t uvc_reserved2;
+};
+
+struct usbd_interface_list_entry {
+ usb_interface_descriptor_t *uil_intfdesc;
+ struct usbd_interface_information *uil_intf;
+};
+
+union usbd_urb {
+ struct usbd_urb_header uu_hdr;
+ struct usbd_urb_select_configuration uu_selconf;
+ struct usbd_urb_bulk_or_intr_transfer uu_bulkintr;
+ struct usbd_urb_control_descriptor_request uu_ctldesc;
+ struct usbd_urb_vendor_or_class_request uu_vcreq;
+};
+
+#define USBD_URB_STATUS(urb) ((urb)->uu_hdr.uuh_status)
+
+#define USBDI_VERSION 0x00000500
+#define USB_VER_1_1 0x00000110
+#define USB_VER_2_0 0x00000200
struct usbd_version_info {
uint32_t uvi_usbdi_vers;
@@ -46,6 +205,13 @@ struct usbd_version_info {
typedef struct usbd_version_info usbd_version_info;
+/* used for IRP cancel. */
+struct ndisusb_cancel {
+ device_t dev;
+ usbd_xfer_handle xfer;
+ struct usb_task task;
+};
+
extern image_patch_table usbd_functbl[];
__BEGIN_DECLS
OpenPOWER on IntegriCloud