VirtualBox

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

Last change on this file since 46727 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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