VirtualBox

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

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

VBoxUSB/solaris: undo temporary change.

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

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