[project] Rename winvblock__uint32 back to UINT32
[people/sha0/winvblock.git] / src / winvblock / disk / pnp.c
1 /**
2  * Copyright (C) 2009-2011, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  * Copyright 2006-2008, V.
4  * For WinAoE contact information, see http://winaoe.org/
5  *
6  * This file is part of WinVBlock, derived from WinAoE.
7  *
8  * WinVBlock is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * WinVBlock is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23  * @file
24  *
25  * Disk PnP IRP handling.
26  */
27
28 #include <stdio.h>
29 #include <ntddk.h>
30 #include <initguid.h>
31
32 #include "winvblock.h"
33 #include "wv_stdlib.h"
34 #include "portable.h"
35 #include "driver.h"
36 #include "bus.h"
37 #include "device.h"
38 #include "disk.h"
39 #include "debug.h"
40
41 /* Forward declarations. */
42 static WV_F_DEV_DISPATCH disk_pnp__query_dev_text_;
43 static WV_F_DEV_DISPATCH disk_pnp__query_dev_relations_;
44 static WV_F_DEV_DISPATCH disk_pnp__query_bus_info_;
45 static WV_F_DEV_DISPATCH disk_pnp__query_capabilities_;
46 static WV_F_DEV_PNP disk_pnp__simple_;
47 WV_F_DEV_PNP disk_pnp__dispatch;
48
49 static NTSTATUS STDCALL disk_pnp__query_dev_text_(
50     IN WV_SP_DEV_T dev,
51     IN PIRP irp
52   ) {
53     WV_SP_DISK_T disk;
54     WCHAR (*str)[512];
55     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
56     NTSTATUS status;
57     UINT32 str_len;
58
59     disk = disk__get_ptr(dev);
60     /* Allocate a string buffer. */
61     str = wv_mallocz(sizeof *str);
62     if (str == NULL) {
63         DBG("wv_malloc IRP_MN_QUERY_DEVICE_TEXT\n");
64         status = STATUS_INSUFFICIENT_RESOURCES;
65         goto alloc_str;
66       }
67     /* Determine the query type. */
68     switch (io_stack_loc->Parameters.QueryDeviceText.DeviceTextType) {
69         case DeviceTextDescription:
70           str_len = swprintf(*str, WVL_M_WLIT L" Disk") + 1;
71           irp->IoStatus.Information =
72             (ULONG_PTR) wv_palloc(str_len * sizeof *str);
73           if (irp->IoStatus.Information == 0) {
74               DBG("wv_palloc DeviceTextDescription\n");
75               status = STATUS_INSUFFICIENT_RESOURCES;
76               goto alloc_info;
77             }
78           RtlCopyMemory(
79               (PWCHAR) irp->IoStatus.Information,
80               str,
81               str_len * sizeof (WCHAR)
82             );
83           status = STATUS_SUCCESS;
84           goto alloc_info;
85
86         case DeviceTextLocationInformation:
87           str_len = WvDevPnpId(
88               dev,
89               BusQueryInstanceID,
90               str
91             );
92           irp->IoStatus.Information =
93             (ULONG_PTR) wv_palloc(str_len * sizeof *str);
94           if (irp->IoStatus.Information == 0) {
95               DBG("wv_palloc DeviceTextLocationInformation\n");
96               status = STATUS_INSUFFICIENT_RESOURCES;
97               goto alloc_info;
98             }
99           RtlCopyMemory(
100               (PWCHAR) irp->IoStatus.Information,
101               str,
102               str_len * sizeof (WCHAR)
103             );
104           status = STATUS_SUCCESS;
105           goto alloc_info;
106
107         default:
108           irp->IoStatus.Information = 0;
109           status = STATUS_NOT_SUPPORTED;
110       }
111     /* irp->IoStatus.Information not freed. */
112     alloc_info:
113
114     wv_free(str);
115     alloc_str:
116
117     return driver__complete_irp(irp, irp->IoStatus.Information, status);
118   }
119
120 static NTSTATUS STDCALL disk_pnp__query_dev_relations_(
121     IN WV_SP_DEV_T dev,
122     IN PIRP irp
123   ) {
124     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
125     NTSTATUS status;
126     PDEVICE_RELATIONS dev_relations;
127
128     if (io_stack_loc->Parameters.QueryDeviceRelations.Type !=
129         TargetDeviceRelation
130       ) {
131         status = irp->IoStatus.Status;
132         goto out;
133       }
134     dev_relations = wv_palloc(sizeof *dev_relations + sizeof dev->Self);
135     if (dev_relations == NULL) {
136         DBG("wv_palloc IRP_MN_QUERY_DEVICE_RELATIONS\n");
137         status = STATUS_INSUFFICIENT_RESOURCES;
138         goto alloc_dev_relations;
139       }
140     dev_relations->Objects[0] = dev->Self;
141     dev_relations->Count = 1;
142     ObReferenceObject(dev->Self);
143     irp->IoStatus.Information = (ULONG_PTR) dev_relations;
144     status = STATUS_SUCCESS;
145
146     /* irp->IoStatus.Information (dev_relations) not freed. */
147     alloc_dev_relations:
148
149     out:
150
151     irp->IoStatus.Status = status;
152     IoCompleteRequest(irp, IO_NO_INCREMENT);
153     return status;
154   }
155
156 DEFINE_GUID(
157     GUID_BUS_TYPE_INTERNAL,
158     0x2530ea73L,
159     0x086b,
160     0x11d1,
161     0xa0,
162     0x9f,
163     0x00,
164     0xc0,
165     0x4f,
166     0xc3,
167     0x40,
168     0xb1
169   );
170
171 static NTSTATUS STDCALL disk_pnp__query_bus_info_(
172     IN WV_SP_DEV_T dev,
173     IN PIRP irp
174   ) {
175     PPNP_BUS_INFORMATION pnp_bus_info;
176     NTSTATUS status;
177
178     pnp_bus_info = wv_palloc(sizeof *pnp_bus_info);
179     if (pnp_bus_info == NULL) {
180         DBG("wv_palloc IRP_MN_QUERY_BUS_INFORMATION\n");
181         status = STATUS_INSUFFICIENT_RESOURCES;
182         goto alloc_pnp_bus_info;
183       }
184     pnp_bus_info->BusTypeGuid = GUID_BUS_TYPE_INTERNAL;
185     pnp_bus_info->LegacyBusType = PNPBus;
186     pnp_bus_info->BusNumber = 0;
187     irp->IoStatus.Information = (ULONG_PTR) pnp_bus_info;
188     status = STATUS_SUCCESS;
189
190     /* irp-IoStatus.Information (pnp_bus_info) not freed. */
191     alloc_pnp_bus_info:
192
193     irp->IoStatus.Status = status;
194     IoCompleteRequest(irp, IO_NO_INCREMENT);
195     return status;
196   }
197
198 static NTSTATUS STDCALL disk_pnp__query_capabilities_(
199     IN WV_SP_DEV_T dev,
200     IN PIRP irp
201   ) {
202     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
203     PDEVICE_CAPABILITIES DeviceCapabilities =
204       io_stack_loc->Parameters.DeviceCapabilities.Capabilities;
205     NTSTATUS status;
206     WV_SP_DISK_T disk;
207     DEVICE_CAPABILITIES ParentDeviceCapabilities;
208
209     if (DeviceCapabilities->Version != 1 ||
210         DeviceCapabilities->Size < sizeof (DEVICE_CAPABILITIES)
211       ) {
212         status = STATUS_UNSUCCESSFUL;
213         goto out;
214       }
215     disk = disk__get_ptr(dev);
216     status = WvDriverGetDevCapabilities(dev->Parent, &ParentDeviceCapabilities);
217     if (!NT_SUCCESS(status))
218       goto out;
219
220     RtlCopyMemory(
221         DeviceCapabilities->DeviceState,
222         ParentDeviceCapabilities.DeviceState,
223         (PowerSystemShutdown + 1) * sizeof (DEVICE_POWER_STATE)
224       );
225     DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
226     if (DeviceCapabilities->DeviceState[PowerSystemSleeping1] != PowerDeviceD0)
227       DeviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
228     if (DeviceCapabilities->DeviceState[PowerSystemSleeping2] != PowerDeviceD0)
229       DeviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
230     #if 0
231     if (DeviceCapabilities->DeviceState[PowerSystemSleeping3] != PowerDeviceD0)
232       DeviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
233     #endif
234     DeviceCapabilities->DeviceWake = PowerDeviceD1;
235     DeviceCapabilities->DeviceD1 = TRUE;
236     DeviceCapabilities->DeviceD2 = FALSE;
237     DeviceCapabilities->WakeFromD0 = FALSE;
238     DeviceCapabilities->WakeFromD1 = FALSE;
239     DeviceCapabilities->WakeFromD2 = FALSE;
240     DeviceCapabilities->WakeFromD3 = FALSE;
241     DeviceCapabilities->D1Latency = 0;
242     DeviceCapabilities->D2Latency = 0;
243     DeviceCapabilities->D3Latency = 0;
244     DeviceCapabilities->EjectSupported = FALSE;
245     DeviceCapabilities->HardwareDisabled = FALSE;
246     DeviceCapabilities->Removable = WvDiskIsRemovable[disk->Media];
247     DeviceCapabilities->SurpriseRemovalOK = FALSE;
248     DeviceCapabilities->UniqueID = FALSE;
249     DeviceCapabilities->SilentInstall = FALSE;
250     #if 0
251     DeviceCapabilities->Address = dev->Self->SerialNo;
252     DeviceCapabilities->UINumber = dev->Self->SerialNo;
253     #endif
254     status = STATUS_SUCCESS;
255
256     out:
257     irp->IoStatus.Status = status;
258     IoCompleteRequest(irp, IO_NO_INCREMENT);
259     return status;
260   }
261
262 static NTSTATUS STDCALL disk_pnp__simple_(
263     IN WV_SP_DEV_T dev,
264     IN PIRP irp,
265     IN UCHAR code
266   ) {
267     WV_SP_DISK_T disk = disk__get_ptr(dev);
268     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
269     NTSTATUS status;
270
271     switch (code) {
272         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
273           DBG("disk_pnp: IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
274           if (io_stack_loc->Parameters.UsageNotification.InPath) {
275               disk->SpecialFileCount++;
276             } else {
277               disk->SpecialFileCount--;
278             }
279           irp->IoStatus.Information = 0;
280           status = STATUS_SUCCESS;
281           break;
282
283         case IRP_MN_QUERY_PNP_DEVICE_STATE:
284           DBG("disk_pnp: IRP_MN_QUERY_PNP_DEVICE_STATE\n");
285           irp->IoStatus.Information = 0;
286           status = STATUS_SUCCESS;
287           break;
288
289         case IRP_MN_START_DEVICE:
290           DBG("disk_pnp: IRP_MN_START_DEVICE\n");
291           dev->OldState = dev->State;
292           dev->State = WvDevStateStarted;
293           status = STATUS_SUCCESS;
294           break;
295
296         case IRP_MN_QUERY_STOP_DEVICE:
297           DBG("disk_pnp: IRP_MN_QUERY_STOP_DEVICE\n");
298           dev->OldState = dev->State;
299           dev->State = WvDevStateStopPending;
300           status = STATUS_SUCCESS;
301           break;
302
303         case IRP_MN_CANCEL_STOP_DEVICE:
304           DBG("disk_pnp: IRP_MN_CANCEL_STOP_DEVICE\n");
305           dev->State = dev->OldState;
306           status = STATUS_SUCCESS;
307           break;
308
309         case IRP_MN_STOP_DEVICE:
310           DBG("disk_pnp: IRP_MN_STOP_DEVICE\n");
311           dev->OldState = dev->State;
312           dev->State = WvDevStateStopped;
313           status = STATUS_SUCCESS;
314           break;
315
316         case IRP_MN_QUERY_REMOVE_DEVICE:
317           DBG("disk_pnp: IRP_MN_QUERY_REMOVE_DEVICE\n");
318           dev->OldState = dev->State;
319           dev->State = WvDevStateRemovePending;
320           status = STATUS_SUCCESS;
321           break;
322
323         case IRP_MN_REMOVE_DEVICE:
324           DBG("disk_pnp: IRP_MN_REMOVE_DEVICE\n");
325           dev->OldState = dev->State;
326           dev->State = WvDevStateNotStarted;
327           if (disk->Unmount) {
328               WvDevClose(dev);
329               IoDeleteDevice(dev->Self);
330               WvDevFree(dev);
331               status = STATUS_NO_SUCH_DEVICE;
332             } else {
333               status = STATUS_SUCCESS;
334             }
335           break;
336
337         case IRP_MN_CANCEL_REMOVE_DEVICE:
338           DBG("disk_pnp: IRP_MN_CANCEL_REMOVE_DEVICE\n");
339           dev->State = dev->OldState;
340           status = STATUS_SUCCESS;
341           break;
342
343         case IRP_MN_SURPRISE_REMOVAL:
344           DBG("disk_pnp: IRP_MN_SURPRISE_REMOVAL\n");
345           dev->OldState = dev->State;
346           dev->State = WvDevStateSurpriseRemovePending;
347           status = STATUS_SUCCESS;
348           break;
349
350         default:
351           DBG("disk_pnp: Unhandled IRP_MN_*: %d\n", code);
352           status = irp->IoStatus.Status;
353       }
354
355     irp->IoStatus.Status = status;
356     IoCompleteRequest(irp, IO_NO_INCREMENT);
357     return status;
358   }
359
360 /* Disk PnP dispatch routine. */
361 NTSTATUS STDCALL disk_pnp__dispatch(
362     IN WV_SP_DEV_T dev,
363     IN PIRP irp,
364     IN UCHAR code
365   ) {
366     switch (code) {
367         case IRP_MN_QUERY_ID:
368           DBG("disk_pnp: IIRP_MN_QUERY_ID\n");
369           return WvDevPnpQueryId(dev, irp);
370
371         case IRP_MN_QUERY_DEVICE_TEXT:
372           DBG("disk_pnp: IRP_MN_QUERY_DEVICE_TEXT\n");
373           return disk_pnp__query_dev_text_(dev, irp);
374
375         case IRP_MN_QUERY_DEVICE_RELATIONS:
376           DBG("disk_pnp: IRP_MN_QUERY_DEVICE_RELATIONS\n");
377           return disk_pnp__query_dev_relations_(dev, irp);
378
379         case IRP_MN_QUERY_BUS_INFORMATION:
380           DBG("disk_pnp: IRP_MN_QUERY_BUS_INFORMATION\n");
381           return disk_pnp__query_bus_info_(dev, irp);
382
383         case IRP_MN_QUERY_CAPABILITIES:
384           DBG("disk_pnp: IRP_MN_QUERY_CAPABILITIES\n");
385           return disk_pnp__query_capabilities_(dev, irp);
386
387         default:
388           return disk_pnp__simple_(dev, irp, code);
389       }
390   }