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.

408 lines
11 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. KeAcquireSpinLock(
  121. &deviceExtension->SpinLock,
  122. &OldIrql
  123. );
  124. while ( !IsListEmpty(&deviceExtension->ReadQueue)) {
  125. PLIST_ENTRY ListElement;
  126. KIRQL CancelIrql;
  127. ListElement=RemoveHeadList(
  128. &deviceExtension->ReadQueue
  129. );
  130. Irp=CONTAINING_RECORD(ListElement,IRP,
  131. Tail.Overlay.ListEntry);
  132. IoAcquireCancelSpinLock(&CancelIrql);
  133. if (Irp->Cancel) {
  134. //
  135. // this one has been canceled
  136. //
  137. Irp->IoStatus.Information=STATUS_CANCELLED;
  138. IoReleaseCancelSpinLock(CancelIrql);
  139. continue;
  140. }
  141. IoSetCancelRoutine( Irp, NULL);
  142. IoReleaseCancelSpinLock(CancelIrql);
  143. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  144. Irp->IoStatus.Information=0;
  145. RemoveReferenceAndCompleteRequest(
  146. deviceExtension->DeviceObject, Irp, STATUS_CANCELLED);
  147. KeAcquireSpinLock( &deviceExtension->SpinLock, &OldIrql);
  148. }
  149. Irp=NULL;
  150. if (deviceExtension->CurrentReadIrp != NULL)
  151. {
  152. //
  153. // get the current one
  154. //
  155. Irp=deviceExtension->CurrentReadIrp;
  156. deviceExtension->CurrentReadIrp=NULL;
  157. }
  158. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  159. if (Irp != NULL) {
  160. Irp->IoStatus.Information=0;
  161. RemoveReferenceAndCompleteRequest(
  162. deviceExtension->DeviceObject, Irp, STATUS_CANCELLED);
  163. }
  164. }
  165. break;
  166. }
  167. case IOCTL_SERIAL_GET_MODEMSTATUS: {
  168. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  169. sizeof(ULONG)) {
  170. status = STATUS_BUFFER_TOO_SMALL;
  171. break;
  172. }
  173. Irp->IoStatus.Information=sizeof(ULONG);
  174. *((PULONG)Irp->AssociatedIrp.SystemBuffer)=
  175. deviceExtension->ModemStatus;
  176. break;
  177. }
  178. case IOCTL_SERIAL_SET_TIMEOUTS: {
  179. PSERIAL_TIMEOUTS NewTimeouts =
  180. ((PSERIAL_TIMEOUTS)(Irp->AssociatedIrp.SystemBuffer));
  181. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  182. sizeof(SERIAL_TIMEOUTS)) {
  183. status = STATUS_BUFFER_TOO_SMALL;
  184. break;
  185. }
  186. RtlCopyMemory(
  187. &deviceExtension->CurrentTimeouts, NewTimeouts,
  188. sizeof(PSERIAL_TIMEOUTS));
  189. Irp->IoStatus.Information = sizeof(PSERIAL_TIMEOUTS);
  190. break;
  191. }
  192. case IOCTL_SERIAL_GET_TIMEOUTS: {
  193. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  194. sizeof(SERIAL_TIMEOUTS)) {
  195. status = STATUS_BUFFER_TOO_SMALL;
  196. break;
  197. }
  198. RtlCopyMemory(
  199. Irp->AssociatedIrp.SystemBuffer,
  200. &deviceExtension->CurrentTimeouts, sizeof(PSERIAL_TIMEOUTS));
  201. Irp->IoStatus.Information = sizeof(PSERIAL_TIMEOUTS);
  202. break;
  203. }
  204. case IOCTL_SERIAL_GET_COMMSTATUS: {
  205. PSERIAL_STATUS SerialStatus=(PSERIAL_STATUS)Irp->AssociatedIrp.SystemBuffer;
  206. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  207. sizeof(SERIAL_STATUS)) {
  208. status = STATUS_BUFFER_TOO_SMALL;
  209. break;
  210. }
  211. RtlZeroMemory( SerialStatus, sizeof(SERIAL_STATUS));
  212. KeAcquireSpinLock( &deviceExtension->SpinLock, &OldIrql);
  213. SerialStatus->AmountInInQueue=deviceExtension->BytesInReadBuffer;
  214. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  215. Irp->IoStatus.Information = sizeof(SERIAL_STATUS);
  216. break;
  217. }
  218. case IOCTL_SERIAL_SET_DTR:
  219. case IOCTL_SERIAL_CLR_DTR: {
  220. KeAcquireSpinLock( &deviceExtension->SpinLock, &OldIrql);
  221. if (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_DTR) {
  222. //
  223. // raising DTR
  224. //
  225. deviceExtension->ModemStatus=SERIAL_DTR_STATE | SERIAL_DSR_STATE;
  226. D_TRACE(DbgPrint("FAKEMODEM: Set DTR\n");)
  227. } else {
  228. //
  229. // dropping DTR, drop connection if there is one
  230. //
  231. D_TRACE(DbgPrint("FAKEMODEM: Clear DTR\n");)
  232. if (deviceExtension->CurrentlyConnected == TRUE) {
  233. //
  234. // not connected any more
  235. //
  236. deviceExtension->CurrentlyConnected=FALSE;
  237. deviceExtension->ConnectionStateChanged=TRUE;
  238. }
  239. }
  240. KeReleaseSpinLock( &deviceExtension->SpinLock, OldIrql);
  241. ProcessConnectionStateChange( DeviceObject);
  242. break;
  243. }
  244. default:
  245. status=STATUS_SUCCESS;
  246. }
  247. if (status != STATUS_PENDING) {
  248. //
  249. // complete now if not pending
  250. //
  251. RemoveReferenceAndCompleteRequest( DeviceObject, Irp, status);
  252. }
  253. RemoveReferenceForDispatch(DeviceObject);
  254. return status;
  255. }