PERFORCE change 142519 for review
Weongyo Jeong
weongyo at FreeBSD.org
Thu May 29 05:17:37 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=142519
Change 142519 by weongyo at weongyo_ws on 2008/05/29 05:16:48
Commit the basic implementation of NDIS USB support. With this
changeset, we can support few NDIS USB drivers (e.g. currently U-Khan
UW-2054u).
Affected files ...
.. //depot/projects/ndisusb/sys/compat/ndis/cfg_var.h#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/hal_var.h#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/kern_ndis.c#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/kern_windrv.c#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/ndis_var.h#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/ntoskrnl_var.h#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/pe_var.h#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/resource_var.h#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/subr_hal.c#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/subr_ndis.c#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/subr_ntoskrnl.c#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/subr_pe.c#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/subr_usbd.c#2 edit
.. //depot/projects/ndisusb/sys/compat/ndis/usbd_var.h#2 edit
.. //depot/projects/ndisusb/sys/dev/if_ndis/if_ndis.c#2 edit
.. //depot/projects/ndisusb/sys/dev/if_ndis/if_ndis_pccard.c#2 edit
.. //depot/projects/ndisusb/sys/dev/if_ndis/if_ndis_pci.c#2 edit
.. //depot/projects/ndisusb/sys/dev/if_ndis/if_ndis_usb.c#2 edit
.. //depot/projects/ndisusb/sys/dev/if_ndis/if_ndisvar.h#2 edit
.. //depot/projects/ndisusb/usr.sbin/ndiscvt/inf.c#2 edit
.. //depot/projects/ndisusb/usr.sbin/ndiscvt/windrv_stub.c#2 edit
Differences ...
==== //depot/projects/ndisusb/sys/compat/ndis/cfg_var.h#2 (text+ko) ====
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/compat/ndis/cfg_var.h,v 1.3 2005/01/05 22:34:36 imp Exp $
+ * $FreeBSD$
*/
#ifndef _CFG_VAR_H_
==== //depot/projects/ndisusb/sys/compat/ndis/hal_var.h#2 (text+ko) ====
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/compat/ndis/hal_var.h,v 1.8 2005/04/11 02:02:34 wpaul Exp $
+ * $FreeBSD$
*/
#ifndef _HAL_VAR_H_
==== //depot/projects/ndisusb/sys/compat/ndis/kern_ndis.c#2 (text+ko) ====
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.97 2008/02/01 19:36:22 phk Exp $");
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
@@ -65,6 +65,9 @@
#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>
==== //depot/projects/ndisusb/sys/compat/ndis/kern_windrv.c#2 (text+ko) ====
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.14 2007/05/20 22:03:57 jeff Exp $");
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
@@ -56,6 +56,9 @@
#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>
==== //depot/projects/ndisusb/sys/compat/ndis/ndis_var.h#2 (text+ko) ====
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/compat/ndis/ndis_var.h,v 1.48 2007/12/02 04:04:42 thompsa Exp $
+ * $FreeBSD$
*/
#ifndef _NDIS_VAR_H_
==== //depot/projects/ndisusb/sys/compat/ndis/ntoskrnl_var.h#2 (text+ko) ====
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/compat/ndis/ntoskrnl_var.h,v 1.44 2007/12/02 08:54:50 thompsa Exp $
+ * $FreeBSD$
*/
#ifndef _NTOSKRNL_VAR_H_
@@ -987,7 +987,13 @@
} 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;
};
@@ -995,6 +1001,9 @@
#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) \
@@ -1007,6 +1016,10 @@
(cancel_func)InterlockedExchangePointer( \
(void *)&(ip)->irp_cancelfunc, (void *)(func))
+#define IoSetCancelValue(irp, val) \
+ (uint32_t)InterlockedExchangePointer( \
+ (void *)&(ip)->irp_cancel, (void *)(val))
+
#define IoGetCurrentIrpStackLocation(irp) \
(irp)->irp_tail.irp_overlay.irp_csl
@@ -1033,6 +1046,8 @@
#define IoMarkIrpPending(irp) \
IoGetCurrentIrpStackLocation(irp)->isl_ctl |= SL_PENDING_RETURNED
+#define IoUnmarkIrpPending(irp) \
+ IoGetCurrentIrpStackLocation(irp)->isl_ctl &= ~SL_PENDING_RETURNED
#define IoCopyCurrentIrpStackLocationToNext(irp) \
do { \
@@ -1189,14 +1204,20 @@
#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_CANCELLED 0xC0000120
#define STATUS_NOT_FOUND 0xC0000225
+#define STATUS_DEVICE_REMOVED 0xC00002B6
#define STATUS_WAIT_0 0x00000000
@@ -1363,6 +1384,7 @@
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 *);
==== //depot/projects/ndisusb/sys/compat/ndis/pe_var.h#2 (text+ko) ====
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/compat/ndis/pe_var.h,v 1.14 2005/10/26 18:46:27 wpaul Exp $
+ * $FreeBSD$
*/
#ifndef _PE_VAR_H_
==== //depot/projects/ndisusb/sys/compat/ndis/resource_var.h#2 (text+ko) ====
@@ -29,7 +29,7 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/sys/compat/ndis/resource_var.h,v 1.3 2005/02/16 05:41:17 wpaul Exp $
+ * $FreeBSD$
*/
#ifndef _RESOURCE_VAR_H_
==== //depot/projects/ndisusb/sys/compat/ndis/subr_hal.c#2 (text+ko) ====
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_hal.c,v 1.28 2006/05/16 14:37:57 phk Exp $");
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/types.h>
==== //depot/projects/ndisusb/sys/compat/ndis/subr_ndis.c#2 (text+ko) ====
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_ndis.c,v 1.112 2008/05/15 04:29:28 weongyo Exp $");
+__FBSDID("$FreeBSD$");
/*
* This file implements a translation layer between the BSD networking
@@ -95,6 +95,8 @@
#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>
==== //depot/projects/ndisusb/sys/compat/ndis/subr_ntoskrnl.c#2 (text+ko) ====
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_ntoskrnl.c,v 1.94 2007/12/25 17:51:56 rwatson Exp $");
+__FBSDID("$FreeBSD$");
#include <sys/ctype.h>
#include <sys/unistd.h>
@@ -207,7 +207,6 @@
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);
@@ -249,6 +248,7 @@
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 void dummy(void);
static struct mtx ntoskrnl_dispatchlock;
@@ -1141,16 +1141,18 @@
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
@@ -1184,24 +1186,27 @@
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 &&
@@ -1212,12 +1217,16 @@
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. */
@@ -2669,7 +2678,7 @@
* here, but it doesn't.
*/
-static uint8_t
+uint8_t
MmIsAddressValid(vaddr)
void *vaddr;
{
@@ -4244,6 +4253,37 @@
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 void
dummy()
{
@@ -4426,6 +4466,8 @@
IMPORT_CFUNC(WmiTraceMessage, 0),
IMPORT_SFUNC(KeQuerySystemTime, 1),
IMPORT_CFUNC(KeTickCount, 0),
+ IMPORT_SFUNC(KeDelayExecutionThread, 3),
+ IMPORT_SFUNC(KeQueryInterruptTime, 0),
/*
* This last entry is a catch-all for any function we haven't
==== //depot/projects/ndisusb/sys/compat/ndis/subr_pe.c#2 (text+ko) ====
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_pe.c,v 1.13 2007/04/06 11:18:57 pjd Exp $");
+__FBSDID("$FreeBSD$");
/*
* This file contains routines for relocating and dynamically linking
==== //depot/projects/ndisusb/sys/compat/ndis/subr_usbd.c#2 (text+ko) ====
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_usbd.c,v 1.3 2005/05/05 03:56:09 wpaul Exp $");
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
@@ -45,10 +45,24 @@
#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,56 @@
#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_bulkintr_iin(irp *);
+static int32_t usbd_func_vendorclass(irp *);
+static int32_t usbd_func_selconf(irp *);
+static int32_t usbd_func_getdesc(irp *);
+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 void usbd_intr(usbd_xfer_handle, usbd_private_handle, usbd_status);
+static int32_t usbd_iodispatch(device_object *, irp *);
+static int32_t usbd_ioinvalid(device_object *, irp *);
+static int32_t usbd_irpcancel(device_object *, irp *);
+static void usbd_irpcancel_cb(void *);
+static int32_t usbd_irpcancel_iin(device_object *, irp *);
+static void usbd_irpcancel_iin_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 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 void dummy(void);
+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_irpcancel_wrap;
+static funcptr usbd_irpcancel_iin_wrap;
int
usbd_libinit(void)
{
image_patch_table *patch;
+ int i;
patch = usbd_functbl;
while (patch->ipt_func != NULL) {
@@ -77,14 +129,26 @@
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_irpcancel,
+ (funcptr *)&usbd_irpcancel_wrap, 2, WINDRV_WRAP_STDCALL);
+ windrv_wrap((funcptr)usbd_irpcancel_iin,
+ (funcptr *)&usbd_irpcancel_iin_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;
return(0);
}
@@ -100,17 +164,925 @@
patch++;
}
+ windrv_unwrap(usbd_ioinvalid_wrap);
+ windrv_unwrap(usbd_iodispatch_wrap);
+ windrv_unwrap(usbd_irpcancel_wrap);
+ windrv_unwrap(usbd_irpcancel_iin_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);
+}
+
+/* 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_REMOVED);
+ 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);
+ default:
+ break;
+ }
+
+ return (STATUS_FAILURE);
+}
+
+/* Convert FreeBSD's usbd_status to USBD_STATUS */
+static int32_t
+usbd_usb2urb(int urb_status)
+{
+
+ switch (urb_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_INVALID_PIPE_HANDLE);
+ 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);
+ 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);
+ switch (urb->uu_hdr.uuh_func) {
+ case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
+ status = usbd_func_bulkintr(ip);
+ 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);
+ 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 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;
+
+ 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;
+ return usbd_usb2urb(status);
+ }
+ len = UGETW(cd.wTotalLength);
+ /* Get the full descriptor. Try a few times for slow devices. */
+ for (i = 0; i < 3; i++) {
+ status = usbd_get_desc(uaa->device,
+ ctldesc->ucd_desctype, ctldesc->ucd_idx,
+ len, ctldesc->ucd_trans_buf);
+ if (status == USBD_NORMAL_COMPLETION)
+ break;
+ usbd_delay_ms(uaa->device, 200);
+ }
+ if (status != USBD_NORMAL_COMPLETION) {
+ ctldesc->ucd_trans_buflen = 0;
+ 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(uaa->device,
+ (UDESC_STRING << 8) + ctldesc->ucd_idx,
+ ctldesc->ucd_trans_buf, ctldesc->ucd_trans_buflen);
+ if (status != USBD_NORMAL_COMPLETION)
+ break;
+ usbd_delay_ms(uaa->device, 200);
+ }
+ } else
+ status = usbd_get_desc(uaa->device, ctldesc->ucd_desctype,
+ ctldesc->ucd_idx, ctldesc->ucd_trans_buflen,
+ ctldesc->ucd_trans_buf);
+
+ if (status != USBD_NORMAL_COMPLETION) {
+ ctldesc->ucd_trans_buflen = 0;
+ return usbd_usb2urb(status);
+ }
+
+ ctldesc->ucd_trans_buflen = status;
+ ip->irp_iostat.isb_info = status;
+ return (USBD_STATUS_SUCCESS);
+}
+
+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) {
+ 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 = 1, 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);
+ 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;
+ }
+
+ vcreq = &urb->uu_vcreq;
+ if (!(vcreq->uvc_trans_flags & USBD_TRANSFER_DIRECTION_IN))
+ type |= UT_WRITE;
+ else
+ type |= UT_READ;
+ 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);
+
+ status = usbd_do_request(uaa->device, &req, vcreq->uvc_trans_buf);
+
+ return usbd_usb2urb(status);
+}
+
+static void
+usbd_irpcancel_iin_cb(priv)
+ void *priv;
+{
+ struct ndisusb_cancel *nc = priv;
+ irp *ip = nc->ip;
+ 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_status status;
+ usbd_xfer_handle xfer;
+
+ usb_rem_task(uaa->device, &nc->task);
+ free(priv, M_USBDEV);
+
+ xfer = IRP_NDISUSB_XFER(ip);
+ IRP_NDISUSB_XFER(ip) = NULL;
+
+ status = usbd_abort_pipe(sc->ndisusb_ep[NDISUSB_ENDPT_IIN]);
+ if (status != USBD_NORMAL_COMPLETION)
+ device_printf(dev, "IIN can't be canceld");
+}
+
+static int32_t
+usbd_irpcancel_iin(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);
+
+ /* XXX see the description of usbd_irpcancel() */
+ nc = malloc(sizeof(struct ndisusb_cancel), M_USBDEV, M_NOWAIT | M_ZERO);
+ if (nc == NULL) {
+ ip->irp_cancel = FALSE;
+ IoReleaseCancelSpinLock(ip->irp_cancelirql);
+ return (-1);
+ }
+
+ nc->ip = ip;
+ usb_init_task(&nc->task, usbd_irpcancel_iin_cb, nc);
+ usb_add_task(uaa->device, &nc->task, USB_TASKQ_DRIVER);
+
+ IoReleaseCancelSpinLock(ip->irp_cancelirql);
+
+ return (0);
+}
+
+static int32_t
+usbd_func_bulkintr_iin(ip)
+ irp *ip;
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list