[bus] Don't use winvblock__def_struct for bus__type
[people/sha0/winvblock.git] / src / winvblock / bus / 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  * Bus PnP IRP handling.
26  */
27
28 #include <ntddk.h>
29
30 #include "winvblock.h"
31 #include "wv_stdlib.h"
32 #include "portable.h"
33 #include "irp.h"
34 #include "driver.h"
35 #include "device.h"
36 #include "disk.h"
37 #include "bus.h"
38 #include "debug.h"
39 #include "probe.h"
40
41 static NTSTATUS STDCALL
42 Bus_IoCompletionRoutine (
43   IN PDEVICE_OBJECT DeviceObject,
44   IN PIRP Irp,
45   IN PKEVENT Event
46  )
47 {
48   KeSetEvent ( Event, 0, FALSE );
49   return STATUS_MORE_PROCESSING_REQUIRED;
50 }
51
52 NTSTATUS STDCALL bus_pnp__start_dev(
53     IN PDEVICE_OBJECT DeviceObject,
54     IN PIRP Irp,
55     IN PIO_STACK_LOCATION Stack,
56     IN struct _device__type * dev_ptr,
57     OUT winvblock__bool_ptr completion_ptr
58   )
59 {
60   NTSTATUS status;
61   KEVENT event;
62   struct bus__type * bus_ptr;
63
64   bus_ptr = bus__get(dev_ptr);
65   KeInitializeEvent ( &event, NotificationEvent, FALSE );
66   IoCopyCurrentIrpStackLocationToNext ( Irp );
67   IoSetCompletionRoutine ( Irp,
68                            ( PIO_COMPLETION_ROUTINE ) Bus_IoCompletionRoutine,
69                            ( void * )&event, TRUE, TRUE, TRUE );
70   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
71   if ( status == STATUS_PENDING )
72     {
73       DBG ( "Locked\n" );
74       KeWaitForSingleObject ( &event, Executive, KernelMode, FALSE, NULL );
75     }
76   if ( NT_SUCCESS ( status = Irp->IoStatus.Status ) )
77     {
78       dev_ptr->OldState = dev_ptr->State;
79       dev_ptr->State = Started;
80     }
81   status = STATUS_SUCCESS;
82   Irp->IoStatus.Status = status;
83   IoCompleteRequest ( Irp, IO_NO_INCREMENT );
84   *completion_ptr = TRUE;
85   return status;
86 }
87
88 NTSTATUS STDCALL bus_pnp__remove_dev(
89     IN PDEVICE_OBJECT DeviceObject,
90     IN PIRP Irp,
91     IN PIO_STACK_LOCATION Stack,
92     IN struct _device__type * dev_ptr,
93     OUT winvblock__bool_ptr completion_ptr
94   )
95 {
96   NTSTATUS status;
97   struct bus__type * bus_ptr;
98   device__type_ptr walker,
99    next;
100
101   dev_ptr->OldState = dev_ptr->State;
102   dev_ptr->State = Deleted;
103   Irp->IoStatus.Information = 0;
104   Irp->IoStatus.Status = STATUS_SUCCESS;
105   IoSkipCurrentIrpStackLocation ( Irp );
106   bus_ptr = bus__get(dev_ptr);
107   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
108   walker = bus_ptr->first_child_ptr;
109   while ( walker != NULL )
110     {
111       next = walker->next_sibling_ptr;
112       device__close ( walker );
113       IoDeleteDevice ( walker->Self );
114       device__free ( walker );
115       walker = next;
116     }
117   bus_ptr->Children = 0;
118   bus_ptr->first_child_ptr = NULL;
119   IoDetachDevice ( bus_ptr->LowerDeviceObject );
120   IoDeleteDevice ( dev_ptr->Self );
121   device__free ( dev_ptr );
122   *completion_ptr = TRUE;
123   return status;
124 }
125
126 NTSTATUS STDCALL bus_pnp__query_dev_relations(
127     IN PDEVICE_OBJECT DeviceObject,
128     IN PIRP Irp,
129     IN PIO_STACK_LOCATION Stack,
130     IN struct _device__type * dev_ptr,
131     OUT winvblock__bool_ptr completion_ptr
132   )
133 {
134   NTSTATUS status;
135   struct bus__type * bus_ptr;
136   winvblock__uint32 count;
137   device__type_ptr walker;
138   PDEVICE_RELATIONS dev_relations;
139
140   bus_ptr = bus__get(dev_ptr);
141   if ( Stack->Parameters.QueryDeviceRelations.Type != BusRelations
142        || Irp->IoStatus.Information )
143     {
144       status = Irp->IoStatus.Status;
145       IoSkipCurrentIrpStackLocation ( Irp );
146       status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
147       *completion_ptr = TRUE;
148       return status;
149     }
150   probe__disks (  );
151   count = 0;
152   walker = bus_ptr->first_child_ptr;
153   while ( walker != NULL )
154     {
155       count++;
156       walker = walker->next_sibling_ptr;
157     }
158   dev_relations = wv_malloc(
159       sizeof *dev_relations + (sizeof (PDEVICE_OBJECT) * count)
160     );
161   if ( dev_relations == NULL )
162     {
163       Irp->IoStatus.Information = 0;
164       status = STATUS_INSUFFICIENT_RESOURCES;
165       Irp->IoStatus.Status = status;
166       IoSkipCurrentIrpStackLocation ( Irp );
167       status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
168       *completion_ptr = TRUE;
169       return status;
170     }
171   dev_relations->Count = count;
172
173   count = 0;
174   walker = bus_ptr->first_child_ptr;
175   while ( walker != NULL )
176     {
177       ObReferenceObject ( walker->Self );
178       dev_relations->Objects[count] = walker->Self;
179       count++;
180       walker = walker->next_sibling_ptr;
181     }
182   Irp->IoStatus.Information = ( ULONG_PTR ) dev_relations;
183   status = STATUS_SUCCESS;
184   Irp->IoStatus.Status = status;
185   IoSkipCurrentIrpStackLocation ( Irp );
186   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
187   *completion_ptr = TRUE;
188   return status;
189 }
190
191 NTSTATUS STDCALL bus_pnp__simple(
192     IN PDEVICE_OBJECT DeviceObject,
193     IN PIRP Irp,
194     IN PIO_STACK_LOCATION Stack,
195     IN struct _device__type * dev_ptr,
196     OUT winvblock__bool_ptr completion_ptr
197   )
198 {
199   NTSTATUS status;
200   struct bus__type * bus_ptr;
201
202   bus_ptr = bus__get(dev_ptr);
203   switch ( Stack->MinorFunction )
204     {
205       case IRP_MN_QUERY_PNP_DEVICE_STATE:
206         Irp->IoStatus.Information = 0;
207         status = STATUS_SUCCESS;
208         break;
209       case IRP_MN_QUERY_STOP_DEVICE:
210         dev_ptr->OldState = dev_ptr->State;
211         dev_ptr->State = StopPending;
212         status = STATUS_SUCCESS;
213         break;
214       case IRP_MN_CANCEL_STOP_DEVICE:
215         dev_ptr->State = dev_ptr->OldState;
216         status = STATUS_SUCCESS;
217         break;
218       case IRP_MN_STOP_DEVICE:
219         dev_ptr->OldState = dev_ptr->State;
220         dev_ptr->State = Stopped;
221         status = STATUS_SUCCESS;
222         break;
223       case IRP_MN_QUERY_REMOVE_DEVICE:
224         dev_ptr->OldState = dev_ptr->State;
225         dev_ptr->State = RemovePending;
226         status = STATUS_SUCCESS;
227         break;
228       case IRP_MN_CANCEL_REMOVE_DEVICE:
229         dev_ptr->State = dev_ptr->OldState;
230         status = STATUS_SUCCESS;
231         break;
232       case IRP_MN_SURPRISE_REMOVAL:
233         dev_ptr->OldState = dev_ptr->State;
234         dev_ptr->State = SurpriseRemovePending;
235         status = STATUS_SUCCESS;
236         break;
237       default:
238         status = Irp->IoStatus.Status;
239     }
240
241   Irp->IoStatus.Status = status;
242   IoSkipCurrentIrpStackLocation ( Irp );
243   status = IoCallDriver ( bus_ptr->LowerDeviceObject, Irp );
244   *completion_ptr = TRUE;
245   return status;
246 }