Sync with trunk r63743.
[reactos.git] / 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 //
421 // enable symbolic link
422 //
423 Status = SetSymbolicLink(TRUE);
424 }
425
426 DPRINT("[%s] HandlePnp IRP_MN_START FDO: Status %x\n", m_USBType ,Status);
427 break;
428 }
429 case IRP_MN_QUERY_DEVICE_RELATIONS:
430 {
431 DPRINT("[%s] HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", m_USBType, IoStack->Parameters.QueryDeviceRelations.Type);
432
433 if (m_HubController == NULL)
434 {
435 //
436 // create hub controller
437 //
438 Status = CreateHubController(&m_HubController);
439 if (!NT_SUCCESS(Status))
440 {
441 //
442 // failed to create hub controller
443 //
444 break;
445 }
446
447 //
448 // initialize hub controller
449 //
450 Status = m_HubController->Initialize(m_DriverObject, PHCDCONTROLLER(this), m_Hardware, TRUE, 0 /* FIXME*/);
451 if (!NT_SUCCESS(Status))
452 {
453 //
454 // failed to initialize hub controller
455 //
456 break;
457 }
458
459 //
460 // add reference to prevent it from getting deleting while hub driver adds / removes references
461 //
462 m_HubController->AddRef();
463 }
464
465 if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
466 {
467 //
468 // allocate device relations
469 //
470 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
471
472 if (!DeviceRelations)
473 {
474 //
475 // no memory
476 //
477 Status = STATUS_INSUFFICIENT_RESOURCES;
478 break;
479 }
480
481 //
482 // init device relations
483 //
484 DeviceRelations->Count = 1;
485 Status = m_HubController->GetHubControllerDeviceObject(&DeviceRelations->Objects [0]);
486
487 //
488 // sanity check
489 //
490 PC_ASSERT(Status == STATUS_SUCCESS);
491
492 ObReferenceObject(DeviceRelations->Objects [0]);
493
494 //
495 // store result
496 //
497 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
498 Status = STATUS_SUCCESS;
499 }
500 else
501 {
502 //
503 // not supported
504 //
505 Status = STATUS_NOT_SUPPORTED;
506 }
507 break;
508 }
509 case IRP_MN_STOP_DEVICE:
510 {
511 DPRINT("[%s] HandlePnp IRP_MN_STOP_DEVICE\n", m_USBType);
512
513 if (m_Hardware)
514 {
515 //
516 // stop the hardware
517 //
518 Status = m_Hardware->PnpStop();
519 }
520 else
521 {
522 //
523 // fake success
524 //
525 Status = STATUS_SUCCESS;
526 }
527
528 if (NT_SUCCESS(Status))
529 {
530 //
531 // stop lower device
532 //
533 Status = SyncForwardIrp(m_NextDeviceObject, Irp);
534 }
535 break;
536 }
537 case IRP_MN_QUERY_REMOVE_DEVICE:
538 case IRP_MN_QUERY_STOP_DEVICE:
539 {
540 #if 0
541 //
542 // sure
543 //
544 Irp->IoStatus.Status = STATUS_SUCCESS;
545
546 //
547 // forward irp to next device object
548 //
549 IoSkipCurrentIrpStackLocation(Irp);
550 return IoCallDriver(m_NextDeviceObject, Irp);
551 #else
552 DPRINT1("[%s] Denying controller removal due to reinitialization bugs\n", m_USBType);
553 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
554 IoCompleteRequest(Irp, IO_NO_INCREMENT);
555 return STATUS_UNSUCCESSFUL;
556 #endif
557 }
558 case IRP_MN_REMOVE_DEVICE:
559 {
560 DPRINT("[%s] HandlePnp IRP_MN_REMOVE_DEVICE FDO\n", m_USBType);
561
562 //
563 // delete the symbolic link
564 //
565 SetSymbolicLink(FALSE);
566
567 //
568 // forward irp to next device object
569 //
570 IoSkipCurrentIrpStackLocation(Irp);
571 IoCallDriver(m_NextDeviceObject, Irp);
572
573 //
574 // detach device from device stack
575 //
576 IoDetachDevice(m_NextDeviceObject);
577
578 //
579 // delete device
580 //
581 IoDeleteDevice(m_FunctionalDeviceObject);
582
583 return STATUS_SUCCESS;
584 }
585 default:
586 {
587 //
588 // forward irp to next device object
589 //
590 IoSkipCurrentIrpStackLocation(Irp);
591 return IoCallDriver(m_NextDeviceObject, Irp);
592 }
593 }
594
595 //
596 // store result and complete request
597 //
598 Irp->IoStatus.Status = Status;
599 IoCompleteRequest(Irp, IO_NO_INCREMENT);
600
601 return Status;
602 }
603
604 NTSTATUS
605 CHCDController::HandlePower(
606 IN PDEVICE_OBJECT DeviceObject,
607 IN PIRP Irp)
608 {
609 PoStartNextPowerIrp(Irp);
610 IoSkipCurrentIrpStackLocation(Irp);
611 return PoCallDriver(m_NextDeviceObject, Irp);
612 }
613
614 NTSTATUS
615 CHCDController::HandleSystemControl(
616 IN PDEVICE_OBJECT DeviceObject,
617 IN PIRP Irp)
618 {
619 IoSkipCurrentIrpStackLocation(Irp);
620 return IoCallDriver(m_NextDeviceObject, Irp);
621 }
622
623 NTSTATUS
624 CHCDController::CreateFDO(
625 PDRIVER_OBJECT DriverObject,
626 PDEVICE_OBJECT * OutDeviceObject)
627 {
628 WCHAR CharDeviceName[64];
629 NTSTATUS Status;
630 ULONG UsbDeviceNumber = 0;
631 UNICODE_STRING DeviceName;
632
633 while (TRUE)
634 {
635 //
636 // construct device name
637 //
638 swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
639
640 //
641 // initialize device name
642 //
643 RtlInitUnicodeString(&DeviceName, CharDeviceName);
644
645 //
646 // create device
647 //
648 Status = IoCreateDevice(DriverObject,
649 sizeof(COMMON_DEVICE_EXTENSION),
650 &DeviceName,
651 FILE_DEVICE_CONTROLLER,
652 0,
653 FALSE,
654 OutDeviceObject);
655
656 //
657 // check for success
658 //
659 if (NT_SUCCESS(Status))
660 break;
661
662 //
663 // is there a device object with that same name
664 //
665 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
666 {
667 //
668 // Try the next name
669 //
670 UsbDeviceNumber++;
671 continue;
672 }
673
674 //
675 // bail out on other errors
676 //
677 if (!NT_SUCCESS(Status))
678 {
679 DPRINT1("[%s] CreateFDO: Failed to create %wZ, Status %x\n", m_USBType, &DeviceName, Status);
680 return Status;
681 }
682 }
683
684 //
685 // store FDO number
686 //
687 m_FDODeviceNumber = UsbDeviceNumber;
688
689 DPRINT("[%s] CreateFDO: DeviceName %wZ\n", m_USBType, &DeviceName);
690
691 /* done */
692 return Status;
693 }
694
695 NTSTATUS
696 CHCDController::SetSymbolicLink(
697 BOOLEAN Enable)
698 {
699 NTSTATUS Status;
700 WCHAR LinkName[32];
701 WCHAR FDOName[32];
702 UNICODE_STRING Link, FDO;
703
704 if (Enable)
705 {
706 //
707 // create legacy link
708 //
709 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
710 swprintf(FDOName, L"\\Device\\USBFDO-%d", m_FDODeviceNumber);
711 RtlInitUnicodeString(&Link, LinkName);
712 RtlInitUnicodeString(&FDO, FDOName);
713
714 //
715 // create symbolic link
716 //
717 Status = IoCreateSymbolicLink(&Link, &FDO);
718
719 if (!NT_SUCCESS(Status))
720 {
721 //
722 // FIXME: handle me
723 //
724 ASSERT(0);
725 }
726 }
727 else
728 {
729 //
730 // create legacy link
731 //
732 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
733 RtlInitUnicodeString(&Link, LinkName);
734
735 //
736 // now delete the symbolic link
737 //
738 Status = IoDeleteSymbolicLink(&Link);
739
740 if (!NT_SUCCESS(Status))
741 {
742 //
743 // FIXME: handle me
744 //
745 ASSERT(0);
746 }
747 }
748
749 //
750 // done
751 //
752 return Status;
753 }
754
755 NTSTATUS
756 NTAPI
757 CreateHCDController(
758 PHCDCONTROLLER *OutHcdController)
759 {
760 PHCDCONTROLLER This;
761
762 //
763 // allocate controller
764 //
765 This = new(NonPagedPool, TAG_USBLIB) CHCDController(0);
766 if (!This)
767 {
768 //
769 // failed to allocate
770 //
771 return STATUS_INSUFFICIENT_RESOURCES;
772 }
773
774 //
775 // add reference count
776 //
777 This->AddRef();
778
779 //
780 // return result
781 //
782 *OutHcdController = (PHCDCONTROLLER)This;
783
784 //
785 // done
786 //
787 return STATUS_SUCCESS;
788 }