VirtualBox

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

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

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.4 KB
Line 
1/* $Id: USBProxyDevice-freebsd.cpp 76553 2019-01-01 01:45:53Z 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-2019 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 * @param pvBackend Backend specific pointer, unused for the linux backend.
369 */
370static DECLCALLBACK(int) usbProxyFreeBSDOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress,
371 void *pvBackend)
372{
373 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
374 int rc;
375
376 LogFlow(("usbProxyFreeBSDOpen: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
377
378 NOREF(pvBackend);
379
380 /*
381 * Try open the device node.
382 */
383 RTFILE hFile;
384 rc = RTFileOpen(&hFile, pszAddress, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
385 if (RT_SUCCESS(rc))
386 {
387 /*
388 * Initialize the FreeBSD backend data.
389 */
390 pDevFBSD->hFile = hFile;
391 rc = usbProxyFreeBSDFsInit(pProxyDev);
392 if (RT_SUCCESS(rc))
393 {
394 /*
395 * Create wakeup pipe.
396 */
397 rc = RTPipeCreate(&pDevFBSD->hPipeWakeupR, &pDevFBSD->hPipeWakeupW, 0);
398 if (RT_SUCCESS(rc))
399 {
400 LogFlow(("usbProxyFreeBSDOpen(%p, %s): returns successfully hFile=%RTfile iActiveCfg=%d\n",
401 pProxyDev, pszAddress, pDevFBSD->hFile, pProxyDev->iActiveCfg));
402
403 return VINF_SUCCESS;
404 }
405 }
406
407 RTFileClose(hFile);
408 }
409 else if (rc == VERR_ACCESS_DENIED)
410 rc = VERR_VUSB_USBFS_PERMISSION;
411
412 Log(("usbProxyFreeBSDOpen(%p, %s) failed, rc=%d!\n",
413 pProxyDev, pszAddress, rc));
414
415 return rc;
416}
417
418
419/**
420 * Claims all the interfaces and figures out the
421 * current configuration.
422 *
423 * @returns VINF_SUCCESS.
424 * @param pProxyDev The proxy device.
425 */
426static DECLCALLBACK(int) usbProxyFreeBSDInit(PUSBPROXYDEV pProxyDev)
427{
428 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
429 int rc;
430
431 LogFlow(("usbProxyFreeBSDInit: pProxyDev=%s\n",
432 pProxyDev->pUsbIns->pszName));
433
434 /* Retrieve current active configuration. */
435 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_GET_CONFIG,
436 &pProxyDev->iActiveCfg, true);
437 if (RT_FAILURE(rc) || pProxyDev->iActiveCfg == 255)
438 {
439 pProxyDev->cIgnoreSetConfigs = 0;
440 pProxyDev->iActiveCfg = -1;
441 }
442 else
443 {
444 pProxyDev->cIgnoreSetConfigs = 1;
445 pProxyDev->iActiveCfg++;
446 }
447
448 Log(("usbProxyFreeBSDInit: iActiveCfg=%d\n", pProxyDev->iActiveCfg));
449
450 return rc;
451}
452
453/**
454 * Closes the proxy device.
455 */
456static DECLCALLBACK(void) usbProxyFreeBSDClose(PUSBPROXYDEV pProxyDev)
457{
458 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
459
460 LogFlow(("usbProxyFreeBSDClose: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
461
462 /* sanity check */
463 AssertPtrReturnVoid(pDevFBSD);
464
465 usbProxyFreeBSDFsUnInit(pProxyDev);
466
467 RTPipeClose(pDevFBSD->hPipeWakeupR);
468 RTPipeClose(pDevFBSD->hPipeWakeupW);
469
470 RTFileClose(pDevFBSD->hFile);
471 pDevFBSD->hFile = NIL_RTFILE;
472
473 LogFlow(("usbProxyFreeBSDClose: returns\n"));
474}
475
476/**
477 * Reset a device.
478 *
479 * @returns VBox status code.
480 * @param pDev The device to reset.
481 */
482static DECLCALLBACK(int) usbProxyFreeBSDReset(PUSBPROXYDEV pProxyDev, bool fResetOnFreeBSD)
483{
484 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
485 int iParm;
486 int rc = VINF_SUCCESS;
487
488 LogFlow(("usbProxyFreeBSDReset: pProxyDev=%s\n",
489 pProxyDev->pUsbIns->pszName));
490
491 if (!fResetOnFreeBSD)
492 goto done;
493
494 /* We need to release kernel ressources first. */
495 rc = usbProxyFreeBSDFsUnInit(pProxyDev);
496 if (RT_FAILURE(rc))
497 goto done;
498
499 /* Resetting is only possible as super-user, ignore any failures: */
500 iParm = 0;
501 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DEVICEENUMERATE, &iParm, true);
502 if (RT_FAILURE(rc))
503 {
504 /* Set the config instead of bus reset */
505 iParm = 255;
506 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iParm, true);
507 if (RT_SUCCESS(rc))
508 {
509 iParm = 0;
510 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iParm, true);
511 }
512 }
513 usleep(10000); /* nice it! */
514
515 /* Allocate kernel ressources again. */
516 rc = usbProxyFreeBSDFsInit(pProxyDev);
517 if (RT_FAILURE(rc))
518 goto done;
519
520 /* Retrieve current active configuration. */
521 rc = usbProxyFreeBSDInit(pProxyDev);
522
523done:
524 pProxyDev->cIgnoreSetConfigs = 2;
525
526 return rc;
527}
528
529/**
530 * SET_CONFIGURATION.
531 *
532 * The caller makes sure that it's not called first time after open or reset
533 * with the active interface.
534 *
535 * @returns success indicator.
536 * @param pProxyDev The device instance data.
537 * @param iCfg The configuration to set.
538 */
539static DECLCALLBACK(int) usbProxyFreeBSDSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
540{
541 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
542 int iCfgIndex;
543 int rc;
544
545 LogFlow(("usbProxyFreeBSDSetConfig: pProxyDev=%s cfg=%x\n",
546 pProxyDev->pUsbIns->pszName, iCfg));
547
548 /* We need to release kernel ressources first. */
549 rc = usbProxyFreeBSDFsUnInit(pProxyDev);
550 if (RT_FAILURE(rc))
551 {
552 LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
553 "failed failed rc=%d\n", rc));
554 return rc;
555 }
556
557 if (iCfg == 0)
558 {
559 /* Unconfigure */
560 iCfgIndex = 255;
561 }
562 else
563 {
564 /* Get the configuration index matching the value. */
565 for (iCfgIndex = 0; iCfgIndex < pProxyDev->DevDesc.bNumConfigurations; iCfgIndex++)
566 {
567 if (pProxyDev->paCfgDescs[iCfgIndex].Core.bConfigurationValue == iCfg)
568 break;
569 }
570
571 if (iCfgIndex == pProxyDev->DevDesc.bNumConfigurations)
572 {
573 LogFlow(("usbProxyFreeBSDSetConfig: configuration "
574 "%d not found\n", iCfg));
575 return VERR_NOT_FOUND;
576 }
577 }
578
579 /* Set the config */
580 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iCfgIndex, true);
581 if (RT_FAILURE(rc))
582 return rc;
583
584 /* Allocate kernel ressources again. */
585 return usbProxyFreeBSDFsInit(pProxyDev);
586}
587
588/**
589 * Claims an interface.
590 * @returns success indicator.
591 */
592static DECLCALLBACK(int) usbProxyFreeBSDClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
593{
594 int rc;
595
596 LogFlow(("usbProxyFreeBSDClaimInterface: pProxyDev=%s "
597 "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));
598
599 /*
600 * Try to detach kernel driver on this interface, ignore any
601 * failures
602 */
603 usbProxyFreeBSDDoIoCtl(pProxyDev, USB_IFACE_DRIVER_DETACH, &iIf, true);
604
605 /* Try to claim interface */
606 return usbProxyFreeBSDDoIoCtl(pProxyDev, USB_CLAIM_INTERFACE, &iIf, true);
607}
608
609/**
610 * Releases an interface.
611 * @returns success indicator.
612 */
613static DECLCALLBACK(int) usbProxyFreeBSDReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
614{
615 int rc;
616
617 LogFlow(("usbProxyFreeBSDReleaseInterface: pProxyDev=%s "
618 "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));
619
620 return usbProxyFreeBSDDoIoCtl(pProxyDev, USB_RELEASE_INTERFACE, &iIf, true);
621}
622
623/**
624 * SET_INTERFACE.
625 *
626 * @returns success indicator.
627 */
628static DECLCALLBACK(int) usbProxyFreeBSDSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
629{
630 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
631 struct usb_alt_interface UsbIntAlt;
632 int rc;
633
634 LogFlow(("usbProxyFreeBSDSetInterface: pProxyDev=%p iIf=%x iAlt=%x\n",
635 pProxyDev, iIf, iAlt));
636
637 /* We need to release kernel ressources first. */
638 rc = usbProxyFreeBSDFsUnInit(pProxyDev);
639 if (RT_FAILURE(rc))
640 {
641 LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
642 "failed failed rc=%d\n", rc));
643 return rc;
644 }
645 memset(&UsbIntAlt, 0, sizeof(UsbIntAlt));
646 UsbIntAlt.uai_interface_index = iIf;
647 UsbIntAlt.uai_alt_index = iAlt;
648
649 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_ALTINTERFACE, &UsbIntAlt, true);
650 if (RT_FAILURE(rc))
651 {
652 LogFlow(("usbProxyFreeBSDSetInterface: Setting interface %d %d "
653 "failed rc=%d\n", iIf, iAlt, rc));
654 return rc;
655 }
656
657 return usbProxyFreeBSDFsInit(pProxyDev);
658}
659
660/**
661 * Clears the halted endpoint 'ep_num'.
662 */
663static DECLCALLBACK(int) usbProxyFreeBSDClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int ep_num)
664{
665 LogFlow(("usbProxyFreeBSDClearHaltedEp: pProxyDev=%s ep_num=%u\n",
666 pProxyDev->pUsbIns->pszName, ep_num));
667
668 /*
669 * Clearing the zero control pipe doesn't make sense.
670 * Just ignore it.
671 */
672 if ((ep_num & 0xF) == 0)
673 return VINF_SUCCESS;
674
675 struct usb_ctl_request Req;
676 memset(&Req, 0, sizeof(Req));
677 usbProxyFreeBSDSetupReq(&Req.ucr_request,
678 VUSB_DIR_TO_DEV | VUSB_TO_ENDPOINT,
679 VUSB_REQ_CLEAR_FEATURE, 0, ep_num, 0);
680
681 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DO_REQUEST, &Req, true);
682
683 LogFlow(("usbProxyFreeBSDClearHaltedEp: rc=%Rrc\n", rc));
684 return rc;
685}
686
687/**
688 * @interface_method_impl{USBPROXYBACK,pfnUrbQueue}
689 */
690static DECLCALLBACK(int) usbProxyFreeBSDUrbQueue(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
691{
692 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
693 PUSBENDPOINTFBSD pEndpointFBSD;
694 struct usb_fs_endpoint *pXferEndpoint;
695 struct usb_fs_start UsbFsStart;
696 unsigned cFrames;
697 uint8_t *pbData;
698 int index;
699 int ep_num;
700 int rc;
701
702 LogFlow(("usbProxyFreeBSDUrbQueue: pUrb=%p EndPt=%u Dir=%u\n",
703 pUrb, (unsigned)pUrb->EndPt, (unsigned)pUrb->enmDir));
704
705 ep_num = pUrb->EndPt;
706 if ((pUrb->enmType != VUSBXFERTYPE_MSG) && (pUrb->enmDir == VUSBDIRECTION_IN)) {
707 /* set IN-direction bit */
708 ep_num |= 0x80;
709 }
710
711 index = 0;
712
713retry:
714
715 index = usbProxyFreeBSDEndpointOpen(pProxyDev, ep_num,
716 (pUrb->enmType == VUSBXFERTYPE_ISOC),
717 index);
718
719 if (index < 0)
720 return VERR_INVALID_PARAMETER;
721
722 pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
723 pXferEndpoint = &pDevFBSD->aHwEndpoint[index];
724
725 pbData = pUrb->abData;
726
727 switch (pUrb->enmType)
728 {
729 case VUSBXFERTYPE_MSG:
730 {
731 pEndpointFBSD->apvData[0] = pbData;
732 pEndpointFBSD->acbData[0] = 8;
733
734 /* check wLength */
735 if (pbData[6] || pbData[7])
736 {
737 pEndpointFBSD->apvData[1] = pbData + 8;
738 pEndpointFBSD->acbData[1] = pbData[6] | (pbData[7] << 8);
739 cFrames = 2;
740 }
741 else
742 {
743 pEndpointFBSD->apvData[1] = NULL;
744 pEndpointFBSD->acbData[1] = 0;
745 cFrames = 1;
746 }
747
748 LogFlow(("usbProxyFreeBSDUrbQueue: pUrb->cbData=%u, 0x%02x, "
749 "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
750 pUrb->cbData, pbData[0], pbData[1], pbData[2], pbData[3],
751 pbData[4], pbData[5], pbData[6], pbData[7]));
752
753 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
754 pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
755 break;
756 }
757 case VUSBXFERTYPE_ISOC:
758 {
759 unsigned i;
760
761 for (i = 0; i < pUrb->cIsocPkts; i++)
762 {
763 if (i >= pEndpointFBSD->cMaxFrames)
764 break;
765 pEndpointFBSD->apvData[i] = pbData + pUrb->aIsocPkts[i].off;
766 pEndpointFBSD->acbData[i] = pUrb->aIsocPkts[i].cb;
767 }
768 /* Timeout handling will be done during reap. */
769 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
770 pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
771 cFrames = i;
772 break;
773 }
774 default:
775 {
776 pEndpointFBSD->apvData[0] = pbData;
777 pEndpointFBSD->cbData0 = pUrb->cbData;
778
779 /* XXX maybe we have to loop */
780 if (pUrb->cbData > pEndpointFBSD->cMaxIo)
781 pEndpointFBSD->acbData[0] = pEndpointFBSD->cMaxIo;
782 else
783 pEndpointFBSD->acbData[0] = pUrb->cbData;
784
785 /* Timeout handling will be done during reap. */
786 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
787 pXferEndpoint->flags = pUrb->fShortNotOk ? 0 : USB_FS_FLAG_MULTI_SHORT_OK;
788 cFrames = 1;
789 break;
790 }
791 }
792
793 /* store number of frames */
794 pXferEndpoint->nFrames = cFrames;
795
796 /* zero-default */
797 memset(&UsbFsStart, 0, sizeof(UsbFsStart));
798
799 /* Start the transfer */
800 UsbFsStart.ep_index = index;
801
802 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_START, &UsbFsStart, true);
803
804 LogFlow(("usbProxyFreeBSDUrbQueue: USB_FS_START returned rc=%d "
805 "len[0]=%u len[1]=%u cbData=%u index=%u ep_num=%u\n", rc,
806 (unsigned)pEndpointFBSD->acbData[0],
807 (unsigned)pEndpointFBSD->acbData[1],
808 (unsigned)pUrb->cbData,
809 (unsigned)index, (unsigned)ep_num));
810
811 if (RT_FAILURE(rc))
812 {
813 if (rc == VERR_RESOURCE_BUSY)
814 {
815 index++;
816 goto retry;
817 }
818 return rc;
819 }
820 pUrb->Dev.pvPrivate = (void *)(long)(index + 1);
821 pEndpointFBSD->pUrb = pUrb;
822
823 return rc;
824}
825
826/**
827 * Reap URBs in-flight on a device.
828 *
829 * @returns Pointer to a completed URB.
830 * @returns NULL if no URB was completed.
831 * @param pProxyDev The device.
832 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
833 */
834static DECLCALLBACK(PVUSBURB) usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
835{
836 struct usb_fs_endpoint *pXferEndpoint;
837 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
838 PUSBENDPOINTFBSD pEndpointFBSD;
839 PVUSBURB pUrb;
840 struct usb_fs_complete UsbFsComplete;
841 struct pollfd pfd[2];
842 int rc;
843
844 LogFlow(("usbProxyFreeBSDUrbReap: pProxyDev=%p, cMillies=%u\n",
845 pProxyDev, cMillies));
846
847repeat:
848
849 pUrb = NULL;
850
851 /* check for cancelled transfers */
852 if (pDevFBSD->fCancelling)
853 {
854 for (unsigned n = 0; n < USBFBSD_MAXENDPOINTS; n++)
855 {
856 pEndpointFBSD = &pDevFBSD->aSwEndpoint[n];
857 if (pEndpointFBSD->fCancelling)
858 {
859 pEndpointFBSD->fCancelling = false;
860 pUrb = pEndpointFBSD->pUrb;
861 pEndpointFBSD->pUrb = NULL;
862
863 if (pUrb != NULL)
864 break;
865 }
866 }
867
868 if (pUrb != NULL)
869 {
870 pUrb->enmStatus = VUSBSTATUS_INVALID;
871 pUrb->Dev.pvPrivate = NULL;
872
873 switch (pUrb->enmType)
874 {
875 case VUSBXFERTYPE_MSG:
876 pUrb->cbData = 0;
877 break;
878 case VUSBXFERTYPE_ISOC:
879 pUrb->cbData = 0;
880 for (int n = 0; n < (int)pUrb->cIsocPkts; n++)
881 pUrb->aIsocPkts[n].cb = 0;
882 break;
883 default:
884 pUrb->cbData = 0;
885 break;
886 }
887 return pUrb;
888 }
889 pDevFBSD->fCancelling = false;
890 }
891 /* Zero default */
892
893 memset(&UsbFsComplete, 0, sizeof(UsbFsComplete));
894
895 /* Check if any endpoints are complete */
896 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true);
897 if (RT_SUCCESS(rc))
898 {
899 pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index];
900 pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index];
901
902 LogFlow(("usbProxyFreeBSDUrbReap: Reaped "
903 "URB %#p\n", pEndpointFBSD->pUrb));
904
905 if (pXferEndpoint->status == USB_ERR_CANCELLED)
906 goto repeat;
907
908 pUrb = pEndpointFBSD->pUrb;
909 pEndpointFBSD->pUrb = NULL;
910 if (pUrb == NULL)
911 goto repeat;
912
913 switch (pXferEndpoint->status)
914 {
915 case USB_ERR_NORMAL_COMPLETION:
916 pUrb->enmStatus = VUSBSTATUS_OK;
917 break;
918 case USB_ERR_STALLED:
919 pUrb->enmStatus = VUSBSTATUS_STALL;
920 break;
921 default:
922 pUrb->enmStatus = VUSBSTATUS_INVALID;
923 break;
924 }
925
926 pUrb->Dev.pvPrivate = NULL;
927
928 switch (pUrb->enmType)
929 {
930 case VUSBXFERTYPE_MSG:
931 pUrb->cbData = pEndpointFBSD->acbData[0] + pEndpointFBSD->acbData[1];
932 break;
933 case VUSBXFERTYPE_ISOC:
934 {
935 int n;
936
937 if (pUrb->enmDir == VUSBDIRECTION_OUT)
938 break;
939 pUrb->cbData = 0;
940 for (n = 0; n < (int)pUrb->cIsocPkts; n++)
941 {
942 if (n >= (int)pEndpointFBSD->cMaxFrames)
943 break;
944 pUrb->cbData += pEndpointFBSD->acbData[n];
945 pUrb->aIsocPkts[n].cb = pEndpointFBSD->acbData[n];
946 }
947 for (; n < (int)pUrb->cIsocPkts; n++)
948 pUrb->aIsocPkts[n].cb = 0;
949
950 break;
951 }
952 default:
953 pUrb->cbData = pEndpointFBSD->acbData[0];
954 break;
955 }
956
957 LogFlow(("usbProxyFreeBSDUrbReap: Status=%d epindex=%u "
958 "len[0]=%d len[1]=%d\n",
959 (int)pXferEndpoint->status,
960 (unsigned)UsbFsComplete.ep_index,
961 (unsigned)pEndpointFBSD->acbData[0],
962 (unsigned)pEndpointFBSD->acbData[1]));
963
964 }
965 else if (cMillies != 0 && rc == VERR_RESOURCE_BUSY)
966 {
967 for (;;)
968 {
969 pfd[0].fd = RTFileToNative(pDevFBSD->hFile);
970 pfd[0].events = POLLIN | POLLRDNORM;
971 pfd[0].revents = 0;
972
973 pfd[1].fd = RTPipeToNative(pDevFBSD->hPipeWakeupR);
974 pfd[1].events = POLLIN | POLLRDNORM;
975 pfd[1].revents = 0;
976
977 rc = poll(pfd, 2, (cMillies == RT_INDEFINITE_WAIT) ? INFTIM : cMillies);
978 if (rc > 0)
979 {
980 if (pfd[1].revents & POLLIN)
981 {
982 /* Got woken up, drain pipe. */
983 uint8_t bRead;
984 size_t cbIgnored = 0;
985 RTPipeRead(pDevFBSD->hPipeWakeupR, &bRead, 1, &cbIgnored);
986 /* Make sure we return from this function */
987 cMillies = 0;
988 }
989 break;
990 }
991 if (rc == 0)
992 return NULL;
993 if (errno != EAGAIN)
994 return NULL;
995 }
996 goto repeat;
997 }
998 return pUrb;
999}
1000
1001/**
1002 * Cancels the URB.
1003 * The URB requires reaping, so we don't change its state.
1004 */
1005static DECLCALLBACK(int) usbProxyFreeBSDUrbCancel(PUSBPROXYDEV pProxyDev, PVUSBURB pUrb)
1006{
1007 int index;
1008
1009 index = (int)(long)pUrb->Dev.pvPrivate - 1;
1010
1011 if (index < 0 || index >= USBFBSD_MAXENDPOINTS)
1012 return VINF_SUCCESS; /* invalid index, pretend success. */
1013
1014 LogFlow(("usbProxyFreeBSDUrbCancel: epindex=%u\n", (unsigned)index));
1015 return usbProxyFreeBSDEndpointClose(pProxyDev, index);
1016}
1017
1018static DECLCALLBACK(int) usbProxyFreeBSDWakeup(PUSBPROXYDEV pProxyDev)
1019{
1020 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
1021 size_t cbIgnored;
1022
1023 LogFlowFunc(("pProxyDev=%p\n", pProxyDev));
1024
1025 return RTPipeWrite(pDevFBSD->hPipeWakeupW, "", 1, &cbIgnored);
1026}
1027
1028/**
1029 * The FreeBSD USB Proxy Backend.
1030 */
1031extern const USBPROXYBACK g_USBProxyDeviceHost =
1032{
1033 /* pszName */
1034 "host",
1035 /* cbBackend */
1036 sizeof(USBPROXYDEVFBSD),
1037 usbProxyFreeBSDOpen,
1038 usbProxyFreeBSDInit,
1039 usbProxyFreeBSDClose,
1040 usbProxyFreeBSDReset,
1041 usbProxyFreeBSDSetConfig,
1042 usbProxyFreeBSDClaimInterface,
1043 usbProxyFreeBSDReleaseInterface,
1044 usbProxyFreeBSDSetInterface,
1045 usbProxyFreeBSDClearHaltedEp,
1046 usbProxyFreeBSDUrbQueue,
1047 usbProxyFreeBSDUrbCancel,
1048 usbProxyFreeBSDUrbReap,
1049 usbProxyFreeBSDWakeup,
1050 0
1051};
1052
1053/*
1054 * Local Variables:
1055 * mode: c
1056 * c-file-style: "bsd"
1057 * c-basic-offset: 4
1058 * tab-width: 4
1059 * indent-tabs-mode: s
1060 * End:
1061 */
1062
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