Allow more than one USB controller (was a XBOX hack no more needed)
[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 PCI_COMMON_CONFIG PciData;
108 ULONG BusNumber, SlotNumber;
109 ULONG ret;
110 PDEVICE_OBJECT Pdo;
111
112 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryHardwareIDs\n");
113
114 Pdo = DeviceExtension->PhysicalDeviceObject;
115 Status = IoGetDeviceProperty(
116 Pdo,
117 DevicePropertyBusNumber,
118 sizeof(ULONG),
119 &BusNumber,
120 &ret);
121 if (!NT_SUCCESS(Status))
122 {
123 DPRINT("USBMP: IoGetDeviceProperty() failed with status 0x%08lx\n", Status);
124 break;
125 }
126
127 Status = IoGetDeviceProperty(
128 Pdo,
129 DevicePropertyAddress,
130 sizeof(ULONG),
131 &SlotNumber,
132 &ret);
133 if (!NT_SUCCESS(Status))
134 {
135 DPRINT("USBMP: IoGetDeviceProperty() failed with status 0x%08lx\n", Status);
136 break;
137 }
138
139 ret = HalGetBusDataByOffset(PCIConfiguration,
140 BusNumber,
141 SlotNumber,
142 &PciData,
143 0,
144 PCI_COMMON_HDR_LENGTH);
145 if (ret != PCI_COMMON_HDR_LENGTH)
146 {
147 DPRINT("USBMP: HalGetBusDataByOffset() failed (ret = %ld)\n", ret);
148 Status = STATUS_IO_DEVICE_ERROR;
149 break;
150 }
151
152 sprintf(Buffer[0], "USB\\VID%04X&PID%04X&REV%04X",
153 PciData.VendorID, PciData.DeviceID, PciData.RevisionID);
154 sprintf(Buffer[1], "USB\\VID%04X&PID%04X",
155 PciData.VendorID, PciData.DeviceID);
156 if (roothub->speed == USB_SPEED_LOW || roothub->speed == USB_SPEED_FULL)
157 RootHubName = "USB\\ROOT_HUB"; /* USB 1.1 */
158 else
159 RootHubName = "USB\\ROOT_HUB20"; /* USB 2.0 */
160 Status = UsbMpInitMultiSzString(
161 &SourceString,
162 Buffer[0], Buffer[1], RootHubName, NULL);
163 break;
164 }
165 case BusQueryCompatibleIDs:
166 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryCompatibleIDs\n");
167 /* No compatible ID */
168 *Information = 0;
169 return STATUS_NOT_SUPPORTED;
170 case BusQueryInstanceID:
171 {
172 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / BusQueryInstanceID\n");
173 RtlInitUnicodeString(&SourceString, L"");
174 break;
175 }
176 default:
177 DPRINT1("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_ID / unknown query id type 0x%lx\n", IdType);
178 return STATUS_NOT_SUPPORTED;
179 }
180
181 if (NT_SUCCESS(Status))
182 {
183 Status = UsbMpDuplicateUnicodeString(
184 &String,
185 &SourceString,
186 PagedPool);
187 *Information = (ULONG_PTR)String.Buffer;
188 }
189 return Status;
190 }
191
192 static NTSTATUS
193 UsbMpPnpStartDevice(
194 IN PDEVICE_OBJECT DeviceObject)
195 {
196 PUSBMP_DEVICE_EXTENSION DeviceExtension;
197 NTSTATUS Status;
198
199 DeviceExtension = (PUSBMP_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
200
201 /* Register device interface for root hub */
202 Status = IoRegisterDeviceInterface(
203 DeviceObject,
204 &GUID_DEVINTERFACE_USB_HUB,
205 NULL,
206 &DeviceExtension->HcdInterfaceName);
207 if (!NT_SUCCESS(Status))
208 {
209 DPRINT("USBMP: IoRegisterDeviceInterface() failed with status 0x%08lx\n", Status);
210 return Status;
211 }
212
213 return Status;
214 }
215
216 NTSTATUS STDCALL
217 UsbMpPnpPdo(
218 IN PDEVICE_OBJECT DeviceObject,
219 IN PIRP Irp)
220 {
221 ULONG MinorFunction;
222 PIO_STACK_LOCATION Stack;
223 ULONG_PTR Information = 0;
224 NTSTATUS Status;
225
226 Stack = IoGetCurrentIrpStackLocation(Irp);
227 MinorFunction = Stack->MinorFunction;
228
229 switch (MinorFunction)
230 {
231 case IRP_MN_START_DEVICE: /* 0x00 */
232 {
233 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
234 Status = UsbMpPnpStartDevice(DeviceObject);
235 break;
236 }
237 case IRP_MN_QUERY_CAPABILITIES: /* 0x09 */
238 {
239 PDEVICE_CAPABILITIES DeviceCapabilities;
240 ULONG i;
241 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_CAPABILITIES\n");
242
243 DeviceCapabilities = (PDEVICE_CAPABILITIES)Stack->Parameters.DeviceCapabilities.Capabilities;
244 /* FIXME: capabilities can change with connected device */
245 DeviceCapabilities->LockSupported = FALSE;
246 DeviceCapabilities->EjectSupported = FALSE;
247 DeviceCapabilities->Removable = FALSE;
248 DeviceCapabilities->DockDevice = FALSE;
249 DeviceCapabilities->UniqueID = FALSE;
250 DeviceCapabilities->SilentInstall = TRUE;
251 DeviceCapabilities->RawDeviceOK = FALSE;
252 DeviceCapabilities->SurpriseRemovalOK = FALSE;
253 DeviceCapabilities->HardwareDisabled = FALSE; /* FIXME */
254 //DeviceCapabilities->NoDisplayInUI = FALSE; /* FIXME */
255 DeviceCapabilities->DeviceState[0] = PowerDeviceD0; /* FIXME */
256 for (i = 0; i < PowerSystemMaximum; i++)
257 DeviceCapabilities->DeviceState[i] = PowerDeviceD3; /* FIXME */
258 //DeviceCapabilities->DeviceWake = PowerDeviceUndefined; /* FIXME */
259 DeviceCapabilities->D1Latency = 0; /* FIXME */
260 DeviceCapabilities->D2Latency = 0; /* FIXME */
261 DeviceCapabilities->D3Latency = 0; /* FIXME */
262 Status = STATUS_SUCCESS;
263 break;
264 }
265 case IRP_MN_QUERY_RESOURCES: /* 0x0a */
266 {
267 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCES\n");
268 /* Root buses don't need resources, except the ones of
269 * the usb controller. This PDO is the root bus PDO, so
270 * report no resource by not changing Information and
271 * Status
272 */
273 Information = Irp->IoStatus.Information;
274 Status = Irp->IoStatus.Status;
275 break;
276 }
277 case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: /* 0x0b */
278 {
279 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
280 /* Root buses don't need resources, except the ones of
281 * the usb controller. This PDO is the root bus PDO, so
282 * report no resource by not changing Information and
283 * Status
284 */
285 Information = Irp->IoStatus.Information;
286 Status = Irp->IoStatus.Status;
287 break;
288 }
289 case IRP_MN_QUERY_DEVICE_TEXT: /* 0x0c */
290 {
291 switch (Stack->Parameters.QueryDeviceText.DeviceTextType)
292 {
293 case DeviceTextDescription:
294 {
295 UNICODE_STRING SourceString = RTL_CONSTANT_STRING(L"Root USB hub");
296 UNICODE_STRING Description;
297
298 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / DeviceTextDescription\n");
299
300 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE, &SourceString, &Description);
301 if (NT_SUCCESS(Status))
302 Information = (ULONG_PTR)Description.Buffer;
303 break;
304 }
305 case DeviceTextLocationInformation:
306 {
307 /* We don't have any text location to report,
308 * and this query is optional, so ignore it.
309 */
310 Information = Irp->IoStatus.Information;
311 Status = Irp->IoStatus.Status;
312 break;
313 }
314 default:
315 {
316 DPRINT1("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_TEXT / unknown type 0x%lx\n",
317 Stack->Parameters.QueryDeviceText.DeviceTextType);
318 Status = STATUS_NOT_SUPPORTED;
319 }
320 }
321 break;
322 }
323 case IRP_MN_QUERY_ID: /* 0x13 */
324 {
325 Status = UsbMpPdoQueryId(DeviceObject, Irp, &Information);
326 break;
327 }
328 default:
329 {
330 /* We can't forward request to the lower driver, because
331 * we are a Pdo, so we don't have lower driver...
332 */
333 DPRINT1("USBMP: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
334 Information = Irp->IoStatus.Information;
335 Status = Irp->IoStatus.Status;
336 }
337 }
338
339 Irp->IoStatus.Information = Information;
340 Irp->IoStatus.Status = Status;
341 IoCompleteRequest(Irp, IO_NO_INCREMENT);
342 return Status;
343 }
344