mirror of
https://github.com/reactos/reactos.git
synced 2025-01-11 16:51:06 +00:00
c424146e2c
svn path=/branches/cmake-bringup/; revision=48236
417 lines
14 KiB
C
417 lines
14 KiB
C
/*
|
|
* PROJECT: ReactOS USB Drivers
|
|
* COPYRIGHT: GPL - See COPYING in the top level directory
|
|
* FILE: mouse.c
|
|
* PURPOSE: Generic USB mouse driver
|
|
* PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
|
|
*/
|
|
|
|
#include "usbdriver.h"
|
|
|
|
BOOLEAN mouse_connect(PDEV_CONNECT_DATA dev_mgr, DEV_HANDLE dev_handle);
|
|
BOOLEAN mouse_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
|
|
BOOLEAN mouse_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle);
|
|
VOID mouse_irq(PURB purb, PVOID pcontext);
|
|
static NTSTATUS MouseCreateDevice(IN PDRIVER_OBJECT DriverObject, IN PMOUSE_DRVR_EXTENSION DriverExtension);
|
|
|
|
BOOLEAN
|
|
mouse_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
|
|
{
|
|
PMOUSE_DRVR_EXTENSION pdrvr_ext;
|
|
|
|
if (dev_mgr == NULL || pdriver == NULL)
|
|
return FALSE;
|
|
|
|
//init driver structure, no PNP table functions
|
|
pdriver->driver_desc.flags = USB_DRIVER_FLAG_IF_CAPABLE;
|
|
pdriver->driver_desc.vendor_id = 0xffff; // USB Vendor ID
|
|
pdriver->driver_desc.product_id = 0xffff; // USB Product ID.
|
|
pdriver->driver_desc.release_num = 0x100; // Release Number of Device
|
|
|
|
pdriver->driver_desc.config_val = 1; // Configuration Value
|
|
pdriver->driver_desc.if_num = 1; // Interface Number
|
|
pdriver->driver_desc.if_class = USB_CLASS_HID; // Interface Class
|
|
pdriver->driver_desc.if_sub_class = 1; // Interface SubClass
|
|
pdriver->driver_desc.if_protocol = 2; // Interface Protocol
|
|
|
|
pdriver->driver_desc.driver_name = "USB Mouse driver"; // Driver name for Name Registry
|
|
pdriver->driver_desc.dev_class = USB_CLASS_HID;
|
|
pdriver->driver_desc.dev_sub_class = 1; // Device Subclass
|
|
pdriver->driver_desc.dev_protocol = 2; // Protocol Info.
|
|
|
|
pdriver->driver_ext = usb_alloc_mem(NonPagedPool, sizeof(MOUSE_DRVR_EXTENSION));
|
|
if (!pdriver->driver_ext) return FALSE;
|
|
|
|
pdriver->driver_ext_size = sizeof(MOUSE_DRVR_EXTENSION);
|
|
|
|
RtlZeroMemory(pdriver->driver_ext, sizeof(MOUSE_DRVR_EXTENSION));
|
|
pdrvr_ext = (PMOUSE_DRVR_EXTENSION) pdriver->driver_ext;
|
|
pdrvr_ext->dev_mgr = dev_mgr;
|
|
|
|
pdriver->disp_tbl.version = 1;
|
|
pdriver->disp_tbl.dev_connect = mouse_connect;
|
|
pdriver->disp_tbl.dev_disconnect = mouse_disconnect;
|
|
pdriver->disp_tbl.dev_stop = mouse_stop;
|
|
pdriver->disp_tbl.dev_reserved = NULL;
|
|
|
|
// Create the device
|
|
MouseCreateDevice(dev_mgr->usb_driver_obj, pdrvr_ext);
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_driver_init(): mouse driver is initialized\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
mouse_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
|
|
{
|
|
//PMOUSE_DRVR_EXTENSION pdrvr_ext;
|
|
if (dev_mgr == NULL || pdriver == NULL)
|
|
return FALSE;
|
|
|
|
//pdrvr_ext = (PUMSS_DRVR_EXTENSION) pdriver->driver_ext;
|
|
//umss_delete_port_device(pdrvr_ext->port_dev_obj);
|
|
//pdrvr_ext->port_dev_obj = NULL;
|
|
|
|
//ASSERT(IsListEmpty(&pdrvr_ext->dev_list) == TRUE);
|
|
usb_free_mem(pdriver->driver_ext);
|
|
pdriver->driver_ext = NULL;
|
|
pdriver->driver_ext_size = 0;
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_driver_destroy(): mouse driver is destroyed\n"));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
mouse_connect(PDEV_CONNECT_DATA param, DEV_HANDLE dev_handle)
|
|
{
|
|
PURB purb;
|
|
NTSTATUS status;
|
|
PUSB_DEV_MANAGER dev_mgr;
|
|
PUSB_DRIVER pdrvr;
|
|
PUSB_DEV pdev;
|
|
PMOUSE_DRVR_EXTENSION pdev_ext;
|
|
// LONG i;
|
|
PUSB_ENDPOINT_DESC pendp_desc = NULL;
|
|
ULONG MaxPacketSize;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_connect(): entering...\n"));
|
|
|
|
dev_mgr = param->dev_mgr;
|
|
pdrvr = param->pdriver;
|
|
pdev_ext = (PMOUSE_DRVR_EXTENSION)pdrvr->driver_ext;
|
|
|
|
// Lock USB Device
|
|
status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
|
|
if (status != STATUS_SUCCESS)
|
|
{
|
|
//usb_free_mem(desc_buf);
|
|
usb_dbg_print(DBGLVL_MEDIUM, ("mouse_connect(): unable to query&lock device, status=0x%x\n", status));
|
|
return FALSE;
|
|
}
|
|
|
|
// Get pointer to the endpoint descriptor
|
|
pendp_desc = pdev->usb_config->interf[0].endp[0].pusb_endp_desc;
|
|
|
|
// Store max packet size
|
|
MaxPacketSize = pendp_desc->wMaxPacketSize;
|
|
if (MaxPacketSize > 8)
|
|
MaxPacketSize = 8;
|
|
|
|
// Unlock USB Device
|
|
usb_unlock_dev(pdev);
|
|
|
|
// Send URB
|
|
purb = usb_alloc_mem(NonPagedPool, sizeof(URB));
|
|
if (purb == NULL)
|
|
return FALSE;
|
|
RtlZeroMemory(purb, sizeof(URB));
|
|
|
|
// Build a URB for our interrupt transfer
|
|
UsbBuildInterruptOrBulkTransferRequest(purb,
|
|
usb_make_handle((dev_handle >> 16), 0, 0),
|
|
(PUCHAR)&pdev_ext->mouse_data,
|
|
MaxPacketSize, //use max packet size
|
|
mouse_irq,
|
|
pdev_ext->device_ext,
|
|
0);
|
|
|
|
// Call USB driver stack
|
|
status = usb_submit_urb(pdev_ext->dev_mgr, purb);
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
usb_free_mem(purb);
|
|
purb = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
mouse_irq(PURB purb, PVOID pcontext)
|
|
{
|
|
MOUSE_INPUT_DATA MouseInputData;
|
|
ULONG InputDataConsumed;
|
|
NTSTATUS status;
|
|
PMOUSE_DRVR_EXTENSION pdev_ext;
|
|
PMOUSE_DEVICE_EXTENSION DeviceExtension = (PMOUSE_DEVICE_EXTENSION)pcontext;
|
|
signed char *data;
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_irq(): called\n"));
|
|
|
|
ASSERT(purb);
|
|
|
|
if (purb->status != STATUS_SUCCESS)
|
|
{
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("mouse_irq(): purb->status 0x%08X\n", purb->status));
|
|
return;
|
|
}
|
|
|
|
pdev_ext = DeviceExtension->DriverExtension;
|
|
data = pdev_ext->mouse_data;
|
|
|
|
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]));
|
|
|
|
// Fill mouse input data structure
|
|
MouseInputData.Flags = MOUSE_MOVE_RELATIVE;
|
|
MouseInputData.LastX = data[1];
|
|
MouseInputData.LastY = data[2];
|
|
|
|
MouseInputData.ButtonFlags = 0;
|
|
MouseInputData.ButtonData = 0;
|
|
|
|
if ((data[0] & 0x01) && ((pdev_ext->btn_old & 0x01) != (data[0] & 0x01)))
|
|
MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_DOWN;
|
|
else if (!(data[0] & 0x01) && ((pdev_ext->btn_old & 0x01) != (data[0] & 0x01)))
|
|
MouseInputData.ButtonFlags |= MOUSE_LEFT_BUTTON_UP;
|
|
|
|
if ((data[0] & 0x02) && ((pdev_ext->btn_old & 0x02) != (data[0] & 0x02)))
|
|
MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_DOWN;
|
|
else if (!(data[0] & 0x02) && ((pdev_ext->btn_old & 0x02) != (data[0] & 0x02)))
|
|
MouseInputData.ButtonFlags |= MOUSE_RIGHT_BUTTON_UP;
|
|
|
|
if ((data[0] & 0x04) && ((pdev_ext->btn_old & 0x04) != (data[0] & 0x04)))
|
|
MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_DOWN;
|
|
else if (!(data[0] & 0x04) && ((pdev_ext->btn_old & 0x04) != (data[0] & 0x04)))
|
|
MouseInputData.ButtonFlags |= MOUSE_MIDDLE_BUTTON_UP;
|
|
|
|
if ((data[0] & 0x08) && ((pdev_ext->btn_old & 0x08) != (data[0] & 0x08)))
|
|
MouseInputData.ButtonFlags |= MOUSE_BUTTON_4_DOWN;
|
|
else if (!(data[0] & 0x08) && ((pdev_ext->btn_old & 0x08) != (data[0] & 0x08)))
|
|
MouseInputData.ButtonFlags |= MOUSE_BUTTON_4_UP;
|
|
|
|
if ((data[0] & 0x10) && ((pdev_ext->btn_old & 0x10) != (data[0] & 0x10)))
|
|
MouseInputData.ButtonFlags |= MOUSE_BUTTON_5_DOWN;
|
|
else if (!(data[0] & 0x10) && ((pdev_ext->btn_old & 0x10) != (data[0] & 0x10)))
|
|
MouseInputData.ButtonFlags |= MOUSE_BUTTON_5_UP;
|
|
|
|
if (data[3])
|
|
{
|
|
MouseInputData.ButtonFlags |= MOUSE_WHEEL;
|
|
MouseInputData.ButtonData = data[3];
|
|
}
|
|
|
|
// Commit the input data somewhere...
|
|
if (DeviceExtension->ConnectData.ClassService)
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
(*(PSERVICE_CALLBACK_ROUTINE)DeviceExtension->ConnectData.ClassService)(
|
|
DeviceExtension->ConnectData.ClassDeviceObject,
|
|
&MouseInputData,
|
|
(&MouseInputData)+1,
|
|
&InputDataConsumed);
|
|
KeLowerIrql(OldIrql);
|
|
}
|
|
|
|
// Save old button data
|
|
pdev_ext->btn_old = data[0];
|
|
|
|
// resubmit the urb
|
|
status = usb_submit_urb(pdev_ext->dev_mgr, purb);
|
|
}
|
|
|
|
BOOLEAN
|
|
mouse_stop(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
|
|
{
|
|
UNREFERENCED_PARAMETER(dev_handle);
|
|
UNREFERENCED_PARAMETER(dev_mgr);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
mouse_disconnect(PUSB_DEV_MANAGER dev_mgr, DEV_HANDLE dev_handle)
|
|
{
|
|
PDEVICE_OBJECT dev_obj;
|
|
NTSTATUS status;
|
|
PUSB_DEV pdev;
|
|
PUSB_DRIVER pdrvr;
|
|
|
|
if (dev_mgr == NULL || dev_handle == 0)
|
|
return FALSE;
|
|
|
|
pdev = NULL;
|
|
//special use of the lock dev, simply use this routine to get the dev
|
|
status = usb_query_and_lock_dev(dev_mgr, dev_handle, &pdev);
|
|
if (pdev == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (status == STATUS_SUCCESS)
|
|
{
|
|
// must be a bug
|
|
TRAP();
|
|
usb_unlock_dev(pdev);
|
|
}
|
|
pdrvr = pdev->dev_driver;
|
|
dev_obj = pdev->dev_obj;
|
|
pdev = NULL;
|
|
|
|
return TRUE;//umss_delete_device(dev_mgr, pdrvr, dev_obj, FALSE);
|
|
}
|
|
|
|
// Dispatch routine for our IRPs
|
|
NTSTATUS
|
|
MouseDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
|
|
{
|
|
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
PMOUSE_DEVICE_EXTENSION DeviceExtension;
|
|
|
|
DeviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("MouseDispatch(DO %p, code 0x%lx) called\n",
|
|
DeviceObject,
|
|
IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode));
|
|
|
|
if (DeviceObject == DeviceExtension->Fdo)
|
|
{
|
|
// it's mouse's IOCTL
|
|
PIO_STACK_LOCATION Stk;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
Stk = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch (Stk->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_INTERNAL_MOUSE_CONNECT:
|
|
usb_dbg_print(DBGLVL_MAXIMUM, ("IOCTL_INTERNAL_MOUSE_CONNECT\n"));
|
|
if (Stk->Parameters.DeviceIoControl.InputBufferLength < sizeof(CONNECT_DATA)) {
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("IOCTL_INTERNAL_MOUSE_CONNECT: "
|
|
"invalid buffer size\n"));
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
goto intcontfailure2;
|
|
}
|
|
|
|
RtlCopyMemory(&DeviceExtension->ConnectData,
|
|
Stk->Parameters.DeviceIoControl.Type3InputBuffer,
|
|
sizeof(CONNECT_DATA));
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;//STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
intcontfailure2:
|
|
Status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
if (Status == STATUS_INVALID_DEVICE_REQUEST)
|
|
{
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("Invalid internal device request!\n"));
|
|
}
|
|
|
|
if (Status != STATUS_PENDING)
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
AddRegistryEntry(
|
|
IN PCWSTR PortTypeName,
|
|
IN PUNICODE_STRING DeviceName,
|
|
IN PCWSTR RegistryPath)
|
|
{
|
|
UNICODE_STRING PathU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE hDeviceMapKey = (HANDLE)-1;
|
|
HANDLE hPortKey = (HANDLE)-1;
|
|
UNICODE_STRING PortTypeNameU;
|
|
NTSTATUS Status;
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes, &PathU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
|
|
Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("ZwOpenKey() failed with status 0x%08lx\n", Status));
|
|
goto cleanup;
|
|
}
|
|
|
|
RtlInitUnicodeString(&PortTypeNameU, PortTypeName);
|
|
InitializeObjectAttributes(&ObjectAttributes, &PortTypeNameU, OBJ_KERNEL_HANDLE, hDeviceMapKey, NULL);
|
|
Status = ZwCreateKey(&hPortKey, KEY_SET_VALUE, &ObjectAttributes, 0, NULL, REG_OPTION_VOLATILE, NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("ZwCreateKey() failed with status 0x%08lx\n", Status));
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = ZwSetValueKey(hPortKey, DeviceName, 0, REG_SZ, (PVOID)RegistryPath, (ULONG)(wcslen(RegistryPath) * sizeof(WCHAR) + sizeof(UNICODE_NULL)));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("ZwSetValueKey() failed with status 0x%08lx\n", Status));
|
|
goto cleanup;
|
|
}
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
cleanup:
|
|
if (hDeviceMapKey != (HANDLE)-1)
|
|
ZwClose(hDeviceMapKey);
|
|
if (hPortKey != (HANDLE)-1)
|
|
ZwClose(hPortKey);
|
|
return Status;
|
|
}
|
|
|
|
static NTSTATUS
|
|
MouseCreateDevice(IN PDRIVER_OBJECT DriverObject, IN PMOUSE_DRVR_EXTENSION DriverExtension)
|
|
{
|
|
UNICODE_STRING DeviceName = RTL_CONSTANT_STRING(L"\\Device\\PointerPortUSB");
|
|
PMOUSE_DEVICE_EXTENSION DeviceExtension;
|
|
PDEVICE_OBJECT Fdo;
|
|
NTSTATUS Status;
|
|
|
|
Status = AddRegistryEntry(L"PointerPort", &DeviceName, L"REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\usbdriver");
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("AddRegistryEntry() for usb mouse driver failed with status 0x%08lx\n", Status));
|
|
return Status;
|
|
}
|
|
|
|
Status = IoCreateDevice(DriverObject,
|
|
sizeof(MOUSE_DEVICE_EXTENSION),
|
|
&DeviceName,
|
|
FILE_DEVICE_MOUSE,
|
|
FILE_DEVICE_SECURE_OPEN,
|
|
TRUE,
|
|
&Fdo);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
usb_dbg_print(DBGLVL_MINIMUM, ("IoCreateDevice() for usb mouse driver failed with status 0x%08lx\n", Status));
|
|
return Status;
|
|
}
|
|
DeviceExtension = (PMOUSE_DEVICE_EXTENSION)Fdo->DeviceExtension;
|
|
RtlZeroMemory(DeviceExtension, sizeof(MOUSE_DEVICE_EXTENSION));
|
|
|
|
DeviceExtension->hdr.dispatch = MouseDispatch;
|
|
DeviceExtension->DriverExtension = DriverExtension;
|
|
DriverExtension->device_ext = DeviceExtension;
|
|
|
|
DeviceExtension->Fdo = Fdo;
|
|
Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
usb_dbg_print(DBGLVL_MEDIUM, ("Created mouse Fdo: %p\n", Fdo));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|