73125137c89565fe4f13766b68daab7fc676d81d
[reactos.git] / drivers / usb / usbehci_new / 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/usbehci/hcd_controller.cpp
5 * PURPOSE: USB EHCI 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 "usbehci.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 CreatePDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject);
48 NTSTATUS SetSymbolicLink(BOOLEAN Enable);
49
50 // constructor / destructor
51 CHCDController(IUnknown *OuterUnknown){}
52 virtual ~CHCDController(){}
53
54 protected:
55 LONG m_Ref;
56 PROOTHDCCONTROLLER m_RootController;
57 PDRIVER_OBJECT m_DriverObject;
58 PDEVICE_OBJECT m_PhysicalDeviceObject;
59 PDEVICE_OBJECT m_FunctionalDeviceObject;
60 PDEVICE_OBJECT m_NextDeviceObject;
61 PUSBHARDWAREDEVICE m_Hardware;
62 PHUBCONTROLLER m_HubController;
63 ULONG m_FDODeviceNumber;
64 };
65
66 //=================================================================================================
67 // COM
68 //
69 NTSTATUS
70 STDMETHODCALLTYPE
71 CHCDController::QueryInterface(
72 IN REFIID refiid,
73 OUT PVOID* Output)
74 {
75 return STATUS_UNSUCCESSFUL;
76 }
77
78 //-------------------------------------------------------------------------------------------------
79 NTSTATUS
80 CHCDController::Initialize(
81 IN PROOTHDCCONTROLLER RootHCDController,
82 IN PDRIVER_OBJECT DriverObject,
83 IN PDEVICE_OBJECT PhysicalDeviceObject)
84 {
85 NTSTATUS Status;
86 PCOMMON_DEVICE_EXTENSION DeviceExtension;
87
88 //
89 // create usb hardware
90 //
91 Status = CreateUSBHardware(&m_Hardware);
92 if (!NT_SUCCESS(Status))
93 {
94 //
95 // failed to create hardware object
96 //
97 DPRINT1("Failed to create hardware object\n");
98 return STATUS_INSUFFICIENT_RESOURCES;
99 }
100
101 //
102 // initialize members
103 //
104 m_DriverObject = DriverObject;
105 m_PhysicalDeviceObject = PhysicalDeviceObject;
106 m_RootController = RootHCDController;
107
108 //
109 // create FDO
110 //
111 Status = CreateFDO(m_DriverObject, &m_FunctionalDeviceObject);
112 if (!NT_SUCCESS(Status))
113 {
114 //
115 // failed to create PDO
116 //
117 return Status;
118 }
119
120 //
121 // now attach to device stack
122 //
123 m_NextDeviceObject = IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject, m_PhysicalDeviceObject);
124 if (!m_NextDeviceObject)
125 {
126 //
127 // failed to attach to device stack
128 //
129 IoDeleteDevice(m_FunctionalDeviceObject);
130 m_FunctionalDeviceObject = 0;
131
132 return STATUS_NO_SUCH_DEVICE;
133 }
134
135 //
136 // initialize hardware object
137 //
138 Status = m_Hardware->Initialize(m_DriverObject, m_FunctionalDeviceObject, m_PhysicalDeviceObject, m_NextDeviceObject);
139 if (!NT_SUCCESS(Status))
140 {
141 DPRINT1("Failed to initialize hardware object %x\n", Status);
142
143 //
144 // failed to initialize hardware object, detach from device stack
145 //
146 IoDetachDevice(m_NextDeviceObject);
147
148 //
149 // now delete the device
150 //
151 IoDeleteDevice(m_FunctionalDeviceObject);
152
153 //
154 // nullify pointers :)
155 //
156 m_FunctionalDeviceObject = 0;
157 m_NextDeviceObject = 0;
158
159 return Status;
160 }
161
162
163 //
164 // set device flags
165 //
166 m_FunctionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
167
168
169 //
170 // get device extension
171 //
172 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_FunctionalDeviceObject->DeviceExtension;
173 PC_ASSERT(DeviceExtension);
174
175 //
176 // initialize device extension
177 //
178 DeviceExtension->IsFDO = TRUE;
179 DeviceExtension->IsHub = FALSE;
180 DeviceExtension->Dispatcher = PDISPATCHIRP(this);
181
182 //
183 // device is initialized
184 //
185 m_FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
186
187
188 //
189 // is there a root controller
190 //
191 if (m_RootController)
192 {
193 //
194 // add reference
195 //
196 m_RootController->AddRef();
197
198 //
199 // register with controller
200 //
201 m_RootController->RegisterHCD(this);
202 }
203
204
205 //
206 // done
207 //
208 return STATUS_SUCCESS;
209 }
210
211 //-------------------------------------------------------------------------------------------------
212 NTSTATUS
213 CHCDController::HandleDeviceControl(
214 IN PDEVICE_OBJECT DeviceObject,
215 IN PIRP Irp)
216 {
217 PIO_STACK_LOCATION IoStack;
218 PCOMMON_DEVICE_EXTENSION DeviceExtension;
219 NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
220 PUSB_HCD_DRIVERKEY_NAME DriverKey;
221 ULONG ResultLength;
222
223 //
224 // get current stack location
225 //
226 IoStack = IoGetCurrentIrpStackLocation(Irp);
227
228 //
229 // get device extension
230 //
231 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
232
233
234 DPRINT1("HandleDeviceControl>Type: FDO %u IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n",
235 DeviceExtension->IsFDO,
236 IoStack->Parameters.DeviceIoControl.IoControlCode,
237 IoStack->Parameters.DeviceIoControl.InputBufferLength,
238 IoStack->Parameters.DeviceIoControl.OutputBufferLength);
239
240 //
241 // get device type
242 //
243 if (DeviceExtension->IsFDO)
244 {
245 //
246 // perform ioctl for FDO
247 //
248 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_HCD_DRIVERKEY_NAME)
249 {
250 //
251 // check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
252 //
253 if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
254 {
255 //
256 // get device property size
257 //
258 Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, 0, NULL, &ResultLength);
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 DPRINT1("IOCTL_USB_GET_ROOT_HUB_NAME is not implemented yet\n");
306 }
307 }
308 else
309 {
310 //
311 // the PDO does not support any device IOCTLs
312 //
313 Status = STATUS_SUCCESS;
314 }
315
316 //
317 // complete the request
318 //
319 Irp->IoStatus.Status = Status;
320 IoCompleteRequest(Irp, IO_NO_INCREMENT);
321
322 //
323 // done
324 //
325 return Status;
326 }
327
328 NTSTATUS
329 CHCDController::HandlePnp(
330 IN PDEVICE_OBJECT DeviceObject,
331 IN PIRP Irp)
332 {
333 PIO_STACK_LOCATION IoStack;
334 PCOMMON_DEVICE_EXTENSION DeviceExtension;
335 PCM_RESOURCE_LIST RawResourceList;
336 PCM_RESOURCE_LIST TranslatedResourceList;
337 PDEVICE_RELATIONS DeviceRelations;
338 NTSTATUS Status;
339
340 //
341 // get device extension
342 //
343 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
344
345 //
346 // sanity check
347 //
348 PC_ASSERT(DeviceExtension->IsFDO);
349
350 //
351 // get current stack location
352 //
353 IoStack = IoGetCurrentIrpStackLocation(Irp);
354
355 switch(IoStack->MinorFunction)
356 {
357 case IRP_MN_START_DEVICE:
358 {
359 DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO\n");
360
361 //
362 // first start lower device object
363 //
364 Status = SyncForwardIrp(m_NextDeviceObject, Irp);
365
366 if (NT_SUCCESS(Status))
367 {
368 //
369 // operation succeeded, lets start the device
370 //
371 RawResourceList = IoStack->Parameters.StartDevice.AllocatedResources;
372 TranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
373
374 if (m_Hardware)
375 {
376 //
377 // start the hardware
378 //
379 Status = m_Hardware->PnpStart(RawResourceList, TranslatedResourceList);
380 }
381
382 //
383 // enable symbolic link
384 //
385 Status = SetSymbolicLink(TRUE);
386 }
387
388 DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO: Status %x\n", Status);
389 break;
390 }
391 case IRP_MN_QUERY_DEVICE_RELATIONS:
392 {
393 DPRINT1("CHCDController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", IoStack->Parameters.QueryDeviceRelations.Type);
394
395 if (m_HubController == NULL)
396 {
397 //
398 // create hub controller
399 //
400 Status = CreateHubController(&m_HubController);
401 if (!NT_SUCCESS(Status))
402 {
403 //
404 // failed to create hub controller
405 //
406 break;
407 }
408
409 //
410 // initialize hub controller
411 //
412 Status = m_HubController->Initialize(m_DriverObject, PHCDCONTROLLER(this), m_Hardware, TRUE, 0 /* FIXME*/);
413 if (!NT_SUCCESS(Status))
414 {
415 //
416 // failed to initialize hub controller
417 //
418 break;
419 }
420 }
421
422 if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
423 {
424 //
425 // allocate device relations
426 //
427 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
428
429 if (!DeviceRelations)
430 {
431 //
432 // no memory
433 //
434 Status = STATUS_INSUFFICIENT_RESOURCES;
435 break;
436 }
437
438 //
439 // init device relations
440 //
441 DeviceRelations->Count = 1;
442 Status = m_HubController->GetHubControllerDeviceObject(&DeviceRelations->Objects [0]);
443
444 //
445 // sanity check
446 //
447 PC_ASSERT(Status == STATUS_SUCCESS);
448
449 ObReferenceObject(DeviceRelations->Objects [0]);
450
451 //
452 // store result
453 //
454 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
455 Status = STATUS_SUCCESS;
456 }
457 else
458 {
459 //
460 // not supported
461 //
462 PC_ASSERT(0);
463 Status = STATUS_NOT_SUPPORTED;
464 }
465 break;
466 }
467 case IRP_MN_STOP_DEVICE:
468 {
469 DPRINT1("CHCDController::HandlePnp IRP_MN_STOP_DEVICE\n");
470
471 if (m_Hardware)
472 {
473 //
474 // stop the hardware
475 //
476 Status = m_Hardware->PnpStop();
477 }
478 else
479 {
480 //
481 // fake success
482 //
483 Status = STATUS_SUCCESS;
484 }
485
486 if (NT_SUCCESS(Status))
487 {
488 //
489 // stop lower device
490 //
491 Status = SyncForwardIrp(m_NextDeviceObject, Irp);
492 }
493 break;
494 }
495 case IRP_MN_REMOVE_DEVICE:
496 {
497 DPRINT1("CHCDController::HandlePnp IRP_MN_REMOVE_DEVICE FDO\n");
498
499 //
500 // detach device from device stack
501 //
502 IoDetachDevice(m_NextDeviceObject);
503
504 //
505 // delete device
506 //
507 IoDeleteDevice(m_FunctionalDeviceObject);
508
509 Status = STATUS_SUCCESS;
510 break;
511 }
512 default:
513 {
514 DPRINT1("CHCDController::HandlePnp Dispatch to lower device object %lu\n", IoStack->MinorFunction);
515 //
516 // forward irp to next device object
517 //
518 IoSkipCurrentIrpStackLocation(Irp);
519 return IoCallDriver(m_NextDeviceObject, Irp);
520 }
521 }
522
523 //
524 // store result and complete request
525 //
526 Irp->IoStatus.Status = Status;
527 IoCompleteRequest(Irp, IO_NO_INCREMENT);
528
529 return Status;
530 }
531
532 NTSTATUS
533 CHCDController::HandlePower(
534 IN PDEVICE_OBJECT DeviceObject,
535 IN PIRP Irp)
536 {
537 UNIMPLEMENTED
538
539 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
540 IoCompleteRequest(Irp, IO_NO_INCREMENT);
541
542 return STATUS_NOT_IMPLEMENTED;
543 }
544
545 NTSTATUS
546 CHCDController::CreateFDO(
547 PDRIVER_OBJECT DriverObject,
548 PDEVICE_OBJECT * OutDeviceObject)
549 {
550 WCHAR CharDeviceName[64];
551 NTSTATUS Status;
552 ULONG UsbDeviceNumber = 0;
553 UNICODE_STRING DeviceName;
554
555 while (TRUE)
556 {
557 //
558 // construct device name
559 //
560 swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
561
562 //
563 // initialize device name
564 //
565 RtlInitUnicodeString(&DeviceName, CharDeviceName);
566
567 //
568 // create device
569 //
570 Status = IoCreateDevice(DriverObject,
571 sizeof(COMMON_DEVICE_EXTENSION),
572 &DeviceName,
573 FILE_DEVICE_CONTROLLER,
574 0,
575 FALSE,
576 OutDeviceObject);
577
578 //
579 // check for success
580 //
581 if (NT_SUCCESS(Status))
582 break;
583
584 //
585 // is there a device object with that same name
586 //
587 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
588 {
589 //
590 // Try the next name
591 //
592 UsbDeviceNumber++;
593 continue;
594 }
595
596 //
597 // bail out on other errors
598 //
599 if (!NT_SUCCESS(Status))
600 {
601 DPRINT1("CreateFDO: Failed to create %wZ, Status %x\n", &DeviceName, Status);
602 return Status;
603 }
604 }
605
606 //
607 // store FDO number
608 //
609 m_FDODeviceNumber = UsbDeviceNumber;
610
611 DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName);
612
613 /* done */
614 return Status;
615 }
616
617 NTSTATUS
618 CHCDController::SetSymbolicLink(
619 BOOLEAN Enable)
620 {
621 NTSTATUS Status;
622 WCHAR LinkName[32];
623 WCHAR FDOName[32];
624 UNICODE_STRING Link, FDO;
625
626 if (Enable)
627 {
628 //
629 // create legacy link
630 //
631 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
632 swprintf(FDOName, L"\\Device\\USBFDO-%d", m_FDODeviceNumber);
633 RtlInitUnicodeString(&Link, LinkName);
634 RtlInitUnicodeString(&FDO, FDOName);
635
636 //
637 // create symbolic link
638 //
639 Status = IoCreateSymbolicLink(&Link, &FDO);
640
641 if (!NT_SUCCESS(Status))
642 {
643 //
644 // FIXME: handle me
645 //
646 ASSERT(0);
647 }
648 }
649 else
650 {
651 //
652 // create legacy link
653 //
654 swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
655 RtlInitUnicodeString(&Link, LinkName);
656
657 //
658 // now delete the symbolic link
659 //
660 Status = IoDeleteSymbolicLink(&Link);
661
662 if (!NT_SUCCESS(Status))
663 {
664 //
665 // FIXME: handle me
666 //
667 ASSERT(0);
668 }
669 }
670
671 //
672 // done
673 //
674 return Status;
675 }
676
677 NTSTATUS
678 CreateHCDController(
679 PHCDCONTROLLER *OutHcdController)
680 {
681 PHCDCONTROLLER This;
682
683 //
684 // allocate controller
685 //
686 This = new(NonPagedPool, TAG_USBEHCI) CHCDController(0);
687 if (!This)
688 {
689 //
690 // failed to allocate
691 //
692 return STATUS_INSUFFICIENT_RESOURCES;
693 }
694
695 //
696 // add reference count
697 //
698 This->AddRef();
699
700 //
701 // return result
702 //
703 *OutHcdController = (PHCDCONTROLLER)This;
704
705 //
706 // done
707 //
708 return STATUS_SUCCESS;
709 }