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.

461 lines
12 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1993 - 1999
  3. Module Name:
  4. port.c
  5. Abstract:
  6. This module contains the code to acquire and release the port
  7. from the port driver parport.sys.
  8. Author:
  9. Anthony V. Ercolano 1-Aug-1992
  10. Norbert P. Kusters 22-Oct-1993
  11. Environment:
  12. Kernel mode
  13. Revision History :
  14. --*/
  15. #include "pch.h"
  16. NTSTATUS
  17. ParGetPortInfoFromPortDevice(
  18. IN OUT PDEVICE_EXTENSION Extension
  19. );
  20. VOID
  21. ParReleasePortInfoToPortDevice(
  22. IN PDEVICE_EXTENSION Extension
  23. );
  24. VOID
  25. ParFreePort(
  26. IN PDEVICE_EXTENSION Extension
  27. );
  28. NTSTATUS
  29. ParAllocPortCompletionRoutine(
  30. IN PDEVICE_OBJECT DeviceObject,
  31. IN PIRP Irp,
  32. IN PVOID Context
  33. );
  34. BOOLEAN
  35. ParAllocPort(
  36. IN PDEVICE_EXTENSION Extension
  37. );
  38. NTSTATUS
  39. ParGetPortInfoFromPortDevice(
  40. IN OUT PDEVICE_EXTENSION Extension
  41. )
  42. /*++
  43. Routine Description:
  44. This routine will request the port information from the port driver
  45. and fill it in the device extension.
  46. Arguments:
  47. Extension - Supplies the device extension.
  48. Return Value:
  49. STATUS_SUCCESS - Success.
  50. !STATUS_SUCCESS - Failure.
  51. --*/
  52. {
  53. KEVENT Event;
  54. PIRP Irp;
  55. PARALLEL_PORT_INFORMATION PortInfo;
  56. PARALLEL_PNP_INFORMATION PnpInfo;
  57. IO_STATUS_BLOCK IoStatus;
  58. NTSTATUS Status;
  59. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  60. //
  61. // Get Parallel Port Info
  62. //
  63. ASSERT(Extension->PortDeviceObject != NULL);
  64. Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_GET_PARALLEL_PORT_INFO,
  65. Extension->PortDeviceObject,
  66. NULL,
  67. 0,
  68. &PortInfo,
  69. sizeof(PARALLEL_PORT_INFORMATION),
  70. TRUE,
  71. &Event,
  72. &IoStatus);
  73. ASSERT(Irp->StackCount > 0);
  74. if (!Irp) {
  75. return STATUS_INSUFFICIENT_RESOURCES;
  76. }
  77. Status = ParCallDriver(Extension->PortDeviceObject, Irp);
  78. if (!NT_SUCCESS(Status)) {
  79. return Status;
  80. }
  81. Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  82. if (!NT_SUCCESS(Status)) {
  83. return Status;
  84. }
  85. Status = IoStatus.Status;
  86. if (!NT_SUCCESS(Status)) {
  87. return(Status);
  88. }
  89. Extension->OriginalController = PortInfo.OriginalController;
  90. Extension->Controller = PortInfo.Controller;
  91. Extension->SpanOfController = PortInfo.SpanOfController;
  92. Extension->TryAllocatePort = PortInfo.TryAllocatePort;
  93. Extension->FreePort = PortInfo.FreePort;
  94. Extension->QueryNumWaiters = PortInfo.QueryNumWaiters;
  95. Extension->PortContext = PortInfo.Context;
  96. if (Extension->SpanOfController < PARALLEL_REGISTER_SPAN) {
  97. return STATUS_INSUFFICIENT_RESOURCES;
  98. }
  99. //
  100. // Get Parallel Pnp Info
  101. //
  102. Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_GET_PARALLEL_PNP_INFO,
  103. Extension->PortDeviceObject,
  104. NULL,
  105. 0,
  106. &PnpInfo,
  107. sizeof(PARALLEL_PNP_INFORMATION),
  108. TRUE,
  109. &Event,
  110. &IoStatus);
  111. if (!Irp) {
  112. return STATUS_INSUFFICIENT_RESOURCES;
  113. }
  114. Status = ParCallDriver(Extension->PortDeviceObject, Irp);
  115. if (!NT_SUCCESS(Status)) {
  116. return Status;
  117. }
  118. Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  119. if (!NT_SUCCESS(Status)) {
  120. return Status;
  121. }
  122. Status = IoStatus.Status;
  123. if (!NT_SUCCESS(Status)) {
  124. return(Status);
  125. }
  126. Extension->EcrController = PnpInfo.EcpController;
  127. Extension->HardwareCapabilities = PnpInfo.HardwareCapabilities;
  128. Extension->TrySetChipMode = PnpInfo.TrySetChipMode;
  129. Extension->ClearChipMode = PnpInfo.ClearChipMode;
  130. Extension->TrySelectDevice = PnpInfo.TrySelectDevice;
  131. Extension->DeselectDevice = PnpInfo.DeselectDevice;
  132. Extension->FifoDepth = PnpInfo.FifoDepth;
  133. Extension->FifoWidth = PnpInfo.FifoWidth;
  134. //
  135. // get symbolic link name to use for this end of chain device
  136. // object from ParPort
  137. //
  138. // if anything goes wrong, simply leave Extension->SymbolicLinkName alone
  139. // as it was cleared to all zeros via an RtlZeroMemory in
  140. // ParPnpCreateDevice(...) in parpnp.c
  141. //
  142. if( ( 0 == Extension->SymbolicLinkName.Length ) && PnpInfo.PortName ) {
  143. //
  144. // If we have no SymbolicLinkName and we have a port name, use the port
  145. // name to initialize our symbolic link name in our device extension
  146. //
  147. UNICODE_STRING pathPrefix;
  148. UNICODE_STRING portName;
  149. ULONG length;
  150. PWSTR buffer;
  151. RtlInitUnicodeString(&pathPrefix, (PWSTR)L"\\DosDevices\\");
  152. RtlInitUnicodeString(&portName, PnpInfo.PortName);
  153. length = pathPrefix.Length + portName.Length + sizeof(UNICODE_NULL);
  154. buffer = ExAllocatePool(PagedPool, length);
  155. if(buffer) {
  156. Extension->SymbolicLinkName.Buffer = buffer;
  157. Extension->SymbolicLinkName.Length = 0;
  158. Extension->SymbolicLinkName.MaximumLength = (USHORT)length;
  159. RtlAppendUnicodeStringToString(&Extension->SymbolicLinkName, &pathPrefix);
  160. RtlAppendUnicodeStringToString(&Extension->SymbolicLinkName, &portName);
  161. }
  162. }
  163. ParDumpV( ("ParGetPortInfoFromPortDevice(...):\n") );
  164. ParDumpV( (" - ClassName= %wZ , SymbolicLinkName= %wZ , PortDeviceObject= %08x\n",
  165. &Extension->ClassName, &Extension->SymbolicLinkName, Extension->PortDeviceObject) );
  166. return Status;
  167. }
  168. VOID
  169. ParReleasePortInfoToPortDevice(
  170. IN PDEVICE_EXTENSION Extension
  171. )
  172. /*++
  173. Routine Description:
  174. This routine will release the port information back to the port driver.
  175. Arguments:
  176. Extension - Supplies the device extension.
  177. Return Value:
  178. None.
  179. --*/
  180. {
  181. //
  182. // ParPort treats this as a NO-OP in Win2K, so don't bother sending the IOCTL.
  183. //
  184. // In follow-on to Win2K parport may use this to page the entire driver as
  185. // it was originally intended, so we'll turn this back on then.
  186. //
  187. return;
  188. #if 0
  189. KEVENT Event;
  190. PIRP Irp;
  191. IO_STATUS_BLOCK IoStatus;
  192. NTSTATUS Status;
  193. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  194. Irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_RELEASE_PARALLEL_PORT_INFO,
  195. Extension->PortDeviceObject,
  196. NULL,
  197. 0,
  198. NULL,
  199. 0,
  200. TRUE,
  201. &Event,
  202. &IoStatus);
  203. if (!Irp) {
  204. return;
  205. }
  206. Status = ParCallDriver(Extension->PortDeviceObject, Irp);
  207. if (!NT_SUCCESS(Status)) {
  208. return;
  209. }
  210. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  211. #endif
  212. }
  213. VOID
  214. ParFreePort(
  215. IN PDEVICE_EXTENSION Extension
  216. )
  217. /*++
  218. Routine Description:
  219. This routine calls the internal free port ioctl. This routine
  220. should be called before completing an IRP that has allocated
  221. the port.
  222. Arguments:
  223. Extension - Supplies the device extension.
  224. Return Value:
  225. None.
  226. --*/
  227. {
  228. // Don't allow multiple releases
  229. if (Extension->bAllocated) {
  230. ParDump2(PARALLOCFREEPORT, ("port::ParFreePort: %x - calling ParPort's FreePort function\n", Extension->Controller) );
  231. Extension->FreePort(Extension->PortContext);
  232. } else {
  233. ParDump2(PARALLOCFREEPORT, ("port::ParFreePort: %x - we don't have the Port!!! (!Ext->bAllocated)\n", Extension->Controller) );
  234. }
  235. Extension->bAllocated = FALSE;
  236. }
  237. NTSTATUS
  238. ParAllocPortCompletionRoutine(
  239. IN PDEVICE_OBJECT DeviceObject,
  240. IN PIRP Irp,
  241. IN PVOID Event
  242. )
  243. /*++
  244. Routine Description:
  245. This routine is the completion routine for a port allocate request.
  246. Arguments:
  247. DeviceObject - Supplies the device object.
  248. Irp - Supplies the I/O request packet.
  249. Context - Supplies the notification event.
  250. Return Value:
  251. STATUS_MORE_PROCESSING_REQUIRED - The Irp still requires processing.
  252. --*/
  253. {
  254. UNREFERENCED_PARAMETER( Irp );
  255. UNREFERENCED_PARAMETER( DeviceObject );
  256. KeSetEvent((PKEVENT) Event, 0, FALSE);
  257. return STATUS_MORE_PROCESSING_REQUIRED;
  258. }
  259. BOOLEAN
  260. ParAllocPort(
  261. IN PDEVICE_EXTENSION Extension
  262. )
  263. /*++
  264. Routine Description:
  265. This routine takes the given Irp and sends it down as a port allocate
  266. request. When this request completes, the Irp will be queued for
  267. processing.
  268. Arguments:
  269. Extension - Supplies the device extension.
  270. Return Value:
  271. FALSE - The port was not successfully allocated.
  272. TRUE - The port was successfully allocated.
  273. --*/
  274. {
  275. PIO_STACK_LOCATION NextSp;
  276. KEVENT Event;
  277. PIRP Irp;
  278. BOOLEAN bAllocated;
  279. NTSTATUS Status;
  280. LARGE_INTEGER Timeout;
  281. /*
  282. ParDump(PARDUMP_VERBOSE_MAX,
  283. ("PARALLEL: "
  284. "ParAllocPort(...): %wZ\n",
  285. &Extension->SymbolicLinkName) );
  286. // Don't allow multiple allocations
  287. if (Extension->bAllocated) {
  288. ParDump(PARDUMP_VERBOSE_MAX,
  289. ("PARALLEL: "
  290. "ParAllocPort(...): %wZ\n",
  291. &Extension->SymbolicLinkName) );
  292. return TRUE;
  293. }
  294. */
  295. ParDump2(PARALLOCFREEPORT,
  296. ("ParAllocPort: Enter %x\n", Extension->Controller) );
  297. // Don't allow multiple allocations
  298. if (Extension->bAllocated) {
  299. ParDump2(PARALLOCFREEPORT,
  300. ("ParAllocPort: %x Already allocated\n", Extension->Controller) );
  301. return TRUE;
  302. }
  303. Irp = Extension->CurrentOpIrp;
  304. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  305. NextSp = IoGetNextIrpStackLocation(Irp);
  306. NextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  307. NextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_PARALLEL_PORT_ALLOCATE;
  308. IoSetCompletionRoutine(Irp,
  309. ParAllocPortCompletionRoutine,
  310. &Event,
  311. TRUE,
  312. TRUE,
  313. TRUE);
  314. ParCallDriver(Extension->PortDeviceObject, Irp);
  315. Timeout.QuadPart = -((LONGLONG) Extension->TimerStart*10*1000*1000);
  316. Status = KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout);
  317. if (Status == STATUS_TIMEOUT) {
  318. IoCancelIrp(Irp);
  319. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  320. }
  321. bAllocated = (BOOLEAN)NT_SUCCESS(Irp->IoStatus.Status);
  322. Extension->bAllocated = bAllocated;
  323. if (!bAllocated) {
  324. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  325. ParDump2(PARALLOCFREEPORT,
  326. ("ParAllocPort: %x FAILED - DEVICE_BUSY\n", Extension->Controller) );
  327. /*
  328. ParDump(PARDUMP_VERBOSE_MAX,
  329. ("PARALLEL: "
  330. "ParAllocPort(...): %wZ FAILED - DEVICE_BUSY\n",
  331. &Extension->SymbolicLinkName) );
  332. */
  333. }
  334. return bAllocated;
  335. }