VirtualBox

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

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

HostDrivers/VBoxUSB/solaris: LogRel device capture/release and fix misleading variable names.

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