Skip to content

Commit 05a87d3

Browse files
committed
char: vcio: Rewrite as a firmware node child
The old vcio driver is a simple character device that manually locates the firmware driver. Initialising it before the firmware driver causes a failure, and no retries are attempted. Rewrite vcio as a platform driver that depends on a DT node for its instantiation and the location of the firmware driver, making use of the miscdevice framework to reduce the code size. N.B. Using miscdevice changes the udev SUBSYSTEM string, so a change to the companion udev rule is required in order to continue to set the correct device permissions, e.g.: KERNEL="vcio", GROUP="video", MODE="0660" See: raspberrypi#4620 Signed-off-by: Phil Elwell <[email protected]>
1 parent 24c8b05 commit 05a87d3

File tree

1 file changed

+63
-70
lines changed

1 file changed

+63
-70
lines changed

drivers/char/broadcom/vcio.c

Lines changed: 63 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
/*
22
* Copyright (C) 2010 Broadcom
33
* Copyright (C) 2015 Noralf Trønnes
4+
* Copyright (C) 2021 Raspberry Pi (Trading) Ltd.
45
*
56
* This program is free software; you can redistribute it and/or modify
67
* it under the terms of the GNU General Public License version 2 as
78
* published by the Free Software Foundation.
89
*
910
*/
1011

11-
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12+
#define MODULE_NAME "vcio"
13+
#define pr_fmt(fmt) MODULE_NAME ": " fmt
1214

1315
#include <linux/cdev.h>
1416
#include <linux/device.h>
@@ -19,24 +21,21 @@
1921
#include <linux/slab.h>
2022
#include <linux/uaccess.h>
2123
#include <linux/compat.h>
24+
#include <linux/miscdevice.h>
2225
#include <soc/bcm2835/raspberrypi-firmware.h>
2326

24-
#define MBOX_CHAN_PROPERTY 8
25-
2627
#define VCIO_IOC_MAGIC 100
2728
#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
2829
#ifdef CONFIG_COMPAT
2930
#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
3031
#endif
3132

32-
static struct {
33-
dev_t devt;
34-
struct cdev cdev;
35-
struct class *class;
33+
struct vcio_data {
3634
struct rpi_firmware *fw;
37-
} vcio;
35+
struct miscdevice misc_dev;
36+
};
3837

39-
static int vcio_user_property_list(void *user)
38+
static int vcio_user_property_list(struct vcio_data *vcio, void *user)
4039
{
4140
u32 *buf, size;
4241
int ret;
@@ -55,7 +54,7 @@ static int vcio_user_property_list(void *user)
5554
}
5655

