win-pvdrivers

view xenvbd_filter/xenvbd_filter.c @ 1062:5775fb8612ab

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