xref: /reactos/drivers/usb/usbehci/roothub.c (revision 803b5e13)
1 /*
2  * PROJECT:     ReactOS USB EHCI Miniport Driver
3  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE:     USBEHCI root hub functions
5  * COPYRIGHT:   Copyright 2017-2018 Vadim Galyant <vgal@rambler.ru>
6  */
7 
8 #include "usbehci.h"
9 
10 #define NDEBUG
11 #include <debug.h>
12 
13 #define NDEBUG_EHCI_ROOT_HUB
14 #include "dbg_ehci.h"
15 
16 MPSTATUS
17 NTAPI
18 EHCI_RH_ChirpRootPort(IN PVOID ehciExtension,
19                       IN USHORT Port)
20 {
21     PEHCI_EXTENSION EhciExtension = ehciExtension;
22     PULONG PortStatusReg;
23     EHCI_PORT_STATUS_CONTROL PortSC;
24     ULONG PortBit;
25     ULONG ix;
26 
27     DPRINT_RH("EHCI_RH_ChirpRootPort: Port - %x\n", Port);
28     ASSERT(Port != 0);
29 
30     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
31     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
32     DPRINT_RH("EHCI_RH_ChirpRootPort: PortSC - %X\n", PortSC.AsULONG);
33 
34     PortBit = 1 << (Port - 1);
35 
36     if (PortBit & EhciExtension->ResetPortBits)
37     {
38         DPRINT_RH("EHCI_RH_ChirpRootPort: Skip port - %x\n", Port);
39         return MP_STATUS_SUCCESS;
40     }
41 
42     if (PortSC.PortPower == 0)
43     {
44         DPRINT_RH("EHCI_RH_ChirpRootPort: Skip port - %x\n", Port);
45         return MP_STATUS_SUCCESS;
46     }
47 
48     if (PortSC.CurrentConnectStatus == 0 ||
49         PortSC.PortEnabledDisabled == 1 ||
50         PortSC.PortOwner == EHCI_PORT_OWNER_COMPANION_CONTROLLER)
51     {
52         DPRINT_RH("EHCI_RH_ChirpRootPort: No port - %x\n", Port);
53         return MP_STATUS_SUCCESS;
54     }
55 
56     if (PortSC.LineStatus == EHCI_LINE_STATUS_K_STATE_LOW_SPEED &&
57         PortSC.Suspend == 0 &&
58         PortSC.CurrentConnectStatus == 1)
59     {
60         /* Attached device is not a high-speed device.
61            Release ownership of the port to a selected HC.
62            Companion HC owns and controls the port. Section 4.2 */
63         PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER;
64         WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
65 
66         DPRINT_RH("EHCI_RH_ChirpRootPort: Companion HC port - %x\n", Port);
67         return MP_STATUS_SUCCESS;
68     }
69 
70     DPRINT("EHCI_RH_ChirpRootPort: EhciExtension - %p, Port - %x\n",
71            EhciExtension,
72            Port);
73 
74     PortSC.PortEnabledDisabled = 0;
75     PortSC.PortReset = 1;
76     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
77 
78     RegPacket.UsbPortWait(EhciExtension, 10);
79 
80     do
81     {
82         PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
83 
84         PortSC.ConnectStatusChange = 0;
85         PortSC.PortEnableDisableChange = 0;
86         PortSC.OverCurrentChange = 0;
87         PortSC.PortReset = 0;
88 
89         WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
90 
91         for (ix = 0; ix <= 500; ix += 20)
92         {
93              KeStallExecutionProcessor(20);
94              PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
95 
96              DPRINT_RH("EHCI_RH_ChirpRootPort: Reset port - %x\n", Port);
97 
98              if (PortSC.PortReset == 0)
99                  break;
100         }
101     }
102     while (PortSC.PortReset == 1);
103 
104     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
105 
106     if (PortSC.PortEnabledDisabled == 1)
107     {
108         PortSC.ConnectStatusChange = 0;
109         PortSC.PortEnabledDisabled = 0;
110         PortSC.PortEnableDisableChange = 0;
111         PortSC.OverCurrentChange = 0;
112 
113         RegPacket.UsbPortWait(EhciExtension, 10);
114 
115         EhciExtension->ResetPortBits |= PortBit;
116 
117         WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
118         DPRINT_RH("EHCI_RH_ChirpRootPort: Disable port - %x\n", Port);
119     }
120     else
121     {
122         PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER;
123         WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
124         DPRINT_RH("EHCI_RH_ChirpRootPort: Companion HC port - %x\n", Port);
125     }
126 
127     return MP_STATUS_SUCCESS;
128 }
129 
130 VOID
131 NTAPI
132 EHCI_RH_GetRootHubData(IN PVOID ehciExtension,
133                        IN PVOID rootHubData)
134 {
135     PEHCI_EXTENSION EhciExtension = ehciExtension;
136     PUSBPORT_ROOT_HUB_DATA RootHubData;
137     USBPORT_HUB_20_CHARACTERISTICS HubCharacteristics;
138 
139     DPRINT_RH("EHCI_RH_GetRootHubData: EhciExtension - %p, rootHubData - %p\n",
140               EhciExtension,
141               rootHubData);
142 
143     RootHubData = rootHubData;
144 
145     RootHubData->NumberOfPorts = EhciExtension->NumberOfPorts;
146 
147     HubCharacteristics.AsUSHORT = 0;
148 
149     /* Logical Power Switching Mode */
150     if (EhciExtension->PortPowerControl == 1)
151     {
152         /* Individual port power switching */
153         HubCharacteristics.PowerControlMode = 1;
154     }
155     else
156     {
157         /* Ganged power switching (all ports� power at once) */
158         HubCharacteristics.PowerControlMode = 0;
159     }
160 
161     HubCharacteristics.NoPowerSwitching = 0;
162 
163     /* EHCI RH is not part of a compound device */
164     HubCharacteristics.PartOfCompoundDevice = 0;
165 
166     /* Global Over-current Protection */
167     HubCharacteristics.OverCurrentProtectionMode = 0;
168 
169     RootHubData->HubCharacteristics.Usb20HubCharacteristics = HubCharacteristics;
170 
171     RootHubData->PowerOnToPowerGood = 2; // Time (in 2 ms intervals)
172     RootHubData->HubControlCurrent = 0;
173 }
174 
175 MPSTATUS
176 NTAPI
177 EHCI_RH_GetStatus(IN PVOID ehciExtension,
178                   IN PUSHORT Status)
179 {
180     DPRINT_RH("EHCI_RH_GetStatus: ... \n");
181     *Status = USB_GETSTATUS_SELF_POWERED;
182     return MP_STATUS_SUCCESS;
183 }
184 
185 MPSTATUS
186 NTAPI
187 EHCI_RH_GetPortStatus(IN PVOID ehciExtension,
188                       IN USHORT Port,
189                       IN PUSB_PORT_STATUS_AND_CHANGE PortStatus)
190 {
191     PEHCI_EXTENSION EhciExtension = ehciExtension;
192     PULONG PortStatusReg;
193     EHCI_PORT_STATUS_CONTROL PortSC;
194     USB_PORT_STATUS_AND_CHANGE status;
195     ULONG PortMaskBits;
196 
197     ASSERT(Port != 0);
198 
199     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
200     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
201 
202     if (PortSC.CurrentConnectStatus)
203     {
204         DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, PortSC.AsULONG - %X\n",
205                   Port,
206                   PortSC.AsULONG);
207     }
208 
209     PortStatus->AsUlong32 = 0;
210 
211     if (PortSC.LineStatus == EHCI_LINE_STATUS_K_STATE_LOW_SPEED &&
212         PortSC.PortOwner != EHCI_PORT_OWNER_COMPANION_CONTROLLER &&
213         (PortSC.PortEnabledDisabled | PortSC.Suspend) && // Enable or Suspend
214         PortSC.CurrentConnectStatus == 1) // Device is present
215     {
216         DPRINT("EHCI_RH_GetPortStatus: LowSpeed device detected\n");
217         PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER; // release ownership
218         WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
219         return MP_STATUS_SUCCESS;
220     }
221 
222     status.AsUlong32 = 0;
223 
224     status.PortStatus.Usb20PortStatus.CurrentConnectStatus = PortSC.CurrentConnectStatus;
225     status.PortStatus.Usb20PortStatus.PortEnabledDisabled = PortSC.PortEnabledDisabled;
226     status.PortStatus.Usb20PortStatus.Suspend = PortSC.Suspend;
227     status.PortStatus.Usb20PortStatus.OverCurrent = PortSC.OverCurrentActive;
228     status.PortStatus.Usb20PortStatus.Reset = PortSC.PortReset;
229     status.PortStatus.Usb20PortStatus.PortPower = PortSC.PortPower;
230     if (PortSC.PortOwner == EHCI_PORT_OWNER_COMPANION_CONTROLLER)
231         status.PortStatus.Usb20PortStatus.Reserved1 = USB20_PORT_STATUS_RESERVED1_OWNED_BY_COMPANION;
232 
233     status.PortChange.Usb20PortChange.PortEnableDisableChange = PortSC.PortEnableDisableChange;
234     status.PortChange.Usb20PortChange.OverCurrentIndicatorChange = PortSC.OverCurrentChange;
235 
236     PortMaskBits = 1 << (Port - 1);
237 
238     if (status.PortStatus.Usb20PortStatus.CurrentConnectStatus)
239         status.PortStatus.Usb20PortStatus.LowSpeedDeviceAttached = 0;
240 
241     status.PortStatus.Usb20PortStatus.HighSpeedDeviceAttached = 1;
242 
243     if (PortSC.ConnectStatusChange)
244         EhciExtension->ConnectPortBits |= PortMaskBits;
245 
246     if (EhciExtension->FinishResetPortBits & PortMaskBits)
247         status.PortChange.Usb20PortChange.ResetChange = 1;
248 
249     if (EhciExtension->ConnectPortBits & PortMaskBits)
250         status.PortChange.Usb20PortChange.ConnectStatusChange = 1;
251 
252     if (EhciExtension->SuspendPortBits & PortMaskBits)
253         status.PortChange.Usb20PortChange.SuspendChange = 1;
254 
255     *PortStatus = status;
256 
257     if (status.PortStatus.Usb20PortStatus.CurrentConnectStatus)
258     {
259         DPRINT_RH("EHCI_RH_GetPortStatus: Port - %x, status.AsULONG - %X\n",
260                   Port,
261                   status.AsUlong32);
262     }
263 
264     return MP_STATUS_SUCCESS;
265 }
266 
267 MPSTATUS
268 NTAPI
269 EHCI_RH_GetHubStatus(IN PVOID ehciExtension,
270                      IN PUSB_HUB_STATUS_AND_CHANGE HubStatus)
271 {
272     DPRINT_RH("EHCI_RH_GetHubStatus: ... \n");
273     HubStatus->AsUlong32 = 0;
274     return MP_STATUS_SUCCESS;
275 }
276 
277 VOID
278 NTAPI
279 EHCI_RH_FinishReset(IN PVOID ehciExtension,
280                     IN PVOID Context)
281 {
282     PEHCI_EXTENSION EhciExtension = ehciExtension;
283     PULONG PortStatusReg;
284     EHCI_PORT_STATUS_CONTROL PortSC;
285     PUSHORT Port = Context;
286 
287     DPRINT("EHCI_RH_FinishReset: *Port - %x\n", *Port);
288 
289     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG;
290     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
291 
292     if (PortSC.AsULONG != -1)
293     {
294         if (!PortSC.CurrentConnectStatus)
295             DPRINT("EHCI_RH_FinishReset: PortSC.AsULONG - %X\n", PortSC.AsULONG);
296 
297         if (PortSC.PortEnabledDisabled ||
298             !PortSC.CurrentConnectStatus ||
299             PortSC.ConnectStatusChange)
300         {
301             EhciExtension->FinishResetPortBits |= (1 << (*Port - 1));
302             RegPacket.UsbPortInvalidateRootHub(EhciExtension);
303         }
304         else
305         {
306             PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
307             PortSC.PortOwner = EHCI_PORT_OWNER_COMPANION_CONTROLLER;
308             WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
309             EhciExtension->FinishResetPortBits |= (1 << (*Port - 1));
310         }
311 
312         EhciExtension->ResetPortBits &= ~(1 << (*Port - 1));
313     }
314 }
315 
316 VOID
317 NTAPI
318 EHCI_RH_PortResetComplete(IN PVOID ehciExtension,
319                           IN PVOID Context)
320 {
321     PEHCI_EXTENSION EhciExtension = ehciExtension;
322     PULONG PortStatusReg;
323     EHCI_PORT_STATUS_CONTROL PortSC;
324     ULONG ix;
325     PUSHORT Port = Context;
326 
327     DPRINT("EHCI_RH_PortResetComplete: *Port - %x\n", *Port);
328 
329     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG;
330 
331     do
332     {
333         PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
334 
335         PortSC.ConnectStatusChange = 0;
336         PortSC.PortEnableDisableChange = 0;
337         PortSC.OverCurrentChange = 0;
338         PortSC.PortReset = 0;
339 
340         WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
341 
342         for (ix = 0; ix <= 500; ix += 20)
343         {
344              KeStallExecutionProcessor(20);
345              PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
346 
347              DPRINT("EHCI_RH_PortResetComplete: Reset port - %x\n", Port);
348 
349              if (PortSC.PortReset == 0)
350                  break;
351         }
352     }
353     while (PortSC.PortReset == 1 && (PortSC.AsULONG != -1));
354 
355     RegPacket.UsbPortRequestAsyncCallback(EhciExtension,
356                                           50, // TimerValue
357                                           Port,
358                                           sizeof(Port),
359                                           EHCI_RH_FinishReset);
360 }
361 
362 MPSTATUS
363 NTAPI
364 EHCI_RH_SetFeaturePortReset(IN PVOID ehciExtension,
365                             IN USHORT Port)
366 {
367     PEHCI_EXTENSION EhciExtension = ehciExtension;
368     PULONG PortStatusReg;
369     EHCI_PORT_STATUS_CONTROL PortSC;
370 
371     DPRINT("EHCI_RH_SetFeaturePortReset: Port - %x\n", Port);
372     ASSERT(Port != 0);
373 
374     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
375 
376     EhciExtension->ResetPortBits |= 1 << (Port - 1);
377 
378     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
379 
380     PortSC.ConnectStatusChange = 0;
381     PortSC.PortEnabledDisabled = 0;
382     PortSC.PortEnableDisableChange = 0;
383     PortSC.OverCurrentChange = 0;
384     PortSC.PortReset = 1;
385 
386     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
387 
388     RegPacket.UsbPortRequestAsyncCallback(EhciExtension,
389                                           50, // TimerValue
390                                           &Port,
391                                           sizeof(Port),
392                                           EHCI_RH_PortResetComplete);
393 
394     return MP_STATUS_SUCCESS;
395 }
396 
397 MPSTATUS
398 NTAPI
399 EHCI_RH_SetFeaturePortPower(IN PVOID ehciExtension,
400                             IN USHORT Port)
401 {
402     PEHCI_EXTENSION EhciExtension = ehciExtension;
403     PULONG PortStatusReg;
404     EHCI_PORT_STATUS_CONTROL PortSC;
405 
406     DPRINT_RH("EHCI_RH_SetFeaturePortPower: Port - %x\n", Port);
407     ASSERT(Port != 0);
408 
409     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
410 
411     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
412 
413     PortSC.ConnectStatusChange = 0;
414     PortSC.PortEnableDisableChange = 0;
415     PortSC.OverCurrentChange = 0;
416     PortSC.PortPower = 1;
417 
418     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
419 
420     return MP_STATUS_SUCCESS;
421 }
422 
423 MPSTATUS
424 NTAPI
425 EHCI_RH_SetFeaturePortEnable(IN PVOID ehciExtension,
426                              IN USHORT Port)
427 {
428     DPRINT_RH("EHCI_RH_SetFeaturePortEnable: Not supported\n");
429     ASSERT(Port != 0);
430     return MP_STATUS_SUCCESS;
431 }
432 
433 MPSTATUS
434 NTAPI
435 EHCI_RH_SetFeaturePortSuspend(IN PVOID ehciExtension,
436                               IN USHORT Port)
437 {
438     PEHCI_EXTENSION EhciExtension = ehciExtension;
439     PULONG PortStatusReg;
440     EHCI_PORT_STATUS_CONTROL PortSC;
441 
442     DPRINT("EHCI_RH_SetFeaturePortSuspend: Port - %x\n", Port);
443     ASSERT(Port != 0);
444 
445     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
446 
447     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
448 
449     PortSC.ConnectStatusChange = 0;
450     PortSC.PortEnableDisableChange = 0;
451     PortSC.OverCurrentChange = 0;
452     PortSC.Suspend = 1;
453 
454     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
455     KeStallExecutionProcessor(125);
456 
457     return MP_STATUS_SUCCESS;
458 }
459 
460 MPSTATUS
461 NTAPI
462 EHCI_RH_ClearFeaturePortEnable(IN PVOID ehciExtension,
463                                IN USHORT Port)
464 {
465     PEHCI_EXTENSION EhciExtension = ehciExtension;
466     PULONG PortStatusReg;
467     EHCI_PORT_STATUS_CONTROL PortSC;
468 
469     DPRINT("EHCI_RH_ClearFeaturePortEnable: Port - %x\n", Port);
470     ASSERT(Port != 0);
471 
472     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
473 
474     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
475 
476     PortSC.ConnectStatusChange = 0;
477     PortSC.PortEnabledDisabled = 0;
478     PortSC.PortEnableDisableChange = 0;
479     PortSC.OverCurrentChange = 0;
480 
481     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
482 
483     return MP_STATUS_SUCCESS;
484 }
485 
486 MPSTATUS
487 NTAPI
488 EHCI_RH_ClearFeaturePortPower(IN PVOID ehciExtension,
489                               IN USHORT Port)
490 {
491     PEHCI_EXTENSION EhciExtension = ehciExtension;
492     PULONG PortStatusReg;
493     EHCI_PORT_STATUS_CONTROL PortSC;
494 
495     DPRINT("EHCI_RH_ClearFeaturePortPower: Port - %x\n", Port);
496     ASSERT(Port != 0);
497 
498     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
499 
500     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
501     PortSC.PortPower = 0;
502     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
503 
504     return MP_STATUS_SUCCESS;
505 }
506 
507 VOID
508 NTAPI
509 EHCI_RH_PortResumeComplete(IN PVOID ehciExtension,
510                            IN PVOID Context)
511 {
512     PEHCI_EXTENSION EhciExtension = ehciExtension;
513     PULONG PortStatusReg;
514     EHCI_PORT_STATUS_CONTROL PortSC;
515     PUSHORT Port = Context;
516 
517     DPRINT("EHCI_RH_PortResumeComplete: *Port - %x\n", *Port);
518     ASSERT(Port != 0);
519 
520     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[*Port - 1].AsULONG;
521 
522     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
523 
524     PortSC.ConnectStatusChange = 0;
525     PortSC.PortEnableDisableChange = 0;
526     PortSC.OverCurrentChange = 0;
527     PortSC.ForcePortResume = 0;
528     PortSC.Suspend = 0;
529 
530     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
531     READ_REGISTER_ULONG(PortStatusReg);
532 
533     EhciExtension->SuspendPortBits |= 1 << (*Port - 1);
534 }
535 
536 MPSTATUS
537 NTAPI
538 EHCI_RH_ClearFeaturePortSuspend(IN PVOID ehciExtension,
539                                 IN USHORT Port)
540 {
541     PEHCI_EXTENSION EhciExtension = ehciExtension;
542     PULONG PortStatusReg;
543     EHCI_PORT_STATUS_CONTROL PortSC;
544 
545     DPRINT("EHCI_RH_ClearFeaturePortSuspend: Port - %x\n", Port);
546     ASSERT(Port != 0);
547 
548     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
549     EhciExtension->ResetPortBits |= 1 << (Port - 1);
550 
551     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
552     PortSC.ForcePortResume = 1;
553     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
554 
555     RegPacket.UsbPortRequestAsyncCallback(EhciExtension,
556                                           50, // TimerValue
557                                           &Port,
558                                           sizeof(Port),
559                                           EHCI_RH_PortResumeComplete);
560 
561     return MP_STATUS_SUCCESS;
562 }
563 
564 MPSTATUS
565 NTAPI
566 EHCI_RH_ClearFeaturePortEnableChange(IN PVOID ehciExtension,
567                                      IN USHORT Port)
568 {
569     PEHCI_EXTENSION EhciExtension = ehciExtension;
570     PULONG PortStatusReg;
571     EHCI_PORT_STATUS_CONTROL PortSC;
572 
573     DPRINT("EHCI_RH_ClearFeaturePortEnableChange: Port - %p\n", Port);
574     ASSERT(Port != 0);
575 
576     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
577 
578     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
579 
580     PortSC.ConnectStatusChange = 0;
581     PortSC.OverCurrentChange = 0;
582     PortSC.PortEnableDisableChange = 1;
583 
584     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
585 
586     return MP_STATUS_SUCCESS;
587 }
588 
589 MPSTATUS
590 NTAPI
591 EHCI_RH_ClearFeaturePortConnectChange(IN PVOID ehciExtension,
592                                       IN USHORT Port)
593 {
594     PEHCI_EXTENSION EhciExtension = ehciExtension;
595     PULONG PortStatusReg;
596     EHCI_PORT_STATUS_CONTROL PortSC;
597 
598     DPRINT_RH("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port);
599     ASSERT(Port != 0);
600 
601     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
602 
603     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
604 
605     if (PortSC.ConnectStatusChange)
606     {
607         PortSC.ConnectStatusChange = 1;
608         PortSC.PortEnableDisableChange = 0;
609         PortSC.OverCurrentChange = 0;
610 
611         WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
612     }
613 
614     EhciExtension->ConnectPortBits &= ~(1 << (Port - 1));
615 
616     return MP_STATUS_SUCCESS;
617 }
618 
619 MPSTATUS
620 NTAPI
621 EHCI_RH_ClearFeaturePortResetChange(IN PVOID ehciExtension,
622                                     IN USHORT Port)
623 {
624     PEHCI_EXTENSION EhciExtension = ehciExtension;
625 
626     DPRINT("EHCI_RH_ClearFeaturePortConnectChange: Port - %x\n", Port);
627     ASSERT(Port != 0);
628 
629     EhciExtension->FinishResetPortBits &= ~(1 << (Port - 1));
630     return MP_STATUS_SUCCESS;
631 }
632 
633 MPSTATUS
634 NTAPI
635 EHCI_RH_ClearFeaturePortSuspendChange(IN PVOID ehciExtension,
636                                       IN USHORT Port)
637 {
638     PEHCI_EXTENSION EhciExtension = ehciExtension;
639 
640     DPRINT("EHCI_RH_ClearFeaturePortSuspendChange: Port - %x\n", Port);
641     ASSERT(Port != 0);
642 
643     EhciExtension->SuspendPortBits &= ~(1 << (Port - 1));
644     return MP_STATUS_SUCCESS;
645 }
646 
647 MPSTATUS
648 NTAPI
649 EHCI_RH_ClearFeaturePortOvercurrentChange(IN PVOID ehciExtension,
650                                           IN USHORT Port)
651 {
652     PEHCI_EXTENSION EhciExtension = ehciExtension;
653     PULONG PortStatusReg;
654     EHCI_PORT_STATUS_CONTROL PortSC;
655 
656     DPRINT_RH("EHCI_RH_ClearFeaturePortOvercurrentChange: Port - %x\n", Port);
657     ASSERT(Port != 0);
658 
659     PortStatusReg = &EhciExtension->OperationalRegs->PortControl[Port - 1].AsULONG;
660 
661     PortSC.AsULONG = READ_REGISTER_ULONG(PortStatusReg);
662 
663     PortSC.ConnectStatusChange = 0;
664     PortSC.PortEnableDisableChange = 0;
665     PortSC.OverCurrentChange = 1;
666 
667     WRITE_REGISTER_ULONG(PortStatusReg, PortSC.AsULONG);
668 
669     return MP_STATUS_SUCCESS;
670 }
671 
672 VOID
673 NTAPI
674 EHCI_RH_DisableIrq(IN PVOID ehciExtension)
675 {
676     PEHCI_EXTENSION EhciExtension = ehciExtension;
677     PULONG IntrStsReg;
678     EHCI_INTERRUPT_ENABLE IntrSts;
679 
680     DPRINT_RH("EHCI_RH_DisableIrq: ... \n");
681 
682     IntrStsReg = &EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG;
683     IntrSts.AsULONG = READ_REGISTER_ULONG(IntrStsReg);
684 
685     EhciExtension->InterruptMask.PortChangeInterrupt = 0;
686     IntrSts.PortChangeInterrupt = 0;
687 
688     if (IntrSts.Interrupt)
689         WRITE_REGISTER_ULONG(IntrStsReg, IntrSts.AsULONG);
690 }
691 
692 VOID
693 NTAPI
694 EHCI_RH_EnableIrq(IN PVOID ehciExtension)
695 {
696     PEHCI_EXTENSION EhciExtension = ehciExtension;
697     PULONG IntrStsReg;
698     EHCI_INTERRUPT_ENABLE IntrSts;
699 
700     DPRINT_RH("EHCI_RH_EnableIrq: ... \n");
701 
702     IntrStsReg = &EhciExtension->OperationalRegs->HcInterruptEnable.AsULONG;
703     IntrSts.AsULONG = READ_REGISTER_ULONG(IntrStsReg);
704 
705     EhciExtension->InterruptMask.PortChangeInterrupt = 1;
706     IntrSts.PortChangeInterrupt = 1;
707 
708     if (IntrSts.Interrupt)
709         WRITE_REGISTER_ULONG(IntrStsReg, IntrSts.AsULONG);
710 }
711