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.

413 lines
10 KiB

  1. /*
  2. * UNIMODEM "Fakemodem" controllerless driver illustrative example
  3. *
  4. * (C) 2000 Microsoft Corporation
  5. * All Rights Reserved
  6. *
  7. */
  8. #include "fakemodem.h"
  9. NTSTATUS
  10. FakeModemIoControl(
  11. IN PDEVICE_OBJECT DeviceObject,
  12. IN PIRP Irp
  13. )
  14. {
  15. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  16. NTSTATUS status=STATUS_UNSUCCESSFUL;
  17. KIRQL OldIrql;
  18. PIO_STACK_LOCATION IrpSp;
  19. Irp->IoStatus.Information = 0;
  20. // make sure the device is ready for irp's
  21. status=CheckStateAndAddReference( DeviceObject, Irp);
  22. if (STATUS_SUCCESS != status)
  23. {
  24. // not accepting irp's. The irp has already been complted
  25. return status;
  26. }
  27. IrpSp=IoGetCurrentIrpStackLocation(Irp);
  28. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  29. case IOCTL_SERIAL_GET_WAIT_MASK: {
  30. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  31. sizeof(ULONG))
  32. {
  33. status = STATUS_BUFFER_TOO_SMALL;
  34. break;
  35. }
  36. *((PULONG)Irp->AssociatedIrp.SystemBuffer)=
  37. deviceExtension->CurrentMask;
  38. Irp->IoStatus.Information=sizeof(ULONG);
  39. break;
  40. }
  41. case IOCTL_SERIAL_SET_WAIT_MASK: {
  42. PIRP CurrentWaitIrp=NULL;
  43. ULONG NewMask;
  44. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  45. sizeof(ULONG)) {
  46. status = STATUS_BUFFER_TOO_SMALL;
  47. break;
  48. } else {
  49. KeAcquireSpinLock( &deviceExtension->SpinLock, &OldIrql);
  50. // get rid of the current wait
  51. CurrentWaitIrp=deviceExtension->CurrentMaskIrp;
  52. deviceExtension->CurrentMaskIrp=NULL;
  53. Irp->IoStatus.Information=sizeof(ULONG);
  54. // save the new mask
  55. NewMask = *((ULONG *)Irp->AssociatedIrp.SystemBuffer);
  56. deviceExtension->CurrentMask=NewMask;
  57. D_TRACE(DbgPrint("FAKEMODEM: set wait mask, %08lx\n",NewMask);)
  58. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  59. if (CurrentWaitIrp != NULL) {
  60. D_TRACE(DbgPrint("FAKEMODEM: set wait mask- complete wait\n");)
  61. *((PULONG)CurrentWaitIrp->AssociatedIrp.SystemBuffer)=0;
  62. CurrentWaitIrp->IoStatus.Information=sizeof(ULONG);
  63. RemoveReferenceAndCompleteRequest(
  64. deviceExtension->DeviceObject,
  65. CurrentWaitIrp, STATUS_SUCCESS);
  66. }
  67. }
  68. break;
  69. }
  70. case IOCTL_SERIAL_WAIT_ON_MASK: {
  71. PIRP CurrentWaitIrp=NULL;
  72. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  73. sizeof(ULONG)) {
  74. status = STATUS_BUFFER_TOO_SMALL;
  75. break;
  76. }
  77. D_TRACE(DbgPrint("FAKEMODEM: wait on mask\n");)
  78. KeAcquireSpinLock(&deviceExtension->SpinLock, &OldIrql);
  79. //
  80. // capture the current irp if any
  81. //
  82. CurrentWaitIrp=deviceExtension->CurrentMaskIrp;
  83. deviceExtension->CurrentMaskIrp=NULL;
  84. if (deviceExtension->CurrentMask == 0) {
  85. //
  86. // can only set if mask is not zero
  87. //
  88. status=STATUS_UNSUCCESSFUL;
  89. } else {
  90. deviceExtension->CurrentMaskIrp=Irp;
  91. Irp->IoStatus.Status=STATUS_PENDING;
  92. IoMarkIrpPending(Irp);
  93. #if DBG
  94. Irp=NULL;
  95. #endif
  96. status=STATUS_PENDING;
  97. }
  98. KeReleaseSpinLock(
  99. &deviceExtension->SpinLock,
  100. OldIrql
  101. );
  102. if (CurrentWaitIrp != NULL) {
  103. D_TRACE(DbgPrint("FAKEMODEM: wait on mask- complete wait\n");)
  104. *((PULONG)CurrentWaitIrp->AssociatedIrp.SystemBuffer)=0;
  105. CurrentWaitIrp->IoStatus.Information=sizeof(ULONG);
  106. RemoveReferenceAndCompleteRequest(
  107. deviceExtension->DeviceObject,
  108. CurrentWaitIrp, STATUS_SUCCESS);
  109. }
  110. break;
  111. }
  112. case IOCTL_SERIAL_PURGE: {
  113. ULONG Mask=*((PULONG)Irp->AssociatedIrp.SystemBuffer);
  114. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  115. sizeof(ULONG)) {
  116. status = STATUS_BUFFER_TOO_SMALL;
  117. break;
  118. }
  119. if (Mask & SERIAL_PURGE_RXABORT) {
  120. PIRP Irp;
  121. KeAcquireSpinLock(
  122. &deviceExtension->SpinLock,
  123. &OldIrql
  124. );
  125. while ( !IsListEmpty(&deviceExtension->ReadQueue)) {
  126. PLIST_ENTRY ListElement;
  127. PIRP Irp;
  128. PIO_STACK_LOCATION IrpSp;
  129. KIRQL CancelIrql;
  130. ListElement=RemoveHeadList(
  131. &deviceExtension->ReadQueue
  132. );
  133. Irp=CONTAINING_RECORD(ListElement,IRP,
  134. Tail.Overlay.ListEntry);
  135. IoAcquireCancelSpinLock(&CancelIrql);
  136. if (Irp->Cancel) {
  137. //
  138. // this one has been canceled
  139. //
  140. Irp->IoStatus.Information=STATUS_CANCELLED;
  141. IoReleaseCancelSpinLock(CancelIrql);
  142. continue;
  143. }
  144. IoSetCancelRoutine( Irp, NULL);
  145. IoReleaseCancelSpinLock(CancelIrql);
  146. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  147. Irp->IoStatus.Information=0;
  148. RemoveReferenceAndCompleteRequest(
  149. deviceExtension->DeviceObject, Irp, STATUS_CANCELLED);
  150. KeAcquireSpinLock( &deviceExtension->SpinLock, &OldIrql);
  151. }
  152. Irp=NULL;
  153. if (deviceExtension->CurrentReadIrp != NULL)
  154. {
  155. //
  156. // get the current one
  157. //
  158. Irp=deviceExtension->CurrentReadIrp;
  159. deviceExtension->CurrentReadIrp=NULL;
  160. }
  161. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  162. if (Irp != NULL) {
  163. Irp->IoStatus.Information=0;
  164. RemoveReferenceAndCompleteRequest(
  165. deviceExtension->DeviceObject, Irp, STATUS_CANCELLED);
  166. }
  167. }
  168. break;
  169. }
  170. case IOCTL_SERIAL_GET_MODEMSTATUS: {
  171. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  172. sizeof(ULONG)) {
  173. status = STATUS_BUFFER_TOO_SMALL;
  174. break;
  175. }
  176. Irp->IoStatus.Information=sizeof(ULONG);
  177. *((PULONG)Irp->AssociatedIrp.SystemBuffer)=
  178. deviceExtension->ModemStatus;
  179. break;
  180. }
  181. case IOCTL_SERIAL_SET_TIMEOUTS: {
  182. PSERIAL_TIMEOUTS NewTimeouts =
  183. ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
  184. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  185. sizeof(SERIAL_TIMEOUTS)) {
  186. status = STATUS_BUFFER_TOO_SMALL;
  187. break;
  188. }
  189. RtlCopyMemory(
  190. &deviceExtension->CurrentTimeouts, NewTimeouts,
  191. sizeof(PSERIAL_TIMEOUTS));
  192. Irp->IoStatus.Information = sizeof(PSERIAL_TIMEOUTS);
  193. break;
  194. }
  195. case IOCTL_SERIAL_GET_TIMEOUTS: {
  196. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  197. sizeof(SERIAL_TIMEOUTS)) {
  198. status = STATUS_BUFFER_TOO_SMALL;
  199. break;
  200. }
  201. RtlCopyMemory(
  202. Irp->AssociatedIrp.SystemBuffer,
  203. &deviceExtension->CurrentTimeouts, sizeof(PSERIAL_TIMEOUTS));
  204. Irp->IoStatus.Information = sizeof(PSERIAL_TIMEOUTS);
  205. break;
  206. }
  207. case IOCTL_SERIAL_GET_COMMSTATUS: {
  208. PSERIAL_STATUS SerialStatus=(PSERIAL_STATUS)Irp->AssociatedIrp.SystemBuffer;
  209. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  210. sizeof(SERIAL_STATUS)) {
  211. status = STATUS_BUFFER_TOO_SMALL;
  212. break;
  213. }
  214. RtlZeroMemory( SerialStatus, sizeof(SERIAL_STATUS));
  215. KeAcquireSpinLock( &deviceExtension->SpinLock, &OldIrql);
  216. SerialStatus->AmountInInQueue=deviceExtension->BytesInReadBuffer;
  217. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  218. Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
  219. break;
  220. }
  221. case IOCTL_SERIAL_SET_DTR:
  222. case IOCTL_SERIAL_CLR_DTR: {
  223. KeAcquireSpinLock( &deviceExtension->SpinLock, &OldIrql);
  224. if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR) {
  225. //
  226. // raising DTR
  227. //
  228. deviceExtension->ModemStatus=SERIAL_DTR_STATE | SERIAL_DSR_STATE;
  229. D_TRACE(DbgPrint("FAKEMODEM: Set DTR\n");)
  230. } else {
  231. //
  232. // dropping DTR, drop connection if there is one
  233. //
  234. D_TRACE(DbgPrint("FAKEMODEM: Clear DTR\n");)
  235. if (deviceExtension->CurrentlyConnected == TRUE) {
  236. //
  237. // not connected any more
  238. //
  239. deviceExtension->CurrentlyConnected=FALSE;
  240. deviceExtension->ConnectionStateChanged=TRUE;
  241. }
  242. }
  243. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  244. ProcessConnectionStateChange( DeviceObject);
  245. break;
  246. }
  247. default:
  248. status=STATUS_SUCCESS;
  249. }
  250. if (status != STATUS_PENDING) {
  251. //
  252. // complete now if not pending
  253. //
  254. RemoveReferenceAndCompleteRequest( DeviceObject, Irp, status);
  255. }
  256. RemoveReferenceForDispatch(DeviceObject);
  257. return status;
  258. }