Move drivers to the right location
[reactos.git] / reactos / drivers / usb / usbhub / fdo.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: USB hub driver
4 * FILE: drivers/usb/cromwell/hub/fdo.c
5 * PURPOSE: IRP_MJ_PNP operations for FDOs
6 *
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
8 */
9
10 #define INITGUID
11 #define NDEBUG
12 #include "usbhub.h"
13
14 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
15
16 static VOID
17 UsbhubGetUserBuffers(
18 IN PIRP Irp,
19 IN ULONG IoControlCode,
20 OUT PVOID* BufferIn,
21 OUT PVOID* BufferOut)
22 {
23 ASSERT(Irp);
24 ASSERT(BufferIn);
25 ASSERT(BufferOut);
26
27 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
28 {
29 case METHOD_BUFFERED:
30 *BufferIn = *BufferOut = Irp->AssociatedIrp.SystemBuffer;
31 break;
32 case METHOD_IN_DIRECT:
33 case METHOD_OUT_DIRECT:
34 *BufferIn = Irp->AssociatedIrp.SystemBuffer;
35 *BufferOut = MmGetSystemAddressForMdl(Irp->MdlAddress);
36 break;
37 case METHOD_NEITHER:
38 *BufferIn = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.Type3InputBuffer;
39 *BufferOut = Irp->UserBuffer;
40 break;
41 default:
42 /* Should never happen */
43 *BufferIn = NULL;
44 *BufferOut = NULL;
45 break;
46 }
47 }
48
49 static NTSTATUS
50 UsbhubFdoQueryBusRelations(
51 IN PDEVICE_OBJECT DeviceObject,
52 OUT PDEVICE_RELATIONS* pDeviceRelations)
53 {
54 PHUB_DEVICE_EXTENSION DeviceExtension;
55 PDEVICE_RELATIONS DeviceRelations;
56 PDEVICE_OBJECT Pdo;
57 PHUB_DEVICE_EXTENSION PdoExtension;
58 struct usb_device* dev;
59 ULONG i;
60 ULONG Children = 0;
61 ULONG NeededSize;
62 NTSTATUS Status;
63 CHAR Buffer[3][40];
64
65 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
66 dev = DeviceExtension->dev;
67
68 /* Create PDOs that are missing */
69 for (i = 0; i < USB_MAXCHILDREN; i++)
70 {
71 if (dev->children[i] == NULL)
72 {
73 /* No child device at this place */
74 continue;
75 }
76 Children++;
77 if (DeviceExtension->Children[i] != NULL)
78 {
79 /* PDO already exists */
80 continue;
81 }
82 /* Need to create the PDO */
83 Status = IoCreateDevice(
84 DeviceObject->DriverObject,
85 sizeof(HUB_DEVICE_EXTENSION),
86 NULL, /* Device name */
87 FILE_DEVICE_CONTROLLER,
88 FILE_AUTOGENERATED_DEVICE_NAME,
89 FALSE,
90 &DeviceExtension->Children[i]);
91 if (!NT_SUCCESS(Status))
92 {
93 DPRINT("Usbhub: IoCreateDevice() failed with status 0x%08lx\n", Status);
94 return Status;
95 }
96
97 Pdo = DeviceExtension->Children[i];
98 Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
99
100 PdoExtension = Pdo->DeviceExtension;
101 RtlZeroMemory(PdoExtension, sizeof(HUB_DEVICE_EXTENSION));
102
103 PdoExtension->IsFDO = FALSE;
104 PdoExtension->dev = dev->children[i];
105
106 sprintf(Buffer[0], "%lu", i + 1);
107 Status = UsbhubInitMultiSzString(
108 &PdoExtension->InstanceId,
109 Buffer[0], NULL);
110 if (!NT_SUCCESS(Status))
111 goto ByeBye;
112
113
114 sprintf(Buffer[0], "USB\\Vid_%04x&Pid_%04x&Rev_%04x",
115 PdoExtension->dev->descriptor.idVendor,
116 PdoExtension->dev->descriptor.idProduct,
117 PdoExtension->dev->descriptor.bcdDevice);
118 sprintf(Buffer[1], "USB\\Vid_%04x&Pid_%04x",
119 PdoExtension->dev->descriptor.idVendor,
120 PdoExtension->dev->descriptor.idProduct);
121 Status = UsbhubInitMultiSzString(
122 &PdoExtension->HardwareIds,
123 Buffer[0], Buffer[1], NULL);
124 if (!NT_SUCCESS(Status))
125 goto ByeBye;
126
127 Status = UsbhubInitMultiSzString(
128 &PdoExtension->DeviceId,
129 Buffer[1], NULL);
130 if (!NT_SUCCESS(Status))
131 goto ByeBye;
132
133 if (PdoExtension->dev->actconfig->desc.bNumInterfaces == 1)
134 {
135 /* Single-interface USB device */
136 sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
137 PdoExtension->dev->descriptor.bDeviceClass,
138 PdoExtension->dev->descriptor.bDeviceSubClass,
139 PdoExtension->dev->descriptor.bDeviceProtocol);
140 sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
141 PdoExtension->dev->descriptor.bDeviceClass,
142 PdoExtension->dev->descriptor.bDeviceSubClass);
143 sprintf(Buffer[2], "USB\\Class_%02x",
144 PdoExtension->dev->descriptor.bDeviceClass);
145 Status = UsbhubInitMultiSzString(
146 &PdoExtension->CompatibleIds,
147 Buffer[0], Buffer[1], Buffer[2], NULL);
148 }
149 else
150 {
151 /* Multiple-interface USB device */
152 sprintf(Buffer[0], "USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
153 PdoExtension->dev->descriptor.bDeviceClass,
154 PdoExtension->dev->descriptor.bDeviceSubClass,
155 PdoExtension->dev->descriptor.bDeviceProtocol);
156 sprintf(Buffer[1], "USB\\DevClass_%02x&SubClass_%02x",
157 PdoExtension->dev->descriptor.bDeviceClass,
158 PdoExtension->dev->descriptor.bDeviceSubClass);
159 sprintf(Buffer[2], "USB\\DevClass_%02x",
160 PdoExtension->dev->descriptor.bDeviceClass);
161 Status = UsbhubInitMultiSzString(
162 &PdoExtension->CompatibleIds,
163 Buffer[0], Buffer[1], Buffer[2], "USB\\COMPOSITE", NULL);
164 }
165
166 if (!NT_SUCCESS(Status))
167 goto ByeBye;
168
169 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
170 }
171
172 /* Fill returned structure */
173 NeededSize = sizeof(DEVICE_RELATIONS);
174 if (Children > 1)
175 NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
176 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
177 PagedPool,
178 NeededSize);
179 if (!DeviceRelations)
180 return STATUS_INSUFFICIENT_RESOURCES;
181 DeviceRelations->Count = Children;
182 Children = 0;
183 for (i = 0; i < USB_MAXCHILDREN; i++)
184 {
185 if (DeviceExtension->Children[i])
186 {
187 ObReferenceObject(DeviceExtension->Children[i]);
188 DeviceRelations->Objects[Children++] = DeviceExtension->Children[i];
189 }
190 }
191 ASSERT(Children == DeviceRelations->Count);
192
193 *pDeviceRelations = DeviceRelations;
194 return STATUS_SUCCESS;
195
196 ByeBye:
197 RtlFreeUnicodeString(&PdoExtension->DeviceId);
198 RtlFreeUnicodeString(&PdoExtension->InstanceId);
199 RtlFreeUnicodeString(&PdoExtension->HardwareIds);
200 RtlFreeUnicodeString(&PdoExtension->CompatibleIds);
201 IoDeleteDevice(Pdo);
202 return Status;
203 }
204
205 NTSTATUS STDCALL
206 UsbhubPnpFdo(
207 IN PDEVICE_OBJECT DeviceObject,
208 IN PIRP Irp)
209 {
210 PIO_STACK_LOCATION IrpSp;
211 NTSTATUS Status;
212 ULONG MinorFunction;
213 ULONG_PTR Information = 0;
214
215 IrpSp = IoGetCurrentIrpStackLocation(Irp);
216 MinorFunction = IrpSp->MinorFunction;
217
218 switch (MinorFunction)
219 {
220 case IRP_MN_START_DEVICE: /* 0x0 */
221 {
222 DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
223 Status = ForwardIrpAndWait(DeviceObject, Irp);
224 break;
225 }
226
227 case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
228 {
229 switch (IrpSp->Parameters.QueryDeviceRelations.Type)
230 {
231 case BusRelations:
232 {
233 PDEVICE_RELATIONS DeviceRelations;
234 DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
235 Status = UsbhubFdoQueryBusRelations(DeviceObject, &DeviceRelations);
236 Information = (ULONG_PTR)DeviceRelations;
237 break;
238 }
239 case RemovalRelations:
240 {
241 DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
242 return ForwardIrpAndForget(DeviceObject, Irp);
243 }
244 default:
245 DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
246 IrpSp->Parameters.QueryDeviceRelations.Type);
247 return ForwardIrpAndForget(DeviceObject, Irp);
248 }
249 break;
250 }
251
252 default:
253 {
254 DPRINT1("Usbhub: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
255 return ForwardIrpAndForget(DeviceObject, Irp);
256 }
257 }
258 Irp->IoStatus.Information = Information;
259 Irp->IoStatus.Status = Status;
260 IoCompleteRequest(Irp, IO_NO_INCREMENT);
261 return Status;
262 }
263
264 NTSTATUS
265 UsbhubDeviceControlFdo(
266 IN PDEVICE_OBJECT DeviceObject,
267 IN PIRP Irp)
268 {
269 PIO_STACK_LOCATION Stack;
270 ULONG IoControlCode;
271 PHUB_DEVICE_EXTENSION DeviceExtension;
272 ULONG LengthIn, LengthOut;
273 ULONG_PTR Information = 0;
274 PVOID BufferIn, BufferOut;
275 NTSTATUS Status;
276
277 Stack = IoGetCurrentIrpStackLocation(Irp);
278 LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength;
279 LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength;
280 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
281 IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
282 UsbhubGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut);
283
284 switch (IoControlCode)
285 {
286 case IOCTL_USB_GET_NODE_INFORMATION:
287 {
288 PUSB_NODE_INFORMATION NodeInformation;
289 struct usb_device* dev;
290 DPRINT("Usbhub: IOCTL_USB_GET_NODE_INFORMATION\n");
291 if (LengthOut < sizeof(USB_NODE_INFORMATION))
292 Status = STATUS_BUFFER_TOO_SMALL;
293 else if (BufferOut == NULL)
294 Status = STATUS_INVALID_PARAMETER;
295 else
296 {
297 NodeInformation = (PUSB_NODE_INFORMATION)BufferOut;
298 dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
299 NodeInformation->NodeType = UsbHub;
300 RtlCopyMemory(
301 &NodeInformation->u.HubInformation.HubDescriptor,
302 ((struct usb_hub *)usb_get_intfdata(to_usb_interface(&dev->actconfig->interface[0].dev)))->descriptor,
303 sizeof(USB_HUB_DESCRIPTOR));
304 NodeInformation->u.HubInformation.HubIsBusPowered = dev->actconfig->desc.bmAttributes & 0x80;
305 Information = sizeof(USB_NODE_INFORMATION);
306 Status = STATUS_SUCCESS;
307 }
308 break;
309 }
310 case IOCTL_USB_GET_NODE_CONNECTION_NAME:
311 {
312 PHUB_DEVICE_EXTENSION DeviceExtension;
313 PUSB_NODE_CONNECTION_NAME ConnectionName;
314 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
315 ConnectionName = (PUSB_NODE_CONNECTION_NAME)BufferOut;
316
317 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME\n");
318 if (LengthOut < sizeof(USB_NODE_CONNECTION_NAME))
319 Status = STATUS_BUFFER_TOO_SMALL;
320 else if (BufferOut == NULL)
321 Status = STATUS_INVALID_PARAMETER;
322 else if (ConnectionName->ConnectionIndex < 1
323 || ConnectionName->ConnectionIndex > USB_MAXCHILDREN)
324 Status = STATUS_INVALID_PARAMETER;
325 else if (DeviceExtension->Children[ConnectionName->ConnectionIndex - 1] == NULL)
326 Status = STATUS_INVALID_PARAMETER;
327 else
328 {
329 ULONG NeededStructureSize;
330 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceExtension->Children[ConnectionName->ConnectionIndex - 1]->DeviceExtension;
331 NeededStructureSize = DeviceExtension->SymbolicLinkName.Length + sizeof(UNICODE_NULL) + FIELD_OFFSET(USB_NODE_CONNECTION_NAME, NodeName);
332 if (ConnectionName->ActualLength < NeededStructureSize / sizeof(WCHAR)
333 || LengthOut < NeededStructureSize)
334 {
335 /* Buffer too small */
336 ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
337 Information = sizeof(USB_NODE_CONNECTION_NAME);
338 Status = STATUS_BUFFER_TOO_SMALL;
339 }
340 else
341 {
342 RtlCopyMemory(
343 ConnectionName->NodeName,
344 DeviceExtension->SymbolicLinkName.Buffer,
345 DeviceExtension->SymbolicLinkName.Length);
346 ConnectionName->NodeName[DeviceExtension->SymbolicLinkName.Length / sizeof(WCHAR)] = UNICODE_NULL;
347 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME returns '%S'\n", ConnectionName->NodeName);
348 ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
349 Information = NeededStructureSize;
350 Status = STATUS_SUCCESS;
351 }
352 Information = LengthOut;
353 }
354 break;
355 }
356 case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
357 {
358 PUSB_NODE_CONNECTION_INFORMATION ConnectionInformation;
359 ULONG i, j, k;
360 struct usb_device* dev;
361 ULONG NumberOfOpenPipes = 0;
362 ULONG SizeOfOpenPipesArray;
363 ConnectionInformation = (PUSB_NODE_CONNECTION_INFORMATION)BufferOut;
364
365 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n");
366 if (LengthOut < sizeof(USB_NODE_CONNECTION_INFORMATION))
367 Status = STATUS_BUFFER_TOO_SMALL;
368 else if (BufferOut == NULL)
369 Status = STATUS_INVALID_PARAMETER;
370 else if (ConnectionInformation->ConnectionIndex < 1
371 || ConnectionInformation->ConnectionIndex > USB_MAXCHILDREN)
372 Status = STATUS_INVALID_PARAMETER;
373 else
374 {
375 dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
376 dev = dev->children[ConnectionInformation->ConnectionIndex - 1];
377 if (dev == NULL)
378 {
379 /* No device connected to this port */
380 RtlZeroMemory(
381 &ConnectionInformation->DeviceDescriptor,
382 sizeof(USB_NODE_CONNECTION_INFORMATION) - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, DeviceDescriptor));
383 ConnectionInformation->ConnectionStatus = NoDeviceConnected;
384 Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
385 Status = STATUS_SUCCESS;
386 break;
387 }
388 SizeOfOpenPipesArray = (LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, PipeList)) / sizeof(USB_PIPE_INFO);
389 RtlCopyMemory(
390 &ConnectionInformation->DeviceDescriptor,
391 &dev->descriptor,
392 sizeof(USB_DEVICE_DESCRIPTOR));
393 ConnectionInformation->CurrentConfigurationValue = dev->actconfig->desc.bConfigurationValue;
394 ConnectionInformation->LowSpeed = dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL;
395 ConnectionInformation->DeviceIsHub = dev->descriptor.bDeviceClass == USB_CLASS_HUB;
396 ConnectionInformation->DeviceAddress = dev->devnum;
397 ConnectionInformation->ConnectionStatus = DeviceConnected;
398
399 for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
400 for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
401 for (k = 0; k < dev->actconfig->interface[i].altsetting[j].desc.bNumEndpoints; k++)
402 {
403 if (NumberOfOpenPipes < SizeOfOpenPipesArray)
404 {
405 PUSB_PIPE_INFO Pipe = &ConnectionInformation->PipeList[NumberOfOpenPipes];
406 struct usb_host_endpoint* endpoint = &dev->actconfig->interface[i].altsetting[j].endpoint[k];
407 RtlCopyMemory(
408 &Pipe->EndpointDescriptor,
409 &endpoint->desc,
410 endpoint->desc.bLength);
411 Pipe->ScheduleOffset = 0; /* FIXME */
412 }
413 NumberOfOpenPipes++;
414 }
415 ConnectionInformation->NumberOfOpenPipes = NumberOfOpenPipes;
416
417 Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
418 if (NumberOfOpenPipes <= SizeOfOpenPipesArray)
419 Status = STATUS_SUCCESS;
420 else
421 Status = STATUS_BUFFER_OVERFLOW;
422 }
423 break;
424 }
425 case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION:
426 {
427 //PUSB_DESCRIPTOR_REQUEST Descriptor;
428 DPRINT("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n");
429 DPRINT1("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION unimplemented\n");
430 Information = 0;
431 Status = STATUS_NOT_IMPLEMENTED;
432 break;
433 }
434 case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
435 {
436 PHUB_DEVICE_EXTENSION DeviceExtension;
437 PUSB_NODE_CONNECTION_DRIVERKEY_NAME StringDescriptor;
438 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n");
439 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
440 StringDescriptor = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)BufferOut;
441 if (LengthOut < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME))
442 Status = STATUS_BUFFER_TOO_SMALL;
443 else if (StringDescriptor == NULL)
444 Status = STATUS_INVALID_PARAMETER;
445 else if (StringDescriptor->ConnectionIndex < 1
446 || StringDescriptor->ConnectionIndex > USB_MAXCHILDREN)
447 Status = STATUS_INVALID_PARAMETER;
448 else if (DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1] == NULL)
449 Status = STATUS_INVALID_PARAMETER;
450 else
451 {
452 ULONG StringSize;
453 Status = IoGetDeviceProperty(
454 DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1],
455 DevicePropertyDriverKeyName,
456 LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName),
457 StringDescriptor->DriverKeyName,
458 &StringSize);
459 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
460 {
461 StringDescriptor->ActualLength = StringSize + FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName);
462 Information = LengthOut;
463 Status = STATUS_SUCCESS;
464 }
465 }
466 break;
467 }
468 default:
469 {
470 /* Pass Irp to lower driver */
471 DPRINT1("Usbhub: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
472 return ForwardIrpAndForget(DeviceObject, Irp);
473 }
474 }
475
476 Irp->IoStatus.Information = Information;
477 Irp->IoStatus.Status = Status;
478 IoCompleteRequest(Irp, IO_NO_INCREMENT);
479 return Status;
480 }