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.

2397 lines
74 KiB

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