VirtualBox

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

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

HostDrivers: Updated (C) year.

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