[aoe] Rename aoe_bus to AoeBusMain
[people/sha0/winvblock.git] / src / aoe / bus.c
1 /**
2  * Copyright (C) 2010, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  *
4  * This file is part of WinVBlock, originally derived from WinAoE.
5  *
6  * WinVBlock is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * WinVBlock is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /**
21  * @file
22  *
23  * AoE bus specifics.
24  */
25
26 #include <stdio.h>
27 #include <ntddk.h>
28
29 #include "winvblock.h"
30 #include "portable.h"
31 #include "driver.h"
32 #include "device.h"
33 #include "bus.h"
34 #include "aoe.h"
35 #include "mount.h"
36 #include "debug.h"
37
38 /* Names for the AoE bus. */
39 #define AOE_M_BUS_NAME_ (L"\\Device\\AoE")
40 #define AOE_M_BUS_DOSNAME_ (L"\\DosDevices\\AoE")
41
42 /* TODO: Remove this pull from aoe/driver.c */
43 extern WV_F_DEV_DISPATCH aoe__scan;
44 extern WV_F_DEV_DISPATCH aoe__show;
45 extern WV_F_DEV_DISPATCH aoe__mount;
46
47 /* Forward declarations. */
48 static WV_F_DEV_CTL aoe_bus__dev_ctl_dispatch_;
49 static WV_F_DEV_PNP_ID aoe_bus__pnp_id_;
50 winvblock__bool aoe_bus__create(void);
51 void aoe_bus__free(void);
52
53 /* Globals. */
54 WV_SP_BUS_T AoeBusMain = NULL;
55 static UNICODE_STRING AoeBusName_ = {
56     sizeof AOE_M_BUS_NAME_,
57     sizeof AOE_M_BUS_NAME_,
58     AOE_M_BUS_NAME_
59   };
60 static UNICODE_STRING AoeBusDosname_ = {
61     sizeof AOE_M_BUS_DOSNAME_,
62     sizeof AOE_M_BUS_DOSNAME_,
63     AOE_M_BUS_DOSNAME_
64   };
65
66 static NTSTATUS STDCALL aoe_bus__dev_ctl_dispatch_(
67     IN WV_SP_DEV_T dev,
68     IN PIRP irp,
69     IN ULONG POINTER_ALIGNMENT code
70   ) {
71     switch(code) {
72         case IOCTL_AOE_SCAN:
73           return aoe__scan(dev, irp);
74
75         case IOCTL_AOE_SHOW:
76           return aoe__show(dev, irp);
77
78         case IOCTL_AOE_MOUNT:
79           return aoe__mount(dev, irp);
80
81         case IOCTL_AOE_UMOUNT: {
82             WV_SP_BUS_T bus = WvBusFromDev(dev);
83
84             /* Pretend it's an IOCTL_FILE_DETACH. */
85             return WvDevFromDevObj(bus->LowerDeviceObject)->IrpMj->DevCtl(
86                 dev,
87                 irp,
88                 IOCTL_FILE_DETACH
89               );
90           }
91         default:
92           DBG("Unsupported IOCTL\n");
93           return driver__complete_irp(irp, 0, STATUS_NOT_SUPPORTED);
94       }
95   }
96
97 /**
98  * Create the AoE bus.
99  *
100  * @ret         TRUE for success, else FALSE.
101  */
102 winvblock__bool aoe_bus__create(void) {
103     WV_SP_BUS_T new_bus;
104     NTSTATUS status;
105
106     /* We should only be called once. */
107     if (AoeBusMain) {
108         DBG("AoE bus already created\n");
109         return FALSE;
110       }
111     /* Try to create the AoE bus. */
112     new_bus = WvBusCreate();
113     if (!new_bus) {
114         DBG("Failed to create AoE bus!\n");
115         goto err_new_bus;
116       }
117     /* When the PDO is created, we need to handle PnP ID queries. */
118     new_bus->Dev->Ops.PnpId = aoe_bus__pnp_id_;
119     /* Add it as a sub-bus to WinVBlock. */
120     if (!WvBusAddChild(driver__bus(), new_bus->Dev)) {
121         DBG("Couldn't add AoE bus to WinVBlock bus!\n");
122         goto err_add_child;
123       }
124     /* DosDevice symlink. */
125     status = IoCreateSymbolicLink(
126         &AoeBusDosname_,
127         &AoeBusName_
128       );
129     if (!NT_SUCCESS(status)) {
130         DBG("IoCreateSymbolicLink() failed!\n");
131         goto err_dos_symlink;
132       }
133     /* All done. */
134     AoeBusMain = new_bus;
135     return TRUE;
136
137     IoDeleteSymbolicLink(&AoeBusDosname_);
138     err_dos_symlink:
139
140     IoDeleteDevice(AoeBusMain->Dev->Self);
141     err_add_child:
142
143     WvDevFree(new_bus->Dev);
144     err_new_bus:
145
146     return FALSE;
147   }
148
149 /* Destroy the AoE bus. */
150 void aoe_bus__free(void) {
151     if (!AoeBusMain)
152       /* Nothing to do. */
153       return;
154
155     IoDeleteSymbolicLink(&AoeBusDosname_);
156     IoDeleteDevice(AoeBusMain->Dev->Self);
157     #if 0
158     bus__remove_child(driver__bus(), AoeBusMain->Dev);
159     #endif
160     WvDevFree(AoeBusMain->Dev);
161     return;
162   }
163
164 static winvblock__uint32 STDCALL aoe_bus__pnp_id_(
165     IN WV_SP_DEV_T dev,
166     IN BUS_QUERY_ID_TYPE query_type,
167     IN OUT WCHAR (*buf)[512]
168   ) {
169     switch (query_type) {
170         case BusQueryDeviceID:
171           return swprintf(*buf, winvblock__literal_w L"\\AoE") + 1;
172
173         case BusQueryInstanceID:
174           return swprintf(*buf, L"0") + 1;
175
176         case BusQueryHardwareIDs:
177           return swprintf(*buf, winvblock__literal_w L"\\AoE") + 2;
178
179         case BusQueryCompatibleIDs:
180           return swprintf(*buf, winvblock__literal_w L"\\AoE") + 4;
181
182         default:
183           return 0;
184       }
185   }