VirtualBox

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

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

VBoxGuest-netbsd.c: catch up with ioctl changes

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