Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3608 lines
97 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. usbport.c
  5. Abstract:
  6. Port driver for USB host controllers
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. 6-20-99 : created
  12. --*/
  13. #include "common.h"
  14. // paged functions
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, USBPORT_QueryCapabilities)
  17. #pragma alloc_text(PAGE, USBPORT_CalculateUsbBandwidth)
  18. #pragma alloc_text(PAGE, USBPORT_ReadWriteConfigSpace)
  19. #pragma alloc_text(PAGE, USBPORT_ReadWriteConfigSpace)
  20. #pragma alloc_text(PAGE, USBPORT_InTextmodeSetup)
  21. #pragma alloc_text(PAGE, USBPORT_IsCompanionController)
  22. #pragma alloc_text(PAGE, USBPORT_GetHcFlavor)
  23. #pragma alloc_text(PAGE, USBPORT_ComputeAllocatedBandwidth)
  24. #endif
  25. // non paged functions
  26. // USBPORT_StopDevice
  27. // USBPORT_StartDevice
  28. // USBPORT_CompleteIrp
  29. // USBPORT_Dispatch
  30. // USBPORT_TrackPendingRequest
  31. // USBPORT_GetConfigValue
  32. // USBPORT_DeferIrpCompletion
  33. // USBPORT_AllocPool
  34. NTSTATUS
  35. DriverEntry(
  36. PDRIVER_OBJECT DriverObject,
  37. PUNICODE_STRING RegistryPath
  38. )
  39. /*++
  40. Routine Description:
  41. Installable driver initialization entry point.
  42. This entry point is called directly by the I/O system.
  43. Arguments:
  44. DriverObject - pointer to the driver object
  45. RegistryPath - pointer to a unicode string representing the path
  46. to driver-specific key in the registry
  47. Return Value:
  48. NT status code
  49. --*/
  50. {
  51. // BUGBUG
  52. // This function is never called
  53. return STATUS_SUCCESS;
  54. }
  55. NTSTATUS
  56. USBPORT_StopDevice(
  57. PDEVICE_OBJECT FdoDeviceObject,
  58. BOOLEAN HardwarePresent
  59. )
  60. /*++
  61. Routine Description:
  62. Stop the port and miniport
  63. Arguments:
  64. DeviceObject - DeviceObject of the controller to stop
  65. Return Value:
  66. NT status code.
  67. --*/
  68. {
  69. PDEVICE_EXTENSION devExt;
  70. ULONG deviceCount;
  71. BOOLEAN haveWork;
  72. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  73. ASSERT_FDOEXT(devExt);
  74. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'stpD', 0, 0, HardwarePresent);
  75. DEBUG_BREAK();
  76. USBPORT_FlushCahcedRegistryKeys(FdoDeviceObject);
  77. // the reoot hub and ALL devices should be 'stopped' at
  78. // this point. We should have no device handles in the
  79. // system, if we do these are orphaned and we need to
  80. // remove them now.
  81. deviceCount = USBPORT_GetDeviceCount(FdoDeviceObject);
  82. while (deviceCount != 0 ) {
  83. PUSBD_DEVICE_HANDLE zombieDeviceHandle;
  84. KIRQL irql;
  85. PLIST_ENTRY listEntry;
  86. USBPORT_KdPrint((0, "%d zombie device handles on STOP\n",
  87. deviceCount));
  88. KeAcquireSpinLock(&devExt->Fdo.DevHandleListSpin.sl, &irql);
  89. USBPORT_ASSERT(!IsListEmpty(&devExt->Fdo.DeviceHandleList));
  90. listEntry = devExt->Fdo.DeviceHandleList.Flink;
  91. zombieDeviceHandle = (PUSBD_DEVICE_HANDLE) CONTAINING_RECORD(
  92. listEntry,
  93. struct _USBD_DEVICE_HANDLE,
  94. ListEntry);
  95. ASSERT_DEVICE_HANDLE(zombieDeviceHandle)
  96. KeReleaseSpinLock(&devExt->Fdo.DevHandleListSpin.sl, irql);
  97. USBPORT_KdPrint((0, "deleting zombie handle %x\n",
  98. zombieDeviceHandle));
  99. DEBUG_BREAK();
  100. USBPORT_RemoveDevice(zombieDeviceHandle,
  101. FdoDeviceObject,
  102. 0);
  103. deviceCount = USBPORT_GetDeviceCount(FdoDeviceObject);
  104. }
  105. // make sure all lists are empty and all endpoints
  106. // are freed before terminating the worker thread
  107. do {
  108. KIRQL irql;
  109. haveWork = FALSE;
  110. KeAcquireSpinLock(&devExt->Fdo.EpClosedListSpin.sl, &irql);
  111. if (!IsListEmpty(&devExt->Fdo.EpClosedList)) {
  112. haveWork = TRUE;
  113. }
  114. KeReleaseSpinLock(&devExt->Fdo.EpClosedListSpin.sl, irql);
  115. KeAcquireSpinLock(&devExt->Fdo.EndpointListSpin.sl, &irql);
  116. if (!IsListEmpty(&devExt->Fdo.GlobalEndpointList)) {
  117. haveWork = TRUE;
  118. }
  119. KeReleaseSpinLock(&devExt->Fdo.EndpointListSpin.sl, irql);
  120. if (haveWork) {
  121. USBPORT_Wait(FdoDeviceObject, 10);
  122. }
  123. } while (haveWork);
  124. // all of our lists should be empty
  125. USBPORT_ASSERT(IsListEmpty(&devExt->Fdo.EpClosedList) == TRUE);
  126. USBPORT_ASSERT(IsListEmpty(&devExt->Fdo.MapTransferList) == TRUE);
  127. USBPORT_ASSERT(IsListEmpty(&devExt->Fdo.DoneTransferList) == TRUE);
  128. USBPORT_ASSERT(IsListEmpty(&devExt->Fdo.EpStateChangeList) == TRUE);
  129. USBPORT_ASSERT(IsListEmpty(&devExt->Fdo.EpClosedList) == TRUE);
  130. // kill our system thread
  131. USBPORT_TerminateWorkerThread(FdoDeviceObject);
  132. if (devExt->Fdo.MpStateFlags & MP_STATE_STARTED) {
  133. // stop the miniport, disable interrupts
  134. // if hw is not present then it can't be interrupting
  135. // now can it.
  136. if (HardwarePresent) {
  137. MP_DisableInterrupts(FdoDeviceObject, devExt);
  138. }
  139. devExt->Fdo.MpStateFlags &= ~MP_STATE_STARTED;
  140. MP_StopController(devExt, HardwarePresent);
  141. }
  142. // kill our deadman timer
  143. USBPORT_StopDM_Timer(FdoDeviceObject);
  144. // see if we have an interrupt
  145. // if so disconnect it
  146. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_CONNECTED)) {
  147. // fortunately this cannot fail
  148. IoDisconnectInterrupt(devExt->Fdo.InterruptObject);
  149. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'IOCd', 0, 0, 0);
  150. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_CONNECTED);
  151. }
  152. USBPORT_FreeIrpTable(FdoDeviceObject,
  153. devExt->PendingTransferIrpTable);
  154. USBPORT_FreeIrpTable(FdoDeviceObject,
  155. devExt->ActiveTransferIrpTable);
  156. // free any common buffer we allocated for the miniport
  157. if (devExt->Fdo.ControllerCommonBuffer != NULL) {
  158. USBPORT_HalFreeCommonBuffer(FdoDeviceObject,
  159. devExt->Fdo.ControllerCommonBuffer);
  160. devExt->Fdo.ControllerCommonBuffer = NULL;
  161. }
  162. if (devExt->Fdo.ScratchCommonBuffer != NULL) {
  163. USBPORT_HalFreeCommonBuffer(FdoDeviceObject,
  164. devExt->Fdo.ScratchCommonBuffer);
  165. devExt->Fdo.ScratchCommonBuffer = NULL;
  166. }
  167. if (devExt->Fdo.AdapterObject) {
  168. (devExt->Fdo.AdapterObject->DmaOperations->PutDmaAdapter)
  169. (devExt->Fdo.AdapterObject);
  170. devExt->Fdo.AdapterObject = NULL;
  171. }
  172. // delete the HCD symbolic link
  173. if (TEST_FLAG(devExt->Flags, USBPORT_FLAG_SYM_LINK)) {
  174. USBPORT_SymbolicLink(FALSE,
  175. devExt,
  176. devExt->Fdo.PhysicalDeviceObject,
  177. (LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER);
  178. }
  179. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_LEGACY_SYM_LINK)) {
  180. IoDeleteSymbolicLink(&devExt->Fdo.LegacyLinkUnicodeString);
  181. RtlFreeUnicodeString(&devExt->Fdo.LegacyLinkUnicodeString);
  182. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_LEGACY_SYM_LINK);
  183. }
  184. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_FDO_REGISTERED)) {
  185. if (USBPORT_IS_USB20(devExt)) {
  186. USBPORT_DeregisterUSB2fdo(FdoDeviceObject);
  187. } else {
  188. USBPORT_DeregisterUSB1fdo(FdoDeviceObject);
  189. }
  190. }
  191. // successful stop clears the 'started flag'
  192. CLEAR_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STARTED);
  193. return STATUS_SUCCESS;
  194. }
  195. NTSTATUS
  196. USBPORT_DeferIrpCompletion(
  197. PDEVICE_OBJECT DeviceObject,
  198. PIRP Irp,
  199. PVOID Context
  200. )
  201. /*++
  202. Routine Description:
  203. Arguments:
  204. Return Value:
  205. --*/
  206. {
  207. PKEVENT event = Context;
  208. KeSetEvent(event,
  209. 1,
  210. FALSE);
  211. return STATUS_MORE_PROCESSING_REQUIRED;
  212. }
  213. NTSTATUS
  214. USBPORT_QueryCapabilities(
  215. PDEVICE_OBJECT FdoDeviceObject,
  216. PDEVICE_CAPABILITIES DeviceCapabilities
  217. )
  218. /*++
  219. Routine Description:
  220. Arguments:
  221. Return Value:
  222. ntstatus
  223. --*/
  224. {
  225. PIO_STACK_LOCATION nextStack;
  226. PIRP irp;
  227. NTSTATUS ntStatus;
  228. KEVENT event;
  229. PDEVICE_EXTENSION devExt;
  230. PAGED_CODE();
  231. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  232. ASSERT_FDOEXT(devExt);
  233. // init the caps structure before calldown
  234. RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  235. DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  236. DeviceCapabilities->Version = 1;
  237. DeviceCapabilities->Address = -1;
  238. DeviceCapabilities->UINumber = -1;
  239. irp =
  240. IoAllocateIrp(devExt->Fdo.TopOfStackDeviceObject->StackSize, FALSE);
  241. if (!irp) {
  242. USBPORT_KdPrint((1, "failed to allocate Irp\n"));
  243. DEBUG_BREAK();
  244. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  245. } else {
  246. // All PnP IRP's need the Status field initialized
  247. // to STATUS_NOT_SUPPORTED before calldown
  248. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  249. nextStack = IoGetNextIrpStackLocation(irp);
  250. USBPORT_ASSERT(nextStack != NULL);
  251. nextStack->MajorFunction = IRP_MJ_PNP;
  252. nextStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  253. KeInitializeEvent(&event, NotificationEvent, FALSE);
  254. IoSetCompletionRoutine(irp,
  255. USBPORT_DeferIrpCompletion,
  256. &event,
  257. TRUE,
  258. TRUE,
  259. TRUE);
  260. nextStack->Parameters.DeviceCapabilities.Capabilities =
  261. DeviceCapabilities;
  262. ntStatus = IoCallDriver(devExt->Fdo.TopOfStackDeviceObject,
  263. irp);
  264. if (ntStatus == STATUS_PENDING) {
  265. // wait for irp to complete
  266. KeWaitForSingleObject(
  267. &event,
  268. Suspended,
  269. KernelMode,
  270. FALSE,
  271. NULL);
  272. ntStatus = irp->IoStatus.Status;
  273. }
  274. }
  275. IoFreeIrp(irp);
  276. return ntStatus;
  277. }
  278. NTSTATUS
  279. USBPORT_StartDevice(
  280. PDEVICE_OBJECT FdoDeviceObject,
  281. PHC_RESOURCES HcResources
  282. )
  283. /*++
  284. Routine Description:
  285. Stop the port and miiport
  286. Arguments:
  287. DeviceObject - DeviceObject of the controller to stop
  288. Return Value:
  289. NT status code.
  290. --*/
  291. {
  292. PDEVICE_EXTENSION devExt;
  293. NTSTATUS ntStatus = STATUS_SUCCESS;
  294. USB_MINIPORT_STATUS mpStatus;
  295. DEVICE_DESCRIPTION deviceDescription;
  296. ULONG mpOptionFlags, i, legsup;
  297. ULONG globalDisableSS = 0;
  298. ULONG globalDisableCCDetect = 0;
  299. ULONG enIdleEndpointSupport = 0;
  300. ULONG hactionFlag;
  301. ULONG tmpLength;
  302. BOOLEAN isCC;
  303. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'SRT>', FdoDeviceObject, 0, 0);
  304. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  305. ASSERT_FDOEXT(devExt);
  306. //
  307. // hardcoded initialization, not failable
  308. //
  309. USBPORT_InitializeSpinLock(&devExt->Fdo.CoreFunctionSpin, 'CRS+', 'CRS-');
  310. USBPORT_InitializeSpinLock(&devExt->Fdo.MapTransferSpin, 'MPS+', 'MPS-');
  311. USBPORT_InitializeSpinLock(&devExt->Fdo.DoneTransferSpin, 'DNS+', 'DNS-');
  312. KeInitializeSpinLock(&devExt->Fdo.EndpointListSpin.sl);
  313. KeInitializeSpinLock(&devExt->Fdo.EpStateChangeListSpin.sl);
  314. KeInitializeSpinLock(&devExt->Fdo.EpClosedListSpin.sl);
  315. KeInitializeSpinLock(&devExt->Fdo.TtEndpointListSpin.sl);
  316. KeInitializeSpinLock(&devExt->Fdo.DevHandleListSpin.sl);
  317. KeInitializeSpinLock(&devExt->Fdo.HcSyncSpin.sl);
  318. KeInitializeSpinLock(&devExt->Fdo.RootHubSpin.sl);
  319. KeInitializeSpinLock(&devExt->Fdo.WorkerThreadSpin.sl);
  320. KeInitializeSpinLock(&devExt->Fdo.PowerSpin.sl);
  321. KeInitializeSpinLock(&devExt->Fdo.DM_TimerSpin.sl);
  322. KeInitializeSpinLock(&devExt->Fdo.PendingIrpSpin.sl);
  323. KeInitializeSpinLock(&devExt->Fdo.WakeIrpSpin.sl);
  324. KeInitializeSpinLock(&devExt->Fdo.IdleIrpSpin.sl);
  325. KeInitializeSpinLock(&devExt->Fdo.BadRequestSpin.sl);
  326. KeInitializeSpinLock(&devExt->Fdo.IsrDpcSpin.sl);
  327. USBPORT_InitializeSpinLock(&devExt->Fdo.ActiveTransferIrpSpin, 'ALS+', 'ALS-');
  328. KeInitializeSpinLock(&devExt->Fdo.PendingTransferIrpSpin.sl);
  329. KeInitializeSpinLock(&devExt->Fdo.StatCounterSpin.sl);
  330. KeInitializeSpinLock(&devExt->Fdo.HcPendingWakeIrpSpin.sl);
  331. devExt->Fdo.LastSystemSleepState = PowerSystemUnspecified;
  332. devExt->Fdo.HcWakeState = HCWAKESTATE_DISARMED;
  333. // this event will be signalled when the wake irp completes
  334. KeInitializeEvent(&devExt->Fdo.HcPendingWakeIrpEvent,
  335. NotificationEvent, TRUE);
  336. devExt->Fdo.BadReqFlushThrottle = 0;
  337. switch(USBPORT_DetectOSVersion(FdoDeviceObject)) {
  338. case Win2K:
  339. // need a long delay for win2k hidclass
  340. USBPORT_KdPrint((0, "We are running on Win2k!\n"));
  341. devExt->Fdo.BadReqFlushThrottle = 5;
  342. globalDisableSS = 1;
  343. }
  344. devExt->PendingTransferIrpTable = NULL;
  345. devExt->ActiveTransferIrpTable = NULL;
  346. // Always start with the default address (0) assigned.
  347. // Address array has one bit for every address 0..127
  348. devExt->Fdo.AddressList[0] = 1;
  349. devExt->Fdo.AddressList[1] =
  350. devExt->Fdo.AddressList[2] =
  351. devExt->Fdo.AddressList[3] = 0;
  352. KeInitializeDpc(&devExt->Fdo.TransferFlushDpc,
  353. USBPORT_TransferFlushDpc,
  354. FdoDeviceObject);
  355. KeInitializeDpc(&devExt->Fdo.SurpriseRemoveDpc,
  356. USBPORT_SurpriseRemoveDpc,
  357. FdoDeviceObject);
  358. KeInitializeDpc(&devExt->Fdo.HcResetDpc,
  359. USBPORT_HcResetDpc,
  360. FdoDeviceObject);
  361. KeInitializeDpc(&devExt->Fdo.HcWakeDpc,
  362. USBPORT_HcWakeDpc,
  363. FdoDeviceObject);
  364. KeInitializeDpc(&devExt->Fdo.IsrDpc,
  365. USBPORT_IsrDpc,
  366. FdoDeviceObject);
  367. devExt->Fdo.DmaBusy = -1;
  368. devExt->Fdo.WorkerDpc = -1;
  369. // set up adapter object
  370. RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
  371. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  372. deviceDescription.Master = TRUE;
  373. deviceDescription.ScatterGather = TRUE;
  374. deviceDescription.Dma32BitAddresses = TRUE;
  375. deviceDescription.InterfaceType = PCIBus;
  376. deviceDescription.DmaWidth = Width32Bits;
  377. deviceDescription.DmaSpeed = Compatible;
  378. deviceDescription.MaximumLength = (ULONG)-1;
  379. devExt->Fdo.NumberOfMapRegisters = (ULONG)-1;
  380. devExt->Fdo.AdapterObject = NULL;
  381. // miniport common buffer
  382. devExt->Fdo.ControllerCommonBuffer = NULL;
  383. // fetch the global BIOS hacks from the registry
  384. USBPORT_GetDefaultBIOS_X(FdoDeviceObject,
  385. &devExt->Fdo.BiosX,
  386. &globalDisableSS,
  387. &globalDisableCCDetect,
  388. &enIdleEndpointSupport);
  389. if (globalDisableSS) {
  390. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_DISABLE_SS);
  391. }
  392. // check reg for SS flag, note that miniport can
  393. // stil override
  394. if (USBPORT_SelectiveSuspendEnabled(FdoDeviceObject) &&
  395. !globalDisableSS) {
  396. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_RH_CAN_SUSPEND);
  397. }
  398. //
  399. // failable initailization
  400. //
  401. // make sure we got all the resources we need
  402. // note that we check here becuase problems may occurr
  403. // if we attempt to connect the interrupt without all
  404. // the necessary resources
  405. mpOptionFlags = REGISTRATION_PACKET(devExt).OptionFlags;
  406. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'mpOP',
  407. mpOptionFlags, 0, HcResources->Flags);
  408. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_POLL_CONTROLLER)) {
  409. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_POLL_CONTROLLER);
  410. }
  411. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_POLL_IN_SUSPEND)) {
  412. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_POLL_IN_SUSPEND);
  413. }
  414. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NO_SS)) {
  415. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_RH_CAN_SUSPEND);
  416. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_DISABLE_SS);
  417. }
  418. // make sure we got an IRQ
  419. if ( (mpOptionFlags & USB_MINIPORT_OPT_NEED_IRQ) &&
  420. !(HcResources->Flags & HCR_IRQ)) {
  421. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  422. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'noIQ', 0, 0, 0);
  423. goto USBPORT_StartDevice_Done;
  424. }
  425. if ( (mpOptionFlags & USB_MINIPORT_OPT_NEED_IOPORT) &&
  426. !(HcResources->Flags & HCR_IO_REGS)) {
  427. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  428. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'noRG', 0, 0, 0);
  429. goto USBPORT_StartDevice_Done;
  430. }
  431. if ( (mpOptionFlags & USB_MINIPORT_OPT_NEED_MEMORY) &&
  432. !(HcResources->Flags & HCR_MEM_REGS)) {
  433. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  434. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'noMM', 0, 0, 0);
  435. goto USBPORT_StartDevice_Done;
  436. }
  437. // simulates a failry common scenario where PnP gives us
  438. // the wrong resources.
  439. TEST_PATH(ntStatus, FAILED_NEED_RESOURCE);
  440. if (!NT_SUCCESS(ntStatus)) {
  441. goto USBPORT_StartDevice_Done;
  442. }
  443. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NO_PNP_RESOURCES)) {
  444. TEST_TRAP();
  445. devExt->Fdo.PciVendorId = 0;
  446. devExt->Fdo.PciDeviceId = 0;
  447. devExt->Fdo.PciRevisionId = 0;
  448. devExt->Fdo.PciClass = 0;
  449. devExt->Fdo.PciSubClass = 0;
  450. devExt->Fdo.PciProgIf = 0;
  451. } else {
  452. // fetch the Dev Prod and Rev IDs from config space
  453. ULONG ClassCodeRev;
  454. ntStatus = USBPORT_ReadConfigSpace(
  455. FdoDeviceObject,
  456. &devExt->Fdo.PciVendorId,
  457. 0,
  458. sizeof(devExt->Fdo.PciVendorId));
  459. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Gvid',
  460. devExt->Fdo.PciVendorId, 0, ntStatus);
  461. if (!NT_SUCCESS(ntStatus)) {
  462. goto USBPORT_StartDevice_Done;
  463. }
  464. ntStatus = USBPORT_ReadConfigSpace(
  465. FdoDeviceObject,
  466. &devExt->Fdo.PciDeviceId,
  467. 2,
  468. sizeof(devExt->Fdo.PciDeviceId));
  469. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Gdid',
  470. devExt->Fdo.PciDeviceId, 0, ntStatus);
  471. if (!NT_SUCCESS(ntStatus)) {
  472. goto USBPORT_StartDevice_Done;
  473. }
  474. ntStatus = USBPORT_ReadConfigSpace(
  475. FdoDeviceObject,
  476. &ClassCodeRev,
  477. 8,
  478. sizeof(ClassCodeRev));
  479. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Grev',
  480. ClassCodeRev, 0, ntStatus);
  481. if (!NT_SUCCESS(ntStatus)) {
  482. goto USBPORT_StartDevice_Done;
  483. }
  484. devExt->Fdo.PciRevisionId = (UCHAR)ClassCodeRev;
  485. devExt->Fdo.PciClass = (UCHAR)(ClassCodeRev >> 24);
  486. devExt->Fdo.PciSubClass = (UCHAR)(ClassCodeRev >> 16);
  487. devExt->Fdo.PciProgIf = (UCHAR)(ClassCodeRev >> 8);
  488. USBPORT_ASSERT(devExt->Fdo.PciClass == PCI_CLASS_SERIAL_BUS_CTLR);
  489. USBPORT_ASSERT(devExt->Fdo.PciSubClass == PCI_SUBCLASS_SB_USB);
  490. USBPORT_ASSERT(devExt->Fdo.PciProgIf == 0x00 ||
  491. devExt->Fdo.PciProgIf == 0x10 ||
  492. devExt->Fdo.PciProgIf == 0x20);
  493. }
  494. USBPORT_KdPrint((1, "USB Controller VID %x DEV %x REV %x\n",
  495. devExt->Fdo.PciVendorId,
  496. devExt->Fdo.PciDeviceId,
  497. devExt->Fdo.PciRevisionId));
  498. // set the HW flavor so that the miniports and possibly
  499. // the port know what hacks to do to make the controller
  500. // be good.
  501. HcResources->ControllerFlavor =
  502. devExt->Fdo.HcFlavor =
  503. USBPORT_GetHcFlavor(FdoDeviceObject,
  504. devExt->Fdo.PciVendorId,
  505. devExt->Fdo.PciDeviceId,
  506. devExt->Fdo.PciRevisionId);
  507. // check for Fredbhs global idle endpoint support, if the global key is set
  508. // the write the instanced key
  509. USBPORT_KdPrint((1, "Idle Endpoint Support %d%x\n",enIdleEndpointSupport));
  510. USBPORT_SetRegistryKeyValueForPdo(devExt->Fdo.PhysicalDeviceObject,
  511. USBPORT_SW_BRANCH,
  512. REG_DWORD,
  513. EN_IDLE_ENDPOINT_SUPPORT,
  514. sizeof(EN_IDLE_ENDPOINT_SUPPORT),
  515. &enIdleEndpointSupport,
  516. sizeof(enIdleEndpointSupport));
  517. //
  518. // If this is an OHCI or UHCI controller check if it is a companion
  519. // controller.
  520. //
  521. if ((devExt->Fdo.PciClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
  522. (devExt->Fdo.PciSubClass == PCI_SUBCLASS_SB_USB) &&
  523. (devExt->Fdo.PciProgIf < 0x20) &&
  524. NT_SUCCESS(USBPORT_IsCompanionController(FdoDeviceObject, &isCC)))
  525. {
  526. if (isCC)
  527. {
  528. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC);
  529. }
  530. else
  531. {
  532. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC);
  533. }
  534. }
  535. /* global flag overrides registry settings from inf and
  536. any hard coded detection
  537. */
  538. if (globalDisableCCDetect) {
  539. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC);
  540. }
  541. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC))
  542. {
  543. USBPORT_KdPrint((1,"Is CC %04X %04X %02X %02X %02X %02X\n",
  544. devExt->Fdo.PciVendorId,
  545. devExt->Fdo.PciDeviceId,
  546. devExt->Fdo.PciRevisionId,
  547. devExt->Fdo.PciClass,
  548. devExt->Fdo.PciSubClass,
  549. devExt->Fdo.PciProgIf
  550. ));
  551. }
  552. else
  553. {
  554. USBPORT_KdPrint((1,"Is not CC %04X %04X %02X %02X %02X %02X\n",
  555. devExt->Fdo.PciVendorId,
  556. devExt->Fdo.PciDeviceId,
  557. devExt->Fdo.PciRevisionId,
  558. devExt->Fdo.PciClass,
  559. devExt->Fdo.PciSubClass,
  560. devExt->Fdo.PciProgIf
  561. ));
  562. }
  563. // detect companion controller by registry method
  564. if (USBPORT_GetRegistryKeyValueForPdo(devExt->HcFdoDeviceObject,
  565. devExt->Fdo.PhysicalDeviceObject,
  566. USBPORT_HW_BRANCH,
  567. HACTION_KEY,
  568. sizeof(HACTION_KEY),
  569. &hactionFlag,
  570. sizeof(hactionFlag)) != STATUS_SUCCESS) {
  571. // default is to NO_WAIT on HC if no key is found, UNLESS
  572. // textmode setup is currently running.
  573. //
  574. // note: the goatpack default is to wait
  575. if (USBPORT_InTextmodeSetup())
  576. {
  577. USBPORT_KdPrint((1, "Textmode Setup Detected: hactionFlag=1\n"));
  578. hactionFlag = 1;
  579. }
  580. else
  581. {
  582. USBPORT_KdPrint((1, "Textmode Setup Not Detected: hactionFlag=0\n"));
  583. hactionFlag = 0;
  584. }
  585. }
  586. if (hactionFlag == 0 ) {
  587. USBPORT_KdPrint((1, "Detected HACTION 0 -- OK to enumerate\n"));
  588. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_CC_ENUM_OK);
  589. }
  590. devExt->Fdo.TotalBusBandwidth =
  591. REGISTRATION_PACKET(devExt).BusBandwidth;
  592. // allow a registry override of the total BW for
  593. // this bus
  594. {
  595. ULONG busBandwidth = devExt->Fdo.TotalBusBandwidth;
  596. USBPORT_GetRegistryKeyValueForPdo(devExt->HcFdoDeviceObject,
  597. devExt->Fdo.PhysicalDeviceObject,
  598. USBPORT_SW_BRANCH,
  599. BW_KEY,
  600. sizeof(BW_KEY),
  601. &busBandwidth,
  602. sizeof(busBandwidth));
  603. if (busBandwidth != devExt->Fdo.TotalBusBandwidth) {
  604. USBPORT_KdPrint((0, "Warning: Registry Override of bus bandwidth\n"));
  605. devExt->Fdo.TotalBusBandwidth = busBandwidth;
  606. }
  607. }
  608. // init the bandwidth table
  609. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  610. devExt->Fdo.BandwidthTable[i]
  611. = devExt->Fdo.TotalBusBandwidth -
  612. devExt->Fdo.TotalBusBandwidth/10;
  613. }
  614. // allocate internal irp tracking tables
  615. ALLOC_POOL_Z(devExt->PendingTransferIrpTable, NonPagedPool,
  616. sizeof(USBPORT_IRP_TABLE));
  617. ALLOC_POOL_Z(devExt->ActiveTransferIrpTable, NonPagedPool,
  618. sizeof(USBPORT_IRP_TABLE));
  619. if (devExt->PendingTransferIrpTable == NULL ||
  620. devExt->ActiveTransferIrpTable == NULL) {
  621. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  622. goto USBPORT_StartDevice_Done;
  623. }
  624. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'irpT',
  625. devExt->PendingTransferIrpTable,
  626. devExt->ActiveTransferIrpTable, 0);
  627. ntStatus = USBPORT_CreateWorkerThread(FdoDeviceObject);
  628. if (!NT_SUCCESS(ntStatus)) {
  629. goto USBPORT_StartDevice_Done;
  630. }
  631. // query our device caps from the PDO and save them
  632. ntStatus =
  633. USBPORT_QueryCapabilities(FdoDeviceObject,
  634. &devExt->DeviceCapabilities);
  635. if (!NT_SUCCESS(ntStatus)) {
  636. goto USBPORT_StartDevice_Done;
  637. }
  638. ntStatus = IoGetDeviceProperty(devExt->Fdo.PhysicalDeviceObject,
  639. DevicePropertyBusNumber,
  640. sizeof(devExt->Fdo.BusNumber),
  641. &devExt->Fdo.BusNumber,
  642. &tmpLength);
  643. if (!NT_SUCCESS(ntStatus)) {
  644. goto USBPORT_StartDevice_Done;
  645. }
  646. // extract device and function number from the caps
  647. devExt->Fdo.BusDevice = devExt->DeviceCapabilities.Address>>16;
  648. devExt->Fdo.BusFunction = devExt->DeviceCapabilities.Address & 0x0000ffff;
  649. USBPORT_KdPrint((1, "'BUS %x, device %x, function %x\n",
  650. devExt->Fdo.BusNumber, devExt->Fdo.BusDevice, devExt->Fdo.BusFunction));
  651. if (!NT_SUCCESS(ntStatus)) {
  652. goto USBPORT_StartDevice_Done;
  653. }
  654. // this will modify the DeviceCaps reported by the BIOS
  655. USBPORT_ApplyBIOS_X(FdoDeviceObject,
  656. &devExt->DeviceCapabilities,
  657. devExt->Fdo.BiosX);
  658. // got the capabilities, compute the power state table
  659. USBPORT_ComputeHcPowerStates(
  660. FdoDeviceObject,
  661. &devExt->DeviceCapabilities,
  662. &devExt->Fdo.HcPowerStateTbl);
  663. //
  664. // Create our adapter object for a standard USB PCI adapter
  665. //
  666. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NO_PNP_RESOURCES)) {
  667. devExt->Fdo.AdapterObject = NULL;
  668. } else {
  669. devExt->Fdo.AdapterObject =
  670. IoGetDmaAdapter(devExt->Fdo.PhysicalDeviceObject,
  671. &deviceDescription,
  672. &devExt->Fdo.NumberOfMapRegisters);
  673. if (devExt->Fdo.AdapterObject == NULL) {
  674. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  675. goto USBPORT_StartDevice_Done;
  676. }
  677. }
  678. // see if we have an interrupt
  679. if (HcResources->Flags & HCR_IRQ) {
  680. ntStatus = IoConnectInterrupt(
  681. &devExt->Fdo.InterruptObject,
  682. (PKSERVICE_ROUTINE) USBPORT_InterruptService,
  683. (PVOID) FdoDeviceObject,
  684. (PKSPIN_LOCK)NULL,
  685. HcResources->InterruptVector,
  686. HcResources->InterruptLevel,
  687. HcResources->InterruptLevel,
  688. HcResources->InterruptMode,
  689. HcResources->ShareIRQ,
  690. HcResources->Affinity,
  691. FALSE); // BUGBUG FloatingSave, this is configurable
  692. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'IOCi', 0, 0, ntStatus);
  693. if (NT_SUCCESS(ntStatus)) {
  694. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_CONNECTED);
  695. } else {
  696. goto USBPORT_StartDevice_Done;
  697. }
  698. }
  699. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NO_PNP_RESOURCES)) {
  700. REGISTRATION_PACKET(devExt).CommonBufferBytes = 0;
  701. }
  702. if (REGISTRATION_PACKET(devExt).CommonBufferBytes) {
  703. PUSBPORT_COMMON_BUFFER commonBuffer;
  704. ULONG bytesNeeded =
  705. REGISTRATION_PACKET(devExt).CommonBufferBytes;
  706. commonBuffer =
  707. USBPORT_HalAllocateCommonBuffer(FdoDeviceObject,
  708. bytesNeeded);
  709. if (commonBuffer == NULL) {
  710. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  711. goto USBPORT_StartDevice_Done;
  712. } else {
  713. devExt->Fdo.ControllerCommonBuffer = commonBuffer;
  714. HcResources->CommonBufferVa =
  715. commonBuffer->MiniportVa;
  716. HcResources->CommonBufferPhys =
  717. commonBuffer->MiniportPhys;
  718. }
  719. // allocate some scratch space
  720. bytesNeeded = USB_PAGE_SIZE - sizeof(USBPORT_COMMON_BUFFER);
  721. commonBuffer =
  722. USBPORT_HalAllocateCommonBuffer(FdoDeviceObject,
  723. bytesNeeded);
  724. if (commonBuffer == NULL) {
  725. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  726. goto USBPORT_StartDevice_Done;
  727. } else {
  728. devExt->Fdo.ScratchCommonBuffer = commonBuffer;
  729. }
  730. } else {
  731. // no common buffer for this controller
  732. devExt->Fdo.ControllerCommonBuffer = NULL;
  733. }
  734. // zero the controller extension
  735. RtlZeroMemory(devExt->Fdo.MiniportDeviceData,
  736. devExt->Fdo.MiniportDriver->RegistrationPacket.DeviceDataSize);
  737. // attempt to start the miniport
  738. USBPORT_FlushCahcedRegistryKeys(FdoDeviceObject);
  739. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_ON_PNP_THREAD);
  740. MP_StartController(devExt, HcResources, mpStatus);
  741. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_ON_PNP_THREAD);
  742. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'mpST', mpStatus, 0, 0);
  743. if (HcResources->DetectedLegacyBIOS) {
  744. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_LEGACY_BIOS);
  745. legsup = 1;
  746. } else {
  747. legsup = 0;
  748. }
  749. USBPORT_SetRegistryKeyValueForPdo(
  750. devExt->Fdo.PhysicalDeviceObject,
  751. USBPORT_HW_BRANCH,
  752. REG_DWORD,
  753. SYM_LEGSUP_KEY,
  754. sizeof(SYM_LEGSUP_KEY),
  755. &legsup,
  756. sizeof(legsup));
  757. // since common buff signature is at the end this will detect if
  758. // the miniport overwrites the allocated block
  759. #if DBG
  760. if (devExt->Fdo.ControllerCommonBuffer != NULL) {
  761. ASSERT_COMMON_BUFFER(devExt->Fdo.ControllerCommonBuffer);
  762. }
  763. #endif
  764. if (mpStatus == USBMP_STATUS_SUCCESS) {
  765. // controller started, set flag and begin passing
  766. // interrupts to the miniport
  767. SET_FLAG(devExt->Fdo.MpStateFlags, MP_STATE_STARTED);
  768. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'eIRQ', mpStatus, 0, 0);
  769. MP_EnableInterrupts(devExt);
  770. } else {
  771. // error occured, disconnect interrupt now
  772. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_CONNECTED)) {
  773. IoDisconnectInterrupt(devExt->Fdo.InterruptObject);
  774. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_CONNECTED);
  775. }
  776. // free memory resources
  777. if (devExt->Fdo.ControllerCommonBuffer != NULL) {
  778. USBPORT_HalFreeCommonBuffer(FdoDeviceObject,
  779. devExt->Fdo.ControllerCommonBuffer);
  780. devExt->Fdo.ControllerCommonBuffer = NULL;
  781. }
  782. }
  783. ntStatus = MPSTATUS_TO_NTSTATUS(mpStatus);
  784. // placing the faiure here simulates a failure from
  785. // some point above. We won't start the DM timer unless
  786. // everything succeeds
  787. TEST_PATH(ntStatus, FAILED_USBPORT_START);
  788. // start up the 'DEADMAN' timer
  789. if (NT_SUCCESS(ntStatus)) {
  790. devExt->Fdo.DM_TimerInterval = USBPORT_DM_TIMER_INTERVAL;
  791. USBPORT_StartDM_Timer(FdoDeviceObject,
  792. USBPORT_DM_TIMER_INTERVAL);
  793. }
  794. // create symbolic links for user mode
  795. if (NT_SUCCESS(ntStatus)) {
  796. // create the link based on guid for USB 2.0
  797. ntStatus = USBPORT_CreatePortFdoSymbolicLink(FdoDeviceObject);
  798. }
  799. if (NT_SUCCESS(ntStatus)) {
  800. // create the legacy link only for USB 1.1 controllers
  801. //
  802. // BUGBUG
  803. // Failure to create the legacy link will not keep the
  804. // driver from loading.
  805. // This fails during text mode setup if you still have the
  806. // UHCD loaded, we can remove this when UHCD is completely
  807. // out of the build.
  808. // ntStatus =
  809. USBPORT_CreateLegacyFdoSymbolicLink(FdoDeviceObject);
  810. }
  811. USBPORT_StartDevice_Done:
  812. if (!NT_SUCCESS(ntStatus)) {
  813. // stop_device will(should) cleanup for us
  814. USBPORT_KdPrint((0, "'Start Device Failed (status %08.8x)\n", ntStatus));
  815. DEBUG_BREAK();
  816. // since we won't be marked 'started' call stop here
  817. // to cleanup a failed start
  818. USBPORT_StopDevice(FdoDeviceObject,
  819. TRUE);
  820. } else {
  821. // enable system wake support
  822. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_ENABLE_SYSTEM_WAKE);
  823. }
  824. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'SRT<', ntStatus, 0, 0);
  825. return ntStatus;
  826. }
  827. NTSTATUS
  828. USBPORT_PassIrp(
  829. PDEVICE_OBJECT DeviceObject,
  830. PIO_COMPLETION_ROUTINE CompletionRoutine,
  831. PVOID Context,
  832. BOOLEAN InvokeOnSuccess,
  833. BOOLEAN InvokeOnError,
  834. BOOLEAN InvokeOnCancel,
  835. PIRP Irp
  836. )
  837. /*++
  838. Routine Description:
  839. Passes an irp to the next lower driver,
  840. this is done by the FDO for all PnP Irps
  841. Arguments:
  842. Return Value:
  843. --*/
  844. {
  845. PDEVICE_EXTENSION devExt;
  846. NTSTATUS ntStatus;
  847. GET_DEVICE_EXT(devExt, DeviceObject);
  848. ASSERT_FDOEXT(devExt);
  849. // note that we do not dec the pending request count
  850. // if we set a completion routine.
  851. // We do not want to 'go away' before the completion
  852. // routine is called.
  853. if (CompletionRoutine) {
  854. IoCopyCurrentIrpStackLocationToNext(Irp);
  855. IoSetCompletionRoutine(Irp,
  856. CompletionRoutine,
  857. Context,
  858. InvokeOnSuccess,
  859. InvokeOnError,
  860. InvokeOnCancel);
  861. } else {
  862. IoSkipCurrentIrpStackLocation(Irp);
  863. DECREMENT_PENDING_REQUEST_COUNT(DeviceObject, Irp);
  864. }
  865. ntStatus = IoCallDriver(devExt->Fdo.TopOfStackDeviceObject, Irp);
  866. return ntStatus;
  867. }
  868. VOID
  869. USBPORT_CompleteIrp(
  870. PDEVICE_OBJECT DeviceObject,
  871. PIRP Irp,
  872. NTSTATUS ntStatus,
  873. ULONG_PTR Information
  874. )
  875. /*++
  876. Routine Description:
  877. Completes an I/O Request
  878. Arguments:
  879. Return Value:
  880. --*/
  881. {
  882. USBPORT_KdPrint((2, "'USBPORT_CompleteIrp status = %x\n", ntStatus));
  883. DECREMENT_PENDING_REQUEST_COUNT(DeviceObject, Irp);
  884. Irp->IoStatus.Status = ntStatus;
  885. Irp->IoStatus.Information = Information;
  886. // LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'irpC', Irp, DeviceObject, Urb);
  887. IoCompleteRequest(Irp,
  888. IO_NO_INCREMENT);
  889. }
  890. NTSTATUS
  891. USBPORT_Dispatch(
  892. PDEVICE_OBJECT DeviceObject,
  893. PIRP Irp
  894. )
  895. /*++
  896. Routine Description:
  897. Process the IRPs sent to this device.
  898. Arguments:
  899. DeviceObject - pointer to a device object
  900. Irp - pointer to an I/O Request Packet
  901. Return Value:
  902. NT status code
  903. --*/
  904. {
  905. PIO_STACK_LOCATION irpStack;
  906. NTSTATUS ntStatus = STATUS_SUCCESS;
  907. PDEVICE_EXTENSION devExt;
  908. BOOLEAN forRootHubPdo = FALSE;
  909. KIRQL irql;
  910. USBPORT_KdPrint((2, "'enter USBPORT_Dispatch\n"));
  911. GET_DEVICE_EXT(devExt, DeviceObject);
  912. irpStack = IoGetCurrentIrpStackLocation (Irp);
  913. USBPORT_KdPrint((2, "'USBPORT_Dispatch IRP = %x, stack = %x (func) %x %x\n",
  914. Irp, irpStack, irpStack->MajorFunction, irpStack->MinorFunction));
  915. // figure out if this is the FDO for the HC or the PDO
  916. // for the root hub
  917. if (devExt->Sig == ROOTHUB_DEVICE_EXT_SIG) {
  918. forRootHubPdo = TRUE;
  919. USBPORT_KdPrint((2, "'IRP->PDO\n"));
  920. } else if (devExt->Sig == USBPORT_DEVICE_EXT_SIG) {
  921. forRootHubPdo = FALSE;
  922. USBPORT_KdPrint((2, "'IRP->FDO\n"));
  923. } else {
  924. // this is a bug, bugcheck
  925. USBPORT_ASSERT(FALSE);
  926. }
  927. // *BEGIN SPECIAL CASE
  928. // Before doing anything see if this devobj is 'removed'
  929. // if so do some 'special' handling
  930. KeAcquireSpinLock(&devExt->PendingRequestSpin.sl, &irql);
  931. if (TEST_FLAG(devExt->PnpStateFlags, USBPORT_PNP_REMOVED)) {
  932. // someone has managed to call us after the remove
  933. USBPORT_KdPrint((1, "'(irp after remove) IRP = %x, DO %x MJx%x MNx%x\n",
  934. Irp, DeviceObject, irpStack->MajorFunction,
  935. irpStack->MinorFunction));
  936. KeReleaseSpinLock(&devExt->PendingRequestSpin.sl, irql);
  937. if (forRootHubPdo) {
  938. switch(irpStack->MajorFunction) {
  939. // in the removed state complete all power irps with
  940. // success, this happens if you suspend with the root
  941. // hub disbaled
  942. case IRP_MJ_POWER:
  943. Irp->IoStatus.Status = ntStatus = STATUS_SUCCESS;
  944. PoStartNextPowerIrp(Irp);
  945. IoCompleteRequest(Irp,
  946. IO_NO_INCREMENT);
  947. goto USBPORT_Dispatch_Done;
  948. // since the root hub pdo exists even when the device
  949. // is removed by PnP we still allow irps thru
  950. default:
  951. break;
  952. }
  953. } else {
  954. switch(irpStack->MajorFunction) {
  955. // allow PnP irps even though we are removed
  956. case IRP_MJ_PNP:
  957. break;
  958. case IRP_MJ_POWER:
  959. TEST_TRAP();
  960. Irp->IoStatus.Status = ntStatus = STATUS_DEVICE_REMOVED;
  961. PoStartNextPowerIrp(Irp);
  962. IoCompleteRequest(Irp,
  963. IO_NO_INCREMENT);
  964. goto USBPORT_Dispatch_Done;
  965. default:
  966. Irp->IoStatus.Status = ntStatus = STATUS_DEVICE_REMOVED;
  967. IoCompleteRequest(Irp,
  968. IO_NO_INCREMENT);
  969. goto USBPORT_Dispatch_Done;
  970. }
  971. }
  972. } else {
  973. KeReleaseSpinLock(&devExt->PendingRequestSpin.sl, irql);
  974. }
  975. // *END SPECIAL CASE
  976. INCREMENT_PENDING_REQUEST_COUNT(DeviceObject, Irp);
  977. switch (irpStack->MajorFunction) {
  978. case IRP_MJ_CREATE:
  979. USBPORT_KdPrint((2, "'IRP_MJ_CREATE\n"));
  980. USBPORT_CompleteIrp(DeviceObject, Irp, ntStatus, 0);
  981. break;
  982. case IRP_MJ_CLOSE:
  983. USBPORT_KdPrint((2, "'IRP_MJ_CLOSE\n"));
  984. USBPORT_CompleteIrp(DeviceObject, Irp, ntStatus, 0);
  985. break;
  986. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  987. USBPORT_KdPrint((2, "'IRP_MJ_NTERNAL_DEVICE_CONTROL\n"));
  988. if (forRootHubPdo) {
  989. ntStatus = USBPORT_PdoInternalDeviceControlIrp(DeviceObject, Irp);
  990. } else {
  991. ntStatus = USBPORT_FdoInternalDeviceControlIrp(DeviceObject, Irp);
  992. }
  993. break;
  994. case IRP_MJ_DEVICE_CONTROL:
  995. USBPORT_KdPrint((2, "'IRP_MJ_DEVICE_CONTROL\n"));
  996. if (forRootHubPdo) {
  997. ntStatus = USBPORT_PdoDeviceControlIrp(DeviceObject, Irp);
  998. } else {
  999. ntStatus = USBPORT_FdoDeviceControlIrp(DeviceObject, Irp);
  1000. }
  1001. break;
  1002. case IRP_MJ_POWER:
  1003. if (forRootHubPdo) {
  1004. ntStatus = USBPORT_PdoPowerIrp(DeviceObject, Irp);
  1005. } else {
  1006. ntStatus = USBPORT_FdoPowerIrp(DeviceObject, Irp);
  1007. }
  1008. break;
  1009. case IRP_MJ_PNP:
  1010. if (forRootHubPdo) {
  1011. ntStatus = USBPORT_PdoPnPIrp(DeviceObject, Irp);
  1012. } else {
  1013. ntStatus = USBPORT_FdoPnPIrp(DeviceObject, Irp);
  1014. }
  1015. break;
  1016. case IRP_MJ_SYSTEM_CONTROL:
  1017. if (forRootHubPdo) {
  1018. USBPORT_KdPrint((2, "'IRP_MJ_SYSTEM_CONTROL\n"));
  1019. ntStatus = Irp->IoStatus.Status;
  1020. USBPORT_CompleteIrp(DeviceObject, Irp, ntStatus, 0);
  1021. } else {
  1022. USBPORT_KdPrint((2, "'IRP_MJ_SYSTEM_CONTROL\n"));
  1023. //
  1024. // pass on to our PDO
  1025. //
  1026. ntStatus =
  1027. USBPORT_PassIrp(DeviceObject,
  1028. NULL,
  1029. NULL,
  1030. TRUE,
  1031. TRUE,
  1032. TRUE,
  1033. Irp);
  1034. }
  1035. break;
  1036. default:
  1037. USBPORT_KdPrint((2, "'unrecognized IRP_MJ_ function (%x)\n", irpStack->MajorFunction));
  1038. ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1039. USBPORT_CompleteIrp(DeviceObject, Irp, ntStatus, 0);
  1040. } /* case MJ_FUNCTION */
  1041. USBPORT_KdPrint((2, "'exit USBPORT_Dispatch 0x%x\n", ntStatus));
  1042. USBPORT_Dispatch_Done:
  1043. return ntStatus;
  1044. }
  1045. VOID
  1046. USBPORT_TrackPendingRequest(
  1047. PDEVICE_OBJECT DeviceObject,
  1048. PIRP Irp,
  1049. BOOLEAN AddToList
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. Keep track of Irps sent to our DevObjs
  1054. Arguments:
  1055. Return Value:
  1056. --*/
  1057. {
  1058. PDEVICE_EXTENSION devExt;
  1059. KIRQL irql;
  1060. GET_DEVICE_EXT(devExt, DeviceObject);
  1061. if (AddToList) {
  1062. KeAcquireSpinLock(&devExt->PendingRequestSpin.sl, &irql);
  1063. // -1 to 0 means we are starting, initialize the event
  1064. if (devExt->PendingRequestCount == -1) {
  1065. KeInitializeEvent(&devExt->PendingRequestEvent,
  1066. NotificationEvent,
  1067. FALSE);
  1068. }
  1069. USBPORT_KdPrint((4, "'INC pending Request(%x) %d\n",
  1070. devExt, devExt->PendingRequestCount));
  1071. devExt->PendingRequestCount++;
  1072. // the following is debug only code
  1073. #ifdef TRACK_IRPS
  1074. if (Irp != NULL) {
  1075. PTRACK_IRP trackIrp;
  1076. PLIST_ENTRY listEntry;
  1077. listEntry = devExt->TrackIrpList.Flink;
  1078. while (listEntry != &devExt->TrackIrpList) {
  1079. trackIrp = (PTRACK_IRP) CONTAINING_RECORD(
  1080. listEntry,
  1081. struct _TRACK_IRP,
  1082. ListEntry);
  1083. if (trackIrp->Irp == Irp) {
  1084. USBPORT_KdPrint((0, " IRP %x already pending\n",
  1085. Irp));
  1086. BUGCHECK();
  1087. }
  1088. listEntry = trackIrp->ListEntry.Flink;
  1089. }
  1090. ALLOC_POOL_Z(trackIrp,
  1091. NonPagedPool,
  1092. sizeof(*trackIrp));
  1093. USBPORT_ASSERT(trackIrp != NULL);
  1094. if (trackIrp != NULL) {
  1095. trackIrp->Irp = Irp;
  1096. InsertTailList(&devExt->TrackIrpList,
  1097. &trackIrp->ListEntry);
  1098. }
  1099. }
  1100. #endif
  1101. KeReleaseSpinLock(&devExt->PendingRequestSpin.sl, irql);
  1102. } else {
  1103. KeAcquireSpinLock(&devExt->PendingRequestSpin.sl, &irql);
  1104. USBPORT_KdPrint((4, "'DEC pending Request(%x) %d\n",
  1105. devExt, devExt->PendingRequestCount));
  1106. #ifdef TRACK_IRPS
  1107. if (Irp != NULL) {
  1108. PTRACK_IRP trackIrp;
  1109. PLIST_ENTRY listEntry;
  1110. listEntry = devExt->TrackIrpList.Flink;
  1111. while (listEntry != &devExt->TrackIrpList) {
  1112. trackIrp = (PTRACK_IRP) CONTAINING_RECORD(
  1113. listEntry,
  1114. struct _TRACK_IRP,
  1115. ListEntry);
  1116. if (trackIrp->Irp == Irp) {
  1117. goto found_irp;
  1118. }
  1119. listEntry = trackIrp->ListEntry.Flink;
  1120. }
  1121. trackIrp = NULL;
  1122. found_irp:
  1123. if (trackIrp == NULL) {
  1124. USBPORT_KdPrint((0, " Pending IRP %x not found\n",
  1125. Irp));
  1126. BUGCHECK();
  1127. }
  1128. RemoveEntryList(&trackIrp->ListEntry);
  1129. FREE_POOL(NULL, trackIrp);
  1130. }
  1131. #endif
  1132. devExt->PendingRequestCount--;
  1133. // 0 -> -1 indicates we have no more pending io
  1134. // signal the event
  1135. if (devExt->PendingRequestCount == -1) {
  1136. KeSetEvent(&devExt->PendingRequestEvent,
  1137. 1,
  1138. FALSE);
  1139. }
  1140. KeReleaseSpinLock(&devExt->PendingRequestSpin.sl, irql);
  1141. }
  1142. }
  1143. NTSTATUS
  1144. USBPORT_GetConfigValue(
  1145. PWSTR ValueName,
  1146. ULONG ValueType,
  1147. PVOID ValueData,
  1148. ULONG ValueLength,
  1149. PVOID Context,
  1150. PVOID EntryContext
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. This routine is a callback routine for RtlQueryRegistryValues
  1155. It is called for each entry in the Parameters
  1156. node to set the config values. The table is set up
  1157. so that this function will be called with correct default
  1158. values for keys that are not present.
  1159. Arguments:
  1160. ValueName - The name of the value (ignored).
  1161. ValueType - The type of the value
  1162. ValueData - The data for the value.
  1163. ValueLength - The length of ValueData.
  1164. Context - A pointer to the CONFIG structure.
  1165. EntryContext - The index in Config->Parameters to save the value.
  1166. Return Value:
  1167. --*/
  1168. {
  1169. NTSTATUS ntStatus = STATUS_SUCCESS;
  1170. USBPORT_KdPrint((2, "'Type 0x%x, Length 0x%x\n", ValueType, ValueLength));
  1171. switch (ValueType) {
  1172. case REG_DWORD:
  1173. RtlCopyMemory(EntryContext, ValueData, sizeof(ULONG));
  1174. break;
  1175. case REG_BINARY:
  1176. // BUGBUG we are only set up to read a byte
  1177. RtlCopyMemory(EntryContext, ValueData, 1);
  1178. break;
  1179. default:
  1180. ntStatus = STATUS_INVALID_PARAMETER;
  1181. }
  1182. return ntStatus;
  1183. }
  1184. VOID
  1185. USBPORT_Wait(
  1186. PDEVICE_OBJECT FdoDeviceObject,
  1187. ULONG Milliseconds
  1188. )
  1189. /*++
  1190. Routine Description:
  1191. Synchrounously wait the specified number of miliseconds
  1192. Return Value:
  1193. None
  1194. --*/
  1195. {
  1196. LONG time;
  1197. ULONG timerIncerent;
  1198. LARGE_INTEGER time64;
  1199. USBPORT_KdPrint((2,"'Wait for %d ms\n", Milliseconds));
  1200. //
  1201. // work only when LowPart is not overflown.
  1202. //
  1203. USBPORT_ASSERT(21474 > Milliseconds);
  1204. //
  1205. // wait MilliSeconds( 10000 100ns unit)
  1206. //
  1207. timerIncerent = KeQueryTimeIncrement() - 1;
  1208. // round up to the next highest timer increment
  1209. time = -1 * (MILLISECONDS_TO_100_NS_UNITS(Milliseconds) + timerIncerent);
  1210. time64 = RtlConvertLongToLargeInteger(time),
  1211. KeDelayExecutionThread(KernelMode, FALSE, &time64);
  1212. USBPORT_KdPrint((2,"'Wait done\n"));
  1213. return;
  1214. }
  1215. ULONG
  1216. USBPORT_CalculateUsbBandwidth(
  1217. PDEVICE_OBJECT FdoDeviceObject,
  1218. PHCD_ENDPOINT Endpoint
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. Computes the bandwidth that must be reserved for a
  1223. given endpoint
  1224. Arguments:
  1225. Return Value:
  1226. banwidth required in bits/ms, returns 0 for bulk
  1227. and control endpoints
  1228. --*/
  1229. {
  1230. ULONG bw;
  1231. ULONG overhead;
  1232. ULONG maxPacketSize;
  1233. BOOLEAN lowSpeed = FALSE;
  1234. #define USB_ISO_OVERHEAD_BYTES 9
  1235. #define USB_INTERRUPT_OVERHEAD_BYTES 13
  1236. PAGED_CODE();
  1237. ASSERT_ENDPOINT(Endpoint);
  1238. maxPacketSize = Endpoint->Parameters.MaxPacketSize;
  1239. if (Endpoint->Parameters.DeviceSpeed == LowSpeed) {
  1240. lowSpeed = TRUE;
  1241. }
  1242. //
  1243. // control, iso, bulk, interrupt
  1244. //
  1245. switch(Endpoint->Parameters.TransferType) {
  1246. case Bulk:
  1247. case Control:
  1248. overhead = 0;
  1249. break;
  1250. case Isochronous:
  1251. overhead = USB_ISO_OVERHEAD_BYTES;
  1252. break;
  1253. case Interrupt:
  1254. overhead = USB_INTERRUPT_OVERHEAD_BYTES;
  1255. break;
  1256. }
  1257. //
  1258. // Calculate bandwidth for endpoint. We will use the
  1259. // approximation: (overhead bytes plus MaxPacket bytes)
  1260. // times 8 bits/byte times worst case bitstuffing overhead.
  1261. // This gives bit times, for low speed endpoints we multiply
  1262. // by 8 again to convert to full speed bits.
  1263. //
  1264. //
  1265. // Figure out how many bits are required for the transfer.
  1266. // (multiply by 7/6 because, in the worst case you might
  1267. // have a bit-stuff every six bits requiring 7 bit times to
  1268. // transmit 6 bits of data.)
  1269. //
  1270. // overhead(bytes) * maxpacket(bytes/ms) * 8
  1271. // (bits/byte) * bitstuff(7/6) = bits/ms
  1272. bw = ((overhead+maxPacketSize) * 8 * 7) / 6;
  1273. // return zero for control or bulk
  1274. if (!overhead) {
  1275. bw = 0;
  1276. }
  1277. if (lowSpeed) {
  1278. bw *= 8;
  1279. }
  1280. return bw;
  1281. }
  1282. VOID
  1283. USBPORT_UpdateAllocatedBw(
  1284. PDEVICE_OBJECT FdoDeviceObject
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. Arguments:
  1289. Return Value:
  1290. --*/
  1291. {
  1292. PDEVICE_EXTENSION devExt;
  1293. ULONG alloced_bw, i, m;
  1294. PAGED_CODE();
  1295. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1296. ASSERT_FDOEXT(devExt);
  1297. m = 0;
  1298. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  1299. alloced_bw = devExt->Fdo.TotalBusBandwidth -
  1300. devExt->Fdo.BandwidthTable[i];
  1301. if (alloced_bw > m) {
  1302. m = alloced_bw;
  1303. }
  1304. }
  1305. devExt->Fdo.MaxAllocedBw = m;
  1306. m = devExt->Fdo.TotalBusBandwidth;
  1307. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  1308. alloced_bw = devExt->Fdo.TotalBusBandwidth -
  1309. devExt->Fdo.BandwidthTable[i];
  1310. if (alloced_bw < m) {
  1311. m = alloced_bw;
  1312. }
  1313. }
  1314. devExt->Fdo.MinAllocedBw = m;
  1315. if (m == devExt->Fdo.TotalBusBandwidth) {
  1316. devExt->Fdo.MinAllocedBw = 0;
  1317. }
  1318. }
  1319. VOID
  1320. USBPORT_UpdateAllocatedBwTt(
  1321. PTRANSACTION_TRANSLATOR Tt
  1322. )
  1323. /*++
  1324. Routine Description:
  1325. This function and the one above it should be merged
  1326. Arguments:
  1327. Return Value:
  1328. --*/
  1329. {
  1330. ULONG alloced_bw, i, m;
  1331. m = 0;
  1332. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  1333. alloced_bw = Tt->TotalBusBandwidth -
  1334. Tt->BandwidthTable[i];
  1335. if (alloced_bw > m) {
  1336. m = alloced_bw;
  1337. }
  1338. }
  1339. Tt->MaxAllocedBw = m;
  1340. m = Tt->TotalBusBandwidth;
  1341. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  1342. alloced_bw = Tt->TotalBusBandwidth -
  1343. Tt->BandwidthTable[i];
  1344. if (alloced_bw < m) {
  1345. m = alloced_bw;
  1346. }
  1347. }
  1348. Tt->MinAllocedBw = m;
  1349. if (m == Tt->TotalBusBandwidth) {
  1350. Tt->MinAllocedBw = 0;
  1351. }
  1352. }
  1353. BOOLEAN
  1354. USBPORT_AllocateBandwidthUSB11(
  1355. PDEVICE_OBJECT FdoDeviceObject,
  1356. PHCD_ENDPOINT Endpoint
  1357. )
  1358. /*++
  1359. Routine Description:
  1360. Computes the best schedule offset for this endpoint
  1361. and allocates the bandwidth.
  1362. Offsets in the bw allocation table orrespond to the values
  1363. in the following tree structure.
  1364. The schedule offset is the best possible posoition for the
  1365. endpoint to reside in the schedule based on its period.
  1366. for 32 ms or mf ep there are 32 possible positions
  1367. for 16 there are 16
  1368. for 8 there are 8
  1369. ...
  1370. fr <32> <16> <08> <04> <02> <01>
  1371. 0 ( 0) -\
  1372. ( 0)-\
  1373. 16 ( 1) -/ \
  1374. ( 0)-\
  1375. 8 ( 2) -\ / \
  1376. ( 1)-/ \
  1377. 24 ( 3) -/ \
  1378. (0)-\
  1379. 4 ( 4) -\ / \
  1380. ( 2)-\ / \
  1381. 20 ( 5) -/ \ / \
  1382. ( 1)-/ \
  1383. 12 ( 6) -\ / \
  1384. ( 3)-/ \
  1385. 28 ( 7) -/ \
  1386. (0)-\
  1387. 2 ( 8) -\ / \
  1388. ( 4)-\ / \
  1389. 18 ( 9) -/ \ / \
  1390. ( 2)-\ / \
  1391. 10 (10) -\ / \ / \
  1392. ( 5)-/ \ / \
  1393. 26 (11) -/ \ / \
  1394. (1)-/ \
  1395. 6 (12) -\ / \
  1396. ( 6)-\ / \
  1397. 22 (13) -/ \ / \
  1398. ( 3)-/ \
  1399. 14 (14) -\ / \
  1400. ( 7)-/ \
  1401. 30 (15) -/ \
  1402. (0)
  1403. 1 (16) -\ /
  1404. ( 8)-\ /
  1405. 17 (17) -/ \ /
  1406. ( 4)-\ /
  1407. 9 (18) -\ / \ /
  1408. ( 9)-/ \ /
  1409. 25 (19) -/ \ /
  1410. (2)-\ /
  1411. 5 (20) -\ / \ /
  1412. (10)-\ / \ /
  1413. 21 (21) -/ \ / \ /
  1414. ( 5)-/ \ /
  1415. 13 (22) -\ / \ /
  1416. (11)-/ \ /
  1417. 29 (23) -/ \ /
  1418. (1)-/
  1419. 3 (24) -\ /
  1420. (12)-\ /
  1421. 19 (25) -/ \ /
  1422. ( 6)-\ /
  1423. 11 (26) -\ / \ /
  1424. (13)-/ \ /
  1425. 27 (27) -/ \ /
  1426. (3)-/
  1427. 7 (28) -\ /
  1428. (14)-\ /
  1429. 23 (29) -/ \ /
  1430. ( 7)-/
  1431. 15 (30) -\ /
  1432. (15)-/
  1433. 31 (32) -/
  1434. Allocations:
  1435. period.offset table entries
  1436. 1 0, 1, 2.........31
  1437. 2.0 0, 1, 2.........15
  1438. 2.1 16,17,18.........31
  1439. 4.0 0, 1, 2..........7
  1440. 4.1 8, 9,10.........15
  1441. 4.2 16,17,18.........23
  1442. 4.3 24,25,26.........31
  1443. 8.0 0, 1, 2, 3
  1444. 8.1 4, 5, 6, 7
  1445. 8.2 8, 9,10,11
  1446. 8.3 12,13,14,15
  1447. 8.4 16,17,18,19
  1448. 8.5 20,21,22,23
  1449. 8.6 24,25,26,27
  1450. 8.7 28,29,30,31
  1451. ...
  1452. frame nodes visited (period.offset)
  1453. 0 32.0 16.0 8.0 4.0 2.0
  1454. 1 32.16 16.8 8.4 4.2 2.1
  1455. 2 32.8 16.4 8.2 4.1 2.0
  1456. 3 32.24 16.12 8.6 4.3 2.1
  1457. 4 32.4 16.2 8.1 4.0 2.0
  1458. 5 32.20 16.10 8.5 4.2 2.1
  1459. 6 32.12 16.6 8.3 4.1 2.0
  1460. 7 32.28 16.14 8.7 4.3 2.1
  1461. ...
  1462. all miniports should maintain a 32 entry table for
  1463. interrupt endpoints, the lower 5 bits of the current
  1464. frame are used as an index in to this table. see the
  1465. above graph for index to frame mappings
  1466. Arguments:
  1467. Return Value:
  1468. FALSE if no bandwidth availble
  1469. --*/
  1470. {
  1471. PDEVICE_EXTENSION devExt;
  1472. ULONG period, bandwidth, scheduleOffset, i;
  1473. ULONG bestFitBW, min, n;
  1474. LONG bestScheduleOffset;
  1475. BOOLEAN willFit;
  1476. PAGED_CODE();
  1477. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1478. ASSERT_FDOEXT(devExt);
  1479. ASSERT_ENDPOINT(Endpoint);
  1480. if (Endpoint->Parameters.TransferType == Bulk ||
  1481. Endpoint->Parameters.TransferType == Control ||
  1482. TEST_FLAG(Endpoint->Flags, EPFLAG_ROOTHUB)) {
  1483. // control/bulk come out of our standard 10%
  1484. // and root hub endpoints consume no BW
  1485. Endpoint->Parameters.ScheduleOffset = 0;
  1486. return TRUE;
  1487. }
  1488. // Iso and interrupt -- iso is just like interrupt with
  1489. // a period of 1
  1490. // see if we can fit it
  1491. scheduleOffset = 0;
  1492. period = Endpoint->Parameters.Period;
  1493. USBPORT_ASSERT(period != 0);
  1494. bandwidth = Endpoint->Parameters.Bandwidth;
  1495. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'rqBW', scheduleOffset,
  1496. bandwidth, Endpoint);
  1497. // The bandwidth table conatins the bw avaialble for all
  1498. // possible schedule offsets up to the max polling interval
  1499. // we support.
  1500. bestFitBW = 0;
  1501. bestScheduleOffset = -1;
  1502. // scan all possible offsets and select the 'best fit'
  1503. // our goal here is to position the ep in the location
  1504. // with the most free bw
  1505. do {
  1506. // assume it will fit
  1507. willFit = TRUE;
  1508. min = devExt->Fdo.TotalBusBandwidth;
  1509. n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
  1510. for (i=0; i<n; i++) {
  1511. if (devExt->Fdo.BandwidthTable[n*scheduleOffset+i] < bandwidth) {
  1512. willFit = FALSE;
  1513. break;
  1514. }
  1515. // set min to the lowest free entry for this
  1516. // offset
  1517. if (min > devExt->Fdo.BandwidthTable[n*scheduleOffset+i]) {
  1518. min = devExt->Fdo.BandwidthTable[n*scheduleOffset+i];
  1519. }
  1520. }
  1521. if (willFit && min > bestFitBW) {
  1522. // it will fit compare this to the we have found
  1523. bestFitBW = min;
  1524. bestScheduleOffset = scheduleOffset;
  1525. }
  1526. scheduleOffset++;
  1527. } while (scheduleOffset < period);
  1528. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'ckBW', bestScheduleOffset,
  1529. bandwidth, period);
  1530. if (bestScheduleOffset != -1) {
  1531. scheduleOffset = bestScheduleOffset;
  1532. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'alBW', scheduleOffset,
  1533. bandwidth, period);
  1534. // we found an offset that will work for the
  1535. // given period, alloc the bw and return the
  1536. // offset
  1537. Endpoint->Parameters.ScheduleOffset =
  1538. scheduleOffset;
  1539. n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
  1540. for (i=0; i<n; i++) {
  1541. USBPORT_ASSERT(n*scheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
  1542. USBPORT_ASSERT(devExt->Fdo.BandwidthTable[n*scheduleOffset+i] >= bandwidth);
  1543. devExt->Fdo.BandwidthTable[n*scheduleOffset+i] -= bandwidth;
  1544. }
  1545. // update our bw tracking info
  1546. if (Endpoint->Parameters.TransferType == Isochronous) {
  1547. devExt->Fdo.AllocedIsoBW += bandwidth;
  1548. } else {
  1549. USBPORT_GET_BIT_SET(period, n);
  1550. USBPORT_ASSERT(n<6);
  1551. devExt->Fdo.AllocedInterruptBW[n] += bandwidth;
  1552. }
  1553. }
  1554. USBPORT_UpdateAllocatedBw(FdoDeviceObject);
  1555. return bestScheduleOffset == -1 ? FALSE : TRUE;
  1556. }
  1557. VOID
  1558. USBPORT_FreeBandwidthUSB11(
  1559. PDEVICE_OBJECT FdoDeviceObject,
  1560. PHCD_ENDPOINT Endpoint
  1561. )
  1562. /*++
  1563. Routine Description:
  1564. Frees the bw reserved for a give endpoint
  1565. Arguments:
  1566. Return Value:
  1567. FALSE if no bandwidth availble
  1568. --*/
  1569. {
  1570. PDEVICE_EXTENSION devExt;
  1571. ULONG period, bandwidth, scheduleOffset, i, n;
  1572. PAGED_CODE();
  1573. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1574. ASSERT_FDOEXT(devExt);
  1575. ASSERT_ENDPOINT(Endpoint);
  1576. if (Endpoint->Parameters.TransferType == Bulk ||
  1577. Endpoint->Parameters.TransferType == Control ||
  1578. TEST_FLAG(Endpoint->Flags, EPFLAG_ROOTHUB)) {
  1579. // these come out of our standard 10%
  1580. return;
  1581. }
  1582. scheduleOffset = Endpoint->Parameters.ScheduleOffset;
  1583. bandwidth = Endpoint->Parameters.Bandwidth;
  1584. period = Endpoint->Parameters.Period;
  1585. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'frBW', scheduleOffset, bandwidth, period);
  1586. n = USBPORT_MAX_INTEP_POLLING_INTERVAL/period;
  1587. for (i=0; i<n; i++) {
  1588. USBPORT_ASSERT(n*scheduleOffset+i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
  1589. devExt->Fdo.BandwidthTable[n*scheduleOffset+i] += bandwidth;
  1590. }
  1591. //for (i=sheduleOffset; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i+=period) {
  1592. // USBPORT_ASSERT(i < USBPORT_MAX_INTEP_POLLING_INTERVAL);
  1593. // devExt->Fdo.BandwidthTable[i] += bandwidth;
  1594. //}
  1595. // update our bw tracking info
  1596. if (Endpoint->Parameters.TransferType == Isochronous) {
  1597. devExt->Fdo.AllocedIsoBW -= bandwidth;
  1598. } else {
  1599. USBPORT_GET_BIT_SET(period, n);
  1600. USBPORT_ASSERT(n<6);
  1601. devExt->Fdo.AllocedInterruptBW[n] -= bandwidth;
  1602. }
  1603. // update max allocated BW
  1604. USBPORT_UpdateAllocatedBw(FdoDeviceObject);
  1605. return;
  1606. }
  1607. NTSTATUS
  1608. USBPORT_ReadWriteConfigSpace(
  1609. PDEVICE_OBJECT FdoDeviceObject,
  1610. BOOLEAN Read,
  1611. PVOID Buffer,
  1612. ULONG Offset,
  1613. ULONG Length
  1614. )
  1615. /*++
  1616. Routine Description:
  1617. This routine reads or writes config space.
  1618. Arguments:
  1619. DeviceObject - .
  1620. Read - TRUE if read, FALSE if write.
  1621. Buffer - The info to read or write.
  1622. Offset - The offset in config space to read or write.
  1623. Length - The length to transfer.
  1624. Return Value:
  1625. NTSTATUS
  1626. --*/
  1627. {
  1628. PIO_STACK_LOCATION nextStack;
  1629. PIRP irp;
  1630. NTSTATUS ntStatus;
  1631. KEVENT event;
  1632. PDEVICE_OBJECT deviceObject;
  1633. PDEVICE_EXTENSION devExt;
  1634. PAGED_CODE();
  1635. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1636. ASSERT_FDOEXT(devExt);
  1637. deviceObject = devExt->Fdo.PhysicalDeviceObject;
  1638. if (Read) {
  1639. RtlZeroMemory(Buffer, Length);
  1640. }
  1641. irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
  1642. if (irp == NULL) {
  1643. return STATUS_INSUFFICIENT_RESOURCES;
  1644. }
  1645. // All PnP IRP's need the Status field initialized to STATUS_NOT_SUPPORTED.
  1646. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1647. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1648. IoSetCompletionRoutine(irp,
  1649. USBPORT_DeferIrpCompletion,
  1650. &event,
  1651. TRUE,
  1652. TRUE,
  1653. TRUE);
  1654. nextStack = IoGetNextIrpStackLocation(irp);
  1655. USBPORT_ASSERT(nextStack != NULL);
  1656. nextStack->MajorFunction= IRP_MJ_PNP;
  1657. nextStack->MinorFunction= Read ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG;
  1658. nextStack->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
  1659. nextStack->Parameters.ReadWriteConfig.Buffer = Buffer;
  1660. nextStack->Parameters.ReadWriteConfig.Offset = Offset;
  1661. nextStack->Parameters.ReadWriteConfig.Length = Length;
  1662. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'rwC>', 0, 0, 0);
  1663. ntStatus = IoCallDriver(deviceObject,
  1664. irp);
  1665. if (ntStatus == STATUS_PENDING) {
  1666. // wait for irp to complete
  1667. KeWaitForSingleObject(
  1668. &event,
  1669. Suspended,
  1670. KernelMode,
  1671. FALSE,
  1672. NULL);
  1673. ntStatus = irp->IoStatus.Status;
  1674. }
  1675. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'rwC<', 0, 0, ntStatus);
  1676. IoFreeIrp(irp);
  1677. return ntStatus;
  1678. }
  1679. VOID
  1680. USBPORTSVC_Wait(
  1681. PDEVICE_DATA DeviceData,
  1682. ULONG MillisecondsToWait
  1683. )
  1684. /*++
  1685. Routine Description:
  1686. Arguments:
  1687. Return Value:
  1688. None.
  1689. --*/
  1690. {
  1691. PDEVICE_EXTENSION devExt;
  1692. PDEVICE_OBJECT fdoDeviceObject;
  1693. DEVEXT_FROM_DEVDATA(devExt, DeviceData);
  1694. ASSERT_FDOEXT(devExt);
  1695. fdoDeviceObject = devExt->HcFdoDeviceObject;
  1696. USBPORT_Wait(fdoDeviceObject, MillisecondsToWait);
  1697. }
  1698. VOID
  1699. USBPORT_InvalidateController(
  1700. PDEVICE_OBJECT FdoDeviceObject,
  1701. USB_CONTROLLER_STATE ControllerState
  1702. )
  1703. /*++
  1704. Routine Description:
  1705. Arguments:
  1706. Return Value:
  1707. None.
  1708. --*/
  1709. {
  1710. PDEVICE_EXTENSION devExt;
  1711. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1712. ASSERT_FDOEXT(devExt);
  1713. switch(ControllerState) {
  1714. case UsbMpControllerPowerFault:
  1715. USBPORT_PowerFault(FdoDeviceObject,
  1716. "Miniport Raised Exception");
  1717. break;
  1718. case UsbMpControllerNeedsHwReset:
  1719. USBPORT_KdPrint((1,"'<UsbMpControllerNeedsHwReset>\n"));
  1720. if (KeInsertQueueDpc(&devExt->Fdo.HcResetDpc, 0, 0)) {
  1721. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_HW_RESET_PENDING);
  1722. INCREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, NULL);
  1723. }
  1724. break;
  1725. case UsbMpControllerRemoved:
  1726. // set our flag indicating the controller has been
  1727. // removed and signal the worker thread.
  1728. USBPORT_KdPrint((1,"'<UsbMpControllerRemoved>\n"));
  1729. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_CONTROLLER_GONE);
  1730. if (KeInsertQueueDpc(&devExt->Fdo.SurpriseRemoveDpc, 0, 0)) {
  1731. INCREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, NULL);
  1732. }
  1733. break;
  1734. case UsbMpSimulateInterrupt:
  1735. // queue the ISR DPC as if we got a hardware interrupt
  1736. KeInsertQueueDpc(&devExt->Fdo.IsrDpc,
  1737. NULL,
  1738. NULL);
  1739. break;
  1740. default:
  1741. TEST_TRAP();
  1742. }
  1743. }
  1744. VOID
  1745. USBPORTSVC_InvalidateController(
  1746. PDEVICE_DATA DeviceData,
  1747. USB_CONTROLLER_STATE ControllerState
  1748. )
  1749. /*++
  1750. Routine Description:
  1751. Arguments:
  1752. Return Value:
  1753. None.
  1754. --*/
  1755. {
  1756. PDEVICE_EXTENSION devExt;
  1757. PDEVICE_OBJECT fdoDeviceObject;
  1758. DEVEXT_FROM_DEVDATA(devExt, DeviceData);
  1759. ASSERT_FDOEXT(devExt);
  1760. fdoDeviceObject = devExt->HcFdoDeviceObject;
  1761. USBPORT_InvalidateController(fdoDeviceObject, ControllerState);
  1762. }
  1763. VOID
  1764. USBPORT_HcResetDpc(
  1765. PKDPC Dpc,
  1766. PVOID DeferredContext,
  1767. PVOID SystemArgument1,
  1768. PVOID SystemArgument2
  1769. )
  1770. /*++
  1771. Routine Description:
  1772. This routine runs at DISPATCH_LEVEL IRQL.
  1773. Arguments:
  1774. Dpc - Pointer to the DPC object.
  1775. DeferredContext - supplies FdoDeviceObject.
  1776. SystemArgument1 - not used.
  1777. SystemArgument2 - not used.
  1778. Return Value:
  1779. None.
  1780. --*/
  1781. {
  1782. PDEVICE_OBJECT fdoDeviceObject = DeferredContext;
  1783. PDEVICE_EXTENSION devExt;
  1784. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1785. ASSERT_FDOEXT(devExt);
  1786. devExt->Fdo.StatHardResetCount++;
  1787. // allow Dr. Slick to work his magic on the ohci controller
  1788. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_HW_RESET_PENDING);
  1789. // core lock is held here so that we don't poll the
  1790. // controler endpoints while we reset
  1791. MP_ResetController(devExt);
  1792. DECREMENT_PENDING_REQUEST_COUNT(fdoDeviceObject, NULL);
  1793. }
  1794. VOID
  1795. USBPORT_SurpriseRemoveDpc(
  1796. PKDPC Dpc,
  1797. PVOID DeferredContext,
  1798. PVOID SystemArgument1,
  1799. PVOID SystemArgument2
  1800. )
  1801. /*++
  1802. Routine Description:
  1803. This routine runs at DISPATCH_LEVEL IRQL.
  1804. Arguments:
  1805. Dpc - Pointer to the DPC object.
  1806. DeferredContext - supplies FdoDeviceObject.
  1807. SystemArgument1 - not used.
  1808. SystemArgument2 - not used.
  1809. Return Value:
  1810. None.
  1811. --*/
  1812. {
  1813. PDEVICE_OBJECT fdoDeviceObject = DeferredContext;
  1814. PDEVICE_EXTENSION devExt;
  1815. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1816. ASSERT_FDOEXT(devExt);
  1817. USBPORT_NukeAllEndpoints(fdoDeviceObject);
  1818. DECREMENT_PENDING_REQUEST_COUNT(fdoDeviceObject, NULL);
  1819. }
  1820. VOID
  1821. USBPORTSVC_BugCheck(
  1822. PDEVICE_DATA DeviceData
  1823. )
  1824. /*++
  1825. Routine Description:
  1826. Arguments:
  1827. Return Value:
  1828. None.
  1829. --*/
  1830. {
  1831. PDEVICE_EXTENSION devExt;
  1832. PDEVICE_OBJECT fdoDeviceObject;
  1833. ULONG vidDev;
  1834. ULONG ilog;
  1835. PLOG_ENTRY lelog;
  1836. DEVEXT_FROM_DEVDATA(devExt, DeviceData);
  1837. ASSERT_FDOEXT(devExt);
  1838. fdoDeviceObject = devExt->HcFdoDeviceObject;
  1839. vidDev = devExt->Fdo.PciVendorId;
  1840. vidDev <<=16;
  1841. vidDev |= devExt->Fdo.PciDeviceId;
  1842. ilog &= devExt->Log.LogSizeMask;
  1843. lelog = devExt->Log.LogStart+ilog;
  1844. BUGCHECK(USBBUGCODE_MINIPORT_ERROR, vidDev, (ULONG_PTR)lelog, 0);
  1845. }
  1846. USB_MINIPORT_STATUS
  1847. USBPORTSVC_ReadWriteConfigSpace(
  1848. PDEVICE_DATA DeviceData,
  1849. BOOLEAN Read,
  1850. PVOID Buffer,
  1851. ULONG Offset,
  1852. ULONG Length
  1853. )
  1854. /*++
  1855. Routine Description:
  1856. Service Exported to miniports for accessing config
  1857. spzce if needed. This service is synchronous and cannot
  1858. be called at raised IRQL
  1859. USBUHCI uses this service to clear set the PIRQD bit which
  1860. enables/disables the controller.
  1861. Arguments:
  1862. Return Value:
  1863. None.
  1864. --*/
  1865. {
  1866. NTSTATUS ntStatus;
  1867. PDEVICE_EXTENSION devExt;
  1868. PDEVICE_OBJECT fdoDeviceObject;
  1869. DEVEXT_FROM_DEVDATA(devExt, DeviceData);
  1870. ASSERT_FDOEXT(devExt);
  1871. fdoDeviceObject = devExt->HcFdoDeviceObject;
  1872. ntStatus = USBPORT_ReadWriteConfigSpace(
  1873. fdoDeviceObject,
  1874. Read,
  1875. Buffer,
  1876. Offset,
  1877. Length);
  1878. return USBPORT_NtStatus_TO_MiniportStatus(ntStatus);
  1879. }
  1880. BOOLEAN
  1881. USBPORT_InTextmodeSetup(
  1882. VOID
  1883. )
  1884. /*++
  1885. Routine Description:
  1886. Arguments:
  1887. None
  1888. Return Value:
  1889. TRUE if textmode setup is currently running, else FALSE
  1890. Notes:
  1891. --*/
  1892. {
  1893. UNICODE_STRING keyName;
  1894. OBJECT_ATTRIBUTES objectAttributes;
  1895. HANDLE hKey;
  1896. BOOLEAN textmodeSetup;
  1897. NTSTATUS ntStatus;
  1898. PAGED_CODE();
  1899. RtlInitUnicodeString(&keyName,
  1900. L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\setupdd");
  1901. InitializeObjectAttributes(&objectAttributes,
  1902. &keyName,
  1903. OBJ_CASE_INSENSITIVE,
  1904. NULL,
  1905. (PSECURITY_DESCRIPTOR) NULL);
  1906. ntStatus = ZwOpenKey(&hKey,
  1907. KEY_READ,
  1908. &objectAttributes);
  1909. if (!NT_SUCCESS(ntStatus))
  1910. {
  1911. textmodeSetup = FALSE;
  1912. }
  1913. else
  1914. {
  1915. textmodeSetup = TRUE;
  1916. ZwClose(hKey);
  1917. }
  1918. return textmodeSetup;
  1919. }
  1920. NTSTATUS
  1921. USBPORT_IsCompanionController(
  1922. PDEVICE_OBJECT FdoDeviceObject,
  1923. PBOOLEAN ReturnResult
  1924. )
  1925. /*++
  1926. Routine Description:
  1927. Arguments:
  1928. FdoDeviceObject - USB 1.0 OHCI or UHCI Host Controller FDO for which
  1929. an associated USB 2.0 EHCI Host Controller is searched.
  1930. ReturnResult - TRUE if the query is successful and an associated USB 2.0
  1931. EHCI Host Controller is found, otherwise FALSE.
  1932. Return Value:
  1933. Success or failure of the query, not the answer to the query.
  1934. Notes:
  1935. --*/
  1936. {
  1937. KEVENT irpCompleted;
  1938. PDEVICE_OBJECT targetDevice;
  1939. IO_STATUS_BLOCK statusBlock;
  1940. PIRP irp;
  1941. PIO_STACK_LOCATION irpStack;
  1942. PCI_DEVICE_PRESENT_INTERFACE dpInterface;
  1943. PCI_DEVICE_PRESENCE_PARAMETERS dpParameters;
  1944. BOOLEAN result;
  1945. NTSTATUS status;
  1946. PAGED_CODE();
  1947. //
  1948. // Set the default return value;
  1949. //
  1950. *ReturnResult = FALSE;
  1951. //
  1952. // Initialize the event we'll wait on
  1953. //
  1954. KeInitializeEvent(&irpCompleted, SynchronizationEvent, FALSE);
  1955. //
  1956. // Find out where we are sending the irp
  1957. //
  1958. targetDevice = IoGetAttachedDeviceReference(FdoDeviceObject);
  1959. //
  1960. // Get an IRP
  1961. //
  1962. irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
  1963. targetDevice,
  1964. NULL, // Buffer
  1965. 0, // Length
  1966. 0, // StartingOffset
  1967. &irpCompleted,
  1968. &statusBlock
  1969. );
  1970. if (!irp)
  1971. {
  1972. status = STATUS_INSUFFICIENT_RESOURCES;
  1973. goto USBPORT_IsCompanionControllerDone;
  1974. }
  1975. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1976. irp->IoStatus.Information = 0;
  1977. //
  1978. // Initialize the stack location
  1979. //
  1980. irpStack = IoGetNextIrpStackLocation(irp);
  1981. irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1982. irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCI_DEVICE_PRESENT_INTERFACE;
  1983. irpStack->Parameters.QueryInterface.Version = PCI_DEVICE_PRESENT_INTERFACE_VERSION;
  1984. irpStack->Parameters.QueryInterface.Size = sizeof(PCI_DEVICE_PRESENT_INTERFACE);
  1985. irpStack->Parameters.QueryInterface.Interface = (PINTERFACE)&dpInterface;
  1986. irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1987. //
  1988. // Call the driver and wait for completion
  1989. //
  1990. status = IoCallDriver(targetDevice, irp);
  1991. if (status == STATUS_PENDING)
  1992. {
  1993. KeWaitForSingleObject(&irpCompleted, Executive, KernelMode, FALSE, NULL);
  1994. status = statusBlock.Status;
  1995. }
  1996. if (!NT_SUCCESS(status))
  1997. {
  1998. USBPORT_KdPrint((1,"PCI_DEVICE_PRESENT_INTERFACE query interface failed\n"));
  1999. //
  2000. // Don't have the interface so don't free it.
  2001. //
  2002. goto USBPORT_IsCompanionControllerDone;
  2003. }
  2004. else
  2005. {
  2006. USBPORT_KdPrint((1,"PCI_DEVICE_PRESENT_INTERFACE query interface succeeded\n"));
  2007. }
  2008. if (dpInterface.Size < sizeof(PCI_DEVICE_PRESENT_INTERFACE))
  2009. {
  2010. USBPORT_KdPrint((1,"PCI_DEVICE_PRESENT_INTERFACE old version\n"));
  2011. //
  2012. // Do have the interface so do free it.
  2013. //
  2014. goto USBPORT_IsCompanionControllerFreeInterface;
  2015. }
  2016. //
  2017. // Initialize the Device Presence Parameters
  2018. //
  2019. dpParameters.Size = sizeof(dpParameters);
  2020. // We care about the Class / SubClass / Programming Interface
  2021. // and the search target Function has to be on the same Bus and
  2022. // Device.
  2023. dpParameters.Flags = PCI_USE_CLASS_SUBCLASS | PCI_USE_PROGIF |
  2024. PCI_USE_LOCAL_BUS | PCI_USE_LOCAL_DEVICE;
  2025. dpParameters.VendorID = 0; // We don't care.
  2026. dpParameters.DeviceID = 0; // We don't care.
  2027. dpParameters.RevisionID = 0; // We don't care.
  2028. dpParameters.SubVendorID = 0; // We don't care.
  2029. dpParameters.SubSystemID = 0; // We don't care.
  2030. dpParameters.BaseClass = PCI_CLASS_SERIAL_BUS_CTLR;
  2031. dpParameters.SubClass = PCI_SUBCLASS_SB_USB;
  2032. dpParameters.ProgIf = 0x20; // USB 2.0 Programming Interface
  2033. //
  2034. // Now call the Device Present Interface to see if the specified
  2035. // device is present.
  2036. //
  2037. result = dpInterface.IsDevicePresentEx(dpInterface.Context,
  2038. &dpParameters);
  2039. if (result)
  2040. {
  2041. USBPORT_KdPrint((1,"Found EHCI controller for FDO %08X\n", FdoDeviceObject));
  2042. }
  2043. else
  2044. {
  2045. USBPORT_KdPrint((1,"Did not find EHCI controller for FDO %08X\n", FdoDeviceObject));
  2046. }
  2047. //
  2048. // Set the return value
  2049. //
  2050. *ReturnResult = result;
  2051. USBPORT_IsCompanionControllerFreeInterface:
  2052. //
  2053. // We're done with this interface
  2054. //
  2055. dpInterface.InterfaceDereference(dpInterface.Context);
  2056. USBPORT_IsCompanionControllerDone:
  2057. //
  2058. // We're done with this device stack
  2059. //
  2060. ObDereferenceObject(targetDevice);
  2061. return status;
  2062. }
  2063. USB_CONTROLLER_FLAVOR
  2064. USBPORT_GetHcFlavor(
  2065. PDEVICE_OBJECT FdoDeviceObject,
  2066. USHORT PciVendorId,
  2067. USHORT PciProductId,
  2068. UCHAR PciRevision
  2069. )
  2070. /*++
  2071. Routine Description:
  2072. See if this is some known broken HW.
  2073. We look at the VID,PID and rev in addition to
  2074. reg keys.
  2075. Arguments:
  2076. Return Value:
  2077. HC Flavor
  2078. --*/
  2079. {
  2080. USB_CONTROLLER_FLAVOR flavor;
  2081. PDEVICE_EXTENSION devExt;
  2082. PAGED_CODE();
  2083. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2084. ASSERT_FDOEXT(devExt);
  2085. // set a base type from what the miniport told us
  2086. switch (REGISTRATION_PACKET(devExt).HciType) {
  2087. case USB_OHCI:
  2088. flavor = OHCI_Generic;
  2089. break;
  2090. case USB_UHCI:
  2091. flavor = UHCI_Generic;
  2092. break;
  2093. case USB_EHCI:
  2094. flavor = EHCI_Generic;
  2095. break;
  2096. default:
  2097. flavor = USB_HcGeneric;
  2098. }
  2099. // hardcoded checks of vid pid
  2100. // if (PciVendorId == HC_VID_INTEL &&
  2101. // PciProductId == 0x7112) {
  2102. // flavor = UHCI_Piix4;
  2103. // }
  2104. if (PciVendorId == HC_VID_OPTI &&
  2105. PciProductId == HC_PID_OPTI_HYDRA) {
  2106. flavor = OHCI_Hydra;
  2107. }
  2108. if (PciVendorId == HC_VID_INTEL) {
  2109. if (PciProductId == HC_PID_INTEL_ICH2_1) {
  2110. flavor = UHCI_Ich2_1;
  2111. } else if (PciProductId == HC_PID_INTEL_ICH2_2) {
  2112. flavor = UHCI_Ich2_2;
  2113. } else if (PciProductId == HC_PID_INTEL_ICH1) {
  2114. flavor = UHCI_Ich1;
  2115. }
  2116. }
  2117. if (PciVendorId == HC_VID_VIA &&
  2118. PciProductId == HC_PID_VIA) {
  2119. flavor = UHCI_VIA + PciRevision;
  2120. }
  2121. // for now consider rest of UHCI as PIIX4
  2122. if (flavor == UHCI_Generic) {
  2123. flavor = UHCI_Piix4;
  2124. }
  2125. if (flavor == EHCI_Generic) {
  2126. // check for variations of EHCI controllers
  2127. if (PciVendorId == 0x1033) {
  2128. flavor = EHCI_NEC;
  2129. }
  2130. //if (PciProductId == 0x1033) {
  2131. // flavor == EHCI_Lucent;
  2132. //}
  2133. }
  2134. // identify NEC companion controllers by VID/PID
  2135. if (PciVendorId == HC_VID_NEC_CC &&
  2136. PciProductId == HC_PID_NEC_CC &&
  2137. PciRevision == HC_REV_NEC_CC) {
  2138. // this controller used func 2 for the USB 2 controller
  2139. devExt->Fdo.Usb2BusFunction = 2;
  2140. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC);
  2141. }
  2142. // identify VIA companion controllers by VID/PID
  2143. if (PciVendorId == HC_VID_VIA_CC &&
  2144. PciProductId == HC_PID_VIA_CC &&
  2145. PciRevision == HC_REV_VIA_CC) {
  2146. // this controller used func 2 for the USB 2 controller
  2147. devExt->Fdo.Usb2BusFunction = 2;
  2148. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC);
  2149. }
  2150. // identify INTEL companion controllers by VID/PID
  2151. if (PciVendorId == HC_VID_INTEL_CC &&
  2152. (PciProductId == HC_PID_INTEL_CC1 ||
  2153. PciProductId == HC_PID_INTEL_CC2 ||
  2154. PciProductId == HC_PID_INTEL_CC3)) {
  2155. // this controller used func 7 for the USB 2 controller
  2156. devExt->Fdo.Usb2BusFunction = 7;
  2157. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_IS_CC);
  2158. }
  2159. // now check the registry
  2160. // NOTE: checking the registry last allows this to override
  2161. // any setting from the miniport or the port
  2162. USBPORT_GetRegistryKeyValueForPdo(devExt->HcFdoDeviceObject,
  2163. devExt->Fdo.PhysicalDeviceObject,
  2164. USBPORT_SW_BRANCH,
  2165. FLAVOR_KEY,
  2166. sizeof(FLAVOR_KEY),
  2167. &flavor,
  2168. sizeof(flavor));
  2169. return flavor;
  2170. }
  2171. ULONG
  2172. USBPORT_ComputeTotalBandwidth(
  2173. PDEVICE_OBJECT FdoDeviceObject,
  2174. PVOID BusContext
  2175. )
  2176. /*++
  2177. Routine Description:
  2178. Compute total bandwidth for this virtual bus
  2179. Arguments:
  2180. Return Value:
  2181. bandwidth availble on this bus
  2182. --*/
  2183. {
  2184. PDEVICE_EXTENSION devExt;
  2185. ULONG bw;
  2186. PAGED_CODE();
  2187. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2188. ASSERT_FDOEXT(devExt);
  2189. if (USBPORT_IS_USB20(devExt)) {
  2190. PTRANSACTION_TRANSLATOR translator = BusContext;
  2191. // bus conetext will be a TT if the query
  2192. // is for a 1.1 device atached to a TT or
  2193. // the root hub Pdo if it is a native 2.0
  2194. // device
  2195. if (translator->Sig == SIG_TT) {
  2196. bw = translator->TotalBusBandwidth;
  2197. } else {
  2198. // return bw on or 2.0 bus
  2199. bw = devExt->Fdo.TotalBusBandwidth;
  2200. }
  2201. } else {
  2202. bw = devExt->Fdo.TotalBusBandwidth;
  2203. }
  2204. USBPORT_KdPrint((1,"'Total bus BW %d\n", bw));
  2205. return bw;
  2206. }
  2207. ULONG
  2208. USBPORT_ComputeAllocatedBandwidth(
  2209. PDEVICE_OBJECT FdoDeviceObject,
  2210. PVOID BusContext
  2211. )
  2212. /*++
  2213. Routine Description:
  2214. Compute total bandwidth currently allocated
  2215. Arguments:
  2216. Return Value:
  2217. consumed bandwidth in bits/sec
  2218. --*/
  2219. {
  2220. PDEVICE_EXTENSION devExt;
  2221. ULONG totalBW, used, i;
  2222. PTRANSACTION_TRANSLATOR translator = BusContext;
  2223. PAGED_CODE();
  2224. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2225. ASSERT_FDOEXT(devExt);
  2226. if (USBPORT_IS_USB20(devExt) &&
  2227. translator->Sig == SIG_TT) {
  2228. // bus conetext will be a TT if the query
  2229. // is for a 1.1 device atached to a TT or
  2230. // the root hub Pdo if it is a native 2.0
  2231. // device
  2232. totalBW = translator->TotalBusBandwidth;
  2233. used = 0;
  2234. // table contains available bw, total-available = used
  2235. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  2236. if (totalBW - translator->BandwidthTable[i] > used) {
  2237. used = totalBW - translator->BandwidthTable[i];
  2238. }
  2239. }
  2240. } else {
  2241. totalBW = devExt->Fdo.TotalBusBandwidth;
  2242. used = 0;
  2243. // table contains available bw, total-available = used
  2244. for (i=0; i<USBPORT_MAX_INTEP_POLLING_INTERVAL; i++) {
  2245. if (totalBW - devExt->Fdo.BandwidthTable[i] > used) {
  2246. used = totalBW - devExt->Fdo.BandwidthTable[i];
  2247. }
  2248. }
  2249. }
  2250. USBPORT_KdPrint((1,"'Bus BW used %d\n", used));
  2251. return used;
  2252. }
  2253. BOOLEAN
  2254. USBPORT_SelectiveSuspendEnabled(
  2255. PDEVICE_OBJECT FdoDeviceObject
  2256. )
  2257. /*++
  2258. Routine Description:
  2259. Compute total bandwidth currently allocated
  2260. Arguments:
  2261. Return Value:
  2262. TRUE if selective suspend supported for this HC
  2263. --*/
  2264. {
  2265. PDEVICE_EXTENSION devExt;
  2266. ULONG disableSelectiveSuspend = 0;
  2267. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2268. ASSERT_FDOEXT(devExt);
  2269. USBPORT_GetRegistryKeyValueForPdo(devExt->HcFdoDeviceObject,
  2270. devExt->Fdo.PhysicalDeviceObject,
  2271. USBPORT_SW_BRANCH,
  2272. DISABLE_SS_KEY,
  2273. sizeof(DISABLE_SS_KEY),
  2274. &disableSelectiveSuspend,
  2275. sizeof(disableSelectiveSuspend));
  2276. #if DBG
  2277. if (disableSelectiveSuspend) {
  2278. USBPORT_KdPrint((1,"'<Selective Suspend> Disabled in Registry for HC\n"));
  2279. }
  2280. #endif
  2281. return disableSelectiveSuspend ? FALSE : TRUE;
  2282. }
  2283. VOID
  2284. USBPORT_InitializeSpinLock(
  2285. PUSBPORT_SPIN_LOCK SpinLock,
  2286. LONG SigA,
  2287. LONG SigR
  2288. )
  2289. {
  2290. KeInitializeSpinLock(&(SpinLock->sl));
  2291. SpinLock->Check = -1;
  2292. SpinLock->SigA = SigA;
  2293. SpinLock->SigR = SigR;
  2294. }
  2295. #if DBG
  2296. VOID
  2297. USBPORT_DbgAcquireSpinLock(
  2298. PDEVICE_OBJECT FdoDeviceObject,
  2299. PUSBPORT_SPIN_LOCK SpinLock,
  2300. PKIRQL OldIrql
  2301. )
  2302. {
  2303. PDEVICE_EXTENSION devExt;
  2304. LONG n;
  2305. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2306. ASSERT_FDOEXT(devExt);
  2307. KeAcquireSpinLock(&(SpinLock->sl), OldIrql);
  2308. n = InterlockedIncrement(&SpinLock->Check);
  2309. LOGENTRY(NULL, FdoDeviceObject, LOG_SPIN, SpinLock->SigA, 0, 0, n);
  2310. // detect recursively acquired spinlock
  2311. USBPORT_ASSERT(n == 0);
  2312. }
  2313. VOID
  2314. USBPORT_DbgReleaseSpinLock(
  2315. PDEVICE_OBJECT FdoDeviceObject,
  2316. PUSBPORT_SPIN_LOCK SpinLock,
  2317. KIRQL NewIrql
  2318. )
  2319. {
  2320. PDEVICE_EXTENSION devExt;
  2321. LONG n;
  2322. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2323. ASSERT_FDOEXT(devExt);
  2324. n = InterlockedDecrement(&SpinLock->Check);
  2325. LOGENTRY(NULL, FdoDeviceObject, LOG_SPIN, SpinLock->SigR, 0xFFFFFFFF, 0, n);
  2326. USBPORT_ASSERT(n == -1);
  2327. KeReleaseSpinLock(&(SpinLock->sl), NewIrql);
  2328. }
  2329. #endif
  2330. VOID
  2331. USBPORT_PowerFault(
  2332. PDEVICE_OBJECT FdoDeviceObject,
  2333. PUCHAR MessageText
  2334. )
  2335. /*++
  2336. Routine Description:
  2337. A power fault has occurred, dump information we will need
  2338. to debug it.
  2339. In the future we may take additional action such as event
  2340. logging and disabling the controller.
  2341. Arguments:
  2342. Return Value:
  2343. none.
  2344. --*/
  2345. {
  2346. PDEVICE_EXTENSION devExt;
  2347. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2348. ASSERT_FDOEXT(devExt);
  2349. // take a power dump,
  2350. // lets see the comment police find this one
  2351. USBPORT_KdPrint((0, "*** USBPORT POWER FAULT ***\n"));
  2352. USBPORT_KdPrint((0, "Warning:\n"));
  2353. USBPORT_KdPrint((0, "The USB controller as failed a consistency check\n"));
  2354. USBPORT_KdPrint((0, "following an OS power event.\n"));
  2355. USBPORT_KdPrint((0, "The controller will not function and the system\n"));
  2356. USBPORT_KdPrint((0, "may bugcheck or hang.\n"));
  2357. // print the specific cause
  2358. USBPORT_KdPrint((0, "CAUSE: <%s>\n", MessageText));
  2359. // now dump relevent power information
  2360. USBPORT_KdPrint((0, "FdoDeviceObject: %x\n", FdoDeviceObject));
  2361. USBPORT_KdPrint((0, "Returning from? (SystemState): "));
  2362. switch(devExt->Fdo.LastSystemSleepState) {
  2363. case PowerSystemUnspecified:
  2364. USBPORT_KdPrint((0, "PowerSystemUnspecified"));
  2365. break;
  2366. case PowerSystemWorking:
  2367. USBPORT_KdPrint((0, "PowerSystemWorking"));
  2368. break;
  2369. case PowerSystemSleeping1:
  2370. USBPORT_KdPrint((0, "PowerSystemSleeping1"));
  2371. break;
  2372. case PowerSystemSleeping2:
  2373. USBPORT_KdPrint((0, "PowerSystemSleeping2"));
  2374. break;
  2375. case PowerSystemSleeping3:
  2376. USBPORT_KdPrint((0, "PowerSystemSleeping3"));
  2377. break;
  2378. case PowerSystemHibernate:
  2379. USBPORT_KdPrint((0, "PowerSystemHibernate"));
  2380. break;
  2381. case PowerSystemShutdown:
  2382. USBPORT_KdPrint((0, "PowerSystemShutdown"));
  2383. break;
  2384. }
  2385. USBPORT_KdPrint((0, "\n"));
  2386. #if DBG
  2387. // break if we are in debug mode, otherwise this ends up being a warning
  2388. DEBUG_BREAK();
  2389. #endif
  2390. }
  2391. NTSTATUS
  2392. USBPORT_CreateLegacyFdoSymbolicLink(
  2393. PDEVICE_OBJECT FdoDeviceObject
  2394. )
  2395. /*++
  2396. Routine Description:
  2397. Create the legacy symbolic name \\DosDevices\HCDn where
  2398. n = 0...9,A...Z
  2399. Many older applications detect the presence of USB by opening
  2400. HCDn
  2401. Arguments:
  2402. Return Value:
  2403. none.
  2404. --*/
  2405. {
  2406. PDEVICE_EXTENSION devExt;
  2407. WCHAR legacyLinkBuffer[] = L"\\DosDevices\\HCD0";
  2408. WCHAR *buffer;
  2409. UNICODE_STRING deviceNameUnicodeString;
  2410. NTSTATUS ntStatus;
  2411. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2412. ASSERT_FDOEXT(devExt);
  2413. USBPORT_ASSERT(!TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_LEGACY_SYM_LINK));
  2414. ntStatus = USBPORT_MakeHcdDeviceName(&deviceNameUnicodeString,
  2415. devExt->Fdo.DeviceNameIdx);
  2416. if (NT_SUCCESS(ntStatus)) {
  2417. ALLOC_POOL_Z(buffer,
  2418. PagedPool,
  2419. sizeof(legacyLinkBuffer));
  2420. if (buffer != NULL) {
  2421. RtlCopyMemory(buffer,
  2422. legacyLinkBuffer,
  2423. sizeof(legacyLinkBuffer));
  2424. USBPORT_ASSERT(devExt->Fdo.DeviceNameIdx < 10);
  2425. buffer[15] = (WCHAR)('0'+ devExt->Fdo.DeviceNameIdx);
  2426. RtlInitUnicodeString(&devExt->Fdo.LegacyLinkUnicodeString,
  2427. buffer);
  2428. ntStatus =
  2429. IoCreateSymbolicLink(&devExt->Fdo.LegacyLinkUnicodeString,
  2430. &deviceNameUnicodeString);
  2431. if (!NT_SUCCESS(ntStatus)) {
  2432. // free now since we won't be setting our flag
  2433. RtlFreeUnicodeString(&devExt->Fdo.LegacyLinkUnicodeString);
  2434. }
  2435. } else {
  2436. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2437. }
  2438. RtlFreeUnicodeString(&deviceNameUnicodeString);
  2439. }
  2440. if (NT_SUCCESS(ntStatus)) {
  2441. SET_FDO_FLAG(devExt, USBPORT_FDOFLAG_LEGACY_SYM_LINK);
  2442. }
  2443. return ntStatus;
  2444. }
  2445. #if 0
  2446. VOID
  2447. USBPORT_WriteErrorLogEntry(
  2448. PDEVICE_OBJECT FdoDeviceObject,
  2449. ULONG DumpDataSize,
  2450. PULONG DumData
  2451. )
  2452. /*++
  2453. Routine Description:
  2454. Arguments:
  2455. Return Value:
  2456. none
  2457. --*/
  2458. {
  2459. PIO_ERROR_LOG_PACKET errorLogEntry;
  2460. ASSERT_PASSIVE();
  2461. errorLogEntry = IoAllocateErrorLogEntry(
  2462. FdoDeviceObject,
  2463. sizeof(IO_ERROR_LOG_PACKET) + DumpDataSize * sizeof(ULONG) +
  2464. sizeof(InsertionStrings)
  2465. );
  2466. if (errorLogEntry != NULL) {
  2467. errorLogEntry->ErrorCode = ErrorCode;
  2468. errorLogEntry->SequenceNumber = 0;
  2469. errorLogEntry->MajorFunctionCode = 0;
  2470. errorLogEntry->RetryCount = 0;
  2471. errorLogEntry->UniqueErrorValue = 0;
  2472. errorLogEntry->FinalStatus = STATUS_SUCCESS;
  2473. errorLogEntry->DumpDataSize = 0;
  2474. errorLogEntry->DumpData[0] = DumpData;
  2475. }
  2476. if (InsertionString) {
  2477. errorLogEntry->StringOffset =
  2478. sizeof(IO_ERROR_LOG_PACKET);
  2479. errorLogEntry->NumberOfStrings = 1;
  2480. RtlCopyMemory(
  2481. ((PCHAR)(errorLogEntry) + errorLogEntry->StringOffset),
  2482. InsertionString->Buffer,
  2483. InsertionString->Length);
  2484. }
  2485. IoWriteErrorLogEntry(errorLogEntry);
  2486. }
  2487. #endif
  2488. NTSTATUS
  2489. USBPORT_GetDefaultBIOS_X(
  2490. PDEVICE_OBJECT FdoDeviceObject,
  2491. PULONG BiosX,
  2492. PULONG GlobalDisableSS,
  2493. PULONG GlobalDisableCCDetect,
  2494. PULONG EnIdleEndpointSupport
  2495. )
  2496. /*++
  2497. Routine Description:
  2498. Read the regkeys defining BIOS specific hacks, these hacks are
  2499. applied globaly to all controllers in the system and usualy
  2500. involve power management.
  2501. Arguments:
  2502. DeviceObject - DeviceObject of the controller
  2503. Return Value:
  2504. NT status code.
  2505. --*/
  2506. {
  2507. PDEVICE_EXTENSION devExt;
  2508. #define MAX_HACK_KEYS 5
  2509. NTSTATUS ntStatus;
  2510. RTL_QUERY_REGISTRY_TABLE QueryTable[MAX_HACK_KEYS];
  2511. PWCHAR usb = L"usb";
  2512. ULONG k = 0;
  2513. PAGED_CODE();
  2514. // Set default BIOS hacks here, these can be overriden by
  2515. // global reg keys based on a particular BIOS rev.
  2516. // set the default behavior then override with the key
  2517. *BiosX = BIOS_X_NO_USB_WAKE_S2;
  2518. //
  2519. // Set up QueryTable to do the following:
  2520. //
  2521. // bios hacks
  2522. QueryTable[k].QueryRoutine = USBPORT_GetConfigValue;
  2523. QueryTable[k].Flags = 0;
  2524. QueryTable[k].Name = BIOS_X_KEY;
  2525. QueryTable[k].EntryContext = BiosX;
  2526. QueryTable[k].DefaultType = REG_DWORD;
  2527. QueryTable[k].DefaultData = BiosX;
  2528. QueryTable[k].DefaultLength = sizeof(*BiosX);
  2529. k++;
  2530. QueryTable[k].QueryRoutine = USBPORT_GetConfigValue;
  2531. QueryTable[k].Flags = 0;
  2532. QueryTable[k].Name = G_DISABLE_SS_KEY;
  2533. QueryTable[k].EntryContext = GlobalDisableSS;
  2534. QueryTable[k].DefaultType = REG_DWORD;
  2535. QueryTable[k].DefaultData = GlobalDisableSS;
  2536. QueryTable[k].DefaultLength = sizeof(*GlobalDisableSS);
  2537. k++;
  2538. QueryTable[k].QueryRoutine = USBPORT_GetConfigValue;
  2539. QueryTable[k].Flags = 0;
  2540. QueryTable[k].Name = G_DISABLE_CC_DETECT_KEY;
  2541. QueryTable[k].EntryContext = GlobalDisableCCDetect;
  2542. QueryTable[k].DefaultType = REG_DWORD;
  2543. QueryTable[k].DefaultData = GlobalDisableCCDetect;
  2544. QueryTable[k].DefaultLength = sizeof(*GlobalDisableCCDetect);
  2545. k++;
  2546. QueryTable[k].QueryRoutine = USBPORT_GetConfigValue;
  2547. QueryTable[k].Flags = 0;
  2548. QueryTable[k].Name = G_EN_IDLE_ENDPOINT_SUPPORT;
  2549. QueryTable[k].EntryContext = EnIdleEndpointSupport;
  2550. QueryTable[k].DefaultType = REG_DWORD;
  2551. QueryTable[k].DefaultData = EnIdleEndpointSupport;
  2552. QueryTable[k].DefaultLength = sizeof(*EnIdleEndpointSupport);
  2553. k++;
  2554. USBPORT_ASSERT(k < MAX_HACK_KEYS);
  2555. // stop
  2556. QueryTable[k].QueryRoutine = NULL;
  2557. QueryTable[k].Flags = 0;
  2558. QueryTable[k].Name = NULL;
  2559. ntStatus = RtlQueryRegistryValues(
  2560. RTL_REGISTRY_SERVICES,
  2561. usb,
  2562. QueryTable, // QueryTable
  2563. NULL, // Context
  2564. NULL); // Environment
  2565. #undef MAX_HACK_KEYS
  2566. return ntStatus;
  2567. }
  2568. VOID
  2569. USBPORT_ApplyBIOS_X(
  2570. PDEVICE_OBJECT FdoDeviceObject,
  2571. PDEVICE_CAPABILITIES DeviceCaps,
  2572. ULONG BiosX
  2573. )
  2574. /*++
  2575. Routine Description:
  2576. Arguments:
  2577. DeviceObject - DeviceObject of the controller
  2578. Return Value:
  2579. --*/
  2580. {
  2581. PDEVICE_EXTENSION devExt;
  2582. ULONG wakeHack;
  2583. HC_POWER_STATE_TABLE tmpPowerTable;
  2584. PHC_POWER_STATE hcPowerState;
  2585. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2586. ASSERT_FDOEXT(devExt);
  2587. if (BiosX == 0) {
  2588. return;
  2589. }
  2590. USBPORT_KdPrint((1, "'USB Apply BIOS Hacks\n"));
  2591. wakeHack = BiosX;
  2592. // change Device Caps to reflect the fact that the controller
  2593. // cannot wake from a given S state
  2594. USBPORT_ComputeHcPowerStates(
  2595. FdoDeviceObject,
  2596. DeviceCaps,
  2597. &tmpPowerTable);
  2598. switch (wakeHack) {
  2599. case BIOS_X_NO_USB_WAKE_S4:
  2600. // this has never been tested
  2601. if (DeviceCaps->SystemWake >= PowerSystemHibernate) {
  2602. USBPORT_KdPrint((1, "'USB BIOS X - disable remote wakeup (S4)\n"));
  2603. TEST_TRAP();
  2604. DeviceCaps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
  2605. DeviceCaps->SystemWake = PowerSystemSleeping3;
  2606. }
  2607. break;
  2608. case BIOS_X_NO_USB_WAKE_S3:
  2609. // this has never been tested
  2610. if (DeviceCaps->SystemWake >= PowerSystemSleeping3) {
  2611. USBPORT_KdPrint((1, "'USB BIOS X - disable remote wakeup (S3)\n"));
  2612. TEST_TRAP();
  2613. DeviceCaps->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
  2614. DeviceCaps->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
  2615. DeviceCaps->SystemWake = PowerSystemSleeping2;
  2616. }
  2617. break;
  2618. case BIOS_X_NO_USB_WAKE_S2:
  2619. if (DeviceCaps->SystemWake >= PowerSystemSleeping2) {
  2620. USBPORT_KdPrint((1, "'USB BIOS X - disable remote wakeup (S2)\n"));
  2621. DeviceCaps->DeviceState[PowerSystemHibernate] = PowerDeviceUnspecified;
  2622. DeviceCaps->DeviceState[PowerSystemSleeping3] = PowerDeviceUnspecified;
  2623. DeviceCaps->DeviceState[PowerSystemSleeping2] = PowerDeviceUnspecified;
  2624. // mimic how we deterine wake for the root hub
  2625. hcPowerState = USBPORT_GetHcPowerState(FdoDeviceObject,
  2626. &tmpPowerTable,
  2627. PowerSystemSleeping1);
  2628. if (hcPowerState &&
  2629. hcPowerState->Attributes == HcPower_Y_Wakeup_Y) {
  2630. DeviceCaps->SystemWake = PowerSystemSleeping1;
  2631. } else {
  2632. DeviceCaps->SystemWake = PowerSystemUnspecified;
  2633. }
  2634. }
  2635. break;
  2636. case BIOS_X_NO_USB_WAKE_S1:
  2637. // this has never been tested
  2638. if (DeviceCaps->SystemWake >= PowerSystemSleeping1) {
  2639. USBPORT_KdPrint((1, "'USB BIOS X - disable remote wakeup (S1)\n"));
  2640. TEST_TRAP();
  2641. DeviceCaps->DeviceState[PowerSystemHibernate] = PowerDeviceUnspecified;
  2642. DeviceCaps->DeviceState[PowerSystemSleeping3] = PowerDeviceUnspecified;
  2643. DeviceCaps->DeviceState[PowerSystemSleeping2] = PowerDeviceUnspecified;
  2644. DeviceCaps->DeviceState[PowerSystemSleeping1] = PowerDeviceUnspecified;
  2645. DeviceCaps->SystemWake = PowerSystemUnspecified;
  2646. }
  2647. break;
  2648. }
  2649. }
  2650. USBPORT_OS_VERSION
  2651. USBPORT_DetectOSVersion(
  2652. PDEVICE_OBJECT FdoDeviceObject
  2653. )
  2654. /*++
  2655. Routine Description:
  2656. Arguments:
  2657. DeviceObject - DeviceObject of the controller
  2658. Return Value:
  2659. --*/
  2660. {
  2661. PDEVICE_EXTENSION devExt;
  2662. USBPORT_OS_VERSION osVersion;
  2663. if (IoIsWdmVersionAvailable(1, 0x20)) {
  2664. USBPORT_KdPrint((1, "Detected: WinXP\n"));
  2665. osVersion = WinXP;
  2666. } else if (IoIsWdmVersionAvailable(1, 0x10)) {
  2667. USBPORT_KdPrint((1, "Detected: Win2K\n"));
  2668. osVersion = Win2K;
  2669. } else if (IoIsWdmVersionAvailable(1, 0x05)) {
  2670. USBPORT_KdPrint((1, "Detected: WinMe\n"));
  2671. osVersion = WinMe;
  2672. } else {
  2673. // 98 or 98se
  2674. USBPORT_KdPrint((1, "Detected: Win98\n"));
  2675. osVersion = Win98;
  2676. }
  2677. return osVersion;
  2678. }
  2679. VOID
  2680. USBPORT_WriteHaction(
  2681. PDEVICE_OBJECT Usb2FdoDeviceObject,
  2682. ULONG Haction
  2683. )
  2684. /*++
  2685. Routine Description:
  2686. specify 'hactions' for the CC to be taken by the
  2687. coinstaller
  2688. Arguments:
  2689. DeviceObject - DeviceObject of the USB 2 controller
  2690. Return Value:
  2691. --*/
  2692. {
  2693. PDEVICE_EXTENSION devExt;
  2694. PDEVICE_RELATIONS devRelations;
  2695. NTSTATUS ntStatus;
  2696. ULONG i;
  2697. PAGED_CODE();
  2698. devRelations =
  2699. USBPORT_FindCompanionControllers(Usb2FdoDeviceObject,
  2700. FALSE,
  2701. FALSE);
  2702. for (i=0; devRelations && i< devRelations->Count; i++) {
  2703. PDEVICE_OBJECT pdo = devRelations->Objects[i];
  2704. ntStatus = USBPORT_SetRegistryKeyValueForPdo(
  2705. pdo,
  2706. USBPORT_HW_BRANCH,
  2707. REG_DWORD,
  2708. HACTION_KEY,
  2709. sizeof(HACTION_KEY),
  2710. &Haction,
  2711. sizeof(Haction));
  2712. LOGENTRY(NULL, Usb2FdoDeviceObject, LOG_PNP, 'Hact', pdo,
  2713. Haction, ntStatus);
  2714. }
  2715. // thou shall not leak memory
  2716. if (devRelations != NULL) {
  2717. FREE_POOL(Usb2FdoDeviceObject, devRelations);
  2718. }
  2719. }