Source code of Windows XP (NT5)
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.

742 lines
17 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. USBHUBF.C
  5. Abstract:
  6. Environment:
  7. kernel mode only
  8. Notes:
  9. Revision History:
  10. --*/
  11. #include <wdm.h>
  12. #include "stdarg.h"
  13. #include "stdio.h"
  14. #include "dbci.h"
  15. #include "dbclass.h"
  16. #include "dbfilter.h"
  17. #include "usbioctl.h"
  18. //
  19. // Registry keys
  20. //
  21. #define DBCLASS_HUB_IS_ACPI_DBC 0x00000001
  22. #define DBCLASS_HUB_IS_USB_DBC 0x00000002
  23. extern LONG DBCLASS_AcpiDBCHubParentPort;
  24. NTSTATUS
  25. DBCLASS_UsbhubQBusRelationsComplete(
  26. IN PDEVICE_OBJECT DeviceObject,
  27. IN PIRP Irp,
  28. IN PVOID Context
  29. )
  30. /*++
  31. Routine Description:
  32. Arguments:
  33. DeviceObject - a pointer to the device object
  34. Irp - a pointer to the irp
  35. Context - NULL ptr
  36. Return Value:
  37. STATUS_SUCCESS
  38. --*/
  39. {
  40. PDEVICE_RELATIONS deviceRelations;
  41. ULONG i;
  42. PDEVICE_OBJECT busFilterMdo = Context;
  43. PDEVICE_EXTENSION deviceExtension;
  44. PDEVICE_OBJECT mdoUSB;
  45. PDBC_CONTEXT dbcContext;
  46. deviceExtension = busFilterMdo->DeviceExtension;
  47. deviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  48. LOGENTRY(LOG_MISC, 'UQBR', busFilterMdo, 0, deviceRelations);
  49. if (deviceRelations == NULL) {
  50. LOGENTRY(LOG_MISC, 'UQBn', busFilterMdo, 0, deviceRelations);
  51. return STATUS_SUCCESS;
  52. }
  53. // try to find the DBC controller associated with this hub
  54. //
  55. // Since the filter is loaded for every hub we need to see
  56. // if this hub is part of a DBC subsystem
  57. dbcContext = deviceExtension->DbcContext;
  58. if (dbcContext == NULL) {
  59. DBCLASS_KdPrint((1, "'>QBR USB, HUB NOT DBC\n"));
  60. // no context means the hub is not part of DBC
  61. LOGENTRY(LOG_MISC, 'hQBi', 0, 0, 0);
  62. return STATUS_SUCCESS;
  63. }
  64. for (i=0; i< deviceRelations->Count; i++) {
  65. DBCLASS_KdPrint((1, "'>QBR USB PDO[%d] %x\n", i,
  66. deviceRelations->Objects[i]));
  67. LOGENTRY(LOG_MISC, 'QBRd', deviceRelations->Objects[i], i, 0);
  68. // hub is returning a PDO, see if we know
  69. // about it
  70. mdoUSB = DBCLASS_FindDevicePdo(deviceRelations->Objects[i]);
  71. if (mdoUSB) {
  72. // we know about this one,
  73. // see if we can link it to a controller
  74. PDEVICE_EXTENSION mdoUSBDeviceExtension;
  75. mdoUSBDeviceExtension = mdoUSB->DeviceExtension;
  76. mdoUSBDeviceExtension->DbcContext = dbcContext;
  77. } else {
  78. PDEVICE_OBJECT deviceFilterObject;
  79. NTSTATUS ntStatus;
  80. // don't know about it,
  81. // create an MDO for this device
  82. ntStatus = DBCLASS_CreateDeviceFilterObject(
  83. deviceExtension->DriverObject,
  84. &deviceFilterObject,
  85. deviceRelations->Objects[i],
  86. dbcContext,
  87. DB_FDO_USB_DEVICE);
  88. DBCLASS_KdPrint((1, "'>>QBR attaching to USB PDO[%d] %x\n", i,
  89. deviceRelations->Objects[i]));
  90. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB) Create DO %x for USB PDO\n", deviceFilterObject));
  91. }
  92. }
  93. return STATUS_SUCCESS;
  94. }
  95. NTSTATUS
  96. DBCLASS_UsbhubBusFilterDispatch(
  97. PDEVICE_OBJECT DeviceObject,
  98. PIRP Irp,
  99. PBOOLEAN Handled
  100. )
  101. /*++
  102. Routine Description:
  103. This is a call to the root hub PDO
  104. Arguments:
  105. DeviceObject - Device bay Filter FDO
  106. Return Value:
  107. NTSTATUS
  108. --*/
  109. {
  110. PIO_STACK_LOCATION irpStack;
  111. NTSTATUS ntStatus;
  112. PDEVICE_EXTENSION deviceExtension;
  113. deviceExtension = DeviceObject->DeviceExtension;
  114. ntStatus = Irp->IoStatus.Status;
  115. *Handled = FALSE;
  116. irpStack = IoGetCurrentIrpStackLocation (Irp);
  117. LOGENTRY(LOG_MISC, 'HBf>', 0, DeviceObject, Irp);
  118. DBCLASS_ASSERT(deviceExtension->FdoType == DB_FDO_USBHUB_BUS);
  119. DBCLASS_KdPrint((2, "'(dbfilter)(bus)(USB)IRP_MJ_ (%08X) IRP_MN_ (%08X)\n",
  120. irpStack->MajorFunction, irpStack->MinorFunction));
  121. switch (irpStack->MajorFunction) {
  122. case IRP_MJ_PNP:
  123. switch (irpStack->MinorFunction) {
  124. case IRP_MN_START_DEVICE:
  125. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_START_DEVICE\n"));
  126. break;
  127. case IRP_MN_STOP_DEVICE:
  128. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_STOP_DEVICE\n"));
  129. break;
  130. case IRP_MN_REMOVE_DEVICE:
  131. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_REMOVE_DEVICE\n"));
  132. // detach from the usbhub FDO and delete our
  133. // MDO
  134. DBCLASS_RemoveBusFilterMDOFromList(DeviceObject);
  135. IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
  136. IoDeleteDevice (DeviceObject);
  137. DBCLASS_KdPrint((1, "'REMOVE DB Filter on USB HUB\n"));
  138. break;
  139. case IRP_MN_QUERY_DEVICE_RELATIONS:
  140. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(USB)IRP_MN_QUERY_DEVICE_RELATIONS\n"));
  141. //#if DBG
  142. // DBCLASS_Get1394BayPortMapping(deviceExtension->DbcContext);
  143. //#endif
  144. //
  145. // do the check for USB hubs that are part of a DBC
  146. //
  147. //
  148. // Ask the hub if it has a DBC hanging on it
  149. //
  150. if (deviceExtension->DbcContext == NULL &&
  151. DBCLASS_IsHubPartOfUSB_DBC(DeviceObject)) {
  152. deviceExtension->DbcContext =
  153. DBCLASS_FindControllerUSB(deviceExtension->DriverObject,
  154. DeviceObject,
  155. deviceExtension->PhysicalDeviceObject);
  156. }
  157. *Handled = TRUE;
  158. if (irpStack->Parameters.QueryDeviceRelations.Type == BusRelations) {
  159. DBCLASS_KdPrint((1,"'>>QBR USB BUS\n"));
  160. IoCopyCurrentIrpStackLocationToNext(Irp);
  161. // Set up a completion routine to handle marking the IRP.
  162. IoSetCompletionRoutine(Irp,
  163. DBCLASS_UsbhubQBusRelationsComplete,
  164. DeviceObject,
  165. TRUE,
  166. TRUE,
  167. TRUE);
  168. } else {
  169. IoSkipCurrentIrpStackLocation(Irp)
  170. }
  171. // Now Pass down the IRP
  172. ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
  173. break;
  174. } /* irpStack->MinorFunction */
  175. break;
  176. } /* irpStack->MajorFunction */
  177. LOGENTRY(LOG_MISC, 'HBf<', 0, DeviceObject, 0);
  178. return ntStatus;
  179. }
  180. ULONG
  181. DBCLASS_IsHubPartOf_DBC(
  182. PDEVICE_OBJECT DeviceObject
  183. )
  184. /*++
  185. Routine Description:
  186. This call reads a registry key that tells us if this usb hub is part
  187. of a device bay controller
  188. Arguments:
  189. DeviceObject - Device bay Filter FDO
  190. Return Value:
  191. NTSTATUS
  192. --*/
  193. {
  194. ULONG flags = 0;
  195. NTSTATUS ntStatus;
  196. PDEVICE_EXTENSION deviceExtension;
  197. PAGED_CODE();
  198. deviceExtension = DeviceObject->DeviceExtension;
  199. ntStatus = DBCLASS_GetRegistryKeyValueForPdo(
  200. deviceExtension->PhysicalDeviceObject,
  201. FALSE,
  202. IS_DEVICE_BAY_KEY,
  203. sizeof(IS_DEVICE_BAY_KEY),
  204. &flags,
  205. sizeof(flags));
  206. DBCLASS_KdPrint((2, "'GetRegistryKeyValueForPdo ntStatus = %x flags = %x\n",
  207. ntStatus, flags));
  208. return flags;
  209. }
  210. BOOLEAN
  211. DBCLASS_IsHubPartOfACPI_DBC(
  212. PDEVICE_OBJECT DeviceObject
  213. )
  214. /*++
  215. Routine Description:
  216. This is a call to a usb hub PDO
  217. Arguments:
  218. DeviceObject - Device bay Filter FDO
  219. Return Value:
  220. NTSTATUS
  221. --*/
  222. {
  223. BOOLEAN isDB;
  224. ULONG flags;
  225. // see if it is an acpiDBC, if so mark it in
  226. // the registry
  227. if (DBCLASS_AcpiDBCHubParentPort != -1) {
  228. PDEVICE_EXTENSION deviceExtension;
  229. deviceExtension = DeviceObject->DeviceExtension;
  230. DBCLASS_CheckForAcpiDeviceBayHubs(
  231. deviceExtension->PhysicalDeviceObject,
  232. (ULONG) DBCLASS_AcpiDBCHubParentPort);
  233. }
  234. flags = DBCLASS_IsHubPartOf_DBC(DeviceObject);
  235. isDB = (BOOLEAN) flags & DBCLASS_HUB_IS_ACPI_DBC;
  236. #ifdef DBG
  237. if (isDB) {
  238. DBCLASS_KdPrint((1, "'*** USBHUB for ACPI DBC Found\n"));
  239. BRK_ON_TRAP();
  240. }
  241. #endif
  242. return isDB;
  243. }
  244. BOOLEAN
  245. DBCLASS_IsHubPartOfUSB_DBC(
  246. PDEVICE_OBJECT DeviceObject
  247. )
  248. /*++
  249. Routine Description:
  250. This is a call to a usb hub PDO
  251. Arguments:
  252. DeviceObject - Device bay Filter FDO
  253. Return Value:
  254. NTSTATUS
  255. --*/
  256. {
  257. BOOLEAN isDB;
  258. ULONG flags;
  259. flags = DBCLASS_IsHubPartOf_DBC(DeviceObject);
  260. isDB = (BOOLEAN) flags & DBCLASS_HUB_IS_USB_DBC;
  261. #ifdef DBG
  262. if (isDB) {
  263. DBCLASS_KdPrint((1, "'USBHUB for USB DBC Found!\n"));
  264. BRK_ON_TRAP();
  265. }
  266. #endif
  267. return isDB;
  268. }
  269. NTSTATUS
  270. DBCLASS_GetHubDBCGuid(
  271. PDEVICE_OBJECT DeviceObject,
  272. PUCHAR DbcGuid
  273. )
  274. /*++
  275. Routine Description:
  276. This is a call to the root hub PDO
  277. Arguments:
  278. DeviceObject - Device bay Filter FDO
  279. Return Value:
  280. NTSTATUS
  281. --*/
  282. {
  283. NTSTATUS ntStatus;
  284. PDEVICE_EXTENSION deviceExtension;
  285. PAGED_CODE();
  286. deviceExtension = DeviceObject->DeviceExtension;
  287. ntStatus = DBCLASS_GetRegistryKeyValueForPdo(
  288. deviceExtension->PhysicalDeviceObject,
  289. FALSE,
  290. DBC_GUID_KEY,
  291. sizeof(DBC_GUID_KEY),
  292. DbcGuid,
  293. 8);
  294. DBCLASS_KdPrint((2, "'GetRegistryKeyValueForPdo ntStatus = %x \n",
  295. ntStatus));
  296. #if DBG
  297. DBCLASS_KdPrint((1, "'DBC GUID FOR HUB\n"));
  298. DBCLASS_KdPrintGuid(1, DbcGuid);
  299. #endif
  300. return ntStatus;
  301. }
  302. NTSTATUS
  303. DBCLASS_SyncGetUsbInfo(
  304. IN PDEVICE_OBJECT DeviceObject,
  305. IN PDEVICE_OBJECT *ParentDeviceObject,
  306. IN PDEVICE_OBJECT *RootHubPdo,
  307. IN PULONG PortNumber
  308. )
  309. /* ++
  310. *
  311. * Routine Description:
  312. *
  313. * Arguments:
  314. *
  315. * Return Value:
  316. *
  317. * NTSTATUS
  318. *
  319. * -- */
  320. {
  321. NTSTATUS ntStatus, status;
  322. PIRP irp;
  323. KEVENT event;
  324. IO_STATUS_BLOCK ioStatus;
  325. PIO_STACK_LOCATION nextStack;
  326. PAGED_CODE();
  327. //
  328. // issue a synchronous request to the Hub Pdo
  329. //
  330. KeInitializeEvent(&event, NotificationEvent, FALSE);
  331. irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO,
  332. DeviceObject,
  333. NULL,
  334. 0,
  335. NULL,
  336. 0,
  337. TRUE, // INTERNAL
  338. &event,
  339. &ioStatus);
  340. if (NULL == irp) {
  341. TRAP();
  342. return STATUS_INSUFFICIENT_RESOURCES;
  343. }
  344. nextStack = IoGetNextIrpStackLocation(irp);
  345. nextStack->Parameters.Others.Argument1 = ParentDeviceObject;
  346. nextStack->Parameters.Others.Argument2 = PortNumber;
  347. nextStack->Parameters.Others.Argument4 = RootHubPdo;
  348. ntStatus = IoCallDriver(DeviceObject, irp);
  349. if (ntStatus == STATUS_PENDING) {
  350. status = KeWaitForSingleObject(&event,
  351. Suspended,
  352. KernelMode,
  353. FALSE,
  354. NULL);
  355. } else {
  356. ioStatus.Status = ntStatus;
  357. }
  358. ntStatus = ioStatus.Status;
  359. DBCLASS_KdPrint((0, "'>>USB-PDO-INFO((%08X)) Parent = (%08X) Port = %d status = %x\n",
  360. DeviceObject, *ParentDeviceObject, *PortNumber, ntStatus));
  361. return ntStatus;
  362. }
  363. USHORT
  364. DBCLASS_GetBayForUSBPdo(
  365. PDBC_CONTEXT DbcContext,
  366. PDEVICE_OBJECT PdoUSB
  367. )
  368. /*++
  369. Routine Description:
  370. given a USB PDO figure out wich bay it is associated with
  371. Arguments:
  372. Return Value:
  373. zero if not a device bay PDO.
  374. --*/
  375. {
  376. USHORT bay = 0;
  377. NTSTATUS ntStatus;
  378. PDEVICE_OBJECT parent = NULL, rootHubPdo = NULL;
  379. ULONG portNumber = 0xFFFFFFFF;
  380. PAGED_CODE();
  381. // find out what port this PDO is in
  382. ntStatus = DBCLASS_SyncGetUsbInfo(PdoUSB,
  383. &parent,
  384. &rootHubPdo,
  385. &portNumber);
  386. if (NT_SUCCESS(ntStatus)) {
  387. for (bay=1; bay <=NUMBER_OF_BAYS(DbcContext); bay++) {
  388. DBCLASS_KdPrint((2, "'bay[%d]-> port %d, hub (%08X)\n",
  389. bay,
  390. DbcContext->BayInformation[bay].UsbHubPort,
  391. DbcContext->BayInformation[bay].UsbHubPdo));
  392. if (DbcContext->BayInformation[bay].UsbHubPort == portNumber
  393. /*&&
  394. DbcContext->BayInformation[bay].UsbHubPdo == parent */) {
  395. break;
  396. }
  397. }
  398. }
  399. if (!bay || bay > NUMBER_OF_BAYS(DbcContext)) {
  400. bay = 0;
  401. DBCLASS_KdPrint((2, "'No bay->port mapping for USB PDO\n"));
  402. }
  403. return bay;
  404. }
  405. NTSTATUS
  406. DBCLASS_SetupUSB_DBC(
  407. PDBC_CONTEXT DbcContext
  408. )
  409. /*++
  410. Routine Description:
  411. given a USB DbcContext, write the appropriate keys
  412. to the registry
  413. Arguments:
  414. Return Value:
  415. NTSTATUS
  416. --*/
  417. {
  418. NTSTATUS ntStatus = STATUS_SUCCESS;
  419. ULONG flags = DBCLASS_HUB_IS_USB_DBC;
  420. PDEVICE_OBJECT parentHubPdo = NULL, rootHubPdo = NULL;
  421. ULONG portNumber;
  422. // get the parent hub info
  423. ntStatus = DBCLASS_SyncGetUsbInfo(
  424. DbcContext->ControllerPdo,
  425. &parentHubPdo,
  426. &rootHubPdo,
  427. &portNumber);
  428. // set the keys
  429. if (NT_SUCCESS(ntStatus)) {
  430. ntStatus = DBCLASS_SetRegistryKeyValueForPdo(
  431. parentHubPdo,
  432. FALSE,
  433. REG_DWORD,
  434. IS_DEVICE_BAY_KEY,
  435. sizeof(IS_DEVICE_BAY_KEY),
  436. &flags,
  437. sizeof(flags));
  438. }
  439. if (NT_SUCCESS(ntStatus)) {
  440. ntStatus = DBCLASS_SetRegistryKeyValueForPdo(
  441. parentHubPdo,
  442. FALSE,
  443. REG_BINARY,
  444. DBC_GUID_KEY,
  445. sizeof(DBC_GUID_KEY),
  446. &DbcContext->SubsystemDescriptor.guid1394Link[0],
  447. 8);
  448. }
  449. return ntStatus;
  450. }
  451. NTSTATUS
  452. DBCLASS_CheckForAcpiDeviceBayHubs(
  453. PDEVICE_OBJECT HubPdo,
  454. ULONG AcpiDBCHubParentPort
  455. )
  456. /*++
  457. Routine Description:
  458. Check to see if this device object
  459. is for a hub that is part of an ACPI DBC
  460. Arguments:
  461. AcpiDBCHubParentPort
  462. 0 = acpi hub is root otherwise upstream port on root
  463. hub the ACPI hub is connected to
  464. Return Value:
  465. NTSTATUS
  466. --*/
  467. {
  468. PDEVICE_OBJECT parentHubPdo = NULL, rootHubPdo = NULL;
  469. ULONG portNumber = 0;
  470. BOOLEAN writeKeys = FALSE;
  471. NTSTATUS ntStatus;
  472. // get the root hub PDO
  473. ntStatus = DBCLASS_SyncGetUsbInfo(
  474. HubPdo,
  475. &parentHubPdo,
  476. &rootHubPdo,
  477. &portNumber);
  478. // failure indicates this is root
  479. if (!NT_SUCCESS(ntStatus)) {
  480. ntStatus = STATUS_SUCCESS;
  481. rootHubPdo = HubPdo;
  482. }
  483. if (NT_SUCCESS(ntStatus)) {
  484. DBCLASS_KdPrint((1, "'>**Check Hub: RHPDO = %x, parentPDO %x, port %d\n",
  485. rootHubPdo,
  486. parentHubPdo,
  487. portNumber));
  488. // is this the root hub?
  489. if (HubPdo == rootHubPdo) {
  490. // Yes
  491. if (AcpiDBCHubParentPort == 0) {
  492. // root hub is acpi hub
  493. writeKeys = TRUE;
  494. }
  495. } else {
  496. // is the parent the root hub?
  497. if (parentHubPdo == rootHubPdo) {
  498. // Yes
  499. if (AcpiDBCHubParentPort == portNumber) {
  500. // root hub ius acpi hub
  501. writeKeys = TRUE;
  502. }
  503. }
  504. }
  505. }
  506. if (writeKeys) {
  507. ULONG flags;
  508. flags = DBCLASS_HUB_IS_ACPI_DBC;
  509. DBCLASS_SetRegistryKeyValueForPdo(
  510. HubPdo,
  511. FALSE,
  512. REG_DWORD,
  513. IS_DEVICE_BAY_KEY,
  514. sizeof(IS_DEVICE_BAY_KEY),
  515. &flags,
  516. sizeof(flags));
  517. // DBCLASS_SetRegistryKeyValueForPdo(
  518. // HubPdo,
  519. // FALSE,
  520. // REG_BINARY,
  521. // DBC_GUID_KEY,
  522. // sizeof(DBC_GUID_KEY),
  523. // &DbcContext->SubsystemDescriptor.guid1394Link[0],
  524. // 8);
  525. }
  526. return ntStatus;
  527. }