VirtualBox

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

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

*: scm cleanup run.

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