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.

2492 lines
76 KiB

  1. /* ++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. SERIOCTL.C
  5. Abstract:
  6. Routines to handle IOCTL_SERIAL_Xxx
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. 07-14-99 Jeff Midkiff (jeffmi)
  11. -- */
  12. #include "wceusbsh.h"
  13. VOID
  14. SerialCompletePendingWaitMasks(
  15. IN PDEVICE_EXTENSION PDevExt
  16. );
  17. VOID
  18. SerialCancelWaitMask(
  19. IN PDEVICE_OBJECT PDevObj,
  20. IN PIRP PIrp
  21. );
  22. //
  23. // Debug spew
  24. //
  25. #if DBG
  26. //
  27. // gets the function code fom an ioctl code, which uses method buffered.
  28. // assumes the device type is serial port
  29. //
  30. #define SERIAL_FNCT_CODE( _ctl_code_ ) ( (_ctl_code_ & 0xFF) >> 2)
  31. //
  32. // debug dumps. no spin lock usage to better simulate free build's run time.
  33. // if these trap in the debugger you know why.
  34. //
  35. #define DBG_DUMP_BAUD_RATE( _PDevExt ) \
  36. { \
  37. DbgDump(DBG_SERIAL, ("SerialPort.CurrentBaud: %d\n", _PDevExt->SerialPort.CurrentBaud.BaudRate)); \
  38. }
  39. #define DBG_DUMP_LINE_CONTROL( _PDevExt ) \
  40. { \
  41. DbgDump(DBG_SERIAL, ("SerialPort.LineControl.StopBits : 0x%x\n", _PDevExt->SerialPort.LineControl.StopBits )); \
  42. DbgDump(DBG_SERIAL, ("SerialPort.LineControl.Parity : 0x%x\n", _PDevExt->SerialPort.LineControl.Parity )); \
  43. DbgDump(DBG_SERIAL, ("SerialPort.LineControl.WordLength : 0x%x\n", _PDevExt->SerialPort.LineControl.WordLength )); \
  44. }
  45. #define DBG_DUMP_SERIAL_HANDFLOW( _PDevExt ) \
  46. { \
  47. DbgDump(DBG_SERIAL, ("SerialPort.HandFlow.ControlHandShake: 0x%x\n", PDevExt->SerialPort.HandFlow.ControlHandShake)); \
  48. DbgDump(DBG_SERIAL, ("SerialPort.HandFlow.FlowReplace: 0x%x\n", PDevExt->SerialPort.HandFlow.FlowReplace)); \
  49. DbgDump(DBG_SERIAL, ("SerialPort.HandFlow.XonLimit: 0x%x\n", PDevExt->SerialPort.HandFlow.XonLimit)); \
  50. DbgDump(DBG_SERIAL, ("SerialPort.HandFlow.XoffLimit: 0x%x\n", PDevExt->SerialPort.HandFlow.XoffLimit)); \
  51. }
  52. #define DBG_DUMP_SERIAL_TIMEOUTS( _PDevExt ) \
  53. { \
  54. DbgDump(DBG_SERIAL|DBG_TIME, ("SerialPort.Timeouts.ReadIntervalTimeout: %d\n", _PDevExt->SerialPort.Timeouts.ReadIntervalTimeout )); \
  55. DbgDump(DBG_SERIAL|DBG_TIME, ("SerialPort.Timeouts.ReadTotalTimeoutMultiplier: %d\n", _PDevExt->SerialPort.Timeouts.ReadTotalTimeoutMultiplier )); \
  56. DbgDump(DBG_SERIAL|DBG_TIME, ("SerialPort.Timeouts.ReadTotalTimeoutConstant: %d\n", _PDevExt->SerialPort.Timeouts.ReadTotalTimeoutConstant )); \
  57. DbgDump(DBG_SERIAL|DBG_TIME, ("SerialPort.Timeouts.WriteTotalTimeoutMultiplier: %d\n", _PDevExt->SerialPort.Timeouts.WriteTotalTimeoutMultiplier )); \
  58. DbgDump(DBG_SERIAL|DBG_TIME, ("SerialPort.Timeouts.WriteTotalTimeoutConstant: %d\n", _PDevExt->SerialPort.Timeouts.WriteTotalTimeoutConstant )); \
  59. }
  60. #define DBG_DUMP_SERIAL_CHARS( _PDevExt) \
  61. { \
  62. DbgDump(DBG_SERIAL, ("SerialPort.SpecialChars.EofChar: 0x%x\n", _PDevExt->SerialPort.SpecialChars.EofChar )); \
  63. DbgDump(DBG_SERIAL, ("SerialPort.SpecialChars.ErrorChar: 0x%x\n", _PDevExt->SerialPort.SpecialChars.ErrorChar )); \
  64. DbgDump(DBG_SERIAL, ("SerialPort.SpecialChars.BreakChar: 0x%x\n", _PDevExt->SerialPort.SpecialChars.BreakChar )); \
  65. DbgDump(DBG_SERIAL, ("SerialPort.SpecialChars.EventChar: 0x%x\n", _PDevExt->SerialPort.SpecialChars.EventChar )); \
  66. DbgDump(DBG_SERIAL, ("SerialPort.SpecialChars.XonChar: 0x%x\n", _PDevExt->SerialPort.SpecialChars.XonChar )); \
  67. DbgDump(DBG_SERIAL, ("SerialPort.SpecialChars.XoffChar: 0x%x\n", _PDevExt->SerialPort.SpecialChars.XoffChar )); \
  68. }
  69. #else
  70. #define DBG_DUMP_BAUD_RATE( _PDevExt )
  71. #define DBG_DUMP_LINE_CONTROL( _PDevExt )
  72. #define DBG_DUMP_SERIAL_HANDFLOW( _PDevExt )
  73. #define DBG_DUMP_SERIAL_TIMEOUTS( _PDevExt )
  74. #define DBG_DUMP_SERIAL_CHARS( _PDevExt)
  75. #endif
  76. __inline
  77. NTSTATUS
  78. IoctlSetSerialValue(
  79. IN PDEVICE_EXTENSION PDevExt,
  80. IN PIRP PIrp,
  81. ULONG Size,
  82. IN OUT PVOID PDest
  83. )
  84. {
  85. PIO_STACK_LOCATION pIrpSp;
  86. NTSTATUS status = STATUS_DELETE_PENDING;
  87. ULONG information = Size;
  88. KIRQL oldIrql;
  89. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  90. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  91. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < Size) {
  92. information = 0;
  93. status = STATUS_BUFFER_TOO_SMALL;
  94. DbgDump(DBG_ERR, ("IoctlSetSerialValue: (0x%x)\n", status));
  95. } else {
  96. memcpy( PDest, PIrp->AssociatedIrp.SystemBuffer, Size);
  97. status = STATUS_SUCCESS;
  98. }
  99. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  100. PIrp->IoStatus.Information = information;
  101. PIrp->IoStatus.Status = status;
  102. return status;
  103. }
  104. __inline
  105. NTSTATUS
  106. IoctlGetSerialValue(
  107. IN PDEVICE_EXTENSION PDevExt,
  108. IN PIRP PIrp,
  109. ULONG Size,
  110. IN PVOID PSrc
  111. )
  112. {
  113. PIO_STACK_LOCATION pIrpSp;
  114. NTSTATUS status = STATUS_DELETE_PENDING;
  115. ULONG information = Size;
  116. KIRQL oldIrql;
  117. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  118. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  119. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < Size) {
  120. information = 0;
  121. status = STATUS_BUFFER_TOO_SMALL;
  122. DbgDump(DBG_ERR, ("IoctlGetSerialValue: (0x%x)\n", status));
  123. } else {
  124. memcpy( PIrp->AssociatedIrp.SystemBuffer, PSrc, Size );
  125. status = STATUS_SUCCESS;
  126. }
  127. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  128. PIrp->IoStatus.Information = information;
  129. PIrp->IoStatus.Status = status;
  130. return status;
  131. }
  132. __inline
  133. NTSTATUS
  134. SetBaudRate(
  135. IN PIRP PIrp,
  136. IN PDEVICE_EXTENSION PDevExt
  137. )
  138. {
  139. NTSTATUS status = STATUS_DELETE_PENDING;
  140. DbgDump(DBG_SERIAL, (">SetBaudRate(%p)\n", PIrp));
  141. status = IoctlSetSerialValue(PDevExt,
  142. PIrp,
  143. sizeof( PDevExt->SerialPort.CurrentBaud ),
  144. &PDevExt->SerialPort.CurrentBaud );
  145. DBG_DUMP_BAUD_RATE(PDevExt);
  146. DbgDump(DBG_SERIAL, ("<SetBaudRate %x\n", status));
  147. return status;
  148. }
  149. __inline
  150. NTSTATUS
  151. GetBaudRate(
  152. IN PIRP PIrp,
  153. IN PDEVICE_EXTENSION PDevExt
  154. )
  155. {
  156. NTSTATUS status = STATUS_DELETE_PENDING;
  157. DbgDump(DBG_SERIAL, (">GetBaudRate(%p)\n", PIrp));
  158. status = IoctlGetSerialValue( PDevExt,
  159. PIrp,
  160. sizeof( PDevExt->SerialPort.CurrentBaud ),
  161. &PDevExt->SerialPort.CurrentBaud);
  162. DBG_DUMP_BAUD_RATE(PDevExt);
  163. DbgDump(DBG_SERIAL, ("<GetBaudRate %x\n", status));
  164. return status;
  165. }
  166. __inline
  167. NTSTATUS
  168. SetLineControl(
  169. IN PIRP PIrp,
  170. IN PDEVICE_EXTENSION PDevExt
  171. )
  172. {
  173. NTSTATUS status = STATUS_DELETE_PENDING;
  174. DbgDump(DBG_SERIAL, (">SetLineControl(%p)\n", PIrp));
  175. status = IoctlSetSerialValue( PDevExt,
  176. PIrp,
  177. sizeof(PDevExt->SerialPort.LineControl),
  178. &PDevExt->SerialPort.LineControl);
  179. DBG_DUMP_LINE_CONTROL( PDevExt );
  180. DbgDump(DBG_SERIAL, ("<SetLineControl %x\n",
  181. status));
  182. return status;
  183. }
  184. __inline
  185. NTSTATUS
  186. GetLineControl(
  187. IN PIRP PIrp,
  188. IN PDEVICE_EXTENSION PDevExt
  189. )
  190. {
  191. NTSTATUS status= STATUS_DELETE_PENDING;
  192. DbgDump(DBG_SERIAL, (">GetLineControl(%p)\n", PIrp));
  193. status = IoctlGetSerialValue( PDevExt,
  194. PIrp,
  195. sizeof(PDevExt->SerialPort.LineControl),
  196. &PDevExt->SerialPort.LineControl );
  197. DBG_DUMP_LINE_CONTROL( PDevExt );
  198. DbgDump(DBG_SERIAL, ("<GetLineControl %x\n",
  199. status));
  200. return status;
  201. }
  202. __inline
  203. NTSTATUS
  204. SetTimeouts(
  205. IN PIRP PIrp,
  206. IN PDEVICE_EXTENSION PDevExt
  207. )
  208. {
  209. NTSTATUS status = STATUS_DELETE_PENDING;
  210. DbgDump(DBG_SERIAL|DBG_TIME,(">SetTimeouts(%p)\n", PIrp));
  211. status = IoctlSetSerialValue( PDevExt,
  212. PIrp,
  213. sizeof(PDevExt->SerialPort.Timeouts),
  214. &PDevExt->SerialPort.Timeouts);
  215. DBG_DUMP_SERIAL_TIMEOUTS( PDevExt );
  216. DbgDump(DBG_SERIAL|DBG_TIME,("<SetTimeouts %x\n", status));
  217. return status;
  218. }
  219. __inline
  220. NTSTATUS
  221. GetTimeouts(
  222. IN PIRP PIrp,
  223. IN PDEVICE_EXTENSION PDevExt
  224. )
  225. {
  226. NTSTATUS status = STATUS_DELETE_PENDING;
  227. DbgDump(DBG_SERIAL|DBG_TIME, (">GetTimeouts(%p)\n", PIrp));
  228. status = IoctlGetSerialValue( PDevExt,
  229. PIrp,
  230. sizeof(PDevExt->SerialPort.Timeouts),
  231. &PDevExt->SerialPort.Timeouts);
  232. DBG_DUMP_SERIAL_TIMEOUTS( PDevExt );
  233. DbgDump(DBG_SERIAL|DBG_TIME, ("<GetTimeouts %x\n", status));
  234. return status;
  235. }
  236. __inline
  237. NTSTATUS
  238. SetSpecialChars(
  239. IN PIRP PIrp,
  240. IN PDEVICE_EXTENSION PDevExt
  241. )
  242. {
  243. NTSTATUS status = STATUS_DELETE_PENDING;
  244. DbgDump(DBG_SERIAL, (">SetSpecialChars(%p)\n", PIrp));
  245. status = IoctlSetSerialValue( PDevExt,
  246. PIrp,
  247. sizeof(PDevExt->SerialPort.SpecialChars),
  248. &PDevExt->SerialPort.SpecialChars);
  249. DBG_DUMP_SERIAL_CHARS( PDevExt);
  250. DbgDump(DBG_SERIAL, ("<SetSpecialChars %x\n", status));
  251. return status;
  252. }
  253. __inline
  254. NTSTATUS
  255. GetSpecialChars(
  256. IN PIRP PIrp,
  257. IN PDEVICE_EXTENSION PDevExt
  258. )
  259. {
  260. NTSTATUS status = STATUS_DELETE_PENDING;
  261. DbgDump(DBG_SERIAL, (">GetSpecialChars(%p)\n", PIrp));
  262. status = IoctlGetSerialValue( PDevExt,
  263. PIrp,
  264. sizeof(PDevExt->SerialPort.SpecialChars),
  265. &PDevExt->SerialPort.SpecialChars);
  266. DBG_DUMP_SERIAL_CHARS( PDevExt);
  267. DbgDump(DBG_SERIAL, ("<GetSpecialChars %x\n", status));
  268. return status;
  269. }
  270. __inline
  271. NTSTATUS
  272. SetClearDTR(
  273. IN PDEVICE_EXTENSION PDevExt,
  274. IN PIRP Irp,
  275. IN BOOLEAN Set
  276. )
  277. {
  278. NTSTATUS status = STATUS_DELETE_PENDING;
  279. KIRQL irql;
  280. USHORT usState = 0; // DRT/RTS state to send to USB device
  281. USHORT usOldMSR = 0;
  282. USHORT usDeltaMSR = 0;
  283. ULONG ulOldHistoryMask = 0;
  284. ULONG ulOldRS232Lines = 0;
  285. DbgDump(DBG_SERIAL, (">SetClearDTR (%x, %x)\n", PDevExt->DeviceObject, Set));
  286. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  287. //
  288. // we queue the user's Irp because this operation may take some time,
  289. // and we only want to hit the USB with one of these requests at a time.
  290. //
  291. if ( NULL != PDevExt->SerialPort.ControlIrp ) {
  292. DbgDump(DBG_WRN, ("SetClearDTR: STATUS_DEVICE_BUSY\n"));
  293. status = STATUS_DEVICE_BUSY;
  294. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  295. return status;
  296. }
  297. if ( !CanAcceptIoRequests(PDevExt->DeviceObject, FALSE, TRUE) ||
  298. !NT_SUCCESS(AcquireRemoveLock(&PDevExt->RemoveLock, Irp)) )
  299. {
  300. status = STATUS_DELETE_PENDING;
  301. DbgDump(DBG_ERR, ("SetClearDTR: 0x%x\n", status));
  302. KeReleaseSpinLock( &PDevExt->ControlLock, irql);
  303. return status;
  304. }
  305. //
  306. // Queue the Irp.
  307. //
  308. ASSERT( NULL == PDevExt->SerialPort.ControlIrp );
  309. PDevExt->SerialPort.ControlIrp = Irp;
  310. usOldMSR = PDevExt->SerialPort.ModemStatus;
  311. ulOldRS232Lines = PDevExt->SerialPort.RS232Lines;
  312. ulOldHistoryMask = PDevExt->SerialPort.HistoryMask;
  313. if (PDevExt->SerialPort.RS232Lines & SERIAL_RTS_STATE) {
  314. usState |= USB_COMM_RTS;
  315. }
  316. if (Set) {
  317. PDevExt->SerialPort.RS232Lines |= SERIAL_DTR_STATE;
  318. //
  319. // If there is an INT pipe then MSR could get modified
  320. //
  321. PDevExt->SerialPort.ModemStatus |= SERIAL_MSR_DSR | SERIAL_MSR_DCD;
  322. usState |= USB_COMM_DTR;
  323. } else {
  324. PDevExt->SerialPort.RS232Lines &= ~SERIAL_DTR_STATE;
  325. //
  326. // If there is an INT pipe then MSR could get modified
  327. //
  328. PDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_DSR & ~SERIAL_MSR_DCD;
  329. }
  330. // see what has changed in the MSR
  331. usDeltaMSR = usOldMSR ^ PDevExt->SerialPort.ModemStatus;
  332. if (usDeltaMSR & (SERIAL_MSR_DSR|SERIAL_MSR_DCD)) {
  333. // set delta MSR bits
  334. PDevExt->SerialPort.ModemStatus |= SERIAL_MSR_DDSR | SERIAL_MSR_DDCD;
  335. }
  336. DbgDump(DBG_SERIAL, ("SerialPort.RS232Lines : 0x%x\n", PDevExt->SerialPort.RS232Lines ));
  337. DbgDump(DBG_SERIAL, ("SerialPort.ModemStatus: 0x%x\n", PDevExt->SerialPort.ModemStatus ));
  338. DbgDump(DBG_SERIAL, ("SerialPort.HistoryMask: 0x%x\n", PDevExt->SerialPort.HistoryMask ));
  339. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  340. //
  341. // set DTR/RTS on the USB device
  342. //
  343. status = UsbClassVendorCommand( PDevExt->DeviceObject,
  344. USB_COMM_SET_CONTROL_LINE_STATE,
  345. usState,
  346. PDevExt->UsbInterfaceNumber,
  347. NULL,
  348. NULL,
  349. FALSE,
  350. WCEUSB_CLASS_COMMAND );
  351. DbgDump(DBG_SERIAL|DBG_READ_LENGTH, ("USB_COMM_SET_CONTROL_LINE_STATE(1, State: 0x%x, Status: 0x%x)\n", usState, status ));
  352. _EzLink:
  353. if ( STATUS_SUCCESS == status ) {
  354. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  355. // signal history massk
  356. if ( usDeltaMSR & (SERIAL_MSR_DSR|SERIAL_MSR_DCD) ) {
  357. PDevExt->SerialPort.HistoryMask |= SERIAL_EV_DSR | SERIAL_EV_RLSD;
  358. }
  359. PDevExt->EP0DeviceErrors = 0;
  360. DbgDump(DBG_SERIAL, ("SerialPort.HistoryMask: 0x%x\n", PDevExt->SerialPort.HistoryMask ));
  361. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  362. } else {
  363. // Ez-link
  364. if ((PDevExt->DeviceDescriptor.idVendor != 0x0547) &&
  365. ((PDevExt->DeviceDescriptor.idProduct != 0x2710) && (PDevExt->DeviceDescriptor.idProduct != 0x2720)))
  366. {
  367. // WINCE BUG 19544:
  368. // AS 3.1 does not handle STATUS_TIMEOUT, so will not see a problem.
  369. // A side effect is that it could sit spinning the green light trying to connect forever.
  370. // However, this is a different case from BUG 19544, which is a disconnect problem.
  371. // If we return failure then it will keep pounding us with Set DTR Irps.
  372. // This would be OK if AS would recognize that we disabled the interface, but it won't - see above.
  373. // You only see this bug when you have a flakey device (iPAQ, hung Jornada, etc.) that times out or
  374. // fails to properly handle the command. To prevent the bugcheck 0xCE the choices as of today are:
  375. // a) let it spin and never connect for these bad devices (iPAQ). Fix your firmware.
  376. // b) fix AcvtiveSync
  377. // I prefer both - pending email with COMPAQ (HTC) and ActiveSync. When AS gets their changes in then we need to
  378. // investigate again.
  379. status = STATUS_TIMEOUT;
  380. KeAcquireSpinLock( &PDevExt->ControlLock, &irql);
  381. if ( ++PDevExt->EP0DeviceErrors < MAX_EP0_DEVICE_ERRORS) {
  382. DbgDump(DBG_ERR, ("USB_COMM_SET_CONTROL_LINE_STATE error: 0x%x\n", status ));
  383. //
  384. // The command failed. Reset the old states, propogate status, and disable the device interface.
  385. // This should stop AS 3.1 from pounding us with Set DTR Irps.
  386. // However, AS does not participate in PnP well if we disable the interface
  387. // (see the note in IRP_MN_QUERY_PNP_DEVICE_STATE). Disabeling the
  388. // interface has the desired effect of notifying apps to stop sending us requests and Close the handle.
  389. //
  390. PDevExt->SerialPort.ModemStatus = usOldMSR;
  391. PDevExt->SerialPort.HistoryMask = ulOldHistoryMask;
  392. PDevExt->SerialPort.RS232Lines = ulOldRS232Lines;
  393. KeReleaseSpinLock( &PDevExt->ControlLock, irql);
  394. } else {
  395. DbgDump(DBG_ERR, ("*** UNRECOVERABLE DEVICE ERROR.2: (0x%x, %d) No longer Accepting Requests ***\n", status, PDevExt->EP0DeviceErrors ));
  396. // mark as PNP_DEVICE_FAILED
  397. InterlockedExchange(&PDevExt->AcceptingRequests, FALSE);
  398. KeReleaseSpinLock( &PDevExt->ControlLock, irql);
  399. IoInvalidateDeviceState( PDevExt->PDO );
  400. LogError( NULL,
  401. PDevExt->DeviceObject,
  402. 0, 0,
  403. (UCHAR)PDevExt->EP0DeviceErrors,
  404. ERR_NO_DTR,
  405. status,
  406. SERIAL_HARDWARE_FAILURE,
  407. PDevExt->DeviceName.Length + sizeof(WCHAR),
  408. PDevExt->DeviceName.Buffer,
  409. 0,
  410. NULL );
  411. }
  412. } else {
  413. DbgDump(DBG_WRN, ("Ez-Link\n" ));
  414. status = STATUS_SUCCESS;
  415. goto _EzLink;
  416. }
  417. }
  418. //
  419. // finally, release any pending serial events
  420. //
  421. ProcessSerialWaits(PDevExt);
  422. //
  423. // DeQueue the user's Irp. It gets completed in the SerialIoctl dispatch
  424. //
  425. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  426. ReleaseRemoveLock(&PDevExt->RemoveLock, Irp);
  427. ASSERT( NULL != PDevExt->SerialPort.ControlIrp );
  428. PDevExt->SerialPort.ControlIrp = NULL;
  429. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  430. DbgDump(DBG_SERIAL, ("<SetClearDTR %x\n", status ));
  431. return status;
  432. }
  433. __inline
  434. NTSTATUS
  435. SetClearRTS(
  436. IN PDEVICE_EXTENSION PDevExt,
  437. IN PIRP Irp,
  438. IN BOOLEAN Set
  439. )
  440. {
  441. NTSTATUS status = STATUS_DELETE_PENDING;
  442. KIRQL irql;
  443. USHORT usState = 0; // DRT/RTS state to send to USB device
  444. USHORT usOldMSR = 0;
  445. USHORT usDeltaMSR = 0;
  446. ULONG ulOldRS232Lines = 0;
  447. ULONG ulOldHistoryMask = 0;
  448. DbgDump(DBG_SERIAL, (">SetClearRTS (%x, %x)\n", PDevExt->DeviceObject, Set));
  449. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  450. //
  451. // we queue the user's Irp because this operation may take some time,
  452. // and we only want to hit the USB with one of these requests at a time.
  453. //
  454. if ( NULL != PDevExt->SerialPort.ControlIrp ) {
  455. status = STATUS_DEVICE_BUSY;
  456. DbgDump(DBG_WRN, ("SetClearRTS.1: 0x%x\n", status));
  457. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  458. return status;
  459. }
  460. if ( !CanAcceptIoRequests(PDevExt->DeviceObject, FALSE, TRUE) ||
  461. !NT_SUCCESS(AcquireRemoveLock(&PDevExt->RemoveLock, Irp)) )
  462. {
  463. status = STATUS_DELETE_PENDING;
  464. DbgDump(DBG_ERR, ("SetClearRTS.2: 0x%x\n", status));
  465. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  466. return status;
  467. }
  468. //
  469. // Queue the Irp.
  470. //
  471. ASSERT( NULL == PDevExt->SerialPort.ControlIrp );
  472. PDevExt->SerialPort.ControlIrp = Irp;
  473. usOldMSR = PDevExt->SerialPort.ModemStatus;
  474. ulOldRS232Lines = PDevExt->SerialPort.RS232Lines;
  475. ulOldHistoryMask = PDevExt->SerialPort.HistoryMask;
  476. if (PDevExt->SerialPort.RS232Lines & SERIAL_DTR_STATE) {
  477. usState |= USB_COMM_DTR;
  478. }
  479. if (Set) {
  480. PDevExt->SerialPort.RS232Lines |= SERIAL_RTS_STATE;
  481. //
  482. // If there is an INT pipe then MSR could get modified
  483. //
  484. PDevExt->SerialPort.ModemStatus |= SERIAL_MSR_CTS;
  485. usState |= USB_COMM_RTS;
  486. } else {
  487. PDevExt->SerialPort.RS232Lines &= ~SERIAL_RTS_STATE;
  488. //
  489. // If there is an INT pipe then MSR could get modified
  490. //
  491. PDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_CTS;
  492. }
  493. // see what has changed in the MSR
  494. usDeltaMSR = usOldMSR ^ PDevExt->SerialPort.ModemStatus;
  495. if (usDeltaMSR & SERIAL_MSR_CTS) {
  496. // set delta MSR bits
  497. PDevExt->SerialPort.ModemStatus |= SERIAL_MSR_DCTS;
  498. }
  499. DbgDump(DBG_SERIAL, ("SerialPort.RS232Lines : 0x%x\n", PDevExt->SerialPort.RS232Lines ));
  500. DbgDump(DBG_SERIAL, ("SerialPort.ModemStatus: 0x%x\n", PDevExt->SerialPort.ModemStatus));
  501. DbgDump(DBG_SERIAL, ("SerialPort.HistoryMask: 0x%x\n", PDevExt->SerialPort.HistoryMask ));
  502. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  503. //
  504. // set DTR/RTS on the USB device
  505. //
  506. status = UsbClassVendorCommand( PDevExt->DeviceObject,
  507. USB_COMM_SET_CONTROL_LINE_STATE,
  508. usState,
  509. PDevExt->UsbInterfaceNumber,
  510. NULL,
  511. NULL,
  512. FALSE,
  513. WCEUSB_CLASS_COMMAND );
  514. DbgDump(DBG_SERIAL|DBG_READ_LENGTH, ("USB_COMM_SET_CONTROL_LINE_STATE(2, State: 0x%x, Status: 0x%x)\n", usState, status ));
  515. _EzLink:
  516. if ( STATUS_SUCCESS == status ) {
  517. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  518. // signal history mask
  519. if ( usDeltaMSR & SERIAL_MSR_CTS ) {
  520. PDevExt->SerialPort.HistoryMask |= SERIAL_EV_CTS;
  521. }
  522. PDevExt->EP0DeviceErrors = 0;
  523. DbgDump(DBG_SERIAL, ("SerialPort.HistoryMask: 0x%x\n", PDevExt->SerialPort.HistoryMask ));
  524. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  525. } else {
  526. // Ez-link
  527. if ((PDevExt->DeviceDescriptor.idVendor != 0x0547) &&
  528. ((PDevExt->DeviceDescriptor.idProduct != 0x2710) && (PDevExt->DeviceDescriptor.idProduct != 0x2720)))
  529. {
  530. // AS 3.1 does not handle STATUS_TIMEOUT, so will not see a problem.
  531. // A side effect is that it could sit spinning the green light trying to connect forever.
  532. // However, this is a different case from BUG 19544, which is a disconnect problem.
  533. // If we return failure then it will keep pounding us with Set DTR Irps.
  534. // This would be OK if AS would recognize that we disabled the interface, but it won't - see above.
  535. // You only see this bug when you have a flakey device (iPAQ, hung Jornada, etc.) that times out or
  536. // fails to properly handle the command. To prevent the bugcheck 0xCE the choices as of today are:
  537. // a) let it spin and never connect for these bad devices (iPAQ). Fix your firmware.
  538. // b) fix AcvtiveSync
  539. // I prefer both - pending email with COMPAQ (HTC) and ActiveSync. When AS gets their changes in then we need to
  540. // investigate again.
  541. status = STATUS_TIMEOUT;
  542. KeAcquireSpinLock( &PDevExt->ControlLock, &irql);
  543. TEST_TRAP();
  544. if ( ++PDevExt->EP0DeviceErrors < MAX_EP0_DEVICE_ERRORS) {
  545. DbgDump(DBG_ERR, ("USB_COMM_SET_CONTROL_LINE_STATE error: %x\n", status ));
  546. //
  547. // The command failed. Reset the old states, propogate status, and disable the device interface.
  548. // This should stop AS 3.1 from pounding us with Set DTR Irps.
  549. // However, AS does not participate in PnP well if we disable the interface
  550. // (see the note in IRP_MN_QUERY_PNP_DEVICE_STATE). Disabeling the
  551. // interface has the desired effect of notifying apps to stop sending us requests and Close the handle.
  552. //
  553. PDevExt->SerialPort.ModemStatus = usOldMSR;
  554. PDevExt->SerialPort.RS232Lines = ulOldRS232Lines;
  555. PDevExt->SerialPort.HistoryMask = ulOldHistoryMask;
  556. KeReleaseSpinLock( &PDevExt->ControlLock, irql);
  557. } else {
  558. DbgDump(DBG_ERR, ("*** UNRECOVERABLE DEVICE ERROR.3: (0x%x, %d) No longer Accepting Requests ***\n", status, PDevExt->EP0DeviceErrors ));
  559. // mark as PNP_DEVICE_FAILED
  560. InterlockedExchange(&PDevExt->AcceptingRequests, FALSE);
  561. KeReleaseSpinLock( &PDevExt->ControlLock, irql);
  562. IoInvalidateDeviceState( PDevExt->PDO );
  563. LogError( NULL,
  564. PDevExt->DeviceObject,
  565. 0, 0,
  566. (UCHAR)PDevExt->EP0DeviceErrors,
  567. ERR_NO_RTS,
  568. status,
  569. SERIAL_HARDWARE_FAILURE,
  570. PDevExt->DeviceName.Length + sizeof(WCHAR),
  571. PDevExt->DeviceName.Buffer,
  572. 0,
  573. NULL );
  574. }
  575. } else {
  576. DbgDump(DBG_WRN, ("Ez-Link\n" ));
  577. status = STATUS_SUCCESS;
  578. goto _EzLink;
  579. }
  580. }
  581. //
  582. // finally, release any pending serial events
  583. //
  584. ProcessSerialWaits(PDevExt);
  585. //
  586. // DeQueue the user's Irp. It gets completed in the SerialIoctl dispatch
  587. //
  588. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  589. ReleaseRemoveLock(&PDevExt->RemoveLock, Irp);
  590. ASSERT( NULL != PDevExt->SerialPort.ControlIrp );
  591. PDevExt->SerialPort.ControlIrp = NULL;
  592. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  593. DbgDump(DBG_SERIAL, ("<SetClearRTS %x\n", status ));
  594. return status;
  595. }
  596. __inline
  597. NTSTATUS
  598. GetDtrRts(
  599. IN PIRP Irp,
  600. IN PDEVICE_EXTENSION PDevExt
  601. )
  602. {
  603. NTSTATUS status = STATUS_DELETE_PENDING;
  604. DbgDump(DBG_SERIAL, (">GetDtrRts (%p)\n", Irp));
  605. status = IoctlGetSerialValue( PDevExt,
  606. Irp,
  607. sizeof(PDevExt->SerialPort.RS232Lines),
  608. &PDevExt->SerialPort.RS232Lines);
  609. DbgDump(DBG_SERIAL, ("SerialPort.RS232Lines: 0x%x\n", PDevExt->SerialPort.RS232Lines ));
  610. DbgDump(DBG_SERIAL, ("<GetDtrRts %x\n", status));
  611. return status;
  612. }
  613. __inline
  614. NTSTATUS
  615. SerialResetDevice(
  616. IN PDEVICE_EXTENSION PDevExt,
  617. IN PIRP Irp,
  618. IN BOOLEAN ClearDTR
  619. )
  620. {
  621. NTSTATUS status = STATUS_DELETE_PENDING;
  622. BOOLEAN bRelease = TRUE;
  623. KIRQL oldIrql;
  624. DbgDump(DBG_SERIAL, (">SerialResetDevice (%x, %d)\n", PDevExt->DeviceObject, ClearDTR ));
  625. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  626. ASSERT_SERIAL_PORT( PDevExt->SerialPort );
  627. PDevExt->SerialPort.SupportedBauds = SERIAL_BAUD_075 | SERIAL_BAUD_110 | SERIAL_BAUD_150
  628. | SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200
  629. | SERIAL_BAUD_1800 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200
  630. | SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400 | SERIAL_BAUD_56K
  631. | SERIAL_BAUD_128K | SERIAL_BAUD_57600 | SERIAL_BAUD_115200 | SERIAL_BAUD_USER;
  632. PDevExt->SerialPort.CurrentBaud.BaudRate = 115200;
  633. PDevExt->SerialPort.LineControl.StopBits = STOP_BIT_1;
  634. PDevExt->SerialPort.LineControl.Parity = NO_PARITY;
  635. PDevExt->SerialPort.LineControl.WordLength = SERIAL_DATABITS_8;
  636. PDevExt->SerialPort.HandFlow.ControlHandShake = 0;
  637. PDevExt->SerialPort.HandFlow.FlowReplace = 0;
  638. PDevExt->SerialPort.HandFlow.XonLimit = 0;
  639. PDevExt->SerialPort.HandFlow.XoffLimit = 0;
  640. RtlZeroMemory( &PDevExt->SerialPort.Timeouts, sizeof(SERIAL_TIMEOUTS) );
  641. RtlZeroMemory( &PDevExt->SerialPort.SpecialChars, sizeof(SERIAL_CHARS) );
  642. PDevExt->SerialPort.RS232Lines = 0;
  643. PDevExt->SerialPort.HistoryMask = 0;
  644. PDevExt->SerialPort.WaitMask = 0;
  645. PDevExt->SerialPort.ModemStatus = 0;
  646. DbgDump(DBG_SERIAL, ("SerialPort.RS232Lines : 0x%x\n", PDevExt->SerialPort.RS232Lines ));
  647. DbgDump(DBG_SERIAL, ("SerialPort.ModemStatus: 0x%x\n", PDevExt->SerialPort.ModemStatus));
  648. DbgDump(DBG_SERIAL, ("SerialPort.HistoryMask: 0x%x\n", PDevExt->SerialPort.HistoryMask));
  649. if ( PDevExt->SerialPort.CurrentWaitMaskIrp ) {
  650. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  651. bRelease = FALSE;
  652. SerialCompletePendingWaitMasks(PDevExt);
  653. }
  654. //
  655. // drop the RTS/DTR lines on the USB device
  656. //
  657. if (bRelease) {
  658. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  659. bRelease = FALSE;
  660. }
  661. status = ClearDTR ? SetClearDTR(PDevExt, Irp, FALSE) : STATUS_SUCCESS;
  662. if (bRelease) {
  663. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  664. }
  665. DBG_DUMP_BAUD_RATE(PDevExt);
  666. DBG_DUMP_LINE_CONTROL(PDevExt);
  667. DBG_DUMP_SERIAL_HANDFLOW(PDevExt);
  668. DBG_DUMP_SERIAL_TIMEOUTS(PDevExt);
  669. DBG_DUMP_SERIAL_CHARS(PDevExt);
  670. DbgDump(DBG_SERIAL, ("<SerialResetDevice %x\n", status));
  671. return status;
  672. }
  673. __inline
  674. NTSTATUS
  675. SetBreak(
  676. IN PIRP PIrp,
  677. IN PDEVICE_EXTENSION PDevExt,
  678. USHORT Time
  679. )
  680. {
  681. UNREFERENCED_PARAMETER(PIrp);
  682. UNREFERENCED_PARAMETER(PDevExt);
  683. UNREFERENCED_PARAMETER(Time);
  684. DbgDump(DBG_SERIAL, (">SetBreak(%p)\n", PIrp));
  685. DbgDump(DBG_SERIAL, ("<SetBreak %x\n", STATUS_NOT_SUPPORTED));
  686. return STATUS_NOT_SUPPORTED;
  687. }
  688. __inline
  689. NTSTATUS
  690. SetQueueSize(
  691. IN PIRP PIrp,
  692. IN PDEVICE_EXTENSION PDevExt
  693. )
  694. /* ++
  695. IOCTL_SERIAL_SET_QUEUE_SIZE
  696. Operation
  697. Resizes the driver's internal typeahead and input buffers.
  698. The driver can allocate buffers larger than the requested sizes
  699. and can refuse to allocate buffers larger than its capacity.
  700. Input
  701. Parameters.DeviceIoControl.InputBufferLength
  702. indicates the size in bytes (must be >= sizeof(SERIAL_QUEUE_SIZE))
  703. of the buffer at Irp->AssociatedIrp.SystemBuffer, containing the
  704. InSize and OutSize specifications.
  705. Output
  706. None
  707. I/O Status Block
  708. The Information field is set to zero.
  709. The Status field is set to STATUS_SUCCESS or
  710. possibly to STATUS_BUFFER_TOO_SMALL or
  711. STATUS_INSUFFICIENT_RESOURCES if the driver
  712. cannot satisfy the request by allocating more memory.
  713. -- */
  714. {
  715. NTSTATUS status = STATUS_DELETE_PENDING;
  716. UNREFERENCED_PARAMETER(PIrp);
  717. UNREFERENCED_PARAMETER(PDevExt);
  718. DbgDump(DBG_SERIAL, (">SetQueueSize (%p)\n", PIrp));
  719. // we pretend to set this, but don't really care
  720. status = IoctlSetSerialValue(PDevExt,
  721. PIrp,
  722. sizeof(PDevExt->SerialPort.FakeQueueSize ),
  723. &PDevExt->SerialPort.FakeQueueSize );
  724. DbgDump( DBG_SERIAL, ("SerialPort.FakeQueueSize.InSize = 0x%x\n", PDevExt->SerialPort.FakeQueueSize.InSize ));
  725. DbgDump( DBG_SERIAL, ("SerialPort.FakeQueueSize.OutSize = 0x%x\n", PDevExt->SerialPort.FakeQueueSize.OutSize));
  726. DbgDump(DBG_SERIAL, ("DataOutMaxPacketSize = %d\n", PDevExt->WritePipe.MaxPacketSize));
  727. DbgDump(DBG_SERIAL, ("UsbReadBuffSize = %d\n", PDevExt->UsbReadBuffSize ));
  728. #if USE_RING_BUFF
  729. DbgDump(DBG_SERIAL, ("Internal RingBuffer Size: %d\n", PDevExt->RingBuff.Size ));
  730. #endif
  731. DbgDump(DBG_SERIAL, ("<SetQueueSize %x\n", status));
  732. return status;
  733. }
  734. __inline
  735. NTSTATUS
  736. GetWaitMask(
  737. IN PIRP PIrp,
  738. IN PDEVICE_EXTENSION PDevExt
  739. )
  740. {
  741. NTSTATUS status = STATUS_DELETE_PENDING;
  742. DbgDump(DBG_SERIAL, (">GetWaitMask (%p)\n", PIrp));
  743. status = IoctlGetSerialValue(PDevExt,
  744. PIrp,
  745. sizeof(PDevExt->SerialPort.WaitMask),
  746. &PDevExt->SerialPort.WaitMask);
  747. DbgDump(DBG_SERIAL, ("Current SerialPort.WaitMask = 0x%x\n", PDevExt->SerialPort.WaitMask));
  748. DbgDump(DBG_SERIAL, ("<GetWaitMask %x\n", status));
  749. return status;
  750. }
  751. __inline
  752. NTSTATUS
  753. SetWaitMask(
  754. IN PIRP PIrp,
  755. IN PDEVICE_EXTENSION PDevExt
  756. )
  757. /* ++
  758. IOCTL_SERIAL_SET_WAIT_MASK
  759. Operation
  760. Causes the driver to track the specified events, or,
  761. if the specified value is zero, to complete pending waits.
  762. Input
  763. Parameters.DeviceIoControl.InputBufferLength
  764. indicates the size in bytes (must be >= sizeof(ULONG)) of
  765. the bitmask at Irp->AssociatedIrp.SystemBuffer.
  766. Output
  767. None
  768. I/O Status Block
  769. The Information field is set to zero.
  770. The Status field is set to STATUS_SUCCESS or
  771. possibly to STATUS_PENDING, STATUS_CANCELLED,
  772. STATUS_BUFFER_TOO_SMALL, or STATUS_INVALID_PARAMETER.
  773. -- */
  774. {
  775. PULONG pWaitMask = (PULONG)PIrp->AssociatedIrp.SystemBuffer;
  776. NTSTATUS status = STATUS_DELETE_PENDING;
  777. KIRQL oldIrql;
  778. PIO_STACK_LOCATION pIrpSp;
  779. DbgDump(DBG_SERIAL, (">SetWaitMask (%p)\n", PIrp));
  780. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  781. PIrp->IoStatus.Information = 0;
  782. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  783. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) {
  784. status = STATUS_BUFFER_TOO_SMALL;
  785. DbgDump(DBG_ERR, ("SetWaitMask: (0x%x)\n", status));
  786. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  787. } else {
  788. // make sure it's a valid request
  789. if (*pWaitMask & ~(SERIAL_EV_RXCHAR |
  790. SERIAL_EV_RXFLAG |
  791. SERIAL_EV_TXEMPTY |
  792. SERIAL_EV_CTS |
  793. SERIAL_EV_DSR |
  794. SERIAL_EV_RLSD |
  795. SERIAL_EV_BREAK |
  796. SERIAL_EV_ERR |
  797. SERIAL_EV_RING |
  798. SERIAL_EV_PERR |
  799. SERIAL_EV_RX80FULL |
  800. SERIAL_EV_EVENT1 |
  801. SERIAL_EV_EVENT2) ) {
  802. status = STATUS_INVALID_PARAMETER;
  803. DbgDump(DBG_ERR, ("Invalid WaitMask: (0x%x)\n", *pWaitMask));
  804. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  805. } else {
  806. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  807. // force completion of any pending waits
  808. SerialCompletePendingWaitMasks( PDevExt );
  809. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  810. PDevExt->SerialPort.HistoryMask = 0; // clear the history mask
  811. PDevExt->SerialPort.WaitMask = *pWaitMask;
  812. //
  813. // for NT RAS
  814. // A value of '0' means clear any pending waits, which should have read
  815. // and cleared the MSR delta bits. The delta bits are the low nibble.
  816. //
  817. if (PDevExt->SerialPort.WaitMask == 0) {
  818. // clear delta bits
  819. PDevExt->SerialPort.ModemStatus &= 0xF0;
  820. }
  821. DbgDump(DBG_SERIAL, ("New SerialPort.WaitMask = 0x%x\n", PDevExt->SerialPort.WaitMask));
  822. DbgDump(DBG_SERIAL, ("SerialPort.RS232Lines = 0x%x\n", PDevExt->SerialPort.RS232Lines ));
  823. DbgDump(DBG_SERIAL, ("SerialPort.ModemStatus = 0x%x\n", PDevExt->SerialPort.ModemStatus));
  824. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  825. status = STATUS_SUCCESS;
  826. }
  827. }
  828. DbgDump(DBG_SERIAL, ("<SetWaitMask %x\n", status));
  829. return status;
  830. }
  831. VOID
  832. ProcessSerialWaits(
  833. IN PDEVICE_EXTENSION PDevExt
  834. )
  835. {
  836. KIRQL irql;
  837. PULONG pWaitMask;
  838. PIRP pMaskIrp;
  839. BOOLEAN bReleaseNeeded = TRUE;
  840. PERF_ENTRY( PERF_ProcessSerialWaits );
  841. ASSERT(PDevExt);
  842. DbgDump(DBG_SERIAL|DBG_TRACE, (">ProcessSerialWaits\n"));
  843. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  844. if ( PDevExt->SerialPort.CurrentWaitMaskIrp ) {
  845. ASSERT_SERIAL_PORT( PDevExt->SerialPort );
  846. if ( PDevExt->SerialPort.WaitMask & PDevExt->SerialPort.HistoryMask) {
  847. DbgDump(DBG_SERIAL, ("Releasing SerialPort.CurrentWaitMaskIrp(%p) with Mask: 0x%x\n",
  848. PDevExt->SerialPort.CurrentWaitMaskIrp, PDevExt->SerialPort.HistoryMask));
  849. pWaitMask = (PULONG)PDevExt->SerialPort.CurrentWaitMaskIrp->AssociatedIrp.SystemBuffer;
  850. *pWaitMask = PDevExt->SerialPort.HistoryMask;
  851. PDevExt->SerialPort.HistoryMask = 0;
  852. pMaskIrp = PDevExt->SerialPort.CurrentWaitMaskIrp;
  853. pMaskIrp->IoStatus.Information = sizeof(ULONG);
  854. pMaskIrp->IoStatus.Status = STATUS_SUCCESS;
  855. PDevExt->SerialPort.CurrentWaitMaskIrp = NULL;
  856. IoSetCancelRoutine(pMaskIrp, NULL);
  857. bReleaseNeeded = FALSE;
  858. ReleaseRemoveLock(&PDevExt->RemoveLock, pMaskIrp);
  859. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  860. IoCompleteRequest(pMaskIrp, IO_NO_INCREMENT );
  861. } else {
  862. DbgDump(DBG_SERIAL, ("No Serial Events\n" ));
  863. }
  864. } else {
  865. DbgDump(DBG_SERIAL, ("No CurrentWaitMaskIrp\n"));
  866. }
  867. if (bReleaseNeeded) {
  868. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  869. }
  870. DbgDump(DBG_SERIAL|DBG_TRACE, ("<ProcessSerialWaits\n"));
  871. PERF_EXIT( PERF_ProcessSerialWaits );
  872. return;
  873. }
  874. __inline
  875. NTSTATUS
  876. WaitOnMask(
  877. IN PIRP PIrp,
  878. IN PDEVICE_EXTENSION PDevExt
  879. )
  880. /* ++
  881. IOCTL_SERIAL_WAIT_ON_MASK
  882. Operation
  883. Returns information about which events have occurred
  884. among those that the caller was waiting on.
  885. Input
  886. Parameters.DeviceIoControl.OutputBufferLength indicates the
  887. size in bytes (must be >= sizeof(ULONG)) of the buffer.
  888. Output
  889. The driver returns a bitmask with bits set for events that
  890. occurred (or with a value of zero if the preceding
  891. set-waitmask request specified zero) to the buffer at
  892. Irp->AssociatedIrp.SystemBuffer.
  893. I/O Status Block
  894. The Information field is set to sizeof(ULONG) when the
  895. Status field is set to STATUS_SUCCESS. Otherwise,
  896. the Information field is set to zero, and the Status field
  897. can be set to STATUS_PENDING or
  898. STATUS_INVALID_PARAMETER if a wait is already pending.
  899. -- */
  900. {
  901. PULONG pWaitMask = (PULONG)PIrp->AssociatedIrp.SystemBuffer;
  902. PIO_STACK_LOCATION pIrpSp;
  903. NTSTATUS status = STATUS_DELETE_PENDING;
  904. KIRQL oldIrql;
  905. DbgDump(DBG_SERIAL|DBG_TRACE, (">WaitOnMask (%p)\n", PIrp));
  906. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  907. if ( !CanAcceptIoRequests(PDevExt->DeviceObject, FALSE, TRUE) ) {
  908. status = STATUS_DELETE_PENDING;
  909. DbgDump(DBG_ERR, ("WaitOnMask: 0x%x\n", status) );
  910. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  911. return status;
  912. }
  913. status = STATUS_SUCCESS;
  914. PIrp->IoStatus.Information = 0;
  915. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  916. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
  917. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  918. status = STATUS_BUFFER_TOO_SMALL;
  919. DbgDump(DBG_ERR, ("WaitOnMask: (0x%x)\n", status));
  920. } else {
  921. //
  922. // Fake NULL modem...
  923. //
  924. if ((PDevExt->SerialPort.WaitMask & SERIAL_EV_CTS) && (PDevExt->SerialPort.ModemStatus & SERIAL_MSR_DCTS) ) {
  925. PDevExt->SerialPort.HistoryMask |= SERIAL_EV_CTS;
  926. PDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_DCTS;
  927. }
  928. if ((PDevExt->SerialPort.WaitMask & SERIAL_EV_DSR) && (PDevExt->SerialPort.ModemStatus & SERIAL_MSR_DDSR) ) {
  929. PDevExt->SerialPort.HistoryMask |= SERIAL_EV_DSR;
  930. PDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_DDSR;
  931. // make RAS happy
  932. PDevExt->SerialPort.HistoryMask |= SERIAL_EV_RLSD;
  933. PDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_DDCD;
  934. }
  935. if ((PDevExt->SerialPort.WaitMask & SERIAL_EV_RLSD) && (PDevExt->SerialPort.ModemStatus & SERIAL_MSR_DDCD) ) {
  936. PDevExt->SerialPort.HistoryMask |= SERIAL_EV_RLSD;
  937. PDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_DDCD;
  938. }
  939. if ((PDevExt->SerialPort.WaitMask & SERIAL_EV_RING) && (PDevExt->SerialPort.ModemStatus & SERIAL_MSR_DRI) ) {
  940. PDevExt->SerialPort.HistoryMask |= SERIAL_EV_RING;
  941. PDevExt->SerialPort.ModemStatus &= ~SERIAL_MSR_DRI;
  942. }
  943. DbgDump(DBG_SERIAL, ("WaitOnMask::SerialPort.ModemStatus: 0x%x\n", PDevExt->SerialPort.ModemStatus ));
  944. DbgDump(DBG_SERIAL, ("WaitOnMask::SerialPort.WaitMask : 0x%x\n", PDevExt->SerialPort.WaitMask ));
  945. DbgDump(DBG_SERIAL, ("WaitOnMask::SerialPort.HistoryMask: 0x%x\n", PDevExt->SerialPort.HistoryMask ));
  946. //
  947. // If we already have an event to report, then just go ahead and return it.
  948. //
  949. if ( PDevExt->SerialPort.HistoryMask ) {
  950. *pWaitMask = PDevExt->SerialPort.HistoryMask;
  951. PDevExt->SerialPort.HistoryMask = 0;
  952. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  953. PIrp->IoStatus.Information = sizeof(PDevExt->SerialPort.HistoryMask);
  954. // the Irp gets completed by the calling routine
  955. DbgDump(DBG_SERIAL | DBG_EVENTS, ("Returning WatiMask: 0x%08x\n", *pWaitMask));
  956. } else {
  957. //
  958. // we don't have any events yet,
  959. // so queue the input Irp (PIrp)
  960. //
  961. //
  962. // just in case something comes in (Rx/Tx),
  963. // we'll use a while loop to complete any
  964. // pending wait mask Irps.
  965. //
  966. while (PDevExt->SerialPort.CurrentWaitMaskIrp) {
  967. PIRP pOldIrp;
  968. pOldIrp = PDevExt->SerialPort.CurrentWaitMaskIrp;
  969. PDevExt->SerialPort.CurrentWaitMaskIrp = NULL;
  970. pOldIrp->IoStatus.Status = STATUS_SUCCESS;
  971. IoSetCancelRoutine(pOldIrp, NULL);
  972. *pWaitMask = 0;
  973. DbgDump(DBG_SERIAL|DBG_EVENTS|DBG_TRACE, ("Completing maskirp(4) %p\n", pOldIrp));
  974. //
  975. // Release locks, complete request, then reacquire locks
  976. //
  977. ReleaseRemoveLock(&PDevExt->RemoveLock, pOldIrp);
  978. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  979. IoCompleteRequest(pOldIrp, IO_SERIAL_INCREMENT);
  980. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  981. }
  982. //
  983. // Check to see if the input Irp needs to be cancelled
  984. //
  985. if (PIrp->Cancel) {
  986. PIrp->IoStatus.Information = 0;
  987. status = PIrp->IoStatus.Status = STATUS_CANCELLED;
  988. //
  989. // the caller completes the Irp
  990. //
  991. } else {
  992. //
  993. // queue the input Irp as the SerialPort.CurrentWaitMaskIrp
  994. //
  995. DbgDump(DBG_SERIAL | DBG_EVENTS, ("Queuing Irp: %p for WatiMask: 0x%08x\n", PIrp, PDevExt->SerialPort.WaitMask ));
  996. IoSetCancelRoutine( PIrp, SerialCancelWaitMask );
  997. IoMarkIrpPending(PIrp);
  998. status = PIrp->IoStatus.Status = STATUS_PENDING;
  999. ASSERT( NULL == PDevExt->SerialPort.CurrentWaitMaskIrp); // don't want to drop Irps on the floor
  1000. PDevExt->SerialPort.CurrentWaitMaskIrp = PIrp;
  1001. //
  1002. // now the Irp is on our queue,
  1003. // so the caller should NOT try to complete it.
  1004. //
  1005. }
  1006. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  1007. } // !SerialPort.HistoryMask
  1008. } // pIrpSp->Parameters
  1009. DbgDump(DBG_SERIAL, ("<WaitOnMask %x\n", status));
  1010. return status;
  1011. }
  1012. VOID
  1013. SerialCompletePendingWaitMasks(
  1014. IN PDEVICE_EXTENSION PDevExt
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. This function is used to complete the pending SerialPort.WaitMask Irp
  1019. due to IOCTL_SERIAL_SET_WAIT_MASK
  1020. Arguments:
  1021. Return Value:
  1022. VOID
  1023. --*/
  1024. {
  1025. KIRQL oldIrql;
  1026. PIRP pCurrentMaskIrp = NULL;
  1027. ASSERT(PDevExt);
  1028. DbgDump(DBG_SERIAL|DBG_TRACE, (">SerialCompletePendingWaitMasks\n"));
  1029. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  1030. ASSERT_SERIAL_PORT( PDevExt->SerialPort );
  1031. pCurrentMaskIrp = PDevExt->SerialPort.CurrentWaitMaskIrp;
  1032. if (pCurrentMaskIrp) {
  1033. pCurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
  1034. pCurrentMaskIrp->IoStatus.Information = sizeof(PDevExt->SerialPort.HistoryMask);
  1035. DbgDump(DBG_SERIAL, ("SerialCompletePendingWaitMasks: %p with 0x%x\n", PDevExt->SerialPort.CurrentWaitMaskIrp, PDevExt->SerialPort.HistoryMask));
  1036. *((PULONG)pCurrentMaskIrp->AssociatedIrp.SystemBuffer) = PDevExt->SerialPort.HistoryMask;
  1037. PDevExt->SerialPort.HistoryMask = 0;
  1038. PDevExt->SerialPort.CurrentWaitMaskIrp = NULL;
  1039. IoSetCancelRoutine(pCurrentMaskIrp, NULL);
  1040. }
  1041. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  1042. // complete the queued SerialPort.WaitMask IRP if needed
  1043. if (pCurrentMaskIrp) {
  1044. ReleaseRemoveLock(&PDevExt->RemoveLock, pCurrentMaskIrp);
  1045. IoCompleteRequest(pCurrentMaskIrp, IO_SERIAL_INCREMENT);
  1046. }
  1047. DbgDump(DBG_SERIAL|DBG_TRACE, ("<SerialCompletePendingWaitMasks\n"));
  1048. return;
  1049. }
  1050. VOID
  1051. SerialCancelWaitMask(
  1052. IN PDEVICE_OBJECT PDevObj,
  1053. IN PIRP PIrp
  1054. )
  1055. /*++
  1056. Routine Description:
  1057. This function is used as a cancel routine for Irps queued due
  1058. to IOCTL_SERIAL_WAIT_ON_MASK
  1059. Arguments:
  1060. PDevObj - Pointer to Device Object
  1061. PIrp - Pointer to IRP that is being canceled; must be the same as
  1062. the current mask IRP.
  1063. Return Value:
  1064. VOID
  1065. --*/
  1066. {
  1067. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
  1068. KIRQL oldIrql;
  1069. DbgDump(DBG_SERIAL|DBG_IRP|DBG_CANCEL|DBG_TRACE, (">SerialCancelWaitMask (%p)\n", PIrp));
  1070. //
  1071. // release ASAP since we queue our own Irps
  1072. //
  1073. IoReleaseCancelSpinLock(PIrp->CancelIrql);
  1074. KeAcquireSpinLock(&pDevExt->ControlLock, &oldIrql);
  1075. ASSERT_SERIAL_PORT( pDevExt->SerialPort );
  1076. ASSERT(pDevExt->SerialPort.CurrentWaitMaskIrp == PIrp);
  1077. PIrp->IoStatus.Status = STATUS_CANCELLED;
  1078. PIrp->IoStatus.Information = 0;
  1079. pDevExt->SerialPort.CurrentWaitMaskIrp = NULL;
  1080. ReleaseRemoveLock(&pDevExt->RemoveLock, PIrp);
  1081. KeReleaseSpinLock(&pDevExt->ControlLock, oldIrql);
  1082. IoCompleteRequest(PIrp, IO_SERIAL_INCREMENT);
  1083. DbgDump(DBG_SERIAL|DBG_IRP|DBG_CANCEL|DBG_TRACE, ("<SerialCancelWaitMask\n"));
  1084. return;
  1085. }
  1086. __inline
  1087. NTSTATUS
  1088. GetCommStatus(
  1089. IN PIRP PIrp,
  1090. IN PDEVICE_EXTENSION PDevExt
  1091. )
  1092. /* ++
  1093. IOCTL_SERIAL_GET_COMMSTATUS
  1094. Operation
  1095. Returns general status information, including how many
  1096. Errors and HoldReasons have occurred, how much data
  1097. is in the driver's buffers as indicated by the AmountInInQueue
  1098. and AmountInOutQueue values, and whether EofReceived and
  1099. WaitForImmediate are set.
  1100. Input
  1101. Parameters.DeviceIoControl.OutputBufferLength
  1102. indicates the size in bytes of the buffer, which must be
  1103. >= sizeof(SERIAL_STATUS).
  1104. Output
  1105. The driver returns information to the buffer at
  1106. Irp->AssociatedIrp.SystemBuffer.
  1107. I/O Status Block
  1108. The Information field is set to sizeof(SERIAL_STATUS)
  1109. when the Status field is set to STATUS_SUCCESS. Otherwise,
  1110. the Information field is set to zero and the Status field is set to
  1111. STATUS_BUFFER_TOO_SMALL.
  1112. -- */
  1113. {
  1114. PSERIAL_STATUS pSerialStatus = (PSERIAL_STATUS)PIrp->AssociatedIrp.SystemBuffer;
  1115. NTSTATUS status = STATUS_DELETE_PENDING;
  1116. KIRQL oldIrql;
  1117. PIO_STACK_LOCATION pIrpSp;
  1118. DbgDump(DBG_SERIAL, (">GetCommStatus (%p)\n", PIrp));
  1119. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  1120. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  1121. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) {
  1122. status = STATUS_BUFFER_TOO_SMALL;
  1123. PIrp->IoStatus.Information = 0;
  1124. DbgDump(DBG_ERR, ("GetCommStatus: (0x%x)\n", status));
  1125. } else {
  1126. status = STATUS_SUCCESS;
  1127. PIrp->IoStatus.Information = sizeof(SERIAL_STATUS);
  1128. RtlZeroMemory(pSerialStatus, sizeof(SERIAL_STATUS));
  1129. pSerialStatus->Errors = 0;
  1130. pSerialStatus->EofReceived = FALSE;
  1131. pSerialStatus->WaitForImmediate = 0;
  1132. pSerialStatus->HoldReasons = 0;
  1133. #if defined (USE_RING_BUFF)
  1134. pSerialStatus->AmountInInQueue = PDevExt->RingBuff.CharsInBuff;
  1135. #else
  1136. pSerialStatus->AmountInInQueue = PDevExt->UsbReadBuffChars;
  1137. #endif
  1138. pSerialStatus->AmountInOutQueue= PDevExt->SerialPort.CharsInWriteBuf;
  1139. DbgDump(DBG_SERIAL, ("AmountInInQueue: %x\n", pSerialStatus->AmountInInQueue ));
  1140. DbgDump(DBG_SERIAL, ("AmountInOutQueue: %x\n", pSerialStatus->AmountInOutQueue));
  1141. }
  1142. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  1143. DbgDump(DBG_SERIAL, ("<GetCommStatus %x\n", status));
  1144. return status;
  1145. }
  1146. __inline
  1147. NTSTATUS
  1148. GetModemStatus(
  1149. IN PIRP PIrp,
  1150. IN PDEVICE_EXTENSION PDevExt
  1151. )
  1152. {
  1153. NTSTATUS status = STATUS_DELETE_PENDING;
  1154. DbgDump(DBG_SERIAL, (">GetModemStatus (%p)\n", PIrp));
  1155. // get current MSR
  1156. status = IoctlGetSerialValue(PDevExt,
  1157. PIrp,
  1158. sizeof( PDevExt->SerialPort.ModemStatus ),
  1159. &PDevExt->SerialPort.ModemStatus );
  1160. DbgDump(DBG_SERIAL, ("<GetModemStatus %x\n", status));
  1161. return status;
  1162. }
  1163. __inline
  1164. NTSTATUS
  1165. ImmediateChar(
  1166. IN PIRP Irp,
  1167. IN PDEVICE_OBJECT DeviceObject
  1168. )
  1169. {
  1170. PUCHAR Char = (PUCHAR) Irp->AssociatedIrp.SystemBuffer;
  1171. NTSTATUS status = STATUS_SUCCESS;
  1172. PIO_STACK_LOCATION IrpStack;
  1173. DbgDump(DBG_SERIAL, (">ImmediateChar (%p)\n", Irp));
  1174. TEST_TRAP();
  1175. Irp->IoStatus.Information = 0;
  1176. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1177. if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) {
  1178. status = STATUS_BUFFER_TOO_SMALL;
  1179. DbgDump(DBG_ERR, ("ImmediateChar: (0x%x)\n", status));
  1180. } else {
  1181. //
  1182. // Fabricate a write irp & send it to our write path.
  1183. // We do this because the R/W path depends on receiving an Irp of type
  1184. // IRP_MJ_WRITE or IRP_MJ_READ. It would be easier to
  1185. // simply say "not supported", but legacy apps depend on this.
  1186. //
  1187. PIRP pIrp;
  1188. KEVENT event;
  1189. IO_STATUS_BLOCK ioStatusBlock = {0, 0};
  1190. LARGE_INTEGER startingOffset = {0, 0};
  1191. PAGED_CODE();
  1192. KeInitializeEvent(
  1193. &event,
  1194. NotificationEvent,
  1195. FALSE
  1196. );
  1197. pIrp = IoBuildSynchronousFsdRequest(
  1198. IRP_MJ_WRITE, // MajorFunction,
  1199. DeviceObject, // DeviceObject,
  1200. &Char, // Buffer,
  1201. sizeof(Char), // Length ,
  1202. &startingOffset,// StartingOffset,
  1203. &event, // Event,
  1204. &ioStatusBlock // OUT PIO_STATUS_BLOCK IoStatusBlock
  1205. );
  1206. if ( !pIrp ) {
  1207. status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1208. DbgDump(DBG_ERR, ("IoBuildSynchronousFsdRequest: STATUS_INSUFFICIENT_RESOURCES\n", status));
  1209. } else {
  1210. status = IoCallDriver( DeviceObject,
  1211. pIrp );
  1212. if ( STATUS_PENDING == status ) {
  1213. KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL );
  1214. }
  1215. //
  1216. // Propogate Write status.
  1217. // Note: the system released the Irp we just created & sent
  1218. // when the Write completes.... so don't touch it.
  1219. //
  1220. status = ioStatusBlock.Status ;
  1221. }
  1222. }
  1223. DbgDump(DBG_SERIAL, ("<ImmediateChar, %x\n", status));
  1224. return status;
  1225. }
  1226. NTSTATUS
  1227. SerialPurgeRxClear(
  1228. IN PDEVICE_OBJECT PDevObj,
  1229. IN BOOLEAN CancelRead
  1230. )
  1231. {
  1232. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  1233. NTSTATUS status = STATUS_SUCCESS;
  1234. KIRQL irql;
  1235. DbgDump( DBG_SERIAL, (">SerialPurgeRxClear:%d\n", CancelRead));
  1236. //
  1237. // Cancel the USB INT & Read Irps, which effectvely NAKs all packets from the client
  1238. // device untill we resubmit it.
  1239. //
  1240. if ( CancelRead )
  1241. {
  1242. if (pDevExt->IntIrp)
  1243. {
  1244. status = CancelUsbInterruptIrp( PDevObj );
  1245. }
  1246. status = CancelUsbReadIrp( PDevObj );
  1247. }
  1248. if (STATUS_SUCCESS == status) {
  1249. //
  1250. // Now, purge the Rx buffer.
  1251. //
  1252. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  1253. #if DBG
  1254. if ( DebugLevel & (DBG_DUMP_READS|DBG_READ_LENGTH))
  1255. {
  1256. ULONG i;
  1257. #if defined (USE_RING_BUFF)
  1258. KdPrint( ("PurgeRxBuff[%d]: ", pDevExt->RingBuff.CharsInBuff ));
  1259. for (i = 0; i < pDevExt->RingBuff.CharsInBuff; i++) {
  1260. KdPrint(("%02x ", *pDevExt->RingBuff.pHead++ & 0xFF));
  1261. }
  1262. #else
  1263. KdPrint( ("PurgeRxBuff[%d]: ", pDevExt->UsbReadBuffChars ));
  1264. for (i = 0; i < pDevExt->UsbReadBuffChars; i++) {
  1265. KdPrint(("%02x ", pDevExt->UsbReadBuff[i] & 0xFF));
  1266. }
  1267. #endif // USE_RING_BUFF
  1268. KdPrint(("\n"));
  1269. }
  1270. #endif // DBG
  1271. #if defined (USE_RING_BUFF)
  1272. pDevExt->RingBuff.CharsInBuff = 0;
  1273. pDevExt->RingBuff.pHead =
  1274. pDevExt->RingBuff.pTail =
  1275. pDevExt->RingBuff.pBase;
  1276. #else // USE_RING_BUFF
  1277. pDevExt->UsbReadBuffChars = 0;
  1278. pDevExt->UsbReadBuffIndex = 0;
  1279. #endif
  1280. if ( CancelRead ) {
  1281. //
  1282. // reset read states
  1283. //
  1284. InterlockedExchange(&pDevExt->UsbReadState, IRP_STATE_COMPLETE);
  1285. InterlockedExchange(&pDevExt->IntState, IRP_STATE_COMPLETE);
  1286. }
  1287. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  1288. }
  1289. DbgDump(DBG_SERIAL, ("<SerialPurgeRxClear:0x%x\n", status ));
  1290. return status;
  1291. }
  1292. __inline
  1293. NTSTATUS
  1294. Purge(
  1295. IN PDEVICE_OBJECT PDevObj,
  1296. IN PIRP Irp
  1297. )
  1298. /* ++
  1299. IOCTL_SERIAL_PURGE
  1300. Operation
  1301. Purges the specified operation(s) or queues: one or more of
  1302. the current and all pending writes, the current and all pending
  1303. reads, the transmit buffer if one exists, and the receive buffer
  1304. if one exists.
  1305. Input
  1306. Parameters.DeviceIoControl.InputBufferLength indicates the
  1307. size in bytes of the buffer at Irp->AssociatedIrp.SystemBuffer,
  1308. which contains a bitmask of type ULONG, indicating what to purge.
  1309. Output
  1310. None
  1311. I/O Status Block
  1312. The Information field is set to zero, and the Status field is set
  1313. to STATUS_SUCCESS or possibly to STATUS_PENDING,
  1314. STATUS_CANCELLED, or STATUS_INVALID_PARAMETER
  1315. -- */
  1316. {
  1317. PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension;
  1318. PIO_STACK_LOCATION pIrpStack;
  1319. NTSTATUS status = STATUS_DELETE_PENDING;
  1320. ULONG ulMask = 0;
  1321. KIRQL irql;
  1322. PIRP NulllIrp = NULL;
  1323. DbgDump(DBG_SERIAL|DBG_IRP, (">Purge (%p)\n", Irp));
  1324. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  1325. Irp->IoStatus.Information = 0;
  1326. pIrpStack = IoGetCurrentIrpStackLocation(Irp);
  1327. if (!Irp->AssociatedIrp.SystemBuffer ||
  1328. pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG) ) {
  1329. status = STATUS_BUFFER_TOO_SMALL;
  1330. DbgDump(DBG_ERR, ("Purge: (0x%x)\n", status));
  1331. } else {
  1332. ulMask = *((PULONG) Irp->AssociatedIrp.SystemBuffer);
  1333. // make sure purge request is valid
  1334. if ( (!ulMask) || (ulMask & ( ~( SERIAL_PURGE_TXABORT |
  1335. SERIAL_PURGE_RXABORT |
  1336. SERIAL_PURGE_TXCLEAR |
  1337. SERIAL_PURGE_RXCLEAR)))) {
  1338. status = STATUS_INVALID_PARAMETER;
  1339. DbgDump(DBG_ERR, ("Purge: (0x%x)\n", status));
  1340. } else {
  1341. DbgDump(DBG_SERIAL, ("Purge Mask: 0x%x\n", ulMask ));
  1342. status = STATUS_SUCCESS;
  1343. if ( ulMask & SERIAL_PURGE_RXCLEAR) {
  1344. //
  1345. // SERIAL_PURGE_RXCLEAR - Implies the receive buffer if exists.
  1346. //
  1347. DbgDump(DBG_SERIAL|DBG_IRP, ("SERIAL_PURGE_RXCLEAR\n"));
  1348. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  1349. status = SerialPurgeRxClear(PDevObj, TRUE);
  1350. if ( NT_SUCCESS(status) ) {
  1351. if ( !pDevExt->IntPipe.hPipe ) {
  1352. DbgDump(DBG_SERIAL, ("kick starting another USB Read\n" ));
  1353. status = UsbRead( pDevExt, FALSE );
  1354. } else {
  1355. DbgDump(DBG_SERIAL, ("kick starting another USB INT Read\n" ));
  1356. status = UsbInterruptRead( pDevExt );
  1357. }
  1358. }
  1359. if ( NT_SUCCESS(status) ) {
  1360. // should be STATUS_PENDING
  1361. status = STATUS_SUCCESS;
  1362. }
  1363. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  1364. }
  1365. if (ulMask & SERIAL_PURGE_RXABORT) {
  1366. //
  1367. // SERIAL_PURGE_RXABORT - Implies the current and all pending reads.
  1368. //
  1369. DbgDump(DBG_SERIAL|DBG_IRP, ("SERIAL_PURGE_RXABORT\n"));
  1370. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  1371. // cancel all outstanding USB read requests
  1372. //status = CleanUpPacketList( PDevObj, &pDevExt->PendingReadPackets);
  1373. // cancel all outstanding user reads
  1374. KillAllPendingUserReads( PDevObj,
  1375. &pDevExt->UserReadQueue,
  1376. &pDevExt->UserReadIrp ); //&NulllIrp );
  1377. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  1378. }
  1379. if (ulMask & SERIAL_PURGE_TXCLEAR) {
  1380. //
  1381. // SERIAL_PURGE_TXCLEAR - Implies the transmit buffer if exists
  1382. //
  1383. DbgDump(DBG_SERIAL|DBG_IRP, ("SERIAL_PURGE_TXCLEAR\n"));
  1384. pDevExt->SerialPort.CharsInWriteBuf = 0;
  1385. }
  1386. if (ulMask & SERIAL_PURGE_TXABORT) {
  1387. //
  1388. // SERIAL_PURGE_TXABORT - Implies the current and all pending writes.
  1389. //
  1390. DbgDump(DBG_SERIAL|DBG_IRP, ("SERIAL_PURGE_TXABORT\n"));
  1391. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  1392. //
  1393. // We don't queue write Irps, rather write packets.
  1394. // So, cancel all outstanding write requests
  1395. //
  1396. status = CleanUpPacketList( PDevObj,
  1397. &pDevExt->PendingWritePackets,
  1398. &pDevExt->PendingDataOutEvent
  1399. );
  1400. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  1401. }
  1402. }
  1403. }
  1404. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  1405. DbgDump(DBG_SERIAL|DBG_IRP, ("<Purge %x\n", status));
  1406. return status;
  1407. }
  1408. __inline
  1409. NTSTATUS
  1410. GetHandflow(
  1411. IN PIRP Irp,
  1412. IN PDEVICE_EXTENSION PDevExt
  1413. )
  1414. {
  1415. NTSTATUS status = STATUS_DELETE_PENDING;
  1416. DbgDump(DBG_SERIAL, (">GetHandFlow (%p)\n", Irp));
  1417. status = IoctlGetSerialValue(PDevExt,
  1418. Irp,
  1419. sizeof( PDevExt->SerialPort.HandFlow ),
  1420. &PDevExt->SerialPort.HandFlow);
  1421. DBG_DUMP_SERIAL_HANDFLOW( PDevExt );
  1422. DbgDump(DBG_SERIAL, ("<GetHandFlow %x\n", status));
  1423. return status;
  1424. }
  1425. __inline
  1426. NTSTATUS
  1427. SetHandflow(
  1428. IN PIRP PIrp,
  1429. IN PDEVICE_EXTENSION PDevExt
  1430. )
  1431. {
  1432. NTSTATUS status= STATUS_DELETE_PENDING;
  1433. DbgDump(DBG_SERIAL, (">SetHandFlow(%p)\n", PIrp));
  1434. status = IoctlSetSerialValue( PDevExt,
  1435. PIrp,
  1436. sizeof( PDevExt->SerialPort.HandFlow ),
  1437. &PDevExt->SerialPort.HandFlow);
  1438. DBG_DUMP_SERIAL_HANDFLOW( PDevExt );
  1439. DbgDump(DBG_SERIAL, ("<SetHandFlow %x\n", status));
  1440. return status;
  1441. }
  1442. NTSTATUS
  1443. GetProperties(
  1444. IN PIRP Irp,
  1445. IN PDEVICE_EXTENSION PDevExt
  1446. )
  1447. {
  1448. NTSTATUS status = STATUS_DELETE_PENDING;
  1449. PSERIAL_COMMPROP Properties;
  1450. PIO_STACK_LOCATION IrpStack;
  1451. KIRQL oldIrql;
  1452. DbgDump(DBG_SERIAL, (">GetProperties (%p)\n", Irp));
  1453. KeAcquireSpinLock(&PDevExt->ControlLock, &oldIrql);
  1454. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1455. if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_COMMPROP)) {
  1456. status = STATUS_BUFFER_TOO_SMALL;
  1457. DbgDump(DBG_ERR, ("GetProperties: (0x%x)\n", status));
  1458. } else {
  1459. Properties = (PSERIAL_COMMPROP)Irp->AssociatedIrp.SystemBuffer;
  1460. RtlZeroMemory(Properties, sizeof(SERIAL_COMMPROP));
  1461. Properties->PacketLength = sizeof(SERIAL_COMMPROP);
  1462. Properties->PacketVersion = 2;
  1463. Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
  1464. // internal limits
  1465. Properties->MaxTxQueue = DEFAULT_PIPE_MAX_TRANSFER_SIZE;
  1466. #if defined (USE_RING_BUFF)
  1467. Properties->MaxRxQueue = PDevExt->RingBuff.Size;
  1468. #else
  1469. Properties->MaxRxQueue = PDevExt->UsbReadBuffSize;
  1470. #endif
  1471. Properties->MaxBaud = SERIAL_BAUD_USER; // SERIAL_BAUD_115200;
  1472. Properties->SettableBaud = PDevExt->SerialPort.SupportedBauds;
  1473. Properties->ProvSubType = SERIAL_SP_UNSPECIFIED; // SERIAL_SP_RS232;
  1474. Properties->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS
  1475. | SERIAL_PCF_CD | SERIAL_PCF_XONXOFF
  1476. | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS
  1477. | SERIAL_PCF_SPECIALCHARS;
  1478. Properties->SettableParams = SERIAL_SP_BAUD | SERIAL_SP_CARRIER_DETECT;
  1479. Properties->SettableData = SERIAL_DATABITS_8;
  1480. Properties->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_20
  1481. | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD
  1482. | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK
  1483. | SERIAL_PARITY_SPACE;
  1484. #if defined (USE_RING_BUFF)
  1485. Properties->CurrentRxQueue = PDevExt->RingBuff.Size;
  1486. #else
  1487. Properties->CurrentRxQueue = PDevExt->UsbReadBuffSize;
  1488. Properties->CurrentTxQueue = PDevExt->ReadPipe.MaxPacketSize;
  1489. #endif
  1490. status = STATUS_SUCCESS;
  1491. }
  1492. KeReleaseSpinLock(&PDevExt->ControlLock, oldIrql);
  1493. if (STATUS_SUCCESS == status) {
  1494. Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
  1495. } else {
  1496. Irp->IoStatus.Information = 0;
  1497. }
  1498. DbgDump(DBG_SERIAL, ("<GetProperties %x\n", status));
  1499. return status;
  1500. }
  1501. __inline
  1502. NTSTATUS
  1503. LsrmstInsert(
  1504. IN PIRP Irp,
  1505. IN PDEVICE_EXTENSION PDevExt
  1506. )
  1507. {
  1508. UNREFERENCED_PARAMETER( Irp );
  1509. UNREFERENCED_PARAMETER( PDevExt );
  1510. DbgDump(DBG_SERIAL, (">LsrmstInsert (%p)\n", Irp));
  1511. DbgDump(DBG_SERIAL, ("<LsrmstInsert (%x)\n", STATUS_NOT_SUPPORTED));
  1512. return STATUS_NOT_SUPPORTED;
  1513. }
  1514. __inline
  1515. NTSTATUS
  1516. ConfigSize(
  1517. IN PIRP Irp,
  1518. IN PDEVICE_EXTENSION PDevExt
  1519. )
  1520. {
  1521. PULONG ConfigSize = (PULONG) Irp->AssociatedIrp.SystemBuffer;
  1522. NTSTATUS status = STATUS_SUCCESS;
  1523. PIO_STACK_LOCATION IrpStack;
  1524. UNREFERENCED_PARAMETER( PDevExt );
  1525. DbgDump(DBG_SERIAL, (">ConfigSize (%p)\n", Irp));
  1526. Irp->IoStatus.Information = 0;
  1527. IrpStack = IoGetCurrentIrpStackLocation(Irp);
  1528. if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
  1529. status = STATUS_BUFFER_TOO_SMALL;
  1530. DbgDump(DBG_ERR, ("ConfigSize: (0x%x)\n", status));
  1531. } else {
  1532. *ConfigSize = 0;
  1533. Irp->IoStatus.Information = sizeof(ULONG);
  1534. }
  1535. DbgDump(DBG_SERIAL, ("<ConfigSize %x\n", status));
  1536. return status;
  1537. }
  1538. __inline
  1539. NTSTATUS
  1540. GetStats(
  1541. IN PIRP PIrp,
  1542. IN PDEVICE_EXTENSION PDevExt
  1543. )
  1544. {
  1545. PSERIALPERF_STATS pStats = NULL;
  1546. PIO_STACK_LOCATION pIrpSp;
  1547. NTSTATUS status = STATUS_DELETE_PENDING;
  1548. ULONG information = 0;
  1549. KIRQL irql;
  1550. DbgDump(DBG_SERIAL, (">GetStats %p\n", PIrp));
  1551. KeAcquireSpinLock(&PDevExt->ControlLock, &irql );
  1552. pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  1553. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS) ) {
  1554. status = STATUS_BUFFER_TOO_SMALL;
  1555. DbgDump(DBG_ERR, ("GetStats: (0x%x)\n", status));
  1556. } else {
  1557. information = sizeof(SERIALPERF_STATS);
  1558. status = STATUS_SUCCESS;
  1559. pStats = (PSERIALPERF_STATS)PIrp->AssociatedIrp.SystemBuffer;
  1560. RtlZeroMemory(pStats , sizeof(SERIALPERF_STATS));
  1561. pStats->ReceivedCount = PDevExt->TtlUSBReadBytes;
  1562. pStats->TransmittedCount = PDevExt->TtlWriteBytes;
  1563. pStats->FrameErrorCount = PDevExt->ReadDeviceErrors + PDevExt->WriteDeviceErrors + PDevExt->IntDeviceErrors; // ??
  1564. pStats->SerialOverrunErrorCount = PDevExt->TtlUSBReadBuffOverruns;
  1565. #if defined (USE_RING_BUFF)
  1566. pStats->BufferOverrunErrorCount = PDevExt->TtlRingBuffOverruns;
  1567. #else
  1568. pStats->BufferOverrunErrorCount = 0;
  1569. #endif
  1570. pStats->ParityErrorCount = 0;
  1571. DbgDump(DBG_SERIAL, ("ReceivedCount: %d\n", pStats->ReceivedCount )); \
  1572. DbgDump(DBG_SERIAL, ("TransmittedCount: %d\n", pStats->TransmittedCount )); \
  1573. DbgDump(DBG_SERIAL, ("FrameErrorCount: %d\n", pStats->FrameErrorCount )); \
  1574. DbgDump(DBG_SERIAL, ("SerialOverrunErrorCount: %d\n", pStats->SerialOverrunErrorCount )); \
  1575. DbgDump(DBG_SERIAL, ("BufferOverrunErrorCount: %d\n", pStats->BufferOverrunErrorCount )); \
  1576. DbgDump(DBG_SERIAL, ("ParityErrorCount: %d\n", pStats->ParityErrorCount )); \
  1577. }
  1578. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  1579. PIrp->IoStatus.Information = information;
  1580. PIrp->IoStatus.Status = status;
  1581. DbgDump(DBG_SERIAL, ("<GetStats %x\n", status));
  1582. return status;
  1583. }
  1584. NTSTATUS
  1585. ClearStats(
  1586. IN PIRP Irp,
  1587. IN PDEVICE_EXTENSION PDevExt
  1588. )
  1589. {
  1590. NTSTATUS status = STATUS_DELETE_PENDING;
  1591. KIRQL irql;
  1592. DbgDump(DBG_SERIAL, (">ClearStats (%p)\n", Irp));
  1593. KeAcquireSpinLock(&PDevExt->ControlLock, &irql);
  1594. PDevExt->TtlWriteRequests = 0;
  1595. PDevExt->TtlWriteBytes = 0;
  1596. PDevExt->TtlReadRequests = 0;
  1597. PDevExt->TtlReadBytes = 0;
  1598. PDevExt->TtlUSBReadRequests = 0;
  1599. PDevExt->TtlUSBReadBytes = 0;
  1600. PDevExt->TtlUSBReadBuffOverruns = 0;
  1601. #if defined (USE_RING_BUFF)
  1602. PDevExt->TtlRingBuffOverruns = 0;
  1603. #endif
  1604. status = STATUS_SUCCESS;
  1605. Irp->IoStatus.Information = 0;
  1606. KeReleaseSpinLock(&PDevExt->ControlLock, irql);
  1607. DbgDump(DBG_SERIAL, ("<ClearStats %x\n", status));
  1608. return status;
  1609. }
  1610. /*++
  1611. Note: Unhandled IOCTL_SERIAL_: 0x2b002c : function code 11 is IOCTL_MODEM_CHECK_FOR_MODEM,
  1612. which if unhandled tells the system to load modem.sys over this serial port driver.
  1613. This is setup by RAS & unimodem.
  1614. --*/
  1615. NTSTATUS
  1616. SerialIoctl(
  1617. PDEVICE_OBJECT PDevObj,
  1618. PIRP PIrp
  1619. )
  1620. {
  1621. PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)PDevObj->DeviceExtension;
  1622. PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation(PIrp);
  1623. ULONG ioctl = pIrpSp->Parameters.DeviceIoControl.IoControlCode;
  1624. NTSTATUS status = STATUS_NOT_SUPPORTED;
  1625. BOOLEAN bSignalNeeded = FALSE;
  1626. KIRQL irql;
  1627. LONG lSanity = 0;
  1628. DbgDump(DBG_SERIAL|DBG_TRACE, (">SerialIoctl(%p)\n", PIrp));
  1629. do {
  1630. KeAcquireSpinLock(&pDevExt->ControlLock, &irql);
  1631. //
  1632. // Make sure the device is accepting request
  1633. //
  1634. if ( !CanAcceptIoRequests( PDevObj, FALSE, TRUE) ||
  1635. !NT_SUCCESS(AcquireRemoveLock(&pDevExt->RemoveLock, PIrp)) )
  1636. {
  1637. status = STATUS_DELETE_PENDING;
  1638. DbgDump(DBG_WRN, ("SerialIoctl: 0x%x, 0x%x\n", ioctl, status));
  1639. PIrp->IoStatus.Status = status;
  1640. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  1641. IoCompleteRequest(PIrp, IO_NO_INCREMENT);
  1642. return status;
  1643. }
  1644. ASSERT_SERIAL_PORT( pDevExt->SerialPort );
  1645. KeReleaseSpinLock(&pDevExt->ControlLock, irql);
  1646. switch (ioctl)
  1647. {
  1648. case IOCTL_SERIAL_SET_BAUD_RATE:
  1649. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_BAUD_RATE\n"));
  1650. status = SetBaudRate(PIrp, pDevExt);
  1651. break;
  1652. case IOCTL_SERIAL_GET_BAUD_RATE:
  1653. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_BAUD_RATE\n"));
  1654. status = GetBaudRate(PIrp, pDevExt);
  1655. break;
  1656. case IOCTL_SERIAL_SET_LINE_CONTROL:
  1657. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_LINE_CONTROL\n"));
  1658. status = SetLineControl(PIrp, pDevExt);
  1659. break;
  1660. case IOCTL_SERIAL_GET_LINE_CONTROL:
  1661. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_LINE_CONTROL\n"));
  1662. status = GetLineControl(PIrp, pDevExt);
  1663. break;
  1664. case IOCTL_SERIAL_SET_TIMEOUTS:
  1665. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_TIMEOUTS\n"));
  1666. status = SetTimeouts(PIrp, pDevExt);
  1667. break;
  1668. case IOCTL_SERIAL_GET_TIMEOUTS:
  1669. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_TIMEOUTS\n"));
  1670. status = GetTimeouts(PIrp, pDevExt);
  1671. break;
  1672. case IOCTL_SERIAL_SET_CHARS:
  1673. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_CHARS\n"));
  1674. status = SetSpecialChars(PIrp, pDevExt);
  1675. break;
  1676. case IOCTL_SERIAL_GET_CHARS:
  1677. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_CHARS\n"));
  1678. status = GetSpecialChars(PIrp, pDevExt);
  1679. break;
  1680. case IOCTL_SERIAL_SET_DTR:
  1681. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_DTR\n"));
  1682. status = SetClearDTR(pDevExt, PIrp, TRUE);
  1683. break;
  1684. case IOCTL_SERIAL_CLR_DTR:
  1685. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_CLR_DTR\n"));
  1686. status = SetClearDTR(pDevExt, PIrp, FALSE);
  1687. break;
  1688. case IOCTL_SERIAL_SET_RTS:
  1689. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_RTS\n"));
  1690. status = SetClearRTS(pDevExt, PIrp, TRUE);
  1691. break;
  1692. case IOCTL_SERIAL_CLR_RTS:
  1693. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_CLR_RTS\n"));
  1694. status = SetClearRTS(pDevExt, PIrp, FALSE);
  1695. break;
  1696. case IOCTL_SERIAL_GET_DTRRTS:
  1697. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_DTRRTS\n"));
  1698. status = GetDtrRts(PIrp, pDevExt);
  1699. break;
  1700. case IOCTL_SERIAL_SET_BREAK_ON:
  1701. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_BREAK_ON\n"));
  1702. status = SetBreak(PIrp, pDevExt, 0xFFFF);
  1703. break;
  1704. case IOCTL_SERIAL_SET_BREAK_OFF:
  1705. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_BREAK_OFF\n"));
  1706. status = SetBreak(PIrp, pDevExt, 0);
  1707. break;
  1708. case IOCTL_SERIAL_SET_QUEUE_SIZE:
  1709. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_QUEUE_SIZE\n"));
  1710. status = SetQueueSize(PIrp, pDevExt);
  1711. break;
  1712. case IOCTL_SERIAL_GET_WAIT_MASK:
  1713. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_WAIT_MASK\n"));
  1714. status = GetWaitMask(PIrp, pDevExt);
  1715. break;
  1716. case IOCTL_SERIAL_SET_WAIT_MASK:
  1717. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_WAIT_MASK\n"));
  1718. status = SetWaitMask(PIrp, pDevExt);
  1719. break;
  1720. case IOCTL_SERIAL_WAIT_ON_MASK:
  1721. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_WAIT_ON_MASK\n"));
  1722. status = WaitOnMask(PIrp, pDevExt);
  1723. break;
  1724. case IOCTL_SERIAL_GET_MODEMSTATUS:
  1725. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_MODEMSTATUS\n"));
  1726. status = GetModemStatus(PIrp, pDevExt);
  1727. break;
  1728. case IOCTL_SERIAL_GET_COMMSTATUS:
  1729. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_COMMSTATUS\n"));
  1730. status = GetCommStatus(PIrp, pDevExt);
  1731. break;
  1732. case IOCTL_SERIAL_IMMEDIATE_CHAR:
  1733. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_IMMEDIATE_CHAR\n"));
  1734. status = ImmediateChar(PIrp, PDevObj);
  1735. break;
  1736. case IOCTL_SERIAL_PURGE:
  1737. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_PURGE\n"));
  1738. status = Purge(PDevObj, PIrp);
  1739. break;
  1740. case IOCTL_SERIAL_GET_HANDFLOW:
  1741. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_HANDFLOW\n"));
  1742. status = GetHandflow(PIrp, pDevExt);
  1743. break;
  1744. case IOCTL_SERIAL_SET_HANDFLOW:
  1745. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_SET_HANDFLOW\n"));
  1746. status = SetHandflow(PIrp, pDevExt);
  1747. break;
  1748. case IOCTL_SERIAL_RESET_DEVICE:
  1749. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_RESET_DEVICE\n"));
  1750. status = SerialResetDevice(pDevExt, PIrp, TRUE);
  1751. break;
  1752. case IOCTL_SERIAL_LSRMST_INSERT:
  1753. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_LSRMST_INSERT\n"));
  1754. status = LsrmstInsert(PIrp, pDevExt);
  1755. break;
  1756. case IOCTL_SERIAL_CONFIG_SIZE:
  1757. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_CONFIG_SIZE\n"));
  1758. status = ConfigSize(PIrp, pDevExt);
  1759. break;
  1760. case IOCTL_SERIAL_GET_STATS:
  1761. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_STATS\n"));
  1762. status = GetStats(PIrp, pDevExt);
  1763. break;
  1764. case IOCTL_SERIAL_CLEAR_STATS:
  1765. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_CLEAR_STATS\n"));
  1766. status = ClearStats(PIrp, pDevExt);
  1767. break;
  1768. case IOCTL_SERIAL_GET_PROPERTIES:
  1769. DbgDump(DBG_SERIAL, ("IOCTL_SERIAL_GET_PROPERTIES\n"));
  1770. status = GetProperties(PIrp, pDevExt);
  1771. break;
  1772. default:
  1773. DbgDump(DBG_WRN, ("Unhandled IOCTL_SERIAL_: 0x%x : function code %d\n",
  1774. ioctl, SERIAL_FNCT_CODE(ioctl) ) );
  1775. status = STATUS_NOT_SUPPORTED;
  1776. break;
  1777. }
  1778. } while (0);
  1779. //
  1780. // Don't complete any pending Irps
  1781. //
  1782. if ( STATUS_PENDING != status) {
  1783. PIrp->IoStatus.Status = status;
  1784. ReleaseRemoveLock(&pDevExt->RemoveLock, PIrp);
  1785. IoCompleteRequest(PIrp, IO_SERIAL_INCREMENT);
  1786. }
  1787. #ifdef DELAY_RXBUFF
  1788. //
  1789. // Special Case: the device was just opened.
  1790. // To emulate a serial port RX buffer we need to kick start a USB read.
  1791. // We don't want to do this in the IRP_MJ_CREATE code since AS does
  1792. // IOCTL_SERIAL_SET_WAIT_MASK then *two* IOCTL_SERIAL_SET_DTR requests. If we start the USB read
  1793. // too soon then the CE device can get confused with a Read then SetDTR requests.
  1794. // So, if we were just opened, and we have seen *one* successful IOCTL_SERIAL_SET_DTR then start our USB read.
  1795. // Two good DTRs works better, but we'll let one slip for a timeout or something to recover, e.g. iPAQ on NEC E13+.
  1796. // This may cause problems with other apps, but our target is ActiveSync. We could add a magic registry flag is required.
  1797. // This means that outside of the initial get/set descriptors/configuration the USB is quiet until
  1798. // an app opens the device for I/O... which is a good thing.
  1799. // However, this implementation causes the initial connect to a bit too slow for slow devices (e.g., HP Jornada, Cassiopeia).
  1800. //
  1801. if ( pDevExt->StartUsbRead && (IOCTL_SERIAL_SET_DTR == ioctl) && (STATUS_SUCCESS == status))
  1802. {
  1803. if ( 0 == InterlockedDecrement(&pDevExt->StartUsbRead))
  1804. {
  1805. if ( !pDevExt->IntPipe.hPipe ) {
  1806. DbgDump(DBG_SERIAL, ("SerialIoctl: kick starting another USB Read\n" ));
  1807. status = UsbRead( pDevExt, FALSE );
  1808. } else {
  1809. DbgDump(DBG_SERIAL, ("SerialIoctl: kick starting another USB INT Read\n" ));
  1810. status = UsbInterruptRead( pDevExt );
  1811. }
  1812. if ( NT_SUCCESS(status) ) {
  1813. // should be STATUS_PENDING
  1814. status = STATUS_SUCCESS;
  1815. } else {
  1816. InterlockedIncrement(&pDevExt->StartUsbRead);
  1817. }
  1818. }
  1819. }
  1820. #endif
  1821. DbgDump(DBG_SERIAL|DBG_TRACE, ("<SerialIoctl: %p, 0x%x\n", PIrp, status));
  1822. return status;
  1823. }
  1824. // EOF