xref: /reactos/drivers/bluetooth/fbtusb/fbtrwr.c (revision 40462c92)
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 
544