c370343b0a160aef16220d9404cc357c61d96840
[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 //
22 // set event
23 //
24 KeSetEvent((PRKEVENT)Context, 0, FALSE);
25
26 //
27 // completion is done in the HidClassFDO_QueryCapabilities routine
28 //
29 return STATUS_MORE_PROCESSING_REQUIRED;
30 }
31
32 NTSTATUS
33 FDO_QueryCapabilities(
34 IN PDEVICE_OBJECT DeviceObject,
35 IN OUT PDEVICE_CAPABILITIES Capabilities)
36 {
37 PIRP Irp;
38 KEVENT Event;
39 NTSTATUS Status;
40 PIO_STACK_LOCATION IoStack;
41 PFDO_DEVICE_EXTENSION FDODeviceExtension;
42
43 //
44 // get device extension
45 //
46 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
47 ASSERT(FDODeviceExtension->Common.IsFDO);
48
49 //
50 // init event
51 //
52 KeInitializeEvent(&Event, NotificationEvent, FALSE);
53
54 //
55 // now allocte the irp
56 //
57 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
58 if (!Irp)
59 {
60 //
61 // no memory
62 //
63 return STATUS_INSUFFICIENT_RESOURCES;
64 }
65
66 //
67 // get next stack location
68 //
69 IoStack = IoGetNextIrpStackLocation(Irp);
70
71 //
72 // init stack location
73 //
74 IoStack->MajorFunction = IRP_MJ_PNP;
75 IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
76 IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities;
77
78 //
79 // set completion routine
80 //
81 IoSetCompletionRoutine(Irp, FDO_QueryCapabilitiesCompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
82
83 //
84 // init capabilities
85 //
86 RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
87 Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
88 Capabilities->Version = 1; // FIXME hardcoded constant
89 Capabilities->Address = MAXULONG;
90 Capabilities->UINumber = MAXULONG;
91
92 //
93 // pnp irps have default completion code
94 //
95 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
96
97 //
98 // call lower device
99 //
100 Status = IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
101 if (Status == STATUS_PENDING)
102 {
103 //
104 // wait for completion
105 //
106 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
107 }
108
109 //
110 // get status
111 //
112 Status = Irp->IoStatus.Status;
113
114 //
115 // complete request
116 //
117 IoFreeIrp(Irp);
118
119 //
120 // done
121 //
122 return Status;
123 }
124
125 NTSTATUS
126 FDO_DeviceRelations(
127 PDEVICE_OBJECT DeviceObject,
128 PIRP Irp)
129 {
130 ULONG DeviceCount = 0;
131 ULONG Index;
132 PDEVICE_RELATIONS DeviceRelations;
133 PIO_STACK_LOCATION IoStack;
134 PFDO_DEVICE_EXTENSION FDODeviceExtension;
135
136 //
137 // get device extension
138 //
139 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
140
141 //
142 // get current irp stack location
143 //
144 IoStack = IoGetCurrentIrpStackLocation(Irp);
145
146 //
147 // check if relation type is BusRelations
148 //
149 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
150 {
151 //
152 // FDO always only handles bus relations
153 //
154 return USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
155 }
156
157 //
158 // go through array and count device objects
159 //
160 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
161 {
162 if (FDODeviceExtension->ChildPDO[Index])
163 {
164 //
165 // child pdo
166 //
167 DeviceCount++;
168 }
169 }
170
171 //
172 // allocate device relations
173 //
174 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
175 if (!DeviceRelations)
176 {
177 //
178 // no memory
179 //
180 return STATUS_INSUFFICIENT_RESOURCES;
181 }
182
183 //
184 // add device objects
185 //
186 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
187 {
188 if (FDODeviceExtension->ChildPDO[Index])
189 {
190 //
191 // store child pdo
192 //
193 DeviceRelations->Objects[DeviceRelations->Count] = FDODeviceExtension->ChildPDO[Index];
194
195 //
196 // add reference
197 //
198 ObReferenceObject(FDODeviceExtension->ChildPDO[Index]);
199
200 //
201 // increment count
202 //
203 DeviceRelations->Count++;
204 }
205 }
206
207 //
208 // store result
209 //
210 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
211
212 //
213 // request completed successfully
214 //
215 return STATUS_SUCCESS;
216 }
217
218 NTSTATUS
219 FDO_CreateChildPdo(
220 IN PDEVICE_OBJECT DeviceObject)
221 {
222 NTSTATUS Status;
223 PDEVICE_OBJECT PDODeviceObject;
224 PPDO_DEVICE_EXTENSION PDODeviceExtension;
225 PFDO_DEVICE_EXTENSION FDODeviceExtension;
226 ULONG Index;
227
228 //
229 // get device extension
230 //
231 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
232 ASSERT(FDODeviceExtension->Common.IsFDO);
233
234 //
235 // lets create array for the child PDO
236 //
237 FDODeviceExtension->ChildPDO = AllocateItem(NonPagedPool, sizeof(PDEVICE_OBJECT) * FDODeviceExtension->FunctionDescriptorCount);
238 if (!FDODeviceExtension->ChildPDO)
239 {
240 //
241 // no memory
242 //
243 return STATUS_INSUFFICIENT_RESOURCES;
244 }
245
246 //
247 // create pdo for each function
248 //
249 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
250 {
251 //
252 // create the PDO
253 //
254 Status = IoCreateDevice(FDODeviceExtension->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_USB, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject);
255 if (!NT_SUCCESS(Status))
256 {
257 //
258 // failed to create device object
259 //
260 DPRINT1("IoCreateDevice failed with %x\n", Status);
261 return Status;
262 }
263
264 //
265 // store in array
266 //
267 FDODeviceExtension->ChildPDO[Index] = PDODeviceObject;
268
269 //
270 // get device extension
271 //
272 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
273 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
274
275 //
276 // init device extension
277 //
278 PDODeviceExtension->Common.IsFDO = FALSE;
279 PDODeviceExtension->FunctionDescriptor = &FDODeviceExtension->FunctionDescriptor[Index];
280 PDODeviceExtension->NextDeviceObject = DeviceObject;
281 PDODeviceExtension->FunctionIndex = Index;
282 PDODeviceExtension->FDODeviceExtension = FDODeviceExtension;
283 PDODeviceExtension->InterfaceList = FDODeviceExtension->InterfaceList;
284 PDODeviceExtension->InterfaceListCount = FDODeviceExtension->InterfaceListCount;
285 PDODeviceExtension->ConfigurationHandle = FDODeviceExtension->ConfigurationHandle;
286 PDODeviceExtension->ConfigurationDescriptor = FDODeviceExtension->ConfigurationDescriptor;
287 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
288 RtlCopyMemory(&PDODeviceExtension->DeviceDescriptor, &FDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
289
290 //
291 // patch the stack size
292 //
293 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
294
295 //
296 // set device flags
297 //
298 PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
299
300 //
301 // device is initialized
302 //
303 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
304 }
305
306 //
307 // done
308 //
309 return STATUS_SUCCESS;
310 }
311
312 NTSTATUS
313 FDO_StartDevice(
314 PDEVICE_OBJECT DeviceObject,
315 PIRP Irp)
316 {
317 NTSTATUS Status;
318 PFDO_DEVICE_EXTENSION FDODeviceExtension;
319
320 //
321 // get device extension
322 //
323 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
324 ASSERT(FDODeviceExtension->Common.IsFDO);
325
326 //
327 // first start lower device
328 //
329 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
330
331 if (!NT_SUCCESS(Status))
332 {
333 //
334 // failed to start lower device
335 //
336 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
337 return Status;
338 }
339
340 // get descriptors
341 Status = USBCCGP_GetDescriptors(DeviceObject);
342 if (!NT_SUCCESS(Status))
343 {
344 // failed to start lower device
345 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
346 return Status;
347 }
348
349 // get capabilities
350 Status = FDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
351 if (!NT_SUCCESS(Status))
352 {
353 // failed to start lower device
354 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
355 return Status;
356 }
357
358 // now select the configuration
359 Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
360 if (!NT_SUCCESS(Status))
361 {
362 // failed to select interface
363 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
364 return Status;
365 }
366
367 // query bus interface
368 USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject, &FDODeviceExtension->BusInterface);
369
370 // now enumerate the functions
371 Status = USBCCGP_EnumerateFunctions(DeviceObject);
372 if (!NT_SUCCESS(Status))
373 {
374 // failed to enumerate functions
375 DPRINT1("Failed to enumerate functions with %x\n", Status);
376 return Status;
377 }
378
379 //
380 // sanity checks
381 //
382 ASSERT(FDODeviceExtension->FunctionDescriptorCount);
383 ASSERT(FDODeviceExtension->FunctionDescriptor);
384 DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor, FDODeviceExtension->FunctionDescriptorCount);
385
386 //
387 // now create the pdo
388 //
389 Status = FDO_CreateChildPdo(DeviceObject);
390 if (!NT_SUCCESS(Status))
391 {
392 //
393 // failed
394 //
395 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
396 return Status;
397 }
398
399 //
400 // inform pnp manager of new device objects
401 //
402 IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject, BusRelations);
403
404 //
405 // done
406 //
407 DPRINT1("[USBCCGP] FDO initialized successfully\n");
408 return Status;
409 }
410
411 NTSTATUS
412 FDO_HandlePnp(
413 PDEVICE_OBJECT DeviceObject,
414 PIRP Irp)
415 {
416 PIO_STACK_LOCATION IoStack;
417 NTSTATUS Status;
418 PFDO_DEVICE_EXTENSION FDODeviceExtension;
419
420 // get device extension
421 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
422 ASSERT(FDODeviceExtension->Common.IsFDO);
423
424
425 // get stack location
426 IoStack = IoGetCurrentIrpStackLocation(Irp);
427 DPRINT1("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction);
428 switch(IoStack->MinorFunction)
429 {
430 case IRP_MN_REMOVE_DEVICE:
431 {
432 /* Send the IRP down the stack */
433 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
434 if (NT_SUCCESS(Status))
435 {
436 //
437 // Detach from the device stack
438 //
439 IoDetachDevice(FDODeviceExtension->NextDeviceObject);
440
441 //
442 // Delete the device object
443 //
444 IoDeleteDevice(DeviceObject);
445 }
446
447 //
448 // request completed
449 //
450 break;
451 }
452 case IRP_MN_START_DEVICE:
453 {
454 //
455 // start the device
456 //
457 Status = FDO_StartDevice(DeviceObject, Irp);
458 break;
459 }
460 case IRP_MN_QUERY_DEVICE_RELATIONS:
461 {
462 //
463 // handle device relations
464 //
465 Status = FDO_DeviceRelations(DeviceObject, Irp);
466 break;
467 }
468 case IRP_MN_QUERY_CAPABILITIES:
469 {
470 //
471 // copy capabilities
472 //
473 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
474 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
475 if (NT_SUCCESS(Status))
476 {
477 //
478 // surprise removal ok
479 //
480 IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
481 }
482 break;
483 }
484 case IRP_MN_QUERY_REMOVE_DEVICE:
485 case IRP_MN_QUERY_STOP_DEVICE:
486 {
487 //
488 // sure
489 //
490 Irp->IoStatus.Status = STATUS_SUCCESS;
491
492 //
493 // forward irp to next device object
494 //
495 IoSkipCurrentIrpStackLocation(Irp);
496 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
497 }
498 default:
499 {
500 //
501 // forward irp to next device object
502 //
503 IoSkipCurrentIrpStackLocation(Irp);
504 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
505 }
506
507 }
508
509 //
510 // complete request
511 //
512 Irp->IoStatus.Status = Status;
513 IoCompleteRequest(Irp, IO_NO_INCREMENT);
514 return Status;
515 }
516
517 NTSTATUS
518 FDO_HandleResetCyclePort(
519 PDEVICE_OBJECT DeviceObject,
520 PIRP Irp)
521 {
522 PIO_STACK_LOCATION IoStack;
523 NTSTATUS Status;
524 PFDO_DEVICE_EXTENSION FDODeviceExtension;
525 PLIST_ENTRY ListHead, Entry;
526 LIST_ENTRY TempList;
527 PUCHAR ResetActive;
528 PIRP ListIrp;
529 KIRQL OldLevel;
530
531 //
532 // get device extension
533 //
534 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
535 ASSERT(FDODeviceExtension->Common.IsFDO);
536
537 // get stack location
538 IoStack = IoGetCurrentIrpStackLocation(Irp);
539 DPRINT1("FDO_HandleResetCyclePort IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
540
541 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT)
542 {
543 //
544 // use reset port list
545 //
546 ListHead = &FDODeviceExtension->ResetPortListHead;
547 ResetActive = &FDODeviceExtension->ResetPortActive;
548 }
549 else
550 {
551 //
552 // use cycle port list
553 //
554 ListHead = &FDODeviceExtension->CyclePortListHead;
555 ResetActive = &FDODeviceExtension->CyclePortActive;
556 }
557
558 //
559 // acquire lock
560 //
561 KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
562
563 if (*ResetActive)
564 {
565 //
566 // insert into pending list
567 //
568 InsertTailList(ListHead, &Irp->Tail.Overlay.ListEntry);
569
570 //
571 // mark irp pending
572 //
573 IoMarkIrpPending(Irp);
574 Status = STATUS_PENDING;
575
576 //
577 // release lock
578 //
579 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
580 }
581 else
582 {
583 //
584 // mark reset active
585 //
586 *ResetActive = TRUE;
587
588 //
589 // release lock
590 //
591 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
592
593 //
594 // forward request synchronized
595 //
596 USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
597
598 //
599 // reacquire lock
600 //
601 KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
602
603 //
604 // mark reset as completed
605 //
606 *ResetActive = FALSE;
607
608 //
609 // move all requests into temporary list
610 //
611 InitializeListHead(&TempList);
612 while(!IsListEmpty(ListHead))
613 {
614 Entry = RemoveHeadList(ListHead);
615 InsertTailList(&TempList, Entry);
616 }
617
618 //
619 // release lock
620 //
621 KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
622
623 //
624 // complete pending irps
625 //
626 while(!IsListEmpty(&TempList))
627 {
628 Entry = RemoveHeadList(&TempList);
629 ListIrp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
630
631 //
632 // complete request with status success
633 //
634 Irp->IoStatus.Status = STATUS_SUCCESS;
635 IoCompleteRequest(Irp, IO_NO_INCREMENT);
636 }
637
638 //
639 // status success
640 //
641 Status = STATUS_SUCCESS;
642 }
643
644 return Status;
645 }
646
647
648
649 NTSTATUS
650 FDO_HandleInternalDeviceControl(
651 PDEVICE_OBJECT DeviceObject,
652 PIRP Irp)
653 {
654 PIO_STACK_LOCATION IoStack;
655 NTSTATUS Status;
656 PFDO_DEVICE_EXTENSION FDODeviceExtension;
657
658 //
659 // get device extension
660 //
661 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
662 ASSERT(FDODeviceExtension->Common.IsFDO);
663
664 // get stack location
665 IoStack = IoGetCurrentIrpStackLocation(Irp);
666
667 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT ||
668 IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT)
669 {
670 //
671 // handle reset / cycle ports
672 //
673 Status = FDO_HandleResetCyclePort(DeviceObject, Irp);
674 DPRINT1("FDO_HandleResetCyclePort Status %x\n", Status);
675 if (Status != STATUS_PENDING)
676 {
677 //
678 // complete request
679 //
680 Irp->IoStatus.Status = Status;
681 IoCompleteRequest(Irp, IO_NO_INCREMENT);
682 }
683 return Status;
684 }
685
686 //
687 // forward and forget request
688 //
689 IoSkipCurrentIrpStackLocation(Irp);
690 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
691 }
692
693 NTSTATUS
694 FDO_Dispatch(
695 PDEVICE_OBJECT DeviceObject,
696 PIRP Irp)
697 {
698 PIO_STACK_LOCATION IoStack;
699 NTSTATUS Status;
700
701 /* get stack location */
702 IoStack = IoGetCurrentIrpStackLocation(Irp);
703
704 switch(IoStack->MajorFunction)
705 {
706 case IRP_MJ_PNP:
707 return FDO_HandlePnp(DeviceObject, Irp);
708 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
709 return FDO_HandleInternalDeviceControl(DeviceObject, Irp);
710 default:
711 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
712 ASSERT(FALSE);
713 Status = Irp->IoStatus.Status;
714 IoCompleteRequest(Irp, IO_NO_INCREMENT);
715 return Status;
716 }
717
718 }
719
720