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.

2533 lines
63 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. --*/
  14. #include "precomp.h"
  15. BOOLEAN
  16. SerialGetModemUpdate(
  17. IN PVOID Context
  18. );
  19. BOOLEAN
  20. SerialGetCommStatus(
  21. IN PVOID Context
  22. );
  23. VOID
  24. SerialGetProperties(
  25. IN PSERIAL_DEVICE_EXTENSION Extension,
  26. IN PSERIAL_COMMPROP Properties
  27. );
  28. BOOLEAN
  29. SerialSetEscapeChar(
  30. IN PVOID Context
  31. );
  32. #ifdef ALLOC_PRAGMA
  33. //
  34. // Locked during PnP operations and while open
  35. //
  36. #pragma alloc_text(PAGESER,SerialSetBaud)
  37. #pragma alloc_text(PAGESER,SerialSetLineControl)
  38. #pragma alloc_text(PAGESER,SerialIoControl)
  39. #pragma alloc_text(PAGESER,SerialSetChars)
  40. #pragma alloc_text(PAGESER,SerialGetModemUpdate)
  41. #pragma alloc_text(PAGESER,SerialGetCommStatus)
  42. #pragma alloc_text(PAGESER,SerialGetProperties)
  43. #pragma alloc_text(PAGESER,SerialSetEscapeChar)
  44. #pragma alloc_text(PAGESER,SerialGetStats)
  45. #pragma alloc_text(PAGESER,SerialClearStats)
  46. #pragma alloc_text(PAGESER, SerialSetMCRContents)
  47. #pragma alloc_text(PAGESER, SerialGetMCRContents)
  48. #pragma alloc_text(PAGESER, SerialSetFCRContents)
  49. #pragma alloc_text(PAGESER, SerialInternalIoControl)
  50. #endif
  51. BOOLEAN
  52. SerialGetStats(
  53. IN PVOID Context
  54. )
  55. /*++
  56. Routine Description:
  57. In sync with the interrpt service routine (which sets the perf stats)
  58. return the perf stats to the caller.
  59. Arguments:
  60. Context - Pointer to a the irp.
  61. Return Value:
  62. This routine always returns FALSE.
  63. --*/
  64. {
  65. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation((PIRP)Context);
  66. PSERIAL_DEVICE_EXTENSION extension = irpSp->DeviceObject->DeviceExtension;
  67. PSERIALPERF_STATS sp = ((PIRP)Context)->AssociatedIrp.SystemBuffer;
  68. SERIAL_LOCKED_PAGED_CODE();
  69. *sp = extension->PerfStats;
  70. return FALSE;
  71. }
  72. BOOLEAN
  73. SerialClearStats(
  74. IN PVOID Context
  75. )
  76. /*++
  77. Routine Description:
  78. In sync with the interrpt service routine (which sets the perf stats)
  79. clear the perf stats.
  80. Arguments:
  81. Context - Pointer to a the extension.
  82. Return Value:
  83. This routine always returns FALSE.
  84. --*/
  85. {
  86. SERIAL_LOCKED_PAGED_CODE();
  87. RtlZeroMemory(
  88. &((PSERIAL_DEVICE_EXTENSION)Context)->PerfStats,
  89. sizeof(SERIALPERF_STATS)
  90. );
  91. RtlZeroMemory(&((PSERIAL_DEVICE_EXTENSION)Context)->WmiPerfData,
  92. sizeof(SERIAL_WMI_PERF_DATA));
  93. return FALSE;
  94. }
  95. BOOLEAN
  96. SerialSetChars(
  97. IN PVOID Context
  98. )
  99. /*++
  100. Routine Description:
  101. This routine is used to set the special characters for the
  102. driver.
  103. Arguments:
  104. Context - Pointer to a structure that contains a pointer to
  105. the device extension and a pointer to a special characters
  106. structure.
  107. Return Value:
  108. This routine always returns FALSE.
  109. --*/
  110. {
  111. ((PSERIAL_IOCTL_SYNC)Context)->Extension->SpecialChars =
  112. *((PSERIAL_CHARS)(((PSERIAL_IOCTL_SYNC)Context)->Data));
  113. SERIAL_LOCKED_PAGED_CODE();
  114. return FALSE;
  115. }
  116. BOOLEAN
  117. SerialSetBaud(
  118. IN PVOID Context
  119. )
  120. /*++
  121. Routine Description:
  122. This routine is used to set the baud rate of the device.
  123. Arguments:
  124. Context - Pointer to a structure that contains a pointer to
  125. the device extension and what should be the current
  126. baud rate.
  127. Return Value:
  128. This routine always returns FALSE.
  129. --*/
  130. {
  131. PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;
  132. USHORT Appropriate = PtrToUshort(((PSERIAL_IOCTL_SYNC)Context)->Data);
  133. SERIAL_LOCKED_PAGED_CODE();
  134. WRITE_DIVISOR_LATCH(
  135. Extension->Controller,
  136. Appropriate
  137. );
  138. return FALSE;
  139. }
  140. BOOLEAN
  141. SerialSetLineControl(
  142. IN PVOID Context
  143. )
  144. /*++
  145. Routine Description:
  146. This routine is used to set the buad rate of the device.
  147. Arguments:
  148. Context - Pointer to the device extension.
  149. Return Value:
  150. This routine always returns FALSE.
  151. --*/
  152. {
  153. PSERIAL_DEVICE_EXTENSION Extension = Context;
  154. SERIAL_LOCKED_PAGED_CODE();
  155. WRITE_LINE_CONTROL(
  156. Extension->Controller,
  157. Extension->LineControl
  158. );
  159. return FALSE;
  160. }
  161. BOOLEAN
  162. SerialGetModemUpdate(
  163. IN PVOID Context
  164. )
  165. /*++
  166. Routine Description:
  167. This routine is simply used to call the interrupt level routine
  168. that handles modem status update.
  169. Arguments:
  170. Context - Pointer to a structure that contains a pointer to
  171. the device extension and a pointer to a ulong.
  172. Return Value:
  173. This routine always returns FALSE.
  174. --*/
  175. {
  176. PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;
  177. ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);
  178. SERIAL_LOCKED_PAGED_CODE();
  179. *Result = SerialHandleModemUpdate(
  180. Extension,
  181. FALSE
  182. );
  183. return FALSE;
  184. }
  185. BOOLEAN
  186. SerialSetMCRContents(IN PVOID Context)
  187. /*++
  188. Routine Description:
  189. This routine is simply used to set the contents of the MCR
  190. Arguments:
  191. Context - Pointer to a structure that contains a pointer to
  192. the device extension and a pointer to a ulong.
  193. Return Value:
  194. This routine always returns FALSE.
  195. --*/
  196. {
  197. PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;
  198. ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);
  199. SERIAL_LOCKED_PAGED_CODE();
  200. //
  201. // This is severe casting abuse!!!
  202. //
  203. WRITE_MODEM_CONTROL(Extension->Controller, (UCHAR)PtrToUlong(Result));
  204. return FALSE;
  205. }
  206. BOOLEAN
  207. SerialGetMCRContents(IN PVOID Context)
  208. /*++
  209. Routine Description:
  210. This routine is simply used to get the contents of the MCR
  211. Arguments:
  212. Context - Pointer to a structure that contains a pointer to
  213. the device extension and a pointer to a ulong.
  214. Return Value:
  215. This routine always returns FALSE.
  216. --*/
  217. {
  218. PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;
  219. ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);
  220. SERIAL_LOCKED_PAGED_CODE();
  221. *Result = READ_MODEM_CONTROL(Extension->Controller);
  222. return FALSE;
  223. }
  224. BOOLEAN
  225. SerialSetFCRContents(IN PVOID Context)
  226. /*++
  227. Routine Description:
  228. This routine is simply used to set the contents of the FCR
  229. Arguments:
  230. Context - Pointer to a structure that contains a pointer to
  231. the device extension and a pointer to a ulong.
  232. Return Value:
  233. This routine always returns FALSE.
  234. --*/
  235. {
  236. PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;
  237. ULONG *Result = (ULONG *)(((PSERIAL_IOCTL_SYNC)Context)->Data);
  238. SERIAL_LOCKED_PAGED_CODE();
  239. //
  240. // This is severe casting abuse!!!
  241. //
  242. WRITE_FIFO_CONTROL(Extension->Controller, (UCHAR)PtrToUlong(Result));
  243. return FALSE;
  244. }
  245. BOOLEAN
  246. SerialGetCommStatus(
  247. IN PVOID Context
  248. )
  249. /*++
  250. Routine Description:
  251. This is used to get the current state of the serial driver.
  252. Arguments:
  253. Context - Pointer to a structure that contains a pointer to
  254. the device extension and a pointer to a serial status
  255. record.
  256. Return Value:
  257. This routine always returns FALSE.
  258. --*/
  259. {
  260. PSERIAL_DEVICE_EXTENSION Extension = ((PSERIAL_IOCTL_SYNC)Context)->Extension;
  261. PSERIAL_STATUS Stat = ((PSERIAL_IOCTL_SYNC)Context)->Data;
  262. SERIAL_LOCKED_PAGED_CODE();
  263. Stat->Errors = Extension->ErrorWord;
  264. Extension->ErrorWord = 0;
  265. //
  266. // BUG BUG We need to do something about eof (binary mode).
  267. //
  268. Stat->EofReceived = FALSE;
  269. Stat->AmountInInQueue = Extension->CharsInInterruptBuffer;
  270. Stat->AmountInOutQueue = Extension->TotalCharsQueued;
  271. if (Extension->WriteLength) {
  272. //
  273. // By definition if we have a writelength the we have
  274. // a current write irp.
  275. //
  276. ASSERT(Extension->CurrentWriteIrp);
  277. ASSERT(Stat->AmountInOutQueue >= Extension->WriteLength);
  278. Stat->AmountInOutQueue -=
  279. IoGetCurrentIrpStackLocation(Extension->CurrentWriteIrp)
  280. ->Parameters.Write.Length - (Extension->WriteLength);
  281. }
  282. Stat->WaitForImmediate = Extension->TransmitImmediate;
  283. Stat->HoldReasons = 0;
  284. if (Extension->TXHolding) {
  285. if (Extension->TXHolding & SERIAL_TX_CTS) {
  286. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS;
  287. }
  288. if (Extension->TXHolding & SERIAL_TX_DSR) {
  289. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DSR;
  290. }
  291. if (Extension->TXHolding & SERIAL_TX_DCD) {
  292. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_DCD;
  293. }
  294. if (Extension->TXHolding & SERIAL_TX_XOFF) {
  295. Stat->HoldReasons |= SERIAL_TX_WAITING_FOR_XON;
  296. }
  297. if (Extension->TXHolding & SERIAL_TX_BREAK) {
  298. Stat->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK;
  299. }
  300. }
  301. if (Extension->RXHolding & SERIAL_RX_DSR) {
  302. Stat->HoldReasons |= SERIAL_RX_WAITING_FOR_DSR;
  303. }
  304. if (Extension->RXHolding & SERIAL_RX_XOFF) {
  305. Stat->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT;
  306. }
  307. return FALSE;
  308. }
  309. BOOLEAN
  310. SerialSetEscapeChar(
  311. IN PVOID Context
  312. )
  313. /*++
  314. Routine Description:
  315. This is used to set the character that will be used to escape
  316. line status and modem status information when the application
  317. has set up that line status and modem status should be passed
  318. back in the data stream.
  319. Arguments:
  320. Context - Pointer to the irp that is specify the escape character.
  321. Implicitly - An escape character of 0 means no escaping
  322. will occur.
  323. Return Value:
  324. This routine always returns FALSE.
  325. --*/
  326. {
  327. PSERIAL_DEVICE_EXTENSION extension =
  328. IoGetCurrentIrpStackLocation((PIRP)Context)
  329. ->DeviceObject->DeviceExtension;
  330. extension->EscapeChar =
  331. *(PUCHAR)((PIRP)Context)->AssociatedIrp.SystemBuffer;
  332. return FALSE;
  333. }
  334. NTSTATUS
  335. SerialIoControl(
  336. IN PDEVICE_OBJECT DeviceObject,
  337. IN PIRP Irp
  338. )
  339. /*++
  340. Routine Description:
  341. This routine provides the initial processing for all of the
  342. Ioctrls for the serial device.
  343. Arguments:
  344. DeviceObject - Pointer to the device object for this device
  345. Irp - Pointer to the IRP for the current request
  346. Return Value:
  347. The function value is the final status of the call
  348. --*/
  349. {
  350. //
  351. // The status that gets returned to the caller and
  352. // set in the Irp.
  353. //
  354. NTSTATUS Status;
  355. //
  356. // The current stack location. This contains all of the
  357. // information we need to process this particular request.
  358. //
  359. PIO_STACK_LOCATION IrpSp;
  360. //
  361. // Just what it says. This is the serial specific device
  362. // extension of the device object create for the serial driver.
  363. //
  364. PSERIAL_DEVICE_EXTENSION Extension = DeviceObject->DeviceExtension;
  365. //
  366. // A temporary to hold the old IRQL so that it can be
  367. // restored once we complete/validate this request.
  368. //
  369. KIRQL OldIrql;
  370. NTSTATUS prologueStatus;
  371. SERIAL_LOCKED_PAGED_CODE();
  372. //
  373. // We expect to be open so all our pages are locked down. This is, after
  374. // all, an IO operation, so the device should be open first.
  375. //
  376. if (Extension->DeviceIsOpened != TRUE) {
  377. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  378. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  379. return STATUS_INVALID_DEVICE_REQUEST;
  380. }
  381. if ((prologueStatus = SerialIRPPrologue(Irp, Extension))
  382. != STATUS_SUCCESS) {
  383. Irp->IoStatus.Status = prologueStatus;
  384. SerialCompleteRequest(Extension, Irp, IO_NO_INCREMENT);
  385. return prologueStatus;
  386. }
  387. SerialDump(
  388. SERIRPPATH,
  389. ("SERIAL: Dispatch entry for: %x\n",Irp)
  390. );
  391. if (SerialCompleteIfError(
  392. DeviceObject,
  393. Irp
  394. ) != STATUS_SUCCESS) {
  395. return STATUS_CANCELLED;
  396. }
  397. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  398. Irp->IoStatus.Information = 0L;
  399. Status = STATUS_SUCCESS;
  400. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  401. case IOCTL_SERIAL_SET_BAUD_RATE : {
  402. ULONG BaudRate;
  403. //
  404. // Will hold the value of the appropriate divisor for
  405. // the requested baud rate. If the baudrate is invalid
  406. // (because the device won't support that baud rate) then
  407. // this value is undefined.
  408. //
  409. // Note: in one sense the concept of a valid baud rate
  410. // is cloudy. We could allow the user to request any
  411. // baud rate. We could then calculate the divisor needed
  412. // for that baud rate. As long as the divisor wasn't less
  413. // than one we would be "ok". (The percentage difference
  414. // between the "true" divisor and the "rounded" value given
  415. // to the hardware might make it unusable, but... ) It would
  416. // really be up to the user to "Know" whether the baud rate
  417. // is suitable. So much for theory, *We* only support a given
  418. // set of baud rates.
  419. //
  420. SHORT AppropriateDivisor;
  421. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  422. sizeof(SERIAL_BAUD_RATE)) {
  423. Status = STATUS_BUFFER_TOO_SMALL;
  424. break;
  425. } else {
  426. BaudRate = ((PSERIAL_BAUD_RATE)(Irp->AssociatedIrp.SystemBuffer))->BaudRate;
  427. }
  428. //
  429. // Get the baud rate from the irp. We pass it
  430. // to a routine which will set the correct divisor.
  431. //
  432. Status = SerialGetDivisorFromBaud(
  433. Extension->ClockRate,
  434. BaudRate,
  435. &AppropriateDivisor
  436. );
  437. //
  438. // Make sure we are at power D0
  439. //
  440. if (NT_SUCCESS(Status)) {
  441. if (Extension->PowerState != PowerDeviceD0) {
  442. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  443. PowerDeviceD0);
  444. if (!NT_SUCCESS(Status)) {
  445. break;
  446. }
  447. }
  448. }
  449. KeAcquireSpinLock(
  450. &Extension->ControlLock,
  451. &OldIrql
  452. );
  453. if (NT_SUCCESS(Status)) {
  454. SERIAL_IOCTL_SYNC S;
  455. Extension->CurrentBaud = BaudRate;
  456. Extension->WmiCommData.BaudRate = BaudRate;
  457. S.Extension = Extension;
  458. S.Data = (PVOID)AppropriateDivisor;
  459. KeSynchronizeExecution(
  460. Extension->Interrupt,
  461. SerialSetBaud,
  462. &S
  463. );
  464. }
  465. KeReleaseSpinLock(
  466. &Extension->ControlLock,
  467. OldIrql
  468. );
  469. break;
  470. }
  471. case IOCTL_SERIAL_GET_BAUD_RATE: {
  472. PSERIAL_BAUD_RATE Br = (PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer;
  473. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  474. sizeof(SERIAL_BAUD_RATE)) {
  475. Status = STATUS_BUFFER_TOO_SMALL;
  476. break;
  477. }
  478. KeAcquireSpinLock(
  479. &Extension->ControlLock,
  480. &OldIrql
  481. );
  482. Br->BaudRate = Extension->CurrentBaud;
  483. KeReleaseSpinLock(
  484. &Extension->ControlLock,
  485. OldIrql
  486. );
  487. Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);
  488. break;
  489. }
  490. case IOCTL_SERIAL_GET_MODEM_CONTROL: {
  491. SERIAL_IOCTL_SYNC S;
  492. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  493. sizeof(ULONG)) {
  494. Status = STATUS_BUFFER_TOO_SMALL;
  495. break;
  496. }
  497. Irp->IoStatus.Information = sizeof(ULONG);
  498. S.Extension = Extension;
  499. S.Data = Irp->AssociatedIrp.SystemBuffer;
  500. KeAcquireSpinLock(
  501. &Extension->ControlLock,
  502. &OldIrql
  503. );
  504. KeSynchronizeExecution(
  505. Extension->Interrupt,
  506. SerialGetMCRContents,
  507. &S
  508. );
  509. KeReleaseSpinLock(
  510. &Extension->ControlLock,
  511. OldIrql
  512. );
  513. break;
  514. }
  515. case IOCTL_SERIAL_SET_MODEM_CONTROL: {
  516. SERIAL_IOCTL_SYNC S;
  517. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  518. sizeof(ULONG)) {
  519. Status = STATUS_BUFFER_TOO_SMALL;
  520. break;
  521. }
  522. S.Extension = Extension;
  523. S.Data = Irp->AssociatedIrp.SystemBuffer;
  524. //
  525. // Make sure we are at power D0
  526. //
  527. if (Extension->PowerState != PowerDeviceD0) {
  528. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  529. PowerDeviceD0);
  530. if (!NT_SUCCESS(Status)) {
  531. break;
  532. }
  533. }
  534. KeAcquireSpinLock(
  535. &Extension->ControlLock,
  536. &OldIrql
  537. );
  538. KeSynchronizeExecution(
  539. Extension->Interrupt,
  540. SerialSetMCRContents,
  541. &S
  542. );
  543. KeReleaseSpinLock(
  544. &Extension->ControlLock,
  545. OldIrql
  546. );
  547. break;
  548. }
  549. case IOCTL_SERIAL_SET_FIFO_CONTROL: {
  550. SERIAL_IOCTL_SYNC S;
  551. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  552. sizeof(ULONG)) {
  553. Status = STATUS_BUFFER_TOO_SMALL;
  554. break;
  555. }
  556. S.Extension = Extension;
  557. S.Data = Irp->AssociatedIrp.SystemBuffer;
  558. //
  559. // Make sure we are at power D0
  560. //
  561. if (Extension->PowerState != PowerDeviceD0) {
  562. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  563. PowerDeviceD0);
  564. if (!NT_SUCCESS(Status)) {
  565. break;
  566. }
  567. }
  568. KeAcquireSpinLock(
  569. &Extension->ControlLock,
  570. &OldIrql
  571. );
  572. KeSynchronizeExecution(
  573. Extension->Interrupt,
  574. SerialSetFCRContents,
  575. &S
  576. );
  577. KeReleaseSpinLock(
  578. &Extension->ControlLock,
  579. OldIrql
  580. );
  581. break;
  582. }
  583. case IOCTL_SERIAL_SET_LINE_CONTROL: {
  584. //
  585. // Points to the line control record in the Irp.
  586. //
  587. PSERIAL_LINE_CONTROL Lc =
  588. ((PSERIAL_LINE_CONTROL)(Irp->AssociatedIrp.SystemBuffer));
  589. UCHAR LData;
  590. UCHAR LStop;
  591. UCHAR LParity;
  592. UCHAR Mask = 0xff;
  593. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  594. sizeof(SERIAL_LINE_CONTROL)) {
  595. Status = STATUS_BUFFER_TOO_SMALL;
  596. break;
  597. }
  598. //
  599. // Make sure we are at power D0
  600. //
  601. if (Extension->PowerState != PowerDeviceD0) {
  602. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  603. PowerDeviceD0);
  604. if (!NT_SUCCESS(Status)) {
  605. break;
  606. }
  607. }
  608. switch (Lc->WordLength) {
  609. case 5: {
  610. LData = SERIAL_5_DATA;
  611. Mask = 0x1f;
  612. break;
  613. }
  614. case 6: {
  615. LData = SERIAL_6_DATA;
  616. Mask = 0x3f;
  617. break;
  618. }
  619. case 7: {
  620. LData = SERIAL_7_DATA;
  621. Mask = 0x7f;
  622. break;
  623. }
  624. case 8: {
  625. LData = SERIAL_8_DATA;
  626. break;
  627. }
  628. default: {
  629. Status = STATUS_INVALID_PARAMETER;
  630. goto DoneWithIoctl;
  631. }
  632. }
  633. Extension->WmiCommData.BitsPerByte = Lc->WordLength;
  634. switch (Lc->Parity) {
  635. case NO_PARITY: {
  636. Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE;
  637. LParity = SERIAL_NONE_PARITY;
  638. break;
  639. }
  640. case EVEN_PARITY: {
  641. Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN;
  642. LParity = SERIAL_EVEN_PARITY;
  643. break;
  644. }
  645. case ODD_PARITY: {
  646. Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD;
  647. LParity = SERIAL_ODD_PARITY;
  648. break;
  649. }
  650. #if defined(NEC_98)
  651. //
  652. // COM1 of PC-9800 series is not support MarkParity and SpaceParity.
  653. //
  654. #else
  655. case SPACE_PARITY: {
  656. Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE;
  657. LParity = SERIAL_SPACE_PARITY;
  658. break;
  659. }
  660. case MARK_PARITY: {
  661. Extension->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK;
  662. LParity = SERIAL_MARK_PARITY;
  663. break;
  664. }
  665. #endif //defined(NEC_98)
  666. default: {
  667. Status = STATUS_INVALID_PARAMETER;
  668. goto DoneWithIoctl;
  669. break;
  670. }
  671. }
  672. switch (Lc->StopBits) {
  673. case STOP_BIT_1: {
  674. Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1;
  675. LStop = SERIAL_1_STOP;
  676. break;
  677. }
  678. case STOP_BITS_1_5: {
  679. if (LData != SERIAL_5_DATA) {
  680. Status = STATUS_INVALID_PARAMETER;
  681. goto DoneWithIoctl;
  682. }
  683. Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5;
  684. LStop = SERIAL_1_5_STOP;
  685. break;
  686. }
  687. case STOP_BITS_2: {
  688. if (LData == SERIAL_5_DATA) {
  689. Status = STATUS_INVALID_PARAMETER;
  690. goto DoneWithIoctl;
  691. }
  692. Extension->WmiCommData.StopBits = SERIAL_WMI_STOP_2;
  693. LStop = SERIAL_2_STOP;
  694. break;
  695. }
  696. default: {
  697. Status = STATUS_INVALID_PARAMETER;
  698. goto DoneWithIoctl;
  699. }
  700. }
  701. KeAcquireSpinLock(
  702. &Extension->ControlLock,
  703. &OldIrql
  704. );
  705. Extension->LineControl =
  706. (UCHAR)((Extension->LineControl & SERIAL_LCR_BREAK) |
  707. (LData | LParity | LStop));
  708. Extension->ValidDataMask = Mask;
  709. KeSynchronizeExecution(
  710. Extension->Interrupt,
  711. SerialSetLineControl,
  712. Extension
  713. );
  714. KeReleaseSpinLock(
  715. &Extension->ControlLock,
  716. OldIrql
  717. );
  718. break;
  719. }
  720. case IOCTL_SERIAL_GET_LINE_CONTROL: {
  721. PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer;
  722. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  723. sizeof(SERIAL_LINE_CONTROL)) {
  724. Status = STATUS_BUFFER_TOO_SMALL;
  725. break;
  726. }
  727. KeAcquireSpinLock(
  728. &Extension->ControlLock,
  729. &OldIrql
  730. );
  731. if ((Extension->LineControl & SERIAL_DATA_MASK) == SERIAL_5_DATA) {
  732. Lc->WordLength = 5;
  733. } else if ((Extension->LineControl & SERIAL_DATA_MASK)
  734. == SERIAL_6_DATA) {
  735. Lc->WordLength = 6;
  736. } else if ((Extension->LineControl & SERIAL_DATA_MASK)
  737. == SERIAL_7_DATA) {
  738. Lc->WordLength = 7;
  739. } else if ((Extension->LineControl & SERIAL_DATA_MASK)
  740. == SERIAL_8_DATA) {
  741. Lc->WordLength = 8;
  742. }
  743. if ((Extension->LineControl & SERIAL_PARITY_MASK)
  744. == SERIAL_NONE_PARITY) {
  745. Lc->Parity = NO_PARITY;
  746. } else if ((Extension->LineControl & SERIAL_PARITY_MASK)
  747. == SERIAL_ODD_PARITY) {
  748. Lc->Parity = ODD_PARITY;
  749. } else if ((Extension->LineControl & SERIAL_PARITY_MASK)
  750. == SERIAL_EVEN_PARITY) {
  751. Lc->Parity = EVEN_PARITY;
  752. } else if ((Extension->LineControl & SERIAL_PARITY_MASK)
  753. == SERIAL_MARK_PARITY) {
  754. Lc->Parity = MARK_PARITY;
  755. } else if ((Extension->LineControl & SERIAL_PARITY_MASK)
  756. == SERIAL_SPACE_PARITY) {
  757. Lc->Parity = SPACE_PARITY;
  758. }
  759. if (Extension->LineControl & SERIAL_2_STOP) {
  760. if (Lc->WordLength == 5) {
  761. Lc->StopBits = STOP_BITS_1_5;
  762. } else {
  763. Lc->StopBits = STOP_BITS_2;
  764. }
  765. } else {
  766. Lc->StopBits = STOP_BIT_1;
  767. }
  768. Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL);
  769. KeReleaseSpinLock(
  770. &Extension->ControlLock,
  771. OldIrql
  772. );
  773. break;
  774. }
  775. case IOCTL_SERIAL_SET_TIMEOUTS: {
  776. PSERIAL_TIMEOUTS NewTimeouts =
  777. ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
  778. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  779. sizeof(SERIAL_TIMEOUTS)) {
  780. Status = STATUS_BUFFER_TOO_SMALL;
  781. break;
  782. }
  783. if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) &&
  784. (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&
  785. (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG)) {
  786. Status = STATUS_INVALID_PARAMETER;
  787. break;
  788. }
  789. KeAcquireSpinLock(
  790. &Extension->ControlLock,
  791. &OldIrql
  792. );
  793. Extension->Timeouts.ReadIntervalTimeout =
  794. NewTimeouts->ReadIntervalTimeout;
  795. Extension->Timeouts.ReadTotalTimeoutMultiplier =
  796. NewTimeouts->ReadTotalTimeoutMultiplier;
  797. Extension->Timeouts.ReadTotalTimeoutConstant =
  798. NewTimeouts->ReadTotalTimeoutConstant;
  799. Extension->Timeouts.WriteTotalTimeoutMultiplier =
  800. NewTimeouts->WriteTotalTimeoutMultiplier;
  801. Extension->Timeouts.WriteTotalTimeoutConstant =
  802. NewTimeouts->WriteTotalTimeoutConstant;
  803. KeReleaseSpinLock(
  804. &Extension->ControlLock,
  805. OldIrql
  806. );
  807. break;
  808. }
  809. case IOCTL_SERIAL_GET_TIMEOUTS: {
  810. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  811. sizeof(SERIAL_TIMEOUTS)) {
  812. Status = STATUS_BUFFER_TOO_SMALL;
  813. break;
  814. }
  815. KeAcquireSpinLock(
  816. &Extension->ControlLock,
  817. &OldIrql
  818. );
  819. *((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) = Extension->Timeouts;
  820. Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
  821. KeReleaseSpinLock(
  822. &Extension->ControlLock,
  823. OldIrql
  824. );
  825. break;
  826. }
  827. case IOCTL_SERIAL_SET_CHARS: {
  828. SERIAL_IOCTL_SYNC S;
  829. PSERIAL_CHARS NewChars =
  830. ((PSERIAL_CHARS)(Irp->AssociatedIrp.SystemBuffer));
  831. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  832. sizeof(SERIAL_CHARS)) {
  833. Status = STATUS_BUFFER_TOO_SMALL;
  834. break;
  835. }
  836. //
  837. // The only thing that can be wrong with the chars
  838. // is that the xon and xoff characters are the
  839. // same.
  840. //
  841. #if 0
  842. if (NewChars->XonChar == NewChars->XoffChar) {
  843. Status = STATUS_INVALID_PARAMETER;
  844. break;
  845. }
  846. #endif
  847. //
  848. // We acquire the control lock so that only
  849. // one request can GET or SET the characters
  850. // at a time. The sets could be synchronized
  851. // by the interrupt spinlock, but that wouldn't
  852. // prevent multiple gets at the same time.
  853. //
  854. S.Extension = Extension;
  855. S.Data = NewChars;
  856. KeAcquireSpinLock(
  857. &Extension->ControlLock,
  858. &OldIrql
  859. );
  860. //
  861. // Under the protection of the lock, make sure that
  862. // the xon and xoff characters aren't the same as
  863. // the escape character.
  864. //
  865. if (Extension->EscapeChar) {
  866. if ((Extension->EscapeChar == NewChars->XonChar) ||
  867. (Extension->EscapeChar == NewChars->XoffChar)) {
  868. Status = STATUS_INVALID_PARAMETER;
  869. KeReleaseSpinLock(
  870. &Extension->ControlLock,
  871. OldIrql
  872. );
  873. break;
  874. }
  875. }
  876. Extension->WmiCommData.XonCharacter = NewChars->XonChar;
  877. Extension->WmiCommData.XoffCharacter = NewChars->XoffChar;
  878. KeSynchronizeExecution(
  879. Extension->Interrupt,
  880. SerialSetChars,
  881. &S
  882. );
  883. KeReleaseSpinLock(
  884. &Extension->ControlLock,
  885. OldIrql
  886. );
  887. break;
  888. }
  889. case IOCTL_SERIAL_GET_CHARS: {
  890. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  891. sizeof(SERIAL_CHARS)) {
  892. Status = STATUS_BUFFER_TOO_SMALL;
  893. break;
  894. }
  895. KeAcquireSpinLock(
  896. &Extension->ControlLock,
  897. &OldIrql
  898. );
  899. *((PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer) = Extension->SpecialChars;
  900. Irp->IoStatus.Information = sizeof(SERIAL_CHARS);
  901. KeReleaseSpinLock(
  902. &Extension->ControlLock,
  903. OldIrql
  904. );
  905. break;
  906. }
  907. case IOCTL_SERIAL_SET_DTR:
  908. case IOCTL_SERIAL_CLR_DTR: {
  909. //
  910. // Make sure we are at power D0
  911. //
  912. if (Extension->PowerState != PowerDeviceD0) {
  913. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  914. PowerDeviceD0);
  915. if (!NT_SUCCESS(Status)) {
  916. break;
  917. }
  918. }
  919. //
  920. // We acquire the lock so that we can check whether
  921. // automatic dtr flow control is enabled. If it is
  922. // then we return an error since the app is not allowed
  923. // to touch this if it is automatic.
  924. //
  925. KeAcquireSpinLock(
  926. &Extension->ControlLock,
  927. &OldIrql
  928. );
  929. if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK)
  930. == SERIAL_DTR_HANDSHAKE) {
  931. Status = STATUS_INVALID_PARAMETER;
  932. } else {
  933. KeSynchronizeExecution(
  934. Extension->Interrupt,
  935. ((IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  936. IOCTL_SERIAL_SET_DTR)?
  937. (SerialSetDTR):(SerialClrDTR)),
  938. Extension
  939. );
  940. }
  941. KeReleaseSpinLock(
  942. &Extension->ControlLock,
  943. OldIrql
  944. );
  945. break;
  946. }
  947. case IOCTL_SERIAL_RESET_DEVICE: {
  948. break;
  949. }
  950. case IOCTL_SERIAL_SET_RTS:
  951. case IOCTL_SERIAL_CLR_RTS: {
  952. //
  953. // Make sure we are at power D0
  954. //
  955. if (Extension->PowerState != PowerDeviceD0) {
  956. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  957. PowerDeviceD0);
  958. if (!NT_SUCCESS(Status)) {
  959. break;
  960. }
  961. }
  962. //
  963. // We acquire the lock so that we can check whether
  964. // automatic rts flow control or transmit toggleing
  965. // is enabled. If it is then we return an error since
  966. // the app is not allowed to touch this if it is automatic
  967. // or toggling.
  968. //
  969. KeAcquireSpinLock(
  970. &Extension->ControlLock,
  971. &OldIrql
  972. );
  973. if (((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
  974. == SERIAL_RTS_HANDSHAKE) ||
  975. ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
  976. == SERIAL_TRANSMIT_TOGGLE)) {
  977. Status = STATUS_INVALID_PARAMETER;
  978. } else {
  979. KeSynchronizeExecution(
  980. Extension->Interrupt,
  981. ((IrpSp->Parameters.DeviceIoControl.IoControlCode ==
  982. IOCTL_SERIAL_SET_RTS)?
  983. (SerialSetRTS):(SerialClrRTS)),
  984. Extension
  985. );
  986. }
  987. KeReleaseSpinLock(
  988. &Extension->ControlLock,
  989. OldIrql
  990. );
  991. break;
  992. }
  993. case IOCTL_SERIAL_SET_XOFF: {
  994. KeSynchronizeExecution(
  995. Extension->Interrupt,
  996. SerialPretendXoff,
  997. Extension
  998. );
  999. break;
  1000. }
  1001. case IOCTL_SERIAL_SET_XON: {
  1002. KeSynchronizeExecution(
  1003. Extension->Interrupt,
  1004. SerialPretendXon,
  1005. Extension
  1006. );
  1007. break;
  1008. }
  1009. case IOCTL_SERIAL_SET_BREAK_ON: {
  1010. //
  1011. // Make sure we are at power D0
  1012. //
  1013. if (Extension->PowerState != PowerDeviceD0) {
  1014. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  1015. PowerDeviceD0);
  1016. if (!NT_SUCCESS(Status)) {
  1017. break;
  1018. }
  1019. }
  1020. KeSynchronizeExecution(
  1021. Extension->Interrupt,
  1022. SerialTurnOnBreak,
  1023. Extension
  1024. );
  1025. break;
  1026. }
  1027. case IOCTL_SERIAL_SET_BREAK_OFF: {
  1028. //
  1029. // Make sure we are at power D0
  1030. //
  1031. if (Extension->PowerState != PowerDeviceD0) {
  1032. Status = SerialGotoPowerState(Extension->Pdo, Extension,
  1033. PowerDeviceD0);
  1034. if (!NT_SUCCESS(Status)) {
  1035. break;
  1036. }
  1037. }
  1038. KeSynchronizeExecution(
  1039. Extension->Interrupt,
  1040. SerialTurnOffBreak,
  1041. Extension
  1042. );
  1043. break;
  1044. }
  1045. case IOCTL_SERIAL_SET_QUEUE_SIZE: {
  1046. //
  1047. // Type ahead buffer is fixed, so we just validate
  1048. // the the users request is not bigger that our
  1049. // own internal buffer size.
  1050. //
  1051. PSERIAL_QUEUE_SIZE Rs =
  1052. ((PSERIAL_QUEUE_SIZE)(Irp->AssociatedIrp.SystemBuffer));
  1053. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1054. sizeof(SERIAL_QUEUE_SIZE)) {
  1055. Status = STATUS_BUFFER_TOO_SMALL;
  1056. break;
  1057. }
  1058. //
  1059. // We have to allocate the memory for the new
  1060. // buffer while we're still in the context of the
  1061. // caller. We don't even try to protect this
  1062. // with a lock because the value could be stale
  1063. // as soon as we release the lock - The only time
  1064. // we will know for sure is when we actually try
  1065. // to do the resize.
  1066. //
  1067. if (Rs->InSize <= Extension->BufferSize) {
  1068. Status = STATUS_SUCCESS;
  1069. break;
  1070. }
  1071. try {
  1072. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  1073. ExAllocatePoolWithQuota(
  1074. NonPagedPool,
  1075. Rs->InSize
  1076. );
  1077. } except (EXCEPTION_EXECUTE_HANDLER) {
  1078. IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  1079. Status = GetExceptionCode();
  1080. }
  1081. if (!IrpSp->Parameters.DeviceIoControl.Type3InputBuffer) {
  1082. break;
  1083. }
  1084. //
  1085. // Well the data passed was big enough. Do the request.
  1086. //
  1087. // There are two reason we place it in the read queue:
  1088. //
  1089. // 1) We want to serialize these resize requests so that
  1090. // they don't contend with each other.
  1091. //
  1092. // 2) We want to serialize these requests with reads since
  1093. // we don't want reads and resizes contending over the
  1094. // read buffer.
  1095. //
  1096. return SerialStartOrQueue(
  1097. Extension,
  1098. Irp,
  1099. &Extension->ReadQueue,
  1100. &Extension->CurrentReadIrp,
  1101. SerialStartRead
  1102. );
  1103. break;
  1104. }
  1105. case IOCTL_SERIAL_GET_WAIT_MASK: {
  1106. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1107. sizeof(ULONG)) {
  1108. Status = STATUS_BUFFER_TOO_SMALL;
  1109. break;
  1110. }
  1111. //
  1112. // Simple scalar read. No reason to acquire a lock.
  1113. //
  1114. Irp->IoStatus.Information = sizeof(ULONG);
  1115. *((ULONG *)Irp->AssociatedIrp.SystemBuffer) = Extension->IsrWaitMask;
  1116. break;
  1117. }
  1118. case IOCTL_SERIAL_SET_WAIT_MASK: {
  1119. ULONG NewMask;
  1120. SerialDump(
  1121. SERDIAG3 | SERIRPPATH,
  1122. ("SERIAL: In Ioctl processing for set mask\n")
  1123. );
  1124. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1125. sizeof(ULONG)) {
  1126. SerialDump(
  1127. SERDIAG3,
  1128. ("SERIAL: Invalid size fo the buffer %d\n",
  1129. IrpSp->Parameters.DeviceIoControl.InputBufferLength)
  1130. );
  1131. Status = STATUS_BUFFER_TOO_SMALL;
  1132. break;
  1133. } else {
  1134. NewMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer);
  1135. }
  1136. //
  1137. // Make sure that the mask only contains valid
  1138. // waitable events.
  1139. //
  1140. if (NewMask & ~(SERIAL_EV_RXCHAR |
  1141. SERIAL_EV_RXFLAG |
  1142. SERIAL_EV_TXEMPTY |
  1143. SERIAL_EV_CTS |
  1144. SERIAL_EV_DSR |
  1145. SERIAL_EV_RLSD |
  1146. SERIAL_EV_BREAK |
  1147. SERIAL_EV_ERR |
  1148. SERIAL_EV_RING |
  1149. SERIAL_EV_PERR |
  1150. SERIAL_EV_RX80FULL |
  1151. SERIAL_EV_EVENT1 |
  1152. SERIAL_EV_EVENT2)) {
  1153. SerialDump(
  1154. SERDIAG3,
  1155. ("SERIAL: Unknown mask %x\n",NewMask)
  1156. );
  1157. Status = STATUS_INVALID_PARAMETER;
  1158. break;
  1159. }
  1160. //
  1161. // Either start this irp or put it on the
  1162. // queue.
  1163. //
  1164. SerialDump(
  1165. SERDIAG3 | SERIRPPATH,
  1166. ("SERIAL: Starting or queuing set mask irp %x\n",Irp)
  1167. );
  1168. return SerialStartOrQueue(
  1169. Extension,
  1170. Irp,
  1171. &Extension->MaskQueue,
  1172. &Extension->CurrentMaskIrp,
  1173. SerialStartMask
  1174. );
  1175. }
  1176. case IOCTL_SERIAL_WAIT_ON_MASK: {
  1177. SerialDump(
  1178. SERDIAG3 | SERIRPPATH,
  1179. ("SERIAL: In Ioctl processing for wait mask\n")
  1180. );
  1181. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1182. sizeof(ULONG)) {
  1183. SerialDump(
  1184. SERDIAG3,
  1185. ("SERIAL: Invalid size for the buffer %d\n",
  1186. IrpSp->Parameters.DeviceIoControl.OutputBufferLength)
  1187. );
  1188. Status = STATUS_BUFFER_TOO_SMALL;
  1189. break;
  1190. }
  1191. //
  1192. // Either start this irp or put it on the
  1193. // queue.
  1194. //
  1195. SerialDump(
  1196. SERDIAG3 | SERIRPPATH,
  1197. ("SERIAL: Starting or queuing wait mask irp %x\n",Irp)
  1198. );
  1199. return SerialStartOrQueue(
  1200. Extension,
  1201. Irp,
  1202. &Extension->MaskQueue,
  1203. &Extension->CurrentMaskIrp,
  1204. SerialStartMask
  1205. );
  1206. }
  1207. case IOCTL_SERIAL_IMMEDIATE_CHAR: {
  1208. KIRQL OldIrql;
  1209. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1210. sizeof(UCHAR)) {
  1211. Status = STATUS_BUFFER_TOO_SMALL;
  1212. break;
  1213. }
  1214. IoAcquireCancelSpinLock(&OldIrql);
  1215. if (Extension->CurrentImmediateIrp) {
  1216. Status = STATUS_INVALID_PARAMETER;
  1217. IoReleaseCancelSpinLock(OldIrql);
  1218. } else {
  1219. //
  1220. // We can queue the char. We need to set
  1221. // a cancel routine because flow control could
  1222. // keep the char from transmitting. Make sure
  1223. // that the irp hasn't already been canceled.
  1224. //
  1225. if (Irp->Cancel) {
  1226. IoReleaseCancelSpinLock(OldIrql);
  1227. Status = STATUS_CANCELLED;
  1228. } else {
  1229. Extension->CurrentImmediateIrp = Irp;
  1230. Extension->TotalCharsQueued++;
  1231. IoReleaseCancelSpinLock(OldIrql);
  1232. SerialStartImmediate(Extension);
  1233. return STATUS_PENDING;
  1234. }
  1235. }
  1236. break;
  1237. }
  1238. case IOCTL_SERIAL_PURGE: {
  1239. ULONG Mask;
  1240. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1241. sizeof(ULONG)) {
  1242. Status = STATUS_BUFFER_TOO_SMALL;
  1243. break;
  1244. }
  1245. //
  1246. // Check to make sure that the mask only has
  1247. // 0 or the other appropriate values.
  1248. //
  1249. Mask = *((ULONG *)(Irp->AssociatedIrp.SystemBuffer));
  1250. if ((!Mask) || (Mask & (~(SERIAL_PURGE_TXABORT |
  1251. SERIAL_PURGE_RXABORT |
  1252. SERIAL_PURGE_TXCLEAR |
  1253. SERIAL_PURGE_RXCLEAR
  1254. )
  1255. )
  1256. )) {
  1257. Status = STATUS_INVALID_PARAMETER;
  1258. break;
  1259. }
  1260. //
  1261. // Either start this irp or put it on the
  1262. // queue.
  1263. //
  1264. return SerialStartOrQueue(
  1265. Extension,
  1266. Irp,
  1267. &Extension->PurgeQueue,
  1268. &Extension->CurrentPurgeIrp,
  1269. SerialStartPurge
  1270. );
  1271. }
  1272. case IOCTL_SERIAL_GET_HANDFLOW: {
  1273. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1274. sizeof(SERIAL_HANDFLOW)) {
  1275. Status = STATUS_BUFFER_TOO_SMALL;
  1276. break;
  1277. }
  1278. Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW);
  1279. KeAcquireSpinLock(
  1280. &Extension->ControlLock,
  1281. &OldIrql
  1282. );
  1283. *((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) =
  1284. Extension->HandFlow;
  1285. KeReleaseSpinLock(
  1286. &Extension->ControlLock,
  1287. OldIrql
  1288. );
  1289. break;
  1290. }
  1291. case IOCTL_SERIAL_SET_HANDFLOW: {
  1292. SERIAL_IOCTL_SYNC S;
  1293. PSERIAL_HANDFLOW HandFlow = Irp->AssociatedIrp.SystemBuffer;
  1294. //
  1295. // Make sure that the hand shake and control is the
  1296. // right size.
  1297. //
  1298. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1299. sizeof(SERIAL_HANDFLOW)) {
  1300. Status = STATUS_BUFFER_TOO_SMALL;
  1301. break;
  1302. }
  1303. //
  1304. // Make sure that there are no invalid bits set in
  1305. // the control and handshake.
  1306. //
  1307. if (HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) {
  1308. Status = STATUS_INVALID_PARAMETER;
  1309. break;
  1310. }
  1311. if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID) {
  1312. Status = STATUS_INVALID_PARAMETER;
  1313. break;
  1314. }
  1315. //
  1316. // Make sure that the app hasn't set an invlid DTR mode.
  1317. //
  1318. if ((HandFlow->ControlHandShake & SERIAL_DTR_MASK) ==
  1319. SERIAL_DTR_MASK) {
  1320. Status = STATUS_INVALID_PARAMETER;
  1321. break;
  1322. }
  1323. //
  1324. // Make sure that haven't set totally invalid xon/xoff
  1325. // limits.
  1326. //
  1327. if ((HandFlow->XonLimit < 0) ||
  1328. ((ULONG)HandFlow->XonLimit > Extension->BufferSize)) {
  1329. Status = STATUS_INVALID_PARAMETER;
  1330. break;
  1331. }
  1332. if ((HandFlow->XoffLimit < 0) ||
  1333. ((ULONG)HandFlow->XoffLimit > Extension->BufferSize)) {
  1334. Status = STATUS_INVALID_PARAMETER;
  1335. break;
  1336. }
  1337. S.Extension = Extension;
  1338. S.Data = HandFlow;
  1339. KeAcquireSpinLock(
  1340. &Extension->ControlLock,
  1341. &OldIrql
  1342. );
  1343. //
  1344. // Under the protection of the lock, make sure that
  1345. // we aren't turning on error replacement when we
  1346. // are doing line status/modem status insertion.
  1347. //
  1348. if (Extension->EscapeChar) {
  1349. if (HandFlow->FlowReplace & SERIAL_ERROR_CHAR) {
  1350. Status = STATUS_INVALID_PARAMETER;
  1351. KeReleaseSpinLock(
  1352. &Extension->ControlLock,
  1353. OldIrql
  1354. );
  1355. break;
  1356. }
  1357. }
  1358. KeSynchronizeExecution(
  1359. Extension->Interrupt,
  1360. SerialSetHandFlow,
  1361. &S
  1362. );
  1363. KeReleaseSpinLock(
  1364. &Extension->ControlLock,
  1365. OldIrql
  1366. );
  1367. break;
  1368. }
  1369. case IOCTL_SERIAL_GET_MODEMSTATUS: {
  1370. SERIAL_IOCTL_SYNC S;
  1371. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1372. sizeof(ULONG)) {
  1373. Status = STATUS_BUFFER_TOO_SMALL;
  1374. break;
  1375. }
  1376. Irp->IoStatus.Information = sizeof(ULONG);
  1377. S.Extension = Extension;
  1378. S.Data = Irp->AssociatedIrp.SystemBuffer;
  1379. KeAcquireSpinLock(
  1380. &Extension->ControlLock,
  1381. &OldIrql
  1382. );
  1383. KeSynchronizeExecution(
  1384. Extension->Interrupt,
  1385. SerialGetModemUpdate,
  1386. &S
  1387. );
  1388. KeReleaseSpinLock(
  1389. &Extension->ControlLock,
  1390. OldIrql
  1391. );
  1392. break;
  1393. }
  1394. case IOCTL_SERIAL_GET_DTRRTS: {
  1395. ULONG ModemControl;
  1396. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1397. sizeof(ULONG)) {
  1398. Status = STATUS_BUFFER_TOO_SMALL;
  1399. break;
  1400. }
  1401. Irp->IoStatus.Information = sizeof(ULONG);
  1402. Irp->IoStatus.Status = STATUS_SUCCESS;
  1403. //
  1404. // Reading this hardware has no effect on the device.
  1405. //
  1406. ModemControl = READ_MODEM_CONTROL(Extension->Controller);
  1407. ModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE;
  1408. *(PULONG)Irp->AssociatedIrp.SystemBuffer = ModemControl;
  1409. break;
  1410. }
  1411. case IOCTL_SERIAL_GET_COMMSTATUS: {
  1412. SERIAL_IOCTL_SYNC S;
  1413. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1414. sizeof(SERIAL_STATUS)) {
  1415. Status = STATUS_BUFFER_TOO_SMALL;
  1416. break;
  1417. }
  1418. Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
  1419. S.Extension = Extension;
  1420. S.Data = Irp->AssociatedIrp.SystemBuffer;
  1421. //
  1422. // Acquire the cancel spin lock so nothing much
  1423. // changes while were getting the state.
  1424. //
  1425. IoAcquireCancelSpinLock(&OldIrql);
  1426. KeSynchronizeExecution(
  1427. Extension->Interrupt,
  1428. SerialGetCommStatus,
  1429. &S
  1430. );
  1431. IoReleaseCancelSpinLock(OldIrql);
  1432. break;
  1433. }
  1434. case IOCTL_SERIAL_GET_PROPERTIES: {
  1435. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1436. sizeof(SERIAL_COMMPROP)) {
  1437. Status = STATUS_BUFFER_TOO_SMALL;
  1438. break;
  1439. }
  1440. //
  1441. // No synchronization is required since this information
  1442. // is "static".
  1443. //
  1444. SerialGetProperties(
  1445. Extension,
  1446. Irp->AssociatedIrp.SystemBuffer
  1447. );
  1448. Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
  1449. Irp->IoStatus.Status = STATUS_SUCCESS;
  1450. break;
  1451. }
  1452. case IOCTL_SERIAL_XOFF_COUNTER: {
  1453. PSERIAL_XOFF_COUNTER Xc = Irp->AssociatedIrp.SystemBuffer;
  1454. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1455. sizeof(SERIAL_XOFF_COUNTER)) {
  1456. Status = STATUS_BUFFER_TOO_SMALL;
  1457. break;
  1458. }
  1459. if (Xc->Counter <= 0) {
  1460. Status = STATUS_INVALID_PARAMETER;
  1461. break;
  1462. }
  1463. //
  1464. // There is no output, so make that clear now
  1465. //
  1466. Irp->IoStatus.Information = 0;
  1467. //
  1468. // So far so good. Put the irp onto the write queue.
  1469. //
  1470. return SerialStartOrQueue(
  1471. Extension,
  1472. Irp,
  1473. &Extension->WriteQueue,
  1474. &Extension->CurrentWriteIrp,
  1475. SerialStartWrite
  1476. );
  1477. }
  1478. case IOCTL_SERIAL_LSRMST_INSERT: {
  1479. PUCHAR escapeChar = Irp->AssociatedIrp.SystemBuffer;
  1480. SERIAL_IOCTL_SYNC S;
  1481. //
  1482. // Make sure we get a byte.
  1483. //
  1484. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1485. sizeof(UCHAR)) {
  1486. Status = STATUS_BUFFER_TOO_SMALL;
  1487. break;
  1488. }
  1489. KeAcquireSpinLock(
  1490. &Extension->ControlLock,
  1491. &OldIrql
  1492. );
  1493. if (*escapeChar) {
  1494. //
  1495. // We've got some escape work to do. We will make sure that
  1496. // the character is not the same as the Xon or Xoff character,
  1497. // or that we are already doing error replacement.
  1498. //
  1499. if ((*escapeChar == Extension->SpecialChars.XoffChar) ||
  1500. (*escapeChar == Extension->SpecialChars.XonChar) ||
  1501. (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR)) {
  1502. Status = STATUS_INVALID_PARAMETER;
  1503. KeReleaseSpinLock(
  1504. &Extension->ControlLock,
  1505. OldIrql
  1506. );
  1507. break;
  1508. }
  1509. }
  1510. S.Extension = Extension;
  1511. S.Data = Irp->AssociatedIrp.SystemBuffer;
  1512. KeSynchronizeExecution(
  1513. Extension->Interrupt,
  1514. SerialSetEscapeChar,
  1515. Irp
  1516. );
  1517. KeReleaseSpinLock(
  1518. &Extension->ControlLock,
  1519. OldIrql
  1520. );
  1521. break;
  1522. }
  1523. case IOCTL_SERIAL_CONFIG_SIZE: {
  1524. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1525. sizeof(ULONG)) {
  1526. Status = STATUS_BUFFER_TOO_SMALL;
  1527. break;
  1528. }
  1529. Irp->IoStatus.Information = sizeof(ULONG);
  1530. Irp->IoStatus.Status = STATUS_SUCCESS;
  1531. *(PULONG)Irp->AssociatedIrp.SystemBuffer = 0;
  1532. break;
  1533. }
  1534. case IOCTL_SERIAL_GET_STATS: {
  1535. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1536. sizeof(SERIALPERF_STATS)) {
  1537. Status = STATUS_BUFFER_TOO_SMALL;
  1538. break;
  1539. }
  1540. Irp->IoStatus.Information = sizeof(SERIALPERF_STATS);
  1541. Irp->IoStatus.Status = STATUS_SUCCESS;
  1542. KeSynchronizeExecution(
  1543. Extension->Interrupt,
  1544. SerialGetStats,
  1545. Irp
  1546. );
  1547. break;
  1548. }
  1549. case IOCTL_SERIAL_CLEAR_STATS: {
  1550. KeSynchronizeExecution(
  1551. Extension->Interrupt,
  1552. SerialClearStats,
  1553. Extension
  1554. );
  1555. break;
  1556. }
  1557. default: {
  1558. Status = STATUS_INVALID_PARAMETER;
  1559. break;
  1560. }
  1561. }
  1562. DoneWithIoctl:;
  1563. Irp->IoStatus.Status = Status;
  1564. SerialDump(
  1565. SERIRPPATH,
  1566. ("SERIAL: Complete Irp: %x\n",Irp)
  1567. );
  1568. SerialCompleteRequest(Extension, Irp, 0);
  1569. return Status;
  1570. }
  1571. VOID
  1572. SerialGetProperties(
  1573. IN PSERIAL_DEVICE_EXTENSION Extension,
  1574. IN PSERIAL_COMMPROP Properties
  1575. )
  1576. /*++
  1577. Routine Description:
  1578. This function returns the capabilities of this particular
  1579. serial device.
  1580. Arguments:
  1581. Extension - The serial device extension.
  1582. Properties - The structure used to return the properties
  1583. Return Value:
  1584. None.
  1585. --*/
  1586. {
  1587. SERIAL_LOCKED_PAGED_CODE();
  1588. RtlZeroMemory(
  1589. Properties,
  1590. sizeof(SERIAL_COMMPROP)
  1591. );
  1592. Properties->PacketLength = sizeof(SERIAL_COMMPROP);
  1593. Properties->PacketVersion = 2;
  1594. Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
  1595. Properties->MaxTxQueue = 0;
  1596. Properties->MaxRxQueue = 0;
  1597. Properties->MaxBaud = SERIAL_BAUD_USER;
  1598. Properties->SettableBaud = Extension->SupportedBauds;
  1599. Properties->ProvSubType = SERIAL_SP_RS232;
  1600. Properties->ProvCapabilities = SERIAL_PCF_DTRDSR |
  1601. SERIAL_PCF_RTSCTS |
  1602. SERIAL_PCF_CD |
  1603. SERIAL_PCF_PARITY_CHECK |
  1604. SERIAL_PCF_XONXOFF |
  1605. SERIAL_PCF_SETXCHAR |
  1606. SERIAL_PCF_TOTALTIMEOUTS |
  1607. SERIAL_PCF_INTTIMEOUTS;
  1608. Properties->SettableParams = SERIAL_SP_PARITY |
  1609. SERIAL_SP_BAUD |
  1610. SERIAL_SP_DATABITS |
  1611. SERIAL_SP_STOPBITS |
  1612. SERIAL_SP_HANDSHAKING |
  1613. SERIAL_SP_PARITY_CHECK |
  1614. SERIAL_SP_CARRIER_DETECT;
  1615. Properties->SettableData = SERIAL_DATABITS_5 |
  1616. SERIAL_DATABITS_6 |
  1617. SERIAL_DATABITS_7 |
  1618. SERIAL_DATABITS_8;
  1619. #if defined(NEC_98)
  1620. //
  1621. // COM1 of PC-9800 series is not support MarkParity and SpaceParity.
  1622. //
  1623. Properties->SettableStopParity = SERIAL_STOPBITS_10 |
  1624. SERIAL_STOPBITS_15 |
  1625. SERIAL_STOPBITS_20 |
  1626. SERIAL_PARITY_NONE |
  1627. SERIAL_PARITY_ODD |
  1628. SERIAL_PARITY_EVEN;
  1629. #else
  1630. Properties->SettableStopParity = SERIAL_STOPBITS_10 |
  1631. SERIAL_STOPBITS_15 |
  1632. SERIAL_STOPBITS_20 |
  1633. SERIAL_PARITY_NONE |
  1634. SERIAL_PARITY_ODD |
  1635. SERIAL_PARITY_EVEN |
  1636. SERIAL_PARITY_MARK |
  1637. SERIAL_PARITY_SPACE;
  1638. #endif //defined(NEC_98)
  1639. Properties->CurrentTxQueue = 0;
  1640. Properties->CurrentRxQueue = Extension->BufferSize;
  1641. }
  1642. NTSTATUS
  1643. SerialInternalIoControl(IN PDEVICE_OBJECT PDevObj, IN PIRP PIrp)
  1644. /*++
  1645. Routine Description:
  1646. This routine provides the initial processing for all of the
  1647. internal Ioctrls for the serial device.
  1648. Arguments:
  1649. PDevObj - Pointer to the device object for this device
  1650. PIrp - Pointer to the IRP for the current request
  1651. Return Value:
  1652. The function value is the final status of the call
  1653. --*/
  1654. {
  1655. //
  1656. // The status that gets returned to the caller and
  1657. // set in the Irp.
  1658. //
  1659. NTSTATUS status;
  1660. //
  1661. // The current stack location. This contains all of the
  1662. // information we need to process this particular request.
  1663. //
  1664. PIO_STACK_LOCATION pIrpStack;
  1665. //
  1666. // Just what it says. This is the serial specific device
  1667. // extension of the device object create for the serial driver.
  1668. //
  1669. PSERIAL_DEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  1670. #if defined(NEC_98)
  1671. //
  1672. // This argument use at MACRO only.
  1673. //
  1674. PSERIAL_DEVICE_EXTENSION Extension = pDevExt;
  1675. #else
  1676. #endif //defined(NEC_98)
  1677. //
  1678. // A temporary to hold the old IRQL so that it can be
  1679. // restored once we complete/validate this request.
  1680. //
  1681. KIRQL OldIrql;
  1682. NTSTATUS prologueStatus;
  1683. SERIAL_LOCKED_PAGED_CODE();
  1684. if ((prologueStatus = SerialIRPPrologue(PIrp, pDevExt))
  1685. != STATUS_SUCCESS) {
  1686. SerialCompleteRequest(pDevExt, PIrp, IO_NO_INCREMENT);
  1687. return prologueStatus;
  1688. }
  1689. SerialDump(SERIRPPATH, ("SERIAL: Dispatch entry for: %x\n", PIrp));
  1690. if (SerialCompleteIfError(PDevObj, PIrp) != STATUS_SUCCESS) {
  1691. return STATUS_CANCELLED;
  1692. }
  1693. pIrpStack = IoGetCurrentIrpStackLocation(PIrp);
  1694. PIrp->IoStatus.Information = 0L;
  1695. status = STATUS_SUCCESS;
  1696. switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode) {
  1697. //
  1698. // Send a wait-wake IRP
  1699. //
  1700. case IOCTL_SERIAL_INTERNAL_DO_WAIT_WAKE:
  1701. pDevExt->SendWaitWake = TRUE;
  1702. status = STATUS_SUCCESS;
  1703. break;
  1704. case IOCTL_SERIAL_INTERNAL_CANCEL_WAIT_WAKE:
  1705. pDevExt->SendWaitWake = FALSE;
  1706. if (pDevExt->PendingWakeIrp != NULL) {
  1707. IoCancelIrp(pDevExt->PendingWakeIrp);
  1708. }
  1709. status = STATUS_SUCCESS;
  1710. break;
  1711. //
  1712. // Put the serial port in a "filter-driver" appropriate state
  1713. //
  1714. // WARNING: This code assumes it is being called by a trusted kernel
  1715. // entity and no checking is done on the validity of the settings
  1716. // passed to IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS
  1717. //
  1718. // If validity checking is desired, the regular ioctl's should be used
  1719. //
  1720. case IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS:
  1721. case IOCTL_SERIAL_INTERNAL_RESTORE_SETTINGS: {
  1722. SERIAL_BASIC_SETTINGS basic;
  1723. PSERIAL_BASIC_SETTINGS pBasic;
  1724. SHORT AppropriateDivisor;
  1725. SERIAL_IOCTL_SYNC S;
  1726. if (pIrpStack->Parameters.DeviceIoControl.IoControlCode
  1727. == IOCTL_SERIAL_INTERNAL_BASIC_SETTINGS) {
  1728. //
  1729. // Check the buffer size
  1730. //
  1731. if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength <
  1732. sizeof(SERIAL_BASIC_SETTINGS)) {
  1733. status = STATUS_BUFFER_TOO_SMALL;
  1734. break;
  1735. }
  1736. //
  1737. // Everything is 0 -- timeouts and flow control and fifos. If
  1738. // We add additional features, this zero memory method
  1739. // may not work.
  1740. //
  1741. RtlZeroMemory(&basic, sizeof(SERIAL_BASIC_SETTINGS));
  1742. basic.TxFifo = 1;
  1743. basic.RxFifo = SERIAL_1_BYTE_HIGH_WATER;
  1744. PIrp->IoStatus.Information = sizeof(SERIAL_BASIC_SETTINGS);
  1745. pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer;
  1746. //
  1747. // Save off the old settings
  1748. //
  1749. RtlCopyMemory(&pBasic->Timeouts, &pDevExt->Timeouts,
  1750. sizeof(SERIAL_TIMEOUTS));
  1751. RtlCopyMemory(&pBasic->HandFlow, &pDevExt->HandFlow,
  1752. sizeof(SERIAL_HANDFLOW));
  1753. pBasic->RxFifo = pDevExt->RxFifoTrigger;
  1754. pBasic->TxFifo = pDevExt->TxFifoAmount;
  1755. //
  1756. // Point to our new settings
  1757. //
  1758. pBasic = &basic;
  1759. } else { // restoring settings
  1760. if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength
  1761. < sizeof(SERIAL_BASIC_SETTINGS)) {
  1762. status = STATUS_BUFFER_TOO_SMALL;
  1763. break;
  1764. }
  1765. pBasic = (PSERIAL_BASIC_SETTINGS)PIrp->AssociatedIrp.SystemBuffer;
  1766. }
  1767. KeAcquireSpinLock(&pDevExt->ControlLock, &OldIrql);
  1768. //
  1769. // Set the timeouts
  1770. //
  1771. RtlCopyMemory(&pDevExt->Timeouts, &pBasic->Timeouts,
  1772. sizeof(SERIAL_TIMEOUTS));
  1773. //
  1774. // Set flowcontrol
  1775. //
  1776. S.Extension = pDevExt;
  1777. S.Data = &pBasic->HandFlow;
  1778. KeSynchronizeExecution(pDevExt->Interrupt, SerialSetHandFlow, &S);
  1779. if (pDevExt->FifoPresent) {
  1780. pDevExt->TxFifoAmount = pBasic->TxFifo;
  1781. pDevExt->RxFifoTrigger = (UCHAR)pBasic->RxFifo;
  1782. WRITE_FIFO_CONTROL(pDevExt->Controller, (UCHAR)0);
  1783. READ_RECEIVE_BUFFER(pDevExt->Controller);
  1784. WRITE_FIFO_CONTROL(pDevExt->Controller,
  1785. (UCHAR)(SERIAL_FCR_ENABLE | pDevExt->RxFifoTrigger
  1786. | SERIAL_FCR_RCVR_RESET
  1787. | SERIAL_FCR_TXMT_RESET));
  1788. } else {
  1789. pDevExt->TxFifoAmount = pDevExt->RxFifoTrigger = 0;
  1790. WRITE_FIFO_CONTROL(pDevExt->Controller, (UCHAR)0);
  1791. }
  1792. KeReleaseSpinLock(&pDevExt->ControlLock, OldIrql);
  1793. break;
  1794. }
  1795. default:
  1796. status = STATUS_INVALID_PARAMETER;
  1797. break;
  1798. }
  1799. PIrp->IoStatus.Status = status;
  1800. SerialDump(SERIRPPATH, ("SERIAL: Complete Irp: %x\n", PIrp));
  1801. SerialCompleteRequest(pDevExt, PIrp, 0);
  1802. return status;
  1803. }