VirtualBox

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

Last change on this file since 37808 was 36361, checked in by vboxsync, 14 years ago

fix solaris debug builds

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.2 KB
Line 
1/* $Id: VBoxUSBMon-solaris.c 36361 2011-03-23 10:37:49Z vboxsync $ */
2/** @file
3 * VirtualBox USB Monitor Driver, Solaris Hosts.
4 */
5
6/*
7 * Copyright (C) 2008 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_USB_DRV
22#include "VBoxUSBFilterMgr.h"
23#include <VBox/usblib-solaris.h>
24#include <VBox/version.h>
25#include <VBox/log.h>
26#include <VBox/cdefs.h>
27#include <VBox/types.h>
28#include <VBox/version.h>
29#include <iprt/assert.h>
30#include <iprt/string.h>
31#include <iprt/initterm.h>
32#include <iprt/process.h>
33#include <iprt/mem.h>
34#include <iprt/semaphore.h>
35#include <iprt/path.h>
36
37#define USBDRV_MAJOR_VER 2
38#define USBDRV_MINOR_VER 0
39#include <sys/usb/usba.h>
40#include <sys/conf.h>
41#include <sys/modctl.h>
42#include <sys/mutex.h>
43#include <sys/stat.h>
44#include <sys/ddi.h>
45#include <sys/sunddi.h>
46#include <sys/sunndi.h>
47#include <sys/open.h>
48#include <sys/cmn_err.h>
49
50
51/*******************************************************************************
52* Defined Constants And Macros *
53*******************************************************************************/
54/** The module name. */
55#define DEVICE_NAME "vboxusbmon"
56/** The module description as seen in 'modinfo'. */
57#define DEVICE_DESC_DRV "VirtualBox USBMon"
58
59#if defined(DEBUG_ramshankar)
60# undef LogFlowFunc
61# define LogFlowFunc LogRel
62# undef Log
63# define Log LogRel
64# undef LogFlow
65# define LogFlow LogRel
66#endif
67
68/*******************************************************************************
69* Internal Functions *
70*******************************************************************************/
71static int VBoxUSBMonSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
72static int VBoxUSBMonSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
73static int VBoxUSBMonSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
74static int VBoxUSBMonSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
75static int VBoxUSBMonSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal);
76static int VBoxUSBMonSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
77static int VBoxUSBMonSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
78static int VBoxUSBMonSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
79
80/*******************************************************************************
81* Structures and Typedefs *
82*******************************************************************************/
83/**
84 * cb_ops: for drivers that support char/block entry points
85 */
86static struct cb_ops g_VBoxUSBMonSolarisCbOps =
87{
88 VBoxUSBMonSolarisOpen,
89 VBoxUSBMonSolarisClose,
90 nodev, /* b strategy */
91 nodev, /* b dump */
92 nodev, /* b print */
93 VBoxUSBMonSolarisRead,
94 VBoxUSBMonSolarisWrite,
95 VBoxUSBMonSolarisIOCtl,
96 nodev, /* c devmap */
97 nodev, /* c mmap */
98 nodev, /* c segmap */
99 nochpoll, /* c poll */
100 ddi_prop_op, /* property ops */
101 NULL, /* streamtab */
102 D_NEW | D_MP, /* compat. flag */
103 CB_REV /* revision */
104};
105
106/**
107 * dev_ops: for driver device operations
108 */
109static struct dev_ops g_VBoxUSBMonSolarisDevOps =
110{
111 DEVO_REV, /* driver build revision */
112 0, /* ref count */
113 VBoxUSBMonSolarisGetInfo,
114 nulldev, /* identify */
115 nulldev, /* probe */
116 VBoxUSBMonSolarisAttach,
117 VBoxUSBMonSolarisDetach,
118 nodev, /* reset */
119 &g_VBoxUSBMonSolarisCbOps,
120 (struct bus_ops *)0,
121 nodev /* power */
122};
123
124/**
125 * modldrv: export driver specifics to the kernel
126 */
127static struct modldrv g_VBoxUSBMonSolarisModule =
128{
129 &mod_driverops, /* extern from kernel */
130 DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
131 &g_VBoxUSBMonSolarisDevOps
132};
133
134/**
135 * modlinkage: export install/remove/info to the kernel
136 */
137static struct modlinkage g_VBoxUSBMonSolarisModLinkage =
138{
139 MODREV_1,
140 &g_VBoxUSBMonSolarisModule,
141 NULL,
142};
143
144/**
145 * Client driver info.
146 */
147typedef struct vboxusbmon_client_t
148{
149 dev_info_t *pDip; /* Client device info. pointer */
150 VBOXUSB_CLIENT_INFO Info; /* Client registration data. */
151 struct vboxusbmon_client_t *pNext; /* Pointer to next client */
152} vboxusbmon_client_t;
153
154/**
155 * Device state info.
156 */
157typedef struct
158{
159 RTPROCESS Process; /* The process (id) of the session */
160} vboxusbmon_state_t;
161
162
163/*******************************************************************************
164* Global Variables *
165*******************************************************************************/
166/** Global Device handle we only support one instance. */
167static dev_info_t *g_pDip;
168/** Global Mutex. */
169static kmutex_t g_VBoxUSBMonSolarisMtx;
170/** Number of userland clients that have kept us open. */
171static uint64_t g_cVBoxUSBMonSolarisClient = 0;
172/** Global list of client drivers registered with us. */
173vboxusbmon_client_t *g_pVBoxUSBMonSolarisClients = 0;
174/** Opaque pointer to list of soft states. */
175static void *g_pVBoxUSBMonSolarisState;
176
177/*******************************************************************************
178* Internal Functions *
179*******************************************************************************/
180static int vboxUSBMonSolarisProcessIOCtl(int iFunction, void *pvState, void *pvData, size_t cbData, size_t *pcbReturnedData);
181static int vboxUSBMonSolarisResetDevice(char *pszDevicePath, bool fReattach);
182
183
184/*******************************************************************************
185* Monitor Global Hooks *
186*******************************************************************************/
187static int vboxUSBMonSolarisClientInfo(vboxusbmon_state_t *pState, PVBOXUSB_CLIENT_INFO pClientInfo);
188int VBoxUSBMonSolarisRegisterClient(dev_info_t *pClientDip, PVBOXUSB_CLIENT_INFO pClientInfo);
189int VBoxUSBMonSolarisUnregisterClient(dev_info_t *pClientDip);
190int VBoxUSBMonSolarisElectDriver(usb_dev_descr_t *pDevDesc, usb_dev_str_t *pDevStrings, char *pszDevicePath, int Bus, int Port,
191 char **ppszDrv, void *pvReserved);
192
193
194/**
195 * Kernel entry points
196 */
197int _init(void)
198{
199 int rc;
200
201 LogFlowFunc((DEVICE_NAME ":_init\n"));
202
203 g_pDip = NULL;
204
205 /*
206 * Prevent module autounloading.
207 */
208 modctl_t *pModCtl = mod_getctl(&g_VBoxUSBMonSolarisModLinkage);
209 if (pModCtl)
210 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
211 else
212 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
213
214 /*
215 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
216 */
217 rc = RTR0Init(0);
218 if (RT_SUCCESS(rc))
219 {
220 /*
221 * Initialize global mutex.
222 */
223 mutex_init(&g_VBoxUSBMonSolarisMtx, NULL, MUTEX_DRIVER, NULL);
224 rc = VBoxUSBFilterInit();
225 if (RT_SUCCESS(rc))
226 {
227 rc = ddi_soft_state_init(&g_pVBoxUSBMonSolarisState, sizeof(vboxusbmon_state_t), 1);
228 if (!rc)
229 {
230 rc = mod_install(&g_VBoxUSBMonSolarisModLinkage);
231 if (!rc)
232 return rc;
233
234 LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
235 ddi_soft_state_fini(&g_pVBoxUSBMonSolarisState);
236 }
237 else
238 LogRel((DEVICE_NAME ":ddi_soft_state_init failed! rc=%d\n", rc));
239 }
240 else
241 LogRel((DEVICE_NAME ":VBoxUSBFilterInit failed! rc=%d\n", rc));
242
243 mutex_destroy(&g_VBoxUSBMonSolarisMtx);
244 RTR0Term();
245 }
246 else
247 LogRel((DEVICE_NAME ":RTR0Init failed! rc=%d\n", rc));
248
249 return -1;
250}
251
252
253int _fini(void)
254{
255 int rc;
256
257 LogFlowFunc((DEVICE_NAME ":_fini\n"));
258
259 rc = mod_remove(&g_VBoxUSBMonSolarisModLinkage);
260 if (!rc)
261 {
262 ddi_soft_state_fini(&g_pVBoxUSBMonSolarisState);
263 VBoxUSBFilterTerm();
264 mutex_destroy(&g_VBoxUSBMonSolarisMtx);
265
266 RTR0Term();
267 }
268 return rc;
269}
270
271
272int _info(struct modinfo *pModInfo)
273{
274 LogFlowFunc((DEVICE_NAME ":_info\n"));
275
276 return mod_info(&g_VBoxUSBMonSolarisModLinkage, pModInfo);
277}
278
279
280/**
281 * Attach entry point, to attach a device to the system or resume it.
282 *
283 * @param pDip The module structure instance.
284 * @param enmCmd Attach type (ddi_attach_cmd_t)
285 *
286 * @returns corresponding solaris error code.
287 */
288static int VBoxUSBMonSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
289{
290 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
291 switch (enmCmd)
292 {
293 case DDI_ATTACH:
294 {
295 vboxusbmon_state_t *pState = NULL;
296 int instance = ddi_get_instance(pDip);
297 int rc;
298
299 pState = RTMemAllocZ(sizeof(*pState));
300 if (pState)
301 {
302 g_pDip = pDip;
303 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0,
304 "none", "none", 0666);
305 if (rc == DDI_SUCCESS)
306 {
307 ddi_set_driver_private(pDip, pState);
308 ddi_report_dev(pDip);
309 return rc;
310 }
311 else
312 LogRel((DEVICE_NAME ":ddi_create_minor_node failed! rc=%d\n", rc));
313 RTMemFree(pState);
314 }
315 else
316 LogRel((DEVICE_NAME ":RTMemAllocZ failed to allocated %d bytes for pState\n", sizeof(*pState)));
317 return DDI_FAILURE;
318 }
319
320 case DDI_RESUME:
321 {
322 /* We don't have to bother about power management. */
323 return DDI_SUCCESS;
324 }
325
326 default:
327 return DDI_FAILURE;
328 }
329}
330
331
332/**
333 * Detach entry point, to detach a device to the system or suspend it.
334 *
335 * @param pDip The module structure instance.
336 * @param enmCmd Attach type (ddi_attach_cmd_t)
337 *
338 * @returns corresponding solaris error code.
339 */
340static int VBoxUSBMonSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
341{
342 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisDetach\n"));
343
344 switch (enmCmd)
345 {
346 case DDI_DETACH:
347 {
348 /*
349 * Free all registered clients' info.
350 */
351 mutex_enter(&g_VBoxUSBMonSolarisMtx);
352 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
353 while (pCur)
354 {
355 vboxusbmon_client_t *pNext = pCur->pNext;
356 RTMemFree(pCur);
357 pCur = pNext;
358 }
359 mutex_exit(&g_VBoxUSBMonSolarisMtx);
360
361 vboxusbmon_state_t *pState = ddi_get_driver_private(g_pDip);
362 if (pState)
363 {
364 ddi_remove_minor_node(pDip, NULL);
365 RTMemFree(pState);
366 return DDI_SUCCESS;
367 }
368 else
369 LogRel((DEVICE_NAME ":failed to get soft state on detach.\n"));
370 break;
371 }
372
373 case DDI_SUSPEND:
374 {
375 /* We don't have to bother about power management. */
376 return DDI_SUCCESS;
377 }
378
379 default:
380 return DDI_FAILURE;
381 }
382}
383
384
385/**
386 * Info entry point, called by solaris kernel for obtaining driver info.
387 *
388 * @param pDip The module structure instance (do not use).
389 * @param enmCmd Information request type.
390 * @param pvArg Type specific argument.
391 * @param ppvResult Where to store the requested info.
392 *
393 * @returns corresponding solaris error code.
394 */
395static int VBoxUSBMonSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
396{
397 int rc = DDI_SUCCESS;
398
399 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisGetInfo\n"));
400
401 switch (enmCmd)
402 {
403 case DDI_INFO_DEVT2DEVINFO:
404 *ppvResult = (void *)g_pDip;
405 break;
406
407 case DDI_INFO_DEVT2INSTANCE:
408 *ppvResult = (void *)(uintptr_t)ddi_get_instance(g_pDip);
409 break;
410
411 default:
412 rc = DDI_FAILURE;
413 break;
414 }
415 return rc;
416}
417
418
419static int VBoxUSBMonSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
420{
421 vboxusbmon_state_t *pState = NULL;
422 unsigned iOpenInstance;
423
424 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisOpen\n"));
425
426 /*
427 * Verify we are being opened as a character device
428 */
429 if (fType != OTYP_CHR)
430 return EINVAL;
431
432 /*
433 * Verify that we're called after attach
434 */
435 if (!g_pDip)
436 {
437 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisOpen invalid state for opening.\n"));
438 return ENXIO;
439 }
440
441 mutex_enter(&g_VBoxUSBMonSolarisMtx);
442 if (!g_cVBoxUSBMonSolarisClient)
443 {
444 mutex_exit(&g_VBoxUSBMonSolarisMtx);
445 int rc = usb_register_dev_driver(g_pDip, VBoxUSBMonSolarisElectDriver);
446 if (RT_UNLIKELY(rc != DDI_SUCCESS))
447 {
448 LogRel((DEVICE_NAME ":Failed to register driver election callback with USBA rc=%d\n", rc));
449 return EINVAL;
450 }
451 LogFlow((DEVICE_NAME ":Successfully registered election callback with USBA\n"));
452 mutex_enter(&g_VBoxUSBMonSolarisMtx);
453 }
454 g_cVBoxUSBMonSolarisClient++;
455 mutex_exit(&g_VBoxUSBMonSolarisMtx);
456
457 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
458 {
459 if ( !ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance) /* faster */
460 && ddi_soft_state_zalloc(g_pVBoxUSBMonSolarisState, iOpenInstance) == DDI_SUCCESS)
461 {
462 pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, iOpenInstance);
463 break;
464 }
465 }
466 if (!pState)
467 {
468 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisOpen: too many open instances."));
469 mutex_enter(&g_VBoxUSBMonSolarisMtx);
470 g_cVBoxUSBMonSolarisClient--;
471 mutex_exit(&g_VBoxUSBMonSolarisMtx);
472 return ENXIO;
473 }
474
475 pState->Process = RTProcSelf();
476 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
477
478 NOREF(fFlag);
479 NOREF(pCred);
480
481 return 0;
482}
483
484
485static int VBoxUSBMonSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred)
486{
487 vboxusbmon_state_t *pState = NULL;
488
489 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisClose\n"));
490
491 pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, getminor(Dev));
492 if (!pState)
493 {
494 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisClose: failed to get pState.\n"));
495 return EFAULT;
496 }
497
498 mutex_enter(&g_VBoxUSBMonSolarisMtx);
499 g_cVBoxUSBMonSolarisClient--;
500 if (!g_cVBoxUSBMonSolarisClient)
501 {
502 if (RT_LIKELY(g_pDip))
503 {
504 mutex_exit(&g_VBoxUSBMonSolarisMtx);
505 usb_unregister_dev_driver(g_pDip);
506 LogFlow((DEVICE_NAME ":Successfully deregistered driver election callback\n"));
507 }
508 else
509 {
510 mutex_exit(&g_VBoxUSBMonSolarisMtx);
511 LogRel((DEVICE_NAME ":Extreme error! Missing device info during close.\n"));
512 }
513 }
514 else
515 mutex_exit(&g_VBoxUSBMonSolarisMtx);
516
517 /*
518 * Remove all filters for this client process.
519 */
520 VBoxUSBFilterRemoveOwner(pState->Process);
521
522 ddi_soft_state_free(g_pVBoxUSBMonSolarisState, getminor(Dev));
523 pState = NULL;
524
525 NOREF(fFlag);
526 NOREF(fType);
527 NOREF(pCred);
528
529 return 0;
530}
531
532
533static int VBoxUSBMonSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
534{
535 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisRead\n"));
536 return 0;
537}
538
539
540static int VBoxUSBMonSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
541{
542 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisWrite\n"));
543 return 0;
544}
545
546
547/** @def IOCPARM_LEN
548 * Gets the length from the ioctl number.
549 * This is normally defined by sys/ioccom.h on BSD systems...
550 */
551#ifndef IOCPARM_LEN
552# define IOCPARM_LEN(Code) (((Code) >> 16) & IOCPARM_MASK)
553#endif
554
555static int VBoxUSBMonSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
556{
557 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl Dev=%d Cmd=%d pArg=%p Mode=%d\n", Dev, Cmd, pArg));
558
559 /*
560 * Get the session from the soft state item.
561 */
562 vboxusbmon_state_t *pState = ddi_get_soft_state(g_pVBoxUSBMonSolarisState, getminor(Dev));
563 if (!pState)
564 {
565 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: no state data for %d\n", getminor(Dev)));
566 return EINVAL;
567 }
568
569 /*
570 * Read the request wrapper. Though We don't really need wrapper struct. now
571 * it's room for the future as Solaris isn't generous regarding the size.
572 */
573 VBOXUSBREQ ReqWrap;
574 if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
575 {
576 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
577 return ENOTTY;
578 }
579
580 int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
581 if (RT_UNLIKELY(rc))
582 {
583 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%d.\n", pArg, Cmd, rc));
584 return EINVAL;
585 }
586
587 if (ReqWrap.u32Magic != VBOXUSBMON_MAGIC)
588 {
589 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad magic %#x; pArg=%p Cmd=%d.\n", ReqWrap.u32Magic, pArg, Cmd));
590 return EINVAL;
591 }
592 if (RT_UNLIKELY( ReqWrap.cbData == 0
593 || ReqWrap.cbData > _1M*16))
594 {
595 LogRel((DEVICE_NAME ": VBoxUSBMonSolarisIOCtl: bad size %#x; pArg=%p Cmd=%d.\n", ReqWrap.cbData, pArg, Cmd));
596 return EINVAL;
597 }
598
599 /*
600 * Read the request.
601 */
602 void *pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
603 if (RT_UNLIKELY(!pvBuf))
604 {
605 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
606 return ENOMEM;
607 }
608
609 rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
610 if (RT_UNLIKELY(rc))
611 {
612 RTMemTmpFree(pvBuf);
613 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
614 return EFAULT;
615 }
616 if (RT_UNLIKELY( ReqWrap.cbData != 0
617 && !VALID_PTR(pvBuf)))
618 {
619 RTMemTmpFree(pvBuf);
620 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: pvBuf invalid pointer %p\n", pvBuf));
621 return EINVAL;
622 }
623 LogFlow((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: pid=%d.\n", (int)RTProcSelf()));
624
625 /*
626 * Process the IOCtl.
627 */
628 size_t cbDataReturned;
629 rc = vboxUSBMonSolarisProcessIOCtl(Cmd, pState, pvBuf, ReqWrap.cbData, &cbDataReturned);
630 ReqWrap.rc = rc;
631 rc = 0;
632
633 if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
634 {
635 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
636 cbDataReturned = ReqWrap.cbData;
637 }
638
639 ReqWrap.cbData = cbDataReturned;
640
641 /*
642 * Copy the request back to user space.
643 */
644 rc = ddi_copyout(&ReqWrap, (void *)pArg, sizeof(ReqWrap), Mode);
645 if (RT_LIKELY(!rc))
646 {
647 /*
648 * Copy the payload (if any) back to user space.
649 */
650 if (cbDataReturned > 0)
651 {
652 rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
653 if (RT_UNLIKELY(rc))
654 {
655 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
656 rc = EFAULT;
657 }
658 }
659 }
660 else
661 {
662 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisIOCtl: ddi_copyout(1) failed pArg=%p Cmd=%d\n", pArg, Cmd));
663 rc = EFAULT;
664 }
665
666 *pVal = rc;
667 RTMemTmpFree(pvBuf);
668 return rc;
669}
670
671
672/**
673 * IOCtl processor for user to kernel and kernel to kernel communication.
674 *
675 * @returns VBox status code.
676 *
677 * @param iFunction The requested function.
678 * @param pvState Opaque pointer to driver state used for getting ring-3 process (Id).
679 * @param pvData The input/output data buffer. Can be NULL depending on the function.
680 * @param cbData The max size of the data buffer.
681 * @param pcbDataReturned Where to store the amount of returned data. Can be NULL.
682 */
683static int vboxUSBMonSolarisProcessIOCtl(int iFunction, void *pvState, void *pvData, size_t cbData, size_t *pcbReturnedData)
684{
685 LogFlowFunc((DEVICE_NAME ":solarisUSBProcessIOCtl iFunction=%d pvBuf=%p cbBuf=%zu\n", iFunction, pvData, cbData));
686
687 AssertPtrReturn(pvState, VERR_INVALID_POINTER);
688 vboxusbmon_state_t *pState = (vboxusbmon_state_t *)pvState;
689 int rc;
690
691#define CHECKRET_MIN_SIZE(mnemonic, cbMin) \
692 do { \
693 if (cbData < (cbMin)) \
694 { \
695 LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": cbData=%#zx (%zu) min is %#zx (%zu)\n", \
696 cbData, cbData, (size_t)(cbMin), (size_t)(cbMin))); \
697 return VERR_BUFFER_OVERFLOW; \
698 } \
699 if ((cbMin) != 0 && !VALID_PTR(pvData)) \
700 { \
701 LogRel(("vboxUSBSolarisProcessIOCtl: " mnemonic ": Invalid pointer %p\n", pvData)); \
702 return VERR_INVALID_POINTER; \
703 } \
704 } while (0)
705
706 switch (iFunction)
707 {
708 case VBOXUSBMON_IOCTL_ADD_FILTER:
709 {
710 CHECKRET_MIN_SIZE("ADD_FILTER", sizeof(VBOXUSBREQ_ADD_FILTER));
711
712 VBOXUSBREQ_ADD_FILTER *pReq = (VBOXUSBREQ_ADD_FILTER *)pvData;
713 PUSBFILTER pFilter = (PUSBFILTER)&pReq->Filter;
714
715 LogFlow(("vboxUSBMonSolarisProcessIOCtl: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
716 USBFilterGetNum(pFilter, USBFILTERIDX_VENDOR_ID),
717 USBFilterGetNum(pFilter, USBFILTERIDX_PRODUCT_ID),
718 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_REV),
719 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_CLASS),
720 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_SUB_CLASS),
721 USBFilterGetNum(pFilter, USBFILTERIDX_DEVICE_PROTOCOL),
722 USBFilterGetNum(pFilter, USBFILTERIDX_BUS),
723 USBFilterGetNum(pFilter, USBFILTERIDX_PORT)));
724 LogFlow(("vboxUSBMonSolarisProcessIOCtl: Manufacturer=%s Product=%s Serial=%s\n",
725 USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
726 USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_PRODUCT_STR) : "<null>",
727 USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(pFilter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
728
729 rc = USBFilterSetMustBePresent(pFilter, USBFILTERIDX_BUS, false /* fMustBePresent */); AssertRC(rc);
730
731 rc = VBoxUSBFilterAdd(pFilter, pState->Process, &pReq->uId);
732 *pcbReturnedData = cbData;
733 LogFlow((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: ADD_FILTER (Process:%d) returned %d\n", pState->Process, rc));
734 break;
735 }
736
737 case VBOXUSBMON_IOCTL_REMOVE_FILTER:
738 {
739 CHECKRET_MIN_SIZE("REMOVE_FILTER", sizeof(VBOXUSBREQ_REMOVE_FILTER));
740
741 VBOXUSBREQ_REMOVE_FILTER *pReq = (VBOXUSBREQ_REMOVE_FILTER *)pvData;
742 rc = VBoxUSBFilterRemove(pState->Process, (uintptr_t)pReq->uId);
743 *pcbReturnedData = 0;
744 LogFlow((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: REMOVE_FILTER (Process:%d) returned %d\n", pState->Process, rc));
745 break;
746 }
747
748 case VBOXUSBMON_IOCTL_RESET_DEVICE:
749 {
750 CHECKRET_MIN_SIZE("RESET_DEVICE", sizeof(VBOXUSBREQ_RESET_DEVICE));
751
752 VBOXUSBREQ_RESET_DEVICE *pReq = (VBOXUSBREQ_RESET_DEVICE *)pvData;
753 rc = vboxUSBMonSolarisResetDevice(pReq->szDevicePath, pReq->fReattach);
754 *pcbReturnedData = 0;
755 LogFlow((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: RESET_DEVICE (Process:%d) returned %d\n", pState->Process, rc));
756 break;
757 }
758
759 case VBOXUSBMON_IOCTL_CLIENT_INFO:
760 {
761 CHECKRET_MIN_SIZE("CLIENT_INFO", sizeof(VBOXUSBREQ_CLIENT_INFO));
762
763 VBOXUSBREQ_CLIENT_INFO *pReq = (VBOXUSBREQ_CLIENT_INFO *)pvData;
764 rc = vboxUSBMonSolarisClientInfo(pState, pReq);
765 *pcbReturnedData = cbData;
766 LogFlow((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: CLIENT_INFO (Process:%d) returned %d\n", pState->Process, rc));
767 break;
768 }
769
770 case VBOXUSBMON_IOCTL_GET_VERSION:
771 {
772 CHECKRET_MIN_SIZE("GET_VERSION", sizeof(VBOXUSBREQ_GET_VERSION));
773
774 PVBOXUSBREQ_GET_VERSION pGetVersionReq = (PVBOXUSBREQ_GET_VERSION)pvData;
775 pGetVersionReq->u32Major = VBOXUSBMON_VERSION_MAJOR;
776 pGetVersionReq->u32Minor = VBOXUSBMON_VERSION_MINOR;
777 *pcbReturnedData = sizeof(VBOXUSBREQ_GET_VERSION);
778 rc = VINF_SUCCESS;
779 LogFlow((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: GET_VERSION returned %d\n", rc));
780 break;
781 }
782
783 default:
784 {
785 LogRel((DEVICE_NAME ":vboxUSBMonSolarisProcessIOCtl: Unknown request (Process:%d) %#x\n", pState->Process, iFunction));
786 rc = VERR_NOT_SUPPORTED;
787 break;
788 }
789 }
790 return rc;
791}
792
793
794static int vboxUSBMonSolarisResetDevice(char *pszDevicePath, bool fReattach)
795{
796 int rc = VERR_GENERAL_FAILURE;
797
798 LogFlowFunc((DEVICE_NAME ":vboxUSBMonSolarisResetDevice pszDevicePath=%s fReattach=%d\n", pszDevicePath, fReattach));
799
800 /*
801 * Try grabbing the dev_info_t.
802 */
803 dev_info_t *pDeviceInfo = e_ddi_hold_devi_by_path(pszDevicePath, 0);
804 if (pDeviceInfo)
805 {
806 ddi_release_devi(pDeviceInfo);
807
808 /*
809 * Grab the root device node from the parent hub for resetting.
810 */
811 dev_info_t *pTmpDeviceInfo = NULL;
812 for (;;)
813 {
814 pTmpDeviceInfo = ddi_get_parent(pDeviceInfo);
815 if (!pTmpDeviceInfo)
816 {
817 LogRel((DEVICE_NAME ":vboxUSBMonSolarisResetDevice failed to get parent device info for %s\n", pszDevicePath));
818 return VERR_GENERAL_FAILURE;
819 }
820
821 if (ddi_prop_exists(DDI_DEV_T_ANY, pTmpDeviceInfo, DDI_PROP_DONTPASS, "usb-port-count")) /* parent hub */
822 break;
823
824 pDeviceInfo = pTmpDeviceInfo;
825 }
826
827 /*
828 * Try re-enumerating the device.
829 */
830 rc = usb_reset_device(pDeviceInfo, fReattach ? USB_RESET_LVL_REATTACH : USB_RESET_LVL_DEFAULT);
831 LogFlow((DEVICE_NAME ":usb_reset_device for %s level=%s returned %d\n", pszDevicePath, fReattach ? "ReAttach" : "Default", rc));
832 switch (rc)
833 {
834 case USB_SUCCESS: rc = VINF_SUCCESS; break;
835 case USB_INVALID_PERM: rc = VERR_PERMISSION_DENIED; break;
836 case USB_INVALID_ARGS: rc = VERR_INVALID_PARAMETER; break;
837
838 /* @todo find better codes for these (especially USB_BUSY) */
839 case USB_BUSY:
840 case USB_INVALID_CONTEXT:
841 case USB_FAILURE: rc = VERR_GENERAL_FAILURE; break;
842
843 default: rc = VERR_UNRESOLVED_ERROR; break;
844 }
845 }
846 else
847 {
848 rc = VERR_INVALID_HANDLE;
849 LogRel((DEVICE_NAME ":vboxUSBMonSolarisResetDevice Cannot obtain device info for %s\n", pszDevicePath));
850 }
851
852 return rc;
853}
854
855static int vboxUSBMonSolarisClientInfo(vboxusbmon_state_t *pState, PVBOXUSB_CLIENT_INFO pClientInfo)
856{
857 LogFlowFunc((DEVICE_NAME ":vboxUSBMonSolarisClientInfo pState=%p pClientInfo=%p\n", pState, pClientInfo));
858
859 AssertPtrReturn(pState, VERR_INVALID_POINTER);
860 AssertPtrReturn(pClientInfo, VERR_INVALID_POINTER);
861
862 mutex_enter(&g_VBoxUSBMonSolarisMtx);
863 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
864 vboxusbmon_client_t *pPrev = NULL;
865 while (pCur)
866 {
867 if (strncmp(pClientInfo->szDeviceIdent, pCur->Info.szDeviceIdent, sizeof(pCur->Info.szDeviceIdent) - 1) == 0)
868 {
869 pClientInfo->Instance = pCur->Info.Instance;
870 RTStrPrintf(pClientInfo->szClientPath, sizeof(pClientInfo->szClientPath), "%s", pCur->Info.szClientPath);
871
872 mutex_exit(&g_VBoxUSBMonSolarisMtx);
873
874 LogFlow((DEVICE_NAME ":vboxUSBMonSolarisClientInfo found. %s\n", pClientInfo->szDeviceIdent));
875 return VINF_SUCCESS;
876 }
877 pPrev = pCur;
878 pCur = pCur->pNext;
879 }
880
881 mutex_exit(&g_VBoxUSBMonSolarisMtx);
882
883 LogRel((DEVICE_NAME ":vboxUSBMonSolarisClientInfo Failed to find client %s\n", pClientInfo->szDeviceIdent));
884 return VERR_NOT_FOUND;
885}
886
887
888/**
889 * Registers client driver.
890 *
891 * @returns VBox status code.
892 * @param pszDevicePath The device path of the client driver.
893 * @param Instance The client driver instance.
894 */
895int VBoxUSBMonSolarisRegisterClient(dev_info_t *pClientDip, PVBOXUSB_CLIENT_INFO pClientInfo)
896{
897 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisRegisterClient pClientDip=%p pClientInfo=%p\n", pClientDip, pClientInfo));
898 AssertPtrReturn(pClientInfo, VERR_INVALID_PARAMETER);
899
900 if (RT_LIKELY(g_pDip))
901 {
902 vboxusbmon_state_t *pState = ddi_get_driver_private(g_pDip);
903
904 if (RT_LIKELY(pState))
905 {
906 vboxusbmon_client_t *pClient = RTMemAlloc(sizeof(vboxusbmon_client_t));
907 if (RT_LIKELY(pClient))
908 {
909 bcopy(pClientInfo, &pClient->Info, sizeof(pClient->Info));
910 pClient->pDip = pClientDip;
911
912 mutex_enter(&g_VBoxUSBMonSolarisMtx);
913 pClient->pNext = g_pVBoxUSBMonSolarisClients;
914 g_pVBoxUSBMonSolarisClients = pClient;
915 mutex_exit(&g_VBoxUSBMonSolarisMtx);
916
917 LogFlow((DEVICE_NAME ":VBoxUSBMonSolarisRegisterClient registered. %d %s %s\n",
918 pClient->Info.Instance, pClient->Info.szClientPath, pClient->Info.szDeviceIdent));
919
920 return VINF_SUCCESS;
921 }
922 else
923 return VERR_NO_MEMORY;
924 }
925 else
926 return VERR_INTERNAL_ERROR;
927 }
928 else
929 return VERR_INTERNAL_ERROR_2;
930}
931
932
933/**
934 * Deregisters client driver.
935 *
936 * @returns VBox status code.
937 * @param pszDevicePath The device path of the client driver.
938 * @param Instance The client driver instance.
939 */
940int VBoxUSBMonSolarisUnregisterClient(dev_info_t *pClientDip)
941{
942 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisUnregisterClient pClientDip=%p\n", pClientDip));
943
944 if (RT_LIKELY(g_pDip))
945 {
946 vboxusbmon_state_t *pState = ddi_get_driver_private(g_pDip);
947
948 if (RT_LIKELY(pState))
949 {
950 mutex_enter(&g_VBoxUSBMonSolarisMtx);
951
952 vboxusbmon_client_t *pCur = g_pVBoxUSBMonSolarisClients;
953 vboxusbmon_client_t *pPrev = NULL;
954 while (pCur)
955 {
956 if (pCur->pDip == pClientDip)
957 {
958 if (pPrev)
959 pPrev->pNext = pCur->pNext;
960 else
961 g_pVBoxUSBMonSolarisClients = pCur->pNext;
962
963 mutex_exit(&g_VBoxUSBMonSolarisMtx);
964
965 LogFlow((DEVICE_NAME ":VBoxUSBMonSolarisUnregisterClient unregistered. %d %s %s\n",
966 pCur->Info.Instance, pCur->Info.szClientPath, pCur->Info.szDeviceIdent));
967 RTMemFree(pCur);
968 pCur = NULL;
969 return VINF_SUCCESS;
970 }
971 pPrev = pCur;
972 pCur = pCur->pNext;
973 }
974
975 mutex_exit(&g_VBoxUSBMonSolarisMtx);
976
977 LogRel((DEVICE_NAME ":VBoxUSBMonSolarisUnregisterClient Failed to find registered client %p\n", pClientDip));
978 return VERR_SEARCH_ERROR;
979 }
980 else
981 return VERR_INTERNAL_ERROR;
982 }
983 else
984 return VERR_INTERNAL_ERROR_2;
985}
986
987
988/**
989 * USBA driver election callback.
990 *
991 * @returns USB_SUCCESS if we want to capture the device, USB_FAILURE otherwise.
992 * @param pDevDesc The parsed device descriptor (does not include subconfigs).
993 * @param pDevStrings Device strings: Manufacturer, Product, Serial Number.
994 * @param pszDevicePath The physical path of the device being attached.
995 * @param Bus The Bus number on which the device is on.
996 * @param Port The Port number on the bus.
997 * @param ppszDrv The name of the driver we wish to capture the device with.
998 * @param pvReserved Reserved for future use.
999 */
1000int VBoxUSBMonSolarisElectDriver(usb_dev_descr_t *pDevDesc, usb_dev_str_t *pDevStrings, char *pszDevicePath, int Bus, int Port,
1001 char **ppszDrv, void *pvReserved)
1002{
1003 LogFlowFunc((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver pDevDesc=%p pDevStrings=%p pszDevicePath=%s Bus=%d Port=%d\n", pDevDesc,
1004 pDevStrings, pszDevicePath, Bus, Port));
1005
1006 AssertPtrReturn(pDevDesc, USB_FAILURE);
1007 AssertPtrReturn(pDevStrings, USB_FAILURE);
1008
1009 /*
1010 * Create a filter from the device being attached.
1011 */
1012 USBFILTER Filter;
1013 USBFilterInit(&Filter, USBFILTERTYPE_CAPTURE);
1014 USBFilterSetNumExact(&Filter, USBFILTERIDX_VENDOR_ID, pDevDesc->idVendor, true);
1015 USBFilterSetNumExact(&Filter, USBFILTERIDX_PRODUCT_ID, pDevDesc->idProduct, true);
1016 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_REV, pDevDesc->bcdDevice, true);
1017 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_CLASS, pDevDesc->bDeviceClass, true);
1018 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS, pDevDesc->bDeviceSubClass, true);
1019 USBFilterSetNumExact(&Filter, USBFILTERIDX_DEVICE_PROTOCOL, pDevDesc->bDeviceProtocol, true);
1020 USBFilterSetNumExact(&Filter, USBFILTERIDX_BUS, 0x0 /* Bus */, true); /* Use 0x0 as userland initFilterFromDevice function in Main: see comment on "SetMustBePresent" below */
1021 USBFilterSetNumExact(&Filter, USBFILTERIDX_PORT, Port, true);
1022 USBFilterSetStringExact(&Filter, USBFILTERIDX_MANUFACTURER_STR, pDevStrings->usb_mfg, true);
1023 USBFilterSetStringExact(&Filter, USBFILTERIDX_PRODUCT_STR, pDevStrings->usb_product, true);
1024 USBFilterSetStringExact(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR, pDevStrings->usb_serialno, true);
1025
1026 /* This doesn't work like it should (USBFilterMatch fails on matching field (6) i.e. Bus despite this. Investigate later. */
1027 USBFilterSetMustBePresent(&Filter, USBFILTERIDX_BUS, false /* fMustBePresent */);
1028
1029 LogFlow((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver: idVendor=%#x idProduct=%#x bcdDevice=%#x bDeviceClass=%#x bDeviceSubClass=%#x bDeviceProtocol=%#x bBus=%#x bPort=%#x\n",
1030 USBFilterGetNum(&Filter, USBFILTERIDX_VENDOR_ID),
1031 USBFilterGetNum(&Filter, USBFILTERIDX_PRODUCT_ID),
1032 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_REV),
1033 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_CLASS),
1034 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_SUB_CLASS),
1035 USBFilterGetNum(&Filter, USBFILTERIDX_DEVICE_PROTOCOL),
1036 USBFilterGetNum(&Filter, USBFILTERIDX_BUS),
1037 USBFilterGetNum(&Filter, USBFILTERIDX_PORT)));
1038 LogFlow((DEVICE_NAME ":VBoxUSBMonSolarisElectDriver: Manufacturer=%s Product=%s Serial=%s\n",
1039 USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_MANUFACTURER_STR) : "<null>",
1040 USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_PRODUCT_STR) : "<null>",
1041 USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) ? USBFilterGetString(&Filter, USBFILTERIDX_SERIAL_NUMBER_STR) : "<null>"));
1042
1043 /*
1044 * Run through user filters and try to see if it has a match.
1045 */
1046 uintptr_t uId = 0;
1047 RTPROCESS Owner = VBoxUSBFilterMatch(&Filter, &uId);
1048 USBFilterDelete(&Filter);
1049 if (Owner == NIL_RTPROCESS)
1050 {
1051 LogFlow((DEVICE_NAME ":No matching filters, device %#x:%#x uninteresting.\n", pDevDesc->idVendor, pDevDesc->idProduct));
1052 return USB_FAILURE;
1053 }
1054
1055 *ppszDrv = ddi_strdup(VBOXUSB_DRIVER_NAME, KM_SLEEP);
1056 LogRel((DEVICE_NAME ": Capturing %s %#x:%#x:%s\n", pDevStrings->usb_product ? pDevStrings->usb_product : "<Unnamed USB device>",
1057 pDevDesc->idVendor, pDevDesc->idProduct, pszDevicePath));
1058 return USB_SUCCESS;
1059}
Note: See TracBrowser for help on using the repository browser.

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