5756
/* Strip off protocol encapsulation */
58-
ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
57+
ret = rpi_firmware_property_list(vcio->fw, &buf[2], size - 12);
5958
if (ret) {
6059
kfree(buf);
6160
return ret;
@@ -87,9 +86,12 @@ static int vcio_device_release(struct inode *inode, struct file *file)
8786
static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
8887
unsigned long ioctl_param)
8988
{
89+
struct vcio_data *vcio = container_of(file->private_data,
90+
struct vcio_data, misc_dev);
91+
9092
switch (ioctl_num) {
9193
case IOCTL_MBOX_PROPERTY:
92-
return vcio_user_property_list((void *)ioctl_param);
94+
return vcio_user_property_list(vcio, (void *)ioctl_param);
9395
default:
9496
pr_err("unknown ioctl: %x\n", ioctl_num);
9597
return -EINVAL;
@@ -100,9 +102,12 @@ static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
100102
static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
101103
unsigned long ioctl_param)
102104
{
105+
struct vcio_data *vcio = container_of(file->private_data,
106+
struct vcio_data, misc_dev);
107+
103108
switch (ioctl_num) {
104109
case IOCTL_MBOX_PROPERTY32:
105-
return vcio_user_property_list(compat_ptr(ioctl_param));
110+
return vcio_user_property_list(vcio, compat_ptr(ioctl_param));
106111
default:
107112
pr_err("unknown ioctl: %x\n", ioctl_num);
108113
return -EINVAL;
@@ -119,77 +124,65 @@ const struct file_operations vcio_fops = {
119124
.release = vcio_device_release,
120125
};
121126

122-
static int __init vcio_init(void)
127+
static int vcio_probe(struct platform_device *pdev)
123128
{
124-
struct device_node *np;
125-
static struct device *dev;
126-
int ret;
127-
128-
np = of_find_compatible_node(NULL, NULL,
129-
"raspberrypi,bcm2835-firmware");
130-
if (!of_device_is_available(np))
131-
return -ENODEV;
132-
133-
vcio.fw = rpi_firmware_get(np);
134-
if (!vcio.fw)
135-
return -ENODEV;
136-
137-
ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
138-
if (ret) {
139-
pr_err("failed to allocate device number\n");
140-
return ret;
141-
}
142-
143-
cdev_init(&vcio.cdev, &vcio_fops);
144-
vcio.cdev.owner = THIS_MODULE;
145-
ret = cdev_add(&vcio.cdev, vcio.devt, 1);
146-
if (ret) {
147-
pr_err("failed to register device\n");
148-
goto err_unregister_chardev;
149-
}
129+
struct device *dev = &pdev->dev;
130+
struct device_node *np = dev->of_node;
131+
struct device_node *fw_node;
132+
struct rpi_firmware *fw;
133+
struct vcio_data *vcio;
150134

151-
/*
152-
* Create sysfs entries
153-
* 'bcm2708_vcio' is used for backwards compatibility so we don't break
154-
* userspace. Raspian has a udev rule that changes the permissions.
155-
*/
156-
vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
157-
if (IS_ERR(vcio.class)) {
158-
ret = PTR_ERR(vcio.class);
159-
pr_err("failed to create class\n");
160-
goto err_cdev_del;
135+
fw_node = of_get_parent(np);
136+
if (!fw_node) {
137+
dev_err(dev, "Missing firmware node\n");
138+
return -ENOENT;
161139
}
162140

163-
dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
164-
if (IS_ERR(dev)) {
165-
ret = PTR_ERR(dev);
166-
pr_err("failed to create device\n");
167-
goto err_class_destroy;
168-
}
141+
fw = rpi_firmware_get(fw_node);
142+
of_node_put(fw_node);
143+
if (!fw)
144+
return -EPROBE_DEFER;
169145

170-
return 0;
146+
vcio = devm_kzalloc(dev, sizeof(struct vcio_data), GFP_KERNEL);
147+
if (!vcio)
148+
return -ENOMEM;
171149

172-
err_class_destroy:
173-
class_destroy(vcio.class);
174-
err_cdev_del:
175-
cdev_del(&vcio.cdev);
176-
err_unregister_chardev:
177-
unregister_chrdev_region(vcio.devt, 1);
150+
vcio->fw = fw;
151+
vcio->misc_dev.fops = &vcio_fops;
152+
vcio->misc_dev.minor = MISC_DYNAMIC_MINOR;
153+
vcio->misc_dev.name = "vcio";
154+
vcio->misc_dev.parent = dev;
178155

179-
return ret;
156+
return misc_register(&vcio->misc_dev);
180157
}
181-
module_init(vcio_init);
182158

183-
static void __exit vcio_exit(void)
159+
static int vcio_remove(struct platform_device *pdev)
184160
{
185-
device_destroy(vcio.class, vcio.devt);
186-
class_destroy(vcio.class);
187-
cdev_del(&vcio.cdev);
188-
unregister_chrdev_region(vcio.devt, 1);
161+
struct device *dev = &pdev->dev;
162+
163+
misc_deregister(dev_get_drvdata(dev));
164+
return 0;
189165
}
190-
module_exit(vcio_exit);
166+
167+
static const struct of_device_id vcio_ids[] = {
168+
{ .compatible = "raspberrypi,vcio" },
169+
{ }
170+
};
171+
MODULE_DEVICE_TABLE(of, vcio_ids);
172+
173+
static struct platform_driver vcio_driver = {
174+
.driver = {
175+
.name = MODULE_NAME,
176+
.of_match_table = of_match_ptr(vcio_ids),
177+
},
178+
.probe = vcio_probe,
179+
.remove = vcio_remove,
180+
};
181+
182+
module_platform_driver(vcio_driver);
191183

192184
MODULE_AUTHOR("Gray Girling");
193185
MODULE_AUTHOR("Noralf Trønnes");
194186
MODULE_DESCRIPTION("Mailbox userspace access");
195187
MODULE_LICENSE("GPL");
188+
MODULE_ALIAS("platform:rpi-vcio");

0 commit comments

Comments
 (0)