win-pvdrivers

view xenpci/xenpci_pdo.c @ 1019:df03fde445b8

tidyup xenpci
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 12 20:45:25 2013 +1100 (2013-02-12)
parents 9fb8690938b3
children cd72cd0e1c19
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 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 "xenpci.h"
21 #include <stdlib.h>
22 #include <io/ring.h>
24 #pragma warning(disable : 4200) // zero-sized array
25 #pragma warning(disable: 4127) // conditional expression is constant
27 /* Not really necessary but keeps PREfast happy */
28 static EVT_WDF_INTERRUPT_SYNCHRONIZE XenPci_EvtChn_Sync_Routine;
29 static EVT_WDF_DEVICE_D0_ENTRY XenPciPdo_EvtDeviceD0Entry;
30 static EVT_WDF_DEVICE_D0_EXIT XenPciPdo_EvtDeviceD0Exit;
31 static EVT_WDF_DEVICE_USAGE_NOTIFICATION XenPciPdo_EvtDeviceUsageNotification;
32 static EVT_WDF_DEVICE_PNP_STATE_CHANGE_NOTIFICATION XenPci_EvtDevicePnpStateChange;
36 /*
37 Called at PASSIVE_LEVEL(?)
38 Called during restore
39 */
40 static ULONG
41 XenPci_ReadBackendState(PXENPCI_PDO_DEVICE_DATA xppdd)
42 {
43 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
44 char path[128];
45 char *value;
46 char *err;
47 ULONG backend_state;
49 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
50 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
51 if (err)
52 {
53 XenPci_FreeMem(err);
54 return XenbusStateUnknown;
55 }
56 else
57 {
58 backend_state = atoi(value);
59 XenPci_FreeMem(value);
60 return backend_state;
61 }
62 }
64 static NTSTATUS
65 XenPci_GetBackendDetails(WDFDEVICE device)
66 {
67 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
68 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
69 char path[128];
70 PCHAR res;
71 PCHAR value;
73 FUNCTION_ENTER();
74 /* Get backend path */
75 RtlStringCbPrintfA(path, ARRAY_SIZE(path),
76 "%s/backend", xppdd->path);
77 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
78 if (res)
79 {
80 KdPrint((__DRIVER_NAME " Failed to read backend path\n"));
81 XenPci_FreeMem(res);
82 return STATUS_UNSUCCESSFUL;
83 }
84 RtlStringCbCopyA(xppdd->backend_path, ARRAY_SIZE(xppdd->backend_path), value);
85 XenPci_FreeMem(value);
87 /* Get backend id */
88 RtlStringCbPrintfA(path, ARRAY_SIZE(path),
89 "%s/backend-id", xppdd->path);
90 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
91 if (res) {
92 KdPrint((__DRIVER_NAME " Failed to read backend id\n"));
93 XenPci_FreeMem(res);
94 return STATUS_UNSUCCESSFUL;
95 }
96 xppdd->backend_id = (domid_t)atoi(value);
97 XenPci_FreeMem(value);
98 FUNCTION_EXIT();
99 return STATUS_SUCCESS;
100 }
102 NTSTATUS
103 XenPci_SuspendPdo(WDFDEVICE device) {
104 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
105 PXENPCI_DEVICE_DATA xpdd = xppdd->xpdd;
106 PCHAR response;
107 CHAR path[128];
109 if (xppdd->device_callback) {
110 FUNCTION_MSG("Suspending %s\n", xppdd->device);
111 xppdd->device_callback(xppdd->device_callback_context, XN_DEVICE_CALLBACK_SUSPEND, NULL);
112 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
113 response = XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd);
114 if (response) {
115 FUNCTION_MSG("XnRemWatch - %s = %s\n", path, response);
116 XenPci_FreeMem(response);
117 }
118 }
119 return STATUS_SUCCESS;
120 }
122 NTSTATUS
123 XenPci_ResumePdo(WDFDEVICE device) {
124 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
125 PXENPCI_DEVICE_DATA xpdd = xppdd->xpdd;
126 PCHAR response;
127 CHAR path[128];
129 XenPci_GetBackendDetails(device);
130 if (xppdd->device_callback) {
131 FUNCTION_MSG("Resuming %s\n", xppdd->device);
132 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
133 response = XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd);
134 if (response) {
135 FUNCTION_MSG("XnAddWatch - %s = %s\n", path, response);
136 XenPci_FreeMem(response);
137 xppdd->device_callback = NULL;
138 xppdd->device_callback_context = NULL;
139 FUNCTION_EXIT();
140 return STATUS_UNSUCCESSFUL;
141 }
142 xppdd->device_callback(xppdd->device_callback_context, XN_DEVICE_CALLBACK_RESUME, NULL);
143 }
144 return STATUS_SUCCESS;
145 }
147 NTSTATUS
148 XenPciPdo_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state) {
149 NTSTATUS status = STATUS_SUCCESS;
150 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
151 //PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
152 CHAR path[128];
154 FUNCTION_ENTER();
155 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
157 switch (previous_state) {
158 case WdfPowerDeviceD0:
159 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
160 break;
161 case WdfPowerDeviceD1:
162 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
163 break;
164 case WdfPowerDeviceD2:
165 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
166 break;
167 case WdfPowerDeviceD3:
168 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
169 if (xppdd->hiber_usage_kludge) {
170 KdPrint((__DRIVER_NAME " (but really WdfPowerDevicePrepareForHibernation)\n"));
171 previous_state = WdfPowerDevicePrepareForHibernation;
172 }
173 break;
174 case WdfPowerDeviceD3Final:
175 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
176 break;
177 case WdfPowerDevicePrepareForHibernation:
178 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
179 break;
180 default:
181 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", previous_state));
182 break;
183 }
185 status = XenPci_GetBackendDetails(device);
186 if (!NT_SUCCESS(status)) {
187 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
188 FUNCTION_EXIT_STATUS(status);
189 return status;
190 }
192 if (!NT_SUCCESS(status)) {
193 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
194 //XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
195 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
196 FUNCTION_EXIT_STATUS(status);
197 return status;
198 }
200 FUNCTION_EXIT();
202 return status;
203 }
205 NTSTATUS
206 XenPciPdo_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
207 NTSTATUS status = STATUS_SUCCESS;
208 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
209 //PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
210 char path[128];
212 UNREFERENCED_PARAMETER(device);
213 UNREFERENCED_PARAMETER(target_state);
215 FUNCTION_ENTER();
216 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
218 switch (target_state) {
219 case WdfPowerDeviceD0:
220 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
221 break;
222 case WdfPowerDeviceD1:
223 KdPrint((__DRIVER_NAME " WdfPowerDeviceD1\n"));
224 break;
225 case WdfPowerDeviceD2:
226 KdPrint((__DRIVER_NAME " WdfPowerDeviceD2\n"));
227 break;
228 case WdfPowerDeviceD3:
229 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3\n"));
230 if (xppdd->hiber_usage_kludge) {
231 KdPrint((__DRIVER_NAME " (but really WdfPowerDevicePrepareForHibernation)\n"));
232 target_state = WdfPowerDevicePrepareForHibernation;
233 }
234 break;
235 case WdfPowerDeviceD3Final:
236 KdPrint((__DRIVER_NAME " WdfPowerDeviceD3Final\n"));
237 break;
238 case WdfPowerDevicePrepareForHibernation:
239 KdPrint((__DRIVER_NAME " WdfPowerDevicePrepareForHibernation\n"));
240 break;
241 default:
242 KdPrint((__DRIVER_NAME " Unknown WdfPowerDevice state %d\n", target_state));
243 break;
244 }
246 if (target_state == WdfPowerDevicePrepareForHibernation)
247 {
248 KdPrint((__DRIVER_NAME " not powering down as we are hibernating\n"));
249 // should we set the backend state here so it's correct on resume???
250 }
252 /* Remove watch on backend state */
253 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
254 //XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
256 FUNCTION_EXIT();
258 return status;
259 }
261 static VOID
262 XenPciPdo_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
263 {
264 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
266 FUNCTION_ENTER();
268 KdPrint((__DRIVER_NAME " path = %s\n", xppdd->path));
269 switch (notification_type)
270 {
271 case WdfSpecialFilePaging:
272 KdPrint((__DRIVER_NAME " notification_type = Paging, flag = %d\n", is_in_notification_path));
273 break;
274 case WdfSpecialFileHibernation:
275 xppdd->hiber_usage_kludge = is_in_notification_path;
276 KdPrint((__DRIVER_NAME " notification_type = Hibernation, flag = %d\n", is_in_notification_path));
277 break;
278 case WdfSpecialFileDump:
279 KdPrint((__DRIVER_NAME " notification_type = Dump, flag = %d\n", is_in_notification_path));
280 break;
281 default:
282 KdPrint((__DRIVER_NAME " notification_type = %d, flag = %d\n", notification_type, is_in_notification_path));
283 break;
284 }
286 FUNCTION_EXIT();
287 }
289 static VOID
290 XenPci_EvtDevicePnpStateChange(WDFDEVICE device, PCWDF_DEVICE_PNP_NOTIFICATION_DATA notification_data)
291 {
292 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
294 //FUNCTION_ENTER();
296 if (xppdd->backend_initiated_remove
297 && notification_data->Type == StateNotificationEnterState
298 && notification_data->Data.EnterState.CurrentState == WdfDevStatePnpQueryRemovePending
299 && notification_data->Data.EnterState.NewState == WdfDevStatePnpQueryCanceled)
300 {
301 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
303 KdPrint((__DRIVER_NAME " Eject failed, doing surprise removal\n"));
304 xppdd->do_not_enumerate = TRUE;
305 XenPci_EvtChildListScanForChildren(xpdd->child_list);
306 }
308 //FUNCTION_EXIT();
310 //return STATUS_SUCCESS;
311 }
313 NTSTATUS
314 XenPci_EvtChildListCreateDevice(WDFCHILDLIST child_list,
315 PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER identification_header,
316 PWDFDEVICE_INIT child_init) {
317 NTSTATUS status = STATUS_SUCCESS;
318 WDF_OBJECT_ATTRIBUTES child_attributes;
319 WDFDEVICE child_device;
320 PXENPCI_PDO_IDENTIFICATION_DESCRIPTION identification = (PXENPCI_PDO_IDENTIFICATION_DESCRIPTION)identification_header;
321 WDF_DEVICE_PNP_CAPABILITIES child_pnp_capabilities;
322 DECLARE_UNICODE_STRING_SIZE(buffer, 512);
323 DECLARE_CONST_UNICODE_STRING(location, L"Xen Bus");
324 PXENPCI_PDO_DEVICE_DATA xppdd;
325 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
326 //WDF_PDO_EVENT_CALLBACKS pdo_callbacks;
327 WDF_PNPPOWER_EVENT_CALLBACKS child_pnp_power_callbacks;
328 //UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
329 WDF_DEVICE_POWER_CAPABILITIES child_power_capabilities;
331 FUNCTION_ENTER();
333 WdfDeviceInitSetDeviceType(child_init, FILE_DEVICE_UNKNOWN);
335 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&child_pnp_power_callbacks);
336 child_pnp_power_callbacks.EvtDeviceD0Entry = XenPciPdo_EvtDeviceD0Entry;
337 child_pnp_power_callbacks.EvtDeviceD0Exit = XenPciPdo_EvtDeviceD0Exit;
338 child_pnp_power_callbacks.EvtDeviceUsageNotification = XenPciPdo_EvtDeviceUsageNotification;
339 WdfDeviceInitSetPnpPowerEventCallbacks(child_init, &child_pnp_power_callbacks);
341 KdPrint((__DRIVER_NAME " device = '%s', index = '%d', path = '%s'\n",
342 identification->device, identification->index, identification->path));
344 //status = WdfDeviceInitAssignWdmIrpPreprocessCallback(child_init, XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE,
345 // IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
346 //if (!NT_SUCCESS(status)) {
347 // return status;
348 //}
350 //WDF_PDO_EVENT_CALLBACKS_INIT(&pdo_callbacks);
351 //pdo_callbacks.EvtDeviceResourcesQuery = XenPciPdo_EvtDeviceResourcesQuery;
352 //pdo_callbacks.EvtDeviceResourceRequirementsQuery = XenPciPdo_EvtDeviceResourceRequirementsQuery;
353 //pdo_callbacks.EvtDeviceEject = XenPciPdo_EvtDeviceEject;
354 //pdo_callbacks.EvtDeviceSetLock = XenPciPdo_EvtDeviceSetLock;
355 //WdfPdoInitSetEventCallbacks(child_init, &pdo_callbacks);
357 RtlUnicodeStringPrintf(&buffer, L"xen\\%S", identification->device);
358 status = WdfPdoInitAssignDeviceID(child_init, &buffer);
359 if (!NT_SUCCESS(status))
360 {
361 return status;
362 }
363 status = WdfPdoInitAddHardwareID(child_init, &buffer);
364 if (!NT_SUCCESS(status))
365 {
366 return status;
367 }
368 status = WdfPdoInitAddCompatibleID(child_init, &buffer);
369 if (!NT_SUCCESS(status))
370 {
371 return status;
372 }
374 RtlUnicodeStringPrintf(&buffer, L"%02d", identification->index);
375 status = WdfPdoInitAssignInstanceID(child_init, &buffer);
376 if (!NT_SUCCESS(status))
377 {
378 return status;
379 }
381 RtlUnicodeStringPrintf(&buffer, L"Xen %S device #%d", identification->device, identification->index);
382 status = WdfPdoInitAddDeviceText(child_init, &buffer, &location, 0x0409);
383 if (!NT_SUCCESS(status))
384 {
385 return status;
386 }
387 WdfPdoInitSetDefaultLocale(child_init, 0x0409);
389 WdfDeviceInitSetPowerNotPageable(child_init);
391 WdfDeviceInitRegisterPnpStateChangeCallback(child_init, WdfDevStatePnpQueryCanceled, XenPci_EvtDevicePnpStateChange, StateNotificationEnterState);
393 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&child_attributes, XENPCI_PDO_DEVICE_DATA);
394 status = WdfDeviceCreate(&child_init, &child_attributes, &child_device);
395 if (!NT_SUCCESS(status))
396 {
397 return status;
398 }
400 xppdd = GetXppdd(child_device);
402 xppdd->wdf_device = child_device;
403 xppdd->wdf_device_bus_fdo = WdfChildListGetDevice(child_list);
404 xppdd->xpdd = xpdd;
406 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFilePaging, TRUE);
407 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileHibernation, TRUE);
408 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileDump, TRUE);
410 WDF_DEVICE_PNP_CAPABILITIES_INIT(&child_pnp_capabilities);
411 child_pnp_capabilities.LockSupported = WdfFalse;
412 child_pnp_capabilities.EjectSupported = WdfTrue;
413 child_pnp_capabilities.Removable = WdfTrue;
414 child_pnp_capabilities.DockDevice = WdfFalse;
415 child_pnp_capabilities.UniqueID = WdfFalse;
416 child_pnp_capabilities.SilentInstall = WdfTrue;
417 child_pnp_capabilities.SurpriseRemovalOK = WdfTrue;
418 child_pnp_capabilities.HardwareDisabled = WdfFalse;
419 WdfDeviceSetPnpCapabilities(child_device, &child_pnp_capabilities);
421 WDF_DEVICE_POWER_CAPABILITIES_INIT(&child_power_capabilities);
422 child_power_capabilities.DeviceD1 = WdfTrue;
423 child_power_capabilities.WakeFromD1 = WdfTrue;
424 child_power_capabilities.DeviceWake = PowerDeviceD1;
425 child_power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
426 child_power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
427 child_power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
428 child_power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
429 child_power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
430 child_power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
431 WdfDeviceSetPowerCapabilities(child_device, &child_power_capabilities);
433 RtlStringCbCopyA(xppdd->path, ARRAY_SIZE(xppdd->path), identification->path);
434 RtlStringCbCopyA(xppdd->device, ARRAY_SIZE(xppdd->device), identification->device);
435 xppdd->index = identification->index;
436 KeInitializeEvent(&xppdd->backend_state_event, SynchronizationEvent, FALSE);
437 ExInitializeFastMutex(&xppdd->backend_state_mutex);
438 xppdd->backend_state = XenbusStateUnknown;
439 xppdd->frontend_state = XenbusStateUnknown;
440 xppdd->backend_path[0] = '\0';
441 xppdd->backend_id = 0;
443 FUNCTION_EXIT();
445 return status;