VirtualBox

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

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

VBoxGuest-netbsd.c: shuffle the code around to make the narration
organized more like that of a typical NetBSD driver. Mostly moves
autoconf machinery to the beginning. While here fix a couple of
indentation botches. No functional changes intended.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/* $Id: VBoxGuest-netbsd.c 69979 2017-12-07 13:34: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#ifdef PVM
58# undef PVM
59#endif
60#include "VBoxGuestInternal.h"
61#include <VBox/log.h>
62#include <iprt/assert.h>
63#include <iprt/initterm.h>
64#include <iprt/process.h>
65#include <iprt/mem.h>
66#include <iprt/asm.h>
67
68
69/*********************************************************************************************************************************
70* Defined Constants And Macros *
71*********************************************************************************************************************************/
72/** The module name. */
73#define DEVICE_NAME "vboxguest"
74
75
76/*********************************************************************************************************************************
77* Structures and Typedefs *
78*********************************************************************************************************************************/
79typedef struct VBoxGuestDeviceState
80{
81 device_t sc_dev;
82 pci_chipset_tag_t pc;
83 bus_space_tag_t io_tag;
84 bus_space_handle_t io_handle;
85 bus_addr_t uIOPortBase;
86 bus_size_t io_regsize;
87 bus_space_tag_t iVMMDevMemResId;
88 bus_space_handle_t VMMDevMemHandle;
89
90 /** Size of the memory area. */
91 bus_size_t VMMDevMemSize;
92 /** Mapping of the register space */
93 bus_addr_t pMMIOBase;
94
95 /** IRQ resource handle. */
96 pci_intr_handle_t ih;
97 /** Pointer to the IRQ handler. */
98 void *pfnIrqHandler;
99
100 /** Controller features, limits and status. */
101 u_int vboxguest_state;
102} vboxguest_softc;
103
104
105struct vboxguest_session
106{
107 vboxguest_softc *sc;
108 PVBOXGUESTSESSION session;
109};
110
111#define VBOXGUEST_STATE_INITOK 1 << 0
112
113
114/*********************************************************************************************************************************
115* Internal Functions *
116*********************************************************************************************************************************/
117/*
118 * Driver(9) autoconf machinery.
119 */
120static int VBoxGuestNetBSDMatch(device_t parent, cfdata_t match, void *aux);
121static void VBoxGuestNetBSDAttach(device_t parent, device_t self, void *aux);
122static int VBoxGuestNetBSDDetach(device_t self, int flags);
123
124/*
125 * IRQ related functions.
126 */
127static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *sc, struct pci_attach_args *pa);
128static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *sc);
129static int VBoxGuestNetBSDISR(void *pvState);
130
131/*
132 * Character device file handlers.
133 */
134static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process);
135static int VBoxGuestNetBSDClose(struct file *fp);
136static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long cmd, void *addr);
137static int VBoxGuestNetBSDIOCtlSlow(struct vboxguest_session *session, u_long command, void *data);
138static int VBoxGuestNetBSDPoll(struct file *fp, int events);
139
140
141/*********************************************************************************************************************************
142* Global Variables *
143*********************************************************************************************************************************/
144/*
145 * The /dev/vboxguest character device entry points.
146 */
147static struct cdevsw g_VBoxGuestNetBSDChrDevSW =
148{
149 VBoxGuestNetBSDOpen,
150 noclose,
151 noread,
152 nowrite,
153 noioctl,
154 nostop,
155 notty,
156 nopoll,
157 nommap,
158 nokqfilter,
159};
160
161static const struct fileops vboxguest_fileops = {
162 .fo_read = fbadop_read,
163 .fo_write = fbadop_write,
164 .fo_ioctl = VBoxGuestNetBSDIOCtl,
165 .fo_fcntl = fnullop_fcntl,
166 .fo_poll = VBoxGuestNetBSDPoll,
167 .fo_stat = fbadop_stat,
168 .fo_close = VBoxGuestNetBSDClose,
169 .fo_kqfilter = fnullop_kqfilter,
170 .fo_restart = fnullop_restart
171};
172
173/** Device extention & session data association structure. */
174static VBOXGUESTDEVEXT g_DevExt;
175/** Reference counter */
176static volatile uint32_t cUsers;
177/** selinfo structure used for polling. */
178static struct selinfo g_SelInfo;
179
180CFDRIVER_DECL(vboxguest, DV_DULL, NULL);
181extern struct cfdriver vboxguest_cd;
182
183
184CFATTACH_DECL_NEW(vboxguest, sizeof(vboxguest_softc),
185 VBoxGuestNetBSDMatch, VBoxGuestNetBSDAttach, VBoxGuestNetBSDDetach, NULL);
186
187
188static int VBoxGuestNetBSDMatch(device_t parent, cfdata_t match, void *aux)
189{
190 const struct pci_attach_args *pa = aux;
191
192 if ( PCI_VENDOR(pa->pa_id) == VMMDEV_VENDORID
193 && PCI_PRODUCT(pa->pa_id) == VMMDEV_DEVICEID)
194 {
195 return 1;
196 }
197
198 return 0;
199}
200
201
202static void VBoxGuestNetBSDAttach(device_t parent, device_t self, void *aux)
203{
204 int rc = VINF_SUCCESS;
205 int iResId = 0;
206 vboxguest_softc *vboxguest;
207 struct pci_attach_args *pa = aux;
208 bus_space_tag_t iot, memt;
209 bus_space_handle_t ioh, memh;
210 bus_dma_segment_t seg;
211 int ioh_valid, memh_valid;
212
213 cUsers = 0;
214
215 aprint_normal(": VirtualBox Guest\n");
216
217 vboxguest = device_private(self);
218 vboxguest->sc_dev = self;
219
220 /*
221 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
222 */
223 rc = RTR0Init(0);
224 if (RT_FAILURE(rc))
225 {
226 LogFunc(("RTR0Init failed.\n"));
227 aprint_error_dev(vboxguest->sc_dev, "RTR0Init failed\n");
228 return;
229 }
230
231 vboxguest->pc = pa->pa_pc;
232
233 /*
234 * Allocate I/O port resource.
235 */
236 ioh_valid = (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
237 &vboxguest->io_tag, &vboxguest->io_handle,
238 &vboxguest->uIOPortBase, &vboxguest->io_regsize) == 0);
239
240 if (ioh_valid)
241 {
242
243 /*
244 * Map the MMIO region.
245 */
246 memh_valid = (pci_mapreg_map(pa, PCI_MAPREG_START+4, PCI_MAPREG_TYPE_MEM, BUS_SPACE_MAP_LINEAR,
247 &vboxguest->iVMMDevMemResId, &vboxguest->VMMDevMemHandle,
248 &vboxguest->pMMIOBase, &vboxguest->VMMDevMemSize) == 0);
249 if (memh_valid)
250 {
251 /*
252 * Call the common device extension initializer.
253 */
254 rc = VGDrvCommonInitDevExt(&g_DevExt, vboxguest->uIOPortBase,
255 bus_space_vaddr(vboxguest->iVMMDevMemResId,
256 vboxguest->VMMDevMemHandle),
257 vboxguest->VMMDevMemSize,
258#if ARCH_BITS == 64
259 VBOXOSTYPE_NetBSD_x64,
260#else
261 VBOXOSTYPE_NetBSD,
262#endif
263 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
264 if (RT_SUCCESS(rc))
265 {
266 /*
267 * Add IRQ of VMMDev.
268 */
269 rc = VBoxGuestNetBSDAddIRQ(vboxguest, pa);
270 if (RT_SUCCESS(rc))
271 {
272 vboxguest->vboxguest_state |= VBOXGUEST_STATE_INITOK;
273 return;
274 }
275 VGDrvCommonDeleteDevExt(&g_DevExt);
276 }
277 else
278 {
279 aprint_error_dev(vboxguest->sc_dev, "init failed\n");
280 }
281 bus_space_unmap(vboxguest->iVMMDevMemResId, vboxguest->VMMDevMemHandle, vboxguest->VMMDevMemSize);
282 }
283 else
284 {
285 aprint_error_dev(vboxguest->sc_dev, "MMIO mapping failed\n");
286 }
287 bus_space_unmap(vboxguest->io_tag, vboxguest->io_handle, vboxguest->io_regsize);
288 }
289 else
290 {
291 aprint_error_dev(vboxguest->sc_dev, "IO mapping failed\n");
292 }
293
294 RTR0Term();
295 return;
296}
297
298
299/**
300 * Sets IRQ for VMMDev.
301 *
302 * @returns NetBSD error code.
303 * @param vboxguest Pointer to the state info structure.
304 * @param pa Pointer to the PCI attach arguments.
305 */
306static int VBoxGuestNetBSDAddIRQ(vboxguest_softc *vboxguest, struct pci_attach_args *pa)
307{
308 int iResId = 0;
309 int rc = 0;
310 const char *intrstr;
311#if __NetBSD_Prereq__(6, 99, 39)
312 char intstrbuf[100];
313#endif
314
315 LogFlow((DEVICE_NAME ": %s\n", __func__));
316
317 if (pci_intr_map(pa, &vboxguest->ih))
318 {
319 aprint_error_dev(vboxguest->sc_dev, "couldn't map interrupt.\n");
320 return VERR_DEV_IO_ERROR;
321 }
322
323 intrstr = pci_intr_string(vboxguest->pc, vboxguest->ih
324#if __NetBSD_Prereq__(6, 99, 39)
325 , intstrbuf, sizeof(intstrbuf)
326#endif
327 );
328 aprint_normal_dev(vboxguest->sc_dev, "interrupting at %s\n", intrstr);
329
330 vboxguest->pfnIrqHandler = pci_intr_establish(vboxguest->pc, vboxguest->ih, IPL_BIO, VBoxGuestNetBSDISR, vboxguest);
331 if (vboxguest->pfnIrqHandler == NULL)
332 {
333 aprint_error_dev(vboxguest->sc_dev, "couldn't establish interrupt\n");
334 return VERR_DEV_IO_ERROR;
335 }
336
337 return VINF_SUCCESS;
338}
339
340
341static int VBoxGuestNetBSDDetach(device_t self, int flags)
342{
343 vboxguest_softc *vboxguest;
344 vboxguest = device_private(self);
345
346 LogFlow((DEVICE_NAME ": %s\n", __func__));
347
348 if (cUsers > 0)
349 return EBUSY;
350
351 if ((vboxguest->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
352 return 0;
353
354 /*
355 * Reverse what we did in VBoxGuestNetBSDAttach.
356 */
357
358 VBoxGuestNetBSDRemoveIRQ(vboxguest);
359
360 VGDrvCommonDeleteDevExt(&g_DevExt);
361
362 bus_space_unmap(vboxguest->iVMMDevMemResId, vboxguest->VMMDevMemHandle, vboxguest->VMMDevMemSize);
363 bus_space_unmap(vboxguest->io_tag, vboxguest->io_handle, vboxguest->io_regsize);
364
365 RTR0Term();
366
367 return 0;
368}
369
370
371/**
372 * Removes IRQ for VMMDev.
373 *
374 * @param vboxguest Opaque pointer to the state info structure.
375 */
376static void VBoxGuestNetBSDRemoveIRQ(vboxguest_softc *vboxguest)
377{
378 LogFlow((DEVICE_NAME ": %s\n", __func__));
379
380 if (vboxguest->pfnIrqHandler)
381 {
382 pci_intr_disestablish(vboxguest->pc, vboxguest->pfnIrqHandler);
383 }
384}
385
386
387/**
388 * Interrupt service routine.
389 *
390 * @returns Whether the interrupt was from VMMDev.
391 * @param pvState Opaque pointer to the device state.
392 */
393static int VBoxGuestNetBSDISR(void *pvState)
394{
395 LogFlow((DEVICE_NAME ": %s: pvState=%p\n", __func__, pvState));
396
397 bool fOurIRQ = VGDrvCommonISR(&g_DevExt);
398
399 return fOurIRQ ? 0 : 1;
400}
401
402
403/*
404 * Called by VGDrvCommonISR() if mouse position changed
405 */
406void VGDrvNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
407{
408 LogFlow((DEVICE_NAME ": %s\n", __func__));
409
410 /*
411 * Wake up poll waiters.
412 */
413 selnotify(&g_SelInfo, 0, 0);
414}
415
416
417/**
418 * File open handler
419 *
420 */
421static int VBoxGuestNetBSDOpen(dev_t device, int flags, int fmt, struct lwp *process)
422{
423 int rc;
424 vboxguest_softc *vboxguest;
425 struct vboxguest_session *session;
426 file_t *fp;
427 int fd, error;
428
429 LogFlow((DEVICE_NAME ": %s\n", __func__));
430
431 if ((vboxguest = device_lookup_private(&vboxguest_cd, minor(device))) == NULL)
432 {
433 printf("device_lookup_private failed\n");
434 return (ENXIO);
435 }
436
437 if ((vboxguest->vboxguest_state & VBOXGUEST_STATE_INITOK) == 0)
438 {
439 aprint_error_dev(vboxguest->sc_dev, "device not configured\n");
440 return (ENXIO);
441 }
442
443 session = kmem_alloc(sizeof(*session), KM_SLEEP);
444 if (session == NULL)
445 {
446 return (ENOMEM);
447 }
448
449 session->sc = vboxguest;
450
451 if ((error = fd_allocfile(&fp, &fd)) != 0)
452 {
453 kmem_free(session, sizeof(*session));
454 return error;
455 }
456
457 /*
458 * Create a new session.
459 */
460 rc = VGDrvCommonCreateUserSession(&g_DevExt, &session->session);
461 if (! RT_SUCCESS(rc))
462 {
463 aprint_error_dev(vboxguest->sc_dev, "VBox session creation failed\n");
464 closef(fp); /* ??? */
465 kmem_free(session, sizeof(*session));
466 return RTErrConvertToErrno(rc);
467 }
468 ASMAtomicIncU32(&cUsers);
469 return fd_clone(fp, fd, flags, &vboxguest_fileops, session);
470
471}
472
473/**
474 * File close handler
475 *
476 */
477static int VBoxGuestNetBSDClose(struct file *fp)
478{
479 struct vboxguest_session *session = fp->f_data;
480 vboxguest_softc *vboxguest = session->sc;
481
482 LogFlow((DEVICE_NAME ": %s\n", __func__));
483
484 VGDrvCommonCloseSession(&g_DevExt, session->session);
485 ASMAtomicDecU32(&cUsers);
486
487 kmem_free(session, sizeof(*session));
488
489 return 0;
490}
491
492/**
493 * IOCTL handler
494 *
495 */
496static int VBoxGuestNetBSDIOCtl(struct file *fp, u_long command, void *data)
497{
498 struct vboxguest_session *session = fp->f_data;
499
500 if (VBGL_IOCTL_IS_FAST(command))
501 return VGDrvCommonIoCtlFast(command, &g_DevExt, session->session);
502
503 return VBoxGuestNetBSDIOCtlSlow(session, command, data);
504}
505
506static int VBoxGuestNetBSDIOCtlSlow(struct vboxguest_session *session, u_long command, void *data)
507{
508 vboxguest_softc *vboxguest = session->sc;
509 size_t cbReq = IOCPARM_LEN(command);
510 PVBGLREQHDR pHdr = NULL;
511 void *pvUser = NULL;
512 int err, rc;
513
514 LogFlow(("%s: command=%#lx data=%p\n", __func__, command, data));
515
516 /*
517 * Buffered request?
518 */
519 if ((command & IOC_DIRMASK) == IOC_INOUT)
520 {
521 /* will be validated by VGDrvCommonIoCtl() */
522 pHdr = (PVBGLREQHDR)data;
523 }
524
525 /*
526 * Big unbuffered request? "data" is the userland pointer.
527 */
528 else if ((command & IOC_DIRMASK) == IOC_VOID && cbReq != 0)
529 {
530 /*
531 * Read the header, validate it and figure out how much that
532 * needs to be buffered.
533 */
534 VBGLREQHDR Hdr;
535
536 if (RT_UNLIKELY(cbReq < sizeof(Hdr)))
537 return ENOTTY;
538
539 pvUser = data;
540 err = copyin(pvUser, &Hdr, sizeof(Hdr));
541 if (RT_UNLIKELY(err != 0))
542 return err;
543
544 if (RT_UNLIKELY(Hdr.uVersion != VBGLREQHDR_VERSION))
545 return ENOTTY;
546
547 if (cbReq > 16 * _1M)
548 return EINVAL;
549
550 if (Hdr.cbOut == 0)
551 Hdr.cbOut = Hdr.cbIn;
552
553 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr) || Hdr.cbIn > cbReq
554 || Hdr.cbOut < sizeof(Hdr) || Hdr.cbOut > cbReq))
555 return EINVAL;
556
557 /*
558 * Allocate buffer and copy in the data.
559 */
560 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
561
562 pHdr = (PVBGLREQHDR)RTMemTmpAlloc(cbReq);
563 if (RT_UNLIKELY(pHdr == NULL))
564 {
565 LogRel(("%s: command=%#lx data=%p: unable to allocate %zu bytes\n",
566 __func__, command, data, cbReq));
567 return ENOMEM;
568 }
569
570 err = copyin(pvUser, pHdr, Hdr.cbIn);
571 if (err != 0)
572 {
573 RTMemTmpFree(pHdr);
574 return err;
575 }
576
577 if (Hdr.cbIn < cbReq)
578 memset((uint8_t *)pHdr + Hdr.cbIn, '\0', cbReq - Hdr.cbIn);
579 }
580
581 /*
582 * Process the IOCtl.
583 */
584 rc = VGDrvCommonIoCtl(command, &g_DevExt, session->session, pHdr, cbReq);
585 if (RT_SUCCESS(rc))
586 {
587 err = 0;
588
589 /*
590 * If unbuffered, copy back the result before returning.
591 */
592 if (pvUser != NULL)
593 {
594 size_t cbOut = pHdr->cbOut;
595 if (cbOut > cbReq)
596 {
597 LogRel(("%s: command=%#lx data=%p: too much output: %zu > %zu\n",
598 __func__, command, data, cbOut, cbReq));
599 cbOut = cbReq;
600 }
601
602 err = copyout(pHdr, pvUser, cbOut);
603 RTMemTmpFree(pHdr);
604 }
605 }
606 else
607 {
608 LogRel(("%s: command=%#lx data=%p: error %Rrc\n",
609 __func__, command, data, rc));
610
611 if (pvUser != NULL)
612 RTMemTmpFree(pHdr);
613
614 err = RTErrConvertToErrno(rc);
615 }
616
617 return err;
618}
619
620static int VBoxGuestNetBSDPoll(struct file *fp, int events)
621{
622 struct vboxguest_session *session = fp->f_data;
623 vboxguest_softc *vboxguest = session->sc;
624
625 int rc = 0;
626 int events_processed;
627
628 uint32_t u32CurSeq;
629
630 LogFlow((DEVICE_NAME ": %s\n", __func__));
631
632 u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
633 if (session->session->u32MousePosChangedSeq != u32CurSeq)
634 {
635 events_processed = events & (POLLIN | POLLRDNORM);
636 session->session->u32MousePosChangedSeq = u32CurSeq;
637 }
638 else
639 {
640 events_processed = 0;
641
642 selrecord(curlwp, &g_SelInfo);
643 }
644
645 return events_processed;
646}
647
648
649/**
650 * @note This code is duplicated on other platforms with variations, so please
651 * keep them all up to date when making changes!
652 */
653int VBOXCALL VBoxGuestIDC(void *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq)
654{
655 /*
656 * Simple request validation (common code does the rest).
657 */
658 int rc;
659 if ( RT_VALID_PTR(pReqHdr)
660 && cbReq >= sizeof(*pReqHdr))
661 {
662 /*
663 * All requests except the connect one requires a valid session.
664 */
665 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
666 if (pSession)
667 {
668 if ( RT_VALID_PTR(pSession)
669 && pSession->pDevExt == &g_DevExt)
670 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
671 else
672 rc = VERR_INVALID_HANDLE;
673 }
674 else if (uReq == VBGL_IOCTL_IDC_CONNECT)
675 {
676 rc = VGDrvCommonCreateKernelSession(&g_DevExt, &pSession);
677 if (RT_SUCCESS(rc))
678 {
679 rc = VGDrvCommonIoCtl(uReq, &g_DevExt, pSession, pReqHdr, cbReq);
680 if (RT_FAILURE(rc))
681 VGDrvCommonCloseSession(&g_DevExt, pSession);
682 }
683 }
684 else
685 rc = VERR_INVALID_HANDLE;
686 }
687 else
688 rc = VERR_INVALID_POINTER;
689 return rc;
690}
691
692
693MODULE(MODULE_CLASS_DRIVER, vboxguest, "pci");
694
695static int loc[2] = {-1, -1};
696
697static const struct cfparent pspec = {
698 "pci", "pci", DVUNIT_ANY
699};
700
701static struct cfdata vboxguest_cfdata[] = {
702 {
703 .cf_name = "vboxguest",
704 .cf_atname = "vboxguest",
705 .cf_unit = 0, /* Only unit 0 is ever used */
706 .cf_fstate = FSTATE_STAR,
707 .cf_loc = loc,
708 .cf_flags = 0,
709 .cf_pspec = &pspec,
710 },
711 { NULL, NULL, 0, 0, NULL, 0, NULL }
712};
713
714static int
715vboxguest_modcmd(modcmd_t cmd, void *opaque)
716{
717 devmajor_t bmajor, cmajor;
718 int error;
719 register_t retval;
720
721 LogFlow((DEVICE_NAME ": %s\n", __func__));
722
723 bmajor = cmajor = NODEVMAJOR;
724 switch (cmd)
725 {
726 case MODULE_CMD_INIT:
727 error = config_cfdriver_attach(&vboxguest_cd);
728 if (error)
729 {
730 printf("config_cfdriver_attach failed: %d", error);
731 break;
732 }
733 error = config_cfattach_attach(vboxguest_cd.cd_name, &vboxguest_ca);
734 if (error)
735 {
736 config_cfdriver_detach(&vboxguest_cd);
737 printf("%s: unable to register cfattach\n", vboxguest_cd.cd_name);
738 break;
739 }
740 error = config_cfdata_attach(vboxguest_cfdata, 1);
741 if (error)
742 {
743 printf("%s: unable to attach cfdata\n", vboxguest_cd.cd_name);
744 config_cfattach_detach(vboxguest_cd.cd_name, &vboxguest_ca);
745 config_cfdriver_detach(&vboxguest_cd);
746 break;
747 }
748
749 error = devsw_attach("vboxguest", NULL, &bmajor, &g_VBoxGuestNetBSDChrDevSW, &cmajor);
750
751 if (error == EEXIST)
752 error = 0; /* maybe built-in ... improve eventually */
753
754 if (error)
755 break;
756
757 error = do_sys_mknod(curlwp, "/dev/vboxguest", 0666|S_IFCHR, makedev(cmajor, 0), &retval, UIO_SYSSPACE);
758 if (error == EEXIST)
759 error = 0;
760 break;
761
762 case MODULE_CMD_FINI:
763 error = config_cfdata_detach(vboxguest_cfdata);
764 if (error)
765 break;
766 error = config_cfattach_detach(vboxguest_cd.cd_name, &vboxguest_ca);
767 if (error)
768 break;
769 config_cfdriver_detach(&vboxguest_cd);
770 error = devsw_detach(NULL, &g_VBoxGuestNetBSDChrDevSW);
771 break;
772
773 default:
774 return ENOTTY;
775 }
776 return error;
777}
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