2 * Copyright (C) 2010 Broadcom
3 * Copyright (C) 2015 Noralf Trønnes
4 * Copyright (C) 2021 Raspberry Pi (Trading) Ltd.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
12 #include <linux/cdev.h>
13 #include <linux/device.h>
15 #include <linux/init.h>
16 #include <linux/ioctl.h>
17 #include <linux/module.h>
18 #include <linux/slab.h>
19 #include <linux/uaccess.h>
20 #include <linux/compat.h>
21 #include <linux/miscdevice.h>
22 #include <soc/bcm2835/raspberrypi-firmware.h>
24 #define MODULE_NAME "vcio"
25 #define VCIO_IOC_MAGIC 100
26 #define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
28 #define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
32 struct rpi_firmware *fw;
33 struct miscdevice misc_dev;
36 static int vcio_user_property_list(struct vcio_data *vcio, void *user)
41 /* The first 32-bit is the size of the buffer */
42 if (copy_from_user(&size, user, sizeof(size)))
45 buf = kmalloc(size, GFP_KERNEL);
49 if (copy_from_user(buf, user, size)) {
54 /* Strip off protocol encapsulation */
55 ret = rpi_firmware_property_list(vcio->fw, &buf[2], size - 12);
61 buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
62 if (copy_to_user(user, buf, size))
70 static int vcio_device_open(struct inode *inode, struct file *file)
72 try_module_get(THIS_MODULE);
77 static int vcio_device_release(struct inode *inode, struct file *file)
79 module_put(THIS_MODULE);
84 static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
85 unsigned long ioctl_param)
87 struct vcio_data *vcio = container_of(file->private_data,
88 struct vcio_data, misc_dev);
91 case IOCTL_MBOX_PROPERTY:
92 return vcio_user_property_list(vcio, (void *)ioctl_param);
94 pr_err("unknown ioctl: %x\n", ioctl_num);
100 static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
101 unsigned long ioctl_param)
103 struct vcio_data *vcio = container_of(file->private_data,
104 struct vcio_data, misc_dev);
107 case IOCTL_MBOX_PROPERTY32:
108 return vcio_user_property_list(vcio, compat_ptr(ioctl_param));
110 pr_err("unknown ioctl: %x\n", ioctl_num);
116 const struct file_operations vcio_fops = {
117 .unlocked_ioctl = vcio_device_ioctl,
119 .compat_ioctl = vcio_device_compat_ioctl,
121 .open = vcio_device_open,
122 .release = vcio_device_release,
125 static int vcio_probe(struct platform_device *pdev)
127 struct device *dev = &pdev->dev;
128 struct device_node *np = dev->of_node;
129 struct device_node *fw_node;
130 struct rpi_firmware *fw;
131 struct vcio_data *vcio;
133 fw_node = of_get_parent(np);
135 dev_err(dev, "Missing firmware node\n");
139 fw = rpi_firmware_get(fw_node);
140 of_node_put(fw_node);
142 return -EPROBE_DEFER;
144 vcio = devm_kzalloc(dev, sizeof(struct vcio_data), GFP_KERNEL);
149 vcio->misc_dev.fops = &vcio_fops;
150 vcio->misc_dev.minor = MISC_DYNAMIC_MINOR;
151 vcio->misc_dev.name = "vcio";
152 vcio->misc_dev.parent = dev;
154 return misc_register(&vcio->misc_dev);
157 static int vcio_remove(struct platform_device *pdev)
159 struct device *dev = &pdev->dev;
161 misc_deregister(dev_get_drvdata(dev));
165 static const struct of_device_id vcio_ids[] = {
166 { .compatible = "raspberrypi,vcio" },
169 MODULE_DEVICE_TABLE(of, vcio_ids);
171 static struct platform_driver vcio_driver = {
174 .of_match_table = of_match_ptr(vcio_ids),
177 .remove = vcio_remove,
180 module_platform_driver(vcio_driver);
182 MODULE_AUTHOR("Gray Girling");
183 MODULE_AUTHOR("Noralf Trønnes");
184 MODULE_DESCRIPTION("Mailbox userspace access");
185 MODULE_LICENSE("GPL");
186 MODULE_ALIAS("platform:rpi-vcio");