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.

388 lines
12 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. waitmask.c
  5. Abstract: POS (serial) interface for USB Point-of-Sale devices
  6. Author:
  7. Karan Mehra [t-karanm]
  8. Environment:
  9. Kernel mode
  10. Revision History:
  11. --*/
  12. #include <WDM.H>
  13. #include <usbdi.h>
  14. #include <usbdlib.h>
  15. #include <usbioctl.h>
  16. #include "escpos.h"
  17. #include "debug.h"
  18. NTSTATUS QuerySpecialFeature(PARENTFDOEXT *parentFdoExt)
  19. {
  20. NTSTATUS status = STATUS_SUCCESS;
  21. HANDLE hRegDevice;
  22. parentFdoExt->posFlag = 0;
  23. status = IoOpenDeviceRegistryKey(parentFdoExt->physicalDevObj,
  24. PLUGPLAY_REGKEY_DRIVER,
  25. KEY_READ,
  26. &hRegDevice);
  27. if (NT_SUCCESS(status)) {
  28. UNICODE_STRING keyName;
  29. PKEY_VALUE_FULL_INFORMATION keyValueInfo;
  30. ULONG keyValueTotalSize, actualLength, value;
  31. WCHAR oddKeyName[] = L"OddEndpointFlag";
  32. #if STATUS_ENDPOINT
  33. WCHAR serialKeyName[] = L"SerialEmulationFlag";
  34. RtlInitUnicodeString(&keyName, serialKeyName);
  35. keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) + keyName.Length*sizeof(WCHAR) + sizeof(ULONG);
  36. keyValueInfo = ALLOCPOOL(PagedPool, keyValueTotalSize);
  37. if (keyValueInfo) {
  38. status = ZwQueryValueKey(hRegDevice,
  39. &keyName,
  40. KeyValueFullInformation,
  41. keyValueInfo,
  42. keyValueTotalSize,
  43. &actualLength);
  44. if (NT_SUCCESS(status)) {
  45. ASSERT(keyValueInfo->Type == REG_DWORD);
  46. ASSERT(keyValueInfo->DataLength == sizeof(ULONG));
  47. value = *((PULONG)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset));
  48. if (value == 1)
  49. parentFdoExt->posFlag |= SERIAL_EMULATION;
  50. }
  51. else
  52. DBGVERBOSE(("QuerySpecialFeature: Flag not found. ZwQueryValueKey failed with %xh.", status));
  53. FREEPOOL(keyValueInfo);
  54. }
  55. else
  56. ASSERT(keyValueInfo);
  57. #endif
  58. RtlInitUnicodeString(&keyName, oddKeyName);
  59. keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) + keyName.Length*sizeof(WCHAR) + sizeof(ULONG);
  60. keyValueInfo = ALLOCPOOL(PagedPool, keyValueTotalSize);
  61. if (keyValueInfo) {
  62. status = ZwQueryValueKey(hRegDevice,
  63. &keyName,
  64. KeyValueFullInformation,
  65. keyValueInfo,
  66. keyValueTotalSize,
  67. &actualLength);
  68. if (NT_SUCCESS(status)) {
  69. ASSERT(keyValueInfo->Type == REG_DWORD);
  70. ASSERT(keyValueInfo->DataLength == sizeof(ULONG));
  71. value = *((PULONG)(((PCHAR)keyValueInfo)+keyValueInfo->DataOffset));
  72. if (value == 1)
  73. parentFdoExt->posFlag |= ODD_ENDPOINT;
  74. }
  75. else
  76. DBGVERBOSE(("QuerySpecialFeature: Flag not found. ZwQueryValueKey failed with %xh.", status));
  77. FREEPOOL(keyValueInfo);
  78. }
  79. else
  80. ASSERT(keyValueInfo);
  81. ZwClose(hRegDevice);
  82. /*
  83. * We do not wish to permit the Serial Emulation and
  84. * Odd Endpoint features together on the same device.
  85. */
  86. if((parentFdoExt->posFlag & SERIAL_EMULATION) && (parentFdoExt->posFlag & ODD_ENDPOINT)) {
  87. DBGVERBOSE(("More than one special feature NOT supported on the same device."));
  88. status = STATUS_INVALID_PARAMETER;
  89. }
  90. }
  91. else
  92. DBGERR(("QuerySpecialFeature: IoOpenDeviceRegistryKey failed with %xh.", status));
  93. DBGVERBOSE(("QuerySpecialFeature: posFlag is now: %xh.", parentFdoExt->posFlag));
  94. return status;
  95. }
  96. VOID InitializeSerEmulVariables(POSPDOEXT *pdoExt)
  97. {
  98. InitializeListHead(&pdoExt->pendingWaitIrpsList);
  99. pdoExt->baudRate = SERIAL_BAUD_115200;
  100. pdoExt->waitMask = 0;
  101. pdoExt->supportedBauds = SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200
  102. | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_9600
  103. | SERIAL_BAUD_19200 | SERIAL_BAUD_38400 | SERIAL_BAUD_57600
  104. | SERIAL_BAUD_115200;
  105. pdoExt->currentMask = 0;
  106. pdoExt->fakeRxSize = 100;
  107. pdoExt->fakeLineControl.WordLength = 8;
  108. pdoExt->fakeLineControl.Parity = NO_PARITY;
  109. pdoExt->fakeLineControl.StopBits = STOP_BITS_2;
  110. pdoExt->fakeModemStatus = SERIAL_MSR_DCD | SERIAL_MSR_RI
  111. | SERIAL_MSR_DSR | SERIAL_MSR_CTS;
  112. }
  113. NTSTATUS StatusPipe(POSPDOEXT *pdoExt, USBD_PIPE_HANDLE pipeHandle)
  114. {
  115. NTSTATUS status;
  116. #if STATUS_ENDPOINT
  117. UsbBuildInterruptOrBulkTransferRequest(&pdoExt->statusUrb,
  118. (USHORT) sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
  119. pipeHandle,
  120. (PVOID) &pdoExt->statusPacket,
  121. NULL,
  122. sizeof(pdoExt->statusPacket),
  123. USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN,
  124. NULL);
  125. #else
  126. UsbBuildGetDescriptorRequest(&pdoExt->statusUrb,
  127. (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  128. USB_DEVICE_DESCRIPTOR_TYPE,
  129. 0,
  130. 0,
  131. (PVOID) &pdoExt->dummyPacket,
  132. NULL,
  133. sizeof(pdoExt->dummyPacket),
  134. NULL);
  135. #endif
  136. IncrementPendingActionCount(pdoExt->parentFdoExt);
  137. status = SubmitUrb(pdoExt->parentFdoExt->topDevObj,
  138. &pdoExt->statusUrb,
  139. FALSE,
  140. StatusPipeCompletion,
  141. pdoExt);
  142. return status;
  143. }
  144. NTSTATUS StatusPipeCompletion(IN PDEVICE_OBJECT devObj, IN PIRP irp, IN PVOID context)
  145. {
  146. NTSTATUS status = irp->IoStatus.Status;
  147. POSPDOEXT *pdoExt = (POSPDOEXT *)context;
  148. if(NT_SUCCESS(status)) {
  149. UpdateMask(pdoExt);
  150. StatusPipe(pdoExt, pdoExt->statusEndpointInfo.pipeHandle);
  151. #if STATUS_ENDPOINT
  152. DBGVERBOSE(("Mask Updated and URB sent down to retrieve Status Packet"));
  153. #endif
  154. }
  155. IoFreeIrp(irp);
  156. DecrementPendingActionCount(pdoExt->parentFdoExt);
  157. return STATUS_MORE_PROCESSING_REQUIRED;
  158. }
  159. VOID UpdateMask(POSPDOEXT *pdoExt)
  160. {
  161. KIRQL oldIrql;
  162. PIRP irp;
  163. ULONG mask;
  164. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  165. /*
  166. * Modify the emulated variables based on statusPacket
  167. */
  168. #if STATUS_ENDPOINT
  169. /*
  170. * Fill in the values of DCTS, DDSR, TERI, DDCD by EX-ORing the current
  171. * modem bits CTS, DSR, RI and DCD with those at the STATUS Endpoint.
  172. */
  173. pdoExt->fakeModemStatus = (pdoExt->fakeModemStatus & ~MSR_DELTA_MASK) | (((pdoExt->fakeModemStatus ^ pdoExt->statusPacket) & MSR_GLOBAL_MSK) >> MSR_DELTA_SHFT);
  174. /*
  175. * Replace the bits for CTS, DSR, RI and DCD with those at the STATUS Endpoint.
  176. */
  177. pdoExt->fakeModemStatus = (pdoExt->fakeModemStatus & ~MSR_GLOBAL_MSK) | (pdoExt->statusPacket & MSR_GLOBAL_MSK);
  178. if(pdoExt->statusPacket & EMULSER_OE)
  179. pdoExt->fakeLineStatus |= SERIAL_LSR_OE;
  180. if(pdoExt->statusPacket & EMULSER_PE)
  181. pdoExt->fakeLineStatus |= SERIAL_LSR_PE;
  182. if(pdoExt->statusPacket & EMULSER_FE)
  183. pdoExt->fakeLineStatus |= SERIAL_LSR_FE;
  184. if(pdoExt->statusPacket & EMULSER_BI)
  185. pdoExt->fakeLineStatus |= SERIAL_LSR_BI;
  186. if(pdoExt->statusPacket & EMULSER_DTR)
  187. pdoExt->fakeDTRRTS |= SERIAL_DTR_STATE;
  188. if(pdoExt->statusPacket & EMULSER_RTS)
  189. pdoExt->fakeDTRRTS |= SERIAL_RTS_STATE;
  190. #endif
  191. if(pdoExt->waitMask) {
  192. if((pdoExt->waitMask & SERIAL_EV_CTS) && (pdoExt->fakeModemStatus & SERIAL_MSR_DCTS))
  193. pdoExt->currentMask |= SERIAL_EV_CTS;
  194. if((pdoExt->waitMask & SERIAL_EV_DSR) && (pdoExt->fakeModemStatus & SERIAL_MSR_DDSR))
  195. pdoExt->currentMask |= SERIAL_EV_DSR;
  196. if((pdoExt->waitMask & SERIAL_EV_RING) && (pdoExt->fakeModemStatus & SERIAL_MSR_TERI))
  197. pdoExt->currentMask |= SERIAL_EV_RING;
  198. if((pdoExt->waitMask & SERIAL_EV_RLSD) && (pdoExt->fakeModemStatus & SERIAL_MSR_DDCD))
  199. pdoExt->currentMask |= SERIAL_EV_RLSD;
  200. if((pdoExt->waitMask & SERIAL_EV_ERR) && (pdoExt->fakeLineStatus & (SERIAL_LSR_OE
  201. | SERIAL_LSR_PE | SERIAL_LSR_FE)))
  202. pdoExt->currentMask |= SERIAL_EV_ERR;
  203. if((pdoExt->waitMask & SERIAL_EV_BREAK) && (pdoExt->fakeLineStatus & SERIAL_LSR_BI))
  204. pdoExt->currentMask |= SERIAL_EV_BREAK;
  205. /*
  206. * These are required to be filled by the read and write pipes.
  207. * Currently, we return TRUE always.
  208. */
  209. if(pdoExt->waitMask & SERIAL_EV_RXCHAR)
  210. pdoExt->currentMask |= SERIAL_EV_RXCHAR;
  211. if(pdoExt->waitMask & SERIAL_EV_RXFLAG)
  212. pdoExt->currentMask |= SERIAL_EV_RXFLAG;
  213. if(pdoExt->waitMask & SERIAL_EV_TXEMPTY)
  214. pdoExt->currentMask |= SERIAL_EV_TXEMPTY;
  215. }
  216. mask = pdoExt->currentMask;
  217. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  218. if(mask) {
  219. CompletePendingWaitIrps(pdoExt, mask);
  220. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  221. pdoExt->currentMask = 0;
  222. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  223. }
  224. }
  225. VOID CompletePendingWaitIrps(POSPDOEXT *pdoExt, ULONG mask)
  226. {
  227. PIRP irp;
  228. while((irp = DequeueWaitIrp(pdoExt))) {
  229. irp->IoStatus.Information = sizeof(ULONG);
  230. irp->IoStatus.Status = STATUS_SUCCESS;
  231. *(PULONG)irp->AssociatedIrp.SystemBuffer = mask;
  232. IoCompleteRequest(irp, IO_NO_INCREMENT);
  233. }
  234. }
  235. NTSTATUS EnqueueWaitIrp(POSPDOEXT *pdoExt, PIRP irp)
  236. {
  237. PDRIVER_CANCEL oldCancelRoutine;
  238. NTSTATUS status = STATUS_PENDING;
  239. KIRQL oldIrql;
  240. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  241. if(IsListEmpty(&pdoExt->pendingWaitIrpsList))
  242. {
  243. InsertTailList(&pdoExt->pendingWaitIrpsList, &irp->Tail.Overlay.ListEntry);
  244. IoMarkIrpPending(irp);
  245. oldCancelRoutine = IoSetCancelRoutine(irp, WaitMaskCancelRoutine);
  246. ASSERT(!oldCancelRoutine);
  247. if (irp->Cancel) {
  248. oldCancelRoutine = IoSetCancelRoutine(irp, NULL);
  249. if (oldCancelRoutine) {
  250. RemoveEntryList(&irp->Tail.Overlay.ListEntry);
  251. status = irp->IoStatus.Status = STATUS_CANCELLED;
  252. }
  253. }
  254. }
  255. else
  256. status = irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  257. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  258. if (status != STATUS_PENDING)
  259. IoCompleteRequest(irp, IO_NO_INCREMENT);
  260. return status;
  261. }
  262. PIRP DequeueWaitIrp(POSPDOEXT *pdoExt)
  263. {
  264. PDRIVER_CANCEL oldCancelRoutine;
  265. PLIST_ENTRY listEntry;
  266. KIRQL oldIrql;
  267. PIRP nextIrp = NULL;
  268. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  269. while (!nextIrp && !IsListEmpty(&pdoExt->pendingWaitIrpsList)) {
  270. listEntry = RemoveHeadList(&pdoExt->pendingWaitIrpsList);
  271. nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  272. oldCancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
  273. if(oldCancelRoutine) {
  274. ASSERT(oldCancelRoutine == WaitMaskCancelRoutine);
  275. }
  276. else {
  277. ASSERT(nextIrp->Cancel);
  278. InitializeListHead(&nextIrp->Tail.Overlay.ListEntry);
  279. nextIrp = NULL;
  280. }
  281. }
  282. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  283. return nextIrp;
  284. }
  285. VOID WaitMaskCancelRoutine(PDEVICE_OBJECT devObj, PIRP irp)
  286. {
  287. DEVEXT *devExt;
  288. POSPDOEXT *pdoExt;
  289. KIRQL oldIrql;
  290. devExt = devObj->DeviceExtension;
  291. pdoExt = &devExt->pdoExt;
  292. IoReleaseCancelSpinLock(irp->CancelIrql);
  293. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  294. RemoveEntryList(&irp->Tail.Overlay.ListEntry);
  295. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  296. irp->IoStatus.Status = STATUS_CANCELLED;
  297. IoCompleteRequest(irp, IO_NO_INCREMENT);
  298. }