VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/win/dev/VBoxUsbRt.cpp@ 78097

Last change on this file since 78097 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.3 KB
Line 
1/* $Id: VBoxUsbRt.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBox USB R0 runtime
4 */
5
6/*
7 * Copyright (C) 2011-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "VBoxUsbCmn.h"
32#include "../cmn/VBoxUsbIdc.h"
33#include "../cmn/VBoxUsbTool.h"
34
35#include <VBox/usblib-win.h>
36#include <iprt/assert.h>
37#include <VBox/log.h>
38
39
40/*********************************************************************************************************************************
41* Defined Constants And Macros *
42*********************************************************************************************************************************/
43#define _USBD_ /** @todo r=bird: What is this?? */
44
45#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008
46
47#define VBOXUSB_MAGIC 0xABCF1423
48
49
50/*********************************************************************************************************************************
51* Structures and Typedefs *
52*********************************************************************************************************************************/
53typedef struct VBOXUSB_URB_CONTEXT
54{
55 PURB pUrb;
56 PMDL pMdlBuf;
57 PVBOXUSBDEV_EXT pDevExt;
58 PVOID pOut;
59 ULONG ulTransferType;
60 ULONG ulMagic;
61} VBOXUSB_URB_CONTEXT, * PVBOXUSB_URB_CONTEXT;
62
63typedef struct VBOXUSB_SETUP
64{
65 uint8_t bmRequestType;
66 uint8_t bRequest;
67 uint16_t wValue;
68 uint16_t wIndex;
69 uint16_t wLength;
70} VBOXUSB_SETUP, *PVBOXUSB_SETUP;
71
72
73
74static bool vboxUsbRtCtxSetOwner(PVBOXUSBDEV_EXT pDevExt, PFILE_OBJECT pFObj)
75{
76 bool fRc = ASMAtomicCmpXchgPtr(&pDevExt->Rt.pOwner, pFObj, NULL);
77 if (fRc)
78 LogFunc(("pDevExt (0x%x) Owner(0x%x) acquired\n", pFObj));
79 else
80 LogFunc(("pDevExt (0x%x) Owner(0x%x) FAILED!!\n", pFObj));
81 return fRc;
82}
83
84static bool vboxUsbRtCtxReleaseOwner(PVBOXUSBDEV_EXT pDevExt, PFILE_OBJECT pFObj)
85{
86 bool fRc = ASMAtomicCmpXchgPtr(&pDevExt->Rt.pOwner, NULL, pFObj);
87 if (fRc)
88 LogFunc(("pDevExt (0x%x) Owner(0x%x) released\n", pFObj));
89 else
90 LogFunc(("pDevExt (0x%x) Owner(0x%x) release: is NOT an owner\n", pFObj));
91 return fRc;
92}
93
94static bool vboxUsbRtCtxIsOwner(PVBOXUSBDEV_EXT pDevExt, PFILE_OBJECT pFObj)
95{
96 PFILE_OBJECT pOwner = (PFILE_OBJECT)ASMAtomicReadPtr((void *volatile *)(&pDevExt->Rt.pOwner));
97 return pOwner == pFObj;
98}
99
100static NTSTATUS vboxUsbRtIdcSubmit(ULONG uCtl, void *pvBuffer)
101{
102 /* we just reuse the standard usb tooling for simplicity here */
103 NTSTATUS Status = VBoxUsbToolIoInternalCtlSendSync(g_VBoxUsbGlobals.RtIdc.pDevice, uCtl, pvBuffer, NULL);
104 Assert(Status == STATUS_SUCCESS);
105 return Status;
106}
107
108static NTSTATUS vboxUsbRtIdcInit()
109{
110 UNICODE_STRING UniName;
111 RtlInitUnicodeString(&UniName, USBMON_DEVICE_NAME_NT);
112 NTSTATUS Status = IoGetDeviceObjectPointer(&UniName, FILE_ALL_ACCESS, &g_VBoxUsbGlobals.RtIdc.pFile, &g_VBoxUsbGlobals.RtIdc.pDevice);
113 if (NT_SUCCESS(Status))
114 {
115 VBOXUSBIDC_VERSION Version;
116 vboxUsbRtIdcSubmit(VBOXUSBIDC_INTERNAL_IOCTL_GET_VERSION, &Version);
117 if (NT_SUCCESS(Status))
118 {
119 if ( Version.u32Major == VBOXUSBIDC_VERSION_MAJOR
120#if VBOXUSBIDC_VERSION_MINOR != 0
121 && Version.u32Minor >= VBOXUSBIDC_VERSION_MINOR
122#endif
123 )
124 return STATUS_SUCCESS;
125 AssertFailed();
126 }
127 else
128 {
129 AssertFailed();
130 }
131
132 /* this will as well dereference the dev obj */
133 ObDereferenceObject(g_VBoxUsbGlobals.RtIdc.pFile);
134 }
135 else
136 {
137 AssertFailed();
138 }
139
140 memset(&g_VBoxUsbGlobals.RtIdc, 0, sizeof (g_VBoxUsbGlobals.RtIdc));
141 return Status;
142}
143
144static VOID vboxUsbRtIdcTerm()
145{
146 Assert(g_VBoxUsbGlobals.RtIdc.pFile);
147 Assert(g_VBoxUsbGlobals.RtIdc.pDevice);
148 ObDereferenceObject(g_VBoxUsbGlobals.RtIdc.pFile);
149 memset(&g_VBoxUsbGlobals.RtIdc, 0, sizeof (g_VBoxUsbGlobals.RtIdc));
150}
151
152static NTSTATUS vboxUsbRtIdcReportDevStart(PDEVICE_OBJECT pPDO, HVBOXUSBIDCDEV *phDev)
153{
154 VBOXUSBIDC_PROXY_STARTUP Start;
155 Start.u.pPDO = pPDO;
156
157 *phDev = NULL;
158
159 NTSTATUS Status = vboxUsbRtIdcSubmit(VBOXUSBIDC_INTERNAL_IOCTL_PROXY_STARTUP, &Start);
160 Assert(Status == STATUS_SUCCESS);
161 if (!NT_SUCCESS(Status))
162 return Status;
163
164 *phDev = Start.u.hDev;
165 return STATUS_SUCCESS;
166}
167
168static NTSTATUS vboxUsbRtIdcReportDevStop(HVBOXUSBIDCDEV hDev)
169{
170 VBOXUSBIDC_PROXY_TEARDOWN Stop;
171 Stop.hDev = hDev;
172
173 NTSTATUS Status = vboxUsbRtIdcSubmit(VBOXUSBIDC_INTERNAL_IOCTL_PROXY_TEARDOWN, &Stop);
174 Assert(Status == STATUS_SUCCESS);
175 return Status;
176}
177
178
179DECLHIDDEN(NTSTATUS) vboxUsbRtGlobalsInit()
180{
181 return vboxUsbRtIdcInit();
182}
183
184DECLHIDDEN(VOID) vboxUsbRtGlobalsTerm()
185{
186 vboxUsbRtIdcTerm();
187}
188
189
190DECLHIDDEN(NTSTATUS) vboxUsbRtInit(PVBOXUSBDEV_EXT pDevExt)
191{
192 RtlZeroMemory(&pDevExt->Rt, sizeof (pDevExt->Rt));
193 NTSTATUS Status = IoRegisterDeviceInterface(pDevExt->pPDO, &GUID_CLASS_VBOXUSB,
194 NULL, /* IN PUNICODE_STRING ReferenceString OPTIONAL */
195 &pDevExt->Rt.IfName);
196 Assert(Status == STATUS_SUCCESS);
197 if (NT_SUCCESS(Status))
198 {
199 Status = vboxUsbRtIdcReportDevStart(pDevExt->pPDO, &pDevExt->Rt.hMonDev);
200 Assert(Status == STATUS_SUCCESS);
201 if (NT_SUCCESS(Status))
202 {
203 Assert(pDevExt->Rt.hMonDev);
204 return STATUS_SUCCESS;
205 }
206
207 NTSTATUS tmpStatus = IoSetDeviceInterfaceState(&pDevExt->Rt.IfName, FALSE);
208 Assert(tmpStatus == STATUS_SUCCESS);
209 if (NT_SUCCESS(tmpStatus))
210 {
211 RtlFreeUnicodeString(&pDevExt->Rt.IfName);
212 }
213 }
214 return Status;
215}
216
217/**
218 * Free cached USB device/configuration descriptors
219 *
220 * @param pDevExt USB DevExt pointer
221 */
222static void vboxUsbRtFreeCachedDescriptors(PVBOXUSBDEV_EXT pDevExt)
223{
224 if (pDevExt->Rt.devdescr)
225 {
226 vboxUsbMemFree(pDevExt->Rt.devdescr);
227 pDevExt->Rt.devdescr = NULL;
228 }
229 for (ULONG i = 0; i < VBOXUSBRT_MAX_CFGS; ++i)
230 {
231 if (pDevExt->Rt.cfgdescr[i])
232 {
233 vboxUsbMemFree(pDevExt->Rt.cfgdescr[i]);
234 pDevExt->Rt.cfgdescr[i] = NULL;
235 }
236 }
237}
238
239/**
240 * Free per-device interface info
241 *
242 * @param pDevExt USB DevExt pointer
243 * @param fAbortPipes If true, also abort any open pipes
244 */
245static void vboxUsbRtFreeInterfaces(PVBOXUSBDEV_EXT pDevExt, BOOLEAN fAbortPipes)
246{
247 unsigned i;
248 unsigned j;
249
250 /*
251 * Free old interface info
252 */
253 if (pDevExt->Rt.pVBIfaceInfo)
254 {
255 for (i=0;i<pDevExt->Rt.uNumInterfaces;i++)
256 {
257 if (pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo)
258 {
259 if (fAbortPipes)
260 {
261 for (j=0; j<pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->NumberOfPipes; j++)
262 {
263 Log(("Aborting Pipe %d handle %x address %x\n", j,
264 pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].PipeHandle,
265 pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].EndpointAddress));
266 VBoxUsbToolPipeClear(pDevExt->pLowerDO, pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].PipeHandle, FALSE);
267 }
268 }
269 vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo);
270 }
271 pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo = NULL;
272 if (pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo)
273 vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo);
274 pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo = NULL;
275 }
276 vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo);
277 pDevExt->Rt.pVBIfaceInfo = NULL;
278 }
279}
280
281DECLHIDDEN(VOID) vboxUsbRtClear(PVBOXUSBDEV_EXT pDevExt)
282{
283 vboxUsbRtFreeCachedDescriptors(pDevExt);
284 vboxUsbRtFreeInterfaces(pDevExt, FALSE);
285}
286
287DECLHIDDEN(NTSTATUS) vboxUsbRtRm(PVBOXUSBDEV_EXT pDevExt)
288{
289 if (!pDevExt->Rt.IfName.Buffer)
290 return STATUS_SUCCESS;
291
292 NTSTATUS Status = vboxUsbRtIdcReportDevStop(pDevExt->Rt.hMonDev);
293 Assert(Status == STATUS_SUCCESS);
294 Status = IoSetDeviceInterfaceState(&pDevExt->Rt.IfName, FALSE);
295 Assert(Status == STATUS_SUCCESS);
296 if (NT_SUCCESS(Status))
297 {
298 RtlFreeUnicodeString(&pDevExt->Rt.IfName);
299 pDevExt->Rt.IfName.Buffer = NULL;
300 }
301 return Status;
302}
303
304DECLHIDDEN(NTSTATUS) vboxUsbRtStart(PVBOXUSBDEV_EXT pDevExt)
305{
306 NTSTATUS Status = IoSetDeviceInterfaceState(&pDevExt->Rt.IfName, TRUE);
307 Assert(Status == STATUS_SUCCESS);
308 return Status;
309}
310
311static NTSTATUS vboxUsbRtCacheDescriptors(PVBOXUSBDEV_EXT pDevExt)
312{
313 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
314// uint32_t uTotalLength;
315// unsigned i;
316
317 /* Read device descriptor */
318 Assert(!pDevExt->Rt.devdescr);
319 pDevExt->Rt.devdescr = (PUSB_DEVICE_DESCRIPTOR)vboxUsbMemAlloc(sizeof (USB_DEVICE_DESCRIPTOR));
320 if (pDevExt->Rt.devdescr)
321 {
322 memset(pDevExt->Rt.devdescr, 0, sizeof (USB_DEVICE_DESCRIPTOR));
323 Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDevExt->Rt.devdescr, sizeof (USB_DEVICE_DESCRIPTOR), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, RT_INDEFINITE_WAIT);
324 if (NT_SUCCESS(Status))
325 {
326 Assert(pDevExt->Rt.devdescr->bNumConfigurations > 0);
327 PUSB_CONFIGURATION_DESCRIPTOR pDr = (PUSB_CONFIGURATION_DESCRIPTOR)vboxUsbMemAlloc(sizeof (USB_CONFIGURATION_DESCRIPTOR));
328 Assert(pDr);
329 if (pDr)
330 {
331 UCHAR i = 0;
332 for (; i < pDevExt->Rt.devdescr->bNumConfigurations; ++i)
333 {
334 Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDr, sizeof (USB_CONFIGURATION_DESCRIPTOR), USB_CONFIGURATION_DESCRIPTOR_TYPE, i, 0, RT_INDEFINITE_WAIT);
335 if (!NT_SUCCESS(Status))
336 {
337 break;
338 }
339
340 USHORT uTotalLength = pDr->wTotalLength;
341 pDevExt->Rt.cfgdescr[i] = (PUSB_CONFIGURATION_DESCRIPTOR)vboxUsbMemAlloc(uTotalLength);
342 if (!pDevExt->Rt.cfgdescr[i])
343 {
344 Status = STATUS_INSUFFICIENT_RESOURCES;
345 break;
346 }
347
348 Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDevExt->Rt.cfgdescr[i], uTotalLength, USB_CONFIGURATION_DESCRIPTOR_TYPE, i, 0, RT_INDEFINITE_WAIT);
349 if (!NT_SUCCESS(Status))
350 {
351 break;
352 }
353 }
354
355 vboxUsbMemFree(pDr);
356
357 if (NT_SUCCESS(Status))
358 return Status;
359
360 /* recources will be freed in vboxUsbRtFreeCachedDescriptors below */
361 }
362 }
363
364 vboxUsbRtFreeCachedDescriptors(pDevExt);
365 }
366
367 /* shoud be only on fail here */
368 Assert(!NT_SUCCESS(Status));
369 return Status;
370}
371
372static NTSTATUS vboxUsbRtDispatchClaimDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
373{
374 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
375 PFILE_OBJECT pFObj = pSl->FileObject;
376 PUSBSUP_CLAIMDEV pDev = (PUSBSUP_CLAIMDEV)pIrp->AssociatedIrp.SystemBuffer;
377 ULONG cbOut = 0;
378 NTSTATUS Status = STATUS_SUCCESS;
379
380 do
381 {
382 if (!pFObj)
383 {
384 AssertFailed();
385 Status = STATUS_INVALID_PARAMETER;
386 break;
387 }
388
389 if ( !pDev
390 || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pDev)
391 || pSl->Parameters.DeviceIoControl.OutputBufferLength != sizeof (*pDev))
392 {
393 AssertFailed();
394 Status = STATUS_INVALID_PARAMETER;
395 break;
396 }
397
398 if (!vboxUsbRtCtxSetOwner(pDevExt, pFObj))
399 {
400 AssertFailed();
401 pDev->fClaimed = false;
402 cbOut = sizeof (*pDev);
403 break;
404 }
405
406 vboxUsbRtFreeCachedDescriptors(pDevExt);
407 Status = vboxUsbRtCacheDescriptors(pDevExt);
408 if (NT_SUCCESS(Status))
409 {
410 pDev->fClaimed = true;
411 cbOut = sizeof (*pDev);
412 }
413 } while (0);
414
415 Assert(Status != STATUS_PENDING);
416 VBoxDrvToolIoComplete(pIrp, Status, cbOut);
417 vboxUsbDdiStateRelease(pDevExt);
418 return Status;
419}
420
421static NTSTATUS vboxUsbRtDispatchReleaseDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
422{
423 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
424 PFILE_OBJECT pFObj = pSl->FileObject;
425 NTSTATUS Status= STATUS_SUCCESS;
426
427 if (vboxUsbRtCtxIsOwner(pDevExt, pFObj))
428 {
429 vboxUsbRtFreeCachedDescriptors(pDevExt);
430 bool fRc = vboxUsbRtCtxReleaseOwner(pDevExt, pFObj);
431 Assert(fRc); NOREF(fRc);
432 }
433 else
434 {
435 AssertFailed();
436 Status = STATUS_ACCESS_DENIED;
437 }
438
439 VBoxDrvToolIoComplete(pIrp, STATUS_SUCCESS, 0);
440 vboxUsbDdiStateRelease(pDevExt);
441 return STATUS_SUCCESS;
442}
443
444static NTSTATUS vboxUsbRtGetDeviceDescription(PVBOXUSBDEV_EXT pDevExt)
445{
446 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
447 PUSB_DEVICE_DESCRIPTOR pDr = (PUSB_DEVICE_DESCRIPTOR)vboxUsbMemAllocZ(sizeof (USB_DEVICE_DESCRIPTOR));
448 if (pDr)
449 {
450 Status = VBoxUsbToolGetDescriptor(pDevExt->pLowerDO, pDr, sizeof(*pDr), USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, RT_INDEFINITE_WAIT);
451 if (NT_SUCCESS(Status))
452 {
453 pDevExt->Rt.idVendor = pDr->idVendor;
454 pDevExt->Rt.idProduct = pDr->idProduct;
455 pDevExt->Rt.bcdDevice = pDr->bcdDevice;
456 pDevExt->Rt.szSerial[0] = 0;
457
458 if (pDr->iSerialNumber
459#ifdef DEBUG
460 || pDr->iProduct || pDr->iManufacturer
461#endif
462 )
463 {
464 int langId;
465 Status = VBoxUsbToolGetLangID(pDevExt->pLowerDO, &langId, RT_INDEFINITE_WAIT);
466 if (NT_SUCCESS(Status))
467 {
468 Status = VBoxUsbToolGetStringDescriptor(pDevExt->pLowerDO, pDevExt->Rt.szSerial, sizeof (pDevExt->Rt.szSerial),
469 pDr->iSerialNumber, langId, RT_INDEFINITE_WAIT);
470 }
471 else
472 {
473 Status = STATUS_SUCCESS;
474 }
475 }
476 }
477 vboxUsbMemFree(pDr);
478 }
479
480 return Status;
481}
482
483static NTSTATUS vboxUsbRtDispatchGetDevice(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
484{
485 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
486 PUSBSUP_GETDEV pDev = (PUSBSUP_GETDEV)pIrp->AssociatedIrp.SystemBuffer;
487 ULONG cbOut = 0;
488
489 /* don't check for owner since this request is allowed for non-owners as well */
490 NTSTATUS Status;
491 if ( pDev
492 && pSl->Parameters.DeviceIoControl.InputBufferLength == sizeof(*pDev)
493 && pSl->Parameters.DeviceIoControl.OutputBufferLength == sizeof(*pDev))
494 {
495 /* Even if we don't return it, we need to query the HS flag for later use. */
496 Status = VBoxUsbToolGetDeviceSpeed(pDevExt->pLowerDO, &pDevExt->Rt.fIsHighSpeed);
497 if (NT_SUCCESS(Status))
498 {
499 pDev->hDevice = pDevExt->Rt.hMonDev;
500 cbOut = sizeof (*pDev);
501 }
502 }
503 else
504 Status = STATUS_INVALID_PARAMETER;
505
506 Assert(Status != STATUS_PENDING);
507 VBoxDrvToolIoComplete(pIrp, Status, cbOut);
508 vboxUsbDdiStateRelease(pDevExt);
509 return Status;
510}
511
512static NTSTATUS vboxUsbRtDispatchUsbReset(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
513{
514 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
515 PFILE_OBJECT pFObj = pSl->FileObject;
516 NTSTATUS rcNt;
517 if (pFObj)
518 {
519 if (vboxUsbRtCtxIsOwner(pDevExt, pFObj))
520 {
521 if ( pIrp->AssociatedIrp.SystemBuffer == NULL
522 && pSl->Parameters.DeviceIoControl.InputBufferLength == 0
523 && pSl->Parameters.DeviceIoControl.OutputBufferLength == 0)
524 {
525 rcNt = VBoxUsbToolIoInternalCtlSendSync(pDevExt->pLowerDO, IOCTL_INTERNAL_USB_RESET_PORT, NULL, NULL);
526 Assert(NT_SUCCESS(rcNt));
527 }
528 else
529 {
530 AssertFailed();
531 rcNt = STATUS_INVALID_PARAMETER;
532 }
533 }
534 else
535 {
536 AssertFailed();
537 rcNt = STATUS_ACCESS_DENIED;
538 }
539 }
540 else
541 {
542 AssertFailed();
543 rcNt = STATUS_INVALID_PARAMETER;
544 }
545
546 Assert(rcNt != STATUS_PENDING);
547 VBoxDrvToolIoComplete(pIrp, rcNt, 0);
548 vboxUsbDdiStateRelease(pDevExt);
549 return rcNt;
550}
551
552static PUSB_CONFIGURATION_DESCRIPTOR vboxUsbRtFindConfigDesc(PVBOXUSBDEV_EXT pDevExt, uint8_t uConfiguration)
553{
554 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = NULL;
555
556 for (ULONG i = 0; i < VBOXUSBRT_MAX_CFGS; ++i)
557 {
558 if (pDevExt->Rt.cfgdescr[i])
559 {
560 if (pDevExt->Rt.cfgdescr[i]->bConfigurationValue == uConfiguration)
561 {
562 pCfgDr = pDevExt->Rt.cfgdescr[i];
563 break;
564 }
565 }
566 }
567
568 return pCfgDr;
569}
570
571static NTSTATUS vboxUsbRtSetConfig(PVBOXUSBDEV_EXT pDevExt, uint8_t uConfiguration)
572{
573 PURB pUrb = NULL;
574 NTSTATUS Status = STATUS_SUCCESS;
575 uint32_t i;
576
577 if (!uConfiguration)
578 {
579 pUrb = VBoxUsbToolUrbAllocZ(URB_FUNCTION_SELECT_CONFIGURATION, sizeof (struct _URB_SELECT_CONFIGURATION));
580 if (!pUrb)
581 {
582 AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbAlloc failed\n"));
583 return STATUS_INSUFFICIENT_RESOURCES;
584 }
585
586 vboxUsbRtFreeInterfaces(pDevExt, TRUE);
587
588 pUrb->UrbSelectConfiguration.ConfigurationDescriptor = NULL;
589
590 Status = VBoxUsbToolUrbPost(pDevExt->pLowerDO, pUrb, RT_INDEFINITE_WAIT);
591 if (NT_SUCCESS(Status) && USBD_SUCCESS(pUrb->UrbHeader.Status))
592 {
593 pDevExt->Rt.hConfiguration = pUrb->UrbSelectConfiguration.ConfigurationHandle;
594 pDevExt->Rt.uConfigValue = uConfiguration;
595 }
596 else
597 {
598 AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbPost failed Status (0x%x), usb Status (0x%x)\n", Status, pUrb->UrbHeader.Status));
599 }
600
601 VBoxUsbToolUrbFree(pUrb);
602
603 return Status;
604 }
605
606/** @todo r=bird: Need to write a script for fixing these kind of clueless use
607 * of AssertMsgFailed (into AssertMsgReturn). The __FUNCTION__ is just
608 * the topping it off - the assertion message includes function, file and
609 * line number. Duh! */
610 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = vboxUsbRtFindConfigDesc(pDevExt, uConfiguration);
611 if (!pCfgDr)
612 {
613 AssertMsgFailed((__FUNCTION__": VBoxUSBFindConfigDesc did not find cfg (%d)\n", uConfiguration));
614 return STATUS_INVALID_PARAMETER;
615 }
616
617 PUSBD_INTERFACE_LIST_ENTRY pIfLe = (PUSBD_INTERFACE_LIST_ENTRY)vboxUsbMemAllocZ((pCfgDr->bNumInterfaces + 1) * sizeof(USBD_INTERFACE_LIST_ENTRY));
618 if (!pIfLe)
619 {
620 AssertMsgFailed((__FUNCTION__": vboxUsbMemAllocZ for pIfLe failed\n"));
621 return STATUS_INSUFFICIENT_RESOURCES;
622 }
623
624 for (i = 0; i < pCfgDr->bNumInterfaces; i++)
625 {
626 pIfLe[i].InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(pCfgDr, pCfgDr, i, 0, -1, -1, -1);
627 if (!pIfLe[i].InterfaceDescriptor)
628 {
629 AssertMsgFailed((__FUNCTION__": interface %d not found\n", i));
630 Status = STATUS_INVALID_PARAMETER;
631 break;
632 }
633 }
634 pIfLe[pCfgDr->bNumInterfaces].InterfaceDescriptor = NULL;
635
636 if (NT_SUCCESS(Status))
637 {
638 pUrb = USBD_CreateConfigurationRequestEx(pCfgDr, pIfLe);
639 if (pUrb)
640 {
641 Status = VBoxUsbToolUrbPost(pDevExt->pLowerDO, pUrb, RT_INDEFINITE_WAIT);
642 if (NT_SUCCESS(Status) && USBD_SUCCESS(pUrb->UrbHeader.Status))
643 {
644 vboxUsbRtFreeInterfaces(pDevExt, FALSE);
645
646 pDevExt->Rt.hConfiguration = pUrb->UrbSelectConfiguration.ConfigurationHandle;
647 pDevExt->Rt.uConfigValue = uConfiguration;
648 pDevExt->Rt.uNumInterfaces = pCfgDr->bNumInterfaces;
649
650 pDevExt->Rt.pVBIfaceInfo = (VBOXUSB_IFACE_INFO*)vboxUsbMemAllocZ(pDevExt->Rt.uNumInterfaces * sizeof (VBOXUSB_IFACE_INFO));
651 if (pDevExt->Rt.pVBIfaceInfo)
652 {
653 Assert(NT_SUCCESS(Status));
654 for (i = 0; i < pDevExt->Rt.uNumInterfaces; i++)
655 {
656 size_t uTotalIfaceInfoLength = GET_USBD_INTERFACE_SIZE(pIfLe[i].Interface->NumberOfPipes);
657 pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo = (PUSBD_INTERFACE_INFORMATION)vboxUsbMemAlloc(uTotalIfaceInfoLength);
658 if (!pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo)
659 {
660 AssertMsgFailed((__FUNCTION__": vboxUsbMemAlloc failed\n"));
661 Status = STATUS_INSUFFICIENT_RESOURCES;
662 break;
663 }
664
665 if (pIfLe[i].Interface->NumberOfPipes > 0)
666 {
667 pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo = (VBOXUSB_PIPE_INFO *)vboxUsbMemAlloc(pIfLe[i].Interface->NumberOfPipes * sizeof(VBOXUSB_PIPE_INFO));
668 if (!pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo)
669 {
670 AssertMsgFailed((__FUNCTION__": vboxUsbMemAlloc failed\n"));
671 Status = STATUS_NO_MEMORY;
672 break;
673 }
674 }
675 else
676 {
677 pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo = NULL;
678 }
679
680 RtlCopyMemory(pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo, pIfLe[i].Interface, uTotalIfaceInfoLength);
681
682 for (ULONG j = 0; j < pIfLe[i].Interface->NumberOfPipes; j++)
683 {
684 pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j].EndpointAddress = pIfLe[i].Interface->Pipes[j].EndpointAddress;
685 pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j].NextScheduledFrame = 0;
686 }
687 }
688
689// if (NT_SUCCESS(Status))
690// {
691//
692// }
693 }
694 else
695 {
696 AssertMsgFailed((__FUNCTION__": vboxUsbMemAllocZ failed\n"));
697 Status = STATUS_NO_MEMORY;
698 }
699 }
700 else
701 {
702 AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbPost failed Status (0x%x), usb Status (0x%x)\n", Status, pUrb->UrbHeader.Status));
703 }
704 ExFreePool(pUrb);
705 }
706 else
707 {
708 AssertMsgFailed((__FUNCTION__": USBD_CreateConfigurationRequestEx failed\n"));
709 Status = STATUS_INSUFFICIENT_RESOURCES;
710 }
711 }
712
713 vboxUsbMemFree(pIfLe);
714
715 return Status;
716}
717
718static NTSTATUS vboxUsbRtDispatchUsbSetConfig(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
719{
720 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
721 PFILE_OBJECT pFObj = pSl->FileObject;
722 PUSBSUP_SET_CONFIG pCfg = (PUSBSUP_SET_CONFIG)pIrp->AssociatedIrp.SystemBuffer;
723 NTSTATUS Status = STATUS_SUCCESS;
724
725 do
726 {
727 if (!pFObj)
728 {
729 AssertFailed();
730 Status = STATUS_INVALID_PARAMETER;
731 break;
732 }
733
734 if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj))
735 {
736 AssertFailed();
737 Status = STATUS_ACCESS_DENIED;
738 break;
739 }
740
741 if ( !pCfg
742 || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pCfg)
743 || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0)
744 {
745 AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n"));
746 Status = STATUS_INVALID_PARAMETER;
747 break;
748 }
749
750 Status = vboxUsbRtSetConfig(pDevExt, pCfg->bConfigurationValue);
751 } while (0);
752
753 Assert(Status != STATUS_PENDING);
754 VBoxDrvToolIoComplete(pIrp, Status, 0);
755 vboxUsbDdiStateRelease(pDevExt);
756 return Status;
757}
758
759static NTSTATUS vboxUsbRtSetInterface(PVBOXUSBDEV_EXT pDevExt, uint32_t InterfaceNumber, int AlternateSetting)
760{
761 AssertMsgReturn(pDevExt->Rt.uConfigValue, ("Can't select an interface without an active configuration\n"),
762 STATUS_INVALID_PARAMETER);
763 AssertMsgReturn(InterfaceNumber < pDevExt->Rt.uNumInterfaces, ("InterfaceNumber %d too high!!\n", InterfaceNumber),
764 STATUS_INVALID_PARAMETER);
765 PUSB_CONFIGURATION_DESCRIPTOR pCfgDr = vboxUsbRtFindConfigDesc(pDevExt, pDevExt->Rt.uConfigValue);
766 AssertMsgReturn(pCfgDr, ("configuration %d not found!!\n", pDevExt->Rt.uConfigValue),
767 STATUS_INVALID_PARAMETER);
768 PUSB_INTERFACE_DESCRIPTOR pIfDr = USBD_ParseConfigurationDescriptorEx(pCfgDr, pCfgDr, InterfaceNumber, AlternateSetting, -1, -1, -1);
769 AssertMsgReturn(pIfDr, ("invalid interface %d or alternate setting %d\n", InterfaceNumber, AlternateSetting),
770 STATUS_UNSUCCESSFUL);
771
772 USHORT uUrbSize = GET_SELECT_INTERFACE_REQUEST_SIZE(pIfDr->bNumEndpoints);
773 ULONG uTotalIfaceInfoLength = GET_USBD_INTERFACE_SIZE(pIfDr->bNumEndpoints);
774 NTSTATUS Status = STATUS_SUCCESS;
775 PURB pUrb;
776 PUSBD_INTERFACE_INFORMATION pNewIFInfo = NULL;
777 VBOXUSB_PIPE_INFO *pNewPipeInfo = NULL;
778
779 if (pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo)
780 {
781 /* Clear pipes associated with the interface, else Windows may hang. */
782 for (ULONG i = 0; i < pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo->NumberOfPipes; i++)
783 VBoxUsbToolPipeClear(pDevExt->pLowerDO, pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo->Pipes[i].PipeHandle, FALSE);
784 }
785
786 do {
787 /* First allocate all the structures we'll need. */
788 pUrb = VBoxUsbToolUrbAllocZ(0, uUrbSize);
789 if (!pUrb)
790 {
791 AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbAllocZ failed\n"));
792 Status = STATUS_NO_MEMORY;
793 break;
794 }
795
796 pNewIFInfo = (PUSBD_INTERFACE_INFORMATION)vboxUsbMemAlloc(uTotalIfaceInfoLength);
797 if (!pNewIFInfo)
798 {
799 AssertMsgFailed((__FUNCTION__": Failed allocating interface storage\n"));
800 Status = STATUS_NO_MEMORY;
801 break;
802 }
803
804 if (pIfDr->bNumEndpoints > 0)
805 {
806 pNewPipeInfo = (VBOXUSB_PIPE_INFO *)vboxUsbMemAlloc(pIfDr->bNumEndpoints * sizeof(VBOXUSB_PIPE_INFO));
807 if (!pNewPipeInfo)
808 {
809 AssertMsgFailed((__FUNCTION__": Failed allocating pipe info storage\n"));
810 Status = STATUS_NO_MEMORY;
811 break;
812 }
813 }
814 else
815 pNewPipeInfo = NULL;
816
817 /* Now that we have all the bits, select the interface. */
818 UsbBuildSelectInterfaceRequest(pUrb, uUrbSize, pDevExt->Rt.hConfiguration, InterfaceNumber, AlternateSetting);
819 pUrb->UrbSelectInterface.Interface.Length = GET_USBD_INTERFACE_SIZE(pIfDr->bNumEndpoints);
820
821 Status = VBoxUsbToolUrbPost(pDevExt->pLowerDO, pUrb, RT_INDEFINITE_WAIT);
822 if (NT_SUCCESS(Status) && USBD_SUCCESS(pUrb->UrbHeader.Status))
823 {
824 /* Free the old memory and put new in. */
825 if (pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo)
826 vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo);
827 pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo = pNewIFInfo;
828 if (pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo)
829 vboxUsbMemFree(pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo);
830 pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo = pNewPipeInfo;
831 pNewPipeInfo = NULL; pNewIFInfo = NULL; /* Don't try to free it again. */
832
833 USBD_INTERFACE_INFORMATION *pIfInfo = &pUrb->UrbSelectInterface.Interface;
834 memcpy(pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pInterfaceInfo, pIfInfo, GET_USBD_INTERFACE_SIZE(pIfDr->bNumEndpoints));
835
836 Assert(pIfInfo->NumberOfPipes == pIfDr->bNumEndpoints);
837 for (ULONG i = 0; i < pIfInfo->NumberOfPipes; i++)
838 {
839 pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo[i].EndpointAddress = pIfInfo->Pipes[i].EndpointAddress;
840 pDevExt->Rt.pVBIfaceInfo[InterfaceNumber].pPipeInfo[i].NextScheduledFrame = 0;
841 }
842 }
843 else
844 {
845 AssertMsgFailed((__FUNCTION__": VBoxUsbToolUrbPost failed Status (0x%x) usb Status (0x%x)\n", Status, pUrb->UrbHeader.Status));
846 }
847 } while (0);
848
849 /* Clean up. */
850 if (pUrb)
851 VBoxUsbToolUrbFree(pUrb);
852 if (pNewIFInfo)
853 vboxUsbMemFree(pNewIFInfo);
854 if (pNewPipeInfo)
855 vboxUsbMemFree(pNewPipeInfo);
856
857 return Status;
858}
859
860static NTSTATUS vboxUsbRtDispatchUsbSelectInterface(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
861{
862 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
863 PFILE_OBJECT pFObj = pSl->FileObject;
864 PUSBSUP_SELECT_INTERFACE pIf = (PUSBSUP_SELECT_INTERFACE)pIrp->AssociatedIrp.SystemBuffer;
865 NTSTATUS Status;
866
867 do
868 {
869 if (!pFObj)
870 {
871 AssertFailed();
872 Status = STATUS_INVALID_PARAMETER;
873 break;
874 }
875
876 if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj))
877 {
878 AssertFailed();
879 Status = STATUS_ACCESS_DENIED;
880 break;
881 }
882
883 if ( !pIf
884 || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pIf)
885 || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0)
886 {
887 AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n"));
888 Status = STATUS_INVALID_PARAMETER;
889 break;
890 }
891
892 Status = vboxUsbRtSetInterface(pDevExt, pIf->bInterfaceNumber, pIf->bAlternateSetting);
893 } while (0);
894
895 Assert(Status != STATUS_PENDING);
896 VBoxDrvToolIoComplete(pIrp, Status, 0);
897 vboxUsbDdiStateRelease(pDevExt);
898 return Status;
899}
900
901static HANDLE vboxUsbRtGetPipeHandle(PVBOXUSBDEV_EXT pDevExt, uint32_t EndPointAddress)
902{
903 if (EndPointAddress == 0)
904 return pDevExt->Rt.hPipe0;
905
906 for (ULONG i = 0; i < pDevExt->Rt.uNumInterfaces; i++)
907 {
908 for (ULONG j = 0; j < pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->NumberOfPipes; j++)
909 {
910 /* Note that bit 7 determines pipe direction, but is still significant
911 * because endpoints may be numbered like 0x01, 0x81, 0x02, 0x82 etc.
912 */
913 if (pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].EndpointAddress == EndPointAddress)
914 return pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->Pipes[j].PipeHandle;
915 }
916 }
917 return 0;
918}
919
920static VBOXUSB_PIPE_INFO* vboxUsbRtGetPipeInfo(PVBOXUSBDEV_EXT pDevExt, uint32_t EndPointAddress)
921{
922 for (ULONG i = 0; i < pDevExt->Rt.uNumInterfaces; i++)
923 {
924 for (ULONG j = 0; j < pDevExt->Rt.pVBIfaceInfo[i].pInterfaceInfo->NumberOfPipes; j++)
925 {
926 if (pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j].EndpointAddress == EndPointAddress)
927 return &pDevExt->Rt.pVBIfaceInfo[i].pPipeInfo[j];
928 }
929 }
930 return NULL;
931}
932
933
934
935static NTSTATUS vboxUsbRtClearEndpoint(PVBOXUSBDEV_EXT pDevExt, uint32_t EndPointAddress, bool fReset)
936{
937 NTSTATUS Status = VBoxUsbToolPipeClear(pDevExt->pLowerDO, vboxUsbRtGetPipeHandle(pDevExt, EndPointAddress), fReset);
938 if (!NT_SUCCESS(Status))
939 {
940 AssertMsgFailed((__FUNCTION__": VBoxUsbToolPipeClear failed Status (0x%x)\n", Status));
941 }
942
943 return Status;
944}
945
946static NTSTATUS vboxUsbRtDispatchUsbClearEndpoint(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
947{
948 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
949 PFILE_OBJECT pFObj = pSl->FileObject;
950 PUSBSUP_CLEAR_ENDPOINT pCe = (PUSBSUP_CLEAR_ENDPOINT)pIrp->AssociatedIrp.SystemBuffer;
951 NTSTATUS Status;
952
953 do
954 {
955 if (!pFObj)
956 {
957 AssertFailed();
958 Status = STATUS_INVALID_PARAMETER;
959 break;
960 }
961
962 if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj))
963 {
964 AssertFailed();
965 Status = STATUS_ACCESS_DENIED;
966 break;
967 }
968
969 if ( !pCe
970 || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pCe)
971 || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0)
972 {
973 AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n"));
974 Status = STATUS_INVALID_PARAMETER;
975 break;
976 }
977
978 Status = vboxUsbRtClearEndpoint(pDevExt, pCe->bEndpoint, TRUE);
979 } while (0);
980
981 Assert(Status != STATUS_PENDING);
982 VBoxDrvToolIoComplete(pIrp, Status, 0);
983 vboxUsbDdiStateRelease(pDevExt);
984 return Status;
985}
986
987static NTSTATUS vboxUsbRtDispatchUsbAbortEndpoint(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
988{
989 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
990 PFILE_OBJECT pFObj = pSl->FileObject;
991 PUSBSUP_CLEAR_ENDPOINT pCe = (PUSBSUP_CLEAR_ENDPOINT)pIrp->AssociatedIrp.SystemBuffer;
992 NTSTATUS Status;
993
994 do
995 {
996 if (!pFObj)
997 {
998 AssertFailed();
999 Status = STATUS_INVALID_PARAMETER;
1000 break;
1001 }
1002
1003 if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj))
1004 {
1005 AssertFailed();
1006 Status = STATUS_ACCESS_DENIED;
1007 break;
1008 }
1009
1010 if ( !pCe
1011 || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pCe)
1012 || pSl->Parameters.DeviceIoControl.OutputBufferLength != 0)
1013 {
1014 AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n"));
1015 Status = STATUS_INVALID_PARAMETER;
1016 break;
1017 }
1018
1019 Status = vboxUsbRtClearEndpoint(pDevExt, pCe->bEndpoint, FALSE);
1020 } while (0);
1021
1022 Assert(Status != STATUS_PENDING);
1023 VBoxDrvToolIoComplete(pIrp, Status, 0);
1024 vboxUsbDdiStateRelease(pDevExt);
1025 return Status;
1026}
1027
1028static NTSTATUS vboxUsbRtUrbSendCompletion(PDEVICE_OBJECT pDevObj, IRP *pIrp, void *pvContext)
1029{
1030 RT_NOREF1(pDevObj);
1031
1032 if (!pvContext)
1033 {
1034 AssertMsgFailed((__FUNCTION__": context is NULL\n"));
1035 pIrp->IoStatus.Information = 0;
1036 return STATUS_CONTINUE_COMPLETION;
1037 }
1038
1039 PVBOXUSB_URB_CONTEXT pContext = (PVBOXUSB_URB_CONTEXT)pvContext;
1040
1041 if (pContext->ulMagic != VBOXUSB_MAGIC)
1042 {
1043 AssertMsgFailed((__FUNCTION__": Invalid context magic\n"));
1044 pIrp->IoStatus.Information = 0;
1045 return STATUS_CONTINUE_COMPLETION;
1046 }
1047
1048 PURB pUrb = pContext->pUrb;
1049 PMDL pMdlBuf = pContext->pMdlBuf;
1050 PUSBSUP_URB pUrbInfo = (PUSBSUP_URB)pContext->pOut;
1051 PVBOXUSBDEV_EXT pDevExt = pContext->pDevExt;
1052
1053 if (!pUrb || !pMdlBuf || !pUrbInfo || !pDevExt)
1054 {
1055 AssertMsgFailed((__FUNCTION__": Invalid args\n"));
1056 if (pDevExt)
1057 vboxUsbDdiStateRelease(pDevExt);
1058 pIrp->IoStatus.Information = 0;
1059 return STATUS_CONTINUE_COMPLETION;
1060 }
1061
1062 NTSTATUS Status = pIrp->IoStatus.Status;
1063 if (Status == STATUS_SUCCESS)
1064 {
1065 switch(pUrb->UrbHeader.Status)
1066 {
1067 case USBD_STATUS_CRC:
1068 pUrbInfo->error = USBSUP_XFER_CRC;
1069 break;
1070 case USBD_STATUS_SUCCESS:
1071 pUrbInfo->error = USBSUP_XFER_OK;
1072 break;
1073 case USBD_STATUS_STALL_PID:
1074 pUrbInfo->error = USBSUP_XFER_STALL;
1075 break;
1076 case USBD_STATUS_INVALID_URB_FUNCTION:
1077 case USBD_STATUS_INVALID_PARAMETER:
1078 AssertMsgFailed((__FUNCTION__": sw error, urb Status (0x%x)\n", pUrb->UrbHeader.Status));
1079 case USBD_STATUS_DEV_NOT_RESPONDING:
1080 default:
1081 pUrbInfo->error = USBSUP_XFER_DNR;
1082 break;
1083 }
1084
1085 switch(pContext->ulTransferType)
1086 {
1087 case USBSUP_TRANSFER_TYPE_MSG:
1088 pUrbInfo->len = pUrb->UrbControlTransfer.TransferBufferLength;
1089 /* QUSB_TRANSFER_TYPE_MSG is a control transfer, but it is special
1090 * the first 8 bytes of the buffer is the setup packet so the real
1091 * data length is therefore urb->len - 8
1092 */
1093 pUrbInfo->len += sizeof (pUrb->UrbControlTransfer.SetupPacket);
1094
1095 /* If a control URB was successfully completed on the default control
1096 * pipe, stash away the handle. When submitting the URB, we don't need
1097 * to know (and initially don't have) the handle. If we want to abort
1098 * the default control pipe, we *have* to have a handle. This is how we
1099 * find out what the handle is.
1100 */
1101 if (!pUrbInfo->ep && (pDevExt->Rt.hPipe0 == NULL))
1102 {
1103 pDevExt->Rt.hPipe0 = pUrb->UrbControlTransfer.PipeHandle;
1104 }
1105
1106 break;
1107 case USBSUP_TRANSFER_TYPE_ISOC:
1108 pUrbInfo->len = pUrb->UrbIsochronousTransfer.TransferBufferLength;
1109 break;
1110 case USBSUP_TRANSFER_TYPE_BULK:
1111 case USBSUP_TRANSFER_TYPE_INTR:
1112 if (pUrbInfo->dir == USBSUP_DIRECTION_IN && pUrbInfo->error == USBSUP_XFER_OK
1113 && !(pUrbInfo->flags & USBSUP_FLAG_SHORT_OK)
1114 && pUrbInfo->len > pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength
1115 )
1116 {
1117 /* If we don't use the USBD_SHORT_TRANSFER_OK flag, the returned buffer lengths are
1118 * wrong for short transfers (always a multiple of max packet size?). So we just figure
1119 * out if this was a data underrun on our own.
1120 */
1121 pUrbInfo->error = USBSUP_XFER_UNDERRUN;
1122 }
1123 pUrbInfo->len = pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength;
1124 break;
1125 default:
1126 break;
1127 }
1128 }
1129 else
1130 {
1131 pUrbInfo->len = 0;
1132
1133 LogFunc(("URB failed Status (0x%x) urb Status (0x%x)\n", Status, pUrb->UrbHeader.Status));
1134#ifdef DEBUG
1135 switch(pContext->ulTransferType)
1136 {
1137 case USBSUP_TRANSFER_TYPE_MSG:
1138 LogRel(("Msg (CTRL) length=%d\n", pUrb->UrbControlTransfer.TransferBufferLength));
1139 break;
1140 case USBSUP_TRANSFER_TYPE_ISOC:
1141 LogRel(("ISOC length=%d\n", pUrb->UrbIsochronousTransfer.TransferBufferLength));
1142 break;
1143 case USBSUP_TRANSFER_TYPE_BULK:
1144 case USBSUP_TRANSFER_TYPE_INTR:
1145 LogRel(("BULK/INTR length=%d\n", pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength));
1146 break;
1147 }
1148#endif
1149 switch(pUrb->UrbHeader.Status)
1150 {
1151 case USBD_STATUS_CRC:
1152 pUrbInfo->error = USBSUP_XFER_CRC;
1153 Status = STATUS_SUCCESS;
1154 break;
1155 case USBD_STATUS_STALL_PID:
1156 pUrbInfo->error = USBSUP_XFER_STALL;
1157 Status = STATUS_SUCCESS;
1158 break;
1159 case USBD_STATUS_DEV_NOT_RESPONDING:
1160 case USBD_STATUS_DEVICE_GONE:
1161 pUrbInfo->error = USBSUP_XFER_DNR;
1162 Status = STATUS_SUCCESS;
1163 break;
1164 case ((USBD_STATUS)0xC0010000L): // USBD_STATUS_CANCELED - too bad usbdi.h and usb.h aren't consistent!
1165 /// @todo What the heck are we really supposed to do here?
1166 pUrbInfo->error = USBSUP_XFER_STALL;
1167 Status = STATUS_SUCCESS;
1168 break;
1169 case USBD_STATUS_BAD_START_FRAME: // This one really shouldn't happen
1170 case USBD_STATUS_ISOCH_REQUEST_FAILED:
1171 pUrbInfo->error = USBSUP_XFER_NAC;
1172 Status = STATUS_SUCCESS;
1173 break;
1174 default:
1175 AssertMsgFailed((__FUNCTION__": err Status (0x%x) (0x%x)\n", Status, pUrb->UrbHeader.Status));
1176 pUrbInfo->error = USBSUP_XFER_DNR;
1177 Status = STATUS_SUCCESS;
1178 break;
1179 }
1180 }
1181 // For isochronous transfers, always update the individual packets
1182 if (pContext->ulTransferType == USBSUP_TRANSFER_TYPE_ISOC)
1183 {
1184 Assert(pUrbInfo->numIsoPkts == pUrb->UrbIsochronousTransfer.NumberOfPackets);
1185 for (ULONG i = 0; i < pUrbInfo->numIsoPkts; ++i)
1186 {
1187 Assert(pUrbInfo->aIsoPkts[i].off == pUrb->UrbIsochronousTransfer.IsoPacket[i].Offset);
1188 pUrbInfo->aIsoPkts[i].cb = (uint16_t)pUrb->UrbIsochronousTransfer.IsoPacket[i].Length;
1189 switch (pUrb->UrbIsochronousTransfer.IsoPacket[i].Status)
1190 {
1191 case USBD_STATUS_SUCCESS:
1192 pUrbInfo->aIsoPkts[i].stat = USBSUP_XFER_OK;
1193 break;
1194 case USBD_STATUS_NOT_ACCESSED:
1195 pUrbInfo->aIsoPkts[i].stat = USBSUP_XFER_NAC;
1196 break;
1197 default:
1198 pUrbInfo->aIsoPkts[i].stat = USBSUP_XFER_STALL;
1199 break;
1200 }
1201 }
1202 }
1203
1204 MmUnlockPages(pMdlBuf);
1205 IoFreeMdl(pMdlBuf);
1206
1207 vboxUsbMemFree(pContext);
1208
1209 vboxUsbDdiStateRelease(pDevExt);
1210
1211 Assert(pIrp->IoStatus.Status != STATUS_IO_TIMEOUT);
1212 pIrp->IoStatus.Information = sizeof(*pUrbInfo);
1213 pIrp->IoStatus.Status = Status;
1214 return STATUS_CONTINUE_COMPLETION;
1215}
1216
1217static NTSTATUS vboxUsbRtUrbSend(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp, PUSBSUP_URB pUrbInfo)
1218{
1219 NTSTATUS Status = STATUS_SUCCESS;
1220 PVBOXUSB_URB_CONTEXT pContext = NULL;
1221 PMDL pMdlBuf = NULL;
1222 ULONG cbUrb;
1223
1224 Assert(pUrbInfo);
1225 if (pUrbInfo->type == USBSUP_TRANSFER_TYPE_ISOC)
1226 {
1227 Assert(pUrbInfo->numIsoPkts <= 8);
1228 cbUrb = GET_ISO_URB_SIZE(pUrbInfo->numIsoPkts);
1229 }
1230 else
1231 cbUrb = sizeof (URB);
1232
1233 do
1234 {
1235 pContext = (PVBOXUSB_URB_CONTEXT)vboxUsbMemAllocZ(cbUrb + sizeof (VBOXUSB_URB_CONTEXT));
1236 if (!pContext)
1237 {
1238 AssertMsgFailed((__FUNCTION__": vboxUsbMemAlloc failed\n"));
1239 Status = STATUS_INSUFFICIENT_RESOURCES;
1240 break;
1241 }
1242
1243 PURB pUrb = (PURB)(pContext + 1);
1244 HANDLE hPipe = NULL;
1245 if (pUrbInfo->ep)
1246 {
1247 hPipe = vboxUsbRtGetPipeHandle(pDevExt, pUrbInfo->ep | ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? 0x80 : 0x00));
1248 if (!hPipe)
1249 {
1250 AssertMsgFailed((__FUNCTION__": vboxUsbRtGetPipeHandle failed for endpoint (0x%x)\n", pUrbInfo->ep));
1251 Status = STATUS_INVALID_PARAMETER;
1252 break;
1253 }
1254 }
1255
1256 pMdlBuf = IoAllocateMdl(pUrbInfo->buf, (ULONG)pUrbInfo->len, FALSE, FALSE, NULL);
1257 if (!pMdlBuf)
1258 {
1259 AssertMsgFailed((__FUNCTION__": IoAllocateMdl failed for buffer (0x%p) length (%d)\n", pUrbInfo->buf, pUrbInfo->len));
1260 Status = STATUS_INSUFFICIENT_RESOURCES;
1261 break;
1262 }
1263
1264 __try
1265 {
1266 MmProbeAndLockPages(pMdlBuf, KernelMode, IoModifyAccess);
1267 }
1268 __except(EXCEPTION_EXECUTE_HANDLER)
1269 {
1270 Status = GetExceptionCode();
1271 IoFreeMdl(pMdlBuf);
1272 pMdlBuf = NULL;
1273 AssertMsgFailed((__FUNCTION__": Exception Code (0x%x)\n", Status));
1274 break;
1275 }
1276
1277 /* For some reason, passing a MDL in the URB does not work reliably. Notably
1278 * the iPhone when used with iTunes fails.
1279 */
1280 PVOID pBuffer = MmGetSystemAddressForMdlSafe(pMdlBuf, NormalPagePriority);
1281 if (!pBuffer)
1282 {
1283 AssertMsgFailed((__FUNCTION__": MmGetSystemAddressForMdlSafe failed\n"));
1284 Status = STATUS_INSUFFICIENT_RESOURCES;
1285 break;
1286 }
1287
1288 switch (pUrbInfo->type)
1289 {
1290 case USBSUP_TRANSFER_TYPE_MSG:
1291 {
1292 pUrb->UrbHeader.Function = URB_FUNCTION_CONTROL_TRANSFER;
1293 pUrb->UrbHeader.Length = sizeof (struct _URB_CONTROL_TRANSFER);
1294 pUrb->UrbControlTransfer.PipeHandle = hPipe;
1295 pUrb->UrbControlTransfer.TransferBufferLength = (ULONG)pUrbInfo->len;
1296 pUrb->UrbControlTransfer.TransferFlags = ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT);
1297 pUrb->UrbControlTransfer.UrbLink = 0;
1298
1299 if (!hPipe)
1300 pUrb->UrbControlTransfer.TransferFlags |= USBD_DEFAULT_PIPE_TRANSFER;
1301
1302 /* QUSB_TRANSFER_TYPE_MSG is a control transfer, but it is special
1303 * the first 8 bytes of the buffer is the setup packet so the real
1304 * data length is therefore pUrb->len - 8
1305 */
1306 //PVBOXUSB_SETUP pSetup = (PVBOXUSB_SETUP)pUrb->UrbControlTransfer.SetupPacket;
1307 memcpy(pUrb->UrbControlTransfer.SetupPacket, pBuffer, min(sizeof (pUrb->UrbControlTransfer.SetupPacket), pUrbInfo->len));
1308
1309 if (pUrb->UrbControlTransfer.TransferBufferLength <= sizeof (pUrb->UrbControlTransfer.SetupPacket))
1310 pUrb->UrbControlTransfer.TransferBufferLength = 0;
1311 else
1312 pUrb->UrbControlTransfer.TransferBufferLength -= sizeof (pUrb->UrbControlTransfer.SetupPacket);
1313
1314 pUrb->UrbControlTransfer.TransferBuffer = (uint8_t *)pBuffer + sizeof(pUrb->UrbControlTransfer.SetupPacket);
1315 pUrb->UrbControlTransfer.TransferBufferMDL = 0;
1316 pUrb->UrbControlTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK;
1317 break;
1318 }
1319 case USBSUP_TRANSFER_TYPE_ISOC:
1320 {
1321 Assert(hPipe);
1322 VBOXUSB_PIPE_INFO *pPipeInfo = vboxUsbRtGetPipeInfo(pDevExt, pUrbInfo->ep | ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? 0x80 : 0x00));
1323 if (pPipeInfo == NULL)
1324 {
1325 /* Can happen if the isoc request comes in too early or late. */
1326 AssertMsgFailed((__FUNCTION__": pPipeInfo not found\n"));
1327 Status = STATUS_INVALID_PARAMETER;
1328 break;
1329 }
1330
1331 pUrb->UrbHeader.Function = URB_FUNCTION_ISOCH_TRANSFER;
1332 pUrb->UrbHeader.Length = (USHORT)cbUrb;
1333 pUrb->UrbIsochronousTransfer.PipeHandle = hPipe;
1334 pUrb->UrbIsochronousTransfer.TransferBufferLength = (ULONG)pUrbInfo->len;
1335 pUrb->UrbIsochronousTransfer.TransferBufferMDL = 0;
1336 pUrb->UrbIsochronousTransfer.TransferBuffer = pBuffer;
1337 pUrb->UrbIsochronousTransfer.TransferFlags = ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT);
1338 pUrb->UrbIsochronousTransfer.TransferFlags |= USBD_SHORT_TRANSFER_OK; // May be implied already
1339 pUrb->UrbIsochronousTransfer.NumberOfPackets = pUrbInfo->numIsoPkts;
1340 pUrb->UrbIsochronousTransfer.ErrorCount = 0;
1341 pUrb->UrbIsochronousTransfer.UrbLink = 0;
1342
1343 Assert(pUrbInfo->numIsoPkts == pUrb->UrbIsochronousTransfer.NumberOfPackets);
1344 for (ULONG i = 0; i < pUrbInfo->numIsoPkts; ++i)
1345 {
1346 pUrb->UrbIsochronousTransfer.IsoPacket[i].Offset = pUrbInfo->aIsoPkts[i].off;
1347 pUrb->UrbIsochronousTransfer.IsoPacket[i].Length = pUrbInfo->aIsoPkts[i].cb;
1348 }
1349
1350 /* We have to schedule the URBs ourselves. There is an ASAP flag but
1351 * that can only be reliably used after pipe creation/reset, ie. it's
1352 * almost completely useless.
1353 */
1354 ULONG iFrame, iStartFrame;
1355 VBoxUsbToolCurrentFrame(pDevExt->pLowerDO, pIrp, &iFrame);
1356 iFrame += 2;
1357 iStartFrame = pPipeInfo->NextScheduledFrame;
1358 if ((iFrame < iStartFrame) || (iStartFrame > iFrame + 512))
1359 iFrame = iStartFrame;
1360 /* For full-speed devices, there must be one transfer per frame (Windows USB
1361 * stack requirement), but URBs can contain multiple packets. For high-speed or
1362 * faster transfers, we expect one URB per frame, regardless of the interval.
1363 */
1364 if (pDevExt->Rt.devdescr->bcdUSB < 0x300 && !pDevExt->Rt.fIsHighSpeed)
1365 pPipeInfo->NextScheduledFrame = iFrame + pUrbInfo->numIsoPkts;
1366 else
1367 pPipeInfo->NextScheduledFrame = iFrame + 1;
1368 pUrb->UrbIsochronousTransfer.StartFrame = iFrame;
1369 break;
1370 }
1371 case USBSUP_TRANSFER_TYPE_BULK:
1372 case USBSUP_TRANSFER_TYPE_INTR:
1373 {
1374 Assert(pUrbInfo->dir != USBSUP_DIRECTION_SETUP);
1375 Assert(pUrbInfo->dir == USBSUP_DIRECTION_IN || pUrbInfo->type == USBSUP_TRANSFER_TYPE_BULK);
1376 Assert(hPipe);
1377
1378 pUrb->UrbHeader.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
1379 pUrb->UrbHeader.Length = sizeof (struct _URB_BULK_OR_INTERRUPT_TRANSFER);
1380 pUrb->UrbBulkOrInterruptTransfer.PipeHandle = hPipe;
1381 pUrb->UrbBulkOrInterruptTransfer.TransferBufferLength = (ULONG)pUrbInfo->len;
1382 pUrb->UrbBulkOrInterruptTransfer.TransferBufferMDL = 0;
1383 pUrb->UrbBulkOrInterruptTransfer.TransferBuffer = pBuffer;
1384 pUrb->UrbBulkOrInterruptTransfer.TransferFlags = ((pUrbInfo->dir == USBSUP_DIRECTION_IN) ? USBD_TRANSFER_DIRECTION_IN : USBD_TRANSFER_DIRECTION_OUT);
1385
1386 if (pUrb->UrbBulkOrInterruptTransfer.TransferFlags & USBD_TRANSFER_DIRECTION_IN)
1387 pUrb->UrbBulkOrInterruptTransfer.TransferFlags |= (USBD_SHORT_TRANSFER_OK);
1388
1389 pUrb->UrbBulkOrInterruptTransfer.UrbLink = 0;
1390 break;
1391 }
1392 default:
1393 {
1394 AssertFailed();
1395 Status = STATUS_INVALID_PARAMETER;
1396 break;
1397 }
1398 }
1399
1400 if (!NT_SUCCESS(Status))
1401 {
1402 break;
1403 }
1404
1405 pContext->pDevExt = pDevExt;
1406 pContext->pMdlBuf = pMdlBuf;
1407 pContext->pUrb = pUrb;
1408 pContext->pOut = pUrbInfo;
1409 pContext->ulTransferType = pUrbInfo->type;
1410 pContext->ulMagic = VBOXUSB_MAGIC;
1411
1412 PIO_STACK_LOCATION pSl = IoGetNextIrpStackLocation(pIrp);
1413 pSl->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1414 pSl->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
1415 pSl->Parameters.Others.Argument1 = pUrb;
1416 pSl->Parameters.Others.Argument2 = NULL;
1417
1418 IoSetCompletionRoutine(pIrp, vboxUsbRtUrbSendCompletion, pContext, TRUE, TRUE, TRUE);
1419 IoMarkIrpPending(pIrp);
1420 Status = IoCallDriver(pDevExt->pLowerDO, pIrp);
1421 AssertMsg(NT_SUCCESS(Status), (__FUNCTION__": IoCallDriver failed Status (0x%x)\n", Status));
1422 return STATUS_PENDING;
1423 } while (0);
1424
1425 Assert(!NT_SUCCESS(Status));
1426
1427 if (pMdlBuf)
1428 {
1429 MmUnlockPages(pMdlBuf);
1430 IoFreeMdl(pMdlBuf);
1431 }
1432
1433 if (pContext)
1434 vboxUsbMemFree(pContext);
1435
1436 VBoxDrvToolIoComplete(pIrp, Status, 0);
1437 vboxUsbDdiStateRelease(pDevExt);
1438 return Status;
1439}
1440
1441static NTSTATUS vboxUsbRtDispatchSendUrb(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
1442{
1443 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1444 PFILE_OBJECT pFObj = pSl->FileObject;
1445 PUSBSUP_URB pUrbInfo = (PUSBSUP_URB)pIrp->AssociatedIrp.SystemBuffer;
1446 NTSTATUS Status;
1447
1448 do
1449 {
1450 if (!pFObj)
1451 {
1452 AssertFailed();
1453 Status = STATUS_INVALID_PARAMETER;
1454 break;
1455 }
1456
1457 if (!vboxUsbRtCtxIsOwner(pDevExt, pFObj))
1458 {
1459 AssertFailed();
1460 Status = STATUS_ACCESS_DENIED;
1461 break;
1462 }
1463
1464 if ( !pUrbInfo
1465 || pSl->Parameters.DeviceIoControl.InputBufferLength != sizeof (*pUrbInfo)
1466 || pSl->Parameters.DeviceIoControl.OutputBufferLength != sizeof (*pUrbInfo))
1467 {
1468 AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n"));
1469 Status = STATUS_INVALID_PARAMETER;
1470 break;
1471 }
1472 return vboxUsbRtUrbSend(pDevExt, pIrp, pUrbInfo);
1473 } while (0);
1474
1475 Assert(Status != STATUS_PENDING);
1476 VBoxDrvToolIoComplete(pIrp, Status, 0);
1477 vboxUsbDdiStateRelease(pDevExt);
1478 return Status;
1479}
1480
1481static NTSTATUS vboxUsbRtDispatchIsOperational(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
1482{
1483 VBoxDrvToolIoComplete(pIrp, STATUS_SUCCESS, 0);
1484 vboxUsbDdiStateRelease(pDevExt);
1485 return STATUS_SUCCESS;
1486}
1487
1488static NTSTATUS vboxUsbRtDispatchGetVersion(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
1489{
1490 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1491 PUSBSUP_VERSION pVer= (PUSBSUP_VERSION)pIrp->AssociatedIrp.SystemBuffer;
1492 NTSTATUS Status = STATUS_SUCCESS;
1493
1494 if ( pVer
1495 && pSl->Parameters.DeviceIoControl.InputBufferLength == 0
1496 && pSl->Parameters.DeviceIoControl.OutputBufferLength == sizeof(*pVer))
1497 {
1498 pVer->u32Major = USBDRV_MAJOR_VERSION;
1499 pVer->u32Minor = USBDRV_MINOR_VERSION;
1500 }
1501 else
1502 {
1503 AssertMsgFailed((__FUNCTION__": STATUS_INVALID_PARAMETER\n"));
1504 Status = STATUS_INVALID_PARAMETER;
1505 }
1506
1507 Assert(Status != STATUS_PENDING);
1508 VBoxDrvToolIoComplete(pIrp, Status, sizeof (*pVer));
1509 vboxUsbDdiStateRelease(pDevExt);
1510 return Status;
1511}
1512
1513static NTSTATUS vboxUsbRtDispatchDefault(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
1514{
1515 VBoxDrvToolIoComplete(pIrp, STATUS_INVALID_DEVICE_REQUEST, 0);
1516 vboxUsbDdiStateRelease(pDevExt);
1517 return STATUS_INVALID_DEVICE_REQUEST;
1518}
1519
1520DECLHIDDEN(NTSTATUS) vboxUsbRtCreate(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
1521{
1522 RT_NOREF1(pDevExt);
1523 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1524 PFILE_OBJECT pFObj = pSl->FileObject;
1525 AssertReturn(pFObj, STATUS_INVALID_PARAMETER);
1526 return STATUS_SUCCESS;
1527}
1528
1529DECLHIDDEN(NTSTATUS) vboxUsbRtClose(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
1530{
1531 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1532 PFILE_OBJECT pFObj = pSl->FileObject;
1533 Assert(pFObj);
1534
1535 vboxUsbRtCtxReleaseOwner(pDevExt, pFObj);
1536
1537 return STATUS_SUCCESS;
1538}
1539
1540DECLHIDDEN(NTSTATUS) vboxUsbRtDispatch(PVBOXUSBDEV_EXT pDevExt, PIRP pIrp)
1541{
1542 PIO_STACK_LOCATION pSl = IoGetCurrentIrpStackLocation(pIrp);
1543 switch (pSl->Parameters.DeviceIoControl.IoControlCode)
1544 {
1545 case SUPUSB_IOCTL_USB_CLAIM_DEVICE:
1546 return vboxUsbRtDispatchClaimDevice(pDevExt, pIrp);
1547
1548 case SUPUSB_IOCTL_USB_RELEASE_DEVICE:
1549 return vboxUsbRtDispatchReleaseDevice(pDevExt, pIrp);
1550
1551 case SUPUSB_IOCTL_GET_DEVICE:
1552 return vboxUsbRtDispatchGetDevice(pDevExt, pIrp);
1553
1554 case SUPUSB_IOCTL_USB_RESET:
1555 return vboxUsbRtDispatchUsbReset(pDevExt, pIrp);
1556
1557 case SUPUSB_IOCTL_USB_SET_CONFIG:
1558 return vboxUsbRtDispatchUsbSetConfig(pDevExt, pIrp);
1559
1560 case SUPUSB_IOCTL_USB_SELECT_INTERFACE:
1561 return vboxUsbRtDispatchUsbSelectInterface(pDevExt, pIrp);
1562
1563 case SUPUSB_IOCTL_USB_CLEAR_ENDPOINT:
1564 return vboxUsbRtDispatchUsbClearEndpoint(pDevExt, pIrp);
1565
1566 case SUPUSB_IOCTL_USB_ABORT_ENDPOINT:
1567 return vboxUsbRtDispatchUsbAbortEndpoint(pDevExt, pIrp);
1568
1569 case SUPUSB_IOCTL_SEND_URB:
1570 return vboxUsbRtDispatchSendUrb(pDevExt, pIrp);
1571
1572 case SUPUSB_IOCTL_IS_OPERATIONAL:
1573 return vboxUsbRtDispatchIsOperational(pDevExt, pIrp);
1574
1575 case SUPUSB_IOCTL_GET_VERSION:
1576 return vboxUsbRtDispatchGetVersion(pDevExt, pIrp);
1577
1578 default:
1579 return vboxUsbRtDispatchDefault(pDevExt, pIrp);
1580 }
1581}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette