[bus/pnp,disk/pnp,aoe] Get AoE sub-bus to work
[people/sha0/winvblock.git] / src / winvblock / disk / pnp.c
1 /**
2  * Copyright (C) 2009-2010, 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 "device.h"
37 #include "disk.h"
38 #include "bus.h"
39 #include "debug.h"
40
41 /* Forward declarations. */
42 static device__dispatch_func disk_pnp__query_dev_text_;
43 static device__dispatch_func disk_pnp__query_dev_relations_;
44 static device__dispatch_func disk_pnp__query_bus_info_;
45 static device__dispatch_func disk_pnp__query_capabilities_;
46 static device__pnp_func disk_pnp__simple_;
47 device__pnp_func disk_pnp__dispatch;
48
49 static NTSTATUS STDCALL disk_pnp__query_dev_text_(
50     IN struct device__type * dev,
51     IN PIRP irp
52   ) {
53     disk__type_ptr disk;
54     WCHAR (*str)[512];
55     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
56     NTSTATUS status;
57     winvblock__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, winvblock__literal_w 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 = device__pnp_id(
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 struct device__type * 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 struct device__type * 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 struct device__type * 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     disk__type_ptr disk;
207     struct bus__type * bus;
208     DEVICE_CAPABILITIES ParentDeviceCapabilities;
209     PDEVICE_OBJECT bus_lower;
210
211     if (DeviceCapabilities->Version != 1 ||
212         DeviceCapabilities->Size < sizeof (DEVICE_CAPABILITIES)
213       ) {
214         status = STATUS_UNSUCCESSFUL;
215         goto out;
216       }
217     disk = disk__get_ptr(dev);
218     bus = bus__get(device__get(dev->Parent));
219     bus_lower = bus->LowerDeviceObject;
220     if (bus_lower) {
221         status = bus__get_dev_capabilities(
222             bus_lower,
223             &ParentDeviceCapabilities
224           );
225       } else {
226         status = bus__get_dev_capabilities(
227             bus->device->Self,
228             &ParentDeviceCapabilities
229           );
230       }      
231     if (!NT_SUCCESS(status))
232       goto out;
233
234     RtlCopyMemory(
235         DeviceCapabilities->DeviceState,
236         ParentDeviceCapabilities.DeviceState,
237         (PowerSystemShutdown + 1) * sizeof (DEVICE_POWER_STATE)
238       );
239     DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
240     if (DeviceCapabilities->DeviceState[PowerSystemSleeping1] != PowerDeviceD0)
241       DeviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1;
242     if (DeviceCapabilities->DeviceState[PowerSystemSleeping2] != PowerDeviceD0)
243       DeviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
244     #if 0
245     if (DeviceCapabilities->DeviceState[PowerSystemSleeping3] != PowerDeviceD0)
246       DeviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
247     #endif
248     DeviceCapabilities->DeviceWake = PowerDeviceD1;
249     DeviceCapabilities->DeviceD1 = TRUE;
250     DeviceCapabilities->DeviceD2 = FALSE;
251     DeviceCapabilities->WakeFromD0 = FALSE;
252     DeviceCapabilities->WakeFromD1 = FALSE;
253     DeviceCapabilities->WakeFromD2 = FALSE;
254     DeviceCapabilities->WakeFromD3 = FALSE;
255     DeviceCapabilities->D1Latency = 0;
256     DeviceCapabilities->D2Latency = 0;
257     DeviceCapabilities->D3Latency = 0;
258     DeviceCapabilities->EjectSupported = FALSE;
259     DeviceCapabilities->HardwareDisabled = FALSE;
260     DeviceCapabilities->Removable = disk__removable[disk->media];
261     DeviceCapabilities->SurpriseRemovalOK = FALSE;
262     DeviceCapabilities->UniqueID = FALSE;
263     DeviceCapabilities->SilentInstall = FALSE;
264     #if 0
265     DeviceCapabilities->Address = dev->Self->SerialNo;
266     DeviceCapabilities->UINumber = dev->Self->SerialNo;
267     #endif
268     status = STATUS_SUCCESS;
269
270     out:
271     irp->IoStatus.Status = status;
272     IoCompleteRequest(irp, IO_NO_INCREMENT);
273     return status;
274   }
275
276 static NTSTATUS STDCALL disk_pnp__simple_(
277     IN struct device__type * dev,
278     IN PIRP irp,
279     IN UCHAR code
280   ) {
281     disk__type_ptr disk = disk__get_ptr(dev);
282     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
283     NTSTATUS status;
284
285     switch (code) {
286         case IRP_MN_DEVICE_USAGE_NOTIFICATION:
287           DBG("disk_pnp: IRP_MN_DEVICE_USAGE_NOTIFICATION\n");
288           if (io_stack_loc->Parameters.UsageNotification.InPath) {
289               disk->SpecialFileCount++;
290             } else {
291               disk->SpecialFileCount--;
292             }
293           irp->IoStatus.Information = 0;
294           status = STATUS_SUCCESS;
295           break;
296
297         case IRP_MN_QUERY_PNP_DEVICE_STATE:
298           DBG("disk_pnp: IRP_MN_QUERY_PNP_DEVICE_STATE\n");
299           irp->IoStatus.Information = 0;
300           status = STATUS_SUCCESS;
301           break;
302
303         case IRP_MN_START_DEVICE:
304           DBG("disk_pnp: IRP_MN_START_DEVICE\n");
305           dev->old_state = dev->state;
306           dev->state = device__state_started;
307           status = STATUS_SUCCESS;
308           break;
309
310         case IRP_MN_QUERY_STOP_DEVICE:
311           DBG("disk_pnp: IRP_MN_QUERY_STOP_DEVICE\n");
312           dev->old_state = dev->state;
313           dev->state = device__state_stop_pending;
314           status = STATUS_SUCCESS;
315           break;
316
317         case IRP_MN_CANCEL_STOP_DEVICE:
318           DBG("disk_pnp: IRP_MN_CANCEL_STOP_DEVICE\n");
319           dev->state = dev->old_state;
320           status = STATUS_SUCCESS;
321           break;
322
323         case IRP_MN_STOP_DEVICE:
324           DBG("disk_pnp: IRP_MN_STOP_DEVICE\n");
325           dev->old_state = dev->state;
326           dev->state = device__state_stopped;
327           status = STATUS_SUCCESS;
328           break;
329
330         case IRP_MN_QUERY_REMOVE_DEVICE:
331           DBG("disk_pnp: IRP_MN_QUERY_REMOVE_DEVICE\n");
332           dev->old_state = dev->state;
333           dev->state = device__state_remove_pending;
334           status = STATUS_SUCCESS;
335           break;
336
337         case IRP_MN_REMOVE_DEVICE:
338           DBG("disk_pnp: IRP_MN_REMOVE_DEVICE\n");
339           dev->old_state = dev->state;
340           dev->state = device__state_not_started;
341           if (disk->Unmount) {
342               device__close(dev);
343               IoDeleteDevice(dev->Self);
344               device__free(dev);
345               status = STATUS_NO_SUCH_DEVICE;
346             } else {
347               status = STATUS_SUCCESS;
348             }
349           break;
350
351         case IRP_MN_CANCEL_REMOVE_DEVICE:
352           DBG("disk_pnp: IRP_MN_CANCEL_REMOVE_DEVICE\n");
353           dev->state = dev->old_state;
354           status = STATUS_SUCCESS;
355           break;
356
357         case IRP_MN_SURPRISE_REMOVAL:
358           DBG("disk_pnp: IRP_MN_SURPRISE_REMOVAL\n");
359           dev->old_state = dev->state;
360           dev->state = device__state_surprise_remove_pending;
361           status = STATUS_SUCCESS;
362           break;
363
364         default:
365           DBG("disk_pnp: Unhandled IRP_MN_*: %d\n", code);
366           status = irp->IoStatus.Status;
367       }
368
369     irp->IoStatus.Status = status;
370     IoCompleteRequest(irp, IO_NO_INCREMENT);
371     return status;
372   }
373
374 /* Disk PnP dispatch routine. */
375 NTSTATUS STDCALL disk_pnp__dispatch(
376     IN struct device__type * dev,
377     IN PIRP irp,
378     IN UCHAR code
379   ) {
380     switch (code) {
381         case IRP_MN_QUERY_ID:
382           DBG("disk_pnp: IIRP_MN_QUERY_ID\n");
383           return device__pnp_query_id(dev, irp);
384
385         case IRP_MN_QUERY_DEVICE_TEXT:
386           DBG("disk_pnp: IRP_MN_QUERY_DEVICE_TEXT\n");
387           return disk_pnp__query_dev_text_(dev, irp);
388
389         case IRP_MN_QUERY_DEVICE_RELATIONS:
390           DBG("disk_pnp: IRP_MN_QUERY_DEVICE_RELATIONS\n");
391           return disk_pnp__query_dev_relations_(dev, irp);
392
393         case IRP_MN_QUERY_BUS_INFORMATION:
394           DBG("disk_pnp: IRP_MN_QUERY_BUS_INFORMATION\n");
395           return disk_pnp__query_bus_info_(dev, irp);
396
397         case IRP_MN_QUERY_CAPABILITIES:
398           DBG("disk_pnp: IRP_MN_QUERY_CAPABILITIES\n");
399           return disk_pnp__query_capabilities_(dev, irp);
400
401         default:
402           return disk_pnp__simple_(dev, irp, code);
403       }
404   }