- Revert 44301
[reactos.git] / drivers / usb / nt4compat / usbdriver / mouse.c
1 /*
2 * PROJECT: ReactOS USB Drivers
3 * COPYRIGHT: GPL - See COPYING in the top level directory
4 * FILE: mouse.c
5 * PURPOSE: Generic USB mouse driver
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
7 */
8
9 #include "usbdriver.h"
10
11 BOOLEAN mouse_connect(PDEV_CONNECT_DATA dev_mgr, DEV_HANDLE dev_handle);
12 BOOLEAN mouse_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
13 BOOLEAN mouse_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
14 VOID mouse_irq(PURB purb, PVOID pcontext);
15 static NTSTATUS MouseCreateDevice(IN PDRIVER_OBJECT DriverObject, IN PMOUSE_DRVR_EXTENSION DriverExtension);
16
17 BOOLEAN
18 mouse_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
19 {
20 PMOUSE_DRVR_EXTENSION pdrvr_ext;
21
22 if (dev_mgr == NULL || pdriver == NULL)
23 return FALSE;
24
25 //init driver structure, no PNP table functions
26 pdriver->driver_desc.flags = USB_DRIVER_FLAG_IF_CAPABLE;
27 pdriver->driver_desc.vendor_id = 0xffff; // USB Vendor ID
28 pdriver->driver_desc.product_id = 0xffff; // USB Product ID.
29 pdriver->driver_desc.release_num = 0x100; // Release Number of Device
30
31 pdriver->driver_desc.config_val = 1; // Configuration Value
32 pdriver->driver_desc.if_num = 1; // Interface Number
33 pdriver->driver_desc.if_class = USB_CLASS_HID; // Interface Class
34 pdriver->driver_desc.if_sub_class = 1; // Interface SubClass
35 pdriver->driver_desc.if_protocol = 2; // Interface Protocol
36
37 pdriver->driver_desc.driver_name = "USB Mouse driver"; // Driver name for Name Registry
38 pdriver->driver_desc.dev_class = USB_CLASS_HID;
39 pdriver->driver_desc.dev_sub_class = 1; // Device Subclass
40 pdriver->driver_desc.dev_protocol = 2; // Protocol Info.
41
42 pdriver->driver_ext = usb_alloc_mem(NonPagedPool, sizeof(MOUSE_DRVR_EXTENSION));
43 if (!pdriver->driver_ext) return FALSE;
44
45 pdriver->driver_ext_size = sizeof(MOUSE_DRVR_EXTENSION);
46
47 RtlZeroMemory(pdriver->driver_ext, sizeof(MOUSE_DRVR_EXTENSION));
48 pdrvr_ext = (PMOUSE_DRVR_EXTENSION) pdriver->driver_ext;
49 pdrvr_ext->dev_mgr = dev_mgr;
50
51 pdriver->disp_tbl.version = 1;
52 pdriver->disp_tbl.dev_connect = mouse_connect;
53 pdriver->disp_tbl.dev_disconnect = mouse_disconnect;
54 pdriver->disp_tbl.dev_stop = mouse_stop;
55 pdriver->disp_tbl.dev_reserved = NULL;
56
57 // Create the device
58 MouseCreateDevice(dev_mgr->usb_driver_obj, pdrvr_ext);
59
60 usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_driver_init(): mouse driver is initialized\n"));
61 return TRUE;
62 }
63
64 BOOLEAN
65 mouse_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
66 {
67 //PMOUSE_DRVR_EXTENSION pdrvr_ext;
68 if (dev_mgr == NULL || pdriver == NULL)
69 return FALSE;
70
71 //pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdriver->driver_ext;
72 //umss_delete_port_device(pdrvr_ext->port_dev_obj);
73 //pdrvr_ext->port_dev_obj = NULL;
74
75 //ASSERT(IsListEmpty(&pdrvr_ext->dev_list) == TRUE);
76 usb_free_mem(pdriver->driver_ext);
77 pdriver->driver_ext = NULL;
78 pdriver->driver_ext_size = 0;
79 usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_driver_destroy(): mouse driver is destroyed\n"));
80 return TRUE;
81 }
82
83 BOOLEAN
84 mouse_connect(PDEV_CONNECT_DATA param, DEV_HANDLE dev_handle)
85 {
86 PURB purb;
87 NTSTATUS status;
88 PUSB_DEV_MANAGER dev_mgr;
89 PUSB_DRIVER pdrvr;
90 PUSB_DEV pdev;
91 PMOUSE_DRVR_EXTENSION pdev_ext;
92 // LONG i;
93 PUSB_ENDPOINT_DESC pendp_desc = NULL;
94 ULONG MaxPacketSize;
95
96 usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_connect(): entering...\n"));
97
98 dev_mgr = param->dev_mgr;
99 pdrvr = param->pdriver;
100 pdev_ext = (PMOUSE_DRVR_EXTENSION)pdrvr->driver_ext;
101
102 // Lock USB Device
103 status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
104 if (status != STATUS_SUCCESS)
105 {
106 //usb_free_mem(desc_buf);
107 usb_dbg_print(DBGLVL_MEDIUM, ("mouse_connect(): unable to query&lock device, status=0x%x\n", status));
108 return FALSE;
109 }
110
111 // Get pointer to the endpoint descriptor
112 pendp_desc = pdev->usb_config->interf[0].endp[0].pusb_endp_desc;
113
114 // Store max packet size
115 MaxPacketSize = pendp_desc->wMaxPacketSize;
116 if (MaxPacketSize > 8)
117 MaxPacketSize = 8;
118
119 // Unlock USB Device
120 usb_unlock_dev(pdev);
121
122 // Send URB
123 purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
124 if (purb == NULL)
125 return FALSE;
126 RtlZeroMemory(purb, sizeof(URB));
127
128 // Build a URB for our interrupt transfer
129 UsbBuildInterruptOrBulkTransferRequest(purb,
130 usb_make_handle((dev_handle >> 16), 0, 0),
131 (PUCHAR)&pdev_ext->mouse_data,
132 MaxPacketSize, //use max packet size
133 mouse_irq,
134 pdev_ext->device_ext,
135 0);
136
137 // Call USB driver stack
138 status = usb_submit_urb(pdev_ext->dev_mgr, purb);
139 if (status != STATUS_PENDING)
140 {
141 usb_free_mem(purb);
142 purb = NULL;
143 }
144
145 return TRUE;
146 }
147
148 VOID
149 mouse_irq(PURB purb, PVOID pcontext)
150 {
151 MOUSE_INPUT_DATA MouseInputData;
152 ULONG InputDataConsumed;
153 NTSTATUS status;
154 PMOUSE_DRVR_EXTENSION pdev_ext;
155 PMOUSE_DEVICE_EXTENSION DeviceExtension = (PMOUSE_DEVICE_EXTENSION)pcontext;
156 signed char *data;
157 usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_irq(): called\n"));
158
159 ASSERT(purb);
160
161 if (purb->status != STATUS_SUCCESS)
162 {
163 usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_irq(): purb->status 0x%08X\n", purb->status));
164 return;
165 }
166
167 pdev_ext = DeviceExtension->DriverExtension;
168 data = pdev_ext->mouse_data;
169
170 usb_dbg_print(DBGLVL_MAXIMUM, ("Mouse input: x %d, y %d, w %d, btn: 0x%02x\n", data[1], data[2], data[3], data[0]));
171
172 // Fill mouse input data structure
173 MouseInputData.Flags = MOUSE_MOVE_RELATIVE;
174 MouseInputData.LastX = data[1];
175 MouseInputData.LastY = data[2];
176
177 MouseInputData.ButtonFlags = 0;
178 MouseInputData.ButtonData = 0;
179
180 if ((data[0] & 0x01) && ((pdev_ext->btn_old & 0x01) != (data[0] & 0x01)))
181 MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
182 else if (!(data[0] & 0x01) && ((pdev_ext->btn_old & 0x01) != (data[0] & 0x01)))
183 MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
184
185 if ((data[0] & 0x02) && ((pdev_ext->btn_old & 0x02) != (data[0] & 0x02)))
186 MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
187 else if (!(data[0] & 0x02) && ((pdev_ext->btn_old & 0x02) != (data[0] & 0x02)))
188 MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
189
190 if ((data[0] & 0x04) && ((pdev_ext->btn_old & 0x04) != (data[0] & 0x04)))
191 MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
192 else if (!(data[0] & 0x04) && ((pdev_ext->btn_old & 0x04) != (data[0] & 0x04)))
193 MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
194
195 if ((data[0] & 0x08) && ((pdev_ext->btn_old & 0x08) != (data[0] & 0x08)))
196 MouseInputData.ButtonFlags |= MOUSE_BUTTON_4_DOWN;
197 else if (!(data[0] & 0x08) && ((pdev_ext->btn_old & 0x08) != (data[0] & 0x08)))
198 MouseInputData.ButtonFlags |= MOUSE_BUTTON_4_UP;
199
200 if ((data[0] & 0x10) && ((pdev_ext->btn_old & 0x10) != (data[0] & 0x10)))
201 MouseInputData.ButtonFlags |= MOUSE_BUTTON_5_DOWN;
202 else if (!(data[0] & 0x10) && ((pdev_ext->btn_old & 0x10) != (data[0] & 0x10)))
203 MouseInputData.ButtonFlags |= MOUSE_BUTTON_5_UP;
204
205 if (data[3])
206 {
207 MouseInputData.ButtonFlags |= MOUSE_WHEEL;
208 MouseInputData.ButtonData = data[3];
209 }
210
211 // Commit the input data somewhere...
212 if (DeviceExtension->ConnectData.ClassService)
213 {
214 KIRQL OldIrql;
215
216 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
217 (*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ConnectData.ClassService)(
218 DeviceExtension->ConnectData.ClassDeviceObject,
219 &MouseInputData,
220 (&MouseInputData)+1,
221 &InputDataConsumed);
222 KeLowerIrql(OldIrql);
223 }
224
225 // Save old button data
226 pdev_ext->btn_old = data[0];
227
228 // resubmit the urb
229 status = usb_submit_urb(pdev_ext->dev_mgr, purb);
230 }
231
232 BOOLEAN
233 mouse_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
234 {
235 UNREFERENCED_PARAMETER(dev_handle);
236 UNREFERENCED_PARAMETER(dev_mgr);
237 return TRUE;
238 }
239
240 BOOLEAN
241 mouse_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
242 {
243 PDEVICE_OBJECT dev_obj;
244 NTSTATUS status;
245 PUSB_DEV pdev;
246 PUSB_DRIVER pdrvr;
247
248 if (dev_mgr == NULL || dev_handle == 0)
249 return FALSE;
250
251 pdev = NULL;
252 //special use of the lock dev, simply use this routine to get the dev
253 status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
254 if (pdev == NULL)
255 {
256 return FALSE;
257 }
258 if (status == STATUS_SUCCESS)
259 {
260 // must be a bug
261 TRAP();
262 usb_unlock_dev(pdev);
263 }
264 pdrvr = pdev->dev_driver;
265 dev_obj = pdev->dev_obj;
266 pdev = NULL;
267
268 return TRUE;//umss_delete_device(dev_mgr, pdrvr, dev_obj, FALSE);
269 }
270
271 // Dispatch routine for our IRPs
272 NTSTATUS
273 MouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
274 {
275 NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
276 PMOUSE_DEVICE_EXTENSION DeviceExtension;
277
278 DeviceExtension = DeviceObject->DeviceExtension;
279
280 usb_dbg_print(DBGLVL_MAXIMUM, ("MouseDispatch(DO %p, code 0x%lx) called\n",
281 DeviceObject,
282 IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode));
283
284 if (DeviceObject == DeviceExtension->Fdo)
285 {
286 // it's mouse's IOCTL
287 PIO_STACK_LOCATION Stk;
288
289 Irp->IoStatus.Information = 0;
290 Stk = IoGetCurrentIrpStackLocation(Irp);
291
292 switch (Stk->Parameters.DeviceIoControl.IoControlCode)
293 {
294 case IOCTL_INTERNAL_MOUSE_CONNECT:
295 usb_dbg_print(DBGLVL_MAXIMUM, ("IOCTL_INTERNAL_MOUSE_CONNECT\n"));
296 if (Stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA)) {
297 usb_dbg_print(DBGLVL_MINIMUM, ("IOCTL_INTERNAL_MOUSE_CONNECT: "
298 "invalid buffer size\n"));
299 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
300 goto intcontfailure2;
301 }
302
303 RtlCopyMemory(&DeviceExtension->ConnectData,
304 Stk->Parameters.DeviceIoControl.Type3InputBuffer,
305 sizeof(CONNECT_DATA));
306
307 Irp->IoStatus.Status = STATUS_SUCCESS;
308 break;
309
310 default:
311 Irp->IoStatus.Status = STATUS_SUCCESS;//STATUS_INVALID_DEVICE_REQUEST;
312 break;
313 }
314 intcontfailure2:
315 Status = Irp->IoStatus.Status;
316 }
317
318 if (Status == STATUS_INVALID_DEVICE_REQUEST)
319 {
320 usb_dbg_print(DBGLVL_MINIMUM, ("Invalid internal device request!\n"));
321 }
322
323 if (Status != STATUS_PENDING)
324 IoCompleteRequest(Irp, IO_NO_INCREMENT);
325
326 return Status;
327 }
328
329 NTSTATUS
330 AddRegistryEntry(
331 IN PCWSTR PortTypeName,
332 IN PUNICODE_STRING DeviceName,
333 IN PCWSTR RegistryPath)
334 {
335 UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
336 OBJECT_ATTRIBUTES ObjectAttributes;
337 HANDLE hDeviceMapKey = (HANDLE)-1;
338 HANDLE hPortKey = (HANDLE)-1;
339 UNICODE_STRING PortTypeNameU;
340 NTSTATUS Status;
341
342 InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
343 Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
344 if (!NT_SUCCESS(Status))
345 {
346 usb_dbg_print(DBGLVL_MINIMUM, ("ZwOpenKey() failed with status 0x%08lx\n", Status));
347 goto cleanup;
348 }
349
350 RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
351 InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
352 Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
353 if (!NT_SUCCESS(Status))
354 {
355 usb_dbg_print(DBGLVL_MINIMUM, ("ZwCreateKey() failed with status 0x%08lx\n", Status));
356 goto cleanup;
357 }
358
359 Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, (ULONG)(wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL)));
360 if (!NT_SUCCESS(Status))
361 {
362 usb_dbg_print(DBGLVL_MINIMUM, ("ZwSetValueKey() failed with status 0x%08lx\n", Status));
363 goto cleanup;
364 }
365
366 Status = STATUS_SUCCESS;
367
368 cleanup:
369 if (hDeviceMapKey != (HANDLE)-1)
370 ZwClose(hDeviceMapKey);
371 if (hPortKey != (HANDLE)-1)
372 ZwClose(hPortKey);
373 return Status;
374 }
375
376 static NTSTATUS
377 MouseCreateDevice(IN PDRIVER_OBJECT DriverObject, IN PMOUSE_DRVR_EXTENSION DriverExtension)
378 {
379 UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerPortUSB");
380 PMOUSE_DEVICE_EXTENSION DeviceExtension;
381 PDEVICE_OBJECT Fdo;
382 NTSTATUS Status;
383
384 Status = AddRegistryEntry(L"PointerPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usbdriver");
385 if (!NT_SUCCESS(Status))
386 {
387 usb_dbg_print(DBGLVL_MINIMUM, ("AddRegistryEntry() for usb mouse driver failed with status 0x%08lx\n", Status));
388 return Status;
389 }
390
391 Status = IoCreateDevice(DriverObject,
392 sizeof(MOUSE_DEVICE_EXTENSION),
393 &DeviceName,
394 FILE_DEVICE_MOUSE,
395 FILE_DEVICE_SECURE_OPEN,
396 TRUE,
397 &Fdo);
398
399 if (!NT_SUCCESS(Status))
400 {
401 usb_dbg_print(DBGLVL_MINIMUM, ("IoCreateDevice() for usb mouse driver failed with status 0x%08lx\n", Status));
402 return Status;
403 }
404 DeviceExtension = (PMOUSE_DEVICE_EXTENSION)Fdo->DeviceExtension;
405 RtlZeroMemory(DeviceExtension, sizeof(MOUSE_DEVICE_EXTENSION));
406
407 DeviceExtension->hdr.dispatch = MouseDispatch;
408 DeviceExtension->DriverExtension = DriverExtension;
409 DriverExtension->device_ext = DeviceExtension;
410
411 DeviceExtension->Fdo = Fdo;
412 Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
413 usb_dbg_print(DBGLVL_MEDIUM, ("Created mouse Fdo: %p\n", Fdo));
414
415 return STATUS_SUCCESS;
416 }
417