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.

2290 lines
70 KiB

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