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.

496 lines
17 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. ioctl.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 Ioctl(POSPDOEXT *pdoExt, PIRP irp)
  19. {
  20. NTSTATUS status = STATUS_SUCCESS;
  21. PIO_STACK_LOCATION irpSp;
  22. KIRQL oldIrql;
  23. irp->IoStatus.Information = 0;
  24. irpSp = IoGetCurrentIrpStackLocation(irp);
  25. /*
  26. * Private Ioctls for applications to be able to get the device's pretty name and attributes.
  27. */
  28. switch (irpSp->Parameters.DeviceIoControl.IoControlCode){
  29. case IOCTL_SERIAL_QUERY_DEVICE_NAME:
  30. return QueryDeviceName(pdoExt, irp);
  31. case IOCTL_SERIAL_QUERY_DEVICE_ATTR: {
  32. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
  33. return STATUS_BUFFER_TOO_SMALL;
  34. irp->IoStatus.Information = sizeof(ULONG);
  35. KeAcquireSpinLock(&pdoExt->parentFdoExt->devExtSpinLock, &oldIrql);
  36. *(PULONG)irp->AssociatedIrp.SystemBuffer = pdoExt->parentFdoExt->posFlag;
  37. KeReleaseSpinLock(&pdoExt->parentFdoExt->devExtSpinLock, oldIrql);
  38. return status;
  39. }
  40. }
  41. /*
  42. * The following Ioctl calls are ONLY for Serial Emulation.
  43. */
  44. if(!(pdoExt->parentFdoExt->posFlag & SERIAL_EMULATION)) {
  45. DBGVERBOSE(("Serial Emulation NOT supported by this device - Ioctl Rejected."));
  46. return STATUS_NOT_SUPPORTED;
  47. }
  48. switch (irpSp->Parameters.DeviceIoControl.IoControlCode){
  49. case IOCTL_SERIAL_GET_STATS: {
  50. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS)) {
  51. status = STATUS_BUFFER_TOO_SMALL;
  52. break;
  53. }
  54. irp->IoStatus.Information = sizeof(SERIALPERF_STATS);
  55. irp->IoStatus.Status = STATUS_SUCCESS;
  56. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  57. *(PSERIALPERF_STATS)irp->AssociatedIrp.SystemBuffer = pdoExt->fakePerfStats;
  58. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  59. break;
  60. }
  61. case IOCTL_SERIAL_CLEAR_STATS: {
  62. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  63. RtlZeroMemory(&pdoExt->fakePerfStats, sizeof(SERIALPERF_STATS));
  64. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  65. break;
  66. }
  67. case IOCTL_SERIAL_GET_PROPERTIES: {
  68. PSERIAL_COMMPROP properties = (PSERIAL_COMMPROP)irp->AssociatedIrp.SystemBuffer;
  69. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_COMMPROP)) {
  70. status = STATUS_BUFFER_TOO_SMALL;
  71. break;
  72. }
  73. irp->IoStatus.Information = sizeof(SERIAL_COMMPROP);
  74. irp->IoStatus.Status = STATUS_SUCCESS;
  75. RtlZeroMemory(properties, sizeof(SERIAL_COMMPROP));
  76. properties->PacketLength = sizeof(SERIAL_COMMPROP);
  77. properties->PacketVersion = 2;
  78. properties->ServiceMask = SERIAL_SP_SERIALCOMM;
  79. properties->MaxTxQueue = 0;
  80. properties->MaxRxQueue = 0;
  81. properties->MaxBaud = SERIAL_BAUD_115200;
  82. properties->SettableBaud = pdoExt->supportedBauds;
  83. properties->ProvSubType = SERIAL_SP_MODEM;
  84. properties->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS
  85. | SERIAL_PCF_SPECIALCHARS | SERIAL_PCF_PARITY_CHECK
  86. | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS;
  87. properties->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS
  88. | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY_CHECK
  89. | SERIAL_SP_CARRIER_DETECT;
  90. properties->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6
  91. | SERIAL_DATABITS_7 | SERIAL_DATABITS_8;
  92. properties->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20
  93. | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN
  94. | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE;
  95. properties->CurrentTxQueue = 0;
  96. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  97. properties->CurrentRxQueue = pdoExt->fakeRxSize;
  98. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  99. break;
  100. }
  101. case IOCTL_SERIAL_GET_MODEMSTATUS: {
  102. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
  103. status = STATUS_BUFFER_TOO_SMALL;
  104. break;
  105. }
  106. irp->IoStatus.Information = sizeof(ULONG);
  107. irp->IoStatus.Status = STATUS_SUCCESS;
  108. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  109. *(PULONG)irp->AssociatedIrp.SystemBuffer = pdoExt->fakeModemStatus;
  110. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  111. break;
  112. }
  113. case IOCTL_SERIAL_GET_COMMSTATUS: {
  114. PSERIAL_STATUS commStatus = (PSERIAL_STATUS)irp->AssociatedIrp.SystemBuffer;
  115. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) {
  116. status = STATUS_BUFFER_TOO_SMALL;
  117. break;
  118. }
  119. irp->IoStatus.Information = sizeof(SERIAL_STATUS);
  120. irp->IoStatus.Status = STATUS_SUCCESS;
  121. commStatus->Errors = 0;
  122. commStatus->HoldReasons = 0;
  123. commStatus->AmountInInQueue = 100;
  124. commStatus->AmountInOutQueue = 0;
  125. commStatus->EofReceived = FALSE;
  126. commStatus->WaitForImmediate = 0;
  127. break;
  128. }
  129. case IOCTL_SERIAL_RESET_DEVICE: {
  130. break;
  131. }
  132. case IOCTL_SERIAL_GET_BAUD_RATE: {
  133. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE)) {
  134. status = STATUS_BUFFER_TOO_SMALL;
  135. break;
  136. }
  137. irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);
  138. irp->IoStatus.Status = STATUS_SUCCESS;
  139. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  140. ((PSERIAL_BAUD_RATE)irp->AssociatedIrp.SystemBuffer)->BaudRate = pdoExt->baudRate;
  141. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  142. break;
  143. }
  144. case IOCTL_SERIAL_SET_BAUD_RATE: {
  145. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE)) {
  146. status = STATUS_BUFFER_TOO_SMALL;
  147. break;
  148. }
  149. irp->IoStatus.Status = STATUS_SUCCESS;
  150. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  151. pdoExt->baudRate = ((PSERIAL_BAUD_RATE)irp->AssociatedIrp.SystemBuffer)->BaudRate;
  152. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  153. break;
  154. }
  155. case IOCTL_SERIAL_GET_LINE_CONTROL: {
  156. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) {
  157. status = STATUS_BUFFER_TOO_SMALL;
  158. break;
  159. }
  160. irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL);
  161. irp->IoStatus.Status = STATUS_SUCCESS;
  162. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  163. *(PSERIAL_LINE_CONTROL)irp->AssociatedIrp.SystemBuffer = pdoExt->fakeLineControl;
  164. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  165. break;
  166. }
  167. case IOCTL_SERIAL_SET_LINE_CONTROL: {
  168. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) {
  169. status = STATUS_BUFFER_TOO_SMALL;
  170. break;
  171. }
  172. irp->IoStatus.Status = STATUS_SUCCESS;
  173. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  174. pdoExt->fakeLineControl = *(PSERIAL_LINE_CONTROL)irp->AssociatedIrp.SystemBuffer;
  175. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  176. break;
  177. }
  178. case IOCTL_SERIAL_GET_TIMEOUTS: {
  179. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS)) {
  180. status = STATUS_BUFFER_TOO_SMALL;
  181. break;
  182. }
  183. irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS);
  184. irp->IoStatus.Status = STATUS_SUCCESS;
  185. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  186. *(PSERIAL_TIMEOUTS)irp->AssociatedIrp.SystemBuffer = pdoExt->fakeTimeouts;
  187. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  188. break;
  189. }
  190. case IOCTL_SERIAL_SET_TIMEOUTS: {
  191. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS)) {
  192. status = STATUS_BUFFER_TOO_SMALL;
  193. break;
  194. }
  195. irp->IoStatus.Status = STATUS_SUCCESS;
  196. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  197. pdoExt->fakeTimeouts = *(PSERIAL_TIMEOUTS)irp->AssociatedIrp.SystemBuffer;
  198. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  199. break;
  200. }
  201. case IOCTL_SERIAL_SET_DTR: {
  202. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  203. pdoExt->fakeDTRRTS |= SERIAL_DTR_STATE;
  204. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  205. break;
  206. }
  207. case IOCTL_SERIAL_CLR_DTR: {
  208. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  209. pdoExt->fakeDTRRTS &= ~SERIAL_DTR_STATE;
  210. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  211. break;
  212. }
  213. case IOCTL_SERIAL_SET_RTS: {
  214. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  215. pdoExt->fakeDTRRTS |= SERIAL_RTS_STATE;
  216. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  217. break;
  218. }
  219. case IOCTL_SERIAL_CLR_RTS: {
  220. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  221. pdoExt->fakeDTRRTS &= ~SERIAL_RTS_STATE;
  222. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  223. break;
  224. }
  225. case IOCTL_SERIAL_GET_DTRRTS: {
  226. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
  227. status = STATUS_BUFFER_TOO_SMALL;
  228. break;
  229. }
  230. irp->IoStatus.Information = sizeof(ULONG);
  231. irp->IoStatus.Status = STATUS_SUCCESS;
  232. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  233. *(PULONG)irp->AssociatedIrp.SystemBuffer = pdoExt->fakeDTRRTS;
  234. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  235. break;
  236. }
  237. case IOCTL_SERIAL_GET_WAIT_MASK: {
  238. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
  239. status = STATUS_BUFFER_TOO_SMALL;
  240. break;
  241. }
  242. irp->IoStatus.Information = sizeof(ULONG);
  243. irp->IoStatus.Status = STATUS_SUCCESS;
  244. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  245. *(PULONG)irp->AssociatedIrp.SystemBuffer = pdoExt->waitMask;
  246. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  247. break;
  248. }
  249. case IOCTL_SERIAL_SET_WAIT_MASK: {
  250. ULONG mask = *(PULONG)irp->AssociatedIrp.SystemBuffer;
  251. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) {
  252. status = STATUS_BUFFER_TOO_SMALL;
  253. break;
  254. }
  255. if (mask & ~(SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS
  256. | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR
  257. | SERIAL_EV_RING | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1
  258. | SERIAL_EV_EVENT2)) {
  259. status = STATUS_INVALID_PARAMETER;
  260. break;
  261. }
  262. CompletePendingWaitIrps(pdoExt, 0);
  263. irp->IoStatus.Status = STATUS_SUCCESS;
  264. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  265. pdoExt->waitMask = mask;
  266. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  267. break;
  268. }
  269. case IOCTL_SERIAL_WAIT_ON_MASK: {
  270. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
  271. status = STATUS_BUFFER_TOO_SMALL;
  272. break;
  273. }
  274. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  275. if(pdoExt->currentMask || !pdoExt->waitMask) {
  276. irp->IoStatus.Information = sizeof(ULONG);
  277. irp->IoStatus.Status = STATUS_SUCCESS;
  278. *(PULONG)irp->AssociatedIrp.SystemBuffer = pdoExt->currentMask;
  279. pdoExt->currentMask = 0;
  280. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  281. return status;
  282. }
  283. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  284. status = EnqueueWaitIrp(pdoExt, irp);
  285. break;
  286. }
  287. case IOCTL_SERIAL_GET_CHARS: {
  288. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS)) {
  289. status = STATUS_BUFFER_TOO_SMALL;
  290. break;
  291. }
  292. irp->IoStatus.Information = sizeof(SERIAL_CHARS);
  293. irp->IoStatus.Status = STATUS_SUCCESS;
  294. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  295. *(PSERIAL_CHARS)irp->AssociatedIrp.SystemBuffer = pdoExt->specialChars;
  296. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  297. break;
  298. }
  299. case IOCTL_SERIAL_SET_CHARS: {
  300. if (irpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS)) {
  301. status = STATUS_BUFFER_TOO_SMALL;
  302. break;
  303. }
  304. irp->IoStatus.Status = STATUS_SUCCESS;
  305. KeAcquireSpinLock(&pdoExt->devExtSpinLock, &oldIrql);
  306. pdoExt->specialChars = *(PSERIAL_CHARS)irp->AssociatedIrp.SystemBuffer;
  307. KeReleaseSpinLock(&pdoExt->devExtSpinLock, oldIrql);
  308. break;
  309. }
  310. default:
  311. DBGVERBOSE(("Ioctl: ??? (%xh)", (ULONG)irpSp->Parameters.DeviceIoControl.IoControlCode));
  312. status = irp->IoStatus.Status;
  313. break;
  314. }
  315. return status;
  316. }
  317. NTSTATUS QueryDeviceName(POSPDOEXT *pdoExt, PIRP irp)
  318. {
  319. NTSTATUS status;
  320. PIO_STACK_LOCATION irpSp;
  321. HANDLE hRegDevice;
  322. irp->IoStatus.Information = 0;
  323. irpSp = IoGetCurrentIrpStackLocation(irp);
  324. status = IoOpenDeviceRegistryKey(pdoExt->parentFdoExt->physicalDevObj,
  325. PLUGPLAY_REGKEY_DRIVER,
  326. KEY_READ,
  327. &hRegDevice);
  328. if (NT_SUCCESS(status)) {
  329. UNICODE_STRING keyName;
  330. PKEY_VALUE_FULL_INFORMATION keyValueInfo;
  331. ULONG keyValueTotalSize, actualLength;
  332. PWCHAR valueData;
  333. WCHAR deviceKeyName[] = L"DriverDesc";
  334. RtlInitUnicodeString(&keyName, deviceKeyName);
  335. keyValueTotalSize = sizeof(KEY_VALUE_FULL_INFORMATION) + (keyName.Length + MAX_BUFFER)*sizeof(WCHAR);
  336. keyValueInfo = ALLOCPOOL(PagedPool, keyValueTotalSize);
  337. if (keyValueInfo) {
  338. status = ZwQueryValueKey(hRegDevice,
  339. &keyName,
  340. KeyValueFullInformation,
  341. keyValueInfo,
  342. keyValueTotalSize,
  343. &actualLength);
  344. if (NT_SUCCESS(status)) {
  345. ASSERT(keyValueInfo->Type == REG_SZ);
  346. valueData = (PWCHAR)((PCHAR)keyValueInfo + keyValueInfo->DataOffset);
  347. DBGVERBOSE(("Device Name is of Length: %xh.", keyValueInfo->DataLength));
  348. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength < keyValueInfo->DataLength)
  349. status = STATUS_BUFFER_TOO_SMALL;
  350. else {
  351. irp->IoStatus.Information = keyValueInfo->DataLength;
  352. wcscpy((PWCHAR)irp->AssociatedIrp.SystemBuffer, valueData);
  353. }
  354. }
  355. else
  356. DBGVERBOSE(("QueryDeviceName: Device Name not found. ZwQueryValueKey failed with %xh.", status));
  357. FREEPOOL(keyValueInfo);
  358. }
  359. else
  360. ASSERT(keyValueInfo);
  361. ZwClose(hRegDevice);
  362. }
  363. else
  364. DBGERR(("QueryDeviceName: IoOpenDeviceRegistryKey failed with %xh.", status));
  365. return status;
  366. }