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.

3456 lines
79 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. comm.c
  5. Abstract:
  6. This module implements Win32 comm APIs
  7. Author:
  8. Anthony V. Ercolano (tonye) 25-April-1991
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #pragma hdrstop
  13. #include "ntddser.h"
  14. #include "cfgmgr32.h"
  15. WCHAR CfgmgrDllString[] = L"cfgmgr32.dll";
  16. typedef struct _LOCALMATCHSTR {
  17. DWORD FoundIt;
  18. LPCWSTR FriendlyName;
  19. } LOCALMATCHSTR,*PLOCALMATCHSTR;
  20. static
  21. NTSTATUS
  22. GetConfigDialogName(
  23. IN PWSTR ValueName,
  24. IN ULONG ValueType,
  25. IN PVOID ValueData,
  26. IN ULONG ValueLength,
  27. IN PVOID Context,
  28. IN PVOID EntryContext
  29. )
  30. {
  31. PUNICODE_STRING dllToLoad = Context;
  32. if (ValueType != REG_SZ) {
  33. return STATUS_INVALID_PARAMETER;
  34. }
  35. //
  36. // Allocate heap to hold the unicode string. We know
  37. // that the string is zero terminated. Allocate that
  38. // much. Set the maximum size and size to
  39. // sizeof(WCHAR) - ValueLength.
  40. //
  41. RtlInitUnicodeString(
  42. dllToLoad,
  43. NULL
  44. );
  45. dllToLoad->Buffer = RtlAllocateHeap(
  46. RtlProcessHeap(),
  47. MAKE_TAG( TMP_TAG ),
  48. ValueLength
  49. );
  50. if (!dllToLoad->Buffer) {
  51. return STATUS_INSUFFICIENT_RESOURCES;
  52. }
  53. RtlMoveMemory(
  54. dllToLoad->Buffer,
  55. ValueData,
  56. ValueLength
  57. );
  58. dllToLoad->Length = (USHORT)(ValueLength - (sizeof(WCHAR)));
  59. dllToLoad->MaximumLength = (USHORT)ValueLength;
  60. return STATUS_SUCCESS;
  61. }
  62. static
  63. NTSTATUS
  64. GetFriendlyMatchComm(
  65. IN PWSTR ValueName,
  66. IN ULONG ValueType,
  67. IN PVOID ValueData,
  68. IN ULONG ValueLength,
  69. IN PVOID Context,
  70. IN PVOID EntryContext
  71. )
  72. {
  73. UNICODE_STRING s1;
  74. UNICODE_STRING s2;
  75. PLOCALMATCHSTR localMatch = Context;
  76. RtlInitUnicodeString(
  77. &s1,
  78. localMatch->FriendlyName
  79. );
  80. RtlInitUnicodeString(
  81. &s2,
  82. ValueData
  83. );
  84. if (RtlEqualUnicodeString(
  85. &s1,
  86. &s2,
  87. TRUE
  88. )) {
  89. localMatch->FoundIt = TRUE;
  90. }
  91. return STATUS_SUCCESS;
  92. }
  93. VOID
  94. GetFriendlyUi(
  95. LPCWSTR FriendlyName,
  96. PUNICODE_STRING DllToInvoke
  97. )
  98. {
  99. RTL_QUERY_REGISTRY_TABLE paramTable[2] = {0};
  100. LOCALMATCHSTR localMatch = {0,FriendlyName};
  101. HINSTANCE libHandle;
  102. paramTable[0].QueryRoutine = GetFriendlyMatchComm;
  103. paramTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  104. //
  105. // First things first. Load the cfg manager library.
  106. //
  107. libHandle = LoadLibraryW(CfgmgrDllString);
  108. if (libHandle) {
  109. FARPROC getSize;
  110. FARPROC getList;
  111. FARPROC locateDevNode;
  112. FARPROC openDevKey;
  113. try {
  114. getSize = GetProcAddress(
  115. libHandle,
  116. "CM_Get_Device_ID_List_SizeW"
  117. );
  118. getList = GetProcAddress(
  119. libHandle,
  120. "CM_Get_Device_ID_ListW"
  121. );
  122. locateDevNode = GetProcAddress(
  123. libHandle,
  124. "CM_Locate_DevNodeW"
  125. );
  126. openDevKey = GetProcAddress(
  127. libHandle,
  128. "CM_Open_DevNode_Key"
  129. );
  130. if (getSize && getList && locateDevNode && openDevKey) {
  131. PWCHAR bufferForList = NULL;
  132. DWORD sizeOfBuffer;
  133. //
  134. // Find how much memory for the buffer.
  135. //
  136. if (getSize(
  137. &sizeOfBuffer,
  138. L"MODEM",
  139. CM_GETIDLIST_FILTER_SERVICE
  140. ) == CR_SUCCESS) {
  141. //
  142. // Allocate 2 extra wchar.
  143. //
  144. bufferForList = RtlAllocateHeap(
  145. RtlProcessHeap(),
  146. MAKE_TAG( TMP_TAG ),
  147. (sizeOfBuffer*sizeof(WCHAR))
  148. +(sizeof(WCHAR)*2)
  149. );
  150. if (bufferForList) {
  151. PWCHAR currentId;
  152. try {
  153. if (getList(
  154. L"modem",
  155. bufferForList,
  156. sizeOfBuffer,
  157. CM_GETIDLIST_FILTER_SERVICE
  158. ) == CR_SUCCESS) {
  159. for (
  160. currentId = bufferForList;
  161. *currentId;
  162. currentId += wcslen(currentId)+1
  163. ) {
  164. DWORD devInst = 0;
  165. if (locateDevNode(
  166. &devInst,
  167. currentId,
  168. CM_LOCATE_DEVINST_NORMAL
  169. ) == CR_SUCCESS) {
  170. HANDLE handleToDev;
  171. if (openDevKey(
  172. devInst,
  173. KEY_ALL_ACCESS,
  174. 0,
  175. RegDisposition_OpenAlways,
  176. &handleToDev,
  177. CM_REGISTRY_SOFTWARE
  178. ) == CR_SUCCESS) {
  179. NTSTATUS statusOfQuery;
  180. localMatch.FoundIt = 0;
  181. paramTable[0].Name =
  182. L"FriendlyName";
  183. //
  184. // We now have an open
  185. // handle to a dev node.
  186. //
  187. // Check to see if it's
  188. // friendly name matches ours.
  189. //
  190. if (!NT_SUCCESS(
  191. RtlQueryRegistryValues(
  192. RTL_REGISTRY_HANDLE,
  193. handleToDev,
  194. &paramTable[0],
  195. &localMatch,
  196. NULL
  197. )
  198. )) {
  199. CloseHandle(handleToDev);
  200. continue;
  201. }
  202. if (!localMatch.FoundIt) {
  203. CloseHandle(handleToDev);
  204. continue;
  205. }
  206. //
  207. // The names match. Now look
  208. // for the config dll name.
  209. //
  210. paramTable[0].QueryRoutine =
  211. GetConfigDialogName;
  212. paramTable[0].Name =
  213. L"ConfigDialog";
  214. statusOfQuery =
  215. RtlQueryRegistryValues(
  216. RTL_REGISTRY_HANDLE,
  217. handleToDev,
  218. &paramTable[0],
  219. DllToInvoke,
  220. NULL
  221. );
  222. paramTable[0].QueryRoutine =
  223. GetFriendlyMatchComm;
  224. if (!NT_SUCCESS(statusOfQuery)) {
  225. //
  226. // We had a bad status
  227. // back from getting the dll
  228. // name we should have gotten.
  229. //
  230. // There is no point in
  231. // looking for anymore
  232. //
  233. BaseSetLastNTError(
  234. statusOfQuery
  235. );
  236. CloseHandle(handleToDev);
  237. return;
  238. }
  239. //
  240. // We know that we are dealing
  241. // with a local registry here.
  242. // we just call closehandle.
  243. //
  244. CloseHandle(handleToDev);
  245. if (DllToInvoke->Buffer) {
  246. //
  247. // We have found a dll for
  248. // the friendly name. Just
  249. // leave. The finally
  250. // handlers will clean up
  251. // our allocations.
  252. //
  253. return;
  254. }
  255. }
  256. }
  257. }
  258. }
  259. } finally {
  260. //
  261. // Free the idlist memory.
  262. //
  263. RtlFreeHeap(
  264. RtlProcessHeap(),
  265. 0,
  266. bufferForList
  267. );
  268. }
  269. }
  270. }
  271. }
  272. } finally {
  273. FreeLibrary(libHandle);
  274. }
  275. }
  276. if (!DllToInvoke->Buffer) {
  277. //
  278. // Couldn't find the friendly name in the enum tree.
  279. // See if the value is a valid comm port name. If
  280. // it is, default return serialui.dll
  281. //
  282. paramTable[0].Name = NULL;
  283. RtlQueryRegistryValues(
  284. RTL_REGISTRY_DEVICEMAP,
  285. L"SERIALCOMM",
  286. paramTable,
  287. &localMatch,
  288. NULL
  289. );
  290. if (localMatch.FoundIt) {
  291. ANSI_STRING ansiString;
  292. RtlInitAnsiString(
  293. &ansiString,
  294. "serialui.dll"
  295. );
  296. DllToInvoke->Buffer = RtlAllocateHeap(
  297. RtlProcessHeap(),
  298. MAKE_TAG( TMP_TAG ),
  299. (ansiString.Length+2)*sizeof(WCHAR)
  300. );
  301. if (!DllToInvoke->Buffer) {
  302. BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
  303. return;
  304. }
  305. DllToInvoke->Length = 0;
  306. DllToInvoke->MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
  307. RtlAnsiStringToUnicodeString(
  308. DllToInvoke,
  309. &ansiString,
  310. FALSE
  311. );
  312. *(DllToInvoke->Buffer+ansiString.Length) = 0;
  313. } else {
  314. SetLastError(ERROR_INVALID_PARAMETER);
  315. }
  316. }
  317. }
  318. BOOL
  319. CommConfigDialogW(
  320. LPCWSTR lpszName,
  321. HWND hWnd,
  322. LPCOMMCONFIG lpCC
  323. )
  324. {
  325. UNICODE_STRING dllName = {0};
  326. BOOL boolToReturn = TRUE;
  327. HINSTANCE libInstance = 0;
  328. DWORD statOfCall = 0;
  329. //
  330. // Given the "friendly name" get the name of the dll to load.
  331. //
  332. GetFriendlyUi(
  333. lpszName,
  334. &dllName
  335. );
  336. try {
  337. if (dllName.Buffer) {
  338. //
  339. // Got the new library name. Try to load it.
  340. //
  341. libInstance = LoadLibraryW(dllName.Buffer);
  342. if (libInstance) {
  343. FARPROC procToCall;
  344. //
  345. // Got the lib. Get the proc address we need.
  346. //
  347. procToCall = GetProcAddress(
  348. libInstance,
  349. "drvCommConfigDialogW"
  350. );
  351. statOfCall = (DWORD)procToCall(
  352. lpszName,
  353. hWnd,
  354. lpCC
  355. );
  356. } else {
  357. boolToReturn = FALSE;
  358. }
  359. } else {
  360. //
  361. // Assume that an appropriate error has been set.
  362. //
  363. boolToReturn = FALSE;
  364. }
  365. } finally {
  366. if (dllName.Buffer) {
  367. RtlFreeHeap(
  368. RtlProcessHeap(),
  369. 0,
  370. dllName.Buffer
  371. );
  372. }
  373. if (libInstance) {
  374. FreeLibrary(libInstance);
  375. }
  376. if (statOfCall) {
  377. SetLastError(statOfCall);
  378. boolToReturn = FALSE;
  379. }
  380. }
  381. return boolToReturn;
  382. }
  383. BOOL
  384. CommConfigDialogA(
  385. LPCSTR lpszName,
  386. HWND hWnd,
  387. LPCOMMCONFIG lpCC
  388. )
  389. {
  390. PWCHAR unicodeName;
  391. UNICODE_STRING tmpString;
  392. ANSI_STRING ansiString;
  393. BOOL uniBool;
  394. RtlInitAnsiString(
  395. &ansiString,
  396. lpszName
  397. );
  398. unicodeName = RtlAllocateHeap(
  399. RtlProcessHeap(),
  400. MAKE_TAG( TMP_TAG ),
  401. (ansiString.Length+2)*sizeof(WCHAR)
  402. );
  403. if (!unicodeName) {
  404. BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
  405. return FALSE;
  406. }
  407. tmpString.Length = 0;
  408. tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
  409. tmpString.Buffer = unicodeName;
  410. RtlAnsiStringToUnicodeString(
  411. &tmpString,
  412. &ansiString,
  413. FALSE
  414. );
  415. *(unicodeName+ansiString.Length) = 0;
  416. try {
  417. uniBool = CommConfigDialogW(
  418. unicodeName,
  419. hWnd,
  420. lpCC
  421. );
  422. } finally {
  423. RtlFreeHeap(
  424. RtlProcessHeap(),
  425. 0,
  426. unicodeName
  427. );
  428. }
  429. return uniBool;
  430. }
  431. BOOL
  432. GetDefaultCommConfigW(
  433. LPCWSTR lpszName,
  434. LPCOMMCONFIG lpCC,
  435. LPDWORD lpdwSize
  436. )
  437. {
  438. UNICODE_STRING dllName = {0};
  439. BOOL boolToReturn = TRUE;
  440. HINSTANCE libInstance = 0;
  441. DWORD statOfCall = 0;
  442. //
  443. // Given the "friendly name" get the name of the dll to load.
  444. //
  445. GetFriendlyUi(
  446. lpszName,
  447. &dllName
  448. );
  449. try {
  450. if (dllName.Buffer) {
  451. //
  452. // Got the new library name. Try to load it.
  453. //
  454. libInstance = LoadLibraryW(dllName.Buffer);
  455. if (libInstance) {
  456. FARPROC procToCall;
  457. //
  458. // Got the lib. Get the proc address we need.
  459. //
  460. procToCall = GetProcAddress(
  461. libInstance,
  462. "drvGetDefaultCommConfigW"
  463. );
  464. statOfCall = (DWORD)procToCall(
  465. lpszName,
  466. lpCC,
  467. lpdwSize
  468. );
  469. } else {
  470. boolToReturn = FALSE;
  471. }
  472. } else {
  473. //
  474. // Assume that an appropriate error has been set.
  475. //
  476. boolToReturn = FALSE;
  477. }
  478. } finally {
  479. if (dllName.Buffer) {
  480. RtlFreeHeap(
  481. RtlProcessHeap(),
  482. 0,
  483. dllName.Buffer
  484. );
  485. }
  486. if (libInstance) {
  487. FreeLibrary(libInstance);
  488. }
  489. if (statOfCall) {
  490. SetLastError(statOfCall);
  491. boolToReturn = FALSE;
  492. }
  493. }
  494. return boolToReturn;
  495. }
  496. BOOL
  497. GetDefaultCommConfigA(
  498. LPCSTR lpszName,
  499. LPCOMMCONFIG lpCC,
  500. LPDWORD lpdwSize
  501. )
  502. {
  503. PWCHAR unicodeName;
  504. UNICODE_STRING tmpString;
  505. ANSI_STRING ansiString;
  506. BOOL uniBool;
  507. RtlInitAnsiString(
  508. &ansiString,
  509. lpszName
  510. );
  511. unicodeName = RtlAllocateHeap(
  512. RtlProcessHeap(),
  513. MAKE_TAG( TMP_TAG ),
  514. (ansiString.Length+2)*sizeof(WCHAR)
  515. );
  516. if (!unicodeName) {
  517. BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
  518. return FALSE;
  519. }
  520. tmpString.Length = 0;
  521. tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
  522. tmpString.Buffer = unicodeName;
  523. RtlAnsiStringToUnicodeString(
  524. &tmpString,
  525. &ansiString,
  526. FALSE
  527. );
  528. *(unicodeName+ansiString.Length) = 0;
  529. try {
  530. uniBool = GetDefaultCommConfigW(
  531. unicodeName,
  532. lpCC,
  533. lpdwSize
  534. );
  535. } finally {
  536. RtlFreeHeap(
  537. RtlProcessHeap(),
  538. 0,
  539. unicodeName
  540. );
  541. }
  542. return uniBool;
  543. }
  544. BOOL
  545. SetDefaultCommConfigW(
  546. LPCWSTR lpszName,
  547. LPCOMMCONFIG lpCC,
  548. DWORD dwSize
  549. )
  550. {
  551. UNICODE_STRING dllName = {0};
  552. BOOL boolToReturn = TRUE;
  553. HINSTANCE libInstance = 0;
  554. DWORD statOfCall = 0;
  555. //
  556. // Given the "friendly name" get the name of the dll to load.
  557. //
  558. GetFriendlyUi(
  559. lpszName,
  560. &dllName
  561. );
  562. try {
  563. if (dllName.Buffer) {
  564. //
  565. // Got the new library name. Try to load it.
  566. //
  567. libInstance = LoadLibraryW(dllName.Buffer);
  568. if (libInstance) {
  569. FARPROC procToCall;
  570. //
  571. // Got the lib. Get the proc address we need.
  572. //
  573. procToCall = GetProcAddress(
  574. libInstance,
  575. "drvSetDefaultCommConfigW"
  576. );
  577. statOfCall = (DWORD)procToCall(
  578. lpszName,
  579. lpCC,
  580. dwSize
  581. );
  582. } else {
  583. boolToReturn = FALSE;
  584. }
  585. } else {
  586. //
  587. // Assume that an appropriate error has been set.
  588. //
  589. boolToReturn = FALSE;
  590. }
  591. } finally {
  592. if (dllName.Buffer) {
  593. RtlFreeHeap(
  594. RtlProcessHeap(),
  595. 0,
  596. dllName.Buffer
  597. );
  598. }
  599. if (libInstance) {
  600. FreeLibrary(libInstance);
  601. }
  602. if (statOfCall) {
  603. SetLastError(statOfCall);
  604. boolToReturn = FALSE;
  605. }
  606. }
  607. return boolToReturn;
  608. }
  609. BOOL
  610. SetDefaultCommConfigA(
  611. LPCSTR lpszName,
  612. LPCOMMCONFIG lpCC,
  613. DWORD dwSize
  614. )
  615. {
  616. PWCHAR unicodeName;
  617. UNICODE_STRING tmpString;
  618. ANSI_STRING ansiString;
  619. BOOL uniBool = TRUE;
  620. RtlInitAnsiString(
  621. &ansiString,
  622. lpszName
  623. );
  624. unicodeName = RtlAllocateHeap(
  625. RtlProcessHeap(),
  626. MAKE_TAG( TMP_TAG ),
  627. (ansiString.Length+2)*sizeof(WCHAR)
  628. );
  629. if (!unicodeName) {
  630. BaseSetLastNTError(STATUS_INSUFFICIENT_RESOURCES);
  631. return FALSE;
  632. }
  633. tmpString.Length = 0;
  634. tmpString.MaximumLength = (ansiString.Length+1)*sizeof(WCHAR);
  635. tmpString.Buffer = unicodeName;
  636. RtlAnsiStringToUnicodeString(
  637. &tmpString,
  638. &ansiString,
  639. FALSE
  640. );
  641. *(unicodeName+ansiString.Length) = 0;
  642. try {
  643. uniBool = SetDefaultCommConfigW(
  644. unicodeName,
  645. lpCC,
  646. dwSize
  647. );
  648. } finally {
  649. RtlFreeHeap(
  650. RtlProcessHeap(),
  651. 0,
  652. unicodeName
  653. );
  654. }
  655. return uniBool;
  656. }
  657. BOOL
  658. ClearCommBreak(
  659. HANDLE hFile
  660. )
  661. /*++
  662. Routine Description:
  663. The function restores character transmission and places the transmission
  664. line in a nonbreak state.
  665. Arguments:
  666. hFile - Specifies the communication device to be adjusted.
  667. Return Value:
  668. The return value is TRUE if the function is successful or FALSE
  669. if an error occurs.
  670. --*/
  671. {
  672. return EscapeCommFunction(hFile,CLRBREAK);
  673. }
  674. BOOL
  675. ClearCommError(
  676. HANDLE hFile,
  677. LPDWORD lpErrors,
  678. LPCOMSTAT lpStat
  679. )
  680. /*++
  681. Routine Description:
  682. In case of a communications error, such as a buffer overrun or
  683. framing error, the communications software will abort all
  684. read and write operations on the communication port. No further
  685. read or write operations will be accepted until this function
  686. is called.
  687. Arguments:
  688. hFile - Specifies the communication device to be adjusted.
  689. lpErrors - Points to the DWORD that is to receive the mask of the
  690. error that occured.
  691. lpStat - Points to the COMMSTAT structure that is to receive
  692. the device status. The structure contains information
  693. about the communications device.
  694. Return Value:
  695. The return value is TRUE if the function is successful or FALSE
  696. if an error occurs.
  697. --*/
  698. {
  699. NTSTATUS Status;
  700. HANDLE SyncEvent;
  701. IO_STATUS_BLOCK Iosb;
  702. SERIAL_STATUS LocalStat;
  703. RtlZeroMemory(&LocalStat, sizeof(SERIAL_STATUS));
  704. if (!(SyncEvent = CreateEvent(
  705. NULL,
  706. TRUE,
  707. FALSE,
  708. NULL
  709. ))) {
  710. return FALSE;
  711. }
  712. Status = NtDeviceIoControlFile(
  713. hFile,
  714. SyncEvent,
  715. NULL,
  716. NULL,
  717. &Iosb,
  718. IOCTL_SERIAL_GET_COMMSTATUS,
  719. NULL,
  720. 0,
  721. &LocalStat,
  722. sizeof(LocalStat)
  723. );
  724. if ( Status == STATUS_PENDING) {
  725. // Operation must complete before return & IoStatusBlock destroyed
  726. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  727. if ( NT_SUCCESS(Status)) {
  728. Status = Iosb.Status;
  729. }
  730. }
  731. if (NT_ERROR(Status)) {
  732. CloseHandle(SyncEvent);
  733. BaseSetLastNTError(Status);
  734. return FALSE;
  735. }
  736. if (lpStat) {
  737. //
  738. // All is well up to this point. Translate the NT values
  739. // into win32 values.
  740. //
  741. if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_CTS) {
  742. lpStat->fCtsHold = TRUE;
  743. } else {
  744. lpStat->fCtsHold = FALSE;
  745. }
  746. if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_DSR) {
  747. lpStat->fDsrHold = TRUE;
  748. } else {
  749. lpStat->fDsrHold = FALSE;
  750. }
  751. if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_DCD) {
  752. lpStat->fRlsdHold = TRUE;
  753. } else {
  754. lpStat->fRlsdHold = FALSE;
  755. }
  756. if (LocalStat.HoldReasons & SERIAL_TX_WAITING_FOR_XON) {
  757. lpStat->fXoffHold = TRUE;
  758. } else {
  759. lpStat->fXoffHold = FALSE;
  760. }
  761. if (LocalStat.HoldReasons & SERIAL_TX_WAITING_XOFF_SENT) {
  762. lpStat->fXoffSent = TRUE;
  763. } else {
  764. lpStat->fXoffSent = FALSE;
  765. }
  766. lpStat->fEof = LocalStat.EofReceived;
  767. lpStat->fTxim = LocalStat.WaitForImmediate;
  768. lpStat->cbInQue = LocalStat.AmountInInQueue;
  769. lpStat->cbOutQue = LocalStat.AmountInOutQueue;
  770. }
  771. if (lpErrors) {
  772. *lpErrors = 0;
  773. if (LocalStat.Errors & SERIAL_ERROR_BREAK) {
  774. *lpErrors = *lpErrors | CE_BREAK;
  775. }
  776. if (LocalStat.Errors & SERIAL_ERROR_FRAMING) {
  777. *lpErrors = *lpErrors | CE_FRAME;
  778. }
  779. if (LocalStat.Errors & SERIAL_ERROR_OVERRUN) {
  780. *lpErrors = *lpErrors | CE_OVERRUN;
  781. }
  782. if (LocalStat.Errors & SERIAL_ERROR_QUEUEOVERRUN) {
  783. *lpErrors = *lpErrors | CE_RXOVER;
  784. }
  785. if (LocalStat.Errors & SERIAL_ERROR_PARITY) {
  786. *lpErrors = *lpErrors | CE_RXPARITY;
  787. }
  788. }
  789. CloseHandle(SyncEvent);
  790. return TRUE;
  791. }
  792. BOOL
  793. SetupComm(
  794. HANDLE hFile,
  795. DWORD dwInQueue,
  796. DWORD dwOutQueue
  797. )
  798. /*++
  799. Routine Description:
  800. The communication device is not initialized until SetupComm is
  801. called. This function allocates space for receive and transmit
  802. queues. These queues are used by the interrupt-driven transmit/
  803. receive software and are internal to the provider.
  804. Arguments:
  805. hFile - Specifies the communication device to receive the settings.
  806. The CreateFile function returns this value.
  807. dwInQueue - Specifies the recommended size of the provider's
  808. internal receive queue in bytes. This value must be
  809. even. A value of -1 indicates that the default should
  810. be used.
  811. dwOutQueue - Specifies the recommended size of the provider's
  812. internal transmit queue in bytes. This value must be
  813. even. A value of -1 indicates that the default should
  814. be used.
  815. Return Value:
  816. The return value is TRUE if the function is successful or FALSE
  817. if an error occurs.
  818. --*/
  819. {
  820. NTSTATUS Status;
  821. HANDLE SyncEvent;
  822. IO_STATUS_BLOCK Iosb;
  823. SERIAL_QUEUE_SIZE NewSizes = {0};
  824. //
  825. // Make sure that the sizes are even.
  826. //
  827. if (dwOutQueue != ((DWORD)-1)) {
  828. if (((dwOutQueue/2)*2) != dwOutQueue) {
  829. SetLastError(ERROR_INVALID_DATA);
  830. return FALSE;
  831. }
  832. }
  833. if (dwInQueue != ((DWORD)-1)) {
  834. if (((dwInQueue/2)*2) != dwInQueue) {
  835. SetLastError(ERROR_INVALID_DATA);
  836. return FALSE;
  837. }
  838. }
  839. NewSizes.InSize = dwInQueue;
  840. NewSizes.OutSize = dwOutQueue;
  841. if (!(SyncEvent = CreateEvent(
  842. NULL,
  843. TRUE,
  844. FALSE,
  845. NULL
  846. ))) {
  847. return FALSE;
  848. }
  849. Status = NtDeviceIoControlFile(
  850. hFile,
  851. SyncEvent,
  852. NULL,
  853. NULL,
  854. &Iosb,
  855. IOCTL_SERIAL_SET_QUEUE_SIZE,
  856. &NewSizes,
  857. sizeof(SERIAL_QUEUE_SIZE),
  858. NULL,
  859. 0
  860. );
  861. if ( Status == STATUS_PENDING) {
  862. // Operation must complete before return & IoStatusBlock destroyed
  863. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  864. if ( NT_SUCCESS(Status)) {
  865. Status = Iosb.Status;
  866. }
  867. }
  868. if (NT_ERROR(Status)) {
  869. CloseHandle(SyncEvent);
  870. BaseSetLastNTError(Status);
  871. return FALSE;
  872. }
  873. CloseHandle(SyncEvent);
  874. return TRUE;
  875. }
  876. BOOL
  877. EscapeCommFunction(
  878. HANDLE hFile,
  879. DWORD dwFunc
  880. )
  881. /*++
  882. Routine Description:
  883. This function directs the communication-device specified by the
  884. hFile parameter to carry out the extended function specified by
  885. the dwFunc parameter.
  886. Arguments:
  887. hFile - Specifies the communication device to receive the settings.
  888. The CreateFile function returns this value.
  889. dwFunc - Specifies the function code of the extended function.
  890. Return Value:
  891. The return value is TRUE if the function is successful or FALSE
  892. if an error occurs.
  893. --*/
  894. {
  895. NTSTATUS Status;
  896. IO_STATUS_BLOCK Iosb;
  897. ULONG ControlCode;
  898. HANDLE Event;
  899. switch (dwFunc) {
  900. case SETXOFF: {
  901. ControlCode = IOCTL_SERIAL_SET_XOFF;
  902. break;
  903. }
  904. case SETXON: {
  905. ControlCode = IOCTL_SERIAL_SET_XON;
  906. break;
  907. }
  908. case SETRTS: {
  909. ControlCode = IOCTL_SERIAL_SET_RTS;
  910. break;
  911. }
  912. case CLRRTS: {
  913. ControlCode = IOCTL_SERIAL_CLR_RTS;
  914. break;
  915. }
  916. case SETDTR: {
  917. ControlCode = IOCTL_SERIAL_SET_DTR;
  918. break;
  919. }
  920. case CLRDTR: {
  921. ControlCode = IOCTL_SERIAL_CLR_DTR;
  922. break;
  923. }
  924. case RESETDEV: {
  925. ControlCode = IOCTL_SERIAL_RESET_DEVICE;
  926. break;
  927. }
  928. case SETBREAK: {
  929. ControlCode = IOCTL_SERIAL_SET_BREAK_ON;
  930. break;
  931. }
  932. case CLRBREAK: {
  933. ControlCode = IOCTL_SERIAL_SET_BREAK_OFF;
  934. break;
  935. }
  936. default: {
  937. SetLastError(ERROR_INVALID_PARAMETER);
  938. return FALSE;
  939. }
  940. }
  941. if (!(Event = CreateEvent(
  942. NULL,
  943. TRUE,
  944. FALSE,
  945. NULL
  946. ))) {
  947. return FALSE;
  948. }
  949. Status = NtDeviceIoControlFile(
  950. hFile,
  951. Event,
  952. NULL,
  953. NULL,
  954. &Iosb,
  955. ControlCode,
  956. NULL,
  957. 0,
  958. NULL,
  959. 0
  960. );
  961. if ( Status == STATUS_PENDING) {
  962. // Operation must complete before return & IoStatusBlock destroyed
  963. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  964. if ( NT_SUCCESS(Status)) {
  965. Status = Iosb.Status;
  966. }
  967. }
  968. if (NT_ERROR(Status)) {
  969. CloseHandle(Event);
  970. BaseSetLastNTError(Status);
  971. return FALSE;
  972. }
  973. CloseHandle(Event);
  974. return TRUE;
  975. }
  976. BOOL
  977. GetCommConfig(
  978. HANDLE hCommDev,
  979. LPCOMMCONFIG lpCC,
  980. LPDWORD lpdwSize
  981. )
  982. {
  983. NTSTATUS Status;
  984. IO_STATUS_BLOCK Iosb;
  985. ULONG configLength;
  986. HANDLE Event;
  987. DWORD olddwSize = *lpdwSize;
  988. //
  989. // Ask the device how big the device config structure is.
  990. //
  991. if (!(Event = CreateEvent(
  992. NULL,
  993. TRUE,
  994. FALSE,
  995. NULL
  996. ))) {
  997. return FALSE;
  998. }
  999. Status = NtDeviceIoControlFile(
  1000. hCommDev,
  1001. Event,
  1002. NULL,
  1003. NULL,
  1004. &Iosb,
  1005. IOCTL_SERIAL_CONFIG_SIZE,
  1006. NULL,
  1007. 0,
  1008. &configLength,
  1009. sizeof(configLength)
  1010. );
  1011. if ( Status == STATUS_PENDING) {
  1012. // Operation must complete before return & IoStatusBlock destroyed
  1013. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  1014. if ( NT_SUCCESS(Status)) {
  1015. Status = Iosb.Status;
  1016. }
  1017. }
  1018. if (NT_ERROR(Status)) {
  1019. configLength = 0;
  1020. }
  1021. if (!configLength) {
  1022. //
  1023. // The size needed is simply the size of the comm config structure.
  1024. //
  1025. CloseHandle(Event);
  1026. if (!ARGUMENT_PRESENT(lpdwSize)) {
  1027. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1028. return FALSE;
  1029. } else {
  1030. *lpdwSize = sizeof(COMMCONFIG);
  1031. if (ARGUMENT_PRESENT(lpCC)) {
  1032. //
  1033. // Fill in the random fields.
  1034. //
  1035. lpCC->dwSize = sizeof(COMMCONFIG);
  1036. lpCC->wVersion = 1;
  1037. lpCC->wReserved = 0;
  1038. lpCC->dwProviderSubType = PST_RS232;
  1039. lpCC->dwProviderOffset = 0;
  1040. lpCC->dwProviderSize = 0;
  1041. lpCC->wcProviderData[0] = 0;
  1042. return GetCommState(
  1043. hCommDev,
  1044. &lpCC->dcb
  1045. );
  1046. } else {
  1047. return TRUE;
  1048. }
  1049. }
  1050. } else {
  1051. if (!ARGUMENT_PRESENT(lpdwSize)) {
  1052. CloseHandle(Event);
  1053. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1054. return FALSE;
  1055. } else {
  1056. if (*lpdwSize < sizeof(COMMCONFIG)) {
  1057. CloseHandle(Event);
  1058. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1059. *lpdwSize = configLength;
  1060. return FALSE;
  1061. } else {
  1062. if (ARGUMENT_PRESENT(lpCC)) {
  1063. lpCC->wVersion = 1;
  1064. lpCC->dwProviderSubType = PST_MODEM;
  1065. if (*lpdwSize < configLength) {
  1066. lpCC->dwProviderOffset = 0;
  1067. lpCC->dwProviderSize = 0;
  1068. lpCC->wcProviderData[0] = 0;
  1069. *lpdwSize = sizeof(COMMCONFIG);
  1070. CloseHandle(Event);
  1071. return GetCommState(
  1072. hCommDev,
  1073. &lpCC->dcb
  1074. );
  1075. } else {
  1076. *lpdwSize = configLength;
  1077. //
  1078. // Call down to the lower level serial provider
  1079. // if there is a passed comm config. Assume
  1080. // that the buffer is as large as it needs to be.
  1081. // Parameter validation will insure that we
  1082. // can write to at least that much.
  1083. //
  1084. Status = NtDeviceIoControlFile(
  1085. hCommDev,
  1086. Event,
  1087. NULL,
  1088. NULL,
  1089. &Iosb,
  1090. IOCTL_SERIAL_GET_COMMCONFIG,
  1091. NULL,
  1092. 0,
  1093. lpCC,
  1094. configLength
  1095. );
  1096. if ( Status == STATUS_PENDING) {
  1097. // Operation must complete before return & IoStatusBlock destroyed
  1098. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  1099. if ( NT_SUCCESS(Status)) {
  1100. Status = Iosb.Status;
  1101. }
  1102. }
  1103. if (NT_ERROR(Status)) {
  1104. CloseHandle(Event);
  1105. BaseSetLastNTError(Status);
  1106. return FALSE;
  1107. }
  1108. //
  1109. // Got the config stuff, get the comm state too.
  1110. //
  1111. CloseHandle(Event);
  1112. return GetCommState(
  1113. hCommDev,
  1114. &lpCC->dcb
  1115. );
  1116. }
  1117. } else {
  1118. *lpdwSize = configLength;
  1119. CloseHandle(Event);
  1120. return TRUE;
  1121. }
  1122. }
  1123. }
  1124. }
  1125. }
  1126. BOOL
  1127. GetCommMask(
  1128. HANDLE hFile,
  1129. LPDWORD lpEvtMask
  1130. )
  1131. /*++
  1132. Routine Description:
  1133. This function retrieves the value of the event mask for the handle
  1134. hFile. The mask is not cleared
  1135. Arguments:
  1136. hFile - Specifies the communication device to be examined.
  1137. The CreateFile function returns this value.
  1138. lpEvtMask - Points to a DWORD which is to receive the mask of events
  1139. which are currently enabled.
  1140. Return Value:
  1141. The return value is TRUE if the function is successful or FALSE
  1142. if an error occurs.
  1143. --*/
  1144. {
  1145. NTSTATUS Status;
  1146. HANDLE SyncEvent;
  1147. IO_STATUS_BLOCK Iosb;
  1148. //
  1149. // First we do an assert to make sure that the
  1150. // values in the win header files are the same
  1151. // as the nt serial interface, and that the
  1152. // size of the win32 wait mask is the same size
  1153. // as the nt wait mask.
  1154. //
  1155. ASSERT((SERIAL_EV_RXCHAR == EV_RXCHAR ) &&
  1156. (SERIAL_EV_RXFLAG == EV_RXFLAG ) &&
  1157. (SERIAL_EV_TXEMPTY == EV_TXEMPTY ) &&
  1158. (SERIAL_EV_CTS == EV_CTS ) &&
  1159. (SERIAL_EV_DSR == EV_DSR ) &&
  1160. (SERIAL_EV_RLSD == EV_RLSD ) &&
  1161. (SERIAL_EV_BREAK == EV_BREAK ) &&
  1162. (SERIAL_EV_ERR == EV_ERR ) &&
  1163. (SERIAL_EV_RING == EV_RING ) &&
  1164. (SERIAL_EV_PERR == EV_PERR ) &&
  1165. (SERIAL_EV_RX80FULL == EV_RX80FULL) &&
  1166. (SERIAL_EV_EVENT1 == EV_EVENT1 ) &&
  1167. (SERIAL_EV_EVENT2 == EV_EVENT2 ) &&
  1168. (sizeof(ULONG) == sizeof(DWORD)));
  1169. //
  1170. // All is well, get the mask from the driver.
  1171. //
  1172. if (!(SyncEvent = CreateEvent(
  1173. NULL,
  1174. TRUE,
  1175. FALSE,
  1176. NULL
  1177. ))) {
  1178. return FALSE;
  1179. }
  1180. Status = NtDeviceIoControlFile(
  1181. hFile,
  1182. SyncEvent,
  1183. NULL,
  1184. NULL,
  1185. &Iosb,
  1186. IOCTL_SERIAL_GET_WAIT_MASK,
  1187. NULL,
  1188. 0,
  1189. lpEvtMask,
  1190. sizeof(ULONG)
  1191. );
  1192. if ( Status == STATUS_PENDING) {
  1193. // Operation must complete before return & IoStatusBlock destroyed
  1194. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  1195. if ( NT_SUCCESS(Status)) {
  1196. Status = Iosb.Status;
  1197. }
  1198. }
  1199. if (NT_ERROR(Status)) {
  1200. CloseHandle(SyncEvent);
  1201. BaseSetLastNTError(Status);
  1202. return FALSE;
  1203. }
  1204. CloseHandle(SyncEvent);
  1205. return TRUE;
  1206. }
  1207. BOOL
  1208. GetCommModemStatus(
  1209. HANDLE hFile,
  1210. LPDWORD lpModemStat
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. This routine returns the most current value of the modem
  1215. status registers non-delta values.
  1216. Arguments:
  1217. hFile - Specifies the communication device to be examined.
  1218. The CreateFile function returns this value.
  1219. lpEvtMask - Points to a DWORD which is to receive the mask of
  1220. non-delta values in the modem status register.
  1221. Return Value:
  1222. The return value is TRUE if the function is successful or FALSE
  1223. if an error occurs.
  1224. --*/
  1225. {
  1226. NTSTATUS Status;
  1227. HANDLE SyncEvent;
  1228. IO_STATUS_BLOCK Iosb;
  1229. if (!(SyncEvent = CreateEvent(
  1230. NULL,
  1231. TRUE,
  1232. FALSE,
  1233. NULL
  1234. ))) {
  1235. return FALSE;
  1236. }
  1237. Status = NtDeviceIoControlFile(
  1238. hFile,
  1239. SyncEvent,
  1240. NULL,
  1241. NULL,
  1242. &Iosb,
  1243. IOCTL_SERIAL_GET_MODEMSTATUS,
  1244. NULL,
  1245. 0,
  1246. lpModemStat,
  1247. sizeof(DWORD)
  1248. );
  1249. if ( Status == STATUS_PENDING) {
  1250. // Operation must complete before return & IoStatusBlock destroyed
  1251. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  1252. if ( NT_SUCCESS(Status)) {
  1253. Status = Iosb.Status;
  1254. }
  1255. }
  1256. if (NT_ERROR(Status)) {
  1257. CloseHandle(SyncEvent);
  1258. BaseSetLastNTError(Status);
  1259. return FALSE;
  1260. }
  1261. CloseHandle(SyncEvent);
  1262. return TRUE;
  1263. }
  1264. BOOL
  1265. GetCommProperties(
  1266. HANDLE hFile,
  1267. LPCOMMPROP lpCommProp
  1268. )
  1269. /*++
  1270. Routine Description:
  1271. This function fills the ubffer pointed to by lpCommProp with the
  1272. communications properties associated with the communications device
  1273. specified by the hFile.
  1274. Arguments:
  1275. hFile - Specifies the communication device to be examined.
  1276. The CreateFile function returns this value.
  1277. lpCommProp - Points to the COMMPROP data structure that is to
  1278. receive the communications properties structure. This
  1279. structure defines certain properties of the communications
  1280. device.
  1281. Return Value:
  1282. The return value is TRUE if the function is successful or FALSE
  1283. if an error occurs.
  1284. --*/
  1285. {
  1286. NTSTATUS Status;
  1287. HANDLE SyncEvent;
  1288. IO_STATUS_BLOCK Iosb;
  1289. DWORD bufferLength;
  1290. //
  1291. // Make sure that the windows defines and the nt defines are
  1292. // still in sync.
  1293. //
  1294. ASSERT((SERIAL_PCF_DTRDSR == PCF_DTRDSR) &&
  1295. (SERIAL_PCF_RTSCTS == PCF_RTSCTS) &&
  1296. (SERIAL_PCF_CD == PCF_RLSD) &&
  1297. (SERIAL_PCF_PARITY_CHECK == PCF_PARITY_CHECK) &&
  1298. (SERIAL_PCF_XONXOFF == PCF_XONXOFF) &&
  1299. (SERIAL_PCF_SETXCHAR == PCF_SETXCHAR) &&
  1300. (SERIAL_PCF_TOTALTIMEOUTS == PCF_TOTALTIMEOUTS) &&
  1301. (SERIAL_PCF_INTTIMEOUTS == PCF_INTTIMEOUTS) &&
  1302. (SERIAL_PCF_SPECIALCHARS == PCF_SPECIALCHARS) &&
  1303. (SERIAL_PCF_16BITMODE == PCF_16BITMODE) &&
  1304. (SERIAL_SP_PARITY == SP_PARITY) &&
  1305. (SERIAL_SP_BAUD == SP_BAUD) &&
  1306. (SERIAL_SP_DATABITS == SP_DATABITS) &&
  1307. (SERIAL_SP_STOPBITS == SP_STOPBITS) &&
  1308. (SERIAL_SP_HANDSHAKING == SP_HANDSHAKING) &&
  1309. (SERIAL_SP_PARITY_CHECK == SP_PARITY_CHECK) &&
  1310. (SERIAL_SP_CARRIER_DETECT == SP_RLSD) &&
  1311. (SERIAL_BAUD_075 == BAUD_075) &&
  1312. (SERIAL_BAUD_110 == BAUD_110) &&
  1313. (SERIAL_BAUD_134_5 == BAUD_134_5) &&
  1314. (SERIAL_BAUD_150 == BAUD_150) &&
  1315. (SERIAL_BAUD_300 == BAUD_300) &&
  1316. (SERIAL_BAUD_600 == BAUD_600) &&
  1317. (SERIAL_BAUD_1200 == BAUD_1200) &&
  1318. (SERIAL_BAUD_1800 == BAUD_1800) &&
  1319. (SERIAL_BAUD_2400 == BAUD_2400) &&
  1320. (SERIAL_BAUD_4800 == BAUD_4800) &&
  1321. (SERIAL_BAUD_7200 == BAUD_7200) &&
  1322. (SERIAL_BAUD_9600 == BAUD_9600) &&
  1323. (SERIAL_BAUD_14400 == BAUD_14400) &&
  1324. (SERIAL_BAUD_19200 == BAUD_19200) &&
  1325. (SERIAL_BAUD_38400 == BAUD_38400) &&
  1326. (SERIAL_BAUD_56K == BAUD_56K) &&
  1327. (SERIAL_BAUD_57600 == BAUD_57600) &&
  1328. (SERIAL_BAUD_115200 == BAUD_115200) &&
  1329. (SERIAL_BAUD_USER == BAUD_USER) &&
  1330. (SERIAL_DATABITS_5 == DATABITS_5) &&
  1331. (SERIAL_DATABITS_6 == DATABITS_6) &&
  1332. (SERIAL_DATABITS_7 == DATABITS_7) &&
  1333. (SERIAL_DATABITS_8 == DATABITS_8) &&
  1334. (SERIAL_DATABITS_16 == DATABITS_16) &&
  1335. (SERIAL_DATABITS_16X == DATABITS_16X) &&
  1336. (SERIAL_STOPBITS_10 == STOPBITS_10) &&
  1337. (SERIAL_STOPBITS_15 == STOPBITS_15) &&
  1338. (SERIAL_STOPBITS_20 == STOPBITS_20) &&
  1339. (SERIAL_PARITY_NONE == PARITY_NONE) &&
  1340. (SERIAL_PARITY_ODD == PARITY_ODD) &&
  1341. (SERIAL_PARITY_EVEN == PARITY_EVEN) &&
  1342. (SERIAL_PARITY_MARK == PARITY_MARK) &&
  1343. (SERIAL_PARITY_SPACE == PARITY_SPACE));
  1344. ASSERT((SERIAL_SP_UNSPECIFIED == PST_UNSPECIFIED) &&
  1345. (SERIAL_SP_RS232 == PST_RS232) &&
  1346. (SERIAL_SP_PARALLEL == PST_PARALLELPORT) &&
  1347. (SERIAL_SP_RS422 == PST_RS422) &&
  1348. (SERIAL_SP_RS423 == PST_RS423) &&
  1349. (SERIAL_SP_RS449 == PST_RS449) &&
  1350. (SERIAL_SP_FAX == PST_FAX) &&
  1351. (SERIAL_SP_SCANNER == PST_SCANNER) &&
  1352. (SERIAL_SP_BRIDGE == PST_NETWORK_BRIDGE) &&
  1353. (SERIAL_SP_LAT == PST_LAT) &&
  1354. (SERIAL_SP_TELNET == PST_TCPIP_TELNET) &&
  1355. (SERIAL_SP_X25 == PST_X25));
  1356. ASSERT(sizeof(SERIAL_COMMPROP) == sizeof(COMMPROP));
  1357. //
  1358. // Get the total length of what to pass down. If the
  1359. // application indicates that there is provider specific data
  1360. // (by setting dwProvSpec1 to COMMPROP_INITIAILIZED) then
  1361. // use what's at the start of the commprop.
  1362. //
  1363. bufferLength = sizeof(COMMPROP);
  1364. if (lpCommProp->dwProvSpec1 == COMMPROP_INITIALIZED) {
  1365. bufferLength = lpCommProp->wPacketLength;
  1366. }
  1367. //
  1368. // Zero out the commprop. This might create an access violation
  1369. // if it isn't big enough. Which is ok, since we would rather
  1370. // get it before we create the sync event.
  1371. //
  1372. RtlZeroMemory(lpCommProp, bufferLength);
  1373. if (!(SyncEvent = CreateEvent(
  1374. NULL,
  1375. TRUE,
  1376. FALSE,
  1377. NULL
  1378. ))) {
  1379. return FALSE;
  1380. }
  1381. Status = NtDeviceIoControlFile(
  1382. hFile,
  1383. SyncEvent,
  1384. NULL,
  1385. NULL,
  1386. &Iosb,
  1387. IOCTL_SERIAL_GET_PROPERTIES,
  1388. NULL,
  1389. 0,
  1390. lpCommProp,
  1391. bufferLength
  1392. );
  1393. if ( Status == STATUS_PENDING) {
  1394. // Operation must complete before return & IoStatusBlock destroyed
  1395. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  1396. if ( NT_SUCCESS(Status)) {
  1397. Status = Iosb.Status;
  1398. }
  1399. }
  1400. if (NT_ERROR(Status)) {
  1401. CloseHandle(SyncEvent);
  1402. BaseSetLastNTError(Status);
  1403. return FALSE;
  1404. }
  1405. CloseHandle(SyncEvent);
  1406. return TRUE;
  1407. }
  1408. BOOL
  1409. GetCommState(
  1410. HANDLE hFile,
  1411. LPDCB lpDCB
  1412. )
  1413. /*++
  1414. Routine Description:
  1415. This function fills the buffer pointed to by the lpDCB parameter with
  1416. the device control block of the communication device specified by hFile
  1417. parameter.
  1418. Arguments:
  1419. hFile - Specifies the communication device to be examined.
  1420. The CreateFile function returns this value.
  1421. lpDCB - Points to the DCB data structure that is to receive the current
  1422. device control block. The structure defines the control settings
  1423. for the device.
  1424. Return Value:
  1425. The return value is TRUE if the function is successful or FALSE
  1426. if an error occurs.
  1427. --*/
  1428. {
  1429. SERIAL_BAUD_RATE LocalBaud;
  1430. SERIAL_LINE_CONTROL LineControl;
  1431. SERIAL_CHARS Chars;
  1432. SERIAL_HANDFLOW HandFlow;
  1433. IO_STATUS_BLOCK Iosb;
  1434. NTSTATUS Status;
  1435. //
  1436. // Given the possiblity that the app may be doing asynchronous
  1437. // io we need an event to wait on.
  1438. //
  1439. // We need to make sure that any exit to this routine closes this
  1440. // event handle.
  1441. //
  1442. HANDLE SyncEvent;
  1443. //
  1444. // Make sure the windows mapping is the same as the NT mapping.
  1445. //
  1446. ASSERT((ONESTOPBIT == STOP_BIT_1) &&
  1447. (ONE5STOPBITS == STOP_BITS_1_5) &&
  1448. (TWOSTOPBITS == STOP_BITS_2));
  1449. ASSERT((NOPARITY == NO_PARITY) &&
  1450. (ODDPARITY == ODD_PARITY) &&
  1451. (EVENPARITY == EVEN_PARITY) &&
  1452. (MARKPARITY == MARK_PARITY) &&
  1453. (SPACEPARITY == SPACE_PARITY));
  1454. //
  1455. // Zero out the dcb. This might create an access violation
  1456. // if it isn't big enough. Which is ok, since we would rather
  1457. // get it before we create the sync event.
  1458. //
  1459. RtlZeroMemory(lpDCB, sizeof(DCB));
  1460. lpDCB->DCBlength = sizeof(DCB);
  1461. lpDCB->fBinary = TRUE;
  1462. if (!(SyncEvent = CreateEvent(
  1463. NULL,
  1464. TRUE,
  1465. FALSE,
  1466. NULL
  1467. ))) {
  1468. return FALSE;
  1469. }
  1470. Status = NtDeviceIoControlFile(
  1471. hFile,
  1472. SyncEvent,
  1473. NULL,
  1474. NULL,
  1475. &Iosb,
  1476. IOCTL_SERIAL_GET_BAUD_RATE,
  1477. NULL,
  1478. 0,
  1479. &LocalBaud,
  1480. sizeof(LocalBaud)
  1481. );
  1482. if ( Status == STATUS_PENDING) {
  1483. // Operation must complete before return & IoStatusBlock destroyed
  1484. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  1485. if ( NT_SUCCESS(Status)) {
  1486. Status = Iosb.Status;
  1487. }
  1488. }
  1489. if (NT_ERROR(Status)) {
  1490. CloseHandle(SyncEvent);
  1491. BaseSetLastNTError(Status);
  1492. return FALSE;
  1493. }
  1494. lpDCB->BaudRate = LocalBaud.BaudRate;
  1495. Status = NtDeviceIoControlFile(
  1496. hFile,
  1497. SyncEvent,
  1498. NULL,
  1499. NULL,
  1500. &Iosb,
  1501. IOCTL_SERIAL_GET_LINE_CONTROL,
  1502. NULL,
  1503. 0,
  1504. &LineControl,
  1505. sizeof(LineControl)
  1506. );
  1507. if ( Status == STATUS_PENDING) {
  1508. // Operation must complete before return & IoStatusBlock destroyed
  1509. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  1510. if ( NT_SUCCESS(Status)) {
  1511. Status = Iosb.Status;
  1512. }
  1513. }
  1514. if (NT_ERROR(Status)) {
  1515. CloseHandle(SyncEvent);
  1516. BaseSetLastNTError(Status);
  1517. return FALSE;
  1518. }
  1519. lpDCB->Parity = LineControl.Parity;
  1520. lpDCB->ByteSize = LineControl.WordLength;
  1521. lpDCB->StopBits = LineControl.StopBits;
  1522. Status = NtDeviceIoControlFile(
  1523. hFile,
  1524. SyncEvent,
  1525. NULL,
  1526. NULL,
  1527. &Iosb,
  1528. IOCTL_SERIAL_GET_CHARS,
  1529. NULL,
  1530. 0,
  1531. &Chars,
  1532. sizeof(Chars)
  1533. );
  1534. if ( Status == STATUS_PENDING) {
  1535. // Operation must complete before return & IoStatusBlock destroyed
  1536. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  1537. if ( NT_SUCCESS(Status)) {
  1538. Status = Iosb.Status;
  1539. }
  1540. }
  1541. if (NT_ERROR(Status)) {
  1542. CloseHandle(SyncEvent);
  1543. BaseSetLastNTError(Status);
  1544. return FALSE;
  1545. }
  1546. lpDCB->XonChar = Chars.XonChar;
  1547. lpDCB->XoffChar = Chars.XoffChar;
  1548. lpDCB->ErrorChar = Chars.ErrorChar;
  1549. lpDCB->EofChar = Chars.EofChar;
  1550. lpDCB->EvtChar = Chars.EventChar;
  1551. Status = NtDeviceIoControlFile(
  1552. hFile,
  1553. SyncEvent,
  1554. NULL,
  1555. NULL,
  1556. &Iosb,
  1557. IOCTL_SERIAL_GET_HANDFLOW,
  1558. NULL,
  1559. 0,
  1560. &HandFlow,
  1561. sizeof(HandFlow)
  1562. );
  1563. if ( Status == STATUS_PENDING) {
  1564. // Operation must complete before return & IoStatusBlock destroyed
  1565. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  1566. if ( NT_SUCCESS(Status)) {
  1567. Status = Iosb.Status;
  1568. }
  1569. }
  1570. if (NT_ERROR(Status)) {
  1571. CloseHandle(SyncEvent);
  1572. BaseSetLastNTError(Status);
  1573. return FALSE;
  1574. }
  1575. if (HandFlow.ControlHandShake & SERIAL_CTS_HANDSHAKE) {
  1576. lpDCB->fOutxCtsFlow = TRUE;
  1577. }
  1578. if (HandFlow.ControlHandShake & SERIAL_DSR_HANDSHAKE) {
  1579. lpDCB->fOutxDsrFlow = TRUE;
  1580. }
  1581. if (HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) {
  1582. lpDCB->fOutX = TRUE;
  1583. }
  1584. if (HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) {
  1585. lpDCB->fInX = TRUE;
  1586. }
  1587. if (HandFlow.FlowReplace & SERIAL_NULL_STRIPPING) {
  1588. lpDCB->fNull = TRUE;
  1589. }
  1590. if (HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
  1591. lpDCB->fErrorChar = TRUE;
  1592. }
  1593. if (HandFlow.FlowReplace & SERIAL_XOFF_CONTINUE) {
  1594. lpDCB->fTXContinueOnXoff = TRUE;
  1595. }
  1596. if (HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
  1597. lpDCB->fAbortOnError = TRUE;
  1598. }
  1599. switch (HandFlow.FlowReplace & SERIAL_RTS_MASK) {
  1600. case 0:
  1601. lpDCB->fRtsControl = RTS_CONTROL_DISABLE;
  1602. break;
  1603. case SERIAL_RTS_CONTROL:
  1604. lpDCB->fRtsControl = RTS_CONTROL_ENABLE;
  1605. break;
  1606. case SERIAL_RTS_HANDSHAKE:
  1607. lpDCB->fRtsControl = RTS_CONTROL_HANDSHAKE;
  1608. break;
  1609. case SERIAL_TRANSMIT_TOGGLE:
  1610. lpDCB->fRtsControl = RTS_CONTROL_TOGGLE;
  1611. break;
  1612. }
  1613. switch (HandFlow.ControlHandShake & SERIAL_DTR_MASK) {
  1614. case 0:
  1615. lpDCB->fDtrControl = DTR_CONTROL_DISABLE;
  1616. break;
  1617. case SERIAL_DTR_CONTROL:
  1618. lpDCB->fDtrControl = DTR_CONTROL_ENABLE;
  1619. break;
  1620. case SERIAL_DTR_HANDSHAKE:
  1621. lpDCB->fDtrControl = DTR_CONTROL_HANDSHAKE;
  1622. break;
  1623. }
  1624. lpDCB->fDsrSensitivity =
  1625. (HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY)?(TRUE):(FALSE);
  1626. lpDCB->XonLim = (WORD)HandFlow.XonLimit;
  1627. lpDCB->XoffLim = (WORD)HandFlow.XoffLimit;
  1628. CloseHandle(SyncEvent);
  1629. return TRUE;
  1630. }
  1631. BOOL
  1632. GetCommTimeouts(
  1633. HANDLE hFile,
  1634. LPCOMMTIMEOUTS lpCommTimeouts
  1635. )
  1636. /*++
  1637. Routine Description:
  1638. This function returns the timeout characteristics for all read and
  1639. write operations on the handle specified by hFile.
  1640. Arguments:
  1641. hFile - Specifies the communication device to be examined.
  1642. The CreateFile function returns this value.
  1643. lpCommTimeouts - Points to a structure which is to receive the
  1644. current communications timeouts.
  1645. Return Value:
  1646. The return value is TRUE if the function is successful or FALSE
  1647. if an error occurs.
  1648. --*/
  1649. {
  1650. SERIAL_TIMEOUTS To;
  1651. NTSTATUS Status;
  1652. IO_STATUS_BLOCK Iosb;
  1653. HANDLE Event;
  1654. if (!(Event = CreateEvent(
  1655. NULL,
  1656. TRUE,
  1657. FALSE,
  1658. NULL
  1659. ))) {
  1660. return FALSE;
  1661. } else {
  1662. Status = NtDeviceIoControlFile(
  1663. hFile,
  1664. Event,
  1665. NULL,
  1666. NULL,
  1667. &Iosb,
  1668. IOCTL_SERIAL_GET_TIMEOUTS,
  1669. NULL,
  1670. 0,
  1671. &To,
  1672. sizeof(To)
  1673. );
  1674. if ( Status == STATUS_PENDING) {
  1675. // Operation must complete before return & IoStatusBlock destroyed
  1676. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  1677. if ( NT_SUCCESS( Status )) {
  1678. Status = Iosb.Status;
  1679. }
  1680. }
  1681. if (NT_ERROR(Status)) {
  1682. BaseSetLastNTError(Status);
  1683. CloseHandle(Event);
  1684. return FALSE;
  1685. }
  1686. CloseHandle(Event);
  1687. //
  1688. // Everything went ok. Move the value from the Nt records
  1689. // to the windows record.
  1690. //
  1691. lpCommTimeouts->ReadIntervalTimeout = To.ReadIntervalTimeout;
  1692. lpCommTimeouts->ReadTotalTimeoutMultiplier = To.ReadTotalTimeoutMultiplier;
  1693. lpCommTimeouts->ReadTotalTimeoutConstant = To.ReadTotalTimeoutConstant;
  1694. lpCommTimeouts->WriteTotalTimeoutMultiplier = To.WriteTotalTimeoutMultiplier;
  1695. lpCommTimeouts->WriteTotalTimeoutConstant = To.WriteTotalTimeoutConstant;
  1696. return TRUE;
  1697. }
  1698. }
  1699. BOOL
  1700. PurgeComm(
  1701. HANDLE hFile,
  1702. DWORD dwFlags
  1703. )
  1704. /*++
  1705. Routine Description:
  1706. This function is used to purge all characters from the transmit
  1707. or receive queues of the communication device specified by the
  1708. hFile parameter. The dwFlags parameter specifies what function
  1709. is to be performed.
  1710. Arguments:
  1711. hFile - Specifies the communication device to be purged.
  1712. The CreateFile function returns this value.
  1713. dwFlags - Bit mask defining actions to be taken.
  1714. Return Value:
  1715. The return value is TRUE if the function is successful or FALSE
  1716. if an error occurs.
  1717. --*/
  1718. {
  1719. HANDLE Event;
  1720. NTSTATUS Status;
  1721. IO_STATUS_BLOCK Iosb;
  1722. if (!(Event = CreateEvent(
  1723. NULL,
  1724. TRUE,
  1725. FALSE,
  1726. NULL
  1727. ))) {
  1728. return FALSE;
  1729. } else {
  1730. Status = NtDeviceIoControlFile(
  1731. hFile,
  1732. Event,
  1733. NULL,
  1734. NULL,
  1735. &Iosb,
  1736. IOCTL_SERIAL_PURGE,
  1737. &dwFlags,
  1738. sizeof(ULONG),
  1739. NULL,
  1740. 0
  1741. );
  1742. if ( Status == STATUS_PENDING) {
  1743. // Operation must complete before return & IoStatusBlock destroyed
  1744. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  1745. if ( NT_SUCCESS( Status )) {
  1746. Status = Iosb.Status;
  1747. }
  1748. }
  1749. if (NT_ERROR(Status)) {
  1750. CloseHandle(Event);
  1751. BaseSetLastNTError(Status);
  1752. return FALSE;
  1753. }
  1754. CloseHandle(Event);
  1755. return TRUE;
  1756. }
  1757. }
  1758. BOOL
  1759. SetCommBreak(
  1760. HANDLE hFile
  1761. )
  1762. /*++
  1763. Routine Description:
  1764. The function suspends character transmission and places the transmission
  1765. line in a break state until the break condition is cleared..
  1766. Arguments:
  1767. hFile - Specifies the communication device to be suspended.
  1768. The CreateFile function returns this value.
  1769. Return Value:
  1770. The return value is TRUE if the function is successful or FALSE
  1771. if an error occurs.
  1772. --*/
  1773. {
  1774. return EscapeCommFunction(hFile,SETBREAK);
  1775. }
  1776. BOOL
  1777. SetCommConfig(
  1778. HANDLE hCommDev,
  1779. LPCOMMCONFIG lpCC,
  1780. DWORD dwSize
  1781. )
  1782. {
  1783. NTSTATUS Status;
  1784. IO_STATUS_BLOCK Iosb;
  1785. HANDLE Event;
  1786. LPCOMMCONFIG comConf = lpCC;
  1787. if (lpCC->dwProviderOffset) {
  1788. if (!(Event = CreateEvent(
  1789. NULL,
  1790. TRUE,
  1791. FALSE,
  1792. NULL
  1793. ))) {
  1794. return FALSE;
  1795. }
  1796. //
  1797. //
  1798. // Call the driver to set the config structure.
  1799. //
  1800. Status = NtDeviceIoControlFile(
  1801. hCommDev,
  1802. Event,
  1803. NULL,
  1804. NULL,
  1805. &Iosb,
  1806. IOCTL_SERIAL_SET_COMMCONFIG,
  1807. lpCC,
  1808. dwSize,
  1809. NULL,
  1810. 0
  1811. );
  1812. if ( Status == STATUS_PENDING) {
  1813. // Operation must complete before return & IoStatusBlock destroyed
  1814. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  1815. if ( NT_SUCCESS(Status)) {
  1816. Status = Iosb.Status;
  1817. }
  1818. }
  1819. if (NT_ERROR(Status)) {
  1820. CloseHandle(Event);
  1821. BaseSetLastNTError(Status);
  1822. return FALSE;
  1823. }
  1824. CloseHandle(Event);
  1825. }
  1826. return SetCommState(
  1827. hCommDev,
  1828. &comConf->dcb
  1829. );
  1830. }
  1831. BOOL
  1832. SetCommMask(
  1833. HANDLE hFile,
  1834. DWORD dwEvtMask
  1835. )
  1836. /*++
  1837. Routine Description:
  1838. The function enables the event mask of the communication device
  1839. specified by the hFile parameter. The bits of the nEvtMask parameter
  1840. define which events are to be enabled.
  1841. Arguments:
  1842. hFile - Specifies the communication device to receive the settings.
  1843. The CreateFile function returns this value.
  1844. dwEvtMask - Specifies which events are to enabled.
  1845. Return Value:
  1846. The return value is TRUE if the function is successful or FALSE
  1847. if an error occurs.
  1848. --*/
  1849. {
  1850. NTSTATUS Status;
  1851. IO_STATUS_BLOCK Iosb;
  1852. HANDLE Event;
  1853. //
  1854. // First we do an assert to make sure that the
  1855. // values in the win header files are the same
  1856. // as the nt serial interface and the the size
  1857. // mask that serial expects is the same as the
  1858. // size that win32 expects.
  1859. //
  1860. ASSERT((SERIAL_EV_RXCHAR == EV_RXCHAR ) &&
  1861. (SERIAL_EV_RXFLAG == EV_RXFLAG ) &&
  1862. (SERIAL_EV_TXEMPTY == EV_TXEMPTY ) &&
  1863. (SERIAL_EV_CTS == EV_CTS ) &&
  1864. (SERIAL_EV_DSR == EV_DSR ) &&
  1865. (SERIAL_EV_RLSD == EV_RLSD ) &&
  1866. (SERIAL_EV_BREAK == EV_BREAK ) &&
  1867. (SERIAL_EV_ERR == EV_ERR ) &&
  1868. (SERIAL_EV_RING == EV_RING ) &&
  1869. (SERIAL_EV_PERR == EV_PERR ) &&
  1870. (SERIAL_EV_RX80FULL == EV_RX80FULL) &&
  1871. (SERIAL_EV_EVENT1 == EV_EVENT1 ) &&
  1872. (SERIAL_EV_EVENT2 == EV_EVENT2 ) &&
  1873. (sizeof(DWORD) == sizeof(ULONG)));
  1874. //
  1875. // Make sure that the users mask doesn't contain any values
  1876. // we don't support.
  1877. //
  1878. if (dwEvtMask & (~(EV_RXCHAR |
  1879. EV_RXFLAG |
  1880. EV_TXEMPTY |
  1881. EV_CTS |
  1882. EV_DSR |
  1883. EV_RLSD |
  1884. EV_BREAK |
  1885. EV_ERR |
  1886. EV_RING |
  1887. EV_PERR |
  1888. EV_RX80FULL |
  1889. EV_EVENT1 |
  1890. EV_EVENT2))) {
  1891. SetLastError(ERROR_INVALID_DATA);
  1892. return FALSE;
  1893. }
  1894. if (!(Event = CreateEvent(
  1895. NULL,
  1896. TRUE,
  1897. FALSE,
  1898. NULL
  1899. ))) {
  1900. return FALSE;
  1901. } else {
  1902. //
  1903. // All is well, send the mask to the driver.
  1904. //
  1905. ULONG LocalMask = dwEvtMask;
  1906. Status = NtDeviceIoControlFile(
  1907. hFile,
  1908. Event,
  1909. NULL,
  1910. NULL,
  1911. &Iosb,
  1912. IOCTL_SERIAL_SET_WAIT_MASK,
  1913. &LocalMask,
  1914. sizeof(ULONG),
  1915. NULL,
  1916. 0
  1917. );
  1918. if ( Status == STATUS_PENDING) {
  1919. // Operation must complete before return & IoStatusBlock destroyed
  1920. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  1921. if ( NT_SUCCESS( Status )) {
  1922. Status = Iosb.Status;
  1923. }
  1924. }
  1925. if (NT_ERROR(Status)) {
  1926. CloseHandle(Event);
  1927. BaseSetLastNTError(Status);
  1928. return FALSE;
  1929. }
  1930. CloseHandle(Event);
  1931. return TRUE;
  1932. }
  1933. }
  1934. BOOL
  1935. SetCommState(
  1936. HANDLE hFile,
  1937. LPDCB lpDCB
  1938. )
  1939. /*++
  1940. Routine Description:
  1941. The SetCommState function sets a communication device to the state
  1942. specified in the lpDCB parameter. The device is identified by the
  1943. hFile parameter. This function reinitializes all hardwae and controls
  1944. as specified byt the lpDCB, but does not empty the transmit or
  1945. receive queues.
  1946. Arguments:
  1947. hFile - Specifies the communication device to receive the settings.
  1948. The CreateFile function returns this value.
  1949. lpDCB - Points to a DCB structure that contains the desired
  1950. communications setting for the device.
  1951. Return Value:
  1952. The return value is TRUE if the function is successful or FALSE
  1953. if an error occurs.
  1954. --*/
  1955. {
  1956. SERIAL_BAUD_RATE LocalBaud;
  1957. SERIAL_LINE_CONTROL LineControl;
  1958. SERIAL_CHARS Chars;
  1959. SERIAL_HANDFLOW HandFlow = {0};
  1960. IO_STATUS_BLOCK Iosb;
  1961. NTSTATUS Status;
  1962. //
  1963. // Keep a copy of what the DCB was like before we started
  1964. // changing things. If some error occurs we can use
  1965. // it to restore the old setup.
  1966. //
  1967. DCB OldDcb;
  1968. //
  1969. // Given the possiblity that the app may be doing asynchronous
  1970. // io we need an event to wait on. While it would be very
  1971. // strange to be setting the comm state while IO is active
  1972. // we need to make sure we don't compound the problem by
  1973. // returning before this API's IO is actually finished. This
  1974. // can happen because the file handle is set on the completion
  1975. // of any IO.
  1976. //
  1977. // We need to make sure that any exit to this routine closes this
  1978. // event handle.
  1979. //
  1980. HANDLE SyncEvent;
  1981. if (GetCommState(
  1982. hFile,
  1983. &OldDcb
  1984. )) {
  1985. //
  1986. // Try to set the baud rate. If we fail here, we just return
  1987. // because we never actually got to set anything.
  1988. //
  1989. if (!(SyncEvent = CreateEvent(
  1990. NULL,
  1991. TRUE,
  1992. FALSE,
  1993. NULL
  1994. ))) {
  1995. return FALSE;
  1996. }
  1997. LocalBaud.BaudRate = lpDCB->BaudRate;
  1998. Status = NtDeviceIoControlFile(
  1999. hFile,
  2000. SyncEvent,
  2001. NULL,
  2002. NULL,
  2003. &Iosb,
  2004. IOCTL_SERIAL_SET_BAUD_RATE,
  2005. &LocalBaud,
  2006. sizeof(LocalBaud),
  2007. NULL,
  2008. 0
  2009. );
  2010. if ( Status == STATUS_PENDING) {
  2011. // Operation must complete before return & IoStatusBlock destroyed
  2012. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  2013. if ( NT_SUCCESS(Status)) {
  2014. Status = Iosb.Status;
  2015. }
  2016. }
  2017. if (NT_ERROR(Status)) {
  2018. CloseHandle(SyncEvent);
  2019. BaseSetLastNTError(Status);
  2020. return FALSE;
  2021. }
  2022. LineControl.StopBits = lpDCB->StopBits;
  2023. LineControl.Parity = lpDCB->Parity;
  2024. LineControl.WordLength = lpDCB->ByteSize;
  2025. LocalBaud.BaudRate = lpDCB->BaudRate;
  2026. Chars.XonChar = lpDCB->XonChar;
  2027. Chars.XoffChar = lpDCB->XoffChar;
  2028. Chars.ErrorChar = lpDCB->ErrorChar;
  2029. Chars.BreakChar = lpDCB->ErrorChar;
  2030. Chars.EofChar = lpDCB->EofChar;
  2031. Chars.EventChar = lpDCB->EvtChar;
  2032. HandFlow.FlowReplace &= ~SERIAL_RTS_MASK;
  2033. switch (lpDCB->fRtsControl) {
  2034. case RTS_CONTROL_DISABLE:
  2035. break;
  2036. case RTS_CONTROL_ENABLE:
  2037. HandFlow.FlowReplace |= SERIAL_RTS_CONTROL;
  2038. break;
  2039. case RTS_CONTROL_HANDSHAKE:
  2040. HandFlow.FlowReplace |= SERIAL_RTS_HANDSHAKE;
  2041. break;
  2042. case RTS_CONTROL_TOGGLE:
  2043. HandFlow.FlowReplace |= SERIAL_TRANSMIT_TOGGLE;
  2044. break;
  2045. default:
  2046. SetCommState(
  2047. hFile,
  2048. &OldDcb
  2049. );
  2050. CloseHandle(SyncEvent);
  2051. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  2052. return FALSE;
  2053. }
  2054. HandFlow.ControlHandShake &= ~SERIAL_DTR_MASK;
  2055. switch (lpDCB->fDtrControl) {
  2056. case DTR_CONTROL_DISABLE:
  2057. break;
  2058. case DTR_CONTROL_ENABLE:
  2059. HandFlow.ControlHandShake |= SERIAL_DTR_CONTROL;
  2060. break;
  2061. case DTR_CONTROL_HANDSHAKE:
  2062. HandFlow.ControlHandShake |= SERIAL_DTR_HANDSHAKE;
  2063. break;
  2064. default:
  2065. SetCommState(
  2066. hFile,
  2067. &OldDcb
  2068. );
  2069. CloseHandle(SyncEvent);
  2070. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  2071. return FALSE;
  2072. }
  2073. if (lpDCB->fDsrSensitivity) {
  2074. HandFlow.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
  2075. }
  2076. if (lpDCB->fOutxCtsFlow) {
  2077. HandFlow.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
  2078. }
  2079. if (lpDCB->fOutxDsrFlow) {
  2080. HandFlow.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
  2081. }
  2082. if (lpDCB->fOutX) {
  2083. HandFlow.FlowReplace |= SERIAL_AUTO_TRANSMIT;
  2084. }
  2085. if (lpDCB->fInX) {
  2086. HandFlow.FlowReplace |= SERIAL_AUTO_RECEIVE;
  2087. }
  2088. if (lpDCB->fNull) {
  2089. HandFlow.FlowReplace |= SERIAL_NULL_STRIPPING;
  2090. }
  2091. if (lpDCB->fErrorChar) {
  2092. HandFlow.FlowReplace |= SERIAL_ERROR_CHAR;
  2093. }
  2094. if (lpDCB->fTXContinueOnXoff) {
  2095. HandFlow.FlowReplace |= SERIAL_XOFF_CONTINUE;
  2096. }
  2097. if (lpDCB->fAbortOnError) {
  2098. HandFlow.ControlHandShake |= SERIAL_ERROR_ABORT;
  2099. }
  2100. //
  2101. // For win95 compatiblity, if we are setting with
  2102. // xxx_control_XXXXXXX then set the modem status line
  2103. // to that state.
  2104. //
  2105. if (lpDCB->fRtsControl == RTS_CONTROL_ENABLE) {
  2106. EscapeCommFunction(
  2107. hFile,
  2108. SETRTS
  2109. );
  2110. } else if (lpDCB->fRtsControl == RTS_CONTROL_DISABLE) {
  2111. EscapeCommFunction(
  2112. hFile,
  2113. CLRRTS
  2114. );
  2115. }
  2116. if (lpDCB->fDtrControl == DTR_CONTROL_ENABLE) {
  2117. EscapeCommFunction(
  2118. hFile,
  2119. SETDTR
  2120. );
  2121. } else if (lpDCB->fDtrControl == DTR_CONTROL_DISABLE) {
  2122. EscapeCommFunction(
  2123. hFile,
  2124. CLRDTR
  2125. );
  2126. }
  2127. HandFlow.XonLimit = lpDCB->XonLim;
  2128. HandFlow.XoffLimit = lpDCB->XoffLim;
  2129. Status = NtDeviceIoControlFile(
  2130. hFile,
  2131. SyncEvent,
  2132. NULL,
  2133. NULL,
  2134. &Iosb,
  2135. IOCTL_SERIAL_SET_LINE_CONTROL,
  2136. &LineControl,
  2137. sizeof(LineControl),
  2138. NULL,
  2139. 0
  2140. );
  2141. if ( Status == STATUS_PENDING) {
  2142. // Operation must complete before return & IoStatusBlock destroyed
  2143. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  2144. if ( NT_SUCCESS(Status)) {
  2145. Status = Iosb.Status;
  2146. }
  2147. }
  2148. if (NT_ERROR(Status)) {
  2149. CloseHandle(SyncEvent);
  2150. SetCommState(
  2151. hFile,
  2152. &OldDcb
  2153. );
  2154. BaseSetLastNTError(Status);
  2155. return FALSE;
  2156. }
  2157. Status = NtDeviceIoControlFile(
  2158. hFile,
  2159. SyncEvent,
  2160. NULL,
  2161. NULL,
  2162. &Iosb,
  2163. IOCTL_SERIAL_SET_CHARS,
  2164. &Chars,
  2165. sizeof(Chars),
  2166. NULL,
  2167. 0
  2168. );
  2169. if ( Status == STATUS_PENDING) {
  2170. // Operation must complete before return & IoStatusBlock destroyed
  2171. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  2172. if ( NT_SUCCESS(Status)) {
  2173. Status = Iosb.Status;
  2174. }
  2175. }
  2176. if (NT_ERROR(Status)) {
  2177. CloseHandle(SyncEvent);
  2178. SetCommState(
  2179. hFile,
  2180. &OldDcb
  2181. );
  2182. BaseSetLastNTError(Status);
  2183. return FALSE;
  2184. }
  2185. Status = NtDeviceIoControlFile(
  2186. hFile,
  2187. SyncEvent,
  2188. NULL,
  2189. NULL,
  2190. &Iosb,
  2191. IOCTL_SERIAL_SET_HANDFLOW,
  2192. &HandFlow,
  2193. sizeof(HandFlow),
  2194. NULL,
  2195. 0
  2196. );
  2197. if ( Status == STATUS_PENDING) {
  2198. // Operation must complete before return & IoStatusBlock destroyed
  2199. Status = NtWaitForSingleObject( SyncEvent, FALSE, NULL );
  2200. if ( NT_SUCCESS(Status)) {
  2201. Status = Iosb.Status;
  2202. }
  2203. }
  2204. if (NT_ERROR(Status)) {
  2205. CloseHandle(SyncEvent);
  2206. SetCommState(
  2207. hFile,
  2208. &OldDcb
  2209. );
  2210. BaseSetLastNTError(Status);
  2211. return FALSE;
  2212. }
  2213. CloseHandle(SyncEvent);
  2214. return TRUE;
  2215. }
  2216. return FALSE;
  2217. }
  2218. BOOL
  2219. SetCommTimeouts(
  2220. HANDLE hFile,
  2221. LPCOMMTIMEOUTS lpCommTimeouts
  2222. )
  2223. /*++
  2224. Routine Description:
  2225. This function establishes the timeout characteristics for all
  2226. read and write operations on the handle specified by hFile.
  2227. Arguments:
  2228. hFile - Specifies the communication device to receive the settings.
  2229. The CreateFile function returns this value.
  2230. lpCommTimeouts - Points to a structure containing timeout parameters.
  2231. Return Value:
  2232. The return value is TRUE if the function is successful or FALSE
  2233. if an error occurs.
  2234. --*/
  2235. {
  2236. SERIAL_TIMEOUTS To;
  2237. NTSTATUS Status;
  2238. IO_STATUS_BLOCK Iosb;
  2239. HANDLE Event;
  2240. To.ReadIntervalTimeout = lpCommTimeouts->ReadIntervalTimeout;
  2241. To.ReadTotalTimeoutMultiplier = lpCommTimeouts->ReadTotalTimeoutMultiplier;
  2242. To.ReadTotalTimeoutConstant = lpCommTimeouts->ReadTotalTimeoutConstant;
  2243. To.WriteTotalTimeoutMultiplier = lpCommTimeouts->WriteTotalTimeoutMultiplier;
  2244. To.WriteTotalTimeoutConstant = lpCommTimeouts->WriteTotalTimeoutConstant;
  2245. if (!(Event = CreateEvent(
  2246. NULL,
  2247. TRUE,
  2248. FALSE,
  2249. NULL
  2250. ))) {
  2251. return FALSE;
  2252. } else {
  2253. Status = NtDeviceIoControlFile(
  2254. hFile,
  2255. Event,
  2256. NULL,
  2257. NULL,
  2258. &Iosb,
  2259. IOCTL_SERIAL_SET_TIMEOUTS,
  2260. &To,
  2261. sizeof(To),
  2262. NULL,
  2263. 0
  2264. );
  2265. if ( Status == STATUS_PENDING) {
  2266. // Operation must complete before return & IoStatusBlock destroyed
  2267. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  2268. if ( NT_SUCCESS(Status)) {
  2269. Status = Iosb.Status;
  2270. }
  2271. }
  2272. if (NT_ERROR(Status)) {
  2273. CloseHandle(Event);
  2274. BaseSetLastNTError(Status);
  2275. return FALSE;
  2276. }
  2277. CloseHandle(Event);
  2278. return TRUE;
  2279. }
  2280. }
  2281. BOOL
  2282. TransmitCommChar(
  2283. HANDLE hFile,
  2284. char cChar
  2285. )
  2286. /*++
  2287. Routine Description:
  2288. The function marks the character specified by the cChar parameter
  2289. for immediate transmission, by placing it at the head of the transmit
  2290. queue.
  2291. Arguments:
  2292. hFile - Specifies the communication device to send the character.
  2293. The CreateFile function returns this value.
  2294. cChar - Specifies the character to be placed in the recieve queue.
  2295. Return Value:
  2296. The return value is TRUE if the function is successful or FALSE
  2297. if an error occurs.
  2298. --*/
  2299. {
  2300. NTSTATUS Status;
  2301. IO_STATUS_BLOCK Iosb;
  2302. HANDLE Event;
  2303. if (!(Event = CreateEvent(
  2304. NULL,
  2305. TRUE,
  2306. FALSE,
  2307. NULL
  2308. ))) {
  2309. return FALSE;
  2310. } else {
  2311. Status = NtDeviceIoControlFile(
  2312. hFile,
  2313. Event,
  2314. NULL,
  2315. NULL,
  2316. &Iosb,
  2317. IOCTL_SERIAL_IMMEDIATE_CHAR,
  2318. &cChar,
  2319. sizeof(UCHAR),
  2320. NULL,
  2321. 0
  2322. );
  2323. if ( Status == STATUS_PENDING) {
  2324. // Operation must complete before return & IoStatusBlock destroyed
  2325. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  2326. if ( NT_SUCCESS(Status)) {
  2327. Status = Iosb.Status;
  2328. }
  2329. }
  2330. if (NT_ERROR(Status)) {
  2331. CloseHandle(Event);
  2332. BaseSetLastNTError(Status);
  2333. return FALSE;
  2334. }
  2335. CloseHandle(Event);
  2336. return TRUE;
  2337. }
  2338. }
  2339. BOOL
  2340. WaitCommEvent(
  2341. HANDLE hFile,
  2342. LPDWORD lpEvtMask,
  2343. LPOVERLAPPED lpOverlapped
  2344. )
  2345. /*++
  2346. Routine Description:
  2347. This function will wait until any of the events occur that were
  2348. provided as the nEvtMask parameter to SetcommMask. If while waiting
  2349. the event mask is changed (via another call to SetCommMask), the
  2350. function will return immediately. The function will fill the EvtMask
  2351. pointed to by the lpEvtMask parameter with the reasons that the
  2352. wait was satisfied.
  2353. Arguments:
  2354. hFile - Specifies the communication device to be waited on.
  2355. The CreateFile function returns this value.
  2356. lpEvtMask - Points to a mask that will receive the reason that
  2357. the wait was satisfied.
  2358. lpOverLapped - An optional overlapped handle.
  2359. Return Value:
  2360. The return value is TRUE if the function is successful or FALSE
  2361. if an error occurs.
  2362. --*/
  2363. {
  2364. NTSTATUS Status;
  2365. if (ARGUMENT_PRESENT(lpOverlapped)) {
  2366. lpOverlapped->Internal = (DWORD)STATUS_PENDING;
  2367. Status = NtDeviceIoControlFile(
  2368. hFile,
  2369. lpOverlapped->hEvent,
  2370. NULL,
  2371. (ULONG_PTR)lpOverlapped->hEvent & 1 ? NULL : lpOverlapped,
  2372. (PIO_STATUS_BLOCK)&lpOverlapped->Internal,
  2373. IOCTL_SERIAL_WAIT_ON_MASK,
  2374. NULL,
  2375. 0,
  2376. lpEvtMask,
  2377. sizeof(ULONG)
  2378. );
  2379. if (!NT_ERROR(Status) && (Status != STATUS_PENDING)) {
  2380. return TRUE;
  2381. } else {
  2382. BaseSetLastNTError(Status);
  2383. return FALSE;
  2384. }
  2385. } else {
  2386. IO_STATUS_BLOCK Iosb;
  2387. HANDLE Event;
  2388. if (!(Event = CreateEvent(
  2389. NULL,
  2390. TRUE,
  2391. FALSE,
  2392. NULL
  2393. ))) {
  2394. return FALSE;
  2395. } else {
  2396. Status = NtDeviceIoControlFile(
  2397. hFile,
  2398. Event,
  2399. NULL,
  2400. NULL,
  2401. &Iosb,
  2402. IOCTL_SERIAL_WAIT_ON_MASK,
  2403. NULL,
  2404. 0,
  2405. lpEvtMask,
  2406. sizeof(ULONG)
  2407. );
  2408. if ( Status == STATUS_PENDING) {
  2409. //
  2410. // Operation must complete before return &
  2411. // IoStatusBlock destroyed
  2412. Status = NtWaitForSingleObject( Event, FALSE, NULL );
  2413. if ( NT_SUCCESS(Status)) {
  2414. Status = Iosb.Status;
  2415. }
  2416. }
  2417. CloseHandle(Event);
  2418. if (NT_ERROR(Status)) {
  2419. BaseSetLastNTError(Status);
  2420. return FALSE;
  2421. }
  2422. return TRUE;
  2423. }
  2424. }
  2425. }