~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/HostDrivers/VBoxUSB/solaris/VBoxUSB-solaris.c

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

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