VirtualBox

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

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

VBoxUSB/solaris: comment typo.

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

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