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.

1080 lines
26 KiB

  1. /*++
  2. Copyright (c) 1998 Gemplus developpement
  3. Name:
  4. GNTSER.C (Gemplus Win NT SERial port management)
  5. Description :
  6. This module holds the functions needed for a communication on a serial line.
  7. Environment:
  8. Kernel mode
  9. Revision History :
  10. dd/mm/yy
  11. 13/03/98: V1.00.001 (GPZ)
  12. - Start of development.
  13. 26/04/98: V1.00.002 (GPZ)
  14. 22/01/99: V1.00.003 (YN)
  15. - Remove the IRPCancel durnig call the serial driver
  16. --*/
  17. #include <stdio.h>
  18. #include "gntscr.h"
  19. #include "gntser.h"
  20. //
  21. // Type section:
  22. // TPORT_CONFIG:
  23. // - WaitRelease holds the timeout for the release of the semaphore.
  24. // - Counter holds the number of opened session. If its value is 0, the port is
  25. // closed.
  26. // - Error holds Rx over state.
  27. // - TimeOut holds the character level time out.
  28. // - TxSize memorises the transmit buffer size.
  29. // - RxSize memorises the reception buffer size.
  30. // - pSerialPortDevice is a pointer on the serial Device Object.
  31. //
  32. typedef struct
  33. {
  34. ULONG WaitRelease;
  35. USHORT Counter;
  36. short Error;
  37. ULONG TimeOut;
  38. USHORT TxSize;
  39. USHORT RxSize;
  40. PDEVICE_OBJECT pSerialPortDevice;
  41. PKMUTEX pExchangeMutex;
  42. } TPORT_CONFIG;
  43. #define GTSER_DEF_WAIT_RELEASE 2000
  44. #define GTSER_IOCTL_WRITE SCARD_CTL_CODE(1001)
  45. #define GTSER_IOCTL_READ SCARD_CTL_CODE(1000)
  46. //
  47. // Macro section:
  48. // - WORD_LEN, PARITY and STOP retreive the configuration values to pass to
  49. // Windows to configure the port.
  50. //
  51. #define WORD_LEN(x) (BYTE)(((x) & 0x03) + 5)
  52. #define PARITY(x) (BYTE)(parity[((BYTE)(x) >> 3) & 3])
  53. #define STOP(x) (BYTE)(stop[((x) >> 2) & 1])
  54. //
  55. // Global variable section:
  56. // - port_config is an array of TPORT_CONFIG which memorises the port
  57. // configuration at each time.
  58. //
  59. TPORT_CONFIG
  60. port_config[HGTSER_MAX_PORT] =
  61. {
  62. {0,0,0,0,0,0,NULL,NULL},
  63. {0,0,0,0,0,0,NULL,NULL},
  64. {0,0,0,0,0,0,NULL,NULL},
  65. {0,0,0,0,0,0,NULL,NULL}
  66. };
  67. static USHORT
  68. parity[] = {
  69. NO_PARITY,
  70. ODD_PARITY,
  71. NO_PARITY,
  72. EVEN_PARITY
  73. };
  74. static USHORT
  75. stop[] = {
  76. STOP_BIT_1,
  77. STOP_BITS_2
  78. };
  79. //
  80. // Local function definition section:
  81. //
  82. static NTSTATUS GDDKNT_GetCommStatus
  83. (
  84. const SHORT Handle,
  85. SERIAL_STATUS *SerialStatus
  86. );
  87. NTSTATUS
  88. GDDK_SerPortOpen(
  89. const TGTSER_PORT *Param,
  90. SHORT *Handle
  91. )
  92. /*++
  93. Routine Description:
  94. This routine opens a serial port and initializes it according to the
  95. parameters found in Param.
  96. Arguments:
  97. Param holds the following parameters:
  98. - Port indicates the selected port.
  99. - BaudRate is used to set port baud rate.
  100. - Mode gathers
  101. * word size WORD_5 (0), WORD_6 (1), WORD_7 (2) or WORD_8 (3),
  102. * stop bit number STOP_BIT_1 (0) or STOP_BIT_2 (4) and
  103. * parity NO_PARITY (0), ODD_PARITY (8) or EVEN_PARITY (24).
  104. - TxSize is the transmit buffer size, in bytes.
  105. - RxSize is the reception buffer size, in bytes.
  106. --*/
  107. {
  108. NTSTATUS status;
  109. PSMARTCARD_EXTENSION SmartcardExtension;
  110. SERIAL_READER_CONFIG SerialConfig;
  111. PREADER_EXTENSION pReaderExtension;
  112. SERIAL_QUEUE_SIZE SerialQueueSize;
  113. USHORT LengthOut = 0;
  114. SHORT handle = Param->Port - 1;
  115. // Controls the given parameters:
  116. if ((handle < 0) || (handle >= HGTSER_MAX_PORT)) {
  117. return STATUS_INVALID_PARAMETER;
  118. }
  119. if (port_config[handle].Counter != 0) {
  120. return STATUS_DEVICE_ALREADY_ATTACHED;
  121. }
  122. // Retrieve the SmartcardExtension structure of the current device.
  123. SmartcardExtension = (PSMARTCARD_EXTENSION)(Param->pSmartcardExtension);
  124. pReaderExtension = SmartcardExtension->ReaderExtension;
  125. port_config[handle].pSerialPortDevice = pReaderExtension->AttachedDeviceObject;
  126. port_config[handle].pExchangeMutex = &pReaderExtension->ExchangeMutex;
  127. // The current port state is read and stored in current_dcb structure by
  128. // calling GetCommState function.
  129. // If the reading is possible (GetCommState return 0)
  130. // Then
  131. // The current_dcb structure is updated with the given parameter (baud
  132. // rate, ByteSize, Parity, StopBits).
  133. // The modified state is written by calling SetCommState.
  134. status = GDDKNT_GetCommState(handle,&SerialConfig);
  135. if (NT_SUCCESS(status))
  136. {
  137. SerialQueueSize.InSize = 4096L;
  138. SerialQueueSize.OutSize = 4096L;
  139. status = GDDKNT_SerPortIoRequest(
  140. handle,
  141. IOCTL_SERIAL_SET_QUEUE_SIZE,
  142. 500UL,
  143. sizeof(SERIAL_QUEUE_SIZE),
  144. (PUCHAR)&SerialQueueSize,
  145. &LengthOut,
  146. NULL
  147. );
  148. // Set the serial port communication parameters
  149. SerialConfig.BaudRate.BaudRate = Param->BaudRate;
  150. SerialConfig.LineControl.WordLength = WORD_LEN(Param->Mode);
  151. SerialConfig.LineControl.Parity = PARITY(Param->Mode);
  152. SerialConfig.LineControl.StopBits = STOP(Param->Mode);
  153. // Set timeouts
  154. SerialConfig.Timeouts.ReadIntervalTimeout = 1000;
  155. SerialConfig.Timeouts.ReadTotalTimeoutConstant = 50000;
  156. SerialConfig.Timeouts.ReadTotalTimeoutMultiplier = 0; // 50;
  157. // Set special characters
  158. SerialConfig.SerialChars.ErrorChar = 0;
  159. SerialConfig.SerialChars.EofChar = 0;
  160. SerialConfig.SerialChars.EventChar = 0;
  161. SerialConfig.SerialChars.XonChar = 0;
  162. SerialConfig.SerialChars.XoffChar = 0;
  163. SerialConfig.SerialChars.BreakChar = 0xFF;
  164. // Set handflow
  165. SerialConfig.HandFlow.XonLimit = 0;
  166. SerialConfig.HandFlow.XoffLimit = 0;
  167. SerialConfig.HandFlow.FlowReplace = SERIAL_XOFF_CONTINUE ;
  168. SerialConfig.HandFlow.ControlHandShake = 0;
  169. status = GDDKNT_SetCommState(handle,&SerialConfig);
  170. }
  171. if (!NT_SUCCESS(status)) {
  172. return status;
  173. }
  174. // Memorises the given parameters in port_config structure.
  175. // Counter, Error, TimeOut, TxSize and RxSize fields are updated.
  176. port_config[handle].Counter = 1;
  177. port_config[handle].Error = 0;
  178. port_config[handle].TimeOut = Param->TimeOut;
  179. port_config[handle].TxSize = Param->TxSize;
  180. port_config[handle].RxSize = Param->RxSize;
  181. // We update the handle value.
  182. *Handle = handle;
  183. return STATUS_SUCCESS;
  184. }
  185. NTSTATUS
  186. GDDK_SerPortAddUser(
  187. const SHORT Port,
  188. SHORT *Handle
  189. )
  190. /*++
  191. Routine Description:
  192. Add a new user on a port. This function return the handle of a previously
  193. opened port.
  194. When this function is successful, it is mandatory to call G_SerPortClose
  195. to decrement the user number.
  196. Arguments:
  197. Port - indicates the selected port: G_COMx
  198. Return Value:
  199. --*/
  200. {
  201. // Controls the given parameters:
  202. if ((Port < G_COM1) || (Port > G_COM4)) {
  203. return STATUS_INVALID_PARAMETER;
  204. }
  205. if (port_config[Port - 1].Counter == 0) {
  206. return STATUS_PORT_DISCONNECTED;
  207. }
  208. if (port_config[Port - 1].Counter == 65535lu) {
  209. return STATUS_INSUFFICIENT_RESOURCES;
  210. }
  211. // Increments the port_config.Counter.
  212. port_config[Port - 1].Counter += 1;
  213. // We return the Port number.
  214. *Handle = Port - 1;
  215. return STATUS_SUCCESS;
  216. }
  217. NTSTATUS
  218. GDDK_SerPortClose (
  219. const SHORT Handle
  220. )
  221. /*++
  222. Routine Description:
  223. This routine closes a previously opened serial port.
  224. When port is shared, the close will be effective only when all clients will
  225. have closed the port.
  226. Arguments:
  227. Handle - holds the port handle.
  228. Return Value:
  229. --*/
  230. {
  231. // Controls the given parameters:
  232. if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
  233. return STATUS_INVALID_PARAMETER;
  234. }
  235. if (port_config[Handle].Counter == 0) {
  236. return STATUS_PORT_DISCONNECTED;
  237. }
  238. // Decrements the port_config.Counter field.
  239. port_config[Handle].Counter -= 1;
  240. // Closes really the port for the last user:
  241. // The queues are flushed.
  242. if (port_config[Handle].Counter == 0) {
  243. GDDK_SerPortFlush(Handle,SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_TXABORT);
  244. }
  245. return STATUS_SUCCESS;
  246. }
  247. NTSTATUS
  248. GDDK_SerPortWrite(
  249. const SHORT Handle,
  250. const USHORT Length,
  251. const BYTE Buffer[]
  252. )
  253. /*++
  254. Routine Description:
  255. This routine writes bytes on a previously opened serial port.
  256. Arguments:
  257. Handle - holds the port handle.
  258. Length - holds the number of bytes to write.
  259. Buffer - holds the bytes to write.
  260. Return Value:
  261. --*/
  262. {
  263. NTSTATUS status;
  264. SERIAL_STATUS SerialStatus;
  265. USHORT LengthOut;
  266. ASSERT(Buffer != NULL);
  267. // Controls the given parameters:
  268. if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
  269. return STATUS_INVALID_PARAMETER;
  270. }
  271. if (port_config[Handle].Counter == 0) {
  272. return STATUS_PORT_DISCONNECTED;
  273. }
  274. // Control if the write can be made in one time:
  275. // The windows port status is read by calling GetCommError to know how many
  276. // bytes remain in Tx queue (port_config.Error field is updated if needed).
  277. status = GDDKNT_GetCommStatus(Handle,&SerialStatus);
  278. ASSERT(status == STATUS_SUCCESS);
  279. if (status != STATUS_SUCCESS) {
  280. return status;
  281. }
  282. port_config[Handle].Error |= (USHORT)(SERIAL_ERROR_OVERRUN & SerialStatus.Errors);
  283. if (Length > ( port_config[Handle].TxSize - SerialStatus.AmountInOutQueue)) {
  284. return STATUS_INVALID_PARAMETER;
  285. }
  286. // Writes the given byte in Tx queue .
  287. // If an error occurs during this operation
  288. // Then
  289. // The ClearCommError function is called to unblock the port
  290. // (port_config.Error field is updated if needed).
  291. LengthOut = 0;
  292. status = GDDKNT_SerPortIoRequest(
  293. Handle,
  294. GTSER_IOCTL_WRITE,
  295. 500UL,
  296. Length,
  297. Buffer,
  298. &LengthOut,
  299. NULL
  300. );
  301. if (!NT_SUCCESS(status)) {
  302. GDDKNT_GetCommStatus(Handle,&SerialStatus);
  303. port_config[Handle].Error |= (USHORT)(SERIAL_ERROR_OVERRUN & SerialStatus.Errors);
  304. LengthOut = 0;
  305. status = GDDKNT_SerPortIoRequest(
  306. Handle,
  307. IOCTL_SERIAL_RESET_DEVICE,
  308. 500UL,
  309. 0,
  310. NULL,
  311. &LengthOut,
  312. NULL
  313. );
  314. return STATUS_PORT_DISCONNECTED;
  315. }
  316. return STATUS_SUCCESS;
  317. }
  318. NTSTATUS
  319. GDDK_SerPortRead(
  320. const SHORT Handle,
  321. USHORT *Length,
  322. BYTE Buffer[]
  323. )
  324. /*++
  325. Routine Description:
  326. This routine reads bytes on a previously opened serial port.
  327. It ends when required length = read length or when a character level timeout
  328. is detected.
  329. Arguments:
  330. Handle - holds the port handle.
  331. Length - holds the number of bytes to read.
  332. Buffer - is a free area of, at least, Length bytes.
  333. Return Value:
  334. --*/
  335. {
  336. NTSTATUS status;
  337. ASSERT(Buffer != NULL);
  338. // Controls the given parameters:
  339. if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
  340. return STATUS_INVALID_PARAMETER;
  341. }
  342. if (port_config[Handle].Counter == 0) {
  343. *Length = 0;
  344. return STATUS_PORT_DISCONNECTED;
  345. }
  346. // Try to read the bytes.
  347. status = GDDKNT_SerPortIoRequest(
  348. Handle,
  349. GTSER_IOCTL_READ,
  350. port_config[Handle].TimeOut,
  351. 0,
  352. NULL,
  353. Length,
  354. Buffer
  355. );
  356. if (!NT_SUCCESS(status)) {
  357. return status;
  358. } else {
  359. if (*Length == 0) {
  360. return STATUS_INVALID_DEVICE_STATE;
  361. }
  362. }
  363. return STATUS_SUCCESS;
  364. }
  365. NTSTATUS
  366. GDDK_SerPortFlush(
  367. const SHORT Handle,
  368. const USHORT Select
  369. )
  370. /*++
  371. Routine Description:
  372. This function clears Tx and Rx buffers.
  373. When RX_QUEUE is selected, the RX_OVER flag is reseted.
  374. Arguments:
  375. Handle - holds the port handle.
  376. Select - holds the buffers to clear:
  377. Return Value:
  378. --*/
  379. {
  380. NTSTATUS status;
  381. USHORT LengthOut = 0;
  382. ULONG PurgeMask;
  383. // Controls the given parameters:
  384. if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
  385. return STATUS_INVALID_PARAMETER;
  386. }
  387. if (port_config[Handle].Counter == 0) {
  388. return STATUS_PORT_DISCONNECTED;
  389. }
  390. // Clears the selected queues
  391. if (Select & HGTSER_TX_QUEUE) {
  392. PurgeMask = SERIAL_PURGE_TXCLEAR;
  393. }
  394. if (Select & HGTSER_RX_QUEUE) {
  395. PurgeMask = SERIAL_PURGE_RXCLEAR;
  396. port_config[Handle].Error = 0;
  397. }
  398. status = GDDKNT_SerPortIoRequest(
  399. Handle,
  400. IOCTL_SERIAL_PURGE,
  401. 500UL,
  402. sizeof(PurgeMask),
  403. (PUCHAR)&PurgeMask,
  404. &LengthOut,
  405. NULL
  406. );
  407. return STATUS_SUCCESS;
  408. }
  409. NTSTATUS
  410. GDDK_SerPortGetState(
  411. const SHORT Handle,
  412. TGTSER_PORT *Param,
  413. USHORT *UserNb
  414. )
  415. /*++
  416. Routine Description:
  417. This routine read the currently in use parameters for an opened serial port.
  418. Arguments:
  419. Handle - holds the port handle.
  420. Param - is a pointer on the Param structure.
  421. UserNb - is a pointer on the number of user for this port.
  422. Return Value:
  423. --*/
  424. {
  425. NTSTATUS status;
  426. SERIAL_READER_CONFIG SerialConfig;
  427. ASSERT(Param != NULL);
  428. ASSERT(UserNb != NULL);
  429. // Controls the given parameters:
  430. if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
  431. return STATUS_INVALID_PARAMETER;
  432. }
  433. if (port_config[Handle].Counter == 0) {
  434. return STATUS_PORT_DISCONNECTED;
  435. }
  436. // The current port state is read and stored in current_dcb structure by calling
  437. // GetCommState function.
  438. status = GDDKNT_GetCommState(Handle,&SerialConfig);
  439. if (!NT_SUCCESS(status)) {
  440. return status;
  441. }
  442. // The parameters are updated with the read values.
  443. Param->BaudRate = SerialConfig.BaudRate.BaudRate;
  444. switch (SerialConfig.LineControl.WordLength) {
  445. case 5:
  446. Param->Mode = HGTSER_WORD_5;
  447. break;
  448. case 6:
  449. Param->Mode = HGTSER_WORD_6;
  450. break;
  451. case 7:
  452. Param->Mode = HGTSER_WORD_7;
  453. break;
  454. case 8:
  455. Param->Mode = HGTSER_WORD_8;
  456. break;
  457. default:
  458. return STATUS_INVALID_DEVICE_STATE;
  459. }
  460. switch (SerialConfig.LineControl.Parity) {
  461. case NO_PARITY:
  462. Param->Mode |= HGTSER_NO_PARITY;
  463. break;
  464. case ODD_PARITY:
  465. Param->Mode |= HGTSER_ODD_PARITY;
  466. break;
  467. case EVEN_PARITY:
  468. Param->Mode |= HGTSER_EVEN_PARITY;
  469. break;
  470. case SERIAL_PARITY_MARK:
  471. case SERIAL_PARITY_SPACE:
  472. default:
  473. return STATUS_INVALID_DEVICE_STATE;
  474. }
  475. switch (SerialConfig.LineControl.StopBits) {
  476. case STOP_BIT_1:
  477. Param->Mode |= HGTSER_STOP_BIT_1;
  478. break;
  479. case STOP_BITS_2:
  480. Param->Mode |= HGTSER_STOP_BIT_2;
  481. break;
  482. case STOP_BITS_1_5:
  483. default:
  484. return STATUS_INVALID_DEVICE_STATE;
  485. }
  486. // Updates the library fields TimeOut, TxSize and RxSize.
  487. Param->TimeOut = port_config[Handle].TimeOut;
  488. Param->TxSize = port_config[Handle].TxSize;
  489. Param->RxSize = port_config[Handle].RxSize;
  490. // The UserNb parameter is filled with the port_config.Counter.
  491. *UserNb = port_config[Handle].Counter;
  492. return STATUS_SUCCESS;
  493. }
  494. NTSTATUS
  495. GDDK_SerPortSetState(
  496. const SHORT Handle,
  497. TGTSER_PORT *Param
  498. )
  499. /*++
  500. Routine Description:
  501. This routine alters the currently in use parameters for an opened serial port.
  502. Arguments:
  503. Handle - holds the port handle.
  504. Param - is a pointer on the Param structure.
  505. Return Value:
  506. --*/
  507. {
  508. NTSTATUS status;
  509. SERIAL_READER_CONFIG SerialConfig;
  510. ULONG error = 0;
  511. ASSERT(Param != NULL);
  512. // Controls the given parameters:
  513. if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
  514. return STATUS_INVALID_PARAMETER;
  515. }
  516. if (port_config[Handle].Counter == 0) {
  517. return STATUS_PORT_DISCONNECTED;
  518. }
  519. status = GDDKNT_GetCommState(Handle,&SerialConfig);
  520. if (NT_SUCCESS(status))
  521. {
  522. SerialConfig.BaudRate.BaudRate = Param->BaudRate;
  523. SerialConfig.LineControl.WordLength = WORD_LEN(Param->Mode);
  524. SerialConfig.LineControl.Parity = PARITY(Param->Mode);
  525. SerialConfig.LineControl.StopBits = STOP(Param->Mode);
  526. status = GDDKNT_SetCommState(Handle,&SerialConfig);
  527. }
  528. if (!NT_SUCCESS(status)) {
  529. return status;
  530. }
  531. // Updates the library fields TimeOut, TxSize and RxSize.
  532. port_config[Handle].TimeOut = Param->TimeOut;
  533. port_config[Handle].TxSize = Param->TxSize;
  534. port_config[Handle].RxSize = Param->RxSize;
  535. return status;
  536. }
  537. BOOLEAN
  538. GDDK_SerPortLockComm(
  539. const SHORT Handle,
  540. const ULONG WaitRelease
  541. )
  542. /*++
  543. Routine Description:
  544. Take the mutex for a serial port communication if is free or wait
  545. the release
  546. Arguments:
  547. Handle - holds the port handle
  548. WaitRelease - holds the new time to wait the release
  549. Return Value:
  550. --*/
  551. {
  552. NTSTATUS status;
  553. LARGE_INTEGER timeout;
  554. // Controls the given parameters:
  555. if ((Handle < 0) || (Handle >= HGTSER_MAX_PORT)) {
  556. return FALSE;
  557. }
  558. timeout.QuadPart = -((LONGLONG)(
  559. port_config[Handle].WaitRelease > GTSER_DEF_WAIT_RELEASE ?
  560. port_config[Handle].WaitRelease : GTSER_DEF_WAIT_RELEASE)*10*1000);
  561. status = KeWaitForMutexObject(
  562. port_config[Handle].pExchangeMutex,
  563. Executive,
  564. KernelMode,
  565. FALSE,
  566. &timeout
  567. );
  568. if (status != STATUS_SUCCESS) {
  569. return FALSE;
  570. } else {
  571. port_config[Handle].WaitRelease = WaitRelease;
  572. return TRUE;
  573. }
  574. }
  575. VOID
  576. GDDK_SerPortUnlockComm(
  577. const SHORT Handle
  578. )
  579. /*++
  580. Routine Description:
  581. Release the mutex for a serial port communication.
  582. Arguments:
  583. Handle - holds the port handle
  584. Return Value:
  585. --*/
  586. {
  587. NTSTATUS status;
  588. // Controls the given parameters:
  589. if ((Handle >= 0) && (Handle < HGTSER_MAX_PORT)) {
  590. status = KeReleaseMutex(port_config[Handle].pExchangeMutex,FALSE);
  591. }
  592. }
  593. NTSTATUS
  594. GDDKNT_SerPortIoRequest(
  595. CONST SHORT Handle,
  596. CONST ULONG SerialIoControlCode,
  597. CONST ULONG CmdTimeout,
  598. CONST USHORT LengthIn,
  599. CONST BYTE *BufferIn,
  600. USHORT *pLengthOut,
  601. BYTE *BufferOut
  602. )
  603. /*++
  604. Routine Description:
  605. This function sends an IOCTL's to the serial driver. It waits on for their
  606. completion, and then returns.
  607. Arguments:
  608. Handle - holds the port handle
  609. Return Value:
  610. --*/
  611. {
  612. NTSTATUS status;
  613. PIRP irp;
  614. PIO_STACK_LOCATION irpNextStack;
  615. IO_STATUS_BLOCK ioStatus;
  616. KEVENT event;
  617. KeInitializeEvent(&event,NotificationEvent,FALSE);
  618. // Build an Irp to be send to serial driver
  619. irp = IoBuildDeviceIoControlRequest(
  620. SerialIoControlCode,
  621. port_config[Handle].pSerialPortDevice,
  622. (PVOID)BufferIn,
  623. (ULONG)LengthIn,
  624. (PVOID)BufferOut,
  625. (ULONG)(*pLengthOut),
  626. FALSE,
  627. &event,
  628. &ioStatus
  629. );
  630. if (irp == NULL) {
  631. return STATUS_INSUFFICIENT_RESOURCES;
  632. }
  633. irpNextStack = IoGetNextIrpStackLocation(irp);
  634. switch (SerialIoControlCode) {
  635. case GTSER_IOCTL_WRITE:
  636. irpNextStack->MajorFunction = IRP_MJ_WRITE;
  637. irpNextStack->Parameters.Write.Length = (ULONG)LengthIn;
  638. break;
  639. case GTSER_IOCTL_READ:
  640. irpNextStack->MajorFunction = IRP_MJ_READ;
  641. irpNextStack->Parameters.Read.Length = (ULONG)(*pLengthOut);
  642. break;
  643. }
  644. // Call the serial driver
  645. status = IoCallDriver(
  646. port_config[Handle].pSerialPortDevice,
  647. irp
  648. );
  649. if (status == STATUS_PENDING) {
  650. // Wait until the serial driver has processed the Irp
  651. status = KeWaitForSingleObject(
  652. &event,
  653. Suspended,
  654. KernelMode,
  655. FALSE,
  656. NULL
  657. );
  658. //ASSERT(status == STATUS_SUCCESS);
  659. }
  660. if(status == STATUS_SUCCESS)
  661. {
  662. status = ioStatus.Status;
  663. switch (SerialIoControlCode) {
  664. case GTSER_IOCTL_WRITE:
  665. if (ioStatus.Status == STATUS_TIMEOUT) {
  666. // STATUS_TIMEOUT isn't correctly mapped
  667. // to a WIN32 error, that's why we change it here to STATUS_IO_TIMEOUT
  668. status = STATUS_IO_TIMEOUT;
  669. }
  670. break;
  671. case GTSER_IOCTL_READ:
  672. if (ioStatus.Status == STATUS_TIMEOUT) {
  673. // STATUS_TIMEOUT isn't correctly mapped
  674. // to a WIN32 error, that's why we change it here to STATUS_IO_TIMEOUT
  675. status = STATUS_IO_TIMEOUT;
  676. *pLengthOut = 0;
  677. }
  678. break;
  679. default:
  680. *pLengthOut = (USHORT)(ioStatus.Information);
  681. break;
  682. }
  683. }
  684. return status;
  685. }
  686. NTSTATUS
  687. GDDKNT_SetCommState(
  688. const SHORT Handle,
  689. SERIAL_READER_CONFIG *SerialConfig
  690. )
  691. /*++
  692. Routine Description:
  693. This routine will appropriately configure the serial port.
  694. It makes synchronous calls to the serial port.
  695. Arguments:
  696. Handle - holds the port handle
  697. SerialConfig - holds the configuration to set.
  698. Return Value:
  699. --*/
  700. {
  701. NTSTATUS status = STATUS_SUCCESS;
  702. USHORT i;
  703. ULONG SerialIoControlCode;
  704. USHORT LengthIn,LengthOut;
  705. PUCHAR pBufferIn;
  706. ASSERT(SerialConfig != NULL);
  707. for (i=0; NT_SUCCESS(status); i++) {
  708. switch (i) {
  709. case 0:
  710. // Set up baudrate
  711. SerialIoControlCode = IOCTL_SERIAL_SET_BAUD_RATE;
  712. pBufferIn = (PUCHAR)&SerialConfig->BaudRate;
  713. LengthIn = sizeof(SERIAL_BAUD_RATE);
  714. break;
  715. case 1:
  716. // Set up line control parameters
  717. SerialIoControlCode = IOCTL_SERIAL_SET_LINE_CONTROL;
  718. pBufferIn = (PUCHAR)&SerialConfig->LineControl;
  719. LengthIn = sizeof(SERIAL_LINE_CONTROL);
  720. break;
  721. case 2:
  722. // Set serial special characters
  723. SerialIoControlCode = IOCTL_SERIAL_SET_CHARS;
  724. pBufferIn = (PUCHAR)&SerialConfig->SerialChars;
  725. LengthIn = sizeof(SERIAL_CHARS);
  726. break;
  727. case 3:
  728. // Set up timeouts
  729. SerialIoControlCode = IOCTL_SERIAL_SET_TIMEOUTS;
  730. pBufferIn = (PUCHAR)&SerialConfig->Timeouts;
  731. LengthIn = sizeof(SERIAL_TIMEOUTS);
  732. break;
  733. case 4:
  734. // Set flowcontrol and handshaking
  735. SerialIoControlCode = IOCTL_SERIAL_SET_HANDFLOW;
  736. pBufferIn = (PUCHAR)&SerialConfig->HandFlow;
  737. LengthIn = sizeof(SERIAL_HANDFLOW);
  738. break;
  739. case 5:
  740. // Set break off
  741. SerialIoControlCode = IOCTL_SERIAL_SET_BREAK_OFF;
  742. LengthIn = 0;
  743. break;
  744. case 6:
  745. // Set DTR
  746. SerialIoControlCode = IOCTL_SERIAL_SET_DTR;
  747. LengthIn = 0;
  748. break;
  749. case 7:
  750. // Set RTS
  751. SerialIoControlCode = IOCTL_SERIAL_SET_RTS;
  752. LengthIn = 0;
  753. break;
  754. case 8:
  755. return STATUS_SUCCESS;
  756. }
  757. LengthOut = 0;
  758. status = GDDKNT_SerPortIoRequest(Handle,
  759. SerialIoControlCode,
  760. 500UL,
  761. LengthIn,
  762. pBufferIn,
  763. &LengthOut,
  764. NULL
  765. );
  766. }
  767. return status;
  768. }
  769. NTSTATUS
  770. GDDKNT_GetCommState(
  771. const SHORT Handle,
  772. SERIAL_READER_CONFIG *SerialConfig
  773. )
  774. /*++
  775. Routine Description:
  776. This routine will get the configuration of the serial port.
  777. It makes synchronous calls to the serial port.
  778. Arguments:
  779. Handle - holds the port handle
  780. SerialConfig - holds the configuration of the serial port.
  781. Return Value:
  782. --*/
  783. {
  784. NTSTATUS status = STATUS_SUCCESS;
  785. USHORT i;
  786. ULONG SerialIoControlCode;
  787. USHORT LengthOut;
  788. PUCHAR pBufferOut;
  789. ASSERT(SerialConfig != NULL);
  790. for (i=0; NT_SUCCESS(status); i++) {
  791. switch (i) {
  792. case 0:
  793. // Get up baudrate
  794. SerialIoControlCode = IOCTL_SERIAL_GET_BAUD_RATE;
  795. pBufferOut = (PUCHAR)&SerialConfig->BaudRate;
  796. LengthOut = sizeof(SERIAL_BAUD_RATE);
  797. break;
  798. case 1:
  799. // Get up line control parameters
  800. SerialIoControlCode = IOCTL_SERIAL_GET_LINE_CONTROL;
  801. pBufferOut = (PUCHAR)&SerialConfig->LineControl;
  802. LengthOut = sizeof(SERIAL_LINE_CONTROL);
  803. break;
  804. case 2:
  805. // Get serial special characters
  806. SerialIoControlCode = IOCTL_SERIAL_GET_CHARS;
  807. pBufferOut = (PUCHAR)&SerialConfig->SerialChars;
  808. LengthOut = sizeof(SERIAL_CHARS);
  809. break;
  810. case 3:
  811. // Get up timeouts
  812. SerialIoControlCode = IOCTL_SERIAL_GET_TIMEOUTS;
  813. pBufferOut = (PUCHAR)&SerialConfig->Timeouts;
  814. LengthOut = sizeof(SERIAL_TIMEOUTS);
  815. break;
  816. case 4:
  817. // Get flowcontrol and handshaking
  818. SerialIoControlCode = IOCTL_SERIAL_GET_HANDFLOW;
  819. pBufferOut = (PUCHAR)&SerialConfig->HandFlow;
  820. LengthOut = sizeof(SERIAL_HANDFLOW);
  821. break;
  822. case 5:
  823. return STATUS_SUCCESS;
  824. }
  825. status = GDDKNT_SerPortIoRequest(Handle,
  826. SerialIoControlCode,
  827. 500UL,
  828. 0,
  829. NULL,
  830. &LengthOut,
  831. pBufferOut
  832. );
  833. }
  834. return status;
  835. }
  836. static NTSTATUS
  837. GDDKNT_GetCommStatus(
  838. const SHORT Handle,
  839. SERIAL_STATUS *SerialStatus
  840. )
  841. /*++
  842. Routine Description:
  843. This routine will appropriately get status information of the serial port.
  844. It makes synchronous calls to the serial port.
  845. Arguments:
  846. Handle - holds the port handle
  847. SerialStatus - holds the status of the serial port.
  848. Return Value:
  849. --*/
  850. {
  851. NTSTATUS status = STATUS_SUCCESS;
  852. USHORT LengthOut;
  853. ASSERT(SerialStatus != NULL);
  854. LengthOut = sizeof(SERIAL_STATUS);
  855. status = GDDKNT_SerPortIoRequest(Handle,
  856. IOCTL_SERIAL_GET_COMMSTATUS,
  857. 500UL,
  858. 0,
  859. NULL,
  860. &LengthOut,
  861. (PUCHAR)SerialStatus
  862. );
  863. return status;
  864. }
  865. NTSTATUS SER_SetPortTimeout( const short Handle, ULONG Timeout)
  866. { // Controls the given parameters:
  867. short portcom;
  868. if(GDDK_GBPChannelToPortComm(Handle,&portcom)) return STATUS_INVALID_PARAMETER;
  869. port_config[portcom].TimeOut = Timeout;
  870. return STATUS_SUCCESS;
  871. }