1 // Copyright (c) 2004, Antony C. Roberts
3 // Use of this file is subject to the terms
4 // described in the LICENSE.TXT file that
5 // accompanies this file.
7 // Your use of this file indicates your
8 // acceptance of the terms described in
11 // http://www.freebt.net
23 NTSTATUS
FreeBT_DispatchRead(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
30 ULONG_PTR virtualAddress
;
31 PFILE_OBJECT fileObject
;
32 PDEVICE_EXTENSION deviceExtension
;
33 PIO_STACK_LOCATION irpStack
;
34 PIO_STACK_LOCATION nextStack
;
35 PFREEBT_RW_CONTEXT rwContext
;
42 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
43 fileObject
= irpStack
->FileObject
;
44 deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
46 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Entered\n"));
48 if (deviceExtension
->DeviceState
!= Working
)
50 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Invalid device state\n"));
51 ntStatus
= STATUS_INVALID_DEVICE_STATE
;
52 goto FreeBT_DispatchRead_Exit
;
56 // Make sure that any selective suspend request has been completed.
57 if (deviceExtension
->SSEnable
)
59 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Waiting on the IdleReqPendEvent\n"));
60 KeWaitForSingleObject(&deviceExtension
->NoIdleReqPendEvent
,
68 rwContext
= (PFREEBT_RW_CONTEXT
) ExAllocatePool(NonPagedPool
, sizeof(FREEBT_RW_CONTEXT
));
69 if (rwContext
== NULL
)
71 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for rwContext\n"));
72 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
73 goto FreeBT_DispatchRead_Exit
;
79 totalLength
= MmGetMdlByteCount(Irp
->MdlAddress
);
83 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Transfer data length = %d\n", totalLength
));
86 ntStatus
= STATUS_SUCCESS
;
87 ExFreePool(rwContext
);
88 goto FreeBT_DispatchRead_Exit
;
92 virtualAddress
= (ULONG_PTR
) MmGetMdlVirtualAddress(Irp
->MdlAddress
);
93 if (totalLength
> deviceExtension
->DataInPipe
.MaximumPacketSize
)
95 stageLength
= deviceExtension
->DataInPipe
.MaximumPacketSize
;
101 stageLength
= totalLength
;
105 mdl
= IoAllocateMdl((PVOID
) virtualAddress
, totalLength
, FALSE
, FALSE
, NULL
);
108 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for mdl\n"));
109 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
110 ExFreePool(rwContext
);
111 goto FreeBT_DispatchRead_Exit
;
115 // map the portion of user-buffer described by an mdl to another mdl
116 IoBuildPartialMdl(Irp
->MdlAddress
, mdl
, (PVOID
) virtualAddress
, stageLength
);
117 urb
= (PURB
) ExAllocatePool(NonPagedPool
, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
));
120 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for urb\n"));
121 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
122 ExFreePool(rwContext
);
124 goto FreeBT_DispatchRead_Exit
;
128 UsbBuildInterruptOrBulkTransferRequest(
130 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
),
131 deviceExtension
->DataInPipe
.PipeHandle
,
135 USBD_SHORT_TRANSFER_OK
| USBD_TRANSFER_DIRECTION_IN
,
138 // set FREEBT_RW_CONTEXT parameters.
139 rwContext
->Urb
= urb
;
140 rwContext
->Mdl
= mdl
;
141 rwContext
->Length
= totalLength
- stageLength
;
142 rwContext
->Numxfer
= 0;
143 rwContext
->VirtualAddress
= virtualAddress
+ stageLength
;
145 // use the original read/write irp as an internal device control irp
146 nextStack
= IoGetNextIrpStackLocation(Irp
);
147 nextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
148 nextStack
->Parameters
.Others
.Argument1
= (PVOID
) urb
;
149 nextStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
150 IoSetCompletionRoutine(Irp
,
151 (PIO_COMPLETION_ROUTINE
)FreeBT_ReadCompletion
,
157 // We return STATUS_PENDING; call IoMarkIrpPending.
158 IoMarkIrpPending(Irp
);
160 ntStatus
= IoCallDriver(deviceExtension
->TopOfStackDeviceObject
, Irp
);
161 if (!NT_SUCCESS(ntStatus
))
163 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: IoCallDriver fails with status %X\n", ntStatus
));
165 // if the device was yanked out, then the pipeInformation
167 // similarly if the request was cancelled, then we need not
168 // invoked reset pipe/device.
169 if((ntStatus
!= STATUS_CANCELLED
) && (ntStatus
!= STATUS_DEVICE_NOT_CONNECTED
))
171 ntStatus
= FreeBT_ResetPipe(DeviceObject
, deviceExtension
->DataInPipe
.PipeHandle
);
172 if(!NT_SUCCESS(ntStatus
))
174 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: FreeBT_ResetPipe failed\n"));
175 ntStatus
= FreeBT_ResetDevice(DeviceObject
);
183 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
189 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead::"));
190 FreeBT_IoIncrement(deviceExtension
);
192 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: URB sent to lower driver, IRP is pending\n"));
194 // we return STATUS_PENDING and not the status returned by the lower layer.
195 return STATUS_PENDING
;
197 FreeBT_DispatchRead_Exit
:
198 Irp
->IoStatus
.Status
= ntStatus
;
199 Irp
->IoStatus
.Information
= 0;
200 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
201 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Leaving\n"));
207 NTSTATUS
FreeBT_ReadCompletion(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
, IN PVOID Context
)
211 PIO_STACK_LOCATION nextStack
;
212 PFREEBT_RW_CONTEXT rwContext
;
213 PDEVICE_EXTENSION deviceExtension
;
215 deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
216 rwContext
= (PFREEBT_RW_CONTEXT
) Context
;
217 ntStatus
= Irp
->IoStatus
.Status
;
219 UNREFERENCED_PARAMETER(DeviceObject
);
220 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Entered\n"));
222 if (NT_SUCCESS(ntStatus
))
224 Irp
->IoStatus
.Information
= rwContext
->Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
;
230 Irp
->IoStatus
.Information
= 0;
231 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ReadCompletion: - failed with status = %X\n", ntStatus
));
237 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: ::"));
238 FreeBT_IoDecrement(deviceExtension
);
240 ExFreePool(rwContext
->Urb
);
241 IoFreeMdl(rwContext
->Mdl
);
242 ExFreePool(rwContext
);
246 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Leaving\n"));
252 // Read/Write handler
253 NTSTATUS
FreeBT_DispatchWrite(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
)
260 ULONG_PTR virtualAddress
;
261 PFILE_OBJECT fileObject
;
262 PDEVICE_EXTENSION deviceExtension
;
263 PIO_STACK_LOCATION irpStack
;
264 PIO_STACK_LOCATION nextStack
;
265 PFREEBT_RW_CONTEXT rwContext
;
272 irpStack
= IoGetCurrentIrpStackLocation(Irp
);
273 fileObject
= irpStack
->FileObject
;
274 deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
276 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: Entered\n"));
278 if (deviceExtension
->DeviceState
!= Working
)
280 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Invalid device state\n"));
281 ntStatus
= STATUS_INVALID_DEVICE_STATE
;
282 goto FreeBT_DispatchWrite_Exit
;
286 // Make sure that any selective suspend request has been completed.
287 if (deviceExtension
->SSEnable
)
289 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteDispatch: Waiting on the IdleReqPendEvent\n"));
290 KeWaitForSingleObject(&deviceExtension
->NoIdleReqPendEvent
,
298 rwContext
= (PFREEBT_RW_CONTEXT
) ExAllocatePool(NonPagedPool
, sizeof(FREEBT_RW_CONTEXT
));
299 if (rwContext
== NULL
)
301 FreeBT_DbgPrint(1, ("FBTUSB: Failed to alloc mem for rwContext\n"));
302 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
303 goto FreeBT_DispatchWrite_Exit
;
309 totalLength
= MmGetMdlByteCount(Irp
->MdlAddress
);
313 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Transfer data length = %d\n", totalLength
));
314 if (totalLength
>FBT_HCI_DATA_MAX_SIZE
)
316 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Buffer exceeds maximum packet length (%d), failing IRP\n", FBT_HCI_DATA_MAX_SIZE
));
317 ntStatus
= STATUS_INVALID_BUFFER_SIZE
;
318 ExFreePool(rwContext
);
319 goto FreeBT_DispatchWrite_Exit
;
323 if (totalLength
<FBT_HCI_DATA_MIN_SIZE
)
325 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Zero length buffer, completing IRP\n"));
326 ntStatus
= STATUS_BUFFER_TOO_SMALL
;
327 ExFreePool(rwContext
);
328 goto FreeBT_DispatchWrite_Exit
;
332 virtualAddress
= (ULONG_PTR
) MmGetMdlVirtualAddress(Irp
->MdlAddress
);
333 if (totalLength
> deviceExtension
->DataOutPipe
.MaximumPacketSize
)
335 stageLength
= deviceExtension
->DataOutPipe
.MaximumPacketSize
;
341 stageLength
= totalLength
;
345 mdl
= IoAllocateMdl((PVOID
) virtualAddress
, totalLength
, FALSE
, FALSE
, NULL
);
348 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Failed to alloc mem for mdl\n"));
349 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
350 ExFreePool(rwContext
);
351 goto FreeBT_DispatchWrite_Exit
;
355 // map the portion of user-buffer described by an mdl to another mdl
356 IoBuildPartialMdl(Irp
->MdlAddress
, mdl
, (PVOID
) virtualAddress
, stageLength
);
357 urb
= (PURB
) ExAllocatePool(NonPagedPool
, sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
));
360 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Failed to alloc mem for urb\n"));
361 ntStatus
= STATUS_INSUFFICIENT_RESOURCES
;
362 ExFreePool(rwContext
);
364 goto FreeBT_DispatchWrite_Exit
;
368 UsbBuildInterruptOrBulkTransferRequest(
370 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER
),
371 deviceExtension
->DataOutPipe
.PipeHandle
,
375 USBD_SHORT_TRANSFER_OK
| USBD_TRANSFER_DIRECTION_OUT
,
378 // set FREEBT_RW_CONTEXT parameters.
379 rwContext
->Urb
= urb
;
380 rwContext
->Mdl
= mdl
;
381 rwContext
->Length
= totalLength
- stageLength
;
382 rwContext
->Numxfer
= 0;
383 rwContext
->VirtualAddress
= virtualAddress
+ stageLength
;
385 // use the original read/write irp as an internal device control irp
386 nextStack
= IoGetNextIrpStackLocation(Irp
);
387 nextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
388 nextStack
->Parameters
.Others
.Argument1
= (PVOID
) urb
;
389 nextStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
390 IoSetCompletionRoutine(Irp
,
391 (PIO_COMPLETION_ROUTINE
)FreeBT_WriteCompletion
,
397 // We return STATUS_PENDING; call IoMarkIrpPending.
398 IoMarkIrpPending(Irp
);
400 ntStatus
= IoCallDriver(deviceExtension
->TopOfStackDeviceObject
, Irp
);
401 if (!NT_SUCCESS(ntStatus
))
403 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: IoCallDriver fails with status %X\n", ntStatus
));
405 // if the device was yanked out, then the pipeInformation
407 // similarly if the request was cancelled, then we need not
408 // invoked reset pipe/device.
409 if((ntStatus
!= STATUS_CANCELLED
) && (ntStatus
!= STATUS_DEVICE_NOT_CONNECTED
))
411 ntStatus
= FreeBT_ResetPipe(DeviceObject
, deviceExtension
->DataOutPipe
.PipeHandle
);
412 if(!NT_SUCCESS(ntStatus
))
414 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ResetPipe failed\n"));
415 ntStatus
= FreeBT_ResetDevice(DeviceObject
);
423 FreeBT_DbgPrint(3, ("FBTUSB: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
429 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite::"));
430 FreeBT_IoIncrement(deviceExtension
);
432 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: URB sent to lower driver, IRP is pending\n"));
434 // we return STATUS_PENDING and not the status returned by the lower layer.
435 return STATUS_PENDING
;
437 FreeBT_DispatchWrite_Exit
:
438 Irp
->IoStatus
.Status
= ntStatus
;
439 Irp
->IoStatus
.Information
= 0;
440 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
441 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: Leaving\n"));
447 NTSTATUS
FreeBT_WriteCompletion(IN PDEVICE_OBJECT DeviceObject
, IN PIRP Irp
, IN PVOID Context
)
451 PIO_STACK_LOCATION nextStack
;
452 PFREEBT_RW_CONTEXT rwContext
;
453 PDEVICE_EXTENSION deviceExtension
;
455 deviceExtension
= (PDEVICE_EXTENSION
) DeviceObject
->DeviceExtension
;
456 rwContext
= (PFREEBT_RW_CONTEXT
) Context
;
457 ntStatus
= Irp
->IoStatus
.Status
;
459 UNREFERENCED_PARAMETER(DeviceObject
);
460 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Entered\n"));
462 if (NT_SUCCESS(ntStatus
))
466 rwContext
->Numxfer
+= rwContext
->Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
;
467 if (rwContext
->Length
)
469 // More data to transfer
470 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Initiating next transfer\n"));
471 if (rwContext
->Length
> deviceExtension
->DataOutPipe
.MaximumPacketSize
)
473 stageLength
= deviceExtension
->DataOutPipe
.MaximumPacketSize
;
479 stageLength
= rwContext
->Length
;
483 IoBuildPartialMdl(Irp
->MdlAddress
, rwContext
->Mdl
, (PVOID
) rwContext
->VirtualAddress
, stageLength
);
485 // reinitialize the urb
486 rwContext
->Urb
->UrbBulkOrInterruptTransfer
.TransferBufferLength
= stageLength
;
487 rwContext
->VirtualAddress
+= stageLength
;
488 rwContext
->Length
-= stageLength
;
490 nextStack
= IoGetNextIrpStackLocation(Irp
);
491 nextStack
->MajorFunction
= IRP_MJ_INTERNAL_DEVICE_CONTROL
;
492 nextStack
->Parameters
.Others
.Argument1
= rwContext
->Urb
;
493 nextStack
->Parameters
.DeviceIoControl
.IoControlCode
= IOCTL_INTERNAL_USB_SUBMIT_URB
;
495 IoSetCompletionRoutine(Irp
,
496 FreeBT_ReadCompletion
,
502 IoCallDriver(deviceExtension
->TopOfStackDeviceObject
, Irp
);
504 return STATUS_MORE_PROCESSING_REQUIRED
;
510 // No more data to transfer
511 FreeBT_DbgPrint(1, ("FBTUSB: FreeNT_WriteCompletion: Write completed, %d bytes written\n", Irp
->IoStatus
.Information
));
512 Irp
->IoStatus
.Information
= rwContext
->Numxfer
;
522 FreeBT_DbgPrint(1, ("FBTUSB: FreeNT_WriteCompletion - failed with status = %X\n", ntStatus
));
528 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: ::"));
529 FreeBT_IoDecrement(deviceExtension
);
531 ExFreePool(rwContext
->Urb
);
532 IoFreeMdl(rwContext
->Mdl
);
533 ExFreePool(rwContext
);
538 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Leaving\n"));