VirtualBox

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

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

USB/Proxy: Start a source code cleanup, remove unused struct members and make the generic proxy code do the backend specific memory allocation (fixes a small memory leak in the VRDP backend when closing a proxy device)

  • 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 50228 2014-01-24 21:16:37Z 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 false;
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 false;
561 }
562 }
563
564 /* Set the config */
565 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iCfgIndex, true);
566 if (RT_FAILURE(rc))
567 return false;
568
569 /* Allocate kernel ressources again. */
570 rc = usbProxyFreeBSDFsInit(pProxyDev);
571 if (RT_FAILURE(rc))
572 return false;
573
574 return true;
575}
576
577/**
578 * Claims an interface.
579 * @returns success indicator.
580 */
581static DECLCALLBACK(int) usbProxyFreeBSDClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
582{
583 int rc;
584
585 LogFlow(("usbProxyFreeBSDClaimInterface: pProxyDev=%s "
586 "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));
587
588 /*
589 * Try to detach kernel driver on this interface, ignore any
590 * failures
591 */
592 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_IFACE_DRIVER_DETACH, &iIf, true);
593
594 /* Try to claim interface */
595 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_CLAIM_INTERFACE, &iIf, true);
596 if (RT_FAILURE(rc))
597 return false;
598
599 return true;
600}
601
602/**
603 * Releases an interface.
604 * @returns success indicator.
605 */
606static DECLCALLBACK(int) usbProxyFreeBSDReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
607{
608 int rc;
609
610 LogFlow(("usbProxyFreeBSDReleaseInterface: pProxyDev=%s "
611 "ifnum=%x\n", pProxyDev->pUsbIns->pszName, iIf));
612
613 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_RELEASE_INTERFACE, &iIf, true);
614 if (RT_FAILURE(rc))
615 return false;
616
617 return true;
618}
619
620/**
621 * SET_INTERFACE.
622 *
623 * @returns success indicator.
624 */
625static DECLCALLBACK(int)
626usbProxyFreeBSDSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
627{
628 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
629 struct usb_alt_interface UsbIntAlt;
630 int rc;
631
632 LogFlow(("usbProxyFreeBSDSetInterface: pProxyDev=%p iIf=%x iAlt=%x\n",
633 pProxyDev, iIf, iAlt));
634
635 /* We need to release kernel ressources first. */
636 rc = usbProxyFreeBSDFsUnInit(pProxyDev);
637 if (RT_FAILURE(rc))
638 {
639 LogFlow(("usbProxyFreeBSDSetInterface: Freeing kernel resources "
640 "failed failed rc=%d\n", rc));
641 return false;
642 }
643 memset(&UsbIntAlt, 0, sizeof(UsbIntAlt));
644 UsbIntAlt.uai_interface_index = iIf;
645 UsbIntAlt.uai_alt_index = iAlt;
646
647 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_ALTINTERFACE, &UsbIntAlt, true);
648 if (RT_FAILURE(rc))
649 {
650 LogFlow(("usbProxyFreeBSDSetInterface: Setting interface %d %d "
651 "failed rc=%d\n", iIf, iAlt, rc));
652 return false;
653 }
654
655 rc = usbProxyFreeBSDFsInit(pProxyDev);
656 if (RT_FAILURE(rc))
657 return false;
658
659 return true;
660}
661
662/**
663 * Clears the halted endpoint 'ep_num'.
664 */
665static DECLCALLBACK(bool) usbProxyFreeBSDClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int ep_num)
666{
667 struct usb_ctl_request Req;
668 int rc;
669
670 LogFlow(("usbProxyFreeBSDClearHaltedEp: pProxyDev=%s ep_num=%u\n",
671 pProxyDev->pUsbIns->pszName, ep_num));
672
673 /*
674 * Clearing the zero control pipe doesn't make sense.
675 * Just ignore it.
676 */
677 if ((ep_num & 0xF) == 0)
678 return true;
679
680 memset(&Req, 0, sizeof(Req));
681
682 usbProxyFreeBSDSetupReq(&Req.ucr_request,
683 VUSB_DIR_TO_DEV | VUSB_TO_ENDPOINT,
684 VUSB_REQ_CLEAR_FEATURE, 0, ep_num, 0);
685
686 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DO_REQUEST, &Req, true);
687
688 LogFlow(("usbProxyFreeBSDClearHaltedEp: rc=%Rrc\n", rc));
689
690 if (RT_FAILURE(rc))
691 return false;
692
693 return true;
694}
695
696/**
697 * @copydoc USBPROXYBACK::pfnUrbQueue
698 */
699static DECLCALLBACK(int) usbProxyFreeBSDUrbQueue(PVUSBURB pUrb)
700{
701 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
702 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
703 PUSBENDPOINTFBSD pEndpointFBSD;
704 struct usb_fs_endpoint *pXferEndpoint;
705 struct usb_fs_start UsbFsStart;
706 unsigned cFrames;
707 uint8_t *pbData;
708 int index;
709 int ep_num;
710 int rc;
711
712 LogFlow(("usbProxyFreeBSDUrbQueue: pUrb=%p EndPt=%u Dir=%u\n",
713 pUrb, (unsigned)pUrb->EndPt, (unsigned)pUrb->enmDir));
714
715 ep_num = pUrb->EndPt;
716
717 if ((pUrb->enmType != VUSBXFERTYPE_MSG) && (pUrb->enmDir == VUSBDIRECTION_IN))
718 ep_num |= 0x80;
719
720 index = 0;
721
722retry:
723
724 index = usbProxyFreeBSDEndpointOpen(pProxyDev, ep_num,
725 (pUrb->enmType == VUSBXFERTYPE_ISOC),
726 index);
727
728 if (index < 0)
729 return false;
730
731 pEndpointFBSD = &pDevFBSD->aSwEndpoint[index];
732 pXferEndpoint = &pDevFBSD->aHwEndpoint[index];
733
734 pbData = pUrb->abData;
735
736 switch (pUrb->enmType)
737 {
738 case VUSBXFERTYPE_MSG:
739 {
740 pEndpointFBSD->apvData[0] = pbData;
741 pEndpointFBSD->acbData[0] = 8;
742
743 /* check wLength */
744 if (pbData[6] || pbData[7])
745 {
746 pEndpointFBSD->apvData[1] = pbData + 8;
747 pEndpointFBSD->acbData[1] = pbData[6] | (pbData[7] << 8);
748 cFrames = 2;
749 }
750 else
751 {
752 pEndpointFBSD->apvData[1] = NULL;
753 pEndpointFBSD->acbData[1] = 0;
754 cFrames = 1;
755 }
756
757 LogFlow(("usbProxyFreeBSDUrbQueue: pUrb->cbData=%u, 0x%02x, "
758 "0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
759 pUrb->cbData, pbData[0], pbData[1], pbData[2], pbData[3],
760 pbData[4], pbData[5], pbData[6], pbData[7]));
761
762 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
763 pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
764 break;
765 }
766 case VUSBXFERTYPE_ISOC:
767 {
768 unsigned i;
769
770 for (i = 0; i < pUrb->cIsocPkts; i++)
771 {
772 if (i >= pEndpointFBSD->cMaxFrames)
773 break;
774 pEndpointFBSD->apvData[i] = pbData + pUrb->aIsocPkts[i].off;
775 pEndpointFBSD->acbData[i] = pUrb->aIsocPkts[i].cb;
776 }
777 /* Timeout handling will be done during reap. */
778 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
779 pXferEndpoint->flags = USB_FS_FLAG_MULTI_SHORT_OK;
780 cFrames = i;
781 break;
782 }
783 default:
784 {
785 pEndpointFBSD->apvData[0] = pbData;
786 pEndpointFBSD->cbData0 = pUrb->cbData;
787
788 /* XXX maybe we have to loop */
789 if (pUrb->cbData > pEndpointFBSD->cMaxIo)
790 pEndpointFBSD->acbData[0] = pEndpointFBSD->cMaxIo;
791 else
792 pEndpointFBSD->acbData[0] = pUrb->cbData;
793
794 /* Timeout handling will be done during reap. */
795 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE;
796 pXferEndpoint->flags = pUrb->fShortNotOk ? 0 : USB_FS_FLAG_MULTI_SHORT_OK;
797 cFrames = 1;
798 break;
799 }
800 }
801
802 /* store number of frames */
803 pXferEndpoint->nFrames = cFrames;
804
805 /* zero-default */
806 memset(&UsbFsStart, 0, sizeof(UsbFsStart));
807
808 /* Start the transfer */
809 UsbFsStart.ep_index = index;
810
811 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_START, &UsbFsStart, true);
812
813 LogFlow(("usbProxyFreeBSDUrbQueue: USB_FS_START returned rc=%d "
814 "len[0]=%u len[1]=%u cbData=%u index=%u ep_num=%u\n", rc,
815 (unsigned)pEndpointFBSD->acbData[0],
816 (unsigned)pEndpointFBSD->acbData[1],
817 (unsigned)pUrb->cbData,
818 (unsigned)index, (unsigned)ep_num));
819
820 if (RT_FAILURE(rc))
821 {
822 if (rc == VERR_RESOURCE_BUSY)
823 {
824 index++;
825 goto retry;
826 }
827 return false;
828 }
829 pUrb->Dev.pvPrivate = (void *)(long)(index + 1);
830 pEndpointFBSD->pUrb = pUrb;
831
832 return true;
833}
834
835/**
836 * Reap URBs in-flight on a device.
837 *
838 * @returns Pointer to a completed URB.
839 * @returns NULL if no URB was completed.
840 * @param pProxyDev The device.
841 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
842 */
843static DECLCALLBACK(PVUSBURB) usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
844{
845 struct usb_fs_endpoint *pXferEndpoint;
846 PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD);
847 PUSBENDPOINTFBSD pEndpointFBSD;
848 PVUSBURB pUrb;
849 struct usb_fs_complete UsbFsComplete;
850 struct pollfd PollFd;
851 int rc;
852
853 LogFlow(("usbProxyFreeBSDUrbReap: pProxyDev=%p, cMillies=%u\n",
854 pProxyDev, cMillies));
855
856repeat:
857
858 pUrb = NULL;
859
860 /* check for cancelled transfers */
861 if (pDevFBSD->fCancelling)
862 {
863 for (unsigned n = 0; n < USBFBSD_MAXENDPOINTS; n++)
864 {
865 pEndpointFBSD = &pDevFBSD->aSwEndpoint[n];
866 if (pEndpointFBSD->fCancelling)
867 {
868 pEndpointFBSD->fCancelling = false;
869 pUrb = pEndpointFBSD->pUrb;
870 pEndpointFBSD->pUrb = NULL;
871
872 if (pUrb != NULL)
873 break;
874 }
875 }
876
877 if (pUrb != NULL)
878 {
879 pUrb->enmStatus = VUSBSTATUS_INVALID;
880 pUrb->Dev.pvPrivate = NULL;
881
882 switch (pUrb->enmType)
883 {
884 case VUSBXFERTYPE_MSG:
885 pUrb->cbData = 0;
886 break;
887 case VUSBXFERTYPE_ISOC:
888 pUrb->cbData = 0;
889 for (int n = 0; n < (int)pUrb->cIsocPkts; n++)
890 pUrb->aIsocPkts[n].cb = 0;
891 break;
892 default:
893 pUrb->cbData = 0;
894 break;
895 }
896 return pUrb;
897 }
898 pDevFBSD->fCancelling = false;
899 }
900 /* Zero default */
901
902 memset(&UsbFsComplete, 0, sizeof(UsbFsComplete));
903
904 /* Check if any endpoints are complete */
905 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true);
906 if (RT_SUCCESS(rc))
907 {
908 pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index];
909 pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index];
910
911 LogFlow(("usbProxyFreeBSDUrbReap: Reaped "
912 "URB %#p\n", pEndpointFBSD->pUrb));
913
914 if (pXferEndpoint->status == USB_ERR_CANCELLED)
915 goto repeat;
916
917 pUrb = pEndpointFBSD->pUrb;
918 pEndpointFBSD->pUrb = NULL;
919 if (pUrb == NULL)
920 goto repeat;
921
922 switch (pXferEndpoint->status)
923 {
924 case USB_ERR_NORMAL_COMPLETION:
925 pUrb->enmStatus = VUSBSTATUS_OK;
926 break;
927 case USB_ERR_STALLED:
928 pUrb->enmStatus = VUSBSTATUS_STALL;
929 break;
930 default:
931 pUrb->enmStatus = VUSBSTATUS_INVALID;
932 break;
933 }
934
935 pUrb->Dev.pvPrivate = NULL;
936
937 switch (pUrb->enmType)
938 {
939 case VUSBXFERTYPE_MSG:
940 pUrb->cbData = pEndpointFBSD->acbData[0] + pEndpointFBSD->acbData[1];
941 break;
942 case VUSBXFERTYPE_ISOC:
943 {
944 int n;
945
946 if (pUrb->enmDir == VUSBDIRECTION_OUT)
947 break;
948 pUrb->cbData = 0;
949 for (n = 0; n < (int)pUrb->cIsocPkts; n++)
950 {
951 if (n >= (int)pEndpointFBSD->cMaxFrames)
952 break;
953 pUrb->cbData += pEndpointFBSD->acbData[n];
954 pUrb->aIsocPkts[n].cb = pEndpointFBSD->acbData[n];
955 }
956 for (; n < (int)pUrb->cIsocPkts; n++)
957 pUrb->aIsocPkts[n].cb = 0;
958
959 break;
960 }
961 default:
962 pUrb->cbData = pEndpointFBSD->acbData[0];
963 break;
964 }
965
966 LogFlow(("usbProxyFreeBSDUrbReap: Status=%d epindex=%u "
967 "len[0]=%d len[1]=%d\n",
968 (int)pXferEndpoint->status,
969 (unsigned)UsbFsComplete.ep_index,
970 (unsigned)pEndpointFBSD->acbData[0],
971 (unsigned)pEndpointFBSD->acbData[1]));
972
973 }
974 else if (cMillies && rc == VERR_RESOURCE_BUSY)
975 {
976 /* Poll for finished transfers */
977 PollFd.fd = RTFileToNative(pDevFBSD->hFile);
978 PollFd.events = POLLIN | POLLRDNORM;
979 PollFd.revents = 0;
980
981 rc = poll(&PollFd, 1, (cMillies == RT_INDEFINITE_WAIT) ? INFTIM : cMillies);
982 if (rc >= 1)
983 {
984 goto repeat;
985 }
986 else
987 {
988 LogFlow(("usbProxyFreeBSDUrbReap: "
989 "poll returned rc=%d\n", rc));
990 }
991 }
992 return pUrb;
993}
994
995/**
996 * Cancels the URB.
997 * The URB requires reaping, so we don't change its state.
998 */
999static DECLCALLBACK(void) usbProxyFreeBSDUrbCancel(PVUSBURB pUrb)
1000{
1001 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
1002 int index;
1003
1004 index = (int)(long)pUrb->Dev.pvPrivate - 1;
1005
1006 if (index < 0 || index >= USBFBSD_MAXENDPOINTS)
1007 return;
1008
1009 LogFlow(("usbProxyFreeBSDUrbCancel: epindex=%u\n", (unsigned)index));
1010
1011 usbProxyFreeBSDEndpointClose(pProxyDev, index);
1012}
1013
1014/**
1015 * The FreeBSD USB Proxy Backend.
1016 */
1017extern const USBPROXYBACK g_USBProxyDeviceHost =
1018{
1019 /* pszName */
1020 "host",
1021 /* cbBackend */
1022 sizeof(PUSBPROXYDEVFBSD),
1023 usbProxyFreeBSDOpen,
1024 usbProxyFreeBSDInit,
1025 usbProxyFreeBSDClose,
1026 usbProxyFreeBSDReset,
1027 usbProxyFreeBSDSetConfig,
1028 usbProxyFreeBSDClaimInterface,
1029 usbProxyFreeBSDReleaseInterface,
1030 usbProxyFreeBSDSetInterface,
1031 usbProxyFreeBSDClearHaltedEp,
1032 usbProxyFreeBSDUrbQueue,
1033 usbProxyFreeBSDUrbCancel,
1034 usbProxyFreeBSDUrbReap,
1035 0
1036};
1037
1038/*
1039 * Local Variables:
1040 * mode: c
1041 * c-file-style: "bsd"
1042 * c-basic-offset: 4
1043 * tab-width: 4
1044 * indent-tabs-mode: s
1045 * End:
1046 */
1047
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