VirtualBox

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

Last change on this file was 98327, checked in by vboxsync, 16 months ago

VBoxUSB.sys: Be more careful before calling MmUnlockPages.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use