[bus/pnp,disk/pnp,aoe] Get AoE sub-bus to work
[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 /* TODO: Remove this pull from aoe/driver.c */
39 extern device__dispatch_func aoe__scan;
40 extern device__dispatch_func aoe__show;
41 extern device__dispatch_func aoe__mount;
42
43 /* Forward declarations. */
44 static device__dev_ctl_func aoe_bus__dev_ctl_dispatch_;
45 static device__pnp_id_func aoe_bus__pnp_id_;
46 winvblock__bool aoe_bus__create(void);
47 void aoe_bus__free(void);
48
49 /* Globals. */
50 struct bus__type * aoe_bus = NULL;
51
52 static NTSTATUS STDCALL aoe_bus__dev_ctl_dispatch_(
53     IN struct device__type * dev,
54     IN PIRP irp,
55     IN ULONG POINTER_ALIGNMENT code
56   ) {
57     switch(code) {
58         case IOCTL_AOE_SCAN:
59           return aoe__scan(dev, irp);
60
61         case IOCTL_AOE_SHOW:
62           return aoe__show(dev, irp);
63
64         case IOCTL_AOE_MOUNT:
65           return aoe__mount(dev, irp);
66
67         case IOCTL_AOE_UMOUNT:
68           /* Pretend it's an IOCTL_FILE_DETACH. */
69           return device__get(bus__get(dev)->LowerDeviceObject)->irp_mj->dev_ctl(
70               dev,
71               irp,
72               IOCTL_FILE_DETACH
73             );
74
75         default:
76           DBG("Unsupported IOCTL\n");
77           return driver__complete_irp(irp, 0, STATUS_NOT_SUPPORTED);
78       }
79   }
80
81 /**
82  * Create the AoE bus.
83  *
84  * @ret         TRUE for success, else FALSE.
85  */
86 winvblock__bool aoe_bus__create(void) {
87     struct bus__type * new_bus;
88
89     /* We should only be called once. */
90     if (aoe_bus) {
91         DBG("AoE bus already created\n");
92         return FALSE;
93       }
94     /* Try to create the AoE bus. */
95     new_bus = bus__create();
96     if (!new_bus) {
97         DBG("Failed to create AoE bus!\n");
98         goto err_new_bus;
99       }
100     /* When the PDO is created, we need to handle PnP ID queries. */
101     new_bus->device->ops.pnp_id = aoe_bus__pnp_id_;
102     /* Name the bus when the PDO is created. */
103     RtlInitUnicodeString(
104         &new_bus->dev_name,
105         L"\\Device\\AoE"
106       );
107     RtlInitUnicodeString(
108         &new_bus->dos_dev_name,
109         L"\\DosDevices\\AoE"
110       );
111     new_bus->named = TRUE;
112     /* Add it as a sub-bus to WinVBlock. */
113     if (!bus__add_child(driver__bus(), new_bus->device)) {
114         DBG("Couldn't add AoE bus to WinVBlock bus!\n");
115         goto err_add_child;
116       }
117     /* All done. */
118     aoe_bus = new_bus;
119     return TRUE;
120
121     err_add_child:
122
123     device__free(new_bus->device);
124     err_new_bus:
125
126     return FALSE;
127   }
128
129 /* Destroy the AoE bus. */
130 void aoe_bus__free(void) {
131     if (!aoe_bus)
132       /* Nothing to do. */
133       return;
134
135     IoDeleteSymbolicLink(&aoe_bus->dos_dev_name);
136     IoDeleteSymbolicLink(&aoe_bus->dev_name);
137     IoDeleteDevice(aoe_bus->device->Self);
138     #if 0
139     bus__remove_child(driver__bus(), aoe_bus->device);
140     #endif
141     device__free(aoe_bus->device);
142     return;
143   }
144
145 static winvblock__uint32 STDCALL aoe_bus__pnp_id_(
146     IN struct device__type * dev,
147     IN BUS_QUERY_ID_TYPE query_type,
148     IN OUT WCHAR (*buf)[512]
149   ) {
150     switch (query_type) {
151         case BusQueryDeviceID:
152           return swprintf(*buf, winvblock__literal_w L"\\AoE") + 1;
153
154         case BusQueryInstanceID:
155           return swprintf(*buf, L"0") + 1;
156
157         case BusQueryHardwareIDs:
158           return swprintf(*buf, winvblock__literal_w L"\\AoE") + 2;
159
160         case BusQueryCompatibleIDs:
161           return swprintf(*buf, winvblock__literal_w L"\\AoE") + 4;
162
163         default:
164           return 0;
165       }
166   }