VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxUSB/solaris/VBoxUSB-solaris.c@ 31896

最後變更 在這個檔案從31896是 31896,由 vboxsync 提交於 14 年 前

export the VBoxUSB host driver to OSE

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 139.8 KB
 
1/* $Id: VBoxUSB-solaris.c 31896 2010-08-24 09:17:44Z vboxsync $ */
2/** @file
3 * VirtualBox USB Client Driver, Solaris Hosts.
4 */
5
6/*
7 * Copyright (C) 2008 Oracle Corporation
8 *
9 * Oracle Corporation confidential
10 * All rights reserved
11 */
12
13/*******************************************************************************
14* Header Files *
15*******************************************************************************/
16#include <VBox/version.h>
17#include <VBox/log.h>
18#include <VBox/err.h>
19#include <VBox/cdefs.h>
20#include <VBox/sup.h>
21#include <VBox/usblib-solaris.h>
22
23#include <iprt/assert.h>
24#include <iprt/initterm.h>
25#include <iprt/semaphore.h>
26#include <iprt/mem.h>
27#include <iprt/process.h>
28#include <iprt/string.h>
29#include <iprt/path.h>
30#include <iprt/thread.h>
31
32#define USBDRV_MAJOR_VER 2
33#define USBDRV_MINOR_VER 0
34#include <sys/usb/usba.h>
35#include <sys/strsun.h>
36#include "usbai_private.h"
37#include <sys/archsystm.h>
38#include <sys/disp.h>
39
40
41/*******************************************************************************
42* Defined Constants And Macros *
43*******************************************************************************/
44/** The module name. */
45#define DEVICE_NAME "vboxusb"
46/** The module description as seen in 'modinfo'. */
47#define DEVICE_DESC_DRV "VirtualBox USB"
48
49/** Endpoint states */
50#define VBOXUSB_EP_INITIALIZED 0xa1fa1fa
51#define VBOXUSB_EP_STATE_NONE RT_BIT(0)
52#define VBOXUSB_EP_STATE_CLOSED RT_BIT(1)
53#define VBOXUSB_EP_STATE_OPENED RT_BIT(2)
54/** Polling states */
55#define VBOXUSB_POLL_OFF RT_BIT(0)
56#define VBOXUSB_POLL_ON RT_BIT(1)
57#define VBOXUSB_POLL_REAP_PENDING RT_BIT(2)
58#define VBOXUSB_POLL_DEV_UNPLUGGED RT_BIT(3)
59
60/** -=-=-=-=-=-=- Standard Specifics -=-=-=-=-=-=- */
61/** Max. supported endpoints */
62#define VBOXUSB_MAX_ENDPOINTS 32
63/** Size of USB Ctrl Xfer Header */
64#define VBOXUSB_CTRL_XFER_SIZE 0x08
65/**
66 * USB2.0 (Sec. 9-13) Bits 10..0 is the max packet size; for high speed Isoc/Intr, bits 12..11 is
67 * number of additional transaction opportunities per microframe.
68 */
69#define VBOXUSB_PKT_SIZE(pkt) (pkt & 0x07FF) * (1 + ((pkt >> 11) & 3))
70/** Endpoint Xfer Type */
71#define VBOXUSB_XFER_TYPE(endp) ((endp)->EpDesc.bmAttributes & USB_EP_ATTR_MASK)
72/** Endpoint Xfer Direction */
73#define VBOXUSB_XFER_DIR(endp) ((endp)->EpDesc.bEndpointAddress & USB_EP_DIR_IN)
74
75/** -=-=-=-=-=-=- Tunable Parameters -=-=-=-=-=-=- */
76/** Time to wait while draining inflight UBRs on suspend, in seconds. */
77#define VBOXUSB_DRAIN_TIME 30
78/** Ctrl Xfer timeout in seconds. */
79#define VBOXUSB_CTRL_XFER_TIMEOUT 10
80/** Bulk Xfer timeout in seconds. */
81#define VBOXUSB_BULK_XFER_TIMEOUT 10
82/** Intr Xfer timeout in seconds. */
83#define VBOXUSB_INTR_XFER_TIMEOUT 10
84/** Maximum URB queue length. */
85#define VBOXUSB_URB_QUEUE_SIZE 64
86/** Maximum asynchronous requests per pipe */
87#define VBOXUSB_MAX_PIPE_ASYNC_REQS 2
88
89#if defined(DEBUG_ramshankar)
90# undef Log
91# define Log LogRel
92# undef LogFlow
93# define LogFlow LogRel
94# undef LogFlowFunc
95# define LogFlowFunc LogRel
96#endif
97
98/** For enabling global symbols while debugging **/
99#if defined(DEBUG_ramshankar)
100# define LOCAL
101#else
102# define LOCAL static
103#endif
104
105
106/*******************************************************************************
107* Kernel Entry Hook *
108*******************************************************************************/
109int VBoxUSBSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
110int VBoxUSBSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
111int VBoxUSBSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
112int VBoxUSBSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
113int VBoxUSBSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal);
114int VBoxUSBSolarisPoll(dev_t Dev, short fEvents, int fAnyYet, short *pReqEvents, struct pollhead **ppPollHead);
115int VBoxUSBSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
116int VBoxUSBSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
117int VBoxUSBSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
118int VBoxUSBSolarisPower(dev_info_t *pDip, int Component, int Level);
119
120
121/*******************************************************************************
122* Structures and Typedefs *
123*******************************************************************************/
124/**
125 * cb_ops: for drivers that support char/block entry points
126 */
127static struct cb_ops g_VBoxUSBSolarisCbOps =
128{
129 VBoxUSBSolarisOpen,
130 VBoxUSBSolarisClose,
131 nodev, /* b strategy */
132 nodev, /* b dump */
133 nodev, /* b print */
134 VBoxUSBSolarisRead,
135 VBoxUSBSolarisWrite,
136 VBoxUSBSolarisIOCtl,
137 nodev, /* c devmap */
138 nodev, /* c mmap */
139 nodev, /* c segmap */
140 VBoxUSBSolarisPoll,
141 ddi_prop_op, /* property ops */
142 NULL, /* streamtab */
143 D_NEW | D_MP, /* compat. flag */
144 CB_REV, /* revision */
145 nodev, /* c aread */
146 nodev /* c awrite */
147};
148
149/**
150 * dev_ops: for driver device operations
151 */
152static struct dev_ops g_VBoxUSBSolarisDevOps =
153{
154 DEVO_REV, /* driver build revision */
155 0, /* ref count */
156 VBoxUSBSolarisGetInfo,
157 nulldev, /* identify */
158 nulldev, /* probe */
159 VBoxUSBSolarisAttach,
160 VBoxUSBSolarisDetach,
161 nodev, /* reset */
162 &g_VBoxUSBSolarisCbOps,
163 NULL, /* bus ops */
164 VBoxUSBSolarisPower,
165 ddi_quiesce_not_needed
166};
167
168/**
169 * modldrv: export driver specifics to the kernel
170 */
171static struct modldrv g_VBoxUSBSolarisModule =
172{
173 &mod_driverops, /* extern from kernel */
174 DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
175 &g_VBoxUSBSolarisDevOps
176};
177
178/**
179 * modlinkage: export install/remove/info to the kernel
180 */
181static struct modlinkage g_VBoxUSBSolarisModLinkage =
182{
183 MODREV_1,
184 &g_VBoxUSBSolarisModule,
185 NULL,
186};
187
188/**
189 * vboxusb_ep_t: Endpoint structure with info. for managing an endpoint.
190 */
191typedef struct vboxusb_ep_t
192{
193 uint_t fInitialized; /* Whether this Endpoint is initialized */
194 uint_t EpState; /* Endpoint state */
195 usb_ep_descr_t EpDesc; /* Endpoint descriptor */
196 uchar_t uCfgValue; /* Configuration value */
197 uchar_t uInterface; /* Interface number */
198 uchar_t uAlt; /* Alternate number */
199 usb_pipe_handle_t pPipe; /* Endpoint pipe handle */
200 usb_pipe_policy_t PipePolicy; /* Endpoint policy */
201 bool fIsocPolling; /* Whether Isoc. IN polling is enabled */
202 list_t hIsocInUrbs; /* Isoc. IN inflight URBs */
203 uint16_t cIsocInUrbs; /* Number of Isoc. IN inflight URBs */
204 list_t hIsocInLandedReqs; /* Isoc. IN landed requests */
205 uint16_t cbIsocInLandedReqs; /* Cummulative size of landed Isoc. IN requests */
206 size_t cbMaxIsocData; /* Maximum size of Isoc. IN landed buffer */
207} vboxusb_ep_t;
208
209/**
210 * vboxusb_isoc_req_t: Isoc IN. requests queued from device till they are reaped.
211 */
212typedef struct vboxusb_isoc_req_t
213{
214 mblk_t *pMsg; /* Pointer to the data buffer */
215 uint32_t cIsocPkts; /* Number of Isoc pkts */
216 VUSBISOC_PKT_DESC aIsocPkts[8]; /* Array of Isoc pkt descriptors */
217 list_node_t hListLink;
218} vboxusb_isoc_req_t;
219
220/**
221 * VBOXUSB_URB_STATE: Internal USB URB state.
222 */
223typedef enum VBOXUSB_URB_STATE
224{
225 VBOXUSB_URB_STATE_FREE = 0x00,
226 VBOXUSB_URB_STATE_INFLIGHT = 0x04,
227 VBOXUSB_URB_STATE_LANDED = 0x08
228} VBOXUSB_URB_STATE;
229
230/**
231 * vboxusb_urb_t: kernel URB representation.
232 */
233typedef struct vboxusb_urb_t
234{
235 void *pvUrbR3; /* Userspace URB address (untouched, returned while reaping) */
236 uint8_t bEndpoint; /* Endpoint address */
237 VUSBXFERTYPE enmType; /* Xfer type */
238 VUSBDIRECTION enmDir; /* Xfer direction */
239 VUSBSTATUS enmStatus; /* URB status */
240 RTR3PTR pvDataR3; /* Userspace address of the original data buffer */
241 size_t cbDataR3; /* Size of the data buffer */
242 mblk_t *pMsg; /* Pointer to the data buffer */
243 uint32_t cIsocPkts; /* Number of Isoc pkts */
244 VUSBISOC_PKT_DESC aIsocPkts[8]; /* Array of Isoc pkt descriptors */
245 VBOXUSB_URB_STATE enmState; /* Whether free/in-flight etc. */
246 struct vboxusb_state_t *pState; /* Pointer to the device instance */
247 list_node_t hListLink; /* List node link handle */
248} vboxusb_urb_t;
249
250/**
251 * vboxusb_power_t: Per Device Power Management info.
252 */
253typedef struct vboxusb_power_t
254{
255 uint_t PowerStates; /* Bit mask of the power states */
256 int PowerBusy; /* Busy counter */
257 bool fPowerWakeup; /* Whether remote power wakeup is enabled */
258 bool fPowerRaise; /* Whether to raise the power level */
259 uint8_t PowerLevel; /* Current power level */
260} vboxusb_power_t;
261
262/**
263 * vboxusb_state_t: Per Device instance state info.
264 */
265typedef struct vboxusb_state_t
266{
267 dev_info_t *pDip; /* Per instance device info. */
268 usb_client_dev_data_t *pDevDesc; /* Parsed & complete device descriptor */
269 uint8_t DevState; /* Current USB Device state */
270 bool fClosed; /* Whether the device (default control pipe) is closed */
271 bool fRestoreCfg; /* Whether we changed configs to restore while tearing down */
272 bool fGetCfgReqDone; /* First GET_CONFIG request has been circumvented */
273 kmutex_t Mtx; /* Mutex state protection */
274 usb_serialization_t StateMulti; /* State serialization */
275 size_t cbMaxBulkXfer; /* Maximum bulk xfer size */
276 vboxusb_ep_t aEps[VBOXUSB_MAX_ENDPOINTS]; /* All endpoints structures */
277 list_t hUrbs; /* Handle to list of free/inflight URBs */
278 list_t hLandedUrbs; /* Handle to list of landed URBs */
279 uint16_t cInflightUrbs; /* Number of inflight URBs. */
280 pollhead_t PollHead; /* Handle to pollhead for waking polling processes */
281 int fPoll; /* Polling status flag */
282 RTPROCESS Process; /* The process (id) of the session */
283 VBOXUSBREQ_CLIENT_INFO ClientInfo; /* Registeration data */
284 vboxusb_power_t *pPower; /* Power Management */
285} vboxusb_state_t;
286
287
288/*******************************************************************************
289* Internal Functions *
290*******************************************************************************/
291LOCAL int vboxUSBSolarisInitEndPoint(vboxusb_state_t *pState, usb_ep_data_t *pEpData, uchar_t uCfgValue,
292 uchar_t uInterface, uchar_t uAlt);
293LOCAL int vboxUSBSolarisInitAllEndPoints(vboxusb_state_t *pState);
294LOCAL int vboxUSBSolarisInitEndPointsForConfig(vboxusb_state_t *pState, uint8_t uCfgIndex);
295LOCAL int vboxUSBSolarisInitEndPointsForInterfaceAlt(vboxusb_state_t *pState, uint8_t uInterface, uint8_t uAlt);
296LOCAL void vboxUSBSolarisDestroyAllEndPoints(vboxusb_state_t *pState);
297LOCAL void vboxUSBSolarisDestroyEndPoint(vboxusb_state_t *pState, vboxusb_ep_t *pEp);
298LOCAL void vboxUSBSolarisCloseAllPipes(vboxusb_state_t *pState, bool fControlPipe);
299LOCAL void vboxUSBSolarisCloseInterface(vboxusb_state_t *pState, uint8_t bInterface);
300LOCAL int vboxUSBSolarisOpenPipe(vboxusb_state_t *pState, vboxusb_ep_t *pEp);
301LOCAL void vboxUSBSolarisClosePipe(vboxusb_state_t *pState, vboxusb_ep_t *pEp);
302LOCAL int vboxUSBSolarisCtrlXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *pUrb);
303LOCAL void vboxUSBSolarisCtrlXferCompleted(usb_pipe_handle_t pPipe, usb_ctrl_req_t *pReq);
304LOCAL int vboxUSBSolarisBulkXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *purb);
305LOCAL void vboxUSBSolarisBulkXferCompleted(usb_pipe_handle_t pPipe, usb_bulk_req_t *pReq);
306LOCAL int vboxUSBSolarisIntrXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *pUrb);
307LOCAL void vboxUSBSolarisIntrXferCompleted(usb_pipe_handle_t pPipe, usb_intr_req_t *pReq);
308LOCAL int vboxUSBSolarisIsocXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *pUrb);
309LOCAL void vboxUSBSolarisIsocInXferCompleted(usb_pipe_handle_t pPipe, usb_isoc_req_t *pReq);
310LOCAL void vboxUSBSolarisIsocInXferError(usb_pipe_handle_t pPipe, usb_isoc_req_t *pReq);
311LOCAL void vboxUSBSolarisIsocOutXferCompleted(usb_pipe_handle_t pPipe, usb_isoc_req_t *pReq);
312LOCAL vboxusb_urb_t *vboxUSBSolarisGetIsocInURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq);
313LOCAL vboxusb_urb_t *vboxUSBSolarisQueueURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq, mblk_t *pMsg);
314LOCAL inline void vboxUSBSolarisConcatMsg(vboxusb_urb_t *pUrb);
315LOCAL inline void vboxUSBSolarisDeQueueURB(vboxusb_urb_t *pUrb, int URBStatus);
316LOCAL inline void vboxUSBSolarisNotifyComplete(vboxusb_state_t *pState);
317LOCAL int vboxUSBSolarisProcessIOCtl(int iFunction, void *pvState, int Mode, PVBOXUSBREQ pUSBReq, void *pvBuf, size_t *pcbDataOut);
318LOCAL bool vboxUSBSolarisIsUSBDevice(dev_info_t *pDip);
319
320/** Device Operation Hooks */
321LOCAL int vboxUSBSolarisSendURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq, int Mode);
322LOCAL int vboxUSBSolarisReapURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq, int Mode);
323LOCAL int vboxUSBSolarisClearEndPoint(vboxusb_state_t *pState, uint8_t bEndpoint);
324LOCAL int vboxUSBSolarisSetConfig(vboxusb_state_t *pState, uint8_t bCfgValue);
325LOCAL int vboxUSBSolarisGetConfig(vboxusb_state_t *pState, uint8_t *pCfgValue);
326LOCAL int vboxUSBSolarisSetInterface(vboxusb_state_t *pState, uint8_t uInterface, uint8_t uAlt);
327LOCAL int vboxUSBSolarisCloseDevice(vboxusb_state_t *pState, VBOXUSB_RESET_LEVEL enmReset);
328LOCAL int vboxUSBSolarisAbortPipe(vboxusb_state_t *pState, uint8_t bEndpoint);
329LOCAL bool vboxUSBSolarisIsAnyPipeOpen(vboxusb_state_t *pState);
330LOCAL int vboxUSBSolarisGetConfigIndex(vboxusb_state_t *pState, uint_t uCfgValue);
331
332/** Hotplug & Power Management Hooks */
333LOCAL inline void vboxUSBSolarisNotifyHotplug(vboxusb_state_t *pState);
334LOCAL int vboxUSBSolarisDeviceDisconnected(dev_info_t *pDip);
335LOCAL int vboxUSBSolarisDeviceReconnected(dev_info_t *pDip);
336
337LOCAL int vboxUSBSolarisInitPower(vboxusb_state_t *pState);
338LOCAL void vboxUSBSolarisDestroyPower(vboxusb_state_t *pState);
339LOCAL int vboxUSBSolarisDeviceSuspend(vboxusb_state_t *pState);
340LOCAL void vboxUSBSolarisDeviceResume(vboxusb_state_t *pState);
341LOCAL void vboxUSBSolarisDeviceRestore(vboxusb_state_t *pState);
342LOCAL void vboxUSBSolarisPowerBusy(vboxusb_state_t *pState);
343LOCAL void vboxUSBSolarisPowerIdle(vboxusb_state_t *pState);
344
345/** Monitor Hooks */
346int VBoxUSBMonSolarisRegisterClient(dev_info_t *pClientDip, PVBOXUSB_CLIENT_INFO pClientInfo);
347int VBoxUSBMonSolarisUnregisterClient(dev_info_t *pClientDip);
348
349
350/*******************************************************************************
351* Global Variables *
352*******************************************************************************/
353/** Global list of all device instances. */
354static void *g_pVBoxUSBSolarisState;
355
356/** The default endpoint descriptor */
357static usb_ep_descr_t g_VBoxUSBSolarisDefaultEpDesc = {7, 5, 0, USB_EP_ATTR_CONTROL, 8, 0};
358
359/** Hotplug events */
360static usb_event_t g_VBoxUSBSolarisEvents =
361{
362 vboxUSBSolarisDeviceDisconnected,
363 vboxUSBSolarisDeviceReconnected,
364 NULL, /* presuspend */
365 NULL /* postresume */
366};
367
368
369/**
370 * Kernel entry points
371 */
372int _init(void)
373{
374 LogFlowFunc((DEVICE_NAME ":_init\n"));
375
376 /*
377 * Prevent module autounloading.
378 */
379 modctl_t *pModCtl = mod_getctl(&g_VBoxUSBSolarisModLinkage);
380 if (pModCtl)
381 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
382 else
383 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
384
385 /*
386 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
387 */
388 int rc = RTR0Init(0);
389 if (RT_SUCCESS(rc))
390 {
391 rc = ddi_soft_state_init(&g_pVBoxUSBSolarisState, sizeof(vboxusb_state_t), 4 /* pre-alloc */);
392 if (!rc)
393 {
394 rc = mod_install(&g_VBoxUSBSolarisModLinkage);
395 if (!rc)
396 return rc;
397
398 LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
399 ddi_soft_state_fini(&g_pVBoxUSBSolarisState);
400 }
401 else
402 LogRel((DEVICE_NAME ":failed to initialize soft state.\n"));
403
404 RTR0Term();
405 }
406 else
407 LogRel((DEVICE_NAME ":RTR0Init failed! rc=%d\n", rc));
408 return RTErrConvertToErrno(rc);
409}
410
411
412int _fini(void)
413{
414 int rc;
415
416 LogFlowFunc((DEVICE_NAME ":_fini\n"));
417
418 rc = mod_remove(&g_VBoxUSBSolarisModLinkage);
419 if (!rc)
420 {
421 ddi_soft_state_fini(&g_pVBoxUSBSolarisState);
422 RTR0Term();
423 }
424
425 return rc;
426}
427
428
429int _info(struct modinfo *pModInfo)
430{
431 LogFlowFunc((DEVICE_NAME ":_info\n"));
432
433 return mod_info(&g_VBoxUSBSolarisModLinkage, pModInfo);
434}
435
436
437/**
438 * Attach entry point, to attach a device to the system or resume it.
439 *
440 * @param pDip The module structure instance.
441 * @param enmCmd Attach type (ddi_attach_cmd_t)
442 *
443 * @returns corresponding solaris error code.
444 */
445int VBoxUSBSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
446{
447 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
448
449 int rc;
450 int instance = ddi_get_instance(pDip);
451 vboxusb_state_t *pState = NULL;
452
453 switch (enmCmd)
454 {
455 case DDI_ATTACH:
456 {
457 rc = ddi_soft_state_zalloc(g_pVBoxUSBSolarisState, instance);
458 if (rc == DDI_SUCCESS)
459 {
460 pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
461 if (pState)
462 {
463 pState->pDip = pDip;
464 pState->pDevDesc = NULL;
465 pState->fClosed = false;
466 pState->fRestoreCfg = false;
467 pState->fGetCfgReqDone = false;
468 bzero(pState->aEps, sizeof(pState->aEps));
469 list_create(&pState->hUrbs, sizeof(vboxusb_urb_t), offsetof(vboxusb_urb_t, hListLink));
470 list_create(&pState->hLandedUrbs, sizeof(vboxusb_urb_t), offsetof(vboxusb_urb_t, hListLink));
471 pState->cInflightUrbs = 0;
472 pState->fPoll = VBOXUSB_POLL_OFF;
473 pState->Process = NIL_RTPROCESS;
474 pState->pPower = NULL;
475
476 /*
477 * There is a bug in usb_client_attach() as of Nevada 120 which panics when we bind to
478 * a non-USB device. So check if we are really binding to a USB device or not.
479 */
480 if (vboxUSBSolarisIsUSBDevice(pState->pDip))
481 {
482 /*
483 * Here starts the USB specifics.
484 */
485 rc = usb_client_attach(pState->pDip, USBDRV_VERSION, 0);
486 if (rc == USB_SUCCESS)
487 {
488 /*
489 * Parse out the entire descriptor.
490 */
491 rc = usb_get_dev_data(pState->pDip, &pState->pDevDesc, USB_PARSE_LVL_ALL, 0 /* Unused */);
492 if (rc == USB_SUCCESS)
493 {
494#ifdef DEBUG_ramshankar
495 usb_print_descr_tree(pState->pDip, pState->pDevDesc);
496#endif
497
498 /*
499 * Initialize state locks.
500 */
501 mutex_init(&pState->Mtx, NULL, MUTEX_DRIVER, pState->pDevDesc->dev_iblock_cookie);
502 pState->StateMulti = usb_init_serialization(pState->pDip, USB_INIT_SER_CHECK_SAME_THREAD);
503
504 /*
505 * Get maximum bulk transfer size supported by the HCD.
506 */
507 rc = usb_pipe_get_max_bulk_transfer_size(pState->pDip, &pState->cbMaxBulkXfer);
508 if (rc == USB_SUCCESS)
509 {
510 LogFlow((DEVICE_NAME ":VBoxUSBSolarisAttach cbMaxBulkXfer=%d\n", pState->cbMaxBulkXfer));
511
512 /*
513 * Initialize all endpoints.
514 */
515 rc = vboxUSBSolarisInitAllEndPoints(pState);
516 if (RT_SUCCESS(rc))
517 {
518 /*
519 * Set the device state.
520 */
521 pState->DevState = USB_DEV_ONLINE;
522
523 /*
524 * Initialize power management for the device.
525 */
526 rc = vboxUSBSolarisInitPower(pState);
527 if (RT_SUCCESS(rc))
528 {
529 /*
530 * Update endpoints (descriptors) for the current config.
531 */
532 vboxUSBSolarisInitEndPointsForConfig(pState, usb_get_current_cfgidx(pState->pDip));
533
534 /*
535 * Publish the minor node.
536 */
537 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0,
538 "none", "none", 0666);
539 if (RT_LIKELY(rc == DDI_SUCCESS))
540 {
541 /*
542 * Register hotplug callbacks.
543 */
544 rc = usb_register_event_cbs(pState->pDip, &g_VBoxUSBSolarisEvents, 0 /* flags */);
545 if (RT_LIKELY(rc == USB_SUCCESS))
546 {
547 /*
548 * Register with our monitor driver.
549 */
550 bzero(&pState->ClientInfo, sizeof(pState->ClientInfo));
551 char szDevicePath[MAXPATHLEN];
552 ddi_pathname(pState->pDip, szDevicePath);
553 RTStrPrintf(pState->ClientInfo.achClientPath, sizeof(pState->ClientInfo.achClientPath),
554 "/devices%s:%s",
555 szDevicePath,
556 DEVICE_NAME);
557 RTPathStripFilename(szDevicePath);
558 RTStrPrintf(pState->ClientInfo.achDeviceIdent, sizeof(pState->ClientInfo.achDeviceIdent),
559 "%#x:%#x:%d:%s",
560 pState->pDevDesc->dev_descr->idVendor,
561 pState->pDevDesc->dev_descr->idProduct,
562 pState->pDevDesc->dev_descr->bcdDevice,
563 szDevicePath);
564 pState->ClientInfo.Instance = instance;
565 rc = VBoxUSBMonSolarisRegisterClient(pState->pDip, &pState->ClientInfo);
566 if (RT_SUCCESS(rc))
567 return DDI_SUCCESS;
568 else
569 {
570 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisRegisterClient failed! rc=%d path=%s instance=%d\n",
571 rc, pState->ClientInfo.achClientPath, instance));
572 }
573
574 usb_unregister_event_cbs(pState->pDip, &g_VBoxUSBSolarisEvents);
575 }
576 else
577 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach failed to register hotplug callbacks! rc=%d\n", rc));
578
579 ddi_remove_minor_node(pState->pDip, NULL);
580 }
581 else
582 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach ddi_create_minor_node failed! rc=%d\n", rc));
583 }
584 else
585 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach failed to initialize power management! rc=%d\n", rc));
586 }
587 else
588 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach vboxUSBSolarisInitAllEndPoints failed! rc=%d\n"));
589 }
590 else
591 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach usb_pipe_get_max_bulk_transfer_size failed! rc=%d\n", rc));
592
593 usb_fini_serialization(pState->StateMulti);
594 mutex_destroy(&pState->Mtx);
595 usb_free_dev_data(pState->pDip, pState->pDevDesc);
596 }
597 else
598 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach failed to get device descriptor. rc=%d\n", rc));
599
600 usb_client_detach(pState->pDip, NULL);
601 }
602 else
603 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach usb_client_attach failed! rc=%d\n", rc));
604 }
605 else
606 LogFlow((DEVICE_NAME ":VBoxUSBSolarisAttach not a USB device.\n")); /* This would appear on every boot if it were Rel */
607 }
608 else
609 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach failed to get soft state\n", sizeof(*pState)));
610
611 ddi_soft_state_free(g_pVBoxUSBSolarisState, instance);
612 }
613 else
614 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach failed to alloc soft state. rc=%d\n", rc));
615
616 return DDI_FAILURE;
617 }
618
619 case DDI_RESUME:
620 {
621 pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
622 if (RT_UNLIKELY(!pState))
623 {
624 LogRel((DEVICE_NAME ":VBoxUSBSolarisAttach DDI_RESUME: failed to get soft state on detach.\n"));
625 return DDI_FAILURE;
626 }
627
628 vboxUSBSolarisDeviceResume(pState);
629 return DDI_SUCCESS;
630 }
631
632 default:
633 return DDI_FAILURE;
634 }
635}
636
637
638/**
639 * Detach entry point, to detach a device to the system or suspend it.
640 *
641 * @param pDip The module structure instance.
642 * @param enmCmd Attach type (ddi_attach_cmd_t)
643 *
644 * @returns corresponding solaris error code.
645 */
646int VBoxUSBSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
647{
648 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
649
650 int instance = ddi_get_instance(pDip);
651 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
652 if (RT_UNLIKELY(!pState))
653 {
654 LogRel((DEVICE_NAME ":VBoxUSBSolarisDetach failed to get soft state on detach.\n"));
655 return DDI_FAILURE;
656 }
657
658 switch (enmCmd)
659 {
660 case DDI_DETACH:
661 {
662 /*
663 * At this point it must be assumed that the default control pipe has
664 * already been closed by userland (via VBoxUSBSolarisClose() entry point).
665 * Once it's closed we can no longer open or reference the device here.
666 */
667
668 /*
669 * Notify userland if any that we're gone (while resetting device held by us).
670 */
671 vboxUSBSolarisNotifyHotplug(pState);
672
673 /*
674 * Unregister hotplug callback events first without holding the mutex as the callbacks
675 * would otherwise block on the mutex.
676 */
677 usb_unregister_event_cbs(pDip, &g_VBoxUSBSolarisEvents);
678
679
680 /*
681 * Serialize: paranoid; drain other driver activity.
682 */
683 usb_serialize_access(pState->StateMulti, USB_WAIT, 0);
684 usb_release_access(pState->StateMulti);
685 mutex_enter(&pState->Mtx);
686
687 /*
688 * Close all endpoints.
689 */
690 vboxUSBSolarisCloseAllPipes(pState, true /* ControlPipe */);
691
692 /*
693 * Deinitialize power, destroy endpoints.
694 */
695 vboxUSBSolarisDestroyPower(pState);
696 vboxUSBSolarisDestroyAllEndPoints(pState);
697
698 /*
699 * Free up all URBs.
700 */
701 vboxusb_urb_t *pUrb = NULL;
702 while ((pUrb = list_remove_head(&pState->hUrbs)) != NULL)
703 {
704 if (pUrb->pMsg)
705 freemsg(pUrb->pMsg);
706 RTMemFree(pUrb);
707 }
708
709 while ((pUrb = list_remove_head(&pState->hLandedUrbs)) != NULL)
710 {
711 if (pUrb->pMsg)
712 freemsg(pUrb->pMsg);
713 RTMemFree(pUrb);
714 }
715 pState->cInflightUrbs = 0;
716 list_destroy(&pState->hUrbs);
717 list_destroy(&pState->hLandedUrbs);
718
719 /*
720 * Destroy locks, free up descriptor and detach from USBA.
721 */
722 mutex_exit(&pState->Mtx);
723 usb_fini_serialization(pState->StateMulti);
724 mutex_destroy(&pState->Mtx);
725
726 usb_free_dev_data(pState->pDip, pState->pDevDesc);
727 usb_client_detach(pState->pDip, NULL);
728
729 /*
730 * Deregister with our Monitor driver.
731 */
732 VBoxUSBMonSolarisUnregisterClient(pState->pDip);
733
734 ddi_remove_minor_node(pState->pDip, NULL);
735
736 ddi_soft_state_free(g_pVBoxUSBSolarisState, instance);
737 pState = NULL;
738
739 return DDI_SUCCESS;
740 }
741
742 case DDI_SUSPEND:
743 {
744 int rc = vboxUSBSolarisDeviceSuspend(pState);
745 if (RT_SUCCESS(rc))
746 return DDI_SUCCESS;
747
748 return DDI_FAILURE;
749 }
750
751 default:
752 return DDI_FAILURE;
753 }
754}
755
756
757/**
758 * Info entry point, called by solaris kernel for obtaining driver info.
759 *
760 * @param pDip The module structure instance (do not use).
761 * @param enmCmd Information request type.
762 * @param pvArg Type specific argument.
763 * @param ppvResult Where to store the requested info.
764 *
765 * @returns corresponding solaris error code.
766 */
767int VBoxUSBSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
768{
769 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisGetInfo\n"));
770
771 vboxusb_state_t *pState = NULL;
772 int instance = getminor((dev_t)pvArg);
773
774 switch (enmCmd)
775 {
776 case DDI_INFO_DEVT2DEVINFO:
777 {
778 /*
779 * One is to one mapping of instance & minor number as we publish only one minor node per device.
780 */
781 pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
782 if (pState)
783 {
784 *ppvResult = (void *)pState->pDip;
785 return DDI_SUCCESS;
786 }
787 else
788 LogRel((DEVICE_NAME ":VBoxUSBSolarisGetInfo failed to get device state.\n"));
789 return DDI_FAILURE;
790 }
791
792 case DDI_INFO_DEVT2INSTANCE:
793 {
794 *ppvResult = (void *)(uintptr_t)instance;
795 return DDI_SUCCESS;
796 }
797
798 default:
799 return DDI_FAILURE;
800 }
801}
802
803
804int VBoxUSBSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
805{
806 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisOpen pDev=%p fFlag=%d fType=%d pCred=%p\n", pDev, fFlag, fType, pCred));
807
808 /*
809 * Verify we are being opened as a character device
810 */
811 if (fType != OTYP_CHR)
812 return EINVAL;
813
814 /*
815 * One is to one mapping. (Minor<=>Instance).
816 */
817 int instance = getminor((dev_t)*pDev);
818 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
819 if (!pState)
820 {
821 LogRel((DEVICE_NAME ":VBoxUSBSolarisOpen failed to get device state for instance %d\n", instance));
822 return ENXIO;
823 }
824
825 /*
826 * Only one user process can open a device instance at a time.
827 */
828 if (pState->Process != NIL_RTPROCESS)
829 {
830 LogRel((DEVICE_NAME ":VBoxUSBSolarisOpen a process is already using this device instance.\n"));
831 return EBUSY;
832 }
833
834 pState->Process = RTProcSelf();
835 pState->fPoll = VBOXUSB_POLL_ON;
836
837 NOREF(fFlag);
838 NOREF(pCred);
839
840 return 0;
841}
842
843
844int VBoxUSBSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred)
845{
846 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisClose Dev=%d fFlag=%d fType=%d pCred=%p\n", Dev, fFlag, fType, pCred));
847
848 int instance = getminor((dev_t)Dev);
849 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
850 if (RT_UNLIKELY(!pState))
851 {
852 LogRel((DEVICE_NAME ":VBoxUSBSolarisClose failed to get device state for instance %d\n", instance));
853 return ENXIO;
854 }
855
856 mutex_enter(&pState->Mtx);
857 pState->fPoll = VBOXUSB_POLL_OFF;
858 pState->Process = NIL_RTPROCESS;
859 mutex_exit(&pState->Mtx);
860
861 return 0;
862}
863
864
865int VBoxUSBSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
866{
867 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisRead\n"));
868 return ENOTSUP;
869}
870
871
872int VBoxUSBSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
873{
874 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisWrite\n"));
875 return ENOTSUP;
876}
877
878
879int VBoxUSBSolarisPoll(dev_t Dev, short fEvents, int fAnyYet, short *pReqEvents, struct pollhead **ppPollHead)
880{
881 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisPoll Dev=%d fEvents=%d fAnyYet=%d pReqEvents=%p\n", Dev, fEvents, fAnyYet, pReqEvents));
882
883 /*
884 * Get the device state (one to one mapping).
885 */
886 int instance = getminor((dev_t)Dev);
887 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
888 if (RT_UNLIKELY(!pState))
889 {
890 LogRel((DEVICE_NAME ":VBoxUSBSolarisPoll: no state data for %d\n", instance));
891 return ENXIO;
892 }
893
894 mutex_enter(&pState->Mtx);
895
896 /*
897 * "fEvents" HAS to be POLLIN. We won't bother to test it. The caller
898 * must always requests input events. Disconnect event (POLLHUP) is invalid in "fEvents".
899 */
900 fEvents = 0;
901 if (pState->fPoll & VBOXUSB_POLL_DEV_UNPLUGGED)
902 {
903 fEvents |= POLLHUP;
904 pState->fPoll &= ~VBOXUSB_POLL_DEV_UNPLUGGED;
905 }
906
907 if (pState->fPoll & VBOXUSB_POLL_REAP_PENDING)
908 {
909 fEvents |= POLLIN;
910 pState->fPoll &= ~VBOXUSB_POLL_REAP_PENDING;
911 }
912
913 if ( !fEvents
914 && !fAnyYet)
915 {
916 *ppPollHead = &pState->PollHead;
917 }
918
919 *pReqEvents = fEvents;
920
921 mutex_exit(&pState->Mtx);
922
923 return 0;
924}
925
926
927int VBoxUSBSolarisPower(dev_info_t *pDip, int Component, int Level)
928{
929 LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisPower pDip=%p Component=%d Level=%d\n", pDip, Component, Level));
930
931 int instance = ddi_get_instance(pDip);
932 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
933 if (RT_UNLIKELY(!pState))
934 {
935 LogRel((DEVICE_NAME ":VBoxUSBSolarisPower Failed! missing state.\n"));
936 return DDI_FAILURE;
937 }
938
939 if (!pState->pPower)
940 return DDI_SUCCESS;
941
942 usb_serialize_access(pState->StateMulti, USB_WAIT, 0);
943 mutex_enter(&pState->Mtx);
944
945 int rc = USB_FAILURE;
946 if (pState->DevState == USB_DEV_ONLINE)
947 {
948 /*
949 * Check if we are transitioning to a valid power state.
950 */
951 if (!USB_DEV_PWRSTATE_OK(pState->pPower->PowerStates, Level))
952 {
953 switch (Level)
954 {
955 case USB_DEV_OS_PWR_OFF:
956 {
957 if (pState->pPower->PowerBusy)
958 break;
959
960 /*
961 * USB D3 command.
962 */
963 pState->pPower->PowerLevel = USB_DEV_OS_PWR_OFF;
964 mutex_exit(&pState->Mtx);
965 rc = usb_set_device_pwrlvl3(pDip);
966 mutex_enter(&pState->Mtx);
967 break;
968 }
969
970 case USB_DEV_OS_FULL_PWR:
971 {
972 /*
973 * Can happen during shutdown of the OS.
974 */
975 pState->pPower->PowerLevel = USB_DEV_OS_FULL_PWR;
976 mutex_exit(&pState->Mtx);
977 rc = usb_set_device_pwrlvl0(pDip);
978 mutex_enter(&pState->Mtx);
979 break;
980 }
981
982 default: /* Power levels 1, 2 not implemented */
983 break;
984 }
985 }
986 else
987 LogFlow((DEVICE_NAME ":USB_DEV_PWRSTATE_OK failed.\n"));
988 }
989 else
990 rc = USB_SUCCESS;
991
992 mutex_exit(&pState->Mtx);
993 usb_release_access(pState->StateMulti);
994 return rc == USB_SUCCESS ? DDI_SUCCESS : DDI_FAILURE;
995}
996
997
998/** @def IOCPARM_LEN
999 * Gets the length from the ioctl number.
1000 * This is normally defined by sys/ioccom.h on BSD systems...
1001 */
1002#ifndef IOCPARM_LEN
1003# define IOCPARM_LEN(Code) (((Code) >> 16) & IOCPARM_MASK)
1004#endif
1005
1006int VBoxUSBSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
1007{
1008/* LogFlowFunc((DEVICE_NAME ":VBoxUSBSolarisIOCtl Dev=%d Cmd=%d pArg=%p Mode=%d\n", Dev, Cmd, pArg)); */
1009
1010 /*
1011 * Get the device state (one to one mapping).
1012 */
1013 int instance = getminor((dev_t)Dev);
1014 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
1015 if (RT_UNLIKELY(!pState))
1016 {
1017 LogRel((DEVICE_NAME ":VBoxUSBSolarisIOCtl: no state data for %d\n", instance));
1018 return EINVAL;
1019 }
1020
1021 /*
1022 * Read the request wrapper.
1023 */
1024 VBOXUSBREQ ReqWrap;
1025 if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
1026 {
1027 LogRel((DEVICE_NAME ": VBoxUSBSolarisIOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
1028 return ENOTTY;
1029 }
1030
1031 int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
1032 if (RT_UNLIKELY(rc))
1033 {
1034 LogRel((DEVICE_NAME ": VBoxUSBSolarisIOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%d.\n", pArg, Cmd, rc));
1035 return EINVAL;
1036 }
1037
1038 if (ReqWrap.u32Magic != VBOXUSB_MAGIC)
1039 {
1040 LogRel((DEVICE_NAME ": VBoxUSBSolarisIOCtl: bad magic %#x; pArg=%p Cmd=%d.\n", ReqWrap.u32Magic, pArg, Cmd));
1041 return EINVAL;
1042 }
1043 if (RT_UNLIKELY( ReqWrap.cbData == 0
1044 || ReqWrap.cbData > _1M*16))
1045 {
1046 LogRel((DEVICE_NAME ": VBoxUSBSolarisIOCtl: bad size %#x; pArg=%p Cmd=%d.\n", ReqWrap.cbData, pArg, Cmd));
1047 return EINVAL;
1048 }
1049
1050 /*
1051 * Read the request.
1052 */
1053 void *pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
1054 if (RT_UNLIKELY(!pvBuf))
1055 {
1056 LogRel((DEVICE_NAME ":VBoxUSBSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
1057 return ENOMEM;
1058 }
1059
1060 rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
1061 if (RT_UNLIKELY(rc))
1062 {
1063 RTMemTmpFree(pvBuf);
1064 LogRel((DEVICE_NAME ":VBoxUSBSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
1065 return EFAULT;
1066 }
1067 if (RT_UNLIKELY( ReqWrap.cbData == 0
1068 || pvBuf == NULL))
1069 {
1070 RTMemTmpFree(pvBuf);
1071 LogRel((DEVICE_NAME ":VBoxUSBSolarisIOCtl: invalid request pvBuf=%p cbData=%d\n", pvBuf, ReqWrap.cbData));
1072 return EINVAL;
1073 }
1074
1075 /*
1076 * Process the IOCtl.
1077 */
1078 size_t cbDataOut;
1079 rc = vboxUSBSolarisProcessIOCtl(Cmd, pState, Mode, &ReqWrap, pvBuf, &cbDataOut);
1080 ReqWrap.rc = rc;
1081 rc = 0;
1082
1083 if (RT_UNLIKELY(cbDataOut > ReqWrap.cbData))
1084 {
1085 LogRel((DEVICE_NAME ":VBoxUSBSolarisIOCtl: too much output data %d expected %d Truncating!\n", cbDataOut, ReqWrap.cbData));
1086 cbDataOut = ReqWrap.cbData;
1087 }
1088
1089 ReqWrap.cbData = cbDataOut;
1090
1091 /*
1092 * Copy VBOXUSBREQ back to userspace (which contains rc for USB operation).
1093 */
1094 rc = ddi_copyout(&ReqWrap, (void *)pArg, sizeof(ReqWrap), Mode);
1095 if (RT_LIKELY(!rc))
1096 {
1097 /*
1098 * Copy payload (if any) back to userspace.
1099 */
1100 if (cbDataOut > 0)
1101 {
1102 rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataOut, Mode);
1103 if (RT_UNLIKELY(rc))
1104 {
1105 LogRel((DEVICE_NAME ":VBoxUSBSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
1106 rc = EFAULT;
1107 }
1108 }
1109 }
1110 else
1111 {
1112 LogRel((DEVICE_NAME ":VBoxUSBSolarisIOCtl: ddi_copyout(1)failed; pReqWrap=%p pArg=%p Cmd=%d. rc=%d\n", &ReqWrap, pArg, Cmd, rc));
1113 rc = EFAULT;
1114 }
1115
1116 *pVal = rc;
1117 RTMemTmpFree(pvBuf);
1118 return rc;
1119}
1120
1121
1122/**
1123 * IOCtl processor for user to kernel and kernel to kernel communcation.
1124 *
1125 * @returns VBox status code.
1126 *
1127 * @param iFunction The requested function.
1128 * @param pvState The USB device instance.
1129 * @param Mode The IOCtl mode.
1130 * @param pUSBReq Pointer to the VBOXUSB request.
1131 * @param pvBuf Pointer to the ring-3 URB.
1132 * @param pcbDataOut Where to store the IOCtl OUT data size.
1133 */
1134LOCAL int vboxUSBSolarisProcessIOCtl(int iFunction, void *pvState, int Mode, PVBOXUSBREQ pUSBReq, void *pvBuf, size_t *pcbDataOut)
1135{
1136// LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl iFunction=%d pvState=%p pUSBReq=%p\n", iFunction, pvState, pUSBReq));
1137
1138 AssertPtrReturn(pvState, VERR_INVALID_PARAMETER);
1139 vboxusb_state_t *pState = (vboxusb_state_t *)pvState;
1140 size_t cbData = pUSBReq->cbData;
1141 int rc;
1142
1143#define CHECKRET_MIN_SIZE(mnemonic, cbMin) \
1144 do { \
1145 if (cbData < (cbMin)) \
1146 { \
1147 LogRel((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: " mnemonic ": cbData=%#zx (%zu) min is %#zx (%zu)\n", \
1148 cbData, cbData, (size_t)(cbMin), (size_t)(cbMin))); \
1149 return VERR_BUFFER_OVERFLOW; \
1150 } \
1151 if ((cbMin) != 0 && !VALID_PTR(pvBuf)) \
1152 { \
1153 LogRel((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: " mnemonic ": Invalid pointer %p\n", pvBuf)); \
1154 return VERR_INVALID_PARAMETER; \
1155 } \
1156 } while (0)
1157
1158 switch (iFunction)
1159 {
1160 case VBOXUSB_IOCTL_SEND_URB:
1161 {
1162 CHECKRET_MIN_SIZE("SEND_URB", sizeof(VBOXUSBREQ_URB));
1163
1164 PVBOXUSBREQ_URB pUrbReq = (PVBOXUSBREQ_URB)pvBuf;
1165 rc = vboxUSBSolarisSendURB(pState, pUrbReq, Mode);
1166 *pcbDataOut = 0;
1167 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: SEND_URB returned %d\n", rc));
1168 break;
1169 }
1170
1171 case VBOXUSB_IOCTL_REAP_URB:
1172 {
1173 CHECKRET_MIN_SIZE("REAP_URB", sizeof(VBOXUSBREQ_URB));
1174
1175 PVBOXUSBREQ_URB pUrbReq = (PVBOXUSBREQ_URB)pvBuf;
1176 rc = vboxUSBSolarisReapURB(pState, pUrbReq, Mode);
1177 *pcbDataOut = sizeof(VBOXUSBREQ_URB);
1178 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: REAP_URB returned %d\n", rc));
1179 break;
1180 }
1181
1182 case VBOXUSB_IOCTL_CLEAR_EP:
1183 {
1184 CHECKRET_MIN_SIZE("CLEAR_EP", sizeof(VBOXUSBREQ_CLEAR_EP));
1185
1186 PVBOXUSBREQ_CLEAR_EP pClearEpReq = (PVBOXUSBREQ_CLEAR_EP)pvBuf;
1187 rc = vboxUSBSolarisClearEndPoint(pState, pClearEpReq->bEndpoint);
1188 *pcbDataOut = 0;
1189 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: CLEAR_EP returned %d\n", rc));
1190 break;
1191 }
1192
1193 case VBOXUSB_IOCTL_SET_CONFIG:
1194 {
1195 CHECKRET_MIN_SIZE("SET_CONFIG", sizeof(VBOXUSBREQ_SET_CONFIG));
1196
1197 PVBOXUSBREQ_SET_CONFIG pSetCfgReq = (PVBOXUSBREQ_SET_CONFIG)pvBuf;
1198 rc = vboxUSBSolarisSetConfig(pState, pSetCfgReq->bConfigValue);
1199 *pcbDataOut = 0;
1200 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: SET_CONFIG returned %d\n", rc));
1201 break;
1202 }
1203
1204 case VBOXUSB_IOCTL_SET_INTERFACE:
1205 {
1206 CHECKRET_MIN_SIZE("SET_INTERFACE", sizeof(VBOXUSBREQ_SET_INTERFACE));
1207
1208 PVBOXUSBREQ_SET_INTERFACE pSetInterfaceReq = (PVBOXUSBREQ_SET_INTERFACE)pvBuf;
1209 rc = vboxUSBSolarisSetInterface(pState, pSetInterfaceReq->bInterface, pSetInterfaceReq->bAlternate);
1210 *pcbDataOut = 0;
1211 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: SET_INTERFACE returned %d\n", rc));
1212 break;
1213 }
1214
1215 case VBOXUSB_IOCTL_CLOSE_DEVICE:
1216 {
1217 CHECKRET_MIN_SIZE("CLOSE_DEVICE", sizeof(VBOXUSBREQ_CLOSE_DEVICE));
1218
1219 PVBOXUSBREQ_CLOSE_DEVICE pCloseDeviceReq = (PVBOXUSBREQ_CLOSE_DEVICE)pvBuf;
1220 rc = vboxUSBSolarisCloseDevice(pState, pCloseDeviceReq->ResetLevel);
1221 *pcbDataOut = 0;
1222 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: CLOSE_DEVICE returned %d\n", rc));
1223 break;
1224 }
1225
1226 case VBOXUSB_IOCTL_ABORT_PIPE:
1227 {
1228 CHECKRET_MIN_SIZE("ABORT_PIPE", sizeof(VBOXUSBREQ_ABORT_PIPE));
1229
1230 PVBOXUSBREQ_ABORT_PIPE pAbortPipeReq = (PVBOXUSBREQ_ABORT_PIPE)pvBuf;
1231 rc = vboxUSBSolarisAbortPipe(pState, pAbortPipeReq->bEndpoint);
1232 *pcbDataOut = 0;
1233 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: ABORT_PIPE returned %d\n", rc));
1234 break;
1235 }
1236
1237 case VBOXUSB_IOCTL_GET_CONFIG:
1238 {
1239 CHECKRET_MIN_SIZE("GET_CONFIG", sizeof(VBOXUSBREQ_GET_CONFIG));
1240
1241 PVBOXUSBREQ_GET_CONFIG pGetCfgReq = (PVBOXUSBREQ_GET_CONFIG)pvBuf;
1242 rc = vboxUSBSolarisGetConfig(pState, &pGetCfgReq->bConfigValue);
1243 *pcbDataOut = sizeof(VBOXUSBREQ_GET_CONFIG);
1244 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: GET_CONFIG returned %d\n", rc));
1245 break;
1246 }
1247
1248 case VBOXUSB_IOCTL_GET_VERSION:
1249 {
1250 CHECKRET_MIN_SIZE("GET_VERSION", sizeof(VBOXUSBREQ_GET_VERSION));
1251
1252 PVBOXUSBREQ_GET_VERSION pGetVersionReq = (PVBOXUSBREQ_GET_VERSION)pvBuf;
1253 pGetVersionReq->u32Major = VBOXUSB_VERSION_MAJOR;
1254 pGetVersionReq->u32Minor = VBOXUSB_VERSION_MINOR;
1255 *pcbDataOut = sizeof(VBOXUSBREQ_GET_VERSION);
1256 rc = VINF_SUCCESS;
1257 LogFlow((DEVICE_NAME ":vboxUSBSolarisProcessIOCtl: GET_VERSION returned %d\n", rc));
1258 break;
1259 }
1260
1261 default:
1262 {
1263 LogRel((DEVICE_NAME ":solarisUSBProcessIOCtl: Unknown request %#x\n", iFunction));
1264 rc = VERR_NOT_SUPPORTED;
1265 *pcbDataOut = 0;
1266 break;
1267 }
1268 }
1269
1270 pUSBReq->cbData = *pcbDataOut;
1271 return rc;
1272}
1273
1274
1275/**
1276 * Initialize device power management functions.
1277 *
1278 * @param pState The USB device instance.
1279 *
1280 * @returns VBox status code.
1281 */
1282LOCAL int vboxUSBSolarisInitPower(vboxusb_state_t *pState)
1283{
1284 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisInitPower pState=%p\n", pState));
1285
1286 int rc = usb_handle_remote_wakeup(pState->pDip, USB_REMOTE_WAKEUP_ENABLE);
1287 if (rc == USB_SUCCESS)
1288 {
1289 vboxusb_power_t *pPower = RTMemAlloc(sizeof(vboxusb_power_t));
1290 if (RT_LIKELY(pPower))
1291 {
1292 mutex_enter(&pState->Mtx);
1293 pState->pPower = pPower;
1294 pState->pPower->fPowerWakeup = false;
1295 mutex_exit(&pState->Mtx);
1296
1297 uint_t PowerStates;
1298 rc = usb_create_pm_components(pState->pDip, &PowerStates);
1299 if (rc == USB_SUCCESS)
1300 {
1301 pState->pPower->fPowerWakeup = true;
1302 pState->pPower->PowerLevel = USB_DEV_OS_FULL_PWR;
1303 pState->pPower->PowerStates = PowerStates;
1304
1305 rc = pm_raise_power(pState->pDip, 0 /* component */, USB_DEV_OS_FULL_PWR);
1306
1307 if (rc != DDI_SUCCESS)
1308 {
1309 LogRel((DEVICE_NAME ":vboxUSBSolarisInitPower failed to raise power level usb(%#x,%#x).\n",
1310 pState->pDevDesc->dev_descr->idVendor, pState->pDevDesc->dev_descr->idProduct));
1311 }
1312 }
1313 else
1314 LogFlow((DEVICE_NAME ":vboxUSBSolarisInitPower failed to create power components.\n"));
1315
1316 return VINF_SUCCESS;
1317 }
1318 else
1319 rc = VERR_NO_MEMORY;
1320 }
1321 else
1322 {
1323 LogFlow((DEVICE_NAME ":vboxUSBSolarisInitPower failed to enable remote wakeup. No PM.\n"));
1324 rc = VINF_SUCCESS;
1325 }
1326
1327 return rc;
1328}
1329
1330
1331/**
1332 * Destroy device power management functions.
1333 *
1334 * @param pState The USB device instance.
1335 * @remarks Requires the device state mutex to be held.
1336 *
1337 * @returns VBox status code.
1338 */
1339LOCAL void vboxUSBSolarisDestroyPower(vboxusb_state_t *pState)
1340{
1341 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDestroyPower pState=%p\n", pState));
1342
1343 if (pState->pPower)
1344 {
1345 mutex_exit(&pState->Mtx);
1346 vboxUSBSolarisPowerBusy(pState);
1347 mutex_enter(&pState->Mtx);
1348
1349 int rc = -1;
1350 if ( pState->pPower->fPowerWakeup
1351 && pState->DevState != USB_DEV_DISCONNECTED)
1352 {
1353 mutex_exit(&pState->Mtx);
1354 rc = pm_raise_power(pState->pDip, 0 /* component */, USB_DEV_OS_FULL_PWR);
1355 if (rc != DDI_SUCCESS)
1356 LogFlow((DEVICE_NAME ":vboxUSBSolarisDestroyPower raising power failed! rc=%d\n", rc));
1357
1358 rc = usb_handle_remote_wakeup(pState->pDip, USB_REMOTE_WAKEUP_DISABLE);
1359 if (rc != DDI_SUCCESS)
1360 LogFlow((DEVICE_NAME ":vboxUSBSolarisDestroyPower failed to disable remote wakeup.\n"));
1361 }
1362 else
1363 mutex_exit(&pState->Mtx);
1364
1365 rc = pm_lower_power(pState->pDip, 0 /* component */, USB_DEV_OS_PWR_OFF);
1366 if (rc != DDI_SUCCESS)
1367 LogFlow((DEVICE_NAME ":vboxUSBSolarisDestroyPower lowering power failed! rc=%d\n", rc));
1368
1369 vboxUSBSolarisPowerIdle(pState);
1370 mutex_enter(&pState->Mtx);
1371 RTMemFree(pState->pPower);
1372 pState->pPower = NULL;
1373 }
1374}
1375
1376
1377/**
1378 * Convert Solaris' USBA URB status to VBox's USB URB status.
1379 *
1380 * @param Status Solaris USBA USB URB status.
1381 *
1382 * @returns VBox USB URB status.
1383 */
1384static inline VUSBSTATUS vboxUSBSolarisGetUrbStatus(usb_cr_t Status)
1385{
1386 switch (Status)
1387 {
1388 case USB_CR_OK: return VUSBSTATUS_OK;
1389 case USB_CR_CRC: return VUSBSTATUS_CRC;
1390 case USB_CR_DEV_NOT_RESP: return VUSBSTATUS_DNR;
1391 case USB_CR_DATA_UNDERRUN: return VUSBSTATUS_DATA_UNDERRUN;
1392 case USB_CR_DATA_OVERRUN: return VUSBSTATUS_DATA_OVERRUN;
1393 case USB_CR_STALL: return VUSBSTATUS_STALL;
1394 /*
1395 case USB_CR_BITSTUFFING:
1396 case USB_CR_DATA_TOGGLE_MM:
1397 case USB_CR_PID_CHECKFAILURE:
1398 case USB_CR_UNEXP_PID:
1399 case USB_CR_BUFFER_OVERRUN:
1400 case USB_CR_BUFFER_UNDERRUN:
1401 case USB_CR_TIMEOUT:
1402 case USB_CR_NOT_ACCESSED:
1403 case USB_CR_NO_RESOURCES:
1404 case USB_CR_UNSPECIFIED_ERR:
1405 case USB_CR_STOPPED_POLLING:
1406 case USB_CR_PIPE_CLOSING:
1407 case USB_CR_PIPE_RESET:
1408 case USB_CR_NOT_SUPPORTED:
1409 case USB_CR_FLUSHED:
1410 case USB_CR_HC_HARDWARE_ERR:
1411 */
1412 default: return VUSBSTATUS_INVALID;
1413 }
1414}
1415
1416
1417/**
1418 * Convert Solaris' USBA error code to VBox's error code.
1419 *
1420 * @param UsbRc Solaris USBA error code.
1421 *
1422 * @returns VBox error code.
1423 */
1424static inline int vboxUSBSolarisToVBoxRC(int UsbRc)
1425{
1426 switch (UsbRc)
1427 {
1428 case USB_SUCCESS: return VINF_SUCCESS;
1429 case USB_INVALID_ARGS: return VERR_INVALID_PARAMETER;
1430 case USB_INVALID_PIPE: return VERR_BAD_PIPE;
1431 case USB_INVALID_CONTEXT: return VERR_INVALID_CONTEXT;
1432 case USB_BUSY: return VERR_PIPE_BUSY;
1433 case USB_PIPE_ERROR: return VERR_PIPE_IO_ERROR;
1434 /*
1435 case USB_FAILURE:
1436 case USB_NO_RESOURCES:
1437 case USB_NO_BANDWIDTH:
1438 case USB_NOT_SUPPORTED:
1439 case USB_PIPE_ERROR:
1440 case USB_NO_FRAME_NUMBER:
1441 case USB_INVALID_START_FRAME:
1442 case USB_HC_HARDWARE_ERROR:
1443 case USB_INVALID_REQUEST:
1444 case USB_INVALID_VERSION:
1445 case USB_INVALID_PERM:
1446 */
1447 default: return VERR_GENERAL_FAILURE;
1448 }
1449}
1450
1451
1452/**
1453 * Convert Solaris' USBA device state to VBox's error code.
1454 *
1455 * @param UsbRc Solaris USBA error code.
1456 *
1457 * @returns VBox error code.
1458 */
1459static inline int vboxUSBSolarisDeviceState(uint8_t uDeviceState)
1460{
1461 switch (uDeviceState)
1462 {
1463 case USB_DEV_ONLINE: return VINF_SUCCESS;
1464 case USB_DEV_SUSPENDED: return VERR_VUSB_DEVICE_IS_SUSPENDED;
1465 case USB_DEV_DISCONNECTED:
1466 case USB_DEV_PWRED_DOWN: return VERR_VUSB_DEVICE_NOT_ATTACHED;
1467 default: return VERR_GENERAL_FAILURE;
1468 }
1469}
1470
1471
1472/**
1473 * Check if the device is a USB device.
1474 *
1475 * @param pDip Pointer to this device info. structure.
1476 *
1477 * @returns If this is really a USB device returns true, otherwise false.
1478 */
1479LOCAL bool vboxUSBSolarisIsUSBDevice(dev_info_t *pDip)
1480{
1481 int rc = DDI_FAILURE;
1482
1483 /*
1484 * Check device for "usb" compatible property, root hubs->device would likely mean parent has no "usb" property.
1485 */
1486 char **ppszCompatible = NULL;
1487 uint_t cCompatible;
1488 rc = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, pDip, DDI_PROP_DONTPASS, "compatible", &ppszCompatible, &cCompatible);
1489 if (RT_LIKELY(rc == DDI_PROP_SUCCESS))
1490 {
1491 while (cCompatible--)
1492 {
1493 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsUSBDevice compatible[%d]=%s\n", cCompatible, ppszCompatible[cCompatible]));
1494 if (!strncmp(ppszCompatible[cCompatible], "usb", 3))
1495 {
1496 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsUSBDevice verified device as USB. pszCompatible=%s\n", ppszCompatible[cCompatible]));
1497 ddi_prop_free(ppszCompatible);
1498 return true;
1499 }
1500 }
1501
1502 ddi_prop_free(ppszCompatible);
1503 ppszCompatible = NULL;
1504 }
1505 else
1506 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsUSBDevice USB property lookup failed. rc=%d\n", rc));
1507
1508 /*
1509 * Check parent for "usb" compatible property.
1510 */
1511 dev_info_t *pParentDip = ddi_get_parent(pDip);
1512 if (pParentDip)
1513 {
1514 rc = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, pParentDip, DDI_PROP_DONTPASS, "compatible", &ppszCompatible, &cCompatible);
1515 if (RT_LIKELY(rc == DDI_PROP_SUCCESS))
1516 {
1517 while (cCompatible--)
1518 {
1519 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsUSBDevice parent compatible[%d]=%s\n", cCompatible, ppszCompatible[cCompatible]));
1520 if (!strncmp(ppszCompatible[cCompatible], "usb", 3))
1521 {
1522 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsUSBDevice verified device as USB. parent pszCompatible=%s\n",
1523 ppszCompatible[cCompatible]));
1524 ddi_prop_free(ppszCompatible);
1525 return true;
1526 }
1527 }
1528
1529 ddi_prop_free(ppszCompatible);
1530 ppszCompatible = NULL;
1531 }
1532 else
1533 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsUSBDevice USB parent property lookup failed. rc=%d\n", rc));
1534 }
1535 else
1536 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsUSBDevice failed to obtain parent device for property lookup.\n"));
1537
1538 return false;
1539}
1540
1541
1542/**
1543 * Submit a URB.
1544 *
1545 * @param pState The USB device instance.
1546 * @param pUrb Pointer to the VBox USB URB.
1547 * @param Mode The IOCtl mode.
1548 *
1549 * @returns VBox error code.
1550 */
1551LOCAL int vboxUSBSolarisSendURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq, int Mode)
1552{
1553 uchar_t EndPtIndex = usb_get_ep_index(pUrbReq->bEndpoint);
1554 vboxusb_ep_t *pEp = &pState->aEps[EndPtIndex];
1555 AssertPtrReturn(pEp, VERR_INVALID_POINTER);
1556
1557// LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisSendUrb pState=%p pUrbReq=%p bEndpoint=%#x[%d] enmDir=%#x enmType=%#x cbData=%d pvData=%p\n",
1558// pState, pUrbReq, pUrbReq->bEndpoint, EndPtIndex, pUrbReq->enmDir, pUrbReq->enmType, pUrbReq->cbData, pUrbReq->pvData));
1559
1560 if (RT_UNLIKELY(!pUrbReq->pvData))
1561 {
1562 LogRel((DEVICE_NAME ":vboxUSBSolarisSendUrb Invalid request. No data.\n"));
1563 return VERR_INVALID_POINTER;
1564 }
1565
1566 /*
1567 * Allocate message block & copy userspace buffer for host to device Xfers and for
1568 * Control Xfers (since input has Setup header that needs copying).
1569 */
1570 mblk_t *pMsg = NULL;
1571 int rc = VINF_SUCCESS;
1572 if ( pUrbReq->enmDir == VUSBDIRECTION_OUT
1573 || pUrbReq->enmType == VUSBXFERTYPE_MSG)
1574 {
1575 pMsg = allocb(pUrbReq->cbData, BPRI_HI);
1576 if (RT_UNLIKELY(!pMsg))
1577 {
1578 LogRel((DEVICE_NAME ":vboxUSBSolarisSendUrb: failed to allocate %d bytes\n", pUrbReq->cbData));
1579 return VERR_NO_MEMORY;
1580 }
1581
1582 rc = ddi_copyin(pUrbReq->pvData, pMsg->b_wptr, pUrbReq->cbData, Mode);
1583 if (RT_UNLIKELY(rc))
1584 {
1585 LogRel((DEVICE_NAME ":vboxUSBSolarisSendUrb: ddi_copyin failed! rc=%d\n", rc));
1586 freemsg(pMsg);
1587 return VERR_NO_MEMORY;
1588 }
1589
1590 pMsg->b_wptr += pUrbReq->cbData;
1591 }
1592
1593 mutex_enter(&pState->Mtx);
1594 rc = vboxUSBSolarisDeviceState(pState->DevState);
1595
1596 if (pState->fClosed) /* Required for Isoc. IN Xfers which don't Xfer through the pipe after polling starts */
1597 rc = VERR_VUSB_DEVICE_NOT_ATTACHED;
1598
1599 if (RT_SUCCESS(rc))
1600 {
1601 /*
1602 * Open the pipe if needed.
1603 */
1604 rc = vboxUSBSolarisOpenPipe(pState, pEp);
1605 if (RT_UNLIKELY(RT_FAILURE(rc)))
1606 {
1607 mutex_exit(&pState->Mtx);
1608 freemsg(pMsg);
1609 LogRel((DEVICE_NAME ":vboxUSBSolarisSendUrb OpenPipe failed. pState=%p pUrbReq=%p bEndpoint=%#x enmDir=%#x enmType=%#x cbData=%d pvData=%p rc=%d\n",
1610 pState, pUrbReq, pUrbReq->bEndpoint, pUrbReq->enmDir, pUrbReq->enmType, pUrbReq->cbData, pUrbReq->pvData, rc));
1611 return VERR_BAD_PIPE;
1612 }
1613
1614 mutex_exit(&pState->Mtx);
1615
1616 vboxusb_urb_t *pUrb = NULL;
1617 if ( pUrbReq->enmType == VUSBXFERTYPE_ISOC
1618 && pUrbReq->enmDir == VUSBDIRECTION_IN)
1619 pUrb = vboxUSBSolarisGetIsocInURB(pState, pUrbReq);
1620 else
1621 pUrb = vboxUSBSolarisQueueURB(pState, pUrbReq, pMsg);
1622
1623 if (RT_LIKELY(pUrb))
1624 {
1625 switch (pUrb->enmType)
1626 {
1627 case VUSBXFERTYPE_MSG:
1628 {
1629 rc = vboxUSBSolarisCtrlXfer(pState, pEp, pUrb);
1630 break;
1631 }
1632
1633 case VUSBXFERTYPE_BULK:
1634 {
1635 rc = vboxUSBSolarisBulkXfer(pState, pEp, pUrb);
1636 break;
1637 }
1638
1639 case VUSBXFERTYPE_INTR:
1640 {
1641 rc = vboxUSBSolarisIntrXfer(pState, pEp, pUrb);
1642 break;
1643 }
1644
1645 case VUSBXFERTYPE_ISOC:
1646 {
1647 rc = vboxUSBSolarisIsocXfer(pState, pEp, pUrb);
1648 break;
1649 }
1650
1651 default:
1652 {
1653 rc = VERR_NOT_SUPPORTED;
1654 break;
1655 }
1656 }
1657
1658 if (RT_FAILURE(rc))
1659 {
1660 freemsg(pUrb->pMsg);
1661
1662 if ( pUrb->enmType == VUSBXFERTYPE_ISOC
1663 && pUrb->enmDir == VUSBDIRECTION_IN)
1664 {
1665 RTMemFree(pUrb);
1666 pUrb = NULL;
1667 }
1668 else
1669 {
1670 pUrb->pMsg = NULL;
1671 pUrb->enmState = VBOXUSB_URB_STATE_FREE;
1672 }
1673 }
1674 }
1675 else
1676 {
1677 LogRel((DEVICE_NAME ":vboxUSBSolarisSendUrb failed to queue URB.\n"));
1678 rc = VERR_NO_MEMORY;
1679 }
1680
1681 if ( RT_FAILURE(rc)
1682 && pUrb)
1683 {
1684 if ( pUrb->enmType != VUSBXFERTYPE_ISOC
1685 || pUrb->enmDir != VUSBDIRECTION_IN)
1686 {
1687 mutex_enter(&pState->Mtx);
1688 pState->cInflightUrbs--;
1689 mutex_exit(&pState->Mtx);
1690 }
1691 }
1692 }
1693 else
1694 {
1695 mutex_exit(&pState->Mtx);
1696 freemsg(pMsg);
1697 }
1698
1699 return rc;
1700}
1701
1702
1703/**
1704 * Reap a completed/error'd URB.
1705 *
1706 * @param pState The USB device instance.
1707 * @param pUrbReq Pointer to the VBox USB URB.
1708 * @param Mode The IOCtl mode.
1709 *
1710 * @returns VBox error code.
1711 */
1712LOCAL int vboxUSBSolarisReapURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq, int Mode)
1713{
1714// LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisReapUrb pState=%p pUrbReq=%p\n", pState, pUrbReq));
1715
1716 AssertPtrReturn(pUrbReq, VERR_INVALID_POINTER);
1717
1718 int rc = VINF_SUCCESS;
1719 mutex_enter(&pState->Mtx);
1720 rc = vboxUSBSolarisDeviceState(pState->DevState);
1721 if (pState->fClosed)
1722 rc = VERR_VUSB_DEVICE_NOT_ATTACHED;
1723 if (RT_SUCCESS(rc))
1724 {
1725 vboxusb_urb_t *pUrb = list_remove_head(&pState->hLandedUrbs);
1726 mutex_exit(&pState->Mtx);
1727 if (pUrb)
1728 {
1729 /*
1730 * Copy the URB which will then be copied to user-space.
1731 */
1732 pUrbReq->pvUrbR3 = pUrb->pvUrbR3;
1733 pUrbReq->bEndpoint = pUrb->bEndpoint;
1734 pUrbReq->enmType = pUrb->enmType;
1735 pUrbReq->enmDir = pUrb->enmDir;
1736 pUrbReq->enmStatus = pUrb->enmStatus;
1737
1738 if (RT_LIKELY(pUrb->pMsg))
1739 {
1740 /*
1741 * Chain copy the message back into the user buffer.
1742 */
1743 if (RT_LIKELY(pUrb->pvDataR3 != NIL_RTR3PTR))
1744 {
1745 size_t cbData = RT_MIN(msgdsize(pUrb->pMsg), pUrb->cbDataR3);
1746 pUrbReq->cbData = cbData;
1747 pUrbReq->pvData = (void *)pUrb->pvDataR3;
1748
1749 /*
1750 * Paranoia: we should have a single message block almost always.
1751 */
1752 if (RT_LIKELY(!pUrb->pMsg->b_cont && cbData > 0))
1753 {
1754 rc = ddi_copyout(pUrb->pMsg->b_rptr, (void *)pUrbReq->pvData, cbData, Mode);
1755 if (RT_UNLIKELY(rc != 0))
1756 {
1757 LogRel((DEVICE_NAME ":vboxUSBSolarisReapUrb ddi_copyout failed! rc=%d\n", rc));
1758 pUrbReq->enmStatus = VUSBSTATUS_INVALID;
1759 }
1760 }
1761 else
1762 {
1763 RTR3PTR pvDataR3 = pUrb->pvDataR3;
1764 mblk_t *pMsg = pUrb->pMsg;
1765 while (pMsg)
1766 {
1767 size_t cbMsg = MBLKL(pMsg);
1768 if (cbMsg > 0)
1769 {
1770 rc = ddi_copyout(pMsg->b_rptr, (void *)pvDataR3, cbMsg, Mode);
1771 if (RT_UNLIKELY(rc != 0))
1772 {
1773 LogRel((DEVICE_NAME ":vboxUSBSolarisReapUrb ddi_copyout (2) failed! rc=%d\n", rc));
1774 pUrbReq->enmStatus = VUSBSTATUS_INVALID;
1775 break;
1776 }
1777 }
1778
1779 pMsg = pMsg->b_cont;
1780 pvDataR3 += cbMsg;
1781 if ((pvDataR3 - pUrb->pvDataR3) >= cbData)
1782 break;
1783 }
1784 }
1785
1786 LogFlow((DEVICE_NAME ":vboxUSBSolarisReapUrb pvUrbR3=%p pvDataR3=%p cbData=%d\n", pUrbReq->pvUrbR3, pUrbReq->pvData, pUrbReq->cbData));
1787 }
1788 else
1789 {
1790 pUrbReq->cbData = 0;
1791 rc = VERR_INVALID_POINTER;
1792 LogFlow((DEVICE_NAME ":vboxUSBSolarisReapUrb missing pvDataR3!!\n"));
1793 }
1794
1795 /*
1796 * Free buffer allocated in VBOXUSB_IOCTL_SEND_URB.
1797 */
1798 freemsg(pUrb->pMsg);
1799 pUrb->pMsg = NULL;
1800 }
1801 else
1802 {
1803 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
1804 {
1805 if (pUrb->enmDir == VUSBDIRECTION_OUT)
1806 pUrbReq->cbData = pUrb->cbDataR3;
1807 else
1808 {
1809 pUrbReq->enmStatus = VUSBSTATUS_INVALID;
1810 pUrbReq->cbData = 0;
1811 }
1812 }
1813 else
1814 {
1815 LogFlow((DEVICE_NAME ":vboxUSBSolarisReapUrb missing message.\n"));
1816 pUrbReq->cbData = 0;
1817 }
1818 }
1819
1820 /*
1821 * Copy Isoc packet descriptors.
1822 */
1823 if (pUrb->enmType == VUSBXFERTYPE_ISOC)
1824 {
1825 AssertCompile(sizeof(pUrbReq->aIsocPkts) == sizeof(pUrb->aIsocPkts));
1826 pUrbReq->cIsocPkts = pUrb->cIsocPkts;
1827#if 0
1828 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
1829 {
1830 pUrbReq->aIsocPkts[i].cbPkt = pUrb->aIsocPkts[i].cbPkt;
1831 pUrbReq->aIsocPkts[i].cbActPkt = pUrb->aIsocPkts[i].cbActPkt;
1832 pUrbReq->aIsocPkts[i].enmStatus = pUrb->aIsocPkts[i].enmStatus;
1833 }
1834#else
1835 bcopy(pUrb->aIsocPkts, pUrbReq->aIsocPkts, pUrb->cIsocPkts * sizeof(VUSBISOC_PKT_DESC));
1836#endif
1837
1838 if (pUrb->enmDir == VUSBDIRECTION_IN)
1839 {
1840 RTMemFree(pUrb);
1841 pUrb = NULL;
1842 }
1843 }
1844
1845 if (pUrb)
1846 {
1847 /*
1848 * Add URB back to the head of the free/inflight list.
1849 */
1850 pUrb->cbDataR3 = 0;
1851 pUrb->pvDataR3 = NIL_RTR3PTR;
1852 pUrb->enmState = VBOXUSB_URB_STATE_FREE;
1853 mutex_enter(&pState->Mtx);
1854 list_insert_head(&pState->hUrbs, pUrb);
1855 mutex_exit(&pState->Mtx);
1856 }
1857 }
1858 else
1859 pUrbReq->pvUrbR3 = NULL;
1860 }
1861 else
1862 mutex_exit(&pState->Mtx);
1863
1864 LogFlow((DEVICE_NAME ":vboxUSBSolarisReapUrb returns %d\n", rc));
1865 return rc;
1866}
1867
1868
1869/**
1870 * Clear a pipe (CLEAR_FEATURE).
1871 *
1872 * @param pState The USB device instance.
1873 * @param bEndpoint The Endpoint address.
1874 *
1875 * @returns VBox error code.
1876 */
1877LOCAL int vboxUSBSolarisClearEndPoint(vboxusb_state_t *pState, uint8_t bEndpoint)
1878{
1879 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisClearEndPoint pState=%p bEndpoint=%#x\n", pState, bEndpoint));
1880
1881 /*
1882 * Serialize access: single threaded per Endpoint, one request at a time.
1883 */
1884 mutex_enter(&pState->Mtx);
1885 int rc = vboxUSBSolarisDeviceState(pState->DevState);
1886 if (RT_SUCCESS(rc))
1887 {
1888 uchar_t EndPtIndex = usb_get_ep_index(bEndpoint);
1889 vboxusb_ep_t *pEp = &pState->aEps[EndPtIndex];
1890 if (RT_LIKELY(pEp))
1891 {
1892 /*
1893 * Check if the endpoint is open to be cleared.
1894 */
1895 if (pEp->pPipe)
1896 {
1897 mutex_exit(&pState->Mtx);
1898#if 0
1899 /*
1900 * Asynchronous clear pipe.
1901 */
1902 rc = usb_clr_feature(pState->pDip, USB_DEV_REQ_RCPT_EP, USB_EP_HALT, bEndpoint,
1903 USB_FLAGS_NOSLEEP, /* Asynchronous */
1904 NULL, /* Completion callback */
1905 NULL); /* Exception callback */
1906#endif
1907 /*
1908 * Synchronous reset pipe.
1909 */
1910 usb_pipe_reset(pState->pDip, pEp->pPipe,
1911 USB_FLAGS_SLEEP, /* Synchronous */
1912 NULL, /* Completion callback */
1913 NULL); /* Exception callback */
1914
1915 mutex_enter(&pState->Mtx);
1916
1917 LogFlow((DEVICE_NAME ":vboxUSBSolarisClearEndPoint bEndpoint=%#x[%d] returns %d\n", bEndpoint, EndPtIndex, rc));
1918
1919 rc = VINF_SUCCESS;
1920 }
1921 else
1922 {
1923 LogFlow((DEVICE_NAME ":vboxUSBSolarisClearEndPoint not opened to be cleared. Faking success. bEndpoint=%#x.\n", bEndpoint));
1924 rc = VINF_SUCCESS;
1925 }
1926 }
1927 else
1928 {
1929 LogRel((DEVICE_NAME ":vboxUSBSolarisClearEndPoint Endpoint missing!! bEndpoint=%#x EndPtIndex=%d.\n", bEndpoint, EndPtIndex));
1930 rc = VERR_GENERAL_FAILURE;
1931 }
1932 }
1933 else
1934 LogFlow((DEVICE_NAME ":vboxUSBSolarisClearEndPoint device state=%d not online.\n", pState->DevState));
1935
1936 mutex_exit(&pState->Mtx);
1937 return rc;
1938}
1939
1940
1941/**
1942 * Set configuration (SET_CONFIGURATION)
1943 *
1944 * @param pState The USB device instance.
1945 * @param uCfgValue The Configuration value.
1946 *
1947 * @returns VBox error code.
1948 */
1949LOCAL int vboxUSBSolarisSetConfig(vboxusb_state_t *pState, uint8_t bCfgValue)
1950{
1951 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisSetConfig pState=%p bCfgValue=%#x\n", pState, bCfgValue));
1952
1953 /*
1954 * Serialize access: single threaded per Endpoint, one request at a time.
1955 */
1956 mutex_enter(&pState->Mtx);
1957 int rc = vboxUSBSolarisDeviceState(pState->DevState);
1958 if (RT_SUCCESS(rc))
1959 {
1960 vboxUSBSolarisCloseAllPipes(pState, false /* ControlPipe */);
1961 int iCfgIndex = vboxUSBSolarisGetConfigIndex(pState, bCfgValue);
1962
1963 if (iCfgIndex >= 0)
1964 {
1965 /*
1966 * Switch Config synchronously.
1967 */
1968 mutex_exit(&pState->Mtx);
1969 rc = usb_set_cfg(pState->pDip, (uint_t)iCfgIndex, USB_FLAGS_SLEEP, NULL /* callback */, NULL /* callback data */);
1970 mutex_enter(&pState->Mtx);
1971
1972 if (rc == USB_SUCCESS)
1973 {
1974 pState->fRestoreCfg = true;
1975 vboxUSBSolarisInitEndPointsForConfig(pState, iCfgIndex);
1976 rc = VINF_SUCCESS;
1977 }
1978 else
1979 {
1980 LogRel((DEVICE_NAME ":vboxUSBSolarisSetConfig usb_set_cfg failed for iCfgIndex=%#x bCfgValue=%#x rc=%d\n",
1981 iCfgIndex, bCfgValue, rc));
1982 rc = vboxUSBSolarisToVBoxRC(rc);
1983 }
1984 }
1985 else
1986 {
1987 LogRel((DEVICE_NAME ":vboxUSBSolarisSetConfig invalid iCfgIndex=%d bCfgValue=%#x\n", iCfgIndex, bCfgValue));
1988 rc = VERR_INVALID_HANDLE;
1989 }
1990 }
1991
1992 mutex_exit(&pState->Mtx);
1993
1994 return rc;
1995}
1996
1997
1998/**
1999 * Get configuration (GET_CONFIGURATION)
2000 *
2001 * @param pState The USB device instance.
2002 * @param pCfgValue Where to store the configuration value.
2003 *
2004 * @returns VBox error code.
2005 */
2006LOCAL int vboxUSBSolarisGetConfig(vboxusb_state_t *pState, uint8_t *pCfgValue)
2007{
2008 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisGetConfig pState=%p pCfgValue=%p\n", pState, pCfgValue));
2009 AssertPtrReturn(pCfgValue, VERR_INVALID_POINTER);
2010
2011 /*
2012 * Solaris keeps the currently active configuration for the first time. Thus for the first request
2013 * we simply pass the cached configuration back to the user.
2014 */
2015 if (!pState->fGetCfgReqDone)
2016 {
2017 pState->fGetCfgReqDone = true;
2018 AssertPtrReturn(pState->pDevDesc, VERR_GENERAL_FAILURE);
2019 usb_cfg_data_t *pCurrCfg = pState->pDevDesc->dev_curr_cfg;
2020 if (pCurrCfg)
2021 {
2022 *pCfgValue = pCurrCfg->cfg_descr.bConfigurationValue;
2023 LogFlow((DEVICE_NAME ":vboxUSBSolarisGetConfig cached config returned. CfgValue=%d\n", *pCfgValue));
2024 return VINF_SUCCESS;
2025 }
2026 }
2027
2028 /*
2029 * Get Config synchronously.
2030 */
2031 uint_t bCfgValue;
2032 int rc = usb_get_cfg(pState->pDip, &bCfgValue, USB_FLAGS_SLEEP);
2033 if (RT_LIKELY(rc == USB_SUCCESS))
2034 {
2035 *pCfgValue = bCfgValue;
2036 rc = VINF_SUCCESS;
2037 }
2038 else
2039 {
2040 LogRel((DEVICE_NAME ":vboxUSBSolarisGetConfig failed. rc=%d\n", rc));
2041 rc = vboxUSBSolarisToVBoxRC(rc);
2042 }
2043
2044 LogFlow((DEVICE_NAME ":vboxUSBSolarisGetConfig returns %d CfgValue=%d\n", rc, *pCfgValue));
2045 return rc;
2046}
2047
2048
2049/**
2050 * Set interface (SET_INTERFACE)
2051 *
2052 * @param pState The USB device instance.
2053 * @param uInterface The Interface number.
2054 * @param uAlt The Alternate setting number.
2055 *
2056 * @returns VBox error code.
2057 */
2058LOCAL int vboxUSBSolarisSetInterface(vboxusb_state_t *pState, uint8_t uInterface, uint8_t uAlt)
2059{
2060 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisSetInterface pState=%p uInterface=%#x uAlt=%#x\n", pState, uInterface, uAlt));
2061
2062 /*
2063 * Serialize access: single threaded per Endpoint, one request at a time.
2064 */
2065 mutex_enter(&pState->Mtx);
2066 int rc = vboxUSBSolarisDeviceState(pState->DevState);
2067 if (RT_SUCCESS(rc))
2068 {
2069 vboxUSBSolarisCloseAllPipes(pState, false /* ControlPipe */);
2070
2071 /*
2072 * Set Interface & Alt setting synchronously.
2073 */
2074 mutex_exit(&pState->Mtx);
2075 rc = usb_set_alt_if(pState->pDip, uInterface, uAlt, USB_FLAGS_SLEEP, NULL /* callback */, NULL /* callback data */);
2076 mutex_enter(&pState->Mtx);
2077
2078 if (rc == USB_SUCCESS)
2079 {
2080 vboxUSBSolarisInitEndPointsForInterfaceAlt(pState, uInterface, uAlt);
2081 rc = VINF_SUCCESS;
2082 }
2083 else
2084 {
2085 LogRel((DEVICE_NAME ":vboxUSBSolarisSetInterface usb_set_alt_if failed for uInterface=%#x bAlt=%#x rc=%d\n",
2086 uInterface, uAlt, rc));
2087 rc = vboxUSBSolarisToVBoxRC(rc);
2088 }
2089 }
2090
2091 mutex_exit(&pState->Mtx);
2092
2093 return rc;
2094}
2095
2096
2097/**
2098 * Close the USB device and reset it if required.
2099 *
2100 * @param pState The USB device instance.
2101 * @param ResetLevel The reset level.
2102 *
2103 * @returns VBox error code.
2104 */
2105LOCAL int vboxUSBSolarisCloseDevice(vboxusb_state_t *pState, VBOXUSB_RESET_LEVEL enmReset)
2106{
2107 LogFlow((DEVICE_NAME ":vboxUSBSolarisCloseDevice pState=%p enmReset=%d\n", pState, enmReset));
2108
2109 /*
2110 * Serialize access: single threaded per Endpoint, one request at a time.
2111 */
2112 mutex_enter(&pState->Mtx);
2113 int rc = vboxUSBSolarisDeviceState(pState->DevState);
2114
2115 if (enmReset == VBOXUSB_RESET_LEVEL_NONE)
2116 {
2117 vboxUSBSolarisCloseAllPipes(pState, true /* ControlPipe */);
2118 pState->fClosed = true;
2119 }
2120 else
2121 vboxUSBSolarisCloseAllPipes(pState, false /* ControlPipe */);
2122
2123
2124 mutex_exit(&pState->Mtx);
2125
2126 if (RT_SUCCESS(rc))
2127 {
2128 switch (enmReset)
2129 {
2130 case VBOXUSB_RESET_LEVEL_REATTACH:
2131 rc = usb_reset_device(pState->pDip, USB_RESET_LVL_REATTACH);
2132 break;
2133
2134 case VBOXUSB_RESET_LEVEL_SOFT:
2135 rc = usb_reset_device(pState->pDip, USB_RESET_LVL_DEFAULT);
2136 break;
2137
2138 default:
2139 rc = USB_SUCCESS;
2140 break;
2141 }
2142
2143 rc = vboxUSBSolarisToVBoxRC(rc);
2144 }
2145
2146 LogFlow((DEVICE_NAME ":vboxUSBSolarisCloseDevice returns %d\n", rc));
2147 return rc;
2148}
2149
2150
2151/**
2152 * Abort pending requests and reset the pipe.
2153 *
2154 * @param pState The USB device instance.
2155 * @param bEndpoint The Endpoint address.
2156 *
2157 * @returns VBox error code.
2158 */
2159LOCAL int vboxUSBSolarisAbortPipe(vboxusb_state_t *pState, uint8_t bEndpoint)
2160{
2161 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisAbortPipe pState=%p bEndpoint=%#x\n", pState, bEndpoint));
2162
2163 /*
2164 * Serialize access: single threaded per Endpoint, one request at a time.
2165 */
2166 mutex_enter(&pState->Mtx);
2167 int rc = vboxUSBSolarisDeviceState(pState->DevState);
2168 if (RT_SUCCESS(rc))
2169 {
2170 uchar_t EndPtIndex = usb_get_ep_index(bEndpoint);
2171 vboxusb_ep_t *pEp = &pState->aEps[EndPtIndex];
2172 if (RT_LIKELY(pEp))
2173 {
2174 if (pEp->pPipe)
2175 {
2176 /*
2177 * Default Endpoint; aborting requests not supported, fake success.
2178 */
2179 if ((pEp->EpDesc.bEndpointAddress & USB_EP_NUM_MASK) == 0)
2180 {
2181 mutex_exit(&pState->Mtx);
2182 LogRel((DEVICE_NAME ":vboxUSBSolarisAbortPipe Cannot reset control pipe.\n"));
2183 return VERR_NOT_SUPPORTED;
2184 }
2185
2186 /*
2187 * Serialize access: single threaded per Endpoint, one request at a time.
2188 */
2189 mutex_exit(&pState->Mtx);
2190 usb_pipe_reset(pState->pDip, pEp->pPipe,
2191 USB_FLAGS_SLEEP, /* Synchronous */
2192 NULL, /* Completion callback */
2193 NULL); /* Callback data */
2194
2195 /*
2196 * Allow pending async requests to complete.
2197 */
2198 rc = usb_pipe_drain_reqs(pState->pDip, pEp->pPipe,
2199 USB_FLAGS_SLEEP, /* Synchronous */
2200 5, /* Timeout (seconds) */
2201 NULL, /* Completion callback */
2202 NULL); /* Callback data*/
2203
2204 mutex_enter(&pState->Mtx);
2205
2206 LogFlow((DEVICE_NAME ":usb_pipe_drain_reqs returns %d\n", rc));
2207 rc = vboxUSBSolarisToVBoxRC(rc);
2208 }
2209 else
2210 {
2211 LogRel((DEVICE_NAME ":vboxUSBSolarisAbortPipe pipe not open. bEndpoint=%#x\n", bEndpoint));
2212 rc = VERR_PIPE_IO_ERROR;
2213 }
2214 }
2215 else
2216 {
2217 LogRel((DEVICE_NAME ":vboxUSBSolarisAbortPipe invalid pipe index %d bEndpoint=%#x\n", EndPtIndex, bEndpoint));
2218 rc = VERR_INVALID_HANDLE;
2219 }
2220 }
2221
2222 mutex_exit(&pState->Mtx);
2223
2224 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisAbortPipe returns %d\n", rc));
2225 return rc;
2226}
2227
2228
2229/**
2230 * Initialize an endpoint.
2231 *
2232 * @param pState The USB device instance.
2233 * @param pEpData The Endpoint data.
2234 * @param uCfgValue The Configuration value.
2235 * @param uCfgIndex The Configuration index.
2236 * @param uInterface The Interface.
2237 * @param uAlt The Alternate setting.
2238 *
2239 * @returns VBox error code.
2240 */
2241LOCAL int vboxUSBSolarisInitEndPoint(vboxusb_state_t *pState, usb_ep_data_t *pEpData, uchar_t uCfgValue,
2242 uchar_t uInterface, uchar_t uAlt)
2243{
2244 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisInitEndPoint pState=%p pEpData=%p CfgVal=%d Iface=%d Alt=%d", pState,
2245 pEpData, uCfgValue, uInterface, uAlt));
2246
2247 /*
2248 * Is this the default endpoint?
2249 */
2250 usb_ep_descr_t *pEpDesc = NULL;
2251 vboxusb_ep_t *pEp = NULL;
2252 int EpIndex = 0;
2253 if (!pEpData)
2254 {
2255 EpIndex = 0;
2256 pEpDesc = &g_VBoxUSBSolarisDefaultEpDesc;
2257 }
2258 else
2259 {
2260 EpIndex = usb_get_ep_index(pEpData->ep_descr.bEndpointAddress);
2261 pEpDesc = &pEpData->ep_descr;
2262 }
2263
2264 pEp = &pState->aEps[EpIndex];
2265 AssertRelease(pEp);
2266
2267 /*
2268 * Initialize the endpoint data structure.
2269 */
2270 pEp->EpDesc = *pEpDesc;
2271 pEp->uCfgValue = uCfgValue;
2272 pEp->uInterface = uInterface;
2273 pEp->uAlt = uAlt;
2274 if (pEp->fInitialized != VBOXUSB_EP_INITIALIZED)
2275 {
2276 pEp->pPipe = NULL;
2277 pEp->EpState = VBOXUSB_EP_STATE_CLOSED;
2278 bzero(&pEp->PipePolicy, sizeof(pEp->PipePolicy));
2279 pEp->PipePolicy.pp_max_async_reqs = VBOXUSB_MAX_PIPE_ASYNC_REQS;
2280 pEp->fIsocPolling = false;
2281 list_create(&pEp->hIsocInUrbs, sizeof(vboxusb_urb_t), offsetof(vboxusb_urb_t, hListLink));
2282 pEp->cIsocInUrbs = 0;
2283 list_create(&pEp->hIsocInLandedReqs, sizeof(vboxusb_isoc_req_t), offsetof(vboxusb_isoc_req_t, hListLink));
2284 pEp->cbIsocInLandedReqs = 0;
2285 pEp->cbMaxIsocData = 0;
2286 pEp->fInitialized = VBOXUSB_EP_INITIALIZED;
2287 }
2288 LogFlow((DEVICE_NAME ":vboxUSBSolarisInitEndPoint done. %s:[%d] bEndpoint=%#x\n", !pEpData ? "Default " : "Endpoint",
2289 EpIndex, pEp->EpDesc.bEndpointAddress));
2290 return VINF_SUCCESS;
2291}
2292
2293
2294/**
2295 * Initialize all Endpoint structures.
2296 *
2297 * @param pState The USB device instance.
2298 *
2299 * @returns VBox status code.
2300 */
2301LOCAL int vboxUSBSolarisInitAllEndPoints(vboxusb_state_t *pState)
2302{
2303 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisInitAllEndPoints pState=%p\n", pState));
2304
2305 /*
2306 * Initialize all Endpoints for all Alternate settings of all Interfaces of all Configs.
2307 */
2308 int rc = vboxUSBSolarisInitEndPoint(pState, NULL /* pEp */, 0 /* uCfgValue */, 0 /* uInterface */, 0 /* uAlt */);
2309
2310 if (RT_SUCCESS(rc))
2311 {
2312 /*
2313 * Initialize all Endpoints for all Alternate settings of all Interfaces of all Configs.
2314 */
2315 for (uchar_t uCfgIndex = 0; uCfgIndex < pState->pDevDesc->dev_n_cfg; uCfgIndex++)
2316 {
2317 rc = vboxUSBSolarisInitEndPointsForConfig(pState, uCfgIndex);
2318 if (RT_FAILURE(rc))
2319 {
2320 LogRel((DEVICE_NAME ":vboxUSBSolarisInitAllEndPoints: vboxUSBSolarisInitEndPoints uCfgIndex=%d failed. rc=%d\n", uCfgIndex, rc));
2321 return rc;
2322 }
2323 }
2324 }
2325 else
2326 LogRel((DEVICE_NAME ":vboxUSBSolarisInitAllEndPoints default Endpoint initialization failed!\n"));
2327
2328 return rc;
2329}
2330
2331
2332/**
2333 * Initialize Endpoints structures for the given Config.
2334 *
2335 * @param pState The USB device instance.
2336 * @param uCfgIndex The current Config. index.
2337 *
2338 * @returns VBox status code.
2339 */
2340LOCAL int vboxUSBSolarisInitEndPointsForConfig(vboxusb_state_t *pState, uint8_t uCfgIndex)
2341{
2342 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForConfig pState=%p uCfgIndex=%d\n", pState, uCfgIndex));
2343 usb_cfg_data_t *pConfig = &pState->pDevDesc->dev_cfg[uCfgIndex];
2344 uchar_t uCfgValue = pConfig->cfg_descr.bConfigurationValue;
2345
2346 for (uchar_t uInterface = 0; uInterface < pConfig->cfg_n_if; uInterface++)
2347 {
2348 usb_if_data_t *pInterface = &pConfig->cfg_if[uInterface];
2349
2350 for (uchar_t uAlt = 0; uAlt < pInterface->if_n_alt; uAlt++)
2351 {
2352 usb_alt_if_data_t *pAlt = &pInterface->if_alt[uAlt];
2353
2354 for (uchar_t uEp = 0; uEp < pAlt->altif_n_ep; uEp++)
2355 {
2356 usb_ep_data_t *pEpData = &pAlt->altif_ep[uEp];
2357
2358 int rc = vboxUSBSolarisInitEndPoint(pState, pEpData, uCfgValue, uInterface, uAlt);
2359 if (RT_FAILURE(rc))
2360 {
2361 LogRel((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForConfig: vboxUSBSolarisInitEndPoint failed! pEp=%p uCfgValue=%u uCfgIndex=%u uInterface=%u, uAlt=%u\n",
2362 uCfgValue, uCfgIndex, uInterface, uAlt));
2363 return rc;
2364 }
2365 }
2366 }
2367 }
2368 return VINF_SUCCESS;
2369}
2370
2371
2372/**
2373 * Initialize Endpoints structures for the given Interface & Alternate setting.
2374 *
2375 * @param pState The USB device instance.
2376 * @param uInterface The interface being switched to.
2377 * @param uAlt The alt being switched to.
2378 *
2379 * @returns VBox status code.
2380 */
2381LOCAL int vboxUSBSolarisInitEndPointsForInterfaceAlt(vboxusb_state_t *pState, uint8_t uInterface, uint8_t uAlt)
2382{
2383 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForInterfaceAlt pState=%p uInterface=%d uAlt=%d\n", pState, uInterface, uAlt));
2384
2385 /* Doesn't hurt to be paranoid */
2386 uint_t uCfgIndex = usb_get_current_cfgidx(pState->pDip);
2387 if (RT_UNLIKELY(uCfgIndex >= pState->pDevDesc->dev_n_cfg))
2388 {
2389 LogRel((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForInterfaceAlt invalid current config index %d\n", uCfgIndex));
2390 return VERR_GENERAL_FAILURE;
2391 }
2392
2393 usb_cfg_data_t *pConfig = &pState->pDevDesc->dev_cfg[uCfgIndex];
2394 uchar_t uCfgValue = pConfig->cfg_descr.bConfigurationValue;
2395 usb_if_data_t *pInterface = &pConfig->cfg_if[uInterface];
2396
2397 int rc = VINF_SUCCESS;
2398 if (RT_LIKELY(pInterface))
2399 {
2400 usb_alt_if_data_t *pAlt = &pInterface->if_alt[uAlt];
2401 if (RT_LIKELY(pAlt))
2402 {
2403 for (uchar_t uEp = 0; uEp < pAlt->altif_n_ep; uEp++)
2404 {
2405 usb_ep_data_t *pEpData = &pAlt->altif_ep[uEp];
2406 rc = vboxUSBSolarisInitEndPoint(pState, pEpData, uCfgValue, uInterface, uAlt);
2407 if (RT_FAILURE(rc))
2408 {
2409 LogRel((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForInterfaceAlt: vboxUSBSolarisInitEndPoint failed! pEp=%p uCfgValue=%u uCfgIndex=%u uInterface=%u, uAlt=%u\n",
2410 uCfgValue, uCfgIndex, uInterface, uAlt));
2411 return rc;
2412 }
2413 }
2414 }
2415 else
2416 {
2417 LogRel((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForInterfaceAlt missing alternate.\n"));
2418 rc = VERR_INVALID_POINTER;
2419 }
2420 }
2421 else
2422 {
2423 LogRel((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForInterfaceAlt missing interface.\n"));
2424 rc = VERR_INVALID_POINTER;
2425 }
2426
2427 LogFlow((DEVICE_NAME ":vboxUSBSolarisInitEndPointsForInterfaceAlt returns %d\n", rc));
2428 return rc;
2429}
2430
2431
2432/**
2433 * Destroy all Endpoint Xfer structures.
2434 *
2435 * @param pState The USB device instance.
2436 * @remarks Requires the state mutex to be held!!
2437 * Call only from Detach() or similar as callbacks
2438 */
2439LOCAL void vboxUSBSolarisDestroyAllEndPoints(vboxusb_state_t *pState)
2440{
2441 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDestroyAllEndPoints pState=%p\n", pState));
2442 for (unsigned i = 0; i < VBOXUSB_MAX_ENDPOINTS; i++)
2443 {
2444 vboxusb_ep_t *pEp = &pState->aEps[i];
2445 if (pEp)
2446 {
2447 vboxUSBSolarisDestroyEndPoint(pState, pEp);
2448 pEp = NULL;
2449 }
2450 }
2451}
2452
2453
2454/**
2455 * Destroy an Endpoint.
2456 *
2457 * @param pState The USB device instance.
2458 * @param pEp The Endpoint.
2459 */
2460LOCAL void vboxUSBSolarisDestroyEndPoint(vboxusb_state_t *pState, vboxusb_ep_t *pEp)
2461{
2462 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDestroyEndPoint pState=%p pEp=%p\n", pState, pEp));
2463
2464 if (pEp->fInitialized == VBOXUSB_EP_INITIALIZED)
2465 {
2466 vboxusb_urb_t *pUrb = list_remove_head(&pEp->hIsocInUrbs);
2467 while (pUrb)
2468 {
2469 if (pUrb->pMsg)
2470 freemsg(pUrb->pMsg);
2471 RTMemFree(pUrb);
2472 pUrb = list_remove_head(&pEp->hIsocInUrbs);
2473 }
2474 pEp->cIsocInUrbs = 0;
2475 list_destroy(&pEp->hIsocInUrbs);
2476
2477 vboxusb_isoc_req_t *pIsocReq = list_remove_head(&pEp->hIsocInLandedReqs);
2478 while (pIsocReq)
2479 {
2480 kmem_free(pIsocReq, sizeof(vboxusb_isoc_req_t));
2481 pIsocReq = list_remove_head(&pEp->hIsocInLandedReqs);
2482 }
2483 pEp->cbIsocInLandedReqs = 0;
2484 list_destroy(&pEp->hIsocInLandedReqs);
2485
2486 pEp->fInitialized = 0;
2487 }
2488}
2489
2490
2491/**
2492 * Close all non-default Endpoints and drains the default pipe.
2493 *
2494 * @param pState The USB device instance.
2495 * @param fDefault Whether to close the default control pipe.
2496 *
2497 * @remarks Requires the device state mutex to be held.
2498 */
2499LOCAL void vboxUSBSolarisCloseAllPipes(vboxusb_state_t *pState, bool fDefault)
2500{
2501 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisCloseAllPipes pState=%p\n", pState));
2502
2503 for (int i = 1; i < VBOXUSB_MAX_ENDPOINTS; i++)
2504 {
2505 vboxusb_ep_t *pEp = &pState->aEps[i];
2506 if ( pEp
2507 && pEp->pPipe)
2508 {
2509 LogFlow((DEVICE_NAME ":vboxUSBSolarisCloseAllPipes closing[%d]\n", i));
2510 vboxUSBSolarisClosePipe(pState, pEp);
2511 }
2512 }
2513
2514 if (fDefault)
2515 {
2516 vboxusb_ep_t *pEp = &pState->aEps[0];
2517 if ( pEp
2518 && pEp->pPipe)
2519 {
2520 vboxUSBSolarisClosePipe(pState, pEp);
2521 LogFlow((DEVICE_NAME ":vboxUSBSolarisCloseAllPipes closed default pipe.\n"));
2522 }
2523 }
2524}
2525
2526
2527/**
2528 * Closes all pipes for a given interface.
2529 *
2530 * @param pState The USB device instance.
2531 * @param bInterface The Interface.
2532 */
2533LOCAL void vboxUSBSolarisCloseInterface(vboxusb_state_t *pState, uint8_t bInterface)
2534{
2535 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisCloseInterface pState=%p bInterface=%#x\n", pState, bInterface));
2536
2537 for (int i = 1; i < VBOXUSB_MAX_ENDPOINTS; i++)
2538 {
2539 vboxusb_ep_t *pEp = &pState->aEps[i];
2540 if ( pEp
2541 && pEp->pPipe
2542 && pEp->uInterface == bInterface)
2543 {
2544 LogFlow((DEVICE_NAME ":vboxUSBSolarisCloseInterface closing[%d]\n", i));
2545 vboxUSBSolarisClosePipe(pState, pEp);
2546 }
2547 }
2548}
2549
2550
2551/**
2552 * Open the pipe for an Endpoint.
2553 *
2554 * @param pState The USB device instance.
2555 * @param pEp The Endpoint.
2556 *
2557 * @returns VBox status code.
2558 */
2559LOCAL int vboxUSBSolarisOpenPipe(vboxusb_state_t *pState, vboxusb_ep_t *pEp)
2560{
2561// LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisOpenPipe pState=%p pEp=%p\n", pState, pEp));
2562
2563 /*
2564 * Make sure the Endpoint isn't open already.
2565 */
2566 if (pEp->pPipe)
2567 return VINF_SUCCESS;
2568
2569 /*
2570 * Default Endpoint; already opened just copy the pipe handle.
2571 */
2572 if ((pEp->EpDesc.bEndpointAddress & USB_EP_NUM_MASK) == 0)
2573 {
2574 pEp->pPipe = pState->pDevDesc->dev_default_ph;
2575 pEp->EpState |= VBOXUSB_EP_STATE_OPENED;
2576 LogFlow((DEVICE_NAME ":vboxUSBSolarisOpenPipe default pipe opened.\n"));
2577 return VINF_SUCCESS;
2578 }
2579
2580 /*
2581 * Open the non-default pipe for the Endpoint.
2582 */
2583 int rc = usb_pipe_open(pState->pDip, &pEp->EpDesc, &pEp->PipePolicy, USB_FLAGS_NOSLEEP, &pEp->pPipe);
2584 if (rc == USB_SUCCESS)
2585 {
2586 usb_pipe_set_private(pEp->pPipe, (usb_opaque_t)pEp);
2587
2588 /*
2589 * Determine input buffer size for Isoc. IN transfers.
2590 */
2591 if ( VBOXUSB_XFER_TYPE(pEp) == VUSBXFERTYPE_ISOC
2592 && VBOXUSB_XFER_DIR(pEp) == VUSB_DIR_TO_HOST)
2593 {
2594 /*
2595 * wMaxPacketSize bits 10..0 specifies maximum packet size which can hold 1024 bytes.
2596 * If bits 12..11 is non-zero, cbMax will be more than 1024 and thus the Endpoint is a
2597 * high-bandwidth Endpoint.
2598 */
2599 uint16_t cbMax = VBOXUSB_PKT_SIZE(pEp->EpDesc.wMaxPacketSize);
2600 if (cbMax <= 1024)
2601 {
2602 /* Buffer 1 second for highspeed and 8 seconds for fullspeed Endpoints. */
2603 pEp->cbMaxIsocData = 1000 * cbMax * 8;
2604 }
2605 else
2606 {
2607 /* Buffer about 400 milliseconds of data for highspeed high-bandwidth endpoints. */
2608 pEp->cbMaxIsocData = 400 * cbMax * 8;
2609 }
2610 LogFlow((DEVICE_NAME ":vboxUSBSolarisOpenPipe pEp=%p cbMaxIsocData=%u\n", pEp->cbMaxIsocData));
2611 }
2612
2613 pEp->EpState |= VBOXUSB_EP_STATE_OPENED;
2614 rc = VINF_SUCCESS;
2615 }
2616 else
2617 {
2618 LogRel((DEVICE_NAME ":vboxUSBSolarisOpenPipe failed! rc=%d pState=%p pEp=%p\n", rc, pState, pEp));
2619 rc = VERR_BAD_PIPE;
2620 }
2621
2622 return rc;
2623}
2624
2625
2626/**
2627 * Close the pipe of the Endpoint.
2628 *
2629 * @param pState The USB device instance.
2630 * @param pEp The Endpoint.
2631 *
2632 * @remarks Requires the device state mutex to be held.
2633 */
2634LOCAL void vboxUSBSolarisClosePipe(vboxusb_state_t *pState, vboxusb_ep_t *pEp)
2635{
2636 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisClosePipe pState=%p pEp=%p\n", pState, pEp));
2637 AssertPtr(pEp);
2638
2639 if (pEp->pPipe)
2640 {
2641 pEp->EpState &= ~(VBOXUSB_EP_STATE_OPENED);
2642
2643 /*
2644 * Default pipe: allow completion of pending requests.
2645 */
2646 if (pEp->pPipe == pState->pDevDesc->dev_default_ph)
2647 {
2648 mutex_exit(&pState->Mtx);
2649 usb_pipe_drain_reqs(pState->pDip, pEp->pPipe, 0, USB_FLAGS_SLEEP, NULL /* callback */, NULL /* callback arg. */);
2650 mutex_enter(&pState->Mtx);
2651 LogFlow((DEVICE_NAME ":vboxUSBSolarisClosePipe closed default pipe\n"));
2652 }
2653 else
2654 {
2655 /*
2656 * Stop Isoc. IN polling if required.
2657 */
2658 if (pEp->fIsocPolling)
2659 {
2660 pEp->fIsocPolling = false;
2661 mutex_exit(&pState->Mtx);
2662 usb_pipe_stop_isoc_polling(pEp->pPipe, USB_FLAGS_NOSLEEP);
2663 mutex_enter(&pState->Mtx);
2664 }
2665
2666 /*
2667 * Non-default pipe: close it.
2668 */
2669 LogFlow((DEVICE_NAME ":vboxUSBSolarisClosePipe pipe bmAttributes=%#x bEndpointAddress=%#x\n", pEp->EpDesc.bmAttributes, pEp->EpDesc.bEndpointAddress));
2670 mutex_exit(&pState->Mtx);
2671 usb_pipe_close(pState->pDip, pEp->pPipe, USB_FLAGS_SLEEP, NULL /* callback */, NULL /* callback arg. */);
2672 mutex_enter(&pState->Mtx);
2673 }
2674
2675 /*
2676 * Free the Endpoint data message block and reset pipe handle.
2677 */
2678 pEp->pPipe = NULL;
2679
2680 LogFlow((DEVICE_NAME ":vboxUSBSolarisClosePipe successful. pEp=%p\n", pEp));
2681 }
2682
2683 Assert(pEp->pPipe == NULL);
2684}
2685
2686
2687/**
2688 * Check if any non-default Endpoints are open.
2689 *
2690 * @param pState The USB device instance.
2691 *
2692 * @returns Returns true if any non-default Endpoint is open, otherwise false.
2693 */
2694LOCAL bool vboxUSBSolarisIsAnyPipeOpen(vboxusb_state_t *pState)
2695{
2696 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisIsAnyPipeOpen pState=%p\n", pState));
2697
2698 for (int i = 1; i < VBOXUSB_MAX_ENDPOINTS; i++)
2699 {
2700 vboxusb_ep_t *pEp = &pState->aEps[i];
2701 if (pEp->pPipe)
2702 {
2703 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsAnyPipeOpen pState=%p pEp=%p returns true.\n", pState, pEp));
2704 return true;
2705 }
2706 }
2707
2708 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsAnyPipeOpen pState=%p returns false.\n", pState));
2709 return false;
2710}
2711
2712
2713/**
2714 * Find the Configuration index for the passed in Configuration value.
2715 *
2716 * @param pState The USB device instance.
2717 * @param uCfgValue The Configuration value.
2718 *
2719 * @returns The configuration index if found, otherwise -1.
2720 */
2721LOCAL int vboxUSBSolarisGetConfigIndex(vboxusb_state_t *pState, uint_t uCfgValue)
2722{
2723 for (int CfgIndex = 0; CfgIndex < pState->pDevDesc->dev_n_cfg; CfgIndex++)
2724 {
2725 usb_cfg_data_t *pConfig = &pState->pDevDesc->dev_cfg[CfgIndex];
2726 if (pConfig->cfg_descr.bConfigurationValue == uCfgValue)
2727 return CfgIndex;
2728 }
2729
2730 return -1;
2731}
2732
2733
2734/**
2735 * Allocates and initializes an Isoc. In URB from the ring-3 equivalent.
2736 *
2737 * @param pState The USB device instance.
2738 * @param pUrb The URB to initialize.
2739 * @param pUrbReq Opaque pointer to the complete request.
2740 * @param pMsg Pointer to the allocated request data.
2741 *
2742 * @returns The allocated Isoc. In URB to be used.
2743 */
2744LOCAL vboxusb_urb_t *vboxUSBSolarisGetIsocInURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq)
2745{
2746 /*
2747 * Isoc. In URBs are not queued into the Inflight list like every other URBs.
2748 * For now we allocate each URB which gets queued into the respective Endpoint during Xfer.
2749 */
2750 vboxusb_urb_t *pUrb = RTMemAllocZ(sizeof(vboxusb_urb_t));
2751 if (RT_LIKELY(pUrb))
2752 {
2753 pUrb->enmState = VBOXUSB_URB_STATE_INFLIGHT;
2754 pUrb->pState = pState;
2755
2756 if (RT_LIKELY(pUrbReq))
2757 {
2758 pUrb->pvUrbR3 = pUrbReq->pvUrbR3;
2759 pUrb->bEndpoint = pUrbReq->bEndpoint;
2760 pUrb->enmType = pUrbReq->enmType;
2761 pUrb->enmDir = pUrbReq->enmDir;
2762 pUrb->enmStatus = pUrbReq->enmStatus;
2763 pUrb->cbDataR3 = pUrbReq->cbData;
2764 pUrb->pvDataR3 = (RTR3PTR)pUrbReq->pvData;
2765 pUrb->cIsocPkts = pUrbReq->cIsocPkts;
2766
2767 for (unsigned i = 0; i < pUrbReq->cIsocPkts; i++)
2768 pUrb->aIsocPkts[i].cbPkt = pUrbReq->aIsocPkts[i].cbPkt;
2769
2770 pUrb->pMsg = NULL;
2771 }
2772 }
2773 else
2774 LogRel((DEVICE_NAME ":vboxUSBSolarisGetIsocInURB failed to alloc %d bytes.\n", sizeof(vboxusb_urb_t)));
2775 return pUrb;
2776}
2777
2778
2779/**
2780 * Queues a URB reusing previously allocated URBs as required.
2781 *
2782 * @param pState The USB device instance.
2783 * @param pUrbReq Opaque pointer to the complete request.
2784 * @param pMsg Pointer to the allocated request data.
2785 *
2786 * @returns The allocated URB to be used.
2787 */
2788LOCAL vboxusb_urb_t *vboxUSBSolarisQueueURB(vboxusb_state_t *pState, PVBOXUSBREQ_URB pUrbReq, mblk_t *pMsg)
2789{
2790 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisQueueURB pState=%p pUrbReq=%p\n", pState, pUrbReq));
2791
2792 mutex_enter(&pState->Mtx);
2793
2794 /*
2795 * Discard oldest queued URB if we've queued max URBs and none of them have completed.
2796 */
2797 if (pState->cInflightUrbs >= VBOXUSB_URB_QUEUE_SIZE)
2798 {
2799 vboxusb_urb_t *pUrb = list_head(&pState->hUrbs);
2800 if (RT_LIKELY(pUrb))
2801 {
2802 if (pUrb->pMsg)
2803 {
2804 freemsg(pUrb->pMsg);
2805 pUrb->pMsg = NULL;
2806 }
2807 pUrb->enmState = VBOXUSB_URB_STATE_FREE;
2808 }
2809 }
2810
2811 vboxusb_urb_t *pUrb = list_head(&pState->hUrbs);
2812 if ( !pUrb
2813 || ( pUrb
2814 && pUrb->enmState != VBOXUSB_URB_STATE_FREE))
2815 {
2816 mutex_exit(&pState->Mtx);
2817 pUrb = RTMemAllocZ(sizeof(vboxusb_urb_t));
2818 if (RT_UNLIKELY(!pUrb))
2819 {
2820 LogRel((DEVICE_NAME ":vboxUSBSolarisQueueURB failed to alloc %d bytes.\n", sizeof(vboxusb_urb_t)));
2821 return NULL;
2822 }
2823 mutex_enter(&pState->Mtx);
2824 }
2825 else
2826 {
2827 /*
2828 * Remove from head and move to tail so that when several URBs are reaped continously we get to use
2829 * up each one free 'head'.
2830 */
2831 list_remove_head(&pState->hUrbs);
2832 }
2833
2834 list_insert_tail(&pState->hUrbs, pUrb);
2835 ++pState->cInflightUrbs;
2836
2837 pUrb->enmState = VBOXUSB_URB_STATE_INFLIGHT;
2838
2839 mutex_exit(&pState->Mtx);
2840
2841 Assert(pUrb->pMsg == NULL);
2842 pUrb->pState = pState;
2843 LogFlow((DEVICE_NAME ":vboxUSBSolarisQueueURB cInflightUrbs=%d\n", pState->cInflightUrbs));
2844
2845 if (RT_LIKELY(pUrbReq))
2846 {
2847 pUrb->pvUrbR3 = pUrbReq->pvUrbR3;
2848 pUrb->bEndpoint = pUrbReq->bEndpoint;
2849 pUrb->enmType = pUrbReq->enmType;
2850 pUrb->enmDir = pUrbReq->enmDir;
2851 pUrb->enmStatus = pUrbReq->enmStatus;
2852 pUrb->cbDataR3 = pUrbReq->cbData;
2853 pUrb->pvDataR3 = (RTR3PTR)pUrbReq->pvData;
2854 pUrb->cIsocPkts = pUrbReq->cIsocPkts;
2855 if (pUrbReq->enmType == VUSBXFERTYPE_ISOC)
2856 {
2857 for (unsigned i = 0; i < pUrbReq->cIsocPkts; i++)
2858 pUrb->aIsocPkts[i].cbPkt = pUrbReq->aIsocPkts[i].cbPkt;
2859 }
2860
2861 pUrb->pMsg = pMsg;
2862 }
2863
2864 return pUrb;
2865}
2866
2867
2868/**
2869 * Dequeues a completed URB into the landed list and informs user-land.
2870 *
2871 * @param pUrb The URB to move.
2872 * @param URBStatus The Solaris URB completion code.
2873 *
2874 * @remarks All pipes could be closed at this point (e.g. Device disconnected during inflight URBs)
2875 */
2876LOCAL inline void vboxUSBSolarisDeQueueURB(vboxusb_urb_t *pUrb, int URBStatus)
2877{
2878 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDeQueue pUrb=%p\n", pUrb));
2879 AssertPtrReturnVoid(pUrb);
2880
2881 pUrb->enmStatus = vboxUSBSolarisGetUrbStatus(URBStatus);
2882
2883 vboxusb_state_t *pState = pUrb->pState;
2884 if (RT_LIKELY(pState))
2885 {
2886 mutex_enter(&pState->Mtx);
2887 pUrb->enmState = VBOXUSB_URB_STATE_LANDED;
2888
2889 /*
2890 * Remove it from the inflight list & move it to landed list.
2891 */
2892 list_remove(&pState->hUrbs, pUrb);
2893 --pState->cInflightUrbs;
2894 list_insert_tail(&pState->hLandedUrbs, pUrb);
2895
2896 vboxUSBSolarisNotifyComplete(pUrb->pState);
2897 mutex_exit(&pState->Mtx);
2898 }
2899 else
2900 {
2901 LogFlow((DEVICE_NAME ":vboxUSBSolarisDeQueue State Gone.\n"));
2902 freemsg(pUrb->pMsg);
2903 pUrb->pMsg = NULL;
2904 pUrb->enmStatus = VUSBSTATUS_INVALID;
2905 }
2906}
2907
2908
2909/**
2910 * Concatenates a chain message block into a single message block if possible.
2911 *
2912 * @param pUrb The URB to move.
2913 */
2914LOCAL inline void vboxUSBSolarisConcatMsg(vboxusb_urb_t *pUrb)
2915{
2916 /*
2917 * Concatenate the whole message rather than doing a chained copy while reaping.
2918 */
2919 if ( pUrb->pMsg
2920 && pUrb->pMsg->b_cont)
2921 {
2922 mblk_t *pFullMsg = msgpullup(pUrb->pMsg, -1 /* all data */);
2923 if (RT_LIKELY(pFullMsg))
2924 {
2925 freemsg(pUrb->pMsg);
2926 pUrb->pMsg = pFullMsg;
2927 }
2928 }
2929}
2930
2931
2932/**
2933 * User process poll wake up wrapper for asynchronous URB completion.
2934 *
2935 * @param pState The USB device instance.
2936 * @remarks Requires the device state mutex to be held!!
2937 */
2938LOCAL inline void vboxUSBSolarisNotifyComplete(vboxusb_state_t *pState)
2939{
2940 if (pState->fPoll & VBOXUSB_POLL_ON)
2941 {
2942 pollhead_t *pPollHead = &pState->PollHead;
2943 pState->fPoll |= VBOXUSB_POLL_REAP_PENDING;
2944 mutex_exit(&pState->Mtx);
2945 pollwakeup(pPollHead, POLLIN);
2946 mutex_enter(&pState->Mtx);
2947 }
2948}
2949
2950
2951/**
2952 * User process poll wake up wrapper for hotplug events.
2953 *
2954 * @param pState The USB device instance.
2955 * @remarks Requires the device state mutex to be held.
2956 */
2957LOCAL inline void vboxUSBSolarisNotifyHotplug(vboxusb_state_t *pState)
2958{
2959 if (pState->fPoll & VBOXUSB_POLL_ON)
2960 {
2961 pollhead_t *pPollHead = &pState->PollHead;
2962 pState->fPoll |= VBOXUSB_POLL_DEV_UNPLUGGED;
2963 mutex_exit(&pState->Mtx);
2964 pollwakeup(pPollHead, POLLHUP);
2965 mutex_enter(&pState->Mtx);
2966 }
2967}
2968
2969
2970/**
2971 * Perform a Control Xfer.
2972 *
2973 * @param pState The USB device instance.
2974 * @param pEp The Endpoint for the Xfer.
2975 * @param pUrb The VBox USB URB.
2976 *
2977 * @returns VBox status code.
2978 * @remarks Any errors, the caller should free pUrb->pMsg.
2979 */
2980LOCAL int vboxUSBSolarisCtrlXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *pUrb)
2981{
2982 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisCtrlXfer pState=%p pEp=%p pUrb=%p enmDir=%d cbData=%d\n", pState, pEp, pUrb, pUrb->enmDir, pUrb->cbDataR3));
2983
2984 AssertPtrReturn(pUrb->pMsg, VERR_INVALID_PARAMETER);
2985 uchar_t *pSetupData = pUrb->pMsg->b_rptr;
2986 size_t cbData = pUrb->cbDataR3 - VBOXUSB_CTRL_XFER_SIZE;
2987
2988 /*
2989 * Solaris USBA gives us garbage and incorrect message lengths making it impossible to use
2990 * pre-allocated control messages. The allocation of "ctrl_data" is not documented well.
2991 */
2992
2993 /*
2994 * Allocate a wrapper request.
2995 */
2996 int rc = VINF_SUCCESS;
2997 usb_ctrl_req_t *pReq = usb_alloc_ctrl_req(pState->pDip, cbData, USB_FLAGS_NOSLEEP);
2998 if (RT_LIKELY(pReq))
2999 {
3000 /*
3001 * Initialize the Ctrl Xfer Header.
3002 */
3003 pReq->ctrl_bmRequestType = pSetupData[0];
3004 pReq->ctrl_bRequest = pSetupData[1];
3005 pReq->ctrl_wValue = (pSetupData[3] << VBOXUSB_CTRL_XFER_SIZE) | pSetupData[2];
3006 pReq->ctrl_wIndex = (pSetupData[5] << VBOXUSB_CTRL_XFER_SIZE) | pSetupData[4];
3007 pReq->ctrl_wLength = (pSetupData[7] << VBOXUSB_CTRL_XFER_SIZE) | pSetupData[6];
3008
3009 if ( pUrb->enmDir == VUSBDIRECTION_OUT
3010 && cbData > 0)
3011 {
3012 pUrb->pMsg->b_rptr += VBOXUSB_CTRL_XFER_SIZE;
3013 bcopy(pUrb->pMsg->b_rptr, pReq->ctrl_data->b_wptr, cbData);
3014 pReq->ctrl_data->b_wptr += cbData;
3015 }
3016
3017 freemsg(pUrb->pMsg);
3018 pUrb->pMsg = NULL;
3019
3020 /*
3021 * Initialize callbacks and timeouts.
3022 */
3023 pReq->ctrl_cb = vboxUSBSolarisCtrlXferCompleted;
3024 pReq->ctrl_exc_cb = vboxUSBSolarisCtrlXferCompleted;
3025 pReq->ctrl_timeout = VBOXUSB_CTRL_XFER_TIMEOUT;
3026 pReq->ctrl_attributes = USB_ATTRS_AUTOCLEARING | (pUrb->enmDir == VUSBDIRECTION_IN ? USB_ATTRS_SHORT_XFER_OK : 0);
3027
3028 pReq->ctrl_client_private = (usb_opaque_t)pUrb;
3029
3030 LogFlow((DEVICE_NAME ":vboxUSBSolarisCtrlXfer %.*Rhxd\n", VBOXUSB_CTRL_XFER_SIZE, pSetupData));
3031
3032 /*
3033 * Submit the request.
3034 */
3035 rc = usb_pipe_ctrl_xfer(pEp->pPipe, pReq, USB_FLAGS_NOSLEEP);
3036
3037 if (RT_LIKELY(rc == USB_SUCCESS))
3038 return VINF_SUCCESS;
3039 else
3040 {
3041 LogRel((DEVICE_NAME ":vboxUSBSolarisCtrlXfer usb_pipe_ctrl_xfer failed! rc=%d\n", rc));
3042 rc = VERR_PIPE_IO_ERROR;
3043 }
3044
3045 usb_free_ctrl_req(pReq);
3046 }
3047 else
3048 {
3049 LogRel((DEVICE_NAME ":vboxUSBSolarisCtrlXfer failed to alloc request.\n"));
3050 rc = VERR_NO_MEMORY;
3051 }
3052
3053 return rc;
3054}
3055
3056
3057/**
3058 * Completion/Exception callback for Control Xfers.
3059 *
3060 * @param pPipe The Ctrl pipe handle.
3061 * @param pReq The Ctrl request.
3062 */
3063LOCAL void vboxUSBSolarisCtrlXferCompleted(usb_pipe_handle_t pPipe, usb_ctrl_req_t *pReq)
3064{
3065 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisCtrlXferCompleted pPipe=%p pReq=%p\n", pPipe, pReq));
3066
3067 vboxusb_urb_t *pUrb = (vboxusb_urb_t *)pReq->ctrl_client_private;
3068 if (RT_LIKELY(pUrb))
3069 {
3070 /*
3071 * Funky stuff: We need to reconstruct the header for control transfers.
3072 * Let us chain along the data and while we dequeue the URB we attempt to
3073 * concatenate the entire message there.
3074 */
3075 mblk_t *pSetupMsg = allocb(sizeof(VUSBSETUP), BPRI_MED);
3076 if (RT_LIKELY(pSetupMsg))
3077 {
3078 VUSBSETUP SetupData;
3079 SetupData.bmRequestType = pReq->ctrl_bmRequestType;
3080 SetupData.bRequest = pReq->ctrl_bRequest;
3081 SetupData.wValue = pReq->ctrl_wValue;
3082 SetupData.wIndex = pReq->ctrl_wIndex;
3083 SetupData.wLength = pReq->ctrl_wLength;
3084 bcopy(&SetupData, pSetupMsg->b_wptr, sizeof(VUSBSETUP));
3085 pSetupMsg->b_wptr += sizeof(VUSBSETUP);
3086
3087 pUrb->pMsg = pSetupMsg;
3088 pUrb->pMsg->b_cont = pReq->ctrl_data;
3089 pReq->ctrl_data = NULL;
3090 vboxUSBSolarisConcatMsg(pUrb);
3091
3092#if defined(DEBUG_ramshankar)
3093 if ( pUrb->pMsg
3094 && pUrb->pMsg->b_cont == NULL) /* Concat succeeded */
3095 {
3096 LogFlow((DEVICE_NAME ":vboxUSBSolarisCtrlXferCompleted prepended header rc=%d cbData=%d.\n", pReq->ctrl_completion_reason,
3097 MBLKL(pUrb->pMsg)));
3098 LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pUrb->pMsg), pUrb->pMsg->b_rptr));
3099 }
3100#endif
3101
3102 /*
3103 * Update the URB and move to landed list for reaping.
3104 */
3105 vboxUSBSolarisDeQueueURB(pUrb, pReq->ctrl_completion_reason);
3106 usb_free_ctrl_req(pReq);
3107 return;
3108 }
3109 else
3110 LogRel((DEVICE_NAME ":vboxUSBSolarisCtrlXferCompleted failed to alloc %d bytes for Setup Header.\n", sizeof(VUSBSETUP)));
3111 }
3112 else
3113 LogRel((DEVICE_NAME ":vboxUSBSolarisCtrlXferCompleted Extreme error! missing private data.\n"));
3114
3115 usb_free_ctrl_req(pReq);
3116}
3117
3118
3119/**
3120 * Perform a Bulk Xfer.
3121 *
3122 * @param pState The USB device instance.
3123 * @param pEp The Endpoint for the Xfer.
3124 * @param pUrb The VBox USB URB.
3125 *
3126 * @returns VBox status code.
3127 * @remarks Any errors, the caller should free pUrb->pMsg.
3128 */
3129LOCAL int vboxUSBSolarisBulkXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *pUrb)
3130{
3131 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisBulkXfer pState=%p pEp=%p pUrb=%p enmDir=%d cbData=%d\n", pState, pEp, pUrb, pUrb->enmDir, pUrb->cbDataR3));
3132
3133 /*
3134 * Allocate a wrapper request.
3135 */
3136 int rc = VINF_SUCCESS;
3137 usb_bulk_req_t *pReq = usb_alloc_bulk_req(pState->pDip, pUrb->enmDir == VUSBDIRECTION_IN ? pUrb->cbDataR3 : 0, USB_FLAGS_NOSLEEP);
3138 if (RT_LIKELY(pReq))
3139 {
3140 /*
3141 * Initialize Bulk Xfer, callbacks and timeouts.
3142 */
3143 if (pUrb->enmDir == VUSBDIRECTION_OUT)
3144 pReq->bulk_data = pUrb->pMsg;
3145
3146 pReq->bulk_len = pUrb->cbDataR3;
3147 pReq->bulk_cb = vboxUSBSolarisBulkXferCompleted;
3148 pReq->bulk_exc_cb = vboxUSBSolarisBulkXferCompleted;
3149 pReq->bulk_timeout = VBOXUSB_BULK_XFER_TIMEOUT;
3150 pReq->bulk_attributes = USB_ATTRS_AUTOCLEARING | (pUrb->enmDir == VUSBDIRECTION_IN ? USB_ATTRS_SHORT_XFER_OK : 0);
3151 pReq->bulk_client_private = (usb_opaque_t)pUrb;
3152
3153 /* Don't obtain state lock here, we're just reading unchanging data... */
3154 if (RT_UNLIKELY(pUrb->cbDataR3 > pState->cbMaxBulkXfer))
3155 {
3156 LogRel((DEVICE_NAME ":vboxUSBSolarisBulkXfer requesting %d bytes when only %d bytes supported by device\n",
3157 pUrb->cbDataR3, pState->cbMaxBulkXfer));
3158 }
3159
3160 /*
3161 * Submit the request.
3162 */
3163 rc = usb_pipe_bulk_xfer(pEp->pPipe, pReq, USB_FLAGS_NOSLEEP);
3164
3165 if (RT_LIKELY(rc == USB_SUCCESS))
3166 return VINF_SUCCESS;
3167 else
3168 {
3169 LogRel((DEVICE_NAME ":vboxUSBSolarisBulkXfer usb_pipe_bulk_xfer enmDir=%#x Ep=%#x failed! rc=%d\n", pUrb->enmDir, pUrb->bEndpoint, rc));
3170 rc = VERR_PIPE_IO_ERROR;
3171 }
3172
3173 if (pUrb->enmDir == VUSBDIRECTION_OUT) /* pUrb->pMsg freed by caller */
3174 pReq->bulk_data = NULL;
3175
3176 usb_free_bulk_req(pReq);
3177 }
3178 else
3179 {
3180 LogRel((DEVICE_NAME ":vboxUSBSolarisBulkXfer failed to alloc bulk request.\n"));
3181 rc = VERR_NO_MEMORY;
3182 }
3183
3184 return rc;
3185}
3186
3187
3188/**
3189 * Completion/Exception callback for Bulk Xfers.
3190 *
3191 * @param pPipe The Bulk pipe handle.
3192 * @param pReq The Bulk request.
3193 */
3194LOCAL void vboxUSBSolarisBulkXferCompleted(usb_pipe_handle_t pPipe, usb_bulk_req_t *pReq)
3195{
3196 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisBulkXferCompleted pPipe=%p pReq=%p\n", pPipe, pReq));
3197
3198 vboxusb_ep_t *pEp = (vboxusb_ep_t *)usb_pipe_get_private(pPipe);
3199 if (RT_LIKELY(pEp))
3200 {
3201 vboxusb_urb_t *pUrb = (vboxusb_urb_t *)pReq->bulk_client_private;
3202 if (RT_LIKELY(pUrb))
3203 {
3204 if (pUrb->enmDir == VUSBDIRECTION_OUT)
3205 pReq->bulk_data = NULL;
3206 else
3207 {
3208 if (pReq->bulk_completion_reason == USB_CR_OK)
3209 {
3210 pUrb->pMsg = pReq->bulk_data;
3211 pReq->bulk_data = NULL;
3212 vboxUSBSolarisConcatMsg(pUrb);
3213 }
3214 }
3215
3216 LogFlow((DEVICE_NAME ":vboxUSBSolarisBulkXferCompleted %s. rc=%d cbData=%d\n",
3217 pReq->bulk_completion_reason != USB_CR_OK ? "failed URB" : "success",
3218 pReq->bulk_completion_reason, pUrb->pMsg ? MBLKL(pUrb->pMsg) : 0));
3219
3220 /*
3221 * Update the URB and move to tail for reaping.
3222 */
3223 vboxUSBSolarisDeQueueURB(pUrb, pReq->bulk_completion_reason);
3224 usb_free_bulk_req(pReq);
3225 return;
3226 }
3227 else
3228 LogRel((DEVICE_NAME ":vboxUSBSolarisBulkXferCompleted Extreme error! private request data missing.\n"));
3229 }
3230 else
3231 LogFlow((DEVICE_NAME ":vboxUSBSolarisBulkXferCompleted Pipe Gone.\n"));
3232
3233 usb_free_bulk_req(pReq);
3234}
3235
3236
3237/**
3238 * Perform an Interrupt Xfer.
3239 *
3240 * @param pState The USB device instance.
3241 * @param pEp The Endpoint for the Xfer.
3242 * @param pUrb The VBox USB URB.
3243 *
3244 * @returns VBox status code.
3245 * @remarks Any errors, the caller should free pUrb->pMsg.
3246 */
3247LOCAL int vboxUSBSolarisIntrXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *pUrb)
3248{
3249 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisIntrXfer pState=%p pEp=%p pUrb=%p enmDir=%d cbData=%d\n", pState, pEp, pUrb, pUrb->enmDir, pUrb->cbDataR3));
3250
3251 int rc = VINF_SUCCESS;
3252 usb_intr_req_t *pReq = usb_alloc_intr_req(pState->pDip, 0 /* length */, USB_FLAGS_NOSLEEP);
3253 if (RT_LIKELY(pReq))
3254 {
3255 /*
3256 * Initialize Intr Xfer, callbacks & timeouts.
3257 */
3258 if (pUrb->enmDir == VUSBDIRECTION_OUT)
3259 {
3260 pReq->intr_data = pUrb->pMsg;
3261 pReq->intr_attributes = USB_ATTRS_AUTOCLEARING;
3262 }
3263 else
3264 {
3265 pReq->intr_data = NULL;
3266 pReq->intr_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_ONE_XFER | USB_ATTRS_SHORT_XFER_OK;
3267 }
3268
3269 pReq->intr_len = pUrb->cbDataR3; /* Not pEp->EpDesc.wMaxPacketSize */
3270 pReq->intr_cb = vboxUSBSolarisIntrXferCompleted;
3271 pReq->intr_exc_cb = vboxUSBSolarisIntrXferCompleted;
3272 pReq->intr_timeout = VBOXUSB_INTR_XFER_TIMEOUT;
3273 pReq->intr_client_private = (usb_opaque_t)pUrb;
3274
3275 /*
3276 * Submit the request.
3277 */
3278 rc = usb_pipe_intr_xfer(pEp->pPipe, pReq, USB_FLAGS_NOSLEEP);
3279
3280 if (RT_LIKELY(rc == USB_SUCCESS))
3281 return VINF_SUCCESS;
3282 else
3283 {
3284 LogRel((DEVICE_NAME ":vboxUSBSolarisIntrXfer usb_pipe_intr_xfer failed! rc=%d\n", rc));
3285 rc = VERR_PIPE_IO_ERROR;
3286 }
3287
3288 pReq->intr_data = NULL;
3289 usb_free_intr_req(pReq);
3290 }
3291 else
3292 {
3293 LogRel((DEVICE_NAME ":vboxUSBSolarisIntrXfer failed to alloc intr request.\n"));
3294 rc = VERR_NO_MEMORY;
3295 }
3296
3297 return rc;
3298}
3299
3300
3301/**
3302 * Completion/Exception callback for Intr Xfers.
3303 *
3304 * @param pPipe The Intr pipe handle.
3305 * @param pReq The Intr request.
3306 */
3307LOCAL void vboxUSBSolarisIntrXferCompleted(usb_pipe_handle_t pPipe, usb_intr_req_t *pReq)
3308{
3309 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisIntrXferCompleted pPipe=%p pReq=%p\n", pPipe, pReq));
3310
3311 vboxusb_ep_t *pEp = (vboxusb_ep_t *)usb_pipe_get_private(pPipe);
3312 if (RT_LIKELY(pEp))
3313 {
3314 vboxusb_urb_t *pUrb = (vboxusb_urb_t *)pReq->intr_client_private;
3315 if (RT_LIKELY(pUrb))
3316 {
3317 if (pUrb->enmDir == VUSBDIRECTION_OUT)
3318 pReq->intr_data = NULL;
3319 else
3320 {
3321 if (pReq->intr_completion_reason == USB_CR_OK)
3322 {
3323 pUrb->pMsg = pReq->intr_data;
3324 pReq->intr_data = NULL;
3325 }
3326 }
3327
3328 LogFlow((DEVICE_NAME ":vboxUSBSolarisIntrXferCompleted rc=%d pMsg=%p enmDir=%#x\n", pReq->intr_completion_reason, pUrb->pMsg,
3329 pUrb->enmDir));
3330
3331 /*
3332 * Update the URB and move to landed list for reaping.
3333 */
3334 vboxUSBSolarisDeQueueURB(pUrb, pReq->intr_completion_reason);
3335 usb_free_intr_req(pReq);
3336 return;
3337 }
3338 else
3339 LogRel((DEVICE_NAME ":vboxUSBSolarisIntrXferCompleted Extreme error! private request data missing.\n"));
3340 }
3341 else
3342 LogFlow((DEVICE_NAME ":vboxUSBSolarisIntrXferCompleted Pipe Gone.\n"));
3343
3344 usb_free_intr_req(pReq);
3345}
3346
3347
3348/**
3349 * Perform an Isochronous Xfer.
3350 *
3351 * @param pState The USB device instance.
3352 * @param pEp The Endpoint for the Xfer.
3353 * @param pUrb The VBox USB URB.
3354 *
3355 * @returns VBox status code.
3356 * @remarks Any errors, the caller should free pUrb->pMsg.
3357 */
3358LOCAL int vboxUSBSolarisIsocXfer(vboxusb_state_t *pState, vboxusb_ep_t *pEp, vboxusb_urb_t *pUrb)
3359{
3360// LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisIsocXfer pState=%p pEp=%p pUrb=%p\n", pState, pEp, pUrb));
3361
3362 /*
3363 * For Isoc. IN transfers we perform one request and USBA polls the device continuously
3364 * and supplies our Xfer callback with input data. We cannot perform one-shot Isoc. In transfers.
3365 */
3366 size_t cbData = (pUrb->enmDir == VUSBDIRECTION_IN ? pUrb->cIsocPkts * pUrb->aIsocPkts[0].cbPkt : 0);
3367 if (pUrb->enmDir == VUSBDIRECTION_IN)
3368 {
3369 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocXfer Isoc. In queueing.\n"));
3370
3371 mutex_enter(&pState->Mtx);
3372 if (pEp->fIsocPolling)
3373 {
3374 /*
3375 * Queue a maximum of cbMaxIsocData bytes, else fail.
3376 */
3377 if (pEp->cbIsocInLandedReqs + cbData > pEp->cbMaxIsocData)
3378 {
3379 mutex_exit(&pState->Mtx);
3380 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocXfer Max Isoc. data %d bytes queued\n", pEp->cbMaxIsocData));
3381 return VERR_TOO_MUCH_DATA;
3382 }
3383
3384 list_insert_tail(&pEp->hIsocInUrbs, pUrb);
3385 ++pEp->cIsocInUrbs;
3386
3387 mutex_exit(&pState->Mtx);
3388 return VINF_SUCCESS;
3389 }
3390 mutex_exit(&pState->Mtx);
3391 }
3392
3393 int rc = VINF_SUCCESS;
3394 usb_isoc_req_t *pReq = usb_alloc_isoc_req(pState->pDip, pUrb->cIsocPkts, cbData, USB_FLAGS_NOSLEEP);
3395 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocXfer enmDir=%#x cIsocPkts=%d aIsocPkts[0]=%d cbDataR3=%d\n", pUrb->enmDir,
3396 pUrb->cIsocPkts, pUrb->aIsocPkts[0].cbPkt, pUrb->cbDataR3));
3397 if (RT_LIKELY(pReq))
3398 {
3399 /*
3400 * Initialize Isoc Xfer, callbacks & timeouts.
3401 */
3402 for (unsigned i = 0; i < pUrb->cIsocPkts; i++)
3403 pReq->isoc_pkt_descr[i].isoc_pkt_length = pUrb->aIsocPkts[i].cbPkt;
3404
3405 if (pUrb->enmDir == VUSBDIRECTION_OUT)
3406 {
3407 pReq->isoc_data = pUrb->pMsg;
3408 pReq->isoc_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_ISOC_XFER_ASAP;
3409 pReq->isoc_cb = vboxUSBSolarisIsocOutXferCompleted;
3410 pReq->isoc_exc_cb = vboxUSBSolarisIsocOutXferCompleted;
3411 pReq->isoc_client_private = (usb_opaque_t)pUrb;
3412 }
3413 else
3414 {
3415 pReq->isoc_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_ISOC_XFER_ASAP | USB_ATTRS_SHORT_XFER_OK;
3416 pReq->isoc_cb = vboxUSBSolarisIsocInXferCompleted;
3417 pReq->isoc_exc_cb = vboxUSBSolarisIsocInXferError;
3418 pReq->isoc_client_private = (usb_opaque_t)pState;
3419 }
3420 pReq->isoc_pkts_count = pUrb->cIsocPkts;
3421 pReq->isoc_pkts_length = 0; /* auto compute */
3422
3423 /*
3424 * Submit the request.
3425 */
3426 rc = usb_pipe_isoc_xfer(pEp->pPipe, pReq, USB_FLAGS_NOSLEEP);
3427 if (RT_LIKELY(rc == USB_SUCCESS))
3428 {
3429 if (pUrb->enmDir == VUSBDIRECTION_IN)
3430 {
3431 /*
3432 * Add the first Isoc. IN URB to the queue as well.
3433 */
3434 mutex_enter(&pState->Mtx);
3435 list_insert_tail(&pEp->hIsocInUrbs, pUrb);
3436 ++pEp->cIsocInUrbs;
3437 pEp->fIsocPolling = true;
3438 mutex_exit(&pState->Mtx);
3439 }
3440
3441 return VINF_SUCCESS;
3442 }
3443 else
3444 {
3445 LogRel((DEVICE_NAME ":vboxUSBSolarisIsocXfer usb_pipe_isoc_xfer failed! rc=%d\n", rc));
3446 rc = VERR_PIPE_IO_ERROR;
3447
3448 if (pUrb->enmDir == VUSBDIRECTION_IN)
3449 {
3450 mutex_enter(&pState->Mtx);
3451 vboxusb_urb_t *pIsocFailedUrb = list_remove_tail(&pEp->hIsocInUrbs);
3452 if (pIsocFailedUrb)
3453 {
3454 RTMemFree(pIsocFailedUrb);
3455 --pEp->cIsocInUrbs;
3456 }
3457 pEp->fIsocPolling = false;
3458 mutex_exit(&pState->Mtx);
3459 }
3460 }
3461
3462 if (pUrb->enmDir == VUSBDIRECTION_OUT) /* pUrb->pMsg freed by caller */
3463 pReq->isoc_data = NULL;
3464
3465 usb_free_isoc_req(pReq);
3466 }
3467 else
3468 {
3469 LogRel((DEVICE_NAME ":vboxUSBSolarisIsocXfer failed to alloc isoc req for %d packets\n", pUrb->cIsocPkts));
3470 rc = VERR_NO_MEMORY;
3471 }
3472
3473 return rc;
3474}
3475
3476
3477/**
3478 * Completion/Exception callback for Isoc IN Xfers.
3479 *
3480 * @param pPipe The Intr pipe handle.
3481 * @param pReq The Intr request.
3482 *
3483 * @remarks Completion callback executes in interrupt context!
3484 */
3485LOCAL void vboxUSBSolarisIsocInXferCompleted(usb_pipe_handle_t pPipe, usb_isoc_req_t *pReq)
3486{
3487// LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted pPipe=%p pReq=%p\n", pPipe, pReq));
3488
3489 vboxusb_state_t *pState = (vboxusb_state_t *)pReq->isoc_client_private;
3490 if (RT_LIKELY(pState))
3491 {
3492 vboxusb_ep_t *pEp = (vboxusb_ep_t *)usb_pipe_get_private(pPipe);
3493 if ( pEp
3494 && pEp->pPipe)
3495 {
3496#if 0
3497 /*
3498 * Stop polling if all packets failed.
3499 */
3500 if (pReq->isoc_error_count == pReq->isoc_pkts_count)
3501 {
3502 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted stopping polling! Too many errors.\n"));
3503 mutex_exit(&pState->Mtx);
3504 usb_pipe_stop_isoc_polling(pPipe, USB_FLAGS_NOSLEEP);
3505 mutex_enter(&pState->Mtx);
3506 pEp->fIsocPolling = false;
3507 }
3508#endif
3509
3510 AssertCompile(sizeof(VUSBISOC_PKT_DESC) == sizeof(usb_isoc_pkt_descr_t));
3511
3512 if (RT_LIKELY(pReq->isoc_data))
3513 {
3514 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted cIsocInUrbs=%d cbIsocInLandedReqs=%d\n", pEp->cIsocInUrbs, pEp->cbIsocInLandedReqs));
3515
3516 mutex_enter(&pState->Mtx);
3517
3518 /*
3519 * If there are waiting URBs, satisfy the oldest one.
3520 */
3521 if ( pEp->cIsocInUrbs > 0
3522 && pEp->cbIsocInLandedReqs == 0)
3523 {
3524 vboxusb_urb_t *pUrb = list_remove_head(&pEp->hIsocInUrbs);
3525 if (RT_LIKELY(pUrb))
3526 {
3527 --pEp->cIsocInUrbs;
3528 mutex_exit(&pState->Mtx);
3529#if 0
3530 for (unsigned i = 0; i < pReq->isoc_pkts_count; i++)
3531 {
3532 pUrb->aIsocPkts[i].cbActPkt = pReq->isoc_pkt_descr[i].isoc_pkt_actual_length;
3533 pUrb->aIsocPkts[i].enmStatus = vboxUSBSolarisGetUrbStatus(pReq->isoc_pkt_descr[i].isoc_pkt_status);
3534 }
3535#else
3536 bcopy(pReq->isoc_pkt_descr, pUrb->aIsocPkts, sizeof(VUSBISOC_PKT_DESC) * pReq->isoc_pkts_count);
3537#endif
3538 pUrb->pMsg = pReq->isoc_data;
3539 pReq->isoc_data = NULL;
3540
3541 /*
3542 * Move to landed list
3543 */
3544 mutex_enter(&pState->Mtx);
3545 list_insert_tail(&pState->hLandedUrbs, pUrb);
3546 vboxUSBSolarisNotifyComplete(pState);
3547 }
3548 else
3549 {
3550 /* Huh!? cIsocInUrbs is wrong then! Should never happen unless we decide to decrement cIsocInUrbs in Reap time */
3551 pEp->cIsocInUrbs = 0;
3552 LogRel((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted Extreme error! Isoc. counter b0rked!\n"));
3553 }
3554
3555 mutex_exit(&pState->Mtx);
3556 usb_free_isoc_req(pReq);
3557 return;
3558 }
3559
3560#if 0
3561 /*
3562 * If the maximum buffer size is reached, discard the oldest data.
3563 */
3564 if (pEp->cbIsocInLandedReqs + MBLKL(pReq->isoc_data) > pEp->cbMaxIsocData)
3565 {
3566 vboxusb_isoc_req_t *pOldReq = list_remove_head(&pEp->hIsocInLandedReqs);
3567 if (RT_LIKELY(pOldReq))
3568 {
3569 pEp->cbIsocInLandedReqs -= MBLKL(pOldReq->pMsg);
3570 kmem_free(pOldReq, sizeof(vboxusb_isoc_req_t));
3571 }
3572 }
3573
3574 mutex_exit(&pState->Mtx);
3575
3576 /*
3577 * Buffer incoming data if the guest has not yet queued any Input URBs.
3578 */
3579 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted Buffering\n"));
3580 vboxusb_isoc_req_t *pIsocReq = kmem_alloc(sizeof(vboxusb_isoc_req_t), KM_NOSLEEP);
3581 if (RT_LIKELY(pIsocReq))
3582 {
3583 pIsocReq->pMsg = pReq->isoc_data;
3584 pReq->isoc_data = NULL;
3585 pIsocReq->cIsocPkts = pReq->isoc_pkts_count;
3586#if 0
3587 for (unsigned i = 0; i < pReq->isoc_pkts_count; i++)
3588 {
3589 pIsocReq->aIsocPkts[i].cbActPkt = pReq->isoc_pkt_descr[i].isoc_pkt_actual_length;
3590 pIsocReq->aIsocPkts[i].enmStatus = vboxUSBSolarisGetUrbStatus(pReq->isoc_pkt_descr[i].isoc_pkt_status);
3591 }
3592#else
3593 bcopy(pReq->isoc_pkt_descr, pIsocReq->aIsocPkts, pReq->isoc_pkts_count * sizeof(VUSBISOC_PKT_DESC));
3594#endif
3595
3596 mutex_enter(&pState->Mtx);
3597 list_insert_tail(&pEp->hIsocInLandedReqs, pIsocReq);
3598 pEp->cbIsocInLandedReqs += MBLKL(pIsocReq->pMsg);
3599 mutex_exit(&pState->Mtx);
3600 }
3601 else
3602 {
3603 LogRel((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted failed to alloc %d bytes for Isoc. queueing\n",
3604 sizeof(vboxusb_isoc_req_t)));
3605 }
3606
3607 /*
3608 * Drain the input URB buffer with the device buffer, queueing them with the landed URBs.
3609 */
3610 mutex_enter(&pState->Mtx);
3611 while (pEp->cIsocInUrbs)
3612 {
3613 vboxusb_urb_t *pUrb = list_remove_head(&pEp->hIsocInUrbs);
3614 if (RT_UNLIKELY(!pUrb))
3615 break;
3616
3617 vboxusb_isoc_req_t *pBuffReq = list_remove_head(&pEp->hIsocInLandedReqs);
3618 if (!pBuffReq)
3619 {
3620 list_insert_head(&pEp->hIsocInUrbs, pUrb);
3621 break;
3622 }
3623
3624 --pEp->cIsocInUrbs;
3625 pEp->cbIsocInLandedReqs -= MBLKL(pBuffReq->pMsg);
3626 mutex_exit(&pState->Mtx);
3627
3628#if 0
3629 for (unsigned i = 0; i < pBuffReq->cIsocPkts; i++)
3630 {
3631 pUrb->aIsocPkts[i].cbActPkt = pBuffReq->aIsocPkts[i].cbActPkt;
3632 pUrb->aIsocPkts[i].enmStatus = pBuffReq->aIsocPkts[i].enmStatus;
3633 }
3634#else
3635 bcopy(pBuffReq->aIsocPkts, pUrb->aIsocPkts, pBuffReq->cIsocPkts * sizeof(VUSBISOC_PKT_DESC));
3636#endif
3637 pUrb->pMsg = pBuffReq->pMsg;
3638 pBuffReq->pMsg = NULL;
3639 kmem_free(pBuffReq, sizeof(vboxusb_isoc_req_t));
3640
3641 /*
3642 * Move to landed list
3643 */
3644 mutex_enter(&pState->Mtx);
3645 list_insert_tail(&pState->hLandedUrbs, pUrb);
3646 vboxUSBSolarisNotifyComplete(pState);
3647 }
3648#endif
3649
3650 mutex_exit(&pState->Mtx);
3651 usb_free_isoc_req(pReq);
3652 return;
3653 }
3654 else
3655 LogRel((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted data missing.\n"));
3656 }
3657 else
3658 LogRel((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted Pipe Gone.\n"));
3659 }
3660 else
3661 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferCompleted State Gone.\n"));
3662
3663 usb_free_isoc_req(pReq);
3664}
3665
3666
3667/**
3668 * Exception callback for Isoc IN Xfers.
3669 *
3670 * @param pPipe The Intr pipe handle.
3671 * @param pReq The Intr request.
3672 * @remarks Completion callback executes in interrupt context!
3673 */
3674LOCAL void vboxUSBSolarisIsocInXferError(usb_pipe_handle_t pPipe, usb_isoc_req_t *pReq)
3675{
3676 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisIsocInXferError pPipe=%p pReq=%p\n", pPipe, pReq));
3677
3678 vboxusb_state_t *pState = (vboxusb_state_t *)pReq->isoc_client_private;
3679 if (RT_UNLIKELY(!pState))
3680 {
3681 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferError State Gone.\n"));
3682 usb_free_isoc_req(pReq);
3683 return;
3684 }
3685
3686 mutex_enter(&pState->Mtx);
3687 vboxusb_ep_t *pEp = (vboxusb_ep_t *)usb_pipe_get_private(pPipe);
3688 if (RT_UNLIKELY(!pEp))
3689 {
3690 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferError Pipe Gone.\n"));
3691 mutex_exit(&pState->Mtx);
3692 usb_free_isoc_req(pReq);
3693 return;
3694 }
3695
3696 switch(pReq->isoc_completion_reason)
3697 {
3698 case USB_CR_NO_RESOURCES:
3699 {
3700 /*
3701 * Resubmit the request in case the original request did not complete due to
3702 * immediately unavailable requests
3703 */
3704 mutex_exit(&pState->Mtx);
3705 usb_pipe_isoc_xfer(pPipe, pReq, USB_FLAGS_NOSLEEP);
3706 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferError resubmmited Isoc. IN request due to immediately unavailable resources.\n"));
3707
3708 return;
3709 }
3710
3711 case USB_CR_PIPE_CLOSING:
3712 case USB_CR_STOPPED_POLLING:
3713 case USB_CR_PIPE_RESET:
3714 {
3715 pEp->fIsocPolling = false;
3716 usb_free_isoc_req(pReq);
3717 break;
3718 }
3719
3720 default:
3721 {
3722 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferError stopping Isoc. In. polling due to rc=%d\n", pReq->isoc_completion_reason));
3723 pEp->fIsocPolling = false;
3724 mutex_exit(&pState->Mtx);
3725 usb_pipe_stop_isoc_polling(pPipe, USB_FLAGS_NOSLEEP);
3726 usb_free_isoc_req(pReq);
3727 mutex_enter(&pState->Mtx);
3728 break;
3729 }
3730 }
3731
3732 /*
3733 * Dequeue i.e. delete the last queued Isoc In. URB. as failed.
3734 */
3735 vboxusb_urb_t *pUrb = list_remove_tail(&pEp->hIsocInUrbs);
3736 if (pUrb)
3737 {
3738 --pEp->cIsocInUrbs;
3739 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocInXferError Deleting last queued URB as it failed.\n"));
3740 freemsg(pUrb->pMsg);
3741 RTMemFree(pUrb);
3742 vboxUSBSolarisNotifyComplete(pState);
3743 }
3744
3745 mutex_exit(&pState->Mtx);
3746}
3747
3748
3749/**
3750 * Completion/Exception callback for Isoc OUT Xfers.
3751 *
3752 * @param pPipe The Intr pipe handle.
3753 * @param pReq The Intr request.
3754 * @remarks Completion callback executes in interrupt context!
3755 */
3756LOCAL void vboxUSBSolarisIsocOutXferCompleted(usb_pipe_handle_t pPipe, usb_isoc_req_t *pReq)
3757{
3758 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisIsocOutXferCompleted pPipe=%p pReq=%p\n", pPipe, pReq));
3759
3760 vboxusb_ep_t *pEp = (vboxusb_ep_t *)usb_pipe_get_private(pPipe);
3761 if (RT_LIKELY(pEp))
3762 {
3763 vboxusb_urb_t *pUrb = (vboxusb_urb_t *)pReq->isoc_client_private;
3764 if (RT_LIKELY(pUrb))
3765 {
3766 size_t cbActPkt = 0;
3767 for (int i = 0; i < pReq->isoc_pkts_count; i++)
3768 {
3769 cbActPkt += pReq->isoc_pkt_descr[i].isoc_pkt_actual_length;
3770 pUrb->aIsocPkts[i].cbActPkt = pReq->isoc_pkt_descr[i].isoc_pkt_actual_length;
3771 pUrb->aIsocPkts[i].enmStatus = vboxUSBSolarisGetUrbStatus(pReq->isoc_pkt_descr[i].isoc_pkt_status);
3772 }
3773
3774 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocOutXferCompleted cIsocPkts=%d cbData=%d cbActPkt=%d\n", pUrb->cIsocPkts, pUrb->cbDataR3, cbActPkt));
3775
3776 if (pReq->isoc_completion_reason == USB_CR_OK)
3777 {
3778 if (RT_UNLIKELY(pUrb->pMsg != pReq->isoc_data)) /* Paranoia */
3779 {
3780 freemsg(pUrb->pMsg);
3781 pUrb->pMsg = pReq->isoc_data;
3782 }
3783 }
3784 pReq->isoc_data = NULL;
3785
3786 pUrb->cIsocPkts = pReq->isoc_pkts_count;
3787 pUrb->cbDataR3 = cbActPkt;
3788
3789 /*
3790 * Update the URB and move to landed list for reaping.
3791 */
3792 vboxUSBSolarisDeQueueURB(pUrb, pReq->isoc_completion_reason);
3793 usb_free_isoc_req(pReq);
3794 return;
3795 }
3796 else
3797 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocOutXferCompleted missing private data!?! Dropping OUT pUrb.\n"));
3798 }
3799 else
3800 LogFlow((DEVICE_NAME ":vboxUSBSolarisIsocOutXferCompleted Pipe Gone.\n"));
3801
3802 usb_free_isoc_req(pReq);
3803}
3804
3805
3806/**
3807 * Callback when the device gets disconnected.
3808 *
3809 * @param pDip The module structure instance.
3810 *
3811 * @returns Solaris USB error code.
3812 */
3813LOCAL int vboxUSBSolarisDeviceDisconnected(dev_info_t *pDip)
3814{
3815 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDeviceDisconnected pDip=%p\n", pDip));
3816
3817 int instance = ddi_get_instance(pDip);
3818 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
3819
3820 if (RT_LIKELY(pState))
3821 {
3822 /*
3823 * Serialize access: exclusive access to the state.
3824 */
3825 usb_serialize_access(pState->StateMulti, USB_WAIT, 0);
3826 mutex_enter(&pState->Mtx);
3827
3828 pState->DevState = USB_DEV_DISCONNECTED;
3829
3830 vboxUSBSolarisCloseAllPipes(pState, true /* ControlPipe */);
3831 vboxUSBSolarisNotifyHotplug(pState);
3832
3833 mutex_exit(&pState->Mtx);
3834 usb_release_access(pState->StateMulti);
3835
3836 return USB_SUCCESS;
3837 }
3838
3839 LogRel((DEVICE_NAME ":vboxUSBSolarisDeviceDisconnected failed to get device state!\n"));
3840 return USB_FAILURE;
3841}
3842
3843
3844/**
3845 * Callback when the device gets reconnected.
3846 *
3847 * @param pDip The module structure instance.
3848 *
3849 * @returns Solaris USB error code.
3850 */
3851LOCAL int vboxUSBSolarisDeviceReconnected(dev_info_t *pDip)
3852{
3853 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDeviceReconnected pDip=%p\n", pDip));
3854
3855 int instance = ddi_get_instance(pDip);
3856 vboxusb_state_t *pState = ddi_get_soft_state(g_pVBoxUSBSolarisState, instance);
3857
3858 if (RT_LIKELY(pState))
3859 {
3860 vboxUSBSolarisDeviceRestore(pState);
3861 return USB_SUCCESS;
3862 }
3863
3864 LogRel((DEVICE_NAME ":vboxUSBSolarisDeviceReconnected failed to get device state!\n"));
3865 return USB_FAILURE;
3866}
3867
3868
3869/**
3870 * Restore device state after a reconnect or resume.
3871 *
3872 * @param pState The USB device instance.
3873 */
3874LOCAL void vboxUSBSolarisDeviceRestore(vboxusb_state_t *pState)
3875{
3876 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDeviceRestore pState=%p\n", pState));
3877 AssertPtrReturnVoid(pState);
3878
3879 /*
3880 * Raise device power.
3881 */
3882 vboxUSBSolarisPowerBusy(pState);
3883 int rc = pm_raise_power(pState->pDip, 0 /* component */, USB_DEV_OS_FULL_PWR);
3884
3885 /*
3886 * Check if the same device is resumed/reconnected.
3887 */
3888 rc = usb_check_same_device(pState->pDip,
3889 NULL, /* log handle */
3890 USB_LOG_L2, /* log level */
3891 -1, /* log mask */
3892 USB_CHK_ALL, /* check level */
3893 NULL); /* device string */
3894
3895 if (rc != USB_SUCCESS)
3896 {
3897 mutex_enter(&pState->Mtx);
3898 pState->DevState = USB_DEV_DISCONNECTED;
3899 mutex_exit(&pState->Mtx);
3900
3901 /* Do we need to inform userland here? */
3902 vboxUSBSolarisPowerIdle(pState);
3903 LogFlow((DEVICE_NAME ":vboxUSBSolarisDeviceRestore not the same device.\n"));
3904 return;
3905 }
3906
3907 /*
3908 * Serialize access to not race with other PM functions.
3909 */
3910 usb_serialize_access(pState->StateMulti, USB_WAIT, 0);
3911
3912 mutex_enter(&pState->Mtx);
3913 if (pState->DevState == USB_DEV_DISCONNECTED)
3914 pState->DevState = USB_DEV_ONLINE;
3915 else if (pState->DevState == USB_DEV_SUSPENDED)
3916 pState->DevState = USB_DEV_ONLINE;
3917
3918 mutex_exit(&pState->Mtx);
3919 usb_release_access(pState->StateMulti);
3920
3921 vboxUSBSolarisPowerIdle(pState);
3922}
3923
3924
3925/**
3926 * Restore device state after a reconnect or resume.
3927 *
3928 * @param pState The USB device instance.
3929 *
3930 * @returns VBox status code.
3931 */
3932LOCAL int vboxUSBSolarisDeviceSuspend(vboxusb_state_t *pState)
3933{
3934 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDeviceSuspend pState=%p\n", pState));
3935
3936 int rc = VERR_VUSB_DEVICE_IS_SUSPENDED;
3937 mutex_enter(&pState->Mtx);
3938
3939 switch (pState->DevState)
3940 {
3941 case USB_DEV_SUSPENDED:
3942 {
3943 LogRel((DEVICE_NAME ":vboxUSBSolarisDeviceSuspend: Invalid device state %d\n", pState->DevState));
3944 break;
3945 }
3946
3947 case USB_DEV_ONLINE:
3948 case USB_DEV_DISCONNECTED:
3949 case USB_DEV_PWRED_DOWN:
3950 {
3951 int PreviousState = pState->DevState;
3952 pState->DevState = USB_DEV_DISCONNECTED;
3953
3954 /*
3955 * Drain pending URBs.
3956 */
3957 for (int i = 0; i < VBOXUSB_DRAIN_TIME; i++)
3958 {
3959 if (pState->cInflightUrbs < 1)
3960 break;
3961
3962 mutex_exit(&pState->Mtx);
3963 delay(drv_usectohz(100000));
3964 mutex_enter(&pState->Mtx);
3965 }
3966
3967 /*
3968 * Deny suspend if we still have pending URBs.
3969 */
3970 if (pState->cInflightUrbs > 0)
3971 {
3972 pState->DevState = PreviousState;
3973 LogRel((DEVICE_NAME ":Cannot suspend, still have %d inflight URBs.\n", pState->cInflightUrbs));
3974
3975 mutex_exit(&pState->Mtx);
3976 return VERR_RESOURCE_BUSY;
3977 }
3978
3979 pState->cInflightUrbs = 0;
3980
3981 /*
3982 * Serialize access to not race with Open/Detach/Close and
3983 * Close all pipes including the default pipe.
3984 */
3985 mutex_exit(&pState->Mtx);
3986 usb_serialize_access(pState->StateMulti, USB_WAIT, 0);
3987 mutex_enter(&pState->Mtx);
3988
3989 vboxUSBSolarisCloseAllPipes(pState, true /* default pipe */);
3990 vboxUSBSolarisNotifyHotplug(pState);
3991
3992 mutex_exit(&pState->Mtx);
3993 usb_release_access(pState->StateMulti);
3994 return VINF_SUCCESS;
3995 }
3996 }
3997
3998 mutex_exit(&pState->Mtx);
3999 LogFlow((DEVICE_NAME ":vboxUSBSolarisDeviceSuspend returns %d\n", rc));
4000 return rc;
4001}
4002
4003
4004/**
4005 * Restore device state after a reconnect or resume.
4006 *
4007 * @param pState The USB device instance.
4008 */
4009LOCAL void vboxUSBSolarisDeviceResume(vboxusb_state_t *pState)
4010{
4011 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisDeviceResume pState=%p\n", pState));
4012 return vboxUSBSolarisDeviceRestore(pState);
4013}
4014
4015
4016/**
4017 * Flag the PM component as busy so the system will not manage it's power.
4018 *
4019 * @param pState The USB device instance.
4020 */
4021LOCAL void vboxUSBSolarisPowerBusy(vboxusb_state_t *pState)
4022{
4023 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisPowerBusy pState=%p\n", pState));
4024 AssertPtrReturnVoid(pState);
4025
4026 mutex_enter(&pState->Mtx);
4027 if (pState->pPower)
4028 {
4029 pState->pPower->PowerBusy++;
4030 mutex_exit(&pState->Mtx);
4031
4032 int rc = pm_busy_component(pState->pDip, 0 /* component */);
4033 if (rc != DDI_SUCCESS)
4034 {
4035 LogFlow((DEVICE_NAME ":vboxUSBSolarisPowerBusy busy component failed! rc=%d\n", rc));
4036 mutex_enter(&pState->Mtx);
4037 pState->pPower->PowerBusy--;
4038 mutex_exit(&pState->Mtx);
4039 }
4040 }
4041 else
4042 mutex_exit(&pState->Mtx);
4043}
4044
4045
4046/**
4047 * Flag the PM component as idle so its power managed by the system.
4048 *
4049 * @param pState The USB device instance.
4050 */
4051LOCAL void vboxUSBSolarisPowerIdle(vboxusb_state_t *pState)
4052{
4053 LogFlowFunc((DEVICE_NAME ":vboxUSBSolarisPowerIdle pState=%p\n", pState));
4054 AssertPtrReturnVoid(pState);
4055
4056 if (pState->pPower)
4057 {
4058 int rc = pm_idle_component(pState->pDip, 0 /* component */);
4059 if (rc == DDI_SUCCESS)
4060 {
4061 mutex_enter(&pState->Mtx);
4062 Assert(pState->pPower->PowerBusy > 0);
4063 pState->pPower->PowerBusy--;
4064 mutex_exit(&pState->Mtx);
4065 }
4066 else
4067 LogFlow((DEVICE_NAME ":vboxUSBSolarisPowerIdle idle component failed! rc=%d\n", rc));
4068 }
4069}
4070
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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