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.

1063 lines
34 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 {
  297. Status = STATUS_PENDING;
  298. }
  299. break;
  300. case IOCTL_IEEE1284_NEGOTIATE:
  301. DD((PCE)Pdx,DDT,"IOCTL_IEEE1284_NEGOTIATE\n");
  302. if ( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) ||
  303. IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_NEGOTIATION_MASK) ) {
  304. DD((PCE)Pdx,DDW,"ParDeviceControl: IOCTL_IEEE1284_NEGOTIATE STATUS_INVALID_PARAMETER\n");
  305. Status = STATUS_INVALID_PARAMETER;
  306. } else {
  307. PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
  308. if ((ppnmMask->usReadMask == arpReverse[Pdx->IdxReverseProtocol].Protocol) &&
  309. (ppnmMask->usWriteMask == afpForward[Pdx->IdxForwardProtocol].Protocol)) {
  310. Irp->IoStatus.Information = sizeof(PARCLASS_NEGOTIATION_MASK);
  311. Status = STATUS_SUCCESS;
  312. } else {
  313. Status = STATUS_PENDING;
  314. }
  315. }
  316. break;
  317. default :
  318. DD((PCE)Pdx,DDT,"IOCTL default case\n");
  319. Status = STATUS_INVALID_PARAMETER;
  320. break;
  321. }
  322. if (Status == STATUS_PENDING) {
  323. IoAcquireCancelSpinLock(&OldIrql);
  324. if (Irp->Cancel) {
  325. IoReleaseCancelSpinLock(OldIrql);
  326. Status = STATUS_CANCELLED;
  327. } else {
  328. //
  329. // This IRP takes more time, so it should be queued.
  330. //
  331. BOOLEAN needToSignalSemaphore = IsListEmpty( &Pdx->WorkQueue ) ? TRUE: FALSE;
  332. IoMarkIrpPending(Irp);
  333. #pragma warning( push )
  334. #pragma warning( disable : 4054 4055 )
  335. IoSetCancelRoutine(Irp, ParCancelRequest);
  336. #pragma warning( pop )
  337. InsertTailList(&Pdx->WorkQueue, &Irp->Tail.Overlay.ListEntry);
  338. IoReleaseCancelSpinLock(OldIrql);
  339. if( needToSignalSemaphore ) {
  340. KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE);
  341. }
  342. }
  343. }
  344. if (Status != STATUS_PENDING) {
  345. P4CompleteRequest( Irp, Status, Irp->IoStatus.Information );
  346. }
  347. return Status;
  348. }
  349. NTSTATUS
  350. ParInternalDeviceControl(
  351. IN PDEVICE_OBJECT DeviceObject,
  352. IN PIRP Irp
  353. )
  354. /*++
  355. Routine Description:
  356. This routine is the dispatch for internal device control requests.
  357. Arguments:
  358. DeviceObject - Supplies the device object.
  359. Irp - Supplies the I/O request packet.
  360. Return Value:
  361. STATUS_SUCCESS - Success.
  362. STATUS_PENDING - Request pending.
  363. STATUS_BUFFER_TOO_SMALL - Buffer too small.
  364. STATUS_INVALID_PARAMETER - Invalid io control request.
  365. STATUS_DELETE_PENDING - This device object is being deleted
  366. --*/
  367. {
  368. PIO_STACK_LOCATION IrpSp;
  369. // PPAR_SET_INFORMATION SetInfo;
  370. NTSTATUS Status;
  371. // PSERIAL_TIMEOUTS SerialTimeouts;
  372. PPDO_EXTENSION Pdx;
  373. KIRQL OldIrql;
  374. PPARCLASS_INFORMATION pParclassInfo;
  375. Irp->IoStatus.Information = 0;
  376. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  377. Pdx = DeviceObject->DeviceExtension;
  378. //
  379. // bail out if a delete is pending for this device object
  380. //
  381. if(Pdx->DeviceStateFlags & PPT_DEVICE_DELETE_PENDING) {
  382. P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
  383. return STATUS_DELETE_PENDING;
  384. }
  385. //
  386. // bail out if a remove is pending for our ParPort device object
  387. //
  388. if(Pdx->DeviceStateFlags & PAR_DEVICE_PORT_REMOVE_PENDING) {
  389. P4CompleteRequest( Irp, STATUS_DELETE_PENDING, Irp->IoStatus.Information );
  390. return STATUS_DELETE_PENDING;
  391. }
  392. //
  393. // bail out if device has been removed
  394. //
  395. if(Pdx->DeviceStateFlags & (PPT_DEVICE_REMOVED|PPT_DEVICE_SURPRISE_REMOVED) ) {
  396. P4CompleteRequest( Irp, STATUS_DEVICE_REMOVED, Irp->IoStatus.Information );
  397. return STATUS_DEVICE_REMOVED;
  398. }
  399. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  400. case IOCTL_INTERNAL_PARCLASS_CONNECT:
  401. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARCLASS_CONNECT\n");
  402. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PARCLASS_INFORMATION)) {
  403. Status = STATUS_BUFFER_TOO_SMALL;
  404. } else {
  405. PFDO_EXTENSION fdx = Pdx->Fdo->DeviceExtension;
  406. PPARALLEL_PORT_INFORMATION portInfo = &fdx->PortInfo;
  407. PPARALLEL_PNP_INFORMATION pnpInfo = &fdx->PnpInfo;
  408. pParclassInfo = Irp->AssociatedIrp.SystemBuffer;
  409. pParclassInfo->ParclassContext = Pdx;
  410. pParclassInfo->Controller = portInfo->Controller;
  411. pParclassInfo->SpanOfController = portInfo->SpanOfController;
  412. pParclassInfo->EcrController = pnpInfo->EcpController;
  413. pParclassInfo->HardwareCapabilities = pnpInfo->HardwareCapabilities;
  414. pParclassInfo->FifoDepth = pnpInfo->FifoDepth;
  415. pParclassInfo->FifoWidth = pnpInfo->FifoWidth;
  416. pParclassInfo->DetermineIeeeModes = ParExportedDetermineIeeeModes;
  417. pParclassInfo->TerminateIeeeMode = ParExportedTerminateIeeeMode;
  418. pParclassInfo->NegotiateIeeeMode = ParExportedNegotiateIeeeMode;
  419. pParclassInfo->IeeeFwdToRevMode = ParExportedIeeeFwdToRevMode;
  420. pParclassInfo->IeeeRevToFwdMode = ParExportedIeeeRevToFwdMode;
  421. pParclassInfo->ParallelRead = ParExportedParallelRead;
  422. pParclassInfo->ParallelWrite = ParExportedParallelWrite;
  423. Irp->IoStatus.Information = sizeof(PARCLASS_INFORMATION);
  424. Status = STATUS_SUCCESS;
  425. }
  426. break;
  427. case IOCTL_INTERNAL_GET_PARPORT_FDO:
  428. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_GET_PARPORT_FDO\n");
  429. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PDEVICE_OBJECT)) {
  430. Status = STATUS_BUFFER_TOO_SMALL;
  431. } else {
  432. PDEVICE_OBJECT *pFdo = Irp->AssociatedIrp.SystemBuffer;
  433. *pFdo = Pdx->Fdo;
  434. Irp->IoStatus.Information = sizeof(PDEVICE_OBJECT);
  435. Status = STATUS_SUCCESS;
  436. }
  437. break;
  438. case IOCTL_INTERNAL_PARCLASS_DISCONNECT:
  439. Status = STATUS_SUCCESS;
  440. break;
  441. case IOCTL_INTERNAL_DISCONNECT_IDLE:
  442. case IOCTL_INTERNAL_LOCK_PORT:
  443. case IOCTL_INTERNAL_UNLOCK_PORT:
  444. case IOCTL_INTERNAL_LOCK_PORT_NO_SELECT:
  445. case IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT:
  446. case IOCTL_INTERNAL_PARDOT3_CONNECT:
  447. case IOCTL_INTERNAL_PARDOT3_RESET:
  448. Status = STATUS_PENDING;
  449. break;
  450. case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
  451. // immediately tell worker thread to stop signalling
  452. Pdx->P12843DL.bEventActive = FALSE;
  453. Status = STATUS_PENDING;
  454. break;
  455. case IOCTL_INTERNAL_PARDOT3_SIGNAL:
  456. if( IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PKEVENT) ) {
  457. Status = STATUS_INVALID_PARAMETER;
  458. } else {
  459. Status = STATUS_PENDING;
  460. }
  461. break;
  462. default :
  463. DD((PCE)Pdx,DDW,"IOCTL_INTERNAL... default case - invalid parameter\n");
  464. Status = STATUS_INVALID_PARAMETER;
  465. break;
  466. }
  467. if (Status == STATUS_PENDING) {
  468. //
  469. // This IRP takes more time, queue it for the worker thread
  470. //
  471. IoAcquireCancelSpinLock(&OldIrql);
  472. if (Irp->Cancel) {
  473. IoReleaseCancelSpinLock(OldIrql);
  474. Status = STATUS_CANCELLED;
  475. } else {
  476. BOOLEAN needToSignalSemaphore = IsListEmpty( &Pdx->WorkQueue ) ? TRUE : FALSE;
  477. IoMarkIrpPending(Irp);
  478. #pragma warning( push )
  479. #pragma warning( disable : 4054 4055 )
  480. IoSetCancelRoutine(Irp, ParCancelRequest);
  481. #pragma warning( pop )
  482. InsertTailList(&Pdx->WorkQueue, &Irp->Tail.Overlay.ListEntry);
  483. IoReleaseCancelSpinLock(OldIrql);
  484. if( needToSignalSemaphore ) {
  485. KeReleaseSemaphore(&Pdx->RequestSemaphore, 0, 1, FALSE);
  486. }
  487. }
  488. }
  489. if (Status != STATUS_PENDING) {
  490. P4CompleteRequest( Irp, Status, Irp->IoStatus.Information );
  491. }
  492. return Status;
  493. }
  494. VOID
  495. ParDeviceIo(
  496. IN PPDO_EXTENSION Pdx
  497. )
  498. /*++
  499. Routine Description:
  500. This routine implements a DEVICE_IOCTL request with the extension's current irp.
  501. Arguments:
  502. Pdx - Supplies the device extension.
  503. Return Value:
  504. None.
  505. --*/
  506. {
  507. PIRP Irp;
  508. PIO_STACK_LOCATION IrpSp;
  509. ULONG IdLength;
  510. NTSTATUS NtStatus;
  511. UCHAR Status;
  512. UCHAR Control;
  513. ULONG ioControlCode;
  514. Irp = Pdx->CurrentOpIrp;
  515. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  516. ioControlCode = IrpSp->Parameters.DeviceIoControl.IoControlCode;
  517. switch( ioControlCode ) {
  518. case IOCTL_PAR_SET_INFORMATION :
  519. {
  520. Status = ParInitializeDevice(Pdx);
  521. if (!PAR_OK(Status)) {
  522. ParNotInitError(Pdx, Status); // Set the IoStatus.Status of the CurrentOpIrp appropriately
  523. } else {
  524. Irp->IoStatus.Status = STATUS_SUCCESS;
  525. }
  526. }
  527. break;
  528. case IOCTL_PAR_QUERY_INFORMATION :
  529. {
  530. PPAR_QUERY_INFORMATION IrpBuffer = Irp->AssociatedIrp.SystemBuffer;
  531. Irp->IoStatus.Status = STATUS_SUCCESS;
  532. Status = GetStatus(Pdx->Controller);
  533. Control = GetControl(Pdx->Controller);
  534. // Interpretating Status & Control
  535. IrpBuffer->Status = 0x0;
  536. if (PAR_POWERED_OFF(Status) || PAR_NO_CABLE(Status)) {
  537. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_POWER_OFF);
  538. } else if (PAR_PAPER_EMPTY(Status)) {
  539. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_PAPER_EMPTY);
  540. } else if (PAR_OFF_LINE(Status)) {
  541. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_OFF_LINE);
  542. } else if (PAR_NOT_CONNECTED(Status)) {
  543. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_NOT_CONNECTED);
  544. }
  545. if (PAR_BUSY(Status)) {
  546. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_BUSY);
  547. }
  548. if (PAR_SELECTED(Status)) {
  549. IrpBuffer->Status = (UCHAR)(IrpBuffer->Status | PARALLEL_SELECTED);
  550. }
  551. Irp->IoStatus.Information = sizeof( PAR_QUERY_INFORMATION );
  552. }
  553. break;
  554. case IOCTL_PAR_QUERY_RAW_DEVICE_ID :
  555. // We always read the Device Id in Nibble Mode.
  556. NtStatus = SppQueryDeviceId(Pdx,
  557. Irp->AssociatedIrp.SystemBuffer,
  558. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  559. &IdLength, TRUE);
  560. Irp->IoStatus.Status = NtStatus;
  561. if (NT_SUCCESS(NtStatus)) {
  562. Irp->IoStatus.Information = IdLength;
  563. } else {
  564. Irp->IoStatus.Information = 0;
  565. }
  566. break;
  567. case IOCTL_PAR_QUERY_DEVICE_ID :
  568. // We always read the Device Id in Nibble Mode.
  569. NtStatus = SppQueryDeviceId(Pdx,
  570. Irp->AssociatedIrp.SystemBuffer,
  571. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  572. &IdLength, FALSE);
  573. Irp->IoStatus.Status = NtStatus;
  574. if( NT_SUCCESS( NtStatus ) ) {
  575. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - SUCCESS - size = %d\n", IdLength);
  576. // Include terminating NULL in the string to copy back to user buffer
  577. Irp->IoStatus.Information = IdLength + sizeof(CHAR);
  578. } else if( NtStatus == STATUS_BUFFER_TOO_SMALL) {
  579. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - FAIL - BUFFER_TOO_SMALL - supplied= %d, required=%d\n",
  580. IrpSp->Parameters.DeviceIoControl.OutputBufferLength, IdLength);
  581. Irp->IoStatus.Information = 0;
  582. } else {
  583. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_ID - FAIL - QUERY ID FAILED\n");
  584. Irp->IoStatus.Information = 0;
  585. }
  586. break;
  587. case IOCTL_PAR_QUERY_DEVICE_ID_SIZE :
  588. //
  589. // Read the first two bytes of the Nibble Id, add room for the terminating NULL and
  590. // return this to the caller.
  591. //
  592. NtStatus = SppQueryDeviceId(Pdx, NULL, 0, &IdLength, FALSE);
  593. if (NtStatus == STATUS_BUFFER_TOO_SMALL) {
  594. DD((PCE)Pdx,DDT,"IOCTL_PAR_QUERY_DEVICE_ID_SIZE - size required = %d\n", IdLength);
  595. Irp->IoStatus.Status = STATUS_SUCCESS;
  596. Irp->IoStatus.Information =
  597. sizeof(PAR_DEVICE_ID_SIZE_INFORMATION);
  598. // include space for terminating NULL
  599. ((PPAR_DEVICE_ID_SIZE_INFORMATION)
  600. Irp->AssociatedIrp.SystemBuffer)->DeviceIdSize = IdLength + sizeof(CHAR);
  601. } else {
  602. Irp->IoStatus.Status = NtStatus;
  603. Irp->IoStatus.Information = 0;
  604. }
  605. break;
  606. case IOCTL_PAR_PING :
  607. // We need to do a quick terminate and negotiate of the current modes
  608. NtStatus = ParPing(Pdx);
  609. DD((PCE)Pdx,DDT,"ParDeviceIo:IOCTL_PAR_PING\n");
  610. Irp->IoStatus.Status = NtStatus;
  611. Irp->IoStatus.Information = 0;
  612. break;
  613. case IOCTL_INTERNAL_DISCONNECT_IDLE :
  614. if ((Pdx->Connected) &&
  615. (afpForward[Pdx->IdxForwardProtocol].fnDisconnect)) {
  616. DD((PCE)Pdx,DDT,"ParDeviceIo:IOCTL_INTERNAL_DISCONNECT_IDLE: Calling afpForward.fnDisconnect\n");
  617. afpForward[Pdx->IdxForwardProtocol].fnDisconnect (Pdx);
  618. }
  619. Irp->IoStatus.Status = STATUS_SUCCESS;
  620. Irp->IoStatus.Information = 0;
  621. break;
  622. case IOCTL_IEEE1284_NEGOTIATE:
  623. {
  624. PPARCLASS_NEGOTIATION_MASK ppnmMask = (PPARCLASS_NEGOTIATION_MASK)Irp->AssociatedIrp.SystemBuffer;
  625. ParTerminate(Pdx);
  626. Irp->IoStatus.Status = IeeeNegotiateMode(Pdx, ppnmMask->usReadMask, ppnmMask->usWriteMask);
  627. if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(PARCLASS_NEGOTIATION_MASK)) {
  628. DD((PCE)Pdx,DDT, "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE Passed.\n");
  629. ppnmMask->usReadMask = arpReverse[Pdx->IdxReverseProtocol].Protocol;
  630. ppnmMask->usWriteMask = afpForward[Pdx->IdxForwardProtocol].Protocol;
  631. Irp->IoStatus.Information = sizeof (PARCLASS_NEGOTIATION_MASK);
  632. } else {
  633. DD((PCE)Pdx,DDT, "ParDeviceIo: IOCTL_IEEE1284_NEGOTIATE failed.\n");
  634. Irp->IoStatus.Information = 0;
  635. }
  636. }
  637. break;
  638. case IOCTL_PAR_GET_DEVICE_CAPS :
  639. Pdx->BadProtocolModes = *((USHORT *) Irp->AssociatedIrp.SystemBuffer);
  640. IeeeDetermineSupportedProtocols(Pdx);
  641. *((USHORT *) Irp->AssociatedIrp.SystemBuffer) = Pdx->ProtocolModesSupported;
  642. Irp->IoStatus.Information = sizeof(Pdx->ProtocolModesSupported);
  643. Irp->IoStatus.Status = STATUS_SUCCESS;
  644. break;
  645. case IOCTL_PAR_SET_READ_ADDRESS:
  646. {
  647. PUCHAR pAddress = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
  648. if (Pdx->ReverseInterfaceAddress != *pAddress) {
  649. Pdx->ReverseInterfaceAddress = *pAddress;
  650. Pdx->SetReverseAddress = TRUE;
  651. }
  652. Irp->IoStatus.Information = 0;
  653. Irp->IoStatus.Status = STATUS_SUCCESS;
  654. }
  655. break;
  656. case IOCTL_PAR_SET_WRITE_ADDRESS :
  657. {
  658. PUCHAR pAddress = (PUCHAR)Irp->AssociatedIrp.SystemBuffer;
  659. NtStatus = STATUS_SUCCESS;
  660. if (Pdx->ForwardInterfaceAddress != *pAddress) {
  661. Pdx->ForwardInterfaceAddress = *pAddress;
  662. if (Pdx->Connected) {
  663. if (afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress) {
  664. if (Pdx->CurrentPhase != PHASE_FORWARD_IDLE &&
  665. Pdx->CurrentPhase != PHASE_FORWARD_XFER) {
  666. NtStatus = ParReverseToForward(Pdx);
  667. }
  668. if (NT_SUCCESS(NtStatus)) {
  669. NtStatus = afpForward[Pdx->IdxForwardProtocol].fnSetInterfaceAddress(
  670. Pdx,
  671. Pdx->ForwardInterfaceAddress
  672. );
  673. }
  674. if (NT_SUCCESS(NtStatus)) {
  675. Pdx->SetForwardAddress = FALSE;
  676. Pdx->SetReverseAddress = FALSE;
  677. Pdx->ReverseInterfaceAddress = *pAddress;
  678. } else {
  679. Pdx->SetForwardAddress = TRUE;
  680. DD((PCE)Pdx,DDE,"ParDeviceIo: IOCTL_PAR_SET_WRITE_ADDRESS Failed\n");
  681. }
  682. } else {
  683. DD((PCE)Pdx,DDE, "ParDeviceIo: Someone called IOCTL_PAR_SET_WRITE_ADDRESS.\n");
  684. DD((PCE)Pdx,DDE, "ParDeviceIo: You don't have a fnSetInterfaceAddress.\n");
  685. DD((PCE)Pdx,DDE, "ParDeviceIo: Either IEEE1284.c has wrong info or your caller is in error!\n");
  686. NtStatus = STATUS_UNSUCCESSFUL;
  687. }
  688. } else {
  689. Pdx->SetForwardAddress = TRUE;
  690. }
  691. }
  692. Irp->IoStatus.Information = 0;
  693. Irp->IoStatus.Status = NtStatus;
  694. }
  695. break;
  696. case IOCTL_INTERNAL_LOCK_PORT :
  697. ParpIoctlThreadLockPort(Pdx);
  698. break;
  699. case IOCTL_INTERNAL_UNLOCK_PORT :
  700. ParpIoctlThreadUnlockPort(Pdx);
  701. break;
  702. case IOCTL_INTERNAL_LOCK_PORT_NO_SELECT:
  703. DD((PCE)Pdx,DDT, "ParDeviceIo - IOCTL_INTERNAL_LOCK_PORT_NO_SELECT\n");
  704. Pdx->AllocatedByLockPort = TRUE;
  705. Irp->IoStatus.Status = STATUS_SUCCESS;
  706. Irp->IoStatus.Information = 0;
  707. break;
  708. case IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT:
  709. DD((PCE)Pdx,DDT, "ParDeviceIo - IOCTL_INTERNAL_UNLOCK_PORT_NO_DESELECT\n");
  710. Pdx->AllocatedByLockPort = FALSE;
  711. PptAssert(!Pdx->Connected && !Pdx->AllocatedByLockPort);
  712. Irp->IoStatus.Status = STATUS_SUCCESS;
  713. Irp->IoStatus.Information = 0;
  714. break;
  715. case IOCTL_SERIAL_SET_TIMEOUTS:
  716. {
  717. PSERIAL_TIMEOUTS ptoNew = Irp->AssociatedIrp.SystemBuffer;
  718. //
  719. // The only other thing let through is setting
  720. // the timer start.
  721. //
  722. Pdx->TimerStart = ptoNew->WriteTotalTimeoutConstant / 1000;
  723. Irp->IoStatus.Status = STATUS_SUCCESS;
  724. }
  725. break;
  726. case IOCTL_INTERNAL_PARDOT3_CONNECT:
  727. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_CONNECT - Dispatch\n");
  728. Irp->IoStatus.Status = ParDot3Connect(Pdx);
  729. Irp->IoStatus.Information = 0;
  730. break;
  731. case IOCTL_INTERNAL_PARDOT3_DISCONNECT:
  732. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_DISCONNECT - Dispatch\n");
  733. Irp->IoStatus.Status = ParDot3Disconnect(Pdx);
  734. Irp->IoStatus.Information = 0;
  735. break;
  736. case IOCTL_INTERNAL_PARDOT3_SIGNAL:
  737. if( Pdx->IdxReverseProtocol != NIBBLE_MODE ) {
  738. PKEVENT Event;// = (PKEVENT)Irp->AssociatedIrp.SystemBuffer;
  739. RtlCopyMemory(&Event, Irp->AssociatedIrp.SystemBuffer, sizeof(PKEVENT));
  740. ASSERT_EVENT(Event);
  741. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_SIGNAL - Dispatch. Event [%x]\n", Event);
  742. Pdx->P12843DL.Event = Event;
  743. Pdx->P12843DL.bEventActive = TRUE;
  744. Irp->IoStatus.Status = STATUS_SUCCESS;
  745. } else {
  746. // don't use signalling in NIBBLE mode - rely on dot4 polling
  747. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  748. }
  749. Irp->IoStatus.Information = 0;
  750. break;
  751. case IOCTL_INTERNAL_PARDOT3_RESET:
  752. DD((PCE)Pdx,DDT,"IOCTL_INTERNAL_PARDOT3_RESET - Dispatch\n");
  753. if (Pdx->P12843DL.fnReset)
  754. Irp->IoStatus.Status = ((PDOT3_RESET_ROUTINE) (Pdx->P12843DL.fnReset))(Pdx);
  755. else
  756. Irp->IoStatus.Status = STATUS_SUCCESS;
  757. Irp->IoStatus.Information = 0;
  758. break;
  759. default:
  760. //
  761. // unrecognized IOCTL? - we should never get here because the
  762. // dispatch routines should have filtered this out
  763. //
  764. // probably harmless, but we want to know if this happens
  765. // so we can fix the problem elsewhere
  766. ASSERTMSG("Unrecognized IOCTL in ParDeviceIo()\n",FALSE);
  767. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  768. }
  769. return;
  770. }