*** empty log message ***
[reactos.git] / reactos / drivers / input / mouclass / mouclass.c
1 /*
2
3 ** Mouse class driver 0.0.1
4 ** Written by Jason Filby (jasonfilby@yahoo.com)
5 ** For ReactOS (www.reactos.com)
6
7 ** The class driver between win32k and the various mouse port drivers
8
9 ** TODO: Change interface to win32k to a callback instead of ReadFile IO
10 Add support for multiple port devices
11
12 */
13
14 #include <ddk/ntddk.h>
15 #include "..\include\mouse.h"
16 #include "mouclass.h"
17
18 BOOLEAN AlreadyOpened = FALSE;
19
20 VOID MouseClassCallBack(PDEVICE_OBJECT ClassDeviceObject, PMOUSE_INPUT_DATA MouseDataStart,
21 PMOUSE_INPUT_DATA MouseDataEnd, PULONG InputCount)
22 {
23 PDEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
24 PIRP Irp;
25 ULONG ReadSize;
26 PIO_STACK_LOCATION Stack;
27
28 if(ClassDeviceExtension->ReadIsPending == TRUE)
29 {
30 Irp = ClassDeviceObject->CurrentIrp;
31 ClassDeviceObject->CurrentIrp = NULL;
32 Stack = IoGetCurrentIrpStackLocation(Irp);
33
34 ReadSize = sizeof(MOUSE_INPUT_DATA) * (*InputCount);
35
36 // A read request is waiting for input, so go straight to it
37 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)MouseDataStart, ReadSize);
38
39 // Go to next packet and complete this request with STATUS_SUCCESS
40 Irp->IoStatus.Status = STATUS_SUCCESS;
41 Irp->IoStatus.Information = ReadSize;
42 Stack->Parameters.Read.Length = ReadSize;
43
44 IoStartNextPacket(ClassDeviceObject, FALSE);
45 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
46 ClassDeviceExtension->ReadIsPending = FALSE;
47 }
48 if(InputCount>0)
49 {
50 // FIXME: If we exceed the buffer, mouse data gets thrown away.. better solution?
51
52 if(ClassDeviceExtension->InputCount + *InputCount > MOUSE_BUFFER_SIZE)
53 {
54 ReadSize = MOUSE_BUFFER_SIZE - ClassDeviceExtension->InputCount;
55 } else {
56 ReadSize = *InputCount;
57 }
58
59 // Move the mouse input data from the port data queue to our class data queue
60 RtlMoveMemory(ClassDeviceExtension->PortData, (PCHAR)MouseDataStart,
61 sizeof(MOUSE_INPUT_DATA) * ReadSize);
62
63 // Move the pointer and counter up
64 ClassDeviceExtension->PortData += ReadSize;
65 ClassDeviceExtension->InputCount += ReadSize;
66 }
67 }
68
69 NTSTATUS ConnectMousePortDriver(PDEVICE_OBJECT ClassDeviceObject)
70 {
71 PDEVICE_OBJECT PortDeviceObject = NULL;
72 PFILE_OBJECT FileObject = NULL;
73 NTSTATUS status;
74 UNICODE_STRING PortName;
75 IO_STATUS_BLOCK ioStatus;
76 KEVENT event;
77 PIRP irp;
78 CLASS_INFORMATION ClassInformation;
79 PDEVICE_EXTENSION DeviceExtension = ClassDeviceObject->DeviceExtension;
80
81 // Get the port driver's DeviceObject
82 // FIXME: The name might change.. find a way to be more dynamic?
83
84 RtlInitUnicodeString(&PortName, L"\\Device\\Mouse");
85 status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
86
87 if(status != STATUS_SUCCESS)
88 {
89 DbgPrint("MOUCLASS: Could not connect to mouse port driver\n");
90 return status;
91 }
92
93 DeviceExtension->PortDeviceObject = PortDeviceObject;
94 DeviceExtension->PortData = ExAllocatePool(NonPagedPool, MOUSE_BUFFER_SIZE * sizeof(MOUSE_INPUT_DATA));
95 DeviceExtension->InputCount = 0;
96 DeviceExtension->ReadIsPending = FALSE;
97
98 // Connect our callback to the port driver
99
100 KeInitializeEvent(&event, NotificationEvent, FALSE);
101
102 ClassInformation.DeviceObject = ClassDeviceObject;
103 ClassInformation.CallBack = MouseClassCallBack;
104
105 irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_MOUSE_CONNECT,
106 PortDeviceObject, &ClassInformation, sizeof(CLASS_INFORMATION), NULL, 0, TRUE, &event, &ioStatus);
107
108 status = IoCallDriver(DeviceExtension->PortDeviceObject, irp);
109
110 if (status == STATUS_PENDING) {
111 KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
112 } else {
113 ioStatus.Status = status;
114 }
115
116 return ioStatus.Status;
117 }
118
119 NTSTATUS MouseClassDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
120 {
121 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
122 NTSTATUS Status;
123
124 switch (Stack->MajorFunction)
125 {
126 case IRP_MJ_CREATE:
127 if (AlreadyOpened == TRUE)
128 {
129 Status = STATUS_SUCCESS;
130 }
131 else
132 {
133 Status = STATUS_SUCCESS;
134 AlreadyOpened = TRUE;
135 }
136 break;
137
138 case IRP_MJ_CLOSE:
139 Status = STATUS_SUCCESS;
140 break;
141
142 case IRP_MJ_READ:
143
144 if (Stack->Parameters.Read.Length == 0) {
145 Status = STATUS_SUCCESS;
146 } else {
147 Status = STATUS_PENDING;
148 }
149 break;
150
151 default:
152 DbgPrint("NOT IMPLEMENTED\n");
153 Status = STATUS_NOT_IMPLEMENTED;
154 break;
155 }
156
157 Irp->IoStatus.Status = Status;
158 Irp->IoStatus.Information = 0;
159 if (Status==STATUS_PENDING)
160 {
161 IoMarkIrpPending(Irp);
162 IoStartPacket(DeviceObject, Irp, NULL, NULL);
163 } else {
164 IoCompleteRequest(Irp, IO_NO_INCREMENT);
165 }
166 return(Status);
167 }
168
169 VOID MouseClassStartIo(PDEVICE_OBJECT DeviceObject, PIRP Irp)
170 {
171 PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
172 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
173 ULONG ReadSize;
174
175 if(DeviceExtension->InputCount>0)
176 {
177 // FIXME: We should not send to much input data.. depends on the max buffer size of the win32k
178 ReadSize = DeviceExtension->InputCount * sizeof(MOUSE_INPUT_DATA);
179
180 // Bring the PortData back to base so that it can be copied
181 DeviceExtension->PortData -= DeviceExtension->InputCount;
182 DeviceExtension->InputCount = 0;
183 DeviceExtension->ReadIsPending = FALSE;
184
185 RtlMoveMemory(Irp->AssociatedIrp.SystemBuffer, (PCHAR)DeviceExtension->PortData, ReadSize);
186
187 // Go to next packet and complete this request with STATUS_SUCCESS
188 Irp->IoStatus.Status = STATUS_SUCCESS;
189
190 Irp->IoStatus.Information = ReadSize;
191 Stack->Parameters.Read.Length = ReadSize;
192
193 IoStartNextPacket(DeviceObject, FALSE);
194 IoCompleteRequest(Irp, IO_MOUSE_INCREMENT);
195 } else {
196 DeviceExtension->ReadIsPending = TRUE;
197 }
198 }
199
200 NTSTATUS STDCALL
201 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
202 {
203 PDEVICE_OBJECT DeviceObject;
204 UNICODE_STRING DeviceName;
205 UNICODE_STRING SymlinkName;
206
207 DbgPrint("Mouse Class Driver 0.0.1\n");
208
209 DriverObject->MajorFunction[IRP_MJ_CREATE] = MouseClassDispatch;
210 DriverObject->MajorFunction[IRP_MJ_CLOSE] = MouseClassDispatch;
211 DriverObject->MajorFunction[IRP_MJ_READ] = MouseClassDispatch;
212 DriverObject->DriverStartIo = MouseClassStartIo;
213
214 RtlInitUnicodeString(&DeviceName, L"\\Device\\MouseClass");
215 IoCreateDevice(DriverObject,
216 sizeof(DEVICE_EXTENSION),
217 &DeviceName,
218 FILE_DEVICE_MOUSE,
219 0,
220 TRUE,
221 &DeviceObject);
222 DeviceObject->Flags = DeviceObject->Flags | DO_BUFFERED_IO;
223
224 RtlInitUnicodeString(&SymlinkName, L"\\??\\MouseClass");
225 IoCreateSymbolicLink(&SymlinkName, &DeviceName);
226
227 return ConnectMousePortDriver(DeviceObject);
228 }