10ba002bcSHans de Goede /* SPDX-License-Identifier: GPL-2.0 */
20ba002bcSHans de Goede /*
30ba002bcSHans de Goede * vboxguest linux pci driver, char-dev and input-device code,
40ba002bcSHans de Goede *
50ba002bcSHans de Goede * Copyright (C) 2006-2016 Oracle Corporation
60ba002bcSHans de Goede */
70ba002bcSHans de Goede
80532a1b0SHans de Goede #include <linux/cred.h>
90ba002bcSHans de Goede #include <linux/input.h>
100ba002bcSHans de Goede #include <linux/kernel.h>
110ba002bcSHans de Goede #include <linux/miscdevice.h>
120ba002bcSHans de Goede #include <linux/module.h>
130ba002bcSHans de Goede #include <linux/pci.h>
140ba002bcSHans de Goede #include <linux/poll.h>
150ba002bcSHans de Goede #include <linux/vbox_utils.h>
160ba002bcSHans de Goede #include "vboxguest_core.h"
170ba002bcSHans de Goede
180ba002bcSHans de Goede /** The device name. */
190ba002bcSHans de Goede #define DEVICE_NAME "vboxguest"
200ba002bcSHans de Goede /** The device name for the device node open to everyone. */
210ba002bcSHans de Goede #define DEVICE_NAME_USER "vboxuser"
220ba002bcSHans de Goede /** VirtualBox PCI vendor ID. */
230ba002bcSHans de Goede #define VBOX_VENDORID 0x80ee
240ba002bcSHans de Goede /** VMMDev PCI card product ID. */
250ba002bcSHans de Goede #define VMMDEV_DEVICEID 0xcafe
260ba002bcSHans de Goede
270ba002bcSHans de Goede /** Mutex protecting the global vbg_gdev pointer used by vbg_get/put_gdev. */
280ba002bcSHans de Goede static DEFINE_MUTEX(vbg_gdev_mutex);
290ba002bcSHans de Goede /** Global vbg_gdev pointer used by vbg_get/put_gdev. */
300ba002bcSHans de Goede static struct vbg_dev *vbg_gdev;
310ba002bcSHans de Goede
vbg_misc_device_requestor(struct inode * inode)320532a1b0SHans de Goede static u32 vbg_misc_device_requestor(struct inode *inode)
330532a1b0SHans de Goede {
340532a1b0SHans de Goede u32 requestor = VMMDEV_REQUESTOR_USERMODE |
350532a1b0SHans de Goede VMMDEV_REQUESTOR_CON_DONT_KNOW |
360532a1b0SHans de Goede VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
370532a1b0SHans de Goede
38da0d6b3aSDenis Efremov if (from_kuid(current_user_ns(), current_uid()) == 0)
390532a1b0SHans de Goede requestor |= VMMDEV_REQUESTOR_USR_ROOT;
400532a1b0SHans de Goede else
410532a1b0SHans de Goede requestor |= VMMDEV_REQUESTOR_USR_USER;
420532a1b0SHans de Goede
430532a1b0SHans de Goede if (in_egroup_p(inode->i_gid))
440532a1b0SHans de Goede requestor |= VMMDEV_REQUESTOR_GRP_VBOX;
450532a1b0SHans de Goede
460532a1b0SHans de Goede return requestor;
470532a1b0SHans de Goede }
480532a1b0SHans de Goede
vbg_misc_device_open(struct inode * inode,struct file * filp)490ba002bcSHans de Goede static int vbg_misc_device_open(struct inode *inode, struct file *filp)
500ba002bcSHans de Goede {
510ba002bcSHans de Goede struct vbg_session *session;
520ba002bcSHans de Goede struct vbg_dev *gdev;
530ba002bcSHans de Goede
540ba002bcSHans de Goede /* misc_open sets filp->private_data to our misc device */
550ba002bcSHans de Goede gdev = container_of(filp->private_data, struct vbg_dev, misc_device);
560ba002bcSHans de Goede
570532a1b0SHans de Goede session = vbg_core_open_session(gdev, vbg_misc_device_requestor(inode));
580ba002bcSHans de Goede if (IS_ERR(session))
590ba002bcSHans de Goede return PTR_ERR(session);
600ba002bcSHans de Goede
610ba002bcSHans de Goede filp->private_data = session;
620ba002bcSHans de Goede return 0;
630ba002bcSHans de Goede }
640ba002bcSHans de Goede
vbg_misc_device_user_open(struct inode * inode,struct file * filp)650ba002bcSHans de Goede static int vbg_misc_device_user_open(struct inode *inode, struct file *filp)
660ba002bcSHans de Goede {
670ba002bcSHans de Goede struct vbg_session *session;
680ba002bcSHans de Goede struct vbg_dev *gdev;
690ba002bcSHans de Goede
700ba002bcSHans de Goede /* misc_open sets filp->private_data to our misc device */
710ba002bcSHans de Goede gdev = container_of(filp->private_data, struct vbg_dev,
720ba002bcSHans de Goede misc_device_user);
730ba002bcSHans de Goede
740532a1b0SHans de Goede session = vbg_core_open_session(gdev, vbg_misc_device_requestor(inode) |
750532a1b0SHans de Goede VMMDEV_REQUESTOR_USER_DEVICE);
760ba002bcSHans de Goede if (IS_ERR(session))
770ba002bcSHans de Goede return PTR_ERR(session);
780ba002bcSHans de Goede
790ba002bcSHans de Goede filp->private_data = session;
800ba002bcSHans de Goede return 0;
810ba002bcSHans de Goede }
820ba002bcSHans de Goede
830ba002bcSHans de Goede /**
840ba002bcSHans de Goede * Close device.
850ba002bcSHans de Goede * Return: 0 on success, negated errno on failure.
860ba002bcSHans de Goede * @inode: Pointer to inode info structure.
870ba002bcSHans de Goede * @filp: Associated file pointer.
880ba002bcSHans de Goede */
vbg_misc_device_close(struct inode * inode,struct file * filp)890ba002bcSHans de Goede static int vbg_misc_device_close(struct inode *inode, struct file *filp)
900ba002bcSHans de Goede {
910ba002bcSHans de Goede vbg_core_close_session(filp->private_data);
920ba002bcSHans de Goede filp->private_data = NULL;
930ba002bcSHans de Goede return 0;
940ba002bcSHans de Goede }
950ba002bcSHans de Goede
960ba002bcSHans de Goede /**
970ba002bcSHans de Goede * Device I/O Control entry point.
980ba002bcSHans de Goede * Return: 0 on success, negated errno on failure.
990ba002bcSHans de Goede * @filp: Associated file pointer.
1000ba002bcSHans de Goede * @req: The request specified to ioctl().
1010ba002bcSHans de Goede * @arg: The argument specified to ioctl().
1020ba002bcSHans de Goede */
vbg_misc_device_ioctl(struct file * filp,unsigned int req,unsigned long arg)1030ba002bcSHans de Goede static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
1040ba002bcSHans de Goede unsigned long arg)
1050ba002bcSHans de Goede {
1060ba002bcSHans de Goede struct vbg_session *session = filp->private_data;
1070ba002bcSHans de Goede size_t returned_size, size;
1080ba002bcSHans de Goede struct vbg_ioctl_hdr hdr;
109faf6a2a4SHans de Goede bool is_vmmdev_req;
1100ba002bcSHans de Goede int ret = 0;
1110ba002bcSHans de Goede void *buf;
1120ba002bcSHans de Goede
1130ba002bcSHans de Goede if (copy_from_user(&hdr, (void *)arg, sizeof(hdr)))
1140ba002bcSHans de Goede return -EFAULT;
1150ba002bcSHans de Goede
1160ba002bcSHans de Goede if (hdr.version != VBG_IOCTL_HDR_VERSION)
1170ba002bcSHans de Goede return -EINVAL;
1180ba002bcSHans de Goede
1190ba002bcSHans de Goede if (hdr.size_in < sizeof(hdr) ||
1200ba002bcSHans de Goede (hdr.size_out && hdr.size_out < sizeof(hdr)))
1210ba002bcSHans de Goede return -EINVAL;
1220ba002bcSHans de Goede
1230ba002bcSHans de Goede size = max(hdr.size_in, hdr.size_out);
1240ba002bcSHans de Goede if (_IOC_SIZE(req) && _IOC_SIZE(req) != size)
1250ba002bcSHans de Goede return -EINVAL;
1260ba002bcSHans de Goede if (size > SZ_16M)
1270ba002bcSHans de Goede return -E2BIG;
1280ba002bcSHans de Goede
129faf6a2a4SHans de Goede /*
130faf6a2a4SHans de Goede * IOCTL_VMMDEV_REQUEST needs the buffer to be below 4G to avoid
131faf6a2a4SHans de Goede * the need for a bounce-buffer and another copy later on.
132faf6a2a4SHans de Goede */
133faf6a2a4SHans de Goede is_vmmdev_req = (req & ~IOCSIZE_MASK) == VBG_IOCTL_VMMDEV_REQUEST(0) ||
134f794db68SHans de Goede req == VBG_IOCTL_VMMDEV_REQUEST_BIG ||
135f794db68SHans de Goede req == VBG_IOCTL_VMMDEV_REQUEST_BIG_ALT;
136faf6a2a4SHans de Goede
137faf6a2a4SHans de Goede if (is_vmmdev_req)
1380532a1b0SHans de Goede buf = vbg_req_alloc(size, VBG_IOCTL_HDR_TYPE_DEFAULT,
1390532a1b0SHans de Goede session->requestor);
140faf6a2a4SHans de Goede else
141faf6a2a4SHans de Goede buf = kmalloc(size, GFP_KERNEL);
1420ba002bcSHans de Goede if (!buf)
1430ba002bcSHans de Goede return -ENOMEM;
1440ba002bcSHans de Goede
145bd23a726SWenwen Wang *((struct vbg_ioctl_hdr *)buf) = hdr;
146bd23a726SWenwen Wang if (copy_from_user(buf + sizeof(hdr), (void *)arg + sizeof(hdr),
147bd23a726SWenwen Wang hdr.size_in - sizeof(hdr))) {
1480ba002bcSHans de Goede ret = -EFAULT;
1490ba002bcSHans de Goede goto out;
1500ba002bcSHans de Goede }
1510ba002bcSHans de Goede if (hdr.size_in < size)
1520ba002bcSHans de Goede memset(buf + hdr.size_in, 0, size - hdr.size_in);
1530ba002bcSHans de Goede
1540ba002bcSHans de Goede ret = vbg_core_ioctl(session, req, buf);
1550ba002bcSHans de Goede if (ret)
1560ba002bcSHans de Goede goto out;
1570ba002bcSHans de Goede
1580ba002bcSHans de Goede returned_size = ((struct vbg_ioctl_hdr *)buf)->size_out;
1590ba002bcSHans de Goede if (returned_size > size) {
1600ba002bcSHans de Goede vbg_debug("%s: too much output data %zu > %zu\n",
1610ba002bcSHans de Goede __func__, returned_size, size);
1620ba002bcSHans de Goede returned_size = size;
1630ba002bcSHans de Goede }
1640ba002bcSHans de Goede if (copy_to_user((void *)arg, buf, returned_size) != 0)
1650ba002bcSHans de Goede ret = -EFAULT;
1660ba002bcSHans de Goede
1670ba002bcSHans de Goede out:
168faf6a2a4SHans de Goede if (is_vmmdev_req)
169faf6a2a4SHans de Goede vbg_req_free(buf, size);
170faf6a2a4SHans de Goede else
1710ba002bcSHans de Goede kfree(buf);
1720ba002bcSHans de Goede
1730ba002bcSHans de Goede return ret;
1740ba002bcSHans de Goede }
1750ba002bcSHans de Goede
1760ba002bcSHans de Goede /** The file_operations structures. */
1770ba002bcSHans de Goede static const struct file_operations vbg_misc_device_fops = {
1780ba002bcSHans de Goede .owner = THIS_MODULE,
1790ba002bcSHans de Goede .open = vbg_misc_device_open,
1800ba002bcSHans de Goede .release = vbg_misc_device_close,
1810ba002bcSHans de Goede .unlocked_ioctl = vbg_misc_device_ioctl,
1820ba002bcSHans de Goede #ifdef CONFIG_COMPAT
1830ba002bcSHans de Goede .compat_ioctl = vbg_misc_device_ioctl,
1840ba002bcSHans de Goede #endif
1850ba002bcSHans de Goede };
1860ba002bcSHans de Goede static const struct file_operations vbg_misc_device_user_fops = {
1870ba002bcSHans de Goede .owner = THIS_MODULE,
1880ba002bcSHans de Goede .open = vbg_misc_device_user_open,
1890ba002bcSHans de Goede .release = vbg_misc_device_close,
1900ba002bcSHans de Goede .unlocked_ioctl = vbg_misc_device_ioctl,
1910ba002bcSHans de Goede #ifdef CONFIG_COMPAT
1920ba002bcSHans de Goede .compat_ioctl = vbg_misc_device_ioctl,
1930ba002bcSHans de Goede #endif
1940ba002bcSHans de Goede };
1950ba002bcSHans de Goede
1960ba002bcSHans de Goede /**
1970ba002bcSHans de Goede * Called when the input device is first opened.
1980ba002bcSHans de Goede *
1990ba002bcSHans de Goede * Sets up absolute mouse reporting.
2000ba002bcSHans de Goede */
vbg_input_open(struct input_dev * input)2010ba002bcSHans de Goede static int vbg_input_open(struct input_dev *input)
2020ba002bcSHans de Goede {
2030ba002bcSHans de Goede struct vbg_dev *gdev = input_get_drvdata(input);
2040ba002bcSHans de Goede u32 feat = VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL;
2050ba002bcSHans de Goede
20603c95e59SQinglang Miao return vbg_core_set_mouse_status(gdev, feat);
2070ba002bcSHans de Goede }
2080ba002bcSHans de Goede
2090ba002bcSHans de Goede /**
2100ba002bcSHans de Goede * Called if all open handles to the input device are closed.
2110ba002bcSHans de Goede *
2120ba002bcSHans de Goede * Disables absolute reporting.
2130ba002bcSHans de Goede */
vbg_input_close(struct input_dev * input)2140ba002bcSHans de Goede static void vbg_input_close(struct input_dev *input)
2150ba002bcSHans de Goede {
2160ba002bcSHans de Goede struct vbg_dev *gdev = input_get_drvdata(input);
2170ba002bcSHans de Goede
2180ba002bcSHans de Goede vbg_core_set_mouse_status(gdev, 0);
2190ba002bcSHans de Goede }
2200ba002bcSHans de Goede
2210ba002bcSHans de Goede /**
2220ba002bcSHans de Goede * Creates the kernel input device.
2230ba002bcSHans de Goede *
2240ba002bcSHans de Goede * Return: 0 on success, negated errno on failure.
2250ba002bcSHans de Goede */
vbg_create_input_device(struct vbg_dev * gdev)2260ba002bcSHans de Goede static int vbg_create_input_device(struct vbg_dev *gdev)
2270ba002bcSHans de Goede {
2280ba002bcSHans de Goede struct input_dev *input;
2290ba002bcSHans de Goede
2300ba002bcSHans de Goede input = devm_input_allocate_device(gdev->dev);
2310ba002bcSHans de Goede if (!input)
2320ba002bcSHans de Goede return -ENOMEM;
2330ba002bcSHans de Goede
2340ba002bcSHans de Goede input->id.bustype = BUS_PCI;
2350ba002bcSHans de Goede input->id.vendor = VBOX_VENDORID;
2360ba002bcSHans de Goede input->id.product = VMMDEV_DEVICEID;
2370ba002bcSHans de Goede input->open = vbg_input_open;
2380ba002bcSHans de Goede input->close = vbg_input_close;
2390ba002bcSHans de Goede input->dev.parent = gdev->dev;
2400ba002bcSHans de Goede input->name = "VirtualBox mouse integration";
2410ba002bcSHans de Goede
2420ba002bcSHans de Goede input_set_abs_params(input, ABS_X, VMMDEV_MOUSE_RANGE_MIN,
2430ba002bcSHans de Goede VMMDEV_MOUSE_RANGE_MAX, 0, 0);
2440ba002bcSHans de Goede input_set_abs_params(input, ABS_Y, VMMDEV_MOUSE_RANGE_MIN,
2450ba002bcSHans de Goede VMMDEV_MOUSE_RANGE_MAX, 0, 0);
2460ba002bcSHans de Goede input_set_capability(input, EV_KEY, BTN_MOUSE);
2470ba002bcSHans de Goede input_set_drvdata(input, gdev);
2480ba002bcSHans de Goede
2490ba002bcSHans de Goede gdev->input = input;
2500ba002bcSHans de Goede
2510ba002bcSHans de Goede return input_register_device(gdev->input);
2520ba002bcSHans de Goede }
2530ba002bcSHans de Goede
host_version_show(struct device * dev,struct device_attribute * attr,char * buf)2540ba002bcSHans de Goede static ssize_t host_version_show(struct device *dev,
2550ba002bcSHans de Goede struct device_attribute *attr, char *buf)
2560ba002bcSHans de Goede {
2570ba002bcSHans de Goede struct vbg_dev *gdev = dev_get_drvdata(dev);
2580ba002bcSHans de Goede
2590ba002bcSHans de Goede return sprintf(buf, "%s\n", gdev->host_version);
2600ba002bcSHans de Goede }
2610ba002bcSHans de Goede
host_features_show(struct device * dev,struct device_attribute * attr,char * buf)2620ba002bcSHans de Goede static ssize_t host_features_show(struct device *dev,
2630ba002bcSHans de Goede struct device_attribute *attr, char *buf)
2640ba002bcSHans de Goede {
2650ba002bcSHans de Goede struct vbg_dev *gdev = dev_get_drvdata(dev);
2660ba002bcSHans de Goede
2670ba002bcSHans de Goede return sprintf(buf, "%#x\n", gdev->host_features);
2680ba002bcSHans de Goede }
2690ba002bcSHans de Goede
2700ba002bcSHans de Goede static DEVICE_ATTR_RO(host_version);
2710ba002bcSHans de Goede static DEVICE_ATTR_RO(host_features);
2720ba002bcSHans de Goede
273*d4d2c58bSJiasheng Jiang static struct attribute *vbg_pci_attrs[] = {
274*d4d2c58bSJiasheng Jiang &dev_attr_host_version.attr,
275*d4d2c58bSJiasheng Jiang &dev_attr_host_features.attr,
276*d4d2c58bSJiasheng Jiang NULL,
277*d4d2c58bSJiasheng Jiang };
278*d4d2c58bSJiasheng Jiang ATTRIBUTE_GROUPS(vbg_pci);
279*d4d2c58bSJiasheng Jiang
2800ba002bcSHans de Goede /**
2810ba002bcSHans de Goede * Does the PCI detection and init of the device.
2820ba002bcSHans de Goede *
2830ba002bcSHans de Goede * Return: 0 on success, negated errno on failure.
2840ba002bcSHans de Goede */
vbg_pci_probe(struct pci_dev * pci,const struct pci_device_id * id)2850ba002bcSHans de Goede static int vbg_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
2860ba002bcSHans de Goede {
2870ba002bcSHans de Goede struct device *dev = &pci->dev;
2880ba002bcSHans de Goede resource_size_t io, io_len, mmio, mmio_len;
2890ba002bcSHans de Goede struct vmmdev_memory *vmmdev;
2900ba002bcSHans de Goede struct vbg_dev *gdev;
2910ba002bcSHans de Goede int ret;
2920ba002bcSHans de Goede
2930ba002bcSHans de Goede gdev = devm_kzalloc(dev, sizeof(*gdev), GFP_KERNEL);
2940ba002bcSHans de Goede if (!gdev)
2950ba002bcSHans de Goede return -ENOMEM;
2960ba002bcSHans de Goede
2970ba002bcSHans de Goede ret = pci_enable_device(pci);
2980ba002bcSHans de Goede if (ret != 0) {
2990ba002bcSHans de Goede vbg_err("vboxguest: Error enabling device: %d\n", ret);
3000ba002bcSHans de Goede return ret;
3010ba002bcSHans de Goede }
3020ba002bcSHans de Goede
3030ba002bcSHans de Goede ret = -ENODEV;
3040ba002bcSHans de Goede
3050ba002bcSHans de Goede io = pci_resource_start(pci, 0);
3060ba002bcSHans de Goede io_len = pci_resource_len(pci, 0);
3070ba002bcSHans de Goede if (!io || !io_len) {
3080ba002bcSHans de Goede vbg_err("vboxguest: Error IO-port resource (0) is missing\n");
3090ba002bcSHans de Goede goto err_disable_pcidev;
3100ba002bcSHans de Goede }
3110ba002bcSHans de Goede if (devm_request_region(dev, io, io_len, DEVICE_NAME) == NULL) {
3120ba002bcSHans de Goede vbg_err("vboxguest: Error could not claim IO resource\n");
3130ba002bcSHans de Goede ret = -EBUSY;
3140ba002bcSHans de Goede goto err_disable_pcidev;
3150ba002bcSHans de Goede }
3160ba002bcSHans de Goede
3170ba002bcSHans de Goede mmio = pci_resource_start(pci, 1);
3180ba002bcSHans de Goede mmio_len = pci_resource_len(pci, 1);
3190ba002bcSHans de Goede if (!mmio || !mmio_len) {
3200ba002bcSHans de Goede vbg_err("vboxguest: Error MMIO resource (1) is missing\n");
3210ba002bcSHans de Goede goto err_disable_pcidev;
3220ba002bcSHans de Goede }
3230ba002bcSHans de Goede
3240ba002bcSHans de Goede if (devm_request_mem_region(dev, mmio, mmio_len, DEVICE_NAME) == NULL) {
3250ba002bcSHans de Goede vbg_err("vboxguest: Error could not claim MMIO resource\n");
3260ba002bcSHans de Goede ret = -EBUSY;
3270ba002bcSHans de Goede goto err_disable_pcidev;
3280ba002bcSHans de Goede }
3290ba002bcSHans de Goede
3300ba002bcSHans de Goede vmmdev = devm_ioremap(dev, mmio, mmio_len);
3310ba002bcSHans de Goede if (!vmmdev) {
3320b598e4fSArnd Bergmann vbg_err("vboxguest: Error ioremap failed; MMIO addr=%pap size=%pap\n",
3330b598e4fSArnd Bergmann &mmio, &mmio_len);
3340ba002bcSHans de Goede goto err_disable_pcidev;
3350ba002bcSHans de Goede }
3360ba002bcSHans de Goede
3370ba002bcSHans de Goede /* Validate MMIO region version and size. */
3380ba002bcSHans de Goede if (vmmdev->version != VMMDEV_MEMORY_VERSION ||
3390ba002bcSHans de Goede vmmdev->size < 32 || vmmdev->size > mmio_len) {
3400ba002bcSHans de Goede vbg_err("vboxguest: Bogus VMMDev memory; version=%08x (expected %08x) size=%d (expected <= %d)\n",
3410ba002bcSHans de Goede vmmdev->version, VMMDEV_MEMORY_VERSION,
3420ba002bcSHans de Goede vmmdev->size, (int)mmio_len);
3430ba002bcSHans de Goede goto err_disable_pcidev;
3440ba002bcSHans de Goede }
3450ba002bcSHans de Goede
3460ba002bcSHans de Goede gdev->io_port = io;
3470ba002bcSHans de Goede gdev->mmio = vmmdev;
3480ba002bcSHans de Goede gdev->dev = dev;
3490ba002bcSHans de Goede gdev->misc_device.minor = MISC_DYNAMIC_MINOR;
3500ba002bcSHans de Goede gdev->misc_device.name = DEVICE_NAME;
3510ba002bcSHans de Goede gdev->misc_device.fops = &vbg_misc_device_fops;
3520ba002bcSHans de Goede gdev->misc_device_user.minor = MISC_DYNAMIC_MINOR;
3530ba002bcSHans de Goede gdev->misc_device_user.name = DEVICE_NAME_USER;
3540ba002bcSHans de Goede gdev->misc_device_user.fops = &vbg_misc_device_user_fops;
3550ba002bcSHans de Goede
3560ba002bcSHans de Goede ret = vbg_core_init(gdev, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
3570ba002bcSHans de Goede if (ret)
3580ba002bcSHans de Goede goto err_disable_pcidev;
3590ba002bcSHans de Goede
3600ba002bcSHans de Goede ret = vbg_create_input_device(gdev);
3610ba002bcSHans de Goede if (ret) {
3620ba002bcSHans de Goede vbg_err("vboxguest: Error creating input device: %d\n", ret);
3630ba002bcSHans de Goede goto err_vbg_core_exit;
3640ba002bcSHans de Goede }
3650ba002bcSHans de Goede
3666169525bSPascal Terjan ret = request_irq(pci->irq, vbg_core_isr, IRQF_SHARED, DEVICE_NAME,
3676169525bSPascal Terjan gdev);
3680ba002bcSHans de Goede if (ret) {
3690ba002bcSHans de Goede vbg_err("vboxguest: Error requesting irq: %d\n", ret);
3700ba002bcSHans de Goede goto err_vbg_core_exit;
3710ba002bcSHans de Goede }
3720ba002bcSHans de Goede
3730ba002bcSHans de Goede ret = misc_register(&gdev->misc_device);
3740ba002bcSHans de Goede if (ret) {
3750ba002bcSHans de Goede vbg_err("vboxguest: Error misc_register %s failed: %d\n",
3760ba002bcSHans de Goede DEVICE_NAME, ret);
3776169525bSPascal Terjan goto err_free_irq;
3780ba002bcSHans de Goede }
3790ba002bcSHans de Goede
3800ba002bcSHans de Goede ret = misc_register(&gdev->misc_device_user);
3810ba002bcSHans de Goede if (ret) {
3820ba002bcSHans de Goede vbg_err("vboxguest: Error misc_register %s failed: %d\n",
3830ba002bcSHans de Goede DEVICE_NAME_USER, ret);
3840ba002bcSHans de Goede goto err_unregister_misc_device;
3850ba002bcSHans de Goede }
3860ba002bcSHans de Goede
3870ba002bcSHans de Goede mutex_lock(&vbg_gdev_mutex);
3880ba002bcSHans de Goede if (!vbg_gdev)
3890ba002bcSHans de Goede vbg_gdev = gdev;
3900ba002bcSHans de Goede else
3910ba002bcSHans de Goede ret = -EBUSY;
3920ba002bcSHans de Goede mutex_unlock(&vbg_gdev_mutex);
3930ba002bcSHans de Goede
3940ba002bcSHans de Goede if (ret) {
3950ba002bcSHans de Goede vbg_err("vboxguest: Error more then 1 vbox guest pci device\n");
3960ba002bcSHans de Goede goto err_unregister_misc_device_user;
3970ba002bcSHans de Goede }
3980ba002bcSHans de Goede
3990ba002bcSHans de Goede pci_set_drvdata(pci, gdev);
4000ba002bcSHans de Goede
4010ba002bcSHans de Goede return 0;
4020ba002bcSHans de Goede
4030ba002bcSHans de Goede err_unregister_misc_device_user:
4040ba002bcSHans de Goede misc_deregister(&gdev->misc_device_user);
4050ba002bcSHans de Goede err_unregister_misc_device:
4060ba002bcSHans de Goede misc_deregister(&gdev->misc_device);
4076169525bSPascal Terjan err_free_irq:
4086169525bSPascal Terjan free_irq(pci->irq, gdev);
4090ba002bcSHans de Goede err_vbg_core_exit:
4100ba002bcSHans de Goede vbg_core_exit(gdev);
4110ba002bcSHans de Goede err_disable_pcidev:
4120ba002bcSHans de Goede pci_disable_device(pci);
4130ba002bcSHans de Goede
4140ba002bcSHans de Goede return ret;
4150ba002bcSHans de Goede }
4160ba002bcSHans de Goede
vbg_pci_remove(struct pci_dev * pci)4170ba002bcSHans de Goede static void vbg_pci_remove(struct pci_dev *pci)
4180ba002bcSHans de Goede {
4190ba002bcSHans de Goede struct vbg_dev *gdev = pci_get_drvdata(pci);
4200ba002bcSHans de Goede
4210ba002bcSHans de Goede mutex_lock(&vbg_gdev_mutex);
4220ba002bcSHans de Goede vbg_gdev = NULL;
4230ba002bcSHans de Goede mutex_unlock(&vbg_gdev_mutex);
4240ba002bcSHans de Goede
4256169525bSPascal Terjan free_irq(pci->irq, gdev);
4260ba002bcSHans de Goede misc_deregister(&gdev->misc_device_user);
4270ba002bcSHans de Goede misc_deregister(&gdev->misc_device);
4280ba002bcSHans de Goede vbg_core_exit(gdev);
4290ba002bcSHans de Goede pci_disable_device(pci);
4300ba002bcSHans de Goede }
4310ba002bcSHans de Goede
vbg_get_gdev(void)4320ba002bcSHans de Goede struct vbg_dev *vbg_get_gdev(void)
4330ba002bcSHans de Goede {
4340ba002bcSHans de Goede mutex_lock(&vbg_gdev_mutex);
4350ba002bcSHans de Goede
4360ba002bcSHans de Goede /*
4370ba002bcSHans de Goede * Note on success we keep the mutex locked until vbg_put_gdev(),
4380ba002bcSHans de Goede * this stops vbg_pci_remove from removing the device from underneath
4390ba002bcSHans de Goede * vboxsf. vboxsf will only hold a reference for a short while.
4400ba002bcSHans de Goede */
4410ba002bcSHans de Goede if (vbg_gdev)
4420ba002bcSHans de Goede return vbg_gdev;
4430ba002bcSHans de Goede
4440ba002bcSHans de Goede mutex_unlock(&vbg_gdev_mutex);
4450ba002bcSHans de Goede return ERR_PTR(-ENODEV);
4460ba002bcSHans de Goede }
4470ba002bcSHans de Goede EXPORT_SYMBOL(vbg_get_gdev);
4480ba002bcSHans de Goede
vbg_put_gdev(struct vbg_dev * gdev)4490ba002bcSHans de Goede void vbg_put_gdev(struct vbg_dev *gdev)
4500ba002bcSHans de Goede {
4510ba002bcSHans de Goede WARN_ON(gdev != vbg_gdev);
4520ba002bcSHans de Goede mutex_unlock(&vbg_gdev_mutex);
4530ba002bcSHans de Goede }
4540ba002bcSHans de Goede EXPORT_SYMBOL(vbg_put_gdev);
4550ba002bcSHans de Goede
4560ba002bcSHans de Goede /**
4570ba002bcSHans de Goede * Callback for mouse events.
4580ba002bcSHans de Goede *
4590ba002bcSHans de Goede * This is called at the end of the ISR, after leaving the event spinlock, if
4600ba002bcSHans de Goede * VMMDEV_EVENT_MOUSE_POSITION_CHANGED was raised by the host.
4610ba002bcSHans de Goede *
4620ba002bcSHans de Goede * @gdev: The device extension.
4630ba002bcSHans de Goede */
vbg_linux_mouse_event(struct vbg_dev * gdev)4640ba002bcSHans de Goede void vbg_linux_mouse_event(struct vbg_dev *gdev)
4650ba002bcSHans de Goede {
4660ba002bcSHans de Goede int rc;
4670ba002bcSHans de Goede
4680ba002bcSHans de Goede /* Report events to the kernel input device */
4690ba002bcSHans de Goede gdev->mouse_status_req->mouse_features = 0;
4700ba002bcSHans de Goede gdev->mouse_status_req->pointer_pos_x = 0;
4710ba002bcSHans de Goede gdev->mouse_status_req->pointer_pos_y = 0;
4720ba002bcSHans de Goede rc = vbg_req_perform(gdev, gdev->mouse_status_req);
4730ba002bcSHans de Goede if (rc >= 0) {
4740ba002bcSHans de Goede input_report_abs(gdev->input, ABS_X,
4750ba002bcSHans de Goede gdev->mouse_status_req->pointer_pos_x);
4760ba002bcSHans de Goede input_report_abs(gdev->input, ABS_Y,
4770ba002bcSHans de Goede gdev->mouse_status_req->pointer_pos_y);
4780ba002bcSHans de Goede input_sync(gdev->input);
4790ba002bcSHans de Goede }
4800ba002bcSHans de Goede }
4810ba002bcSHans de Goede
4820ba002bcSHans de Goede static const struct pci_device_id vbg_pci_ids[] = {
4830ba002bcSHans de Goede { .vendor = VBOX_VENDORID, .device = VMMDEV_DEVICEID },
4840ba002bcSHans de Goede {}
4850ba002bcSHans de Goede };
4860ba002bcSHans de Goede MODULE_DEVICE_TABLE(pci, vbg_pci_ids);
4870ba002bcSHans de Goede
4880ba002bcSHans de Goede static struct pci_driver vbg_pci_driver = {
4890ba002bcSHans de Goede .name = DEVICE_NAME,
490*d4d2c58bSJiasheng Jiang .dev_groups = vbg_pci_groups,
4910ba002bcSHans de Goede .id_table = vbg_pci_ids,
4920ba002bcSHans de Goede .probe = vbg_pci_probe,
4930ba002bcSHans de Goede .remove = vbg_pci_remove,
4940ba002bcSHans de Goede };
4950ba002bcSHans de Goede
4960ba002bcSHans de Goede module_pci_driver(vbg_pci_driver);
4970ba002bcSHans de Goede
4980ba002bcSHans de Goede MODULE_AUTHOR("Oracle Corporation");
4990ba002bcSHans de Goede MODULE_DESCRIPTION("Oracle VM VirtualBox Guest Additions for Linux Module");
5000ba002bcSHans de Goede MODULE_LICENSE("GPL");
501