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.

692 lines
18 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. id.c
  5. Abstract:
  6. This module contains functions used in the generation of responses
  7. to a IRP_MN_QUERY_ID IRP.
  8. Author:
  9. Peter Johnston (peterj) 08-Mar-1997
  10. Revision History:
  11. --*/
  12. #include "pcip.h"
  13. //++
  14. //
  15. // PciQueryId returns UNICODE strings when the ID type is DeviceID
  16. // or InstanceID. For HardwareIDs and CompatibleIDs it returns a
  17. // a zero terminated list of zero terminated UNICODE strings (MULTI_SZ).
  18. //
  19. // The normal process of converting a string to a unicode string involves
  20. // taking it's length, allocating pool memory for the new string and
  21. // calling RtlAnsiStringToUnicodeString to do the conversion. The following
  22. // is an attempt to be a little more efficient in terms of both size and
  23. // speed by keeping track of the relevant string data as it goes past in
  24. // the process of creating the set of strings.
  25. //
  26. //--
  27. #define MAX_ANSI_STRINGS 8
  28. #define MAX_ANSI_BUFFER 256
  29. typedef struct _PCI_ID_BUFFER {
  30. ULONG Count; // number of ansi strings
  31. ANSI_STRING AnsiStrings[MAX_ANSI_STRINGS];
  32. USHORT UnicodeSZSize[MAX_ANSI_STRINGS];
  33. USHORT UnicodeBufferSize;
  34. PUCHAR NextFree; // first unused byte in buffer
  35. UCHAR Bytes[MAX_ANSI_BUFFER];// buffer start address
  36. } PCI_ID_BUFFER, *PPCI_ID_BUFFER;
  37. //
  38. // All functins in this module are pageable.
  39. //
  40. // Define prototypes for module local functions.
  41. //
  42. VOID
  43. PciIdPrintf(
  44. IN PPCI_ID_BUFFER IdBuffer,
  45. PCCHAR Format,
  46. ...
  47. );
  48. VOID
  49. PciIdPrintfAppend(
  50. IN PPCI_ID_BUFFER IdBuffer,
  51. PCCHAR Format,
  52. ...
  53. );
  54. VOID
  55. PciInitIdBuffer(
  56. IN PPCI_ID_BUFFER IdBuffer
  57. );
  58. #ifdef ALLOC_PRAGMA
  59. #pragma alloc_text(PAGE, PciGetDeviceDescriptionMessage)
  60. #pragma alloc_text(PAGE, PciIdPrintf)
  61. #pragma alloc_text(PAGE, PciIdPrintfAppend)
  62. #pragma alloc_text(PAGE, PciInitIdBuffer)
  63. #pragma alloc_text(PAGE, PciQueryId)
  64. #pragma alloc_text(PAGE, PciQueryDeviceText)
  65. #endif
  66. VOID
  67. PciInitIdBuffer(
  68. IN PPCI_ID_BUFFER IdBuffer
  69. )
  70. {
  71. IdBuffer->NextFree = IdBuffer->Bytes;
  72. IdBuffer->UnicodeBufferSize = 0;
  73. IdBuffer->Count = 0;
  74. }
  75. VOID
  76. PciIdPrintf(
  77. IN PPCI_ID_BUFFER IdBuffer,
  78. PCCHAR Format,
  79. ...
  80. )
  81. {
  82. LONG length;
  83. ULONG index;
  84. PUCHAR buffer;
  85. LONG maxLength;
  86. va_list ap;
  87. PANSI_STRING ansiString;
  88. ASSERT(IdBuffer->Count < MAX_ANSI_STRINGS);
  89. //
  90. // Make my life easier, keep repeated values in locals.
  91. //
  92. index = IdBuffer->Count;
  93. buffer = IdBuffer->NextFree;
  94. maxLength = MAX_ANSI_BUFFER - (LONG)(buffer - IdBuffer->Bytes);
  95. ansiString = &IdBuffer->AnsiStrings[index];
  96. //
  97. // Pass the format string and subsequent data into (effectively)
  98. // sprintf.
  99. //
  100. va_start(ap, Format);
  101. length = _vsnprintf(buffer, maxLength, Format, ap);
  102. va_end(ap);
  103. ASSERT(length < maxLength);
  104. //
  105. // RtlInitAnsiString without the strlen.
  106. //
  107. ansiString->Buffer = buffer;
  108. ansiString->Length = (USHORT)length;
  109. ansiString->MaximumLength = (USHORT)length;
  110. //
  111. // Get the length of this string in a unicode world and record it
  112. // for later when the whole set of strings gets converted (keep
  113. // the total size also).
  114. //
  115. IdBuffer->UnicodeSZSize[index] =
  116. (USHORT)RtlAnsiStringToUnicodeSize(ansiString);
  117. IdBuffer->UnicodeBufferSize += IdBuffer->UnicodeSZSize[index];
  118. //
  119. // Bump buffer pointer for next iteration and the count.
  120. //
  121. IdBuffer->NextFree += length + 1;
  122. IdBuffer->Count++;
  123. }
  124. VOID
  125. PciIdPrintfAppend(
  126. IN PPCI_ID_BUFFER IdBuffer,
  127. PCCHAR Format,
  128. ...
  129. )
  130. {
  131. LONG length;
  132. ULONG index;
  133. PUCHAR buffer;
  134. LONG maxLength;
  135. va_list ap;
  136. PANSI_STRING ansiString;
  137. ASSERT(IdBuffer->Count);
  138. //
  139. // Make my life easier, keep repeated values in locals.
  140. //
  141. index = IdBuffer->Count - 1;
  142. buffer = IdBuffer->NextFree - 1;
  143. maxLength = MAX_ANSI_BUFFER - (LONG)(buffer - IdBuffer->Bytes);
  144. ansiString = &IdBuffer->AnsiStrings[index];
  145. //
  146. // Pass the format string and subsequent data into (effectively)
  147. // sprintf.
  148. //
  149. va_start(ap, Format);
  150. length = _vsnprintf(buffer, maxLength, Format, ap);
  151. va_end(ap);
  152. ASSERT(length < maxLength);
  153. //
  154. // Increase the ansi string length by the length of the new
  155. // portion of the string.
  156. //
  157. ansiString->Length += (USHORT)length;
  158. ansiString->MaximumLength += (USHORT)length;
  159. //
  160. // Get the length of this string in a unicode world and record it
  161. // for later when the whole set of strings gets converted (keep
  162. // the total size also).
  163. //
  164. IdBuffer->UnicodeSZSize[index] =
  165. (USHORT)RtlAnsiStringToUnicodeSize(ansiString);
  166. IdBuffer->UnicodeBufferSize += IdBuffer->UnicodeSZSize[index];
  167. //
  168. // Bump buffer pointer for next iteration.
  169. //
  170. IdBuffer->NextFree += length;
  171. }
  172. NTSTATUS
  173. PciQueryId(
  174. IN PPCI_PDO_EXTENSION PdoExtension,
  175. IN BUS_QUERY_ID_TYPE IdType,
  176. IN OUT PWSTR *BusQueryId
  177. )
  178. {
  179. PCI_ID_BUFFER idBuffer;
  180. UCHAR venDevString[sizeof("PCI\\VEN_vvvv&DEV_dddd")];
  181. NTSTATUS status;
  182. UNICODE_STRING unicodeId;
  183. PVOID unicodeBuffer;
  184. ULONG i;
  185. ULONG subsystem;
  186. PPCI_PDO_EXTENSION current;
  187. PAGED_CODE();
  188. *BusQueryId = NULL;
  189. //
  190. // In all the following we want PCI\VEN_vvvv&DEV_dddd.
  191. //
  192. sprintf(venDevString,
  193. "PCI\\VEN_%04X&DEV_%04X",
  194. PdoExtension->VendorId,
  195. PdoExtension->DeviceId);
  196. PciInitIdBuffer(&idBuffer);
  197. subsystem = (PdoExtension->SubsystemId << 16) |
  198. PdoExtension->SubsystemVendorId;
  199. switch (IdType) {
  200. case BusQueryInstanceID:
  201. //
  202. // Caller wants an instance ID for this device. The PCI
  203. // driver reports that it does NOT generate unique IDs for
  204. // devices so PnP Manager will prepend bus information.
  205. //
  206. // The instance ID is of the form-
  207. //
  208. // AABBCCDDEEFF...XXYYZZ
  209. //
  210. // Where AA is the slot number (device/function) of the device
  211. // on the bus, BB, CC,... XX, YY, ZZ are the slot number of the
  212. // PCI-to-PCI bridges on their parent busses all the way up to
  213. // the root. A device on the root bus will have only one entry,
  214. // AA.
  215. //
  216. current = PdoExtension;
  217. //
  218. // Initialize empty buffer.
  219. //
  220. PciIdPrintf(&idBuffer,"");
  221. for (;;) {
  222. PciIdPrintfAppend(&idBuffer,
  223. "%02X",
  224. PCI_DEVFUNC(current)
  225. );
  226. if (PCI_PDO_ON_ROOT(current)) {
  227. break;
  228. }
  229. current = PCI_PARENT_PDO(current)->DeviceExtension;
  230. }
  231. break;
  232. case BusQueryHardwareIDs:
  233. case BusQueryDeviceID:
  234. //
  235. // Hardware and Compatible IDs are generated as specified
  236. // in the ACPI spec (section 6.1.2 in version 0.9).
  237. //
  238. // Hardware IDs are a list of identifiers of the form
  239. //
  240. // PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss&REV_rr
  241. // PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss
  242. // PCI\VEN_vvvv&DEV_dddd&REV_rr
  243. // PCI\VEN_vvvv&DEV_dddd
  244. //
  245. // Where vvvv is the Vendor ID from config space,
  246. // dddd is the Device ID,
  247. // ssssssss is the Subsystem ID/Subsystem Vendor ID, and
  248. // rr is the Revision ID.
  249. //
  250. // Device ID is the same as the first Hardware ID (ie most
  251. // specific of all possible IDs).
  252. //
  253. PciIdPrintf(&idBuffer,
  254. "%s&SUBSYS_%08X&REV_%02X",
  255. venDevString,
  256. subsystem,
  257. PdoExtension->RevisionId);
  258. if (IdType == BusQueryDeviceID) {
  259. break;
  260. }
  261. PciIdPrintf(&idBuffer,
  262. "%s&SUBSYS_%08X",
  263. venDevString,
  264. subsystem);
  265. //
  266. // Fall thru.
  267. //
  268. case BusQueryCompatibleIDs:
  269. //
  270. // If the subsystem is non-zero, the second two are compatible
  271. // IDs, otherwise they are hardware IDs.
  272. //
  273. if (((subsystem == 0) && (IdType == BusQueryHardwareIDs)) ||
  274. ((subsystem != 0) && (IdType == BusQueryCompatibleIDs))) {
  275. PciIdPrintf(&idBuffer,
  276. "%s&REV_%02X",
  277. venDevString,
  278. PdoExtension->RevisionId);
  279. //
  280. // Device ID is PCI\VEN_vvvv&DEV_dddd
  281. //
  282. PciIdPrintf(&idBuffer,
  283. "%s",
  284. venDevString);
  285. }
  286. if (IdType == BusQueryHardwareIDs) {
  287. //
  288. // The comment in the Memphis code says "Add
  289. // special Intel entry". Odd that these entries
  290. // are absent from the spec. They are added for
  291. // PIIX4 which has the same vendor and device IDs
  292. // for two different sub class codes.
  293. //
  294. // These two entries are
  295. //
  296. // PCI\VEN_vvvv&DEV_dddd&CC_ccsspp
  297. // PCI\VEN_vvvv&DEV_dddd&CC_ccss
  298. //
  299. // (See below for cc, ss and pp explanaitions).
  300. //
  301. PciIdPrintf(&idBuffer,
  302. "%s&CC_%02X%02X%02X",
  303. venDevString,
  304. PdoExtension->BaseClass,
  305. PdoExtension->SubClass,
  306. PdoExtension->ProgIf);
  307. PciIdPrintf(&idBuffer,
  308. "%s&CC_%02X%02X",
  309. venDevString,
  310. PdoExtension->BaseClass,
  311. PdoExtension->SubClass);
  312. }
  313. if (IdType == BusQueryCompatibleIDs) {
  314. //
  315. // The Compatible IDs list, consists of the above plus
  316. //
  317. // PCI\VEN_vvvv&CC_ccsspp
  318. // PCI\VEN_vvvv&CC_ccss
  319. // PCI\VEN_vvvv
  320. // PCI\CC_ccsspp
  321. // PCI\CC_ccss
  322. //
  323. // Where cc is the Class Code from config space,
  324. // ss is the Sub-Class Code, and
  325. // pp is the programming interface.
  326. //
  327. // WARNING: Revise the size of the buffer if you increase
  328. // the above list.
  329. //
  330. PciIdPrintf(&idBuffer,
  331. "PCI\\VEN_%04X&CC_%02X%02X%02X",
  332. PdoExtension->VendorId,
  333. PdoExtension->BaseClass,
  334. PdoExtension->SubClass,
  335. PdoExtension->ProgIf);
  336. PciIdPrintf(&idBuffer,
  337. "PCI\\VEN_%04X&CC_%02X%02X",
  338. PdoExtension->VendorId,
  339. PdoExtension->BaseClass,
  340. PdoExtension->SubClass);
  341. PciIdPrintf(&idBuffer,
  342. "PCI\\VEN_%04X",
  343. PdoExtension->VendorId);
  344. PciIdPrintf(&idBuffer,
  345. "PCI\\CC_%02X%02X%02X",
  346. PdoExtension->BaseClass,
  347. PdoExtension->SubClass,
  348. PdoExtension->ProgIf);
  349. PciIdPrintf(&idBuffer,
  350. "PCI\\CC_%02X%02X",
  351. PdoExtension->BaseClass,
  352. PdoExtension->SubClass);
  353. }
  354. //
  355. // HardwareIDs and CompatibleIDs are MULTI_SZ, add a
  356. // NULL list to terminate it all.
  357. //
  358. PciIdPrintf(&idBuffer, "");
  359. break;
  360. default:
  361. PciDebugPrint(PciDbgVerbose,
  362. "PciQueryId expected ID type = %d\n",
  363. IdType);
  364. //ASSERT(0 && "Unexpected BUS_QUERY_ID_TYPE");
  365. return STATUS_NOT_SUPPORTED;
  366. }
  367. ASSERT(idBuffer.Count > 0);
  368. //
  369. // What we have is a (bunch of) ansi strings. What we need is a
  370. // (bunch of) unicode strings.
  371. //
  372. unicodeBuffer = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, idBuffer.UnicodeBufferSize);
  373. if (unicodeBuffer == NULL) {
  374. return STATUS_INSUFFICIENT_RESOURCES;
  375. }
  376. //
  377. // Build the (possibly MULTI_SZ) unicode string(s).
  378. //
  379. PciDebugPrint(PciDbgPrattling,
  380. "PciQueryId(%d)\n",
  381. IdType);
  382. unicodeId.Buffer = unicodeBuffer;
  383. unicodeId.MaximumLength = idBuffer.UnicodeBufferSize;
  384. for (i = 0; i < idBuffer.Count; i++) {
  385. PciDebugPrint(PciDbgPrattling,
  386. " <- \"%s\"\n",
  387. idBuffer.AnsiStrings[i].Buffer);
  388. status = RtlAnsiStringToUnicodeString(&unicodeId,
  389. &idBuffer.AnsiStrings[i],
  390. FALSE);
  391. if (!NT_SUCCESS(status)) {
  392. ASSERT(NT_SUCCESS(status));
  393. ExFreePool(unicodeBuffer);
  394. return status;
  395. }
  396. //
  397. // Bump the base pointer and decrement the max length for the
  398. // next trip thru the loop.
  399. //
  400. (ULONG_PTR)unicodeId.Buffer += idBuffer.UnicodeSZSize[i];
  401. unicodeId.MaximumLength -= idBuffer.UnicodeSZSize[i];
  402. }
  403. *BusQueryId = unicodeBuffer;
  404. return status;
  405. }
  406. PWSTR
  407. PciGetDescriptionMessage(
  408. IN ULONG MessageNumber
  409. )
  410. {
  411. PWSTR description = NULL;
  412. NTSTATUS status;
  413. PMESSAGE_RESOURCE_ENTRY messageEntry;
  414. status = RtlFindMessage(PciDriverObject->DriverStart,
  415. 11, // <-- I wonder what this is.
  416. LANG_NEUTRAL,
  417. MessageNumber,
  418. &messageEntry);
  419. if (NT_SUCCESS(status)) {
  420. if (messageEntry->Flags & MESSAGE_RESOURCE_UNICODE) {
  421. //
  422. // Our caller wants a copy they can free, also we need to
  423. // strip the trailing CR/LF. The Length field of the
  424. // message structure includes both the header and the
  425. // actual text.
  426. //
  427. // Note: The message resource entry length will always be a
  428. // multiple of 4 bytes in length. The 2 byte null terminator
  429. // could be in either the last or second last WCHAR position.
  430. //
  431. ULONG textLength;
  432. textLength = messageEntry->Length -
  433. FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) -
  434. 2 * sizeof(WCHAR);
  435. description = (PWSTR)(messageEntry->Text);
  436. if (description[textLength / sizeof(WCHAR)] == 0) {
  437. textLength -= sizeof(WCHAR);
  438. }
  439. ASSERT((LONG)textLength > 1);
  440. ASSERT(description[textLength / sizeof(WCHAR)] == 0x000a);
  441. description = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, textLength);
  442. if (description) {
  443. //
  444. // Copy the text except for the CR/LF/NULL
  445. //
  446. textLength -= sizeof(WCHAR);
  447. RtlCopyMemory(description, messageEntry->Text, textLength);
  448. //
  449. // New NULL terminator.
  450. //
  451. description[textLength / sizeof(WCHAR)] = 0;
  452. }
  453. } else {
  454. //
  455. // RtlFindMessage returns a string? Wierd.
  456. //
  457. ANSI_STRING ansiDescription;
  458. UNICODE_STRING unicodeDescription;
  459. RtlInitAnsiString(&ansiDescription, messageEntry->Text);
  460. //
  461. // Strip CR/LF off the end of the string.
  462. //
  463. ansiDescription.Length -= 2;
  464. //
  465. // Turn it all into a unicode string so we can grab the buffer
  466. // and return that to our caller.
  467. //
  468. status = RtlAnsiStringToUnicodeString(
  469. &unicodeDescription,
  470. &ansiDescription,
  471. TRUE
  472. );
  473. description = unicodeDescription.Buffer;
  474. }
  475. }
  476. return description;
  477. }
  478. PWSTR
  479. PciGetDeviceDescriptionMessage(
  480. IN UCHAR BaseClass,
  481. IN UCHAR SubClass
  482. )
  483. {
  484. PWSTR deviceDescription = NULL;
  485. ULONG messageNumber;
  486. messageNumber = (BaseClass << 8) | SubClass;
  487. deviceDescription = PciGetDescriptionMessage(messageNumber);
  488. if (!deviceDescription) {
  489. #define TEMP_DESCRIPTION L"PCI Device"
  490. deviceDescription = ExAllocatePool(PagedPool, sizeof(TEMP_DESCRIPTION));
  491. if (deviceDescription) {
  492. RtlCopyMemory(deviceDescription,
  493. TEMP_DESCRIPTION,
  494. sizeof(TEMP_DESCRIPTION));
  495. }
  496. }
  497. return deviceDescription;
  498. }
  499. NTSTATUS
  500. PciQueryDeviceText(
  501. IN PPCI_PDO_EXTENSION PdoExtension,
  502. IN DEVICE_TEXT_TYPE TextType,
  503. IN LCID LocaleId,
  504. IN OUT PWSTR *DeviceText
  505. )
  506. {
  507. PWSTR locationFormat;
  508. ULONG textLength;
  509. PAGED_CODE();
  510. switch (TextType) {
  511. case DeviceTextDescription:
  512. *DeviceText = PciGetDeviceDescriptionMessage(PdoExtension->BaseClass,
  513. PdoExtension->SubClass);
  514. if (*DeviceText) {
  515. return STATUS_SUCCESS;
  516. }
  517. return STATUS_NOT_SUPPORTED;
  518. case DeviceTextLocationInformation:
  519. locationFormat = PciGetDescriptionMessage(PCI_LOCATION_TEXT);
  520. if (locationFormat) {
  521. // Compute max size for location information string
  522. textLength = wcslen(locationFormat) + 2 + 2 + 2 + 1;
  523. *DeviceText = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION,
  524. textLength * sizeof(WCHAR));
  525. if (*DeviceText) {
  526. swprintf(*DeviceText, locationFormat,
  527. (ULONG) PdoExtension->ParentFdoExtension->BaseBus,
  528. (ULONG) PdoExtension->Slot.u.bits.DeviceNumber,
  529. (ULONG) PdoExtension->Slot.u.bits.FunctionNumber);
  530. }
  531. ExFreePool(locationFormat);
  532. if (*DeviceText) {
  533. return STATUS_SUCCESS;
  534. } else {
  535. return STATUS_INSUFFICIENT_RESOURCES;
  536. }
  537. }
  538. // fall thru if we couldn't get format string
  539. default:
  540. return STATUS_NOT_SUPPORTED;
  541. }
  542. }