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.

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