VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/module/vboxmod.c@ 14352

Last change on this file since 14352 was 14352, checked in by vboxsync, 16 years ago

Additions/HGCM: merged code for HGCMCall and HGCMCallTimed, as per todo

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.5 KB
Line 
1/** @file
2 * vboxadd -- VirtualBox Guest Additions for Linux
3 */
4
5/*
6 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
17 * Clara, CA 95054 USA or visit http://www.sun.com if you need
18 * additional information or have any questions.
19 */
20
21#include "the-linux-kernel.h"
22#include "version-generated.h"
23
24/* #define IRQ_DEBUG */
25/* #define IOCTL_DEBUG */
26#ifdef IOCTL_DEBUG
27# define IOCTL_ENTRY(name, arg) \
28do { \
29 Log(("IOCTL_ENTRY: %s, 0x%x\n", (name), (arg))); \
30} while(0)
31# define IOCTL_EXIT(name, arg) \
32do { \
33 Log(("IOCTL_EXIT: %s, 0x%x\n", (name), (arg))); \
34} while(0)
35#else
36# define IOCTL_ENTRY(name, arg) do { } while(0)
37# define IOCTL_EXIT(name, arg) do { } while(0)
38#endif
39#ifdef IOCTL_LOG_DEBUG
40# define IOCTL_LOG_ENTRY(arg) \
41do { \
42 Log(("IOCTL_ENTRY: Log, 0x%x\n", (arg))); \
43} while(0)
44# define IOCTL_LOG_EXIT(arg) \
45do { \
46 Log(("IOCTL_EXIT: Log, 0x%x\n", (arg))); \
47} while(0)
48#else
49# define IOCTL_LOG_ENTRY(arg) do { } while(0)
50# define IOCTL_LOG_EXIT(arg) do { } while(0)
51#endif
52#ifdef IOCTL_VMM_DEBUG
53# define IOCTL_VMM_ENTRY(arg) \
54do { \
55 Log(("IOCTL_ENTRY: VMMDevReq, 0x%x\n", (arg))); \
56} while(0)
57# define IOCTL_VMM_EXIT(arg) \
58do { \
59 Log(("IOCTL_EXIT: VMMDevReq, 0x%x\n", (arg))); \
60} while(0)
61#else
62# define IOCTL_VMM_ENTRY(arg) do { } while(0)
63# define IOCTL_VMM_EXIT(arg) do { } while(0)
64#endif
65
66#include "vboxmod.h"
67#include "waitcompat.h"
68
69#include <VBox/log.h>
70#include <VBox/VBoxDev.h>
71#include <iprt/asm.h>
72#include <iprt/assert.h>
73#include <linux/miscdevice.h>
74#include <linux/poll.h>
75
76#define xstr(s) str(s)
77#define str(s) #s
78
79MODULE_DESCRIPTION("VirtualBox Guest Additions for Linux Module");
80MODULE_AUTHOR("Sun Microsystems, Inc.");
81MODULE_LICENSE("GPL");
82#ifdef MODULE_VERSION
83MODULE_VERSION(VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")");
84#endif
85
86/** device extension structure (we only support one device instance) */
87static VBoxDevice *vboxDev = NULL;
88/** our file node major id (set dynamically) */
89#ifdef CONFIG_VBOXADD_MAJOR
90static unsigned int vbox_major = CONFIG_VBOXADD_MAJOR;
91#else
92static unsigned int vbox_major = 0;
93#endif
94
95DECLVBGL (void *) vboxadd_cmc_open (void)
96{
97 return vboxDev;
98}
99
100DECLVBGL (void) vboxadd_cmc_close (void *opaque)
101{
102 (void) opaque;
103}
104
105EXPORT_SYMBOL (vboxadd_cmc_open);
106EXPORT_SYMBOL (vboxadd_cmc_close);
107
108
109#define MAX_HGCM_CONNECTIONS 1024
110
111/**
112 * Structure for keeping track of HGCM connections owned by user space processes, so that
113 * we can close the connection if a process does not clean up properly (for example if it
114 * was terminated too abruptly).
115 */
116/* We just define a fixed number of these so far. This can be changed if it ever becomes
117 a problem. */
118static struct {
119 /** Open file structure that this connection handle is associated with */
120 struct file *filp;
121 /** HGCM connection ID */
122 uint32_t client_id;
123} hgcm_connections[MAX_HGCM_CONNECTIONS] = { { 0 } };
124
125/**
126 * Register an HGCM connection as being connected with a given file descriptor, so that it
127 * will be closed automatically when that file descriptor is.
128 *
129 * @returns 0 on success or Linux kernel error number
130 * @param clientID the client ID of the HGCM connection
131 * @param filep the file structure that the connection is to be associated with
132 */
133static int vboxadd_register_hgcm_connection(uint32_t client_id, struct file *filp)
134{
135 int i;
136 bool found = false;
137
138 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
139 Assert(hgcm_connections[i].client_id != client_id);
140 }
141 for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
142 if (ASMAtomicCmpXchgU32(&hgcm_connections[i].client_id, client_id, 0)) {
143 hgcm_connections[i].filp = filp;
144 found = true;
145 }
146 }
147 return found ? 0 : -ENFILE; /* Any ideas for a better error code? */
148}
149
150/**
151 * Unregister an HGCM connection associated with a given file descriptor without closing
152 * the connection.
153 *
154 * @returns 0 on success or Linux kernel error number
155 * @param clientID the client ID of the HGCM connection
156 */
157static int vboxadd_unregister_hgcm_connection_no_close(uint32_t client_id)
158{
159 int i;
160 bool found = false;
161
162 for (i = 0; (i < MAX_HGCM_CONNECTIONS) && (false == found); ++i) {
163 if (hgcm_connections[i].client_id == client_id) {
164 hgcm_connections[i].filp = NULL;
165 hgcm_connections[i].client_id = 0;
166 found = true;
167 }
168 }
169 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
170 Assert(hgcm_connections[i].client_id != client_id);
171 }
172 return found ? 0 : -ENOENT;
173}
174
175/**
176 * Unregister all HGCM connections associated with a given file descriptor, closing
177 * the connections in the process. This should be called when a file descriptor is
178 * closed.
179 *
180 * @returns 0 on success or Linux kernel error number
181 * @param clientID the client ID of the HGCM connection
182 */
183static int vboxadd_unregister_all_hgcm_connections(struct file *filp)
184{
185 int i;
186
187 for (i = 0; i < MAX_HGCM_CONNECTIONS; ++i) {
188 if (hgcm_connections[i].filp == filp) {
189 VBoxGuestHGCMDisconnectInfo infoDisconnect;
190 infoDisconnect.u32ClientID = hgcm_connections[i].client_id;
191 vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
192 &infoDisconnect);
193 hgcm_connections[i].filp = NULL;
194 hgcm_connections[i].client_id = 0;
195 }
196 }
197 return 0;
198}
199
200/**
201 * File open handler
202 *
203 */
204static int vboxadd_open(struct inode *inode, struct file *filp)
205{
206 /* no checks required */
207 return 0;
208}
209
210static void
211vboxadd_wait_for_event (VBoxGuestWaitEventInfo *info)
212{
213 long timeleft;
214 uint32_t cInterruptions = vboxDev->u32GuestInterruptions;
215 uint32_t in_mask = info->u32EventMaskIn;
216
217 info->u32Result = VBOXGUEST_WAITEVENT_OK;
218 if (RT_INDEFINITE_WAIT != info->u32TimeoutIn) {
219 timeleft = wait_event_interruptible_timeout
220 (vboxDev->eventq,
221 (vboxDev->u32Events & in_mask)
222 || (vboxDev->u32GuestInterruptions != cInterruptions),
223 msecs_to_jiffies (info->u32TimeoutIn)
224 );
225 if (vboxDev->u32GuestInterruptions != cInterruptions) {
226 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
227 }
228 if (timeleft < 0) {
229 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
230 }
231 if (timeleft == 0) {
232 info->u32Result = VBOXGUEST_WAITEVENT_TIMEOUT;
233 }
234 }
235 else {
236 if (wait_event_interruptible(vboxDev->eventq,
237 (vboxDev->u32Events & in_mask)
238 || (vboxDev->u32GuestInterruptions != cInterruptions)
239 )
240 ) {
241 info->u32Result = VBOXGUEST_WAITEVENT_INTERRUPTED;
242 }
243 }
244 info->u32EventFlagsOut = vboxDev->u32Events & in_mask;
245 vboxDev->u32Events &= ~in_mask;
246}
247
248/**
249 * IOCtl handler - wait for an event from the host.
250 *
251 * @returns Linux kernel return code
252 * @param ptr User space pointer to a structure describing the event
253 */
254static int vboxadd_wait_event(void *ptr)
255{
256 int rc = 0;
257 VBoxGuestWaitEventInfo info;
258
259 if (copy_from_user (&info, ptr, sizeof (info))) {
260 LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not get event info\n"));
261 rc = -EFAULT;
262 }
263
264 if (0 == rc) {
265 vboxadd_wait_for_event (&info);
266
267 if (copy_to_user (ptr, &info, sizeof (info))) {
268 LogRelFunc (("VBOXGUEST_IOCTL_WAITEVENT: can not put out_mask\n"));
269 rc = -EFAULT;
270 }
271 }
272 return 0;
273}
274
275/**
276 * IOCTL handler. Initiate an HGCM connection for a user space application. If the connection
277 * succeeds, it will be associated with the file structure used to open it, so that it will be
278 * automatically shut down again if the file descriptor is closed.
279 *
280 * @returns 0 on success, or a Linux kernel errno value
281 * @param filp the file structure with which the application opened the driver
282 * @param userspace_info userspace pointer to the hgcm connection information
283 * (VBoxGuestHGCMConnectInfo structure)
284 * @retval userspace_info userspace pointer to the hgcm connection information
285 */
286static int vboxadd_hgcm_connect(struct file *filp, unsigned long userspace_info)
287{
288 VBoxGuestHGCMConnectInfo info;
289 int rc = 0;
290
291 if (copy_from_user ((void *)&info, (void *)userspace_info,
292 sizeof (info)) != 0) {
293 LogFunc (("VBOXGUEST_IOCTL_HGCM_CONNECT: can not get connection info\n"));
294 rc = -EFAULT;
295 }
296 info.u32ClientID = 0;
297 if (rc >= 0) {
298 int vrc = vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_CONNECT,
299 &info);
300 rc = RT_FAILURE(vrc) ? -RTErrConvertToErrno(vrc)
301 : -RTErrConvertToErrno(info.result);
302 if (rc < 0)
303 LogFunc(("hgcm connection failed. internal ioctl result %Rrc, hgcm result %Rrc\n",
304 vrc, info.result));
305 }
306 if (rc >= 0) {
307 /* Register that the connection is associated with this file pointer. */
308 LogFunc(("Connected, client ID %u\n", info.u32ClientID));
309 rc = vboxadd_register_hgcm_connection(info.u32ClientID, filp);
310 if (rc < 0)
311 LogFunc(("failed to register the HGCM connection\n"));
312 }
313 if ( rc >= 0
314 && copy_to_user ((void *)userspace_info, (void *)&info,
315 sizeof(info)) != 0) {
316 LogFunc (("failed to return the connection structure\n"));
317 rc = -EFAULT;
318 }
319 if (rc < 0)
320 /* Unregister again, as we didn't get as far as informing userspace. */
321 vboxadd_unregister_hgcm_connection_no_close(info.u32ClientID);
322 if (rc < 0 && info.u32ClientID != 0) {
323 /* Disconnect the hgcm connection again, as we told userspace it failed. */
324 VBoxGuestHGCMDisconnectInfo infoDisconnect;
325 infoDisconnect.u32ClientID = info.u32ClientID;
326 vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
327 &infoDisconnect);
328 }
329 return rc;
330}
331
332/**
333 * IOCTL handler. Disconnect a specific HGCM connection.
334 *
335 * @returns 0 on success, or a Linux kernel errno value
336 * @param filp the file structure with which the application opened the driver
337 * @param userspace_info userspace pointer to the hgcm connection information
338 * (VBoxGuestHGCMConnectInfo structure)
339 * @retval userspace_info userspace pointer to the hgcm connection information
340 */
341static int vboxadd_hgcm_disconnect(struct file *filp, unsigned long userspace_info)
342{
343 int rc = 0, vrc = VINF_SUCCESS;
344
345 VBoxGuestHGCMDisconnectInfo info;
346 if (copy_from_user ((void *)&info, (void *)userspace_info,
347 sizeof (info)) != 0) {
348 LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: can not get info\n"));
349 rc = -EFAULT;
350 }
351 if (rc >= 0) {
352 LogRelFunc(("client ID %u\n", info.u32ClientID));
353 vrc = vboxadd_cmc_call(vboxDev, VBOXGUEST_IOCTL_HGCM_DISCONNECT,
354 &info);
355 rc = -RTErrConvertToErrno(vrc);
356 }
357 if ( rc >= 0
358 && copy_to_user ((void *)userspace_info, (void *)&info,
359 sizeof(info)) != 0) {
360 LogRelFunc (("VBOXGUEST_IOCTL_HGCM_DISCONNECT: failed to return the connection structure\n"));
361 rc = -EFAULT;
362 }
363 return rc;
364}
365
366/**
367 * IOCTL handler. Make an HGCM call.
368 *
369 * @returns 0 on success, or a Linux kernel errno value
370 * @param userspace_info userspace pointer to the hgcm connection information
371 * (VBoxGuestHGCMConnectInfo structure). This will be
372 * updated on success.
373 * @param u32Size the size of the userspace structure
374 */
375static int vboxadd_hgcm_call(unsigned long userspace_info, uint32_t u32Size)
376{
377 VBoxGuestHGCMCallInfo *pInfo = NULL;
378 int rc = 0;
379
380 pInfo = kmalloc(u32Size, GFP_KERNEL);
381 if (pInfo == NULL)
382 rc = -ENOMEM;
383 if (rc >= 0 &&
384 0 != copy_from_user ((void *)pInfo, (void *)userspace_info, u32Size)) {
385 LogRelFunc (("can not get info from user space\n"));
386 rc = -EFAULT;
387 }
388 if (rc >= 0 &&
389 sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) != u32Size) {
390 LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
391 sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter),
392 u32Size));
393 rc = -EINVAL;
394 }
395 if (rc >= 0) {
396 int vrc;
397 LogRelFunc(("client ID %u\n", pInfo->u32ClientID));
398 vrc = vboxadd_cmc_call(vboxDev,
399 VBOXGUEST_IOCTL_HGCM_CALL(u32Size), pInfo);
400 rc = -RTErrConvertToErrno(vrc);
401 if ( rc >= 0
402 && copy_to_user ((void *)userspace_info, (void *)pInfo,
403 u32Size)) {
404 LogRelFunc (("failed to return the information to user space\n"));
405 rc = -EFAULT;
406 }
407 }
408 if (pInfo != NULL)
409 kfree(pInfo);
410 return rc;
411}
412
413/**
414 * IOCTL handler. Make an HGCM call with timeout.
415 *
416 * @returns 0 on success, or a Linux kernel errno value
417 * @param userspace_info userspace pointer to the hgcm connection information
418 * (VBoxGuestHGCMConnectInfo structure). This will be
419 * updated on success.
420 * @param u32Size the size of the userspace structure
421 */
422static int vboxadd_hgcm_call_timed(unsigned long userspace_info,
423 uint32_t u32Size)
424{
425 VBoxGuestHGCMCallInfoTimed *pInfo = NULL;
426 int rc = 0;
427
428 pInfo = kmalloc(u32Size, GFP_KERNEL);
429 if (pInfo == NULL)
430 rc = -ENOMEM;
431 if (rc >= 0 &&
432 0 != copy_from_user ((void *)pInfo, (void *)userspace_info, u32Size)) {
433 LogRelFunc (("can not get info from user space\n"));
434 rc = -EFAULT;
435 }
436 if (rc >= 0 &&
437 sizeof(*pInfo) + pInfo->info.cParms * sizeof(HGCMFunctionParameter) != u32Size) {
438 LogRelFunc (("bad parameter size, structure says %d, ioctl says %d\n",
439 sizeof(*pInfo) + pInfo->info.cParms * sizeof(HGCMFunctionParameter),
440 u32Size));
441 rc = -EINVAL;
442 }
443 if (rc >= 0) {
444 int vrc;
445 LogRelFunc(("client ID %u\n", pInfo->info.u32ClientID));
446 vrc = vboxadd_cmc_call(vboxDev,
447 VBOXGUEST_IOCTL_HGCM_CALL_TIMED(u32Size), pInfo);
448 rc = -RTErrConvertToErrno(vrc);
449 if ( rc >= 0
450 && copy_to_user ((void *)userspace_info, (void *)pInfo,
451 u32Size)) {
452 LogRelFunc (("failed to return the information to user space\n"));
453 rc = -EFAULT;
454 }
455 }
456 if (pInfo != NULL)
457 kfree(pInfo);
458 return rc;
459}
460
461/**
462 * IOCtl handler. Control the interrupt filter mask to specify which VMMDev interrupts
463 * we know how to handle.
464 *
465 * @returns iprt status code
466 * @param pInfo kernel space pointer to the filter mask change info
467 */
468static int vboxadd_control_filter_mask(VBoxGuestFilterMaskInfo *pInfo)
469{
470 VMMDevCtlGuestFilterMask *pReq = NULL;
471 int rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), VMMDevReq_CtlGuestFilterMask);
472
473 LogFlow(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: request received, u32OrMask=0x%x, u32NotMask=0x%x\n", pInfo->u32OrMask, pInfo->u32NotMask));
474 if (RT_FAILURE(rc))
475 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: failed to allocate %u (%#x) bytes to cache the request. rc=%d!!\n", sizeof(*pReq), sizeof(*pReq), rc));
476 else
477 {
478 pReq->u32OrMask = pInfo->u32OrMask;
479 pReq->u32NotMask = pInfo->u32NotMask;
480 rc = VbglGRPerform(&pReq->header);
481 }
482 if (RT_FAILURE(rc))
483 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: VbglGRPerform failed, rc=%Rrc!\n", rc));
484 else if (RT_FAILURE(pReq->header.rc))
485 {
486 Log(("VBoxGuestCommonIOCtl: CTL_FILTER_MASK: The request failed; VMMDev rc=%Rrc!\n", pReq->header.rc));
487 rc = pReq->header.rc;
488 }
489 if (pReq)
490 VbglGRFree(&pReq->header);
491 return rc;
492}
493
494/**
495 * IOCTL handler
496 *
497 */
498static int vboxadd_ioctl(struct inode *inode, struct file *filp,
499 unsigned int cmd, unsigned long arg)
500{
501 int rc = 0;
502
503 /* Deal with variable size ioctls first. */
504 if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_LOG(0))
505 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
506 char *pszMessage;
507
508 IOCTL_LOG_ENTRY(arg);
509 pszMessage = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
510 if (NULL == pszMessage) {
511 LogRelFunc(("VBOXGUEST_IOCTL_LOG: cannot allocate %d bytes of memory!\n",
512 _IOC_SIZE(cmd)));
513 rc = -ENOMEM;
514 }
515 if ( (0 == rc)
516 && copy_from_user(pszMessage, (void*)arg, _IOC_SIZE(cmd))) {
517 LogRelFunc(("VBOXGUEST_IOCTL_LOG: copy_from_user failed!\n"));
518 rc = -EFAULT;
519 }
520 if (0 == rc) {
521 Log(("%.*s", _IOC_SIZE(cmd), pszMessage));
522 }
523 if (NULL != pszMessage) {
524 kfree(pszMessage);
525 }
526 IOCTL_LOG_EXIT(arg);
527 }
528 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_VMMREQUEST(0))
529 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd)) {
530 VMMDevRequestHeader reqHeader;
531 VMMDevRequestHeader *reqFull = NULL;
532 size_t cbRequestSize;
533 size_t cbVanillaRequestSize;
534
535 IOCTL_VMM_ENTRY(arg);
536 if (copy_from_user(&reqHeader, (void*)arg, sizeof(reqHeader)))
537 {
538 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: copy_from_user failed for vmm request!\n"));
539 rc = -EFAULT;
540 }
541 if (0 == rc)
542 {
543 /* get the request size */
544 cbVanillaRequestSize = vmmdevGetRequestSize(reqHeader.requestType);
545 if (!cbVanillaRequestSize)
546 {
547 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request type: %d\n",
548 reqHeader.requestType));
549 rc = -EINVAL;
550 }
551 }
552 if (0 == rc)
553 {
554 cbRequestSize = reqHeader.size;
555 if (cbRequestSize < cbVanillaRequestSize)
556 {
557 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: invalid request size: %d min: %d type: %d\n",
558 cbRequestSize,
559 cbVanillaRequestSize,
560 reqHeader.requestType));
561 rc = -EINVAL;
562 }
563 }
564 if (0 == rc)
565 {
566 /* request storage for the full request */
567 rc = VbglGRAlloc(&reqFull, cbRequestSize, reqHeader.requestType);
568 if (RT_FAILURE(rc))
569 {
570 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: could not allocate request structure! rc = %d\n", rc));
571 rc = -EFAULT;
572 }
573 }
574 if (0 == rc)
575 {
576 /* now get the full request */
577 if (copy_from_user(reqFull, (void*)arg, cbRequestSize))
578 {
579 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: failed to fetch full request from user space!\n"));
580 rc = -EFAULT;
581 }
582 }
583
584 /* now issue the request */
585 if (0 == rc)
586 {
587 int rrc = VbglGRPerform(reqFull);
588
589 /* asynchronous processing? */
590 if (rrc == VINF_HGCM_ASYNC_EXECUTE)
591 {
592 VMMDevHGCMRequestHeader *reqHGCM = (VMMDevHGCMRequestHeader*)reqFull;
593 wait_event_interruptible (vboxDev->eventq, reqHGCM->fu32Flags & VBOX_HGCM_REQ_DONE);
594 rrc = reqFull->rc;
595 }
596
597 /* failed? */
598 if (RT_FAILURE(rrc) || RT_FAILURE(reqFull->rc))
599 {
600 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: request execution failed!\n"));
601 rc = RT_FAILURE(rrc) ? -RTErrConvertToErrno(rrc)
602 : -RTErrConvertToErrno(reqFull->rc);
603 }
604 else
605 {
606 /* success, copy the result data to user space */
607 if (copy_to_user((void*)arg, (void*)reqFull, cbRequestSize))
608 {
609 LogRelFunc(("VBOXGUEST_IOCTL_VMMREQUEST: error copying request result to user space!\n"));
610 rc = -EFAULT;
611 }
612 }
613 }
614 if (NULL != reqFull)
615 VbglGRFree(reqFull);
616 IOCTL_VMM_EXIT(arg);
617 }
618 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL(0))
619 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
620 {
621 /* Do the HGCM call using the Vbgl bits */
622 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL", arg);
623 rc = vboxadd_hgcm_call(arg, _IOC_SIZE(cmd));
624 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL", arg);
625 }
626 else if ( VBOXGUEST_IOCTL_STRIP_SIZE(VBOXGUEST_IOCTL_HGCM_CALL_TIMED(0))
627 == VBOXGUEST_IOCTL_STRIP_SIZE(cmd))
628 {
629 /* Do the HGCM call using the Vbgl bits */
630 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
631 rc = vboxadd_hgcm_call_timed(arg, _IOC_SIZE(cmd));
632 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CALL_TIMED", arg);
633 }
634 else
635 {
636 switch (cmd) {
637 case VBOXGUEST_IOCTL_WAITEVENT:
638 IOCTL_ENTRY("VBOXGUEST_IOCTL_WAITEVENT", arg);
639 rc = vboxadd_wait_event((void *) arg);
640 IOCTL_EXIT("VBOXGUEST_IOCTL_WAITEVENT", arg);
641 break;
642 case VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS:
643 IOCTL_ENTRY("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
644 ++vboxDev->u32GuestInterruptions;
645 IOCTL_EXIT("VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS", arg);
646 break;
647 case VBOXGUEST_IOCTL_HGCM_CONNECT:
648 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
649 rc = vboxadd_hgcm_connect(filp, arg);
650 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_CONNECT", arg);
651 break;
652 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
653 IOCTL_ENTRY("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
654 vboxadd_hgcm_disconnect(filp, arg);
655 IOCTL_EXIT("VBOXGUEST_IOCTL_HGCM_DISCONNECT", arg);
656 break;
657 case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
658 {
659 VBoxGuestFilterMaskInfo info;
660 IOCTL_ENTRY("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
661 if (copy_from_user((void*)&info, (void*)arg, sizeof(info)))
662 {
663 LogRelFunc(("VBOXGUEST_IOCTL_CTL_FILTER_MASK: error getting parameters from user space!\n"));
664 rc = -EFAULT;
665 break;
666 }
667 rc = -RTErrConvertToErrno(vboxadd_control_filter_mask(&info));
668 IOCTL_EXIT("VBOXGUEST_IOCTL_CTL_FILTER_MASK", arg);
669 break;
670 }
671 default:
672 LogRelFunc(("unknown command: %x\n", cmd));
673 rc = -EINVAL;
674 break;
675 }
676 }
677 return rc;
678}
679
680/**
681 * Poll function. This returns "ready to read" if the guest is in absolute
682 * mouse pointer mode and the pointer position has changed since the last
683 * poll.
684 */
685unsigned int
686vboxadd_poll (struct file *file, poll_table *wait)
687{
688 int result = 0;
689 poll_wait(file, &vboxDev->eventq, wait);
690 if (vboxDev->u32Events & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
691 result = (POLLIN | POLLRDNORM);
692 vboxDev->u32Events &= ~VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
693 return result;
694}
695
696/** Asynchronous notification activation method. */
697static int
698vboxadd_fasync(int fd, struct file *file, int mode)
699{
700 return fasync_helper(fd, file, mode, &vboxDev->async_queue);
701}
702
703/**
704 * Dummy read function - we only supply this because we implement poll and
705 * fasync.
706 */
707static ssize_t
708vboxadd_read (struct file *file, char *buf, size_t count, loff_t *loff)
709{
710 if (0 == count || *loff != 0)
711 {
712 return -EINVAL;
713 }
714 buf[0] = 0;
715 return 1;
716}
717
718/**
719 * File close handler. Clean up any HGCM connections associated with the open file
720 * which might still be open.
721 */
722static int vboxadd_release(struct inode *inode, struct file * filp)
723{
724 vboxadd_unregister_all_hgcm_connections(filp);
725 /* Deactivate our asynchronous queue. */
726 vboxadd_fasync(-1, filp, 0);
727 return 0;
728}
729
730/** strategy handlers (file operations) */
731static struct file_operations vbox_fops =
732{
733 .owner = THIS_MODULE,
734 .open = vboxadd_open,
735 .ioctl = vboxadd_ioctl,
736 .poll = vboxadd_poll,
737 .fasync = vboxadd_fasync,
738 .read = vboxadd_read,
739 .release = vboxadd_release,
740 .llseek = no_llseek
741};
742
743static struct miscdevice gMiscDevice =
744{
745 minor: MISC_DYNAMIC_MINOR,
746 name: "vboxadd",
747 fops: &vbox_fops
748};
749
750#ifndef IRQ_RETVAL
751/* interrupt handlers in 2.4 kernels don't return anything */
752# define irqreturn_t void
753# define IRQ_RETVAL(n)
754#endif
755
756/**
757 * vboxadd_irq_handler
758 *
759 * Interrupt handler
760 *
761 * @returns scsi error code
762 * @param irq Irq number
763 * @param dev_id Irq handler parameter
764 * @param regs Regs
765 *
766 */
767#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
768static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id)
769#else
770static irqreturn_t vboxadd_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
771#endif
772{
773 int fIRQTaken = 0;
774 int rcVBox;
775
776#ifdef IRQ_DEBUG
777 Log(("vboxadd IRQ_DEBUG: vboxDev->pVMMDevMemory=%p vboxDev->pVMMDevMemory->fHaveEvents=%d\n",
778 vboxDev->pVMMDevMemory, vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents));
779#endif
780
781 /* check if IRQ was asserted by VBox */
782 if (vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents != 0)
783 {
784#ifdef IRQ_DEBUG
785 Log(("vboxadd IRQ_DEBUG: got IRQ with event mask 0x%x\n",
786 vboxDev->irqAckRequest->events));
787#endif
788
789 /* make a copy of the event mask */
790 rcVBox = VbglGRPerform (&vboxDev->irqAckRequest->header);
791 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(vboxDev->irqAckRequest->header.rc))
792 {
793 if (RT_LIKELY (vboxDev->irqAckRequest->events))
794 {
795 vboxDev->u32Events |= vboxDev->irqAckRequest->events;
796 if ( vboxDev->irqAckRequest->events
797 & VMMDEV_EVENT_MOUSE_POSITION_CHANGED)
798 kill_fasync(&vboxDev->async_queue, SIGIO, POLL_IN);
799 wake_up (&vboxDev->eventq);
800 }
801 }
802 else
803 {
804 /* impossible... */
805 LogRelFunc(("IRQ was not acknowledged! rc = %Rrc, header.rc = %Rrc\n",
806 rcVBox, vboxDev->irqAckRequest->header.rc));
807 BUG ();
808 }
809
810 /* it was ours! */
811 fIRQTaken = 1;
812 }
813#ifdef IRQ_DEBUG
814 else
815 {
816 /* we might be attached to a shared interrupt together with another device. */
817 Log(("vboxadd IRQ_DEBUG: stale IRQ mem=%p events=%d devevents=%#x\n",
818 vboxDev->pVMMDevMemory,
819 vboxDev->pVMMDevMemory->V.V1_04.fHaveEvents,
820 vboxDev->u32Events));
821 }
822#endif
823 /* it was ours */
824 return IRQ_RETVAL(fIRQTaken);
825}
826
827/**
828 * Helper function to reserve a fixed kernel address space window
829 * and tell the VMM that it can safely put its hypervisor there.
830 * This function might fail which is not a critical error.
831 */
832static int vboxadd_reserve_hypervisor(void)
833{
834 VMMDevReqHypervisorInfo *req = NULL;
835 int rcVBox;
836
837 /* allocate request structure */
838 rcVBox = VbglGRAlloc(
839 (VMMDevRequestHeader**)&req,
840 sizeof(VMMDevReqHypervisorInfo),
841 VMMDevReq_GetHypervisorInfo
842 );
843 if (RT_FAILURE(rcVBox))
844 {
845 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
846 goto bail_out;
847 }
848 /* query the hypervisor information */
849 rcVBox = VbglGRPerform(&req->header);
850 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
851 {
852 /* are we supposed to make a reservation? */
853 if (req->hypervisorSize)
854 {
855 /** @todo repeat this several times until we get an address the host likes */
856
857 void *hypervisorArea;
858 /* reserve another 4MB because the start needs to be 4MB aligned */
859 uint32_t hypervisorSize = req->hypervisorSize + 0x400000;
860 /* perform a fictive IO space mapping */
861 hypervisorArea = ioremap(HYPERVISOR_PHYSICAL_START, hypervisorSize);
862 if (hypervisorArea)
863 {
864 /* communicate result to VMM, align at 4MB */
865 req->hypervisorStart = (VMMDEVHYPPTR32)(uintptr_t)RT_ALIGN_P(hypervisorArea, 0x400000);
866 req->header.requestType = VMMDevReq_SetHypervisorInfo;
867 req->header.rc = VERR_GENERAL_FAILURE;
868 rcVBox = VbglGRPerform(&req->header);
869 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
870 {
871 /* store mapping for future unmapping */
872 vboxDev->hypervisorStart = hypervisorArea;
873 vboxDev->hypervisorSize = hypervisorSize;
874 }
875 else
876 {
877 LogRelFunc(("failed to set hypervisor region! rc = %Rrc, header.rc = %Rrc\n",
878 rcVBox, req->header.rc));
879 goto bail_out;
880 }
881 }
882 else
883 {
884 LogRelFunc(("failed to allocate 0x%x bytes of IO space\n", hypervisorSize));
885 goto bail_out;
886 }
887 }
888 }
889 else
890 {
891 LogRelFunc(("failed to query hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
892 rcVBox, req->header.rc));
893 goto bail_out;
894 }
895 /* successful return */
896 VbglGRFree(&req->header);
897 return 0;
898bail_out:
899 /* error return */
900 if (req)
901 VbglGRFree(&req->header);
902 return 1;
903}
904
905/**
906 * Helper function to free the hypervisor address window
907 *
908 */
909static int vboxadd_free_hypervisor(void)
910{
911 VMMDevReqHypervisorInfo *req = NULL;
912 int rcVBox;
913
914 /* allocate request structure */
915 rcVBox = VbglGRAlloc(
916 (VMMDevRequestHeader**)&req,
917 sizeof(VMMDevReqHypervisorInfo),
918 VMMDevReq_SetHypervisorInfo
919 );
920 if (RT_FAILURE(rcVBox))
921 {
922 LogRelFunc(("failed to allocate hypervisor info structure! rc = %Rrc\n", rcVBox));
923 goto bail_out;
924 }
925 /* reset the hypervisor information */
926 req->hypervisorStart = 0;
927 req->hypervisorSize = 0;
928 rcVBox = VbglGRPerform(&req->header);
929 if (RT_SUCCESS(rcVBox) && RT_SUCCESS(req->header.rc))
930 {
931 /* now we can free the associated IO space mapping */
932 iounmap(vboxDev->hypervisorStart);
933 vboxDev->hypervisorStart = 0;
934 }
935 else
936 {
937 LogRelFunc(("failed to reset hypervisor info! rc = %Rrc, header.rc = %Rrc\n",
938 rcVBox, req->header.rc));
939 goto bail_out;
940 }
941 return 0;
942
943 bail_out:
944 if (req)
945 VbglGRFree(&req->header);
946 return 1;
947}
948
949/**
950 * Helper to free resources
951 *
952 */
953static void free_resources(void)
954{
955 if (vboxDev)
956 {
957 {
958 /* Unregister notifications when the host absolute pointer
959 * position changes. */
960 VBoxGuestFilterMaskInfo info;
961 info.u32OrMask = 0;
962 info.u32NotMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
963 vboxadd_control_filter_mask(&info);
964 }
965 /* Detach from IRQ before cleaning up! */
966 if (vboxDev->irq)
967 free_irq(vboxDev->irq, vboxDev);
968 if (vboxDev->hypervisorStart)
969 vboxadd_free_hypervisor();
970 if (vboxDev->irqAckRequest)
971 {
972 VbglGRFree(&vboxDev->irqAckRequest->header);
973 VbglTerminate();
974 }
975 if (vboxDev->pVMMDevMemory)
976 iounmap(vboxDev->pVMMDevMemory);
977 if (vboxDev->vmmdevmem)
978 release_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size);
979 kfree(vboxDev);
980 vboxDev = NULL;
981 }
982}
983
984#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
985#define PCI_DEV_GET(v,d,p) pci_get_device(v,d,p)
986#define PCI_DEV_PUT(x) pci_dev_put(x)
987#else
988#define PCI_DEV_GET(v,d,p) pci_find_device(v,d,p)
989#define PCI_DEV_PUT(x)
990#endif
991
992/**
993 * Module initialization
994 *
995 */
996static __init int init(void)
997{
998 int err;
999 int rcVBox;
1000 struct pci_dev *pcidev = NULL;
1001 VMMDevReportGuestInfo *infoReq = NULL;
1002
1003 if (vboxadd_cmc_init ())
1004 {
1005 printk (KERN_ERR "vboxadd: could not init cmc.\n");
1006 return -ENODEV;
1007 }
1008
1009 /*
1010 * Detect PCI device
1011 */
1012 pcidev = PCI_DEV_GET(VMMDEV_VENDORID, VMMDEV_DEVICEID, pcidev);
1013 if (!pcidev)
1014 {
1015 printk(KERN_ERR "vboxadd: VirtualBox PCI device not found.\n");
1016 return -ENODEV;
1017 }
1018
1019 err = pci_enable_device (pcidev);
1020 if (err)
1021 {
1022 Log(("vboxadd: could not enable device: %d\n", err));
1023 PCI_DEV_PUT(pcidev);
1024 return -ENODEV;
1025 }
1026
1027 LogRel(("Starting VirtualBox version %s Guest Additions\n",
1028 VBOX_VERSION_STRING));
1029 /* register a character device */
1030 if (vbox_major > 0)
1031 {
1032 err = register_chrdev(vbox_major, "vboxadd", &vbox_fops);
1033 if (err < 0 || (vbox_major & err) || (!vbox_major && !err))
1034 {
1035 LogRelFunc(("register_chrdev failed: vbox_major: %d, err = %d\n",
1036 vbox_major, err));
1037 PCI_DEV_PUT(pcidev);
1038 return -ENODEV;
1039 }
1040 /* if no major code was set, take the return value */
1041 if (!vbox_major)
1042 vbox_major = err;
1043 }
1044 else
1045 {
1046 err = misc_register(&gMiscDevice);
1047 if (err)
1048 {
1049 LogRelFunc(("misc_register failed (rc=%d)\n", err));
1050 return -ENODEV;
1051 }
1052 }
1053
1054 /* allocate and initialize device extension */
1055 vboxDev = kmalloc(sizeof(*vboxDev), GFP_KERNEL);
1056 if (!vboxDev)
1057 {
1058 LogRelFunc(("cannot allocate device!\n"));
1059 err = -ENOMEM;
1060 goto fail;
1061 }
1062 memset(vboxDev, 0, sizeof(*vboxDev));
1063 snprintf(vboxDev->name, sizeof(vboxDev->name), "vboxadd");
1064
1065 /* get the IO port region */
1066 vboxDev->io_port = pci_resource_start(pcidev, 0);
1067
1068 /* get the memory region */
1069 vboxDev->vmmdevmem = pci_resource_start(pcidev, 1);
1070 vboxDev->vmmdevmem_size = pci_resource_len(pcidev, 1);
1071
1072 /* all resources found? */
1073 if (!vboxDev->io_port || !vboxDev->vmmdevmem || !vboxDev->vmmdevmem_size)
1074 {
1075 LogRelFunc(("did not find expected hardware resources!\n"));
1076 err = -ENXIO;
1077 goto fail;
1078 }
1079
1080 /* request ownership of adapter memory */
1081 if (request_mem_region(vboxDev->vmmdevmem, vboxDev->vmmdevmem_size, "vboxadd") == 0)
1082 {
1083 LogRelFunc(("failed to request adapter memory!\n"));
1084 err = -ENXIO;
1085 goto fail;
1086 }
1087
1088 /* map adapter memory into kernel address space and check version */
1089 vboxDev->pVMMDevMemory = (VMMDevMemory *) ioremap(vboxDev->vmmdevmem,
1090 vboxDev->vmmdevmem_size);
1091 if (!vboxDev->pVMMDevMemory)
1092 {
1093 LogRelFunc(("ioremap failed\n"));
1094 err = -ENOMEM;
1095 goto fail;
1096 }
1097
1098 if (vboxDev->pVMMDevMemory->u32Version != VMMDEV_MEMORY_VERSION)
1099 {
1100 LogRelFunc(("invalid VMM device memory version! (got 0x%x, expected 0x%x)\n",
1101 vboxDev->pVMMDevMemory->u32Version, VMMDEV_MEMORY_VERSION));
1102 err = -ENXIO;
1103 goto fail;
1104 }
1105
1106 /* initialize VBGL subsystem */
1107 rcVBox = VbglInit(vboxDev->io_port, vboxDev->pVMMDevMemory);
1108 if (RT_FAILURE(rcVBox))
1109 {
1110 LogRelFunc(("could not initialize VBGL subsystem! rc = %Rrc\n", rcVBox));
1111 err = -ENXIO;
1112 goto fail;
1113 }
1114
1115 /* report guest information to host, this must be done as the very first request */
1116 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&infoReq,
1117 sizeof(VMMDevReportGuestInfo), VMMDevReq_ReportGuestInfo);
1118 if (RT_FAILURE(rcVBox))
1119 {
1120 LogRelFunc(("could not allocate request structure! rc = %Rrc\n", rcVBox));
1121 err = -ENOMEM;
1122 goto fail;
1123 }
1124
1125 /* report guest version to host, the VMMDev requires that to be done first */
1126 infoReq->guestInfo.additionsVersion = VMMDEV_VERSION;
1127#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
1128 infoReq->guestInfo.osType = VBOXOSTYPE_Linux26;
1129#else
1130 infoReq->guestInfo.osType = VBOXOSTYPE_Linux24;
1131#endif
1132 rcVBox = VbglGRPerform(&infoReq->header);
1133 if (RT_FAILURE(rcVBox) || RT_FAILURE(infoReq->header.rc))
1134 {
1135 LogRelFunc(("error reporting guest info to host! rc = %Rrc, header.rc = %Rrc\n",
1136 rcVBox, infoReq->header.rc));
1137 VbglGRFree(&infoReq->header);
1138 err = -ENXIO;
1139 goto fail;
1140 }
1141 VbglGRFree(&infoReq->header);
1142
1143 /* Unset the graphics capability until/unless X is loaded. */
1144 /** @todo check the error code once we bump the additions version.
1145 For now we ignore it for compatibility with older hosts. */
1146 {
1147 VMMDevReqGuestCapabilities2 *vmmreqGuestCaps;
1148
1149
1150 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vmmreqGuestCaps,
1151 sizeof(VMMDevReqGuestCapabilities2),
1152 VMMDevReq_SetGuestCapabilities);
1153 if (RT_FAILURE(rcVBox))
1154 {
1155 LogRelFunc(("could not allocate request structure! rc = %Rrc\n", rcVBox));
1156 err = -ENOMEM;
1157 goto fail;
1158 }
1159 vmmreqGuestCaps->u32OrMask = 0;
1160 vmmreqGuestCaps->u32NotMask = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
1161 rcVBox = VbglGRPerform(&vmmreqGuestCaps->header);
1162 VbglGRFree(&vmmreqGuestCaps->header);
1163 if (RT_FAILURE(rcVBox))
1164 {
1165 err = -ENXIO;
1166 goto fail;
1167 }
1168 }
1169
1170 /* perform hypervisor address space reservation */
1171 if (vboxadd_reserve_hypervisor())
1172 {
1173 /* we just ignore the error, no address window reservation, non fatal */
1174 }
1175
1176 /* allocate a VMM request structure for use in the ISR */
1177 rcVBox = VbglGRAlloc((VMMDevRequestHeader**)&vboxDev->irqAckRequest,
1178 sizeof(VMMDevEvents), VMMDevReq_AcknowledgeEvents);
1179 if (RT_FAILURE(rcVBox))
1180 {
1181 LogRelFunc(("could not allocate request structure! rc = %Rrc\n", rcVBox));
1182 err = -ENOMEM;
1183 goto fail;
1184 }
1185
1186 /* get ISR */
1187 err = request_irq(pcidev->irq, vboxadd_irq_handler,
1188#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
1189 IRQF_SHARED,
1190#else
1191 SA_SHIRQ,
1192#endif
1193 "vboxadd", vboxDev);
1194 if (err)
1195 {
1196 LogRelFunc(("could not request IRQ %d, err: %d\n", pcidev->irq, err));
1197 goto fail;
1198 }
1199 vboxDev->irq = pcidev->irq;
1200
1201 init_waitqueue_head (&vboxDev->eventq);
1202
1203 {
1204 /* Register for notification when the host absolute pointer position
1205 * changes. */
1206 VBoxGuestFilterMaskInfo info;
1207 info.u32OrMask = VMMDEV_EVENT_MOUSE_POSITION_CHANGED;
1208 info.u32NotMask = 0;
1209 rcVBox = vboxadd_control_filter_mask(&info);
1210 if (!RT_SUCCESS(rcVBox))
1211 {
1212 LogRelFunc(("failed to register for VMMDEV_EVENT_MOUSE_POSITION_CHANGED events\n"));
1213 err = -RTErrConvertToErrno(rcVBox);
1214 goto fail;
1215 }
1216 }
1217
1218 /* some useful information for the user but don't show this on the console */
1219 LogRel(("VirtualBox device settings: major %d, IRQ %d, "
1220 "I/O port 0x%x, MMIO at 0x%x (size 0x%x), "
1221 "hypervisor window at 0x%p (size 0x%x)\n",
1222 vbox_major, vboxDev->irq, vboxDev->io_port,
1223 vboxDev->vmmdevmem, vboxDev->vmmdevmem_size,
1224 vboxDev->hypervisorStart, vboxDev->hypervisorSize));
1225 printk(KERN_DEBUG "vboxadd: Successfully loaded version "
1226 VBOX_VERSION_STRING " (interface " xstr(VMMDEV_VERSION) ")\n");
1227
1228 /* successful return */
1229 PCI_DEV_PUT(pcidev);
1230 return 0;
1231
1232fail:
1233 PCI_DEV_PUT(pcidev);
1234 free_resources();
1235 if (vbox_major > 0)
1236 unregister_chrdev(vbox_major, "vboxadd");
1237 else
1238 misc_deregister(&gMiscDevice);
1239 return err;
1240}
1241
1242/**
1243 * Module termination
1244 *
1245 */
1246static __exit void fini(void)
1247{
1248 if (vbox_major > 0)
1249 unregister_chrdev(vbox_major, "vboxadd");
1250 else
1251 misc_deregister(&gMiscDevice);
1252 free_resources();
1253 vboxadd_cmc_fini ();
1254}
1255
1256module_init(init);
1257module_exit(fini);
1258
1259/* PCI hotplug structure */
1260static const struct pci_device_id __devinitdata vmmdev_pci_id[] =
1261{
1262 {
1263 .vendor = VMMDEV_VENDORID,
1264 .device = VMMDEV_DEVICEID
1265 },
1266 {
1267 /* empty entry */
1268 }
1269};
1270MODULE_DEVICE_TABLE(pci, vmmdev_pci_id);
1271
1272
1273
1274/*
1275 * Local Variables:
1276 * c-mode: bsd
1277 * indent-tabs-mode: nil
1278 * c-plusplus: evil
1279 * End:
1280 */
1281
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