+ case IOCTL_KMTEST_USERMODE_AWAIT_REQ:
+ {
+ PLIST_ENTRY Entry;
+ PKMT_USER_WORK_ENTRY WorkItem;
+
+ DPRINT("DriverIoControl. IOCTL_KMTEST_USERMODE_AWAIT_REQ, len=%lu\n",
+ IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
+
+ /* TODO: prevent multiple concurrent invocations */
+ Status = KeWaitForSingleObject(&WorkList.NewWorkEvent, UserRequest, UserMode, FALSE, NULL);
+ if (Status == STATUS_USER_APC || Status == STATUS_KERNEL_APC)
+ break;
+
+ if (IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength < sizeof(KMT_CALLBACK_REQUEST_PACKET))
+ {
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ break;
+ }
+
+ ASSERT(!IsListEmpty(&WorkList.ListHead));
+
+ Entry = WorkList.ListHead.Flink;
+ WorkItem = CONTAINING_RECORD(Entry, KMT_USER_WORK_ENTRY, ListEntry);
+
+ Length = sizeof(WorkItem->Request);
+ RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &WorkItem->Request, Length);
+ Status = STATUS_SUCCESS;
+
+ KeResetEvent(&WorkList.NewWorkEvent);
+ break;
+
+ }
+ case IOCTL_KMTEST_USERMODE_SEND_RESPONSE:
+ {
+ PLIST_ENTRY Entry;
+ PKMT_USER_WORK_ENTRY WorkEntry;
+ PVOID Response;
+ ULONG ResponseSize = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength;
+
+ DPRINT("DriverIoControl. IOCTL_KMTEST_USERMODE_SEND_RESPONSE, inlen=%lu, outlen=%lu\n",
+ IoStackLocation->Parameters.DeviceIoControl.InputBufferLength,
+ IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength);
+
+ if (IoStackLocation->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG) || ResponseSize != sizeof(KMT_RESPONSE))
+ {
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ break;
+ }
+
+ /* FIXME: don't misuse the output buffer as an input! */
+ Response = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
+ if (Response == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ ExAcquireFastMutex(&WorkList.Lock);
+
+ Status = STATUS_OBJECTID_NOT_FOUND;
+
+ Entry = WorkList.ListHead.Flink;
+ while (Entry != &WorkList.ListHead)
+ {
+ WorkEntry = CONTAINING_RECORD(Entry, KMT_USER_WORK_ENTRY, ListEntry);
+ if (WorkEntry->Request.RequestId == *(PULONG)Irp->AssociatedIrp.SystemBuffer)
+ {
+ WorkEntry->Response = ExAllocatePoolWithTag(PagedPool, sizeof(KMT_RESPONSE), 'pseR');
+ if (WorkEntry->Response == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ RtlCopyMemory(WorkEntry->Response, Response, ResponseSize);
+ KeSetEvent(&WorkEntry->WorkDoneEvent, IO_NO_INCREMENT, FALSE);
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ Entry = Entry->Flink;
+ }
+
+ ExReleaseFastMutex(&WorkList.Lock);
+
+ break;
+ }