VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-netbsd.c@ 70044

Last change on this file since 70044 was 70044, checked in by vboxsync, 7 years ago

VBoxGuest-netbsd.c: rename very confusingly named struct vboxguest_session
to vboxguest_fdata, adjust related variables accordingly.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.4 KB
Line 
1/* $Id: VBoxGuest-netbsd.c 70044 2017-12-09 00:52:16Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions Driver for NetBSD.
4 */
5
6/*
7 * Copyright (C) 2007-2017 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 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <sys/param.h>
32#include <sys/systm.h>
33#include <sys/select.h>
34#include <sys/conf.h>
35#include <sys/kernel.h>
36#include <sys/kmem.h>
37#include <sys/module.h>
38#include <sys/device.h>
39#include <sys/bus.h>
40#include <sys/poll.h>
41#include <sys/proc.h>
42#include <sys/stat.h>
43#include <sys/selinfo.h>
44#include <sys/queue.h>
45#include <sys/lock.h>
46#include <sys/types.h>
47#include <sys/conf.h>
48#include <sys/malloc.h>
49#include <sys/uio.h>
50#include <sys/file.h>
51#include <sys/filedesc.h>
52#include <sys/vfs_syscalls.h>
53#include <dev/pci/pcivar.h>
54#include <dev/pci/pcireg.h>
55#include <dev/pci/pcidevs.h>
56
57#include <dev/wscons/wsconsio.h>
58#include <dev/wscons/wsmousevar.h>
59#include <dev/wscons/tpcalibvar.h>
60
61#ifdef PVM
62# undef PVM
63#endif
64#include "VBoxGuestInternal.h"
65#include <VBox/log.h>
66#include <iprt/assert.h>
67#include <iprt/initterm.h>
68#include <iprt/process.h>
69#include <iprt/mem.h>
70#include <iprt/asm.h>
71
72
73/*********************************************************************************************************************************
74* Defined Constants And Macros *
75*********************************************************************************************************************************/
76/** The module name. */
77#define DEVICE_NAME "vboxguest"
78
79
80/*********************************************************************************************************************************
81* Structures and Typedefs *
82*********************************************************************************************************************************/
83typedef struct VBoxGuestDeviceState
84{
85 device_t sc_dev;
86 pci_chipset_tag_t pc;
87 bus_space_tag_t io_tag;
88 bus_space_handle_t io_handle;
89 bus_addr_t uIOPortBase;
90 bus_size_t io_regsize;
91 bus_space_tag_t iVMMDevMemResId;
92 bus_space_handle_t VMMDevMemHandle;
93
94 /** Size of the memory area. */
95 bus_size_t VMMDevMemSize;
96 /** Mapping of the register space */
97 bus_addr_t pMMIOBase;
98
99 /** IRQ resource handle. */
100 pci_intr_handle_t ih;
101 /** Pointer to the IRQ handler. */
102 void *pfnIrqHandler;
103
104 /** Controller features, limits and status. */
105 u_int vboxguest_state;
106
107 device_t sc_wsmousedev;
108 VMMDevReqMouseStatus *sc_vmmmousereq;
109 PVBOXGUESTSESSION sc_session;
110 struct tpcalib_softc sc_tpcalib;
111} vboxguest_softc;
112
113
114struct vboxguest_fdata
115{
116 vboxguest_softc *sc;
117 PVBOXGUESTSESSION session;
118};
119
120#define VBOXGUEST_STATE_INITOK 1 << 0
121
122
123/*********************************************************************************************************************************
124* Internal Functions *
125*********************************************************************************************************************************/
126/*
127 * Driver(9) autoconf machinery.
128 */
129static int VBoxGuestNetBSDMatch(device_t parent, cfdata_t match, void *aux);
130static void VBoxGuestNetBSDAttach(device_t parent, device_t self, void *aux);
131static void VBoxGuestNetBSDWsmAttach(vboxguest_softc *sc);
132static int VBoxGuestNetBSDDetach(device_t self, int flags);
133
134/*
135 * IRQ related functions.
136 */
137static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *sc, struct pci_attach_args *pa);
138static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *sc);
139static int VBoxGuestNetBSDISR(void *pvState);
140
141/*
142 * Character device file handlers.
143 */
144static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process);
145static int VBoxGuestNetBSDClose(struct file *fp);
146static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long cmd, void *addr);
147static int VBoxGuestNetBSDIOCtlSlow(struct vboxguest_fdata *fdata, u_long command, void *data);
148static int VBoxGuestNetBSDPoll(struct file *fp, int events);
149
150/*
151 * wsmouse(4) accessops
152 */
153static int VBoxGuestNetBSDWsmEnable(void *cookie);
154static void VBoxGuestNetBSDWsmDisable(void *cookie);
155static int VBoxGuestNetBSDWsmIOCtl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l);
156
157static int VBoxGuestNetBSDSetMouseStatus(vboxguest_softc *sc, uint32_t fStatus);
158
159
160/*********************************************************************************************************************************
161* Global Variables *
162*********************************************************************************************************************************/
163extern struct cfdriver vboxguest_cd; /* CFDRIVER_DECL */
164extern struct cfattach vboxguest_ca; /* CFATTACH_DECL */
165
166/*
167 * The /dev/vboxguest character device entry points.
168 */
169static struct cdevsw g_VBoxGuestNetBSDChrDevSW =
170{
171 VBoxGuestNetBSDOpen,
172 noclose,
173 noread,
174 nowrite,
175 noioctl,
176 nostop,
177 notty,
178 nopoll,
179 nommap,
180 nokqfilter,
181};
182
183static const struct fileops vboxguest_fileops = {
184 .fo_read = fbadop_read,
185 .fo_write = fbadop_write,
186 .fo_ioctl = VBoxGuestNetBSDIOCtl,
187 .fo_fcntl = fnullop_fcntl,
188 .fo_poll = VBoxGuestNetBSDPoll,
189 .fo_stat = fbadop_stat,
190 .fo_close = VBoxGuestNetBSDClose,
191 .fo_kqfilter = fnullop_kqfilter,
192 .fo_restart = fnullop_restart
193};
194
195
196const struct wsmouse_accessops vboxguest_wsm_accessops = {
197 VBoxGuestNetBSDWsmEnable,
198 VBoxGuestNetBSDWsmIOCtl,
199 VBoxGuestNetBSDWsmDisable,
200};
201
202
203static struct wsmouse_calibcoords vboxguest_wsm_default_calib = {
204 .minx = VMMDEV_MOUSE_RANGE_MIN,
205 .miny = VMMDEV_MOUSE_RANGE_MIN,
206 .maxx = VMMDEV_MOUSE_RANGE_MAX,
207 .maxy = VMMDEV_MOUSE_RANGE_MAX,
208 .samplelen = WSMOUSE_CALIBCOORDS_RESET,
209};
210
211/** Device extention & session data association structure. */
212static VBOXGUESTDEVEXT g_DevExt;
213
214static vboxguest_softc *g_SC;
215
216/** Reference counter */
217static volatile uint32_t cUsers;
218/** selinfo structure used for polling. */
219static struct selinfo g_SelInfo;
220
221
222CFATTACH_DECL_NEW(vboxguest, sizeof(vboxguest_softc),
223 VBoxGuestNetBSDMatch, VBoxGuestNetBSDAttach, VBoxGuestNetBSDDetach, NULL);
224
225
226static int VBoxGuestNetBSDMatch(device_t parent, cfdata_t match, void *aux)
227{
228 const struct pci_attach_args *pa = aux;
229
230 if (RT_UNLIKELY(g_SC != NULL)) /* should not happen */
231 return 0;
232
233 if ( PCI_VENDOR(pa->pa_id) == VMMDEV_VENDORID
234 && PCI_PRODUCT(pa->pa_id) == VMMDEV_DEVICEID)
235 {
236 return 1;
237 }
238
239 return 0;
240}
241
242
243static void VBoxGuestNetBSDAttach(device_t parent, device_t self, void *aux)
244{
245 int rc = VINF_SUCCESS;
246 int iResId = 0;
247 vboxguest_softc *sc;
248 struct pci_attach_args *pa = aux;
249 bus_space_tag_t iot, memt;
250 bus_space_handle_t ioh, memh;
251 bus_dma_segment_t seg;
252 int ioh_valid, memh_valid;
253
254 KASSERT(g_SC == NULL);
255
256 cUsers = 0;
257
258 aprint_normal(": VirtualBox Guest\n");
259
260 sc = device_private(self);
261 sc->sc_dev = self;
262
263 /*
264 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
265 */
266 rc = RTR0Init(0);
267 if (RT_FAILURE(rc))
268 {
269 LogFunc(("RTR0Init failed.\n"));
270 aprint_error_dev(sc->sc_dev, "RTR0Init failed\n");
271 return;
272 }
273
274 sc->pc = pa->pa_pc;
275
276 /*
277 * Allocate I/O port resource.
278 */
279 ioh_valid = (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
280 &sc->io_tag, &sc->io_handle,
281 &sc->uIOPortBase, &sc->io_regsize) == 0);
282
283 if (ioh_valid)
284 {
285
286 /*
287 * Map the MMIO region.
288 */
289 memh_valid = (pci_mapreg_map(pa, PCI_MAPREG_START+4, PCI_MAPREG_TYPE_MEM, BUS_SPACE_MAP_LINEAR,
290 &sc->iVMMDevMemResId, &sc->VMMDevMemHandle,
291 &sc->pMMIOBase, &sc->VMMDevMemSize) == 0);
292 if (memh_valid)
293 {
294 /*
295 * Call the common device extension initializer.
296 */
297 rc = VGDrvCommonInitDevExt(&g_DevExt, sc->uIOPortBase,
298 bus_space_vaddr(sc->iVMMDevMemResId,
299 sc->VMMDevMemHandle),
300 sc->VMMDevMemSize,
301#if ARCH_BITS == 64
302 VBOXOSTYPE_NetBSD_x64,
303#else
304 VBOXOSTYPE_NetBSD,
305#endif
306 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
307 if (RT_SUCCESS(rc))
308 {
309 /*
310 * Add IRQ of VMMDev.
311 */
312 rc = VBoxGuestNetBSDAddIRQ(sc, pa);
313 if (RT_SUCCESS(rc))
314 {
315 sc->vboxguest_state |= VBOXGUEST_STATE_INITOK;
316 VBoxGuestNetBSDWsmAttach(sc);
317
318 g_SC = sc;
319 return;
320 }
321 VGDrvCommonDeleteDevExt(&g_DevExt);
322 }
323 else
324 {
325 aprint_error_dev(sc->sc_dev, "init failed\n");
326 }
327 bus_space_unmap(sc->iVMMDevMemResId, sc->VMMDevMemHandle, sc->VMMDevMemSize);
328 }
329 else
330 {
331 aprint_error_dev(sc->sc_dev, "MMIO mapping failed\n");
332 }
333 bus_space_unmap(sc->io_tag, sc->io_handle, sc->io_regsize);
334 }
335 else
336 {
337 aprint_error_dev(sc->sc_dev, "IO mapping failed\n");
338 }
339
340 RTR0Term();
341 return;
342}
343
344
345/**
346 * Sets IRQ for VMMDev.
347 *
348 * @returns NetBSD error code.
349 * @param vboxguest Pointer to the state info structure.
350 * @param pa Pointer to the PCI attach arguments.
351 */
352static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *sc, struct pci_attach_args *pa)
353{
354 int iResId = 0;
355 int rc = 0;
356 const char *intrstr;
357#if __NetBSD_Prereq__(6, 99, 39)
358 char intstrbuf[100];
359#endif
360
361 LogFlow((DEVICE_NAME ": %s\n", __func__));
362
363 if (pci_intr_map(pa, &sc->ih))
364 {
365 aprint_error_dev(sc->sc_dev, "couldn't map interrupt.\n");
366 return VERR_DEV_IO_ERROR;
367 }
368
369 intrstr = pci_intr_string(sc->pc, sc->ih
370#if __NetBSD_Prereq__(6, 99, 39)
371 , intstrbuf, sizeof(intstrbuf)
372#endif
373 );
374 aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
375
376 sc->pfnIrqHandler = pci_intr_establish(sc->pc, sc->ih, IPL_BIO, VBoxGuestNetBSDISR, sc);
377 if (sc->pfnIrqHandler == NULL)
378 {
379 aprint_error_dev(sc->sc_dev, "couldn't establish interrupt\n");
380 return VERR_DEV_IO_ERROR;
381 }
382
383 return VINF_SUCCESS;
384}
385
386
387/*
388 * Optionally attach wsmouse(4) device as a child.
389 */
390static void VBoxGuestNetBSDWsmAttach(vboxguest_softc *sc)
391{
392 struct wsmousedev_attach_args am = { &vboxguest_wsm_accessops, sc };
393
394 PVBOXGUESTSESSION session = NULL;
395 VMMDevReqMouseStatus *req = NULL;
396 int rc;
397
398 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &session);
399 if (RT_FAILURE(rc))
400 goto fail;
401
402 rc = VbglR0GRAlloc((VMMDevRequestHeader **)&req, sizeof(*req),
403 VMMDevReq_GetMouseStatus);
404 if (RT_FAILURE(rc))
405 goto fail;
406
407 sc->sc_wsmousedev = config_found_ia(sc->sc_dev, "wsmousedev", &am, wsmousedevprint);
408 if (sc->sc_wsmousedev == NULL)
409 goto fail;
410
411 sc->sc_session = session;
412 sc->sc_vmmmousereq = req;
413
414 tpcalib_init(&sc->sc_tpcalib);
415 tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
416 &vboxguest_wsm_default_calib, 0, 0);
417 return;
418
419 fail:
420 if (session != NULL)
421 VGDrvCommonCloseSession(&g_DevExt, session);
422 if (req != NULL)
423 VbglR0GRFree((VMMDevRequestHeader *)req);
424}
425
426
427static int VBoxGuestNetBSDDetach(device_t self, int flags)
428{
429 vboxguest_softc *sc;
430 sc = device_private(self);
431
432 LogFlow((DEVICE_NAME ": %s\n", __func__));
433
434 if (cUsers > 0)
435 return EBUSY;
436
437 if ((sc->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
438 return 0;
439
440 /*
441 * Reverse what we did in VBoxGuestNetBSDAttach.
442 */
443 if (sc->sc_vmmmousereq != NULL)
444 VbglR0GRFree((VMMDevRequestHeader *)sc->sc_vmmmousereq);
445
446 VBoxGuestNetBSDRemoveIRQ(sc);
447
448 VGDrvCommonDeleteDevExt(&g_DevExt);
449
450 bus_space_unmap(sc->iVMMDevMemResId, sc->VMMDevMemHandle, sc->VMMDevMemSize);
451 bus_space_unmap(sc->io_tag, sc->io_handle, sc->io_regsize);
452
453 RTR0Term();
454
455 return config_detach_children(self, flags);
456}
457
458
459/**
460 * Removes IRQ for VMMDev.
461 *
462 * @param vboxguest Opaque pointer to the state info structure.
463 */
464static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *sc)
465{
466 LogFlow((DEVICE_NAME ": %s\n", __func__));
467
468 if (sc->pfnIrqHandler)
469 {
470 pci_intr_disestablish(sc->pc, sc->pfnIrqHandler);
471 }
472}
473
474
475/**
476 * Interrupt service routine.
477 *
478 * @returns Whether the interrupt was from VMMDev.
479 * @param pvState Opaque pointer to the device state.
480 */
481static int VBoxGuestNetBSDISR(void *pvState)
482{
483 LogFlow((DEVICE_NAME ": %s: pvState=%p\n", __func__, pvState));
484
485 bool fOurIRQ = VGDrvCommonISR(&g_DevExt);
486
487 return fOurIRQ ? 0 : 1;
488}
489
490
491/*
492 * Called by VGDrvCommonISR() if mouse position changed
493 */
494void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
495{
496 vboxguest_softc *sc = g_SC;
497
498 LogFlow((DEVICE_NAME ": %s\n", __func__));
499
500 /*
501 * Wake up poll waiters.
502 */
503 selnotify(&g_SelInfo, 0, 0);
504
505 if (sc->sc_vmmmousereq != NULL) {
506 int x, y;
507 int rc;
508
509 sc->sc_vmmmousereq->mouseFeatures = 0;
510 sc->sc_vmmmousereq->pointerXPos = 0;
511 sc->sc_vmmmousereq->pointerYPos = 0;
512
513 rc = VbglR0GRPerform(&sc->sc_vmmmousereq->header);
514 if (RT_FAILURE(rc))
515 return;
516
517 tpcalib_trans(&sc->sc_tpcalib,
518 sc->sc_vmmmousereq->pointerXPos,
519 sc->sc_vmmmousereq->pointerYPos,
520 &x, &y);
521
522 wsmouse_input(sc->sc_wsmousedev,
523 0, /* buttons */
524 x, y,
525 0, 0, /* z, w */
526 WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
527 }
528}
529
530
531static int VBoxGuestNetBSDSetMouseStatus(vboxguest_softc *sc, uint32_t fStatus)
532{
533 VBGLIOCSETMOUSESTATUS Req;
534 int rc;
535
536 VBGLREQHDR_INIT(&Req.Hdr, SET_MOUSE_STATUS);
537 Req.u.In.fStatus = fStatus;
538 rc = VGDrvCommonIoCtl(VBGL_IOCTL_SET_MOUSE_STATUS,
539 &g_DevExt,
540 sc->sc_session,
541 &Req.Hdr, sizeof(Req));
542 if (RT_SUCCESS(rc))
543 rc = Req.Hdr.rc;
544
545 return rc;
546}
547
548
549static int
550VBoxGuestNetBSDWsmEnable(void *cookie)
551{
552 vboxguest_softc *sc = cookie;
553 int rc;
554
555 rc = VBoxGuestNetBSDSetMouseStatus(sc, VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE
556 | VMMDEV_MOUSE_NEW_PROTOCOL);
557 if (RT_FAILURE(rc))
558 return RTErrConvertToErrno(rc);
559
560 return 0;
561}
562
563
564static void
565VBoxGuestNetBSDWsmDisable(void *cookie)
566{
567 vboxguest_softc *sc = cookie;
568 VBoxGuestNetBSDSetMouseStatus(sc, 0);
569}
570
571
572static int
573VBoxGuestNetBSDWsmIOCtl(void *cookie, u_long cmd, void *data, int flag, struct lwp *l)
574{
575 vboxguest_softc *sc = cookie;
576
577 switch (cmd) {
578 case WSMOUSEIO_GTYPE:
579 *(u_int *)data = WSMOUSE_TYPE_TPANEL;
580 break;
581
582 case WSMOUSEIO_SCALIBCOORDS:
583 case WSMOUSEIO_GCALIBCOORDS:
584 return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
585
586 default:
587 return EPASSTHROUGH;
588 }
589 return 0;
590}
591
592
593/**
594 * File open handler
595 *
596 */
597static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process)
598{
599 int rc;
600 vboxguest_softc *sc;
601 struct vboxguest_fdata *fdata;
602 file_t *fp;
603 int fd, error;
604
605 LogFlow((DEVICE_NAME ": %s\n", __func__));
606
607 if ((sc = device_lookup_private(&vboxguest_cd, minor(device))) == NULL)
608 {
609 printf("device_lookup_private failed\n");
610 return (ENXIO);
611 }
612
613 if ((sc->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
614 {
615 aprint_error_dev(sc->sc_dev, "device not configured\n");
616 return (ENXIO);
617 }
618
619 fdata = kmem_alloc(sizeof(*fdata), KM_SLEEP);
620 if (fdata == NULL)
621 {
622 return (ENOMEM);
623 }
624
625 fdata->sc = sc;
626
627 if ((error = fd_allocfile(&fp, &fd)) != 0)
628 {
629 kmem_free(fdata, sizeof(*fdata));
630 return error;
631 }
632
633 /*
634 * Create a new session.
635 */
636 rc = VGDrvCommonCreateUserSession(&g_DevExt, &fdata->session);
637 if (! RT_SUCCESS(rc))
638 {
639 aprint_error_dev(sc->sc_dev, "VBox session creation failed\n");
640 closef(fp); /* ??? */
641 kmem_free(fdata, sizeof(*fdata));
642 return RTErrConvertToErrno(rc);
643 }
644 ASMAtomicIncU32(&cUsers);
645 return fd_clone(fp, fd, flags, &vboxguest_fileops, fdata);
646
647}
648
649/**
650 * File close handler
651 *
652 */
653static int VBoxGuestNetBSDClose(struct file *fp)
654{
655 struct vboxguest_fdata *fdata = fp->f_data;
656 vboxguest_softc *sc = fdata->sc;
657
658 LogFlow((DEVICE_NAME ": %s\n", __func__));
659
660 VGDrvCommonCloseSession(&g_DevExt, fdata->session);
661 ASMAtomicDecU32(&cUsers);
662
663 kmem_free(fdata, sizeof(*fdata));
664
665 return 0;
666}
667
668/**
669 * IOCTL handler
670 *
671 */
672static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long command, void *data)
673{
674 struct vboxguest_fdata *fdata = fp->f_data;
675
676 if (VBGL_IOCTL_IS_FAST(command))
677 return VGDrvCommonIoCtlFast(command, &g_DevExt, fdata->session);
678
679 return VBoxGuestNetBSDIOCtlSlow(fdata, command, data);
680}
681
682static int VBoxGuestNetBSDIOCtlSlow(struct vboxguest_fdata *fdata, u_long command, void *data)
683{
684 vboxguest_softc *sc = fdata->sc;
685 size_t cbReq = IOCPARM_LEN(command);
686 PVBGLREQHDR pHdr = NULL;
687 void *pvUser = NULL;
688 int err, rc;
689
690 LogFlow(("%s: command=%#lx data=%p\n", __func__, command, data));
691
692 /*
693 * Buffered request?
694 */
695 if ((command & IOC_DIRMASK) == IOC_INOUT)
696 {
697 /* will be validated by VGDrvCommonIoCtl() */
698 pHdr = (PVBGLREQHDR)data;
699 }
700
701 /*
702 * Big unbuffered request? "data" is the userland pointer.
703 */
704 else if ((command & IOC_DIRMASK) == IOC_VOID && cbReq != 0)
705 {
706 /*
707 * Read the header, validate it and figure out how much that
708 * needs to be buffered.
709 */
710 VBGLREQHDR Hdr;
711
712 if (RT_UNLIKELY(cbReq < sizeof(Hdr)))
713 return ENOTTY;
714
715 pvUser = data;
716 err = copyin(pvUser, &Hdr, sizeof(Hdr));
717 if (RT_UNLIKELY(err != 0))
718 return err;
719
720 if (RT_UNLIKELY(Hdr.uVersion != VBGLREQHDR_VERSION))
721 return ENOTTY;
722
723 if (cbReq > 16 * _1M)
724 return EINVAL;
725
726 if (Hdr.cbOut == 0)
727 Hdr.cbOut = Hdr.cbIn;
728
729 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr) || Hdr.cbIn > cbReq
730 || Hdr.cbOut < sizeof(Hdr) || Hdr.cbOut > cbReq))
731 return EINVAL;
732
733 /*
734 * Allocate buffer and copy in the data.
735 */
736 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
737
738 pHdr = (PVBGLREQHDR)RTMemTmpAlloc(cbReq);
739 if (RT_UNLIKELY(pHdr == NULL))
740 {
741 LogRel(("%s: command=%#lx data=%p: unable to allocate %zu bytes\n",
742 __func__, command, data, cbReq));
743 return ENOMEM;
744 }
745
746 err = copyin(pvUser, pHdr, Hdr.cbIn);
747 if (err != 0)
748 {
749 RTMemTmpFree(pHdr);
750 return err;
751 }
752
753 if (Hdr.cbIn < cbReq)
754 memset((uint8_t *)pHdr + Hdr.cbIn, '\0', cbReq - Hdr.cbIn);
755 }
756
757 /*
758 * Process the IOCtl.
759 */
760 rc = VGDrvCommonIoCtl(command, &g_DevExt, fdata->session, pHdr, cbReq);
761 if (RT_SUCCESS(rc))
762 {
763 err = 0;
764
765 /*
766 * If unbuffered, copy back the result before returning.
767 */
768 if (pvUser != NULL)
769 {
770 size_t cbOut = pHdr->cbOut;
771 if (cbOut > cbReq)
772 {
773 LogRel(("%s: command=%#lx data=%p: too much output: %zu > %zu\n",
774 __func__, command, data, cbOut, cbReq));
775 cbOut = cbReq;
776 }
777
778 err = copyout(pHdr, pvUser, cbOut);
779 RTMemTmpFree(pHdr);
780 }
781 }
782 else
783 {
784 LogRel(("%s: command=%#lx data=%p: error %Rrc\n",
785 __func__, command, data, rc));
786
787 if (pvUser != NULL)
788 RTMemTmpFree(pHdr);
789
790 err = RTErrConvertToErrno(rc);
791 }
792
793 return err;
794}
795
796static int VBoxGuestNetBSDPoll(struct file *fp, int events)
797{
798 struct vboxguest_fdata *fdata = fp->f_data;
799 vboxguest_softc *sc = fdata->sc;
800
801 int rc = 0;
802 int events_processed;
803
804 uint32_t u32CurSeq;
805
806 LogFlow((DEVICE_NAME ": %s\n", __func__));
807
808 u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
809 if (fdata->session->u32MousePosChangedSeq != u32CurSeq)
810 {
811 events_processed = events & (POLLIN | POLLRDNORM);
812 fdata->session->u32MousePosChangedSeq = u32CurSeq;
813 }
814 else
815 {
816 events_processed = 0;
817
818 selrecord(curlwp, &g_SelInfo);
819 }
820
821 return events_processed;
822}
823
824
825/**
826 * @note This code is duplicated on other platforms with variations, so please
827 * keep them all up to date when making changes!
828 */
829int VBOXCALL VBoxGuestIDC(void *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq)
830{
831 /*
832 * Simple request validation (common code does the rest).
833 */
834 int rc;
835 if ( RT_VALID_PTR(pReqHdr)
836 && cbReq >= sizeof(*pReqHdr))
837 {
838 /*
839 * All requests except the connect one requires a valid session.
840 */
841 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
842 if (pSession)
843 {
844 if ( RT_VALID_PTR(pSession)
845 && pSession->pDevExt == &g_DevExt)
846 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
847 else
848 rc = VERR_INVALID_HANDLE;
849 }
850 else if (uReq == VBGL_IOCTL_IDC_CONNECT)
851 {
852 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
853 if (RT_SUCCESS(rc))
854 {
855 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
856 if (RT_FAILURE(rc))
857 VGDrvCommonCloseSession(&g_DevExt, pSession);
858 }
859 }
860 else
861 rc = VERR_INVALID_HANDLE;
862 }
863 else
864 rc = VERR_INVALID_POINTER;
865 return rc;
866}
867
868
869MODULE(MODULE_CLASS_DRIVER, vboxguest, "pci");
870
871static const struct cfiattrdata wsmousedevcf_iattrdata = {
872 "wsmousedev", 1, {
873 { "mux", "0", 0 },
874 }
875};
876
877/* device vboxguest: wsmousedev */
878static const struct cfiattrdata * const vboxguest_attrs[] = { &wsmousedevcf_iattrdata, NULL };
879CFDRIVER_DECL(vboxguest, DV_DULL, vboxguest_attrs);
880
881static struct cfdriver * const cfdriver_ioconf_vboxguest[] = {
882 &vboxguest_cd, NULL
883};
884
885
886static const struct cfparent vboxguest_pspec = {
887 "pci", "pci", DVUNIT_ANY
888};
889static int vboxguest_loc[] = { -1, -1 };
890
891
892static const struct cfparent wsmousedev_pspec = {
893 "wsmousedev", "vboxguest", DVUNIT_ANY
894};
895static int wsmousedev_loc[] = { 0 };
896
897
898static struct cfdata cfdata_ioconf_vboxguest[] = {
899 /* vboxguest0 at pci? dev ? function ? */
900 {
901 .cf_name = "vboxguest",
902 .cf_atname = "vboxguest",
903 .cf_unit = 0, /* Only unit 0 is ever used */
904 .cf_fstate = FSTATE_NOTFOUND,
905 .cf_loc = vboxguest_loc,
906 .cf_flags = 0,
907 .cf_pspec = &vboxguest_pspec,
908 },
909
910 /* wsmouse* at vboxguest? */
911 { "wsmouse", "wsmouse", 0, FSTATE_STAR, wsmousedev_loc, 0, &wsmousedev_pspec },
912
913 { NULL, NULL, 0, 0, NULL, 0, NULL }
914};
915
916static struct cfattach * const vboxguest_cfattachinit[] = {
917 &vboxguest_ca, NULL
918};
919
920static const struct cfattachinit cfattach_ioconf_vboxguest[] = {
921 { "vboxguest", vboxguest_cfattachinit },
922 { NULL, NULL }
923};
924
925static int
926vboxguest_modcmd(modcmd_t cmd, void *opaque)
927{
928 devmajor_t bmajor, cmajor;
929 register_t retval;
930 int error;
931
932 LogFlow((DEVICE_NAME ": %s\n", __func__));
933
934 switch (cmd)
935 {
936 case MODULE_CMD_INIT:
937 error = config_init_component(cfdriver_ioconf_vboxguest,
938 cfattach_ioconf_vboxguest,
939 cfdata_ioconf_vboxguest);
940 if (error)
941 break;
942
943 bmajor = cmajor = NODEVMAJOR;
944 error = devsw_attach("vboxguest",
945 NULL, &bmajor,
946 &g_VBoxGuestNetBSDChrDevSW, &cmajor);
947 if (error)
948 {
949 if (error == EEXIST)
950 error = 0; /* maybe built-in ... improve eventually */
951 else
952 break;
953 }
954
955 error = do_sys_mknod(curlwp, "/dev/vboxguest",
956 0666|S_IFCHR, makedev(cmajor, 0),
957 &retval, UIO_SYSSPACE);
958 if (error == EEXIST)
959 error = 0;
960 break;
961
962 case MODULE_CMD_FINI:
963 error = config_fini_component(cfdriver_ioconf_vboxguest,
964 cfattach_ioconf_vboxguest,
965 cfdata_ioconf_vboxguest);
966 if (error)
967 break;
968
969 devsw_detach(NULL, &g_VBoxGuestNetBSDChrDevSW);
970 break;
971
972 default:
973 return ENOTTY;
974 }
975 return error;
976}
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