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.

1069 lines
35 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. File Name:
  4. ioctl.c
  5. Contained in Module:
  6. parallel.sys
  7. Abstract:
  8. This file contains functions associated with ParClass IOCTL processing.
  9. - The three main entry points in this file are:
  10. - ParDeviceControl() - Dispatch function for non-internal IOCTLs
  11. - ParInternalDeviceControl() - Dispatch function for internal IOCTLs
  12. - ParDeviceIo() - Worker thread entry point for handling all
  13. IOCTLs not completed in a dispatch function
  14. - Helper/Utility function naming conventions:
  15. - ParpIoctlDispatch...() - private helper function called by dispatch function
  16. - ParpIoctlThread...() - private helper function called by worker thread
  17. Authors:
  18. Anthony V. Ercolano 1-Aug-1992
  19. Norbert P. Kusters 22-Oct-1993
  20. Douglas G. Fritz 24-Jul-1998
  21. Revision History :
  22. --*/
  23. #include "pch.h"
  24. VOID
  25. ParpIoctlThreadLockPort(
  26. IN PPDO_EXTENSION Pdx
  27. )
  28. {
  29. NTSTATUS status;
  30. PIRP irp = Pdx->CurrentOpIrp;
  31. DD((PCE)Pdx,DDT,"ParpIoctlThreadLockPort - enter\n");
  32. if( ParSelectDevice(Pdx,TRUE) ) {
  33. DD((PCE)Pdx,DDT,"ParpIoctlThreadLockPort - SUCCESS\n");
  34. Pdx->AllocatedByLockPort = TRUE;
  35. status = STATUS_SUCCESS;
  36. } else {
  37. DD((PCE)Pdx,DDW,"ParpIoctlThreadLockPort - FAIL\n");
  38. Pdx->AllocatedByLockPort = FALSE;
  39. status = STATUS_UNSUCCESSFUL;
  40. }
  41. irp->IoStatus.Status = status;
  42. }
  43. VOID
  44. ParpIoctlThreadUnlockPort(
  45. IN PPDO_EXTENSION Pdx
  46. )
  47. {
  48. PIRP irp = Pdx->CurrentOpIrp;
  49. Pdx->AllocatedByLockPort = FALSE;
  50. DD((PCE)Pdx,DDT,"ParpIoctlThreadUnlockPort - enter\n");
  51. if( ParDeselectDevice(Pdx, FALSE) ) {
  52. DD((PCE)Pdx,DDT,"ParpIoctlThreadUnlockPort - SUCCESS\n");
  53. } else {
  54. DD((PCE)Pdx,DDW,"ParpIoctlThreadUnlockPort - FAIL - nothing we can do\n");
  55. }
  56. irp->IoStatus.Status = STATUS_SUCCESS;
  57. }
  58. NTSTATUS
  59. ParDeviceControl(
  60. IN PDEVICE_OBJECT DeviceObject,
  61. IN PIRP Irp
  62. )
  63. /*++
  64. Routine Description:
  65. This routine is the dispatch for device control requests.
  66. Arguments:
  67. DeviceObject - Supplies the device object.
  68. Irp - Supplies the I/O request packet.
  69. Return Value:
  70. STATUS_SUCCESS - Success.
  71. STATUS_PENDING - Request pending.
  72. STATUS_BUFFER_TOO_SMALL - Buffer too small.
  73. STATUS_INVALID_PARAMETER - Invalid io control request.
  74. STATUS_DELETE_PENDING - This device object is being deleted
  75. --*/
  76. {
  77. PPDO_EXTENSION Pdx = DeviceObject->DeviceExtension;
  78. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  79. PPAR_SET_INFORMATION SetInfo;
  80. NTSTATUS Status;
  81. PSERIAL_TIMEOUTS SerialTimeouts;
  82. KIRQL OldIrql;
  83. Irp->IoStatus.Information = 0;
  84. //
  85. // bail out if a delete is pending for this device object
  86. //
  87. if(Pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING) {
  88. return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, 0 );
  89. }
  90. //
  91. // bail out if a remove is pending for our ParPort device object
  92. //
  93. if(Pdx->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) {
  94. return P4CompleteRequest( Irp, STATUS_DELETE_PENDING, 0 );
  95. }
  96. //
  97. // bail out if device has been removed
  98. //
  99. if(Pdx->DeviceStateFlags & (PPT_DEVICE_REMOVED|PPT_DEVICE_SURPRISE_REMOVED) ) {
  100. return P4CompleteRequest( Irp, STATUS_DEVICE_REMOVED, 0 );
  101. }
  102. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  103. case IOCTL_PAR_QUERY_LOCATION:
  104. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_LOCATION\n");
  105. {
  106. ULONG outBufLen = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  107. ULONG locationLen = strlen(Pdx->Location);
  108. if( outBufLen < locationLen+1 ) {
  109. Status = STATUS_BUFFER_TOO_SMALL;
  110. } else {
  111. PCHAR buffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer;
  112. RtlCopyMemory( buffer, Pdx->Location, locationLen + 1 );
  113. Irp->IoStatus.Information = locationLen + 1;
  114. Status = STATUS_SUCCESS;
  115. }
  116. }
  117. break;
  118. case IOCTL_PAR_SET_INFORMATION:
  119. DD((PCE)Pdx,DDT,"IOCTL_PAR_SET_INFORMATION\n");
  120. SetInfo = Irp->AssociatedIrp.SystemBuffer;
  121. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  122. sizeof(PAR_SET_INFORMATION)) {
  123. Status = STATUS_BUFFER_TOO_SMALL;
  124. } else if (SetInfo->Init != PARALLEL_INIT) {
  125. Status = STATUS_INVALID_PARAMETER;
  126. } else {
  127. //
  128. // This is a parallel reset
  129. //
  130. Status = STATUS_PENDING;
  131. }
  132. break;
  133. case IOCTL_PAR_QUERY_INFORMATION :
  134. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_INFORMATION\n");
  135. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  136. sizeof(PAR_QUERY_INFORMATION)) {
  137. Status = STATUS_BUFFER_TOO_SMALL;
  138. } else {
  139. Status = STATUS_PENDING;
  140. }
  141. break;
  142. case IOCTL_SERIAL_SET_TIMEOUTS:
  143. DD((PCE)Pdx,DDT,"IOCTL_SERIAL_SET_TIMEOUTS\n");
  144. SerialTimeouts = Irp->AssociatedIrp.SystemBuffer;
  145. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength <
  146. sizeof(SERIAL_TIMEOUTS)) {
  147. Status = STATUS_BUFFER_TOO_SMALL;
  148. } else if (SerialTimeouts->WriteTotalTimeoutConstant < 2000) {
  149. Status = STATUS_INVALID_PARAMETER;
  150. } else {
  151. Status = STATUS_PENDING;
  152. }
  153. break;
  154. case IOCTL_SERIAL_GET_TIMEOUTS:
  155. DD((PCE)Pdx,DDT,"IOCTL_SERIAL_GET_TIMEOUTS\n");
  156. SerialTimeouts = Irp->AssociatedIrp.SystemBuffer;
  157. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  158. sizeof(SERIAL_TIMEOUTS)) {
  159. Status = STATUS_BUFFER_TOO_SMALL;
  160. } else {
  161. //
  162. // We don't need to synchronize the read.
  163. //
  164. RtlZeroMemory(SerialTimeouts, sizeof(SERIAL_TIMEOUTS));
  165. SerialTimeouts->WriteTotalTimeoutConstant =
  166. 1000 * Pdx->TimerStart;
  167. Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
  168. Status = STATUS_SUCCESS;
  169. }
  170. break;
  171. case IOCTL_PAR_QUERY_DEVICE_ID:
  172. case IOCTL_PAR_QUERY_RAW_DEVICE_ID:
  173. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_[RAW_]DEVICE_ID\n");
  174. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) {
  175. Status = STATUS_BUFFER_TOO_SMALL;
  176. } else {
  177. Status = STATUS_PENDING;
  178. }
  179. break;
  180. case IOCTL_PAR_QUERY_DEVICE_ID_SIZE:
  181. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE\n");
  182. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  183. sizeof(PAR_DEVICE_ID_SIZE_INFORMATION)) {
  184. Status = STATUS_BUFFER_TOO_SMALL;
  185. } else {
  186. Status = STATUS_PENDING;
  187. }
  188. break;
  189. case IOCTL_PAR_IS_PORT_FREE:
  190. DD((PCE)Pdx,DDT,"IOCTL_PAR_IS_PORT_FREE\n");
  191. if( IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(BOOLEAN) ) {
  192. Status = STATUS_BUFFER_TOO_SMALL;
  193. } else {
  194. if( Pdx->bAllocated ) {
  195. // if we have the port then it is not free
  196. *((PBOOLEAN)Irp->AssociatedIrp.SystemBuffer) = FALSE;
  197. } else {
  198. // determine if the port is free by trying to allocate and free it
  199. // - our alloc/free will only succeed if no one else has the port
  200. BOOLEAN tryAllocSuccess = Pdx->TryAllocatePort( Pdx->PortContext );
  201. if( tryAllocSuccess ) {
  202. // we were able to allocate the port, free it and report that the port is free
  203. Pdx->FreePort( Pdx->PortContext );
  204. *((PBOOLEAN)Irp->AssociatedIrp.SystemBuffer) = TRUE;
  205. } else {
  206. // we were unable to allocate the port, someone else must be using the port
  207. *((PBOOLEAN)Irp->AssociatedIrp.SystemBuffer) = FALSE;
  208. }
  209. }
  210. Irp->IoStatus.Information = sizeof(BOOLEAN);
  211. Status = STATUS_SUCCESS;
  212. }
  213. break;
  214. case IOCTL_PAR_GET_READ_ADDRESS:
  215. DD((PCE)Pdx,DDT,"IOCTL_PAR_GET_READ_ADDRESS\n");
  216. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Pdx->ReverseInterfaceAddress)) {
  217. Status = STATUS_BUFFER_TOO_SMALL;
  218. } else {
  219. *((PUCHAR) Irp->AssociatedIrp.SystemBuffer) = Pdx->ReverseInterfaceAddress;
  220. Irp->IoStatus.Information = sizeof(Pdx->ReverseInterfaceAddress);
  221. Status = STATUS_SUCCESS;
  222. }
  223. break;
  224. case IOCTL_PAR_GET_WRITE_ADDRESS:
  225. DD((PCE)Pdx,DDT,"IOCTL_PAR_GET_WRITE_ADDRESS\n");
  226. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Pdx->ForwardInterfaceAddress)) {
  227. Status = STATUS_BUFFER_TOO_SMALL;
  228. } else {
  229. *((PUCHAR) Irp->AssociatedIrp.SystemBuffer) = Pdx->ForwardInterfaceAddress;
  230. Irp->IoStatus.Information = sizeof(Pdx->ForwardInterfaceAddress);
  231. Status = STATUS_SUCCESS;
  232. }
  233. break;
  234. case IOCTL_PAR_SET_READ_ADDRESS:
  235. DD((PCE)Pdx,DDT," IOCTL_PAR_SET_READ_ADDRESS\n");
  236. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Pdx->ReverseInterfaceAddress)) {
  237. Status = STATUS_INVALID_PARAMETER;
  238. } else {
  239. Status = STATUS_PENDING;
  240. }
  241. break;
  242. case IOCTL_PAR_SET_WRITE_ADDRESS:
  243. DD((PCE)Pdx,DDT," IOCTL_PAR_SET_WRITE_ADDRESS\n");
  244. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Pdx->ForwardInterfaceAddress)) {
  245. Status = STATUS_INVALID_PARAMETER;
  246. } else {
  247. Status = STATUS_PENDING;
  248. }
  249. break;
  250. case IOCTL_IEEE1284_GET_MODE:
  251. DD((PCE)Pdx,DDT,"IOCTL_IEEE1284_GET_MODE\n");
  252. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK)) {
  253. Status = STATUS_BUFFER_TOO_SMALL;
  254. } else {
  255. PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
  256. ppnmMask->usReadMask = arpReverse[Pdx->IdxReverseProtocol].Protocol;
  257. ppnmMask->usWriteMask = afpForward[Pdx->IdxForwardProtocol].Protocol;
  258. Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK);
  259. Status = STATUS_SUCCESS;
  260. }
  261. break;
  262. case IOCTL_PAR_GET_DEFAULT_MODES:
  263. DD((PCE)Pdx,DDT,"IOCTL_IEEE1284_GET_MODE\n");
  264. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK)) {
  265. Status = STATUS_BUFFER_TOO_SMALL;
  266. } else {
  267. PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
  268. ppnmMask->usReadMask = NONE;
  269. ppnmMask->usWriteMask = CENTRONICS;
  270. Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK);
  271. Status = STATUS_SUCCESS;
  272. }
  273. break;
  274. case IOCTL_PAR_ECP_HOST_RECOVERY:
  275. DD((PCE)Pdx,DDT,"IOCTL_PAR_ECP_HOST_RECOVERY\n");
  276. {
  277. BOOLEAN *isSupported;
  278. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(BOOLEAN) ) {
  279. Status = STATUS_INVALID_PARAMETER;
  280. } else {
  281. isSupported = (BOOLEAN *)Irp->AssociatedIrp.SystemBuffer;
  282. Pdx->bIsHostRecoverSupported = *isSupported;
  283. Status = STATUS_SUCCESS;
  284. }
  285. }
  286. break;
  287. case IOCTL_PAR_PING:
  288. DD((PCE)Pdx,DDT,"IOCTL_PAR_PING\n");
  289. // No Parms to check!
  290. Status = STATUS_PENDING;
  291. break;
  292. case IOCTL_PAR_GET_DEVICE_CAPS:
  293. DD((PCE)Pdx,DDT,"IOCTL_PAR_GET_DEVICE_CAPS\n");
  294. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(Pdx->ProtocolModesSupported)) {
  295. Status = STATUS_BUFFER_TOO_SMALL;
  296. } else if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(Pdx->BadProtocolModes)) {
  297. Status = STATUS_BUFFER_TOO_SMALL;
  298. } else {
  299. Status = STATUS_PENDING;
  300. }
  301. break;
  302. case IOCTL_IEEE1284_NEGOTIATE:
  303. DD((PCE)Pdx,DDT,"IOCTL_IEEE1284_NEGOTIATE\n");
  304. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) ||
  305. IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) ) {
  306. DD((PCE)Pdx,DDW,"ParDeviceControl: IOCTL_IEEE1284_NEGOTIATE STATUS_INVALID_PARAMETER\n");
  307. Status = STATUS_INVALID_PARAMETER;
  308. } else {
  309. PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
  310. if ((ppnmMask->usReadMask == arpReverse[Pdx->IdxReverseProtocol].Protocol) &&
  311. (ppnmMask->usWriteMask == afpForward[Pdx->IdxForwardProtocol].Protocol)) {
  312. Irp->IoStatus.Information = sizeof(PARCLASS_NEGOTIATION_MASK);
  313. Status = STATUS_SUCCESS;
  314. } else {
  315. Status = STATUS_PENDING;
  316. }
  317. }
  318. break;
  319. default :
  320. DD((PCE)Pdx,DDT,"IOCTL default case\n");
  321. Status = STATUS_INVALID_PARAMETER;
  322. break;
  323. }
  324. if (Status == STATUS_PENDING) {
  325. IoAcquireCancelSpinLock(&OldIrql);
  326. if (Irp->Cancel) {
  327. IoReleaseCancelSpinLock(OldIrql);
  328. Status = STATUS_CANCELLED;
  329. } else {
  330. //
  331. // This IRP takes more time, so it should be queued.
  332. //
  333. BOOLEAN needToSignalSemaphore = (IsListEmpty( &Pdx->WorkQueue ) &&
  334. !KeReadStateSemaphore( &Pdx->RequestSemaphore )) ? TRUE : FALSE;
  335. IoMarkIrpPending(Irp);
  336. #pragma warning( push )
  337. #pragma warning( disable : 4054 4055 )
  338. IoSetCancelRoutine(Irp, ParCancelRequest);
  339. #pragma warning( pop )
  340. InsertTailList(&Pdx->WorkQueue, &Irp->Tail.Overlay.ListEntry);
  341. IoReleaseCancelSpinLock(OldIrql);
  342. if( needToSignalSemaphore ) {
  343. KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE);
  344. }
  345. }
  346. }
  347. if (Status != STATUS_PENDING) {
  348. P4CompleteRequest( Irp, Status, Irp->IoStatus.Information );
  349. }
  350. return Status;
  351. }
  352. NTSTATUS
  353. ParInternalDeviceControl(
  354. IN PDEVICE_OBJECT DeviceObject,
  355. IN PIRP Irp
  356. )
  357. /*++
  358. Routine Description:
  359. This routine is the dispatch for internal device control requests.
  360. Arguments:
  361. DeviceObject - Supplies the device object.
  362. Irp - Supplies the I/O request packet.
  363. Return Value:
  364. STATUS_SUCCESS - Success.
  365. STATUS_PENDING - Request pending.
  366. STATUS_BUFFER_TOO_SMALL - Buffer too small.
  367. STATUS_INVALID_PARAMETER - Invalid io control request.
  368. STATUS_DELETE_PENDING - This device object is being deleted
  369. --*/
  370. {
  371. PIO_STACK_LOCATION IrpSp;
  372. // PPAR_SET_INFORMATION SetInfo;
  373. NTSTATUS Status;
  374. // PSERIAL_TIMEOUTS SerialTimeouts;
  375. PPDO_EXTENSION Pdx;
  376. KIRQL OldIrql;
  377. PPARCLASS_INFORMATION pParclassInfo;
  378. Irp->IoStatus.Information = 0;
  379. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  380. Pdx = DeviceObject->DeviceExtension;
  381. //
  382. // bail out if a delete is pending for this device object
  383. //
  384. if(Pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING) {
  385. P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
  386. return STATUS_DELETE_PENDING;
  387. }
  388. //
  389. // bail out if a remove is pending for our ParPort device object
  390. //
  391. if(Pdx->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) {
  392. P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
  393. return STATUS_DELETE_PENDING;
  394. }
  395. //
  396. // bail out if device has been removed
  397. //
  398. if(Pdx->DeviceStateFlags & (PPT_DEVICE_REMOVED|PPT_DEVICE_SURPRISE_REMOVED) ) {
  399. P4CompleteRequest( Irp, STATUS_DEVICE_REMOVED, Irp->IoStatus.Information );
  400. return STATUS_DEVICE_REMOVED;
  401. }
  402. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  403. case IOCTL_INTERNAL_PARCLASS_CONNECT:
  404. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARCLASS_CONNECT\n");
  405. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_INFORMATION)) {
  406. Status = STATUS_BUFFER_TOO_SMALL;
  407. } else {
  408. PFDO_EXTENSION fdx = Pdx->Fdo->DeviceExtension;
  409. PPARALLEL_PORT_INFORMATION portInfo = &fdx->PortInfo;
  410. PPARALLEL_PNP_INFORMATION pnpInfo = &fdx->PnpInfo;
  411. pParclassInfo = Irp->AssociatedIrp.SystemBuffer;
  412. pParclassInfo->ParclassContext = Pdx;
  413. pParclassInfo->Controller = portInfo->Controller;
  414. pParclassInfo->SpanOfController = portInfo->SpanOfController;
  415. pParclassInfo->EcrController = pnpInfo->EcpController;
  416. pParclassInfo->HardwareCapabilities = pnpInfo->HardwareCapabilities;
  417. pParclassInfo->FifoDepth = pnpInfo->FifoDepth;
  418. pParclassInfo->FifoWidth = pnpInfo->FifoWidth;
  419. pParclassInfo->DetermineIeeeModes = ParExportedDetermineIeeeModes;
  420. pParclassInfo->TerminateIeeeMode = ParExportedTerminateIeeeMode;
  421. pParclassInfo->NegotiateIeeeMode = ParExportedNegotiateIeeeMode;
  422. pParclassInfo->IeeeFwdToRevMode = ParExportedIeeeFwdToRevMode;
  423. pParclassInfo->IeeeRevToFwdMode = ParExportedIeeeRevToFwdMode;
  424. pParclassInfo->ParallelRead = ParExportedParallelRead;
  425. pParclassInfo->ParallelWrite = ParExportedParallelWrite;
  426. Irp->IoStatus.Information = sizeof(PARCLASS_INFORMATION);
  427. Status = STATUS_SUCCESS;
  428. }
  429. break;
  430. case IOCTL_INTERNAL_GET_PARPORT_FDO:
  431. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_GET_PARPORT_FDO\n");
  432. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PDEVICE_OBJECT)) {
  433. Status = STATUS_BUFFER_TOO_SMALL;
  434. } else {
  435. PDEVICE_OBJECT *pFdo = Irp->AssociatedIrp.SystemBuffer;
  436. *pFdo = Pdx->Fdo;
  437. Irp->IoStatus.Information = sizeof(PDEVICE_OBJECT);
  438. Status = STATUS_SUCCESS;
  439. }
  440. break;
  441. case IOCTL_INTERNAL_PARCLASS_DISCONNECT:
  442. Status = STATUS_SUCCESS;
  443. break;
  444. case IOCTL_INTERNAL_DISCONNECT_IDLE:
  445. case IOCTL_INTERNAL_LOCK_PORT:
  446. case IOCTL_INTERNAL_UNLOCK_PORT:
  447. case IOCTL_INTERNAL_LOCK_PORT_NO_SELECT:
  448. case IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT:
  449. case IOCTL_INTERNAL_PARDOT3_CONNECT:
  450. case IOCTL_INTERNAL_PARDOT3_RESET:
  451. Status = STATUS_PENDING;
  452. break;
  453. case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
  454. // immediately tell worker thread to stop signalling
  455. Pdx->P12843DL.bEventActive = FALSE;
  456. Status = STATUS_PENDING;
  457. break;
  458. case IOCTL_INTERNAL_PARDOT3_SIGNAL:
  459. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PKEVENT) ) {
  460. Status = STATUS_INVALID_PARAMETER;
  461. } else {
  462. Status = STATUS_PENDING;
  463. }
  464. break;
  465. default :
  466. DD((PCE)Pdx,DDW,"IOCTL_INTERNAL... default case - invalid parameter\n");
  467. Status = STATUS_INVALID_PARAMETER;
  468. break;
  469. }
  470. if (Status == STATUS_PENDING) {
  471. //
  472. // This IRP takes more time, queue it for the worker thread
  473. //
  474. IoAcquireCancelSpinLock(&OldIrql);
  475. if (Irp->Cancel) {
  476. IoReleaseCancelSpinLock(OldIrql);
  477. Status = STATUS_CANCELLED;
  478. } else {
  479. BOOLEAN needToSignalSemaphore = (IsListEmpty( &Pdx->WorkQueue ) &&
  480. !KeReadStateSemaphore( &Pdx->RequestSemaphore )) ? TRUE : FALSE;
  481. IoMarkIrpPending(Irp);
  482. #pragma warning( push )
  483. #pragma warning( disable : 4054 4055 )
  484. IoSetCancelRoutine(Irp, ParCancelRequest);
  485. #pragma warning( pop )
  486. InsertTailList(&Pdx->WorkQueue, &Irp->Tail.Overlay.ListEntry);
  487. IoReleaseCancelSpinLock(OldIrql);
  488. if( needToSignalSemaphore ) {
  489. KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE);
  490. }
  491. }
  492. }
  493. if (Status != STATUS_PENDING) {
  494. P4CompleteRequest( Irp, Status, Irp->IoStatus.Information );
  495. }
  496. return Status;
  497. }
  498. VOID
  499. ParDeviceIo(
  500. IN PPDO_EXTENSION Pdx
  501. )
  502. /*++
  503. Routine Description:
  504. This routine implements a DEVICE_IOCTL request with the extension's current irp.
  505. Arguments:
  506. Pdx - Supplies the device extension.
  507. Return Value:
  508. None.
  509. --*/
  510. {
  511. PIRP Irp;
  512. PIO_STACK_LOCATION IrpSp;
  513. ULONG IdLength;
  514. NTSTATUS NtStatus;
  515. UCHAR Status;
  516. UCHAR Control;
  517. ULONG ioControlCode;
  518. Irp = Pdx->CurrentOpIrp;
  519. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  520. ioControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  521. switch( ioControlCode ) {
  522. case IOCTL_PAR_SET_INFORMATION :
  523. {
  524. Status = ParInitializeDevice(Pdx);
  525. if (!PAR_OK(Status)) {
  526. ParNotInitError(Pdx, Status); // Set the IoStatus.Status of the CurrentOpIrp appropriately
  527. } else {
  528. Irp->IoStatus.Status = STATUS_SUCCESS;
  529. }
  530. }
  531. break;
  532. case IOCTL_PAR_QUERY_INFORMATION :
  533. {
  534. PPAR_QUERY_INFORMATION IrpBuffer = Irp->AssociatedIrp.SystemBuffer;
  535. Irp->IoStatus.Status = STATUS_SUCCESS;
  536. Status = GetStatus(Pdx->Controller);
  537. Control = GetControl(Pdx->Controller);
  538. // Interpretating Status & Control
  539. IrpBuffer->Status = 0x0;
  540. if (PAR_POWERED_OFF(Status) || PAR_NO_CABLE(Status)) {
  541. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_POWER_OFF);
  542. } else if (PAR_PAPER_EMPTY(Status)) {
  543. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_PAPER_EMPTY);
  544. } else if (PAR_OFF_LINE(Status)) {
  545. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_OFF_LINE);
  546. } else if (PAR_NOT_CONNECTED(Status)) {
  547. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_NOT_CONNECTED);
  548. }
  549. if (PAR_BUSY(Status)) {
  550. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_BUSY);
  551. }
  552. if (PAR_SELECTED(Status)) {
  553. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_SELECTED);
  554. }
  555. Irp->IoStatus.Information = sizeof( PAR_QUERY_INFORMATION );
  556. }
  557. break;
  558. case IOCTL_PAR_QUERY_RAW_DEVICE_ID :
  559. // We always read the Device Id in Nibble Mode.
  560. NtStatus = SppQueryDeviceId(Pdx,
  561. Irp->AssociatedIrp.SystemBuffer,
  562. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  563. &IdLength, TRUE);
  564. Irp->IoStatus.Status = NtStatus;
  565. if (NT_SUCCESS(NtStatus)) {
  566. Irp->IoStatus.Information = IdLength + sizeof(CHAR);
  567. } else {
  568. Irp->IoStatus.Information = 0;
  569. }
  570. break;
  571. case IOCTL_PAR_QUERY_DEVICE_ID :
  572. // We always read the Device Id in Nibble Mode.
  573. NtStatus = SppQueryDeviceId(Pdx,
  574. Irp->AssociatedIrp.SystemBuffer,
  575. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  576. &IdLength, FALSE);
  577. Irp->IoStatus.Status = NtStatus;
  578. if( NT_SUCCESS( NtStatus ) ) {
  579. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - SUCCESS - size = %d\n", IdLength);
  580. // Include terminating NULL in the string to copy back to user buffer
  581. Irp->IoStatus.Information = IdLength + sizeof(CHAR);
  582. } else if( NtStatus == STATUS_BUFFER_TOO_SMALL) {
  583. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - FAIL - BUFFER_TOO_SMALL - supplied= %d, required=%d\n",
  584. IrpSp->Parameters.DeviceIoControl.OutputBufferLength, IdLength);
  585. Irp->IoStatus.Information = 0;
  586. } else {
  587. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - FAIL - QUERY ID FAILED\n");
  588. Irp->IoStatus.Information = 0;
  589. }
  590. break;
  591. case IOCTL_PAR_QUERY_DEVICE_ID_SIZE :
  592. //
  593. // Read the first two bytes of the Nibble Id, add room for the terminating NULL and
  594. // return this to the caller.
  595. //
  596. NtStatus = SppQueryDeviceId(Pdx, NULL, 0, &IdLength, FALSE);
  597. if (NtStatus == STATUS_BUFFER_TOO_SMALL) {
  598. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE - size required = %d\n", IdLength);
  599. Irp->IoStatus.Status = STATUS_SUCCESS;
  600. Irp->IoStatus.Information =
  601. sizeof(PAR_DEVICE_ID_SIZE_INFORMATION);
  602. // include space for terminating NULL
  603. ((PPAR_DEVICE_ID_SIZE_INFORMATION)
  604. Irp->AssociatedIrp.SystemBuffer)->DeviceIdSize = IdLength + sizeof(CHAR);
  605. } else {
  606. Irp->IoStatus.Status = NtStatus;
  607. Irp->IoStatus.Information = 0;
  608. }
  609. break;
  610. case IOCTL_PAR_PING :
  611. // We need to do a quick terminate and negotiate of the current modes
  612. NtStatus = ParPing(Pdx);
  613. DD((PCE)Pdx,DDT,"ParDeviceIo:IOCTL_PAR_PING\n");
  614. Irp->IoStatus.Status = NtStatus;
  615. Irp->IoStatus.Information = 0;
  616. break;
  617. case IOCTL_INTERNAL_DISCONNECT_IDLE :
  618. if ((Pdx->Connected) &&
  619. (afpForward[Pdx->IdxForwardProtocol].fnDisconnect)) {
  620. DD((PCE)Pdx,DDT,"ParDeviceIo:IOCTL_INTERNAL_DISCONNECT_IDLE: Calling afpForward.fnDisconnect\n");
  621. afpForward[Pdx->IdxForwardProtocol].fnDisconnect (Pdx);
  622. }
  623. Irp->IoStatus.Status = STATUS_SUCCESS;
  624. Irp->IoStatus.Information = 0;
  625. break;
  626. case IOCTL_IEEE1284_NEGOTIATE:
  627. {
  628. PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
  629. ParTerminate(Pdx);
  630. Irp->IoStatus.Status = IeeeNegotiateMode(Pdx, ppnmMask->usReadMask, ppnmMask->usWriteMask);
  631. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PARCLASS_NEGOTIATION_MASK)) {
  632. DD((PCE)Pdx,DDT, "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE Passed.\n");
  633. ppnmMask->usReadMask = arpReverse[Pdx->IdxReverseProtocol].Protocol;
  634. ppnmMask->usWriteMask = afpForward[Pdx->IdxForwardProtocol].Protocol;
  635. Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK);
  636. } else {
  637. DD((PCE)Pdx,DDT, "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE failed.\n");
  638. Irp->IoStatus.Information = 0;
  639. }
  640. }
  641. break;
  642. case IOCTL_PAR_GET_DEVICE_CAPS :
  643. Pdx->BadProtocolModes = *((USHORT *) Irp->AssociatedIrp.SystemBuffer);
  644. IeeeDetermineSupportedProtocols(Pdx);
  645. *((USHORT *) Irp->AssociatedIrp.SystemBuffer) = Pdx->ProtocolModesSupported;
  646. Irp->IoStatus.Information = sizeof(Pdx->ProtocolModesSupported);
  647. Irp->IoStatus.Status = STATUS_SUCCESS;
  648. break;
  649. case IOCTL_PAR_SET_READ_ADDRESS:
  650. {
  651. PUCHAR pAddress = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
  652. if (Pdx->ReverseInterfaceAddress != *pAddress) {
  653. Pdx->ReverseInterfaceAddress = *pAddress;
  654. Pdx->SetReverseAddress = TRUE;
  655. }
  656. Irp->IoStatus.Information = 0;
  657. Irp->IoStatus.Status = STATUS_SUCCESS;
  658. }
  659. break;
  660. case IOCTL_PAR_SET_WRITE_ADDRESS :
  661. {
  662. PUCHAR pAddress = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
  663. NtStatus = STATUS_SUCCESS;
  664. if (Pdx->ForwardInterfaceAddress != *pAddress) {
  665. Pdx->ForwardInterfaceAddress = *pAddress;
  666. if (Pdx->Connected) {
  667. if (afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress) {
  668. if (Pdx->CurrentPhase != PHASE_FORWARD_IDLE &&
  669. Pdx->CurrentPhase != PHASE_FORWARD_XFER) {
  670. NtStatus = ParReverseToForward(Pdx);
  671. }
  672. if (NT_SUCCESS(NtStatus)) {
  673. NtStatus = afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress(
  674. Pdx,
  675. Pdx->ForwardInterfaceAddress
  676. );
  677. }
  678. if (NT_SUCCESS(NtStatus)) {
  679. Pdx->SetForwardAddress = FALSE;
  680. Pdx->SetReverseAddress = FALSE;
  681. Pdx->ReverseInterfaceAddress = *pAddress;
  682. } else {
  683. Pdx->SetForwardAddress = TRUE;
  684. DD((PCE)Pdx,DDE,"ParDeviceIo: IOCTL_PAR_SET_WRITE_ADDRESS Failed\n");
  685. }
  686. } else {
  687. DD((PCE)Pdx,DDE, "ParDeviceIo: Someone called IOCTL_PAR_SET_WRITE_ADDRESS.\n");
  688. DD((PCE)Pdx,DDE, "ParDeviceIo: You don't have a fnSetInterfaceAddress.\n");
  689. DD((PCE)Pdx,DDE, "ParDeviceIo: Either IEEE1284.c has wrong info or your caller is in error!\n");
  690. NtStatus = STATUS_UNSUCCESSFUL;
  691. }
  692. } else {
  693. Pdx->SetForwardAddress = TRUE;
  694. }
  695. }
  696. Irp->IoStatus.Information = 0;
  697. Irp->IoStatus.Status = NtStatus;
  698. }
  699. break;
  700. case IOCTL_INTERNAL_LOCK_PORT :
  701. ParpIoctlThreadLockPort(Pdx);
  702. break;
  703. case IOCTL_INTERNAL_UNLOCK_PORT :
  704. ParpIoctlThreadUnlockPort(Pdx);
  705. break;
  706. case IOCTL_INTERNAL_LOCK_PORT_NO_SELECT:
  707. DD((PCE)Pdx,DDT, "ParDeviceIo - IOCTL_INTERNAL_LOCK_PORT_NO_SELECT\n");
  708. Pdx->AllocatedByLockPort = TRUE;
  709. Irp->IoStatus.Status = STATUS_SUCCESS;
  710. Irp->IoStatus.Information = 0;
  711. break;
  712. case IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT:
  713. DD((PCE)Pdx,DDT, "ParDeviceIo - IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT\n");
  714. Pdx->AllocatedByLockPort = FALSE;
  715. PptAssert(!Pdx->Connected && !Pdx->AllocatedByLockPort);
  716. Irp->IoStatus.Status = STATUS_SUCCESS;
  717. Irp->IoStatus.Information = 0;
  718. break;
  719. case IOCTL_SERIAL_SET_TIMEOUTS:
  720. {
  721. PSERIAL_TIMEOUTS ptoNew = Irp->AssociatedIrp.SystemBuffer;
  722. //
  723. // The only other thing let through is setting
  724. // the timer start.
  725. //
  726. Pdx->TimerStart = ptoNew->WriteTotalTimeoutConstant / 1000;
  727. Irp->IoStatus.Status = STATUS_SUCCESS;
  728. }
  729. break;
  730. case IOCTL_INTERNAL_PARDOT3_CONNECT:
  731. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_CONNECT - Dispatch\n");
  732. Irp->IoStatus.Status = ParDot3Connect(Pdx);
  733. Irp->IoStatus.Information = 0;
  734. break;
  735. case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
  736. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_DISCONNECT - Dispatch\n");
  737. Irp->IoStatus.Status = ParDot3Disconnect(Pdx);
  738. Irp->IoStatus.Information = 0;
  739. break;
  740. case IOCTL_INTERNAL_PARDOT3_SIGNAL:
  741. if( Pdx->IdxReverseProtocol != NIBBLE_MODE ) {
  742. PKEVENT Event;// = (PKEVENT)Irp->AssociatedIrp.SystemBuffer;
  743. RtlCopyMemory(&Event, Irp->AssociatedIrp.SystemBuffer, sizeof(PKEVENT));
  744. ASSERT_EVENT(Event);
  745. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_SIGNAL - Dispatch. Event [%x]\n", Event);
  746. Pdx->P12843DL.Event = Event;
  747. Pdx->P12843DL.bEventActive = TRUE;
  748. Irp->IoStatus.Status = STATUS_SUCCESS;
  749. } else {
  750. // don't use signalling in NIBBLE mode - rely on dot4 polling
  751. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  752. }
  753. Irp->IoStatus.Information = 0;
  754. break;
  755. case IOCTL_INTERNAL_PARDOT3_RESET:
  756. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_RESET - Dispatch\n");
  757. if (Pdx->P12843DL.fnReset)
  758. Irp->IoStatus.Status = ((PDOT3_RESET_ROUTINE) (Pdx->P12843DL.fnReset))(Pdx);
  759. else
  760. Irp->IoStatus.Status = STATUS_SUCCESS;
  761. Irp->IoStatus.Information = 0;
  762. break;
  763. default:
  764. //
  765. // unrecognized IOCTL? - we should never get here because the
  766. // dispatch routines should have filtered this out
  767. //
  768. // probably harmless, but we want to know if this happens
  769. // so we can fix the problem elsewhere
  770. ASSERTMSG("Unrecognized IOCTL in ParDeviceIo()\n",FALSE);
  771. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  772. }
  773. return;
  774. }