VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/freebsd/USBProxyDevice-freebsd.cpp@ 94342

Last change on this file since 94342 was 94342, checked in by vboxsync, 3 years ago

Main,VMM/PDMUsb,Devices/USB,VRDP: Drop passing pointers through CFGM in favor of using VMM2USERMETHODS::pfnQueryGenericObject, bugref:10053

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.2 KB
Line 
1/* $Id: USBProxyDevice-freebsd.cpp 94342 2022-03-23 19:53:21Z vboxsync $ */
2/** @file
3 * USB device proxy - the FreeBSD backend.
4 */
5
6/*
7 * Includes contributions from Hans Petter Selasky
8 *
9 * Copyright (C) 2006-2022 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20
21/*********************************************************************************************************************************
22* Header Files *
23*********************************************************************************************************************************/
24#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
25#ifdef VBOX
26# include <iprt/stdint.h>
27#endif
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/ioctl.h>
31#include <sys/poll.h>
32#include <stdint.h>
33#include <stdio.h>
34#include <string.h>
35#include <stdlib.h>
36#include <limits.h>
37#include <unistd.h>
38#include <fcntl.h>
39#include <errno.h>
40#include <dev/usb/usb.h>
41#include <dev/usb/usbdi.h>
42#include <dev/usb/usb_ioctl.h>
43
44#include <VBox/vmm/pdm.h>
45#include <VBox/err.h>
46#include <VBox/log.h>
47#include <VBox/vusb.h>
48#include <iprt/assert.h>
49#include <iprt/stream.h>
50#include <iprt/alloc.h>
51#include <iprt/thread.h>
52#include <iprt/time.h>
53#include <iprt/asm.h>
54#include <iprt/string.h>
55#include <iprt/file.h>
56#include <iprt/pipe.h>
57#include "../USBProxyDevice.h"
58
59/** Maximum endpoints supported. */
60#define USBFBSD_MAXENDPOINTS 127
61#define USBFBSD_MAXFRAMES 56
62
63/** This really needs to be defined in vusb.h! */
64#ifndef VUSB_DIR_TO_DEV
65# define VUSB_DIR_TO_DEV 0x00
66#endif
67
68
69/*********************************************************************************************************************************
70* Structures and Typedefs *
71*********************************************************************************************************************************/
72typedef struct USBENDPOINTFBSD
73{
74 /** Flag whether it is opened. */
75 bool fOpen;
76 /** Flag whether it is cancelling. */
77 bool fCancelling;
78 /** Buffer pointers. */
79 void *apvData[USBFBSD_MAXFRAMES];
80 /** Buffer lengths. */
81 uint32_t acbData[USBFBSD_MAXFRAMES];
82 /** Initial buffer length. */
83 uint32_t cbData0;
84 /** Pointer to the URB. */
85 PVUSBURB pUrb;
86 /** Copy of endpoint number. */
87 unsigned iEpNum;
88 /** Maximum transfer length. */
89 unsigned cMaxIo;
90 /** Maximum frame count. */
91 unsigned cMaxFrames;
92} USBENDPOINTFBSD, *PUSBENDPOINTFBSD;
93
94/**
95 * Data for the FreeBSD usb proxy backend.
96 */
97typedef struct USBPROXYDEVFBSD
98{
99 /** The open file. */
100 RTFILE hFile;
101 /** Flag whether an URB is cancelling. */
102 bool fCancelling;
103 /** Flag whether initialised or not */
104 bool fInit;
105 /** Pipe handle for waking up - writing end. */
106 RTPIPE hPipeWakeupW;
107 /** Pipe handle for waking up - reading end. */
108 RTPIPE hPipeWakeupR;
109 /** Software endpoint structures */
110 USBENDPOINTFBSD aSwEndpoint[USBFBSD_MAXENDPOINTS];
111 /** Kernel endpoint structures */
112 struct usb_fs_endpoint aHwEndpoint[USBFBSD_MAXENDPOINTS];
113} USBPROXYDEVFBSD, *PUSBPROXYDEVFBSD;
114
115
116/*********************************************************************************************************************************
117* Internal Functions *
118*********************************************************************************************************************************/
119static int usbProxyFreeBSDEndpointClose(PUSBPROXYDEV pProxyDev, int Endpoint);
120
121/**
122 * Wrapper for the ioctl call.
123 *
124 * This wrapper will repeat the call if we get an EINTR or EAGAIN. It can also
125 * handle ENODEV (detached device) errors.
126 *
127 * @returns whatever ioctl returns.
128 * @param pProxyDev The proxy device.
129 * @param iCmd The ioctl command / function.
130 * @param pvArg The ioctl argument / data.
131 * @param fHandleNoDev Whether to handle ENXIO.
132 * @internal
133 */
134static int usbProxyFreeBSDDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd,
135 void *pvArg, bool fHandleNoDev)
136{
137 int rc = VINF_SUCCESS;
138 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
139
140 LogFlow(("usbProxyFreeBSDDoIoCtl: iCmd=%#x\n", iCmd));
141
142 do
143 {
144 rc = ioctl(RTFileToNative(pDevFBSD->hFile), iCmd, pvArg);
145 if (rc >= 0)
146 return VINF_SUCCESS;
147 } while (errno == EINTR);
148
149 if (errno == ENXIO && fHandleNoDev)
150 {
151 Log(("usbProxyFreeBSDDoIoCtl: ENXIO -> unplugged. pProxyDev=%s\n",
152 pProxyDev->pUsbIns->pszName));
153 errno = ENODEV;
154 }
155 else if (errno != EAGAIN)
156 {
157 LogFlow(("usbProxyFreeBSDDoIoCtl: Returned %d. pProxyDev=%s\n",
158 errno, pProxyDev->pUsbIns->pszName));
159 }
160 return RTErrConvertFromErrno(errno);
161}
162
163/**
164 * Init USB subsystem.
165 */
166static int usbProxyFreeBSDFsInit(PUSBPROXYDEV pProxyDev)
167{
168 struct usb_fs_init UsbFsInit;
169 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
170 int rc;
171
172 LogFlow(("usbProxyFreeBSDFsInit: pProxyDev=%p\n", (void *)pProxyDev));
173
174 /* Sanity check */
175 AssertPtrReturn(pDevFBSD, VERR_INVALID_PARAMETER);
176
177 if (pDevFBSD->fInit == true)
178 return VINF_SUCCESS;
179
180 /* Zero default */
181 memset(&UsbFsInit, 0, sizeof(UsbFsInit));
182
183 UsbFsInit.pEndpoints = pDevFBSD->aHwEndpoint;
184 UsbFsInit.ep_index_max = USBFBSD_MAXENDPOINTS;
185
186 /* Init USB subsystem */
187 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_INIT, &UsbFsInit, false);
188 if (RT_SUCCESS(rc))
189 pDevFBSD->fInit = true;
190
191 return rc;
192}
193
194/**
195 * Uninit USB subsystem.
196 */
197static int usbProxyFreeBSDFsUnInit(PUSBPROXYDEV pProxyDev)
198{
199 struct usb_fs_uninit UsbFsUninit;
200 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
201 int rc;
202
203 LogFlow(("usbProxyFreeBSDFsUnInit: ProxyDev=%p\n", (void *)pProxyDev));
204
205 /* Sanity check */
206 AssertPtrReturn(pDevFBSD, VERR_INVALID_PARAMETER);
207
208 if (pDevFBSD->fInit != true)
209 return VINF_SUCCESS;
210
211 /* Close any open endpoints. */
212 for (unsigned n = 0; n != USBFBSD_MAXENDPOINTS; n++)
213 usbProxyFreeBSDEndpointClose(pProxyDev, n);
214
215 /* Zero default */
216 memset(&UsbFsUninit, 0, sizeof(UsbFsUninit));
217
218 /* Uninit USB subsystem */
219 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_UNINIT, &UsbFsUninit, false);
220 if (RT_SUCCESS(rc))
221 pDevFBSD->fInit = false;
222
223 return rc;
224}
225
226/**
227 * Setup a USB request packet.
228 */
229static void usbProxyFreeBSDSetupReq(struct usb_device_request *pSetupData,
230 uint8_t bmRequestType, uint8_t bRequest, uint16_t wValue,
231 uint16_t wIndex, uint16_t wLength)
232{
233 LogFlow(("usbProxyFreeBSDSetupReq: pSetupData=%p bmRequestType=%x "
234 "bRequest=%x wValue=%x wIndex=%x wLength=%x\n", (void *)pSetupData,
235 bmRequestType, bRequest, wValue, wIndex, wLength));
236
237 pSetupData->bmRequestType = bmRequestType;
238 pSetupData->bRequest = bRequest;
239
240 /* Handle endianess here. Currently no swapping is needed. */
241 pSetupData->wValue[0] = wValue & 0xff;
242 pSetupData->wValue[1] = (wValue >> 8) & 0xff;
243 pSetupData->wIndex[0] = wIndex & 0xff;
244 pSetupData->wIndex[1] = (wIndex >> 8) & 0xff;
245 pSetupData->wLength[0] = wLength & 0xff;
246 pSetupData->wLength[1] = (wLength >> 8) & 0xff;
247}
248
249static int usbProxyFreeBSDEndpointOpen(PUSBPROXYDEV pProxyDev, int Endpoint, bool fIsoc, int index)
250{
251 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
252 PUSBENDPOINTFBSD pEndpointFBSD = NULL; /* shut up gcc */
253 struct usb_fs_endpoint *pXferEndpoint;
254 struct usb_fs_open UsbFsOpen;
255 int rc;
256
257 LogFlow(("usbProxyFreeBSDEndpointOpen: pProxyDev=%p Endpoint=%d\n",
258 (void *)pProxyDev, Endpoint));
259
260 for (; index < USBFBSD_MAXENDPOINTS; index++)
261 {
262 pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
263 if (pEndpointFBSD->fCancelling)
264 continue;
265 if ( pEndpointFBSD->fOpen
266 && !pEndpointFBSD->pUrb
267 && (int)pEndpointFBSD->iEpNum == Endpoint)
268 return index;
269 }
270
271 if (index == USBFBSD_MAXENDPOINTS)
272 {
273 for (index = 0; index != USBFBSD_MAXENDPOINTS; index++)
274 {
275 pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
276 if (pEndpointFBSD->fCancelling)
277 continue;
278 if (!pEndpointFBSD->fOpen)
279 break;
280 }
281 if (index == USBFBSD_MAXENDPOINTS)
282 return -1;
283 }
284 /* set ppBuffer and pLength */
285
286 pXferEndpoint = &pDevFBSD->aHwEndpoint[index];
287 pXferEndpoint->ppBuffer = &pEndpointFBSD->apvData[0];
288 pXferEndpoint->pLength = &pEndpointFBSD->acbData[0];
289
290 LogFlow(("usbProxyFreeBSDEndpointOpen: ep_index=%d ep_num=%d\n",
291 index, Endpoint));
292
293 memset(&UsbFsOpen, 0, sizeof(UsbFsOpen));
294
295 UsbFsOpen.ep_index = index;
296 UsbFsOpen.ep_no = Endpoint;
297 UsbFsOpen.max_bufsize = 256 * 1024;
298 /* Hardcoded assumption about the URBs we get. */
299
300 UsbFsOpen.max_frames = fIsoc ? USBFBSD_MAXFRAMES : 2;
301
302 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_OPEN, &UsbFsOpen, true);
303 if (RT_FAILURE(rc))
304 {
305 if (rc == VERR_RESOURCE_BUSY)
306 LogFlow(("usbProxyFreeBSDEndpointOpen: EBUSY\n"));
307
308 return -1;
309 }
310 pEndpointFBSD->fOpen = true;
311 pEndpointFBSD->pUrb = NULL;
312 pEndpointFBSD->iEpNum = Endpoint;
313 pEndpointFBSD->cMaxIo = UsbFsOpen.max_bufsize;
314 pEndpointFBSD->cMaxFrames = UsbFsOpen.max_frames;
315
316 return index;
317}
318
319/**
320 * Close an endpoint.
321 *
322 * @returns VBox status code.
323 */
324static int usbProxyFreeBSDEndpointClose(PUSBPROXYDEV pProxyDev, int Endpoint)
325{
326 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
327 PUSBENDPOINTFBSD pEndpointFBSD = &pDevFBSD->aSwEndpoint[Endpoint];
328 struct usb_fs_close UsbFsClose;
329 int rc = VINF_SUCCESS;
330
331 LogFlow(("usbProxyFreeBSDEndpointClose: pProxyDev=%p Endpoint=%d\n",
332 (void *)pProxyDev, Endpoint));
333
334 /* check for cancelling */
335 if (pEndpointFBSD->pUrb != NULL)
336 {
337 pEndpointFBSD->fCancelling = true;
338 pDevFBSD->fCancelling = true;
339 }
340
341 /* check for opened */
342 if (pEndpointFBSD->fOpen)
343 {
344 pEndpointFBSD->fOpen = false;
345
346 /* Zero default */
347 memset(&UsbFsClose, 0, sizeof(UsbFsClose));
348
349 /* Set endpoint index */
350 UsbFsClose.ep_index = Endpoint;
351
352 /* Close endpoint */
353 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_CLOSE, &UsbFsClose, true);
354 }
355 return rc;
356}
357
358/**
359 * Opens the device file.
360 *
361 * @returns VBox status code.
362 * @param pProxyDev The device instance.
363 * @param pszAddress If we are using usbfs, this is the path to the
364 * device. If we are using sysfs, this is a string of
365 * the form "sysfs:<sysfs path>//device:<device node>".
366 * In the second case, the two paths are guaranteed
367 * not to contain the substring "//".
368 */
369static DECLCALLBACK(int) usbProxyFreeBSDOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress)
370{
371 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
372 int rc;
373
374 LogFlow(("usbProxyFreeBSDOpen: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
375
376 /*
377 * Try open the device node.
378 */
379 RTFILE hFile;
380 rc = RTFileOpen(&hFile, pszAddress, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
381 if (RT_SUCCESS(rc))
382 {
383 /*
384 * Initialize the FreeBSD backend data.
385 */
386 pDevFBSD->hFile = hFile;
387 rc = usbProxyFreeBSDFsInit(pProxyDev);
388 if (RT_SUCCESS(rc))
389 {
390 /*
391 * Create wakeup pipe.
392 */
393 rc = RTPipeCreate(&pDevFBSD->hPipeWakeupR, &pDevFBSD->hPipeWakeupW, 0);
394 if (RT_SUCCESS(rc))
395 {
396 LogFlow(("usbProxyFreeBSDOpen(%p, %s): returns successfully hFile=%RTfile iActiveCfg=%d\n",
397 pProxyDev, pszAddress, pDevFBSD->hFile, pProxyDev->iActiveCfg));
398
399 return VINF_SUCCESS;
400 }
401 }
402
403 RTFileClose(hFile);
404 }
405 else if (rc == VERR_ACCESS_DENIED)
406 rc = VERR_VUSB_USBFS_PERMISSION;
407
408 Log(("usbProxyFreeBSDOpen(%p, %s) failed, rc=%d!\n",
409 pProxyDev, pszAddress, rc));
410
411 return rc;
412}
413
414
415/**
416 * Claims all the interfaces and figures out the
417 * current configuration.
418 *
419 * @returns VINF_SUCCESS.
420 * @param pProxyDev The proxy device.
421 */
422static DECLCALLBACK(int) usbProxyFreeBSDInit(PUSBPROXYDEV pProxyDev)
423{
424 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
425 int rc;
426
427 LogFlow(("usbProxyFreeBSDInit: pProxyDev=%s\n",
428 pProxyDev->pUsbIns->pszName));
429
430 /* Retrieve current active configuration. */
431 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_GET_CONFIG,
432 &pProxyDev->iActiveCfg, true);
433 if (RT_FAILURE(rc) || pProxyDev->iActiveCfg == 255)
434 {
435 pProxyDev->cIgnoreSetConfigs = 0;
436 pProxyDev->iActiveCfg = -1;
437 }
438 else
439 {
440 pProxyDev->cIgnoreSetConfigs = 1;
441 pProxyDev->iActiveCfg++;
442 }
443
444 Log(("usbProxyFreeBSDInit: iActiveCfg=%d\n", pProxyDev->iActiveCfg));
445
446 return rc;
447}
448
449/**
450 * Closes the proxy device.
451 */
452static DECLCALLBACK(void) usbProxyFreeBSDClose(PUSBPROXYDEV pProxyDev)
453{
454 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
455
456 LogFlow(("usbProxyFreeBSDClose: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
457
458 /* sanity check */
459 AssertPtrReturnVoid(pDevFBSD);
460
461 usbProxyFreeBSDFsUnInit(pProxyDev);
462
463 RTPipeClose(pDevFBSD->hPipeWakeupR);
464 RTPipeClose(pDevFBSD->hPipeWakeupW);
465
466 RTFileClose(pDevFBSD->hFile);
467 pDevFBSD->hFile = NIL_RTFILE;
468
469 LogFlow(("usbProxyFreeBSDClose: returns\n"));
470}
471
472/**
473 * Reset a device.
474 *
475 * @returns VBox status code.
476 * @param pDev The device to reset.
477 */
478static DECLCALLBACK(int) usbProxyFreeBSDReset(PUSBPROXYDEV pProxyDev, bool fResetOnFreeBSD)
479{
480 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
481 int iParm;
482 int rc = VINF_SUCCESS;
483
484 LogFlow(("usbProxyFreeBSDReset: pProxyDev=%s\n",
485 pProxyDev->pUsbIns->pszName));
486
487 if (!fResetOnFreeBSD)
488 goto done;
489
490 /* We need to release kernel ressources first. */
491 rc = usbProxyFreeBSDFsUnInit(pProxyDev);
492 if (RT_FAILURE(rc))
493 goto done;
494
495 /* Resetting is only possible as super-user, ignore any failures: */
496 iParm = 0;
497 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DEVICEENUMERATE, &iParm, true);
498 if (RT_FAILURE(rc))
499 {
500 /* Set the config instead of bus reset */
501 iParm = 255;
502 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iParm, true);
503 if (RT_SUCCESS(rc))
504 {
505 iParm = 0;
506 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iParm, true);
507 }
508 }
509 usleep(10000); /* nice it! */
510
511 /* Allocate kernel ressources again. */
512 rc = usbProxyFreeBSDFsInit(pProxyDev);
513 if (RT_FAILURE(rc))
514 goto done;
515
516 /* Retrieve current active configuration. */
517 rc = usbProxyFreeBSDInit(pProxyDev);
518
519done:
520 pProxyDev->cIgnoreSetConfigs = 2;
521
522 return rc;
523}
524
525/**
526 * SET_CONFIGURATION.
527 *
528 * The caller makes sure that it's not called first time after open or reset
529 * with the active interface.
530 *
531 * @returns success indicator.
532 * @param pProxyDev The device instance data.
533 * @param iCfg The configuration to set.
534 */
535static DECLCALLBACK(int) usbProxyFreeBSDSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
536{
537 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
538 int iCfgIndex;
539 int rc;
540
541 LogFlow(("usbProxyFreeBSDSetConfig: pProxyDev=%s cfg=%x\n",
542 pProxyDev->pUsbIns->pszName, iCfg));
543
544 /* We need to release kernel ressources first. */
545 rc = usbProxyFreeBSDFsUnInit(pProxyDev);
546 if (RT_FAILURE(rc))
547 {
548 LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
549 "failed failed rc=%d\n", rc));
550 return rc;
551 }
552
553 if (iCfg == 0)
554 {
555 /* Unconfigure */
556 iCfgIndex = 255;
557 }
558 else
559 {
560 /* Get the configuration index matching the value. */
561 for (iCfgIndex = 0; iCfgIndex < pProxyDev->DevDesc.bNumConfigurations; iCfgIndex++)
562 {
563 if (pProxyDev->paCfgDescs[iCfgIndex].Core.bConfigurationValue == iCfg)
564 break;
565 }
566
567 if (iCfgIndex == pProxyDev->DevDesc.bNumConfigurations)
568 {
569 LogFlow(("usbProxyFreeBSDSetConfig: configuration "
570 "%d not found\n", iCfg));
571 return VERR_NOT_FOUND;
572 }
573 }
574
575 /* Set the config */
576 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iCfgIndex, true);
577 if (RT_FAILURE(rc))
578 return rc;
579
580 /* Allocate kernel ressources again. */
581 return usbProxyFreeBSDFsInit(pProxyDev);
582}
583
584/**
585 * Claims an interface.
586 * @returns success indicator.
587 */
588static DECLCALLBACK(int) usbProxyFreeBSDClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
589{
590 int rc;
591
592 LogFlow(("usbProxyFreeBSDClaimInterface: pProxyDev=%s "
593 "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));
594
595 /*
596 * Try to detach kernel driver on this interface, ignore any
597 * failures
598 */
599 usbProxyFreeBSDDoIoCtl(pProxyDev, USB_IFACE_DRIVER_DETACH, &iIf, true);
600
601 /* Try to claim interface */
602 return usbProxyFreeBSDDoIoCtl(pProxyDev, USB_CLAIM_INTERFACE, &iIf, true);
603}
604
605/**
606 * Releases an interface.
607 * @returns success indicator.
608 */
609static DECLCALLBACK(int) usbProxyFreeBSDReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
610{
611 int rc;
612
613 LogFlow(("usbProxyFreeBSDReleaseInterface: pProxyDev=%s "
614 "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));
615
616 return usbProxyFreeBSDDoIoCtl(pProxyDev, USB_RELEASE_INTERFACE, &iIf, true);
617}
618
619/**
620 * SET_INTERFACE.
621 *
622 * @returns success indicator.
623 */
624static DECLCALLBACK(int) usbProxyFreeBSDSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
625{
626 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
627 struct usb_alt_interface UsbIntAlt;
628 int rc;
629
630 LogFlow(("usbProxyFreeBSDSetInterface: pProxyDev=%p iIf=%x iAlt=%x\n",
631 pProxyDev, iIf, iAlt));
632
633 /* We need to release kernel ressources first. */
634 rc = usbProxyFreeBSDFsUnInit(pProxyDev);
635 if (RT_FAILURE(rc))
636 {
637 LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
638 "failed failed rc=%d\n", rc));
639 return rc;
640 }
641 memset(&UsbIntAlt, 0, sizeof(UsbIntAlt));
642 UsbIntAlt.uai_interface_index = iIf;
643 UsbIntAlt.uai_alt_index = iAlt;
644
645 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_ALTINTERFACE, &UsbIntAlt, true);
646 if (RT_FAILURE(rc))
647 {
648 LogFlow(("usbProxyFreeBSDSetInterface: Setting interface %d %d "
649 "failed rc=%d\n", iIf, iAlt, rc));
650 return rc;
651 }
652
653 return usbProxyFreeBSDFsInit(pProxyDev);
654}
655
656/**
657 * Clears the halted endpoint 'ep_num'.
658 */
659static DECLCALLBACK(int) usbProxyFreeBSDClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int ep_num)
660{
661 LogFlow(("usbProxyFreeBSDClearHaltedEp: pProxyDev=%s ep_num=%u\n",
662 pProxyDev->pUsbIns->pszName, ep_num));
663
664 /*
665 * Clearing the zero control pipe doesn't make sense.
666 * Just ignore it.
667 */
668 if ((ep_num & 0xF) == 0)
669 return VINF_SUCCESS;
670
671 struct usb_ctl_request Req;
672 memset(&Req, 0, sizeof(Req));
673 usbProxyFreeBSDSetupReq(&Req.ucr_request,
674 VUSB_DIR_TO_DEV | VUSB_TO_ENDPOINT,
675 VUSB_REQ_CLEAR_FEATURE, 0, ep_num, 0);
676
677 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DO_REQUEST, &Req, true);
678
679 LogFlow(("usbProxyFreeBSDClearHaltedEp: rc=%Rrc\n", rc));
680 return rc;
681}
682
683/**
684 * @interface_method_impl{USBPROXYBACK,pfnUrbQueue}
685 */
686static DECLCALLBACK(int) usbProxyFreeBSDUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
687{
688 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
689 PUSBENDPOINTFBSD pEndpointFBSD;
690 struct usb_fs_endpoint *pXferEndpoint;
691 struct usb_fs_start UsbFsStart;
692 unsigned cFrames;
693 uint8_t *pbData;
694 int index;
695 int ep_num;
696 int rc;
697
698 LogFlow(("usbProxyFreeBSDUrbQueue: pUrb=%p EndPt=%u Dir=%u\n",
699 pUrb, (unsigned)pUrb->EndPt, (unsigned)pUrb->enmDir));
700
701 ep_num = pUrb->EndPt;
702 if ((pUrb->enmType != VUSBXFERTYPE_MSG) && (pUrb->enmDir == VUSBDIRECTION_IN)) {
703 /* set IN-direction bit */
704 ep_num |= 0x80;
705 }
706
707 index = 0;
708
709retry:
710
711 index = usbProxyFreeBSDEndpointOpen(pProxyDev, ep_num,
712 (pUrb->enmType == VUSBXFERTYPE_ISOC),
713 index);
714
715 if (index < 0)
716 return VERR_INVALID_PARAMETER;
717
718 pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
719 pXferEndpoint = &pDevFBSD->aHwEndpoint[index];
720
721 pbData = pUrb->abData;
722
723 switch (pUrb->enmType)
724 {
725 case VUSBXFERTYPE_MSG:
726 {
727 pEndpointFBSD->apvData[0] = pbData;
728 pEndpointFBSD->acbData[0] = 8;
729
730 /* check wLength */
731 if (pbData[6] || pbData[7])
732 {
733 pEndpointFBSD->apvData[1] = pbData + 8;
734 pEndpointFBSD->acbData[1] = pbData[6] | (pbData[7] << 8);
735 cFrames = 2;
736 }
737 else
738 {
739 pEndpointFBSD->apvData[1] = NULL;
740 pEndpointFBSD->acbData[1] = 0;
741 cFrames = 1;
742 }
743
744 LogFlow(("usbProxyFreeBSDUrbQueue: pUrb->cbData=%u, 0x%02x, "
745 "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
746 pUrb->cbData, pbData[0], pbData[1], pbData[2], pbData[3],
747 pbData[4], pbData[5], pbData[6], pbData[7]));
748
749 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
750 pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
751 break;
752 }
753 case VUSBXFERTYPE_ISOC:
754 {
755 unsigned i;
756
757 for (i = 0; i < pUrb->cIsocPkts; i++)
758 {
759 if (i >= pEndpointFBSD->cMaxFrames)
760 break;
761 pEndpointFBSD->apvData[i] = pbData + pUrb->aIsocPkts[i].off;
762 pEndpointFBSD->acbData[i] = pUrb->aIsocPkts[i].cb;
763 }
764 /* Timeout handling will be done during reap. */
765 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
766 pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
767 cFrames = i;
768 break;
769 }
770 default:
771 {
772 pEndpointFBSD->apvData[0] = pbData;
773 pEndpointFBSD->cbData0 = pUrb->cbData;
774
775 /* XXX maybe we have to loop */
776 if (pUrb->cbData > pEndpointFBSD->cMaxIo)
777 pEndpointFBSD->acbData[0] = pEndpointFBSD->cMaxIo;
778 else
779 pEndpointFBSD->acbData[0] = pUrb->cbData;
780
781 /* Timeout handling will be done during reap. */
782 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
783 pXferEndpoint->flags = pUrb->fShortNotOk ? 0 : USB_FS_FLAG_MULTI_SHORT_OK;
784 cFrames = 1;
785 break;
786 }
787 }
788
789 /* store number of frames */
790 pXferEndpoint->nFrames = cFrames;
791
792 /* zero-default */
793 memset(&UsbFsStart, 0, sizeof(UsbFsStart));
794
795 /* Start the transfer */
796 UsbFsStart.ep_index = index;
797
798 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_START, &UsbFsStart, true);
799
800 LogFlow(("usbProxyFreeBSDUrbQueue: USB_FS_START returned rc=%d "
801 "len[0]=%u len[1]=%u cbData=%u index=%u ep_num=%u\n", rc,
802 (unsigned)pEndpointFBSD->acbData[0],
803 (unsigned)pEndpointFBSD->acbData[1],
804 (unsigned)pUrb->cbData,
805 (unsigned)index, (unsigned)ep_num));
806
807 if (RT_FAILURE(rc))
808 {
809 if (rc == VERR_RESOURCE_BUSY)
810 {
811 index++;
812 goto retry;
813 }
814 return rc;
815 }
816 pUrb->Dev.pvPrivate = (void *)(long)(index + 1);
817 pEndpointFBSD->pUrb = pUrb;
818
819 return rc;
820}
821
822/**
823 * Reap URBs in-flight on a device.
824 *
825 * @returns Pointer to a completed URB.
826 * @returns NULL if no URB was completed.
827 * @param pProxyDev The device.
828 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
829 */
830static DECLCALLBACK(PVUSBURB) usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
831{
832 struct usb_fs_endpoint *pXferEndpoint;
833 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
834 PUSBENDPOINTFBSD pEndpointFBSD;
835 PVUSBURB pUrb;
836 struct usb_fs_complete UsbFsComplete;
837 struct pollfd pfd[2];
838 int rc;
839
840 LogFlow(("usbProxyFreeBSDUrbReap: pProxyDev=%p, cMillies=%u\n",
841 pProxyDev, cMillies));
842
843repeat:
844
845 pUrb = NULL;
846
847 /* check for cancelled transfers */
848 if (pDevFBSD->fCancelling)
849 {
850 for (unsigned n = 0; n < USBFBSD_MAXENDPOINTS; n++)
851 {
852 pEndpointFBSD = &pDevFBSD->aSwEndpoint[n];
853 if (pEndpointFBSD->fCancelling)
854 {
855 pEndpointFBSD->fCancelling = false;
856 pUrb = pEndpointFBSD->pUrb;
857 pEndpointFBSD->pUrb = NULL;
858
859 if (pUrb != NULL)
860 break;
861 }
862 }
863
864 if (pUrb != NULL)
865 {
866 pUrb->enmStatus = VUSBSTATUS_INVALID;
867 pUrb->Dev.pvPrivate = NULL;
868
869 switch (pUrb->enmType)
870 {
871 case VUSBXFERTYPE_MSG:
872 pUrb->cbData = 0;
873 break;
874 case VUSBXFERTYPE_ISOC:
875 pUrb->cbData = 0;
876 for (int n = 0; n < (int)pUrb->cIsocPkts; n++)
877 pUrb->aIsocPkts[n].cb = 0;
878 break;
879 default:
880 pUrb->cbData = 0;
881 break;
882 }
883 return pUrb;
884 }
885 pDevFBSD->fCancelling = false;
886 }
887 /* Zero default */
888
889 memset(&UsbFsComplete, 0, sizeof(UsbFsComplete));
890
891 /* Check if any endpoints are complete */
892 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true);
893 if (RT_SUCCESS(rc))
894 {
895 pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index];
896 pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index];
897
898 LogFlow(("usbProxyFreeBSDUrbReap: Reaped "
899 "URB %#p\n", pEndpointFBSD->pUrb));
900
901 if (pXferEndpoint->status == USB_ERR_CANCELLED)
902 goto repeat;
903
904 pUrb = pEndpointFBSD->pUrb;
905 pEndpointFBSD->pUrb = NULL;
906 if (pUrb == NULL)
907 goto repeat;
908
909 switch (pXferEndpoint->status)
910 {
911 case USB_ERR_NORMAL_COMPLETION:
912 pUrb->enmStatus = VUSBSTATUS_OK;
913 break;
914 case USB_ERR_STALLED:
915 pUrb->enmStatus = VUSBSTATUS_STALL;
916 break;
917 default:
918 pUrb->enmStatus = VUSBSTATUS_INVALID;
919 break;
920 }
921
922 pUrb->Dev.pvPrivate = NULL;
923
924 switch (pUrb->enmType)
925 {
926 case VUSBXFERTYPE_MSG:
927 pUrb->cbData = pEndpointFBSD->acbData[0] + pEndpointFBSD->acbData[1];
928 break;
929 case VUSBXFERTYPE_ISOC:
930 {
931 int n;
932
933 if (pUrb->enmDir == VUSBDIRECTION_OUT)
934 break;
935 pUrb->cbData = 0;
936 for (n = 0; n < (int)pUrb->cIsocPkts; n++)
937 {
938 if (n >= (int)pEndpointFBSD->cMaxFrames)
939 break;
940 pUrb->cbData += pEndpointFBSD->acbData[n];
941 pUrb->aIsocPkts[n].cb = pEndpointFBSD->acbData[n];
942 }
943 for (; n < (int)pUrb->cIsocPkts; n++)
944 pUrb->aIsocPkts[n].cb = 0;
945
946 break;
947 }
948 default:
949 pUrb->cbData = pEndpointFBSD->acbData[0];
950 break;
951 }
952
953 LogFlow(("usbProxyFreeBSDUrbReap: Status=%d epindex=%u "
954 "len[0]=%d len[1]=%d\n",
955 (int)pXferEndpoint->status,
956 (unsigned)UsbFsComplete.ep_index,
957 (unsigned)pEndpointFBSD->acbData[0],
958 (unsigned)pEndpointFBSD->acbData[1]));
959
960 }
961 else if (cMillies != 0 && rc == VERR_RESOURCE_BUSY)
962 {
963 for (;;)
964 {
965 pfd[0].fd = RTFileToNative(pDevFBSD->hFile);
966 pfd[0].events = POLLIN | POLLRDNORM;
967 pfd[0].revents = 0;
968
969 pfd[1].fd = RTPipeToNative(pDevFBSD->hPipeWakeupR);
970 pfd[1].events = POLLIN | POLLRDNORM;
971 pfd[1].revents = 0;
972
973 rc = poll(pfd, 2, (cMillies == RT_INDEFINITE_WAIT) ? INFTIM : cMillies);
974 if (rc > 0)
975 {
976 if (pfd[1].revents & POLLIN)
977 {
978 /* Got woken up, drain pipe. */
979 uint8_t bRead;
980 size_t cbIgnored = 0;
981 RTPipeRead(pDevFBSD->hPipeWakeupR, &bRead, 1, &cbIgnored);
982 /* Make sure we return from this function */
983 cMillies = 0;
984 }
985 break;
986 }
987 if (rc == 0)
988 return NULL;
989 if (errno != EAGAIN)
990 return NULL;
991 }
992 goto repeat;
993 }
994 return pUrb;
995}
996
997/**
998 * Cancels the URB.
999 * The URB requires reaping, so we don't change its state.
1000 */
1001static DECLCALLBACK(int) usbProxyFreeBSDUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1002{
1003 int index;
1004
1005 index = (int)(long)pUrb->Dev.pvPrivate - 1;
1006
1007 if (index < 0 || index >= USBFBSD_MAXENDPOINTS)
1008 return VINF_SUCCESS; /* invalid index, pretend success. */
1009
1010 LogFlow(("usbProxyFreeBSDUrbCancel: epindex=%u\n", (unsigned)index));
1011 return usbProxyFreeBSDEndpointClose(pProxyDev, index);
1012}
1013
1014static DECLCALLBACK(int) usbProxyFreeBSDWakeup(PUSBPROXYDEV pProxyDev)
1015{
1016 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
1017 size_t cbIgnored;
1018
1019 LogFlowFunc(("pProxyDev=%p\n", pProxyDev));
1020
1021 return RTPipeWrite(pDevFBSD->hPipeWakeupW, "", 1, &cbIgnored);
1022}
1023
1024/**
1025 * The FreeBSD USB Proxy Backend.
1026 */
1027extern const USBPROXYBACK g_USBProxyDeviceHost =
1028{
1029 /* pszName */
1030 "host",
1031 /* cbBackend */
1032 sizeof(USBPROXYDEVFBSD),
1033 usbProxyFreeBSDOpen,
1034 usbProxyFreeBSDInit,
1035 usbProxyFreeBSDClose,
1036 usbProxyFreeBSDReset,
1037 usbProxyFreeBSDSetConfig,
1038 usbProxyFreeBSDClaimInterface,
1039 usbProxyFreeBSDReleaseInterface,
1040 usbProxyFreeBSDSetInterface,
1041 usbProxyFreeBSDClearHaltedEp,
1042 usbProxyFreeBSDUrbQueue,
1043 usbProxyFreeBSDUrbCancel,
1044 usbProxyFreeBSDUrbReap,
1045 usbProxyFreeBSDWakeup,
1046 0
1047};
1048
1049/*
1050 * Local Variables:
1051 * mode: c
1052 * c-file-style: "bsd"
1053 * c-basic-offset: 4
1054 * tab-width: 4
1055 * indent-tabs-mode: s
1056 * End:
1057 */
1058
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