Create a branch for network fixes.
[reactos.git] / 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 < dev->maxchild; 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);
107 Status = UsbhubInitMultiSzString(
108 &PdoExtension->InstanceId,
109 Buffer[0], NULL);
110 if (!NT_SUCCESS(Status))
111 goto ByeBye;
112
113 DPRINT1("child #%lu: USB\\Vid_%04x&Pid_%04x&Rev_%04x\n",
114 i,
115 PdoExtension->dev->descriptor.idVendor,
116 PdoExtension->dev->descriptor.idProduct,
117 PdoExtension->dev->descriptor.bcdDevice);
118 sprintf(Buffer[0], "USB\\Vid_%04x&Pid_%04x&Rev_%04x",
119 PdoExtension->dev->descriptor.idVendor,
120 PdoExtension->dev->descriptor.idProduct,
121 PdoExtension->dev->descriptor.bcdDevice);
122 sprintf(Buffer[1], "USB\\Vid_%04x&Pid_%04x",
123 PdoExtension->dev->descriptor.idVendor,
124 PdoExtension->dev->descriptor.idProduct);
125 Status = UsbhubInitMultiSzString(
126 &PdoExtension->HardwareIds,
127 Buffer[0], Buffer[1], NULL);
128 if (!NT_SUCCESS(Status))
129 goto ByeBye;
130
131 Status = UsbhubInitMultiSzString(
132 &PdoExtension->DeviceId,
133 Buffer[1], NULL);
134 if (!NT_SUCCESS(Status))
135 goto ByeBye;
136
137 if (PdoExtension->dev->actconfig->desc.bNumInterfaces == 1)
138 {
139 /* Single-interface USB device */
140 if (PdoExtension->dev->descriptor.bDeviceClass != 0)
141 {
142 /* Use these values for device class/sub class/protocol */
143 sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
144 PdoExtension->dev->descriptor.bDeviceClass,
145 PdoExtension->dev->descriptor.bDeviceSubClass,
146 PdoExtension->dev->descriptor.bDeviceProtocol);
147 sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
148 PdoExtension->dev->descriptor.bDeviceClass,
149 PdoExtension->dev->descriptor.bDeviceSubClass);
150 sprintf(Buffer[2], "USB\\Class_%02x",
151 PdoExtension->dev->descriptor.bDeviceClass);
152 }
153 else
154 {
155 /* Use values specified in the interface descriptor */
156 struct usb_host_interface *itf = PdoExtension->dev->actconfig->interface->altsetting;
157 sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
158 itf->desc.bInterfaceClass,
159 itf->desc.bInterfaceSubClass,
160 itf->desc.bInterfaceProtocol);
161 sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
162 itf->desc.bInterfaceClass,
163 itf->desc.bInterfaceSubClass);
164 sprintf(Buffer[2], "USB\\Class_%02x",
165 itf->desc.bInterfaceClass);
166 }
167 Status = UsbhubInitMultiSzString(
168 &PdoExtension->CompatibleIds,
169 Buffer[0], Buffer[1], Buffer[2], NULL);
170 }
171 else
172 {
173 /* Multiple-interface USB device */
174 sprintf(Buffer[0], "USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
175 PdoExtension->dev->descriptor.bDeviceClass,
176 PdoExtension->dev->descriptor.bDeviceSubClass,
177 PdoExtension->dev->descriptor.bDeviceProtocol);
178 sprintf(Buffer[1], "USB\\DevClass_%02x&SubClass_%02x",
179 PdoExtension->dev->descriptor.bDeviceClass,
180 PdoExtension->dev->descriptor.bDeviceSubClass);
181 sprintf(Buffer[2], "USB\\DevClass_%02x",
182 PdoExtension->dev->descriptor.bDeviceClass);
183 Status = UsbhubInitMultiSzString(
184 &PdoExtension->CompatibleIds,
185 Buffer[0], Buffer[1], Buffer[2], "USB\\COMPOSITE", NULL);
186 }
187
188 if (!NT_SUCCESS(Status))
189 goto ByeBye;
190
191 Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
192 }
193
194 /* Fill returned structure */
195 NeededSize = sizeof(DEVICE_RELATIONS);
196 if (Children > 1)
197 NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
198 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
199 PagedPool,
200 NeededSize);
201 if (!DeviceRelations)
202 return STATUS_INSUFFICIENT_RESOURCES;
203 DeviceRelations->Count = Children;
204 Children = 0;
205 for (i = 0; i < USB_MAXCHILDREN; i++)
206 {
207 if (DeviceExtension->Children[i])
208 {
209 ObReferenceObject(DeviceExtension->Children[i]);
210 DeviceRelations->Objects[Children++] = DeviceExtension->Children[i];
211 }
212 }
213 ASSERT(Children == DeviceRelations->Count);
214
215 *pDeviceRelations = DeviceRelations;
216 return STATUS_SUCCESS;
217
218 ByeBye:
219 RtlFreeUnicodeString(&PdoExtension->DeviceId);
220 RtlFreeUnicodeString(&PdoExtension->InstanceId);
221 RtlFreeUnicodeString(&PdoExtension->HardwareIds);
222 RtlFreeUnicodeString(&PdoExtension->CompatibleIds);
223 IoDeleteDevice(Pdo);
224 return Status;
225 }
226
227 NTSTATUS STDCALL
228 UsbhubPnpFdo(
229 IN PDEVICE_OBJECT DeviceObject,
230 IN PIRP Irp)
231 {
232 PIO_STACK_LOCATION IrpSp;
233 NTSTATUS Status;
234 ULONG MinorFunction;
235 ULONG_PTR Information = 0;
236
237 IrpSp = IoGetCurrentIrpStackLocation(Irp);
238 MinorFunction = IrpSp->MinorFunction;
239
240 switch (MinorFunction)
241 {
242 case IRP_MN_START_DEVICE: /* 0x0 */
243 {
244 DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
245 Status = ForwardIrpAndWait(DeviceObject, Irp);
246 break;
247 }
248
249 case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
250 {
251 switch (IrpSp->Parameters.QueryDeviceRelations.Type)
252 {
253 case BusRelations:
254 {
255 PDEVICE_RELATIONS DeviceRelations = NULL;
256 DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
257 Status = UsbhubFdoQueryBusRelations(DeviceObject, &DeviceRelations);
258 Information = (ULONG_PTR)DeviceRelations;
259 break;
260 }
261 case RemovalRelations:
262 {
263 DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
264 return ForwardIrpAndForget(DeviceObject, Irp);
265 }
266 default:
267 DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
268 IrpSp->Parameters.QueryDeviceRelations.Type);
269 return ForwardIrpAndForget(DeviceObject, Irp);
270 }
271 break;
272 }
273
274 default:
275 {
276 DPRINT1("Usbhub: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
277 return ForwardIrpAndForget(DeviceObject, Irp);
278 }
279 }
280 Irp->IoStatus.Information = Information;
281 Irp->IoStatus.Status = Status;
282 IoCompleteRequest(Irp, IO_NO_INCREMENT);
283 return Status;
284 }
285
286 NTSTATUS
287 UsbhubDeviceControlFdo(
288 IN PDEVICE_OBJECT DeviceObject,
289 IN PIRP Irp)
290 {
291 PIO_STACK_LOCATION Stack;
292 ULONG IoControlCode;
293 PHUB_DEVICE_EXTENSION DeviceExtension;
294 ULONG LengthIn, LengthOut;
295 ULONG_PTR Information = 0;
296 PVOID BufferIn, BufferOut;
297 NTSTATUS Status;
298
299 Stack = IoGetCurrentIrpStackLocation(Irp);
300 LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength;
301 LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength;
302 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
303 IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
304 UsbhubGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut);
305
306 switch (IoControlCode)
307 {
308 case IOCTL_USB_GET_NODE_INFORMATION:
309 {
310 PUSB_NODE_INFORMATION NodeInformation;
311 struct usb_device* dev;
312 DPRINT("Usbhub: IOCTL_USB_GET_NODE_INFORMATION\n");
313 if (LengthOut < sizeof(USB_NODE_INFORMATION))
314 Status = STATUS_BUFFER_TOO_SMALL;
315 else if (BufferOut == NULL)
316 Status = STATUS_INVALID_PARAMETER;
317 else
318 {
319 NodeInformation = (PUSB_NODE_INFORMATION)BufferOut;
320 dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
321 NodeInformation->NodeType = UsbHub;
322 RtlCopyMemory(
323 &NodeInformation->u.HubInformation.HubDescriptor,
324 ((struct usb_hub *)usb_get_intfdata(to_usb_interface(&dev->actconfig->interface[0].dev)))->descriptor,
325 sizeof(USB_HUB_DESCRIPTOR));
326 NodeInformation->u.HubInformation.HubIsBusPowered = dev->actconfig->desc.bmAttributes & 0x80;
327 Information = sizeof(USB_NODE_INFORMATION);
328 Status = STATUS_SUCCESS;
329 }
330 break;
331 }
332 case IOCTL_USB_GET_NODE_CONNECTION_NAME:
333 {
334 PHUB_DEVICE_EXTENSION DeviceExtension;
335 PUSB_NODE_CONNECTION_NAME ConnectionName;
336 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
337 ConnectionName = (PUSB_NODE_CONNECTION_NAME)BufferOut;
338
339 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME\n");
340 if (LengthOut < sizeof(USB_NODE_CONNECTION_NAME))
341 Status = STATUS_BUFFER_TOO_SMALL;
342 else if (BufferOut == NULL)
343 Status = STATUS_INVALID_PARAMETER;
344 else if (ConnectionName->ConnectionIndex < 1
345 || ConnectionName->ConnectionIndex > USB_MAXCHILDREN)
346 Status = STATUS_INVALID_PARAMETER;
347 else if (DeviceExtension->Children[ConnectionName->ConnectionIndex - 1] == NULL)
348 Status = STATUS_INVALID_PARAMETER;
349 else
350 {
351 ULONG NeededStructureSize;
352 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceExtension->Children[ConnectionName->ConnectionIndex - 1]->DeviceExtension;
353 NeededStructureSize = DeviceExtension->SymbolicLinkName.Length + sizeof(UNICODE_NULL) + FIELD_OFFSET(USB_NODE_CONNECTION_NAME, NodeName);
354 if (ConnectionName->ActualLength < NeededStructureSize / sizeof(WCHAR)
355 || LengthOut < NeededStructureSize)
356 {
357 /* Buffer too small */
358 ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
359 Information = sizeof(USB_NODE_CONNECTION_NAME);
360 Status = STATUS_BUFFER_TOO_SMALL;
361 }
362 else
363 {
364 RtlCopyMemory(
365 ConnectionName->NodeName,
366 DeviceExtension->SymbolicLinkName.Buffer,
367 DeviceExtension->SymbolicLinkName.Length);
368 ConnectionName->NodeName[DeviceExtension->SymbolicLinkName.Length / sizeof(WCHAR)] = UNICODE_NULL;
369 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME returns '%S'\n", ConnectionName->NodeName);
370 ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
371 Information = NeededStructureSize;
372 Status = STATUS_SUCCESS;
373 }
374 Information = LengthOut;
375 }
376 break;
377 }
378 case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
379 {
380 PUSB_NODE_CONNECTION_INFORMATION ConnectionInformation;
381 ULONG i, j, k;
382 struct usb_device* dev;
383 ULONG NumberOfOpenPipes = 0;
384 ULONG SizeOfOpenPipesArray;
385 ConnectionInformation = (PUSB_NODE_CONNECTION_INFORMATION)BufferOut;
386
387 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n");
388 if (LengthOut < sizeof(USB_NODE_CONNECTION_INFORMATION))
389 Status = STATUS_BUFFER_TOO_SMALL;
390 else if (BufferOut == NULL)
391 Status = STATUS_INVALID_PARAMETER;
392 else if (ConnectionInformation->ConnectionIndex < 1
393 || ConnectionInformation->ConnectionIndex > USB_MAXCHILDREN)
394 Status = STATUS_INVALID_PARAMETER;
395 else
396 {
397 dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
398 dev = dev->children[ConnectionInformation->ConnectionIndex - 1];
399 if (dev == NULL)
400 {
401 /* No device connected to this port */
402 RtlZeroMemory(
403 &ConnectionInformation->DeviceDescriptor,
404 sizeof(USB_NODE_CONNECTION_INFORMATION) - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, DeviceDescriptor));
405 ConnectionInformation->ConnectionStatus = NoDeviceConnected;
406 Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
407 Status = STATUS_SUCCESS;
408 break;
409 }
410 SizeOfOpenPipesArray = (LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, PipeList)) / sizeof(USB_PIPE_INFO);
411 RtlCopyMemory(
412 &ConnectionInformation->DeviceDescriptor,
413 &dev->descriptor,
414 sizeof(USB_DEVICE_DESCRIPTOR));
415 ConnectionInformation->CurrentConfigurationValue = dev->actconfig->desc.bConfigurationValue;
416 ConnectionInformation->LowSpeed = dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL;
417 ConnectionInformation->DeviceIsHub = dev->descriptor.bDeviceClass == USB_CLASS_HUB;
418 ConnectionInformation->DeviceAddress = dev->devnum;
419 ConnectionInformation->ConnectionStatus = DeviceConnected;
420
421 for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
422 for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
423 for (k = 0; k < dev->actconfig->interface[i].altsetting[j].desc.bNumEndpoints; k++)
424 {
425 if (NumberOfOpenPipes < SizeOfOpenPipesArray)
426 {
427 PUSB_PIPE_INFO Pipe = &ConnectionInformation->PipeList[NumberOfOpenPipes];
428 struct usb_host_endpoint* endpoint = &dev->actconfig->interface[i].altsetting[j].endpoint[k];
429 RtlCopyMemory(
430 &Pipe->EndpointDescriptor,
431 &endpoint->desc,
432 endpoint->desc.bLength);
433 Pipe->ScheduleOffset = 0; /* FIXME */
434 }
435 NumberOfOpenPipes++;
436 }
437 ConnectionInformation->NumberOfOpenPipes = NumberOfOpenPipes;
438
439 Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
440 if (NumberOfOpenPipes <= SizeOfOpenPipesArray)
441 Status = STATUS_SUCCESS;
442 else
443 Status = STATUS_BUFFER_OVERFLOW;
444 }
445 break;
446 }
447 case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION:
448 {
449 //PUSB_DESCRIPTOR_REQUEST Descriptor;
450 DPRINT("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n");
451 DPRINT1("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION unimplemented\n");
452 Information = 0;
453 Status = STATUS_NOT_IMPLEMENTED;
454 break;
455 }
456 case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
457 {
458 PHUB_DEVICE_EXTENSION DeviceExtension;
459 PUSB_NODE_CONNECTION_DRIVERKEY_NAME StringDescriptor;
460 DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n");
461 DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
462 StringDescriptor = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)BufferOut;
463 if (LengthOut < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME))
464 Status = STATUS_BUFFER_TOO_SMALL;
465 else if (StringDescriptor == NULL)
466 Status = STATUS_INVALID_PARAMETER;
467 else if (StringDescriptor->ConnectionIndex < 1
468 || StringDescriptor->ConnectionIndex > USB_MAXCHILDREN)
469 Status = STATUS_INVALID_PARAMETER;
470 else if (DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1] == NULL)
471 Status = STATUS_INVALID_PARAMETER;
472 else
473 {
474 ULONG StringSize;
475 Status = IoGetDeviceProperty(
476 DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1],
477 DevicePropertyDriverKeyName,
478 LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName),
479 StringDescriptor->DriverKeyName,
480 &StringSize);
481 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
482 {
483 StringDescriptor->ActualLength = StringSize + FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName);
484 Information = LengthOut;
485 Status = STATUS_SUCCESS;
486 }
487 }
488 break;
489 }
490 default:
491 {
492 /* Pass Irp to lower driver */
493 DPRINT1("Usbhub: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
494 return ForwardIrpAndForget(DeviceObject, Irp);
495 }
496 }
497
498 Irp->IoStatus.Information = Information;
499 Irp->IoStatus.Status = Status;
500 IoCompleteRequest(Irp, IO_NO_INCREMENT);
501 return Status;
502 }