hidclass.sys: Remove old reports from WINE_HIDP_PREPARSED_DATA.
[wine.git] / dlls / hidclass.sys / device.c
blob1990142f9555cf3d7a076437500f63f538f1256a
1 /*
2 * HIDClass device functions
4 * Copyright (C) 2015 Aric Stewart
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
23 #include "hid.h"
24 #include "winreg.h"
25 #include "winuser.h"
27 #include "wine/debug.h"
28 #include "ddk/hidsdi.h"
29 #include "ddk/hidtypes.h"
30 #include "ddk/wdm.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(hid);
33 WINE_DECLARE_DEBUG_CHANNEL(hid_report);
35 IRP *pop_irp_from_queue(BASE_DEVICE_EXTENSION *ext)
37 LIST_ENTRY *entry;
38 KIRQL old_irql;
39 IRP *irp = NULL;
41 KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &old_irql);
43 while (!irp && (entry = RemoveHeadList(&ext->u.pdo.irp_queue)) != &ext->u.pdo.irp_queue)
45 irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
46 if (!IoSetCancelRoutine(irp, NULL))
48 /* cancel routine is already cleared, meaning that it was called. let it handle completion. */
49 InitializeListHead(&irp->Tail.Overlay.ListEntry);
50 irp = NULL;
54 KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql);
55 return irp;
58 static void WINAPI read_cancel_routine(DEVICE_OBJECT *device, IRP *irp)
60 BASE_DEVICE_EXTENSION *ext;
61 KIRQL old_irql;
63 TRACE("cancel %p IRP on device %p\n", irp, device);
65 ext = device->DeviceExtension;
67 IoReleaseCancelSpinLock(irp->CancelIrql);
69 KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &old_irql);
71 RemoveEntryList(&irp->Tail.Overlay.ListEntry);
73 KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql);
75 irp->IoStatus.Status = STATUS_CANCELLED;
76 irp->IoStatus.Information = 0;
77 IoCompleteRequest(irp, IO_NO_INCREMENT);
80 static void hid_device_send_input(DEVICE_OBJECT *device, HID_XFER_PACKET *packet)
82 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
83 RAWINPUT *rawinput;
84 ULONG data_size;
85 INPUT input;
87 data_size = offsetof(RAWINPUT, data.hid.bRawData) + packet->reportBufferLen;
89 if (!(rawinput = malloc(data_size)))
91 ERR("Failed to allocate rawinput data!\n");
92 return;
95 rawinput->header.dwType = RIM_TYPEHID;
96 rawinput->header.dwSize = data_size;
97 rawinput->header.hDevice = ULongToHandle(ext->u.pdo.rawinput_handle);
98 rawinput->header.wParam = RIM_INPUT;
99 rawinput->data.hid.dwCount = 1;
100 rawinput->data.hid.dwSizeHid = data_size - offsetof(RAWINPUT, data.hid.bRawData);
101 memcpy( rawinput->data.hid.bRawData, packet->reportBuffer, packet->reportBufferLen );
103 input.type = INPUT_HARDWARE;
104 input.hi.uMsg = WM_INPUT;
105 input.hi.wParamH = 0;
106 input.hi.wParamL = 0;
107 __wine_send_input(0, &input, rawinput);
109 free(rawinput);
112 static void HID_Device_processQueue(DEVICE_OBJECT *device)
114 IRP *irp;
115 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
116 UINT buffer_size = RingBuffer_GetBufferSize(ext->u.pdo.ring_buffer);
117 const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
118 HID_XFER_PACKET *packet;
120 packet = malloc(buffer_size);
122 while((irp = pop_irp_from_queue(ext)))
124 int ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
126 RingBuffer_Read(ext->u.pdo.ring_buffer, ptr, packet, &buffer_size);
127 if (buffer_size)
129 TRACE_(hid_report)("Processing Request (%i)\n",ptr);
130 memcpy( irp->AssociatedIrp.SystemBuffer, packet + 1, data->caps.InputReportByteLength );
131 irp->IoStatus.Information = packet->reportBufferLen;
132 irp->IoStatus.Status = STATUS_SUCCESS;
134 else
136 irp->IoStatus.Information = 0;
137 irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
139 IoCompleteRequest( irp, IO_NO_INCREMENT );
141 free(packet);
144 static DWORD CALLBACK hid_device_thread(void *args)
146 DEVICE_OBJECT *device = (DEVICE_OBJECT*)args;
147 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
148 const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
149 BYTE report_id = HID_INPUT_VALUE_CAPS( data )->report_id;
150 ULONG buffer_len = data->caps.InputReportByteLength;
151 IO_STATUS_BLOCK io;
152 HID_XFER_PACKET *packet;
153 BYTE *buffer;
154 DWORD rc;
156 packet = malloc( sizeof(*packet) + buffer_len );
157 buffer = (BYTE *)(packet + 1);
158 packet->reportBuffer = buffer;
160 if (ext->u.pdo.information.Polled)
162 while(1)
164 packet->reportId = buffer[0] = report_id;
165 packet->reportBufferLen = buffer_len;
167 if (!report_id)
169 packet->reportBuffer++;
170 packet->reportBufferLen--;
173 call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, packet,
174 sizeof(*packet), &io );
176 if (io.Status == STATUS_SUCCESS)
178 if (!report_id) io.Information++;
179 packet->reportId = buffer[0];
180 packet->reportBuffer = buffer;
181 packet->reportBufferLen = io.Information;
183 RingBuffer_Write(ext->u.pdo.ring_buffer, packet);
184 hid_device_send_input(device, packet);
185 HID_Device_processQueue(device);
188 rc = WaitForSingleObject(ext->u.pdo.halt_event,
189 ext->u.pdo.poll_interval ? ext->u.pdo.poll_interval : DEFAULT_POLL_INTERVAL);
191 if (rc == WAIT_OBJECT_0)
192 break;
193 else if (rc != WAIT_TIMEOUT)
194 ERR("Wait returned unexpected value %x\n",rc);
197 else
199 INT exit_now = FALSE;
201 while(1)
203 packet->reportId = buffer[0] = report_id;
204 packet->reportBufferLen = buffer_len;
206 if (!report_id)
208 packet->reportBuffer++;
209 packet->reportBufferLen--;
212 call_minidriver( IOCTL_HID_READ_REPORT, ext->u.pdo.parent_fdo, NULL, 0,
213 packet->reportBuffer, packet->reportBufferLen, &io );
215 rc = WaitForSingleObject(ext->u.pdo.halt_event, 0);
216 if (rc == WAIT_OBJECT_0)
217 exit_now = TRUE;
219 if (!exit_now && io.Status == STATUS_SUCCESS)
221 if (!report_id) io.Information++;
222 packet->reportId = buffer[0];
223 packet->reportBuffer = buffer;
224 packet->reportBufferLen = io.Information;
226 RingBuffer_Write(ext->u.pdo.ring_buffer, packet);
227 hid_device_send_input(device, packet);
228 HID_Device_processQueue(device);
231 if (exit_now)
232 break;
236 TRACE("Device thread exiting\n");
237 return 1;
240 void HID_StartDeviceThread(DEVICE_OBJECT *device)
242 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
243 ext->u.pdo.halt_event = CreateEventA(NULL, TRUE, FALSE, NULL);
244 ext->u.pdo.thread = CreateThread(NULL, 0, hid_device_thread, device, 0, NULL);
247 static void handle_IOCTL_HID_GET_COLLECTION_INFORMATION( IRP *irp, BASE_DEVICE_EXTENSION *ext )
249 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
250 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(HID_COLLECTION_INFORMATION))
252 irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
253 irp->IoStatus.Information = 0;
255 else
257 memcpy(irp->AssociatedIrp.SystemBuffer, &ext->u.pdo.information, sizeof(HID_COLLECTION_INFORMATION));
258 irp->IoStatus.Information = sizeof(HID_COLLECTION_INFORMATION);
259 irp->IoStatus.Status = STATUS_SUCCESS;
263 static void handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( IRP *irp, BASE_DEVICE_EXTENSION *ext )
265 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
266 const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
268 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < data->dwSize)
270 irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
271 irp->IoStatus.Information = 0;
273 else
275 memcpy(irp->UserBuffer, data, data->dwSize);
276 irp->IoStatus.Information = data->dwSize;
277 irp->IoStatus.Status = STATUS_SUCCESS;
281 static void handle_minidriver_string( BASE_DEVICE_EXTENSION *ext, IRP *irp, SHORT index )
283 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
284 WCHAR buffer[127];
285 ULONG InputBuffer;
287 InputBuffer = MAKELONG(index, 0);
289 call_minidriver( IOCTL_HID_GET_STRING, ext->u.pdo.parent_fdo, ULongToPtr( InputBuffer ),
290 sizeof(InputBuffer), buffer, sizeof(buffer), &irp->IoStatus );
292 if (irp->IoStatus.Status == STATUS_SUCCESS)
294 WCHAR *out_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);
295 int length = irpsp->Parameters.DeviceIoControl.OutputBufferLength/sizeof(WCHAR);
296 TRACE("got string %s from minidriver\n",debugstr_w(buffer));
297 lstrcpynW(out_buffer, buffer, length);
298 irp->IoStatus.Information = (lstrlenW(buffer)+1) * sizeof(WCHAR);
302 static void hid_device_xfer_report( BASE_DEVICE_EXTENSION *ext, ULONG code, IRP *irp )
304 WINE_HIDP_PREPARSED_DATA *preparsed = ext->u.pdo.preparsed_data;
305 IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
306 struct hid_value_caps *caps = NULL, *caps_end = NULL;
307 ULONG report_len = 0, buffer_len = 0;
308 HID_XFER_PACKET packet;
309 BYTE *buffer = NULL;
311 switch (code)
313 case IOCTL_HID_GET_FEATURE:
314 case IOCTL_HID_GET_INPUT_REPORT:
315 buffer_len = stack->Parameters.DeviceIoControl.OutputBufferLength;
316 buffer = MmGetSystemAddressForMdlSafe( irp->MdlAddress, NormalPagePriority );
317 break;
318 case IOCTL_HID_SET_FEATURE:
319 case IOCTL_HID_SET_OUTPUT_REPORT:
320 buffer_len = stack->Parameters.DeviceIoControl.InputBufferLength;
321 buffer = irp->AssociatedIrp.SystemBuffer;
322 break;
323 case IOCTL_HID_WRITE_REPORT:
324 buffer_len = stack->Parameters.Write.Length;
325 buffer = irp->AssociatedIrp.SystemBuffer;
326 break;
329 switch (code)
331 case IOCTL_HID_GET_INPUT_REPORT:
332 report_len = preparsed->caps.InputReportByteLength;
333 caps = HID_INPUT_VALUE_CAPS( preparsed );
334 caps_end = caps + preparsed->value_caps_count[HidP_Input];
335 break;
336 case IOCTL_HID_SET_OUTPUT_REPORT:
337 case IOCTL_HID_WRITE_REPORT:
338 report_len = preparsed->caps.OutputReportByteLength;
339 caps = HID_OUTPUT_VALUE_CAPS( preparsed );
340 caps_end = caps + preparsed->value_caps_count[HidP_Output];
341 break;
342 case IOCTL_HID_GET_FEATURE:
343 case IOCTL_HID_SET_FEATURE:
344 report_len = preparsed->caps.FeatureReportByteLength;
345 caps = HID_FEATURE_VALUE_CAPS( preparsed );
346 caps_end = caps + preparsed->value_caps_count[HidP_Feature];
347 break;
350 if (!buffer || !buffer_len)
352 irp->IoStatus.Status = STATUS_INVALID_USER_BUFFER;
353 return;
355 if (buffer_len < report_len)
357 irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
358 return;
361 for (; caps != caps_end; ++caps) if (!caps->report_id || caps->report_id == buffer[0]) break;
362 if (caps == caps_end)
364 irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
365 return;
368 packet.reportId = buffer[0];
369 packet.reportBuffer = buffer;
370 packet.reportBufferLen = buffer_len;
372 if (!caps->report_id)
374 packet.reportId = 0;
375 packet.reportBuffer++;
376 packet.reportBufferLen--;
379 switch (code)
381 case IOCTL_HID_GET_FEATURE:
382 case IOCTL_HID_GET_INPUT_REPORT:
383 call_minidriver( code, ext->u.pdo.parent_fdo, NULL, 0, &packet, sizeof(packet), &irp->IoStatus );
384 break;
385 case IOCTL_HID_SET_FEATURE:
386 case IOCTL_HID_SET_OUTPUT_REPORT:
387 case IOCTL_HID_WRITE_REPORT:
388 call_minidriver( code, ext->u.pdo.parent_fdo, NULL, sizeof(packet), &packet, 0, &irp->IoStatus );
389 if (code == IOCTL_HID_WRITE_REPORT && packet.reportId) irp->IoStatus.Information--;
390 break;
394 NTSTATUS WINAPI pdo_ioctl(DEVICE_OBJECT *device, IRP *irp)
396 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
397 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
398 NTSTATUS status;
399 BOOL removed;
400 ULONG code;
401 KIRQL irql;
403 irp->IoStatus.Information = 0;
405 TRACE("device %p ioctl(%x)\n", device, irpsp->Parameters.DeviceIoControl.IoControlCode);
407 KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
408 removed = ext->u.pdo.removed;
409 KeReleaseSpinLock(&ext->u.pdo.lock, irql);
411 if (removed)
413 irp->IoStatus.Status = STATUS_DELETE_PENDING;
414 IoCompleteRequest(irp, IO_NO_INCREMENT);
415 return STATUS_DELETE_PENDING;
418 switch ((code = irpsp->Parameters.DeviceIoControl.IoControlCode))
420 case IOCTL_HID_GET_POLL_FREQUENCY_MSEC:
421 TRACE("IOCTL_HID_GET_POLL_FREQUENCY_MSEC\n");
422 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
424 irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
425 irp->IoStatus.Information = 0;
426 break;
428 *(ULONG *)irp->AssociatedIrp.SystemBuffer = ext->u.pdo.poll_interval;
429 irp->IoStatus.Information = sizeof(ULONG);
430 irp->IoStatus.Status = STATUS_SUCCESS;
431 break;
432 case IOCTL_HID_SET_POLL_FREQUENCY_MSEC:
434 ULONG poll_interval;
435 TRACE("IOCTL_HID_SET_POLL_FREQUENCY_MSEC\n");
436 if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
438 irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
439 break;
441 poll_interval = *(ULONG *)irp->AssociatedIrp.SystemBuffer;
442 if (poll_interval <= MAX_POLL_INTERVAL_MSEC)
444 ext->u.pdo.poll_interval = poll_interval;
445 irp->IoStatus.Status = STATUS_SUCCESS;
447 else
448 irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
449 break;
451 case IOCTL_HID_GET_PRODUCT_STRING:
453 handle_minidriver_string( ext, irp, HID_STRING_ID_IPRODUCT );
454 break;
456 case IOCTL_HID_GET_SERIALNUMBER_STRING:
458 handle_minidriver_string( ext, irp, HID_STRING_ID_ISERIALNUMBER );
459 break;
461 case IOCTL_HID_GET_MANUFACTURER_STRING:
463 handle_minidriver_string( ext, irp, HID_STRING_ID_IMANUFACTURER );
464 break;
466 case IOCTL_HID_GET_COLLECTION_INFORMATION:
468 handle_IOCTL_HID_GET_COLLECTION_INFORMATION( irp, ext );
469 break;
471 case IOCTL_HID_GET_COLLECTION_DESCRIPTOR:
473 handle_IOCTL_HID_GET_COLLECTION_DESCRIPTOR( irp, ext );
474 break;
476 case IOCTL_SET_NUM_DEVICE_INPUT_BUFFERS:
478 irp->IoStatus.Information = 0;
480 if (irpsp->Parameters.DeviceIoControl.InputBufferLength != sizeof(ULONG))
481 irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
482 else
483 irp->IoStatus.Status = RingBuffer_SetSize( ext->u.pdo.ring_buffer, *(ULONG *)irp->AssociatedIrp.SystemBuffer );
484 break;
486 case IOCTL_GET_NUM_DEVICE_INPUT_BUFFERS:
488 if (irpsp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG))
490 irp->IoStatus.Information = 0;
491 irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
493 else
495 *(ULONG *)irp->AssociatedIrp.SystemBuffer = RingBuffer_GetSize(ext->u.pdo.ring_buffer);
496 irp->IoStatus.Information = sizeof(ULONG);
497 irp->IoStatus.Status = STATUS_SUCCESS;
499 break;
501 case IOCTL_HID_GET_FEATURE:
502 case IOCTL_HID_SET_FEATURE:
503 case IOCTL_HID_GET_INPUT_REPORT:
504 case IOCTL_HID_SET_OUTPUT_REPORT:
505 hid_device_xfer_report( ext, code, irp );
506 break;
507 default:
509 ULONG code = irpsp->Parameters.DeviceIoControl.IoControlCode;
510 FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n",
511 code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3);
512 irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
513 break;
517 status = irp->IoStatus.Status;
518 if (status != STATUS_PENDING) IoCompleteRequest( irp, IO_NO_INCREMENT );
519 return status;
522 NTSTATUS WINAPI pdo_read(DEVICE_OBJECT *device, IRP *irp)
524 HID_XFER_PACKET *packet;
525 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
526 const WINE_HIDP_PREPARSED_DATA *data = ext->u.pdo.preparsed_data;
527 UINT buffer_size = RingBuffer_GetBufferSize(ext->u.pdo.ring_buffer);
528 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation(irp);
529 BYTE report_id = HID_INPUT_VALUE_CAPS( data )->report_id;
530 NTSTATUS status;
531 int ptr = -1;
532 BOOL removed;
533 KIRQL irql;
535 KeAcquireSpinLock(&ext->u.pdo.lock, &irql);
536 removed = ext->u.pdo.removed;
537 KeReleaseSpinLock(&ext->u.pdo.lock, irql);
539 if (removed)
541 irp->IoStatus.Status = STATUS_DELETE_PENDING;
542 IoCompleteRequest(irp, IO_NO_INCREMENT);
543 return STATUS_DELETE_PENDING;
546 if (irpsp->Parameters.Read.Length < data->caps.InputReportByteLength)
548 irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
549 IoCompleteRequest( irp, IO_NO_INCREMENT );
550 return STATUS_INVALID_BUFFER_SIZE;
553 packet = malloc(buffer_size);
554 ptr = PtrToUlong( irp->Tail.Overlay.OriginalFileObject->FsContext );
556 irp->IoStatus.Information = 0;
557 RingBuffer_ReadNew(ext->u.pdo.ring_buffer, ptr, packet, &buffer_size);
559 if (buffer_size)
561 memcpy( irp->AssociatedIrp.SystemBuffer, packet + 1, data->caps.InputReportByteLength );
562 irp->IoStatus.Information = packet->reportBufferLen;
563 irp->IoStatus.Status = STATUS_SUCCESS;
565 else
567 if (ext->u.pdo.poll_interval)
569 KIRQL old_irql;
570 TRACE_(hid_report)("Queue irp\n");
572 KeAcquireSpinLock(&ext->u.pdo.irp_queue_lock, &old_irql);
574 IoSetCancelRoutine(irp, read_cancel_routine);
575 if (irp->Cancel && !IoSetCancelRoutine(irp, NULL))
577 /* IRP was canceled before we set cancel routine */
578 InitializeListHead(&irp->Tail.Overlay.ListEntry);
579 KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql);
580 return STATUS_CANCELLED;
583 InsertTailList(&ext->u.pdo.irp_queue, &irp->Tail.Overlay.ListEntry);
584 irp->IoStatus.Status = STATUS_PENDING;
585 IoMarkIrpPending(irp);
587 KeReleaseSpinLock(&ext->u.pdo.irp_queue_lock, old_irql);
589 else
591 HID_XFER_PACKET packet;
592 BYTE *buffer = irp->AssociatedIrp.SystemBuffer;
593 ULONG buffer_len = irpsp->Parameters.Read.Length;
595 TRACE("No packet, but opportunistic reads enabled\n");
597 packet.reportId = buffer[0];
598 packet.reportBuffer = buffer;
599 packet.reportBufferLen = buffer_len;
601 if (!report_id)
603 packet.reportId = 0;
604 packet.reportBuffer++;
605 packet.reportBufferLen--;
608 call_minidriver( IOCTL_HID_GET_INPUT_REPORT, ext->u.pdo.parent_fdo, NULL, 0, &packet,
609 sizeof(packet), &irp->IoStatus );
612 free(packet);
614 status = irp->IoStatus.Status;
615 if (status != STATUS_PENDING) IoCompleteRequest( irp, IO_NO_INCREMENT );
616 return status;
619 NTSTATUS WINAPI pdo_write(DEVICE_OBJECT *device, IRP *irp)
621 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
622 NTSTATUS status;
624 hid_device_xfer_report( ext, IOCTL_HID_WRITE_REPORT, irp );
626 status = irp->IoStatus.Status;
627 IoCompleteRequest( irp, IO_NO_INCREMENT );
628 return status;
631 NTSTATUS WINAPI pdo_create(DEVICE_OBJECT *device, IRP *irp)
633 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
635 TRACE("Open handle on device %p\n", device);
636 irp->Tail.Overlay.OriginalFileObject->FsContext = UlongToPtr(RingBuffer_AddPointer(ext->u.pdo.ring_buffer));
637 irp->IoStatus.Status = STATUS_SUCCESS;
638 IoCompleteRequest( irp, IO_NO_INCREMENT );
639 return STATUS_SUCCESS;
642 NTSTATUS WINAPI pdo_close(DEVICE_OBJECT *device, IRP *irp)
644 BASE_DEVICE_EXTENSION *ext = device->DeviceExtension;
645 int ptr = PtrToUlong(irp->Tail.Overlay.OriginalFileObject->FsContext);
646 TRACE("Close handle on device %p\n", device);
647 RingBuffer_RemovePointer(ext->u.pdo.ring_buffer, ptr);
648 irp->IoStatus.Status = STATUS_SUCCESS;
649 IoCompleteRequest( irp, IO_NO_INCREMENT );
650 return STATUS_SUCCESS;