Synchronize with trunk r58606.
[reactos.git] / drivers / usb / usbccgp / fdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbccgp/fdo.c
5 * PURPOSE: USB device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 * Cameron Gutman
10 */
11
12 #include "usbccgp.h"
13
14 NTSTATUS
15 NTAPI
16 FDO_QueryCapabilitiesCompletionRoutine(
17 IN PDEVICE_OBJECT DeviceObject,
18 IN PIRP Irp,
19 IN PVOID Context)
20 {
21 /* Set event */
22 KeSetEvent((PRKEVENT)Context, 0, FALSE);
23
24 /* Completion is done in the HidClassFDO_QueryCapabilities routine */
25 return STATUS_MORE_PROCESSING_REQUIRED;
26 }
27
28 NTSTATUS
29 FDO_QueryCapabilities(
30 IN PDEVICE_OBJECT DeviceObject,
31 IN OUT PDEVICE_CAPABILITIES Capabilities)
32 {
33 PIRP Irp;
34 KEVENT Event;
35 NTSTATUS Status;
36 PIO_STACK_LOCATION IoStack;
37 PFDO_DEVICE_EXTENSION FDODeviceExtension;
38
39 /* Get device extension */
40 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
41 ASSERT(FDODeviceExtension->Common.IsFDO);
42
43 /* Init event */
44 KeInitializeEvent(&Event, NotificationEvent, FALSE);
45
46 /* Now allocte the irp */
47 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
48 if (!Irp)
49 {
50 /* No memory */
51 return STATUS_INSUFFICIENT_RESOURCES;
52 }
53
54 /* Get next stack location */
55 IoStack = IoGetNextIrpStackLocation(Irp);
56
57 /* Init stack location */
58 IoStack->MajorFunction = IRP_MJ_PNP;
59 IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
60 IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities;
61
62 /* Set completion routine */
63 IoSetCompletionRoutine(Irp,
64 FDO_QueryCapabilitiesCompletionRoutine,
65 (PVOID)&Event,
66 TRUE,
67 TRUE,
68 TRUE);
69
70 /* Init capabilities */
71 RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
72 Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
73 Capabilities->Version = 1; // FIXME hardcoded constant
74 Capabilities->Address = MAXULONG;
75 Capabilities->UINumber = MAXULONG;
76
77 /* Pnp irps have default completion code */
78 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
79
80 /* Call lower device */
81 Status = IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
82 if (Status == STATUS_PENDING)
83 {
84 /* Wait for completion */
85 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
86 }
87
88 /* Get status */
89 Status = Irp->IoStatus.Status;
90
91 /* Complete request */
92 IoFreeIrp(Irp);
93
94 /* Done */
95 return Status;
96 }
97
98 NTSTATUS
99 FDO_DeviceRelations(
100 PDEVICE_OBJECT DeviceObject,
101 PIRP Irp)
102 {
103 ULONG DeviceCount = 0;
104 ULONG Index;
105 PDEVICE_RELATIONS DeviceRelations;
106 PIO_STACK_LOCATION IoStack;
107 PFDO_DEVICE_EXTENSION FDODeviceExtension;
108
109 /* Get device extension */
110 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
111
112 /* Get current irp stack location */
113 IoStack = IoGetCurrentIrpStackLocation(Irp);
114
115 /* Check if relation type is BusRelations */
116 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
117 {
118 /* FDO always only handles bus relations */
119 return USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
120 }
121
122 /* Go through array and count device objects */
123 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
124 {
125 if (FDODeviceExtension->ChildPDO[Index])
126 {
127 /* Child pdo */
128 DeviceCount++;
129 }
130 }
131
132 /* Allocate device relations */
133 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool,
134 sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
135 if (!DeviceRelations)
136 {
137 /* No memory */
138 return STATUS_INSUFFICIENT_RESOURCES;
139 }
140
141 /* Add device objects */
142 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
143 {
144 if (FDODeviceExtension->ChildPDO[Index])
145 {
146 /* Store child pdo */
147 DeviceRelations->Objects[DeviceRelations->Count] = FDODeviceExtension->ChildPDO[Index];
148
149 /* Add reference */
150 ObReferenceObject(FDODeviceExtension->ChildPDO[Index]);
151
152 /* Increment count */
153 DeviceRelations->Count++;
154 }
155 }
156
157 /* Store result */
158 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
159
160 /* Request completed successfully */
161 return STATUS_SUCCESS;
162 }
163
164 NTSTATUS
165 FDO_CreateChildPdo(
166 IN PDEVICE_OBJECT DeviceObject)
167 {
168 NTSTATUS Status;
169 PDEVICE_OBJECT PDODeviceObject;
170 PPDO_DEVICE_EXTENSION PDODeviceExtension;
171 PFDO_DEVICE_EXTENSION FDODeviceExtension;
172 ULONG Index;
173
174 /* Get device extension */
175 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
176 ASSERT(FDODeviceExtension->Common.IsFDO);
177
178 /* Lets create array for the child PDO */
179 FDODeviceExtension->ChildPDO = AllocateItem(NonPagedPool,
180 sizeof(PDEVICE_OBJECT) * FDODeviceExtension->FunctionDescriptorCount);
181 if (!FDODeviceExtension->ChildPDO)
182 {
183 /* No memory */
184 return STATUS_INSUFFICIENT_RESOURCES;
185 }
186
187 /* Create pdo for each function */
188 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
189 {
190 /* Create the PDO */
191 Status = IoCreateDevice(FDODeviceExtension->DriverObject,
192 sizeof(PDO_DEVICE_EXTENSION),
193 NULL,
194 FILE_DEVICE_USB,
195 FILE_AUTOGENERATED_DEVICE_NAME,
196 FALSE,
197 &PDODeviceObject);
198 if (!NT_SUCCESS(Status))
199 {
200 /* Failed to create device object */
201 DPRINT1("IoCreateDevice failed with %x\n", Status);
202 return Status;
203 }
204
205 /* Store in array */
206 FDODeviceExtension->ChildPDO[Index] = PDODeviceObject;
207
208 /* Get device extension */
209 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
210 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
211
212 /* Init device extension */
213 PDODeviceExtension->Common.IsFDO = FALSE;
214 PDODeviceExtension->FunctionDescriptor = &FDODeviceExtension->FunctionDescriptor[Index];
215 PDODeviceExtension->NextDeviceObject = DeviceObject;
216 PDODeviceExtension->FunctionIndex = Index;
217 PDODeviceExtension->FDODeviceExtension = FDODeviceExtension;
218 PDODeviceExtension->InterfaceList = FDODeviceExtension->InterfaceList;
219 PDODeviceExtension->InterfaceListCount = FDODeviceExtension->InterfaceListCount;
220 PDODeviceExtension->ConfigurationHandle = FDODeviceExtension->ConfigurationHandle;
221 PDODeviceExtension->ConfigurationDescriptor = FDODeviceExtension->ConfigurationDescriptor;
222 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
223 RtlCopyMemory(&PDODeviceExtension->DeviceDescriptor, &FDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
224
225 /* Patch the stack size */
226 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
227
228 /* Set device flags */
229 PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
230
231 /* Device is initialized */
232 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
233 }
234
235 /* Done */
236 return STATUS_SUCCESS;
237 }
238
239 NTSTATUS
240 FDO_StartDevice(
241 PDEVICE_OBJECT DeviceObject,
242 PIRP Irp)
243 {
244 NTSTATUS Status;
245 PFDO_DEVICE_EXTENSION FDODeviceExtension;
246
247 /* Get device extension */
248 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
249 ASSERT(FDODeviceExtension->Common.IsFDO);
250
251 /* First start lower device */
252 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
253
254 if (!NT_SUCCESS(Status))
255 {
256 /* Failed to start lower device */
257 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
258 return Status;
259 }
260
261 /* Get descriptors */
262 Status = USBCCGP_GetDescriptors(DeviceObject);
263 if (!NT_SUCCESS(Status))
264 {
265 /* Failed to start lower device */
266 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
267 return Status;
268 }
269
270 /* Get capabilities */
271 Status = FDO_QueryCapabilities(DeviceObject,
272 &FDODeviceExtension->Capabilities);
273 if (!NT_SUCCESS(Status))
274 {
275 /* Failed to start lower device */
276 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
277 return Status;
278 }
279
280 /* Now select the configuration */
281 Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
282 if (!NT_SUCCESS(Status))
283 {
284 /* Failed to select interface */
285 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
286 return Status;
287 }
288
289 /* Query bus interface */
290 USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject,
291 &FDODeviceExtension->BusInterface);
292
293 /* Now enumerate the functions */
294 Status = USBCCGP_EnumerateFunctions(DeviceObject);
295 if (!NT_SUCCESS(Status))
296 {
297 /* Failed to enumerate functions */
298 DPRINT1("Failed to enumerate functions with %x\n", Status);
299 return Status;
300 }
301
302 /* Sanity checks */
303 ASSERT(FDODeviceExtension->FunctionDescriptorCount);
304 ASSERT(FDODeviceExtension->FunctionDescriptor);
305 DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor,
306 FDODeviceExtension->FunctionDescriptorCount);
307
308 /* Now create the pdo */
309 Status = FDO_CreateChildPdo(DeviceObject);
310 if (!NT_SUCCESS(Status))
311 {
312 /* Failed */
313 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
314 return Status;
315 }
316
317 /* Inform pnp manager of new device objects */
318 IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject,
319 BusRelations);
320
321 /* Done */
322 DPRINT("[USBCCGP] FDO initialized successfully\n");
323 return Status;
324 }
325
326 NTSTATUS
327 FDO_CloseConfiguration(
328 IN PDEVICE_OBJECT DeviceObject)
329 {
330 NTSTATUS Status;
331 PURB Urb;
332 PFDO_DEVICE_EXTENSION FDODeviceExtension;
333
334 /* Get device extension */
335 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
336 ASSERT(FDODeviceExtension->Common.IsFDO);
337
338 /* Now allocate the urb */
339 Urb = USBD_CreateConfigurationRequestEx(FDODeviceExtension->ConfigurationDescriptor,
340 FDODeviceExtension->InterfaceList);
341 if (!Urb)
342 {
343 /* No memory */
344 return STATUS_INSUFFICIENT_RESOURCES;
345 }
346
347 /* Clear configuration descriptor to make it an unconfigure request */
348 Urb->UrbSelectConfiguration.ConfigurationDescriptor = NULL;
349
350 /* Submit urb */
351 Status = USBCCGP_SyncUrbRequest(FDODeviceExtension->NextDeviceObject, Urb);
352 if (!NT_SUCCESS(Status))
353 {
354 /* Failed to set configuration */
355 DPRINT1("USBCCGP_SyncUrbRequest failed to unconfigure device\n", Status);
356 }
357
358 ExFreePool(Urb);
359 return Status;
360 }
361
362
363 NTSTATUS
364 FDO_HandlePnp(
365 PDEVICE_OBJECT DeviceObject,
366 PIRP Irp)
367 {
368 PIO_STACK_LOCATION IoStack;
369 NTSTATUS Status;
370 PFDO_DEVICE_EXTENSION FDODeviceExtension;
371
372 /* Get device extension */
373 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
374 ASSERT(FDODeviceExtension->Common.IsFDO);
375
376
377 /* Get stack location */
378 IoStack = IoGetCurrentIrpStackLocation(Irp);
379 DPRINT("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction);
380 switch(IoStack->MinorFunction)
381 {
382 case IRP_MN_REMOVE_DEVICE:
383 {
384 // Unconfigure device */
385 DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n");
386 FDO_CloseConfiguration(DeviceObject);
387
388 /* Send the IRP down the stack */
389 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject,
390 Irp);
391 if (NT_SUCCESS(Status))
392 {
393 /* Detach from the device stack */
394 IoDetachDevice(FDODeviceExtension->NextDeviceObject);
395
396 /* Delete the device object */
397 IoDeleteDevice(DeviceObject);
398 }
399
400 /* Request completed */
401 break;
402 }
403 case IRP_MN_START_DEVICE:
404 {
405 /* Start the device */
406 Status = FDO_StartDevice(DeviceObject, Irp);
407 break;
408 }
409 case IRP_MN_QUERY_DEVICE_RELATIONS:
410 {
411 /* Handle device relations */
412 Status = FDO_DeviceRelations(DeviceObject, Irp);
413 break;
414 }
415 case IRP_MN_QUERY_CAPABILITIES:
416 {
417 /* Copy capabilities */
418 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities,
419 &FDODeviceExtension->Capabilities,
420 sizeof(DEVICE_CAPABILITIES));
421 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
422 if (NT_SUCCESS(Status))
423 {
424 /* Surprise removal ok */
425 IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
426 }
427 break;
428 }
429 case IRP_MN_QUERY_REMOVE_DEVICE:
430 case IRP_MN_QUERY_STOP_DEVICE:
431 {
432 /* Sure */
433 Irp->IoStatus.Status = STATUS_SUCCESS;
434
435 /* Forward irp to next device object */
436 IoSkipCurrentIrpStackLocation(Irp);
437 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
438 }
439 default:
440 {
441 /* Forward irp to next device object */
442 IoSkipCurrentIrpStackLocation(Irp);
443 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
444 }
445
446 }
447
448 /* Complete request */
449 Irp->IoStatus.Status = Status;
450 IoCompleteRequest(Irp, IO_NO_INCREMENT);
451 return Status;
452 }
453
454 NTSTATUS
455 FDO_HandleResetCyclePort(
456 PDEVICE_OBJECT DeviceObject,
457 PIRP Irp)
458 {
459 PIO_STACK_LOCATION IoStack;
460 NTSTATUS Status;
461 PFDO_DEVICE_EXTENSION FDODeviceExtension;
462 PLIST_ENTRY ListHead, Entry;
463 LIST_ENTRY TempList;
464 PUCHAR ResetActive;
465 PIRP ListIrp;
466 KIRQL OldLevel;
467
468 /* Get device extension */
469 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
470 ASSERT(FDODeviceExtension->Common.IsFDO);
471
472 /* Get stack location */
473 IoStack = IoGetCurrentIrpStackLocation(Irp);
474 DPRINT("FDO_HandleResetCyclePort IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
475
476 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT)
477 {
478 /* Use reset port list */
479 ListHead = &FDODeviceExtension->ResetPortListHead;
480 ResetActive = &FDODeviceExtension->ResetPortActive;
481 }
482 else
483 {
484 /* Use cycle port list */
485 ListHead = &FDODeviceExtension->CyclePortListHead;
486 ResetActive = &FDODeviceExtension->CyclePortActive;
487 }
488
489 /* Acquire lock */
490 KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
491
492 if (*ResetActive)
493 {
494 /* Insert into pending list */
495 InsertTailList(ListHead, &Irp->Tail.Overlay.ListEntry);
496
497 /* Mark irp pending */
498 IoMarkIrpPending(Irp);
499 Status = STATUS_PENDING;
500
501 /* Release lock */
502 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
503 }
504 else
505 {
506 /* Mark reset active */
507 *ResetActive = TRUE;
508
509 /* Release lock */
510 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
511
512 /* Forward request synchronized */
513 USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
514
515 /* Reacquire lock */
516 KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
517
518 /* Mark reset as completed */
519 *ResetActive = FALSE;
520
521 /* Move all requests into temporary list */
522 InitializeListHead(&TempList);
523 while(!IsListEmpty(ListHead))
524 {
525 Entry = RemoveHeadList(ListHead);
526 InsertTailList(&TempList, Entry);
527 }
528
529 /* Release lock */
530 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
531
532 /* Complete pending irps */
533 while(!IsListEmpty(&TempList))
534 {
535 Entry = RemoveHeadList(&TempList);
536 ListIrp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
537
538 /* Complete request with status success */
539 Irp->IoStatus.Status = STATUS_SUCCESS;
540 IoCompleteRequest(Irp, IO_NO_INCREMENT);
541 }
542
543 /* Status success */
544 Status = STATUS_SUCCESS;
545 }
546
547 return Status;
548 }
549
550
551
552 NTSTATUS
553 FDO_HandleInternalDeviceControl(
554 PDEVICE_OBJECT DeviceObject,
555 PIRP Irp)
556 {
557 PIO_STACK_LOCATION IoStack;
558 NTSTATUS Status;
559 PFDO_DEVICE_EXTENSION FDODeviceExtension;
560
561 /* Get device extension */
562 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
563 ASSERT(FDODeviceExtension->Common.IsFDO);
564
565 /* Get stack location */
566 IoStack = IoGetCurrentIrpStackLocation(Irp);
567
568 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT ||
569 IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT)
570 {
571 /* Handle reset / cycle ports */
572 Status = FDO_HandleResetCyclePort(DeviceObject, Irp);
573 DPRINT("FDO_HandleResetCyclePort Status %x\n", Status);
574 if (Status != STATUS_PENDING)
575 {
576 /* Complete request */
577 Irp->IoStatus.Status = Status;
578 IoCompleteRequest(Irp, IO_NO_INCREMENT);
579 }
580 return Status;
581 }
582
583 /* Forward and forget request */
584 IoSkipCurrentIrpStackLocation(Irp);
585 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
586 }
587
588 NTSTATUS
589 FDO_Dispatch(
590 PDEVICE_OBJECT DeviceObject,
591 PIRP Irp)
592 {
593 PIO_STACK_LOCATION IoStack;
594 NTSTATUS Status;
595
596 /* Get stack location */
597 IoStack = IoGetCurrentIrpStackLocation(Irp);
598
599 switch(IoStack->MajorFunction)
600 {
601 case IRP_MJ_PNP:
602 return FDO_HandlePnp(DeviceObject, Irp);
603 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
604 return FDO_HandleInternalDeviceControl(DeviceObject, Irp);
605 default:
606 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
607 ASSERT(FALSE);
608 Status = Irp->IoStatus.Status;
609 IoCompleteRequest(Irp, IO_NO_INCREMENT);
610 return Status;
611 }
612
613 }