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.

1677 lines
44 KiB

  1. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Copyright (c) 1991, 1992, 1993 Microsoft Corporation
  3. Module Name:
  4. ioctl.c
  5. Abstract:
  6. This module contains the ioctl dispatcher as well as a couple
  7. of routines that are generally just called in response to
  8. ioctl calls.
  9. Author:
  10. Anthony V. Ercolano 26-Sep-1991
  11. Environment:
  12. Kernel mode
  13. Revision History :
  14. -----------------------------------------------------------------------------*/
  15. #include "precomp.h"
  16. BOOLEAN SerialGetModemUpdate(IN PVOID Context);
  17. BOOLEAN SerialGetCommStatus(IN PVOID Context);
  18. VOID SerialGetProperties(IN PPORT_DEVICE_EXTENSION pPort, IN PSERIAL_COMMPROP Properties);
  19. BOOLEAN SerialSetEscapeChar(IN PVOID Context);
  20. #ifdef ALLOC_PRAGMA
  21. #endif
  22. BOOLEAN
  23. SerialGetStats(IN PVOID Context)
  24. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  25. Routine Description:
  26. In sync with the interrpt service routine (which sets the perf stats)
  27. return the perf stats to the caller.
  28. Arguments:
  29. Context - Pointer to a the irp.
  30. Return Value:
  31. This routine always returns FALSE.
  32. -----------------------------------------------------------------------------*/
  33. {
  34. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation((PIRP)Context);
  35. PPORT_DEVICE_EXTENSION pPort = irpSp->DeviceObject->DeviceExtension;
  36. PSERIALPERF_STATS sp = ((PIRP)Context)->AssociatedIrp.SystemBuffer;
  37. *sp = *((PSERIALPERF_STATS) &pPort->PerfStats);
  38. return FALSE;
  39. }
  40. BOOLEAN
  41. SerialClearStats(IN PVOID Context)
  42. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  43. Routine Description:
  44. In sync with the interrpt service routine (which sets the perf stats)
  45. clear the perf stats.
  46. Arguments:
  47. Context - Pointer to a the extension.
  48. Return Value:
  49. This routine always returns FALSE.
  50. -----------------------------------------------------------------------------*/
  51. {
  52. PPORT_DEVICE_EXTENSION pPort = (PPORT_DEVICE_EXTENSION)Context;
  53. RtlZeroMemory(&pPort->PerfStats, sizeof(SERIALPERF_STATS));
  54. #ifdef WMI_SUPPORT
  55. RtlZeroMemory(&pPort->WmiPerfData, sizeof(pPort->WmiPerfData));
  56. #endif
  57. return FALSE;
  58. }
  59. BOOLEAN
  60. SerialSetChars(IN PVOID Context)
  61. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  62. Routine Description:
  63. This routine is used to set the special characters for the driver.
  64. Arguments:
  65. Context - Pointer to a structure that contains a pointer to
  66. the device extension and a pointer to a special characters
  67. structure.
  68. Return Value:
  69. This routine always returns FALSE.
  70. -----------------------------------------------------------------------------*/
  71. {
  72. PPORT_DEVICE_EXTENSION pPort = ((PSERIAL_IOCTL_SYNC)Context)->pPort;
  73. pPort->SpecialChars = *((PSERIAL_CHARS)(((PSERIAL_IOCTL_SYNC)Context)->Data));
  74. pPort->UartConfig.XON = pPort->SpecialChars.XonChar;
  75. pPort->UartConfig.XOFF = pPort->SpecialChars.XoffChar;
  76. pPort->UartConfig.SpecialCharDetect = pPort->SpecialChars.EventChar;
  77. pPort->pUartLib->UL_SetConfig_XXXX(pPort->pUart, &pPort->UartConfig, UC_SPECIAL_CHARS_MASK);
  78. return FALSE;
  79. }
  80. BOOLEAN
  81. SerialSetBaud(IN PVOID Context)
  82. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  83. Routine Description:
  84. This routine is used to set the buad rate of the device.
  85. Arguments:
  86. Context - Pointer to a structure that contains a pointer to
  87. the device extension and what should be the current
  88. baud rate.
  89. Return Value:
  90. This routine returns TRUE if it succeeds otherwise FALSE.
  91. -----------------------------------------------------------------------------*/
  92. {
  93. PPORT_DEVICE_EXTENSION pPort = Context;
  94. if(pPort->pUartLib->UL_SetConfig_XXXX(pPort->pUart, &pPort->UartConfig, UC_TX_BAUD_RATE_MASK) == UL_STATUS_SUCCESS)
  95. {
  96. // If baud rate is 300 or less then reduce the Tx FIFO size.
  97. if(pPort->UartConfig.TxBaud <= 75)
  98. {
  99. pPort->BufferSizes.TxFIFOSize = 16;
  100. pPort->BufferSizes.TxFIFOTrigLevel = 4;
  101. }
  102. else if(pPort->UartConfig.TxBaud <= 300)
  103. {
  104. pPort->BufferSizes.TxFIFOSize = 32;
  105. pPort->BufferSizes.TxFIFOTrigLevel = 8;
  106. }
  107. else
  108. {
  109. pPort->BufferSizes.TxFIFOSize = pPort->TxFIFOSize;
  110. pPort->BufferSizes.TxFIFOTrigLevel = (BYTE) pPort->TxFIFOTrigLevel;
  111. }
  112. // Set Tx FIFO size.
  113. pPort->pUartLib->UL_BufferControl_XXXX(pPort->pUart, &pPort->BufferSizes, UL_BC_OP_SET, UL_BC_FIFO | UL_BC_OUT);
  114. return TRUE;
  115. }
  116. // It failed so lets revert the config settings back to those currently set.
  117. pPort->pUartLib->UL_GetConfig_XXXX(pPort->pUart, &pPort->UartConfig);
  118. return FALSE;
  119. }
  120. BOOLEAN
  121. SerialSetLineControl(IN PVOID Context)
  122. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  123. Routine Description:
  124. This routine is used to set the buad rate of the device.
  125. Arguments:
  126. Context - Pointer to the device extension.
  127. Return Value:
  128. This routine always returns FALSE.
  129. -----------------------------------------------------------------------------*/
  130. {
  131. PPORT_DEVICE_EXTENSION pPort = Context;
  132. pPort->pUartLib->UL_SetConfig_XXXX(pPort->pUart, &pPort->UartConfig, UC_FRAME_CONFIG_MASK);
  133. return FALSE;
  134. }
  135. BOOLEAN
  136. SerialGetModemUpdate(IN PVOID Context)
  137. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  138. Routine Description:
  139. This routine is simply used to call the interrupt level routine
  140. that handles modem status update.
  141. Arguments:
  142. Context - Pointer to a structure that contains a pointer to
  143. the device extension and a pointer to a ulong.
  144. Return Value:
  145. This routine always returns FALSE.
  146. -----------------------------------------------------------------------------*/
  147. {
  148. PPORT_DEVICE_EXTENSION pPort = ((PSERIAL_IOCTL_SYNC)Context)->pPort;
  149. ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);
  150. *Result = SerialHandleModemUpdate(pPort, FALSE);
  151. return FALSE;
  152. }
  153. BOOLEAN
  154. SerialGetCommStatus(IN PVOID Context)
  155. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  156. Routine Description:
  157. This is used to get the current state of the serial driver.
  158. Arguments:
  159. Context - Pointer to a structure that contains a pointer to
  160. the device extension and a pointer to a serial status
  161. record.
  162. Return Value:
  163. This routine always returns FALSE.
  164. -----------------------------------------------------------------------------*/
  165. {
  166. PPORT_DEVICE_EXTENSION pPort = ((PSERIAL_IOCTL_SYNC)Context)->pPort;
  167. PSERIAL_STATUS Stat = ((PSERIAL_IOCTL_SYNC)Context)->Data;
  168. GET_BUFFER_STATE BufferState;
  169. DWORD HoldingReasons = 0;
  170. Stat->Errors = pPort->ErrorWord;
  171. pPort->ErrorWord = 0;
  172. // BUG BUG We need to do something about eof (binary mode).
  173. Stat->EofReceived = FALSE;
  174. pPort->pUartLib->UL_BufferControl_XXXX(pPort->pUart, &BufferState, UL_BC_OP_GET, UL_BC_IN | UL_BC_BUFFER);
  175. Stat->AmountInInQueue = BufferState.BytesInINBuffer;
  176. Stat->AmountInOutQueue = pPort->TotalCharsQueued;
  177. if(pPort->WriteLength)
  178. {
  179. // By definition if we have a writelength, then we have a current write irp.
  180. ASSERT(pPort->CurrentWriteIrp);
  181. ASSERT(Stat->AmountInOutQueue >= pPort->WriteLength);
  182. ASSERT((IoGetCurrentIrpStackLocation(pPort->CurrentWriteIrp)->Parameters.Write.Length)
  183. >= pPort->WriteLength);
  184. Stat->AmountInOutQueue -= IoGetCurrentIrpStackLocation(pPort->CurrentWriteIrp)->Parameters.Write.Length
  185. - (pPort->WriteLength);
  186. }
  187. Stat->WaitForImmediate = pPort->TransmitImmediate;
  188. Stat->HoldReasons = 0;
  189. pPort->pUartLib->UL_GetStatus_XXXX(pPort->pUart, &HoldingReasons, UL_GS_OP_HOLDING_REASONS);
  190. // Transmit holding reasons
  191. if(HoldingReasons & UL_TX_WAITING_FOR_CTS)
  192. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS;
  193. if(HoldingReasons & UL_TX_WAITING_FOR_DSR)
  194. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DSR;
  195. if(HoldingReasons & UL_TX_WAITING_FOR_DCD)
  196. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DCD;
  197. if(HoldingReasons & UL_TX_WAITING_FOR_XON)
  198. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_XON;
  199. if(HoldingReasons & UL_TX_WAITING_ON_BREAK)
  200. Stat->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK;
  201. // Receive holding reasons
  202. if(HoldingReasons & UL_RX_WAITING_FOR_DSR)
  203. Stat->HoldReasons |= SERIAL_RX_WAITING_FOR_DSR;
  204. if(HoldingReasons & UL_TX_WAITING_XOFF_SENT)
  205. Stat->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT;
  206. return FALSE;
  207. }
  208. BOOLEAN
  209. SerialSetEscapeChar(IN PVOID Context)
  210. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  211. Routine Description:
  212. This is used to set the character that will be used to escape
  213. line status and modem status information when the application
  214. has set up that line status and modem status should be passed
  215. back in the data stream.
  216. Arguments:
  217. Context - Pointer to the irp that is specify the escape character.
  218. Implicitly - An escape character of 0 means no escaping
  219. will occur.
  220. Return Value:
  221. This routine always returns FALSE.
  222. -----------------------------------------------------------------------------*/
  223. {
  224. PPORT_DEVICE_EXTENSION pPort = IoGetCurrentIrpStackLocation((PIRP)Context)->DeviceObject->DeviceExtension;
  225. pPort->EscapeChar = *(PUCHAR)((PIRP)Context)->AssociatedIrp.SystemBuffer;
  226. return FALSE;
  227. }
  228. NTSTATUS
  229. SerialIoControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  230. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  231. Routine Description:
  232. This routine provides the initial processing for all of the
  233. Ioctrls for the serial device.
  234. Arguments:
  235. DeviceObject - Pointer to the device object for this device
  236. Irp - Pointer to the IRP for the current request
  237. Return Value:
  238. The function value is the final status of the call
  239. -----------------------------------------------------------------------------*/
  240. {
  241. // The status that gets returned to the caller and
  242. // set in the Irp.
  243. NTSTATUS Status;
  244. // The current stack location. This contains all of the
  245. // information we need to process this particular request.
  246. PIO_STACK_LOCATION IrpSp;
  247. // Just what it says. This is the serial specific device
  248. // extension of the device object create for the serial driver.
  249. PPORT_DEVICE_EXTENSION pPort = DeviceObject->DeviceExtension;
  250. // A temporary to hold the old IRQL so that it can be
  251. // restored once we complete/validate this request.
  252. KIRQL OldIrql;
  253. SerialDump(SERIRPPATH, ("Serial I/O Ctrl Dispatch entry for Irp: %x\n",Irp));
  254. SpxIRPCounter(pPort, Irp, IRP_SUBMITTED); // Increment counter for performance stats.
  255. if(SerialCompleteIfError(DeviceObject, Irp) != STATUS_SUCCESS)
  256. return STATUS_CANCELLED;
  257. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  258. Irp->IoStatus.Information = 0L;
  259. Status = STATUS_SUCCESS;
  260. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode)
  261. {
  262. case IOCTL_SERIAL_SET_BAUD_RATE:
  263. {
  264. ULONG BaudRate;
  265. // Will hold the value of the appropriate divisor for
  266. // the requested baud rate. If the baudrate is invalid
  267. // (because the device won't support that baud rate) then
  268. // this value is undefined.
  269. //
  270. // Note: in one sense the concept of a valid baud rate
  271. // is cloudy. We could allow the user to request any
  272. // baud rate. We could then calculate the divisor needed
  273. // for that baud rate. As long as the divisor wasn't less
  274. // than one we would be "ok". (The percentage difference
  275. // between the "true" divisor and the "rounded" value given
  276. // to the hardware might make it unusable, but... ) It would
  277. // really be up to the user to "Know" whether the baud rate
  278. // is suitable. So much for theory, *We* only support a given
  279. // set of baud rates.
  280. SHORT AppropriateDivisor;
  281. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE))
  282. {
  283. Status = STATUS_BUFFER_TOO_SMALL;
  284. break;
  285. }
  286. else
  287. {
  288. BaudRate = ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate;
  289. }
  290. // Get the baud rate from the irp. We pass it
  291. // to a routine which will set the correct divisor.
  292. pPort->UartConfig.TxBaud = BaudRate;
  293. SpxDbgMsg(BAUDINFO,("%s: Requested Baud Rate: %d\n", PRODUCT_NAME, BaudRate));
  294. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  295. if(KeSynchronizeExecution(pPort->Interrupt, SerialSetBaud, pPort))
  296. {
  297. Status = STATUS_SUCCESS;
  298. #ifdef WMI_SUPPORT
  299. pPort->WmiCommData.BaudRate = BaudRate;
  300. #endif
  301. }
  302. else
  303. {
  304. Status = STATUS_INVALID_PARAMETER;
  305. }
  306. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  307. break;
  308. }
  309. case IOCTL_SERIAL_GET_BAUD_RATE:
  310. {
  311. PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer;
  312. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE))
  313. {
  314. Status = STATUS_BUFFER_TOO_SMALL;
  315. break;
  316. }
  317. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  318. Br->BaudRate = pPort->UartConfig.TxBaud;
  319. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  320. Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);
  321. break;
  322. }
  323. case IOCTL_SERIAL_SET_LINE_CONTROL:
  324. {
  325. // Points to the line control record in the Irp.
  326. PSERIAL_LINE_CONTROL Lc = ((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer));
  327. ULONG FCData;
  328. ULONG FCStop;
  329. ULONG FCParity;
  330. UCHAR LData;
  331. UCHAR LStop;
  332. UCHAR LParity;
  333. UCHAR Mask = 0xff;
  334. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL))
  335. {
  336. Status = STATUS_BUFFER_TOO_SMALL;
  337. break;
  338. }
  339. switch(Lc->WordLength)
  340. {
  341. case 5:
  342. FCData = UC_FCFG_DATALEN_5;
  343. LData = SERIAL_5_DATA;
  344. Mask = 0x1f;
  345. break;
  346. case 6:
  347. FCData = UC_FCFG_DATALEN_6;
  348. LData = SERIAL_6_DATA;
  349. Mask = 0x3f;
  350. break;
  351. case 7:
  352. FCData = UC_FCFG_DATALEN_7;
  353. LData = SERIAL_7_DATA;
  354. Mask = 0x7f;
  355. break;
  356. case 8:
  357. FCData = UC_FCFG_DATALEN_8;
  358. LData = SERIAL_8_DATA;
  359. break;
  360. default:
  361. Status = STATUS_INVALID_PARAMETER;
  362. goto DoneWithIoctl;
  363. }
  364. switch(Lc->Parity)
  365. {
  366. case NO_PARITY:
  367. FCParity = UC_FCFG_NO_PARITY;
  368. LParity = SERIAL_NONE_PARITY;
  369. break;
  370. case EVEN_PARITY:
  371. FCParity = UC_FCFG_EVEN_PARITY;
  372. LParity = SERIAL_EVEN_PARITY;
  373. break;
  374. case ODD_PARITY:
  375. FCParity = UC_FCFG_ODD_PARITY;
  376. LParity = SERIAL_ODD_PARITY;
  377. break;
  378. case SPACE_PARITY:
  379. FCParity = UC_FCFG_SPACE_PARITY;
  380. LParity = SERIAL_SPACE_PARITY;
  381. break;
  382. case MARK_PARITY:
  383. FCParity = UC_FCFG_MARK_PARITY;
  384. LParity = SERIAL_MARK_PARITY;
  385. break;
  386. default:
  387. Status = STATUS_INVALID_PARAMETER;
  388. goto DoneWithIoctl;
  389. break;
  390. }
  391. switch(Lc->StopBits)
  392. {
  393. case STOP_BIT_1:
  394. FCStop = UC_FCFG_STOPBITS_1;
  395. LStop = SERIAL_1_STOP;
  396. break;
  397. case STOP_BITS_1_5:
  398. {
  399. if(LData != SERIAL_5_DATA)
  400. {
  401. Status = STATUS_INVALID_PARAMETER;
  402. goto DoneWithIoctl;
  403. }
  404. FCStop = UC_FCFG_STOPBITS_1_5;
  405. LStop = SERIAL_1_5_STOP;
  406. break;
  407. }
  408. case STOP_BITS_2:
  409. {
  410. if(LData == SERIAL_5_DATA)
  411. {
  412. Status = STATUS_INVALID_PARAMETER;
  413. goto DoneWithIoctl;
  414. }
  415. FCStop = UC_FCFG_STOPBITS_2;
  416. LStop = SERIAL_2_STOP;
  417. break;
  418. }
  419. default:
  420. Status = STATUS_INVALID_PARAMETER;
  421. goto DoneWithIoctl;
  422. }
  423. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  424. pPort->UartConfig.FrameConfig = (pPort->UartConfig.FrameConfig & ~UC_FCFG_DATALEN_MASK) | FCData;
  425. pPort->UartConfig.FrameConfig = (pPort->UartConfig.FrameConfig & ~UC_FCFG_PARITY_MASK) | FCParity;
  426. pPort->UartConfig.FrameConfig = (pPort->UartConfig.FrameConfig & ~UC_FCFG_STOPBITS_MASK) | FCStop;
  427. pPort->LineControl = (UCHAR)((pPort->LineControl & SERIAL_LCR_BREAK) | (LData | LParity | LStop));
  428. pPort->ValidDataMask = Mask;
  429. KeSynchronizeExecution(pPort->Interrupt, SerialSetLineControl, pPort);
  430. #ifdef WMI_SUPPORT
  431. UPDATE_WMI_LINE_CONTROL(pPort->WmiCommData, pPort->LineControl);
  432. #endif
  433. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  434. break;
  435. }
  436. case IOCTL_SERIAL_GET_LINE_CONTROL:
  437. {
  438. PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer;
  439. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL))
  440. {
  441. Status = STATUS_BUFFER_TOO_SMALL;
  442. break;
  443. }
  444. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  445. switch(pPort->UartConfig.FrameConfig & UC_FCFG_DATALEN_MASK)
  446. {
  447. case UC_FCFG_DATALEN_5:
  448. Lc->WordLength = 5;
  449. break;
  450. case UC_FCFG_DATALEN_6:
  451. Lc->WordLength = 6;
  452. break;
  453. case UC_FCFG_DATALEN_7:
  454. Lc->WordLength = 7;
  455. break;
  456. case UC_FCFG_DATALEN_8:
  457. Lc->WordLength = 8;
  458. break;
  459. default:
  460. break;
  461. }
  462. switch(pPort->UartConfig.FrameConfig & UC_FCFG_PARITY_MASK)
  463. {
  464. case UC_FCFG_NO_PARITY:
  465. Lc->Parity = NO_PARITY;
  466. break;
  467. case UC_FCFG_ODD_PARITY:
  468. Lc->Parity = ODD_PARITY;
  469. break;
  470. case UC_FCFG_EVEN_PARITY:
  471. Lc->Parity = EVEN_PARITY;
  472. break;
  473. case UC_FCFG_MARK_PARITY:
  474. Lc->Parity = MARK_PARITY;
  475. break;
  476. case UC_FCFG_SPACE_PARITY:
  477. Lc->Parity = SPACE_PARITY;
  478. break;
  479. default:
  480. break;
  481. }
  482. switch(pPort->UartConfig.FrameConfig & UC_FCFG_STOPBITS_MASK)
  483. {
  484. case UC_FCFG_STOPBITS_1:
  485. Lc->StopBits = STOP_BIT_1;
  486. break;
  487. case UC_FCFG_STOPBITS_1_5:
  488. Lc->StopBits = STOP_BITS_1_5;
  489. break;
  490. case UC_FCFG_STOPBITS_2:
  491. Lc->StopBits = STOP_BITS_2;
  492. break;
  493. default:
  494. break;
  495. }
  496. Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL);
  497. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  498. break;
  499. }
  500. case IOCTL_SERIAL_SET_TIMEOUTS:
  501. {
  502. PSERIAL_TIMEOUTS NewTimeouts = ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
  503. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS))
  504. {
  505. Status = STATUS_BUFFER_TOO_SMALL;
  506. break;
  507. }
  508. if((NewTimeouts->ReadIntervalTimeout == MAXULONG)
  509. && (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG)
  510. && (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG))
  511. {
  512. Status = STATUS_INVALID_PARAMETER;
  513. break;
  514. }
  515. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  516. pPort->Timeouts.ReadIntervalTimeout = NewTimeouts->ReadIntervalTimeout;
  517. pPort->Timeouts.ReadTotalTimeoutMultiplier = NewTimeouts->ReadTotalTimeoutMultiplier;
  518. pPort->Timeouts.ReadTotalTimeoutConstant = NewTimeouts->ReadTotalTimeoutConstant;
  519. pPort->Timeouts.WriteTotalTimeoutMultiplier = NewTimeouts->WriteTotalTimeoutMultiplier;
  520. pPort->Timeouts.WriteTotalTimeoutConstant = NewTimeouts->WriteTotalTimeoutConstant;
  521. KeReleaseSpinLock(&pPort->ControlLock,OldIrql);
  522. break;
  523. }
  524. case IOCTL_SERIAL_GET_TIMEOUTS:
  525. {
  526. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS))
  527. {
  528. Status = STATUS_BUFFER_TOO_SMALL;
  529. break;
  530. }
  531. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  532. *((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) = pPort->Timeouts;
  533. Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
  534. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  535. break;
  536. }
  537. case IOCTL_SERIAL_SET_CHARS:
  538. {
  539. SERIAL_IOCTL_SYNC S;
  540. PSERIAL_CHARS NewChars = ((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer));
  541. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS))
  542. {
  543. Status = STATUS_BUFFER_TOO_SMALL;
  544. break;
  545. }
  546. //
  547. // The only thing that can be wrong with the chars
  548. // is that the xon and xoff characters are the
  549. // same.
  550. //
  551. #if 0
  552. if(NewChars->XonChar == NewChars->XoffChar)
  553. {
  554. Status = STATUS_INVALID_PARAMETER;
  555. break;
  556. }
  557. #endif
  558. //
  559. // We acquire the control lock so that only
  560. // one request can GET or SET the characters
  561. // at a time. The sets could be synchronized
  562. // by the interrupt spinlock, but that wouldn't
  563. // prevent multiple gets at the same time.
  564. //
  565. S.pPort = pPort;
  566. S.Data = NewChars;
  567. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  568. //
  569. // Under the protection of the lock, make sure that
  570. // the xon and xoff characters aren't the same as
  571. // the escape character.
  572. //
  573. if(pPort->EscapeChar)
  574. {
  575. if((pPort->EscapeChar == NewChars->XonChar) || (pPort->EscapeChar == NewChars->XoffChar))
  576. {
  577. Status = STATUS_INVALID_PARAMETER;
  578. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  579. break;
  580. }
  581. }
  582. KeSynchronizeExecution(pPort->Interrupt, SerialSetChars, &S);
  583. #ifdef WMI_SUPPORT
  584. UPDATE_WMI_XON_XOFF_CHARS(pPort->WmiCommData, pPort->SpecialChars);
  585. #endif
  586. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  587. break;
  588. }
  589. case IOCTL_SERIAL_GET_CHARS:
  590. {
  591. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS))
  592. {
  593. Status = STATUS_BUFFER_TOO_SMALL;
  594. break;
  595. }
  596. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  597. *((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer) = pPort->SpecialChars;
  598. Irp->IoStatus.Information = sizeof(SERIAL_CHARS);
  599. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  600. break;
  601. }
  602. case IOCTL_SERIAL_SET_DTR:
  603. case IOCTL_SERIAL_CLR_DTR:
  604. {
  605. //
  606. // We acquire the lock so that we can check whether
  607. // automatic dtr flow control is enabled. If it is
  608. // then we return an error since the app is not allowed
  609. // to touch this if it is automatic.
  610. //
  611. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  612. if((pPort->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE)
  613. {
  614. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  615. }
  616. else
  617. {
  618. KeSynchronizeExecution(pPort->Interrupt,
  619. ((IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR)
  620. ? (SerialSetDTR) : (SerialClrDTR)) , pPort);
  621. }
  622. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  623. break;
  624. }
  625. case IOCTL_SERIAL_RESET_DEVICE:
  626. {
  627. break;
  628. }
  629. case IOCTL_SERIAL_SET_RTS:
  630. case IOCTL_SERIAL_CLR_RTS:
  631. {
  632. //
  633. // We acquire the lock so that we can check whether automatic rts flow control
  634. // or transmit toggleing is enabled. If it is then we return an error since
  635. // the app is not allowed to touch this if it is automatic or toggling.
  636. //
  637. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  638. if(((pPort->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE)
  639. || ((pPort->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE))
  640. {
  641. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  642. }
  643. else
  644. {
  645. KeSynchronizeExecution(pPort->Interrupt,
  646. ((IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_RTS)
  647. ? (SerialSetRTS) : (SerialClrRTS)), pPort);
  648. }
  649. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  650. break;
  651. }
  652. case IOCTL_SERIAL_SET_XOFF:
  653. {
  654. KeSynchronizeExecution(pPort->Interrupt, SerialPretendXoff, pPort);
  655. break;
  656. }
  657. case IOCTL_SERIAL_SET_XON:
  658. {
  659. KeSynchronizeExecution(pPort->Interrupt, SerialPretendXon, pPort);
  660. break;
  661. }
  662. case IOCTL_SERIAL_SET_BREAK_ON:
  663. {
  664. KeSynchronizeExecution(pPort->Interrupt, SerialTurnOnBreak, pPort);
  665. break;
  666. }
  667. case IOCTL_SERIAL_SET_BREAK_OFF:
  668. {
  669. KeSynchronizeExecution(pPort->Interrupt, SerialTurnOffBreak, pPort);
  670. break;
  671. }
  672. case IOCTL_SERIAL_SET_QUEUE_SIZE:
  673. {
  674. // Type ahead buffer is fixed, so we just validate
  675. // the the users request is not bigger that our
  676. // own internal buffer size.
  677. PSERIAL_QUEUE_SIZE Rs = ((PSERIAL_QUEUE_SIZE)(Irp->AssociatedIrp.SystemBuffer));
  678. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_QUEUE_SIZE))
  679. {
  680. Status = STATUS_BUFFER_TOO_SMALL;
  681. break;
  682. }
  683. // We have to allocate the memory for the new
  684. // buffer while we're still in the context of the
  685. // caller. We don't even try to protect this
  686. // with a lock because the value could be stale
  687. // as soon as we release the lock - The only time
  688. // we will know for sure is when we actually try
  689. // to do the resize.
  690. if(Rs->InSize <= pPort->BufferSize)
  691. {
  692. Status = STATUS_SUCCESS;
  693. break;
  694. }
  695. try
  696. {
  697. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer
  698. = SpxAllocateMemWithQuota(NonPagedPool, Rs->InSize);
  699. }
  700. except (EXCEPTION_EXECUTE_HANDLER)
  701. {
  702. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  703. Status = GetExceptionCode();
  704. }
  705. if(!IrpSp->Parameters.DeviceIoControl.Type3InputBuffer)
  706. {
  707. break;
  708. }
  709. //
  710. // Well the data passed was big enough. Do the request.
  711. //
  712. // There are two reason we place it in the read queue:
  713. //
  714. // 1) We want to serialize these resize requests so that
  715. // they don't contend with each other.
  716. //
  717. // 2) We want to serialize these requests with reads since
  718. // we don't want reads and resizes contending over the
  719. // read buffer.
  720. //
  721. return SerialStartOrQueue(pPort, Irp, &pPort->ReadQueue,
  722. &pPort->CurrentReadIrp, SerialStartRead);
  723. break;
  724. }
  725. case IOCTL_SERIAL_GET_WAIT_MASK:
  726. {
  727. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
  728. {
  729. Status = STATUS_BUFFER_TOO_SMALL;
  730. break;
  731. }
  732. // Simple scalar read. No reason to acquire a lock.
  733. Irp->IoStatus.Information = sizeof(ULONG);
  734. *((ULONG *)Irp->AssociatedIrp.SystemBuffer) = pPort->IsrWaitMask;
  735. break;
  736. }
  737. case IOCTL_SERIAL_SET_WAIT_MASK:
  738. {
  739. ULONG NewMask;
  740. SerialDump(SERDIAG3 | SERIRPPATH, ("In Ioctl processing for set mask\n"));
  741. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
  742. {
  743. SerialDump(SERDIAG3, ("Invalid size for the buffer %d\n", IrpSp->Parameters.DeviceIoControl.InputBufferLength));
  744. Status = STATUS_BUFFER_TOO_SMALL;
  745. break;
  746. }
  747. else
  748. {
  749. NewMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer);
  750. }
  751. // Make sure that the mask only contains valid
  752. // waitable events.
  753. if(NewMask & ~( SERIAL_EV_RXCHAR |
  754. SERIAL_EV_RXFLAG |
  755. SERIAL_EV_TXEMPTY |
  756. SERIAL_EV_CTS |
  757. SERIAL_EV_DSR |
  758. SERIAL_EV_RLSD |
  759. SERIAL_EV_BREAK |
  760. SERIAL_EV_ERR |
  761. SERIAL_EV_RING |
  762. SERIAL_EV_PERR |
  763. SERIAL_EV_RX80FULL |
  764. SERIAL_EV_EVENT1 |
  765. SERIAL_EV_EVENT2))
  766. {
  767. SerialDump(SERDIAG3,("Unknown mask %x\n", NewMask));
  768. Status = STATUS_INVALID_PARAMETER;
  769. break;
  770. }
  771. // Either start this irp or put it on the
  772. // queue.
  773. SerialDump(SERDIAG3 | SERIRPPATH, ("Starting or queuing set mask irp %x\n", Irp));
  774. return SerialStartOrQueue(pPort, Irp, &pPort->MaskQueue,
  775. &pPort->CurrentMaskIrp, SerialStartMask);
  776. }
  777. case IOCTL_SERIAL_WAIT_ON_MASK:
  778. {
  779. SerialDump(SERDIAG3 | SERIRPPATH, ("In Ioctl processing for wait mask\n"));
  780. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
  781. {
  782. SerialDump(SERDIAG3,("Invalid size fo the buffer %d\n",
  783. IrpSp->Parameters.DeviceIoControl.InputBufferLength));
  784. Status = STATUS_BUFFER_TOO_SMALL;
  785. break;
  786. }
  787. // Either start this irp or put it on the queue.
  788. SerialDump(SERDIAG3 | SERIRPPATH,("Starting or queuing wait mask irp %x\n", Irp));
  789. return SerialStartOrQueue(pPort, Irp, &pPort->MaskQueue,
  790. &pPort->CurrentMaskIrp, SerialStartMask);
  791. }
  792. case IOCTL_SERIAL_IMMEDIATE_CHAR:
  793. {
  794. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR))
  795. {
  796. Status = STATUS_BUFFER_TOO_SMALL;
  797. break;
  798. }
  799. IoAcquireCancelSpinLock(&OldIrql);
  800. if(pPort->CurrentImmediateIrp)
  801. {
  802. Status = STATUS_INVALID_PARAMETER;
  803. IoReleaseCancelSpinLock(OldIrql);
  804. }
  805. else
  806. {
  807. // We can queue the char. We need to set
  808. // a cancel routine because flow control could
  809. // keep the char from transmitting. Make sure
  810. // that the irp hasn't already been canceled.
  811. if(Irp->Cancel)
  812. {
  813. IoReleaseCancelSpinLock(OldIrql);
  814. Status = STATUS_CANCELLED;
  815. }
  816. else
  817. {
  818. pPort->CurrentImmediateIrp = Irp;
  819. pPort->TotalCharsQueued++;
  820. IoReleaseCancelSpinLock(OldIrql);
  821. SerialStartImmediate(pPort);
  822. return STATUS_PENDING;
  823. }
  824. }
  825. break;
  826. }
  827. case IOCTL_SERIAL_PURGE:
  828. {
  829. ULONG Mask;
  830. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
  831. {
  832. Status = STATUS_BUFFER_TOO_SMALL;
  833. break;
  834. }
  835. // Check to make sure that the mask only has
  836. // 0 or the other appropriate values.
  837. Mask = *((ULONG *)(Irp->AssociatedIrp.SystemBuffer));
  838. if((!Mask) || (Mask & (~( SERIAL_PURGE_TXABORT |
  839. SERIAL_PURGE_RXABORT |
  840. SERIAL_PURGE_TXCLEAR |
  841. SERIAL_PURGE_RXCLEAR ))))
  842. {
  843. Status = STATUS_INVALID_PARAMETER;
  844. break;
  845. }
  846. // Either start this irp or put it on the queue.
  847. return SerialStartOrQueue(pPort, Irp, &pPort->PurgeQueue,
  848. &pPort->CurrentPurgeIrp, SerialStartPurge);
  849. }
  850. case IOCTL_SERIAL_GET_HANDFLOW:
  851. {
  852. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_HANDFLOW))
  853. {
  854. Status = STATUS_BUFFER_TOO_SMALL;
  855. break;
  856. }
  857. Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW);
  858. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  859. *((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) = pPort->HandFlow;
  860. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  861. break;
  862. }
  863. case IOCTL_SERIAL_SET_HANDFLOW:
  864. {
  865. SERIAL_IOCTL_SYNC S;
  866. PSERIAL_HANDFLOW HandFlow = Irp->AssociatedIrp.SystemBuffer;
  867. // Make sure that the hand shake and control is the right size.
  868. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_HANDFLOW))
  869. {
  870. Status = STATUS_BUFFER_TOO_SMALL;
  871. break;
  872. }
  873. // Make sure that there are no invalid bits set in the control and handshake.
  874. if(HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID)
  875. {
  876. Status = STATUS_INVALID_PARAMETER;
  877. break;
  878. }
  879. if(HandFlow->FlowReplace & SERIAL_FLOW_INVALID)
  880. {
  881. Status = STATUS_INVALID_PARAMETER;
  882. break;
  883. }
  884. // Make sure that the app hasn't set an invlid DTR mode.
  885. if((HandFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK)
  886. {
  887. Status = STATUS_INVALID_PARAMETER;
  888. break;
  889. }
  890. // Make sure that haven't set totally invalid xon/xoff limits.
  891. if((HandFlow->XonLimit < 0) || ((ULONG)HandFlow->XonLimit > pPort->BufferSize))
  892. {
  893. Status = STATUS_INVALID_PARAMETER;
  894. break;
  895. }
  896. if((HandFlow->XoffLimit < 0) || ((ULONG)HandFlow->XoffLimit > pPort->BufferSize))
  897. {
  898. Status = STATUS_INVALID_PARAMETER;
  899. break;
  900. }
  901. S.pPort = pPort;
  902. S.Data = HandFlow;
  903. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  904. // Under the protection of the lock, make sure that we aren't turning on error
  905. // replacement when we are doing line status/modem status insertion.
  906. if(pPort->EscapeChar)
  907. {
  908. if(HandFlow->FlowReplace & SERIAL_ERROR_CHAR)
  909. {
  910. Status = STATUS_INVALID_PARAMETER;
  911. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  912. break;
  913. }
  914. }
  915. KeSynchronizeExecution(pPort->Interrupt, SerialSetHandFlow, &S);
  916. #ifdef WMI_SUPPORT
  917. UPDATE_WMI_XMIT_THRESHOLDS(pPort->WmiCommData, pPort->HandFlow);
  918. #endif
  919. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  920. break;
  921. }
  922. case IOCTL_SERIAL_GET_MODEMSTATUS:
  923. {
  924. SERIAL_IOCTL_SYNC S;
  925. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
  926. {
  927. Status = STATUS_BUFFER_TOO_SMALL;
  928. break;
  929. }
  930. Irp->IoStatus.Information = sizeof(ULONG);
  931. S.pPort = pPort;
  932. S.Data = Irp->AssociatedIrp.SystemBuffer;
  933. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  934. KeSynchronizeExecution(pPort->Interrupt, SerialGetModemUpdate, &S);
  935. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  936. break;
  937. }
  938. case IOCTL_SERIAL_GET_DTRRTS:
  939. {
  940. ULONG ModemControl = 0;
  941. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
  942. {
  943. Status = STATUS_BUFFER_TOO_SMALL;
  944. break;
  945. }
  946. Irp->IoStatus.Information = sizeof(ULONG);
  947. Status = STATUS_SUCCESS;
  948. // Reading this hardware has no effect on the device.
  949. if(pPort->DTR_Set)
  950. ModemControl |= SERIAL_DTR_STATE;
  951. if(pPort->RTS_Set)
  952. ModemControl |= SERIAL_RTS_STATE;
  953. *(PULONG)Irp->AssociatedIrp.SystemBuffer = ModemControl;
  954. break;
  955. }
  956. case IOCTL_SERIAL_GET_COMMSTATUS:
  957. {
  958. SERIAL_IOCTL_SYNC S;
  959. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength <sizeof(SERIAL_STATUS))
  960. {
  961. Status = STATUS_BUFFER_TOO_SMALL;
  962. break;
  963. }
  964. Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
  965. S.pPort = pPort;
  966. S.Data = Irp->AssociatedIrp.SystemBuffer;
  967. //
  968. // Acquire the cancel spin lock so nothing much
  969. // changes while were getting the state.
  970. //
  971. IoAcquireCancelSpinLock(&OldIrql);
  972. KeSynchronizeExecution(pPort->Interrupt, SerialGetCommStatus, &S);
  973. IoReleaseCancelSpinLock(OldIrql);
  974. break;
  975. }
  976. case IOCTL_SERIAL_GET_PROPERTIES:
  977. {
  978. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength <sizeof(SERIAL_COMMPROP))
  979. {
  980. Status = STATUS_BUFFER_TOO_SMALL;
  981. break;
  982. }
  983. // No synchronization is required since this information is "static".
  984. SerialGetProperties(pPort, Irp->AssociatedIrp.SystemBuffer);
  985. Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
  986. Status = STATUS_SUCCESS;
  987. break;
  988. }
  989. case IOCTL_SERIAL_XOFF_COUNTER:
  990. {
  991. PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer;
  992. Status = STATUS_NOT_IMPLEMENTED;
  993. /*
  994. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_XOFF_COUNTER))
  995. {
  996. Status = STATUS_BUFFER_TOO_SMALL;
  997. break;
  998. }
  999. if(Xc->Counter <= 0)
  1000. {
  1001. Status = STATUS_INVALID_PARAMETER;
  1002. break;
  1003. }
  1004. // So far so good. Put the irp onto the write queue.
  1005. return SerialStartOrQueue(pPort, Irp, &pPort->WriteQueue,
  1006. &pPort->CurrentWriteIrp,SerialStartWrite);
  1007. */
  1008. break;
  1009. }
  1010. case IOCTL_SERIAL_LSRMST_INSERT:
  1011. {
  1012. PUCHAR escapeChar = Irp->AssociatedIrp.SystemBuffer;
  1013. // Make sure we get a byte.
  1014. if(IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR))
  1015. {
  1016. Status = STATUS_BUFFER_TOO_SMALL;
  1017. break;
  1018. }
  1019. KeAcquireSpinLock(&pPort->ControlLock, &OldIrql);
  1020. if(*escapeChar)
  1021. {
  1022. // We've got some escape work to do. We will make sure that
  1023. // the character is not the same as the Xon or Xoff character,
  1024. // or that we are already doing error replacement.
  1025. if((*escapeChar == pPort->SpecialChars.XoffChar)
  1026. || (*escapeChar == pPort->SpecialChars.XonChar)
  1027. || (pPort->HandFlow.FlowReplace & SERIAL_ERROR_CHAR))
  1028. {
  1029. Status = STATUS_INVALID_PARAMETER;
  1030. KeReleaseSpinLock(&pPort->ControlLock,OldIrql);
  1031. break;
  1032. }
  1033. }
  1034. KeSynchronizeExecution(pPort->Interrupt, SerialSetEscapeChar, Irp);
  1035. KeReleaseSpinLock(&pPort->ControlLock, OldIrql);
  1036. break;
  1037. }
  1038. case IOCTL_SERIAL_CONFIG_SIZE:
  1039. {
  1040. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
  1041. {
  1042. Status = STATUS_BUFFER_TOO_SMALL;
  1043. break;
  1044. }
  1045. Irp->IoStatus.Information = sizeof(ULONG);
  1046. Status = STATUS_SUCCESS;
  1047. *(PULONG)Irp->AssociatedIrp.SystemBuffer = 0;
  1048. break;
  1049. }
  1050. case IOCTL_SERIAL_GET_STATS:
  1051. {
  1052. if(IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS))
  1053. {
  1054. Status = STATUS_BUFFER_TOO_SMALL;
  1055. break;
  1056. }
  1057. Irp->IoStatus.Information = sizeof(SERIALPERF_STATS);
  1058. Status = STATUS_SUCCESS;
  1059. KeSynchronizeExecution(pPort->Interrupt, SerialGetStats, Irp);
  1060. break;
  1061. }
  1062. case IOCTL_SERIAL_CLEAR_STATS:
  1063. {
  1064. KeSynchronizeExecution(pPort->Interrupt, SerialClearStats, pPort);
  1065. break;
  1066. }
  1067. default:
  1068. {
  1069. Status = STATUS_INVALID_PARAMETER;
  1070. break;
  1071. }
  1072. }
  1073. DoneWithIoctl:;
  1074. Irp->IoStatus.Status = Status;
  1075. SerialDump(SERIRPPATH, ("Complete Irp: %x\n",Irp));
  1076. SpxIRPCounter(pPort, Irp, IRP_COMPLETED); // Increment counter for performance stats.
  1077. IoCompleteRequest(Irp, 0);
  1078. return Status;
  1079. }
  1080. VOID
  1081. SerialGetProperties(IN PPORT_DEVICE_EXTENSION pPort, IN PSERIAL_COMMPROP Properties)
  1082. /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1083. Routine Description:
  1084. This function returns the capabilities of this particular
  1085. serial device.
  1086. Arguments:
  1087. Extension - The serial device extension.
  1088. Properties - The structure used to return the properties
  1089. Return Value:
  1090. None.
  1091. -----------------------------------------------------------------------------*/
  1092. {
  1093. RtlZeroMemory(Properties, sizeof(SERIAL_COMMPROP));
  1094. Properties->PacketLength = sizeof(SERIAL_COMMPROP);
  1095. Properties->PacketVersion = 2;
  1096. Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
  1097. Properties->MaxTxQueue = 0;
  1098. Properties->MaxRxQueue = 0;
  1099. Properties->MaxBaud = SERIAL_BAUD_USER;
  1100. Properties->SettableBaud = pPort->SupportedBauds;
  1101. Properties->ProvSubType = SERIAL_SP_RS232;
  1102. Properties->ProvCapabilities = SERIAL_PCF_DTRDSR |
  1103. SERIAL_PCF_RTSCTS |
  1104. SERIAL_PCF_CD |
  1105. SERIAL_PCF_PARITY_CHECK |
  1106. SERIAL_PCF_XONXOFF |
  1107. SERIAL_PCF_SETXCHAR |
  1108. SERIAL_PCF_TOTALTIMEOUTS |
  1109. SERIAL_PCF_INTTIMEOUTS |
  1110. SERIAL_PCF_SPECIALCHARS;
  1111. Properties->SettableParams = SERIAL_SP_PARITY |
  1112. SERIAL_SP_BAUD |
  1113. SERIAL_SP_DATABITS |
  1114. SERIAL_SP_STOPBITS |
  1115. SERIAL_SP_HANDSHAKING |
  1116. SERIAL_SP_PARITY_CHECK |
  1117. SERIAL_SP_CARRIER_DETECT;
  1118. Properties->SettableData = SERIAL_DATABITS_5 |
  1119. SERIAL_DATABITS_6 |
  1120. SERIAL_DATABITS_7 |
  1121. SERIAL_DATABITS_8;
  1122. Properties->SettableStopParity = SERIAL_STOPBITS_10 |
  1123. SERIAL_STOPBITS_15 |
  1124. SERIAL_STOPBITS_20 |
  1125. SERIAL_PARITY_NONE |
  1126. SERIAL_PARITY_ODD |
  1127. SERIAL_PARITY_EVEN |
  1128. SERIAL_PARITY_MARK |
  1129. SERIAL_PARITY_SPACE;
  1130. Properties->CurrentTxQueue = 0;
  1131. Properties->CurrentRxQueue = pPort->BufferSize;
  1132. }
  1133. // Set Fast 16 and Fast 16 FMC cards to delay UART interrupts by 1.1 ms
  1134. // to improve performance when more than 50% of the ports are in full use.
  1135. // This is the default option.
  1136. BOOLEAN SetCardToDelayInterrupt(PCARD_DEVICE_EXTENSION pCard)
  1137. {
  1138. if((pCard->CardType == Fast16_Pci) || pCard->CardType == Fast16FMC_Pci)
  1139. {
  1140. /* NOTE: If bit 7 of the PLX9050 config space physical address is set in either I/O Space or Memory...
  1141. * ...then reads from the registers will only return 0. However, writes are OK. */
  1142. if(READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET) == 0)
  1143. {
  1144. // We have to blindly write the value to the register.
  1145. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET), 0x59);
  1146. }
  1147. else
  1148. {
  1149. // Read Register Value and set bit 2 to enable RTS on Fast 16 PCI card.
  1150. UCHAR Val = READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET) | 0x8;
  1151. // Write the new value back to the register.
  1152. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET), Val);
  1153. }
  1154. return TRUE;
  1155. }
  1156. return FALSE;
  1157. }
  1158. // Set Fast 16 and Fast 16 FMC cards not to delay UART interrupts by 1.1 ms.
  1159. BOOLEAN SetCardNotToDelayInterrupt(PCARD_DEVICE_EXTENSION pCard)
  1160. {
  1161. if((pCard->CardType == Fast16_Pci) || pCard->CardType == Fast16FMC_Pci)
  1162. {
  1163. /* NOTE: If bit 7 of the PLX9050 config space physical address is set in either I/O Space or Memory...
  1164. * ...then reads from the registers will only return 0. However, writes are OK. */
  1165. if(READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET) == 0)
  1166. {
  1167. // We have to blindly write the value to the register.
  1168. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET), 0x51);
  1169. }
  1170. else
  1171. {
  1172. // Read Register Value and set bit 2 to enable RTS on Fast 16 PCI card.
  1173. UCHAR Val = READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET) & ~0x8;
  1174. // Write the new value back to the register.
  1175. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_INT_CNTRL_REG_OFFSET), Val);
  1176. }
  1177. return TRUE;
  1178. }
  1179. return FALSE;
  1180. }
  1181. // Sets card not to use DTR instead of RTS on Fast 16 PCI cards only.
  1182. // This is the default option.
  1183. BOOLEAN SetCardNotToUseDTRInsteadOfRTS(PCARD_DEVICE_EXTENSION pCard)
  1184. {
  1185. if(pCard->CardType == Fast16_Pci)
  1186. {
  1187. /* NOTE: If bit 7 of the PLX9050 config space physical address is set in either I/O Space or Memory...
  1188. * ...then reads from the registers will only return 0. However, writes are OK. */
  1189. if(READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET) == 0)
  1190. {
  1191. // We have to blindly write the value to the register.
  1192. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET), 0x56);
  1193. }
  1194. else
  1195. {
  1196. // Read Register Value and set bit 2 to enable RTS on Fast 16 PCI card.
  1197. UCHAR Val = READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET) | 0x4;
  1198. // Write the new value back to the register.
  1199. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET), Val);
  1200. }
  1201. return TRUE;
  1202. }
  1203. return FALSE;
  1204. }
  1205. // Sets card to use DTR instead of RTS on Fast 16 PCI cards only.
  1206. BOOLEAN SetCardToUseDTRInsteadOfRTS(PCARD_DEVICE_EXTENSION pCard)
  1207. {
  1208. if(pCard->CardType == Fast16_Pci)
  1209. {
  1210. /* NOTE: If bit 7 of the PLX9050 config space physical address is set in either I/O Space or Memory...
  1211. * ...then reads from the registers will only return 0. However, writes are OK. */
  1212. if(READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET) == 0)
  1213. {
  1214. // We have to blindly write the value to the register.
  1215. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET), 0x52);
  1216. }
  1217. else
  1218. {
  1219. // Read Register Value and clear bit 2 to enable DTR on Fast 16 PCI card.
  1220. UCHAR Val = READ_REGISTER_UCHAR(pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET) & ~0x4;
  1221. // Write the new value back to the register.
  1222. WRITE_REGISTER_UCHAR((pCard->LocalConfigRegisters + PLX9050_CNTRL_REG_OFFSET), Val);
  1223. }
  1224. return TRUE;
  1225. }
  1226. return FALSE;
  1227. }