[NTOSKRNL_VISTA] Implement IoGetIrpExtraCreateParameter
[reactos.git] / sdk / lib / drivers / libusb / hcd_controller.cpp
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/libusb/hcd_controller.cpp
5 * PURPOSE: USB Common Driver Library.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #include "libusb.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 class CHCDController : public IHCDController,
17 public IDispatchIrp
18 {
19 public:
20 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
21
22 STDMETHODIMP_(ULONG) AddRef()
23 {
24 InterlockedIncrement(&m_Ref);
25 return m_Ref;
26 }
27 STDMETHODIMP_(ULONG) Release()
28 {
29 InterlockedDecrement(&m_Ref);
30
31 if (!m_Ref)
32 {
33 delete this;
34 return 0;
35 }
36 return m_Ref;
37 }
38
39 // IHCDController interface functions
40 NTSTATUS Initialize(IN PROOTHDCCONTROLLER RootHCDController, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
41
42 // IDispatchIrp interface functions
43 NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
44 NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
45 NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
46 NTSTATUS HandleSystemControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
47
48 // local functions
49 NTSTATUS CreateFDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject);
50 NTSTATUS SetSymbolicLink(BOOLEAN Enable);
51
52 // constructor / destructor
53 CHCDController(IUnknown *OuterUnknown){}
54 virtual ~CHCDController(){}
55
56 protected:
57 LONG m_Ref;
58 PROOTHDCCONTROLLER m_RootController;
59 PDRIVER_OBJECT m_DriverObject;
60 PDEVICE_OBJECT m_PhysicalDeviceObject;
61 PDEVICE_OBJECT m_FunctionalDeviceObject;
62 PDEVICE_OBJECT m_NextDeviceObject;
63 PUSBHARDWAREDEVICE m_Hardware;
64 PHUBCONTROLLER m_HubController;
65 ULONG m_FDODeviceNumber;
66 LPCSTR m_USBType;
67 };
68
69 //=================================================================================================
70 // COM
71 //
72 NTSTATUS
73 STDMETHODCALLTYPE
74 CHCDController::QueryInterface(
75 IN REFIID refiid,
76 OUT PVOID* Output)
77 {
78 return STATUS_UNSUCCESSFUL;
79 }
80
81 //-------------------------------------------------------------------------------------------------
82 NTSTATUS
83 CHCDController::Initialize(
84 IN PROOTHDCCONTROLLER RootHCDController,
85 IN PDRIVER_OBJECT DriverObject,
86 IN PDEVICE_OBJECT PhysicalDeviceObject)
87 {
88 NTSTATUS Status;
89 PCOMMON_DEVICE_EXTENSION DeviceExtension;
90
91 //
92 // create usb hardware
93 //
94 Status = CreateUSBHardware(&m_Hardware);
95 if (!NT_SUCCESS(Status))
96 {
97 //
98 // failed to create hardware object
99 //
100 DPRINT1("Failed to create hardware object\n");
101 return STATUS_INSUFFICIENT_RESOURCES;
102 }
103
104 //
105 // initialize members
106 //
107 m_DriverObject = DriverObject;
108 m_PhysicalDeviceObject = PhysicalDeviceObject;
109 m_RootController = RootHCDController;
110
111 //
112 // create FDO
113 //
114 Status = CreateFDO(m_DriverObject, &m_FunctionalDeviceObject);
115 if (!NT_SUCCESS(Status))
116 {
117 //
118 // failed to create PDO
119 //
120 return Status;
121 }
122
123 //
124 // now attach to device stack
125 //
126 m_NextDeviceObject = IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject, m_PhysicalDeviceObject);
127 if (!m_NextDeviceObject)
128 {
129 //
130 // failed to attach to device stack
131 //
132 IoDeleteDevice(m_FunctionalDeviceObject);
133 m_FunctionalDeviceObject = 0;
134
135 return STATUS_NO_SUCH_DEVICE;
136 }
137
138 //
139 // initialize hardware object
140 //
141 Status = m_Hardware->Initialize(m_DriverObject, m_FunctionalDeviceObject, m_PhysicalDeviceObject, m_NextDeviceObject);
142 if (!NT_SUCCESS(Status))
143 {
144 DPRINT1("[%s] Failed to initialize hardware object %x\n", m_Hardware->GetUSBType(), Status);
145
146 //
147 // failed to initialize hardware object, detach from device stack
148 //
149 IoDetachDevice(m_NextDeviceObject);
150
151 //
152 // now delete the device
153 //
154 IoDeleteDevice(m_FunctionalDeviceObject);
155
156 //
157 // nullify pointers :)
158 //
159 m_FunctionalDeviceObject = 0;
160 m_NextDeviceObject = 0;
161
162 return Status;
163 }
164
165 //
166 // get usb controller type
167 //
168 m_USBType = m_Hardware->GetUSBType();
169
170
171 //
172 // set device flags
173 //
174 m_FunctionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
175
176
177 //
178 // get device extension
179 //
180 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_FunctionalDeviceObject->DeviceExtension;
181 PC_ASSERT(DeviceExtension);
182
183 //
184 // initialize device extension
185 //
186 DeviceExtension->IsFDO = TRUE;
187 DeviceExtension->IsHub = FALSE;
188 DeviceExtension->Dispatcher = PDISPATCHIRP(this);
189
190 //
191 // device is initialized
192 //
193 m_FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
194
195
196 //
197 // is there a root controller
198 //
199 if (m_RootController)
200 {
201 //
202 // add reference
203 //
204 m_RootController->AddRef();
205
206 //
207 // register with controller
208 //
209 m_RootController->RegisterHCD(this);
210 }
211
212
213 //
214 // done
215 //
216 return STATUS_SUCCESS;
217 }
218
219 //-------------------------------------------------------------------------------------------------
220 NTSTATUS
221 CHCDController::HandleDeviceControl(
222 IN PDEVICE_OBJECT DeviceObject,
223 IN PIRP Irp)
224 {
225 PIO_STACK_LOCATION IoStack;
226 PCOMMON_DEVICE_EXTENSION DeviceExtension;
227 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
228 PUSB_HCD_DRIVERKEY_NAME DriverKey;
229 ULONG ResultLength;
230
231 //
232 // get current stack location
233 //
234 IoStack = IoGetCurrentIrpStackLocation(Irp);
235
236 //
237 // get device extension
238 //
239 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
240
241 //
242 // sanity check
243 //
244 PC_ASSERT(DeviceExtension->IsFDO);
245
246 DPRINT1("[%s] HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n", m_USBType,
247 IoStack->Parameters.DeviceIoControl.IoControlCode,
248 IoStack->Parameters.DeviceIoControl.InputBufferLength,
249 IoStack->Parameters.DeviceIoControl.OutputBufferLength);
250
251 //
252 // perform ioctl for FDO
253 //
254 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_HCD_DRIVERKEY_NAME)
255 {
256 //
257 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
258 //
259 if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
260 {
261 //
262 // get device property size
263 //
264 Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, 0, NULL, &ResultLength);
265
266 //
267 // get input buffer
268 //
269 DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
270
271 //
272 // check result
273 //
274 if (Status == STATUS_BUFFER_TOO_SMALL)
275 {
276 //
277 // does the caller provide enough buffer space
278 //
279 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength >= ResultLength)
280 {
281 //
282 // it does
283 //
284 Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
285 }
286
287 //
288 // store result
289 //
290 DriverKey->ActualLength = ResultLength + FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + sizeof(WCHAR);
291 Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
292 Status = STATUS_SUCCESS;
293 }
294 }
295 else
296 {
297 //
298 // buffer is certainly too small
299 //
300 Status = STATUS_BUFFER_OVERFLOW;
301 Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
302 }
303 }
304 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_ROOT_HUB_NAME)
305 {
306 //
307 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
308 //
309 if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
310 {
311 //
312 // sanity check
313 //
314 PC_ASSERT(m_HubController);
315
316 //
317 // get input buffer
318 //
319 DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
320
321 //
322 // get symbolic link
323 //
324 Status = m_HubController->GetHubControllerSymbolicLink(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
325
326
327 if (NT_SUCCESS(Status))
328 {
329 //
330 // null terminate it
331 //
332 PC_ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG) - sizeof(WCHAR) >= ResultLength);
333
334 DriverKey->DriverKeyName[ResultLength / sizeof(WCHAR)] = L'\0';
335 }
336
337 //
338 // store result
339 //
340 DriverKey->ActualLength = ResultLength + FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + sizeof(WCHAR);
341 Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
342 Status = STATUS_SUCCESS;
343 }
344 else
345 {
346 //
347 // buffer is certainly too small
348 //
349 Status = STATUS_BUFFER_OVERFLOW;
350 Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
351 }
352 }
353
354 //
355 // complete the request
356 //
357 Irp->IoStatus.Status = Status;
358 IoCompleteRequest(Irp, IO_NO_INCREMENT);
359
360 //
361 // done
362 //
363 return Status;
364 }
365
366 NTSTATUS
367 CHCDController::HandlePnp(
368 IN PDEVICE_OBJECT DeviceObject,
369 IN PIRP Irp)
370 {
371 PIO_STACK_LOCATION IoStack;
372 PCOMMON_DEVICE_EXTENSION DeviceExtension;
373 PCM_RESOURCE_LIST RawResourceList;
374 PCM_RESOURCE_LIST TranslatedResourceList;
375 PDEVICE_RELATIONS DeviceRelations;
376 NTSTATUS Status;
377
378 //
379 // get device extension
380 //
381 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
382
383 //
384 // sanity check
385 //
386 PC_ASSERT(DeviceExtension->IsFDO);
387
388 //
389 // get current stack location
390 //
391 IoStack = IoGetCurrentIrpStackLocation(Irp);
392
393 switch(IoStack->MinorFunction)
394 {
395 case IRP_MN_START_DEVICE:
396 {
397 DPRINT("[%s] HandlePnp IRP_MN_START FDO\n", m_USBType);
398
399 //
400 // first start lower device object
401 //
402 Status = SyncForwardIrp(m_NextDeviceObject, Irp);
403
404 if (NT_SUCCESS(Status))
405 {
406 //
407 // operation succeeded, lets start the device
408 //
409 RawResourceList = IoStack->Parameters.StartDevice.AllocatedResources;
410 TranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
411
412 if (m_Hardware)
413 {
414 //
415 // start the hardware
416 //
417 Status = m_Hardware->PnpStart(RawResourceList, TranslatedResourceList);
418 }
419
420 if (NT_SUCCESS(Status))
421 {
422 //
423 // enable symbolic link
424 //
425 Status = SetSymbolicLink(TRUE);
426 }
427 }
428
429 DPRINT("[%s] HandlePnp IRP_MN_START FDO: Status %x\n", m_USBType ,Status);
430 break;
431 }
432 case IRP_MN_QUERY_DEVICE_RELATIONS:
433 {
434 DPRINT("[%s] HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", m_USBType, IoStack->Parameters.QueryDeviceRelations.Type);
435
436 if (m_HubController == NULL)
437 {
438 //
439 // create hub controller
440 //
441 Status = CreateHubController(&m_HubController);
442 if (!NT_SUCCESS(Status))
443 {
444 //
445 // failed to create hub controller
446 //
447 break;
448 }
449
450 //
451 // initialize hub controller
452 //
453 Status = m_HubController->Initialize(m_DriverObject, PHCDCONTROLLER(this), m_Hardware, TRUE, 0 /* FIXME*/);
454 if (!NT_SUCCESS(Status))
455 {
456 //
457 // failed to initialize hub controller
458 //
459 break;
460 }
461
462 //
463 // add reference to prevent it from getting deleting while hub driver adds / removes references
464 //
465 m_HubController->AddRef();
466 }
467
468 if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
469 {
470 //
471 // allocate device relations
472 //
473 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
474
475 if (!DeviceRelations)
476 {
477 //
478 // no memory
479 //
480 Status = STATUS_INSUFFICIENT_RESOURCES;
481 break;
482 }
483
484 //
485 // init device relations
486 //
487 DeviceRelations->Count = 1;
488 Status = m_HubController->GetHubControllerDeviceObject(&DeviceRelations->Objects [0]);
489
490 //
491 // sanity check
492 //
493 PC_ASSERT(Status == STATUS_SUCCESS);
494
495 ObReferenceObject(DeviceRelations->Objects [0]);
496
497 //
498 // store result
499 //
500 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
501 Status = STATUS_SUCCESS;
502 }
503 else
504 {
505 //
506 // not supported
507 //
508 Status = STATUS_NOT_SUPPORTED;
509 }
510 break;
511 }
512 case IRP_MN_STOP_DEVICE:
513 {
514 DPRINT("[%s] HandlePnp IRP_MN_STOP_DEVICE\n", m_USBType);
515
516 if (m_Hardware)
517 {
518 //
519 // stop the hardware
520 //
521 Status = m_Hardware->PnpStop();
522 }
523 else
524 {
525 //
526 // fake success
527 //
528 Status = STATUS_SUCCESS;
529 }
530
531 if (NT_SUCCESS(Status))
532 {
533 //
534 // stop lower device
535 //
536 Status = SyncForwardIrp(m_NextDeviceObject, Irp);
537 }
538 break;
539 }
540 case IRP_MN_QUERY_REMOVE_DEVICE:
541 case IRP_MN_QUERY_STOP_DEVICE:
542 {
543 #if 0
544 //
545 // sure
546 //
547 Irp->IoStatus.Status = STATUS_SUCCESS;
548
549 //
550 // forward irp to next device object
551 //
552 IoSkipCurrentIrpStackLocation(Irp);
553 return IoCallDriver(m_NextDeviceObject, Irp);
554 #else
555 DPRINT1("[%s] Denying controller removal due to reinitialization bugs\n", m_USBType);
556 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
557 IoCompleteRequest(Irp, IO_NO_INCREMENT);
558 return STATUS_UNSUCCESSFUL;
559 #endif
560 }
561 case IRP_MN_REMOVE_DEVICE:
562 {
563 DPRINT("[%s] HandlePnp IRP_MN_REMOVE_DEVICE FDO\n", m_USBType);
564
565 //
566 // delete the symbolic link
567 //
568 SetSymbolicLink(FALSE);
569
570 //
571 // forward irp to next device object
572 //
573 IoSkipCurrentIrpStackLocation(Irp);
574 IoCallDriver(m_NextDeviceObject, Irp);
575
576 //
577 // detach device from device stack
578 //
579 IoDetachDevice(m_NextDeviceObject);
580
581 //
582 // delete device
583 //
584 IoDeleteDevice(m_FunctionalDeviceObject);
585
586 return STATUS_SUCCESS;
587 }
588 default:
589 {
590 //
591 // forward irp to next device object
592 //
593 IoSkipCurrentIrpStackLocation(Irp);
594 return IoCallDriver(m_NextDeviceObject, Irp);
595 }
596 }
597
598 //
599 // store result and complete request
600 //
601 Irp->IoStatus.Status = Status;
602 IoCompleteRequest(Irp, IO_NO_INCREMENT);
603
604 return Status;
605 }
606
607 NTSTATUS
608 CHCDController::HandlePower(
609 IN PDEVICE_OBJECT DeviceObject,
610 IN PIRP Irp)
611 {
612 PoStartNextPowerIrp(Irp);
613 IoSkipCurrentIrpStackLocation(Irp);
614 return PoCallDriver(m_NextDeviceObject, Irp);
615 }
616
617 NTSTATUS
618 CHCDController::HandleSystemControl(
619 IN PDEVICE_OBJECT DeviceObject,
620 IN PIRP Irp)
621 {
622 IoSkipCurrentIrpStackLocation(Irp);
623 return IoCallDriver(m_NextDeviceObject, Irp);
624 }
625
626 NTSTATUS
627 CHCDController::CreateFDO(
628 PDRIVER_OBJECT DriverObject,
629 PDEVICE_OBJECT * OutDeviceObject)
630 {
631 WCHAR CharDeviceName[64];
632 NTSTATUS Status;
633 ULONG UsbDeviceNumber = 0;
634 UNICODE_STRING DeviceName;
635
636 while (TRUE)
637 {
638 //
639 // construct device name
640 //
641 swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
642
643 //
644 // initialize device name
645 //
646 RtlInitUnicodeString(&DeviceName, CharDeviceName);
647
648 //
649 // create device
650 //
651 Status = IoCreateDevice(DriverObject,
652 sizeof(COMMON_DEVICE_EXTENSION),
653 &DeviceName,
654 FILE_DEVICE_CONTROLLER,
655 0,
656 FALSE,
657 OutDeviceObject);
658
659 //
660 // check for success
661 //
662 if (NT_SUCCESS(Status))
663 break;
664
665 //
666 // is there a device object with that same name
667 //
668 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
669 {
670 //
671 // Try the next name
672 //
673 UsbDeviceNumber++;
674 continue;
675 }
676
677 //
678 // bail out on other errors
679 //
680 if (!NT_SUCCESS(Status))
681 {
682 DPRINT1("[%s] CreateFDO: Failed to create %wZ, Status %x\n", m_USBType, &DeviceName, Status);
683 return Status;
684 }
685 }
686
687 //
688 // store FDO number
689 //
690 m_FDODeviceNumber = UsbDeviceNumber;
691
692 DPRINT("[%s] CreateFDO: DeviceName %wZ\n", m_USBType, &DeviceName);
693
694 /* done */
695 return Status;
696 }
697
698 NTSTATUS
699 CHCDController::SetSymbolicLink(
700 BOOLEAN Enable)
701 {
702 NTSTATUS Status;
703 WCHAR LinkName[32];
704 WCHAR FDOName[32];
705 UNICODE_STRING Link, FDO;
706
707 if (Enable)
708 {
709 //
710 // create legacy link
711 //
712 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
713 swprintf(FDOName, L"\\Device\\USBFDO-%d", m_FDODeviceNumber);
714 RtlInitUnicodeString(&Link, LinkName);
715 RtlInitUnicodeString(&FDO, FDOName);
716
717 //
718 // create symbolic link
719 //
720 Status = IoCreateSymbolicLink(&Link, &FDO);
721
722 if (!NT_SUCCESS(Status))
723 {
724 //
725 // FIXME: handle me
726 //
727 ASSERT(0);
728 }
729 }
730 else
731 {
732 //
733 // create legacy link
734 //
735 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
736 RtlInitUnicodeString(&Link, LinkName);
737
738 //
739 // now delete the symbolic link
740 //
741 Status = IoDeleteSymbolicLink(&Link);
742
743 if (!NT_SUCCESS(Status))
744 {
745 //
746 // FIXME: handle me
747 //
748 ASSERT(0);
749 }
750 }
751
752 //
753 // done
754 //
755 return Status;
756 }
757
758 NTSTATUS
759 NTAPI
760 CreateHCDController(
761 PHCDCONTROLLER *OutHcdController)
762 {
763 PHCDCONTROLLER This;
764
765 //
766 // allocate controller
767 //
768 This = new(NonPagedPool, TAG_USBLIB) CHCDController(0);
769 if (!This)
770 {
771 //
772 // failed to allocate
773 //
774 return STATUS_INSUFFICIENT_RESOURCES;
775 }
776
777 //
778 // add reference count
779 //
780 This->AddRef();
781
782 //
783 // return result
784 //
785 *OutHcdController = (PHCDCONTROLLER)This;
786
787 //
788 // done
789 //
790 return STATUS_SUCCESS;
791 }