win-pvdrivers

annotate xenvbd_filter/xenvbd_filter.c @ 1027:0f40ce5cb467

Fix hibernate in scsiport
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 20:57:09 2013 +1100 (2013-02-19)
parents aa2e51f67f7c
children b448f01b31e8
rev   line source
james@1005 1 /*
james@1005 2 PV Drivers for Windows Xen HVM Domains
james@1005 3 Copyright (C) 2013 James Harper
james@1005 4
james@1005 5 This program is free software; you can redistribute it and/or
james@1005 6 modify it under the terms of the GNU General Public License
james@1005 7 as published by the Free Software Foundation; either version 2
james@1005 8 of the License, or (at your option) any later version.
james@1005 9
james@1005 10 This program is distributed in the hope that it will be useful,
james@1005 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
james@1005 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
james@1005 13 GNU General Public License for more details.
james@1005 14
james@1005 15 You should have received a copy of the GNU General Public License
james@1005 16 along with this program; if not, write to the Free Software
james@1005 17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
james@1005 18 */
james@1005 19
james@1005 20 #include "xenvbd_filter.h"
james@1005 21 #include "ntddscsi.h"
james@1005 22 #include "srb.h"
james@1005 23
james@1005 24 DRIVER_INITIALIZE DriverEntry;
james@1005 25
james@1005 26 static EVT_WDF_DRIVER_UNLOAD XenVbd_EvtDriverUnload;
james@1005 27 static EVT_WDF_DRIVER_DEVICE_ADD XenVbd_EvtDeviceAdd;
james@1025 28 static EVT_WDF_REQUEST_COMPLETION_ROUTINE XenVbd_SendRequestComplete;
james@1025 29 static EVT_WDF_DEVICE_D0_ENTRY XenVbd_EvtDeviceD0Entry;
james@1025 30 static EVT_WDF_DEVICE_D0_EXIT XenVbd_EvtDeviceD0Exit;
james@1025 31 static EVT_WDFDEVICE_WDM_IRP_PREPROCESS XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE;
james@1027 32 static EVT_WDFDEVICE_WDM_IRP_PREPROCESS XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER;
james@1025 33 static EVT_WDF_DPC XenVbd_EvtDpcEvent;
james@1025 34 static IO_COMPLETION_ROUTINE XenVbd_IoCompletion_START_DEVICE;
james@1005 35
james@1005 36 static VOID XenVbd_DeviceCallback(PVOID context, ULONG callback_type, PVOID value);
james@1005 37 static VOID XenVbd_HandleEventDIRQL(PVOID context);
james@1005 38 static VOID XenVbd_StopRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend);
james@1005 39 static VOID XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend);
james@1005 40
james@1005 41 #include "../xenvbd_common/common_xen.h"
james@1005 42
james@1008 43 static VOID XenVbd_SendEvent(WDFDEVICE device);
james@1008 44
james@1005 45 static VOID
james@1005 46 XenVbd_StopRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
james@1005 47 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
james@1005 48 NTSTATUS status;
james@1005 49 WDFREQUEST request;
james@1005 50 WDF_REQUEST_SEND_OPTIONS send_options;
james@1005 51 IO_STACK_LOCATION stack;
james@1005 52 SCSI_REQUEST_BLOCK srb;
james@1005 53 SRB_IO_CONTROL sic;
james@1005 54
james@1005 55 FUNCTION_ENTER();
james@1005 56
james@1005 57 /* send a 'stop' down if we are suspending */
james@1005 58 if (suspend) {
james@1005 59 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
james@1005 60 FUNCTION_MSG("WdfRequestCreate = %08x\n", status);
james@1005 61
james@1005 62 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
james@1005 63 stack.MajorFunction = IRP_MJ_SCSI;
james@1008 64 stack.MinorFunction = IRP_MN_SCSI_CLASS;
james@1005 65 stack.Parameters.Scsi.Srb = &srb;
james@1005 66
james@1005 67 RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
james@1005 68 srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
james@1005 69 srb.Length = SCSI_REQUEST_BLOCK_SIZE;
james@1005 70 srb.PathId = 0;
james@1005 71 srb.TargetId = 0;
james@1005 72 srb.Lun = 0;
james@1005 73 srb.OriginalRequest = WdfRequestWdmGetIrp(request);
james@1005 74 srb.Function = SRB_FUNCTION_IO_CONTROL;
james@1005 75 srb.DataBuffer = &sic;
james@1005 76
james@1005 77 RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL));
james@1005 78 sic.HeaderLength = sizeof(SRB_IO_CONTROL);
james@1005 79 memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8);
james@1005 80 sic.Timeout = 60;
james@1005 81 sic.ControlCode = XENVBD_CONTROL_STOP;
james@1005 82
james@1005 83 WdfRequestWdmFormatUsingStackLocation(request, &stack);
james@1005 84
james@1005 85 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
james@1005 86 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
james@1005 87 FUNCTION_MSG("Request was _NOT_ sent\n");
james@1005 88 }
james@1005 89 status = WdfRequestGetStatus(request);
james@1005 90 FUNCTION_MSG("Request Status = %08x\n", status);
james@1005 91 FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
james@1005 92
james@1005 93 WdfObjectDelete(request);
james@1005 94 }
james@1005 95
james@1005 96 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateClosing);
james@1005 97
james@1005 98 FUNCTION_EXIT();
james@1005 99 }
james@1005 100
james@1005 101 static VOID
james@1005 102 XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
james@1005 103 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
james@1005 104 NTSTATUS status;
james@1005 105 WDFREQUEST request;
james@1005 106 WDF_REQUEST_SEND_OPTIONS send_options;
james@1005 107 IO_STACK_LOCATION stack;
james@1005 108 SCSI_REQUEST_BLOCK srb;
james@1005 109 SRB_IO_CONTROL sic;
james@1005 110
james@1005 111 FUNCTION_ENTER();
james@1005 112
james@1005 113 /* send a 'start' down if we are resuming from a suspend */
james@1005 114 if (suspend) {
james@1005 115 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
james@1005 116 FUNCTION_MSG("WdfRequestCreate = %08x\n", status);
james@1005 117
james@1005 118 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
james@1005 119 stack.MajorFunction = IRP_MJ_SCSI;
james@1005 120 stack.Parameters.Scsi.Srb = &srb;
james@1005 121
james@1005 122 RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
james@1005 123 srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
james@1005 124 srb.Length = SCSI_REQUEST_BLOCK_SIZE;
james@1005 125 srb.PathId = 0;
james@1005 126 srb.TargetId = 0;
james@1005 127 srb.Lun = 0;
james@1005 128 srb.OriginalRequest = WdfRequestWdmGetIrp(request);
james@1005 129 srb.Function = SRB_FUNCTION_IO_CONTROL;
james@1005 130 srb.DataBuffer = &sic;
james@1005 131
james@1005 132 RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL));
james@1005 133 sic.HeaderLength = sizeof(SRB_IO_CONTROL);
james@1005 134 memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8);
james@1005 135 sic.Timeout = 60;
james@1005 136 sic.ControlCode = XENVBD_CONTROL_START;
james@1005 137
james@1005 138 WdfRequestWdmFormatUsingStackLocation(request, &stack);
james@1005 139
james@1005 140 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
james@1005 141 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
james@1005 142 FUNCTION_MSG("Request was _NOT_ sent\n");
james@1005 143 }
james@1005 144 status = WdfRequestGetStatus(request);
james@1005 145 FUNCTION_MSG("Request Status = %08x\n", status);
james@1005 146 FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
james@1005 147
james@1005 148 WdfObjectDelete(request);
james@1005 149 }
james@1005 150
james@1005 151 FUNCTION_EXIT();
james@1005 152 }
james@1005 153
james@1005 154 static VOID
james@1008 155 XenVbd_SendRequestComplete(WDFREQUEST request, WDFIOTARGET target, PWDF_REQUEST_COMPLETION_PARAMS params, WDFCONTEXT context) {
james@1005 156 NTSTATUS status;
james@1005 157 PSCSI_REQUEST_BLOCK srb = context;
james@1005 158
james@1005 159 UNREFERENCED_PARAMETER(target);
james@1005 160 UNREFERENCED_PARAMETER(params);
james@1005 161 UNREFERENCED_PARAMETER(context);
james@1008 162
james@1005 163 status = WdfRequestGetStatus(request);
james@1008 164 if (status != 0 || srb->SrbStatus != SRB_STATUS_SUCCESS) {
james@1008 165 FUNCTION_MSG("Request Status = %08x, SRB Status = %08x\n", status, srb->SrbStatus);
james@1005 166 }
james@1005 167 ExFreePoolWithTag(context, XENVBD_POOL_TAG);
james@1005 168 WdfObjectDelete(request);
james@1005 169 }
james@1005 170
james@1005 171 static VOID
james@1008 172 XenVbd_SendEvent(WDFDEVICE device) {
james@1005 173 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
james@1005 174 NTSTATUS status;
james@1005 175 WDFREQUEST request;
james@1005 176 WDF_REQUEST_SEND_OPTIONS send_options;
james@1005 177 IO_STACK_LOCATION stack;
james@1005 178 PUCHAR buf;
james@1005 179 PSCSI_REQUEST_BLOCK srb;
james@1005 180 PSRB_IO_CONTROL sic;
james@1008 181
james@1005 182 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
james@1025 183 if (status != STATUS_SUCCESS) {
james@1025 184 /* this is bad - event will be dropped */
james@1025 185 return;
james@1025 186 }
james@1005 187
james@1008 188 buf = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL), XENVBD_POOL_TAG);
james@1008 189 RtlZeroMemory(buf, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL));
james@1005 190 srb = (PSCSI_REQUEST_BLOCK)(buf);
james@1005 191 sic = (PSRB_IO_CONTROL)(buf + sizeof(SCSI_REQUEST_BLOCK));
james@1005 192
james@1005 193 srb->Length = sizeof(SCSI_REQUEST_BLOCK);
james@1005 194 srb->SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
james@1005 195 srb->PathId = 0;
james@1005 196 srb->TargetId = 0;
james@1005 197 srb->Lun = 0;
james@1005 198 srb->OriginalRequest = WdfRequestWdmGetIrp(request);
james@1005 199 srb->Function = SRB_FUNCTION_IO_CONTROL;
james@1005 200 srb->DataBuffer = sic;
james@1008 201 srb->DataTransferLength = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL);
james@1008 202 srb->TimeOutValue = (ULONG)-1;
james@1005 203
james@1008 204 sic->HeaderLength = sizeof(SRB_IO_CONTROL);
james@1008 205 memcpy(sic->Signature, XENVBD_CONTROL_SIG, 8);
james@1008 206 sic->Timeout = (ULONG)-1;
james@1008 207 sic->ControlCode = XENVBD_CONTROL_EVENT;
james@1008 208
james@1005 209 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
james@1005 210 stack.MajorFunction = IRP_MJ_SCSI;
james@1008 211 stack.MinorFunction = IRP_MN_SCSI_CLASS;
james@1005 212 stack.Parameters.Scsi.Srb = srb;
james@1005 213
james@1005 214 WdfRequestWdmFormatUsingStackLocation(request, &stack);
james@1008 215 WdfRequestSetCompletionRoutine(request, XenVbd_SendRequestComplete, buf);
james@1005 216
james@1008 217 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, 0); //WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
james@1005 218 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
james@1008 219 FUNCTION_MSG("Error sending request\n");
james@1005 220 }
james@1005 221 }
james@1005 222
james@1005 223 static VOID
james@1008 224 XenVbd_EvtDpcEvent(WDFDPC dpc) {
james@1008 225 WDFDEVICE device = WdfDpcGetParentObject(dpc);
james@1008 226
james@1008 227 XenVbd_SendEvent(device);
james@1008 228 }
james@1008 229
james@1008 230 static VOID
james@1005 231 XenVbd_HandleEventDIRQL(PVOID context) {
james@1005 232 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)context;
james@1005 233 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
james@1005 234 WdfDpcEnqueue(xvfd->dpc);
james@1005 235 }
james@1005 236
james@1005 237 static NTSTATUS
james@1005 238 XenVbd_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state) {
james@1005 239 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
james@1005 240 NTSTATUS status;
james@1005 241
james@1005 242 UNREFERENCED_PARAMETER(previous_state);
james@1005 243 // if waking from hibernate then same as suspend... maybe?
james@1005 244 FUNCTION_ENTER();
james@1005 245 status = XenVbd_Connect(&xvfd->xvdd, FALSE);
james@1005 246 FUNCTION_EXIT();
james@1005 247 return status;
james@1005 248 }
james@1005 249
james@1008 250 static NTSTATUS
james@1005 251 XenVbd_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
james@1005 252 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
james@1027 253 NTSTATUS status = STATUS_SUCCESS;
james@1027 254
james@1005 255 FUNCTION_ENTER();
james@1027 256 switch (target_state) {
james@1027 257 case WdfPowerDeviceD0:
james@1027 258 FUNCTION_MSG("WdfPowerDeviceD1\n");
james@1027 259 break;
james@1027 260 case WdfPowerDeviceD1:
james@1027 261 FUNCTION_MSG("WdfPowerDeviceD1\n");
james@1027 262 break;
james@1027 263 case WdfPowerDeviceD2:
james@1027 264 FUNCTION_MSG("WdfPowerDeviceD2\n");
james@1027 265 break;
james@1027 266 case WdfPowerDeviceD3:
james@1027 267 FUNCTION_MSG("WdfPowerDeviceD3\n");
james@1027 268 if (xvfd->hibernate_flag) {
james@1027 269 FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n");
james@1027 270 target_state = WdfPowerDevicePrepareForHibernation;
james@1027 271 }
james@1027 272 break;
james@1027 273 case WdfPowerDeviceD3Final:
james@1027 274 FUNCTION_MSG("WdfPowerDeviceD3Final\n");
james@1027 275 break;
james@1027 276 case WdfPowerDevicePrepareForHibernation:
james@1027 277 FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n");
james@1027 278 break;
james@1027 279 default:
james@1027 280 FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", target_state);
james@1027 281 break;
james@1027 282 }
james@1027 283 if (target_state != WdfPowerDevicePrepareForHibernation) {
james@1027 284 status = XenVbd_Disconnect(&xvfd->xvdd, FALSE);
james@1027 285 }
james@1005 286 FUNCTION_EXIT();
james@1005 287 return status;
james@1005 288 }
james@1005 289
james@1005 290 static NTSTATUS
james@1005 291 XenVbd_IoCompletion_START_DEVICE(PDEVICE_OBJECT device, PIRP irp, PVOID context) {
james@1005 292 UNREFERENCED_PARAMETER(device);
james@1005 293 UNREFERENCED_PARAMETER(irp);
james@1005 294 FUNCTION_ENTER();
james@1005 295 ExFreePoolWithTag(context, XENVBD_POOL_TAG);
james@1005 296 FUNCTION_EXIT();
james@1005 297 return STATUS_SUCCESS;
james@1005 298 }
james@1005 299
james@1005 300 static NTSTATUS
james@1005 301 XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE(WDFDEVICE device, PIRP irp) {
james@1005 302 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
james@1005 303 PIO_STACK_LOCATION stack;
james@1005 304 PCM_RESOURCE_LIST crl;
james@1005 305 PCM_FULL_RESOURCE_DESCRIPTOR cfrd;
james@1005 306 PCM_PARTIAL_RESOURCE_LIST cprl;
james@1005 307 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
james@1005 308
james@1005 309 FUNCTION_ENTER();
james@1005 310
james@1008 311 /*
james@1008 312 Pass down the xvdd area as a memory resource. This gives xenvbd the data in a known place
james@1008 313 and also satisifies the scsiport requirement for a memory resource
james@1008 314 */
james@1005 315 IoCopyCurrentIrpStackLocationToNext(irp);
james@1005 316 stack = IoGetNextIrpStackLocation(irp);
james@1005 317
james@1005 318 crl = ExAllocatePoolWithTag(NonPagedPool,
james@1005 319 FIELD_OFFSET(CM_RESOURCE_LIST, List) +
james@1005 320 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
james@1005 321 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
james@1008 322 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 1, XENVBD_POOL_TAG);
james@1005 323 if (!crl) {
james@1005 324 // TODO: Fail this correctly
james@1005 325 }
james@1005 326 crl->Count = 1;
james@1005 327 cfrd = &crl->List[0];
james@1005 328 cfrd->InterfaceType = PNPBus;
james@1005 329 cfrd->BusNumber = 0;
james@1005 330 cprl = &cfrd->PartialResourceList;
james@1005 331 cprl->Version = 1;
james@1005 332 cprl->Revision = 1;
james@1005 333 cprl->Count = 1;
james@1005 334 prd = &cprl->PartialDescriptors[0];
james@1005 335 prd->Type = CmResourceTypeMemory;
james@1005 336 prd->ShareDisposition = CmResourceShareShared;
james@1005 337 prd->Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
james@1005 338 prd->u.Memory.Start.QuadPart = (ULONG_PTR)&xvfd->xvdd;
james@1005 339 prd->u.Memory.Length = sizeof(XENVBD_DEVICE_DATA);
james@1005 340 stack->Parameters.StartDevice.AllocatedResources = crl;
james@1005 341 stack->Parameters.StartDevice.AllocatedResourcesTranslated = crl;
james@1005 342
james@1005 343 IoSetCompletionRoutine(irp, XenVbd_IoCompletion_START_DEVICE, crl, TRUE, TRUE, TRUE);
james@1005 344
james@1005 345 FUNCTION_EXIT();
james@1005 346
james@1005 347 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
james@1005 348 }
james@1005 349
james@1027 350 /* scsiport doesn't process SET_POWER correctly so we have to fudge detection of hibernate */
james@1027 351 static NTSTATUS
james@1027 352 XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER(WDFDEVICE device, PIRP irp) {
james@1027 353 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
james@1027 354 PIO_STACK_LOCATION stack;
james@1027 355
james@1027 356 FUNCTION_ENTER();
james@1027 357 stack = IoGetCurrentIrpStackLocation(irp);
james@1027 358 if (stack->Parameters.Power.Type == DevicePowerState && stack->Parameters.Power.State.DeviceState == PowerDeviceD3 && stack->Parameters.Power.ShutdownType == PowerActionHibernate) {
james@1027 359 FUNCTION_MSG("Going to hibernate\n");
james@1027 360 xvfd->hibernate_flag = TRUE;
james@1027 361 } else {
james@1027 362 xvfd->hibernate_flag = FALSE;
james@1027 363 }
james@1027 364 IoSkipCurrentIrpStackLocation(irp);
james@1027 365 FUNCTION_EXIT();
james@1027 366 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
james@1027 367 }
james@1027 368
james@1005 369 static NTSTATUS
james@1005 370 XenVbd_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init) {
james@1005 371 PXENVBD_FILTER_DATA xvfd;
james@1005 372 NTSTATUS status;
james@1005 373 WDFDEVICE device;
james@1005 374 WDF_OBJECT_ATTRIBUTES device_attributes;
james@1005 375 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
james@1005 376 WDF_DPC_CONFIG dpc_config;
james@1005 377 WDF_OBJECT_ATTRIBUTES oa;
james@1005 378 UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
james@1027 379 UCHAR power_minor_functions[] = { IRP_MN_SET_POWER };
james@1005 380
james@1005 381 UNREFERENCED_PARAMETER(driver);
james@1005 382
james@1005 383 FUNCTION_ENTER();
james@1005 384
james@1008 385 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
james@1008 386
james@1005 387 WdfFdoInitSetFilter(device_init);
james@1005 388
james@1005 389 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
james@1005 390 pnp_power_callbacks.EvtDeviceD0Entry = XenVbd_EvtDeviceD0Entry;
james@1005 391 pnp_power_callbacks.EvtDeviceD0Exit = XenVbd_EvtDeviceD0Exit;
james@1005 392 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
james@1005 393
james@1005 394 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE,
james@1005 395 IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
james@1005 396 if (!NT_SUCCESS(status)) {
james@1005 397 return status;
james@1005 398 }
james@1005 399
james@1027 400 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER,
james@1027 401 IRP_MJ_POWER, power_minor_functions, ARRAY_SIZE(power_minor_functions));
james@1027 402 if (!NT_SUCCESS(status)) {
james@1027 403 return status;
james@1027 404 }
james@1027 405
james@1005 406 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENVBD_FILTER_DATA);
james@1005 407 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
james@1005 408 if (!NT_SUCCESS(status)) {
james@1005 409 FUNCTION_MSG("Error creating device 0x%x\n", status);
james@1005 410 return status;
james@1005 411 }
james@1005 412
james@1005 413 xvfd = GetXvfd(device);
james@1005 414 xvfd->wdf_device = device;
james@1005 415 xvfd->wdf_target = WdfDeviceGetIoTarget(device);
james@1005 416 xvfd->xvdd.xvfd = xvfd;
james@1005 417 xvfd->xvdd.pdo = WdfDeviceWdmGetPhysicalDevice(device);
james@1005 418 xvfd->xvdd.grant_tag = XENVBD_POOL_TAG;
james@1005 419
james@1005 420 KeInitializeEvent(&xvfd->xvdd.backend_event, SynchronizationEvent, FALSE);
james@1005 421
james@1005 422 WDF_DPC_CONFIG_INIT(&dpc_config, XenVbd_EvtDpcEvent);
james@1005 423 WDF_OBJECT_ATTRIBUTES_INIT(&oa);
james@1005 424 oa.ParentObject = device;
james@1005 425 status = WdfDpcCreate(&dpc_config, &oa, &xvfd->dpc);
james@1005 426
james@1005 427 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
james@1005 428 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
james@1005 429 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
james@1005 430
james@1005 431 FUNCTION_EXIT();
james@1005 432 return status;
james@1005 433 }
james@1005 434
james@1005 435 NTSTATUS
james@1008 436 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
james@1005 437 NTSTATUS status;
james@1005 438 WDF_DRIVER_CONFIG config;
james@1005 439 WDFDRIVER driver;
james@1005 440
james@1005 441 UNREFERENCED_PARAMETER(RegistryPath);
james@1005 442
james@1005 443 FUNCTION_ENTER();
james@1005 444
james@1005 445 WDF_DRIVER_CONFIG_INIT(&config, XenVbd_EvtDeviceAdd);
james@1005 446 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
james@1005 447 if (!NT_SUCCESS(status)) {
james@1005 448 FUNCTION_MSG("WdfDriverCreate failed with status 0x%x\n", status);
james@1005 449 FUNCTION_EXIT();
james@1005 450 return status;
james@1005 451 }
james@1005 452 FUNCTION_EXIT();
james@1005 453 return status;
james@1005 454 }