[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] | 82 | typedef 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 | */
|
---|
| 107 | typedef 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] | 129 | static 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] | 144 | static 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] | 176 | static 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] | 207 | static 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 | */
|
---|
| 239 | static 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] | 259 | static 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] | 334 | static 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] | 379 | static 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] | 432 | static 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] | 462 | static 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] | 488 | static 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 |
|
---|
| 529 | done:
|
---|
| 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] | 545 | static 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] | 598 | static 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] | 619 | static 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] | 634 | static 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] | 669 | static 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] | 696 | static 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 |
|
---|
| 719 | retry:
|
---|
| 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] | 840 | static 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] | 853 | repeat:
|
---|
[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] | 1011 | static 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] | 1024 | static 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 | */
|
---|
| 1037 | extern 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 |
|
---|