Implement IRP_MN_QUERY_CAPABILITIES, IRP_MN_QUERY_RESOURCES, IRP_MN_QUERY_RESOURCE_RE...
[reactos.git] / reactos / drivers / usb / miniport / common / pdo.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS USB miniport driver (Cromwell type)
4 * FILE: drivers/usb/miniport/common/pdo.c
5 * PURPOSE: IRP_MJ_PNP/IRP_MJ_DEVICE_CONTROL operations for PDOs
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org),
8 * James Tabor (jimtabor@adsl-64-217-116-74.dsl.hstntx.swbell.net)
9 */
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #include "usbcommon.h"
15
16 extern struct usb_driver hub_driver;
17
18 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
19
20 NTSTATUS
21 UsbMpDeviceControlPdo(
22 IN PDEVICE_OBJECT DeviceObject,
23 IN PIRP Irp)
24 {
25 PIO_STACK_LOCATION Stack;
26 ULONG_PTR Information = 0;
27 NTSTATUS Status;
28
29 DPRINT("USBMP: UsbMpDeviceControlPdo() called\n");
30
31 Stack = IoGetCurrentIrpStackLocation(Irp);
32 Status = Irp->IoStatus.Status;
33
34 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
35 {
36 case IOCTL_INTERNAL_USB_GET_ROOT_USB_DEVICE:
37 {
38 PUSBMP_DEVICE_EXTENSION DeviceExtension;
39
40 DPRINT("USBMP: IOCTL_INTERNAL_USB_GET_ROOT_USB_DEVICE\n");
41 if (Irp->AssociatedIrp.SystemBuffer == NULL
42 || Stack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(PVOID))
43 {
44 Status = STATUS_INVALID_PARAMETER;
45 }
46 else
47 {
48 PVOID* pRootHubPointer;
49 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
50 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)DeviceExtension->FunctionalDeviceObject->DeviceExtension;
51
52 pRootHubPointer = (PVOID*)Irp->AssociatedIrp.SystemBuffer;
53 *pRootHubPointer = ((struct usb_hcd*)DeviceExtension->pdev->data)->self.root_hub;
54 Information = sizeof(PVOID);
55 Status = STATUS_SUCCESS;
56 }
57 break;
58 }
59 default:
60 {
61 DPRINT1("USBMP: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
62 Information = Irp->IoStatus.Information;
63 Status = Irp->IoStatus.Status;
64 }
65 }
66
67 Irp->IoStatus.Information = Information;
68 Irp->IoStatus.Status = Status;
69 IoCompleteRequest(Irp, IO_NO_INCREMENT);
70 return Status;
71 }
72
73 static NTSTATUS
74 UsbMpPdoQueryId(
75 IN PDEVICE_OBJECT DeviceObject,
76 IN PIRP Irp,
77 OUT ULONG_PTR* Information)
78 {
79 PUSBMP_DEVICE_EXTENSION DeviceExtension;
80 ULONG IdType;
81 UNICODE_STRING SourceString;
82 UNICODE_STRING String;
83 struct usb_device *roothub;
84 NTSTATUS Status = STATUS_SUCCESS;
85
86 IdType = IoGetCurrentIrpStackLocation(Irp)->Parameters.QueryId.IdType;
87 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
88 RtlInitUnicodeString(&String, NULL);
89 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)DeviceExtension->FunctionalDeviceObject->DeviceExtension;
90 roothub = ((struct usb_hcd*)DeviceExtension->pdev->data)->self.root_hub;
91
92 switch (IdType)
93 {
94 case BusQueryDeviceID:
95 {
96 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryDeviceID\n");
97 if (roothub->speed == USB_SPEED_LOW || roothub->speed == USB_SPEED_FULL)
98 RtlInitUnicodeString(&SourceString, L"USB\\ROOT_HUB"); /* USB 1.1 */
99 else
100 RtlInitUnicodeString(&SourceString, L"USB\\ROOT_HUB20"); /* USB 2.0 */
101 break;
102 }
103 case BusQueryHardwareIDs:
104 {
105 CHAR Buffer[2][40];
106 PCHAR RootHubName;
107 USHORT Vendor, Product, Revision;
108
109 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
110
111 Vendor = DeviceExtension->pdev->vendor;
112 Product = DeviceExtension->pdev->device;
113 Revision = 0; /* FIXME */
114
115 sprintf(Buffer[0], "USB\\VID%04X&PID%04X&REV%04X",
116 Vendor, Product, Revision);
117 sprintf(Buffer[1], "USB\\VID%04X&PID%04X",
118 Vendor, Product);
119 if (roothub->speed == USB_SPEED_LOW || roothub->speed == USB_SPEED_FULL)
120 RootHubName = "USB\\ROOT_HUB"; /* USB 1.1 */
121 else
122 RootHubName = "USB\\ROOT_HUB20"; /* USB 2.0 */
123 Status = UsbMpInitMultiSzString(
124 &SourceString,
125 Buffer[0], Buffer[1], RootHubName, NULL);
126 break;
127 }
128 case BusQueryCompatibleIDs:
129 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
130 /* No compatible ID */
131 *Information = 0;
132 return STATUS_NOT_SUPPORTED;
133 case BusQueryInstanceID:
134 {
135 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
136 RtlInitUnicodeString(&SourceString, L"0000"); /* FIXME */
137 break;
138 }
139 default:
140 DPRINT1("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
141 return STATUS_NOT_SUPPORTED;
142 }
143
144 if (NT_SUCCESS(Status))
145 {
146 Status = UsbMpDuplicateUnicodeString(
147 &String,
148 &SourceString,
149 PagedPool);
150 *Information = (ULONG_PTR)String.Buffer;
151 }
152 return Status;
153 }
154
155 static NTSTATUS
156 UsbMpPnpStartDevice(
157 IN PDEVICE_OBJECT DeviceObject)
158 {
159 PUSBMP_DEVICE_EXTENSION DeviceExtension;
160 NTSTATUS Status;
161
162 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
163
164 /* Register device interface for root hub */
165 Status = IoRegisterDeviceInterface(
166 DeviceObject,
167 &GUID_DEVINTERFACE_USB_HUB,
168 NULL,
169 &DeviceExtension->HcdInterfaceName);
170 if (!NT_SUCCESS(Status))
171 {
172 DPRINT("USBMP: IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
173 return Status;
174 }
175
176 return Status;
177 }
178
179 NTSTATUS STDCALL
180 UsbMpPnpPdo(
181 IN PDEVICE_OBJECT DeviceObject,
182 IN PIRP Irp)
183 {
184 ULONG MinorFunction;
185 PIO_STACK_LOCATION Stack;
186 ULONG_PTR Information = 0;
187 NTSTATUS Status;
188
189 Stack = IoGetCurrentIrpStackLocation(Irp);
190 MinorFunction = Stack->MinorFunction;
191
192 switch (MinorFunction)
193 {
194 case IRP_MN_START_DEVICE: /* 0x00 */
195 {
196 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
197 Status = UsbMpPnpStartDevice(DeviceObject);
198 break;
199 }
200 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
201 {
202 PDEVICE_CAPABILITIES DeviceCapabilities;
203 ULONG i;
204 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
205
206 DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
207 /* FIXME: capabilities can change with connected device */
208 DeviceCapabilities->LockSupported = FALSE;
209 DeviceCapabilities->EjectSupported = FALSE;
210 DeviceCapabilities->Removable = FALSE;
211 DeviceCapabilities->DockDevice = FALSE;
212 DeviceCapabilities->UniqueID = FALSE;
213 DeviceCapabilities->SilentInstall = TRUE;
214 DeviceCapabilities->RawDeviceOK = FALSE;
215 DeviceCapabilities->SurpriseRemovalOK = FALSE;
216 DeviceCapabilities->HardwareDisabled = FALSE; /* FIXME */
217 //DeviceCapabilities->NoDisplayInUI = FALSE; /* FIXME */
218 DeviceCapabilities->DeviceState[0] = PowerDeviceD0; /* FIXME */
219 for (i = 0; i < PowerSystemMaximum; i++)
220 DeviceCapabilities->DeviceState[i] = PowerDeviceD3; /* FIXME */
221 //DeviceCapabilities->DeviceWake = PowerDeviceUndefined; /* FIXME */
222 DeviceCapabilities->D1Latency = 0; /* FIXME */
223 DeviceCapabilities->D2Latency = 0; /* FIXME */
224 DeviceCapabilities->D3Latency = 0; /* FIXME */
225 Status = STATUS_SUCCESS;
226 break;
227 }
228 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
229 {
230 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
231 /* Root buses don't need resources, except the ones of
232 * the usb controller. This PDO is the root bus PDO, so
233 * report no resource by not changing Information and
234 * Status
235 */
236 Information = Irp->IoStatus.Information;
237 Status = Irp->IoStatus.Status;
238 break;
239 }
240 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
241 {
242 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
243 /* Root buses don't need resources, except the ones of
244 * the usb controller. This PDO is the root bus PDO, so
245 * report no resource by not changing Information and
246 * Status
247 */
248 Information = Irp->IoStatus.Information;
249 Status = Irp->IoStatus.Status;
250 break;
251 }
252 #if 0 /* FIXME */
253 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
254 {
255 switch (Stack->Parameters.QueryDeviceText.DeviceTextType)
256 {
257 case DeviceTextDescription:
258 {
259 ULONG DescriptionSize;
260 PWSTR Description;
261 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
262
263 Status = IoGetDeviceProperty(
264 DeviceObject,
265 DevicePropertyDeviceDescription,
266 0, NULL,
267 &DescriptionSize);
268 if (Status == STATUS_BUFFER_TOO_SMALL)
269 {
270 Description = ExAllocatePool(PagedPool, DescriptionSize);
271 if (!Description)
272 Status = STATUS_INSUFFICIENT_RESOURCES;
273 else
274 {
275 Status = IoGetDeviceProperty(
276 DeviceObject,
277 DevicePropertyDeviceDescription,
278 DescriptionSize, Description,
279 &DescriptionSize);
280 Information = DescriptionSize;
281 }
282 }
283 break;
284 }
285 case DeviceTextLocationInformation:
286 {
287 /* We don't have any text location to report,
288 * and this query is optional, so ignore it.
289 */
290 Information = Irp->IoStatus.Information;
291 Status = Irp->IoStatus.Status;
292 break;
293 }
294 default:
295 {
296 DPRINT1("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n",
297 Stack->Parameters.QueryDeviceText.DeviceTextType);
298 Status = STATUS_NOT_SUPPORTED;
299 }
300 }
301 break;
302 }
303 #endif
304 case IRP_MN_QUERY_ID: /* 0x13 */
305 {
306 Status = UsbMpPdoQueryId(DeviceObject, Irp, &Information);
307 break;
308 }
309 default:
310 {
311 /* We can't forward request to the lower driver, because
312 * we are a Pdo, so we don't have lower driver...
313 */
314 DPRINT1("USBMP: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
315 Information = Irp->IoStatus.Information;
316 Status = Irp->IoStatus.Status;
317 }
318 }
319
320 Irp->IoStatus.Information = Information;
321 Irp->IoStatus.Status = Status;
322 IoCompleteRequest(Irp, IO_NO_INCREMENT);
323 return Status;
324 }
325