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