* Sync up to trunk head (r64716).
[reactos.git] / drivers / bluetooth / fbtusb / fbtrwr.c
1 // Copyright (c) 2004, Antony C. Roberts
2
3 // Use of this file is subject to the terms
4 // described in the LICENSE.TXT file that
5 // accompanies this file.
6 //
7 // Your use of this file indicates your
8 // acceptance of the terms described in
9 // LICENSE.TXT.
10 //
11 // http://www.freebt.net
12
13 #include "fbtusb.h"
14 #include "fbtpnp.h"
15 #include "fbtpwr.h"
16 #include "fbtdev.h"
17 #include "fbtrwr.h"
18 #include "fbtwmi.h"
19
20 #include "fbtusr.h"
21
22 // Read/Write handler
23 NTSTATUS NTAPI FreeBT_DispatchRead(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
24 {
25 PMDL mdl;
26 PURB urb;
27 ULONG totalLength;
28 ULONG stageLength;
29 NTSTATUS ntStatus;
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;
36 //ULONG maxLength=0;
37
38 urb = NULL;
39 mdl = NULL;
40 rwContext = NULL;
41 totalLength = 0;
42 irpStack = IoGetCurrentIrpStackLocation(Irp);
43 fileObject = irpStack->FileObject;
44 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
45
46 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Entered\n"));
47
48 if (deviceExtension->DeviceState != Working)
49 {
50 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Invalid device state\n"));
51 ntStatus = STATUS_INVALID_DEVICE_STATE;
52 goto FreeBT_DispatchRead_Exit;
53
54 }
55
56 // Make sure that any selective suspend request has been completed.
57 if (deviceExtension->SSEnable)
58 {
59 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: Waiting on the IdleReqPendEvent\n"));
60 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
61 Executive,
62 KernelMode,
63 FALSE,
64 NULL);
65
66 }
67
68 rwContext = (PFREEBT_RW_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(FREEBT_RW_CONTEXT));
69 if (rwContext == NULL)
70 {
71 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for rwContext\n"));
72 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
73 goto FreeBT_DispatchRead_Exit;
74
75 }
76
77 if (Irp->MdlAddress)
78 {
79 totalLength = MmGetMdlByteCount(Irp->MdlAddress);
80
81 }
82
83 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Transfer data length = %d\n", totalLength));
84 if (totalLength == 0)
85 {
86 ntStatus = STATUS_SUCCESS;
87 ExFreePool(rwContext);
88 goto FreeBT_DispatchRead_Exit;
89
90 }
91
92 virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
93 if (totalLength > deviceExtension->DataInPipe.MaximumPacketSize)
94 {
95 stageLength = deviceExtension->DataInPipe.MaximumPacketSize;
96
97 }
98
99 else
100 {
101 stageLength = totalLength;
102
103 }
104
105 mdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL);
106 if (mdl == NULL)
107 {
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;
112
113 }
114
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));
118 if (urb == NULL)
119 {
120 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: Failed to alloc mem for urb\n"));
121 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
122 ExFreePool(rwContext);
123 IoFreeMdl(mdl);
124 goto FreeBT_DispatchRead_Exit;
125
126 }
127
128 UsbBuildInterruptOrBulkTransferRequest(
129 urb,
130 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
131 deviceExtension->DataInPipe.PipeHandle,
132 NULL,
133 mdl,
134 stageLength,
135 USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_IN,
136 NULL);
137
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;
144
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,
152 rwContext,
153 TRUE,
154 TRUE,
155 TRUE);
156
157 // We return STATUS_PENDING; call IoMarkIrpPending.
158 IoMarkIrpPending(Irp);
159
160 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
161 if (!NT_SUCCESS(ntStatus))
162 {
163 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: IoCallDriver fails with status %X\n", ntStatus));
164
165 // if the device was yanked out, then the pipeInformation
166 // field is invalid.
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))
170 {
171 ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->DataInPipe.PipeHandle);
172 if(!NT_SUCCESS(ntStatus))
173 {
174 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_DispatchRead: FreeBT_ResetPipe failed\n"));
175 ntStatus = FreeBT_ResetDevice(DeviceObject);
176
177 }
178
179 }
180
181 else
182 {
183 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
184
185 }
186
187 }
188
189 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead::"));
190 FreeBT_IoIncrement(deviceExtension);
191
192 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchRead: URB sent to lower driver, IRP is pending\n"));
193
194 // we return STATUS_PENDING and not the status returned by the lower layer.
195 return STATUS_PENDING;
196
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"));
202
203 return ntStatus;
204
205 }
206
207 NTSTATUS NTAPI FreeBT_ReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
208 {
209 //ULONG stageLength;
210 NTSTATUS ntStatus;
211 //PIO_STACK_LOCATION nextStack;
212 PFREEBT_RW_CONTEXT rwContext;
213 PDEVICE_EXTENSION deviceExtension;
214
215 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
216 rwContext = (PFREEBT_RW_CONTEXT) Context;
217 ntStatus = Irp->IoStatus.Status;
218
219 UNREFERENCED_PARAMETER(DeviceObject);
220 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Entered\n"));
221
222 if (NT_SUCCESS(ntStatus))
223 {
224 Irp->IoStatus.Information = rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
225
226 }
227
228 else
229 {
230 Irp->IoStatus.Information = 0;
231 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ReadCompletion: - failed with status = %X\n", ntStatus));
232
233 }
234
235 if (rwContext)
236 {
237 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: ::"));
238 FreeBT_IoDecrement(deviceExtension);
239
240 ExFreePool(rwContext->Urb);
241 IoFreeMdl(rwContext->Mdl);
242 ExFreePool(rwContext);
243
244 }
245
246 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_ReadCompletion: Leaving\n"));
247
248 return ntStatus;
249
250 }
251
252 // Read/Write handler
253 NTSTATUS NTAPI FreeBT_DispatchWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
254 {
255 PMDL mdl;
256 PURB urb;
257 ULONG totalLength;
258 ULONG stageLength;
259 NTSTATUS ntStatus;
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;
266 //ULONG maxLength=0;
267
268 urb = NULL;
269 mdl = NULL;
270 rwContext = NULL;
271 totalLength = 0;
272 irpStack = IoGetCurrentIrpStackLocation(Irp);
273 fileObject = irpStack->FileObject;
274 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
275
276 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: Entered\n"));
277
278 if (deviceExtension->DeviceState != Working)
279 {
280 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Invalid device state\n"));
281 ntStatus = STATUS_INVALID_DEVICE_STATE;
282 goto FreeBT_DispatchWrite_Exit;
283
284 }
285
286 // Make sure that any selective suspend request has been completed.
287 if (deviceExtension->SSEnable)
288 {
289 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteDispatch: Waiting on the IdleReqPendEvent\n"));
290 KeWaitForSingleObject(&deviceExtension->NoIdleReqPendEvent,
291 Executive,
292 KernelMode,
293 FALSE,
294 NULL);
295
296 }
297
298 rwContext = (PFREEBT_RW_CONTEXT) ExAllocatePool(NonPagedPool, sizeof(FREEBT_RW_CONTEXT));
299 if (rwContext == NULL)
300 {
301 FreeBT_DbgPrint(1, ("FBTUSB: Failed to alloc mem for rwContext\n"));
302 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
303 goto FreeBT_DispatchWrite_Exit;
304
305 }
306
307 if (Irp->MdlAddress)
308 {
309 totalLength = MmGetMdlByteCount(Irp->MdlAddress);
310
311 }
312
313 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Transfer data length = %d\n", totalLength));
314 if (totalLength>FBT_HCI_DATA_MAX_SIZE)
315 {
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;
320
321 }
322
323 if (totalLength<FBT_HCI_DATA_MIN_SIZE)
324 {
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;
329
330 }
331
332 virtualAddress = (ULONG_PTR) MmGetMdlVirtualAddress(Irp->MdlAddress);
333 if (totalLength > deviceExtension->DataOutPipe.MaximumPacketSize)
334 {
335 stageLength = deviceExtension->DataOutPipe.MaximumPacketSize;
336
337 }
338
339 else
340 {
341 stageLength = totalLength;
342
343 }
344
345 mdl = IoAllocateMdl((PVOID) virtualAddress, totalLength, FALSE, FALSE, NULL);
346 if (mdl == NULL)
347 {
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;
352
353 }
354
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));
358 if (urb == NULL)
359 {
360 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: Failed to alloc mem for urb\n"));
361 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
362 ExFreePool(rwContext);
363 IoFreeMdl(mdl);
364 goto FreeBT_DispatchWrite_Exit;
365
366 }
367
368 UsbBuildInterruptOrBulkTransferRequest(
369 urb,
370 sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER),
371 deviceExtension->DataOutPipe.PipeHandle,
372 NULL,
373 mdl,
374 stageLength,
375 USBD_SHORT_TRANSFER_OK | USBD_TRANSFER_DIRECTION_OUT,
376 NULL);
377
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;
384
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,
392 rwContext,
393 TRUE,
394 TRUE,
395 TRUE);
396
397 // We return STATUS_PENDING; call IoMarkIrpPending.
398 IoMarkIrpPending(Irp);
399
400 ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
401 if (!NT_SUCCESS(ntStatus))
402 {
403 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_WriteDispatch: IoCallDriver fails with status %X\n", ntStatus));
404
405 // if the device was yanked out, then the pipeInformation
406 // field is invalid.
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))
410 {
411 ntStatus = FreeBT_ResetPipe(DeviceObject, deviceExtension->DataOutPipe.PipeHandle);
412 if(!NT_SUCCESS(ntStatus))
413 {
414 FreeBT_DbgPrint(1, ("FBTUSB: FreeBT_ResetPipe failed\n"));
415 ntStatus = FreeBT_ResetDevice(DeviceObject);
416
417 }
418
419 }
420
421 else
422 {
423 FreeBT_DbgPrint(3, ("FBTUSB: ntStatus is STATUS_CANCELLED or STATUS_DEVICE_NOT_CONNECTED\n"));
424
425 }
426
427 }
428
429 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite::"));
430 FreeBT_IoIncrement(deviceExtension);
431
432 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_DispatchWrite: URB sent to lower driver, IRP is pending\n"));
433
434 // we return STATUS_PENDING and not the status returned by the lower layer.
435 return STATUS_PENDING;
436
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"));
442
443 return ntStatus;
444
445 }
446
447 NTSTATUS NTAPI FreeBT_WriteCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
448 {
449 ULONG stageLength;
450 NTSTATUS ntStatus;
451 PIO_STACK_LOCATION nextStack;
452 PFREEBT_RW_CONTEXT rwContext;
453 PDEVICE_EXTENSION deviceExtension;
454
455 deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
456 rwContext = (PFREEBT_RW_CONTEXT) Context;
457 ntStatus = Irp->IoStatus.Status;
458
459 UNREFERENCED_PARAMETER(DeviceObject);
460 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Entered\n"));
461
462 if (NT_SUCCESS(ntStatus))
463 {
464 if (rwContext)
465 {
466 rwContext->Numxfer += rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
467 if (rwContext->Length)
468 {
469 // More data to transfer
470 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Initiating next transfer\n"));
471 if (rwContext->Length > deviceExtension->DataOutPipe.MaximumPacketSize)
472 {
473 stageLength = deviceExtension->DataOutPipe.MaximumPacketSize;
474
475 }
476
477 else
478 {
479 stageLength = rwContext->Length;
480
481 }
482
483 IoBuildPartialMdl(Irp->MdlAddress, rwContext->Mdl, (PVOID) rwContext->VirtualAddress, stageLength);
484
485 // reinitialize the urb
486 rwContext->Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = stageLength;
487 rwContext->VirtualAddress += stageLength;
488 rwContext->Length -= stageLength;
489
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;
494
495 IoSetCompletionRoutine(Irp,
496 FreeBT_ReadCompletion,
497 rwContext,
498 TRUE,
499 TRUE,
500 TRUE);
501
502 IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
503
504 return STATUS_MORE_PROCESSING_REQUIRED;
505
506 }
507
508 else
509 {
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;
513
514 }
515
516 }
517
518 }
519
520 else
521 {
522 FreeBT_DbgPrint(1, ("FBTUSB: FreeNT_WriteCompletion - failed with status = %X\n", ntStatus));
523
524 }
525
526 if (rwContext)
527 {
528 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: ::"));
529 FreeBT_IoDecrement(deviceExtension);
530
531 ExFreePool(rwContext->Urb);
532 IoFreeMdl(rwContext->Mdl);
533 ExFreePool(rwContext);
534
535 }
536
537
538 FreeBT_DbgPrint(3, ("FBTUSB: FreeBT_WriteCompletion: Leaving\n"));
539
540 return ntStatus;
541
542 }
543