VirtualBox

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

最後變更 在這個檔案從33360是 31890,由 vboxsync 提交於 15 年 前

OSE header fixes

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 31.0 KB
 
1/* $Id: USBProxyDevice-freebsd.cpp 31890 2010-08-24 07:50:47Z vboxsync $ */
2/** @file
3 * USB device proxy - the FreeBSD backend.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
22#ifdef VBOX
23# include <iprt/stdint.h>
24#endif
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/ioctl.h>
28#include <sys/poll.h>
29#include <stdint.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
33#include <limits.h>
34#include <unistd.h>
35#include <fcntl.h>
36#include <errno.h>
37#include <dev/usb/usb.h>
38#include <dev/usb/usbdi.h>
39#include <dev/usb/usb_ioctl.h>
40
41#include <VBox/pdm.h>
42#include <VBox/err.h>
43#include <VBox/log.h>
44#include <VBox/vusb.h>
45#include <iprt/assert.h>
46#include <iprt/stream.h>
47#include <iprt/alloc.h>
48#include <iprt/thread.h>
49#include <iprt/time.h>
50#include <iprt/asm.h>
51#include <iprt/string.h>
52#include <iprt/file.h>
53#include "../USBProxyDevice.h"
54
55/** Maximum endpoints supported. */
56#define USBFBSD_MAXENDPOINTS 32
57#define USBFBSD_EPADDR_NUM_MASK 0x0F
58#define USBFBSD_EPADDR_DIR_MASK 0x80
59#define USBPROXY_FREEBSD_NO_ENTRY_FREE ((unsigned)~0)
60/** This really needs to be defined in vusb.h! */
61#ifndef VUSB_DIR_TO_DEV
62# define VUSB_DIR_TO_DEV 0x00
63#endif
64
65/*******************************************************************************
66* Structures and Typedefs *
67*******************************************************************************/
68typedef struct VUSBURBFBSD
69{
70 /** Pointer to the URB. */
71 PVUSBURB pUrb;
72 /** Buffer pointers. */
73 void *apvData[2];
74 /** Buffer lengths. */
75 uint32_t acbData[2];
76} VUSBURBFBSD, *PVUSBURBFBSD;
77
78typedef struct USBENDPOINTFBSD
79{
80 /** Flag whether it is opened. */
81 bool fOpen;
82 /** Index in the endpoint list. */
83 unsigned iEndpoint;
84 /** Associated endpoint. */
85 struct usb_fs_endpoint *pXferEndpoint;
86} USBENDPOINTFBSD, *PUSBENDPOINTFBSD;
87
88/**
89 * Data for the FreeBSD usb proxy backend.
90 */
91typedef struct USBPROXYDEVFBSD
92{
93 /** The open file. */
94 RTFILE File;
95 /** Critical section protecting the two lists. */
96 RTCRITSECT CritSect;
97 /** Pointer to the array of USB endpoints. */
98 struct usb_fs_endpoint *paXferEndpoints;
99 /** Pointer to the array of URB structures.
100 * They entries must be in sync with the above array. */
101 PVUSBURBFBSD paUrbs;
102 /** Number of entries in both arrays. */
103 unsigned cXferEndpoints;
104 /** Pointer to the Fifo containing the indexes for free Xfer
105 * endpoints. */
106 unsigned *paXferFree;
107 /** Index of the next free entry to write to. */
108 unsigned iXferFreeNextWrite;
109 /** Index of the next entry to read from. */
110 unsigned iXferFreeNextRead;
111 /** Status of opened endpoints. */
112 USBENDPOINTFBSD aEpOpened[USBFBSD_MAXENDPOINTS];
113 /** The list of landed FreeBSD URBs. Doubly linked.
114 * Only the split head will appear in this list. */
115 PVUSBURB pTaxingHead;
116 /** The tail of the landed FreeBSD URBs. */
117 PVUSBURB pTaxingTail;
118} USBPROXYDEVFBSD, *PUSBPROXYDEVFBSD;
119
120/*******************************************************************************
121* Internal Functions *
122*******************************************************************************/
123static int usbProxyFreeBSDDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries);
124static void usbProxFreeBSDUrbUnplugged(PUSBPROXYDEV pProxyDev);
125static PUSBENDPOINTFBSD usbProxyFreeBSDEndpointOpen(PUSBPROXYDEV pProxyDev, int Endpoint);
126static int usbProxyFreeBSDEndpointClose(PUSBPROXYDEV pProxyDev, int Endpoint);
127
128/**
129 * Wrapper for the ioctl call.
130 *
131 * This wrapper will repeate the call if we get an EINTR or EAGAIN. It can also
132 * handle ENODEV (detached device) errors.
133 *
134 * @returns whatever ioctl returns.
135 * @param pProxyDev The proxy device.
136 * @param iCmd The ioctl command / function.
137 * @param pvArg The ioctl argument / data.
138 * @param fHandleNoDev Whether to handle ENXIO.
139 * @param cTries The number of retries. Use UINT32_MAX for (kind of) indefinite retries.
140 * @internal
141 */
142static int usbProxyFreeBSDDoIoCtl(PUSBPROXYDEV pProxyDev, unsigned long iCmd, void *pvArg, bool fHandleNoDev, uint32_t cTries)
143{
144 int rc = VINF_SUCCESS;
145
146 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
147 do
148 {
149 do
150 {
151 rc = ioctl(pDevFBSD->File, iCmd, pvArg);
152 if (rc >= 0)
153 return rc;
154 } while (errno == EINTR);
155
156 if (errno == ENXIO && fHandleNoDev)
157 {
158 usbProxFreeBSDUrbUnplugged(pProxyDev);
159 Log(("usb-freebsd: ENXIO -> unplugged. pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
160 errno = ENODEV;
161 break;
162 }
163 if (errno != EAGAIN)
164 {
165 LogFlow(("usbProxyFreeBSDDoIoCtl returned %Rrc\n", RTErrConvertFromErrno(errno)));
166 break;
167 }
168 } while (cTries-- > 0);
169
170 return rc;
171}
172
173/**
174 * Setup a USB request packet.
175 */
176static void usbProxyFreeBSDSetupReq(struct usb_device_request *pSetupData, uint8_t bmRequestType, uint8_t bRequest,
177 uint16_t wValue, uint16_t wIndex, uint16_t wLength)
178{
179 LogFlow(("usbProxyFreeBSDSetupReq: pSetupData=%p bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
180 pSetupData, bmRequestType, bRequest, wValue, wIndex, wLength));
181
182 pSetupData->bmRequestType = bmRequestType;
183 pSetupData->bRequest = bRequest;
184
185 /* Handle endianess here. Currently no swapping is needed. */
186 pSetupData->wValue[0] = wValue & 0xff;
187 pSetupData->wValue[1] = (wValue >> 8) & 0xff;
188 pSetupData->wIndex[0] = wIndex & 0xff;
189 pSetupData->wIndex[1] = (wIndex >> 8) & 0xff;
190 pSetupData->wLength[0] = wLength & 0xff;
191 pSetupData->wLength[1] = (wLength >> 8) & 0xff;
192// pSetupData->wIndex = wIndex;
193// pSetupData->wLength = wLength;
194}
195
196/**
197 * The device has been unplugged.
198 * Cancel all in-flight URBs and put them up for reaping.
199 */
200static void usbProxFreeBSDUrbUnplugged(PUSBPROXYDEV pProxyDev)
201{
202 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
203
204 /*
205 * Shoot down all flying URBs.
206 */
207 RTCritSectEnter(&pDevFBSD->CritSect);
208 pProxyDev->fDetached = true;
209
210#if 0 /** @todo */
211 PUSBPROXYURBFBSD pUrbTaxing = NULL;
212 PUSBPROXYURBFBSD pUrbFBSD = pDevLnx->pInFlightHead;
213 pDevFBSD->pInFlightHead = NULL;
214 while (pUrbFBSD)
215 {
216 PUSBPROXYURBFBSD pCur = pUrbFBSD;
217 pUrbFBSD = pUrbFBSD->pNext;
218
219 ioctl(pDevFBSD->File, USBDEVFS_DISCARDURB, &pCur->KUrb);
220 if (!pCur->KUrb.status)
221 pCur->KUrb.status = -ENODEV;
222
223 /* insert into the taxing list. */
224 pCur->pPrev = NULL;
225 if ( !pCur->pSplitHead
226 || pCur == pCur->pSplitHead)
227 {
228 pCur->pNext = pUrbTaxing;
229 if (pUrbTaxing)
230 pUrbTaxing->pPrev = pCur;
231 pUrbTaxing = pCur;
232 }
233 else
234 pCur->pNext = NULL;
235 }
236
237 /* Append the URBs we shot down to the taxing queue. */
238 if (pUrbTaxing)
239 {
240 pUrbTaxing->pPrev = pDevFBSD->pTaxingTail;
241 if (pUrbTaxing->pPrev)
242 pUrbTaxing->pPrev->pNext = pUrbTaxing;
243 else
244 pDevFBSD->pTaxingTail = pDevFBSD->pTaxingHead = pUrbTaxing;
245 }
246#endif
247 RTCritSectLeave(&pDevFBSD->CritSect);
248}
249
250DECLINLINE(void) usbProxyFreeBSDSetEntryFree(PUSBPROXYDEVFBSD pProxyDev, unsigned iEntry)
251{
252 pProxyDev->paXferFree[pProxyDev->iXferFreeNextWrite] = iEntry;
253 pProxyDev->iXferFreeNextWrite++;
254 pProxyDev->iXferFreeNextWrite %= (pProxyDev->cXferEndpoints+1);
255}
256
257DECLINLINE(unsigned) usbProxyFreeBSDGetEntryFree(PUSBPROXYDEVFBSD pProxyDev)
258{
259 unsigned iEntry;
260
261 if (pProxyDev->iXferFreeNextWrite != pProxyDev->iXferFreeNextRead)
262 {
263 iEntry = pProxyDev->paXferFree[pProxyDev->iXferFreeNextRead];
264 pProxyDev->iXferFreeNextRead++;
265 pProxyDev->iXferFreeNextRead %= (pProxyDev->cXferEndpoints+1);
266 }
267 else
268 iEntry = USBPROXY_FREEBSD_NO_ENTRY_FREE;
269
270 return iEntry;
271}
272
273static PUSBENDPOINTFBSD usbProxyFreeBSDEndpointOpen(PUSBPROXYDEV pProxyDev, int Endpoint)
274{
275 LogFlow(("usbProxyFreeBSDEndpointOpen: pProxyDev=%p Endpoint=%d\n", pProxyDev, Endpoint));
276
277 int EndPtIndex = (Endpoint & USBFBSD_EPADDR_NUM_MASK) + ((Endpoint & USBFBSD_EPADDR_DIR_MASK) ? USBFBSD_MAXENDPOINTS / 2 : 0);
278 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
279 PUSBENDPOINTFBSD pEndpointFBSD = &pDevFBSD->aEpOpened[EndPtIndex];
280 struct usb_fs_endpoint *pXferEndpoint;
281
282 AssertMsg(EndPtIndex < USBFBSD_MAXENDPOINTS, ("Endpoint index exceeds limit %d\n", EndPtIndex));
283
284 if (!pEndpointFBSD->fOpen)
285 {
286 struct usb_fs_open UsbFsOpen;
287
288 pEndpointFBSD->iEndpoint = usbProxyFreeBSDGetEntryFree(pDevFBSD);
289 if (pEndpointFBSD->iEndpoint == USBPROXY_FREEBSD_NO_ENTRY_FREE)
290 return NULL;
291
292 LogFlow(("usbProxyFreeBSDEndpointOpen: ep_index=%d\n", pEndpointFBSD->iEndpoint));
293
294 UsbFsOpen.ep_index = pEndpointFBSD->iEndpoint;
295 UsbFsOpen.ep_no = Endpoint;
296 UsbFsOpen.max_bufsize = 256 * _1K; /* Hardcoded assumption about the URBs we get. */
297 UsbFsOpen.max_frames = 2;
298
299 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_OPEN, &UsbFsOpen, true, UINT32_MAX);
300 if (rc)
301 return NULL;
302
303 pEndpointFBSD->fOpen = true;
304 pEndpointFBSD->pXferEndpoint = &pDevFBSD->paXferEndpoints[pEndpointFBSD->iEndpoint];
305 }
306 else
307 {
308 AssertMsgReturn(!pDevFBSD->paUrbs[pEndpointFBSD->iEndpoint].pUrb, ("Endpoint is busy"), NULL);
309 pEndpointFBSD->pXferEndpoint = &pDevFBSD->paXferEndpoints[pEndpointFBSD->iEndpoint];
310 }
311
312 return pEndpointFBSD;
313}
314
315static int usbProxyFreeBSDEndpointClose(PUSBPROXYDEV pProxyDev, int Endpoint)
316{
317 LogFlow(("usbProxyFreeBSDEndpointClose: pProxyDev=%p Endpoint=%d\n", pProxyDev, Endpoint));
318
319 AssertMsg(Endpoint < USBFBSD_MAXENDPOINTS, ("Endpoint index exceeds limit %d\n", Endpoint));
320
321 int EndPtIndex = (Endpoint & USBFBSD_EPADDR_NUM_MASK) + ((Endpoint & USBFBSD_EPADDR_DIR_MASK) ? USBFBSD_MAXENDPOINTS / 2 : 0);
322 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
323 PUSBENDPOINTFBSD pEndpointFBSD = &pDevFBSD->aEpOpened[EndPtIndex];
324
325 if (pEndpointFBSD->fOpen)
326 {
327 struct usb_fs_close UsbFsClose;
328
329 AssertMsgReturn(!pDevFBSD->paUrbs[pEndpointFBSD->iEndpoint].pUrb, ("Endpoint is busy"), NULL);
330
331 UsbFsClose.ep_index = pEndpointFBSD->iEndpoint;
332
333 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_CLOSE, &UsbFsClose, true, UINT32_MAX);
334 if (rc)
335 {
336 LogFlow(("usbProxyFreeBSDEndpointClose: failed rc=%d errno=%Rrc\n", rc, RTErrConvertFromErrno(errno)));
337 return RTErrConvertFromErrno(errno);
338 }
339
340 usbProxyFreeBSDSetEntryFree(pDevFBSD, pEndpointFBSD->iEndpoint);
341 pEndpointFBSD->fOpen = false;
342 }
343
344 return VINF_SUCCESS;
345}
346
347/**
348 * Opens the device file.
349 *
350 * @returns VBox status code.
351 * @param pProxyDev The device instance.
352 * @param pszAddress If we are using usbfs, this is the path to the
353 * device. If we are using sysfs, this is a string of
354 * the form "sysfs:<sysfs path>//device:<device node>".
355 * In the second case, the two paths are guaranteed
356 * not to contain the substring "//".
357 * @param pvBackend Backend specific pointer, unused for the linux backend.
358 */
359static int usbProxyFreeBSDOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
360{
361 LogFlow(("usbProxyFreeBSDOpen: pProxyDev=%p pszAddress=%s\n", pProxyDev, pszAddress));
362
363 /*
364 * Try open the device node.
365 */
366 RTFILE File;
367 int rc = RTFileOpen(&File, pszAddress, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
368 if (RT_SUCCESS(rc))
369 {
370 /*
371 * Allocate and initialize the linux backend data.
372 */
373 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)RTMemAllocZ(sizeof(USBPROXYDEVFBSD));
374 if (pDevFBSD)
375 {
376 pDevFBSD->File = File;
377 rc = RTCritSectInit(&pDevFBSD->CritSect);
378 if (RT_SUCCESS(rc))
379 {
380 unsigned cTransfersMax = 127; /* Maximum in the kernel atm. */
381
382 /* Allocate arrays for data transfers. */
383 pDevFBSD->paXferEndpoints = (struct usb_fs_endpoint *)RTMemAllocZ(cTransfersMax * sizeof(struct usb_fs_endpoint));
384 pDevFBSD->paUrbs = (PVUSBURBFBSD)RTMemAllocZ(cTransfersMax * sizeof(VUSBURBFBSD));
385 pDevFBSD->paXferFree = (unsigned *)RTMemAllocZ((cTransfersMax + 1) * sizeof(unsigned));
386 pDevFBSD->cXferEndpoints = cTransfersMax;
387
388 if (pDevFBSD->paXferEndpoints && pDevFBSD->paUrbs && pDevFBSD->paXferFree)
389 {
390 /* Initialize the kernel side. */
391 struct usb_fs_init UsbFsInit;
392
393 UsbFsInit.pEndpoints = pDevFBSD->paXferEndpoints;
394 UsbFsInit.ep_index_max = cTransfersMax;
395 rc = ioctl(File, USB_FS_INIT, &UsbFsInit);
396 if (!rc)
397 {
398 for (unsigned i = 0; i < cTransfersMax; i++)
399 usbProxyFreeBSDSetEntryFree(pDevFBSD, i);
400
401 for (unsigned i= 0; i < USBFBSD_MAXENDPOINTS; i++)
402 pDevFBSD->aEpOpened[i].fOpen = false;
403
404 pProxyDev->Backend.pv = pDevFBSD;
405
406 LogFlow(("usbProxyFreeBSDOpen(%p, %s): returns successfully File=%d iActiveCfg=%d\n",
407 pProxyDev, pszAddress, pDevFBSD->File, pProxyDev->iActiveCfg));
408
409 return VINF_SUCCESS;
410 }
411 else
412 rc = RTErrConvertFromErrno(errno);
413 }
414 else
415 rc = VERR_NO_MEMORY;
416
417 if (pDevFBSD->paXferEndpoints)
418 RTMemFree(pDevFBSD->paXferEndpoints);
419 if (pDevFBSD->paUrbs)
420 RTMemFree(pDevFBSD->paUrbs);
421 if (pDevFBSD->paXferFree)
422 RTMemFree(pDevFBSD->paXferFree);
423 }
424
425 RTMemFree(pDevFBSD);
426 }
427 else
428 rc = VERR_NO_MEMORY;
429 RTFileClose(File);
430 }
431 else if (rc == VERR_ACCESS_DENIED)
432 rc = VERR_VUSB_USBFS_PERMISSION;
433
434 Log(("usbProxyFreeBSDOpen(%p, %s) failed, rc=%Rrc!\n", pProxyDev, pszAddress, rc));
435 pProxyDev->Backend.pv = NULL;
436
437 NOREF(pvBackend);
438 return rc;
439
440 return VINF_SUCCESS;
441}
442
443
444/**
445 * Claims all the interfaces and figures out the
446 * current configuration.
447 *
448 * @returns VINF_SUCCESS.
449 * @param pProxyDev The proxy device.
450 */
451static int usbProxyFreeBSDInit(PUSBPROXYDEV pProxyDev)
452{
453 LogFlow(("usbProxyFreeBSDInit: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
454 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
455
456 /* Retrieve current active configuration. */
457 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_GET_CONFIG, &pProxyDev->iActiveCfg, true, UINT32_MAX);
458 if (RT_FAILURE(rc))
459 {
460 pProxyDev->iActiveCfg = -1;
461 return rc;
462 }
463
464 Log(("usbProxyFreeBSDInit: iActiveCfg=%d\n", pProxyDev->iActiveCfg));
465 pProxyDev->cIgnoreSetConfigs = 1;
466 pProxyDev->iActiveCfg++;
467
468 return VINF_SUCCESS;
469}
470
471
472/**
473 * Closes the proxy device.
474 */
475static void usbProxyFreeBSDClose(PUSBPROXYDEV pProxyDev)
476{
477 LogFlow(("usbProxyFreeBSDClose: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
478 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
479 Assert(pDevFBSD);
480 if (!pDevFBSD)
481 return;
482
483 RTCritSectDelete(&pDevFBSD->CritSect);
484
485 struct usb_fs_uninit UsbFsUninit;
486 UsbFsUninit.dummy = 0;
487
488 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_UNINIT, &UsbFsUninit, false, 1);
489 AssertMsg(!rc, ("Freeing kernel ressources failed rc=%Rrc\n", RTErrConvertFromErrno(errno)));
490
491 if (pDevFBSD->paXferEndpoints)
492 RTMemFree(pDevFBSD->paXferEndpoints);
493 if (pDevFBSD->paUrbs)
494 RTMemFree(pDevFBSD->paUrbs);
495 if (pDevFBSD->paXferFree)
496 RTMemFree(pDevFBSD->paXferFree);
497
498 RTFileClose(pDevFBSD->File);
499 pDevFBSD->File = NIL_RTFILE;
500
501 RTMemFree(pDevFBSD);
502 pProxyDev->Backend.pv = NULL;
503
504 LogFlow(("usbProxyFreeBSDClose: returns\n"));
505}
506
507
508/**
509 * Reset a device.
510 *
511 * @returns VBox status code.
512 * @param pDev The device to reset.
513 */
514static int usbProxyFreeBSDReset(PUSBPROXYDEV pProxyDev, bool fResetOnFreeBSD)
515{
516 LogFlow(("usbProxyFreeBSDReset: pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
517 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
518
519 /* Close any open endpoints. */
520 for (unsigned i = 0; i < USBFBSD_MAXENDPOINTS; i++)
521 usbProxyFreeBSDEndpointClose(pProxyDev, i);
522
523 /* We need to release kernel ressources first. */
524 struct usb_fs_uninit UsbFsUninit;
525 UsbFsUninit.dummy = 0;
526
527 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_UNINIT, &UsbFsUninit, false, 1);
528 AssertMsg(!rc, ("Freeing kernel ressources failed rc=%Rrc\n", RTErrConvertFromErrno(errno)));
529
530 /* Resetting is not possible from a normal user account */
531#if 0
532 int iUnused = 0;
533 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DEVICEENUMERATE, &iUnused, true, UINT32_MAX);
534 if (rc)
535 return RTErrConvertFromErrno(errno);
536#endif
537
538 /* Allocate kernel ressources again. */
539 struct usb_fs_init UsbFsInit;
540
541 UsbFsInit.pEndpoints = pDevFBSD->paXferEndpoints;
542 UsbFsInit.ep_index_max = pDevFBSD->cXferEndpoints;
543 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_INIT, &UsbFsInit, true, UINT32_MAX);
544 if (!rc)
545 {
546 /* Retrieve current active configuration. */
547 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_GET_CONFIG, &pProxyDev->iActiveCfg, true, UINT32_MAX);
548 if (rc)
549 {
550 pProxyDev->iActiveCfg = -1;
551 rc = RTErrConvertFromErrno(errno);
552 }
553 else
554 {
555 pProxyDev->cIgnoreSetConfigs = 2;
556 pProxyDev->iActiveCfg++;
557 }
558 }
559 else
560 rc = RTErrConvertFromErrno(errno);
561
562 Log(("usbProxyFreeBSDReset: iActiveCfg=%d\n", pProxyDev->iActiveCfg));
563
564 return rc;
565}
566
567
568/**
569 * SET_CONFIGURATION.
570 *
571 * The caller makes sure that it's not called first time after open or reset
572 * with the active interface.
573 *
574 * @returns success indicator.
575 * @param pProxyDev The device instance data.
576 * @param iCfg The configuration to set.
577 */
578static int usbProxyFreeBSDSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
579{
580 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
581
582 LogFlow(("usbProxyFreeBSDSetConfig: pProxyDev=%s cfg=%#x\n",
583 pProxyDev->pUsbIns->pszName, iCfg));
584
585 /* Close any open endpoints. */
586 for (unsigned i = 0; i < USBFBSD_MAXENDPOINTS; i++)
587 usbProxyFreeBSDEndpointClose(pProxyDev, i);
588
589 /* We need to release kernel ressources first. */
590 struct usb_fs_uninit UsbFsUninit;
591 UsbFsUninit.dummy = 0;
592
593 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_UNINIT, &UsbFsUninit, false, 1);
594 AssertMsg(!rc, ("Freeing kernel ressources failed rc=%Rrc\n", RTErrConvertFromErrno(errno)));
595
596 int iCfgIndex = 0;
597
598 /* Get theconfiguration index matching the value. */
599 for (iCfgIndex = 0; iCfgIndex < pProxyDev->DevDesc.bNumConfigurations; iCfgIndex++)
600 {
601 if (pProxyDev->paCfgDescs[iCfgIndex].Core.bConfigurationValue == iCfg)
602 break;
603 }
604
605 if (RT_UNLIKELY(iCfgIndex == pProxyDev->DevDesc.bNumConfigurations))
606 {
607 LogFlow(("usbProxyFreeBSDSetConfig: configuration %d not found\n", iCfg));
608 return false;
609 }
610
611 /* Set the config */
612 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_CONFIG, &iCfgIndex, true, UINT32_MAX);
613 if (RT_FAILURE(rc))
614 {
615 LogFlow(("usbProxyFreeBSDSetConfig: setting config index %d failed rc=%d errno=%Rrc\n", iCfgIndex, rc, RTErrConvertFromErrno(errno)));
616 return false;
617 }
618
619 /* Allocate kernel ressources again. */
620 struct usb_fs_init UsbFsInit;
621
622 UsbFsInit.pEndpoints = pDevFBSD->paXferEndpoints;
623 UsbFsInit.ep_index_max = pDevFBSD->cXferEndpoints;
624 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_INIT, &UsbFsInit, true, UINT32_MAX);
625
626
627 LogFlow(("usbProxyFreeBSDSetConfig: rc=%d errno=%Rrc\n", rc, RTErrConvertFromErrno(errno)));
628
629 if (!rc)
630 return true;
631 else
632 return false;
633}
634
635
636/**
637 * Claims an interface.
638 * @returns success indicator.
639 */
640static int usbProxyFreeBSDClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
641{
642 LogFlow(("usbProxyFreeBSDClaimInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
643
644 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_CLAIM_INTERFACE, &iIf, true, UINT32_MAX);
645 if (RT_FAILURE(rc))
646 return false;
647
648 return true;
649}
650
651
652/**
653 * Releases an interface.
654 * @returns success indicator.
655 */
656static int usbProxyFreeBSDReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
657{
658 LogFlow(("usbProxyFreeBSDReleaseInterface: pProxyDev=%s ifnum=%#x\n", pProxyDev->pUsbIns->pszName, iIf));
659
660 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_RELEASE_INTERFACE, &iIf, true, UINT32_MAX);
661 if (RT_FAILURE(rc))
662 return false;
663
664 return true;
665}
666
667
668/**
669 * SET_INTERFACE.
670 *
671 * @returns success indicator.
672 */
673static int usbProxyFreeBSDSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
674{
675 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
676
677 LogFlow(("usbProxyFreeBSDSetInterface: pProxyDev=%p iIf=%#x iAlt=%#x\n", pProxyDev, iIf, iAlt));
678
679 /* Close any open endpoints. */
680 for (unsigned i = 0; i < USBFBSD_MAXENDPOINTS; i++)
681 usbProxyFreeBSDEndpointClose(pProxyDev, i);
682
683 /* We need to release kernel ressources first. */
684 struct usb_fs_uninit UsbFsUninit;
685 UsbFsUninit.dummy = 0;
686
687 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_UNINIT, &UsbFsUninit, false, 1);
688 AssertMsg(!rc, ("Freeing kernel ressources failed rc=%Rrc\n", RTErrConvertFromErrno(errno)));
689
690 struct usb_alt_interface UsbIntAlt;
691 UsbIntAlt.uai_interface_index = iIf;
692 UsbIntAlt.uai_alt_index = iAlt;
693 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_SET_ALTINTERFACE, &UsbIntAlt, true, UINT32_MAX);
694 if (rc)
695 {
696 LogFlow(("usbProxyFreeBSDSetInterface: Setting interface %d %d failed rc=%d errno=%Rrc\n", iIf, iAlt, rc,RTErrConvertFromErrno(errno)));
697 return false;
698 }
699
700 /* Allocate kernel ressources again. */
701 struct usb_fs_init UsbFsInit;
702
703 UsbFsInit.pEndpoints = pDevFBSD->paXferEndpoints;
704 UsbFsInit.ep_index_max = pDevFBSD->cXferEndpoints;
705 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_INIT, &UsbFsInit, true, UINT32_MAX);
706
707 LogFlow(("usbProxyFreeBSDSetInterface: rc=%d errno=%Rrc\n", rc, RTErrConvertFromErrno(errno)));
708
709 if (!rc)
710 return true;
711 else
712 return false;
713}
714
715
716/**
717 * Clears the halted endpoint 'EndPt'.
718 */
719static bool usbProxyFreeBSDClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
720{
721 LogFlow(("usbProxyFreeBSDClearHaltedEp: pProxyDev=%s EndPt=%u\n", pProxyDev->pUsbIns->pszName, EndPt));
722
723 /*
724 * Clearing the zero control pipe doesn't make sense. Just ignore it.
725 */
726 if (EndPt == 0)
727 return true;
728
729 struct usb_ctl_request Req;
730
731 memset(&Req, 0, sizeof(struct usb_ctl_request));
732 usbProxyFreeBSDSetupReq(&Req.ucr_request, VUSB_DIR_TO_DEV | VUSB_TO_ENDPOINT, VUSB_REQ_CLEAR_FEATURE, 0, EndPt, 0);
733
734 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_DO_REQUEST, &Req, true, 1);
735 if (rc)
736 {
737 LogFlow(("usbProxyFreeBSDClearHaltedEp: failed rc=%d errno=%Rrc\n", rc, RTErrConvertFromErrno(errno)));
738 return false;
739 }
740
741 LogFlow(("usbProxyFreeBSDClearHaltedEp: succeeded\n"));
742
743 return true;
744}
745
746
747/**
748 * @copydoc USBPROXYBACK::pfnUrbQueue
749 */
750static int usbProxyFreeBSDUrbQueue(PVUSBURB pUrb)
751{
752 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
753 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
754
755 LogFlow(("usbProxyFreeBSDUrbQueue: pUrb=%p\n", pUrb));
756
757 uint8_t EndPt = pUrb->EndPt;
758 if (pUrb->EndPt)
759 EndPt = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
760
761 PUSBENDPOINTFBSD pEndpointFBSD = usbProxyFreeBSDEndpointOpen(pProxyDev, EndPt);
762 if (!pEndpointFBSD)
763 return false;
764
765 PVUSBURBFBSD pUrbFBSD = &pDevFBSD->paUrbs[pEndpointFBSD->iEndpoint];
766 AssertMsg(!pUrbFBSD->pUrb, ("Assigned entry is busy\n"));
767 pUrbFBSD->pUrb = pUrb;
768
769 struct usb_fs_start UsbFsStart;
770 unsigned cFrames;
771
772 if (pUrb->enmType == VUSBXFERTYPE_MSG)
773 {
774 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
775
776 pUrbFBSD->apvData[0] = pSetup;
777 pUrbFBSD->acbData[0] = sizeof(VUSBSETUP);
778
779 if (pSetup->wLength)
780 {
781 pUrbFBSD->apvData[1] = &pUrb->abData[sizeof(VUSBSETUP)];
782 pUrbFBSD->acbData[1] = pSetup->wLength;
783 cFrames = 2;
784 }
785 else
786 cFrames = 1;
787 }
788 else
789 {
790 pUrbFBSD->apvData[0] = &pUrb->abData[0];
791 pUrbFBSD->acbData[0] = pUrb->cbData;
792 cFrames = 1;
793 }
794
795 struct usb_fs_endpoint *pXferEndpoint = pEndpointFBSD->pXferEndpoint;
796 pXferEndpoint->ppBuffer = &pUrbFBSD->apvData[0];
797 pXferEndpoint->pLength = &pUrbFBSD->acbData[0];
798 pXferEndpoint->nFrames = cFrames;
799 pXferEndpoint->timeout = USB_FS_TIMEOUT_NONE; /* Timeout handling will be done during reap. */
800 pXferEndpoint->flags = pUrb->fShortNotOk ? 0 : USB_FS_FLAG_MULTI_SHORT_OK;
801
802 /* Start the transfer */
803 UsbFsStart.ep_index = pEndpointFBSD->iEndpoint;
804 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_START, &UsbFsStart, true, UINT32_MAX);
805
806 LogFlow(("usbProxyFreeBSDUrbQueue: USB_FS_START returned rc=%d errno=%Rrc\n", rc, RTErrConvertFromErrno(errno)));
807 if (rc)
808 {
809 return false;
810 }
811
812 return true;
813}
814
815
816/**
817 * Reap URBs in-flight on a device.
818 *
819 * @returns Pointer to a completed URB.
820 * @returns NULL if no URB was completed.
821 * @param pProxyDev The device.
822 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
823 */
824static PVUSBURB usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
825{
826 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
827
828 LogFlow(("usbProxyFreeBSDUrbReap: cMillies=%u\n", cMillies));
829
830 /* We will poll for finished urbs because the ioctl doesn't take a timeout parameter. */
831 struct pollfd PollFd;
832 PVUSBURB pUrb = NULL;
833
834 PollFd.fd = (int)pDevFBSD->File;
835 PollFd.events = POLLIN | POLLRDNORM | POLLOUT;
836 PollFd.revents = 0;
837
838 struct usb_fs_complete UsbFsComplete;
839
840 UsbFsComplete.ep_index = 0;
841
842 int rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true, UINT32_MAX);
843 if (!rc)
844 {
845 struct usb_fs_endpoint *pXferEndpoint = &pDevFBSD->paXferEndpoints[UsbFsComplete.ep_index];
846 PVUSBURBFBSD pUrbFBSD = &pDevFBSD->paUrbs[UsbFsComplete.ep_index];
847
848 LogFlow(("Reaped URB %#p\n", pUrbFBSD->pUrb));
849
850 pUrb = pUrbFBSD->pUrb;
851 AssertMsg(pUrb, ("No URB handle for the completed entry\n"));
852 pUrbFBSD->pUrb = NULL;
853
854 switch (pXferEndpoint->status)
855 {
856 case USB_ERR_NORMAL_COMPLETION:
857 pUrb->enmStatus = VUSBSTATUS_OK;
858 break;
859 case USB_ERR_STALLED:
860 pUrb->enmStatus = VUSBSTATUS_STALL;
861 break;
862 default:
863 AssertMsgFailed(("Unexpected status code %d\n", pXferEndpoint->status));
864 }
865 }
866 else
867 {
868
869 rc = poll(&PollFd, 1, cMillies == RT_INDEFINITE_WAIT ? INFTIM : cMillies);
870 if (rc == 1)
871 {
872 // do
873 {
874 UsbFsComplete.ep_index = 0;
875 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true, UINT32_MAX);
876 if (!rc)
877 {
878 struct usb_fs_endpoint *pXferEndpoint = &pDevFBSD->paXferEndpoints[UsbFsComplete.ep_index];
879 PVUSBURBFBSD pUrbFBSD = &pDevFBSD->paUrbs[UsbFsComplete.ep_index];
880
881 LogFlow(("Reaped URB %#p\n", pUrbFBSD->pUrb));
882
883 pUrb = pUrbFBSD->pUrb;
884 AssertMsg(pUrb, ("No URB handle for the completed entry\n"));
885 pUrbFBSD->pUrb = NULL;
886
887 switch (pXferEndpoint->status)
888 {
889 case USB_ERR_NORMAL_COMPLETION:
890 pUrb->enmStatus = VUSBSTATUS_OK;
891 break;
892 case USB_ERR_STALLED:
893 pUrb->enmStatus = VUSBSTATUS_STALL;
894 break;
895 default:
896 AssertMsgFailed(("Unexpected status code %d\n", pXferEndpoint->status));
897 }
898
899 rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true, UINT32_MAX);
900 AssertMsg(((rc == -1) && (errno == EBUSY)), ("Expected return value rc=%d rc=%Rrc\n", rc, RTErrConvertFromErrno(errno)));
901 }
902 else
903 LogFlow(("couldn't get completed URB rc=%Rrc\n", RTErrConvertFromErrno(errno)));
904 }
905 // while (!rc);
906 }
907 else
908 LogFlow(("poll returned rc=%d rcRT=%Rrc\n", rc, rc < 0 ? RTErrConvertFromErrno(errno) : VERR_TIMEOUT));
909 }
910
911 return pUrb;
912}
913
914
915/**
916 * Cancels the URB.
917 * The URB requires reaping, so we don't change its state.
918 */
919static void usbProxyFreeBSDUrbCancel(PVUSBURB pUrb)
920{
921 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
922 PUSBPROXYDEVFBSD pDevFBSD = (PUSBPROXYDEVFBSD)pProxyDev->Backend.pv;
923
924
925}
926
927
928/**
929 * The FreeBSD USB Proxy Backend.
930 */
931extern const USBPROXYBACK g_USBProxyDeviceHost =
932{
933 "host",
934 usbProxyFreeBSDOpen,
935 usbProxyFreeBSDInit,
936 usbProxyFreeBSDClose,
937 usbProxyFreeBSDReset,
938 usbProxyFreeBSDSetConfig,
939 usbProxyFreeBSDClaimInterface,
940 usbProxyFreeBSDReleaseInterface,
941 usbProxyFreeBSDSetInterface,
942 usbProxyFreeBSDClearHaltedEp,
943 usbProxyFreeBSDUrbQueue,
944 usbProxyFreeBSDUrbCancel,
945 usbProxyFreeBSDUrbReap,
946 0
947};
948
949
950/*
951 * Local Variables:
952 * mode: c
953 * c-file-style: "bsd"
954 * c-basic-offset: 4
955 * tab-width: 4
956 * indent-tabs-mode: s
957 * End:
958 */
959
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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