From owner-p4-projects@FreeBSD.ORG Thu May 29 05:17:37 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 6ECA91065673; Thu, 29 May 2008 05:17:37 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 33B271065672 for ; Thu, 29 May 2008 05:17:37 +0000 (UTC) (envelope-from weongyo@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 3B34E8FC22 for ; Thu, 29 May 2008 05:17:37 +0000 (UTC) (envelope-from weongyo@FreeBSD.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m4T5HbXa043290 for ; Thu, 29 May 2008 05:17:37 GMT (envelope-from weongyo@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m4T5HbDm043288 for perforce@freebsd.org; Thu, 29 May 2008 05:17:37 GMT (envelope-from weongyo@FreeBSD.org) Date: Thu, 29 May 2008 05:17:37 GMT Message-Id: <200805290517.m4T5HbDm043288@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to weongyo@FreeBSD.org using -f From: Weongyo Jeong To: Perforce Change Reviews Cc: Subject: PERFORCE change 142519 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 29 May 2008 05:17:37 -0000 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 -__FBSDID("$FreeBSD: src/sys/compat/ndis/kern_ndis.c,v 1.97 2008/02/01 19:36:22 phk Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -65,6 +65,9 @@ #include #include +#include +#include + #include #include #include ==== //depot/projects/ndisusb/sys/compat/ndis/kern_windrv.c#2 (text+ko) ==== @@ -31,7 +31,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/compat/ndis/kern_windrv.c,v 1.14 2007/05/20 22:03:57 jeff Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -56,6 +56,9 @@ #include #endif +#include +#include + #include #include #include ==== //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 -__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_hal.c,v 1.28 2006/05/16 14:37:57 phk Exp $"); +__FBSDID("$FreeBSD$"); #include #include ==== //depot/projects/ndisusb/sys/compat/ndis/subr_ndis.c#2 (text+ko) ==== @@ -31,7 +31,7 @@ */ #include -__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 #include +#include +#include #include #include ==== //depot/projects/ndisusb/sys/compat/ndis/subr_ntoskrnl.c#2 (text+ko) ==== @@ -31,7 +31,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_ntoskrnl.c,v 1.94 2007/12/25 17:51:56 rwatson Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -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 -__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 -__FBSDID("$FreeBSD: src/sys/compat/ndis/subr_usbd.c,v 1.3 2005/05/05 03:56:09 wpaul Exp $"); +__FBSDID("$FreeBSD$"); #include #include @@ -45,10 +45,24 @@ #include #include #include +#include +#include #include #include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include "usbdevs.h" + #include #include #include @@ -56,18 +70,56 @@ #include #include #include +#include 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) <<<