VirtualBox

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

Last change on this file since 43346 was 41700, checked in by vboxsync, 13 years ago

Solaris: license header update for kernel bits.

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