win-pvdrivers

view xenpci/xenpci_pdo.c @ 1026:d9a2a6de2ab4

More debugprint updates
author James Harper <james.harper@bendigoit.com.au>
date Tue Feb 19 20:54:48 2013 +1100 (2013-02-19)
parents cd72cd0e1c19
children 27bd2a5a4704
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;
34 /*
35 Called at PASSIVE_LEVEL(?)
36 Called during restore
37 */
38 static ULONG
39 XenPci_ReadBackendState(PXENPCI_PDO_DEVICE_DATA xppdd)
40 {
41 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
42 char path[128];
43 char *value;
44 char *err;
45 ULONG backend_state;
47 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
48 err = XenBus_Read(xpdd, XBT_NIL, path, &value);
49 if (err)
50 {
51 XenPci_FreeMem(err);
52 return XenbusStateUnknown;
53 }
54 else
55 {
56 backend_state = atoi(value);
57 XenPci_FreeMem(value);
58 return backend_state;
59 }
60 }
62 static NTSTATUS
63 XenPci_GetBackendDetails(WDFDEVICE device)
64 {
65 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
66 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
67 char path[128];
68 PCHAR res;
69 PCHAR value;
71 FUNCTION_ENTER();
72 /* Get backend path */
73 RtlStringCbPrintfA(path, ARRAY_SIZE(path),
74 "%s/backend", xppdd->path);
75 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
76 if (res)
77 {
78 FUNCTION_MSG("Failed to read backend path\n");
79 XenPci_FreeMem(res);
80 return STATUS_UNSUCCESSFUL;
81 }
82 RtlStringCbCopyA(xppdd->backend_path, ARRAY_SIZE(xppdd->backend_path), value);
83 XenPci_FreeMem(value);
85 /* Get backend id */
86 RtlStringCbPrintfA(path, ARRAY_SIZE(path),
87 "%s/backend-id", xppdd->path);
88 res = XenBus_Read(xpdd, XBT_NIL, path, &value);
89 if (res) {
90 FUNCTION_MSG("Failed to read backend id\n");
91 XenPci_FreeMem(res);
92 return STATUS_UNSUCCESSFUL;
93 }
94 xppdd->backend_id = (domid_t)atoi(value);
95 XenPci_FreeMem(value);
96 FUNCTION_EXIT();
97 return STATUS_SUCCESS;
98 }
100 NTSTATUS
101 XenPci_SuspendPdo(WDFDEVICE device) {
102 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
103 PXENPCI_DEVICE_DATA xpdd = xppdd->xpdd;
104 PCHAR response;
105 CHAR path[128];
107 if (xppdd->device_callback) {
108 FUNCTION_MSG("Suspending %s\n", xppdd->device);
109 xppdd->device_callback(xppdd->device_callback_context, XN_DEVICE_CALLBACK_SUSPEND, NULL);
110 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
111 response = XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd);
112 if (response) {
113 FUNCTION_MSG("XnRemWatch - %s = %s\n", path, response);
114 XenPci_FreeMem(response);
115 }
116 }
117 return STATUS_SUCCESS;
118 }
120 NTSTATUS
121 XenPci_ResumePdo(WDFDEVICE device) {
122 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
123 PXENPCI_DEVICE_DATA xpdd = xppdd->xpdd;
124 PCHAR response;
125 CHAR path[128];
127 XenPci_GetBackendDetails(device);
128 if (xppdd->device_callback) {
129 FUNCTION_MSG("Resuming %s\n", xppdd->device);
130 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
131 response = XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd);
132 if (response) {
133 FUNCTION_MSG("XnAddWatch - %s = %s\n", path, response);
134 XenPci_FreeMem(response);
135 xppdd->device_callback = NULL;
136 xppdd->device_callback_context = NULL;
137 FUNCTION_EXIT();
138 return STATUS_UNSUCCESSFUL;
139 }
140 xppdd->device_callback(xppdd->device_callback_context, XN_DEVICE_CALLBACK_RESUME, NULL);
141 }
142 return STATUS_SUCCESS;
143 }
145 NTSTATUS
146 XenPciPdo_EvtDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previous_state) {
147 NTSTATUS status = STATUS_SUCCESS;
148 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
149 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
150 CHAR path[128];
152 FUNCTION_ENTER();
153 FUNCTION_MSG("path = %s\n", xppdd->path);
155 switch (previous_state) {
156 case WdfPowerDeviceD0:
157 FUNCTION_MSG("WdfPowerDeviceD1\n");
158 break;
159 case WdfPowerDeviceD1:
160 FUNCTION_MSG("WdfPowerDeviceD1\n");
161 break;
162 case WdfPowerDeviceD2:
163 FUNCTION_MSG("WdfPowerDeviceD2\n");
164 break;
165 case WdfPowerDeviceD3:
166 FUNCTION_MSG("WdfPowerDeviceD3\n");
167 if (xppdd->hiber_usage_kludge) {
168 FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n");
169 previous_state = WdfPowerDevicePrepareForHibernation;
170 }
171 break;
172 case WdfPowerDeviceD3Final:
173 FUNCTION_MSG("WdfPowerDeviceD3Final\n");
174 break;
175 case WdfPowerDevicePrepareForHibernation:
176 FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n");
177 break;
178 default:
179 FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", previous_state);
180 break;
181 }
183 status = XenPci_GetBackendDetails(device);
184 if (!NT_SUCCESS(status)) {
185 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
186 FUNCTION_EXIT_STATUS(status);
187 return status;
188 }
190 if (previous_state == WdfPowerDevicePrepareForHibernation && xppdd->device_callback) {
191 FUNCTION_MSG("Restoring watch %s\n", xppdd->device);
192 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
193 XenBus_AddWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd);
194 }
196 if (!NT_SUCCESS(status)) {
197 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
198 //XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateHandler, device);
199 WdfDeviceSetFailed(device, WdfDeviceFailedNoRestart);
200 FUNCTION_EXIT_STATUS(status);
201 return status;
202 }
204 FUNCTION_EXIT();
206 return status;
207 }
209 NTSTATUS
210 XenPciPdo_EvtDeviceD0Exit(WDFDEVICE device, WDF_POWER_DEVICE_STATE target_state) {
211 NTSTATUS status = STATUS_SUCCESS;
212 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
213 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
214 char path[128];
216 UNREFERENCED_PARAMETER(device);
217 UNREFERENCED_PARAMETER(target_state);
219 FUNCTION_ENTER();
220 FUNCTION_MSG("path = %s\n", xppdd->path);
222 switch (target_state) {
223 case WdfPowerDeviceD0:
224 FUNCTION_MSG("WdfPowerDeviceD1\n");
225 break;
226 case WdfPowerDeviceD1:
227 FUNCTION_MSG("WdfPowerDeviceD1\n");
228 break;
229 case WdfPowerDeviceD2:
230 FUNCTION_MSG("WdfPowerDeviceD2\n");
231 break;
232 case WdfPowerDeviceD3:
233 FUNCTION_MSG("WdfPowerDeviceD3\n");
234 if (xppdd->hiber_usage_kludge) {
235 FUNCTION_MSG("(but really WdfPowerDevicePrepareForHibernation)\n");
236 target_state = WdfPowerDevicePrepareForHibernation;
237 }
238 break;
239 case WdfPowerDeviceD3Final:
240 FUNCTION_MSG("WdfPowerDeviceD3Final\n");
241 break;
242 case WdfPowerDevicePrepareForHibernation:
243 FUNCTION_MSG("WdfPowerDevicePrepareForHibernation\n");
244 break;
245 default:
246 FUNCTION_MSG("Unknown WdfPowerDevice state %d\n", target_state);
247 break;
248 }
250 if (target_state == WdfPowerDevicePrepareForHibernation)
251 {
252 FUNCTION_MSG("not powering down as we are hibernating\n");
253 // should we set the backend state here so it's correct on resume???
254 }
256 /* Remove watch on backend state */
257 /* even if hibernate */
258 if (xppdd->device_callback) {
259 FUNCTION_MSG("Removing watch %s\n", xppdd->device);
260 RtlStringCbPrintfA(path, ARRAY_SIZE(path), "%s/state", xppdd->backend_path);
261 XenBus_RemWatch(xpdd, XBT_NIL, path, XenPci_BackendStateCallback, xppdd);
262 }
263 FUNCTION_EXIT();
265 return status;
266 }
268 static VOID
269 XenPciPdo_EvtDeviceUsageNotification(WDFDEVICE device, WDF_SPECIAL_FILE_TYPE notification_type, BOOLEAN is_in_notification_path)
270 {
271 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
273 FUNCTION_ENTER();
275 FUNCTION_MSG("path = %s\n", xppdd->path);
276 switch (notification_type)
277 {
278 case WdfSpecialFilePaging:
279 FUNCTION_MSG("notification_type = Paging, flag = %d\n", is_in_notification_path);
280 break;
281 case WdfSpecialFileHibernation:
282 xppdd->hiber_usage_kludge = is_in_notification_path;
283 FUNCTION_MSG("notification_type = Hibernation, flag = %d\n", is_in_notification_path);
284 break;
285 case WdfSpecialFileDump:
286 FUNCTION_MSG("notification_type = Dump, flag = %d\n", is_in_notification_path);
287 break;
288 default:
289 FUNCTION_MSG("notification_type = %d, flag = %d\n", notification_type, is_in_notification_path);
290 break;
291 }
293 FUNCTION_EXIT();
294 }
296 static VOID
297 XenPci_EvtDevicePnpStateChange(WDFDEVICE device, PCWDF_DEVICE_PNP_NOTIFICATION_DATA notification_data)
298 {
299 PXENPCI_PDO_DEVICE_DATA xppdd = GetXppdd(device);
301 //FUNCTION_ENTER();
303 if (xppdd->backend_initiated_remove
304 && notification_data->Type == StateNotificationEnterState
305 && notification_data->Data.EnterState.CurrentState == WdfDevStatePnpQueryRemovePending
306 && notification_data->Data.EnterState.NewState == WdfDevStatePnpQueryCanceled)
307 {
308 PXENPCI_DEVICE_DATA xpdd = GetXpdd(xppdd->wdf_device_bus_fdo);
310 FUNCTION_MSG("Eject failed, doing surprise removal\n");
311 xppdd->do_not_enumerate = TRUE;
312 XenPci_EvtChildListScanForChildren(xpdd->child_list);
313 }
315 //FUNCTION_EXIT();
317 //return STATUS_SUCCESS;
318 }
320 NTSTATUS
321 XenPci_EvtChildListCreateDevice(WDFCHILDLIST child_list,
322 PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER identification_header,
323 PWDFDEVICE_INIT child_init) {
324 NTSTATUS status = STATUS_SUCCESS;
325 WDF_OBJECT_ATTRIBUTES child_attributes;
326 WDFDEVICE child_device;
327 PXENPCI_PDO_IDENTIFICATION_DESCRIPTION identification = (PXENPCI_PDO_IDENTIFICATION_DESCRIPTION)identification_header;
328 WDF_DEVICE_PNP_CAPABILITIES child_pnp_capabilities;
329 DECLARE_UNICODE_STRING_SIZE(buffer, 512);
330 DECLARE_CONST_UNICODE_STRING(location, L"Xen Bus");
331 PXENPCI_PDO_DEVICE_DATA xppdd;
332 PXENPCI_DEVICE_DATA xpdd = GetXpdd(WdfChildListGetDevice(child_list));
333 //WDF_PDO_EVENT_CALLBACKS pdo_callbacks;
334 WDF_PNPPOWER_EVENT_CALLBACKS child_pnp_power_callbacks;
335 //UCHAR pnp_minor_functions[] = { IRP_MN_START_DEVICE };
336 WDF_DEVICE_POWER_CAPABILITIES child_power_capabilities;
338 FUNCTION_ENTER();
340 WdfDeviceInitSetDeviceType(child_init, FILE_DEVICE_UNKNOWN);
342 WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&child_pnp_power_callbacks);
343 child_pnp_power_callbacks.EvtDeviceD0Entry = XenPciPdo_EvtDeviceD0Entry;
344 child_pnp_power_callbacks.EvtDeviceD0Exit = XenPciPdo_EvtDeviceD0Exit;
345 child_pnp_power_callbacks.EvtDeviceUsageNotification = XenPciPdo_EvtDeviceUsageNotification;
346 WdfDeviceInitSetPnpPowerEventCallbacks(child_init, &child_pnp_power_callbacks);
348 FUNCTION_MSG("device = '%s', index = '%d', path = '%s'\n",
349 identification->device, identification->index, identification->path);
351 //status = WdfDeviceInitAssignWdmIrpPreprocessCallback(child_init, XenPciPdo_EvtDeviceWdmIrpPreprocess_START_DEVICE,
352 // IRP_MJ_PNP, pnp_minor_functions, ARRAY_SIZE(pnp_minor_functions));
353 //if (!NT_SUCCESS(status)) {
354 // return status;
355 //}
357 //WDF_PDO_EVENT_CALLBACKS_INIT(&pdo_callbacks);
358 //pdo_callbacks.EvtDeviceResourcesQuery = XenPciPdo_EvtDeviceResourcesQuery;
359 //pdo_callbacks.EvtDeviceResourceRequirementsQuery = XenPciPdo_EvtDeviceResourceRequirementsQuery;
360 //pdo_callbacks.EvtDeviceEject = XenPciPdo_EvtDeviceEject;
361 //pdo_callbacks.EvtDeviceSetLock = XenPciPdo_EvtDeviceSetLock;
362 //WdfPdoInitSetEventCallbacks(child_init, &pdo_callbacks);
364 RtlUnicodeStringPrintf(&buffer, L"xen\\%S", identification->device);
365 status = WdfPdoInitAssignDeviceID(child_init, &buffer);
366 if (!NT_SUCCESS(status))
367 {
368 return status;
369 }
370 status = WdfPdoInitAddHardwareID(child_init, &buffer);
371 if (!NT_SUCCESS(status))
372 {
373 return status;
374 }
375 status = WdfPdoInitAddCompatibleID(child_init, &buffer);
376 if (!NT_SUCCESS(status))
377 {
378 return status;
379 }
381 RtlUnicodeStringPrintf(&buffer, L"%02d", identification->index);
382 status = WdfPdoInitAssignInstanceID(child_init, &buffer);
383 if (!NT_SUCCESS(status))
384 {
385 return status;
386 }
388 RtlUnicodeStringPrintf(&buffer, L"Xen %S device #%d", identification->device, identification->index);
389 status = WdfPdoInitAddDeviceText(child_init, &buffer, &location, 0x0409);
390 if (!NT_SUCCESS(status))
391 {
392 return status;
393 }
394 WdfPdoInitSetDefaultLocale(child_init, 0x0409);
396 WdfDeviceInitSetPowerNotPageable(child_init);
398 WdfDeviceInitRegisterPnpStateChangeCallback(child_init, WdfDevStatePnpQueryCanceled, XenPci_EvtDevicePnpStateChange, StateNotificationEnterState);
400 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&child_attributes, XENPCI_PDO_DEVICE_DATA);
401 status = WdfDeviceCreate(&child_init, &child_attributes, &child_device);
402 if (!NT_SUCCESS(status))
403 {
404 return status;
405 }
407 xppdd = GetXppdd(child_device);
409 xppdd->wdf_device = child_device;
410 xppdd->wdf_device_bus_fdo = WdfChildListGetDevice(child_list);
411 xppdd->xpdd = xpdd;
413 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFilePaging, TRUE);
414 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileHibernation, TRUE);
415 WdfDeviceSetSpecialFileSupport(child_device, WdfSpecialFileDump, TRUE);
417 WDF_DEVICE_PNP_CAPABILITIES_INIT(&child_pnp_capabilities);
418 child_pnp_capabilities.LockSupported = WdfFalse;
419 child_pnp_capabilities.EjectSupported = WdfTrue;
420 child_pnp_capabilities.Removable = WdfTrue;
421 child_pnp_capabilities.DockDevice = WdfFalse;
422 child_pnp_capabilities.UniqueID = WdfFalse;
423 child_pnp_capabilities.SilentInstall = WdfTrue;
424 child_pnp_capabilities.SurpriseRemovalOK = WdfTrue;
425 child_pnp_capabilities.HardwareDisabled = WdfFalse;
426 WdfDeviceSetPnpCapabilities(child_device, &child_pnp_capabilities);
428 WDF_DEVICE_POWER_CAPABILITIES_INIT(&child_power_capabilities);
429 child_power_capabilities.DeviceD1 = WdfTrue;
430 child_power_capabilities.WakeFromD1 = WdfTrue;
431 child_power_capabilities.DeviceWake = PowerDeviceD1;
432 child_power_capabilities.DeviceState[PowerSystemWorking] = PowerDeviceD0;
433 child_power_capabilities.DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
434 child_power_capabilities.DeviceState[PowerSystemSleeping2] = PowerDeviceD2;
435 child_power_capabilities.DeviceState[PowerSystemSleeping3] = PowerDeviceD2;
436 child_power_capabilities.DeviceState[PowerSystemHibernate] = PowerDeviceD3;
437 child_power_capabilities.DeviceState[PowerSystemShutdown] = PowerDeviceD3;
438 WdfDeviceSetPowerCapabilities(child_device, &child_power_capabilities);
440 RtlStringCbCopyA(xppdd->path, ARRAY_SIZE(xppdd->path), identification->path);
441 RtlStringCbCopyA(xppdd->device, ARRAY_SIZE(xppdd->device), identification->device);
442 xppdd->index = identification->index;
443 KeInitializeEvent(&xppdd->backend_state_event, SynchronizationEvent, FALSE);
444 ExInitializeFastMutex(&xppdd->backend_state_mutex);
445 xppdd->backend_state = XenbusStateUnknown;
446 xppdd->frontend_state = XenbusStateUnknown;
447 xppdd->backend_path[0] = '\0';
448 xppdd->backend_id = 0;
450 FUNCTION_EXIT();
452 return status;