VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use