VirtualBox

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

最後變更 在這個檔案從95092是 95092,由 vboxsync 提交於 3 年 前

VBoxGuest-netbsd.c: Adapt to cdevsw changes. bugref:8547

cdevsw::d_cancel was introduced riding the 9.99.95 bump. Unlike other
methods the caller does check it for NULL, so we can avoid #ifdefs by
just switching to designed initializers (which is a good thing to do
anyway).

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

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