1 /* 2 * PROJECT: ReactOS USB OHCI Miniport Driver 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: USBOHCI root hub functions 5 * COPYRIGHT: Copyright 2017-2018 Vadim Galyant <vgal@rambler.ru> 6 */ 7 8 #include "usbohci.h" 9 10 #define NDEBUG 11 #include <debug.h> 12 13 OHCI_REG_RH_DESCRIPTORA 14 NTAPI 15 OHCI_ReadRhDescriptorA(IN POHCI_EXTENSION OhciExtension) 16 { 17 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 18 OHCI_REG_RH_DESCRIPTORA DescriptorA; 19 PULONG DescriptorAReg; 20 ULONG ix; 21 22 OperationalRegs = OhciExtension->OperationalRegs; 23 DescriptorAReg = (PULONG)&OperationalRegs->HcRhDescriptorA; 24 25 DPRINT("OHCI_ReadRhDescriptorA: OhciExtension - %p\n", OhciExtension); 26 27 for (ix = 0; ix < 10; ix++) 28 { 29 DescriptorA.AsULONG = READ_REGISTER_ULONG(DescriptorAReg); 30 31 if (DescriptorA.AsULONG != 0 && 32 DescriptorA.Reserved == 0 && 33 DescriptorA.NumberDownstreamPorts <= OHCI_MAX_PORT_COUNT) 34 { 35 break; 36 } 37 38 DPRINT1("OHCI_ReadRhDescriptorA: DescriptorA - %lX, ix - %d\n", 39 DescriptorA.AsULONG, ix); 40 41 KeStallExecutionProcessor(5); 42 } 43 44 return DescriptorA; 45 } 46 47 VOID 48 NTAPI 49 OHCI_RH_GetRootHubData(IN PVOID ohciExtension, 50 IN PVOID rootHubData) 51 { 52 POHCI_EXTENSION OhciExtension; 53 PUSBPORT_ROOT_HUB_DATA RootHubData; 54 OHCI_REG_RH_DESCRIPTORA DescriptorA; 55 UCHAR PowerOnToPowerGoodTime; 56 USBPORT_HUB_11_CHARACTERISTICS HubCharacteristics; 57 58 OhciExtension = ohciExtension; 59 60 DPRINT("OHCI_RH_GetRootHubData: OhciExtension - %p, rootHubData - %p\n", 61 OhciExtension, 62 rootHubData); 63 64 RootHubData = rootHubData; 65 DescriptorA = OHCI_ReadRhDescriptorA(OhciExtension); 66 67 RootHubData->NumberOfPorts = DescriptorA.NumberDownstreamPorts; 68 69 /* Waiting time (in 2 ms intervals) */ 70 PowerOnToPowerGoodTime = DescriptorA.PowerOnToPowerGoodTime; 71 if (PowerOnToPowerGoodTime <= OHCI_MINIMAL_POTPGT) 72 PowerOnToPowerGoodTime = OHCI_MINIMAL_POTPGT; 73 RootHubData->PowerOnToPowerGood = PowerOnToPowerGoodTime; 74 75 HubCharacteristics.AsUSHORT = 0; 76 77 if (DescriptorA.PowerSwitchingMode) 78 { 79 /* Individual port power switching */ 80 HubCharacteristics.PowerControlMode = 1; 81 } 82 else 83 { 84 /* Ganged power switching */ 85 HubCharacteristics.PowerControlMode = 0; 86 } 87 88 HubCharacteristics.NoPowerSwitching = 0; 89 90 /* always 0 (OHCI RH is not a compound device) */ 91 ASSERT(DescriptorA.DeviceType == 0); 92 HubCharacteristics.PartOfCompoundDevice = DescriptorA.DeviceType; 93 94 HubCharacteristics.OverCurrentProtectionMode = DescriptorA.OverCurrentProtectionMode; 95 HubCharacteristics.NoOverCurrentProtection = DescriptorA.NoOverCurrentProtection; 96 97 RootHubData->HubCharacteristics.Usb11HubCharacteristics = HubCharacteristics; 98 RootHubData->HubControlCurrent = 0; 99 } 100 101 MPSTATUS 102 NTAPI 103 OHCI_RH_GetStatus(IN PVOID ohciExtension, 104 IN PUSHORT Status) 105 { 106 DPRINT("OHCI_RH_GetStatus: \n"); 107 *Status = USB_GETSTATUS_SELF_POWERED; 108 return MP_STATUS_SUCCESS; 109 } 110 111 MPSTATUS 112 NTAPI 113 OHCI_RH_GetPortStatus(IN PVOID ohciExtension, 114 IN USHORT Port, 115 IN PUSB_PORT_STATUS_AND_CHANGE PortStatus) 116 { 117 POHCI_EXTENSION OhciExtension; 118 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 119 PULONG PortStatusReg; 120 OHCI_REG_RH_PORT_STATUS OhciPortStatus; 121 ULONG ix; 122 ULONG Reserved; 123 124 OhciExtension = ohciExtension; 125 126 DPRINT("OHCI_RH_GetPortStatus: OhciExtension - %p, Port - %x, PortStatus - %lX\n", 127 OhciExtension, 128 Port, 129 PortStatus->AsUlong32); 130 131 ASSERT(Port > 0); 132 133 OperationalRegs = OhciExtension->OperationalRegs; 134 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 135 136 for (ix = 0; ix < 10; ix++) 137 { 138 OhciPortStatus.AsULONG = READ_REGISTER_ULONG(PortStatusReg); 139 140 Reserved = OhciPortStatus.Reserved1r | 141 OhciPortStatus.Reserved2r | 142 OhciPortStatus.Reserved3; 143 144 if (OhciPortStatus.AsULONG && !Reserved) 145 break; 146 147 DPRINT("OHCI_RH_GetPortStatus: OhciPortStatus - %X\n", OhciPortStatus.AsULONG); 148 149 KeStallExecutionProcessor(5); 150 } 151 152 PortStatus->AsUlong32 = OhciPortStatus.AsULONG; 153 154 return MP_STATUS_SUCCESS; 155 } 156 157 MPSTATUS 158 NTAPI 159 OHCI_RH_GetHubStatus(IN PVOID ohciExtension, 160 IN PUSB_HUB_STATUS_AND_CHANGE HubStatus) 161 { 162 POHCI_EXTENSION OhciExtension; 163 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 164 PULONG RhStatusReg; 165 OHCI_REG_RH_STATUS HcRhStatus; 166 167 OhciExtension = ohciExtension; 168 169 DPRINT("OHCI_RH_GetHubStatus: ohciExtension - %p, HubStatus - %lX\n", 170 ohciExtension, 171 HubStatus->AsUlong32); 172 173 OperationalRegs = OhciExtension->OperationalRegs; 174 RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus; 175 176 HcRhStatus.AsULONG = READ_REGISTER_ULONG(RhStatusReg); 177 178 HubStatus->HubStatus.LocalPowerLost = HcRhStatus.LocalPowerStatus; 179 HubStatus->HubChange.LocalPowerChange = HcRhStatus.LocalPowerStatusChange; 180 181 HubStatus->HubStatus.OverCurrent = HcRhStatus.OverCurrentIndicator; 182 HubStatus->HubChange.OverCurrentChange = HcRhStatus.OverCurrentIndicatorChangeR; 183 184 return MP_STATUS_SUCCESS; 185 } 186 187 MPSTATUS 188 NTAPI 189 OHCI_RH_SetFeaturePortReset(IN PVOID ohciExtension, 190 IN USHORT Port) 191 { 192 POHCI_EXTENSION OhciExtension; 193 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 194 PULONG PortStatusReg; 195 OHCI_REG_RH_PORT_STATUS PortStatus; 196 197 OhciExtension = ohciExtension; 198 199 DPRINT("OHCI_RH_SetFeaturePortReset: OhciExtension - %p, Port - %x\n", 200 OhciExtension, 201 Port); 202 203 ASSERT(Port > 0); 204 205 OperationalRegs = OhciExtension->OperationalRegs; 206 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 207 208 PortStatus.AsULONG = 0; 209 PortStatus.SetPortReset = 1; 210 211 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 212 213 return MP_STATUS_SUCCESS; 214 } 215 216 MPSTATUS 217 NTAPI 218 OHCI_RH_SetFeaturePortPower(IN PVOID ohciExtension, 219 IN USHORT Port) 220 { 221 POHCI_EXTENSION OhciExtension; 222 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 223 PULONG PortStatusReg; 224 OHCI_REG_RH_PORT_STATUS PortStatus; 225 226 OhciExtension = ohciExtension; 227 228 DPRINT("OHCI_RH_SetFeaturePortPower: OhciExtension - %p, Port - %x\n", 229 OhciExtension, 230 Port); 231 232 ASSERT(Port > 0); 233 234 OperationalRegs = OhciExtension->OperationalRegs; 235 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 236 237 PortStatus.AsULONG = 0; 238 PortStatus.SetPortPower = 1; 239 240 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 241 242 return MP_STATUS_SUCCESS; 243 } 244 245 MPSTATUS 246 NTAPI 247 OHCI_RH_SetFeaturePortEnable(IN PVOID ohciExtension, 248 IN USHORT Port) 249 { 250 POHCI_EXTENSION OhciExtension; 251 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 252 PULONG PortStatusReg; 253 OHCI_REG_RH_PORT_STATUS PortStatus; 254 255 OhciExtension = ohciExtension; 256 257 DPRINT("OHCI_RH_SetFeaturePortEnable: OhciExtension - %p, Port - %x\n", 258 OhciExtension, 259 Port); 260 261 ASSERT(Port > 0); 262 263 OperationalRegs = OhciExtension->OperationalRegs; 264 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 265 266 PortStatus.AsULONG = 0; 267 PortStatus.SetPortEnable = 1; 268 269 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 270 271 return MP_STATUS_SUCCESS; 272 } 273 274 MPSTATUS 275 NTAPI 276 OHCI_RH_SetFeaturePortSuspend(IN PVOID ohciExtension, 277 IN USHORT Port) 278 { 279 POHCI_EXTENSION OhciExtension; 280 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 281 PULONG PortStatusReg; 282 OHCI_REG_RH_PORT_STATUS PortStatus; 283 284 OhciExtension = ohciExtension; 285 286 DPRINT("OHCI_RH_SetFeaturePortSuspend: OhciExtension - %p, Port - %x\n", 287 OhciExtension, 288 Port); 289 290 ASSERT(Port > 0); 291 292 OperationalRegs = OhciExtension->OperationalRegs; 293 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 294 295 PortStatus.AsULONG = 0; 296 PortStatus.SetPortSuspend = 1; 297 298 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 299 300 return MP_STATUS_SUCCESS; 301 } 302 303 MPSTATUS 304 NTAPI 305 OHCI_RH_ClearFeaturePortEnable(IN PVOID ohciExtension, 306 IN USHORT Port) 307 { 308 POHCI_EXTENSION OhciExtension; 309 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 310 PULONG PortStatusReg; 311 OHCI_REG_RH_PORT_STATUS PortStatus; 312 313 OhciExtension = ohciExtension; 314 315 DPRINT("OHCI_RH_ClearFeaturePortEnable: OhciExtension - %p, Port - %x\n", 316 OhciExtension, 317 Port); 318 319 ASSERT(Port > 0); 320 321 OperationalRegs = OhciExtension->OperationalRegs; 322 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 323 324 PortStatus.AsULONG = 0; 325 PortStatus.ClearPortEnable = 1; 326 327 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 328 329 return MP_STATUS_SUCCESS; 330 } 331 332 MPSTATUS 333 NTAPI 334 OHCI_RH_ClearFeaturePortPower(IN PVOID ohciExtension, 335 IN USHORT Port) 336 { 337 POHCI_EXTENSION OhciExtension; 338 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 339 PULONG PortStatusReg; 340 OHCI_REG_RH_PORT_STATUS PortStatus; 341 342 OhciExtension = ohciExtension; 343 344 DPRINT("OHCI_RH_ClearFeaturePortPower: OhciExtension - %p, Port - %x\n", 345 OhciExtension, 346 Port); 347 348 ASSERT(Port > 0); 349 350 OperationalRegs = OhciExtension->OperationalRegs; 351 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 352 353 PortStatus.AsULONG = 0; 354 PortStatus.ClearPortPower = 1; 355 356 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 357 358 return MP_STATUS_SUCCESS; 359 } 360 361 MPSTATUS 362 NTAPI 363 OHCI_RH_ClearFeaturePortSuspend(IN PVOID ohciExtension, 364 IN USHORT Port) 365 { 366 POHCI_EXTENSION OhciExtension; 367 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 368 PULONG PortStatusReg; 369 OHCI_REG_RH_PORT_STATUS PortStatus; 370 371 OhciExtension = ohciExtension; 372 373 DPRINT("OHCI_RH_ClearFeaturePortSuspend: OhciExtension - %p, Port - %x\n", 374 OhciExtension, 375 Port); 376 377 ASSERT(Port > 0); 378 379 OperationalRegs = OhciExtension->OperationalRegs; 380 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 381 382 PortStatus.AsULONG = 0; 383 PortStatus.ClearSuspendStatus = 1; 384 385 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 386 387 return MP_STATUS_SUCCESS; 388 } 389 390 MPSTATUS 391 NTAPI 392 OHCI_RH_ClearFeaturePortEnableChange(IN PVOID ohciExtension, 393 IN USHORT Port) 394 { 395 POHCI_EXTENSION OhciExtension; 396 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 397 PULONG PortStatusReg; 398 OHCI_REG_RH_PORT_STATUS PortStatus; 399 400 OhciExtension = ohciExtension; 401 402 DPRINT("OHCI_RH_ClearFeaturePortEnableChange: ohciExtension - %p, Port - %x\n", 403 ohciExtension, 404 Port); 405 406 ASSERT(Port > 0); 407 408 OperationalRegs = OhciExtension->OperationalRegs; 409 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 410 411 PortStatus.AsULONG = 0; 412 PortStatus.PortEnableStatusChange = 1; 413 414 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 415 416 return MP_STATUS_SUCCESS; 417 } 418 419 MPSTATUS 420 NTAPI 421 OHCI_RH_ClearFeaturePortConnectChange(IN PVOID ohciExtension, 422 IN USHORT Port) 423 { 424 POHCI_EXTENSION OhciExtension; 425 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 426 PULONG PortStatusReg; 427 OHCI_REG_RH_PORT_STATUS PortStatus; 428 429 OhciExtension = ohciExtension; 430 431 DPRINT("OHCI_RH_ClearFeaturePortConnectChange: OhciExtension - %p, Port - %x\n", 432 OhciExtension, 433 Port); 434 435 ASSERT(Port > 0); 436 437 OperationalRegs = OhciExtension->OperationalRegs; 438 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 439 440 PortStatus.AsULONG = 0; 441 PortStatus.ConnectStatusChange = 1; 442 443 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 444 445 return MP_STATUS_SUCCESS; 446 } 447 448 MPSTATUS 449 NTAPI 450 OHCI_RH_ClearFeaturePortResetChange(IN PVOID ohciExtension, 451 IN USHORT Port) 452 { 453 POHCI_EXTENSION OhciExtension; 454 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 455 PULONG PortStatusReg; 456 OHCI_REG_RH_PORT_STATUS PortStatus; 457 458 OhciExtension = ohciExtension; 459 460 DPRINT("OHCI_RH_ClearFeaturePortResetChange: OhciExtension - %p, Port - %x\n", 461 OhciExtension, 462 Port); 463 464 ASSERT(Port > 0); 465 466 OperationalRegs = OhciExtension->OperationalRegs; 467 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 468 469 PortStatus.AsULONG = 0; 470 PortStatus.PortResetStatusChange = 1; 471 472 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 473 474 return MP_STATUS_SUCCESS; 475 } 476 477 MPSTATUS 478 NTAPI 479 OHCI_RH_ClearFeaturePortSuspendChange(IN PVOID ohciExtension, 480 IN USHORT Port) 481 { 482 POHCI_EXTENSION OhciExtension; 483 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 484 PULONG PortStatusReg; 485 OHCI_REG_RH_PORT_STATUS PortStatus; 486 487 OhciExtension = ohciExtension; 488 489 DPRINT("OHCI_RH_ClearFeaturePortSuspendChange: OhciExtension - %p, Port - %x\n", 490 OhciExtension, 491 Port); 492 493 ASSERT(Port > 0); 494 495 OperationalRegs = OhciExtension->OperationalRegs; 496 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 497 498 PortStatus.AsULONG = 0; 499 PortStatus.PortSuspendStatusChange = 1; 500 501 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 502 503 return MP_STATUS_SUCCESS; 504 } 505 506 MPSTATUS 507 NTAPI 508 OHCI_RH_ClearFeaturePortOvercurrentChange(IN PVOID ohciExtension, 509 IN USHORT Port) 510 { 511 POHCI_EXTENSION OhciExtension; 512 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 513 PULONG PortStatusReg; 514 PULONG RhStatusReg; 515 OHCI_REG_RH_PORT_STATUS PortStatus; 516 OHCI_REG_RH_STATUS RhStatus; 517 518 OhciExtension = ohciExtension; 519 520 DPRINT("OHCI_RH_ClearFeaturePortOvercurrentChange: OhciExtension - %p, Port - %x\n", 521 OhciExtension, 522 Port); 523 524 OperationalRegs = OhciExtension->OperationalRegs; 525 526 if (Port) 527 { 528 /* USBPORT_RECIPIENT_PORT */ 529 PortStatus.AsULONG = 0; 530 PortStatus.PortOverCurrentIndicatorChange = 1; 531 532 PortStatusReg = (PULONG)&OperationalRegs->HcRhPortStatus[Port-1]; 533 WRITE_REGISTER_ULONG(PortStatusReg, PortStatus.AsULONG); 534 } 535 else 536 { 537 /* USBPORT_RECIPIENT_HUB */ 538 RhStatus.AsULONG = 0; 539 RhStatus.OverCurrentIndicatorChangeW = 1; 540 541 RhStatusReg = (PULONG)&OperationalRegs->HcRhStatus; 542 WRITE_REGISTER_ULONG(RhStatusReg, RhStatus.AsULONG); 543 } 544 545 return MP_STATUS_SUCCESS; 546 } 547 548 VOID 549 NTAPI 550 OHCI_RH_DisableIrq(IN PVOID ohciExtension) 551 { 552 POHCI_EXTENSION OhciExtension = ohciExtension; 553 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 554 PULONG InterruptDisableReg; 555 OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptDisable; 556 557 DPRINT("OHCI_RH_DisableIrq: OhciExtension - %p\n", OhciExtension); 558 559 OperationalRegs = OhciExtension->OperationalRegs; 560 InterruptDisableReg = (PULONG)&OperationalRegs->HcInterruptDisable; 561 562 InterruptDisable.AsULONG = 0; 563 InterruptDisable.RootHubStatusChange = 1; 564 565 WRITE_REGISTER_ULONG(InterruptDisableReg, InterruptDisable.AsULONG); 566 } 567 568 VOID 569 NTAPI 570 OHCI_RH_EnableIrq(IN PVOID ohciExtension) 571 { 572 POHCI_EXTENSION OhciExtension = ohciExtension; 573 POHCI_OPERATIONAL_REGISTERS OperationalRegs; 574 PULONG InterruptEnableReg; 575 OHCI_REG_INTERRUPT_ENABLE_DISABLE InterruptEnable; 576 577 DPRINT("OHCI_RH_EnableIrq: OhciExtension - %p\n", OhciExtension); 578 579 OperationalRegs = OhciExtension->OperationalRegs; 580 InterruptEnableReg = (PULONG)&OperationalRegs->HcInterruptEnable; 581 582 InterruptEnable.AsULONG = 0; 583 InterruptEnable.RootHubStatusChange = 1; 584 585 WRITE_REGISTER_ULONG(InterruptEnableReg, InterruptEnable.AsULONG); 586 } 587