c4539c6c0a22ee33a686ab5a6db7f0dbd152f43c
[reactos.git] / drivers / usb / usbohci / hcd_controller.cpp
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/usbohci/hcd_controller.cpp
5 * PURPOSE: USB OHCI device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11 #define INITGUID
12 #include "usbohci.h"
13
14 class CHCDController : public IHCDController,
15 public IDispatchIrp
16 {
17 public:
18 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
19
20 STDMETHODIMP_(ULONG) AddRef()
21 {
22 InterlockedIncrement(&m_Ref);
23 return m_Ref;
24 }
25 STDMETHODIMP_(ULONG) Release()
26 {
27 InterlockedDecrement(&m_Ref);
28
29 if (!m_Ref)
30 {
31 delete this;
32 return 0;
33 }
34 return m_Ref;
35 }
36
37 // IHCDController interface functions
38 NTSTATUS Initialize(IN PROOTHDCCONTROLLER RootHCDController, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
39
40 // IDispatchIrp interface functions
41 NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
42 NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
43 NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
44
45 // local functions
46 NTSTATUS CreateFDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject);
47 NTSTATUS SetSymbolicLink(BOOLEAN Enable);
48
49 // constructor / destructor
50 CHCDController(IUnknown *OuterUnknown){}
51 virtual ~CHCDController(){}
52
53 protected:
54 LONG m_Ref;
55 PROOTHDCCONTROLLER m_RootController;
56 PDRIVER_OBJECT m_DriverObject;
57 PDEVICE_OBJECT m_PhysicalDeviceObject;
58 PDEVICE_OBJECT m_FunctionalDeviceObject;
59 PDEVICE_OBJECT m_NextDeviceObject;
60 PUSBHARDWAREDEVICE m_Hardware;
61 PHUBCONTROLLER m_HubController;
62 ULONG m_FDODeviceNumber;
63 };
64
65 //=================================================================================================
66 // COM
67 //
68 NTSTATUS
69 STDMETHODCALLTYPE
70 CHCDController::QueryInterface(
71 IN REFIID refiid,
72 OUT PVOID* Output)
73 {
74 return STATUS_UNSUCCESSFUL;
75 }
76
77 //-------------------------------------------------------------------------------------------------
78 NTSTATUS
79 CHCDController::Initialize(
80 IN PROOTHDCCONTROLLER RootHCDController,
81 IN PDRIVER_OBJECT DriverObject,
82 IN PDEVICE_OBJECT PhysicalDeviceObject)
83 {
84 NTSTATUS Status;
85 PCOMMON_DEVICE_EXTENSION DeviceExtension;
86
87 //
88 // create usb hardware
89 //
90 Status = CreateUSBHardware(&m_Hardware);
91 if (!NT_SUCCESS(Status))
92 {
93 //
94 // failed to create hardware object
95 //
96 DPRINT1("Failed to create hardware object\n");
97 return STATUS_INSUFFICIENT_RESOURCES;
98 }
99
100 //
101 // initialize members
102 //
103 m_DriverObject = DriverObject;
104 m_PhysicalDeviceObject = PhysicalDeviceObject;
105 m_RootController = RootHCDController;
106
107 //
108 // create FDO
109 //
110 Status = CreateFDO(m_DriverObject, &m_FunctionalDeviceObject);
111 if (!NT_SUCCESS(Status))
112 {
113 //
114 // failed to create PDO
115 //
116 return Status;
117 }
118
119 //
120 // now attach to device stack
121 //
122 m_NextDeviceObject = IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject, m_PhysicalDeviceObject);
123 if (!m_NextDeviceObject)
124 {
125 //
126 // failed to attach to device stack
127 //
128 IoDeleteDevice(m_FunctionalDeviceObject);
129 m_FunctionalDeviceObject = 0;
130
131 return STATUS_NO_SUCH_DEVICE;
132 }
133
134 //
135 // initialize hardware object
136 //
137 Status = m_Hardware->Initialize(m_DriverObject, m_FunctionalDeviceObject, m_PhysicalDeviceObject, m_NextDeviceObject);
138 if (!NT_SUCCESS(Status))
139 {
140 DPRINT1("Failed to initialize hardware object %x\n", Status);
141
142 //
143 // failed to initialize hardware object, detach from device stack
144 //
145 IoDetachDevice(m_NextDeviceObject);
146
147 //
148 // now delete the device
149 //
150 IoDeleteDevice(m_FunctionalDeviceObject);
151
152 //
153 // nullify pointers :)
154 //
155 m_FunctionalDeviceObject = 0;
156 m_NextDeviceObject = 0;
157
158 return Status;
159 }
160
161
162 //
163 // set device flags
164 //
165 m_FunctionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
166
167
168 //
169 // get device extension
170 //
171 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_FunctionalDeviceObject->DeviceExtension;
172 PC_ASSERT(DeviceExtension);
173
174 //
175 // initialize device extension
176 //
177 DeviceExtension->IsFDO = TRUE;
178 DeviceExtension->IsHub = FALSE;
179 DeviceExtension->Dispatcher = PDISPATCHIRP(this);
180
181 //
182 // device is initialized
183 //
184 m_FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
185
186
187 //
188 // is there a root controller
189 //
190 if (m_RootController)
191 {
192 //
193 // add reference
194 //
195 m_RootController->AddRef();
196
197 //
198 // register with controller
199 //
200 m_RootController->RegisterHCD(this);
201 }
202
203
204 //
205 // done
206 //
207 return STATUS_SUCCESS;
208 }
209
210 //-------------------------------------------------------------------------------------------------
211 NTSTATUS
212 CHCDController::HandleDeviceControl(
213 IN PDEVICE_OBJECT DeviceObject,
214 IN PIRP Irp)
215 {
216 PIO_STACK_LOCATION IoStack;
217 PCOMMON_DEVICE_EXTENSION DeviceExtension;
218 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
219 PUSB_HCD_DRIVERKEY_NAME DriverKey;
220 ULONG ResultLength;
221
222 //
223 // get current stack location
224 //
225 IoStack = IoGetCurrentIrpStackLocation(Irp);
226
227 //
228 // get device extension
229 //
230 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
231
232 //
233 // sanity check
234 //
235 PC_ASSERT(DeviceExtension->IsFDO);
236
237 DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n",
238 IoStack->Parameters.DeviceIoControl.IoControlCode,
239 IoStack->Parameters.DeviceIoControl.InputBufferLength,
240 IoStack->Parameters.DeviceIoControl.OutputBufferLength);
241
242 //
243 // perform ioctl for FDO
244 //
245 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_HCD_DRIVERKEY_NAME)
246 {
247 //
248 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
249 //
250 if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
251 {
252 //
253 // get device property size
254 //
255 Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, 0, NULL, &ResultLength);
256
257 //
258 // get input buffer
259 //
260 DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
261
262 //
263 // check result
264 //
265 if (Status == STATUS_BUFFER_TOO_SMALL)
266 {
267 //
268 // does the caller provide enough buffer space
269 //
270 if (IoStack->Parameters.DeviceIoControl.OutputBufferLength >= ResultLength)
271 {
272 //
273 // it does
274 //
275 Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
276
277 if (NT_SUCCESS(Status))
278 {
279 //
280 // informal debug print
281 //
282 DPRINT1("Result %S\n", DriverKey->DriverKeyName);
283 }
284 }
285
286 //
287 // store result
288 //
289 DriverKey->ActualLength = ResultLength + FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + sizeof(WCHAR);
290 Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
291 Status = STATUS_SUCCESS;
292 }
293 }
294 else
295 {
296 //
297 // buffer is certainly too small
298 //
299 Status = STATUS_BUFFER_OVERFLOW;
300 Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
301 }
302 }
303 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_ROOT_HUB_NAME)
304 {
305 //
306 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
307 //
308 if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
309 {
310 //
311 // sanity check
312 //
313 PC_ASSERT(m_HubController);
314
315 //
316 // get input buffer
317 //
318 DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
319
320 //
321 // get symbolic link
322 //
323 Status = m_HubController->GetHubControllerSymbolicLink(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
324
325
326 if (NT_SUCCESS(Status))
327 {
328 //
329 // null terminate it
330 //
331 PC_ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG) - sizeof(WCHAR) >= ResultLength);
332
333 DriverKey->DriverKeyName[ResultLength / sizeof(WCHAR)] = L'\0';
334 DPRINT1("Result %S\n", DriverKey->DriverKeyName);
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 DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO\n");
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 DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO: Status %x\n", Status);
427 break;
428 }
429 case IRP_MN_QUERY_DEVICE_RELATIONS:
430 {
431 DPRINT1("CHCDController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", 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 DPRINT1("CHCDController::HandlePnp IRP_MN_STOP_DEVICE\n");
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 if (NT_SUCCESS(Status))
535 {
536 //
537 // detach device
538 //
539 IoDetachDevice(m_NextDeviceObject);
540 IoDeleteDevice(DeviceObject);
541 }
542
543 }
544
545
546
547 break;
548 }
549 case IRP_MN_QUERY_REMOVE_DEVICE:
550 case IRP_MN_QUERY_STOP_DEVICE:
551 {
552 //
553 // sure
554 //
555 Irp->IoStatus.Status = STATUS_SUCCESS;
556
557 //
558 // forward irp to next device object
559 //
560 IoSkipCurrentIrpStackLocation(Irp);
561 return IoCallDriver(m_NextDeviceObject, Irp);
562 }
563 case IRP_MN_REMOVE_DEVICE:
564 {
565 DPRINT1("CHCDController::HandlePnp IRP_MN_REMOVE_DEVICE FDO\n");
566
567 //
568 // delete the symbolic link
569 //
570 SetSymbolicLink(FALSE);
571
572 //
573 // forward irp to next device object
574 //
575 IoSkipCurrentIrpStackLocation(Irp);
576 IoCallDriver(m_NextDeviceObject, Irp);
577
578 //
579 // detach device from device stack
580 //
581 IoDetachDevice(m_NextDeviceObject);
582
583 //
584 // delete device
585 //
586 IoDeleteDevice(m_FunctionalDeviceObject);
587
588 return STATUS_SUCCESS;
589 }
590 default:
591 {
592 //
593 // forward irp to next device object
594 //
595 IoSkipCurrentIrpStackLocation(Irp);
596 return IoCallDriver(m_NextDeviceObject, Irp);
597 }
598 }
599
600 //
601 // store result and complete request
602 //
603 Irp->IoStatus.Status = Status;
604 IoCompleteRequest(Irp, IO_NO_INCREMENT);
605
606 return Status;
607 }
608
609 NTSTATUS
610 CHCDController::HandlePower(
611 IN PDEVICE_OBJECT DeviceObject,
612 IN PIRP Irp)
613 {
614 UNIMPLEMENTED
615
616 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
617 IoCompleteRequest(Irp, IO_NO_INCREMENT);
618
619 return STATUS_NOT_IMPLEMENTED;
620 }
621
622 NTSTATUS
623 CHCDController::CreateFDO(
624 PDRIVER_OBJECT DriverObject,
625 PDEVICE_OBJECT * OutDeviceObject)
626 {
627 WCHAR CharDeviceName[64];
628 NTSTATUS Status;
629 ULONG UsbDeviceNumber = 0;
630 UNICODE_STRING DeviceName;
631
632 while (TRUE)
633 {
634 //
635 // construct device name
636 //
637 swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
638
639 //
640 // initialize device name
641 //
642 RtlInitUnicodeString(&DeviceName, CharDeviceName);
643
644 //
645 // create device
646 //
647 Status = IoCreateDevice(DriverObject,
648 sizeof(COMMON_DEVICE_EXTENSION),
649 &DeviceName,
650 FILE_DEVICE_CONTROLLER,
651 0,
652 FALSE,
653 OutDeviceObject);
654
655 //
656 // check for success
657 //
658 if (NT_SUCCESS(Status))
659 break;
660
661 //
662 // is there a device object with that same name
663 //
664 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
665 {
666 //
667 // Try the next name
668 //
669 UsbDeviceNumber++;
670 continue;
671 }
672
673 //
674 // bail out on other errors
675 //
676 if (!NT_SUCCESS(Status))
677 {
678 DPRINT1("CreateFDO: Failed to create %wZ, Status %x\n", &DeviceName, Status);
679 return Status;
680 }
681 }
682
683 //
684 // store FDO number
685 //
686 m_FDODeviceNumber = UsbDeviceNumber;
687
688 DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName);
689
690 /* done */
691 return Status;
692 }
693
694 NTSTATUS
695 CHCDController::SetSymbolicLink(
696 BOOLEAN Enable)
697 {
698 NTSTATUS Status;
699 WCHAR LinkName[32];
700 WCHAR FDOName[32];
701 UNICODE_STRING Link, FDO;
702
703 if (Enable)
704 {
705 //
706 // create legacy link
707 //
708 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
709 swprintf(FDOName, L"\\Device\\USBFDO-%d", m_FDODeviceNumber);
710 RtlInitUnicodeString(&Link, LinkName);
711 RtlInitUnicodeString(&FDO, FDOName);
712
713 //
714 // create symbolic link
715 //
716 Status = IoCreateSymbolicLink(&Link, &FDO);
717
718 if (!NT_SUCCESS(Status))
719 {
720 //
721 // FIXME: handle me
722 //
723 ASSERT(0);
724 }
725 }
726 else
727 {
728 //
729 // create legacy link
730 //
731 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
732 RtlInitUnicodeString(&Link, LinkName);
733
734 //
735 // now delete the symbolic link
736 //
737 Status = IoDeleteSymbolicLink(&Link);
738
739 if (!NT_SUCCESS(Status))
740 {
741 //
742 // FIXME: handle me
743 //
744 ASSERT(0);
745 }
746 }
747
748 //
749 // done
750 //
751 return Status;
752 }
753
754 NTSTATUS
755 CreateHCDController(
756 PHCDCONTROLLER *OutHcdController)
757 {
758 PHCDCONTROLLER This;
759
760 //
761 // allocate controller
762 //
763 This = new(NonPagedPool, TAG_USBOHCI) CHCDController(0);
764 if (!This)
765 {
766 //
767 // failed to allocate
768 //
769 return STATUS_INSUFFICIENT_RESOURCES;
770 }
771
772 //
773 // add reference count
774 //
775 This->AddRef();
776
777 //
778 // return result
779 //
780 *OutHcdController = (PHCDCONTROLLER)This;
781
782 //
783 // done
784 //
785 return STATUS_SUCCESS;
786 }