mouhid.sys: Request preparsed data and inspect device caps.
This commit is contained in:
parent
0ed830eac5
commit
a05b67b7e5
3 changed files with 120 additions and 2 deletions
|
@ -1906,7 +1906,6 @@ static void test_hid_touch_screen(void)
|
|||
.report_id = 1,
|
||||
.report_len = 2,
|
||||
.report_buf = {1,0x02},
|
||||
.todo = TRUE,
|
||||
};
|
||||
|
||||
RAWINPUTDEVICE rawdevice = {.usUsagePage = HID_USAGE_PAGE_DIGITIZER, .usUsage = HID_USAGE_DIGITIZER_TOUCH_SCREEN};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
MODULE = mouhid.sys
|
||||
IMPORTS = ntoskrnl
|
||||
IMPORTS = ntoskrnl hidparse
|
||||
EXTRADLLFLAGS = -Wl,--subsystem,native
|
||||
|
||||
SOURCES = \
|
||||
|
|
|
@ -42,6 +42,13 @@ struct device
|
|||
{
|
||||
LONG removed;
|
||||
DEVICE_OBJECT *bus_device;
|
||||
PHIDP_PREPARSED_DATA preparsed;
|
||||
|
||||
ULONG caps_count;
|
||||
ULONG contact_max;
|
||||
HIDP_VALUE_CAPS *id_caps;
|
||||
HIDP_VALUE_CAPS *x_caps;
|
||||
HIDP_VALUE_CAPS *y_caps;
|
||||
};
|
||||
|
||||
static inline struct device *impl_from_DEVICE_OBJECT( DEVICE_OBJECT *device )
|
||||
|
@ -49,6 +56,21 @@ static inline struct device *impl_from_DEVICE_OBJECT( DEVICE_OBJECT *device )
|
|||
return (struct device *)device->DeviceExtension;
|
||||
}
|
||||
|
||||
static inline LONG sign_extend( ULONG value, const HIDP_VALUE_CAPS *caps )
|
||||
{
|
||||
UINT sign = 1 << (caps->BitSize - 1);
|
||||
if (sign <= 1 || caps->LogicalMin >= 0) return value;
|
||||
return value - ((value & sign) << 1);
|
||||
}
|
||||
|
||||
static inline LONG scale_value( ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG max )
|
||||
{
|
||||
LONG tmp = sign_extend( value, caps );
|
||||
if (caps->LogicalMin > caps->LogicalMax) return 0;
|
||||
if (caps->LogicalMin > tmp || caps->LogicalMax < tmp) return 0;
|
||||
return min + MulDiv( tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin );
|
||||
}
|
||||
|
||||
static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp )
|
||||
{
|
||||
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
|
||||
|
@ -69,6 +91,98 @@ static NTSTATUS WINAPI driver_ioctl( DEVICE_OBJECT *device, IRP *irp )
|
|||
return IoCallDriver( impl->bus_device, irp );
|
||||
}
|
||||
|
||||
static NTSTATUS call_hid_device( DEVICE_OBJECT *device, DWORD major, DWORD code, void *in_buf,
|
||||
DWORD in_len, void *out_buf, DWORD out_len )
|
||||
{
|
||||
struct device *impl = impl_from_DEVICE_OBJECT( device );
|
||||
IO_STATUS_BLOCK io;
|
||||
NTSTATUS status;
|
||||
KEVENT event;
|
||||
IRP *irp;
|
||||
|
||||
KeInitializeEvent( &event, NotificationEvent, FALSE );
|
||||
irp = IoBuildDeviceIoControlRequest( code, device, in_buf, in_len, out_buf, out_len,
|
||||
FALSE, &event, &io );
|
||||
if (!irp) return STATUS_NO_MEMORY;
|
||||
|
||||
status = IoCallDriver( impl->bus_device, irp );
|
||||
if (status == STATUS_PENDING) KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
|
||||
return io.Status;
|
||||
}
|
||||
|
||||
static NTSTATUS initialize_device( DEVICE_OBJECT *device )
|
||||
{
|
||||
struct device *impl = impl_from_DEVICE_OBJECT( device );
|
||||
HID_COLLECTION_INFORMATION info;
|
||||
USHORT usage, count, report_len;
|
||||
HIDP_VALUE_CAPS value_caps;
|
||||
char *report_buf;
|
||||
NTSTATUS status;
|
||||
HIDP_CAPS caps;
|
||||
|
||||
if ((status = call_hid_device( device, IRP_MJ_DEVICE_CONTROL, IOCTL_HID_GET_COLLECTION_INFORMATION,
|
||||
&info, 0, &info, sizeof(info) )))
|
||||
return status;
|
||||
if (!(impl->preparsed = malloc( info.DescriptorSize ))) return STATUS_NO_MEMORY;
|
||||
if ((status = call_hid_device( device, IRP_MJ_DEVICE_CONTROL, IOCTL_HID_GET_COLLECTION_DESCRIPTOR,
|
||||
NULL, 0, impl->preparsed, info.DescriptorSize )))
|
||||
return status;
|
||||
|
||||
status = HidP_GetCaps( impl->preparsed, &caps );
|
||||
if (status != HIDP_STATUS_SUCCESS) return status;
|
||||
|
||||
count = 1;
|
||||
usage = HID_USAGE_DIGITIZER_CONTACT_COUNT_MAX;
|
||||
status = HidP_GetSpecificValueCaps( HidP_Feature, HID_USAGE_PAGE_DIGITIZER, 0, usage,
|
||||
&value_caps, &count, impl->preparsed );
|
||||
if (status == HIDP_STATUS_SUCCESS)
|
||||
{
|
||||
report_len = caps.FeatureReportByteLength;
|
||||
if (!(report_buf = malloc( report_len ))) return STATUS_NO_MEMORY;
|
||||
report_buf[0] = value_caps.ReportID;
|
||||
|
||||
status = call_hid_device( device, IRP_MJ_DEVICE_CONTROL, IOCTL_HID_GET_FEATURE, NULL, 0, report_buf, report_len );
|
||||
if (!status) status = HidP_GetUsageValue( HidP_Feature, HID_USAGE_PAGE_DIGITIZER, 0, usage,
|
||||
&impl->contact_max, impl->preparsed, report_buf, report_len );
|
||||
free( report_buf );
|
||||
if (status && status != HIDP_STATUS_SUCCESS) return status;
|
||||
|
||||
count = 1;
|
||||
usage = HID_USAGE_DIGITIZER_CONTACT_COUNT;
|
||||
status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_DIGITIZER, 0, usage,
|
||||
&value_caps, &count, impl->preparsed );
|
||||
if (status != HIDP_STATUS_SUCCESS) goto failed;
|
||||
|
||||
count = caps.NumberLinkCollectionNodes;
|
||||
usage = HID_USAGE_DIGITIZER_CONTACT_ID;
|
||||
if (!(impl->id_caps = malloc( sizeof(*impl->id_caps) * caps.NumberLinkCollectionNodes ))) return STATUS_NO_MEMORY;
|
||||
status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_DIGITIZER, 0, usage,
|
||||
impl->id_caps, &count, impl->preparsed );
|
||||
if (status != HIDP_STATUS_SUCCESS) goto failed;
|
||||
impl->caps_count = count;
|
||||
|
||||
count = impl->caps_count;
|
||||
usage = HID_USAGE_GENERIC_X;
|
||||
if (!(impl->x_caps = malloc( sizeof(*impl->x_caps) * impl->caps_count ))) return STATUS_NO_MEMORY;
|
||||
status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_GENERIC, 0, usage,
|
||||
impl->x_caps, &count, impl->preparsed );
|
||||
if (status != HIDP_STATUS_SUCCESS) goto failed;
|
||||
|
||||
count = impl->caps_count;
|
||||
usage = HID_USAGE_GENERIC_Y;
|
||||
if (!(impl->y_caps = malloc( sizeof(*impl->y_caps) * impl->caps_count ))) return STATUS_NO_MEMORY;
|
||||
status = HidP_GetSpecificValueCaps( HidP_Input, HID_USAGE_PAGE_GENERIC, 0, usage,
|
||||
impl->y_caps, &count, impl->preparsed );
|
||||
if (status != HIDP_STATUS_SUCCESS) goto failed;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
failed:
|
||||
ERR( "%#x usage not found, unsupported device\n", usage );
|
||||
return STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
static NTSTATUS WINAPI set_event_completion( DEVICE_OBJECT *device, IRP *irp, void *context )
|
||||
{
|
||||
if (irp->PendingReturned) KeSetEvent( (KEVENT *)context, IO_NO_INCREMENT, FALSE );
|
||||
|
@ -98,6 +212,7 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
|
|||
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
|
||||
status = irp->IoStatus.Status;
|
||||
}
|
||||
if (!status) status = initialize_device( device );
|
||||
|
||||
if (status) irp->IoStatus.Status = status;
|
||||
IoCompleteRequest( irp, IO_NO_INCREMENT );
|
||||
|
@ -111,6 +226,10 @@ static NTSTATUS WINAPI driver_pnp( DEVICE_OBJECT *device, IRP *irp )
|
|||
IoSkipCurrentIrpStackLocation( irp );
|
||||
status = IoCallDriver( impl->bus_device, irp );
|
||||
IoDetachDevice( impl->bus_device );
|
||||
free( impl->id_caps );
|
||||
free( impl->x_caps );
|
||||
free( impl->y_caps );
|
||||
free( impl->preparsed );
|
||||
IoDeleteDevice( device );
|
||||
return status;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue