78ec7d78a6bc3fd88500d59ee41391e09107b39b
[people/sha0/winvblock.git] / src / winvblock / bus / dev_ctl.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 Device Control IRP handling.
26  */
27
28 #include <ntddk.h>
29
30 #include "winvblock.h"
31 #include "portable.h"
32 #include "irp.h"
33 #include "driver.h"
34 #include "device.h"
35 #include "disk.h"
36 #include "mount.h"
37 #include "bus.h"
38 #include "debug.h"
39 #include "filedisk.h"
40
41 static NTSTATUS STDCALL disk_detach(
42     IN PDEVICE_OBJECT dev_obj,
43     IN PIRP irp,
44     IN PIO_STACK_LOCATION io_stack_loc,
45     IN struct device__type * dev,
46     OUT winvblock__bool_ptr completion
47   ) {
48     winvblock__uint8_ptr buffer = irp->AssociatedIrp.SystemBuffer;
49     winvblock__uint32 disk_num = *(winvblock__uint32_ptr) buffer;
50     struct device__type * dev_walker;
51     disk__type_ptr disk_walker = NULL, prev_disk_walker;
52     struct bus__type * bus;
53
54     DBG("Request to detach disk: %d\n", disk_num);
55     bus = bus__get(dev);
56     dev_walker = bus->first_child;
57     if (dev_walker != NULL)
58       disk_walker = disk__get_ptr(dev_walker);
59     prev_disk_walker = disk_walker;
60     while ((disk_walker != NULL) && (disk_walker->DiskNumber != disk_num)) {
61         prev_disk_walker = disk_walker;
62         dev_walker = dev_walker->next_sibling_ptr;
63         if (dev_walker != NULL)
64           disk_walker = disk__get_ptr(dev_walker);
65       }
66     if (disk_walker != NULL) {
67         if (disk_walker->BootDrive) {
68             DBG("Cannot unmount a boot drive.\n");
69             irp->IoStatus.Information = 0;
70             *completion = TRUE;
71             return STATUS_INVALID_DEVICE_REQUEST;
72           }
73         DBG("Deleting disk %d\n", disk_walker->DiskNumber);
74         if (disk_walker == disk__get_ptr(bus->first_child))
75           bus->first_child = dev_walker->next_sibling_ptr;
76           else {
77             prev_disk_walker->device->next_sibling_ptr =
78               dev_walker->next_sibling_ptr;
79           }
80         disk_walker->Unmount = TRUE;
81         dev_walker->next_sibling_ptr = NULL;
82         if (bus->PhysicalDeviceObject != NULL)
83           IoInvalidateDeviceRelations(bus->PhysicalDeviceObject, BusRelations);
84       }
85     bus->Children--;
86     irp->IoStatus.Information = 0;
87     *completion = TRUE;
88     return STATUS_SUCCESS;
89   }
90
91 NTSTATUS STDCALL bus_dev_ctl__dispatch(
92     IN PDEVICE_OBJECT dev_obj,
93     IN PIRP irp,
94     IN PIO_STACK_LOCATION io_stack_loc,
95     IN struct device__type * dev,
96     OUT winvblock__bool_ptr completion
97   ) {
98     NTSTATUS status;
99     switch (io_stack_loc->Parameters.DeviceIoControl.IoControlCode) {
100         case IOCTL_FILE_ATTACH:
101           status = filedisk__attach(
102               dev_obj,
103               irp,
104               io_stack_loc,
105               dev,
106               completion
107             );
108           break;
109
110         case IOCTL_FILE_DETACH:
111           status = disk_detach(
112               dev_obj,
113               irp,
114               io_stack_loc,
115               dev,
116               completion
117             );
118           break;
119
120         default:
121           irp->IoStatus.Information = 0;
122           status = STATUS_INVALID_DEVICE_REQUEST;
123       }
124
125     irp->IoStatus.Status = status;
126     IoCompleteRequest(irp, IO_NO_INCREMENT);
127     *completion = TRUE;
128     return status;
129   }