VirtualBox

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

Last change on this file since 52748 was 52748, checked in by vboxsync, 10 years ago

VBoxUSB/solaris: Another shot at getting logging, temporary change.

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

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