[USBEHCI_NEW]
[reactos.git] / drivers / usb / usbehci_new / hub_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/hub_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 CHubController : public IHubController,
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 // IHubController interface functions
38 virtual NTSTATUS Initialize(IN PDRIVER_OBJECT DriverObject, IN PHCDCONTROLLER Controller, IN PUSBHARDWAREDEVICE Device, IN BOOLEAN IsRootHubDevice, IN ULONG DeviceAddress);
39
40 // IDispatchIrp interface functions
41 virtual NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
42 virtual NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
43 virtual NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
44
45 // local functions
46 NTSTATUS HandleQueryInterface(PIO_STACK_LOCATION IoStack);
47 NTSTATUS SetDeviceInterface(BOOLEAN bEnable);
48 NTSTATUS CreatePDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject);
49 NTSTATUS GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject);
50
51 // constructor / destructor
52 CHubController(IUnknown *OuterUnknown){}
53 virtual ~CHubController(){}
54
55 protected:
56 LONG m_Ref;
57 PHCDCONTROLLER m_Controller;
58 PUSBHARDWAREDEVICE m_Hardware;
59 BOOLEAN m_IsRootHubDevice;
60 ULONG m_DeviceAddress;
61 ULONG m_PDODeviceNumber;
62 BOOLEAN m_InterfaceEnabled;
63 UNICODE_STRING m_HubDeviceInterfaceString;
64 PDEVICE_OBJECT m_HubControllerDeviceObject;
65 PDRIVER_OBJECT m_DriverObject;
66 };
67
68 //----------------------------------------------------------------------------------------
69 NTSTATUS
70 STDMETHODCALLTYPE
71 CHubController::QueryInterface(
72 IN REFIID refiid,
73 OUT PVOID* Output)
74 {
75 return STATUS_UNSUCCESSFUL;
76 }
77 //----------------------------------------------------------------------------------------
78 NTSTATUS
79 CHubController::Initialize(
80 IN PDRIVER_OBJECT DriverObject,
81 IN PHCDCONTROLLER Controller,
82 IN PUSBHARDWAREDEVICE Device,
83 IN BOOLEAN IsRootHubDevice,
84 IN ULONG DeviceAddress)
85 {
86 NTSTATUS Status;
87 PCOMMON_DEVICE_EXTENSION DeviceExtension;
88
89 DPRINT1("CHubController::Initialize\n");
90
91 //
92 // initialize members
93 //
94 m_Controller = Controller;
95 m_Hardware = Device;
96 m_IsRootHubDevice = IsRootHubDevice;
97 m_DeviceAddress = DeviceAddress;
98 m_DriverObject = DriverObject;
99
100 //
101 // create PDO
102 //
103 Status = CreatePDO(m_DriverObject, &m_HubControllerDeviceObject);
104 if (!NT_SUCCESS(Status))
105 {
106 //
107 // failed to create hub device object
108 //
109 return Status;
110 }
111
112 //
113 // get device extension
114 //
115 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_HubControllerDeviceObject->DeviceExtension;
116
117 //
118 // initialize device extension
119 //
120 DeviceExtension->IsFDO = FALSE;
121 DeviceExtension->IsHub = TRUE; //FIXME
122 DeviceExtension->Dispatcher = PDISPATCHIRP(this);
123
124 //
125 // clear init flag
126 //
127 m_HubControllerDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
128
129
130 return STATUS_SUCCESS;
131 }
132
133 //-----------------------------------------------------------------------------------------
134 NTSTATUS
135 CHubController::GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject)
136 {
137 //
138 // store controller object
139 //
140 *HubDeviceObject = m_HubControllerDeviceObject;
141
142 return STATUS_SUCCESS;
143 }
144 //-----------------------------------------------------------------------------------------
145 NTSTATUS
146 CHubController::HandlePnp(
147 IN PDEVICE_OBJECT DeviceObject,
148 IN OUT PIRP Irp)
149 {
150 PIO_STACK_LOCATION IoStack;
151 PCOMMON_DEVICE_EXTENSION DeviceExtension;
152 PDEVICE_CAPABILITIES DeviceCapabilities;
153 LPGUID Guid;
154 NTSTATUS Status;
155 ULONG Index;
156
157 //
158 // get device extension
159 //
160 DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
161
162 //
163 // sanity check
164 //
165 ASSERT(DeviceExtension->IsFDO == FALSE);
166
167 //
168 // get current stack location
169 //
170 IoStack = IoGetCurrentIrpStackLocation(Irp);
171
172 switch(IoStack->MinorFunction)
173 {
174 case IRP_MN_START_DEVICE:
175 {
176 DPRINT1("CHubController::HandlePnp IRP_MN_START_DEVICE\n");
177 //
178 // register device interface
179 //
180 Status = SetDeviceInterface(TRUE);
181 break;
182 }
183 case IRP_MN_QUERY_CAPABILITIES:
184 {
185 DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_CAPABILITIES\n");
186
187 DeviceCapabilities = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
188
189 DeviceCapabilities->LockSupported = FALSE;
190 DeviceCapabilities->EjectSupported = FALSE;
191 DeviceCapabilities->Removable = FALSE;
192 DeviceCapabilities->DockDevice = FALSE;
193 DeviceCapabilities->UniqueID = FALSE;
194 DeviceCapabilities->SilentInstall = FALSE;
195 DeviceCapabilities->RawDeviceOK = FALSE;
196 DeviceCapabilities->SurpriseRemovalOK = FALSE;
197 DeviceCapabilities->Address = 0;
198 DeviceCapabilities->UINumber = 0;
199 DeviceCapabilities->DeviceD2 = 1;
200
201 /* FIXME */
202 DeviceCapabilities->HardwareDisabled = FALSE;
203 DeviceCapabilities->NoDisplayInUI = FALSE;
204 DeviceCapabilities->DeviceState[0] = PowerDeviceD0;
205 for (Index = 0; Index < PowerSystemMaximum; Index++)
206 DeviceCapabilities->DeviceState[Index] = PowerDeviceD3;
207 DeviceCapabilities->DeviceWake = PowerDeviceUnspecified;
208 DeviceCapabilities->D1Latency = 0;
209 DeviceCapabilities->D2Latency = 0;
210 DeviceCapabilities->D3Latency = 0;
211
212 Status = STATUS_SUCCESS;
213 break;
214 }
215 case IRP_MN_QUERY_INTERFACE:
216 {
217 DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_INTERFACE\n");
218
219 //
220 // handle device interface requests
221 //
222 Status = HandleQueryInterface(IoStack);
223 break;
224 }
225 case IRP_MN_REMOVE_DEVICE:
226 {
227 DPRINT1("CHubController::HandlePnp IRP_MN_REMOVE_DEVICE\n");
228
229 //
230 // deactivate device interface for BUS PDO
231 //
232 SetDeviceInterface(FALSE);
233
234 //
235 // complete the request first
236 //
237 Irp->IoStatus.Status = STATUS_SUCCESS;
238 IoCompleteRequest(Irp, IO_NO_INCREMENT);
239
240 //
241 // now delete device
242 //
243 IoDeleteDevice(m_HubControllerDeviceObject);
244
245 //
246 // nullify pointer
247 //
248 m_HubControllerDeviceObject = 0;
249 return STATUS_SUCCESS;
250 }
251 case IRP_MN_QUERY_BUS_INFORMATION:
252 {
253 DPRINT1("CHubController::HandlePnp IRP_MN_QUERY_BUS_INFORMATION\n");
254
255 //
256 // allocate buffer for bus guid
257 //
258 Guid = (LPGUID)ExAllocatePool(PagedPool, sizeof(GUID));
259 if (Guid)
260 {
261 //
262 // copy BUS guid
263 //
264 RtlMoveMemory(Guid, &GUID_BUS_TYPE_USB, sizeof(GUID));
265 Status = STATUS_SUCCESS;
266 Irp->IoStatus.Information = (ULONG_PTR)Guid;
267 }
268 else
269 {
270 //
271 // no memory
272 //
273 Status = STATUS_INSUFFICIENT_RESOURCES;
274 }
275 break;
276 }
277 case IRP_MN_STOP_DEVICE:
278 {
279 DPRINT1("CHubController::HandlePnp IRP_MN_STOP_DEVICE\n");
280 //
281 // stop device
282 //
283 Status = STATUS_SUCCESS;
284 break;
285 }
286 default:
287 {
288 DPRINT1("CHubController::HandlePnp Unhandeled %x\n", IoStack->MinorFunction);
289 Status = STATUS_NOT_SUPPORTED;
290 break;
291 }
292 }
293
294 //
295 // complete request
296 //
297 Irp->IoStatus.Status = Status;
298 IoCompleteRequest(Irp, IO_NO_INCREMENT);
299
300 //
301 // done
302 //
303 return Status;
304 }
305
306 //-----------------------------------------------------------------------------------------
307 NTSTATUS
308 CHubController::HandlePower(
309 IN PDEVICE_OBJECT DeviceObject,
310 IN OUT PIRP Irp)
311 {
312 UNIMPLEMENTED
313 return STATUS_NOT_IMPLEMENTED;
314 }
315
316 //-----------------------------------------------------------------------------------------
317 NTSTATUS
318 CHubController::HandleDeviceControl(
319 IN PDEVICE_OBJECT DeviceObject,
320 IN OUT PIRP Irp)
321 {
322 UNIMPLEMENTED
323 return STATUS_NOT_IMPLEMENTED;
324 }
325
326
327 NTSTATUS
328 CHubController::HandleQueryInterface(
329 PIO_STACK_LOCATION IoStack)
330 {
331 UNICODE_STRING GuidBuffer;
332 NTSTATUS Status;
333
334 if (IsEqualGUIDAligned(*IoStack->Parameters.QueryInterface.InterfaceType, USB_BUS_INTERFACE_HUB_GUID))
335 {
336 DPRINT1("HandleQueryInterface> UNIMPLEMENTED USB_BUS_INTERFACE_HUB_GUID Version %x\n", IoStack->Parameters.QueryInterface.Version);
337
338 }
339 else if (IsEqualGUIDAligned(*IoStack->Parameters.QueryInterface.InterfaceType, USB_BUS_INTERFACE_USBDI_GUID))
340 {
341 DPRINT1("HandleQueryInterface> UNIMPLEMENTED USB_BUS_INTERFACE_USBDI_GUID Version %x\n", IoStack->Parameters.QueryInterface.Version);
342 }
343 else
344 {
345 //
346 // convert guid to string
347 //
348 Status = RtlStringFromGUID(*IoStack->Parameters.QueryInterface.InterfaceType, &GuidBuffer);
349 if (NT_SUCCESS(Status))
350 {
351 //
352 // print interface
353 //
354 DPRINT1("HandleQueryInterface GUID: %wZ Version %x\n", &GuidBuffer, IoStack->Parameters.QueryInterface.Version);
355
356 //
357 // free guid buffer
358 //
359 RtlFreeUnicodeString(&GuidBuffer);
360 }
361 }
362 return STATUS_NOT_SUPPORTED;
363 }
364
365 NTSTATUS
366 CHubController::SetDeviceInterface(
367 BOOLEAN Enable)
368 {
369 NTSTATUS Status = STATUS_SUCCESS;
370
371 if (Enable)
372 {
373 //
374 // register device interface
375 //
376 Status = IoRegisterDeviceInterface(m_HubControllerDeviceObject, &GUID_DEVINTERFACE_USB_HUB, 0, &m_HubDeviceInterfaceString);
377
378 if (NT_SUCCESS(Status))
379 {
380 //
381 // now enable the device interface
382 //
383 Status = IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString, TRUE);
384
385 //
386 // enable interface
387 //
388 m_InterfaceEnabled = TRUE;
389 }
390 }
391 else if (m_InterfaceEnabled)
392 {
393 //
394 // disable device interface
395 //
396 Status = IoSetDeviceInterfaceState(&m_HubDeviceInterfaceString, FALSE);
397
398 if (NT_SUCCESS(Status))
399 {
400 //
401 // now delete interface string
402 //
403 RtlFreeUnicodeString(&m_HubDeviceInterfaceString);
404 }
405
406 //
407 // disable interface
408 //
409 m_InterfaceEnabled = FALSE;
410 }
411
412 //
413 // done
414 //
415 return Status;
416 }
417
418 NTSTATUS
419 CHubController::CreatePDO(
420 PDRIVER_OBJECT DriverObject,
421 PDEVICE_OBJECT * OutDeviceObject)
422 {
423 WCHAR CharDeviceName[64];
424 NTSTATUS Status;
425 ULONG UsbDeviceNumber = 0;
426 UNICODE_STRING DeviceName;
427
428 while (TRUE)
429 {
430 //
431 // construct device name
432 //
433 swprintf(CharDeviceName, L"\\Device\\USBPDO-%d", UsbDeviceNumber);
434
435 //
436 // initialize device name
437 //
438 RtlInitUnicodeString(&DeviceName, CharDeviceName);
439
440 //
441 // create device
442 //
443 Status = IoCreateDevice(DriverObject,
444 sizeof(COMMON_DEVICE_EXTENSION),
445 &DeviceName,
446 FILE_DEVICE_CONTROLLER,
447 0,
448 FALSE,
449 OutDeviceObject);
450
451 /* check for success */
452 if (NT_SUCCESS(Status))
453 break;
454
455 //
456 // is there a device object with that same name
457 //
458 if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
459 {
460 //
461 // Try the next name
462 //
463 UsbDeviceNumber++;
464 continue;
465 }
466
467 //
468 // bail out on other errors
469 //
470 if (!NT_SUCCESS(Status))
471 {
472 DPRINT1("CreatePDO: Failed to create %wZ, Status %x\n", &DeviceName, Status);
473 return Status;
474 }
475 }
476
477 //
478 // store PDO number
479 //
480 //m_PDODeviceNumber = UsbDeviceNumber;
481
482 DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName);
483
484 /* done */
485 return Status;
486 }
487
488
489
490 NTSTATUS
491 CreateHubController(
492 PHUBCONTROLLER *OutHcdController)
493 {
494 PHUBCONTROLLER This;
495
496 //
497 // allocate controller
498 //
499 This = new(NonPagedPool, TAG_USBEHCI) CHubController(0);
500 if (!This)
501 {
502 //
503 // failed to allocate
504 //
505 return STATUS_INSUFFICIENT_RESOURCES;
506 }
507
508 //
509 // add reference count
510 //
511 This->AddRef();
512
513 //
514 // return result
515 //
516 *OutHcdController = (PHUBCONTROLLER)This;
517
518 //
519 // done
520 //
521 return STATUS_SUCCESS;
522 }