2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS USB miniport driver (Cromwell type)
4 * FILE: drivers/usb/miniport/common/fdo.c
5 * PURPOSE: IRP_MJ_PNP/IRP_MJ_DEVICE_CONTROL operations for FDOs
7 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org),
8 * James Tabor (jimtabor@adsl-64-217-116-74.dsl.hstntx.swbell.net)
14 #include "usbcommon.h"
16 #define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
21 IN ULONG IoControlCode
,
29 switch (IO_METHOD_FROM_CTL_CODE(IoControlCode
))
32 *BufferIn
= *BufferOut
= Irp
->AssociatedIrp
.SystemBuffer
;
34 case METHOD_IN_DIRECT
:
35 case METHOD_OUT_DIRECT
:
36 *BufferIn
= Irp
->AssociatedIrp
.SystemBuffer
;
37 *BufferOut
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
40 *BufferIn
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.Type3InputBuffer
;
41 *BufferOut
= Irp
->UserBuffer
;
44 /* Should never happen */
53 IN PDEVICE_OBJECT DeviceObject
,
56 PIO_STACK_LOCATION Stack
= IoGetCurrentIrpStackLocation(Irp
);
57 PDRIVER_OBJECT DriverObject
;
58 PUSBMP_DRIVER_EXTENSION DriverExtension
;
59 PUSBMP_DEVICE_EXTENSION DeviceExtension
;
60 PCM_RESOURCE_LIST AllocatedResources
;
62 if (DeviceObject
== KeyboardFdo
|| DeviceObject
== MouseFdo
)
63 return STATUS_SUCCESS
;
66 * Get the initialization data we saved in VideoPortInitialize.
68 DriverObject
= DeviceObject
->DriverObject
;
69 DriverExtension
= IoGetDriverObjectExtension(DriverObject
, DriverObject
);
70 DeviceExtension
= (PUSBMP_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
73 * Store some resources in the DeviceExtension.
75 AllocatedResources
= Stack
->Parameters
.StartDevice
.AllocatedResources
;
76 if (AllocatedResources
!= NULL
)
78 CM_FULL_RESOURCE_DESCRIPTOR
*FullList
;
79 CM_PARTIAL_RESOURCE_DESCRIPTOR
*Descriptor
;
81 ULONG ResourceListSize
;
83 /* Save the resource list */
84 ResourceCount
= AllocatedResources
->List
[0].PartialResourceList
.Count
;
86 ResourceListSize
= FIELD_OFFSET(CM_RESOURCE_LIST
, List
[0].PartialResourceList
.
87 PartialDescriptors
[ResourceCount
]);
89 DeviceExtension
->AllocatedResources
= ExAllocatePool(PagedPool
, ResourceListSize
);
90 if (DeviceExtension
->AllocatedResources
== NULL
)
92 return STATUS_INSUFFICIENT_RESOURCES
;
95 RtlCopyMemory(DeviceExtension
->AllocatedResources
,
99 /* Get the interrupt level/vector - needed by HwFindAdapter sometimes */
100 for (FullList
= AllocatedResources
->List
;
101 FullList
< AllocatedResources
->List
+ AllocatedResources
->Count
;
104 /* FIXME: Is this ASSERT ok for resources from the PNP manager? */
105 /*ASSERT(FullList->InterfaceType == PCIBus &&
106 FullList->BusNumber == DeviceExtension->SystemIoBusNumber &&
107 1 == FullList->PartialResourceList.Version &&
108 1 == FullList->PartialResourceList.Revision);*/
109 for (Descriptor
= FullList
->PartialResourceList
.PartialDescriptors
;
110 Descriptor
< FullList
->PartialResourceList
.PartialDescriptors
+ FullList
->PartialResourceList
.Count
;
113 if (Descriptor
->Type
== CmResourceTypeInterrupt
)
115 DeviceExtension
->InterruptLevel
= Descriptor
->u
.Interrupt
.Level
;
116 DeviceExtension
->InterruptVector
= Descriptor
->u
.Interrupt
.Vector
;
118 else if (Descriptor
->Type
== CmResourceTypePort
)
120 DeviceExtension
->BaseAddress
= Descriptor
->u
.Port
.Start
;
121 DeviceExtension
->BaseAddrLength
= Descriptor
->u
.Port
.Length
;
122 DeviceExtension
->Flags
= Descriptor
->Flags
;
124 ((struct hc_driver
*)pci_ids
->driver_data
)->flags
&= ~HCD_MEMORY
;
126 else if (Descriptor
->Type
== CmResourceTypeMemory
)
128 DeviceExtension
->BaseAddress
= Descriptor
->u
.Memory
.Start
;
129 DeviceExtension
->BaseAddrLength
= Descriptor
->u
.Memory
.Length
;
130 DeviceExtension
->Flags
= Descriptor
->Flags
;
132 ((struct hc_driver
*)pci_ids
->driver_data
)->flags
|= HCD_MEMORY
;
138 /* Print assigned resources */
139 DPRINT("USBMP: Interrupt Vector 0x%lx, %S base 0x%lx, Length 0x%lx\n",
140 DeviceExtension
->InterruptVector
,
141 ((struct hc_driver
*)pci_ids
->driver_data
)->flags
& HCD_MEMORY
? L
"Memory" : L
"I/O",
142 DeviceExtension
->BaseAddress
,
143 DeviceExtension
->BaseAddrLength
);
145 /* Init wrapper with this object */
146 return InitLinuxWrapper(DeviceObject
);
150 UsbMpFdoQueryBusRelations(
151 IN PDEVICE_OBJECT DeviceObject
,
152 OUT PDEVICE_RELATIONS
* pDeviceRelations
)
154 PUSBMP_DEVICE_EXTENSION DeviceExtension
;
155 PDEVICE_RELATIONS DeviceRelations
;
156 NTSTATUS Status
= STATUS_SUCCESS
;
158 DeviceExtension
= (PUSBMP_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
160 /* Handling this IRP is easy, as we only
161 * have one child: the root hub
163 DeviceRelations
= (PDEVICE_RELATIONS
)ExAllocatePool(
165 sizeof(DEVICE_RELATIONS
));
166 if (!DeviceRelations
)
167 return STATUS_INSUFFICIENT_RESOURCES
;
169 /* Fill returned structure */
170 DeviceRelations
->Count
= 1;
171 ObReferenceObject(DeviceExtension
->RootHubPdo
);
172 DeviceRelations
->Objects
[0] = DeviceExtension
->RootHubPdo
;
174 *pDeviceRelations
= DeviceRelations
;
180 IN PDEVICE_OBJECT DeviceObject
,
183 PIO_STACK_LOCATION IrpSp
;
186 ULONG_PTR Information
= 0;
188 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
189 MinorFunction
= IrpSp
->MinorFunction
;
191 switch (MinorFunction
)
193 case IRP_MN_START_DEVICE
:
195 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
196 if (NT_SUCCESS(Status
) && NT_SUCCESS(Irp
->IoStatus
.Status
))
197 Status
= UsbMpFdoStartDevice(DeviceObject
, Irp
);
201 case IRP_MN_REMOVE_DEVICE
:
202 case IRP_MN_QUERY_REMOVE_DEVICE
:
203 case IRP_MN_CANCEL_REMOVE_DEVICE
:
204 case IRP_MN_SURPRISE_REMOVAL
:
206 case IRP_MN_STOP_DEVICE
:
208 Status
= ForwardIrpAndWait(DeviceObject
, Irp
);
209 if (NT_SUCCESS(Status
) && NT_SUCCESS(Irp
->IoStatus
.Status
))
210 Status
= STATUS_SUCCESS
;
211 IoDeleteDevice(DeviceObject
); // just delete device for now
214 case IRP_MN_QUERY_STOP_DEVICE
:
215 case IRP_MN_CANCEL_STOP_DEVICE
:
217 Status
= STATUS_SUCCESS
;
220 case IRP_MN_QUERY_DEVICE_RELATIONS
: /* (optional) 0x7 */
222 switch (IrpSp
->Parameters
.QueryDeviceRelations
.Type
)
226 PDEVICE_RELATIONS DeviceRelations
;
227 DPRINT("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
228 Status
= UsbMpFdoQueryBusRelations(DeviceObject
, &DeviceRelations
);
229 Information
= (ULONG_PTR
)DeviceRelations
;
232 case RemovalRelations
:
234 DPRINT1("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
235 return ForwardIrpAndForget(DeviceObject
, Irp
);
238 DPRINT1("USBMP: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
239 IrpSp
->Parameters
.QueryDeviceRelations
.Type
);
240 return ForwardIrpAndForget(DeviceObject
, Irp
);
247 DPRINT1("USBMP: unknown minor function 0x%lx\n", MinorFunction
);
248 return ForwardIrpAndForget(DeviceObject
, Irp
);
251 Irp
->IoStatus
.Information
= Information
;
252 Irp
->IoStatus
.Status
= Status
;
253 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
258 UsbMpDeviceControlFdo(
259 IN PDEVICE_OBJECT DeviceObject
,
262 PIO_STACK_LOCATION Stack
;
264 PUSBMP_DEVICE_EXTENSION DeviceExtension
;
265 ULONG LengthIn
, LengthOut
;
266 ULONG_PTR Information
= 0;
267 PVOID BufferIn
, BufferOut
;
270 DPRINT("USBMP: UsbDeviceControlFdo() called\n");
272 Stack
= IoGetCurrentIrpStackLocation(Irp
);
273 LengthIn
= Stack
->Parameters
.DeviceIoControl
.InputBufferLength
;
274 LengthOut
= Stack
->Parameters
.DeviceIoControl
.OutputBufferLength
;
275 DeviceExtension
= (PUSBMP_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
276 IoControlCode
= Stack
->Parameters
.DeviceIoControl
.IoControlCode
;
277 UsbMpGetUserBuffers(Irp
, IoControlCode
, &BufferIn
, &BufferOut
);
279 switch (IoControlCode
)
281 case IOCTL_GET_HCD_DRIVERKEY_NAME
:
283 DPRINT("USBMP: IOCTL_GET_HCD_DRIVERKEY_NAME\n");
284 if (LengthOut
< sizeof(USB_HCD_DRIVERKEY_NAME
))
285 Status
= STATUS_BUFFER_TOO_SMALL
;
286 else if (BufferOut
== NULL
)
287 Status
= STATUS_INVALID_PARAMETER
;
290 PUSB_HCD_DRIVERKEY_NAME StringDescriptor
;
292 StringDescriptor
= (PUSB_HCD_DRIVERKEY_NAME
)BufferOut
;
293 Status
= IoGetDeviceProperty(
294 ((PUSBMP_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->PhysicalDeviceObject
,
295 DevicePropertyDriverKeyName
,
296 LengthOut
- FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME
, DriverKeyName
),
297 StringDescriptor
->DriverKeyName
,
299 if (NT_SUCCESS(Status
) || Status
== STATUS_BUFFER_TOO_SMALL
)
301 StringDescriptor
->ActualLength
= StringSize
+ FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME
, DriverKeyName
);
302 Information
= LengthOut
;
303 Status
= STATUS_SUCCESS
;
308 case IOCTL_USB_GET_ROOT_HUB_NAME
:
310 DPRINT("USBMP: IOCTL_USB_GET_ROOT_HUB_NAME\n");
311 if (LengthOut
< sizeof(USB_ROOT_HUB_NAME
))
312 Status
= STATUS_BUFFER_TOO_SMALL
;
313 else if (BufferOut
== NULL
)
314 Status
= STATUS_INVALID_PARAMETER
;
317 PUSB_ROOT_HUB_NAME StringDescriptor
;
318 PUNICODE_STRING RootHubInterfaceName
;
319 StringDescriptor
= (PUSB_ROOT_HUB_NAME
)BufferOut
;
320 DeviceObject
= ((PUSBMP_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->RootHubPdo
;
321 RootHubInterfaceName
= &((PUSBMP_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->HcdInterfaceName
;
323 StringDescriptor
->ActualLength
= RootHubInterfaceName
->Length
+ sizeof(WCHAR
) + FIELD_OFFSET(USB_ROOT_HUB_NAME
, RootHubName
);
324 if (StringDescriptor
->ActualLength
<= LengthOut
)
326 /* Copy root hub name */
328 StringDescriptor
->RootHubName
,
329 RootHubInterfaceName
->Buffer
,
330 RootHubInterfaceName
->Length
);
331 StringDescriptor
->RootHubName
[RootHubInterfaceName
->Length
/ sizeof(WCHAR
)] = UNICODE_NULL
;
332 DPRINT("USBMP: IOCTL_USB_GET_ROOT_HUB_NAME returns '%S'\n", StringDescriptor
->RootHubName
);
333 Information
= StringDescriptor
->ActualLength
;
336 Information
= sizeof(USB_ROOT_HUB_NAME
);
337 Status
= STATUS_SUCCESS
;
344 /* Pass Irp to lower driver */
345 DPRINT1("USBMP: Unknown IOCTL code 0x%lx\n", Stack
->Parameters
.DeviceIoControl
.IoControlCode
);
346 IoSkipCurrentIrpStackLocation(Irp
);
347 return IoCallDriver(DeviceExtension
->NextDeviceObject
, Irp
);
351 Irp
->IoStatus
.Information
= Information
;
352 Irp
->IoStatus
.Status
= Status
;
353 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
358 UsbMpInternalDeviceControlFdo(
359 IN PDEVICE_OBJECT DeviceObject
,
362 NTSTATUS Status
= STATUS_INVALID_DEVICE_REQUEST
;
364 DPRINT("USBMP: UsbMpDeviceInternalControlFdo(DO %p, code 0x%lx) called\n",
366 IoGetCurrentIrpStackLocation(Irp
)->Parameters
.DeviceIoControl
.IoControlCode
);
368 if (DeviceObject
== KeyboardFdo
)
370 // it's keyboard's IOCTL
371 PIO_STACK_LOCATION Stk
;
373 Irp
->IoStatus
.Information
= 0;
374 Stk
= IoGetCurrentIrpStackLocation(Irp
);
376 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
)
378 case IOCTL_INTERNAL_KEYBOARD_CONNECT
:
379 DPRINT("USBMP: IOCTL_INTERNAL_KEYBOARD_CONNECT\n");
380 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
)) {
381 DPRINT1("USBMP: Keyboard IOCTL_INTERNAL_KEYBOARD_CONNECT "
382 "invalid buffer size\n");
383 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
387 RtlCopyMemory(&KbdClassInformation
,
388 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
389 sizeof(CONNECT_DATA
));
391 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
394 case IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER
:
395 DPRINT("USBMP: IOCTL_INTERNAL_I8042_KEYBOARD_WRITE_BUFFER\n");
396 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
< 1) {
397 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
400 /* if (!DevExt->KeyboardInterruptObject) {
401 Irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
405 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
407 case IOCTL_KEYBOARD_QUERY_ATTRIBUTES
:
408 DPRINT("USBMP: IOCTL_KEYBOARD_QUERY_ATTRIBUTES\n");
409 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
410 sizeof(KEYBOARD_ATTRIBUTES
)) {
411 DPRINT("USBMP: Keyboard IOCTL_KEYBOARD_QUERY_ATTRIBUTES "
412 "invalid buffer size\n");
413 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
416 /*RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
417 &DevExt->KeyboardAttributes,
418 sizeof(KEYBOARD_ATTRIBUTES));*/
420 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
422 case IOCTL_KEYBOARD_QUERY_INDICATORS
:
423 DPRINT("USBMP: IOCTL_KEYBOARD_QUERY_INDICATORS\n");
424 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
425 sizeof(KEYBOARD_INDICATOR_PARAMETERS
)) {
426 DPRINT("USBMP: Keyboard IOCTL_KEYBOARD_QUERY_INDICATORS "
427 "invalid buffer size\n");
428 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
431 /*RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
432 &DevExt->KeyboardIndicators,
433 sizeof(KEYBOARD_INDICATOR_PARAMETERS));*/
435 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
437 case IOCTL_KEYBOARD_QUERY_TYPEMATIC
:
438 DPRINT("USBMP: IOCTL_KEYBOARD_QUERY_TYPEMATIC\n");
439 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
440 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS
)) {
441 DPRINT("USBMP: Keyboard IOCTL_KEYBOARD_QUERY_TYPEMATIC "
442 "invalid buffer size\n");
443 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
446 /*RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
447 &DevExt->KeyboardTypematic,
448 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));*/
450 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
452 case IOCTL_KEYBOARD_SET_INDICATORS
:
453 DPRINT("USBMP: IOCTL_KEYBOARD_SET_INDICATORS\n");
454 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
455 sizeof(KEYBOARD_INDICATOR_PARAMETERS
)) {
456 DPRINT("USBMP: Keyboard IOCTL_KEYBOARD_SET_INDICTATORS "
457 "invalid buffer size\n");
458 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
462 /*RtlCopyMemory(&DevExt->KeyboardIndicators,
463 Irp->AssociatedIrp.SystemBuffer,
464 sizeof(KEYBOARD_INDICATOR_PARAMETERS));*/
466 //DPRINT("%x\n", DevExt->KeyboardIndicators.LedFlags);
468 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
470 case IOCTL_KEYBOARD_SET_TYPEMATIC
:
471 DPRINT("USBMP: IOCTL_KEYBOARD_SET_TYPEMATIC\n");
472 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
<
473 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS
)) {
474 DPRINT("USBMP: Keyboard IOCTL_KEYBOARD_SET_TYPEMATIC "
475 "invalid buffer size\n");
476 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
480 /*RtlCopyMemory(&DevExt->KeyboardTypematic,
481 Irp->AssociatedIrp.SystemBuffer,
482 sizeof(KEYBOARD_TYPEMATIC_PARAMETERS));*/
484 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
486 case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION
:
487 /* We should check the UnitID, but it's kind of pointless as
488 * all keyboards are supposed to have the same one
491 DPRINT("USBMP: IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION\n");
492 if (Stk
->Parameters
.DeviceIoControl
.OutputBufferLength
<
493 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
)) {
494 DPRINT("USBMP: IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: "
495 "invalid buffer size (expected)\n");
496 /* It's to query the buffer size */
497 Irp
->IoStatus
.Status
= STATUS_BUFFER_TOO_SMALL
;
500 Irp
->IoStatus
.Information
=
501 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION
);
503 /*RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
504 &IndicatorTranslation,
505 sizeof(LOCAL_KEYBOARD_INDICATOR_TRANSLATION));*/
507 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
509 case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD
:
510 /* Nothing to do here */
511 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
514 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
519 Status
= Irp
->IoStatus
.Status
;
521 else if (DeviceObject
== MouseFdo
)
523 // it's mouse's IOCTL
524 PIO_STACK_LOCATION Stk
;
526 Irp
->IoStatus
.Information
= 0;
527 Stk
= IoGetCurrentIrpStackLocation(Irp
);
529 switch (Stk
->Parameters
.DeviceIoControl
.IoControlCode
)
531 case IOCTL_INTERNAL_MOUSE_CONNECT
:
532 DPRINT("USBMP: IOCTL_INTERNAL_MOUSE_CONNECT\n");
533 if (Stk
->Parameters
.DeviceIoControl
.InputBufferLength
< sizeof(CONNECT_DATA
)) {
534 DPRINT1("USBMP: IOCTL_INTERNAL_MOUSE_CONNECT "
535 "invalid buffer size\n");
536 Irp
->IoStatus
.Status
= STATUS_INVALID_PARAMETER
;
537 goto intcontfailure2
;
540 RtlCopyMemory(&MouseClassInformation
,
541 Stk
->Parameters
.DeviceIoControl
.Type3InputBuffer
,
542 sizeof(CONNECT_DATA
));
544 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
548 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;//STATUS_INVALID_DEVICE_REQUEST;
552 Status
= Irp
->IoStatus
.Status
;
556 DPRINT("USBMP: We got IOCTL for UsbCore\n");
557 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
558 return STATUS_SUCCESS
;
562 if (Status
== STATUS_INVALID_DEVICE_REQUEST
) {
563 DPRINT1("USBMP: Invalid internal device request!\n");
566 if (Status
!= STATUS_PENDING
)
567 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);