VirtualBox

source: vbox/trunk/src/VBox/Devices/USB/solaris/USBProxyDevice-solaris.cpp@ 31890

Last change on this file since 31890 was 31890, checked in by vboxsync, 14 years ago

OSE header fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 66.1 KB
Line 
1/* $Id: USBProxyDevice-solaris.cpp 31890 2010-08-24 07:50:47Z vboxsync $ */
2/** @file
3 * USB device proxy - the Solaris backend.
4 */
5
6/*
7 * Copyright (C) 2008 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_USBPROXY
23
24#include <limits.h>
25#include <stdio.h>
26#include <signal.h>
27#include <errno.h>
28#include <sys/usb/usba.h>
29#include <sys/usb/clients/ugen/usb_ugen.h>
30#include <sys/asynch.h>
31
32#include <VBox/log.h>
33#include <VBox/err.h>
34#include <VBox/pdm.h>
35
36#include <iprt/assert.h>
37#include <iprt/mem.h>
38#include <iprt/string.h>
39#include <iprt/critsect.h>
40#include <iprt/time.h>
41#include <iprt/file.h>
42#include "../USBProxyDevice.h"
43#include <VBox/usblib.h>
44
45/* WORK-IN-PROGRESS */
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49/** Log Prefix. */
50#define USBR3PROXY "USBProxyDev"
51/** Maximum endpoints supported. */
52#define USBSOL_MAXENDPOINTS 32
53/** Maximum interfaces supported. */
54#define USBSOL_MAXINTERFACES 256
55/** EndPoint address mask (bEndPointAddress) */
56#define USBSOL_EPADDR_NUM_MASK 0x0F
57#define USBSOL_EPADDR_DIR_MASK 0x80
58#define USBSOL_EPADDR_IN 0x80
59#define USBSOL_EPADDR_OUT 0x00
60#define USBSOL_CTRLREQ_SIZE 0x08
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/** Ugen isoc support toggle, disable this for S10. */
67//#define VBOX_WITH_SOLARIS_USB_ISOC
68
69/** -XXX- Remove this hackery eventually */
70#if 0
71#ifdef DEBUG_ramshankar
72# undef LogFlow
73# define LogFlow LogRel
74# undef Log
75# define Log LogRel
76#endif
77#endif
78
79/*******************************************************************************
80* Structures and Typedefs *
81*******************************************************************************/
82typedef struct USBPROXYURBSOL;
83
84/**
85 * Asynchronous URB status.
86 */
87typedef struct URBSTATUSSOL
88{
89 /** The result of the transfer. */
90 aio_result_t Result;
91 /** The URB associated with this transfer. */
92 USBPROXYURBSOL *pUrbSol;
93} URBSTATUSSOL, *PURBSTATUSSOL;
94
95/**
96 * Wrapper around the solaris urb request structure.
97 * This is required to track in-flight and landed URBs.
98 */
99typedef struct USBPROXYURBSOL
100{
101 /** Pointer to the VUSB URB (set to NULL if canceled). */
102 PVUSBURB pVUsbUrb;
103 /** The millisecond timestamp when this URB was submitted. */
104 uint64_t u64SubmitTS;
105 /** Pointer to the Solaris device. */
106 struct USBPROXYDEVSOL *pDevSol;
107 /** Status of this URB. */
108 URBSTATUSSOL Status;
109#ifdef VBOX_WITH_SOLARIS_USB_ISOC
110 /** Isoc. OUT buffer. */
111 caddr_t pIsocBufOut;
112 /** Size of the isoc. OUT buffer */
113 size_t cbIsocBufOut;
114 /** Isoc. IN buffer. */
115 caddr_t pIsocBufIn;
116 /** Size of the isoc. IN buffer. */
117 size_t cbIsocBufIn;
118#endif
119
120 /** Pointer to the next solaris URB. */
121 struct USBPROXYURBSOL *pNext;
122 /** Pointer to the previous solaris URB. */
123 struct USBPROXYURBSOL *pPrev;
124} USBPROXYURBSOL, *PUSBPROXYURBSOL;
125
126/**
127 * Data for the solaris usb proxy backend.
128 */
129typedef struct USBPROXYDEVSOL
130{
131 /** Path of the USB device in the dev tree (driver bound). */
132 char *pszDevPath;
133 /** Path of the USB device in the devices tree (persistent). */
134 char *pszDevicePath;
135 /** Status endpoint. */
136 RTFILE StatFile;
137 /** Pointer to the proxy device instance. */
138 PUSBPROXYDEV pProxyDev;
139 /** Array of all endpoints. */
140 RTFILE aEpFile[USBSOL_MAXENDPOINTS];
141 /** Array of all status endpoints.*/
142 RTFILE aEpStatFile[USBSOL_MAXENDPOINTS];
143
144 /** Critical section protecting the two lists. */
145 RTCRITSECT CritSect;
146 /** The list of free solaris URBs. Singly linked. */
147 PUSBPROXYURBSOL pFreeHead;
148 /** The list of active solaris URBs. Doubly linked.
149 * We must maintain this so we can properly reap URBs of a detached device.
150 * Only the split head will appear in this list. */
151 PUSBPROXYURBSOL pInFlightHead;
152 /** The list of landed solaris URBs. Doubly linked.
153 * Only the split head will appear in this list. */
154 PUSBPROXYURBSOL pTaxingHead;
155 /** The tail of the landed solaris URBs. */
156 PUSBPROXYURBSOL pTaxingTail;
157} USBPROXYDEVSOL, *PUSBPROXYDEVSOL;
158
159
160/*******************************************************************************
161* Internal Functions *
162*******************************************************************************/
163static void usbProxySolarisAsyncNotify(bool fActive);
164
165static int usbProxySolarisSendReq(RTFILE File, RTFILE StatFile, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, int *pStatus);
166static int usbProxySolarisSendReqAsync(RTFILE File, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, PURBSTATUSSOL pUrbStatus);
167static int usbProxySolarisCtrlReq(RTFILE File, RTFILE StatFile, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, int *pStatus);
168static int usbProxySolarisCtrlReqAsync(RTFILE File, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, PURBSTATUSSOL pStatus);
169static int usbProxySolarisIO(RTFILE File, RTFILE StatFile, caddr_t pData, size_t cbData, int fOpenMode, int *pStatus);
170static int usbProxySolarisIOAsync(RTFILE File, caddr_t pData, size_t cbData, int fOpenMode, PURBSTATUSSOL pUrbStatus);
171
172static void usbProxySolarisInitAllPipes(PUSBPROXYDEVSOL pDevSol);
173static int usbProxySolarisOpenDevPipes(PUSBPROXYDEVSOL pDevSol);
174static void usbProxySolarisCloseDevPipes(PUSBPROXYDEVSOL pDevSol);
175static void usbProxySolarisCloseEndPoints(PUSBPROXYDEVSOL pDevSol);
176static void usbProxySolarisCloseDevice(PUSBPROXYDEVSOL pDevSol);
177
178static int usbProxySolarisGetStatus(RTFILE StatFile, int *pStatus, bool fDevStat);
179static int usbProxySolarisGetActiveCfg(PUSBPROXYDEVSOL pDevSol, int *pConfigValue);
180
181static int usbProxySolarisConfigIndex(PUSBPROXYDEVSOL pDevSol, uint8_t bCfgValue);
182static int usbProxySolarisSeizeAllInterfaces(PUSBPROXYDEVSOL pDevSol, uint8_t bCfgValue);
183static VUSBXFERTYPE usbProxySolarisXferType(uint8_t bmAttribute);
184static uint32_t usbProxySolarisOpenMode(uint8_t bmEndPointAddress, VUSBXFERTYPE XferType);
185static int usbProxySolarisOpenEndPoint(PUSBPROXYDEVSOL pDevSol, int EndPoint, VUSBXFERTYPE XferType);
186static int usbProxySolarisOpenNode(PUSBPROXYDEVSOL pDevSol, uint8_t bCfgValue, int iInterface, int iAlternate, int EndPoint,
187 VUSBXFERTYPE XferType);
188
189static void usbProxySolarisAsyncComplete(int Sig);
190
191
192/**
193 * Toggle asynchronous notification signals for asynchronous USB IO.
194 *
195 * @param fNotify Whether notification is active.
196 */
197static void usbProxySolarisAsyncNotify(bool fNotify)
198{
199 if (fNotify)
200 sigset(SIGIO, usbProxySolarisAsyncComplete);
201 else
202 sigrelse(SIGIO);
203}
204
205
206/**
207 * Translate the USB ugen status code to a VUSB status.
208 *
209 * @returns VUSB URB status code.
210 * @param irc ugen status code.
211 */
212static VUSBSTATUS vusbProxySolarisStatusToVUsbStatus(int irc)
213{
214 LogFlow((USBR3PROXY ":vusbProxySolarisStatusToVUsbStatus irc=%d\n", irc));
215
216 switch (irc)
217 {
218 case USB_LC_STAT_NOERROR: return VUSBSTATUS_OK;
219 case USB_LC_STAT_CRC: return VUSBSTATUS_CRC;
220 case USB_LC_STAT_STALL: return VUSBSTATUS_STALL;
221 case USB_LC_STAT_DEV_NOT_RESP: return VUSBSTATUS_DNR;
222 case USB_LC_STAT_DATA_OVERRUN: return VUSBSTATUS_DATA_OVERRUN;
223 case USB_LC_STAT_DATA_UNDERRUN: return VUSBSTATUS_DATA_UNDERRUN;
224 case USB_LC_STAT_TIMEOUT: return VUSBSTATUS_DNR;
225 case USB_LC_STAT_NOT_ACCESSED: return VUSBSTATUS_NOT_ACCESSED;
226 //case USB_LC_STAT_BITSTUFFING:
227 //case USB_LC_STAT_DATA_TOGGLE_MM:
228 //case USB_LC_STAT_PID_CHECKFAILURE:
229 //case USB_LC_STAT_UNEXP_PID:
230 //case USB_LC_STAT_BUFFER_OVERRUN:
231 //case USB_LC_STAT_BUFFER_UNDERRUN:
232 //case USB_LC_STAT_UNSPECIFIED_ERR:
233 //case USB_LC_STAT_NO_BANDWIDTH:
234 //case USB_LC_STAT_HW_ERR:
235 //case USB_LC_STAT_SUSPENDED:
236 //case USB_LC_STAT_DISCONNECTED:
237 //case USB_LC_STAT_INTR_BUF_FULL:
238 //case USB_LC_STAT_INVALID_REQ:
239 //case USB_LC_STAT_INTERRUPTED:
240 //case USB_LC_STAT_NO_RESOURCES:
241 //case USB_LC_STAT_INTR_POLLING_FAILED:
242 default:
243 LogRel((USBR3PROXY ":vusbProxySolarisStatusToVUsbStatus irc=%#x!!\n", irc));
244 return VUSBSTATUS_STALL;
245 }
246}
247
248
249/**
250 * Setup a USB request packet.
251 */
252static void usbProxySolarisSetupReq(PVUSBSETUP pSetupData, uint8_t bmRequestType, uint8_t bRequest,
253 uint16_t wValue, uint16_t wIndex, uint16_t wLength)
254{
255 AssertCompile(sizeof(VUSBSETUP) == USBSOL_CTRLREQ_SIZE);
256 LogFlow((USBR3PROXY ":usbProxySolarisSetupReq pSetupData=%p bmRequestType=%#x bRequest=%#x wValue=%#x wIndex=%#x wLength=%#x\n",
257 pSetupData, bmRequestType, bRequest, wValue, wIndex, wLength));
258
259 pSetupData->bmRequestType = bmRequestType;
260 pSetupData->bRequest = bRequest;
261
262 /* Handle endianess here. Currently no swapping is needed. */
263 pSetupData->wValue = wValue;
264 pSetupData->wIndex = wIndex;
265 pSetupData->wLength = wLength;
266}
267
268
269/**
270 * Helper for sending messages through an endpoint, Synchronous version.
271 * Note: pData is assumed to be (pReq + 1) i.e. following the request! Caller's responsibility.
272 *
273 * @returns Number of bytes transferred.
274 * @param pStatus Where to store the VUSB status (Optional).
275 */
276static int usbProxySolarisSendReq(RTFILE File, RTFILE StatFile, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, int *pStatus)
277{
278 /* Handle read request */
279 if (pReq->bmRequestType & VUSB_DIR_TO_HOST)
280 return usbProxySolarisIO(File, StatFile, (caddr_t)pReq, sizeof(VUSBSETUP), RTFILE_O_WRITE, pStatus);
281
282 /* Handle write request */
283 return usbProxySolarisIO(File, StatFile, (caddr_t)pReq, sizeof(VUSBSETUP) + cbData, RTFILE_O_WRITE, pStatus);
284}
285
286
287/**
288 * Helper for sending messages through an endpoint, Asynchronous version.
289 * Note: pData is assumed to (pReq + 1) i.e. following the request! Caller's responsibility.
290 *
291 * @returns VBox status code
292 * @param pUrbStatus Where to store the status.
293 */
294static int usbProxySolarisSendReqAsync(RTFILE File, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, PURBSTATUSSOL pUrbStatus)
295{
296 /* Handle read request */
297 if (pReq->bmRequestType & VUSB_DIR_TO_HOST)
298 return usbProxySolarisIOAsync(File, (caddr_t)pReq, sizeof(VUSBSETUP), RTFILE_O_WRITE, pUrbStatus);
299
300 /* Handle write request */
301 return usbProxySolarisIOAsync(File, (caddr_t)pReq, sizeof(VUSBSETUP) + cbData, RTFILE_O_WRITE, pUrbStatus);
302}
303
304
305/**
306 * Helper for sending control messages, Synchronous version.
307 *
308 * @returns Number of bytes transferred or -1 for errors.
309 * @param pStatus Where to store the VUSB status (Optional).
310 */
311static int usbProxySolarisCtrlReq(RTFILE File, RTFILE StatFile, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, int *pStatus)
312{
313 int cbIO = usbProxySolarisSendReq(File, StatFile, pReq, pData, cbData, pStatus);
314 if (cbIO < USBSOL_CTRLREQ_SIZE)
315 return cbIO;
316
317 /* Handle read requests, synchronous. */
318 cbIO -= USBSOL_CTRLREQ_SIZE;
319 if ( (pReq->bmRequestType & VUSB_DIR_TO_HOST)
320 && cbData > 0)
321 {
322 cbIO = usbProxySolarisIO(File, StatFile, pData, cbData, RTFILE_O_READ, pStatus);
323 }
324 return cbIO;
325}
326
327
328/**
329 * Helper for sending control messages, Asynchronous version.
330 *
331 * @returns VBox status code.
332 * @param pStatus Where to store the VUSB status (Optional).
333 */
334static int usbProxySolarisCtrlReqAsync(RTFILE File, PVUSBSETUP pReq, caddr_t pData, uint16_t cbData, PURBSTATUSSOL pStatus)
335{
336 int cbIO = usbProxySolarisSendReq(File, NIL_RTFILE, pReq, pData, cbData, NULL);
337 if (cbIO < USBSOL_CTRLREQ_SIZE)
338 return VERR_BUFFER_OVERFLOW;
339
340 /* Handle read requests, asynchronous. */
341 int rc = VINF_SUCCESS;
342 if ( (pReq->bmRequestType & VUSB_DIR_TO_HOST)
343 && cbData > 0)
344 {
345 rc = usbProxySolarisIOAsync(File, pData, cbData, RTFILE_O_READ, pStatus);
346 }
347 return rc;
348}
349
350
351#ifdef VBOX_WITH_SOLARIS_USB_ISOC
352/**
353 * Helper for sending isochronous requests, Asynchronous version.
354 *
355 * @returns VBox status code.
356 * @param pStatus Where to store the VUSB status (Optional).
357 */
358static int usbProxySolarisIsocReqAsync(RTFILE File, PUSBPROXYURBSOL pUrbSol, PURBSTATUSSOL pStatus)
359{
360 PVUSBURB pUrb = pUrbSol->pVUsbUrb;
361 if (pUrb->enmDir == VUSBDIRECTION_OUT)
362 return usbProxySolarisIOAsync(File, pUrbSol->pIsocBufOut, pUrbSol->cbIsocBufOut, RTFILE_O_WRITE, pStatus);
363
364 /* Handle read request, write request info synchronous, read asynchronous */
365 int cbIO = usbProxySolarisIO(File, NIL_RTFILE, pUrbSol->pIsocBufOut, pUrbSol->cbIsocBufOut, RTFILE_O_WRITE, NULL);
366
367 /* Free OUT buffer for the read request. */
368 RTMemFree(pUrbSol->pIsocBufOut);
369 pUrbSol->pIsocBufOut = NULL;
370 pUrbSol->cbIsocBufOut = 0;
371
372 if (cbIO < 0)
373 return VERR_GENERAL_FAILURE; /* @todo find proper error code here */
374
375 return usbProxySolarisIOAsync(File, pUrbSol->pIsocBufIn, pUrbSol->cbIsocBufIn, RTFILE_O_READ, pStatus);
376}
377#endif /* VBOX_WITH_SOLARIS_USB_ISOC */
378
379
380/**
381 * Basic USB IO function for transferring data to/from endpoint nodes, Synchronous version.
382 *
383 * @returns Number of bytes transferred or -1 on errors.
384 * @param File The endpoint node
385 * @param StatFile The associated status endpoint node (Optional, can be NIL_RTFILE).
386 * @param pData Pre-allocated buffer to read/write into.
387 * @param cbData Number of bytes to transfer (should be size of buffer).
388 * @param fOpenMode Open mode for the endpoint determining a Read/Write operation.
389 * @param pError Where to store VUSB result of operation (Optional, can be NULL).
390 */
391static int usbProxySolarisIO(RTFILE File, RTFILE StatFile, caddr_t pData, size_t cbData, int fOpenMode, int *pStatus)
392{
393 AssertReturn(cbData > 0, VERR_IO_BAD_LENGTH);
394 int rc;
395 size_t cbIO;
396
397 if (fOpenMode == RTFILE_O_READ)
398 rc = RTFileRead(File, pData, cbData, &cbIO);
399 else
400 rc = RTFileWrite(File, pData, cbData, &cbIO);
401
402 if ( pStatus
403 && StatFile != NIL_RTFILE)
404 {
405 int Status;
406 usbProxySolarisGetStatus(StatFile, &Status, false);
407 *pStatus = vusbProxySolarisStatusToVUsbStatus(Status);
408 }
409 return cbIO;
410}
411
412
413/**
414 * Basic USB IO function for transferring data to/from endpoint nodes, Asynchronous version.
415 *
416 * @returns VBox status code.
417 * @param File The endpoint node
418 * @param pData Pre-allocated buffer to read/write into.
419 * @param cbData Number of bytes to transfer (should be size of buffer).
420 * @param fMode RT IO mode for the endpoint (RTFILE_O_READ/RTFILE_O_WRITE).
421 * @param pUrbStatus Where to store the result (allocated by caller).
422 */
423static int usbProxySolarisIOAsync(RTFILE File, caddr_t pData, size_t cbData, int fMode, PURBSTATUSSOL pUrbStatus)
424{
425 AssertReturn(cbData > 0, VERR_IO_BAD_LENGTH);
426 int rc;
427
428 /* Turn on asynchronous notifications. */
429 usbProxySolarisAsyncNotify(true);
430
431 if (fMode == RTFILE_O_READ)
432 rc = aioread((int)File, pData, cbData, 0, SEEK_CUR, (aio_result_t *)pUrbStatus);
433 else
434 rc = aiowrite((int)File, pData, cbData, 0, SEEK_CUR, (aio_result_t *)pUrbStatus);
435
436 if (!rc)
437 return VINF_SUCCESS;
438 return RTErrConvertFromErrno(rc);
439}
440
441
442/**
443 * Initializes all pipes (including the default pipe) to their default state.
444 *
445 * @param pDevSol The Solaris USB device.
446 */
447static void usbProxySolarisInitAllPipes(PUSBPROXYDEVSOL pDevSol)
448{
449 for (int i = 0; i < USBSOL_MAXENDPOINTS; i++)
450 {
451 pDevSol->aEpFile[i] = NIL_RTFILE;
452 pDevSol->aEpStatFile[i] = NIL_RTFILE;
453 }
454}
455
456
457/**
458 * Opens the default device pipe and it's corresponding status node.
459 * Also opens the device status node in non-blocking mode.
460 *
461 * @returns VBox status code.
462 * @param pDevSol The Solaris USB device.
463 */
464static int usbProxySolarisOpenDevPipes(PUSBPROXYDEVSOL pDevSol)
465{
466 LogFlow((USBR3PROXY ":usbProxySolarisOpenDevPipes pDevSol=%p\n", pDevSol));
467
468 AssertReturn(pDevSol->pszDevPath, VERR_INVALID_NAME);
469
470 char achBuf[PATH_MAX];
471 RTStrPrintf(achBuf, sizeof(achBuf), "%s/devstat", pDevSol->pszDevPath);
472
473 /*
474 * Open status endpoint as read-only.
475 */
476 int rc = RTFileOpen(&pDevSol->StatFile, achBuf, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_NON_BLOCK);
477 if (RT_FAILURE(rc))
478 {
479 LogRel((USBR3PROXY ":failed to open status end-point. achBuf=%s rc=%Rrc\n", achBuf, rc));
480 return rc;
481 }
482
483 /*
484 * Open default control endpoint as read-write.
485 */
486 RTStrPrintf(achBuf, sizeof(achBuf), "%s/cntrl0", pDevSol->pszDevPath);
487 rc = RTFileOpen(&pDevSol->aEpFile[0], achBuf, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
488 if (RT_FAILURE(rc))
489 LogRel((USBR3PROXY ":failed to open control end-point achBuf=%s. rc=%Rrc\n", achBuf, rc));
490
491 /*
492 * Open default control status endpoint as read-only.
493 */
494 RTStrPrintf(achBuf, sizeof(achBuf), "%s/cntrl0stat", pDevSol->pszDevPath);
495 rc = RTFileOpen(&pDevSol->aEpStatFile[0], achBuf, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
496 if (RT_FAILURE(rc))
497 LogRel((USBR3PROXY ":failed to open control status end-point achBuf=%s. rc=%Rrc\n", achBuf, rc));
498
499 return rc;
500}
501
502
503/**
504 * Closes the default pipe, status node and device status node.
505 *
506 * @param pDevSol The Solaris USB device.
507 */
508static void usbProxySolarisCloseDevPipes(PUSBPROXYDEVSOL pDevSol)
509{
510 LogFlow((USBR3PROXY ":usbProxySolarisCloseDevPipes pDevSol=%p\n", pDevSol));
511
512 int rc;
513#define CLOSEFILE_AND_RESET(servicefile) \
514 do { \
515 if (servicefile != NIL_RTFILE) \
516 { \
517 rc = RTFileClose(servicefile); \
518 AssertRC(rc); \
519 servicefile = NIL_RTFILE; \
520 } \
521 } while(0)
522
523 CLOSEFILE_AND_RESET(pDevSol->StatFile);
524 CLOSEFILE_AND_RESET(pDevSol->aEpFile[0]);
525 CLOSEFILE_AND_RESET(pDevSol->aEpStatFile[0]);
526}
527
528
529/**
530 * Close all endpoints and reset endpoint descriptor arrays.
531 *
532 * @param pDevSol The Solaris USB device.
533 */
534static void usbProxySolarisCloseEndPoints(PUSBPROXYDEVSOL pDevSol)
535{
536 /* Close endpoint and endpoint status descriptors. */
537 for (int i = 1; i < USBSOL_MAXENDPOINTS; i++)
538 {
539 if (pDevSol->aEpFile[i] != NIL_RTFILE)
540 {
541 RTFileClose(pDevSol->aEpFile[i]);
542 pDevSol->aEpFile[i] = NIL_RTFILE;
543 }
544
545 if (pDevSol->aEpStatFile[i] != NIL_RTFILE)
546 {
547 RTFileClose(pDevSol->aEpStatFile[i]);
548 pDevSol->aEpStatFile[i] = NIL_RTFILE;
549 }
550 }
551}
552
553
554/**
555 * Helper/Wrapper for closing all the device nodes and control pipes.
556 *
557 * @param pDevSol The Solaris USB device.
558 */
559static void usbProxySolarisCloseDevice(PUSBPROXYDEVSOL pDevSol)
560{
561 usbProxySolarisCloseEndPoints(pDevSol);
562 usbProxySolarisCloseDevPipes(pDevSol);
563}
564
565
566/**
567 * Get status information from a status node.
568 *
569 * @param StatFile The opened status node,
570 * @param pStatus Where to store the status (optional).
571 * @param fDevStat Whether the passed StatFile is the device status node.
572 */
573static int usbProxySolarisGetStatus(RTFILE StatFile, int *pStatus, bool fDevStat)
574{
575 LogFlow((USBR3PROXY ":usbProxySolarisGetStatus pStatus=%p fDevStat=%d\n", pStatus, fDevStat));
576
577 int Status;
578 size_t cbRead;
579 int rc = RTFileRead(StatFile, &Status, sizeof(Status), &cbRead);
580 if (cbRead != sizeof(Status))
581 {
582 rc = VERR_DEV_IO_ERROR;
583 LogRel((USBR3PROXY "usbProxySolarisGetStatus: failed to read. rc=%Rrc\n", rc));
584 }
585 else
586 {
587 /*
588 * Ugen supplied error codes.
589 */
590 rc = VINF_SUCCESS;
591 if (!fDevStat)
592 {
593 switch (Status)
594 {
595 case USB_LC_STAT_NOERROR: Log((USBR3PROXY ":usbProxySolarisGetStatus: No Error\n")); break;
596 case USB_LC_STAT_CRC: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: CRC Timeout Detected\n")); break;
597 case USB_LC_STAT_BITSTUFFING: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Bit Stuffing Violation\n")); break;
598 case USB_LC_STAT_DATA_TOGGLE_MM: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Data Toggle Mismatch\n")); break;
599 case USB_LC_STAT_STALL: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: End Point Stalled\n")); break;
600 case USB_LC_STAT_DEV_NOT_RESP: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Device Not Responding\n")); break;
601 case USB_LC_STAT_PID_CHECKFAILURE: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: PID Check Failure\n")); break;
602 case USB_LC_STAT_UNEXP_PID: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Unexpected PID\n")); break;
603 case USB_LC_STAT_DATA_OVERRUN: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Data Exceeded Size\n")); break;
604 case USB_LC_STAT_DATA_UNDERRUN: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Less Data Received\n")); break;
605 case USB_LC_STAT_BUFFER_OVERRUN: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Buffer Size Exceeded\n")); break;
606 case USB_LC_STAT_BUFFER_UNDERRUN: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Buffer Underrun\n")); break;
607 case USB_LC_STAT_TIMEOUT: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Command has timed out\n")); break;
608 case USB_LC_STAT_NOT_ACCESSED: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Not Accessed by Hardware\n")); break;
609 case USB_LC_STAT_UNSPECIFIED_ERR: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Unspecified Error\n")); break;
610 case USB_LC_STAT_NO_BANDWIDTH: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: No Bandwidth\n")); break;
611 case USB_LC_STAT_HW_ERR: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Host Controller Hardware Error\n")); break;
612 case USB_LC_STAT_SUSPENDED: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Device Suspended\n")); break;
613 case USB_LC_STAT_DISCONNECTED: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Device Disconnected\n")); break;
614 case USB_LC_STAT_INTR_BUF_FULL: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Interrupt Buffer full\n")); break;
615 case USB_LC_STAT_INVALID_REQ: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Request Invalid\n")); break;
616 case USB_LC_STAT_INTERRUPTED: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Request Interrupted\n")); break;
617 case USB_LC_STAT_NO_RESOURCES: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: No Resources Available for Request\n")); break;
618 case USB_LC_STAT_INTR_POLLING_FAILED: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Failed to Restart Poll")); break;
619 default: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Error Not Determined %d\n", Status)); break;
620 }
621 }
622 else
623 {
624 switch (Status)
625 {
626 case USB_DEV_STAT_ONLINE: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Device Online\n")); break;
627 case USB_DEV_STAT_DISCONNECTED: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Device Disconnected\n")); break;
628 case USB_DEV_STAT_RESUMED: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Device Resumed\n")); break;
629 case USB_DEV_STAT_UNAVAILABLE: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Device Status Unavailable\n")); break;
630 default: LogRel((USBR3PROXY ":usbProxySolarisGetStatus: Unknown error %d!\n", Status)); break;
631 }
632 }
633 }
634 if (pStatus)
635 *pStatus = Status;
636 return rc;
637}
638
639
640/**
641 * Get currently active configuration.
642 *
643 * @param pDevSol The Solaris USB Device.
644 * @param pConfigValue Where to store the configuration value.
645 * @returns VBox status code.
646 */
647static int usbProxySolarisGetActiveCfg(PUSBPROXYDEVSOL pDevSol, int *pConfigValue)
648{
649 LogFlow((USBR3PROXY ":usbProxySolarisGetActiveCfg pDevSol=%p pConfigValue=%p\n", pDevSol, pConfigValue));
650
651 AssertReturn(pConfigValue, VERR_INVALID_POINTER);
652
653 /* USB 2.0(Sec. 9.4.2): bRequest=GET_CONFIGURATION(0x08) wValue=0 wIndex=0 wLength=1 */
654 VUSBSETUP SetupData;
655 usbProxySolarisSetupReq(&SetupData, VUSB_DIR_TO_HOST, VUSB_REQ_GET_CONFIGURATION, 0, 0, 1);
656
657 int iConfig = -1;
658 int rc = RTFileWrite(pDevSol->aEpFile[0], &SetupData, sizeof(SetupData), NULL);
659 if (RT_SUCCESS(rc))
660 {
661 size_t cbRead;
662 rc = RTFileRead(pDevSol->aEpFile[0], &iConfig, sizeof(iConfig), &cbRead);
663 if ( cbRead == sizeof(iConfig)
664 && RT_SUCCESS(rc))
665 {
666 LogRel((USBR3PROXY ":usbProxySolarisGetActiveCfg success. cfg=%d\n", iConfig));
667 *pConfigValue = iConfig;
668 return rc;
669 }
670 rc = VERR_DEV_IO_ERROR;
671 LogRel((USBR3PROXY ":usbProxySolarisGetActiveCfg failed to read configuration. cbRead=%d rc=%Rrc iConfig=%d\n", cbRead, rc, iConfig));
672 }
673 else
674 LogRel((USBR3PROXY ":usbProxySolarisGetActiveCfg failed to write configuration request!\n"));
675 return rc;
676}
677
678
679/**
680 * Finds the interface and alternate setting for a given Endpoint address.
681 *
682 * @returns VBox status code.
683 * @param pDevSol The Solaris USB device.
684 * @param EndPoint The endpoint address as seen in the descriptor.
685 * @param piInterface Where to store the interface number.
686 * @param piAlternate Where to store the alternate number.
687 */
688static int usbProxySolarisGetInterfaceForEndpoint(PUSBPROXYDEVSOL pDevSol, int EndPoint, int *piInterface, int *piAlternate)
689{
690 LogFlow((USBR3PROXY ":usbProxySolarisGetInterfaceForEndpoint pDevSol=%p Endpoint=%#x\n", pDevSol, EndPoint));
691
692 /* Find the interface for this endpoint. */
693 PUSBPROXYDEV pProxyDev = pDevSol->pProxyDev;
694 PCPDMUSBDESCCACHE pDescCache = &pProxyDev->DescCache;
695 AssertReturn(pDescCache, VERR_INVALID_HANDLE);
696
697 /* Find the configuration index for this configuration value. */
698 int iCfg = usbProxySolarisConfigIndex(pDevSol, pProxyDev->iActiveCfg >= 1 ? pProxyDev->iActiveCfg : 1);
699 if (iCfg < 0)
700 {
701 LogRel((USBR3PROXY ":usbProxySolarisGetInterfaceForEndpoint failed to obtain configuration index\n"));
702 return VERR_GENERAL_FAILURE;
703 }
704
705 PCVUSBDESCCONFIGEX pCfg = &pProxyDev->paCfgDescs[iCfg];
706 AssertReturn(pCfg, VERR_INVALID_POINTER);
707
708 /*
709 * Loop through all interfaces for this configuration.
710 */
711 for (int i = 0; i < pCfg->Core.bNumInterfaces; i++)
712 {
713 PCVUSBINTERFACE pInterface = &pCfg->paIfs[i];
714 AssertReturn(pInterface, VERR_INVALID_POINTER);
715
716 /*
717 * Loop through all alternate settings of this interface.
718 */
719 for (uint32_t k = 0; k < pInterface->cSettings; k++)
720 {
721 PCVUSBDESCINTERFACEEX pInterfaceEx = &pInterface->setting[k];
722 AssertReturn(pInterfaceEx, VERR_INVALID_POINTER);
723
724 /*
725 * Loop through all the endpoints of this interface.
726 */
727 for (unsigned j = 0; j < pInterfaceEx->Core.bNumEndpoints; j++)
728 {
729 PCVUSBDESCENDPOINTEX pEndPoint = &pInterfaceEx->paEndpoints[j];
730 AssertReturn(pEndPoint, VERR_INVALID_POINTER);
731
732 if (pEndPoint->Core.bEndpointAddress == EndPoint)
733 {
734 if (piInterface)
735 *piInterface = pInterfaceEx->Core.bInterfaceNumber;
736 if (piAlternate)
737 *piAlternate = pInterfaceEx->Core.bAlternateSetting;
738 return VINF_SUCCESS;
739 }
740 }
741 }
742 }
743 LogRel((USBR3PROXY ":usbProxySolarisGetInterfaceForEndpoint failed for EndPt=%#x\n", EndPoint));
744 return VERR_GENERAL_FAILURE;
745}
746
747
748/**
749 * Finds configuration index for the configuration value.
750 *
751 * @returns Index of configuration with value 'bCfgValue' or -1 if not found.
752 */
753static int usbProxySolarisConfigIndex(PUSBPROXYDEVSOL pDevSol, uint8_t bCfgValue)
754{
755 LogFlow((USBR3PROXY ":usbProxySolarisConfigIndex pDevSol=%p bCfgValue=%d\n", bCfgValue));
756
757 /* Find the configuration index corresponding to this configuration value. */
758 PUSBPROXYDEV pProxyDev = pDevSol->pProxyDev;
759 PCPDMUSBDESCCACHE pDescCache = &pProxyDev->DescCache;
760 AssertReturn(pDescCache, VERR_INVALID_HANDLE);
761
762 int cCfg = pDescCache->pDevice->bNumConfigurations;
763 for (int i = 0; i < cCfg; i++)
764 {
765 PCVUSBDESCCONFIGEX pCfg = &pProxyDev->paCfgDescs[i];
766 AssertReturn(pCfg, -1);
767 if (pCfg->Core.bConfigurationValue == bCfgValue)
768 {
769 LogFlow((USBR3PROXY ":usbProxySolarisConfigIndex found bCfgValue=%d at index %d\n", bCfgValue, i));
770 return i;
771 }
772 }
773 LogRel((USBR3PROXY ":usbProxySolarisConfigIndex bCfgValue=%d not found!\n", bCfgValue));
774 return -1;
775}
776
777
778/**
779 * Claims all interfaces for a given configuration.
780 *
781 * @returns VBox status code.
782 * @param pDevSol The Solaris USB device.
783 * @param bCfgValue The configuration value.
784 */
785static int usbProxySolarisSeizeAllInterfaces(PUSBPROXYDEVSOL pDevSol, uint8_t bCfgValue)
786{
787 LogFlow((USBR3PROXY ":usbProxySolarisSeizeAllInterfaces pDevSol=%p bCfgValue=%d\n", pDevSol, bCfgValue));
788
789 AssertReturn(pDevSol, VERR_INVALID_POINTER);
790
791 /*
792 * ugen doesn't have a seize all interface scheme, but we can just open all the end-points of the interface
793 * in exclusive mode to have a similar effect. This should mostly be called from Init.
794 */
795 PCPDMUSBDESCCACHE pDescCache = &pDevSol->pProxyDev->DescCache;
796 AssertReturn(pDescCache, VERR_INVALID_HANDLE);
797
798 int rc = VERR_GENERAL_FAILURE;
799 int cCfg = pDescCache->pDevice->bNumConfigurations;
800
801 /* Find the configuration index for this configuration value. */
802 int iCfg = usbProxySolarisConfigIndex(pDevSol, bCfgValue);
803 if (iCfg < 0)
804 {
805 LogRel((USBR3PROXY ":usbProxySolarisSeizeAllInterfaces failed to find configuration index for configuration value %d\n", bCfgValue));
806 return VERR_GENERAL_FAILURE; /* @todo find a better code? */
807 }
808
809 if (iCfg < cCfg)
810 {
811 PCVUSBDESCCONFIGEX pCfg = &pDevSol->pProxyDev->paCfgDescs[iCfg];
812
813 /*
814 * Loop through all interfaces for this configuration.
815 */
816 for (int iInterface = 0; iInterface < pCfg->Core.bNumInterfaces; iInterface++)
817 {
818 PCVUSBINTERFACE pInterface = &pCfg->paIfs[iInterface];
819 AssertReturn(pInterface, VERR_INVALID_POINTER);
820
821 /*
822 * Loop through all alternate settings of this interface.
823 */
824 for (uint32_t k = 0; k < pInterface->num_settings; k++)
825 {
826 PCVUSBDESCINTERFACEEX pInterfaceEx = &pInterface->setting[k];
827 AssertReturn(pInterfaceEx, VERR_INVALID_POINTER);
828
829 int iAlternate = pInterfaceEx->Core.bAlternateSetting;
830
831 /*
832 * Loop through all endpoints for this interface.
833 */
834 for (unsigned j = 0; j < pInterfaceEx->Core.bNumEndpoints; j++)
835 {
836 PCVUSBDESCENDPOINTEX pEndPoint = &pInterfaceEx->paEndpoints[j];
837 AssertReturn(pEndPoint, VERR_INVALID_POINTER);
838
839 rc = usbProxySolarisOpenNode(pDevSol,
840 bCfgValue, /* Configuration value */
841 iInterface, /* Interface number */
842 iAlternate, /* Alternate setting */
843 pEndPoint->Core.bEndpointAddress, /* Endpoint Address */
844 usbProxySolarisXferType(pEndPoint->Core.bmAttributes)); /* Xfer Type */
845 if (RT_FAILURE(rc))
846 {
847 LogRel((USBR3PROXY ":usbProxySolarisSeizeAllInterfaces failed to open Cfg%d If%d Alt%d Ep%d(Addr %#x)\n", bCfgValue,
848 iInterface, iAlternate, k, pEndPoint->Core.bEndpointAddress));
849 break;
850 }
851 }
852 }
853 if (RT_FAILURE(rc))
854 break;
855 }
856 }
857 else
858 LogRel((USBR3PROXY ":usbProxySolarisSeizeAllInterfaces failed! iCfg %d > cCfg %d\n", iCfg, cCfg));
859
860 LogFlow((USBR3PROXY ":usbProxySolarisSeizeAllInterfaces returned %d\n", rc));
861 return rc;
862}
863
864
865/**
866 * Determine the XferType from the endpoint attribute.
867 *
868 * @returns XferType for the given endpoint 'bmAttribute'
869 */
870static VUSBXFERTYPE usbProxySolarisXferType(uint8_t bmAttribute)
871{
872 LogFlow((USBR3PROXY ":usbProxySolarisXferType bmAttribute=%#x\n", bmAttribute));
873
874 /*
875 * USB 2.0(Sec. 9.6.6): bmAttribute transfer type.
876 */
877 return (VUSBXFERTYPE)(bmAttribute & 0x03);
878}
879
880
881/**
882 * Determines the ugen node's open mode based on the XferType and direction.
883 *
884 * @returns The file open mode, or UINT32_MAX upon errors.
885 * @param bmEndpointAddress Address of endpoint as seen in the descriptor.
886 * @param XferType The VUSB XferType.
887 */
888DECLINLINE(uint32_t) usbProxySolarisOpenMode(uint8_t bmEndpointAddress, VUSBXFERTYPE XferType)
889{
890 LogFlow((USBR3PROXY ":usbProxySolarisOpenMode bmEndpointAddress=%#x XferType=%d\n", bmEndpointAddress, XferType));
891
892 uint32_t fMode = RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
893 int fIn = bmEndpointAddress & USBSOL_EPADDR_IN;
894 switch (XferType)
895 {
896 case VUSBXFERTYPE_INTR: fMode |= (fIn ? RTFILE_O_READ : RTFILE_O_WRITE | RTFILE_O_NON_BLOCK); break;
897 case VUSBXFERTYPE_BULK: fMode |= (fIn ? RTFILE_O_READ : RTFILE_O_WRITE); break;
898 case VUSBXFERTYPE_ISOC: fMode |= RTFILE_O_READWRITE | RTFILE_O_NON_BLOCK; break;
899 case VUSBXFERTYPE_CTRL: fMode |= RTFILE_O_READWRITE; break;
900 case VUSBXFERTYPE_MSG : fMode |= RTFILE_O_READWRITE | RTFILE_O_NON_BLOCK; break;
901 case VUSBXFERTYPE_INVALID: fMode = UINT32_MAX; LogRel((USBR3PROXY ":invalid XferType %d\n", XferType)); break;
902 }
903 return fMode;
904}
905
906
907/**
908 * Open and endpoint given the XferType and optional OpenMode.
909 *
910 * @returns VBox status code.
911 * @param pDevSol The Solaris USB device.
912 * @param EndPoint The endpoint address as in the descriptor.
913 * @param XferType Endpoint xfer type.
914 */
915static int usbProxySolarisOpenEndPoint(PUSBPROXYDEVSOL pDevSol, int EndPoint, VUSBXFERTYPE XferType)
916{
917 LogFlow((USBR3PROXY ":usbProxySolarisOpenEndPoint pDevSol=%p EndPoint=%#x XferType=%d\n", EndPoint, XferType));
918
919 /* Endpoint zero (the default control pipe) would already be open. */
920 if (EndPoint == 0)
921 return VINF_SUCCESS;
922
923 PUSBPROXYDEV pProxyDev = pDevSol->pProxyDev;
924
925 /* @todo Fix This! I'm not yet sure what's the right thing to do here regarding configuration... */
926 /* Get current configuration index. */
927 int bCfgValue = pProxyDev->iActiveCfg;
928 if (bCfgValue == -1)
929 {
930 /* @todo Fix or remove this. GET_CONFIGURATION requests don't work... */
931 int rc = usbProxySolarisGetActiveCfg(pDevSol, &bCfgValue);
932 if (RT_FAILURE(rc))
933 bCfgValue = 1;
934 }
935
936 /* Get interface for endpoint. */
937 int iInterface;
938 int iAlternate;
939 int rc = usbProxySolarisGetInterfaceForEndpoint(pDevSol, EndPoint, &iInterface, &iAlternate);
940 if (RT_SUCCESS(rc))
941 return usbProxySolarisOpenNode(pDevSol, bCfgValue, iInterface, iAlternate, EndPoint, XferType);
942 else
943 LogRel((USBR3PROXY ":usbProxySolarisOpenEndPoint usbProxySolarisGetInterfaceForEndpoint failed. rc=%Rrc\n", rc));
944
945 return VERR_GENERAL_FAILURE;
946}
947
948
949/**
950 * Open an endpoint node and stores it among the list of open endpoints.
951 *
952 * @returns VBox status code.
953 * @param pDevSol The Solaris USB device.
954 * @param bCfgValue The configuration value.
955 * @param iInterface The interface number.
956 * @param iAlternate The alternate setting.
957 * @param EndPoint The endpoint address as stored in the descriptor.
958 * @param XferType Endpoint xfer type.
959 * @param fOpenMode Open mode for the endpoint (< 0 auto-detects mode based on xfer type and direction).
960 */
961static int usbProxySolarisOpenNode(PUSBPROXYDEVSOL pDevSol, uint8_t bCfgValue, int iInterface, int iAlternate, int EndPoint,
962 VUSBXFERTYPE XferType)
963{
964 LogFlow((USBR3PROXY ":usbProxySolarisOpenNode pDevSol=%p bCfgValue=%d iInterface=%d iAlternate=%d EndPoint=%#x XferType=%d\n",
965 pDevSol, bCfgValue, iInterface, iAlternate, EndPoint, XferType));
966
967 int EndPtIndex = (EndPoint & USBSOL_EPADDR_NUM_MASK) + ((EndPoint & USBSOL_EPADDR_DIR_MASK) ? USBSOL_MAXENDPOINTS / 2 : 0);
968 if (EndPtIndex < 0 || EndPtIndex > USBSOL_MAXENDPOINTS - 1)
969 return VERR_INVALID_HANDLE;
970
971 /* Check if already open; ep0 should already be open as well. */
972 if ( EndPtIndex == 0
973 || pDevSol->aEpFile[EndPtIndex] != NIL_RTFILE)
974 {
975 return VINF_SUCCESS;
976 }
977
978 /*
979 * Construct the node name and open the endpoint.
980 */
981 char szEndPoint[PATH_MAX + 1];
982 char szConfig[12];
983 char szAlternate[12];
984
985 memset(szConfig, 0, sizeof(szConfig));
986 memset(szAlternate, 0, sizeof(szAlternate));
987
988 int iCfg = usbProxySolarisConfigIndex(pDevSol, bCfgValue);
989 if (iCfg > 0)
990 RTStrPrintf(szConfig, sizeof(szConfig), "cfg%d", bCfgValue);
991
992 if (iAlternate > 0)
993 RTStrPrintf(szAlternate, sizeof(szAlternate), ".%d", iAlternate);
994
995 RTStrPrintf(szEndPoint, sizeof(szEndPoint), "%s/%sif%d%s%s%d", pDevSol->pszDevPath, szConfig, iInterface,
996 szAlternate, (EndPoint & USBSOL_EPADDR_DIR_MASK) ? "in" : "out", (EndPoint & USBSOL_EPADDR_NUM_MASK));
997
998 /*
999 * Ugen requires Interrupt IN endpoints to be polled before opening.
1000 */
1001 char szEndPointStat[PATH_MAX + 1];
1002 RTStrPrintf(szEndPointStat, sizeof(szEndPointStat), "%sstat", szEndPoint);
1003
1004 /*
1005 * Open the endpoint status node.
1006 */
1007 if ( XferType == VUSBXFERTYPE_INTR
1008 && (EndPoint & USBSOL_EPADDR_IN))
1009 {
1010 int rc = RTFileOpen(&pDevSol->aEpStatFile[EndPtIndex], szEndPointStat, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
1011 if (RT_FAILURE(rc))
1012 {
1013 LogRel((USBR3PROXY ":usbProxySolarisOpenNode failed to poll Intr IN endpoint stat %s\n", szEndPointStat));
1014 pDevSol->aEpStatFile[EndPtIndex] = NIL_RTFILE;
1015 return rc;
1016 }
1017
1018 /*
1019 * Unbuffered Interrupt IN transfers requires us to open the status endpoint and transfer
1020 * USB_EP_INTR_ONE_XFER once. This will put it in unbuffered transfer mode until it's closed.
1021 */
1022 char cMsg = USB_EP_INTR_ONE_XFER;
1023 rc = RTFileWrite(pDevSol->aEpStatFile[EndPtIndex], &cMsg, sizeof(cMsg), NULL);
1024 if (RT_FAILURE(rc))
1025 {
1026 LogRel((USBR3PROXY ":usbProxySolarisOpenNode failed to poll Intr IN endpoint %s\n", szEndPointStat));
1027 RTFileClose(pDevSol->aEpStatFile[EndPtIndex]);
1028 pDevSol->aEpStatFile[EndPtIndex] = NIL_RTFILE;
1029 return rc;
1030 }
1031 }
1032 else
1033 {
1034 int rc = RTFileOpen(&pDevSol->aEpStatFile[EndPtIndex], szEndPointStat, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
1035 if (RT_FAILURE(rc))
1036 {
1037 LogRel((USBR3PROXY ":usbProxySolarisOpenNode failed to open endpoint stat %s in read only.\n", szEndPointStat));
1038 return rc;
1039 }
1040 }
1041
1042 uint32_t fOpenMode = usbProxySolarisOpenMode(EndPoint, XferType);
1043 if (fOpenMode == UINT32_MAX)
1044 {
1045 LogRel((USBR3PROXY ":usbProxySolarisOpenNode invalid file mode for XferType %d\n", XferType));
1046 return VERR_INVALID_FMODE;
1047 }
1048
1049 /*
1050 * Open the Endpoint.
1051 */
1052 int rc = RTFileOpen(&pDevSol->aEpFile[EndPtIndex], szEndPoint, fOpenMode);
1053 if (RT_FAILURE(rc))
1054 {
1055 LogRel((USBR3PROXY ":usbProxySolarisOpenNode failed to open endpoint %s in mode %d\n", szEndPoint, fOpenMode));
1056 RTFileClose(pDevSol->aEpStatFile[EndPtIndex]);
1057 pDevSol->aEpStatFile[EndPtIndex] = NIL_RTFILE;
1058 }
1059 else
1060 Log((USBR3PROXY ":usbProxySolarisOpenNode Success! szEndPoint=%s Endpoint=%#x EndPtIndex=%#x\n", szEndPoint, EndPoint, EndPtIndex));
1061 return rc;
1062}
1063
1064
1065/**
1066 * Completion callback worker.
1067 *
1068 * @param pTimeout Pointer to a timeval struct specifying the timeout.
1069 */
1070static void usbProxySolarisUrbComplete(struct timeval *pTimeout)
1071{
1072 /*
1073 * Deque the completed URB.
1074 */
1075 aio_result_t *pResult = aiowait(pTimeout);
1076 if (!pResult) /* Timeout */
1077 {
1078 Log(("usbProxySolarisUrbComplete: timed out\n"));
1079 return;
1080 }
1081 else if ((intptr_t)pResult == -1) /* aiowait returns -1 instead of a pointer for errors. crap. */
1082 {
1083 if (errno == EINVAL)
1084 Log(("usbProxySolarisUrbComplete: No pending requests.\n"));
1085 else
1086 Log(("usbProxySolarisUrbComplete: aiowait failed errno=%d\n", errno));
1087 return;
1088 }
1089
1090 /*
1091 * Update the URB status.
1092 */
1093 PURBSTATUSSOL pStatus = (PURBSTATUSSOL)pResult;
1094 PUSBPROXYURBSOL pUrbSol = pStatus->pUrbSol;
1095 PUSBPROXYDEVSOL pDevSol = pUrbSol->pDevSol;
1096 PVUSBURB pUrb = pUrbSol->pVUsbUrb;
1097
1098 RTCritSectEnter(&pDevSol->CritSect);
1099
1100#ifdef VBOX_WITH_SOLARIS_USB_ISOC
1101 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
1102 {
1103 if (pUrb->enmDir == VUSBDIRECTION_IN)
1104 {
1105 void *pvPayload = pUrbSol->pIsocBufIn + pUrb->cIsocPkts * sizeof(ugen_isoc_pkt_descr_t);
1106 memcpy(pUrb->abData, pvPayload, pUrb->cbData);
1107
1108 RTMemFree(pUrbSol->pIsocBufIn);
1109 pUrbSol->pIsocBufIn = NULL;
1110 pUrbSol->cbIsocBufIn = 0;
1111 }
1112 else
1113 {
1114 RTMemFree(pUrbSol->pIsocBufOut);
1115 pUrbSol->pIsocBufOut = NULL;
1116 pUrbSol->cbIsocBufOut = 0;
1117 }
1118 }
1119 else
1120#endif /* !VBOX_WITH_SOLARIS_USB_ISOC */
1121 {
1122 pUrb->cbData = pResult->aio_return;
1123 pUrb->enmStatus = pResult->aio_errno ? VUSBSTATUS_STALL : VUSBSTATUS_OK; /* @todo find a better way */
1124 if (pUrb->enmType == VUSBXFERTYPE_MSG)
1125 pUrb->cbData += sizeof(VUSBSETUP);
1126 }
1127
1128 /*
1129 * Remove from the active list.
1130 */
1131 if (pUrbSol->pNext)
1132 pUrbSol->pNext->pPrev = pUrbSol->pPrev;
1133 if (pUrbSol->pPrev)
1134 pUrbSol->pPrev->pNext = pUrbSol->pNext;
1135 else
1136 {
1137 Assert(pDevSol->pInFlightHead == pUrbSol);
1138 pDevSol->pInFlightHead = pUrbSol->pNext;
1139 }
1140
1141 /*
1142 * Link it into the taxing list.
1143 */
1144 pUrbSol->pNext = NULL;
1145 pUrbSol->pPrev = pDevSol->pTaxingTail;
1146 if (pDevSol->pTaxingTail)
1147 pDevSol->pTaxingTail->pNext = pUrbSol;
1148 else
1149 pDevSol->pTaxingHead = pUrbSol;
1150 pDevSol->pTaxingTail = pUrbSol;
1151
1152 RTCritSectLeave(&pDevSol->CritSect);
1153
1154 Log(("%s: usbProxySolarisUrbComplete: cb=%d EndPt=%#x enmStatus=%s\n",
1155 pUrb->pszDesc, pUrb->cbData, pUrb->EndPt, pUrb->enmStatus == VUSBSTATUS_OK ? "VUSBSTATUS_OK" : "NotSuccessful"));
1156}
1157
1158
1159/**
1160 * Completion callback for asynchronous URBs.
1161 *
1162 */
1163static void usbProxySolarisAsyncComplete(int Sig)
1164{
1165 LogFlow((USBR3PROXY ":usbProxySolarisAsyncComplete Sig=%s %d\n", Sig == SIGIO ? "SIGIO" : "Irrelevant Sig", Sig));
1166
1167 if (Sig == SIGIO)
1168 return usbProxySolarisUrbComplete(NULL);
1169}
1170
1171
1172/**
1173 * Opens the USB device.
1174 *
1175 * @returns VBox status code.
1176 * @param pProxyDev The device instance.
1177 * @param pszAddress The path to the device in the dev and devices tree,
1178 * The format of this string is "/dev/path|/devices/path".
1179 * @param pvBackend Backend specific pointer, unused for the solaris backend.
1180 */
1181static int usbProxySolarisOpen(PUSBPROXYDEV pProxyDev, const char *pszAddress, void *pvBackend)
1182{
1183 LogFlow((USBR3PROXY ":usbProxySolarisOpen pProxyDev=%p pszAddress=%s pvBackend=%p\n", pProxyDev, pszAddress, pvBackend));
1184
1185 /*
1186 * Initialize our USB R3 lib.
1187 */
1188 int rc = USBLibInit();
1189 if (RT_SUCCESS(rc))
1190 {
1191 /*
1192 * Allocate and initialize the solaris backend data.
1193 */
1194 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)RTMemAllocZ(sizeof(*pDevSol));
1195 if (pDevSol)
1196 {
1197 /*
1198 * Parse out 2 paths (dev and devices tree).
1199 */
1200 char szDevBuf[PATH_MAX];
1201 char szDevicesBuf[PATH_MAX];
1202 int cFields = sscanf(pszAddress, "%[^'|']|%s", szDevBuf, szDevicesBuf);
1203 if (cFields == 2)
1204 {
1205 szDevBuf[strlen(szDevBuf)] = 0;
1206 szDevicesBuf[strlen(szDevicesBuf)] = 0;
1207 RTStrAPrintf(&pDevSol->pszDevPath, "%s", szDevBuf);
1208 RTStrAPrintf(&pDevSol->pszDevicePath, "%s", szDevicesBuf);
1209 rc = RTCritSectInit(&pDevSol->CritSect);
1210 if (RT_SUCCESS(rc))
1211 {
1212 pProxyDev->Backend.pv = pDevSol;
1213
1214 /*
1215 * Initialize all pipes.
1216 */
1217 usbProxySolarisInitAllPipes(pDevSol);
1218
1219 /*
1220 * Open the default control and control status endpoint.
1221 */
1222 rc = usbProxySolarisOpenDevPipes(pDevSol);
1223 if (RT_SUCCESS(rc))
1224 {
1225 /*
1226 * @todo Fix this: Try to get the active configuration.
1227 */
1228 //int iActiveCfg = -1;
1229 //rc = usbProxySolarisGetActiveCfg(pDevSol, &iActiveCfg);
1230 if (RT_SUCCESS(rc))
1231 {
1232 //pProxyDev->iActiveCfg = usbProxySolarisConfigIndex(pDevSol, iActiveCfg) > 0 ? iActiveCfg : -1;
1233 pProxyDev->iActiveCfg = -1;
1234 pProxyDev->cIgnoreSetConfigs = 1;
1235 }
1236 else
1237 LogRel((USBR3PROXY ":usbProxySolarisGetActiveCfg failed! rc=%Rrc\n", rc));
1238
1239 pDevSol->pProxyDev = pProxyDev;
1240 return VINF_SUCCESS;
1241 }
1242 else
1243 LogRel((USBR3PROXY ":usbProxySolarisDevPipes failed. rc=%Rrc\n", rc));
1244 usbProxySolarisCloseDevPipes(pDevSol); /* Close here to handle partial open failures. */
1245 RTCritSectDelete(&pDevSol->CritSect);
1246 }
1247 else
1248 LogRel((USBR3PROXY ":RTCritSectInit failed. rc=%Rrc\n", rc));
1249 RTStrFree(pDevSol->pszDevPath);
1250 RTStrFree(pDevSol->pszDevicePath);
1251 }
1252 else
1253 {
1254 rc = VERR_GENERAL_FAILURE;
1255 LogRel((USBR3PROXY ":Failed to parse address of USB device pszAddress=%s\n", pszAddress));
1256 }
1257 RTMemFree(pDevSol);
1258 }
1259 else
1260 rc = VERR_NO_MEMORY;
1261 }
1262 else
1263 LogRel((USBR3PROXY ":USBLibInit failed. rc=%Rrc\n", rc));
1264
1265 USBLibTerm();
1266 pProxyDev->Backend.pv = NULL;
1267 return rc;
1268}
1269
1270
1271/**
1272 * Post-open initialization of the USB device.
1273 *
1274 * @returns VBox status code.
1275 * @param pProxyDev The device instance.
1276 */
1277static int usbProxySolarisInit(PUSBPROXYDEV pProxyDev)
1278{
1279 LogFlow((USBR3PROXY ":usbProxySolarisInit: pProxyDev=%p\n", pProxyDev));
1280
1281 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
1282 AssertReturn(pDevSol, VERR_INVALID_POINTER);
1283
1284 /* Use the first configuration as the active configure. */
1285 PCVUSBDESCCONFIGEX pCfg = &pProxyDev->paCfgDescs[0];
1286 if (pCfg)
1287 {
1288 /* Now seize all the interfaces. */
1289 return usbProxySolarisSeizeAllInterfaces(pDevSol, pCfg->Core.bConfigurationValue);
1290 }
1291
1292 LogRel((USBR3PROXY ":usbProxySolarisInit invalid device descriptors.\n"));
1293 return VERR_INVALID_HANDLE;
1294}
1295
1296
1297/**
1298 * Close the USB device.
1299 *
1300 * @param pProxyDev The device instance.
1301 */
1302static void usbProxySolarisClose(PUSBPROXYDEV pProxyDev)
1303{
1304 LogFlow((USBR3PROXY ":usbProxySolarisClose: pProxyDev=%p\n", pProxyDev));
1305
1306 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
1307
1308 /* Close the device. */
1309 usbProxySolarisCloseDevice(pDevSol);
1310
1311 /* Reset the device without reattaching a new driver. */
1312 USBLibResetDevice(pDevSol->pszDevicePath, false);
1313
1314 /*
1315 * Now we can close it and free all the resources.
1316 */
1317 RTCritSectDelete(&pDevSol->CritSect);
1318
1319 PUSBPROXYURBSOL pUrbSol;
1320 while ((pUrbSol = pDevSol->pInFlightHead) != NULL)
1321 {
1322 pDevSol->pInFlightHead = pUrbSol->pNext;
1323 RTMemFree(pUrbSol);
1324 }
1325
1326 while ((pUrbSol = pDevSol->pFreeHead) != NULL)
1327 {
1328 pDevSol->pFreeHead = pUrbSol->pNext;
1329 RTMemFree(pUrbSol);
1330 }
1331
1332 usbProxySolarisAsyncNotify(false);
1333
1334 RTStrFree(pDevSol->pszDevPath);
1335 pDevSol->pszDevPath = NULL;
1336 RTStrFree(pDevSol->pszDevicePath);
1337 pDevSol->pszDevicePath = NULL;
1338 RTMemFree(pDevSol);
1339 pProxyDev->Backend.pv = NULL;
1340
1341 USBLibTerm();
1342}
1343
1344
1345/**
1346 * Reset the device.
1347 *
1348 * @returns VBox status code.
1349 * @param pProxyDev The device to reset.
1350 */
1351static int usbProxySolarisReset(PUSBPROXYDEV pProxyDev, bool fResetOnSolaris)
1352{
1353 LogFlow((USBR3PROXY ":usbProxySolarisReset pProxyDev=%s\n", pProxyDev->pUsbIns->pszName));
1354
1355 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
1356
1357 /* Close all endpoints and endpoint status nodes. */
1358 usbProxySolarisCloseEndPoints(pDevSol);
1359
1360 /* Stop notifications */
1361 usbProxySolarisAsyncNotify(false);
1362
1363 /*
1364 * Specific device resets are implicitly handled by ugen upon closing/reopening the device.
1365 * Root hub resets that affects all devices are executed.
1366 */
1367 if (fResetOnSolaris)
1368 {
1369 /* Reset the device without reattaching a new driver */
1370 int rc = USBLibResetDevice(pDevSol->pszDevicePath, false);
1371 if (RT_SUCCESS(rc))
1372 {
1373 pProxyDev->cIgnoreSetConfigs = 0;
1374 pProxyDev->iActiveCfg = -1;
1375 }
1376 else
1377 LogRel(("usbProxySolarisReset: failed! rc=%Rrc\n", rc));
1378 return rc;
1379 }
1380 else
1381 return VINF_SUCCESS;
1382}
1383
1384
1385/**
1386 * Set the active configuration.
1387 *
1388 * The caller makes sure that it's not called first time after open or reset
1389 * with the active interface.
1390 *
1391 * @returns success indicator.
1392 * @param pProxyDev The device instance data.
1393 * @param iCfg The configuration value to set.
1394 */
1395static int usbProxySolarisSetConfig(PUSBPROXYDEV pProxyDev, int iCfg)
1396{
1397 LogFlow((USBR3PROXY ":usbProxySolarisSetConfig: pProxyDev=%p iCfg=%d\n", pProxyDev, iCfg));
1398
1399 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
1400
1401 /*
1402 * Solaris ugen ignores any SET_CONFIGURATION requests. It does an implicitly config change while
1403 * opening the appropriate nodes of the configuration. So what we need to do is make sure all the
1404 * nodes of previous configuration is closed before re-opening/claiming the new configuration.
1405 */
1406 if (pProxyDev->iActiveCfg == iCfg)
1407 return true;
1408
1409 usbProxySolarisCloseEndPoints(pDevSol);
1410 int rc = usbProxySolarisSeizeAllInterfaces(pDevSol, (uint8_t)iCfg);
1411 if (RT_SUCCESS(rc))
1412 {
1413 if (iCfg > 0)
1414 pProxyDev->iActiveCfg = iCfg;
1415 else
1416 LogRel((USBR3PROXY ":usbProxySolarisSetConfig invalid iCfg %d\n", iCfg));
1417 return true;
1418 }
1419
1420 LogRel((USBR3PROXY ":usbProxySolarisSetConfig failed to seize all interfaces for iCfg %d\n", iCfg));
1421 return false;
1422}
1423
1424
1425/**
1426 * Claims an interface.
1427 *
1428 * This is a stub on Solaris since we release/claim all interfaces at
1429 * open/reset/setconfig time.
1430 *
1431 * @returns success indicator (always true).
1432 */
1433static int usbProxySolarisClaimInterface(PUSBPROXYDEV pProxyDev, int iIf)
1434{
1435 return true;
1436}
1437
1438
1439/**
1440 * Releases an interface.
1441 *
1442 * This is a stub on Solaris since we release/claim all interfaces at
1443 * open/reset/setconfig time.
1444 *
1445 * @returns success indicator.
1446 */
1447static int usbProxySolarisReleaseInterface(PUSBPROXYDEV pProxyDev, int iIf)
1448{
1449 return true;
1450}
1451
1452
1453/**
1454 * Specify an alternate setting for the specified interface of the current configuration.
1455 *
1456 * @returns success indicator.
1457 */
1458static int usbProxySolarisSetInterface(PUSBPROXYDEV pProxyDev, int iIf, int iAlt)
1459{
1460 /*
1461 * We already open all alternate settings for all interfaces. Don't think we need to do
1462 * anything special here. As talking with the specified alternate setting would already be
1463 * possible as it's already open.
1464 */
1465 return true;
1466}
1467
1468
1469/**
1470 * Clears the halted endpoint 'EndPt'.
1471 */
1472static bool usbProxySolarisClearHaltedEp(PUSBPROXYDEV pProxyDev, unsigned int EndPt)
1473{
1474 LogFlow((USBR3PROXY ":usbProxySolarisClearHaltedEp pProxyDev=%p EndPt=%u", pProxyDev, EndPt));
1475
1476 /*
1477 * Clearing the zero control pipe doesn't make sense and isn't
1478 * supported by the USBA. Just ignore it.
1479 */
1480 if (EndPt == 0)
1481 return true;
1482
1483 int Status;
1484 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
1485
1486 VUSBSETUP Req;
1487 usbProxySolarisSetupReq(&Req, VUSB_DIR_TO_DEV | VUSB_TO_ENDPOINT, VUSB_REQ_CLEAR_FEATURE, 0, EndPt, 0);
1488
1489 usbProxySolarisCtrlReq(pDevSol->aEpFile[0], pDevSol->aEpStatFile[0], &Req, NULL, 0, &Status);
1490 if (Status == VUSBSTATUS_OK)
1491 return true;
1492
1493 LogRel((USBR3PROXY ":usbProxySolarisClearHaltedEp failed! EndPt=%u\n", EndPt));
1494 return false;
1495}
1496
1497
1498/**
1499 * Allocates a Solaris URB request structure.
1500 *
1501 * @returns Pointer to an active URB request.
1502 * @returns NULL on failure.
1503 *
1504 * @param pDevSol The solaris USB device.
1505 */
1506static PUSBPROXYURBSOL usbProxySolarisUrbAlloc(PUSBPROXYDEVSOL pDevSol)
1507{
1508 PUSBPROXYURBSOL pUrbSol;
1509
1510 RTCritSectEnter(&pDevSol->CritSect);
1511
1512 /*
1513 * Try remove a Solaris URB from the free list, if none there allocate a new one.
1514 */
1515 pUrbSol = pDevSol->pFreeHead;
1516 if (pUrbSol)
1517 pDevSol->pFreeHead = pUrbSol->pNext;
1518 else
1519 {
1520 RTCritSectLeave(&pDevSol->CritSect);
1521 pUrbSol = (PUSBPROXYURBSOL)RTMemAllocZ(sizeof(*pUrbSol));
1522 if (!pUrbSol)
1523 return NULL;
1524
1525 pUrbSol->Status.pUrbSol = pUrbSol;
1526
1527 RTCritSectEnter(&pDevSol->CritSect);
1528 }
1529 pUrbSol->pVUsbUrb = NULL;
1530 pUrbSol->pDevSol = pDevSol;
1531
1532 /*
1533 * Link it into the active list
1534 */
1535 pUrbSol->pPrev = NULL;
1536 pUrbSol->pNext = pDevSol->pInFlightHead;
1537 if (pUrbSol->pNext)
1538 pUrbSol->pNext->pPrev = pUrbSol;
1539 pDevSol->pInFlightHead = pUrbSol;
1540
1541 RTCritSectLeave(&pDevSol->CritSect);
1542 return pUrbSol;
1543}
1544
1545
1546#ifdef VBOX_WITH_SOLARIS_USB_ISOC
1547/**
1548 * Allocates an isochronous buffer.
1549 *
1550 * @returns VBox status code.
1551 * @param pUrbSol Pointer to the solaris URB associated with the transfer.
1552 */
1553static int usbProxySolarisUrbAllocIsocBuf(PUSBPROXYURBSOL pUrbSol)
1554{
1555 AssertReturn(pUrbSol, VERR_INVALID_POINTER);
1556
1557 LogFlow((USBR3PROXY ":usbProxySolarisUrbAllocIsocBuf pUrbSol=%p\n", pUrbSol));
1558
1559 PVUSBURB pUrb = pUrbSol->pVUsbUrb;
1560 bool fOut = (pUrb->enmDir == VUSBDIRECTION_OUT);
1561 uint32_t cIsocPkts = pUrb->cIsocPkts;
1562 size_t cbIsocPkt = pUrb->aIsocPkts[0].cb; /* I hope this is okay. */
1563 size_t cbBufOut = sizeof(int) + sizeof(ugen_isoc_pkt_descr_t) * cIsocPkts;
1564 size_t cbBufIn = cbBufOut - sizeof(int);
1565 cbBufOut += cbIsocPkt * cIsocPkts;
1566 caddr_t pBuf = (caddr_t)RTMemAlloc(fOut ? cbBufOut : cbBufIn);
1567 if (pBuf)
1568 {
1569 ugen_isoc_req_head_t *pIsocReq = (ugen_isoc_req_head_t *)pBuf;
1570 ugen_isoc_pkt_descr_t *pIsocPkt = (ugen_isoc_pkt_descr_t *)pIsocReq->req_isoc_pkt_descrs;
1571
1572 pIsocReq->req_isoc_pkts_count = cIsocPkts;
1573 for (ushort_t i = 0; i < cIsocPkts; i++)
1574 {
1575 pIsocPkt[i].dsc_isoc_pkt_len = pUrb->aIsocPkts[i].cb;
1576 pIsocPkt[i].dsc_isoc_pkt_actual_len = 0;
1577 pIsocPkt[i].dsc_isoc_pkt_status = 0;
1578 }
1579
1580 /*
1581 * Copy the isoc. Out buffers.
1582 */
1583 if (fOut)
1584 {
1585 caddr_t pPayload = pBuf + sizeof(int) + sizeof(*pIsocPkt) * cIsocPkts;
1586 memcpy(pPayload, pUrb->abData, pUrb->cbData);
1587 }
1588
1589 /*
1590 * Associate the buffer with the solaris URB to free it later as
1591 * we perform async. transfers.
1592 */
1593 pUrbSol->pIsocBufOut = pBuf;
1594 pUrbSol->cbIsocBufOut = cbBufOut;
1595 if (fOut)
1596 {
1597 pUrbSol->pIsocBufIn = NULL;
1598 pUrbSol->cbIsocBufIn = 0;
1599 }
1600 else
1601 {
1602 /*
1603 * Allocate space for read buffer. While perform isoc. IN request we will make
1604 * use of both the pvIsocIn and pvIsocOut buffers (see usbProxySolarisIsocReqAsync).
1605 */
1606 caddr_t pBufIn = (caddr_t)RTMemAlloc(cbBufIn);
1607 if (pBufIn)
1608 {
1609 pUrbSol->pIsocBufIn = pBufIn;
1610 pUrbSol->cbIsocBufIn = cbBufIn;
1611 }
1612 else
1613 {
1614 RTMemFree(pUrbSol->pIsocBufOut);
1615 return VERR_NO_MEMORY;
1616 }
1617 }
1618
1619 LogFlow((USBR3PROXY ":usbProxySolarisUrbAllocIsocBuf success! cbBufIn=%ld cbBufOut=%ld\n", cbBufIn, cbBufOut));
1620 return VINF_SUCCESS;
1621 }
1622 return VERR_NO_MEMORY;
1623}
1624#endif
1625
1626
1627/**
1628 * Frees a Solaris URB request structure.
1629 *
1630 * @param pDevSol The Solaris USB device.
1631 * @param pUrbSol The Solaris URB to free.
1632 */
1633static void usbProxySolarisUrbFree(PUSBPROXYDEVSOL pDevSol, PUSBPROXYURBSOL pUrbSol)
1634{
1635 RTCritSectEnter(&pDevSol->CritSect);
1636
1637 /*
1638 * Remove from the active or taxing list.
1639 */
1640 if (pUrbSol->pNext)
1641 pUrbSol->pNext->pPrev = pUrbSol->pPrev;
1642 else if (pDevSol->pTaxingTail == pUrbSol)
1643 pDevSol->pTaxingTail = pUrbSol->pPrev;
1644
1645 if (pUrbSol->pPrev)
1646 pUrbSol->pPrev->pNext = pUrbSol->pNext;
1647 else if (pDevSol->pTaxingHead == pUrbSol)
1648 pDevSol->pTaxingHead = pUrbSol->pNext;
1649 else if (pDevSol->pInFlightHead == pUrbSol)
1650 pDevSol->pInFlightHead = pUrbSol->pNext;
1651 else
1652 AssertFailed();
1653
1654 /*
1655 * Link it into the free list.
1656 */
1657 pUrbSol->pPrev = NULL;
1658 pUrbSol->pNext = pDevSol->pFreeHead;
1659 pDevSol->pFreeHead = pUrbSol;
1660
1661 pUrbSol->pVUsbUrb = NULL;
1662 pUrbSol->pDevSol = NULL;
1663
1664 RTCritSectLeave(&pDevSol->CritSect);
1665}
1666
1667
1668/**
1669 * @copydoc USBPROXYBACK::pfnUrbQueue
1670 */
1671static int usbProxySolarisUrbQueue(PVUSBURB pUrb)
1672{
1673 PUSBPROXYDEV pProxyDev = PDMINS_2_DATA(pUrb->pUsbIns, PUSBPROXYDEV);
1674 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
1675
1676 LogFlow((USBR3PROXY ":usbProxySolarisUrbQueue pUrb=%p pProxyDev=%p pDevSol=%p EndPt=%#x cbData=%d\n", pUrb, pProxyDev, pDevSol,
1677 pUrb->EndPt, pUrb->cbData));
1678
1679 /*
1680 * Allocate a solaris urb.
1681 */
1682 PUSBPROXYURBSOL pUrbSol = usbProxySolarisUrbAlloc(pDevSol);
1683 if (!pUrbSol)
1684 return false;
1685
1686 pUrbSol->u64SubmitTS = RTTimeMilliTS();
1687 pUrbSol->pVUsbUrb = pUrb;
1688 pUrbSol->pDevSol = pDevSol;
1689 PVUSBSETUP pSetup = (PVUSBSETUP)&pUrb->abData[0];
1690
1691 uint8_t EndPt = pUrb->EndPt;
1692 if (pUrb->EndPt)
1693 EndPt = pUrb->EndPt | (pUrb->enmDir == VUSBDIRECTION_IN ? 0x80 : 0);
1694
1695 int EndPtIndex = (EndPt & USBSOL_EPADDR_NUM_MASK) + ((EndPt & USBSOL_EPADDR_DIR_MASK) ? USBSOL_MAXENDPOINTS / 2 : 0);
1696 if (EndPtIndex < 0 || EndPtIndex > USBSOL_MAXENDPOINTS - 1)
1697 {
1698 LogRel((USBR3PROXY ":usbProxySolarisUrbQueue invalid endpoint address=%#x!\n", pUrb->EndPt));
1699 return VERR_INVALID_HANDLE;
1700 }
1701
1702 Log((USBR3PROXY ":usbProxySolarisUrbQueue EndPoint=%#x EndPtIndex=%d XferType=%d Direction=%s\n", pUrb->EndPt, EndPtIndex, pUrb->enmType,
1703 pUrb->enmDir == VUSBDIRECTION_IN ? "read" : "write"));
1704
1705 /*
1706 * Open the endpoint.
1707 */
1708 int irc = VERR_GENERAL_FAILURE;
1709 int rc = usbProxySolarisOpenEndPoint(pDevSol, EndPt, pUrb->enmType);
1710 if (RT_SUCCESS(rc))
1711 {
1712 /*
1713 * Perform the transfer.
1714 */
1715 switch (pUrb->enmType)
1716 {
1717 case VUSBXFERTYPE_MSG:
1718 {
1719 AssertMsgBreak(pUrb->cbData >= sizeof(VUSBSETUP), ("cbData=%d\n", pUrb->cbData));
1720 if (EndPtIndex == 0)
1721 {
1722 irc = usbProxySolarisCtrlReqAsync(pDevSol->aEpFile[EndPtIndex], pSetup, (caddr_t)(pSetup + 1), pSetup->wLength,
1723 &pUrbSol->Status);
1724 }
1725 else
1726 {
1727 irc = usbProxySolarisSendReqAsync(pDevSol->aEpFile[EndPtIndex], pSetup, (caddr_t)(pSetup + 1), pSetup->wLength,
1728 &pUrbSol->Status);
1729 }
1730 break;
1731 }
1732
1733 case VUSBXFERTYPE_INTR:
1734 case VUSBXFERTYPE_BULK:
1735 {
1736 AssertMsgBreak(pUrb->enmDir == VUSBDIRECTION_IN || pUrb->enmDir == VUSBDIRECTION_OUT, ("invalid enmDir=%d\n", pUrb->enmDir));
1737 irc = usbProxySolarisIOAsync(pDevSol->aEpFile[EndPtIndex], (caddr_t)(pUrb->abData), pUrb->cbData,
1738 pUrb->enmDir == VUSBDIRECTION_IN ? RTFILE_O_READ : RTFILE_O_WRITE, &pUrbSol->Status);
1739 Log((USBR3PROXY ":usbProxySolarisUrbQueue enmType=%d\n", pUrb->enmType));
1740 break;
1741 }
1742
1743#ifdef VBOX_WITH_SOLARIS_USB_ISOC
1744 case VUSBXFERTYPE_ISOC:
1745 {
1746 /*
1747 * Allocate the isoc buffer and submit the request.
1748 */
1749 irc = usbProxySolarisUrbAllocIsocBuf(pUrbSol);
1750 if (RT_SUCCESS(irc))
1751 irc = usbProxySolarisIsocReqAsync(pDevSol->aEpFile[EndPtIndex], pUrbSol, &pUrbSol->Status);
1752 break;
1753 }
1754#endif
1755
1756 default:
1757 {
1758 AssertMsgFailed(("%s: enmType=%#x\n", pUrb->pszDesc, pUrb->enmType));
1759 break;
1760 }
1761 }
1762 }
1763 if ( RT_SUCCESS(rc)
1764 && RT_SUCCESS(irc))
1765 {
1766 LogFlow((USBR3PROXY ":successfully queued USB %p Endpoint=%d EndPtIndex=%d enmType=%d cbData=%d\n", pUrb, pUrb->EndPt, EndPtIndex,
1767 pUrb->enmType, pUrb->cbData));
1768 pUrb->Dev.pvPrivate = pUrbSol;
1769 return true;
1770 }
1771
1772 usbProxySolarisUrbFree(pDevSol, pUrbSol);
1773 LogRel((USBR3PROXY ":failed to transfer URB %p Endpoint=%d enmType=%d cbData=%d\n", pUrb, pUrb->EndPt, pUrb->enmType, pUrb->cbData));
1774 return false;
1775}
1776
1777
1778/**
1779 * Cancels the URB.
1780 * The URB requires reaping, so we don't change its state.
1781 */
1782static void usbProxySolarisUrbCancel(PVUSBURB pUrb)
1783{
1784 PUSBPROXYURBSOL pUrbSol = (PUSBPROXYURBSOL)pUrb->Dev.pvPrivate;
1785
1786 LogFlow((USBR3PROXY ":usbProxySolarisUrbCancel pUrb=%p pUrbSol=%p pDevSol=%p", pUrb, pUrbSol, pUrbSol->pDevSol));
1787
1788 int rc = aiocancel(&pUrbSol->Status.Result);
1789 Log((USBR3PROXY ":usbProxySolarisUrbCancel aiocancel returned to %d.\n", rc));
1790 NOREF(rc);
1791}
1792
1793
1794/**
1795 * Reap URBs in-flight on a device.
1796 *
1797 * @returns Pointer to a completed URB.
1798 * @returns NULL if no URB was completed.
1799 * @param pProxyDev The device.
1800 * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all.
1801 */
1802static PVUSBURB usbProxySolarisUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies)
1803{
1804 LogFlow((USBR3PROXY ":usbProxySolarisUrbReap pProxyDev=%p cMillies=%u\n", pProxyDev, cMillies));
1805
1806 /*
1807 * Deque URBs inflight or those landed.
1808 */
1809 PUSBPROXYDEVSOL pDevSol = (PUSBPROXYDEVSOL)pProxyDev->Backend.pv;
1810 if ( pDevSol->pInFlightHead
1811 || pDevSol->pTaxingHead)
1812 {
1813 struct timeval *pTimeout = NULL;
1814 if (cMillies > 0)
1815 {
1816 struct timeval Timeout;
1817 Timeout.tv_sec = cMillies >= 1000 ? cMillies / 1000L : 0;
1818 Timeout.tv_usec = cMillies >= 1000 ? cMillies % 1000L : cMillies;
1819 pTimeout = &Timeout;
1820 }
1821 usbProxySolarisUrbComplete(pTimeout);
1822 }
1823
1824 /*
1825 * Any URBs pending delivery?
1826 */
1827 PVUSBURB pUrb = NULL;
1828 while ( pDevSol->pTaxingHead
1829 && !pUrb)
1830 {
1831 RTCritSectEnter(&pDevSol->CritSect);
1832
1833 PUSBPROXYURBSOL pUrbSol = pDevSol->pTaxingHead;
1834 if (pUrbSol)
1835 {
1836 pUrb = pUrbSol->pVUsbUrb;
1837 if (pUrb)
1838 {
1839 pUrb->Dev.pvPrivate = NULL;
1840 usbProxySolarisUrbFree(pDevSol, pUrbSol);
1841 }
1842 }
1843 RTCritSectLeave(&pDevSol->CritSect);
1844 }
1845
1846 if (pUrb)
1847 Log(("%s: usbProxySolarisUrbReap: pProxyDev=%s returns %p enmStatus=%d\n", pUrb->pszDesc, pProxyDev->pUsbIns->pszName, pUrb, pUrb->enmStatus));
1848 return pUrb;
1849}
1850
1851/**
1852 * The Solaris USB Proxy Backend.
1853 */
1854extern const USBPROXYBACK g_USBProxyDeviceHost =
1855{
1856 "host",
1857 usbProxySolarisOpen,
1858 usbProxySolarisInit,
1859 usbProxySolarisClose,
1860 usbProxySolarisReset,
1861 usbProxySolarisSetConfig,
1862 usbProxySolarisClaimInterface,
1863 usbProxySolarisReleaseInterface,
1864 usbProxySolarisSetInterface,
1865 usbProxySolarisClearHaltedEp,
1866 usbProxySolarisUrbQueue,
1867 usbProxySolarisUrbCancel,
1868 usbProxySolarisUrbReap,
1869 NULL
1870};
1871
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