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.

2775 lines
75 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. pnp.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_CreateDeviceObject)
  17. #pragma alloc_text(PAGE, USBPORT_DeferredStartDevice)
  18. #pragma alloc_text(PAGE, USBPORT_SymbolicLink)
  19. #pragma alloc_text(PAGE, USBPORT_GetRegistryKeyValueForPdo)
  20. #pragma alloc_text(PAGE, USBPORT_SetRegistryKeyValueForPdo)
  21. #pragma alloc_text(PAGE, USBPORT_MakeRootHubPdoName)
  22. #pragma alloc_text(PAGE, USBPORT_MakeHcdDeviceName)
  23. #pragma alloc_text(PAGE, USBPORT_CreateRootHubPdo)
  24. #pragma alloc_text(PAGE, USBPORT_GetIdString)
  25. #pragma alloc_text(PAGE, USBPORTSVC_GetMiniportRegistryKeyValue)
  26. #pragma alloc_text(PAGE, USBPORT_CreatePortFdoSymbolicLink)
  27. #endif
  28. // non paged functions
  29. //USBPORT_FindMiniport
  30. //USBPORT_Unload
  31. //USBPORT_PnPAddDevice
  32. //USBPORT_GetResources
  33. //USBPORT_FdoStart_Complete
  34. //USBPORT_FdoPnPIrp
  35. //USBPORT_PdoPnPIrp
  36. // globals
  37. LIST_ENTRY USBPORT_MiniportDriverList;
  38. USBPORT_SPIN_LOCK USBPORT_GlobalsSpinLock;
  39. BOOLEAN USBPORT_GlobalInitialized = FALSE;
  40. LIST_ENTRY USBPORT_USB2fdoList;
  41. LIST_ENTRY USBPORT_USB1fdoList;
  42. ULONG USB2LIB_HcContextSize;
  43. ULONG USB2LIB_EndpointContextSize;
  44. ULONG USB2LIB_TtContextSize;
  45. /*
  46. */
  47. #define USBPORT_DUMMY_USBD_EXT_SIZE 512
  48. PUCHAR USBPORT_DummyUsbdExtension = NULL;
  49. #if DBG
  50. ULONG USBPORT_GlobalAllocedPagedPool;
  51. ULONG USBPORT_GlobalAllocedNonPagedPool;
  52. #endif
  53. USB_MINIPORT_STATUS
  54. USBPORTSVC_GetMiniportRegistryKeyValue(
  55. PDEVICE_DATA DeviceData,
  56. BOOLEAN SoftwareBranch,
  57. PWCHAR KeyNameString,
  58. ULONG KeyNameStringLength,
  59. PVOID Data,
  60. ULONG DataLength
  61. )
  62. /*++
  63. Routine Description:
  64. Get a registry parameter from either the hardware
  65. or software branch of the registry given the PDO
  66. Arguments:
  67. Return Value:
  68. --*/
  69. {
  70. PDEVICE_EXTENSION devExt;
  71. NTSTATUS ntStatus;
  72. PAGED_CODE();
  73. DEVEXT_FROM_DEVDATA(devExt, DeviceData);
  74. ASSERT_FDOEXT(devExt);
  75. ntStatus = USBPORT_GetCachedRegistryKeyValueForPdo(
  76. devExt->HcFdoDeviceObject,
  77. devExt->Fdo.PhysicalDeviceObject,
  78. SoftwareBranch,
  79. KeyNameString,
  80. KeyNameStringLength,
  81. Data,
  82. DataLength);
  83. return USBPORT_NtStatus_TO_MiniportStatus(ntStatus);
  84. }
  85. NTSTATUS
  86. USBPORT_GetRegistryKeyValueForPdo(
  87. PDEVICE_OBJECT FdoDeviceObject,
  88. PDEVICE_OBJECT PhysicalDeviceObject,
  89. BOOLEAN SoftwareBranch,
  90. PWCHAR KeyNameString,
  91. ULONG KeyNameStringLength,
  92. PVOID Data,
  93. ULONG DataLength
  94. )
  95. /*++
  96. Routine Description:
  97. Get a registry parameter from either the hardware
  98. or software branch of the registry given the PDO
  99. Arguments:
  100. Return Value:
  101. --*/
  102. {
  103. NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  104. UNICODE_STRING keyNameUnicodeString;
  105. ULONG length;
  106. PKEY_VALUE_FULL_INFORMATION fullInfo;
  107. HANDLE handle;
  108. PAGED_CODE();
  109. if (SoftwareBranch) {
  110. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  111. PLUGPLAY_REGKEY_DRIVER,
  112. STANDARD_RIGHTS_ALL,
  113. &handle);
  114. } else {
  115. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  116. PLUGPLAY_REGKEY_DEVICE,
  117. STANDARD_RIGHTS_ALL,
  118. &handle);
  119. }
  120. if (NT_SUCCESS(ntStatus)) {
  121. RtlInitUnicodeString(&keyNameUnicodeString, KeyNameString);
  122. length = sizeof(KEY_VALUE_FULL_INFORMATION) +
  123. KeyNameStringLength + DataLength;
  124. ALLOC_POOL_Z(fullInfo, PagedPool, length);
  125. USBPORT_KdPrint((2,"' GetRegistryKeyValueForPdo buffer = 0x%x\n", fullInfo));
  126. if (fullInfo) {
  127. ntStatus = ZwQueryValueKey(handle,
  128. &keyNameUnicodeString,
  129. KeyValueFullInformation,
  130. fullInfo,
  131. length,
  132. &length);
  133. if (NT_SUCCESS(ntStatus)){
  134. USBPORT_ASSERT(DataLength == fullInfo->DataLength);
  135. RtlCopyMemory(Data, ((PUCHAR) fullInfo) + fullInfo->DataOffset, DataLength);
  136. }
  137. FREE_POOL(FdoDeviceObject, fullInfo);
  138. }
  139. }
  140. return ntStatus;
  141. }
  142. NTSTATUS
  143. USBPORT_SetRegistryKeyValueForPdo(
  144. PDEVICE_OBJECT PhysicalDeviceObject,
  145. BOOLEAN SoftwareBranch,
  146. ULONG Type,
  147. PWCHAR KeyNameString,
  148. ULONG KeyNameStringLength,
  149. PVOID Data,
  150. ULONG DataLength
  151. )
  152. /*++
  153. Routine Description:
  154. Arguments:
  155. Return Value:
  156. --*/
  157. {
  158. NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  159. UNICODE_STRING keyNameUnicodeString;
  160. HANDLE handle;
  161. PAGED_CODE();
  162. if (SoftwareBranch) {
  163. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  164. PLUGPLAY_REGKEY_DRIVER,
  165. STANDARD_RIGHTS_ALL,
  166. &handle);
  167. } else {
  168. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  169. PLUGPLAY_REGKEY_DEVICE,
  170. STANDARD_RIGHTS_ALL,
  171. &handle);
  172. }
  173. if (NT_SUCCESS(ntStatus)) {
  174. RtlInitUnicodeString(&keyNameUnicodeString, KeyNameString);
  175. ntStatus = ZwSetValueKey(handle,
  176. &keyNameUnicodeString,
  177. 0,
  178. Type,
  179. Data,
  180. DataLength);
  181. }
  182. return ntStatus;
  183. }
  184. NTSTATUS
  185. USBPORT_SymbolicLink(
  186. BOOLEAN CreateFlag,
  187. PDEVICE_EXTENSION DevExt,
  188. PDEVICE_OBJECT PhysicalDeviceObject,
  189. LPGUID Guid
  190. )
  191. /*++
  192. Routine Description:
  193. create a symbolic link for a given GUID class and
  194. PhysicalDeviceObject
  195. We also write the name to the hw branch of the registry
  196. to make it easy to find for a particular instance
  197. of controller.
  198. Arguments:
  199. DeviceObject - DeviceObject of the controller to stop
  200. Return Value:
  201. NT status code.
  202. --*/
  203. {
  204. NTSTATUS ntStatus;
  205. PAGED_CODE();
  206. if (CreateFlag) {
  207. /*
  208. * Create the symbolic link
  209. */
  210. USBPORT_ASSERT(!TEST_FLAG(DevExt->Flags, USBPORT_FLAG_SYM_LINK));
  211. ntStatus = IoRegisterDeviceInterface(
  212. PhysicalDeviceObject,
  213. Guid,
  214. NULL,
  215. &DevExt->SymbolicLinkName);
  216. if (NT_SUCCESS(ntStatus)) {
  217. /*
  218. * Now set the symbolic link for the association and
  219. * store it..
  220. */
  221. // successfully alloced a link
  222. // set the flag so we will free it
  223. SET_FLAG(DevExt->Flags, USBPORT_FLAG_SYM_LINK);
  224. // write it to the registry -- this is for comaptibilty
  225. // with older OS versions
  226. ntStatus = USBPORT_SetRegistryKeyValueForPdo(
  227. PhysicalDeviceObject,
  228. USBPORT_HW_BRANCH,
  229. REG_SZ,
  230. SYM_LINK_KEY,
  231. sizeof(SYM_LINK_KEY),
  232. &DevExt->SymbolicLinkName.Buffer[0],
  233. DevExt->SymbolicLinkName.Length);
  234. if (NT_SUCCESS(ntStatus)) {
  235. ntStatus =
  236. IoSetDeviceInterfaceState(&DevExt->SymbolicLinkName,
  237. TRUE);
  238. }
  239. }
  240. } else {
  241. USBPORT_ASSERT(TEST_FLAG(DevExt->Flags, USBPORT_FLAG_SYM_LINK));
  242. /*
  243. * Disable the symbolic link
  244. */
  245. ntStatus = IoSetDeviceInterfaceState(
  246. &DevExt->SymbolicLinkName, FALSE);
  247. if (NT_SUCCESS(ntStatus)) {
  248. RtlFreeUnicodeString(&DevExt->SymbolicLinkName);
  249. CLEAR_FLAG(DevExt->Flags, USBPORT_FLAG_SYM_LINK);
  250. } else {
  251. DEBUG_BREAK();
  252. }
  253. }
  254. return ntStatus;
  255. }
  256. PUSBPORT_MINIPORT_DRIVER
  257. USBPORT_FindMiniport(
  258. PDRIVER_OBJECT DriverObject
  259. )
  260. /*++
  261. Routine Description:
  262. Find a miniport given a DriverObject
  263. Arguments:
  264. DriverObject - pointer to a driver object
  265. Return Value:
  266. pointer to miniport or NULL
  267. --*/
  268. {
  269. KIRQL irql;
  270. PUSBPORT_MINIPORT_DRIVER found = NULL;
  271. PUSBPORT_MINIPORT_DRIVER miniportDriver;
  272. PLIST_ENTRY listEntry;
  273. KeAcquireSpinLock(&USBPORT_GlobalsSpinLock.sl, &irql);
  274. listEntry = &USBPORT_MiniportDriverList;
  275. if (!IsListEmpty(listEntry)) {
  276. listEntry = USBPORT_MiniportDriverList.Flink;
  277. }
  278. // LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'FIl+', listEntry,
  279. // &USBPORT_MiniportDriverList, 0);
  280. while (listEntry != &USBPORT_MiniportDriverList) {
  281. miniportDriver = (PUSBPORT_MINIPORT_DRIVER)
  282. CONTAINING_RECORD(listEntry,
  283. struct _USBPORT_MINIPORT_DRIVER,
  284. ListEntry);
  285. if (miniportDriver->DriverObject == DriverObject) {
  286. found = miniportDriver;
  287. break;
  288. }
  289. // next entry
  290. listEntry = miniportDriver->ListEntry.Flink;
  291. }
  292. KeReleaseSpinLock(&USBPORT_GlobalsSpinLock.sl, irql);
  293. // LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Fmpd', found, 0, 0);
  294. return found;
  295. }
  296. VOID
  297. USBPORT_Unload(
  298. PDRIVER_OBJECT DriverObject
  299. )
  300. /*++
  301. Routine Description:
  302. Free globally allocated miniport structure used to
  303. track this particular miniport driver.
  304. note: OS won't unload unless this is the last instance
  305. of the miniport
  306. Arguments:
  307. DriverObject - pointer to a driver object
  308. Return Value:
  309. None
  310. --*/
  311. {
  312. KIRQL irql;
  313. PUSBPORT_MINIPORT_DRIVER miniportDriver;
  314. // find the miniport driver data
  315. miniportDriver = USBPORT_FindMiniport(DriverObject);
  316. // we had better find it! If we don't we screwed up
  317. // the system will crash
  318. USBPORT_ASSERT(miniportDriver != NULL);
  319. if (miniportDriver == NULL) {
  320. BUGCHECK(USBBUGCODE_INTERNAL_ERROR, 0, 0, 0);
  321. // prefix happy
  322. return;
  323. }
  324. // the miniport should not need to do anything.
  325. // But just in case/ we will call them if they
  326. // indicated an unload routine in the DriverObject.
  327. USBPORT_KdPrint((1, "'unloading USB miniport\n"));
  328. if (miniportDriver->MiniportUnload != NULL) {
  329. miniportDriver->MiniportUnload(DriverObject);
  330. }
  331. USBPORT_InterlockedRemoveEntryList(&miniportDriver->ListEntry,
  332. &USBPORT_GlobalsSpinLock.sl);
  333. FREE_POOL(NULL, miniportDriver);
  334. }
  335. NTSTATUS
  336. USBPORT_MakeHcdDeviceName(
  337. PUNICODE_STRING DeviceNameUnicodeString,
  338. ULONG Idx
  339. )
  340. /*++
  341. Routine Description:
  342. This function generates the name used for the FDO. The
  343. name format is USBFDO-n where nnn is 0 - 65535.
  344. Arguments:
  345. Return Value:
  346. None
  347. --*/
  348. {
  349. ULONG bit, i;
  350. PWCHAR deviceNameBuffer;
  351. WCHAR nameBuffer[] = L"\\Device\\USBFDO-";
  352. NTSTATUS ntStatus;
  353. UNICODE_STRING tmpUnicodeString;
  354. WCHAR tmpBuffer[16];
  355. PAGED_CODE();
  356. // enough for 3 digits and NULL
  357. tmpUnicodeString.Buffer = tmpBuffer;
  358. tmpUnicodeString.MaximumLength = sizeof(tmpBuffer);
  359. tmpUnicodeString.Length = 0;
  360. ntStatus = RtlIntegerToUnicodeString(Idx,
  361. 10,
  362. &tmpUnicodeString);
  363. if (NT_SUCCESS(ntStatus)) {
  364. USHORT siz;
  365. siz = sizeof(nameBuffer)+tmpUnicodeString.Length;
  366. // we can't log this alloc because the device object
  367. // has not been created yet
  368. ALLOC_POOL_Z(deviceNameBuffer, PagedPool, siz);
  369. if (deviceNameBuffer != NULL) {
  370. RtlCopyMemory(deviceNameBuffer, nameBuffer, sizeof(nameBuffer));
  371. RtlInitUnicodeString(DeviceNameUnicodeString,
  372. deviceNameBuffer);
  373. DeviceNameUnicodeString->MaximumLength = siz;
  374. ntStatus = RtlAppendUnicodeStringToString(
  375. DeviceNameUnicodeString,
  376. &tmpUnicodeString);
  377. } else {
  378. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  379. }
  380. }
  381. return ntStatus;
  382. }
  383. NTSTATUS
  384. USBPORT_MakeRootHubPdoName(
  385. PDEVICE_OBJECT FdoDeviceObject,
  386. PUNICODE_STRING PdoNameUnicodeString,
  387. ULONG Index
  388. )
  389. /*++
  390. Routine Description:
  391. This service Creates a name for a PDO created by the HUB
  392. Arguments:
  393. Return Value:
  394. --*/
  395. {
  396. PWCHAR nameBuffer = NULL;
  397. WCHAR rootName[] = L"\\Device\\USBPDO-";
  398. UNICODE_STRING idUnicodeString;
  399. WCHAR buffer[32];
  400. NTSTATUS ntStatus = STATUS_SUCCESS;
  401. USHORT length;
  402. BOOLEAN haveString = FALSE;
  403. PAGED_CODE();
  404. length = sizeof(buffer)+sizeof(rootName);
  405. // os frees this when the unicode string is 'freed'
  406. ALLOC_POOL_OSOWNED(nameBuffer, PagedPool, length);
  407. if (nameBuffer) {
  408. RtlCopyMemory(nameBuffer, rootName, sizeof(rootName));
  409. RtlInitUnicodeString(PdoNameUnicodeString,
  410. nameBuffer);
  411. PdoNameUnicodeString->MaximumLength =
  412. length;
  413. haveString = TRUE; // we have a string now
  414. RtlInitUnicodeString(&idUnicodeString,
  415. &buffer[0]);
  416. idUnicodeString.MaximumLength =
  417. sizeof(buffer);
  418. ntStatus = RtlIntegerToUnicodeString(
  419. Index,
  420. 10,
  421. &idUnicodeString);
  422. if (NT_SUCCESS(ntStatus)) {
  423. ntStatus = RtlAppendUnicodeStringToString(PdoNameUnicodeString,
  424. &idUnicodeString);
  425. }
  426. USBPORT_KdPrint((3, "'USBPORT_MakeNodeName string = %x\n",
  427. PdoNameUnicodeString));
  428. } else {
  429. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  430. }
  431. if (!NT_SUCCESS(ntStatus) && haveString) {
  432. RtlFreeUnicodeString(PdoNameUnicodeString);
  433. }
  434. return ntStatus;
  435. }
  436. NTSTATUS
  437. USBPORT_PnPAddDevice(
  438. PDRIVER_OBJECT DriverObject,
  439. PDEVICE_OBJECT PhysicalDeviceObject
  440. )
  441. /*++
  442. Routine Description:
  443. This routine is called to create a new instance of a USB host
  444. controller. This is where we create our deviceObject.
  445. Arguments:
  446. DriverObject - pointer to the driver object for this instance of HCD
  447. PhysicalDeviceObject - pointer to a device object created by the bus
  448. Return Value:
  449. NT STATUS CODE
  450. --*/
  451. {
  452. NTSTATUS ntStatus;
  453. PDEVICE_OBJECT deviceObject = NULL;
  454. PDEVICE_EXTENSION devExt;
  455. UNICODE_STRING deviceNameUnicodeString;
  456. ULONG deviceNameIdx;
  457. PUSBPORT_MINIPORT_DRIVER miniportDriver;
  458. // since we raise IRQL in this function it cannot be pagable
  459. // find the driver
  460. miniportDriver = USBPORT_FindMiniport(DriverObject);
  461. USBPORT_ASSERT(miniportDriver != NULL);
  462. //
  463. // generate a device name
  464. //
  465. deviceNameIdx = 0;
  466. do {
  467. ntStatus = USBPORT_MakeHcdDeviceName(&deviceNameUnicodeString,
  468. deviceNameIdx);
  469. if (NT_SUCCESS(ntStatus)) {
  470. ntStatus = USBPORT_CreateDeviceObject(DriverObject,
  471. miniportDriver,
  472. &deviceObject,
  473. &deviceNameUnicodeString);
  474. RtlFreeUnicodeString(&deviceNameUnicodeString);
  475. if (NT_SUCCESS(ntStatus)) {
  476. //preserve idx
  477. break;
  478. }
  479. }
  480. deviceNameIdx++;
  481. } while (ntStatus == STATUS_OBJECT_NAME_COLLISION);
  482. if (NT_SUCCESS(ntStatus)) {
  483. GET_DEVICE_EXT(devExt, deviceObject);
  484. // BUGBUG OS should zero this
  485. RtlZeroMemory(devExt, sizeof(DEVICE_EXTENSION));
  486. devExt->DummyUsbdExtension = USBPORT_DummyUsbdExtension;
  487. devExt->Sig = USBPORT_DEVICE_EXT_SIG;
  488. devExt->HcFdoDeviceObject = deviceObject;
  489. devExt->Fdo.PhysicalDeviceObject = PhysicalDeviceObject;
  490. devExt->Fdo.DeviceNameIdx = deviceNameIdx;
  491. devExt->Fdo.MiniportDriver = miniportDriver;
  492. devExt->Fdo.MiniportDeviceData = &devExt->Fdo.MiniportExtension[0];
  493. if (USBPORT_IS_USB20(devExt)) {
  494. PUCHAR pch;
  495. pch = (PUCHAR) &devExt->Fdo.MiniportExtension[0];
  496. devExt->Fdo.Usb2LibHcContext = (PVOID) (pch +
  497. devExt->Fdo.MiniportDriver->RegistrationPacket.DeviceDataSize);
  498. USB2LIB_InitController(devExt->Fdo.Usb2LibHcContext);
  499. } else {
  500. devExt->Fdo.Usb2LibHcContext = USB_BAD_PTR;
  501. }
  502. INITIALIZE_PENDING_REQUEST_COUNTER(devExt);
  503. // inc once for the add
  504. // transition to -1 means we have no pending requests
  505. INCREMENT_PENDING_REQUEST_COUNT(deviceObject, NULL);
  506. #if DBG
  507. USBPORT_LogAlloc(&devExt->Log, 16);
  508. #else
  509. USBPORT_LogAlloc(&devExt->Log, 8);
  510. #endif
  511. // init the log spinlock here
  512. KeInitializeSpinLock(&devExt->Fdo.LogSpinLock.sl);
  513. //#if DBG
  514. // USBPORT_LogAlloc(&devExt->TransferLog, 4);
  515. // USBPORT_LogAlloc(&devExt->EnumLog, 4);
  516. //#endif
  517. USBPORT_KdPrint((1, "'**USBPORT DEVICE OBJECT** (fdo) = %x, ext = %x\n",
  518. deviceObject, devExt));
  519. KeInitializeSemaphore(&devExt->Fdo.DeviceLock, 1, 1);
  520. KeInitializeSemaphore(&devExt->Fdo.CcLock, 1, 1);
  521. InitializeListHead(&devExt->Fdo.DeviceHandleList);
  522. InitializeListHead(&devExt->Fdo.MapTransferList);
  523. InitializeListHead(&devExt->Fdo.DoneTransferList);
  524. InitializeListHead(&devExt->Fdo.GlobalEndpointList);
  525. InitializeListHead(&devExt->Fdo.AttendEndpointList);
  526. InitializeListHead(&devExt->Fdo.EpStateChangeList);
  527. InitializeListHead(&devExt->Fdo.EpClosedList);
  528. InitializeListHead(&devExt->Fdo.BadRequestList);
  529. InitializeListHead(&devExt->Fdo.RegistryCache);
  530. devExt->Fdo.BadRequestFlush = 0;
  531. //
  532. // we need to handle a seemingly random set of requests
  533. // to start/stop/remove power up, down etc in order to
  534. // handle this we keep a set of PNP state flags
  535. // not removed, not started, not stopped
  536. devExt->PnpStateFlags = 0;
  537. // until we get a start we will consider ourselves OFF
  538. devExt->CurrentDevicePowerState = PowerDeviceD3;
  539. devExt->Fdo.MpStateFlags = 0;
  540. // attach to top of PnP stack
  541. devExt->Fdo.TopOfStackDeviceObject =
  542. IoAttachDeviceToDeviceStack(deviceObject, PhysicalDeviceObject);
  543. devExt->Fdo.PendingRhCallback = 1;
  544. //
  545. // Indicate that the device object is ready for requests.
  546. //
  547. if (!USBPORT_IS_USB20(devExt)) {
  548. deviceObject->Flags |= DO_POWER_PAGABLE;
  549. }
  550. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  551. }
  552. USBPORT_KdPrint((2, "'exit USBPORT_PnPAddDevice (%x)\n", ntStatus));
  553. return ntStatus;
  554. }
  555. NTSTATUS
  556. USBPORT_CreateDeviceObject(
  557. PDRIVER_OBJECT DriverObject,
  558. PUSBPORT_MINIPORT_DRIVER MiniportDriver,
  559. PDEVICE_OBJECT *DeviceObject,
  560. PUNICODE_STRING DeviceNameUnicodeString
  561. )
  562. /*++
  563. Routine Description:
  564. This routine is called to create a new instance of a USB host
  565. controller.
  566. Arguments:
  567. DriverObject - pointer to the driver object for USBD.
  568. *DeviceObject - ptr to DeviceObject ptr to be filled
  569. in with the device object we create.
  570. DeviceNameUnicodeString - optional pointer to a device
  571. name for this FDO, can be NULL
  572. Return Value:
  573. NT status code
  574. --*/
  575. {
  576. NTSTATUS ntStatus;
  577. PDEVICE_EXTENSION devExt;
  578. ULONG extensionSize;
  579. PAGED_CODE();
  580. USBPORT_KdPrint((2, "'enter USBPORT_CreateDeviceObject\n"));
  581. extensionSize = sizeof(DEVICE_EXTENSION)+
  582. MiniportDriver->RegistrationPacket.DeviceDataSize +
  583. USB2LIB_HcContextSize;
  584. ntStatus = IoCreateDevice(DriverObject,
  585. extensionSize,
  586. DeviceNameUnicodeString, // Name
  587. FILE_DEVICE_CONTROLLER,
  588. 0,
  589. FALSE, //NOT Exclusive
  590. DeviceObject);
  591. if (NT_SUCCESS(ntStatus)) {
  592. devExt = (PDEVICE_EXTENSION) ((*DeviceObject)->DeviceExtension);
  593. USBPORT_KdPrint((2, "'USBPORT_CreateDeviceObject: device object %x device extension = %x\n",
  594. *DeviceObject, devExt));
  595. } else if (*DeviceObject) {
  596. IoDeleteDevice(*DeviceObject);
  597. }
  598. USBPORT_KdPrint((2, "'exit USBPORT_CreateDeviceObject (%x)\n", ntStatus));
  599. return ntStatus;
  600. }
  601. NTSTATUS
  602. USBPORT_GetResources(
  603. PDEVICE_OBJECT FdoDeviceObject,
  604. PCM_RESOURCE_LIST ResourceList,
  605. PHC_RESOURCES HcResources
  606. )
  607. /*++
  608. Routine Description:
  609. Arguments:
  610. DeviceObject - DeviceObject for this USB controller.
  611. ResourceList - Resources for this controller.
  612. Return Value:
  613. NT status code.
  614. --*/
  615. {
  616. ULONG i;
  617. NTSTATUS ntStatus;
  618. PCM_PARTIAL_RESOURCE_DESCRIPTOR interrupt;
  619. PCM_PARTIAL_RESOURCE_DESCRIPTOR memory;
  620. PCM_PARTIAL_RESOURCE_DESCRIPTOR ioport;
  621. PHYSICAL_ADDRESS cardAddress;
  622. ULONG addressSpace;
  623. PCM_PARTIAL_RESOURCE_LIST PartialResourceList;
  624. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDescriptor;
  625. ULONG mpOptionFlags;
  626. PDEVICE_EXTENSION devExt;
  627. USBPORT_KdPrint((2, "'enter USBPORT_GetResources\n"));
  628. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  629. ASSERT_FDOEXT(devExt);
  630. mpOptionFlags = REGISTRATION_PACKET(devExt).OptionFlags;
  631. // assume success
  632. ntStatus = STATUS_SUCCESS;
  633. // init the resource list
  634. RtlZeroMemory(HcResources, sizeof(*HcResources));
  635. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'GRES', 0, 0, ResourceList);
  636. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NO_PNP_RESOURCES)) {
  637. TEST_TRAP();
  638. // no resources, bail with success
  639. return ntStatus;
  640. }
  641. if (ResourceList == NULL) {
  642. USBPORT_KdPrint((1, "'no resources, failing start.\n"));
  643. ntStatus = STATUS_NONE_MAPPED;
  644. goto USBPORT_GetResources_Done;
  645. }
  646. fullResourceDescriptor = &ResourceList->List[0];
  647. PartialResourceList = &fullResourceDescriptor->PartialResourceList;
  648. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'gres',
  649. PartialResourceList->Count,
  650. 0,
  651. PartialResourceList);
  652. interrupt = NULL;
  653. memory = NULL;
  654. ioport = NULL;
  655. for (i = 0; i < PartialResourceList->Count; i++) {
  656. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'resT', i,
  657. PartialResourceList->PartialDescriptors[i].Type, 0);
  658. switch (PartialResourceList->PartialDescriptors[i].Type) {
  659. case CmResourceTypeInterrupt:
  660. if (interrupt == NULL) {
  661. interrupt = &PartialResourceList->PartialDescriptors[i];
  662. }
  663. break;
  664. case CmResourceTypeMemory:
  665. if (memory == NULL) {
  666. memory = &PartialResourceList->PartialDescriptors[i];
  667. }
  668. break;
  669. case CmResourceTypePort:
  670. if (ioport == NULL) {
  671. ioport = &PartialResourceList->PartialDescriptors[i];
  672. }
  673. break;
  674. }
  675. }
  676. // only map resources this miniport actually needs
  677. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NEED_IOPORT) &&
  678. ioport != NULL &&
  679. NT_SUCCESS(ntStatus)) {
  680. //
  681. // Set up AddressSpace to be of type Port I/O
  682. //
  683. USBPORT_KdPrint((1, "'Port Resources Found @ %x'%x, %d Ports Available \n",
  684. ioport->u.Port.Start.HighPart,
  685. ioport->u.Port.Start.LowPart,
  686. ioport->u.Port.Length));
  687. addressSpace =
  688. (ioport->Flags & CM_RESOURCE_PORT_IO) == CM_RESOURCE_PORT_IO? 1:0;
  689. cardAddress=ioport->u.Port.Start;
  690. if (!addressSpace) {
  691. // HcResources->Flags |= MAP_REGISTERS;
  692. HcResources->DeviceRegisters =
  693. MmMapIoSpace(
  694. cardAddress,
  695. ioport->u.Port.Length,
  696. FALSE);
  697. HcResources->DeviceRegistersLength =
  698. ioport->u.Port.Length;
  699. } else {
  700. // HcResources->Flags &= MAP_REGISTERS;
  701. HcResources->DeviceRegisters =
  702. (PVOID)(ULONG_PTR)cardAddress.QuadPart;
  703. HcResources->DeviceRegistersLength =
  704. ioport->u.Port.Length;
  705. }
  706. //
  707. // see if we successfully mapped the IO regs
  708. //
  709. if (HcResources->DeviceRegisters == NULL) {
  710. USBPORT_KdPrint((1, "'Couldn't map the device(port) registers. \n"));
  711. ntStatus = STATUS_NONE_MAPPED;
  712. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Fmio', 0, 0, ntStatus);
  713. } else {
  714. USBPORT_KdPrint((2, "'Mapped device(port) registers to 0x%x.\n",
  715. HcResources->DeviceRegisters));
  716. HcResources->Flags |= HCR_IO_REGS;
  717. }
  718. }
  719. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NEED_MEMORY) &&
  720. memory != NULL &&
  721. NT_SUCCESS(ntStatus)) {
  722. //
  723. // Set up AddressSpace to be of type Memory mapped I/O
  724. //
  725. USBPORT_KdPrint((1,
  726. "'Memory Resources Found @ %x'%x, Length = %x\n",
  727. memory->u.Memory.Start.HighPart,
  728. memory->u.Memory.Start.LowPart,
  729. memory->u.Memory.Length));
  730. addressSpace = 0;
  731. HcResources->DeviceRegistersLength =
  732. memory->u.Memory.Length;
  733. cardAddress = memory->u.Memory.Start;
  734. HcResources->DeviceRegisters =
  735. MmMapIoSpace(cardAddress,
  736. HcResources->DeviceRegistersLength,
  737. FALSE);
  738. if (HcResources->DeviceRegisters == NULL) {
  739. USBPORT_KdPrint((1, "'Couldn't map the device(memory) registers. \n"));
  740. ntStatus = STATUS_NONE_MAPPED;
  741. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'Fmmr', 0, 0, ntStatus);
  742. } else {
  743. USBPORT_KdPrint((2, "'Mapped device(memory) registers to 0x%x.\n",
  744. HcResources->DeviceRegisters));
  745. HcResources->Flags |= HCR_MEM_REGS;
  746. }
  747. }
  748. if (TEST_FLAG(mpOptionFlags, USB_MINIPORT_OPT_NEED_IRQ) &&
  749. interrupt != NULL &&
  750. NT_SUCCESS(ntStatus)) {
  751. //
  752. // Get Vector, level, and affinity information for this interrupt.
  753. //
  754. USBPORT_KdPrint((1, "'Interrupt Resources Found! Level = %x Vector = %x\n",
  755. interrupt->u.Interrupt.Level,
  756. interrupt->u.Interrupt.Vector
  757. ));
  758. HcResources->Flags |= HCR_IRQ;
  759. //
  760. // Set up our interrupt.
  761. //
  762. USBPORT_KdPrint((2, "'requesting interrupt vector %x level %x\n",
  763. interrupt->u.Interrupt.Level,
  764. interrupt->u.Interrupt.Vector));
  765. HcResources->InterruptLevel=(KIRQL)interrupt->u.Interrupt.Level;
  766. HcResources->InterruptVector=interrupt->u.Interrupt.Vector;
  767. HcResources->Affinity=interrupt->u.Interrupt.Affinity;
  768. //
  769. // Initialize the interrupt object for the controller.
  770. //
  771. HcResources->InterruptObject = NULL;
  772. HcResources->ShareIRQ =
  773. interrupt->ShareDisposition == CmResourceShareShared ? TRUE : FALSE;
  774. HcResources->InterruptMode =
  775. interrupt->Flags == CM_RESOURCE_INTERRUPT_LATCHED ?
  776. Latched :
  777. LevelSensitive;
  778. #ifdef DEBUG
  779. USBPORT_KdPrint((2, "'interrupt->ShareDisposition %x\n", interrupt->ShareDisposition));
  780. if (!HcResources->ShareIRQ) {
  781. TEST_TRAP();
  782. }
  783. #endif
  784. }
  785. USBPORT_GetResources_Done:
  786. TEST_PATH(ntStatus, FAILED_GETRESOURCES);
  787. USBPORT_KdPrint((2, "'exit USBPORT_GetResources (%x)\n", ntStatus));
  788. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'GRSd', 0, 0, ntStatus);
  789. return ntStatus;
  790. }
  791. NTSTATUS
  792. USBPORT_FdoStart_Complete(
  793. PDEVICE_OBJECT DeviceObject,
  794. PIRP Irp,
  795. PVOID Context
  796. )
  797. /*++
  798. Routine Description:
  799. This routine is called when the port driver completes an IRP.
  800. Arguments:
  801. DeviceObject - Pointer to the device object for the class device.
  802. Irp - Irp completed.
  803. Context - Driver defined context.
  804. Return Value:
  805. The function value is the final status from the operation.
  806. --*/
  807. {
  808. PIO_STACK_LOCATION irpStack;
  809. PKEVENT event = Context;
  810. irpStack = IoGetCurrentIrpStackLocation (Irp);
  811. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
  812. USBPORT_ASSERT(irpStack->MinorFunction == IRP_MN_START_DEVICE);
  813. // signal the start device dispatch to finsh
  814. KeSetEvent(event,
  815. 1,
  816. FALSE);
  817. // defer completion
  818. return STATUS_MORE_PROCESSING_REQUIRED;
  819. }
  820. NTSTATUS
  821. USBPORT_FdoPnPIrp(
  822. PDEVICE_OBJECT FdoDeviceObject,
  823. PIRP Irp
  824. )
  825. /*++
  826. Routine Description:
  827. Process the PNP IRPs sent to the FDO for the host
  828. controller.
  829. Arguments:
  830. DeviceObject - pointer to a hcd device object (FDO)
  831. Irp - pointer to an I/O Request Packet
  832. Return Value:
  833. NT status code
  834. --*/
  835. {
  836. PIO_STACK_LOCATION irpStack;
  837. NTSTATUS ntStatus = STATUS_SUCCESS;
  838. PDEVICE_EXTENSION devExt;
  839. BOOLEAN hardwarePresent = TRUE;
  840. USBPORT_KdPrint((2, "'IRP_MJ_PNP %x\n", FdoDeviceObject));
  841. irpStack = IoGetCurrentIrpStackLocation(Irp);
  842. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  843. ASSERT_FDOEXT(devExt);
  844. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
  845. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'fPnP', irpStack->MinorFunction, 0, 0);
  846. switch (irpStack->MinorFunction) {
  847. case IRP_MN_START_DEVICE:
  848. {
  849. KEVENT pnpStartEvent;
  850. KeInitializeEvent(&pnpStartEvent,
  851. NotificationEvent,
  852. FALSE);
  853. // pass on to host controllers PDO
  854. ntStatus =
  855. USBPORT_PassIrp(FdoDeviceObject,
  856. USBPORT_FdoStart_Complete,
  857. &pnpStartEvent,
  858. TRUE,
  859. TRUE,
  860. TRUE,
  861. Irp);
  862. if (ntStatus == STATUS_PENDING) {
  863. KeWaitForSingleObject(
  864. &pnpStartEvent,
  865. Suspended,
  866. KernelMode,
  867. FALSE,
  868. NULL);
  869. ntStatus = Irp->IoStatus.Status;
  870. }
  871. TEST_PATH(ntStatus, FAILED_LOWER_START);
  872. if (NT_SUCCESS(ntStatus)) {
  873. //
  874. // irp completed succesfully by lower
  875. // drivers, start usbport and miniport
  876. //
  877. ntStatus =
  878. USBPORT_DeferredStartDevice(
  879. FdoDeviceObject,
  880. Irp);
  881. #if DBG
  882. if (!NT_SUCCESS(ntStatus)) {
  883. USBPORT_KdPrint((1, "'miniport failed start %x\n", ntStatus));
  884. DEBUG_BREAK();
  885. }
  886. #endif
  887. }
  888. #if DBG
  889. else {
  890. USBPORT_KdPrint((1, "'lower drivers failed start %x\n", ntStatus));
  891. DEBUG_BREAK();
  892. }
  893. #endif
  894. //
  895. // we must complete this irp since we defrerred completion
  896. // with the completion routine.
  897. //
  898. USBPORT_CompleteIrp(FdoDeviceObject,
  899. Irp,
  900. ntStatus,
  901. 0);
  902. goto USBPORT_ProcessPnPIrp_Done;
  903. }
  904. break;
  905. //
  906. // STOP & REMOVE messages unload the driver
  907. // when we get a STOP message it is still possible
  908. // touch the hardware, when we get a REMOVE message
  909. // we have to assume that the hardware is gone.
  910. //
  911. case IRP_MN_STOP_DEVICE:
  912. // check our state and take appropriate action
  913. if (TEST_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STARTED)) {
  914. // device is started, stop it now
  915. ntStatus = USBPORT_StopDevice(FdoDeviceObject,
  916. hardwarePresent);
  917. // not started flag, note: not started is not the
  918. // same as stopped
  919. CLEAR_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STARTED);
  920. SET_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STOPPED);
  921. }
  922. if (!NT_SUCCESS(ntStatus)) {
  923. // bugbug what is our state if stop fails?
  924. TEST_TRAP();
  925. }
  926. // PnP commandment: Thou shalt not fail stop.
  927. Irp->IoStatus.Status =
  928. ntStatus = STATUS_SUCCESS;
  929. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'STOP', 0,
  930. devExt->PnpStateFlags, ntStatus);
  931. // Pass on to PDO
  932. break;
  933. case IRP_MN_QUERY_DEVICE_RELATIONS:
  934. {
  935. PDEVICE_RELATIONS deviceRelations;
  936. USBPORT_KdPrint((1,
  937. "'IRP_MN_QUERY_DEVICE_RELATIONS %x %x\n",
  938. FdoDeviceObject,
  939. irpStack->Parameters.QueryDeviceRelations.Type));
  940. ntStatus = STATUS_SUCCESS;
  941. switch(irpStack->Parameters.QueryDeviceRelations.Type) {
  942. case BusRelations:
  943. // query relations.
  944. // we report only one child, the root hub
  945. // assume success
  946. ntStatus = STATUS_SUCCESS;
  947. ALLOC_POOL_OSOWNED(deviceRelations,
  948. PagedPool,
  949. sizeof(*deviceRelations));
  950. if (!deviceRelations) {
  951. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  952. // Complete the Irp now with failure, don't pass it down.
  953. //
  954. USBPORT_CompleteIrp(FdoDeviceObject,
  955. Irp,
  956. ntStatus,
  957. 0);
  958. goto USBPORT_ProcessPnPIrp_Done;
  959. }
  960. if (devExt->Fdo.RootHubPdo == NULL) {
  961. // we either have not created it or the current one
  962. // has been removed by the OS.
  963. // create a new root hub
  964. ntStatus =
  965. USBPORT_CreateRootHubPdo(FdoDeviceObject,
  966. &devExt->Fdo.RootHubPdo);
  967. }
  968. if (NT_SUCCESS(ntStatus)) {
  969. PDEVICE_EXTENSION rhDevExt;
  970. KIRQL irql;
  971. GET_DEVICE_EXT(rhDevExt, devExt->Fdo.RootHubPdo);
  972. ASSERT_PDOEXT(rhDevExt);
  973. deviceRelations->Count=1;
  974. deviceRelations->Objects[0] =
  975. devExt->Fdo.RootHubPdo;
  976. ObReferenceObject(devExt->Fdo.RootHubPdo);
  977. Irp->IoStatus.Information=(ULONG_PTR)deviceRelations;
  978. // report the same PDO every time ie the PDO is never
  979. // truely remove until the controller is removed
  980. } else {
  981. FREE_POOL(FdoDeviceObject, deviceRelations);
  982. deviceRelations = NULL;
  983. // free the device object if we
  984. // created one
  985. TEST_TRAP();
  986. }
  987. Irp->IoStatus.Status = ntStatus;
  988. USBPORT_KdPrint((1,
  989. "'IRP_MN_QUERY_DEVICE_RELATIONS %x BusRelations\n",
  990. FdoDeviceObject));
  991. break;
  992. case TargetDeviceRelation:
  993. //
  994. // this one gets passed on
  995. //
  996. USBPORT_KdPrint((1,
  997. " IRP_MN_QUERY_DEVICE_RELATIONS %x, TargetDeviceRelation\n",
  998. FdoDeviceObject));
  999. break;
  1000. case RemovalRelations:
  1001. // assume success
  1002. ntStatus = STATUS_SUCCESS;
  1003. deviceRelations = NULL;
  1004. if (USBPORT_IS_USB20(devExt)) {
  1005. deviceRelations =
  1006. USBPORT_FindCompanionControllers(FdoDeviceObject,
  1007. TRUE,
  1008. FALSE);
  1009. if (!deviceRelations) {
  1010. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1011. // Complete the Irp now with failure, don't pass it down.
  1012. //
  1013. USBPORT_CompleteIrp(FdoDeviceObject,
  1014. Irp,
  1015. ntStatus,
  1016. 0);
  1017. goto USBPORT_ProcessPnPIrp_Done;
  1018. }
  1019. }
  1020. Irp->IoStatus.Information=(ULONG_PTR)deviceRelations;
  1021. Irp->IoStatus.Status = ntStatus;
  1022. USBPORT_KdPrint((1,
  1023. "'IRP_MN_QUERY_DEVICE_RELATIONS %x RemovalRelations\n",
  1024. FdoDeviceObject));
  1025. break;
  1026. default:
  1027. //
  1028. // some other kind of relations
  1029. // pass this on
  1030. //
  1031. USBPORT_KdPrint((1,
  1032. "'IRP_MN_QUERY_DEVICE_RELATIONS %x, other relations\n",
  1033. FdoDeviceObject));
  1034. } /* case irpStack->Parameters.QueryDeviceRelations.Type */
  1035. }
  1036. break; /* IRP_MN_QUERY_DEVICE_RELATIONS */
  1037. case IRP_MN_SURPRISE_REMOVAL:
  1038. // hardware is gone
  1039. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'hcSR', 0, ntStatus, 0);
  1040. USBPORT_KdPrint((1, " HC FDO (%x) surprise removed\n",
  1041. FdoDeviceObject));
  1042. DEBUG_BREAK();
  1043. if (TEST_FLAG(devExt->PnpStateFlags, USBPORT_PNP_REMOVED)) {
  1044. // it would be odd to get a surprise remove when
  1045. // we are already removed but it would not 'surprise'
  1046. // me if Win2k did this under some cirumstance
  1047. TEST_TRAP();
  1048. ntStatus =
  1049. USBPORT_PassIrp(FdoDeviceObject,
  1050. NULL,
  1051. NULL,
  1052. TRUE,
  1053. TRUE,
  1054. TRUE,
  1055. Irp);
  1056. goto USBPORT_ProcessPnPIrp_Done;
  1057. }
  1058. // see if we have an interrupt
  1059. // if so disconnect it
  1060. // **
  1061. // DDK implies that that interrupt resources bust be
  1062. // freed on surprise remove and the PCI driver depends
  1063. // on this.
  1064. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_CONNECTED)) {
  1065. // fortunately this cannot fail
  1066. IoDisconnectInterrupt(devExt->Fdo.InterruptObject);
  1067. LOGENTRY(NULL, FdoDeviceObject, LOG_MISC, 'IOCd', 0, 0, 0);
  1068. CLEAR_FDO_FLAG(devExt, USBPORT_FDOFLAG_IRQ_CONNECTED);
  1069. }
  1070. USBPORT_InvalidateController(FdoDeviceObject,
  1071. UsbMpControllerRemoved);
  1072. break;
  1073. case IRP_MN_REMOVE_DEVICE:
  1074. {
  1075. PDEVICE_OBJECT rootHubPdo;
  1076. KIRQL irql;
  1077. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'hcRM', 0, ntStatus, 0);
  1078. USBPORT_KdPrint((1, " HC FDO (%x) is being removed\n",
  1079. FdoDeviceObject));
  1080. // this device is now 'REMOVED'
  1081. KeAcquireSpinLock(&devExt->PendingRequestSpin.sl, &irql);
  1082. USBPORT_ASSERT(!TEST_FLAG(devExt->PnpStateFlags, USBPORT_PNP_REMOVED));
  1083. SET_FLAG(devExt->PnpStateFlags, USBPORT_PNP_REMOVED);
  1084. KeReleaseSpinLock(&devExt->PendingRequestSpin.sl, irql);
  1085. // if we are started AND
  1086. // we haven't been stopped yet then stop now.
  1087. if (TEST_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STARTED) &&
  1088. !TEST_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STOPPED)) {
  1089. NTSTATUS status;
  1090. status = USBPORT_StopDevice(FdoDeviceObject,
  1091. hardwarePresent);
  1092. SET_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STOPPED);
  1093. }
  1094. //
  1095. // pass on to our PDO
  1096. //
  1097. Irp->IoStatus.Status = STATUS_SUCCESS;
  1098. ntStatus =
  1099. USBPORT_PassIrp(FdoDeviceObject,
  1100. NULL,
  1101. NULL,
  1102. TRUE,
  1103. TRUE,
  1104. TRUE,
  1105. Irp);
  1106. // bugbug
  1107. // Flush any requests that are still queued in our driver
  1108. // This DEC matches the INC in our add device,
  1109. // this is our last reference and this will cause the
  1110. // transition 0 -> -1 when all irps pending complete
  1111. //
  1112. // after this wait we consider it safe to 'unload'
  1113. DECREMENT_PENDING_REQUEST_COUNT(FdoDeviceObject, NULL);
  1114. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'watP', 0, 0, FdoDeviceObject);
  1115. KeWaitForSingleObject(&devExt->PendingRequestEvent,
  1116. Suspended,
  1117. KernelMode,
  1118. FALSE,
  1119. NULL);
  1120. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'waPD', 0, 0, FdoDeviceObject);
  1121. // last chance to debug with the log
  1122. DEBUG_BREAK();
  1123. USBPORT_LogFree(FdoDeviceObject, &devExt->Log);
  1124. USBPORT_LogFree(FdoDeviceObject, &devExt->TransferLog);
  1125. USBPORT_LogFree(FdoDeviceObject, &devExt->EnumLog);
  1126. //
  1127. // important to detach FDO from PDO after we pass the irp on
  1128. //
  1129. IoDetachDevice(devExt->Fdo.TopOfStackDeviceObject);
  1130. //
  1131. // Delete the device object we created for this controller
  1132. //
  1133. rootHubPdo = devExt->Fdo.RootHubPdo;
  1134. SET_FLAG(devExt->PnpStateFlags, USBPORT_PNP_DELETED);
  1135. USBPORT_KdPrint((1, "'Deleting HC FDO (%x) now.\n",
  1136. FdoDeviceObject));
  1137. IoDeleteDevice(FdoDeviceObject);
  1138. // HC is FDO gone so root hub is gone.
  1139. //
  1140. // note: in some cases we may not have a root hub
  1141. // PDO since we create it in response to a QBR.
  1142. if (rootHubPdo != NULL) {
  1143. PDEVICE_EXTENSION rhDevExt;
  1144. GET_DEVICE_EXT(rhDevExt, rootHubPdo);
  1145. ASSERT_PDOEXT(rhDevExt);
  1146. SET_FLAG(rhDevExt->PnpStateFlags, USBPORT_PNP_DELETED);
  1147. USBPORT_KdPrint((1, "'Deleting root hub PDO (%x) now.\n",
  1148. rootHubPdo));
  1149. IoDeleteDevice(rootHubPdo);
  1150. }
  1151. goto USBPORT_ProcessPnPIrp_Done;
  1152. }
  1153. break;
  1154. // Quoting from the book of PNP
  1155. //
  1156. // 'The FDO must either fail the IRP or set the
  1157. // IRP's status if it is not going change the IRP's status
  1158. // using a completion routine.'
  1159. case IRP_MN_CANCEL_STOP_DEVICE:
  1160. Irp->IoStatus.Status =
  1161. ntStatus = STATUS_SUCCESS;
  1162. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'cstp', 0,
  1163. devExt->PnpStateFlags, ntStatus);
  1164. break;
  1165. case IRP_MN_QUERY_STOP_DEVICE:
  1166. Irp->IoStatus.Status =
  1167. ntStatus = STATUS_SUCCESS;
  1168. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'qstp', 0,
  1169. devExt->PnpStateFlags, ntStatus);
  1170. break;
  1171. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1172. Irp->IoStatus.Status =
  1173. ntStatus = STATUS_SUCCESS;
  1174. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'crmv', 0,
  1175. devExt->PnpStateFlags, ntStatus);
  1176. break;
  1177. case IRP_MN_QUERY_REMOVE_DEVICE:
  1178. // BUGBUG reverse this in cance query remove?
  1179. if (USBPORT_IS_USB20(devExt)) {
  1180. // make a note on the CCs for this USB 2
  1181. // master controller
  1182. USBPORT_WriteHaction(FdoDeviceObject,
  1183. 2);
  1184. }
  1185. Irp->IoStatus.Status =
  1186. ntStatus = STATUS_SUCCESS;
  1187. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'qrmv', 0,
  1188. devExt->PnpStateFlags, ntStatus);
  1189. break;
  1190. //
  1191. // All other PnP messages passed on to our PDO
  1192. //
  1193. default:
  1194. USBPORT_ASSERT(devExt->Fdo.TopOfStackDeviceObject != NULL);
  1195. USBPORT_KdPrint((2, "'UNKNOWN PNP MESSAGE (%x)\n", irpStack->MinorFunction));
  1196. //
  1197. // All unahndled PnP messages are passed on to the PDO
  1198. //
  1199. } /* case PNP minor function */
  1200. //
  1201. // pass on to our PDO
  1202. //
  1203. ntStatus =
  1204. USBPORT_PassIrp(FdoDeviceObject,
  1205. NULL,
  1206. NULL,
  1207. TRUE,
  1208. TRUE,
  1209. TRUE,
  1210. Irp);
  1211. USBPORT_ProcessPnPIrp_Done:
  1212. // DO NOT touch the Irp from this point on
  1213. return ntStatus;
  1214. }
  1215. NTSTATUS
  1216. USBPORT_DeferredStartDevice(
  1217. PDEVICE_OBJECT FdoDeviceObject,
  1218. PIRP Irp
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This function is called as a result of MN_START_DEVICE,
  1223. it is called after successful completion of the START
  1224. irp by the lower drivers.
  1225. Arguments:
  1226. DeviceObject - DeviceObject for this USB controller.
  1227. Return Value:
  1228. NT Status code.
  1229. --*/
  1230. {
  1231. NTSTATUS ntStatus;
  1232. PIO_STACK_LOCATION irpStack;
  1233. PDEVICE_EXTENSION devExt;
  1234. PAGED_CODE();
  1235. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1236. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1237. ntStatus = USBPORT_GetResources(FdoDeviceObject,
  1238. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated,
  1239. &devExt->Fdo.HcResources);
  1240. if (NT_SUCCESS(ntStatus)) {
  1241. // got resources, start the port driver,
  1242. // connect the interrupt and start miniport.
  1243. ntStatus = USBPORT_StartDevice(FdoDeviceObject,
  1244. &devExt->Fdo.HcResources);
  1245. }
  1246. if (NT_SUCCESS(ntStatus)) {
  1247. CLEAR_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STOPPED);
  1248. SET_FLAG(devExt->PnpStateFlags, USBPORT_PNP_STARTED);
  1249. // consider ourselves powered
  1250. //
  1251. // Are we powered if we fail start?
  1252. // PnP sure thinks we are becuse the OS sends power
  1253. // irps. Since we handle this bogus case (ie have hit it)
  1254. // for the OS we just set ourselves to D0 here.
  1255. devExt->CurrentDevicePowerState = PowerDeviceD0;
  1256. if (USBPORT_IS_USB20(devExt)) {
  1257. USBPORT_RegisterUSB2fdo(FdoDeviceObject);
  1258. // for some reason we only do this fot XPSP1
  1259. // this is really only for the WU install
  1260. // if (USBPORT_IS_USB20(devExt)) {
  1261. // // set the default haction to wait (1) on
  1262. // // successful start
  1263. // USBPORT_WriteHaction(FdoDeviceObject,
  1264. // 1);
  1265. // }
  1266. } else {
  1267. USBPORT_RegisterUSB1fdo(FdoDeviceObject);
  1268. }
  1269. } else {
  1270. SET_FLAG(devExt->PnpStateFlags, USBPORT_PNP_START_FAILED);
  1271. }
  1272. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'dfST', 0, 0, ntStatus);
  1273. return ntStatus;
  1274. }
  1275. PWCHAR
  1276. USB_MakeId(
  1277. PDEVICE_OBJECT FdoDeviceObject,
  1278. PWCHAR IdString,
  1279. PWCHAR Buffer,
  1280. PULONG Length,
  1281. USHORT NullCount,
  1282. USHORT Digits,
  1283. USHORT HexId
  1284. )
  1285. /*
  1286. given a wide Id string like "FOOnnnn\0"
  1287. add the HexId value to nnnn as hex
  1288. this string is appended to the buffer passed in
  1289. eg
  1290. in : FOOnnnn\0 , 0x123A
  1291. out : FOO123A\0
  1292. */
  1293. {
  1294. #define NIBBLE_TO_HEX( byte ) ((WCHAR)Nibble[byte])
  1295. CONST UCHAR Nibble[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
  1296. 'B', 'C', 'D', 'E', 'F'};
  1297. PWCHAR tmp, id;
  1298. PUCHAR p;
  1299. SIZE_T siz, idLen;
  1300. idLen = wcslen(IdString)*sizeof(WCHAR);
  1301. siz = idLen+(USHORT)*Length+(NullCount*sizeof(WCHAR));
  1302. ALLOC_POOL_OSOWNED(tmp, PagedPool, siz);
  1303. if (tmp == NULL) {
  1304. *Length = 0;
  1305. } else {
  1306. // this takes care of the nulls
  1307. RtlCopyMemory(tmp, Buffer, *Length);
  1308. p = (PUCHAR) tmp;
  1309. p += *Length;
  1310. RtlCopyMemory(p, IdString, idLen);
  1311. id = (PWCHAR) p;
  1312. *Length = siz;
  1313. // now convert the vaules
  1314. while (*id != (WCHAR)'n' && Digits) {
  1315. id++;
  1316. }
  1317. switch(Digits) {
  1318. case 2:
  1319. *(id) = NIBBLE_TO_HEX((HexId >> 4) & 0x000f);
  1320. *(id+1) = NIBBLE_TO_HEX(HexId & 0x000f);
  1321. break;
  1322. case 4:
  1323. *(id) = NIBBLE_TO_HEX(HexId >> 12);
  1324. *(id+1) = NIBBLE_TO_HEX((HexId >> 8) & 0x000f);
  1325. *(id+2) = NIBBLE_TO_HEX((HexId >> 4) & 0x000f);
  1326. *(id+3) = NIBBLE_TO_HEX(HexId & 0x000f);
  1327. break;
  1328. }
  1329. }
  1330. if (Buffer != NULL) {
  1331. FREE_POOL(FdoDeviceObject, Buffer);
  1332. }
  1333. return tmp;
  1334. #undef NIBBLE_TO_HEX
  1335. }
  1336. PWCHAR
  1337. USBPORT_GetIdString(
  1338. PDEVICE_OBJECT FdoDeviceObject,
  1339. USHORT Vid,
  1340. USHORT Pid,
  1341. USHORT Rev
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. Make an id string for PnP
  1346. Arguments:
  1347. Return Value:
  1348. NT Status code.
  1349. --*/
  1350. {
  1351. PWCHAR id;
  1352. ULONG length;
  1353. PDEVICE_EXTENSION devExt;
  1354. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1355. ASSERT_FDOEXT(devExt);
  1356. // we need to generate the following series of strings
  1357. // USB\\ROOT_HUB&VIDnnnn&PIDnnnn&REVnnnn\0
  1358. // USB\\ROOT_HUB&VIDnnnn&PIDnnnn\0
  1359. // USB\\ROOT_HUB\0\0
  1360. // allocate space for the three id plus a NULL
  1361. id = NULL;
  1362. length = 0;
  1363. // USB\\ROOT_HUB&VIDnnnn&PIDnnnn&REVnnnn\0
  1364. if (USBPORT_IS_USB20(devExt)) {
  1365. id = USB_MakeId(FdoDeviceObject,
  1366. L"USB\\ROOT_HUB20&VIDnnnn\0",
  1367. id,
  1368. &length,
  1369. 0,
  1370. 4, // four digits
  1371. Vid);
  1372. } else {
  1373. id = USB_MakeId(FdoDeviceObject,
  1374. L"USB\\ROOT_HUB&VIDnnnn\0",
  1375. id,
  1376. &length,
  1377. 0,
  1378. 4, // four digits
  1379. Vid);
  1380. }
  1381. id = USB_MakeId(FdoDeviceObject,
  1382. L"&PIDnnnn\0",
  1383. id,
  1384. &length,
  1385. 0,
  1386. 4, // four digits
  1387. Pid);
  1388. id = USB_MakeId(FdoDeviceObject,
  1389. L"&REVnnnn\0",
  1390. id,
  1391. &length,
  1392. 1, // add a NULL
  1393. 4, // four digits
  1394. Rev);
  1395. // USB\\ROOT_HUB&VIDnnnn&PIDnnnn\0
  1396. if (USBPORT_IS_USB20(devExt)) {
  1397. id = USB_MakeId(FdoDeviceObject,
  1398. L"USB\\ROOT_HUB20&VIDnnnn\0",
  1399. id,
  1400. &length,
  1401. 0,
  1402. 4, // four digits
  1403. Vid);
  1404. } else {
  1405. id = USB_MakeId(FdoDeviceObject,
  1406. L"USB\\ROOT_HUB&VIDnnnn\0",
  1407. id,
  1408. &length,
  1409. 0,
  1410. 4, // four digits
  1411. Vid);
  1412. }
  1413. id = USB_MakeId(FdoDeviceObject,
  1414. L"&PIDnnnn\0",
  1415. id,
  1416. &length,
  1417. 1,
  1418. 4, // four digits
  1419. Pid);
  1420. // USB\\ROOT_HUB\0\0
  1421. if (USBPORT_IS_USB20(devExt)) {
  1422. id = USB_MakeId(FdoDeviceObject,
  1423. L"USB\\ROOT_HUB20\0",
  1424. id,
  1425. &length,
  1426. 2, // double null
  1427. 0, // no digits
  1428. 0);
  1429. } else {
  1430. id = USB_MakeId(FdoDeviceObject,
  1431. L"USB\\ROOT_HUB\0",
  1432. id,
  1433. &length,
  1434. 2, // double null
  1435. 0, // no digits
  1436. 0);
  1437. }
  1438. return(id);
  1439. }
  1440. NTSTATUS
  1441. USBPORT_PdoPnPIrp(
  1442. PDEVICE_OBJECT PdoDeviceObject,
  1443. PIRP Irp
  1444. )
  1445. /*++
  1446. Routine Description:
  1447. Disptach routine for PnP Irps sent to the PDO for the root hub.
  1448. NOTE:
  1449. irps sent to the PDO are always completed by the bus driver
  1450. Arguments:
  1451. DeviceObject - Pdo for the root hub
  1452. Return Value:
  1453. NTSTATUS
  1454. --*/
  1455. {
  1456. PIO_STACK_LOCATION irpStack;
  1457. PDEVICE_CAPABILITIES DeviceCapabilities;
  1458. NTSTATUS ntStatus;
  1459. PDEVICE_EXTENSION rhDevExt;
  1460. PDEVICE_OBJECT fdoDeviceObject;
  1461. // return no infornation by default
  1462. ULONG_PTR information;
  1463. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  1464. ASSERT_PDOEXT(rhDevExt);
  1465. fdoDeviceObject = rhDevExt->HcFdoDeviceObject;
  1466. //GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1467. //ASSERT_FDOEXT(devExt);
  1468. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1469. // don't stomp the current value unless we
  1470. // have to.
  1471. information = Irp->IoStatus.Information;
  1472. USBPORT_ASSERT(irpStack->MajorFunction == IRP_MJ_PNP);
  1473. // PNP messages for the PDO created for the root hub
  1474. switch (irpStack->MinorFunction) {
  1475. case IRP_MN_START_DEVICE:
  1476. {
  1477. KIRQL irql;
  1478. USBPORT_KdPrint((1, " Starting Root hub PDO %x\n",
  1479. PdoDeviceObject));
  1480. DEBUG_BREAK();
  1481. INCREMENT_PENDING_REQUEST_COUNT(PdoDeviceObject, NULL);
  1482. // first create the 'Device'
  1483. ntStatus = USBPORT_RootHub_CreateDevice(fdoDeviceObject,
  1484. PdoDeviceObject);
  1485. //
  1486. // create a symbolic link for the root hub PDO
  1487. // USBUI uses this link to talk to the hub
  1488. //
  1489. if (NT_SUCCESS(ntStatus)) {
  1490. ntStatus = USBPORT_SymbolicLink(TRUE,
  1491. rhDevExt,
  1492. PdoDeviceObject,
  1493. (LPGUID)&GUID_CLASS_USBHUB);
  1494. }
  1495. if (NT_SUCCESS(ntStatus)) {
  1496. // erases remove and stop flags
  1497. rhDevExt->PnpStateFlags = USBPORT_PNP_STARTED;
  1498. // consider ourselves powered when started
  1499. rhDevExt->CurrentDevicePowerState = PowerDeviceD0;
  1500. }
  1501. }
  1502. break;
  1503. case IRP_MN_REMOVE_DEVICE:
  1504. {
  1505. PDEVICE_EXTENSION devExt;
  1506. KIRQL irql;
  1507. USBPORT_KdPrint((1, " Root Hub PDO (%x) is being removed\n",
  1508. PdoDeviceObject));
  1509. LOGENTRY(NULL, fdoDeviceObject, LOG_PNP, 'rhRM', 0, 0, 0);
  1510. GET_DEVICE_EXT(devExt, rhDevExt->HcFdoDeviceObject);
  1511. ASSERT_FDOEXT(devExt);
  1512. // stop if necessary
  1513. USBPORT_StopRootHubPdo(fdoDeviceObject,
  1514. PdoDeviceObject);
  1515. // when is a remove not a remove? when PnP sends it.
  1516. // this flag will be reset when the root hub pdo is
  1517. // started
  1518. SET_FLAG(rhDevExt->PnpStateFlags, USBPORT_PNP_REMOVED);
  1519. // since the PnP convention is for the PDO to exist
  1520. // as long as the physical device exists we do not
  1521. // delete the root hub PDO until the controller is
  1522. // removed.
  1523. // we will call this off just to gixe us a defined state
  1524. rhDevExt->CurrentDevicePowerState = PowerDeviceD3;
  1525. ntStatus = STATUS_SUCCESS;
  1526. }
  1527. break;
  1528. case IRP_MN_STOP_DEVICE:
  1529. // note: since OS PnP will STOP things that are not STARTED
  1530. // we maintain two separate flags for this.
  1531. //
  1532. // the state machine looks like this:
  1533. //
  1534. //
  1535. // / Started \
  1536. // stop = = stopped
  1537. // \ Not Started /
  1538. USBPORT_KdPrint((1, " Root Hub PDO %x is being stopped\n",
  1539. PdoDeviceObject));
  1540. USBPORT_StopRootHubPdo(fdoDeviceObject,
  1541. PdoDeviceObject);
  1542. ntStatus = STATUS_SUCCESS;
  1543. break;
  1544. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  1545. ntStatus = STATUS_SUCCESS;
  1546. break;
  1547. case IRP_MN_QUERY_CAPABILITIES:
  1548. //
  1549. // Handle query caps for the root hub PDO
  1550. //
  1551. USBPORT_KdPrint((1, "'IRP_MN_QUERY_CAPABILITIES (rh PDO)\n"));
  1552. //
  1553. // Get the packet.
  1554. //
  1555. DeviceCapabilities =
  1556. irpStack->Parameters.DeviceCapabilities.Capabilities;
  1557. //
  1558. // The power state capabilities for the root
  1559. // hub are based on those of the host controller.
  1560. //
  1561. // We then modify them based on the power rules of
  1562. // USB
  1563. //
  1564. RtlCopyMemory(DeviceCapabilities,
  1565. &rhDevExt->DeviceCapabilities,
  1566. sizeof(*DeviceCapabilities));
  1567. ntStatus = STATUS_SUCCESS;
  1568. break;
  1569. case IRP_MN_QUERY_ID:
  1570. USBPORT_KdPrint((3, "'IOCTL_BUS_QUERY_ID\n"));
  1571. ntStatus = STATUS_SUCCESS;
  1572. switch (irpStack->Parameters.QueryId.IdType) {
  1573. case BusQueryDeviceID:
  1574. // return the 'generic' root hub ID
  1575. {
  1576. PWCHAR deviceId;
  1577. WCHAR rootHubDeviceId[] = L"USB\\ROOT_HUB\0";
  1578. WCHAR rootHubDeviceId_20[] = L"USB\\ROOT_HUB20\0";
  1579. PWCHAR id;
  1580. ULONG siz;
  1581. PDEVICE_EXTENSION devExt;
  1582. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1583. ASSERT_FDOEXT(devExt);
  1584. id = &rootHubDeviceId[0];
  1585. siz = sizeof(rootHubDeviceId);
  1586. if (USBPORT_IS_USB20(devExt)) {
  1587. id = &rootHubDeviceId_20[0];
  1588. siz = sizeof(rootHubDeviceId_20);
  1589. }
  1590. ALLOC_POOL_OSOWNED(deviceId,
  1591. PagedPool,
  1592. siz);
  1593. if (deviceId) {
  1594. RtlCopyMemory(deviceId,
  1595. id,
  1596. siz);
  1597. }
  1598. // device id for root hub is USB\ROOT_HUB
  1599. information = (ULONG_PTR) deviceId;
  1600. }
  1601. LOGENTRY(NULL, fdoDeviceObject, LOG_PNP, 'DVid', information, 0, 0);
  1602. break;
  1603. case BusQueryHardwareIDs:
  1604. {
  1605. PDEVICE_EXTENSION devExt;
  1606. //
  1607. // generate hardware id for root hub
  1608. //
  1609. // A host controllers root hub VID,PID,REV is derived
  1610. // from the controllers PCI VID,DEV,REV that is:
  1611. // root hub VID = hc VID (vendor id)
  1612. // root hub PID = hc DEV (device id)
  1613. // root hub REV = hc REV (revision id)
  1614. //
  1615. // this allows filter drivers to be loaded on
  1616. // specific root hub instances.
  1617. // for HW IDs we generate:
  1618. // USB\PORT_ROOT_HUB&VIDnnnn&PIDnnnn&REVnnnn
  1619. // USB\PORT_ROOT_HUB&VIDnnnn&PIDnnnn
  1620. // USB\PORT_ROOT_HUB
  1621. //
  1622. GET_DEVICE_EXT(devExt, fdoDeviceObject);
  1623. ASSERT_FDOEXT(devExt);
  1624. information =
  1625. (ULONG_PTR) USBPORT_GetIdString(
  1626. fdoDeviceObject,
  1627. devExt->Fdo.PciVendorId,
  1628. devExt->Fdo.PciDeviceId,
  1629. (USHORT) devExt->Fdo.PciRevisionId);
  1630. LOGENTRY(NULL, fdoDeviceObject, LOG_PNP, 'HWid', information, 0, 0);
  1631. }
  1632. break;
  1633. case BusQueryCompatibleIDs:
  1634. information = 0;
  1635. break;
  1636. case BusQueryInstanceID:
  1637. //
  1638. // The root HUB is instanced solely by the controller's id.
  1639. // Hence the UniqueDeviceId above.
  1640. //
  1641. information = 0;
  1642. break;
  1643. default:
  1644. ntStatus = Irp->IoStatus.Status;
  1645. break;
  1646. }
  1647. break;
  1648. case IRP_MN_QUERY_REMOVE_DEVICE:
  1649. case IRP_MN_QUERY_STOP_DEVICE:
  1650. case IRP_MN_CANCEL_STOP_DEVICE:
  1651. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1652. ntStatus = STATUS_SUCCESS;
  1653. break;
  1654. case IRP_MN_QUERY_BUS_INFORMATION:
  1655. {
  1656. // return the standard USB GUID
  1657. PPNP_BUS_INFORMATION busInfo;
  1658. ALLOC_POOL_OSOWNED(busInfo, PagedPool,
  1659. sizeof(PNP_BUS_INFORMATION));
  1660. if (busInfo == NULL) {
  1661. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1662. } else {
  1663. busInfo->BusTypeGuid = GUID_BUS_TYPE_USB;
  1664. busInfo->LegacyBusType = PNPBus;
  1665. busInfo->BusNumber = 0;
  1666. ntStatus = STATUS_SUCCESS;
  1667. information = (ULONG_PTR) busInfo;
  1668. }
  1669. }
  1670. break;
  1671. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1672. USBPORT_KdPrint((1," IRP_MN_QUERY_DEVICE_RELATIONS (PDO) %x %x\n",
  1673. PdoDeviceObject,
  1674. irpStack->Parameters.QueryDeviceRelations.Type));
  1675. if (irpStack->Parameters.QueryDeviceRelations.Type ==
  1676. TargetDeviceRelation) {
  1677. PDEVICE_RELATIONS deviceRelations = NULL;
  1678. ALLOC_POOL_OSOWNED(deviceRelations, PagedPool, sizeof(*deviceRelations));
  1679. if (deviceRelations == NULL) {
  1680. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1681. } else {
  1682. // return a reference to ourselves
  1683. deviceRelations->Count = 1;
  1684. ObReferenceObject(PdoDeviceObject);
  1685. deviceRelations->Objects[0] =
  1686. PdoDeviceObject;
  1687. ntStatus = STATUS_SUCCESS;
  1688. }
  1689. USBPORT_KdPrint((1, " TargetDeviceRelation to Root Hub PDO - complt\n"));
  1690. information = (ULONG_PTR) deviceRelations;
  1691. } else {
  1692. ntStatus = Irp->IoStatus.Status;
  1693. information = Irp->IoStatus.Information;
  1694. }
  1695. break;
  1696. case IRP_MN_QUERY_INTERFACE:
  1697. USBPORT_KdPrint((1," IRP_MN_QUERY_INTERFACE (PDO) %x\n",
  1698. PdoDeviceObject));
  1699. ntStatus =
  1700. USBPORT_GetBusInterface(fdoDeviceObject,
  1701. PdoDeviceObject,
  1702. Irp);
  1703. break;
  1704. case IRP_MN_SURPRISE_REMOVAL:
  1705. USBPORT_KdPrint((1," IRP_MN_SURPRISE_REMOVAL (PDO) %x\n",
  1706. PdoDeviceObject));
  1707. ntStatus = STATUS_SUCCESS;
  1708. break;
  1709. default:
  1710. //
  1711. // default behavior for an unhandled PnP irp is to return the
  1712. // status currently in the irp
  1713. USBPORT_KdPrint((1, " PnP IOCTL(%d) to root hub PDO not handled\n",
  1714. irpStack->MinorFunction));
  1715. ntStatus = Irp->IoStatus.Status;
  1716. } /* switch, PNP minor function */
  1717. USBPORT_CompleteIrp(PdoDeviceObject,
  1718. Irp,
  1719. ntStatus,
  1720. information);
  1721. return ntStatus;
  1722. }
  1723. NTSTATUS
  1724. USBPORT_CreateRootHubPdo(
  1725. PDEVICE_OBJECT FdoDeviceObject,
  1726. PDEVICE_OBJECT *RootHubPdo
  1727. )
  1728. /*++
  1729. Routine Description:
  1730. Attempt to create the root hub
  1731. Arguments:
  1732. *RootHubPdo set to NULL if unsuccessful
  1733. Return Value:
  1734. NTSTATUS
  1735. --*/
  1736. {
  1737. ULONG index = 0;
  1738. UNICODE_STRING rootHubPdoUnicodeString;
  1739. PDEVICE_EXTENSION rhDevExt, devExt;
  1740. PDEVICE_OBJECT deviceObject = NULL;
  1741. NTSTATUS ntStatus;
  1742. PAGED_CODE();
  1743. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1744. ASSERT_FDOEXT(devExt);
  1745. // those who wear priestly robes say we must do this
  1746. do {
  1747. ntStatus =
  1748. USBPORT_MakeRootHubPdoName(FdoDeviceObject,
  1749. &rootHubPdoUnicodeString,
  1750. index);
  1751. if (NT_SUCCESS(ntStatus)) {
  1752. ntStatus =
  1753. IoCreateDevice(devExt->Fdo.MiniportDriver->DriverObject,
  1754. sizeof(DEVICE_EXTENSION),
  1755. &rootHubPdoUnicodeString,
  1756. FILE_DEVICE_BUS_EXTENDER,
  1757. 0,
  1758. FALSE,
  1759. &deviceObject);
  1760. index++;
  1761. // delete the usbicode string we used for the
  1762. // device name -- we don't need it anymore
  1763. RtlFreeUnicodeString(&rootHubPdoUnicodeString);
  1764. }
  1765. } while (ntStatus == STATUS_OBJECT_NAME_COLLISION);
  1766. if (NT_SUCCESS(ntStatus)) {
  1767. if (deviceObject != NULL) {
  1768. rhDevExt = deviceObject->DeviceExtension;
  1769. LOGENTRY(NULL, FdoDeviceObject, LOG_PNP, 'rPDO', deviceObject, rhDevExt, 0);
  1770. rhDevExt->DummyUsbdExtension = USBPORT_DummyUsbdExtension;
  1771. rhDevExt->Sig = ROOTHUB_DEVICE_EXT_SIG;
  1772. INITIALIZE_PENDING_REQUEST_COUNTER(rhDevExt);
  1773. // transition to -1 means we have no pending requests
  1774. INCREMENT_PENDING_REQUEST_COUNT(deviceObject, NULL);
  1775. // point to our creator
  1776. rhDevExt->HcFdoDeviceObject = FdoDeviceObject;
  1777. // initialize root hub extension
  1778. USBPORT_ComputeRootHubDeviceCaps(FdoDeviceObject,
  1779. deviceObject);
  1780. // initialize object
  1781. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  1782. deviceObject->Flags |= DO_POWER_PAGABLE;
  1783. deviceObject->StackSize = FdoDeviceObject->StackSize;
  1784. } else {
  1785. TEST_TRAP();
  1786. // sucess but no devobj?
  1787. // we will return an error
  1788. ntStatus = STATUS_UNSUCCESSFUL;
  1789. }
  1790. }
  1791. if (NT_SUCCESS(ntStatus)) {
  1792. *RootHubPdo = deviceObject;
  1793. } else {
  1794. *RootHubPdo = NULL;
  1795. }
  1796. return ntStatus;
  1797. }
  1798. NTSTATUS
  1799. USBPORT_CreatePortFdoSymbolicLink(
  1800. PDEVICE_OBJECT FdoDeviceObject
  1801. )
  1802. /*++
  1803. Routine Description:
  1804. Attempt to create a symbolic link for the HC. We use the
  1805. PnP APIs to generate a name based on the USBPORT Host
  1806. Controller Class GUID defined in USB.H
  1807. Arguments:
  1808. *RootHubPdo set to NULL if unsuccessful
  1809. Return Value:
  1810. NTSTATUS
  1811. --*/
  1812. {
  1813. PDEVICE_EXTENSION devExt;
  1814. NTSTATUS ntStatus;
  1815. PAGED_CODE();
  1816. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1817. ntStatus = USBPORT_SymbolicLink(TRUE,
  1818. devExt,
  1819. devExt->Fdo.PhysicalDeviceObject,
  1820. (LPGUID)&GUID_CLASS_USB_HOST_CONTROLLER);
  1821. return ntStatus;
  1822. }
  1823. VOID
  1824. USBPORT_StopRootHubPdo(
  1825. PDEVICE_OBJECT FdoDeviceObject,
  1826. PDEVICE_OBJECT PdoDeviceObject
  1827. )
  1828. /*++
  1829. Routine Description:
  1830. Attempt to STOP the root hub
  1831. Arguments:
  1832. Return Value:
  1833. NTSTATUS
  1834. --*/
  1835. {
  1836. PDEVICE_EXTENSION rhDevExt, devExt;
  1837. GET_DEVICE_EXT(rhDevExt, PdoDeviceObject);
  1838. ASSERT_PDOEXT(rhDevExt);
  1839. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1840. ASSERT_FDOEXT(devExt);
  1841. // disable the root hub notification interrupt
  1842. // we won't need it while we are stopped
  1843. MPRH_DisableIrq(devExt);
  1844. // at this point no new notifications can come in for
  1845. // the root hub
  1846. // remove any start callback notifications
  1847. rhDevExt->Pdo.HubInitCallback = NULL;
  1848. rhDevExt->Pdo.HubInitContext = NULL;
  1849. // remove the root hub 'device' the root hub PDO
  1850. // will remain
  1851. if (TEST_FLAG(rhDevExt->PnpStateFlags, USBPORT_PNP_STARTED)) {
  1852. USBPORT_RootHub_RemoveDevice(FdoDeviceObject,
  1853. PdoDeviceObject);
  1854. // stopped = NOT started
  1855. CLEAR_FLAG(rhDevExt->PnpStateFlags, USBPORT_PNP_STARTED);
  1856. }
  1857. if (TEST_FLAG(rhDevExt->Flags, USBPORT_FLAG_SYM_LINK)) {
  1858. USBPORT_SymbolicLink(FALSE,
  1859. rhDevExt,
  1860. PdoDeviceObject,
  1861. (LPGUID)&GUID_CLASS_USBHUB);
  1862. }
  1863. SET_FLAG(rhDevExt->PnpStateFlags, USBPORT_PNP_STOPPED);
  1864. // resume the controller if it is 'suspended'
  1865. USBPORT_ResumeController(FdoDeviceObject);
  1866. }
  1867. /*
  1868. Registry Key cache for miniports. Since the miniports cannot read
  1869. the registry from the another thread other than the PNP thread we cache
  1870. the reg values read from PNP start.
  1871. Miniports re-read the registry on a re-start.
  1872. */
  1873. PUSBPORT_REG_CACHE_ENTRY
  1874. USBPORT_GetCahceEntry(
  1875. PDEVICE_OBJECT FdoDeviceObject,
  1876. BOOLEAN SoftwareBranch,
  1877. PWCHAR KeyNameString,
  1878. ULONG KeyNameStringLength
  1879. )
  1880. /*++
  1881. Routine Description:
  1882. Fetches a registry key value from the cache if there
  1883. Arguments:
  1884. Return Value:
  1885. returns cached entry or NULL if not found
  1886. --*/
  1887. {
  1888. PLIST_ENTRY listEntry;
  1889. PDEVICE_EXTENSION devExt;
  1890. PUSBPORT_REG_CACHE_ENTRY regEntry;
  1891. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1892. ASSERT_FDOEXT(devExt);
  1893. // walk the list
  1894. GET_HEAD_LIST(devExt->Fdo.RegistryCache, listEntry);
  1895. while (listEntry &&
  1896. listEntry != &devExt->Fdo.RegistryCache) {
  1897. regEntry = (PUSBPORT_REG_CACHE_ENTRY) CONTAINING_RECORD(
  1898. listEntry,
  1899. struct _USBPORT_REG_CACHE_ENTRY,
  1900. RegLink);
  1901. ASSERT_REG_CACHE(regEntry);
  1902. if (KeyNameStringLength == regEntry->KeyNameStringLength &&
  1903. SoftwareBranch == regEntry->SoftwareBranch &&
  1904. RtlCompareMemory(regEntry->KeyNameString,
  1905. KeyNameString,
  1906. KeyNameStringLength)) {
  1907. USBPORT_KdPrint((1, " reg entry found in cache\n"));
  1908. return regEntry;
  1909. }
  1910. listEntry = regEntry->RegLink.Flink;
  1911. }
  1912. USBPORT_KdPrint((1, " reg entry not in cache\n"));
  1913. return NULL;
  1914. }
  1915. NTSTATUS
  1916. USBPORT_AddCahcedRegistryKey(
  1917. PDEVICE_OBJECT FdoDeviceObject,
  1918. BOOLEAN SoftwareBranch,
  1919. PWCHAR KeyNameString,
  1920. ULONG KeyNameStringLength,
  1921. PVOID Data,
  1922. ULONG DataLength
  1923. )
  1924. /*++
  1925. Routine Description:
  1926. Adds a reg key value to the cache
  1927. Arguments:
  1928. Return Value:
  1929. returns STATUS_SUCCESS if the value was added to our cache
  1930. --*/
  1931. {
  1932. PDEVICE_EXTENSION devExt;
  1933. PUSBPORT_REG_CACHE_ENTRY regEntry;
  1934. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1935. ASSERT_FDOEXT(devExt);
  1936. ALLOC_POOL_Z(regEntry, PagedPool,
  1937. sizeof(*regEntry)+KeyNameStringLength);
  1938. if (regEntry != NULL) {
  1939. ALLOC_POOL_Z(regEntry->Data, PagedPool, DataLength);
  1940. if (regEntry->Data != NULL) {
  1941. regEntry->Sig = SIG_REG_CACHE;
  1942. regEntry->SoftwareBranch = SoftwareBranch;
  1943. regEntry->KeyNameStringLength;
  1944. regEntry->DataLength = DataLength;
  1945. RtlCopyMemory(regEntry->Data, (PUCHAR)Data, DataLength);
  1946. RtlCopyMemory(&regEntry->KeyNameString[0], KeyNameString,
  1947. KeyNameStringLength);
  1948. InsertTailList(&devExt->Fdo.RegistryCache, &regEntry->RegLink);
  1949. USBPORT_KdPrint((1, " adding cache reg entry %x\n", regEntry));
  1950. return STATUS_SUCCESS;
  1951. } else {
  1952. FREE_POOL(FdoDeviceObject, regEntry);
  1953. }
  1954. }
  1955. return STATUS_INSUFFICIENT_RESOURCES;
  1956. }
  1957. NTSTATUS
  1958. USBPORT_GetCachedRegistryKeyValueForPdo(
  1959. PDEVICE_OBJECT FdoDeviceObject,
  1960. PDEVICE_OBJECT PhysicalDeviceObject,
  1961. BOOLEAN SoftwareBranch,
  1962. PWCHAR KeyNameString,
  1963. ULONG KeyNameStringLength,
  1964. PVOID Data,
  1965. ULONG DataLength
  1966. )
  1967. /*++
  1968. Routine Description:
  1969. Fetches a registry key value from the cache since we cannot read
  1970. the registry on a thread other than the PNP,POWER thread
  1971. We cache entries between PNP start and STOP
  1972. Arguments:
  1973. Return Value:
  1974. returns STATUS_SUCCESS if the value is found in the cache
  1975. --*/
  1976. {
  1977. PDEVICE_EXTENSION devExt;
  1978. PUSBPORT_REG_CACHE_ENTRY regEntry;
  1979. NTSTATUS ntStatus;
  1980. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  1981. ASSERT_FDOEXT(devExt);
  1982. USBPORT_KdPrint((1, " USBPORT_GetCahcedRegistryKeyValueForPDO\n"));
  1983. // read from the registry if we can
  1984. if (TEST_FDO_FLAG(devExt, USBPORT_FDOFLAG_ON_PNP_THREAD)) {
  1985. ntStatus = USBPORT_GetRegistryKeyValueForPdo(FdoDeviceObject,
  1986. PhysicalDeviceObject,
  1987. SoftwareBranch,
  1988. KeyNameString,
  1989. KeyNameStringLength,
  1990. Data,
  1991. DataLength);
  1992. if (NT_SUCCESS(ntStatus)) {
  1993. // cache it, if this fails we just return the result
  1994. // of the read
  1995. USBPORT_AddCahcedRegistryKey(
  1996. FdoDeviceObject,
  1997. SoftwareBranch,
  1998. KeyNameString,
  1999. KeyNameStringLength,
  2000. Data,
  2001. DataLength);
  2002. }
  2003. return ntStatus;
  2004. }
  2005. // just read from the cache
  2006. regEntry = USBPORT_GetCahceEntry(FdoDeviceObject,
  2007. SoftwareBranch,
  2008. KeyNameString,
  2009. KeyNameStringLength);
  2010. if (regEntry != NULL) {
  2011. if (regEntry->DataLength <= DataLength) {
  2012. RtlCopyMemory(Data, regEntry->Data, regEntry->DataLength);
  2013. ntStatus = STATUS_SUCCESS;
  2014. TEST_TRAP();
  2015. } else {
  2016. ntStatus = STATUS_BUFFER_TOO_SMALL;
  2017. }
  2018. } else {
  2019. ntStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  2020. }
  2021. return ntStatus;
  2022. }
  2023. VOID
  2024. USBPORT_FlushCahcedRegistryKeys(
  2025. PDEVICE_OBJECT FdoDeviceObject
  2026. )
  2027. /*++
  2028. Routine Description:
  2029. Flushes cache. Removes all cached registry keys.
  2030. Arguments:
  2031. Return Value:
  2032. none.
  2033. --*/
  2034. {
  2035. PDEVICE_EXTENSION devExt;
  2036. PUSBPORT_REG_CACHE_ENTRY regEntry;
  2037. PLIST_ENTRY listEntry;
  2038. GET_DEVICE_EXT(devExt, FdoDeviceObject);
  2039. ASSERT_FDOEXT(devExt);
  2040. while (!IsListEmpty(&devExt->Fdo.RegistryCache)) {
  2041. listEntry = RemoveHeadList(&devExt->Fdo.RegistryCache);
  2042. regEntry = (PUSBPORT_REG_CACHE_ENTRY) CONTAINING_RECORD(
  2043. listEntry,
  2044. struct _USBPORT_REG_CACHE_ENTRY,
  2045. RegLink);
  2046. ASSERT_REG_CACHE(regEntry);
  2047. FREE_POOL(FdoDeviceObject, regEntry->Data);
  2048. FREE_POOL(FdoDeviceObject, regEntry);
  2049. }
  2050. }