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.

316 lines
7.3 KiB

  1. /*++
  2. Copyright (C) 2002 Microsoft Corporation
  3. Module Name:
  4. mpiosup.c
  5. Abstract:
  6. This module contains routines that port drivers can use for support of the MPIO package.
  7. Author:
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. BOOLEAN
  15. PortpFindMPIOSupportedDevice(
  16. IN PUNICODE_STRING DeviceName,
  17. IN PUNICODE_STRING SupportedDevices
  18. );
  19. BOOLEAN
  20. PortpMPIOLoaded(
  21. VOID
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, PortGetMPIODeviceList)
  25. #pragma alloc_text(PAGE, PortpFindMPIOSupportedDevice)
  26. #pragma alloc_text(PAGE, PortpMPIOLoaded)
  27. #pragma alloc_text(PAGE, PortIsDeviceMPIOSupported)
  28. #endif
  29. NTSTATUS
  30. PortGetMPIODeviceList(
  31. IN PUNICODE_STRING RegistryPath,
  32. OUT PUNICODE_STRING MPIODeviceList
  33. )
  34. /*++
  35. Routine Description:
  36. This routine builds and returns the MPIO SupportedDeviceList by querying the value
  37. MPIOSupportedDeviceList under the key 'RegistryPath' (which should be
  38. HKLM\System\CurrentControlSet\Control\MPDEV).
  39. Arguments:
  40. RegistryPath - The Absolute registry path under which MPIOSupportDeviceList lives.
  41. Return Value:
  42. The MULTI_SZ SupportedDeviceList or NULL.
  43. --*/
  44. {
  45. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  46. WCHAR defaultIDs[] = { L"\0" };
  47. NTSTATUS status;
  48. PAGED_CODE();
  49. //
  50. // Zero the table entries.
  51. //
  52. RtlZeroMemory(queryTable, sizeof(queryTable));
  53. //
  54. // The query table has two entries. One for the supporteddeviceList and
  55. // the second which is the 'NULL' terminator.
  56. //
  57. // Indicate that there is NO call-back routine, and to give back the MULTI_SZ as
  58. // one blob, as opposed to individual unicode strings.
  59. //
  60. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
  61. //
  62. // The value to query.
  63. //
  64. queryTable[0].Name = L"MPIOSupportedDeviceList";
  65. //
  66. // Where to put the strings, the type of the key, default values and length.
  67. //
  68. queryTable[0].EntryContext = MPIODeviceList;
  69. queryTable[0].DefaultType = REG_MULTI_SZ;
  70. queryTable[0].DefaultData = defaultIDs;
  71. queryTable[0].DefaultLength = sizeof(defaultIDs);
  72. //
  73. // Try to get the device list.
  74. //
  75. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  76. RegistryPath->Buffer,
  77. queryTable,
  78. NULL,
  79. NULL);
  80. return status;
  81. }
  82. BOOLEAN
  83. PortpFindMPIOSupportedDevice(
  84. IN PUNICODE_STRING DeviceName,
  85. IN PUNICODE_STRING SupportedDevices
  86. )
  87. /*++
  88. Routine Description:
  89. This internal routine compares the two unicode strings for a match.
  90. Arguments:
  91. DeviceName - String built from the current device's inquiry data.
  92. SupportedDevices - MULTI_SZ of devices that are supported.
  93. Return Value:
  94. TRUE - If VendorId/ProductId is found.
  95. --*/
  96. {
  97. PWSTR devices = SupportedDevices->Buffer;
  98. UNICODE_STRING unicodeString;
  99. LONG compare;
  100. PAGED_CODE();
  101. //
  102. // 'devices' is the current buffer in the MULTI_SZ built from
  103. // the registry.
  104. //
  105. while (devices[0]) {
  106. //
  107. // Make the current entry into a unicode string.
  108. //
  109. RtlInitUnicodeString(&unicodeString, devices);
  110. //
  111. // Compare this one with the current device.
  112. //
  113. compare = RtlCompareUnicodeString(&unicodeString, DeviceName, TRUE);
  114. if (compare == 0) {
  115. return TRUE;
  116. }
  117. //
  118. // Advance to next entry in the MULTI_SZ.
  119. //
  120. devices += (unicodeString.MaximumLength / sizeof(WCHAR));
  121. }
  122. return FALSE;
  123. }
  124. BOOLEAN
  125. PortpMPIOLoaded(
  126. VOID
  127. )
  128. /*++
  129. Routine Description:
  130. This internal routine is used to determine whether an mpio package is installed by trying to
  131. open the MPIO SymLink.
  132. NOTE: Perhaps a more exhaustive method can be used in the future.
  133. Arguments:
  134. NONE
  135. Return Value:
  136. TRUE - If MPIO is present.
  137. --*/
  138. {
  139. UNICODE_STRING unicodeName;
  140. PDEVICE_OBJECT controlDeviceObject;
  141. PFILE_OBJECT fileObject;
  142. NTSTATUS status;
  143. PAGED_CODE();
  144. //
  145. // Build the symlink name.
  146. //
  147. RtlInitUnicodeString(&unicodeName, L"\\DosDevices\\MPIOControl");
  148. //
  149. // Get mpio's deviceObject.
  150. //
  151. status = IoGetDeviceObjectPointer(&unicodeName,
  152. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
  153. &fileObject,
  154. &controlDeviceObject);
  155. if (NT_SUCCESS(status)) {
  156. ObDereferenceObject(fileObject);
  157. }
  158. return ((status == STATUS_SUCCESS) ? TRUE : FALSE);
  159. }
  160. BOOLEAN
  161. PortIsDeviceMPIOSupported(
  162. IN PUNICODE_STRING DeviceList,
  163. IN PUCHAR VendorId,
  164. IN PUCHAR ProductId
  165. )
  166. /*++
  167. Routine Description:
  168. This routine determines whether the device is supported by traversing the SupportedDevice
  169. list and comparing to the VendorId/ProductId values passed in.
  170. Arguments:
  171. DeviceList - MULTI_SZ retrieved from the registry by PortGetDeviceList
  172. VendorId - Pointer to the inquiry data VendorId.
  173. ProductId - Pointer to the inquiry data ProductId.
  174. Return Value:
  175. TRUE - If VendorId/ProductId is found.
  176. --*/
  177. {
  178. UNICODE_STRING deviceName;
  179. UNICODE_STRING productName;
  180. ANSI_STRING ansiVendor;
  181. ANSI_STRING ansiProduct;
  182. NTSTATUS status;
  183. BOOLEAN supported = FALSE;
  184. PAGED_CODE();
  185. //
  186. // The SupportedDevice list was built in DriverEntry from the services key.
  187. //
  188. if (DeviceList->MaximumLength == 0) {
  189. //
  190. // List is empty.
  191. //
  192. return FALSE;
  193. }
  194. //
  195. // If MPIO isn't loaded, don't claim support for the device.
  196. //
  197. if (!PortpMPIOLoaded()) {
  198. return FALSE;
  199. }
  200. //
  201. // Convert the inquiry fields into ansi strings.
  202. //
  203. RtlInitAnsiString(&ansiVendor, VendorId);
  204. RtlInitAnsiString(&ansiProduct, ProductId);
  205. //
  206. // Allocate the deviceName buffer. Needs to be 8+16 plus NULL.
  207. // (productId length + vendorId length + NULL).
  208. // Add another 4 bytes for revision plus one pad, if anyone happens to jam that in.
  209. //
  210. deviceName.MaximumLength = 30 * sizeof(WCHAR);
  211. deviceName.Buffer = ExAllocatePool(PagedPool, deviceName.MaximumLength);
  212. //
  213. // Convert the vendorId to unicode.
  214. //
  215. RtlAnsiStringToUnicodeString(&deviceName, &ansiVendor, FALSE);
  216. //
  217. // Convert the productId to unicode.
  218. //
  219. RtlAnsiStringToUnicodeString(&productName, &ansiProduct, TRUE);
  220. //
  221. // 'cat' them.
  222. //
  223. status = RtlAppendUnicodeStringToString(&deviceName, &productName);
  224. if (status == STATUS_SUCCESS) {
  225. //
  226. // Run the list of supported devices that was captured from the registry
  227. // and see if this one is in the list.
  228. //
  229. supported = PortpFindMPIOSupportedDevice(&deviceName,
  230. DeviceList);
  231. }
  232. return supported;
  233. }