Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 May 2008 05:17:37 GMT
From:      Weongyo Jeong <weongyo@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 142519 for review
Message-ID:  <200805290517.m4T5HbDm043288@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=142519

Change 142519 by weongyo@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) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200805290517.m4T5HbDm043288>