static VOID XenBus_EvtFileCleanup(WDFFILEOBJECT file_object) { PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfFileObjectGetDevice(file_object)); watch_context_t *watch_context; KIRQL old_irql; PCHAR msg; FUNCTION_ENTER(); KeAcquireSpinLock(&xpdid->lock, &old_irql); while (!IsListEmpty(&xpdid->xenbus.watch_list_head)) { watch_context = (watch_context_t *)RemoveHeadList(&xpdid->xenbus.watch_list_head); KeReleaseSpinLock(&xpdid->lock, old_irql); msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_context->path, XenPci_IoWatch, watch_context); if (msg != NULL) { KdPrint((__DRIVER_NAME " Error freeing watch (%s)\n", msg)); XenPci_FreeMem(msg); } ExFreePoolWithTag(watch_context, XENPCI_POOL_TAG); WdfObjectDereference(file_object); KeAcquireSpinLock(&xpdid->lock, &old_irql); } KeReleaseSpinLock(&xpdid->lock, old_irql); FUNCTION_EXIT(); }
NTSTATUS XenPciPdo_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) { NTSTATUS status = STATUS_SUCCESS; PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device); PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo); char path[128]; UNREFERENCED_PARAMETER(device); UNREFERENCED_PARAMETER(target_state); FUNCTION_ENTER(); FUNCTION_MSG("path = %s\n", xppdd->path); switch (target_state) { case WdfPowerDeviceD0: FUNCTION_MSG("WdfPowerDeviceD1\n"); break; case WdfPowerDeviceD1: FUNCTION_MSG("WdfPowerDeviceD1\n"); break; case WdfPowerDeviceD2: FUNCTION_MSG("WdfPowerDeviceD2\n"); break; case WdfPowerDeviceD3: FUNCTION_MSG("WdfPowerDeviceD3\n"); if (xppdd->hiber_usage_kludge) { FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n"); target_state = WdfPowerDevicePrepareForHibernation; } break; case WdfPowerDeviceD3Final: FUNCTION_MSG("WdfPowerDeviceD3Final\n"); break; case WdfPowerDevicePrepareForHibernation: FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n"); break; default: FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", target_state); break; } if (target_state == WdfPowerDevicePrepareForHibernation) { FUNCTION_MSG("not powering down as we are hibernating\n"); // should we set the backend state here so it's correct on resume??? } /* Remove watch on backend state */ /* even if hibernate */ if (xppdd->device_callback) { FUNCTION_MSG("Removing watch %s\n", xppdd->device); RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path); XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd); } FUNCTION_EXIT(); return status; }
/* Called at PASSIVE_LEVEL(?) Called during restore */ static ULONG XenPci_ReadBackendState(PXENPCI_PDO_DEVICE_DATA xppdd) { PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo); char path[128]; char *value; char *err; ULONG backend_state; RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path); err = XenBus_Read(xpdd, XBT_NIL, path, &value); if (err) { XenPci_FreeMem(err); return XenbusStateUnknown; } else { backend_state = atoi(value); XenPci_FreeMem(value); return backend_state; } }
static VOID XenPci_EvtDevicePnpStateChange(WDFDEVICE device, PCWDF_DEVICE_PNP_NOTIFICATION_DATA notification_data) { PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device); //FUNCTION_ENTER(); if (xppdd->backend_initiated_remove && notification_data->Type == StateNotificationEnterState && notification_data->Data.EnterState.CurrentState == WdfDevStatePnpQueryRemovePending && notification_data->Data.EnterState.NewState == WdfDevStatePnpQueryCanceled) { PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo); FUNCTION_MSG("Eject failed, doing surprise removal\n"); xppdd->do_not_enumerate = TRUE; XenPci_EvtChildListScanForChildren(xpdd->child_list); } //FUNCTION_EXIT(); //return STATUS_SUCCESS; }
static NTSTATUS XenPci_GetBackendDetails(WDFDEVICE device) { PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device); PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo); char path[128]; PCHAR res; PCHAR value; FUNCTION_ENTER(); /* Get backend path */ RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/backend", xppdd->path); res = XenBus_Read(xpdd, XBT_NIL, path, &value); if (res) { FUNCTION_MSG("Failed to read backend path\n"); XenPci_FreeMem(res); return STATUS_UNSUCCESSFUL; } RtlStringCbCopyA(xppdd->backend_path, ARRAY_SIZE(xppdd->backend_path), value); XenPci_FreeMem(value); /* Get backend id */ RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/backend-id", xppdd->path); res = XenBus_Read(xpdd, XBT_NIL, path, &value); if (res) { FUNCTION_MSG("Failed to read backend id\n"); XenPci_FreeMem(res); return STATUS_UNSUCCESSFUL; } xppdd->backend_id = (domid_t)atoi(value); XenPci_FreeMem(value); FUNCTION_EXIT(); return STATUS_SUCCESS; }
static VOID XenBus_EvtIoWrite(WDFQUEUE queue, WDFREQUEST request, size_t length) { NTSTATUS status; PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfIoQueueGetDevice(queue)); WDFFILEOBJECT file_object = WdfRequestGetFileObject(request); PXENPCI_DEVICE_INTERFACE_DATA xpdid = GetXpdid(file_object); KIRQL old_irql; WDFREQUEST read_request; PUCHAR buffer; PUCHAR src_ptr; ULONG src_len; PUCHAR dst_ptr; ULONG copy_len; struct xsd_sockmsg *rep; xenbus_read_queue_item_t *list_entry; watch_context_t *watch_context; PCHAR watch_path; PCHAR watch_token; PCHAR msg; FUNCTION_ENTER(); status = WdfRequestRetrieveInputBuffer(request, length, &buffer, NULL); ASSERT(NT_SUCCESS(status)); src_ptr = (PUCHAR)buffer; src_len = (ULONG)length; dst_ptr = xpdid->xenbus.u.buffer + xpdid->xenbus.len; while (src_len != 0) { KdPrint((__DRIVER_NAME " %d bytes of write buffer remaining\n", src_len)); /* get a complete msg header */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg)) { copy_len = min(sizeof(xpdid->xenbus.u.msg) - xpdid->xenbus.len, src_len); if (!copy_len) continue; memcpy(dst_ptr, src_ptr, copy_len); dst_ptr += copy_len; src_ptr += copy_len; src_len -= copy_len; xpdid->xenbus.len += copy_len; } /* exit if we can't get that */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg)) continue; /* get a complete msg body */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len) { copy_len = min(sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len - xpdid->xenbus.len, src_len); if (!copy_len) continue; memcpy(dst_ptr, src_ptr, copy_len); dst_ptr += copy_len; src_ptr += copy_len; src_len -= copy_len; xpdid->xenbus.len += copy_len; } /* exit if we can't get that */ if (xpdid->xenbus.len < sizeof(xpdid->xenbus.u.msg) + xpdid->xenbus.u.msg.len) { continue; } switch (xpdid->xenbus.u.msg.type) { case XS_WATCH: case XS_UNWATCH: KeAcquireSpinLock(&xpdid->lock, &old_irql); watch_context = (watch_context_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(watch_context_t), XENPCI_POOL_TAG); watch_path = (PCHAR)(xpdid->xenbus.u.buffer + sizeof(struct xsd_sockmsg)); watch_token = (PCHAR)(xpdid->xenbus.u.buffer + sizeof(struct xsd_sockmsg) + strlen(watch_path) + 1); RtlStringCbCopyA(watch_context->path, ARRAY_SIZE(watch_context->path), watch_path); RtlStringCbCopyA(watch_context->token, ARRAY_SIZE(watch_context->path), watch_token); watch_context->file_object = file_object; if (xpdid->xenbus.u.msg.type == XS_WATCH) InsertTailList(&xpdid->xenbus.watch_list_head, &watch_context->entry); KeReleaseSpinLock(&xpdid->lock, old_irql); if (xpdid->xenbus.u.msg.type == XS_WATCH) msg = XenBus_AddWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context); else msg = XenBus_RemWatch(xpdd, XBT_NIL, watch_path, XenPci_IoWatch, watch_context); KeAcquireSpinLock(&xpdid->lock, &old_irql); if (msg != NULL) { rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg) + strlen(msg) + 1, XENPCI_POOL_TAG); rep->type = XS_ERROR; rep->req_id = xpdid->xenbus.u.msg.req_id; rep->tx_id = xpdid->xenbus.u.msg.tx_id; rep->len = (ULONG)(strlen(msg) + 0); RtlStringCbCopyA((PCHAR)(rep + 1), strlen(msg) + 1, msg); if (xpdid->xenbus.u.msg.type == XS_WATCH) RemoveEntryList(&watch_context->entry); } else { if (xpdid->xenbus.u.msg.type == XS_WATCH) { WdfObjectReference(file_object); } else { RemoveEntryList(&watch_context->entry); WdfObjectDereference(file_object); } rep = ExAllocatePoolWithTag(NonPagedPool, sizeof(struct xsd_sockmsg), XENPCI_POOL_TAG); rep->type = xpdid->xenbus.u.msg.type; rep->req_id = xpdid->xenbus.u.msg.req_id; rep->tx_id = xpdid->xenbus.u.msg.tx_id; rep->len = 0; } KeReleaseSpinLock(&xpdid->lock, old_irql); break; default: rep = XenBus_Raw(xpdd, &xpdid->xenbus.u.msg); break; } xpdid->xenbus.len = 0; KeAcquireSpinLock(&xpdid->lock, &old_irql); list_entry = (xenbus_read_queue_item_t *)ExAllocatePoolWithTag(NonPagedPool, sizeof(xenbus_read_queue_item_t), XENPCI_POOL_TAG); list_entry->data = rep; list_entry->length = sizeof(*rep) + rep->len; list_entry->offset = 0; InsertTailList(&xpdid->xenbus.read_list_head, (PLIST_ENTRY)list_entry); // Check if someone was waiting for the answer already status = WdfIoQueueRetrieveNextRequest(xpdid->xenbus.io_queue, &read_request); if (NT_SUCCESS(status)) { WDF_REQUEST_PARAMETERS parameters; KdPrint((__DRIVER_NAME " post-write: found pending read\n")); WDF_REQUEST_PARAMETERS_INIT(¶meters); WdfRequestGetParameters(read_request, ¶meters); XenBus_ProcessReadRequest(xpdid->xenbus.io_queue, read_request, parameters.Parameters.Read.Length); WdfRequestComplete(read_request, STATUS_SUCCESS); } else { KdPrint((__DRIVER_NAME " post-write: no pending read (%08x)\n", status)); } KeReleaseSpinLock(&xpdid->lock, old_irql); } KdPrint((__DRIVER_NAME " completing request with length %d\n", length)); WdfRequestCompleteWithInformation(request, STATUS_SUCCESS, length); FUNCTION_EXIT(); }
NTSTATUS XenPci_EvtChildListCreateDevice(WDFCHILDLIST child_list, PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER identification_header, PWDFDEVICE_INIT child_init) { NTSTATUS status = STATUS_SUCCESS; WDF_OBJECT_ATTRIBUTES child_attributes; WDFDEVICE child_device; PXENPCI_PDO_IDENTIFICATION_DESCRIPTION identification = (PXENPCI_PDO_IDENTIFICATION_DESCRIPTION)identification_header; WDF_DEVICE_PNP_CAPABILITIES child_pnp_capabilities; DECLARE_UNICODE_STRING_SIZE(buffer, 512); DECLARE_CONST_UNICODE_STRING(location, L"Xen Bus"); PXENPCI_PDO_DEVICE_DATA xppdd; PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list)); //WDF_PDO_EVENT_CALLBACKS pdo_callbacks; WDF_PNPPOWER_EVENT_CALLBACKS child_pnp_power_callbacks; //UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE }; WDF_DEVICE_POWER_CAPABILITIES child_power_capabilities; FUNCTION_ENTER(); WdfDeviceInitSetDeviceType(child_init, FILE_DEVICE_UNKNOWN); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&child_pnp_power_callbacks); child_pnp_power_callbacks.EvtDeviceD0Entry = XenPciPdo_EvtDeviceD0Entry; child_pnp_power_callbacks.EvtDeviceD0Exit = XenPciPdo_EvtDeviceD0Exit; child_pnp_power_callbacks.EvtDeviceUsageNotification = XenPciPdo_EvtDeviceUsageNotification; WdfDeviceInitSetPnpPowerEventCallbacks(child_init, &child_pnp_power_callbacks); FUNCTION_MSG("device = '%s', index = '%d', path = '%s'\n", identification->device, identification->index, identification->path); //status = WdfDeviceInitAssignWdmIrpPreprocessCallback(child_init, XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE, // IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions)); //if (!NT_SUCCESS(status)) { // return status; //} //WDF_PDO_EVENT_CALLBACKS_INIT(&pdo_callbacks); //pdo_callbacks.EvtDeviceResourcesQuery = XenPciPdo_EvtDeviceResourcesQuery; //pdo_callbacks.EvtDeviceResourceRequirementsQuery = XenPciPdo_EvtDeviceResourceRequirementsQuery; //pdo_callbacks.EvtDeviceEject = XenPciPdo_EvtDeviceEject; //pdo_callbacks.EvtDeviceSetLock = XenPciPdo_EvtDeviceSetLock; //WdfPdoInitSetEventCallbacks(child_init, &pdo_callbacks); RtlUnicodeStringPrintf(&buffer, L"xen\\%S", identification->device); status = WdfPdoInitAssignDeviceID(child_init, &buffer); if (!NT_SUCCESS(status)) { return status; } status = WdfPdoInitAddHardwareID(child_init, &buffer); if (!NT_SUCCESS(status)) { return status; } status = WdfPdoInitAddCompatibleID(child_init, &buffer); if (!NT_SUCCESS(status)) { return status; } RtlUnicodeStringPrintf(&buffer, L"%02d", identification->index); status = WdfPdoInitAssignInstanceID(child_init, &buffer); if (!NT_SUCCESS(status)) { return status; } RtlUnicodeStringPrintf(&buffer, L"Xen %S device #%d", identification->device, identification->index); status = WdfPdoInitAddDeviceText(child_init, &buffer, &location, 0x0409); if (!NT_SUCCESS(status)) { return status; } WdfPdoInitSetDefaultLocale(child_init, 0x0409); WdfDeviceInitSetPowerNotPageable(child_init); WdfDeviceInitRegisterPnpStateChangeCallback(child_init, WdfDevStatePnpQueryCanceled, XenPci_EvtDevicePnpStateChange, StateNotificationEnterState); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&child_attributes, XENPCI_PDO_DEVICE_DATA); status = WdfDeviceCreate(&child_init, &child_attributes, &child_device); if (!NT_SUCCESS(status)) { return status; } xppdd = GetXppdd(child_device); xppdd->wdf_device = child_device; xppdd->wdf_device_bus_fdo = WdfChildListGetDevice(child_list); xppdd->xpdd = xpdd; WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFilePaging, TRUE); WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileHibernation, TRUE); WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileDump, TRUE); WDF_DEVICE_PNP_CAPABILITIES_INIT(&child_pnp_capabilities); child_pnp_capabilities.LockSupported = WdfFalse; child_pnp_capabilities.EjectSupported = WdfTrue; child_pnp_capabilities.Removable = WdfTrue; child_pnp_capabilities.DockDevice = WdfFalse; child_pnp_capabilities.UniqueID = WdfFalse; child_pnp_capabilities.SilentInstall = WdfTrue; child_pnp_capabilities.SurpriseRemovalOK = WdfTrue; child_pnp_capabilities.HardwareDisabled = WdfFalse; WdfDeviceSetPnpCapabilities(child_device, &child_pnp_capabilities); WDF_DEVICE_POWER_CAPABILITIES_INIT(&child_power_capabilities); child_power_capabilities.DeviceD1 = WdfTrue; child_power_capabilities.WakeFromD1 = WdfTrue; child_power_capabilities.DeviceWake = PowerDeviceD1; child_power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0; child_power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1; child_power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2; child_power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2; child_power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3; child_power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3; WdfDeviceSetPowerCapabilities(child_device, &child_power_capabilities); RtlStringCbCopyA(xppdd->path, ARRAY_SIZE(xppdd->path), identification->path); RtlStringCbCopyA(xppdd->device, ARRAY_SIZE(xppdd->device), identification->device); xppdd->index = identification->index; KeInitializeEvent(&xppdd->backend_state_event, SynchronizationEvent, FALSE); ExInitializeFastMutex(&xppdd->backend_state_mutex); xppdd->backend_state = XenbusStateUnknown; xppdd->frontend_state = XenbusStateUnknown; xppdd->backend_path[0] = '\0'; xppdd->backend_id = 0; FUNCTION_EXIT(); return status; }
NTSTATUS XenPciPdo_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state) { NTSTATUS status = STATUS_SUCCESS; PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device); PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo); CHAR path[128]; FUNCTION_ENTER(); FUNCTION_MSG("path = %s\n", xppdd->path); switch (previous_state) { case WdfPowerDeviceD0: FUNCTION_MSG("WdfPowerDeviceD1\n"); break; case WdfPowerDeviceD1: FUNCTION_MSG("WdfPowerDeviceD1\n"); break; case WdfPowerDeviceD2: FUNCTION_MSG("WdfPowerDeviceD2\n"); break; case WdfPowerDeviceD3: FUNCTION_MSG("WdfPowerDeviceD3\n"); if (xppdd->hiber_usage_kludge) { FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n"); previous_state = WdfPowerDevicePrepareForHibernation; } break; case WdfPowerDeviceD3Final: FUNCTION_MSG("WdfPowerDeviceD3Final\n"); break; case WdfPowerDevicePrepareForHibernation: FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n"); break; default: FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", previous_state); break; } status = XenPci_GetBackendDetails(device); if (!NT_SUCCESS(status)) { WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart); FUNCTION_EXIT_STATUS(status); return status; } if (previous_state == WdfPowerDevicePrepareForHibernation && xppdd->device_callback) { FUNCTION_MSG("Restoring watch %s\n", xppdd->device); RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path); XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd); } if (!NT_SUCCESS(status)) { RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path); //XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device); WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart); FUNCTION_EXIT_STATUS(status); return status; } FUNCTION_EXIT(); return status; }