win-pvdrivers

view xenvbd_filter/xenvbd_filter.c @ 1069:1b80cc14ee6d

Fix free build warnings
author James Harper <james.harper@bendigoit.com.au>
date Tue Nov 12 21:17:26 2013 +1100 (2013-11-12)
parents 5775fb8612ab
children 27bd2a5a4704
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 #if DBG
90 status = WdfRequestGetStatus(request);
91 FUNCTION_MSG("Request Status = %08x\n", status);
92 FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
93 #endif
95 WdfObjectDelete(request);
96 }
98 status = XnWriteInt32(xvdd->handle, XN_BASE_FRONTEND, "state", XenbusStateClosing);
100 FUNCTION_EXIT();
101 }
103 static VOID
104 XenVbd_StartRing(PXENVBD_DEVICE_DATA xvdd, BOOLEAN suspend) {
105 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
106 NTSTATUS status;
107 WDFREQUEST request;
108 WDF_REQUEST_SEND_OPTIONS send_options;
109 IO_STACK_LOCATION stack;
110 SCSI_REQUEST_BLOCK srb;
111 SRB_IO_CONTROL sic;
113 FUNCTION_ENTER();
115 /* send a 'start' down if we are resuming from a suspend */
116 if (suspend) {
117 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
118 FUNCTION_MSG("WdfRequestCreate = %08x\n", status);
120 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
121 stack.MajorFunction = IRP_MJ_SCSI;
122 stack.Parameters.Scsi.Srb = &srb;
124 RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
125 srb.SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
126 srb.Length = SCSI_REQUEST_BLOCK_SIZE;
127 srb.PathId = 0;
128 srb.TargetId = 0;
129 srb.Lun = 0;
130 srb.OriginalRequest = WdfRequestWdmGetIrp(request);
131 srb.Function = SRB_FUNCTION_IO_CONTROL;
132 srb.DataBuffer = &sic;
134 RtlZeroMemory(&sic, sizeof(SRB_IO_CONTROL));
135 sic.HeaderLength = sizeof(SRB_IO_CONTROL);
136 memcpy(sic.Signature, XENVBD_CONTROL_SIG, 8);
137 sic.Timeout = 60;
138 sic.ControlCode = XENVBD_CONTROL_START;
140 WdfRequestWdmFormatUsingStackLocation(request, &stack);
142 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS);
143 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
144 FUNCTION_MSG("Request was _NOT_ sent\n");
145 }
146 #if DBG
147 status = WdfRequestGetStatus(request);
148 FUNCTION_MSG("Request Status = %08x\n", status);
149 FUNCTION_MSG("SRB Status = %08x\n", srb.SrbStatus);
150 #endif
152 WdfObjectDelete(request);
153 }
155 FUNCTION_EXIT();
156 }
158 static VOID
159 XenVbd_SendEventComplete(WDFREQUEST request, WDFIOTARGET target, PWDF_REQUEST_COMPLETION_PARAMS params, WDFCONTEXT context) {
160 WDFDEVICE device = WdfIoTargetGetDevice(target);
161 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
162 NTSTATUS status;
163 PSCSI_REQUEST_BLOCK srb = context;
164 LARGE_INTEGER systemtime;
165 ULONGLONG elapsed;
167 UNREFERENCED_PARAMETER(params);
168 UNREFERENCED_PARAMETER(context);
170 status = WdfRequestGetStatus(request);
171 if (status != 0 || srb->SrbStatus != SRB_STATUS_SUCCESS) {
172 FUNCTION_MSG("Request Status = %08x, SRB Status = %08x\n", status, srb->SrbStatus);
173 }
174 KeQuerySystemTime(&systemtime);
175 elapsed = systemtime.QuadPart - ((PLARGE_INTEGER)((PUCHAR)context + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL)))->QuadPart;
176 elapsed = elapsed / 10000; // now in ms
177 if (elapsed > 1000) {
178 FUNCTION_MSG("Event took %d ms\n", (ULONG)elapsed);
179 }
180 ExFreePoolWithTag(context, XENVBD_POOL_TAG);
181 WdfObjectDelete(request);
183 for (;;) {
184 if (InterlockedCompareExchange(&xvfd->event_state, 0, 1) == 1) {
185 /* no pending event, and we cleared outstanding flag */
186 break;
187 }
188 if (InterlockedCompareExchange(&xvfd->event_state, 1, 2) == 2) {
189 /* there was a pending event, and we set the flag back to outstanding */
190 //FUNCTION_MSG("sending pended event\n");
191 XenVbd_SendEvent(device);
192 break;
193 }
194 /* event_state changed while we were looking at it, go round again */
195 }
196 }
198 static VOID
199 XenVbd_SendEvent(WDFDEVICE device) {
200 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
201 NTSTATUS status;
202 WDFREQUEST request;
203 WDF_REQUEST_SEND_OPTIONS send_options;
204 IO_STACK_LOCATION stack;
205 PUCHAR buf;
206 PSCSI_REQUEST_BLOCK srb;
207 PSRB_IO_CONTROL sic;
209 status = WdfRequestCreate(WDF_NO_OBJECT_ATTRIBUTES, xvfd->wdf_target, &request);
210 if (status != STATUS_SUCCESS) {
211 FUNCTION_MSG("WdfRequestCreate failed %08x\n", status);
212 /* this is bad - event will be dropped */
213 return;
214 }
216 buf = ExAllocatePoolWithTag(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL) + sizeof(LARGE_INTEGER), XENVBD_POOL_TAG);
217 RtlZeroMemory(buf, sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL));
218 srb = (PSCSI_REQUEST_BLOCK)(buf);
219 sic = (PSRB_IO_CONTROL)(buf + sizeof(SCSI_REQUEST_BLOCK));
221 srb->Length = sizeof(SCSI_REQUEST_BLOCK);
222 srb->SrbFlags = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE;
223 srb->PathId = 0;
224 srb->TargetId = 0;
225 srb->Lun = 0;
226 srb->OriginalRequest = WdfRequestWdmGetIrp(request);
227 srb->Function = SRB_FUNCTION_IO_CONTROL;
228 srb->DataBuffer = sic;
229 srb->DataTransferLength = sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL);
230 srb->TimeOutValue = (ULONG)-1;
232 sic->HeaderLength = sizeof(SRB_IO_CONTROL);
233 memcpy(sic->Signature, XENVBD_CONTROL_SIG, 8);
234 sic->Timeout = (ULONG)-1;
235 sic->ControlCode = XENVBD_CONTROL_EVENT;
237 KeQuerySystemTime((PLARGE_INTEGER)((PUCHAR)buf + sizeof(SCSI_REQUEST_BLOCK) + sizeof(SRB_IO_CONTROL)));
239 RtlZeroMemory(&stack, sizeof(IO_STACK_LOCATION));
240 stack.MajorFunction = IRP_MJ_SCSI;
241 stack.MinorFunction = IRP_MN_SCSI_CLASS;
242 stack.Parameters.Scsi.Srb = srb;
244 WdfRequestWdmFormatUsingStackLocation(request, &stack);
245 WdfRequestSetCompletionRoutine(request, XenVbd_SendEventComplete, buf);
247 WDF_REQUEST_SEND_OPTIONS_INIT(&send_options, 0); //WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE);
248 if (!WdfRequestSend(request, xvfd->wdf_target, &send_options)) {
249 FUNCTION_MSG("Error sending request\n");
250 }
251 }
253 static VOID
254 XenVbd_EvtDpcEvent(WDFDPC dpc) {
255 WDFDEVICE device = WdfDpcGetParentObject(dpc);
256 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
258 for (;;) {
259 if (InterlockedCompareExchange(&xvfd->event_state, 1, 0) == 0) {
260 /* was no event outstanding, now there is */
261 XenVbd_SendEvent(device);
262 break;
263 }
264 if (InterlockedCompareExchange(&xvfd->event_state, 2, 1) != 0) {
265 //FUNCTION_MSG("event already in progress\n");
266 /* event was outstanding. either we set the need new event flag or it was already set */
267 break;
268 }
269 /* event_state changed while we were looking at it, go around again */
270 }
271 }
273 static VOID
274 XenVbd_HandleEventDIRQL(PVOID context) {
275 PXENVBD_DEVICE_DATA xvdd = (PXENVBD_DEVICE_DATA)context;
276 PXENVBD_FILTER_DATA xvfd = (PXENVBD_FILTER_DATA)xvdd->xvfd;
277 WdfDpcEnqueue(xvfd->dpc);
278 }
280 static NTSTATUS
281 XenVbd_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state) {
282 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
283 NTSTATUS status;
285 UNREFERENCED_PARAMETER(previous_state);
286 // if waking from hibernate then same as suspend... maybe?
287 FUNCTION_ENTER();
288 status = XenVbd_Connect(&xvfd->xvdd, FALSE);
289 FUNCTION_EXIT();
290 return status;
291 }
293 static NTSTATUS
294 XenVbd_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
295 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
296 NTSTATUS status = STATUS_SUCCESS;
298 FUNCTION_ENTER();
299 switch (target_state) {
300 case WdfPowerDeviceD0:
301 FUNCTION_MSG("WdfPowerDeviceD1\n");
302 break;
303 case WdfPowerDeviceD1:
304 FUNCTION_MSG("WdfPowerDeviceD1\n");
305 break;
306 case WdfPowerDeviceD2:
307 FUNCTION_MSG("WdfPowerDeviceD2\n");
308 break;
309 case WdfPowerDeviceD3:
310 FUNCTION_MSG("WdfPowerDeviceD3\n");
311 if (xvfd->hibernate_flag) {
312 FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n");
313 target_state = WdfPowerDevicePrepareForHibernation;
314 }
315 break;
316 case WdfPowerDeviceD3Final:
317 FUNCTION_MSG("WdfPowerDeviceD3Final\n");
318 break;
319 case WdfPowerDevicePrepareForHibernation:
320 FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n");
321 break;
322 default:
323 FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", target_state);
324 break;
325 }
326 if (target_state != WdfPowerDevicePrepareForHibernation) {
327 status = XenVbd_Disconnect(&xvfd->xvdd, FALSE);
328 }
329 FUNCTION_EXIT();
330 return status;
331 }
333 static NTSTATUS
334 XenVbd_IoCompletion_START_DEVICE(PDEVICE_OBJECT device, PIRP irp, PVOID context) {
335 UNREFERENCED_PARAMETER(device);
336 UNREFERENCED_PARAMETER(irp);
337 FUNCTION_ENTER();
338 ExFreePoolWithTag(context, XENVBD_POOL_TAG);
339 FUNCTION_EXIT();
340 return STATUS_SUCCESS;
341 }
343 static NTSTATUS
344 XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE(WDFDEVICE device, PIRP irp) {
345 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
346 PIO_STACK_LOCATION stack;
347 PCM_RESOURCE_LIST crl;
348 PCM_FULL_RESOURCE_DESCRIPTOR cfrd;
349 PCM_PARTIAL_RESOURCE_LIST cprl;
350 PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
352 FUNCTION_ENTER();
354 /*
355 Pass down the xvdd area as a memory resource. This gives xenvbd the data in a known place
356 and also satisifies the scsiport requirement for a memory resource
357 */
358 IoCopyCurrentIrpStackLocationToNext(irp);
359 stack = IoGetNextIrpStackLocation(irp);
361 crl = ExAllocatePoolWithTag(NonPagedPool,
362 FIELD_OFFSET(CM_RESOURCE_LIST, List) +
363 FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList) +
364 FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
365 sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 1, XENVBD_POOL_TAG);
366 if (!crl) {
367 // TODO: Fail this correctly
368 }
369 crl->Count = 1;
370 cfrd = &crl->List[0];
371 cfrd->InterfaceType = PNPBus;
372 cfrd->BusNumber = 0;
373 cprl = &cfrd->PartialResourceList;
374 cprl->Version = 1;
375 cprl->Revision = 1;
376 cprl->Count = 1;
377 prd = &cprl->PartialDescriptors[0];
378 prd->Type = CmResourceTypeMemory;
379 prd->ShareDisposition = CmResourceShareShared;
380 prd->Flags = CM_RESOURCE_MEMORY_READ_WRITE | CM_RESOURCE_MEMORY_CACHEABLE;
381 prd->u.Memory.Start.QuadPart = (ULONG_PTR)&xvfd->xvdd;
382 prd->u.Memory.Length = sizeof(XENVBD_DEVICE_DATA);
383 stack->Parameters.StartDevice.AllocatedResources = crl;
384 stack->Parameters.StartDevice.AllocatedResourcesTranslated = crl;
386 IoSetCompletionRoutine(irp, XenVbd_IoCompletion_START_DEVICE, crl, TRUE, TRUE, TRUE);
388 FUNCTION_EXIT();
390 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
391 }
393 /* scsiport doesn't process SET_POWER correctly so we have to fudge detection of hibernate */
394 static NTSTATUS
395 XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER(WDFDEVICE device, PIRP irp) {
396 PXENVBD_FILTER_DATA xvfd = GetXvfd(device);
397 PIO_STACK_LOCATION stack;
399 FUNCTION_ENTER();
400 stack = IoGetCurrentIrpStackLocation(irp);
401 if (stack->Parameters.Power.Type == DevicePowerState && stack->Parameters.Power.State.DeviceState == PowerDeviceD3 && stack->Parameters.Power.ShutdownType == PowerActionHibernate) {
402 FUNCTION_MSG("Going to hibernate\n");
403 xvfd->hibernate_flag = TRUE;
404 } else {
405 xvfd->hibernate_flag = FALSE;
406 }
407 IoSkipCurrentIrpStackLocation(irp);
408 FUNCTION_EXIT();
409 return WdfDeviceWdmDispatchPreprocessedIrp(device, irp);
410 }
412 static NTSTATUS
413 XenVbd_EvtDeviceAdd(WDFDRIVER driver, PWDFDEVICE_INIT device_init) {
414 PXENVBD_FILTER_DATA xvfd;
415 NTSTATUS status;
416 WDFDEVICE device;
417 WDF_OBJECT_ATTRIBUTES device_attributes;
418 WDF_PNPPOWER_EVENT_CALLBACKS pnp_power_callbacks;
419 WDF_DPC_CONFIG dpc_config;
420 WDF_OBJECT_ATTRIBUTES oa;
421 UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
422 UCHAR power_minor_functions[] = { IRP_MN_SET_POWER };
424 UNREFERENCED_PARAMETER(driver);
426 FUNCTION_ENTER();
428 WdfDeviceInitSetDeviceType(device_init, FILE_DEVICE_UNKNOWN);
430 WdfFdoInitSetFilter(device_init);
432 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnp_power_callbacks);
433 pnp_power_callbacks.EvtDeviceD0Entry = XenVbd_EvtDeviceD0Entry;
434 pnp_power_callbacks.EvtDeviceD0Exit = XenVbd_EvtDeviceD0Exit;
435 WdfDeviceInitSetPnpPowerEventCallbacks(device_init, &pnp_power_callbacks);
437 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_START_DEVICE,
438 IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
439 if (!NT_SUCCESS(status)) {
440 return status;
441 }
443 status = WdfDeviceInitAssignWdmIrpPreprocessCallback(device_init, XenVbd_EvtDeviceWdmIrpPreprocess_SET_POWER,
444 IRP_MJ_POWER, power_minor_functions, ARRAY_SIZE(power_minor_functions));
445 if (!NT_SUCCESS(status)) {
446 return status;
447 }
449 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&device_attributes, XENVBD_FILTER_DATA);
450 status = WdfDeviceCreate(&device_init, &device_attributes, &device);
451 if (!NT_SUCCESS(status)) {
452 FUNCTION_MSG("Error creating device 0x%x\n", status);
453 return status;
454 }
456 xvfd = GetXvfd(device);
457 xvfd->wdf_device = device;
458 xvfd->wdf_target = WdfDeviceGetIoTarget(device);
459 xvfd->xvdd.xvfd = xvfd;
460 xvfd->xvdd.pdo = WdfDeviceWdmGetPhysicalDevice(device);
461 xvfd->xvdd.grant_tag = XENVBD_POOL_TAG;
463 KeInitializeEvent(&xvfd->xvdd.backend_event, SynchronizationEvent, FALSE);
465 WDF_DPC_CONFIG_INIT(&dpc_config, XenVbd_EvtDpcEvent);
466 WDF_OBJECT_ATTRIBUTES_INIT(&oa);
467 oa.ParentObject = device;
468 status = WdfDpcCreate(&dpc_config, &oa, &xvfd->dpc);
470 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFilePaging, TRUE);
471 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileHibernation, TRUE);
472 WdfDeviceSetSpecialFileSupport(device, WdfSpecialFileDump, TRUE);
474 FUNCTION_EXIT();
475 return status;
476 }
478 NTSTATUS
479 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
480 NTSTATUS status;
481 WDF_DRIVER_CONFIG config;
482 WDFDRIVER driver;
484 UNREFERENCED_PARAMETER(RegistryPath);
486 FUNCTION_ENTER();
488 WDF_DRIVER_CONFIG_INIT(&config, XenVbd_EvtDeviceAdd);
489 status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, &driver);
490 if (!NT_SUCCESS(status)) {
491 FUNCTION_MSG("WdfDriverCreate failed with status 0x%x\n", status);
492 FUNCTION_EXIT();
493 return status;
494 }
495 FUNCTION_EXIT();
496 return status;
497 }