From 5b0425c0dfab755c9ea253c8b2797c699d1a60e3 Mon Sep 17 00:00:00 2001 From: lepton-wu Date: Tue, 7 Jul 2009 09:19:47 +0000 Subject: [PATCH] For IRP with URB IoCompleteRequest must run at DISPATCH_LEVEL --- userspace/README | 6 +- userspace/busenum.c | 186 +++++++++++++++++++++++++------------- userspace/busenum.h | 12 ++- userspace/pnp.c | 52 +++++------ userspace/usbip.c | 2 + userspace/usbip_vbus_ui.c | 6 +- 6 files changed, 165 insertions(+), 99 deletions(-) diff --git a/userspace/README b/userspace/README index 290e15f9..d95366f6 100644 --- a/userspace/README +++ b/userspace/README @@ -1,6 +1,9 @@ Because I haven't implemented all the interfaces that a windows usb bus driver should provided, and perhaps some bug in my code, so some devices -won't work now. +won't work now. + +Because I don't know enough about PNP management in windows, one big problem +is that "stop device" is buggy now. USB devices I have tested ok for me: @@ -12,6 +15,7 @@ one dlink DWL-G122 usb wireless card usb camera on asus eeepc 701 model one usb microphone (only work with user space usbipd daemon) one usb sound card (only work with user space usbipd daemon) +one usb webcam (only work with user space usbipd daemon) To build userspace usbip tool: diff --git a/userspace/busenum.c b/userspace/busenum.c index 8ab54bfb..cfee907e 100755 --- a/userspace/busenum.c +++ b/userspace/busenum.c @@ -38,6 +38,7 @@ ULONG BusEnumDebugLevel = BUS_DEFAULT_DEBUG_OUTPUT_LEVEL; GLOBALS Globals; +NPAGED_LOOKASIDE_LIST g_lookaside; #ifdef ALLOC_PRAGMA #pragma alloc_text (INIT, DriverEntry) @@ -76,6 +77,9 @@ Return Value: Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Driver Entry \n")); + ExInitializeNPagedLookasideList(&g_lookaside, NULL,NULL,0, + sizeof(struct urb_req), 'USBV', 0); + // // Save the RegistryPath for WMI. // @@ -314,6 +318,10 @@ static void copy_iso_data(char *dest, int dest_len, KdPrint(("Warning, why this?")); break; } + if(offset+urb->IsoPacket[i].Length > src_len){ + KdPrint(("Warning, why that?")); + break; + } RtlCopyMemory(dest + urb->IsoPacket[i].Offset, src + offset, urb->IsoPacket[i].Length); offset+=urb->IsoPacket[i].Length; @@ -331,8 +339,8 @@ int process_write_irp(PPDO_DEVICE_DATA pdodata, PIRP irp) ULONG len; PIO_STACK_LOCATION irpstack; struct usbip_header *h; - PIRP ioctl_irp; - char *buf, *urb_buf; + PIRP ioctl_irp=NULL; + char *buf; int in, type, i; /* This is a quick hack, in windows, the offsets of all types of * TansferFlags and TransferBuffer and TransferBufferLength are the same, @@ -341,6 +349,7 @@ int process_write_irp(PPDO_DEVICE_DATA pdodata, PIRP irp) struct usbip_iso_packet_descriptor * ip_desc; NTSTATUS ioctl_status = STATUS_INVALID_PARAMETER; int found=0, iso_len=0, in_len=0; + struct urb_req * urb_r; irpstack = IoGetCurrentIrpStackLocation (irp); len = irpstack->Parameters.Write.Length; @@ -349,26 +358,31 @@ int process_write_irp(PPDO_DEVICE_DATA pdodata, PIRP irp) return STATUS_INVALID_PARAMETER; } h = irp->AssociatedIrp.SystemBuffer; - KeAcquireSpinLock(&pdodata->wait_q_lock, &oldirql); - for (le = pdodata->wait_q.Flink; - le != &pdodata->wait_q; + KeAcquireSpinLock(&pdodata->q_lock, &oldirql); + for (le = pdodata->ioctl_q.Flink; + le != &pdodata->ioctl_q; le = le->Flink) { - ioctl_irp = CONTAINING_RECORD (le, IRP, Tail.Overlay.ListEntry); - if(ioctl_irp->Tail.Overlay.DriverContext[0]==(PVOID)h->base.seqnum){ + urb_r = CONTAINING_RECORD (le, struct urb_req, list); + if(urb_r->seq_num == h->base.seqnum){ found=1; - RemoveEntryList (&ioctl_irp->Tail.Overlay.ListEntry); - InitializeListHead(&ioctl_irp->Tail.Overlay.ListEntry); + RemoveEntryList (le); + ioctl_irp = urb_r->irp; break; } } - KeReleaseSpinLock(&pdodata->wait_q_lock, oldirql); + KeReleaseSpinLock(&pdodata->q_lock, oldirql); if(!found){ KdPrint(("can't found %d\n", h->base.seqnum)); return STATUS_INVALID_PARAMETER; } irp->IoStatus.Information = len; irpstack = IoGetCurrentIrpStackLocation(ioctl_irp); - + if(!urb_r->send){ + KdPrint(("Warning, recv not send")); + ioctl_status = STATUS_INVALID_PARAMETER; + goto end; + } + ExFreeToNPagedLookasideList(&g_lookaside, urb_r); switch ( irpstack->Parameters.DeviceIoControl.IoControlCode ){ case IOCTL_INTERNAL_USB_SUBMIT_URB: break; @@ -474,7 +488,7 @@ int process_write_irp(PPDO_DEVICE_DATA pdodata, PIRP irp) else if (urb->TransferBufferMDL){ buf=MmGetSystemAddressForMdlSafe( urb->TransferBufferMDL, - LowPagePriority); + NormalPagePriority); } else KdPrint(("No transferbuffer fo in\n")); if(NULL==buf){ @@ -499,10 +513,16 @@ int process_write_irp(PPDO_DEVICE_DATA pdodata, PIRP irp) in?"in":"out", urb->TransferBufferLength, h->u.ret_submit.actual_length)); urb->TransferBufferLength = h->u.ret_submit.actual_length; - ioctl_status=STATUS_SUCCESS; + ioctl_status = STATUS_SUCCESS; end: ioctl_irp->IoStatus.Status = ioctl_status; + /* it seems windows client usb driver will think + * IoCompleteRequest is running at DISPATCH_LEVEL + * so without this it will change IRQL sometimes, + * and introduce to a dead of my userspace program */ + KeRaiseIrql(DISPATCH_LEVEL, &oldirql); IoCompleteRequest(ioctl_irp, IO_NO_INCREMENT); + KeLowerIrql(oldirql); return STATUS_SUCCESS; } @@ -518,6 +538,9 @@ Bus_Write ( PCOMMON_DEVICE_DATA commonData; PPDO_DEVICE_DATA pdodata; + + KdPrint(("why\n")); + PAGED_CODE (); KdPrint(("enter Write func\n")); @@ -1020,40 +1043,69 @@ int set_read_irp_data(PIRP read_irp, PIRP ioctl_irp, unsigned long seq_num, return STATUS_INVALID_PARAMETER; } -void add_wait_q(PPDO_DEVICE_DATA pdodata, PIRP Irp); - int process_read_irp(PPDO_DEVICE_DATA pdodata, PIRP read_irp) { NTSTATUS status = STATUS_PENDING; KIRQL oldirql; - PIRP ioctl_irp; - PLIST_ENTRY le = NULL; - unsigned long seq_num; + PIRP ioctl_irp = NULL; + struct urb_req *urb_r; + PLIST_ENTRY le; + unsigned long seq_num, old_seq_num; + int found=0; KeAcquireSpinLock(&pdodata->q_lock, &oldirql); - if (!IsListEmpty(&pdodata->ioctl_q)){ - seq_num=++(pdodata->seq_num); - le = RemoveHeadList(&pdodata->ioctl_q); - } else { - if(pdodata->pending_read_irp) - status = STATUS_INVALID_DEVICE_REQUEST; - else{ + for (le = pdodata->ioctl_q.Flink; + le !=&pdodata->ioctl_q; + le = le->Flink){ + urb_r = CONTAINING_RECORD(le, struct urb_req, list); + if(urb_r->send==0){ + ioctl_irp=urb_r->irp; + seq_num = ++(pdodata->seq_num); + urb_r->send=1; + old_seq_num = urb_r->seq_num; + urb_r->seq_num = seq_num; + break; + } + } + if(NULL==ioctl_irp){ + if(pdodata->pending_read_irp) + status = STATUS_INVALID_DEVICE_REQUEST; + else{ IoMarkIrpPending(read_irp); pdodata->pending_read_irp = read_irp; - } + } } KeReleaseSpinLock(&pdodata->q_lock, oldirql); - if(le){ - ioctl_irp = CONTAINING_RECORD(le, IRP, Tail.Overlay.ListEntry); - KdPrint(("get a ioctl_irp %p\n", ioctl_irp)); - ioctl_irp->Tail.Overlay.DriverContext[0]=(PVOID)seq_num; - status = set_read_irp_data(read_irp, ioctl_irp, seq_num, pdodata->devid); - if(status == STATUS_SUCCESS) - add_wait_q(pdodata, ioctl_irp); - else{ - ioctl_irp->IoStatus.Status = STATUS_INVALID_PARAMETER; - IoCompleteRequest (ioctl_irp, IO_NO_INCREMENT); - } + if(NULL==ioctl_irp) + return status; + if(old_seq_num) + KdPrint(("Error, why old_seq_num %d\n", old_seq_num)); + KdPrint(("get a ioctl_irp %p %d\n", ioctl_irp, seq_num)); + status = set_read_irp_data(read_irp, ioctl_irp, seq_num, pdodata->devid); + if(status == STATUS_SUCCESS) + return status; + /* set_read_irp failed, we must complete ioctl_irp */ + found=0; + KeAcquireSpinLock(&pdodata->q_lock, &oldirql); + for (le = pdodata->ioctl_q.Flink; + le !=&pdodata->ioctl_q; + le = le->Flink) { + urb_r = CONTAINING_RECORD(le, struct urb_req, list); + if(urb_r->seq_num == seq_num){ + found = 1; + RemoveEntryList(le); + break; + } } + KeReleaseSpinLock(&pdodata->q_lock, oldirql); + if(!found){ /* perhaps it complete by other */ + KdPrint(("Warning, we can't found irp we should release")); + return status; + } + ExFreeToNPagedLookasideList(&g_lookaside, urb_r); + if(urb_r->send!=1||urb_r->irp!=ioctl_irp) + KdPrint(("Warning, why it change")); + ioctl_irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest (ioctl_irp, IO_NO_INCREMENT); return status; } @@ -1074,6 +1126,8 @@ Bus_Read ( commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension; + KdPrint(("enter Read func\n")); + if (!commonData->IsFDO) { Irp->IoStatus.Status = status = STATUS_INVALID_DEVICE_REQUEST; IoCompleteRequest (Irp, IO_NO_INCREMENT); @@ -1104,6 +1158,7 @@ Bus_Read ( } status = process_read_irp(pdodata, Irp); END: + KdPrint(("Read return:0x%08x\n", status)); if(status != STATUS_PENDING){ Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); @@ -1400,6 +1455,13 @@ int post_select_interface(PPDO_DEVICE_DATA pdodata, return STATUS_SUCCESS; } +int proc_get_frame(PPDO_DEVICE_DATA pdodata, + struct _URB_GET_CURRENT_FRAME_NUMBER * req) +{ + req->FrameNumber = 0; + return STATUS_SUCCESS; +} + int proc_reset_pipe(PPDO_DEVICE_DATA pdodata, struct _URB_PIPE_REQUEST * req) { @@ -1525,6 +1587,8 @@ int proc_urb(PPDO_DEVICE_DATA pdodata, void *arg) return proc_select_config(pdodata, arg); case URB_FUNCTION_RESET_PIPE: return proc_reset_pipe(pdodata, arg); + case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER: + return proc_get_frame(pdodata, arg); case URB_FUNCTION_ISOCH_TRANSFER: /* show_iso_urb(arg); */ /* passthrough */ @@ -1549,46 +1613,46 @@ int proc_urb(PPDO_DEVICE_DATA pdodata, void *arg) return STATUS_INVALID_PARAMETER; } -void add_wait_q(PPDO_DEVICE_DATA pdodata, PIRP Irp) -{ - KIRQL oldirql; - - KeAcquireSpinLock(&pdodata->wait_q_lock, &oldirql); - InsertTailList(&pdodata->wait_q, &Irp->Tail.Overlay.ListEntry); - KeReleaseSpinLock(&pdodata->wait_q_lock, oldirql); - - return; -} - - - int try_addq(PPDO_DEVICE_DATA pdodata, PIRP Irp) { KIRQL oldirql; PIRP read_irp; - NTSTATUS status=STATUS_PENDING; + NTSTATUS status = STATUS_PENDING; unsigned long seq_num; + struct urb_req * urb_r; + urb_r = ExAllocateFromNPagedLookasideList(&g_lookaside); + if(NULL==urb_r) + return STATUS_INSUFFICIENT_RESOURCES; + RtlZeroMemory(urb_r, sizeof(*urb_r)); + urb_r->irp = Irp; KeAcquireSpinLock(&pdodata->q_lock, &oldirql); - read_irp=pdodata->pending_read_irp; + read_irp = pdodata->pending_read_irp; pdodata->pending_read_irp=NULL; if(NULL==read_irp){ IoMarkIrpPending(Irp); - InsertTailList(&pdodata->ioctl_q, &Irp->Tail.Overlay.ListEntry);\ + IoSetCancelRoutine(Irp, NULL); + InsertTailList(&pdodata->ioctl_q, &urb_r->list); } else seq_num = ++(pdodata->seq_num); KeReleaseSpinLock(&pdodata->q_lock, oldirql); if(NULL==read_irp) - return status; - + return STATUS_PENDING; read_irp->IoStatus.Status = set_read_irp_data(read_irp, Irp, seq_num, pdodata->devid); if(read_irp->IoStatus.Status == STATUS_SUCCESS){ - Irp->Tail.Overlay.DriverContext[0]=(PVOID)seq_num; - add_wait_q(pdodata, Irp); - } - else + KeAcquireSpinLock(&pdodata->q_lock, &oldirql); + IoMarkIrpPending(Irp); + urb_r->send = 1; + urb_r->seq_num = seq_num; + IoSetCancelRoutine(Irp, NULL); + InsertTailList(&pdodata->ioctl_q, &urb_r->list); + KeReleaseSpinLock(&pdodata->q_lock, oldirql); + } else { + ExFreeToNPagedLookasideList(&g_lookaside, urb_r); status = STATUS_INVALID_PARAMETER; + } + KdPrint(("finish read_irp seqnum %d\n", seq_num)); IoCompleteRequest(read_irp, IO_NO_INCREMENT); return status; } @@ -1606,8 +1670,6 @@ Bus_Internal_IoCtl ( PVOID buffer; PCOMMON_DEVICE_DATA commonData; - PAGED_CODE (); - commonData = (PCOMMON_DEVICE_DATA) DeviceObject->DeviceExtension; KdPrint(("Enter internal control %d\r\n", commonData->IsFDO)); @@ -1805,6 +1867,8 @@ Return Value: Bus_KdPrint_Def (BUS_DBG_SS_TRACE, ("Unload\n")); + ExDeleteNPagedLookasideList(&g_lookaside); + // // All the device objects should be gone. // diff --git a/userspace/busenum.h b/userspace/busenum.h index d3250032..e8c4232d 100755 --- a/userspace/busenum.h +++ b/userspace/busenum.h @@ -265,9 +265,7 @@ typedef struct _PDO_DEVICE_DATA ULONG InterfaceRefCount; PIRP pending_read_irp; LIST_ENTRY ioctl_q; - LIST_ENTRY wait_q; - KSPIN_LOCK q_lock; - KSPIN_LOCK wait_q_lock; + KSPIN_LOCK q_lock; PFILE_OBJECT fo; unsigned int devid; unsigned long seq_num; @@ -356,6 +354,14 @@ typedef struct _FDO_DEVICE_DATA TOASTER_BUS_WMI_STD_DATA StdToasterBusData; } FDO_DEVICE_DATA, *PFDO_DEVICE_DATA; +struct urb_req { + LIST_ENTRY list; + PIRP irp; + KEVENT *event; + unsigned long seq_num; + unsigned int send; +}; + #define FDO_FROM_PDO(pdoData) \ ((PFDO_DEVICE_DATA) (pdoData)->ParentFdo->DeviceExtension) diff --git a/userspace/pnp.c b/userspace/pnp.c index b515ad24..765a0178 100755 --- a/userspace/pnp.c +++ b/userspace/pnp.c @@ -1097,12 +1097,9 @@ bus_init_pdo ( pdodata->SystemPowerState = PowerSystemWorking; InitializeListHead(&pdodata->ioctl_q); - InitializeListHead(&pdodata->wait_q); KeInitializeSpinLock(&pdodata->q_lock); - KeInitializeSpinLock(&pdodata->wait_q_lock); - - pdo->Flags |= DO_POWER_PAGABLE; + pdo->Flags |= DO_POWER_PAGABLE|DO_DIRECT_IO; ExAcquireFastMutex (&fdodata->Mutex); InsertTailList(&fdodata->ListOfPDOs, &pdodata->Link); @@ -1284,10 +1281,14 @@ NTSTATUS bus_get_ports_status(ioctl_usbvbus_get_ports_status * st, return STATUS_SUCCESS; } + +extern NPAGED_LOOKASIDE_LIST g_lookaside; + void complete_pending_irp(PPDO_DEVICE_DATA pdodata) { KIRQL oldirql; PIRP irp; + struct urb_req * urb_r; PLIST_ENTRY le; //FIXME @@ -1295,37 +1296,28 @@ void complete_pending_irp(PPDO_DEVICE_DATA pdodata) irp=NULL; le=NULL; KeAcquireSpinLock(&pdodata->q_lock, &oldirql); - if (!IsListEmpty(&pdodata->ioctl_q)){ + if (!IsListEmpty(&pdodata->ioctl_q)) le = RemoveHeadList(&pdodata->ioctl_q); - if(pdodata->pending_read_irp){ - KdPrint(("waring, not null read_irp")); - } - } else { - irp=pdodata->pending_read_irp; - pdodata->pending_read_irp=NULL; - } + if(le){ + urb_r = CONTAINING_RECORD(le, struct urb_req, list); + /* FIMXE event */ + irp = urb_r->irp; + } + if(NULL==irp){ + irp=pdodata->pending_read_irp; + pdodata->pending_read_irp=NULL; + } KeReleaseSpinLock(&pdodata->q_lock, oldirql); - if(NULL==le&&NULL==irp) - break; if(le) - irp = CONTAINING_RECORD(le, IRP, Tail.Overlay.ListEntry); - irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE; - IoCompleteRequest (irp, IO_NO_INCREMENT); - }while(1); - - do { - le=NULL; - KeAcquireSpinLock(&pdodata->wait_q_lock, &oldirql); - if (!IsListEmpty(&pdodata->wait_q)){ - le = RemoveHeadList(&pdodata->wait_q); - } - KeReleaseSpinLock(&pdodata->wait_q_lock, oldirql); - if(NULL==le) + ExFreeToNPagedLookasideList(&g_lookaside, urb_r); + if(NULL==irp) break; - if(le) - irp = CONTAINING_RECORD(le, IRP, Tail.Overlay.ListEntry); irp->IoStatus.Status = STATUS_DEVICE_OFF_LINE; - IoCompleteRequest (irp, IO_NO_INCREMENT); + if(le) + KeRaiseIrql(DISPATCH_LEVEL, &oldirql); + IoCompleteRequest (irp, IO_NO_INCREMENT); + if(le) + KeLowerIrql(oldirql); }while(1); } diff --git a/userspace/usbip.c b/userspace/usbip.c index 1cb87060..217e4baa 100755 --- a/userspace/usbip.c +++ b/userspace/usbip.c @@ -311,6 +311,8 @@ static void attach_device(char * host, char * busid) } info("new usb device attached to usbvbus port %d\n", rhport); usbip_vbus_forward(sockfd, devfd); + closesocket(sockfd); + CloseHandle(devfd); return; } diff --git a/userspace/usbip_vbus_ui.c b/userspace/usbip_vbus_ui.c index 369f0243..abf56eac 100644 --- a/userspace/usbip_vbus_ui.c +++ b/userspace/usbip_vbus_ui.c @@ -544,13 +544,11 @@ void usbip_vbus_forward(SOCKET sockfd, HANDLE devfd) switch (ret){ case WAIT_OBJECT_0: - ret = dev_read_completed(devfd, sockfd, &ov[0]); - if(ret) + if(dev_read_completed(devfd, sockfd, &ov[0])) return; break; case WAIT_OBJECT_0 + 1: - ret = sock_read_completed(sockfd, devfd, &ov[1], &ov[2]); - if(ret) + if(sock_read_completed(sockfd, devfd, &ov[1], &ov[2])) return; break; default: