Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Dec 2008 08:03:33 +0000 (UTC)
From:      Weongyo Jeong <weongyo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r186507 - in head: share/man/man4 sys/compat/ndis sys/dev/if_ndis sys/modules/ndis usr.sbin/ndiscvt
Message-ID:  <200812270803.mBR83XA5063933@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: weongyo
Date: Sat Dec 27 08:03:32 2008
New Revision: 186507
URL: http://svn.freebsd.org/changeset/base/186507

Log:
  Integrate the NDIS USB support code to CURRENT.
  
  Now the NDISulator supports NDIS USB drivers that it've tested with
  devices as follows:
  
    - Anygate XM-142 (Conexant)
    - Netgear WG111v2 (Realtek)
    - U-Khan UW-2054u (Marvell)
    - Shuttle XPC Accessory PN20 (Realtek)
    - ipTIME G054U2 (Ralink)
    - UNiCORN WL-54G (ZyDAS)
    - ZyXEL G-200v2 (ZyDAS)
  
  All of them succeeded to attach and worked though there are still some
  problems that it's expected to be solved.
  
  To use NDIS USB support, you should rebuild and install ndiscvt(8) and
  if you encounter a problem to attach please set `hw.ndisusb.halt' to
  0 then retry.
  
  I expect no changes of the NDIS code for PCI, PCMCIA devices.
  
  Obtained from:  //depot/projects/ndisusb/...

Modified:
  head/share/man/man4/ndis.4
  head/sys/compat/ndis/kern_ndis.c
  head/sys/compat/ndis/kern_windrv.c
  head/sys/compat/ndis/ndis_var.h
  head/sys/compat/ndis/ntoskrnl_var.h
  head/sys/compat/ndis/subr_ndis.c
  head/sys/compat/ndis/subr_ntoskrnl.c
  head/sys/compat/ndis/subr_usbd.c
  head/sys/compat/ndis/usbd_var.h
  head/sys/dev/if_ndis/if_ndis.c
  head/sys/dev/if_ndis/if_ndis_pccard.c
  head/sys/dev/if_ndis/if_ndis_pci.c
  head/sys/dev/if_ndis/if_ndis_usb.c
  head/sys/dev/if_ndis/if_ndisvar.h
  head/sys/modules/ndis/Makefile
  head/usr.sbin/ndiscvt/inf.c
  head/usr.sbin/ndiscvt/windrv_stub.c

Modified: head/share/man/man4/ndis.4
==============================================================================
--- head/share/man/man4/ndis.4	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/share/man/man4/ndis.4	Sat Dec 27 08:03:32 2008	(r186507)
@@ -105,7 +105,7 @@ file.
 The
 .Nm
 driver is designed to support mainly Ethernet and wireless
-network devices with PCI and PCMCIA bus attachments.
+network devices with PCI, PCMCIA and USB bus attachments.
 (Cardbus
 devices are also supported as a subset of PCI.)
 It can

Modified: head/sys/compat/ndis/kern_ndis.c
==============================================================================
--- head/sys/compat/ndis/kern_ndis.c	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/sys/compat/ndis/kern_ndis.c	Sat Dec 27 08:03:32 2008	(r186507)
@@ -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, voi
 		}
 
 		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;
 {

Modified: head/sys/compat/ndis/kern_windrv.c
==============================================================================
--- head/sys/compat/ndis/kern_windrv.c	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/sys/compat/ndis/kern_windrv.c	Sat Dec 27 08:03:32 2008	(r186507)
@@ -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, devl
 	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) {

Modified: head/sys/compat/ndis/ndis_var.h
==============================================================================
--- head/sys/compat/ndis/ndis_var.h	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/sys/compat/ndis/ndis_var.h	Sat Dec 27 08:03:32 2008	(r186507)
@@ -1658,6 +1658,7 @@ typedef void (*ndis_return_handler)(ndis
 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_stat
 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_ */

Modified: head/sys/compat/ndis/ntoskrnl_var.h
==============================================================================
--- head/sys/compat/ndis/ntoskrnl_var.h	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/sys/compat/ndis/ntoskrnl_var.h	Sat Dec 27 08:03:32 2008	(r186507)
@@ -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_obje
 #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 *);

Modified: head/sys/compat/ndis/subr_ndis.c
==============================================================================
--- head/sys/compat/ndis/subr_ndis.c	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/sys/compat/ndis/subr_ndis.c	Sat Dec 27 08:03:32 2008	(r186507)
@@ -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
 	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
 	    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;
 }

Modified: head/sys/compat/ndis/subr_ntoskrnl.c
==============================================================================
--- head/sys/compat/ndis/subr_ntoskrnl.c	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/sys/compat/ndis/subr_ntoskrnl.c	Sat Dec 27 08:03:32 2008	(r186507)
@@ -207,7 +207,6 @@ static void *MmMapLockedPages(mdl *, uin
 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);
-
-	for (i = ip->irp_currentstackloc; i < (uint32_t)ip->irp_stackcnt; i++) {
-		if (ip->irp_currentstackloc < ip->irp_stackcnt - 1) {
-			IoSkipCurrentIrpStackLocation(ip);
+	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;
+
+		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

Modified: head/sys/compat/ndis/subr_usbd.c
==============================================================================
--- head/sys/compat/ndis/subr_usbd.c	Sat Dec 27 00:17:41 2008	(r186506)
+++ head/sys/compat/ndis/subr_usbd.c	Sat Dec 27 08:03:32 2008	(r186507)
@@ -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 void USBD_GetUSBDIVersion(usbd_version_info *);
-static void dummy(void);
+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 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;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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