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.

920 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. id.c
  5. Abstract:
  6. This module contains the code to handle IRP_MN_QUERY_ID
  7. Authors:
  8. Ravisankar Pudipeddi (ravisp)
  9. Environment:
  10. Kernel mode only
  11. Notes:
  12. Revision History:
  13. Neil Sandlin (neilsa) - split off from pdopnp.c
  14. --*/
  15. #include "pch.h"
  16. //
  17. // Internal References
  18. //
  19. NTSTATUS
  20. PcmciaGenerateDeviceId(
  21. IN PSOCKET_DATA SocketData,
  22. IN ULONG FunctionNumber,
  23. OUT PUCHAR *DeviceId
  24. );
  25. BOOLEAN
  26. PcmciaCheckInstance(
  27. IN PUCHAR DeviceId,
  28. IN ULONG Instance
  29. );
  30. NTSTATUS
  31. PcmciaGetDeviceType(
  32. IN PDEVICE_OBJECT Pdo,
  33. IN ULONG FunctionNumber,
  34. OUT PUCHAR DeviceType
  35. );
  36. VOID
  37. PcmciaFilterIdString(
  38. IN PUCHAR pIn,
  39. OUT PUCHAR pOut,
  40. ULONG MaxLen
  41. );
  42. #ifdef ALLOC_PRAGMA
  43. #pragma alloc_text(PAGE, PcmciaGenerateDeviceId)
  44. #pragma alloc_text(PAGE, PcmciaGetDeviceId)
  45. #pragma alloc_text(PAGE, PcmciaGetHardwareIds)
  46. #pragma alloc_text(PAGE, PcmciaGetCompatibleIds)
  47. #pragma alloc_text(PAGE, PcmciaGetDeviceType)
  48. #pragma alloc_text(PAGE, PcmciaFilterIdString)
  49. #endif
  50. #define PCMCIA_MAX_DEVICE_TYPE_SUPPORTED 12
  51. const
  52. UCHAR *PcmciaCompatibleIds[PCMCIA_MAX_DEVICE_TYPE_SUPPORTED+1] = {
  53. "", // Unknown..
  54. "", // Memory card (RAM, ROM, EPROM, Flash)
  55. "", // Serial I/O port, includes modems
  56. "", // Parallel printer port
  57. "*PNP0600", // Disk driver (ATA)
  58. "", // Video interface
  59. "", // Local Area Network adapter
  60. "", // Auto Increment Mass Storage card
  61. "", // SCSI bridge card
  62. "", // Security card
  63. "*PNP0D00", // Multi-Function 3.0 PC Card
  64. "", // Flash memory card
  65. "*PNPC200", // Modem card (sync with PCCARD_TYPE_MODEM)
  66. };
  67. NTSTATUS
  68. PcmciaGenerateDeviceId(
  69. IN PSOCKET_DATA SocketData,
  70. IN ULONG FunctionNumber,
  71. OUT PUCHAR *DeviceId
  72. )
  73. /*++
  74. The device ID is created from tuple information on the PC Card
  75. The goal is to create a unique ID for each
  76. card. The device ID is created from the manufacturer name string,
  77. the product name string, and a 16-bit CRC of a set of tuples.
  78. The ID is created by concatenating the "PCMCIA" prefix, the manufacturer
  79. name string, the product name string and the 16-bit CRC for the card.
  80. PCMCIA\<manuf_name>-<prod_name>-<crc>
  81. If the CISTPL_VERS_1 tuple is not available, or the manufacturer name is
  82. NULL, the string "UNKNOWN_MANUFACTURER" will be included in its place.
  83. If this is for a child function within a multifunctionn card, the generated
  84. device id would be:
  85. PCMCIA\<manuf_name>-<prod_name>-DEV<function number>-<crc>
  86. This device id is compatible with win 9x device id's (excluding the instance
  87. number which is returned separtely by handling another IRP.
  88. Arguments:
  89. Pdo - Pointer to the physical device object for the pc-card
  90. FunctionNumber - Function number of the function in a multi-function card.
  91. If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested device id
  92. is for the parent device - not for any individual function
  93. DeviceId - Pointer to the string in which device id is returned
  94. Return Value
  95. Status
  96. --*/
  97. {
  98. PUCHAR deviceId;
  99. PAGED_CODE();
  100. deviceId = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
  101. if (deviceId == NULL) {
  102. return STATUS_INSUFFICIENT_RESOURCES;
  103. }
  104. //
  105. // Generate the device id
  106. //
  107. if (*(SocketData->Mfg) == '\0' ) {
  108. //
  109. // No manufacturer name available
  110. //
  111. if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
  112. //
  113. // Device id for the pc-card
  114. //
  115. if (SocketData->Flags & SDF_JEDEC_ID) {
  116. //
  117. // Flash memory cards have the special device id
  118. //
  119. sprintf(deviceId, "%s\\%s-%04x",
  120. PCMCIA_ID_STRING,
  121. PCMCIA_MEMORY_ID_STRING,
  122. SocketData->JedecId);
  123. } else {
  124. sprintf(deviceId, "%s\\%s-%04X",
  125. PCMCIA_ID_STRING,
  126. PCMCIA_UNKNOWN_MANUFACTURER_STRING,
  127. SocketData->CisCrc);
  128. }
  129. } else {
  130. //
  131. // This is for the individual multifunction child
  132. //
  133. sprintf(deviceId, "%s\\%s-DEV%d-%04X",
  134. PCMCIA_ID_STRING,
  135. PCMCIA_UNKNOWN_MANUFACTURER_STRING,
  136. FunctionNumber,
  137. SocketData->CisCrc);
  138. }
  139. } else {
  140. UCHAR Mfg[MAX_MANFID_LENGTH];
  141. UCHAR Ident[MAX_IDENT_LENGTH];
  142. PcmciaFilterIdString(SocketData->Mfg, Mfg, MAX_MANFID_LENGTH);
  143. PcmciaFilterIdString(SocketData->Ident, Ident, MAX_IDENT_LENGTH);
  144. if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
  145. //
  146. // Device id for the pc-card
  147. //
  148. sprintf(deviceId, "%s\\%s-%s-%04X",
  149. PCMCIA_ID_STRING,
  150. Mfg,
  151. Ident,
  152. SocketData->CisCrc);
  153. } else {
  154. //
  155. // This is for the individual multifunction child
  156. //
  157. sprintf(deviceId, "%s\\%s-%s-DEV%d-%04X",
  158. PCMCIA_ID_STRING,
  159. Mfg,
  160. Ident,
  161. FunctionNumber,
  162. SocketData->CisCrc);
  163. }
  164. }
  165. *DeviceId = deviceId;
  166. DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x Device Id=%s\n", SocketData->PdoExtension->DeviceObject, deviceId));
  167. if ((FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) &&
  168. (SocketData->PdoExtension != NULL) &&
  169. (SocketData->PdoExtension->DeviceId == NULL)) {
  170. //
  171. // Keep a copy of the device id
  172. //
  173. PPDO_EXTENSION pdoExtension = SocketData->PdoExtension;
  174. pdoExtension->DeviceId = ExAllocatePool(NonPagedPool, strlen(deviceId)+1);
  175. if (pdoExtension->DeviceId) {
  176. RtlCopyMemory(pdoExtension->DeviceId, deviceId, strlen(deviceId)+1);
  177. }
  178. }
  179. return STATUS_SUCCESS;
  180. }
  181. NTSTATUS
  182. PcmciaGetDeviceId(
  183. IN PDEVICE_OBJECT Pdo,
  184. IN ULONG FunctionNumber,
  185. OUT PUNICODE_STRING DeviceId
  186. )
  187. /*++
  188. Generated device id is returned for the supplied pc-card
  189. Arguments:
  190. Pdo - Pointer to the physical device object for the pc-card
  191. FunctionNumber - Function number of the function in a multi-function card.
  192. If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested device id
  193. is for the parent device - not for any individual function
  194. DeviceId - Pointer to the unicode string in which device id is returned
  195. Return Value
  196. Status
  197. --*/
  198. {
  199. PPDO_EXTENSION pdoExtension=Pdo->DeviceExtension;
  200. PSOCKET_DATA socketData = pdoExtension->SocketData;
  201. ANSI_STRING ansiId;
  202. PUCHAR deviceId;
  203. NTSTATUS status;
  204. PAGED_CODE();
  205. ASSERT(DeviceId);
  206. if (!socketData) {
  207. ASSERT (socketData);
  208. return STATUS_DEVICE_NOT_READY;
  209. }
  210. status = PcmciaGenerateDeviceId(socketData,
  211. FunctionNumber,
  212. &deviceId);
  213. if (!NT_SUCCESS(status)) {
  214. return status;
  215. }
  216. RtlInitAnsiString(&ansiId, deviceId);
  217. status = RtlAnsiStringToUnicodeString(DeviceId,
  218. &ansiId,
  219. TRUE);
  220. ExFreePool(deviceId);
  221. return status;
  222. }
  223. NTSTATUS
  224. PcmciaGetHardwareIds(
  225. IN PDEVICE_OBJECT Pdo,
  226. IN ULONG FunctionNumber,
  227. OUT PUNICODE_STRING HardwareIds
  228. )
  229. /*++
  230. Routine Description:
  231. This routine generates the hardware id's for the given PC-Card and returns them
  232. as a Unicode multi-string.
  233. Hardware ids for PC-Cards are:
  234. 1. The device id of the PC-Card
  235. 2. The device id of the PC-Card with the CRC replaced with the Manufacturer code and
  236. Manufacturer info fields obtained from the tuple information on the PC-Card
  237. These hardware id's are compatible with win 9x hardware ids
  238. Arguments:
  239. Pdo - Pointer to device object representing the PC-Card
  240. FunctionNumber - Function number of the function in a multi-function card.
  241. If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested hardware id
  242. is for the parent device - not for any individual function
  243. HardwareIds - Pointer to the unicode string which contains the hardware id's as a multi-string
  244. Return value:
  245. --*/
  246. {
  247. PPDO_EXTENSION pdoExtension=Pdo->DeviceExtension;
  248. PSOCKET socket = pdoExtension->Socket;
  249. PSOCKET_DATA socketData = pdoExtension->SocketData;
  250. NTSTATUS status;
  251. PSTR strings[4] = {NULL};
  252. PUCHAR hwId, hwId2;
  253. UCHAR deviceType;
  254. UCHAR stringCount = 0;
  255. PAGED_CODE();
  256. if (!socketData) {
  257. ASSERT (socketData);
  258. return STATUS_DEVICE_NOT_READY;
  259. }
  260. //
  261. // get the device type for later use
  262. //
  263. status = PcmciaGetDeviceType(Pdo, FunctionNumber, &deviceType);
  264. if (!NT_SUCCESS(status)) {
  265. return status;
  266. }
  267. //
  268. // The first hardware id is identical to the device id
  269. // Generate the device id
  270. //
  271. status = PcmciaGenerateDeviceId(socketData,
  272. FunctionNumber,
  273. &strings[stringCount++]);
  274. if (!NT_SUCCESS(status)) {
  275. return status;
  276. }
  277. try {
  278. status = STATUS_INSUFFICIENT_RESOURCES;
  279. hwId = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
  280. if (!hwId) {
  281. leave;
  282. }
  283. strings[stringCount++] = hwId;
  284. //
  285. // The second hardware is the device id with the CRC replaced
  286. // with the manufacturer code and info
  287. //
  288. if (*(socketData->Mfg) == '\0' ) {
  289. //
  290. // No manufacturer name available
  291. //
  292. if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
  293. if (socketData->Flags & SDF_JEDEC_ID) {
  294. sprintf(hwId, "%s\\%s-%04x",
  295. PCMCIA_ID_STRING,
  296. PCMCIA_MEMORY_ID_STRING,
  297. socketData->JedecId);
  298. } else {
  299. sprintf(hwId, "%s\\%s-%04X-%04X",
  300. PCMCIA_ID_STRING,
  301. PCMCIA_UNKNOWN_MANUFACTURER_STRING,
  302. socketData->ManufacturerCode,
  303. socketData->ManufacturerInfo);
  304. }
  305. } else {
  306. sprintf(hwId, "%s\\%s-DEV%d-%04X-%04X", PCMCIA_ID_STRING,
  307. PCMCIA_UNKNOWN_MANUFACTURER_STRING,
  308. FunctionNumber,
  309. socketData->ManufacturerCode,
  310. socketData->ManufacturerInfo);
  311. }
  312. DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x HwId=%s\n", Pdo, hwId));
  313. } else {
  314. UCHAR Mfg[MAX_MANFID_LENGTH];
  315. UCHAR Ident[MAX_IDENT_LENGTH];
  316. PcmciaFilterIdString(socketData->Mfg, Mfg, MAX_MANFID_LENGTH);
  317. PcmciaFilterIdString(socketData->Ident, Ident, MAX_IDENT_LENGTH);
  318. //
  319. // Here a mistake on Win2000 is forcing us to now generate two different
  320. // IDs. The intended and documented form at this point is to generate:
  321. //
  322. // PCMCIA\<mfg>-<ident>-<code>-<info>
  323. //
  324. // but Win2000 had a bug where this was generated instead:
  325. //
  326. // PCMCIA\<mfg>-<code>-<info>
  327. //
  328. // So now we generate both in case someone started using the bogus format.
  329. //
  330. hwId2 = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
  331. if (!hwId2) {
  332. leave;
  333. }
  334. strings[stringCount++] = hwId2;
  335. if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
  336. sprintf(hwId, "%s\\%s-%s-%04X-%04X", PCMCIA_ID_STRING,
  337. Mfg,
  338. Ident,
  339. socketData->ManufacturerCode,
  340. socketData->ManufacturerInfo);
  341. sprintf(hwId2, "%s\\%s-%04X-%04X", PCMCIA_ID_STRING,
  342. Mfg,
  343. socketData->ManufacturerCode,
  344. socketData->ManufacturerInfo);
  345. } else {
  346. sprintf(hwId, "%s\\%s-%s-DEV%d-%04X-%04X",
  347. PCMCIA_ID_STRING,
  348. Mfg,
  349. Ident,
  350. FunctionNumber,
  351. socketData->ManufacturerCode,
  352. socketData->ManufacturerInfo);
  353. sprintf(hwId2, "%s\\%s-DEV%d-%04X-%04X",
  354. PCMCIA_ID_STRING,
  355. Mfg,
  356. FunctionNumber,
  357. socketData->ManufacturerCode,
  358. socketData->ManufacturerInfo);
  359. }
  360. DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x HwId=%s\n", Pdo, hwId));
  361. DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x HwId=%s\n", Pdo, hwId2));
  362. }
  363. if (deviceType == PCCARD_TYPE_ATA) {
  364. hwId = ExAllocatePool(PagedPool, PCMCIA_MAXIMUM_DEVICE_ID_LENGTH);
  365. if (!hwId) {
  366. leave;
  367. }
  368. strings[stringCount++] = hwId;
  369. sprintf(hwId, "%s\\%s",
  370. PCMCIA_ID_STRING,
  371. PcmciaCompatibleIds[PCCARD_TYPE_ATA]);
  372. DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x HwId=%s\n", Pdo, hwId));
  373. }
  374. status = PcmciaStringsToMultiString(strings , stringCount, HardwareIds);
  375. } finally {
  376. while(stringCount != 0) {
  377. ExFreePool(strings[--stringCount]);
  378. }
  379. }
  380. return status;
  381. }
  382. NTSTATUS
  383. PcmciaGetCompatibleIds(
  384. IN PDEVICE_OBJECT Pdo,
  385. IN ULONG FunctionNumber,
  386. OUT PUNICODE_STRING CompatibleIds
  387. )
  388. /*++
  389. Routine Description:
  390. This routine returns the compatible ids for the given PC-Card.
  391. Compatible id's are generated based on the Function Id of the PC-Card
  392. obtained from the CISTPL_FUNCID in the CIS tuple info. on the PC-Card.
  393. A table lookup is done based on the CISTPL_FUNCID to obtain the compatible id
  394. This compatible id is identical to the win 9x generated compatible ids
  395. Arguments:
  396. Pdo - Pointer to the device object representing the PC-Card
  397. FunctionNumber - Function number of the function in a multi-function card.
  398. If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested compatibleid
  399. is for the parent device - not for any individual function
  400. CompatibleIds - Pointer to the unicode string which would contain the compatible ids
  401. as a multi-string on return
  402. Return value:
  403. STATUS_SUCCESS
  404. Any other status - could not generate compatible ids
  405. --*/
  406. {
  407. UCHAR deviceType ;
  408. NTSTATUS status;
  409. PCSTR strings[1] = {""};
  410. PAGED_CODE();
  411. status = PcmciaGetDeviceType(Pdo, FunctionNumber, &deviceType);
  412. if (!NT_SUCCESS(status)) {
  413. return status;
  414. }
  415. if ((deviceType == PCCARD_TYPE_RESERVED) ||
  416. (deviceType > PCMCIA_MAX_DEVICE_TYPE_SUPPORTED)) {
  417. status = PcmciaStringsToMultiString(strings, 1, CompatibleIds);
  418. } else {
  419. status = PcmciaStringsToMultiString(&PcmciaCompatibleIds[deviceType], 1, CompatibleIds);
  420. DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x CompatId=%s\n", Pdo, PcmciaCompatibleIds[deviceType]));
  421. }
  422. return status;
  423. }
  424. NTSTATUS
  425. PcmciaGetDeviceType(
  426. IN PDEVICE_OBJECT Pdo,
  427. IN ULONG FunctionNumber,
  428. OUT PUCHAR DeviceType
  429. )
  430. /*++
  431. Routine Description:
  432. This routine returns the device type for the given PC-Card.
  433. device type is obtained from the CISTPL_FUNCID in the CIS tuple info. on the PC-Card.
  434. Arguments:
  435. Pdo - Pointer to the device object representing the PC-Card
  436. FunctionNumber - Function number of the function in a multi-function card.
  437. If this is PCMCIA_MULTIFUNCTION_PARENT, then the requested compatibleid
  438. is for the parent device - not for any individual function
  439. Return value:
  440. device type
  441. --*/
  442. {
  443. UCHAR deviceType ;
  444. PPDO_EXTENSION pdoExtension;
  445. PAGED_CODE();
  446. pdoExtension = Pdo->DeviceExtension;
  447. if (IsDeviceMultifunction(pdoExtension)) {
  448. if (FunctionNumber == PCMCIA_MULTIFUNCTION_PARENT) {
  449. //
  450. // This is for the root multifunction pc-card
  451. //
  452. deviceType = PCCARD_TYPE_MULTIFUNCTION3;
  453. } else {
  454. //
  455. // This is for the individual multifunction child
  456. //
  457. PSOCKET_DATA socketData;
  458. ULONG index;
  459. for (socketData = pdoExtension->SocketData, index = 0; (socketData != NULL);
  460. socketData = socketData->Next,index++) {
  461. if (socketData->Function == FunctionNumber) {
  462. //
  463. // Found the child;
  464. //
  465. break;
  466. }
  467. }
  468. if (!socketData) {
  469. ASSERT (socketData);
  470. return STATUS_DEVICE_NOT_READY;
  471. }
  472. deviceType = socketData->DeviceType;
  473. }
  474. } else {
  475. //
  476. // This is a run-of-the mill single function card
  477. //
  478. deviceType = pdoExtension->SocketData->DeviceType;
  479. }
  480. *DeviceType = deviceType;
  481. return STATUS_SUCCESS;
  482. }
  483. NTSTATUS
  484. PcmciaStringsToMultiString(
  485. IN PCSTR * Strings,
  486. IN ULONG Count,
  487. IN PUNICODE_STRING MultiString
  488. )
  489. /*++
  490. Routine Description:
  491. This routine formats a set of supplied strings into a multi string format, terminating
  492. it with a double '\0' character
  493. Arguments:
  494. Strings - Pointer to an array of strings
  495. Count - Number of strings in the supplied array which are packed into the multi-string
  496. MultiString - Pointer to the Unicode string which packs the supplied string as a multi-string
  497. terminated by double NULL
  498. Return value:
  499. STATUS_SUCCESS
  500. STATUS_INSUFFICIENT_RESOURCES - Could not allocate memory for the multi-string
  501. --*/
  502. {
  503. ULONG i, multiStringLength=0;
  504. UNICODE_STRING tempMultiString;
  505. PCSTR * currentString;
  506. ANSI_STRING ansiString;
  507. NTSTATUS status;
  508. ASSERT (MultiString->Buffer == NULL);
  509. for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
  510. RtlInitAnsiString(&ansiString, *currentString);
  511. multiStringLength += RtlAnsiStringToUnicodeSize(&ansiString);
  512. }
  513. ASSERT(multiStringLength != 0);
  514. multiStringLength += sizeof(WCHAR);
  515. if (multiStringLength > MAXUSHORT) {
  516. return STATUS_UNSUCCESSFUL;
  517. }
  518. MultiString->Buffer = ExAllocatePool(PagedPool, multiStringLength);
  519. if (MultiString->Buffer == NULL) {
  520. return STATUS_INSUFFICIENT_RESOURCES;
  521. }
  522. MultiString->MaximumLength = (USHORT) multiStringLength;
  523. MultiString->Length = (USHORT) multiStringLength;
  524. tempMultiString = *MultiString;
  525. for (i = Count, currentString = Strings; i > 0;i--, currentString++) {
  526. RtlInitAnsiString(&ansiString, *currentString);
  527. status = RtlAnsiStringToUnicodeString(&tempMultiString,
  528. &ansiString,
  529. FALSE);
  530. ASSERT(NT_SUCCESS(status));
  531. ((PSTR) tempMultiString.Buffer) += tempMultiString.Length + sizeof(WCHAR);
  532. };
  533. //
  534. // Add one more NULL to terminate the multi string
  535. //
  536. RtlZeroMemory(tempMultiString.Buffer, sizeof(WCHAR));
  537. return STATUS_SUCCESS;
  538. }
  539. NTSTATUS
  540. PcmciaGetInstanceId(
  541. IN PDEVICE_OBJECT Pdo,
  542. OUT PUNICODE_STRING InstanceId
  543. )
  544. /*++
  545. Routine Description:
  546. This routine generates a unique instance id (1 upwards) for the supplied
  547. PC-Card which is guaranteed not to clash with any other instance ids under
  548. the same pcmcia controller, for the same type of card.
  549. A new instance id is computed only if it was not already present for the PC-Card.
  550. Arguments:
  551. Pdo - Pointer to the device object representing the PC-Card
  552. InstanceId - Pointer to a unicode string which will contain the generated
  553. instance id.
  554. Memory for the unicode string allocated by this routine.
  555. Caller's responsibility to free it .
  556. Return value:
  557. STATUS_SUCCESS
  558. STATUS_UNSUCCESSFUL - Currently there's a cap on the maximum value of instance id - 999999
  559. This status returned only if more than 999999 PC-Cards exist under
  560. this PCMCIA controller!
  561. Any other status - Something failed in the string allocation/conversion
  562. --*/
  563. {
  564. PPDO_EXTENSION pdoExtension=Pdo->DeviceExtension;
  565. PSOCKET socket = pdoExtension->Socket;
  566. PSOCKET_DATA socketData = pdoExtension->SocketData;
  567. ULONG instance;
  568. NTSTATUS status;
  569. ANSI_STRING sizeString;
  570. ASSERT(InstanceId);
  571. if (!socketData) {
  572. return STATUS_DEVICE_NOT_READY;
  573. }
  574. //
  575. // Allocate memory for the unicode string
  576. // Maximum of 6 digits in the instance..
  577. //
  578. RtlInitAnsiString(&sizeString, "123456");
  579. status = RtlAnsiStringToUnicodeString(InstanceId, &sizeString, TRUE);
  580. if (!NT_SUCCESS(status)) {
  581. return status;
  582. }
  583. //
  584. // Don't recompute instance if it's already present
  585. //
  586. if (socketData->Instance) {
  587. status = RtlIntegerToUnicodeString(socketData->Instance, 10, InstanceId);
  588. } else {
  589. KIRQL OldIrql;
  590. //
  591. // Synchronize access to prevent two identical ids/instances
  592. //
  593. KeAcquireSpinLock(&PcmciaGlobalLock, &OldIrql);
  594. //
  595. // assume failure
  596. //
  597. status = STATUS_UNSUCCESSFUL;
  598. for (instance = 1; instance <= PCMCIA_MAX_INSTANCE; instance++) {
  599. if (PcmciaCheckInstance(pdoExtension->DeviceId,
  600. instance)) {
  601. socketData->Instance = instance;
  602. break;
  603. }
  604. }
  605. KeReleaseSpinLock(&PcmciaGlobalLock, OldIrql);
  606. if (socketData->Instance) {
  607. status = RtlIntegerToUnicodeString(instance, 10, InstanceId);
  608. }
  609. }
  610. if (!NT_SUCCESS(status)) {
  611. RtlFreeUnicodeString(InstanceId);
  612. }
  613. if (NT_SUCCESS(status)) {
  614. DebugPrint((PCMCIA_DEBUG_INFO, "pdo %08x InstanceId=%d\n", Pdo, socketData->Instance));
  615. }
  616. return status;
  617. }
  618. BOOLEAN
  619. PcmciaCheckInstance(
  620. IN PUCHAR DeviceId,
  621. IN ULONG Instance
  622. )
  623. /*++
  624. Routine Description:
  625. This routine checks to see if the supplied instance id clashes with any other PC-card
  626. with the same device id
  627. Arguments:
  628. SocketList - Pointer to the list of sockets on the PCMCIA controller
  629. DeviceId - Pointer to the device id of the PC-Card for which the Instance Id is being checked
  630. Instance - Instance Id which needs to be verified
  631. Return value:
  632. TRUE - Instance is unique for the given DeviceId and may be used
  633. FALSE - Instance clashes with another instance id for the same device id
  634. --*/
  635. {
  636. PPDO_EXTENSION pdoExtension;
  637. PFDO_EXTENSION fdoExtension;
  638. PSOCKET_DATA socketData;
  639. PDEVICE_OBJECT fdo, pdo;
  640. for (fdo = FdoList; fdo != NULL; fdo = fdoExtension->NextFdo) {
  641. fdoExtension = fdo->DeviceExtension;
  642. ASSERT (fdoExtension);
  643. if (!IsDeviceStarted(fdoExtension)) {
  644. continue;
  645. }
  646. for (pdo = fdoExtension->PdoList; pdo != NULL; pdo = pdoExtension->NextPdoInFdoChain) {
  647. pdoExtension = pdo->DeviceExtension;
  648. socketData = pdoExtension->SocketData;
  649. if (IsDevicePhysicallyRemoved(pdoExtension)) {
  650. //
  651. // going to be removed soon
  652. //
  653. continue;
  654. }
  655. if (!socketData) {
  656. //
  657. // socketData already cleaned up
  658. //
  659. continue;
  660. }
  661. //
  662. // If an instance has not
  663. // been assigned yet to this card, skip
  664. //
  665. if (socketData->Instance == 0) {
  666. continue;
  667. }
  668. //
  669. // If this socket's device id matches the given socket's device id
  670. // compare the instances: if equal, then this instance is not ok.
  671. //
  672. //
  673. if ((pdoExtension->DeviceId == NULL) || (DeviceId == NULL)) {
  674. continue;
  675. }
  676. if ((strcmp(pdoExtension->DeviceId, DeviceId)==0) &&
  677. (socketData->Instance == Instance)) {
  678. return FALSE;
  679. }
  680. }
  681. }
  682. //
  683. // Instance is ok and unique
  684. //
  685. return TRUE;
  686. }
  687. VOID
  688. PcmciaFilterIdString(
  689. IN PUCHAR pIn,
  690. OUT PUCHAR pOut,
  691. ULONG MaxLen
  692. )
  693. /*++
  694. Filters out characters that shouldn't appear in device id's
  695. Arguments:
  696. pIn - pointer to input string
  697. pOut - pointer to output string
  698. MaxLen - size of buffers
  699. Return Value
  700. none
  701. --*/
  702. {
  703. ULONG i;
  704. for (i=0; i < MaxLen; i++) {
  705. if (*pIn == 0) {
  706. *pOut = 0;
  707. break;
  708. }
  709. if (*pIn >= ' ' && *pIn < 0x7F) {
  710. *pOut++ = *pIn++;
  711. } else {
  712. pIn++;
  713. }
  714. }
  715. }