Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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