Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

645 lines
17 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. serial.c
  5. Abstract:
  6. Author:
  7. Thomas J. Dimitri (TommyD) 08-May-1992
  8. Environment:
  9. Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
  10. Revision History:
  11. --*/
  12. #include "asyncall.h"
  13. #define IopQueueThreadIrp( Irp ) { \
  14. KIRQL irql; \
  15. KeRaiseIrql( (KIRQL)APC_LEVEL, &irql ); \
  16. InsertHeadList( &Irp->Tail.Overlay.Thread->IrpList, \
  17. &Irp->ThreadListEntry ); \
  18. KeLowerIrql( irql ); \
  19. }
  20. VOID
  21. InitSerialIrp(
  22. PIRP irp,
  23. PASYNC_INFO pInfo,
  24. ULONG IoControlCode,
  25. ULONG InputBufferLength)
  26. {
  27. PIO_STACK_LOCATION irpSp;
  28. PFILE_OBJECT fileObject = pInfo->FileObject;
  29. irpSp = IoGetNextIrpStackLocation(irp);
  30. irp->Tail.Overlay.OriginalFileObject = fileObject;
  31. irp->RequestorMode = KernelMode;
  32. irp->PendingReturned = FALSE;
  33. //
  34. // Fill in the service independent parameters in the IRP.
  35. //
  36. irp->UserEvent = NULL;
  37. irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
  38. irp->Overlay.AsynchronousParameters.UserApcContext = NULL;
  39. irp->Flags = IRP_BUFFERED_IO;
  40. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  41. //
  42. // stuff in file object
  43. //
  44. irpSp->FileObject = fileObject ;
  45. irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
  46. irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  47. irpSp->Parameters.DeviceIoControl.OutputBufferLength = InputBufferLength;
  48. }
  49. NTSTATUS
  50. SerialIoSyncCompletionRoutine(
  51. IN PDEVICE_OBJECT DeviceObject,
  52. IN PIRP Irp,
  53. IN PVOID Context)
  54. {
  55. PASYNC_IO_CTX AsyncIoCtx = (PASYNC_IO_CTX)Context;
  56. DbgTracef(0,("SerialIoSyncCompletion returns 0x%.8x\n", Irp->IoStatus.Status));
  57. ASSERT(AsyncIoCtx->Sync == TRUE);
  58. AsyncIoCtx->IoStatus = Irp->IoStatus;
  59. KeSetEvent(&AsyncIoCtx->Event, // Event
  60. 1, // Priority
  61. (BOOLEAN)FALSE); // Wait (does not follow)
  62. //
  63. // We return STATUS_MORE_PROCESSING_REQUIRED so that the
  64. // IoCompletionRoutine will stop working on the IRP.
  65. return(STATUS_MORE_PROCESSING_REQUIRED);
  66. }
  67. NTSTATUS
  68. SerialIoAsyncCompletionRoutine(
  69. IN PDEVICE_OBJECT DeviceObject,
  70. IN PIRP Irp,
  71. IN PVOID Context)
  72. {
  73. DbgTracef(0,("SerialIoAsyncCompletion returns 0x%.8x\n", Irp->IoStatus.Status));
  74. ASSERT(((PASYNC_IO_CTX)Context)->Sync == FALSE);
  75. //
  76. // Free the irp here. Hopefully this has no disastrous
  77. // side effects such as the IO system trying to reference
  78. // the irp when we complete.
  79. IoFreeIrp(Irp);
  80. AsyncFreeIoCtx((PASYNC_IO_CTX)Context);
  81. //
  82. // We return STATUS_MORE_PROCESSING_REQUIRED so that the
  83. // IoCompletionRoutine will stop working on the IRP.
  84. return(STATUS_MORE_PROCESSING_REQUIRED);
  85. }
  86. //*
  87. // Note: we ignore the irp passed in to work around a problem where the SET_QUEUE_SIZE ioctl
  88. // is not completed synchronously
  89. //
  90. //*
  91. VOID
  92. SetSerialStuff(
  93. PIRP unusedirp,
  94. PASYNC_INFO pInfo,
  95. ULONG linkSpeed)
  96. {
  97. NTSTATUS status;
  98. PIRP irp ;
  99. PASYNC_IO_CTX AsyncIoCtx;
  100. //
  101. // We deallocate the irp in SerialIoAsyncCompletionRoutine
  102. //
  103. irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  104. if (irp == NULL) {
  105. return;
  106. }
  107. InitSerialIrp(
  108. irp,
  109. pInfo,
  110. IOCTL_SERIAL_SET_QUEUE_SIZE,
  111. sizeof(SERIAL_QUEUE_SIZE));
  112. AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
  113. if (AsyncIoCtx == NULL) {
  114. IoFreeIrp(irp);
  115. return;
  116. }
  117. AsyncIoCtx->SerialQueueSize.InSize=4096;
  118. AsyncIoCtx->SerialQueueSize.OutSize=4096;
  119. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialQueueSize;
  120. IoSetCompletionRoutine(
  121. irp, // irp to use
  122. SerialIoAsyncCompletionRoutine, // routine to call when irp is done
  123. AsyncIoCtx, // context to pass routine
  124. TRUE, // call on success
  125. TRUE, // call on error
  126. TRUE); // call on cancel
  127. //
  128. // Now simply invoke the driver at its dispatch entry with the IRP.
  129. //
  130. status = IoCallDriver(pInfo->DeviceObject, irp);
  131. DbgTracef(0,("IoctlSetQueueSize status 0x%.8x\n", status));
  132. SetSerialTimeouts(pInfo,linkSpeed);
  133. }
  134. VOID
  135. CancelSerialRequests(
  136. PASYNC_INFO pInfo)
  137. /*++
  138. --*/
  139. {
  140. NTSTATUS status;
  141. PASYNC_IO_CTX AsyncIoCtx;
  142. PIRP irp;
  143. //
  144. // For PPP we must clear the WAIT MASK if it exists
  145. //
  146. irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  147. if (irp == NULL) {
  148. return;
  149. }
  150. InitSerialIrp(
  151. irp,
  152. pInfo,
  153. IOCTL_SERIAL_SET_WAIT_MASK,
  154. sizeof(ULONG));
  155. AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pInfo);
  156. if (AsyncIoCtx == NULL) {
  157. IoFreeIrp(irp);
  158. return;
  159. }
  160. AsyncIoCtx->WaitMask = 0;
  161. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->WaitMask;
  162. IoSetCompletionRoutine(
  163. irp, // irp to use
  164. SerialIoSyncCompletionRoutine, // routine to call when irp is done
  165. AsyncIoCtx, // context to pass routine
  166. TRUE, // call on success
  167. TRUE, // call on error
  168. TRUE); // call on cancel
  169. //
  170. // Now simply invoke the driver at its dispatch entry with the IRP.
  171. //
  172. KeClearEvent(&AsyncIoCtx->Event);
  173. status = IoCallDriver(pInfo->DeviceObject, irp);
  174. if (status == STATUS_PENDING) {
  175. KeWaitForSingleObject(&AsyncIoCtx->Event,
  176. Executive,
  177. KernelMode,
  178. FALSE,
  179. NULL);
  180. status = AsyncIoCtx->IoStatus.Status;
  181. }
  182. DbgTracef(0,("IoctlSerialWaitMask returned with 0x%.8x\n", status));
  183. if (status != STATUS_SUCCESS) {
  184. KeSetEvent(&pInfo->ClosingEvent, // Event
  185. 1, // Priority
  186. (BOOLEAN)FALSE); // Wait (does not follow)
  187. }
  188. InitSerialIrp(irp, pInfo, IOCTL_SERIAL_PURGE, sizeof(ULONG));
  189. RtlZeroMemory(&AsyncIoCtx->IoStatus, sizeof(IO_STATUS_BLOCK));
  190. // kill all read and write threads.
  191. AsyncIoCtx->SerialPurge = SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT;
  192. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialPurge;
  193. IoSetCompletionRoutine(
  194. irp, // irp to use
  195. SerialIoSyncCompletionRoutine, // routine to call when irp is done
  196. AsyncIoCtx, // context to pass routine
  197. TRUE, // call on success
  198. TRUE, // call on error
  199. TRUE); // call on cancel
  200. //
  201. // Now simply invoke the driver at its dispatch entry with the IRP.
  202. //
  203. KeClearEvent(&AsyncIoCtx->Event);
  204. status = IoCallDriver(pInfo->DeviceObject, irp);
  205. if (status == STATUS_PENDING) {
  206. KeWaitForSingleObject(&AsyncIoCtx->Event,
  207. Executive,
  208. KernelMode,
  209. FALSE,
  210. NULL);
  211. status = AsyncIoCtx->IoStatus.Status;
  212. }
  213. if (status != STATUS_SUCCESS) {
  214. KeSetEvent(&pInfo->ClosingEvent, // Event
  215. 1, // Priority
  216. (BOOLEAN)FALSE); // Wait (does not follow)
  217. }
  218. IoFreeIrp(irp);
  219. AsyncFreeIoCtx(AsyncIoCtx);
  220. DbgTracef(0,("IoctlSerialPurge returned with 0x%.8x\n", status));
  221. }
  222. VOID
  223. SetSerialTimeouts(
  224. PASYNC_INFO pInfo,
  225. ULONG linkSpeed)
  226. /*++
  227. --*/
  228. {
  229. NTSTATUS status;
  230. PIRP irp;
  231. PASYNC_ADAPTER pAdapter=pInfo->Adapter;
  232. PASYNC_IO_CTX AsyncIoCtx;
  233. //
  234. // We deallocate the irp in SerialIoAsyncCompletionRoutine
  235. //
  236. irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  237. if (irp == NULL) {
  238. return;
  239. }
  240. InitSerialIrp(
  241. irp,
  242. pInfo,
  243. IOCTL_SERIAL_SET_TIMEOUTS,
  244. sizeof(SERIAL_TIMEOUTS));
  245. AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
  246. if (AsyncIoCtx == NULL) {
  247. IoFreeIrp(irp);
  248. return;
  249. }
  250. //
  251. // The assumption here is that V.42bis is using 256 byte frames.
  252. // Thus, it takes (256000 / 8) / (linkspeed in 100's of bits per sec)
  253. // time in millisecs to get that frame across.
  254. //
  255. // 500 or 1/2 sec is the fudge factor for satellite delay on
  256. // a long distance call
  257. //
  258. //
  259. // If the linkSpeed is high, we assume we are trying to resync
  260. // so we set the timeout low. linkSpeed is in 100s of bits per sec.
  261. //
  262. if (linkSpeed == 0) {
  263. //
  264. // return immediately (PPP or SLIP framing)
  265. //
  266. AsyncIoCtx->SerialTimeouts.ReadIntervalTimeout= MAXULONG;
  267. } else if (linkSpeed > 20000) {
  268. AsyncIoCtx->SerialTimeouts.ReadIntervalTimeout= pAdapter->TimeoutReSync;
  269. } else {
  270. AsyncIoCtx->SerialTimeouts.ReadIntervalTimeout=
  271. pAdapter->TimeoutBase + (pAdapter->TimeoutBaud / linkSpeed);
  272. }
  273. AsyncIoCtx->SerialTimeouts.ReadTotalTimeoutMultiplier= 0; // none
  274. AsyncIoCtx->SerialTimeouts.ReadTotalTimeoutConstant= 0; // none
  275. AsyncIoCtx->SerialTimeouts.WriteTotalTimeoutMultiplier= 4; // 2400 baud
  276. AsyncIoCtx->SerialTimeouts.WriteTotalTimeoutConstant= 4000; // 4 secs
  277. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialTimeouts;
  278. IoSetCompletionRoutine(
  279. irp, // irp to use
  280. SerialIoAsyncCompletionRoutine, // routine to call when irp is done
  281. AsyncIoCtx, // context to pass routine
  282. TRUE, // call on success
  283. TRUE, // call on error
  284. TRUE); // call on cancel
  285. //
  286. // Now simply invoke the driver at its dispatch entry with the IRP.
  287. //
  288. status = IoCallDriver(pInfo->DeviceObject, irp);
  289. DbgTracef(0,("IoctlSetSerialTimeouts returned 0x%.8x\n", status));
  290. }
  291. VOID
  292. SerialSetEscapeChar(
  293. PASYNC_INFO pInfo,
  294. UCHAR EscapeChar) {
  295. NTSTATUS status;
  296. PIRP irp;
  297. PASYNC_IO_CTX AsyncIoCtx;
  298. //
  299. // We deallocate the irp in SerialIoAsyncCompletionRoutine
  300. //
  301. irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  302. if (irp == NULL) {
  303. return;
  304. }
  305. InitSerialIrp(
  306. irp,
  307. pInfo,
  308. IOCTL_SERIAL_LSRMST_INSERT,
  309. sizeof(UCHAR));
  310. AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
  311. if (AsyncIoCtx == NULL) {
  312. IoFreeIrp(irp);
  313. return;
  314. }
  315. AsyncIoCtx->EscapeChar = EscapeChar;
  316. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->EscapeChar;
  317. IoSetCompletionRoutine(
  318. irp, // irp to use
  319. SerialIoAsyncCompletionRoutine, // routine to call when irp is done
  320. AsyncIoCtx, // context to pass routine
  321. TRUE, // call on success
  322. TRUE, // call on error
  323. TRUE); // call on cancel
  324. //
  325. // Now simply invoke the driver at its dispatch entry with the IRP.
  326. //
  327. status = IoCallDriver(pInfo->DeviceObject, irp);
  328. DbgTracef(0,("IoctlSetEscapeChar returned with 0x%.8x\n", status));
  329. }
  330. VOID
  331. SerialSetWaitMask(
  332. PASYNC_INFO pInfo,
  333. ULONG WaitMask) {
  334. NTSTATUS status;
  335. PIRP irp;
  336. PASYNC_IO_CTX AsyncIoCtx;
  337. //
  338. // We deallocate the irp in SerialIoAsyncCompletionRoutine
  339. //
  340. irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  341. if (irp == NULL) {
  342. return;
  343. }
  344. InitSerialIrp(
  345. irp,
  346. pInfo,
  347. IOCTL_SERIAL_SET_WAIT_MASK,
  348. sizeof(ULONG));
  349. AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
  350. if (AsyncIoCtx == NULL) {
  351. IoFreeIrp(irp);
  352. return;
  353. }
  354. AsyncIoCtx->WaitMask = WaitMask;
  355. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->WaitMask;
  356. IoSetCompletionRoutine(
  357. irp, // irp to use
  358. SerialIoAsyncCompletionRoutine, // routine to call when irp is done
  359. AsyncIoCtx, // context to pass routine
  360. TRUE, // call on success
  361. TRUE, // call on error
  362. TRUE); // call on cancel
  363. //
  364. // Now simply invoke the driver at its dispatch entry with the IRP.
  365. //
  366. status = IoCallDriver(pInfo->DeviceObject, irp);
  367. DbgTracef(0,("IoctlSetWaitMask returned with 0x%.8x\n", status));
  368. }
  369. VOID
  370. SerialSetEventChar(
  371. PASYNC_INFO pInfo,
  372. UCHAR EventChar) {
  373. NTSTATUS status;
  374. PIRP irp;
  375. PASYNC_IO_CTX AsyncIoCtx;
  376. //
  377. // We deallocate the irp in SerialIoAsyncCompletionRoutine
  378. //
  379. irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  380. if (irp == NULL) {
  381. return;
  382. }
  383. InitSerialIrp(
  384. irp,
  385. pInfo,
  386. IOCTL_SERIAL_GET_CHARS,
  387. sizeof(SERIAL_CHARS));
  388. AsyncIoCtx = AsyncAllocateIoCtx(TRUE, pInfo);
  389. if (AsyncIoCtx == NULL) {
  390. IoFreeIrp(irp);
  391. return;
  392. }
  393. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialChars;
  394. IoSetCompletionRoutine(
  395. irp, // irp to use
  396. SerialIoSyncCompletionRoutine, // routine to call when irp is done
  397. AsyncIoCtx, // context to pass routine
  398. TRUE, // call on success
  399. TRUE, // call on error
  400. TRUE); // call on cancel
  401. //
  402. // Now simply invoke the driver at its dispatch entry with the IRP.
  403. //
  404. KeClearEvent(&AsyncIoCtx->Event);
  405. status = IoCallDriver(pInfo->DeviceObject, irp);
  406. if (status == STATUS_PENDING) {
  407. KeWaitForSingleObject(&AsyncIoCtx->Event,
  408. Executive,
  409. KernelMode,
  410. FALSE,
  411. NULL);
  412. status = AsyncIoCtx->IoStatus.Status;
  413. }
  414. DbgTracef(0,("IoctlGetChars returned with 0x%.8x\n", status));
  415. if (status != STATUS_SUCCESS) {
  416. IoFreeIrp(irp);
  417. AsyncFreeIoCtx(AsyncIoCtx);
  418. return;
  419. }
  420. AsyncIoCtx->SerialChars.EventChar = EventChar;
  421. AsyncIoCtx->Sync = FALSE;
  422. InitSerialIrp(
  423. irp,
  424. pInfo,
  425. IOCTL_SERIAL_SET_CHARS,
  426. sizeof(SERIAL_CHARS));
  427. IoSetCompletionRoutine(
  428. irp, // irp to use
  429. SerialIoAsyncCompletionRoutine, // routine to call when irp is done
  430. AsyncIoCtx, // context to pass routine
  431. TRUE, // call on success
  432. TRUE, // call on error
  433. TRUE); // call on cancel
  434. //
  435. // Now simply invoke the driver at its dispatch entry with the IRP.
  436. //
  437. status = IoCallDriver(pInfo->DeviceObject, irp);
  438. DbgTracef(0,("IoctlSetChars returned with 0x%.8x\n", status));
  439. }
  440. VOID
  441. SerialFlushReads(
  442. PASYNC_INFO pInfo) {
  443. ULONG serialPurge;
  444. NTSTATUS status;
  445. PIRP irp;
  446. PASYNC_IO_CTX AsyncIoCtx;
  447. //
  448. // We deallocate the irp in SerialIoAsyncCompletionRoutine
  449. //
  450. irp=IoAllocateIrp(pInfo->DeviceObject->StackSize, (BOOLEAN)FALSE);
  451. if (irp == NULL) {
  452. return;
  453. }
  454. InitSerialIrp(
  455. irp,
  456. pInfo,
  457. IOCTL_SERIAL_PURGE,
  458. sizeof(ULONG));
  459. AsyncIoCtx = AsyncAllocateIoCtx(FALSE, pInfo);
  460. if (AsyncIoCtx == NULL) {
  461. IoFreeIrp(irp);
  462. return;
  463. }
  464. // kill read buffer
  465. AsyncIoCtx->SerialPurge=SERIAL_PURGE_RXCLEAR;
  466. irp->AssociatedIrp.SystemBuffer=&AsyncIoCtx->SerialPurge;
  467. IoSetCompletionRoutine(
  468. irp, // irp to use
  469. SerialIoAsyncCompletionRoutine, // routine to call when irp is done
  470. AsyncIoCtx, // context to pass routine
  471. TRUE, // call on success
  472. TRUE, // call on error
  473. TRUE); // call on cancel
  474. //
  475. // Now simply invoke the driver at its dispatch entry with the IRP.
  476. //
  477. status = IoCallDriver(pInfo->DeviceObject, irp);
  478. DbgTracef(0,("IoctlPurge returned with 0x%.8x\n", status));
  479. }