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.

450 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: ioctl.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. NTSTATUS
  12. PptFdoInternalDeviceControl(
  13. IN PDEVICE_OBJECT DeviceObject,
  14. IN PIRP Irp
  15. )
  16. /*++
  17. Routine Description:
  18. This routine is the dispatch routine for IRP_MJ_INTERNAL_DEVICE_CONTROL.
  19. Arguments:
  20. DeviceObject - Supplies the device object.
  21. Irp - Supplies the I/O request packet.
  22. Return Value:
  23. STATUS_SUCCESS - Success.
  24. STATUS_UNSUCCESSFUL - The request was unsuccessful.
  25. STATUS_PENDING - The request is pending.
  26. STATUS_INVALID_PARAMETER - Invalid parameter.
  27. STATUS_CANCELLED - The request was cancelled.
  28. STATUS_BUFFER_TOO_SMALL - The supplied buffer is too small.
  29. STATUS_INVALID_DEVICE_STATE - The current chip mode is invalid to change to asked mode
  30. --*/
  31. {
  32. PIO_STACK_LOCATION IrpSp;
  33. PFDO_EXTENSION Extension = DeviceObject->DeviceExtension;
  34. NTSTATUS Status;
  35. PPARALLEL_PORT_INFORMATION PortInfo;
  36. PPARALLEL_PNP_INFORMATION PnpInfo;
  37. PMORE_PARALLEL_PORT_INFORMATION MorePortInfo;
  38. KIRQL CancelIrql;
  39. SYNCHRONIZED_COUNT_CONTEXT SyncContext;
  40. PPARALLEL_INTERRUPT_SERVICE_ROUTINE IsrInfo;
  41. PPARALLEL_INTERRUPT_INFORMATION InterruptInfo;
  42. PISR_LIST_ENTRY IsrListEntry;
  43. SYNCHRONIZED_LIST_CONTEXT ListContext;
  44. SYNCHRONIZED_DISCONNECT_CONTEXT DisconnectContext;
  45. BOOLEAN DisconnectInterrupt;
  46. //
  47. // Verify that our device has not been SUPRISE_REMOVED. Generally
  48. // only parallel ports on hot-plug busses (e.g., PCMCIA) and
  49. // parallel ports in docking stations will be surprise removed.
  50. //
  51. // dvdf - RMT - It would probably be a good idea to also check
  52. // here if we are in a "paused" state (stop-pending, stopped, or
  53. // remove-pending) and queue the request until we either return to
  54. // a fully functional state or are removed.
  55. //
  56. if( Extension->PnpState & PPT_DEVICE_SURPRISE_REMOVED ) {
  57. return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
  58. }
  59. //
  60. // Try to acquire RemoveLock to prevent the device object from going
  61. // away while we're using it.
  62. //
  63. Status = PptAcquireRemoveLockOrFailIrp( DeviceObject, Irp );
  64. if ( !NT_SUCCESS(Status) ) {
  65. return Status;
  66. }
  67. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  68. Irp->IoStatus.Information = 0;
  69. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  70. case IOCTL_INTERNAL_DISABLE_END_OF_CHAIN_BUS_RESCAN:
  71. Extension->DisableEndOfChainBusRescan = TRUE;
  72. Status = STATUS_SUCCESS;
  73. break;
  74. case IOCTL_INTERNAL_ENABLE_END_OF_CHAIN_BUS_RESCAN:
  75. Extension->DisableEndOfChainBusRescan = FALSE;
  76. Status = STATUS_SUCCESS;
  77. break;
  78. case IOCTL_INTERNAL_PARALLEL_PORT_FREE:
  79. PptFreePort(Extension);
  80. PptReleaseRemoveLock(&Extension->RemoveLock, Irp);
  81. return P4CompleteRequest( Irp, STATUS_SUCCESS, Irp->IoStatus.Information );
  82. case IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE:
  83. IoAcquireCancelSpinLock(&CancelIrql);
  84. if( Irp->Cancel ) {
  85. Status = STATUS_CANCELLED;
  86. } else {
  87. SyncContext.Count = &Extension->WorkQueueCount;
  88. if( Extension->InterruptRefCount ) {
  89. KeSynchronizeExecution( Extension->InterruptObject, PptSynchronizedIncrement, &SyncContext );
  90. } else {
  91. PptSynchronizedIncrement( &SyncContext );
  92. }
  93. if (SyncContext.NewCount) {
  94. // someone else currently has the port, queue request
  95. PptSetCancelRoutine( Irp, PptCancelRoutine );
  96. IoMarkIrpPending( Irp );
  97. InsertTailList( &Extension->WorkQueue, &Irp->Tail.Overlay.ListEntry );
  98. Status = STATUS_PENDING;
  99. } else {
  100. // port aquired
  101. Extension->WmiPortAllocFreeCounts.PortAllocates++;
  102. Status = STATUS_SUCCESS;
  103. }
  104. } // endif Irp->Cancel
  105. IoReleaseCancelSpinLock(CancelIrql);
  106. break;
  107. case IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO:
  108. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  109. sizeof(PARALLEL_PORT_INFORMATION)) {
  110. Status = STATUS_BUFFER_TOO_SMALL;
  111. } else {
  112. Irp->IoStatus.Information = sizeof(PARALLEL_PORT_INFORMATION);
  113. PortInfo = Irp->AssociatedIrp.SystemBuffer;
  114. *PortInfo = Extension->PortInfo;
  115. Status = STATUS_SUCCESS;
  116. }
  117. break;
  118. case IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO:
  119. Status = STATUS_SUCCESS;
  120. break;
  121. case IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO:
  122. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  123. sizeof(PARALLEL_PNP_INFORMATION)) {
  124. Status = STATUS_BUFFER_TOO_SMALL;
  125. } else {
  126. Irp->IoStatus.Information = sizeof(PARALLEL_PNP_INFORMATION);
  127. PnpInfo = Irp->AssociatedIrp.SystemBuffer;
  128. *PnpInfo = Extension->PnpInfo;
  129. Status = STATUS_SUCCESS;
  130. }
  131. break;
  132. case IOCTL_INTERNAL_GET_MORE_PARALLEL_PORT_INFO:
  133. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  134. sizeof(MORE_PARALLEL_PORT_INFORMATION)) {
  135. Status = STATUS_BUFFER_TOO_SMALL;
  136. } else {
  137. Irp->IoStatus.Information = sizeof(MORE_PARALLEL_PORT_INFORMATION);
  138. MorePortInfo = Irp->AssociatedIrp.SystemBuffer;
  139. MorePortInfo->InterfaceType = Extension->InterfaceType;
  140. MorePortInfo->BusNumber = Extension->BusNumber;
  141. MorePortInfo->InterruptLevel = Extension->InterruptLevel;
  142. MorePortInfo->InterruptVector = Extension->InterruptVector;
  143. MorePortInfo->InterruptAffinity = Extension->InterruptAffinity;
  144. MorePortInfo->InterruptMode = Extension->InterruptMode;
  145. Status = STATUS_SUCCESS;
  146. }
  147. break;
  148. case IOCTL_INTERNAL_PARALLEL_SET_CHIP_MODE:
  149. //
  150. // Port already acquired?
  151. //
  152. // Make sure right parameters are sent in
  153. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  154. sizeof(PARALLEL_CHIP_MODE) ) {
  155. Status = STATUS_BUFFER_TOO_SMALL;
  156. } else {
  157. Status = PptSetChipMode (Extension,
  158. ((PPARALLEL_CHIP_MODE)Irp->AssociatedIrp.SystemBuffer)->ModeFlags );
  159. } // end check input buffer
  160. break;
  161. case IOCTL_INTERNAL_PARALLEL_CLEAR_CHIP_MODE:
  162. //
  163. // Port already acquired?
  164. //
  165. // Make sure right parameters are sent in
  166. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  167. sizeof(PARALLEL_CHIP_MODE) ){
  168. Status = STATUS_BUFFER_TOO_SMALL;
  169. } else {
  170. Status = PptClearChipMode (Extension, ((PPARALLEL_CHIP_MODE)Irp->AssociatedIrp.SystemBuffer)->ModeFlags);
  171. } // end check input buffer
  172. break;
  173. case IOCTL_INTERNAL_INIT_1284_3_BUS:
  174. // Initialize the 1284.3 bus
  175. // RMT - Port is locked out already?
  176. Extension->PnpInfo.Ieee1284_3DeviceCount = PptInitiate1284_3( Extension );
  177. Status = STATUS_SUCCESS;
  178. break;
  179. case IOCTL_INTERNAL_SELECT_DEVICE:
  180. // Takes a flat namespace Id for the device, also acquires the
  181. // port unless HAVE_PORT_KEEP_PORT Flag is set
  182. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARALLEL_1284_COMMAND) ) {
  183. Status = STATUS_BUFFER_TOO_SMALL;
  184. } else {
  185. if ( Irp->Cancel ) {
  186. Status = STATUS_CANCELLED;
  187. } else {
  188. // Call Function to try to select device
  189. Status = PptTrySelectDevice( Extension, Irp->AssociatedIrp.SystemBuffer );
  190. IoAcquireCancelSpinLock(&CancelIrql);
  191. if ( Status == STATUS_PENDING ) {
  192. PptSetCancelRoutine(Irp, PptCancelRoutine);
  193. IoMarkIrpPending(Irp);
  194. InsertTailList(&Extension->WorkQueue, &Irp->Tail.Overlay.ListEntry);
  195. }
  196. IoReleaseCancelSpinLock(CancelIrql);
  197. }
  198. }
  199. break;
  200. case IOCTL_INTERNAL_DESELECT_DEVICE:
  201. // Deselects the current device, also releases the port unless HAVE_PORT_KEEP_PORT Flag set
  202. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARALLEL_1284_COMMAND) ) {
  203. Status = STATUS_BUFFER_TOO_SMALL;
  204. } else {
  205. Status = PptDeselectDevice( Extension, Irp->AssociatedIrp.SystemBuffer );
  206. }
  207. break;
  208. case IOCTL_INTERNAL_PARALLEL_CONNECT_INTERRUPT:
  209. {
  210. //
  211. // Verify that this interface has been explicitly enabled via the registry flag, otherwise
  212. // FAIL the request with STATUS_UNSUCCESSFUL
  213. //
  214. ULONG EnableConnectInterruptIoctl = 0;
  215. PptRegGetDeviceParameterDword( Extension->PhysicalDeviceObject,
  216. (PWSTR)L"EnableConnectInterruptIoctl",
  217. &EnableConnectInterruptIoctl );
  218. if( 0 == EnableConnectInterruptIoctl ) {
  219. Status = STATUS_UNSUCCESSFUL;
  220. goto targetExit;
  221. }
  222. }
  223. //
  224. // This interface has been explicitly enabled via the registry flag, process request.
  225. //
  226. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARALLEL_INTERRUPT_SERVICE_ROUTINE) ||
  227. IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARALLEL_INTERRUPT_INFORMATION)) {
  228. Status = STATUS_BUFFER_TOO_SMALL;
  229. } else {
  230. IsrInfo = Irp->AssociatedIrp.SystemBuffer;
  231. InterruptInfo = Irp->AssociatedIrp.SystemBuffer;
  232. IoAcquireCancelSpinLock(&CancelIrql);
  233. if (Extension->InterruptRefCount) {
  234. ++Extension->InterruptRefCount;
  235. IoReleaseCancelSpinLock(CancelIrql);
  236. Status = STATUS_SUCCESS;
  237. } else {
  238. IoReleaseCancelSpinLock(CancelIrql);
  239. Status = PptConnectInterrupt(Extension);
  240. if (NT_SUCCESS(Status)) {
  241. IoAcquireCancelSpinLock(&CancelIrql);
  242. ++Extension->InterruptRefCount;
  243. IoReleaseCancelSpinLock(CancelIrql);
  244. }
  245. }
  246. if (NT_SUCCESS(Status)) {
  247. IsrListEntry = ExAllocatePool(NonPagedPool, sizeof(ISR_LIST_ENTRY));
  248. if (IsrListEntry) {
  249. IsrListEntry->ServiceRoutine = IsrInfo->InterruptServiceRoutine;
  250. IsrListEntry->ServiceContext = IsrInfo->InterruptServiceContext;
  251. IsrListEntry->DeferredPortCheckRoutine = IsrInfo->DeferredPortCheckRoutine;
  252. IsrListEntry->CheckContext = IsrInfo->DeferredPortCheckContext;
  253. // Put the ISR_LIST_ENTRY onto the ISR list.
  254. ListContext.List = &Extension->IsrList;
  255. ListContext.NewEntry = &IsrListEntry->ListEntry;
  256. KeSynchronizeExecution(Extension->InterruptObject, PptSynchronizedQueue, &ListContext);
  257. InterruptInfo->InterruptObject = Extension->InterruptObject;
  258. InterruptInfo->TryAllocatePortAtInterruptLevel = PptTryAllocatePortAtInterruptLevel;
  259. InterruptInfo->FreePortFromInterruptLevel = PptFreePortFromInterruptLevel;
  260. InterruptInfo->Context = Extension;
  261. Irp->IoStatus.Information = sizeof(PARALLEL_INTERRUPT_INFORMATION);
  262. Status = STATUS_SUCCESS;
  263. } else {
  264. Status = STATUS_INSUFFICIENT_RESOURCES;
  265. }
  266. }
  267. }
  268. break;
  269. case IOCTL_INTERNAL_PARALLEL_DISCONNECT_INTERRUPT:
  270. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  271. sizeof(PARALLEL_INTERRUPT_SERVICE_ROUTINE)) {
  272. Status = STATUS_BUFFER_TOO_SMALL;
  273. } else {
  274. IsrInfo = Irp->AssociatedIrp.SystemBuffer;
  275. // Take the ISR out of the ISR list.
  276. IoAcquireCancelSpinLock(&CancelIrql);
  277. if (Extension->InterruptRefCount) {
  278. IoReleaseCancelSpinLock(CancelIrql);
  279. DisconnectContext.Extension = Extension;
  280. DisconnectContext.IsrInfo = IsrInfo;
  281. if (KeSynchronizeExecution(Extension->InterruptObject, PptSynchronizedDisconnect, &DisconnectContext)) {
  282. Status = STATUS_SUCCESS;
  283. IoAcquireCancelSpinLock(&CancelIrql);
  284. if (--Extension->InterruptRefCount == 0) {
  285. DisconnectInterrupt = TRUE;
  286. } else {
  287. DisconnectInterrupt = FALSE;
  288. }
  289. IoReleaseCancelSpinLock(CancelIrql);
  290. } else {
  291. Status = STATUS_INVALID_PARAMETER;
  292. DisconnectInterrupt = FALSE;
  293. }
  294. } else {
  295. IoReleaseCancelSpinLock(CancelIrql);
  296. DisconnectInterrupt = FALSE;
  297. Status = STATUS_INVALID_PARAMETER;
  298. }
  299. //
  300. // Disconnect the interrupt if appropriate.
  301. //
  302. if (DisconnectInterrupt) {
  303. PptDisconnectInterrupt(Extension);
  304. }
  305. }
  306. break;
  307. default:
  308. DD((PCE)Extension,DDE,"PptDispatchDeviceControl - default case - invalid/unsupported request\n");
  309. Status = STATUS_INVALID_PARAMETER;
  310. break;
  311. }
  312. targetExit:
  313. if( Status != STATUS_PENDING ) {
  314. PptReleaseRemoveLock(&Extension->RemoveLock, Irp);
  315. P4CompleteRequest( Irp, Status, Irp->IoStatus.Information );
  316. }
  317. return Status;
  318. }