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.

479 lines
12 KiB

  1. /*++
  2. Copyright (c) 1990-1998 Microsoft Corporation, All Rights Reserved
  3. Copyright (c) 1993 Logitech Inc.
  4. Module Name:
  5. sermcmn.c
  6. Abstract:
  7. The common portions of the Microsoft serial (i8250) mouse port driver.
  8. This file should not require modification to support new mice
  9. that are similar to the serial mouse.
  10. Environment:
  11. Kernel mode only.
  12. Notes:
  13. NOTES: (Future/outstanding issues)
  14. - Powerfail not implemented.
  15. - IOCTL_INTERNAL_MOUSE_DISCONNECT has not been implemented. It's not
  16. needed until the class unload routine is implemented. Right now,
  17. we don't want to allow the mouse class driver to unload.
  18. - Consolidate duplicate code, where possible and appropriate.
  19. Revision History:
  20. --*/
  21. #include "stdarg.h"
  22. #include "stdio.h"
  23. #include "string.h"
  24. #include "ntddk.h"
  25. #include "mouser.h"
  26. #include "sermlog.h"
  27. #include "debug.h"
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, SerialMouseCreate)
  30. #pragma alloc_text(PAGE, SerialMouseClose)
  31. #endif
  32. NTSTATUS
  33. SerialMouseFlush(
  34. IN PDEVICE_OBJECT DeviceObject,
  35. IN PIRP Irp
  36. )
  37. {
  38. PDEVICE_EXTENSION deviceExtension;
  39. NTSTATUS status;
  40. //
  41. // Get a pointer to the device extension.
  42. //
  43. deviceExtension = DeviceObject->DeviceExtension;
  44. Print(deviceExtension, DBG_UART_INFO, ("Flush \n"));
  45. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  46. if (!NT_SUCCESS(status)) {
  47. return status;
  48. }
  49. //
  50. // Fire and forget
  51. //
  52. IoSkipCurrentIrpStackLocation(Irp);
  53. status = IoCallDriver(deviceExtension->TopOfStack, Irp);
  54. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  55. return status;
  56. }
  57. NTSTATUS
  58. SerialMouseInternalDeviceControl(
  59. IN PDEVICE_OBJECT DeviceObject,
  60. IN PIRP Irp
  61. )
  62. /*++
  63. Routine Description:
  64. This routine is the dispatch routine for internal device control requests.
  65. Arguments:
  66. DeviceObject - Pointer to the device object.
  67. Irp - Pointer to the request packet.
  68. Return Value:
  69. Status is returned.
  70. --*/
  71. {
  72. PIO_STACK_LOCATION irpSp;
  73. PDEVICE_EXTENSION deviceExtension;
  74. NTSTATUS status;
  75. //
  76. // Get a pointer to the device extension.
  77. //
  78. deviceExtension = DeviceObject->DeviceExtension;
  79. Print(deviceExtension, DBG_IOCTL_TRACE, ("IOCTL, enter\n"));
  80. //
  81. // Initialize the returned Information field.
  82. //
  83. Irp->IoStatus.Information = 0;
  84. //
  85. // Get a pointer to the current parameters for this request. The
  86. // information is contained in the current stack location.
  87. //
  88. irpSp = IoGetCurrentIrpStackLocation(Irp);
  89. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  90. if (!NT_SUCCESS(status)) {
  91. Irp->IoStatus.Status = status;
  92. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  93. return status;
  94. }
  95. ASSERT (deviceExtension->Started ||
  96. (IOCTL_INTERNAL_MOUSE_CONNECT ==
  97. irpSp->Parameters.DeviceIoControl.IoControlCode));
  98. //
  99. // Case on the device control subfunction that is being performed by the
  100. // requestor.
  101. //
  102. switch (irpSp->Parameters.DeviceIoControl.IoControlCode) {
  103. //
  104. // Connect a mouse class device driver to the port driver.
  105. //
  106. case IOCTL_INTERNAL_MOUSE_CONNECT:
  107. Print(deviceExtension, DBG_IOCTL_INFO, ("connect\n"));
  108. //
  109. // Only allow one connection.
  110. //
  111. if (deviceExtension->ConnectData.ClassService != NULL) {
  112. Print(deviceExtension, DBG_IOCTL_ERROR, ("error - already connected\n"));
  113. status = STATUS_SHARING_VIOLATION;
  114. break;
  115. }
  116. else if (irpSp->Parameters.DeviceIoControl.InputBufferLength <
  117. sizeof(CONNECT_DATA)) {
  118. Print(deviceExtension, DBG_IOCTL_ERROR,
  119. ("connect error - invalid buffer length\n"));
  120. status = STATUS_INVALID_PARAMETER;
  121. break;
  122. }
  123. //
  124. // Copy the connection parameters to the device extension.
  125. //
  126. deviceExtension->ConnectData =
  127. *((PCONNECT_DATA) (irpSp->Parameters.DeviceIoControl.Type3InputBuffer));
  128. status = STATUS_SUCCESS;
  129. break;
  130. //
  131. // Disconnect a mouse class device driver from the port driver.
  132. //
  133. // NOTE: Not implemented.
  134. //
  135. case IOCTL_INTERNAL_MOUSE_DISCONNECT:
  136. Print(deviceExtension, DBG_IOCTL_INFO, ("disconnect\n"));
  137. TRAP();
  138. //
  139. // Not implemented.
  140. //
  141. // To implement, code the following:
  142. // ---------------------------------
  143. // o ENSURE that we are NOT enabled (extension->EnableCount);
  144. // o If we are, then (a) return STATUS_UNSUCCESSFUL, or
  145. // (b) disable all devices immediately; see
  146. // DISABLE IOCTL call for necessary code.
  147. // o SYNCHRONIZE with the mouse read completion routine (must
  148. // protect the callback pointer from being dereferenced when
  149. // it becomes null). Note that no mechanism currently exists
  150. // for this.
  151. // o CLEAR the connection parameters in the device extension;
  152. // ie. extension->ConnectData = { 0, 0 }
  153. // o RELEASE the synchronizing lock.
  154. // o RETURN STATUS_SUCCESS.
  155. //
  156. //
  157. // Clear the connection parameters in the device extension.
  158. // NOTE: Must synchronize this with the mouse ISR.
  159. //
  160. //
  161. //deviceExtension->ConnectData.ClassDeviceObject =
  162. // Null;
  163. //deviceExtension->ConnectData.ClassService =
  164. // Null;
  165. //
  166. // Set the completion status.
  167. //
  168. status = STATUS_NOT_IMPLEMENTED;
  169. break;
  170. case IOCTL_INTERNAL_MOUSE_ENABLE:
  171. //
  172. // Enable interrupts
  173. //
  174. Print (deviceExtension, DBG_IOCTL_ERROR,
  175. ("ERROR: PnP => use create not enable! \n"));
  176. status = STATUS_NOT_SUPPORTED;
  177. break;
  178. case IOCTL_INTERNAL_MOUSE_DISABLE:
  179. //
  180. // Disable Mouse interrupts
  181. //
  182. Print(deviceExtension, DBG_IOCTL_ERROR,
  183. ("ERROR: PnP => use close not Disable! \n"));
  184. status = STATUS_NOT_SUPPORTED;
  185. break;
  186. //
  187. // Query the mouse attributes. First check for adequate buffer
  188. // length. Then, copy the mouse attributes from the device
  189. // extension to the output buffer.
  190. //
  191. case IOCTL_MOUSE_QUERY_ATTRIBUTES:
  192. Print(deviceExtension, DBG_IOCTL_INFO, ("query attributes\n"));
  193. if (irpSp->Parameters.DeviceIoControl.OutputBufferLength <
  194. sizeof(MOUSE_ATTRIBUTES)) {
  195. Print(deviceExtension, DBG_IOCTL_ERROR, ("QA buffer too small\n"));
  196. status = STATUS_BUFFER_TOO_SMALL;
  197. }
  198. else {
  199. //
  200. // Copy the attributes from the DeviceExtension to the
  201. // buffer.
  202. //
  203. *(PMOUSE_ATTRIBUTES) Irp->AssociatedIrp.SystemBuffer =
  204. deviceExtension->MouseAttributes;
  205. Irp->IoStatus.Information = sizeof(MOUSE_ATTRIBUTES);
  206. status = STATUS_SUCCESS;
  207. }
  208. break;
  209. default:
  210. Print (deviceExtension, DBG_IOCTL_ERROR,
  211. ("ERROR: unknown IOCTL: 0x%x \n",
  212. irpSp->Parameters.DeviceIoControl.IoControlCode));
  213. TRAP();
  214. status = STATUS_INVALID_DEVICE_REQUEST;
  215. break;
  216. }
  217. Irp->IoStatus.Status = status;
  218. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  219. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  220. Print(deviceExtension, DBG_IOCTL_TRACE, ("IOCTL, exit (%x)\n", status));
  221. return status;
  222. }
  223. NTSTATUS
  224. SerialMouseClose(
  225. IN PDEVICE_OBJECT DeviceObject,
  226. IN PIRP Irp
  227. )
  228. {
  229. PDEVICE_EXTENSION deviceExtension;
  230. NTSTATUS status;
  231. PAGED_CODE();
  232. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  233. Print(deviceExtension, DBG_CC_NOISE,
  234. ("Close: enable count is %d\n", deviceExtension->EnableCount));
  235. ASSERT(0 < deviceExtension->EnableCount);
  236. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  237. if (!NT_SUCCESS(status)) {
  238. goto SerialMouseCloseReject;
  239. }
  240. //
  241. // Serial can only handle one create/close, all others fail. This is not
  242. // true for mice though. Only send the last close on to serial.
  243. //
  244. if (0 == InterlockedDecrement(&deviceExtension->EnableCount)) {
  245. Print(deviceExtension, DBG_PNP_INFO | DBG_CC_INFO,
  246. ("Cancelling and stopping detection for close\n"));
  247. //
  248. // Cleanup: cancel the read and stop detection
  249. //
  250. IoCancelIrp(deviceExtension->ReadIrp);
  251. SerialMouseStopDetection(deviceExtension);
  252. //
  253. // Restore the port to the state it was before we opened it
  254. //
  255. SerialMouseRestorePort(deviceExtension);
  256. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  257. IoSkipCurrentIrpStackLocation(Irp);
  258. return IoCallDriver(deviceExtension->TopOfStack, Irp);
  259. }
  260. else {
  261. Print(deviceExtension, DBG_CC_INFO,
  262. ("Close (%d)\n", deviceExtension->EnableCount));
  263. status = STATUS_SUCCESS;
  264. }
  265. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  266. SerialMouseCloseReject:
  267. Irp->IoStatus.Status = status;
  268. Irp->IoStatus.Information = 0;
  269. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  270. return status;
  271. }
  272. NTSTATUS
  273. SerialMouseCreate(
  274. IN PDEVICE_OBJECT DeviceObject,
  275. IN PIRP Irp
  276. )
  277. /*++
  278. Routine Description:
  279. This is the dispatch routine for create/open requests.
  280. These requests complete successfully.
  281. Arguments:
  282. DeviceObject - Pointer to the device object.
  283. Irp - Pointer to the request packet.
  284. Return Value:
  285. Status is returned.
  286. --*/
  287. {
  288. PIO_STACK_LOCATION irpSp = NULL;
  289. NTSTATUS status = STATUS_SUCCESS;
  290. PDEVICE_EXTENSION deviceExtension = NULL;
  291. deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
  292. Print(deviceExtension, DBG_CC_TRACE, ("Create: Enter.\n"));
  293. Print(deviceExtension, DBG_CC_NOISE,
  294. ("Create: enable count is %d\n"));
  295. //
  296. // Get a pointer to the current parameters for this request. The
  297. // information is contained in the current stack location.
  298. //
  299. irpSp = IoGetCurrentIrpStackLocation (Irp);
  300. //
  301. // Determine if request is trying to open a subdirectory of the
  302. // given device object. This is not allowed.
  303. //
  304. if (0 != irpSp->FileObject->FileName.Length) {
  305. Print(deviceExtension, DBG_CC_ERROR,
  306. ("ERROR: Create Access Denied.\n"));
  307. status = STATUS_ACCESS_DENIED;
  308. goto SerialMouseCreateReject;
  309. }
  310. status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
  311. if (!NT_SUCCESS(status)) {
  312. goto SerialMouseCreateReject;
  313. }
  314. if (NULL == deviceExtension->ConnectData.ClassService) {
  315. //
  316. // No Connection yet. How can we be enabled?
  317. //
  318. Print(deviceExtension, DBG_IOCTL_ERROR,
  319. ("ERROR: enable before connect!\n"));
  320. status = STATUS_UNSUCCESSFUL;
  321. }
  322. else if ( 1 == InterlockedIncrement(&deviceExtension->EnableCount)) {
  323. //
  324. // send it down the stack
  325. //
  326. status = SerialMouseSendIrpSynchronously(deviceExtension->TopOfStack,
  327. Irp,
  328. TRUE);
  329. if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) {
  330. //
  331. // Everything worked, start up the mouse.
  332. //
  333. status = SerialMouseStartDevice(deviceExtension, Irp, TRUE);
  334. }
  335. else {
  336. //
  337. // Create failed, decrement the enable count back to zero
  338. //
  339. InterlockedDecrement(&deviceExtension->EnableCount);
  340. }
  341. }
  342. else {
  343. //
  344. // Serial only handles one create/close. Don't send this one down the
  345. // stack, it will fail. The call to InterlockedIncrement above
  346. // correctly adjusts the count.
  347. //
  348. ASSERT (deviceExtension->EnableCount >= 1);
  349. status = STATUS_SUCCESS;
  350. }
  351. IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp);
  352. SerialMouseCreateReject:
  353. Irp->IoStatus.Status = status;
  354. Irp->IoStatus.Information = 0;
  355. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  356. Print(deviceExtension, DBG_CC_TRACE,
  357. ("SerialMouseCreate, 0x%x\n", status));
  358. return status;
  359. }