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.

732 lines
21 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. ULONG index;
  83. PUCHAR buffer;
  84. LONG maxLength;
  85. va_list ap;
  86. PANSI_STRING ansiString;
  87. BOOLEAN ok;
  88. PCI_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. ok = SUCCEEDED(StringCbVPrintfA(buffer, maxLength, Format, ap));
  102. ASSERT(ok);
  103. va_end(ap);
  104. //
  105. // Turn this into a counted Ansi string
  106. //
  107. RtlInitAnsiString(ansiString, buffer);
  108. //
  109. // Get the length of this string in a unicode world and record it
  110. // for later when the whole set of strings gets converted (keep
  111. // the total size also).
  112. //
  113. IdBuffer->UnicodeSZSize[index] =
  114. (USHORT)RtlAnsiStringToUnicodeSize(ansiString);
  115. IdBuffer->UnicodeBufferSize += IdBuffer->UnicodeSZSize[index];
  116. //
  117. // Bump buffer pointer for next iteration and the count.
  118. //
  119. IdBuffer->NextFree += ansiString->Length + 1;
  120. IdBuffer->Count++;
  121. }
  122. VOID
  123. PciIdPrintfAppend(
  124. IN PPCI_ID_BUFFER IdBuffer,
  125. PCCHAR Format,
  126. ...
  127. )
  128. {
  129. ULONG index;
  130. PUCHAR buffer;
  131. va_list ap;
  132. PANSI_STRING ansiString;
  133. SIZE_T maxLength, length;
  134. SIZE_T remainingCount = 0;
  135. BOOLEAN ok;
  136. PCI_ASSERT(IdBuffer->Count);
  137. //
  138. // Make my life easier, keep repeated values in locals.
  139. //
  140. index = IdBuffer->Count - 1;
  141. buffer = IdBuffer->NextFree - 1;
  142. maxLength = MAX_ANSI_BUFFER - (ULONG)(buffer - IdBuffer->Bytes);
  143. ansiString = &IdBuffer->AnsiStrings[index];
  144. //
  145. // Pass the format string and subsequent data into (effectively)
  146. // sprintf.
  147. //
  148. va_start(ap, Format);
  149. ok = SUCCEEDED(StringCbVPrintfExA(buffer, maxLength, NULL, &remainingCount, 0, Format, ap));
  150. ASSERT(ok);
  151. length = maxLength - remainingCount;
  152. va_end(ap);
  153. PCI_ASSERT(length < maxLength);
  154. //
  155. // Increase the ansi string length by the length of the new
  156. // portion of the string.
  157. //
  158. ansiString->Length += (USHORT)length;
  159. ansiString->MaximumLength += (USHORT)length;
  160. //
  161. // Get the length of this string in a unicode world and record it
  162. // for later when the whole set of strings gets converted (keep
  163. // the total size also).
  164. //
  165. IdBuffer->UnicodeSZSize[index] =
  166. (USHORT)RtlAnsiStringToUnicodeSize(ansiString);
  167. IdBuffer->UnicodeBufferSize += IdBuffer->UnicodeSZSize[index];
  168. //
  169. // Bump buffer pointer for next iteration.
  170. //
  171. IdBuffer->NextFree += length;
  172. }
  173. NTSTATUS
  174. PciQueryId(
  175. IN PPCI_PDO_EXTENSION PdoExtension,
  176. IN BUS_QUERY_ID_TYPE IdType,
  177. IN OUT PWSTR *BusQueryId
  178. )
  179. {
  180. PCI_ID_BUFFER idBuffer;
  181. UCHAR venDevString[sizeof("PCI\\VEN_vvvv&DEV_dddd")];
  182. NTSTATUS status = STATUS_SUCCESS;
  183. UNICODE_STRING unicodeId;
  184. PVOID unicodeBuffer;
  185. ULONG i;
  186. ULONG subsystem;
  187. PPCI_PDO_EXTENSION current;
  188. BOOLEAN ok;
  189. PAGED_CODE();
  190. *BusQueryId = NULL;
  191. //
  192. // In all the following we want PCI\VEN_vvvv&DEV_dddd.
  193. //
  194. ok = SUCCEEDED(StringCbPrintfA(venDevString,
  195. sizeof(venDevString),
  196. "PCI\\VEN_%04X&DEV_%04X",
  197. PdoExtension->VendorId,
  198. PdoExtension->DeviceId));
  199. ASSERT(ok);
  200. PciInitIdBuffer(&idBuffer);
  201. subsystem = (PdoExtension->SubsystemId << 16) |
  202. PdoExtension->SubsystemVendorId;
  203. switch (IdType) {
  204. case BusQueryInstanceID:
  205. //
  206. // Caller wants an instance ID for this device. The PCI
  207. // driver reports that it does NOT generate unique IDs for
  208. // devices so PnP Manager will prepend bus information.
  209. //
  210. // The instance ID is of the form-
  211. //
  212. // AABBCCDDEEFF...XXYYZZ
  213. //
  214. // Where AA is the slot number (device/function) of the device
  215. // on the bus, BB, CC,... XX, YY, ZZ are the slot number of the
  216. // PCI-to-PCI bridges on their parent busses all the way up to
  217. // the root. A device on the root bus will have only one entry,
  218. // AA.
  219. //
  220. current = PdoExtension;
  221. //
  222. // Initialize empty buffer.
  223. //
  224. PciIdPrintf(&idBuffer,"");
  225. for (;;) {
  226. PciIdPrintfAppend(&idBuffer,
  227. "%02X",
  228. PCI_DEVFUNC(current)
  229. );
  230. if (PCI_PDO_ON_ROOT(current)) {
  231. break;
  232. }
  233. current = PCI_PARENT_PDO(current)->DeviceExtension;
  234. }
  235. break;
  236. case BusQueryHardwareIDs:
  237. case BusQueryDeviceID:
  238. //
  239. // Hardware and Compatible IDs are generated as specified
  240. // in the ACPI spec (section 6.1.2 in version 0.9).
  241. //
  242. // Hardware IDs are a list of identifiers of the form
  243. //
  244. // PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss&REV_rr
  245. // PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss
  246. // PCI\VEN_vvvv&DEV_dddd&REV_rr
  247. // PCI\VEN_vvvv&DEV_dddd
  248. //
  249. // Where vvvv is the Vendor ID from config space,
  250. // dddd is the Device ID,
  251. // ssssssss is the Subsystem ID/Subsystem Vendor ID, and
  252. // rr is the Revision ID.
  253. //
  254. // Device ID is the same as the first Hardware ID (ie most
  255. // specific of all possible IDs).
  256. //
  257. PciIdPrintf(&idBuffer,
  258. "%s&SUBSYS_%08X&REV_%02X",
  259. venDevString,
  260. subsystem,
  261. PdoExtension->RevisionId);
  262. if (IdType == BusQueryDeviceID) {
  263. break;
  264. }
  265. PciIdPrintf(&idBuffer,
  266. "%s&SUBSYS_%08X",
  267. venDevString,
  268. subsystem);
  269. //
  270. // Fall thru.
  271. //
  272. case BusQueryCompatibleIDs:
  273. //
  274. // If the subsystem is non-zero, the second two are compatible
  275. // IDs, otherwise they are hardware IDs.
  276. //
  277. if (((subsystem == 0) && (IdType == BusQueryHardwareIDs)) ||
  278. ((subsystem != 0) && (IdType == BusQueryCompatibleIDs))) {
  279. PciIdPrintf(&idBuffer,
  280. "%s&REV_%02X",
  281. venDevString,
  282. PdoExtension->RevisionId);
  283. //
  284. // Device ID is PCI\VEN_vvvv&DEV_dddd
  285. //
  286. PciIdPrintf(&idBuffer,
  287. "%s",
  288. venDevString);
  289. }
  290. if (IdType == BusQueryHardwareIDs) {
  291. //
  292. // The comment in the Memphis code says "Add
  293. // special Intel entry". Odd that these entries
  294. // are absent from the spec. They are added for
  295. // PIIX4 which has the same vendor and device IDs
  296. // for two different sub class codes.
  297. //
  298. // These two entries are
  299. //
  300. // PCI\VEN_vvvv&DEV_dddd&CC_ccsspp
  301. // PCI\VEN_vvvv&DEV_dddd&CC_ccss
  302. //
  303. // (See below for cc, ss and pp explanaitions).
  304. //
  305. PciIdPrintf(&idBuffer,
  306. "%s&CC_%02X%02X%02X",
  307. venDevString,
  308. PdoExtension->BaseClass,
  309. PdoExtension->SubClass,
  310. PdoExtension->ProgIf);
  311. PciIdPrintf(&idBuffer,
  312. "%s&CC_%02X%02X",
  313. venDevString,
  314. PdoExtension->BaseClass,
  315. PdoExtension->SubClass);
  316. }
  317. if (IdType == BusQueryCompatibleIDs) {
  318. //
  319. // The Compatible IDs list, consists of the above plus
  320. //
  321. // PCI\VEN_vvvv&CC_ccsspp
  322. // PCI\VEN_vvvv&CC_ccss
  323. // PCI\VEN_vvvv
  324. // PCI\CC_ccsspp
  325. // PCI\CC_ccss
  326. //
  327. // Where cc is the Class Code from config space,
  328. // ss is the Sub-Class Code, and
  329. // pp is the programming interface.
  330. //
  331. // WARNING: Revise the size of the buffer if you increase
  332. // the above list.
  333. //
  334. PciIdPrintf(&idBuffer,
  335. "PCI\\VEN_%04X&CC_%02X%02X%02X",
  336. PdoExtension->VendorId,
  337. PdoExtension->BaseClass,
  338. PdoExtension->SubClass,
  339. PdoExtension->ProgIf);
  340. PciIdPrintf(&idBuffer,
  341. "PCI\\VEN_%04X&CC_%02X%02X",
  342. PdoExtension->VendorId,
  343. PdoExtension->BaseClass,
  344. PdoExtension->SubClass);
  345. PciIdPrintf(&idBuffer,
  346. "PCI\\VEN_%04X",
  347. PdoExtension->VendorId);
  348. PciIdPrintf(&idBuffer,
  349. "PCI\\CC_%02X%02X%02X",
  350. PdoExtension->BaseClass,
  351. PdoExtension->SubClass,
  352. PdoExtension->ProgIf);
  353. PciIdPrintf(&idBuffer,
  354. "PCI\\CC_%02X%02X",
  355. PdoExtension->BaseClass,
  356. PdoExtension->SubClass);
  357. }
  358. //
  359. // HardwareIDs and CompatibleIDs are MULTI_SZ, add a
  360. // NULL list to terminate it all.
  361. //
  362. PciIdPrintf(&idBuffer, "");
  363. break;
  364. default:
  365. PciDebugPrint(PciDbgVerbose,
  366. "PciQueryId expected ID type = %d\n",
  367. IdType);
  368. //PCI_ASSERT(0 && "Unexpected BUS_QUERY_ID_TYPE");
  369. return STATUS_NOT_SUPPORTED;
  370. }
  371. PCI_ASSERT(idBuffer.Count > 0);
  372. //
  373. // What we have is a (bunch of) ansi strings. What we need is a
  374. // (bunch of) unicode strings.
  375. //
  376. unicodeBuffer = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, idBuffer.UnicodeBufferSize);
  377. if (unicodeBuffer == NULL) {
  378. return STATUS_INSUFFICIENT_RESOURCES;
  379. }
  380. //
  381. // Build the (possibly MULTI_SZ) unicode string(s).
  382. //
  383. PciDebugPrint(PciDbgPrattling,
  384. "PciQueryId(%d)\n",
  385. IdType);
  386. unicodeId.Buffer = unicodeBuffer;
  387. unicodeId.MaximumLength = idBuffer.UnicodeBufferSize;
  388. for (i = 0; i < idBuffer.Count; i++) {
  389. PciDebugPrint(PciDbgPrattling,
  390. " <- \"%s\"\n",
  391. idBuffer.AnsiStrings[i].Buffer);
  392. status = RtlAnsiStringToUnicodeString(&unicodeId,
  393. &idBuffer.AnsiStrings[i],
  394. FALSE);
  395. if (!NT_SUCCESS(status)) {
  396. PCI_ASSERT(NT_SUCCESS(status));
  397. ExFreePool(unicodeBuffer);
  398. return status;
  399. }
  400. //
  401. // Bump the base pointer and decrement the max length for the
  402. // next trip thru the loop.
  403. //
  404. unicodeId.Buffer += idBuffer.UnicodeSZSize[i] / sizeof(WCHAR);
  405. unicodeId.MaximumLength -= idBuffer.UnicodeSZSize[i];
  406. }
  407. *BusQueryId = unicodeBuffer;
  408. return status;
  409. }
  410. PWSTR
  411. PciGetDescriptionMessage(
  412. IN ULONG MessageNumber,
  413. OUT PUSHORT MessageLength OPTIONAL
  414. )
  415. {
  416. PWSTR description = NULL;
  417. NTSTATUS status;
  418. PMESSAGE_RESOURCE_ENTRY messageEntry;
  419. status = RtlFindMessage(PciDriverObject->DriverStart,
  420. 11, // <-- I wonder what this is.
  421. LANG_NEUTRAL,
  422. MessageNumber,
  423. &messageEntry);
  424. if (NT_SUCCESS(status)) {
  425. if (messageEntry->Flags & MESSAGE_RESOURCE_UNICODE) {
  426. //
  427. // Our caller wants a copy they can free, also we need to
  428. // strip the trailing CR/LF. The Length field of the
  429. // message structure includes both the header and the
  430. // actual text.
  431. //
  432. // Note: The message resource entry length will always be a
  433. // multiple of 4 bytes in length. The 2 byte null terminator
  434. // could be in either the last or second last WCHAR position.
  435. //
  436. USHORT textLength;
  437. textLength = messageEntry->Length -
  438. FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) -
  439. 2 * sizeof(WCHAR);
  440. description = (PWSTR)(messageEntry->Text);
  441. if (description[textLength / sizeof(WCHAR)] == 0) {
  442. textLength -= sizeof(WCHAR);
  443. }
  444. PCI_ASSERT((LONG)textLength > 1);
  445. PCI_ASSERT(description[textLength / sizeof(WCHAR)] == 0x000a);
  446. description = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, textLength);
  447. if (description) {
  448. //
  449. // Copy the text except for the CR/LF/NULL
  450. //
  451. textLength -= sizeof(WCHAR);
  452. RtlCopyMemory(description, messageEntry->Text, textLength);
  453. //
  454. // New NULL terminator.
  455. //
  456. description[textLength / sizeof(WCHAR)] = 0;
  457. if (MessageLength) {
  458. *MessageLength = textLength;
  459. }
  460. }
  461. } else {
  462. //
  463. // RtlFindMessage returns a string? Wierd.
  464. //
  465. ANSI_STRING ansiDescription;
  466. UNICODE_STRING unicodeDescription;
  467. RtlInitAnsiString(&ansiDescription, messageEntry->Text);
  468. //
  469. // Strip CR/LF off the end of the string.
  470. //
  471. ansiDescription.Length -= 2;
  472. //
  473. // Turn it all into a unicode string so we can grab the buffer
  474. // and return that to our caller.
  475. //
  476. status = RtlAnsiStringToUnicodeString(
  477. &unicodeDescription,
  478. &ansiDescription,
  479. TRUE
  480. );
  481. description = unicodeDescription.Buffer;
  482. if (MessageLength) {
  483. *MessageLength = unicodeDescription.Length;
  484. }
  485. }
  486. }
  487. return description;
  488. }
  489. PWSTR
  490. PciGetDeviceDescriptionMessage(
  491. IN UCHAR BaseClass,
  492. IN UCHAR SubClass
  493. )
  494. {
  495. PWSTR deviceDescription = NULL;
  496. ULONG messageNumber;
  497. messageNumber = (BaseClass << 8) | SubClass;
  498. deviceDescription = PciGetDescriptionMessage(messageNumber, NULL);
  499. if (!deviceDescription) {
  500. #define TEMP_DESCRIPTION L"PCI Device"
  501. deviceDescription = ExAllocatePool(PagedPool, sizeof(TEMP_DESCRIPTION));
  502. if (deviceDescription) {
  503. RtlCopyMemory(deviceDescription,
  504. TEMP_DESCRIPTION,
  505. sizeof(TEMP_DESCRIPTION));
  506. }
  507. }
  508. return deviceDescription;
  509. }
  510. NTSTATUS
  511. PciQueryDeviceText(
  512. IN PPCI_PDO_EXTENSION PdoExtension,
  513. IN DEVICE_TEXT_TYPE TextType,
  514. IN LCID LocaleId,
  515. IN OUT PWSTR *DeviceText
  516. )
  517. {
  518. PWSTR locationFormat;
  519. SIZE_T textLength;
  520. USHORT messageLength;
  521. BOOLEAN ok;
  522. PAGED_CODE();
  523. switch (TextType) {
  524. case DeviceTextDescription:
  525. *DeviceText = PciGetDeviceDescriptionMessage(PdoExtension->BaseClass,
  526. PdoExtension->SubClass);
  527. if (*DeviceText) {
  528. return STATUS_SUCCESS;
  529. }
  530. return STATUS_NOT_SUPPORTED;
  531. case DeviceTextLocationInformation:
  532. //
  533. // Get the internationalized location description string from the
  534. // resources of pci.sys. It contains 3 %u specifiers for each of
  535. // Bus, Device & Function.
  536. //
  537. locationFormat = PciGetDescriptionMessage(PCI_LOCATION_TEXT, &messageLength);
  538. if (locationFormat) {
  539. //
  540. // Compute max size for location information string:
  541. // The messageLength contains 3 %u format specifiers means that
  542. // the messageLength contains 6 unprinted characters. We need to
  543. // allow space for these numbers. Up to 3 digits for bus number
  544. // 0-255, up to 2 digits for device 0-32 and up to 1 digit for
  545. // function 0-7. Note we assume standard arabic numbers in this
  546. // internationalzed string.
  547. //
  548. textLength = messageLength + ((3 + 2 + 2 - 6) * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
  549. *DeviceText = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION,
  550. textLength * sizeof(WCHAR));
  551. if (*DeviceText) {
  552. ok = SUCCEEDED(StringCchPrintfW(
  553. *DeviceText,
  554. textLength,
  555. locationFormat,
  556. (ULONG) PdoExtension->ParentFdoExtension->BaseBus,
  557. (ULONG) PdoExtension->Slot.u.bits.DeviceNumber,
  558. (ULONG) PdoExtension->Slot.u.bits.FunctionNumber
  559. ));
  560. ASSERT(ok);
  561. }
  562. ExFreePool(locationFormat);
  563. if (*DeviceText) {
  564. return STATUS_SUCCESS;
  565. } else {
  566. return STATUS_INSUFFICIENT_RESOURCES;
  567. }
  568. }
  569. // fall thru if we couldn't get format string
  570. default:
  571. return STATUS_NOT_SUPPORTED;
  572. }
  573. }