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.

2378 lines
68 KiB

  1. /*++
  2. Copyright (c) 1991, 1992, 1993 Microsoft Corporation
  3. Module Name:
  4. Legacy.c
  5. Abstract:
  6. This module contains the code that does the legacy configuration and
  7. initialization of the comm ports. As the driver gets more PnP
  8. functionality and the PnP manager appears, most of this module should
  9. go away.
  10. Environment:
  11. Kernel mode
  12. --*/
  13. #include "precomp.h"
  14. #if !defined(NO_LEGACY_DRIVERS)
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(INIT,SerialEnumerateLegacy)
  17. #pragma alloc_text(INIT,SerialMigrateLegacyRegistry)
  18. #pragma alloc_text(INIT,SerialBuildResourceList)
  19. #pragma alloc_text(INIT,SerialTranslateResourceList)
  20. #pragma alloc_text(INIT,SerialBuildRequirementsList)
  21. #pragma alloc_text(INIT,SerialIsUserDataValid)
  22. #endif // ALLOC_PRAGMA
  23. static const PHYSICAL_ADDRESS SerialPhysicalZero = {0};
  24. NTSTATUS
  25. SerialTranslateResourceList(IN PDRIVER_OBJECT DriverObject,
  26. IN PKEY_BASIC_INFORMATION UserSubKey,
  27. OUT PCM_RESOURCE_LIST PTrResourceList,
  28. IN PCM_RESOURCE_LIST PResourceList,
  29. IN ULONG PartialCount,
  30. IN PSERIAL_USER_DATA PUserData)
  31. /*++
  32. Routine Description:
  33. This routine will create a resource list of translated resources
  34. based on PResourceList.
  35. This is pageable INIT because it is only called from SerialEnumerateLegacy
  36. which is also pageable INIT.
  37. Arguments:
  38. DriverObject - Only used for logging.
  39. UserSubKey - Only used for logging.
  40. PPResourceList - Pointer to a PCM_RESOURCE_LIST that we are creating.
  41. PResourceList - PCM_RESOURCE_LIST that we are translating.
  42. ParitalCount - Number of Partial Resource lists in PResourceList.
  43. PUserData - Data retrieved as defaults or from the registry.
  44. Return Value:
  45. STATUS_SUCCESS on success, apropriate error value otherwise.
  46. --*/
  47. {
  48. KIRQL outIrql;
  49. KAFFINITY outAffinity = (KAFFINITY)-1;
  50. ULONG outAddrSpace;
  51. PHYSICAL_ADDRESS outPhysAddr;
  52. NTSTATUS status = STATUS_SUCCESS;
  53. PAGED_CODE();
  54. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialTranslateResourceList\n"));
  55. outIrql = (KIRQL)(PUserData->UserLevel ? PUserData->UserLevel
  56. : PUserData->UserVector);
  57. //
  58. // Copy the list over to the translated buffer and fixup and translate
  59. // what we need.
  60. //
  61. RtlCopyMemory(PTrResourceList, PResourceList, sizeof(CM_RESOURCE_LIST)
  62. + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 2);
  63. outAddrSpace = PTrResourceList->List[0].PartialResourceList
  64. .PartialDescriptors[0].Flags;
  65. outPhysAddr = PTrResourceList->List[0].PartialResourceList
  66. .PartialDescriptors[0].u.Port.Start;
  67. if (HalTranslateBusAddress(PUserData->UserInterfaceType,
  68. PUserData->UserBusNumber, PUserData->UserPort,
  69. &outAddrSpace, &outPhysAddr)
  70. == 0) {
  71. SerialLogError(DriverObject, NULL, PUserData->UserPort,
  72. SerialPhysicalZero, 0, 0, 0, 60, STATUS_SUCCESS,
  73. SERIAL_NO_TRANSLATE_PORT, UserSubKey->NameLength
  74. + sizeof(WCHAR), &UserSubKey->Name[0], 0, NULL);
  75. SerialDump(SERERRORS, ("SERIAL: Port map failed attempt was \n"
  76. "------- Interface: %x\n"
  77. "------- Bus Number: %x\n"
  78. "------- userPort: %x\n"
  79. "------- AddrSpace: %x\n"
  80. "------- PhysAddr: %x\n",
  81. PUserData->UserInterfaceType,
  82. PUserData->UserBusNumber,
  83. PUserData->UserPort,
  84. PTrResourceList->List[0].
  85. PartialResourceList.PartialDescriptors[0]
  86. .Flags,
  87. PTrResourceList->List[0].
  88. PartialResourceList.PartialDescriptors[0]
  89. .u.Port.Start.QuadPart));
  90. status = STATUS_NONE_MAPPED;
  91. goto SerialTranslateError;
  92. }
  93. PTrResourceList->List[0].PartialResourceList.PartialDescriptors[0].Flags
  94. = (USHORT)outAddrSpace;
  95. PTrResourceList->List[0].PartialResourceList.PartialDescriptors[0]
  96. .u.Port.Start = outPhysAddr;
  97. if ((PTrResourceList->List[0].PartialResourceList
  98. .PartialDescriptors[1].u.Interrupt.Vector
  99. = HalGetInterruptVector(PUserData->UserInterfaceType,
  100. PUserData->UserBusNumber, PUserData->UserLevel
  101. ? PUserData->UserLevel
  102. : PUserData->UserVector,
  103. PUserData->UserVector, &outIrql,
  104. &outAffinity)) == 0) {
  105. SerialLogError(DriverObject, NULL, PUserData->UserPort,
  106. SerialPhysicalZero, 0, 0, 0, 61, STATUS_SUCCESS,
  107. SERIAL_NO_GET_INTERRUPT, UserSubKey->NameLength
  108. + sizeof(WCHAR), &UserSubKey->Name[0], 0, NULL);
  109. status = STATUS_NONE_MAPPED;
  110. goto SerialTranslateError;
  111. }
  112. PTrResourceList->List[0].PartialResourceList
  113. .PartialDescriptors[1].u.Interrupt.Level = outIrql;
  114. PTrResourceList->List[0].PartialResourceList
  115. .PartialDescriptors[1].u.Interrupt.Affinity = outAffinity;
  116. outAddrSpace = PTrResourceList->List[0].PartialResourceList
  117. .PartialDescriptors[2].Flags;
  118. outPhysAddr = PTrResourceList->List[0].PartialResourceList
  119. .PartialDescriptors[2].u.Port.Start;
  120. if (PartialCount == 3) {
  121. if (HalTranslateBusAddress(PUserData->UserInterfaceType,
  122. PUserData->UserBusNumber,
  123. PUserData->UserInterruptStatus,
  124. &outAddrSpace, &outPhysAddr) == 0) {
  125. SerialLogError(DriverObject, NULL, PUserData->UserPort,
  126. SerialPhysicalZero, 0, 0, 0, 62, STATUS_SUCCESS,
  127. SERIAL_NO_TRANSLATE_ISR, UserSubKey->NameLength
  128. + sizeof(WCHAR), &UserSubKey->Name[0], 0, NULL);
  129. SerialDump(SERERRORS, ("SERIAL: ISR map failed attempt was \n"
  130. "------- Interface: %x\n"
  131. "------- Bus Number: %x\n"
  132. "------- IntStatus: %x\n"
  133. "------- AddrSpace: %x\n"
  134. "------- PhysAddr: %x\n",
  135. PUserData->UserInterfaceType,
  136. PUserData->UserBusNumber,
  137. PUserData->UserInterruptStatus,
  138. PTrResourceList->List[0].
  139. PartialResourceList.PartialDescriptors[2]
  140. .Flags,
  141. PTrResourceList->List[0].
  142. PartialResourceList.PartialDescriptors[2]
  143. .u.Port.Start.QuadPart));
  144. status = STATUS_NONE_MAPPED;
  145. goto SerialTranslateError;
  146. }
  147. SerialDump(SERDIAG1, ("SERIAL: ISR map was %x\n", outPhysAddr.QuadPart));
  148. PTrResourceList->List[0].PartialResourceList.
  149. PartialDescriptors[2].Flags = (USHORT)outAddrSpace;
  150. PTrResourceList->List[0].PartialResourceList.PartialDescriptors[2]
  151. .u.Port.Start = outPhysAddr;
  152. }
  153. SerialTranslateError:;
  154. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialTranslateResourceList\n"));
  155. return status;
  156. }
  157. NTSTATUS
  158. SerialBuildRequirementsList(OUT PIO_RESOURCE_REQUIREMENTS_LIST PRequiredList,
  159. IN ULONG PartialCount,
  160. IN PSERIAL_USER_DATA PUserData)
  161. /*++
  162. Routine Description:
  163. This routine will build an IO_RESOURCE_REQUIREMENTS_LIST based on
  164. the defaults and user-supplied registry info.
  165. This is pageable INIT because it is only called from SerialEnumerateLegacy
  166. which is also pageable INIT.
  167. Arguments:
  168. DriverObject - Used only for logging.
  169. PRequiredList - PIO_RESOURCE_REQUIREMENTS_LIST we are building.
  170. PartialCount - Number of partial descriptors needed in PPRequiredList.
  171. PUserData - Default and user-supplied values from the registry.
  172. Return Value:
  173. STATUS_SUCCESS on success, apropriate error value otherwise.
  174. --*/
  175. {
  176. PIO_RESOURCE_LIST reqResList;
  177. PIO_RESOURCE_DESCRIPTOR reqResDesc;
  178. NTSTATUS status = STATUS_SUCCESS;
  179. PAGED_CODE();
  180. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialBuildRequirementsList\n"));
  181. // Build requirements list
  182. //
  183. RtlZeroMemory(PRequiredList, sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
  184. + sizeof(IO_RESOURCE_DESCRIPTOR) * 2);
  185. PRequiredList->ListSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
  186. + sizeof(IO_RESOURCE_DESCRIPTOR) * (PartialCount - 1);
  187. PRequiredList->InterfaceType = PUserData->UserInterfaceType;
  188. PRequiredList->BusNumber = PUserData->UserBusNumber;
  189. PRequiredList->SlotNumber = 0;
  190. PRequiredList->AlternativeLists = 1;
  191. reqResList = &PRequiredList->List[0];
  192. reqResList->Version = 1;
  193. reqResList->Revision = 1;
  194. reqResList->Count = PartialCount;
  195. reqResDesc = &reqResList->Descriptors[0];
  196. //
  197. // Port Information
  198. //
  199. reqResDesc->Flags = (USHORT)PUserData->UserAddressSpace;
  200. reqResDesc->Type = CmResourceTypePort;
  201. reqResDesc->ShareDisposition = CmResourceShareDriverExclusive;
  202. reqResDesc->u.Port.Length = SERIAL_REGISTER_SPAN;
  203. reqResDesc->u.Port.Alignment= 1;
  204. reqResDesc->u.Port.MinimumAddress = PUserData->UserPort;
  205. reqResDesc->u.Port.MaximumAddress.QuadPart
  206. = PUserData->UserPort.QuadPart + SERIAL_REGISTER_SPAN - 1;
  207. reqResDesc++;
  208. //
  209. // Interrupt information
  210. //
  211. if (PUserData->UserInterruptMode == Latched) {
  212. reqResDesc->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  213. } else {
  214. reqResDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  215. }
  216. //
  217. // We have to globally share resources even though this is a **BAD**
  218. // thing. We must do it for multiport cards. DO NOT replicate
  219. // this in other drivers.
  220. //
  221. reqResDesc->ShareDisposition = CmResourceShareShared;
  222. reqResDesc->Type = CmResourceTypeInterrupt;
  223. reqResDesc->u.Interrupt.MinimumVector = PUserData->UserVector;
  224. reqResDesc->u.Interrupt.MaximumVector = PUserData->UserVector;
  225. //
  226. // ISR register information (if needed)
  227. //
  228. if (PartialCount == 3) {
  229. reqResDesc++;
  230. reqResDesc->Type = CmResourceTypePort;
  231. //
  232. // We have to globally share resources even though this is a **BAD**
  233. // thing. We must do it for multiport cards. DO NOT replicate
  234. // this in other drivers.
  235. //
  236. reqResDesc->ShareDisposition = CmResourceShareShared;
  237. reqResDesc->Flags = (USHORT)PUserData->UserAddressSpace;
  238. reqResDesc->u.Port.Length = 1;
  239. reqResDesc->u.Port.Alignment= 1;
  240. reqResDesc->u.Port.MinimumAddress = PUserData->UserInterruptStatus;
  241. reqResDesc->u.Port.MaximumAddress = PUserData->UserInterruptStatus;
  242. }
  243. SerialDump(SERTRACECALLS, ("SERIAL: Leave SerialBuildRequirementsList\n"));
  244. return status;
  245. }
  246. NTSTATUS
  247. SerialBuildResourceList(OUT PCM_RESOURCE_LIST PResourceList,
  248. OUT PULONG PPartialCount,
  249. IN PSERIAL_USER_DATA PUserData)
  250. /*++
  251. Routine Description:
  252. This routine will build a resource list based on the information
  253. supplied by the registry.
  254. This is pageable INIT because it is only called from SerialEnumerateLegacy
  255. which is also pageable INIT.
  256. Arguments:
  257. PResourceList - Pointer to PCM_RESOURCE_LIST we are building.
  258. PPartialCount - Number of Partial Resource Lists we required.
  259. PUserData - Pointer to user-supplied and default info from registry.
  260. Return Value:
  261. STATUS_SUCCESS on success, apropriate error value otherwise.
  262. --*/
  263. {
  264. ULONG countOfPartials;
  265. PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartial;
  266. NTSTATUS status = STATUS_SUCCESS;
  267. PAGED_CODE();
  268. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialBuildResourceList\n"));
  269. SerialDump(SERDIAG1, ("SERIAL: Building cmreslist in %x\n", PResourceList));
  270. *PPartialCount = 0;
  271. //
  272. // If we have a separate ISR register requirement, we then have 3
  273. // partials instead of 2.
  274. //
  275. countOfPartials = (PUserData->UserInterruptStatus.LowPart != 0) ? 3 : 2;
  276. RtlZeroMemory(PResourceList, sizeof(CM_RESOURCE_LIST)
  277. + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 2);
  278. PResourceList->Count = 1;
  279. PResourceList->List[0].InterfaceType = PUserData->UserInterfaceType;
  280. PResourceList->List[0].BusNumber = PUserData->UserBusNumber;
  281. PResourceList->List[0].PartialResourceList.Count = countOfPartials;
  282. pPartial
  283. = &PResourceList->List[0].PartialResourceList.PartialDescriptors[0];
  284. //
  285. // Port information
  286. //
  287. pPartial->Type = CmResourceTypePort;
  288. pPartial->ShareDisposition = CmResourceShareDeviceExclusive;
  289. pPartial->Flags = (USHORT)PUserData->UserAddressSpace;
  290. pPartial->u.Port.Start = PUserData->UserPort;
  291. pPartial->u.Port.Length = SERIAL_REGISTER_SPAN;
  292. pPartial++;
  293. //
  294. // Interrupt information
  295. //
  296. pPartial->Type = CmResourceTypeInterrupt;
  297. //
  298. // We have to globally share resources even though this is a **BAD**
  299. // thing. We must do it for multiport cards. DO NOT replicate
  300. // this in other drivers.
  301. //
  302. pPartial->ShareDisposition = CmResourceShareShared;
  303. if (PUserData->UserInterruptMode == Latched) {
  304. pPartial->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  305. } else {
  306. pPartial->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  307. }
  308. pPartial->u.Interrupt.Vector = PUserData->UserVector;
  309. if (PUserData->UserLevel == 0) {
  310. pPartial->u.Interrupt.Level = PUserData->UserVector;
  311. } else {
  312. pPartial->u.Interrupt.Level = PUserData->UserLevel;
  313. }
  314. //
  315. // ISR register information (if needed)
  316. //
  317. if (countOfPartials == 3) {
  318. pPartial++;
  319. pPartial->Type = CmResourceTypePort;
  320. //
  321. // We have to globally share resources even though this is a **BAD**
  322. // thing. We must do it for multiport cards. DO NOT replicate
  323. // this in other drivers.
  324. //
  325. pPartial->ShareDisposition = CmResourceShareShared;
  326. pPartial->Flags = (USHORT)PUserData->UserAddressSpace;
  327. pPartial->u.Port.Start = PUserData->UserInterruptStatus;
  328. pPartial->u.Port.Length = SERIAL_STATUS_LENGTH;
  329. }
  330. *PPartialCount = countOfPartials;
  331. SerialDump(SERTRACECALLS, ("SERIAL: Leave SerialBuildResourceList\n"));
  332. return status;
  333. }
  334. NTSTATUS
  335. SerialMigrateLegacyRegistry(IN PDEVICE_OBJECT PPdo,
  336. IN PSERIAL_USER_DATA PUserData, BOOLEAN IsMulti)
  337. /*++
  338. Routine Description:
  339. This routine will copy information stored in the registry for a legacy
  340. device over to the PnP Device Parameters section.
  341. This is pageable INIT because it is only called from SerialEnumerateLegacy
  342. which is also pageable INIT.
  343. Arguments:
  344. PPdo - Pointer to the Device Object we are migrating.
  345. PUserData - Pointer to user supplied values.
  346. Return Value:
  347. STATUS_SUCCESS on success, apropriate error value otherwise.
  348. --*/
  349. {
  350. NTSTATUS status;
  351. HANDLE pnpKey;
  352. UNICODE_STRING pnpNameBuf;
  353. ULONG isMultiport = 1;
  354. ULONG one = 1;
  355. PAGED_CODE();
  356. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialMigrateLegacyRegistry\n"));
  357. status = IoOpenDeviceRegistryKey(PPdo, PLUGPLAY_REGKEY_DEVICE,
  358. STANDARD_RIGHTS_WRITE, &pnpKey);
  359. if (!NT_SUCCESS(status)) {
  360. SerialDump(SERTRACECALLS, ("SERIAL: Leave (1) SerialMigrateLegacyRegistry"
  361. "\n"));
  362. return status;
  363. }
  364. //
  365. // Allocate a buffer to copy the port name over.
  366. //
  367. pnpNameBuf.MaximumLength = sizeof(WCHAR) * 256;
  368. pnpNameBuf.Length = 0;
  369. pnpNameBuf.Buffer = ExAllocatePool(PagedPool, sizeof(WCHAR) * 257);
  370. if (pnpNameBuf.Buffer == NULL) {
  371. SerialLogError(PPdo->DriverObject, NULL, PUserData->UserPort,
  372. SerialPhysicalZero, 0, 0, 0, 63, STATUS_SUCCESS,
  373. SERIAL_INSUFFICIENT_RESOURCES, 0, NULL, 0, NULL);
  374. SerialDump(SERERRORS, ("SERIAL: Couldn't allocate buffer for the PnP "
  375. "link\n"));
  376. status = STATUS_INSUFFICIENT_RESOURCES;
  377. goto MigrateLegacyExit;
  378. }
  379. RtlZeroMemory(pnpNameBuf.Buffer, pnpNameBuf.MaximumLength + sizeof(WCHAR));
  380. //
  381. // Add the port name -- ALWAYS
  382. //
  383. RtlAppendUnicodeStringToString(&pnpNameBuf, &PUserData->UserSymbolicLink);
  384. RtlZeroMemory(((PUCHAR)(&pnpNameBuf.Buffer[0])) + pnpNameBuf.Length,
  385. sizeof(WCHAR));
  386. status = SerialPutRegistryKeyValue(pnpKey, L"PortName", sizeof(L"PortName"),
  387. REG_SZ, pnpNameBuf.Buffer,
  388. pnpNameBuf.Length + sizeof(WCHAR));
  389. ExFreePool(pnpNameBuf.Buffer);
  390. if (!NT_SUCCESS(status)) {
  391. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate PortName\n"));
  392. goto MigrateLegacyExit;
  393. }
  394. //
  395. // If it was part of a multiport card, save that info as well
  396. //
  397. if (IsMulti) {
  398. status = SerialPutRegistryKeyValue(pnpKey, L"MultiportDevice",
  399. sizeof(L"MultiportDevice"), REG_DWORD,
  400. &isMultiport, sizeof(ULONG));
  401. if (!NT_SUCCESS(status)) {
  402. SerialDump(SERERRORS, ("SERIAL: Couldn't mark multiport\n"));
  403. goto MigrateLegacyExit;
  404. }
  405. }
  406. //
  407. // If a port index was specified, save it
  408. //
  409. if (PUserData->UserPortIndex != 0) {
  410. status = SerialPutRegistryKeyValue(pnpKey, L"PortIndex",
  411. sizeof(L"PortIndex"), REG_DWORD,
  412. &PUserData->UserPortIndex,
  413. sizeof(ULONG));
  414. if (!NT_SUCCESS(status)) {
  415. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate PortIndex\n"));
  416. goto MigrateLegacyExit;
  417. }
  418. }
  419. //
  420. // If not default clock rate, save it
  421. //
  422. if (PUserData->UserClockRate != SERIAL_BAD_VALUE) {
  423. status = SerialPutRegistryKeyValue(pnpKey, L"ClockRate",
  424. sizeof(L"ClockRate"), REG_DWORD,
  425. &PUserData->UserClockRate,
  426. sizeof(ULONG));
  427. if (!NT_SUCCESS(status)) {
  428. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate ClockRate\n"));
  429. goto MigrateLegacyExit;
  430. }
  431. }
  432. //
  433. // If there is a user index, save it.
  434. //
  435. if (PUserData->UserIndexed != SERIAL_BAD_VALUE) {
  436. status = SerialPutRegistryKeyValue(pnpKey, L"Indexed", sizeof(L"Indexed"),
  437. REG_DWORD, &PUserData->UserIndexed,
  438. sizeof(ULONG));
  439. if (!NT_SUCCESS(status)) {
  440. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate Indexed\n"));
  441. goto MigrateLegacyExit;
  442. }
  443. }
  444. //
  445. // If the port was disabled, save that.
  446. //
  447. if (PUserData->DisablePort != SERIAL_BAD_VALUE) {
  448. status = SerialPutRegistryKeyValue(pnpKey, L"DisablePort",
  449. sizeof(L"DisablePort"), REG_DWORD,
  450. &PUserData->DisablePort,
  451. sizeof(ULONG));
  452. if (!NT_SUCCESS(status)) {
  453. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate DisablePort\n"));
  454. goto MigrateLegacyExit;
  455. }
  456. }
  457. //
  458. // If Fifo's were forced enabled, save that.
  459. //
  460. if (PUserData->ForceFIFOEnable != SERIAL_BAD_VALUE) {
  461. status = SerialPutRegistryKeyValue(pnpKey, L"ForceFifoEnable",
  462. sizeof(L"ForceFifoEnable"), REG_DWORD,
  463. &PUserData->ForceFIFOEnable,
  464. sizeof(ULONG));
  465. if (!NT_SUCCESS(status)) {
  466. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate ForceFifoEnable\n"));
  467. goto MigrateLegacyExit;
  468. }
  469. }
  470. //
  471. // If RxFIFO had an override, save that.
  472. //
  473. if (PUserData->RxFIFO != SERIAL_BAD_VALUE) {
  474. status = SerialPutRegistryKeyValue(pnpKey, L"RxFIFO", sizeof(L"RxFIFO"),
  475. REG_DWORD, &PUserData->RxFIFO,
  476. sizeof(ULONG));
  477. if (!NT_SUCCESS(status)) {
  478. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate RxFIFO\n"));
  479. goto MigrateLegacyExit;
  480. }
  481. }
  482. //
  483. // If TxFIFO had an override, save that.
  484. //
  485. if (PUserData->TxFIFO != SERIAL_BAD_VALUE) {
  486. status = SerialPutRegistryKeyValue(pnpKey, L"TxFIFO", sizeof(L"TxFIFO"),
  487. REG_DWORD, &PUserData->TxFIFO,
  488. sizeof(ULONG));
  489. if (!NT_SUCCESS(status)) {
  490. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate TxFIFO\n"));
  491. goto MigrateLegacyExit;
  492. }
  493. }
  494. //
  495. // If MaskInverted had an override, save that.
  496. //
  497. if (PUserData->MaskInverted != SERIAL_BAD_VALUE) {
  498. status = SerialPutRegistryKeyValue(pnpKey, L"MaskInverted",
  499. sizeof(L"MaskInverted"), REG_DWORD,
  500. &PUserData->MaskInverted,
  501. sizeof(ULONG));
  502. if (!NT_SUCCESS(status)) {
  503. SerialDump(SERERRORS, ("SERIAL: Couldn't migrate MaskInverted\n"));
  504. goto MigrateLegacyExit;
  505. }
  506. }
  507. MigrateLegacyExit:;
  508. ZwClose(pnpKey);
  509. SerialDump(SERTRACECALLS, ("SERIAL: Leave (2) SerialMigrateLegacyRegistry"
  510. "\n"));
  511. return status;
  512. }
  513. BOOLEAN
  514. SerialIsUserDataValid(IN PDRIVER_OBJECT DriverObject,
  515. IN PKEY_BASIC_INFORMATION UserSubKey,
  516. IN PRTL_QUERY_REGISTRY_TABLE Parameters,
  517. IN ULONG DefaultInterfaceType,
  518. IN PSERIAL_USER_DATA PUserData)
  519. /*++
  520. Routine Description:
  521. This routine will do some basic sanity checking on the data
  522. found in the registry.
  523. This is pageable INIT because it is only called from SerialEnumerateLegacy
  524. which is also pageable INIT.
  525. Arguments:
  526. DriverObject - Used only for logging.
  527. UserSubKey - Used only for logging.
  528. Parameters - Used only for logging.
  529. DefaultInterfaceType - Default bus type we found.
  530. PUserData - Pointer to the values found in the registry we need to validate.
  531. Return Value:
  532. TRUE if data appears valid, FALSE otherwise.
  533. --*/
  534. {
  535. ULONG zero = 0;
  536. BOOLEAN rval = TRUE;
  537. PAGED_CODE();
  538. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialIsUserDataValid\n"));
  539. //
  540. // Make sure that the interrupt is non zero (which we defaulted
  541. // it to).
  542. //
  543. // Make sure that the portaddress is non zero (which we defaulted
  544. // it to).
  545. //
  546. // Make sure that the DosDevices is not NULL (which we defaulted
  547. // it to).
  548. //
  549. // We need to make sure that if an interrupt status
  550. // was specified, that a port index was also specfied,
  551. // and if so that the port index is <= maximum ports
  552. // on a board.
  553. //
  554. // We should also validate that the bus type and number
  555. // are correct.
  556. //
  557. // We will also validate that the interrupt mode makes
  558. // sense for the bus.
  559. //
  560. if (!PUserData->UserPort.LowPart) {
  561. //
  562. // Ehhhh! Lose Game.
  563. //
  564. SerialLogError(
  565. DriverObject,
  566. NULL,
  567. PUserData->UserPort,
  568. SerialPhysicalZero,
  569. 0,
  570. 0,
  571. 0,
  572. 64,
  573. STATUS_SUCCESS,
  574. SERIAL_INVALID_USER_CONFIG,
  575. UserSubKey->NameLength+sizeof(WCHAR),
  576. &UserSubKey->Name[0],
  577. (wcslen(Parameters[1].Name)*sizeof(WCHAR))
  578. + sizeof(WCHAR),
  579. Parameters[1].Name
  580. );
  581. SerialDump(
  582. SERERRORS,
  583. ("SERIAL: Bogus port address %ws\n",
  584. Parameters[1].Name)
  585. );
  586. rval = FALSE;
  587. goto SerialIsUserDataValidError;
  588. }
  589. if (!PUserData->UserVector) {
  590. //
  591. // Ehhhh! Lose Game.
  592. //
  593. SerialLogError(
  594. DriverObject,
  595. NULL,
  596. PUserData->UserPort,
  597. SerialPhysicalZero,
  598. 0,
  599. 0,
  600. 0,
  601. 65,
  602. STATUS_SUCCESS,
  603. SERIAL_INVALID_USER_CONFIG,
  604. UserSubKey->NameLength+sizeof(WCHAR),
  605. &UserSubKey->Name[0],
  606. (wcslen(Parameters[2].Name)*sizeof(WCHAR))
  607. + sizeof(WCHAR),
  608. Parameters[2].Name
  609. );
  610. SerialDump(
  611. SERERRORS,
  612. ("SERIAL: Bogus vector %ws\n",
  613. Parameters[2].Name)
  614. );
  615. rval = FALSE;
  616. goto SerialIsUserDataValidError;
  617. }
  618. if (!PUserData->UserSymbolicLink.Length) {
  619. //
  620. // Ehhhh! Lose Game.
  621. //
  622. SerialLogError(DriverObject, NULL, PUserData->UserPort,
  623. SerialPhysicalZero, 0, 0, 0, 66, STATUS_SUCCESS,
  624. SERIAL_INVALID_USER_CONFIG,
  625. UserSubKey->NameLength + sizeof(WCHAR),
  626. &UserSubKey->Name[0],
  627. (wcslen(Parameters[3].Name) * sizeof(WCHAR))
  628. + sizeof(WCHAR),
  629. Parameters[3].Name);
  630. SerialDump(
  631. SERERRORS,
  632. ("SERIAL: bogus value for %ws\n",
  633. Parameters[3].Name)
  634. );
  635. rval = FALSE;
  636. goto SerialIsUserDataValidError;
  637. }
  638. if (PUserData->UserInterruptStatus.LowPart != 0) {
  639. if (PUserData->UserPortIndex == MAXULONG) {
  640. //
  641. // Ehhhh! Lose Game.
  642. //
  643. SerialLogError(
  644. DriverObject,
  645. NULL,
  646. PUserData->UserPort,
  647. SerialPhysicalZero,
  648. 0,
  649. 0,
  650. 0,
  651. 67,
  652. STATUS_SUCCESS,
  653. SERIAL_INVALID_PORT_INDEX,
  654. PUserData->UserSymbolicLink.Length+sizeof(WCHAR),
  655. PUserData->UserSymbolicLink.Buffer,
  656. 0,
  657. NULL
  658. );
  659. SerialDump(
  660. SERERRORS,
  661. ("SERIAL: Bogus port index %ws\n",
  662. Parameters[0].Name)
  663. );
  664. rval = FALSE;
  665. goto SerialIsUserDataValidError;
  666. } else if (!PUserData->UserPortIndex) {
  667. //
  668. // So sorry, you must have a non-zero port index.
  669. //
  670. SerialLogError(
  671. DriverObject,
  672. NULL,
  673. PUserData->UserPort,
  674. SerialPhysicalZero,
  675. 0,
  676. 0,
  677. 0,
  678. 68,
  679. STATUS_SUCCESS,
  680. SERIAL_INVALID_PORT_INDEX,
  681. PUserData->UserSymbolicLink.Length+sizeof(WCHAR),
  682. PUserData->UserSymbolicLink.Buffer,
  683. 0,
  684. NULL
  685. );
  686. SerialDump(
  687. SERERRORS,
  688. ("SERIAL: Port index must be > 0 for any\n"
  689. "------- port on a multiport card: %ws\n",
  690. Parameters[0].Name)
  691. );
  692. rval = FALSE;
  693. goto SerialIsUserDataValidError;
  694. } else {
  695. if (PUserData->UserIndexed) {
  696. if (PUserData->UserPortIndex > SERIAL_MAX_PORTS_INDEXED) {
  697. SerialLogError(
  698. DriverObject,
  699. NULL,
  700. PUserData->UserPort,
  701. SerialPhysicalZero,
  702. 0,
  703. 0,
  704. 0,
  705. 69,
  706. STATUS_SUCCESS,
  707. SERIAL_PORT_INDEX_TOO_HIGH,
  708. PUserData->UserSymbolicLink.Length+sizeof(WCHAR),
  709. PUserData->UserSymbolicLink.Buffer,
  710. 0,
  711. NULL
  712. );
  713. SerialDump(
  714. SERERRORS,
  715. ("SERIAL: port index to large %ws\n",
  716. Parameters[0].Name)
  717. );
  718. rval = FALSE;
  719. goto SerialIsUserDataValidError;
  720. }
  721. } else {
  722. if (PUserData->UserPortIndex > SERIAL_MAX_PORTS_NONINDEXED) {
  723. SerialLogError(
  724. DriverObject,
  725. NULL,
  726. PUserData->UserPort,
  727. SerialPhysicalZero,
  728. 0,
  729. 0,
  730. 0,
  731. 70,
  732. STATUS_SUCCESS,
  733. SERIAL_PORT_INDEX_TOO_HIGH,
  734. PUserData->UserSymbolicLink.Length+sizeof(WCHAR),
  735. PUserData->UserSymbolicLink.Buffer,
  736. 0,
  737. NULL
  738. );
  739. SerialDump(
  740. SERERRORS,
  741. ("SERIAL: port index to large %ws\n",
  742. Parameters[0].Name)
  743. );
  744. rval = FALSE;
  745. goto SerialIsUserDataValidError;
  746. }
  747. }
  748. }
  749. }
  750. //
  751. // We don't want to cause the hal to have a bad day,
  752. // so let's check the interface type and bus number.
  753. //
  754. // We only need to check the registry if they aren't
  755. // equal to the defaults.
  756. //
  757. if ((PUserData->UserBusNumber != 0) ||
  758. (PUserData->UserInterfaceType != DefaultInterfaceType)) {
  759. BOOLEAN foundIt;
  760. if (PUserData->UserInterfaceType >= MaximumInterfaceType) {
  761. //
  762. // Ehhhh! Lose Game.
  763. //
  764. SerialLogError(
  765. DriverObject,
  766. NULL,
  767. PUserData->UserPort,
  768. SerialPhysicalZero,
  769. 0,
  770. 0,
  771. 0,
  772. 71,
  773. STATUS_SUCCESS,
  774. SERIAL_UNKNOWN_BUS,
  775. PUserData->UserSymbolicLink.Length+sizeof(WCHAR),
  776. PUserData->UserSymbolicLink.Buffer,
  777. 0,
  778. NULL
  779. );
  780. SerialDump(
  781. SERERRORS,
  782. ("SERIAL: Invalid Bus type %ws\n",
  783. Parameters[0].Name)
  784. );
  785. rval = FALSE;
  786. goto SerialIsUserDataValidError;
  787. }
  788. IoQueryDeviceDescription(
  789. (INTERFACE_TYPE *)&PUserData->UserInterfaceType,
  790. &zero,
  791. NULL,
  792. NULL,
  793. NULL,
  794. NULL,
  795. SerialItemCallBack,
  796. &foundIt
  797. );
  798. if (!foundIt) {
  799. SerialLogError(
  800. DriverObject,
  801. NULL,
  802. PUserData->UserPort,
  803. SerialPhysicalZero,
  804. 0,
  805. 0,
  806. 0,
  807. 72,
  808. STATUS_SUCCESS,
  809. SERIAL_BUS_NOT_PRESENT,
  810. PUserData->UserSymbolicLink.Length+sizeof(WCHAR),
  811. PUserData->UserSymbolicLink.Buffer,
  812. 0,
  813. NULL
  814. );
  815. SerialDump(
  816. SERERRORS,
  817. ("SERIAL: There aren't that many of those\n"
  818. "------- busses on this system,%ws\n",
  819. Parameters[0].Name)
  820. );
  821. rval = FALSE;
  822. goto SerialIsUserDataValidError;
  823. }
  824. }
  825. if ((PUserData->UserInterfaceType == MicroChannel) &&
  826. (PUserData->UserInterruptMode == CM_RESOURCE_INTERRUPT_LATCHED)) {
  827. SerialLogError(
  828. DriverObject,
  829. NULL,
  830. PUserData->UserPort,
  831. SerialPhysicalZero,
  832. 0,
  833. 0,
  834. 0,
  835. 73,
  836. STATUS_SUCCESS,
  837. SERIAL_BUS_INTERRUPT_CONFLICT,
  838. PUserData->UserSymbolicLink.Length+sizeof(WCHAR),
  839. PUserData->UserSymbolicLink.Buffer,
  840. 0,
  841. NULL
  842. );
  843. SerialDump(
  844. SERERRORS,
  845. ("SERIAL: Latched interrupts and MicroChannel\n"
  846. "------- busses don't mix,%ws\n",
  847. Parameters[0].Name)
  848. );
  849. rval = FALSE;
  850. goto SerialIsUserDataValidError;
  851. }
  852. SerialDump(
  853. SERDIAG1,
  854. ("SERIAL: 'user registry info - userPort: %x\n",
  855. PUserData->UserPort.LowPart)
  856. );
  857. SerialDump(
  858. SERDIAG1,
  859. ("SERIAL: 'user registry info - userInterruptStatus: %x\n",
  860. PUserData->UserInterruptStatus.LowPart)
  861. );
  862. SerialDump(
  863. SERDIAG1,
  864. ("SERIAL: 'user registry info - userPortIndex: %d\n",
  865. PUserData->UserPortIndex)
  866. );
  867. SerialDump(
  868. SERDIAG1,
  869. ("SERIAL: 'user registry info - userClockRate: %d\n",
  870. PUserData->UserClockRate)
  871. );
  872. SerialDump(
  873. SERDIAG1,
  874. ("SERIAL: 'user registry info - userBusNumber: %d\n",
  875. PUserData->UserBusNumber)
  876. );
  877. SerialDump(
  878. SERDIAG1,
  879. ("SERIAL: 'user registry info - userAddressSpace: %d\n",
  880. PUserData->UserAddressSpace)
  881. );
  882. SerialDump(
  883. SERDIAG1,
  884. ("SERIAL: 'user registry info - userInterruptMode: %d\n",
  885. PUserData->UserInterruptMode)
  886. );
  887. SerialDump(
  888. SERDIAG1,
  889. ("SERIAL: 'user registry info - userInterfaceType: %d\n",
  890. PUserData->UserInterfaceType)
  891. );
  892. SerialDump(
  893. SERDIAG1,
  894. ("SERIAL: 'user registry info - userVector: %d\n",
  895. PUserData->UserVector)
  896. );
  897. SerialDump(
  898. SERDIAG1,
  899. ("SERIAL: 'user registry info - userLevel: %d\n",
  900. PUserData->UserLevel)
  901. );
  902. SerialDump(
  903. SERDIAG1,
  904. ("SERIAL: 'user registry info - userIndexed: %d\n",
  905. PUserData->UserIndexed)
  906. );
  907. SerialDump(SERTRACECALLS, ("SERIAL: Leave SerialIsUserDataValid\n"));
  908. SerialIsUserDataValidError:
  909. return rval;
  910. }
  911. NTSTATUS
  912. SerialEnumerateLegacy(IN PDRIVER_OBJECT DriverObject,
  913. IN PUNICODE_STRING RegistryPath,
  914. IN PSERIAL_FIRMWARE_DATA DriverDefaultsPtr)
  915. /*++
  916. Routine Description:
  917. This routine will enumerate and initialize all legacy serial ports that
  918. have just been scribbled into the registry. These are usually non-
  919. intelligent multiport boards, but can be any type of "standard" serial
  920. port.
  921. This is pageable INIT because it is only called from DriverEntry.
  922. Arguments:
  923. DriverObject - Used only for logging errors.
  924. RegistryPath - Path to this drivers service node in
  925. the current control set.
  926. DriverDefaultsPtr - Pointer to structure of driver-wide defaults.
  927. Return Value:
  928. STATUS_SUCCESS if consistant configuration was found - otherwise.
  929. returns STATUS_SERIAL_NO_DEVICE_INITED.
  930. --*/
  931. {
  932. SERIAL_FIRMWARE_DATA firmware;
  933. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  934. INTERFACE_TYPE interfaceType;
  935. ULONG defaultInterfaceType;
  936. PULONG countSoFar = &IoGetConfigurationInformation()->SerialCount;
  937. //
  938. // Default values for user data.
  939. //
  940. ULONG maxUlong = MAXULONG;
  941. ULONG zero = 0;
  942. ULONG nonzero = 1;
  943. ULONG badValue = (ULONG)-1;
  944. ULONG defaultInterruptMode;
  945. ULONG defaultAddressSpace = CM_RESOURCE_PORT_IO;
  946. //
  947. // Where user data from the registry will be placed.
  948. //
  949. SERIAL_USER_DATA userData;
  950. ULONG legacyDiscovered;
  951. UNICODE_STRING PnPID;
  952. UNICODE_STRING legacyKeys;
  953. UNICODE_STRING parametersPath;
  954. OBJECT_ATTRIBUTES parametersAttributes;
  955. HANDLE parametersKey;
  956. HANDLE pnpKey;
  957. PKEY_BASIC_INFORMATION userSubKey = NULL;
  958. ULONG i;
  959. PCM_RESOURCE_LIST resourceList = NULL;
  960. PCM_RESOURCE_LIST trResourceList = NULL;
  961. PIO_RESOURCE_REQUIREMENTS_LIST pRequiredList = NULL;
  962. ULONG countOfPartials;
  963. PDEVICE_OBJECT newPdo;
  964. ULONG brokenStatus;
  965. PAGED_CODE();
  966. SerialDump(SERTRACECALLS, ("SERIAL: Enter SerialEnumerateLegacy\n"));
  967. PnPID.Buffer = NULL;
  968. legacyKeys.Buffer = NULL;
  969. userData.UserSymbolicLink.Buffer = NULL;
  970. parametersPath.Buffer = NULL;
  971. userData.ForceFIFOEnableDefault = DriverDefaultsPtr->ForceFifoEnableDefault;
  972. userData.PermitShareDefault = DriverDefaultsPtr->PermitShareDefault;
  973. userData.LogFIFODefault = DriverDefaultsPtr->LogFifoDefault;
  974. userData.DefaultPermitSystemWideShare = FALSE;
  975. userData.RxFIFODefault = DriverDefaultsPtr->RxFIFODefault;
  976. userData.TxFIFODefault = DriverDefaultsPtr->TxFIFODefault;
  977. //
  978. // Start of normal configuration and detection.
  979. //
  980. //
  981. // Query the registry one more time. This time we
  982. // look for the first bus on the system (that isn't
  983. // the internal bus - we assume that the firmware
  984. // code knows about those ports). We will use that
  985. // as the default bus if no bustype or bus number
  986. // is specified in the "user" configuration records.
  987. //
  988. defaultInterfaceType = (ULONG)Isa;
  989. defaultInterruptMode = CM_RESOURCE_INTERRUPT_LATCHED;
  990. for (
  991. interfaceType = 0;
  992. interfaceType < MaximumInterfaceType;
  993. interfaceType++
  994. ) {
  995. ULONG busZero = 0;
  996. BOOLEAN foundOne = FALSE;
  997. if (interfaceType != Internal) {
  998. IoQueryDeviceDescription(
  999. &interfaceType,
  1000. &busZero,
  1001. NULL,
  1002. NULL,
  1003. NULL,
  1004. NULL,
  1005. SerialItemCallBack,
  1006. &foundOne
  1007. );
  1008. if (foundOne) {
  1009. defaultInterfaceType = (ULONG)interfaceType;
  1010. if (defaultInterfaceType == MicroChannel) {
  1011. defaultInterruptMode = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1012. //
  1013. // Microchannel machines can permit the interrupt to be
  1014. // shared system wide.
  1015. //
  1016. userData.DefaultPermitSystemWideShare = TRUE;
  1017. }
  1018. break;
  1019. }
  1020. }
  1021. }
  1022. //
  1023. // Gonna get the user data now. Allocate the
  1024. // structures that we will be using throughout
  1025. // the search for user data. We will deallocate
  1026. // them before we leave this routine.
  1027. //
  1028. userData.UserSymbolicLink.Buffer = NULL;
  1029. parametersPath.Buffer = NULL;
  1030. //
  1031. // Allocate the rtl query table. This should have an entry for each value
  1032. // we retrieve from the registry as well as a terminating zero entry as
  1033. // well the first "goto subkey" entry.
  1034. //
  1035. parameters = ExAllocatePool(
  1036. PagedPool,
  1037. sizeof(RTL_QUERY_REGISTRY_TABLE)*22
  1038. );
  1039. if (!parameters) {
  1040. SerialLogError(
  1041. DriverObject,
  1042. NULL,
  1043. SerialPhysicalZero,
  1044. SerialPhysicalZero,
  1045. 0,
  1046. 0,
  1047. 0,
  1048. 74,
  1049. STATUS_SUCCESS,
  1050. SERIAL_INSUFFICIENT_RESOURCES,
  1051. 0,
  1052. NULL,
  1053. 0,
  1054. NULL
  1055. );
  1056. SerialDump(
  1057. SERERRORS,
  1058. ("SERIAL: Couldn't allocate table for rtl query\n"
  1059. "------ to parameters for %wZ",
  1060. RegistryPath)
  1061. );
  1062. goto LegacyInitLeave;
  1063. }
  1064. RtlZeroMemory(
  1065. parameters,
  1066. sizeof(RTL_QUERY_REGISTRY_TABLE)*22
  1067. );
  1068. //
  1069. // Allocate the place where the user's symbolic link name
  1070. // for the port will go.
  1071. //
  1072. //
  1073. // We will initially allocate space for 257 wchars.
  1074. // we will then set the maximum size to 256
  1075. // This way the rtl routine could return a 256
  1076. // WCHAR wide string with no null terminator.
  1077. // We'll remember that the buffer is one WCHAR
  1078. // longer then it says it is so that we can always
  1079. // have a NULL terminator at the end.
  1080. //
  1081. RtlInitUnicodeString(&userData.UserSymbolicLink, NULL);
  1082. userData.UserSymbolicLink.MaximumLength = sizeof(WCHAR) * 256;
  1083. userData.UserSymbolicLink.Buffer = ExAllocatePool(PagedPool, sizeof(WCHAR)
  1084. * 257);
  1085. if (!userData.UserSymbolicLink.Buffer) {
  1086. SerialLogError(
  1087. DriverObject,
  1088. NULL,
  1089. SerialPhysicalZero,
  1090. SerialPhysicalZero,
  1091. 0,
  1092. 0,
  1093. 0,
  1094. 75,
  1095. STATUS_SUCCESS,
  1096. SERIAL_INSUFFICIENT_RESOURCES,
  1097. 0,
  1098. NULL,
  1099. 0,
  1100. NULL
  1101. );
  1102. SerialDump(
  1103. SERERRORS,
  1104. ("SERIAL: Couldn't allocate buffer for the symbolic link\n"
  1105. "------ for parameters items in %wZ",
  1106. RegistryPath)
  1107. );
  1108. goto LegacyInitLeave;
  1109. }
  1110. //
  1111. // We will initially allocate space for 257 wchars.
  1112. // we will then set the maximum size to 256
  1113. // This way the rtl routine could return a 256
  1114. // WCHAR wide string with no null terminator.
  1115. // We'll remember that the buffer is one WCHAR
  1116. // longer then it says it is so that we can always
  1117. // have a NULL terminator at the end.
  1118. //
  1119. RtlInitUnicodeString(&PnPID, NULL);
  1120. PnPID.MaximumLength = sizeof(WCHAR) * 256;
  1121. PnPID.Buffer = ExAllocatePool(PagedPool, sizeof(WCHAR) * 257);
  1122. if (PnPID.Buffer == 0) {
  1123. SerialLogError(
  1124. DriverObject,
  1125. NULL,
  1126. SerialPhysicalZero,
  1127. SerialPhysicalZero,
  1128. 0,
  1129. 0,
  1130. 0,
  1131. 76,
  1132. STATUS_SUCCESS,
  1133. SERIAL_INSUFFICIENT_RESOURCES,
  1134. 0,
  1135. NULL,
  1136. 0,
  1137. NULL
  1138. );
  1139. SerialDump(
  1140. SERERRORS,
  1141. ("SERIAL: Couldn't allocate buffer for the PnP ID\n"
  1142. "------ for parameters items in %wZ",
  1143. RegistryPath)
  1144. );
  1145. goto LegacyInitLeave;
  1146. }
  1147. // Initialize the legacy key buffer
  1148. RtlInitUnicodeString(&legacyKeys, NULL);
  1149. legacyKeys.MaximumLength = sizeof(WCHAR) * 256;
  1150. legacyKeys.Buffer = ExAllocatePool(PagedPool, sizeof(WCHAR) * 257);
  1151. if (!legacyKeys.Buffer) {
  1152. SerialLogError(
  1153. DriverObject,
  1154. NULL,
  1155. SerialPhysicalZero,
  1156. SerialPhysicalZero,
  1157. 0,
  1158. 0,
  1159. 0,
  1160. 77,
  1161. STATUS_SUCCESS,
  1162. SERIAL_INSUFFICIENT_RESOURCES,
  1163. 0,
  1164. NULL,
  1165. 0,
  1166. NULL
  1167. );
  1168. SerialDump(SERERRORS, ("SERIAL: Couldn't allocate buffer for the legacy"
  1169. " keys\n"));
  1170. goto LegacyInitLeave;
  1171. }
  1172. resourceList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST)
  1173. + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 2);
  1174. if (resourceList == NULL) {
  1175. SerialLogError(
  1176. DriverObject,
  1177. NULL,
  1178. userData.UserPort,
  1179. SerialPhysicalZero,
  1180. 0,
  1181. 0,
  1182. 0,
  1183. 78,
  1184. STATUS_SUCCESS,
  1185. SERIAL_INSUFFICIENT_RESOURCES,
  1186. 0,
  1187. NULL,
  1188. 0,
  1189. NULL
  1190. );
  1191. goto LegacyInitLeave;
  1192. }
  1193. trResourceList = ExAllocatePool(PagedPool, sizeof(CM_RESOURCE_LIST)
  1194. + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  1195. * 2);
  1196. if (trResourceList == NULL) {
  1197. SerialLogError(
  1198. DriverObject,
  1199. NULL,
  1200. userData.UserPort,
  1201. SerialPhysicalZero,
  1202. 0,
  1203. 0,
  1204. 0,
  1205. 79,
  1206. STATUS_SUCCESS,
  1207. SERIAL_INSUFFICIENT_RESOURCES,
  1208. 0,
  1209. NULL,
  1210. 0,
  1211. NULL
  1212. );
  1213. goto LegacyInitLeave;
  1214. }
  1215. pRequiredList
  1216. = ExAllocatePool(PagedPool, sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
  1217. + sizeof(IO_RESOURCE_DESCRIPTOR) * 2);
  1218. if (pRequiredList == NULL) {
  1219. SerialLogError(
  1220. DriverObject,
  1221. NULL,
  1222. userData.UserPort,
  1223. SerialPhysicalZero,
  1224. 0,
  1225. 0,
  1226. 0,
  1227. 80,
  1228. STATUS_SUCCESS,
  1229. SERIAL_INSUFFICIENT_RESOURCES,
  1230. 0,
  1231. NULL,
  1232. 0,
  1233. NULL
  1234. );
  1235. goto LegacyInitLeave;
  1236. }
  1237. //
  1238. // Form a path to our drivers Parameters subkey.
  1239. //
  1240. RtlInitUnicodeString(
  1241. &parametersPath,
  1242. NULL
  1243. );
  1244. parametersPath.MaximumLength = RegistryPath->Length +
  1245. sizeof(L"\\") +
  1246. sizeof(L"Parameters");
  1247. parametersPath.Buffer = ExAllocatePool(
  1248. PagedPool,
  1249. parametersPath.MaximumLength
  1250. );
  1251. if (!parametersPath.Buffer) {
  1252. SerialLogError(
  1253. DriverObject,
  1254. NULL,
  1255. SerialPhysicalZero,
  1256. SerialPhysicalZero,
  1257. 0,
  1258. 0,
  1259. 0,
  1260. 81,
  1261. STATUS_SUCCESS,
  1262. SERIAL_INSUFFICIENT_RESOURCES,
  1263. 0,
  1264. NULL,
  1265. 0,
  1266. NULL
  1267. );
  1268. SerialDump(
  1269. SERERRORS,
  1270. ("SERIAL: Couldn't allocate string for path\n"
  1271. "------ to parameters for %wZ",
  1272. RegistryPath)
  1273. );
  1274. goto LegacyInitLeave;
  1275. }
  1276. //
  1277. // Form the parameters path.
  1278. //
  1279. RtlZeroMemory(
  1280. parametersPath.Buffer,
  1281. parametersPath.MaximumLength
  1282. );
  1283. RtlAppendUnicodeStringToString(
  1284. &parametersPath,
  1285. RegistryPath
  1286. );
  1287. RtlAppendUnicodeToString(
  1288. &parametersPath,
  1289. L"\\"
  1290. );
  1291. RtlAppendUnicodeToString(
  1292. &parametersPath,
  1293. L"Parameters"
  1294. );
  1295. //
  1296. // Form the start of the legacy keys string
  1297. //
  1298. RtlZeroMemory(legacyKeys.Buffer, legacyKeys.MaximumLength);
  1299. RtlAppendUnicodeStringToString(&legacyKeys, &parametersPath);
  1300. userSubKey = ExAllocatePool(
  1301. PagedPool,
  1302. sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*256)
  1303. );
  1304. if (!userSubKey) {
  1305. SerialLogError(
  1306. DriverObject,
  1307. NULL,
  1308. SerialPhysicalZero,
  1309. SerialPhysicalZero,
  1310. 0,
  1311. 0,
  1312. 0,
  1313. 82,
  1314. STATUS_SUCCESS,
  1315. SERIAL_INSUFFICIENT_RESOURCES,
  1316. 0,
  1317. NULL,
  1318. 0,
  1319. NULL
  1320. );
  1321. SerialDump(
  1322. SERERRORS,
  1323. ("SERIAL: Couldn't allocate memory basic information\n"
  1324. "------ structure to enumerate subkeys for %wZ",
  1325. &parametersPath)
  1326. );
  1327. goto LegacyInitLeave;
  1328. }
  1329. //
  1330. // Open the key given by our registry path & Parameters.
  1331. //
  1332. InitializeObjectAttributes(
  1333. &parametersAttributes,
  1334. &parametersPath,
  1335. OBJ_CASE_INSENSITIVE,
  1336. NULL,
  1337. NULL
  1338. );
  1339. if (!NT_SUCCESS(ZwOpenKey(
  1340. &parametersKey,
  1341. MAXIMUM_ALLOWED,
  1342. &parametersAttributes
  1343. ))) {
  1344. SerialLogError(
  1345. DriverObject,
  1346. NULL,
  1347. SerialPhysicalZero,
  1348. SerialPhysicalZero,
  1349. 0,
  1350. 0,
  1351. 0,
  1352. 83,
  1353. STATUS_SUCCESS,
  1354. SERIAL_NO_PARAMETERS_INFO,
  1355. 0,
  1356. NULL,
  1357. 0,
  1358. NULL
  1359. );
  1360. SerialDump(
  1361. SERERRORS,
  1362. ("SERIAL: Couldn't open the drivers Parameters key %wZ\n",
  1363. RegistryPath)
  1364. );
  1365. goto LegacyInitLeave;
  1366. }
  1367. parameters[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
  1368. parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1369. parameters[1].Name = L"PortAddress";
  1370. parameters[1].EntryContext = &userData.UserPort.LowPart;
  1371. parameters[1].DefaultType = REG_DWORD;
  1372. parameters[1].DefaultData = &zero;
  1373. parameters[1].DefaultLength = sizeof(ULONG);
  1374. parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1375. parameters[2].Name = L"Interrupt";
  1376. parameters[2].EntryContext = &userData.UserVector;
  1377. parameters[2].DefaultType = REG_DWORD;
  1378. parameters[2].DefaultData = &zero;
  1379. parameters[2].DefaultLength = sizeof(ULONG);
  1380. parameters[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1381. parameters[3].Name = DEFAULT_DIRECTORY;
  1382. parameters[3].EntryContext = &userData.UserSymbolicLink;
  1383. parameters[3].DefaultType = REG_SZ;
  1384. parameters[3].DefaultData = L"";
  1385. parameters[3].DefaultLength = 0;
  1386. parameters[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1387. parameters[4].Name = L"InterruptStatus";
  1388. parameters[4].EntryContext = &userData.UserInterruptStatus.LowPart;
  1389. parameters[4].DefaultType = REG_DWORD;
  1390. parameters[4].DefaultData = &zero;
  1391. parameters[4].DefaultLength = sizeof(ULONG);
  1392. parameters[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1393. parameters[5].Name = L"PortIndex";
  1394. parameters[5].EntryContext = &userData.UserPortIndex;
  1395. parameters[5].DefaultType = REG_DWORD;
  1396. parameters[5].DefaultData = &zero;
  1397. parameters[5].DefaultLength = sizeof(ULONG);
  1398. parameters[6].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1399. parameters[6].Name = L"BusNumber";
  1400. parameters[6].EntryContext = &userData.UserBusNumber;
  1401. parameters[6].DefaultType = REG_DWORD;
  1402. parameters[6].DefaultData = &zero;
  1403. parameters[6].DefaultLength = sizeof(ULONG);
  1404. parameters[7].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1405. parameters[7].Name = L"BusType";
  1406. parameters[7].EntryContext = &userData.UserInterfaceType;
  1407. parameters[7].DefaultType = REG_DWORD;
  1408. parameters[7].DefaultData = &defaultInterfaceType;
  1409. parameters[7].DefaultLength = sizeof(ULONG);
  1410. parameters[8].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1411. parameters[8].Name = L"ClockRate";
  1412. parameters[8].EntryContext = &userData.UserClockRate;
  1413. parameters[8].DefaultType = REG_DWORD;
  1414. parameters[8].DefaultData = &badValue;
  1415. parameters[8].DefaultLength = sizeof(ULONG);
  1416. parameters[9].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1417. parameters[9].Name = L"Indexed";
  1418. parameters[9].EntryContext = &userData.UserIndexed;
  1419. parameters[9].DefaultType = REG_DWORD;
  1420. parameters[9].DefaultData = &badValue;
  1421. parameters[9].DefaultLength = sizeof(ULONG);
  1422. parameters[10].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1423. parameters[10].Name = L"InterruptMode";
  1424. parameters[10].EntryContext = &userData.UserInterruptMode;
  1425. parameters[10].DefaultType = REG_DWORD;
  1426. parameters[10].DefaultData = &defaultInterruptMode;
  1427. parameters[10].DefaultLength = sizeof(ULONG);
  1428. parameters[11].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1429. parameters[11].Name = L"AddressSpace";
  1430. parameters[11].EntryContext = &userData.UserAddressSpace;
  1431. parameters[11].DefaultType = REG_DWORD;
  1432. parameters[11].DefaultData = &defaultAddressSpace;
  1433. parameters[11].DefaultLength = sizeof(ULONG);
  1434. parameters[12].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1435. parameters[12].Name = L"InterruptLevel";
  1436. parameters[12].EntryContext = &userData.UserLevel;
  1437. parameters[12].DefaultType = REG_DWORD;
  1438. parameters[12].DefaultData = &zero;
  1439. parameters[12].DefaultLength = sizeof(ULONG);
  1440. parameters[13].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1441. parameters[13].Name = L"DisablePort";
  1442. parameters[13].EntryContext = &userData.DisablePort;
  1443. parameters[13].DefaultType = REG_DWORD;
  1444. parameters[13].DefaultData = &badValue;
  1445. parameters[13].DefaultLength = sizeof(ULONG);
  1446. parameters[14].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1447. parameters[14].Name = L"ForceFifoEnable";
  1448. parameters[14].EntryContext = &userData.ForceFIFOEnable;
  1449. parameters[14].DefaultType = REG_DWORD;
  1450. parameters[14].DefaultData = &badValue;
  1451. parameters[14].DefaultLength = sizeof(ULONG);
  1452. parameters[15].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1453. parameters[15].Name = L"RxFIFO";
  1454. parameters[15].EntryContext = &userData.RxFIFO;
  1455. parameters[15].DefaultType = REG_DWORD;
  1456. parameters[15].DefaultData = &badValue;
  1457. parameters[15].DefaultLength = sizeof(ULONG);
  1458. parameters[16].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1459. parameters[16].Name = L"TxFIFO";
  1460. parameters[16].EntryContext = &userData.TxFIFO;
  1461. parameters[16].DefaultType = REG_DWORD;
  1462. parameters[16].DefaultData = &badValue;
  1463. parameters[16].DefaultLength = sizeof(ULONG);
  1464. parameters[17].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1465. parameters[17].Name = L"MaskInverted";
  1466. parameters[17].EntryContext = &userData.MaskInverted;
  1467. parameters[17].DefaultType = REG_DWORD;
  1468. parameters[17].DefaultData = &zero;
  1469. parameters[17].DefaultLength = sizeof(ULONG);
  1470. parameters[18].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1471. parameters[18].Name = L"PnPDeviceID";
  1472. parameters[18].EntryContext = &PnPID;
  1473. parameters[18].DefaultType = REG_SZ;
  1474. parameters[18].DefaultData = L"";
  1475. parameters[18].DefaultLength = 0;
  1476. parameters[19].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1477. parameters[19].Name = L"LegacyDiscovered";
  1478. parameters[19].EntryContext = &legacyDiscovered;
  1479. parameters[19].DefaultType = REG_DWORD;
  1480. parameters[19].DefaultData = &zero;
  1481. parameters[19].DefaultLength = sizeof(ULONG);
  1482. //
  1483. // This is for a buggy Digi serial.ini that worked with pre-NT5.0
  1484. // by accident. DO NOT USE "Interrupt Status" in the future; its
  1485. // use is deprecated. Use the correct "InterruptStatus"
  1486. //
  1487. parameters[20].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1488. parameters[20].Name = L"Interrupt Status";
  1489. parameters[20].EntryContext = &brokenStatus;
  1490. parameters[20].DefaultType = REG_DWORD;
  1491. parameters[20].DefaultData = &zero;
  1492. parameters[20].DefaultLength = sizeof(ULONG);
  1493. i = 0;
  1494. while (TRUE) {
  1495. NTSTATUS status;
  1496. ULONG actuallyReturned;
  1497. PDEVICE_OBJECT newDevObj = NULL;
  1498. PSERIAL_DEVICE_EXTENSION deviceExtension;
  1499. PDEVICE_OBJECT lowerDevice;
  1500. //
  1501. // We lie about the length of the buffer, so that we can
  1502. // MAKE SURE that the name it returns can be padded with
  1503. // a NULL.
  1504. //
  1505. status = ZwEnumerateKey(
  1506. parametersKey,
  1507. i,
  1508. KeyBasicInformation,
  1509. userSubKey,
  1510. sizeof(KEY_BASIC_INFORMATION)+(sizeof(WCHAR)*255),
  1511. &actuallyReturned
  1512. );
  1513. if (status == STATUS_NO_MORE_ENTRIES) {
  1514. break;
  1515. }
  1516. if (status == STATUS_BUFFER_OVERFLOW) {
  1517. SerialLogError(
  1518. DriverObject,
  1519. NULL,
  1520. SerialPhysicalZero,
  1521. SerialPhysicalZero,
  1522. 0,
  1523. 0,
  1524. 0,
  1525. 84,
  1526. STATUS_SUCCESS,
  1527. SERIAL_UNABLE_TO_ACCESS_CONFIG,
  1528. 0,
  1529. NULL,
  1530. 0,
  1531. NULL
  1532. );
  1533. SerialDump(
  1534. SERERRORS,
  1535. ("SERIAL: Overflowed the enumerate buffer\n"
  1536. "------- for subkey #%d of %wZ\n",
  1537. i,parametersPath)
  1538. );
  1539. i++;
  1540. continue;
  1541. }
  1542. if (!NT_SUCCESS(status)) {
  1543. SerialLogError(
  1544. DriverObject,
  1545. NULL,
  1546. SerialPhysicalZero,
  1547. SerialPhysicalZero,
  1548. 0,
  1549. 0,
  1550. 0,
  1551. 85,
  1552. STATUS_SUCCESS,
  1553. SERIAL_UNABLE_TO_ACCESS_CONFIG,
  1554. 0,
  1555. NULL,
  1556. 0,
  1557. NULL
  1558. );
  1559. SerialDump(
  1560. SERERRORS,
  1561. ("SERIAL: Bad status returned: %x \n"
  1562. "------- on enumeration for subkey # %d of %wZ\n",
  1563. status,i,parametersPath)
  1564. );
  1565. i++;
  1566. continue;
  1567. }
  1568. //
  1569. // Pad the name returned with a null.
  1570. //
  1571. RtlZeroMemory(
  1572. ((PUCHAR)(&userSubKey->Name[0]))+userSubKey->NameLength,
  1573. sizeof(WCHAR)
  1574. );
  1575. parameters[0].Name = &userSubKey->Name[0];
  1576. //
  1577. // Make sure that the physical addresses start
  1578. // out clean.
  1579. //
  1580. RtlZeroMemory(&userData.UserPort, sizeof(userData.UserPort));
  1581. RtlZeroMemory(&userData.UserInterruptStatus,
  1582. sizeof(userData.UserInterruptStatus));
  1583. //
  1584. // Make sure the symbolic link buffer starts clean
  1585. //
  1586. RtlZeroMemory(userData.UserSymbolicLink.Buffer,
  1587. userData.UserSymbolicLink.MaximumLength);
  1588. userData.UserSymbolicLink.Length = 0;
  1589. status = RtlQueryRegistryValues(
  1590. RTL_REGISTRY_ABSOLUTE,
  1591. parametersPath.Buffer,
  1592. parameters,
  1593. NULL,
  1594. NULL
  1595. );
  1596. if (!NT_SUCCESS(status)) {
  1597. SerialLogError(
  1598. DriverObject,
  1599. NULL,
  1600. SerialPhysicalZero,
  1601. SerialPhysicalZero,
  1602. 0,
  1603. 0,
  1604. 0,
  1605. 86,
  1606. STATUS_SUCCESS,
  1607. SERIAL_INVALID_USER_CONFIG,
  1608. userSubKey->NameLength+sizeof(WCHAR),
  1609. &userSubKey->Name[0],
  1610. 0,
  1611. NULL
  1612. );
  1613. SerialDump(
  1614. SERERRORS,
  1615. ("SERIAL: Bad status returned: %x \n"
  1616. "------- for the value entries of\n"
  1617. "------- %ws\n",
  1618. status,parameters[0].Name)
  1619. );
  1620. i++;
  1621. continue;
  1622. }
  1623. //
  1624. // Well! Some supposedly valid information was found!
  1625. //
  1626. // We'll see about that.
  1627. //
  1628. //
  1629. // If this is PnP, skip it -- it will be found by an enumerator
  1630. //
  1631. if (PnPID.Length != 0) {
  1632. i++;
  1633. continue;
  1634. }
  1635. //
  1636. // If this was found on a previous boot, skip it -- PnP will send
  1637. // us an add_device()/start_device() for it.
  1638. //
  1639. if (legacyDiscovered != 0) {
  1640. i++;
  1641. continue;
  1642. }
  1643. //
  1644. // Let's just jam the WCHAR null at the end of the
  1645. // user symbolic link. Remember that we left room for
  1646. // one when we allocated it's buffer.
  1647. //
  1648. RtlZeroMemory(((PUCHAR)(&userData.UserSymbolicLink.Buffer[0]))
  1649. + userData.UserSymbolicLink.Length, sizeof(WCHAR));
  1650. //
  1651. // See if this has a busted serial.ini and convert it over.
  1652. //
  1653. if (brokenStatus != 0) {
  1654. userData.UserInterruptStatus.LowPart = brokenStatus;
  1655. }
  1656. //
  1657. // Call a function to validate the data.
  1658. //
  1659. if (SerialIsUserDataValid(DriverObject, userSubKey, parameters,
  1660. defaultInterfaceType, &userData) == FALSE) {
  1661. i++;
  1662. continue;
  1663. }
  1664. //
  1665. // Well ok, I guess we can take the data.
  1666. // There be other tests later on to make
  1667. // sure it doesn't have any other kinds
  1668. // of conflicts.
  1669. //
  1670. //
  1671. // Report this device to the PnP Manager and create the device object
  1672. // Also update the registry entry for this device so we don't enumerate
  1673. // it next time.
  1674. //
  1675. //
  1676. // Build resource lists
  1677. //
  1678. status = SerialBuildResourceList(resourceList, &countOfPartials,
  1679. &userData);
  1680. if (!NT_SUCCESS(status)) {
  1681. i++;
  1682. continue;
  1683. }
  1684. ASSERT(countOfPartials >= 2);
  1685. status = SerialTranslateResourceList(DriverObject, userSubKey,
  1686. trResourceList, resourceList,
  1687. countOfPartials, &userData);
  1688. if (!NT_SUCCESS(status)) {
  1689. i++;
  1690. continue;
  1691. }
  1692. status = SerialBuildRequirementsList(pRequiredList, countOfPartials,
  1693. &userData);
  1694. if (!NT_SUCCESS(status)) {
  1695. i++;
  1696. continue;
  1697. }
  1698. newPdo = NULL;
  1699. //
  1700. // We want **untranslated** resources passed to this call
  1701. // since it calls IoReportResourceUsage() for us.
  1702. //
  1703. status = IoReportDetectedDevice(
  1704. DriverObject,
  1705. InterfaceTypeUndefined,
  1706. -1,
  1707. -1,
  1708. resourceList,
  1709. pRequiredList,
  1710. FALSE,
  1711. &newPdo
  1712. );
  1713. //
  1714. // If we fail, we can keep going but we need to see this device next
  1715. // time, so we won't write its discovery into the registry.
  1716. //
  1717. if (!NT_SUCCESS(status)) {
  1718. if (status == STATUS_INSUFFICIENT_RESOURCES) {
  1719. SerialLogError(DriverObject, NULL, userData.UserPort,
  1720. SerialPhysicalZero, 0, 0, 0, 89, status,
  1721. SERIAL_NO_DEVICE_REPORT_RES, userSubKey->NameLength
  1722. + sizeof(WCHAR), &userSubKey->Name[0], 0,
  1723. NULL);
  1724. } else {
  1725. SerialLogError(DriverObject, NULL, userData.UserPort,
  1726. SerialPhysicalZero, 0, 0, 0, 87, status,
  1727. SERIAL_NO_DEVICE_REPORT, userSubKey->NameLength
  1728. + sizeof(WCHAR), &userSubKey->Name[0], 0, NULL);
  1729. }
  1730. SerialDump(SERERRORS, ("SERIAL: Could not report legacy device - %x\n",
  1731. status));
  1732. i++;
  1733. continue;
  1734. }
  1735. //
  1736. // Scribble our name in PnP land
  1737. //
  1738. status = SerialMigrateLegacyRegistry(newPdo, &userData,
  1739. (BOOLEAN)(countOfPartials == 3
  1740. ? TRUE : FALSE));
  1741. if (!NT_SUCCESS(status)) {
  1742. //
  1743. // For now leave pdo floating until there is a cleanup
  1744. // for IoReportDetectedDevice()
  1745. //
  1746. i++;
  1747. continue;
  1748. }
  1749. //
  1750. // Now, we call our add device and start device for this PDO
  1751. //
  1752. status = SerialCreateDevObj(DriverObject, &newDevObj);
  1753. if (!NT_SUCCESS(status)) {
  1754. //
  1755. // For now leave pdo floating until there is a cleanup
  1756. // for IoReportDetectedDevice()
  1757. //
  1758. i++;
  1759. continue;
  1760. }
  1761. lowerDevice = IoAttachDeviceToDeviceStack(newDevObj, newPdo);
  1762. deviceExtension = newDevObj->DeviceExtension;
  1763. deviceExtension->LowerDeviceObject = lowerDevice;
  1764. deviceExtension->Pdo = newPdo;
  1765. newDevObj->Flags |= DO_POWER_PAGABLE | DO_BUFFERED_IO;
  1766. //
  1767. // Try to start the device...
  1768. //
  1769. SerialLockPagableSectionByHandle(SerialGlobals.PAGESER_Handle);
  1770. status = SerialFinishStartDevice(newDevObj, resourceList, trResourceList,
  1771. &userData);
  1772. SerialUnlockPagableImageSection(SerialGlobals.PAGESER_Handle);
  1773. //
  1774. // If the port is disabled, SerialFinishStartDevice returns
  1775. // an error, but we should still mark legacydiscovered and
  1776. // leave the registry migrated.
  1777. //
  1778. if (!NT_SUCCESS(status)) {
  1779. //
  1780. // For now leave pdo floating until there is a cleanup
  1781. // for IoReportDetectedDevice()
  1782. //
  1783. SerialRemoveDevObj(newDevObj);
  1784. i++;
  1785. continue;
  1786. }
  1787. //
  1788. // Fix up the path to the entry we are currently working on
  1789. //
  1790. RtlAppendUnicodeToString(&legacyKeys, L"\\");
  1791. RtlAppendUnicodeToString(&legacyKeys, &userSubKey->Name[0]);
  1792. status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  1793. legacyKeys.Buffer,
  1794. L"LegacyDiscovered", REG_DWORD,
  1795. &nonzero, sizeof(nonzero));
  1796. //
  1797. // Clean up our path buffer
  1798. //
  1799. RtlZeroMemory(legacyKeys.Buffer, legacyKeys.MaximumLength);
  1800. legacyKeys.Length = 0;
  1801. RtlAppendUnicodeStringToString(&legacyKeys, &parametersPath);
  1802. //
  1803. // Failure is non-fatal; it just means that the device will be
  1804. // re-enumerated next time, and a collision will occur.
  1805. //
  1806. if (!NT_SUCCESS(status)) {
  1807. SerialLogError(DriverObject, NULL, userData.UserPort,
  1808. SerialPhysicalZero, 0, 0, 0, 88, STATUS_SUCCESS,
  1809. SERIAL_REGISTRY_WRITE_FAILED, 0, NULL, 0, NULL);
  1810. SerialDump(SERERRORS, ("SERIAL: Couldn't write registry value"
  1811. "for LegacyDiscovered in %wZ\n",
  1812. legacyKeys));
  1813. }
  1814. i++;
  1815. (*countSoFar)++;
  1816. } // while(TRUE)
  1817. ZwClose(parametersKey);
  1818. LegacyInitLeave:;
  1819. if (userSubKey != NULL) {
  1820. ExFreePool(userSubKey);
  1821. }
  1822. if (PnPID.Buffer != NULL) {
  1823. ExFreePool(PnPID.Buffer);
  1824. }
  1825. if (legacyKeys.Buffer != NULL) {
  1826. ExFreePool(legacyKeys.Buffer);
  1827. }
  1828. if (userData.UserSymbolicLink.Buffer != NULL) {
  1829. ExFreePool(userData.UserSymbolicLink.Buffer);
  1830. }
  1831. if (parametersPath.Buffer != NULL) {
  1832. ExFreePool(parametersPath.Buffer);
  1833. }
  1834. if (parameters != NULL) {
  1835. ExFreePool(parameters);
  1836. }
  1837. if (resourceList != NULL) {
  1838. ExFreePool(resourceList);
  1839. }
  1840. if (trResourceList != NULL) {
  1841. ExFreePool(trResourceList);
  1842. }
  1843. if (pRequiredList != NULL) {
  1844. ExFreePool(pRequiredList);
  1845. }
  1846. SerialDump(SERTRACECALLS, ("SERIAL: Leave SerialEnumerateLegacy\n"));
  1847. return STATUS_SUCCESS;
  1848. }
  1849. #endif // NO_LEGACY_DRIVERS