VirtualBox

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

Last change on this file since 52270 was 52148, checked in by vboxsync, 11 years ago

Devices/USB: ancel URBs on the I/O thread if available, fixes a race causing an assertion

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette