Skip to content

Commit 95baef1

Browse files
pelwellpopcornmix
authored andcommitted
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: #4620 Signed-off-by: Phil Elwell <[email protected]>
1 parent 88ab5f8 commit 95baef1

File tree

1 file changed

+62
-71
lines changed

1 file changed

+62
-71
lines changed

drivers/char/broadcom/vcio.c

Lines changed: 62 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
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-
1312
#include <linux/cdev.h>
1413
#include <linux/device.h>
1514
#include <linux/fs.h>
@@ -19,24 +18,22 @@
1918
#include <linux/slab.h>
2019
#include <linux/uaccess.h>
2120
#include <linux/compat.h>
21+
#include <linux/miscdevice.h>
2222
#include <soc/bcm2835/raspberrypi-firmware.h>
2323

24-
#define MBOX_CHAN_PROPERTY 8
25-
24+
#define MODULE_NAME "vcio"
2625
#define VCIO_IOC_MAGIC 100
2726
#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
2827
#ifdef CONFIG_COMPAT
2928
#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
3029
#endif
3130

32-
static struct {
33-
dev_t devt;
34-
struct cdev cdev;
35-
struct class *class;
31+
struct vcio_data {
3632
struct rpi_firmware *fw;
37-
} vcio;
33+
struct miscdevice misc_dev;
34+
};
3835

39-
static int vcio_user_property_list(void *user)
36+
static int vcio_user_property_list(struct vcio_data *vcio, void *user)
4037
{
4138
u32 *buf, size;
4239
int ret;
@@ -55,7 +52,7 @@ static int vcio_user_property_list(void *user)
5552
}
5653

5754
/* Strip off protocol encapsulation */
58-
ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
55+
ret = rpi_firmware_property_list(vcio->fw, &buf[2], size - 12);
5956
if (ret) {
6057
kfree(buf);
6158
return ret;
@@ -87,9 +84,12 @@ static int vcio_device_release(struct inode *inode, struct file *file)
8784
static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
8885
unsigned long ioctl_param)
8986
{
87+
struct vcio_data *vcio = container_of(file->private_data,
88+
struct vcio_data, misc_dev);
89+
9090
switch (ioctl_num) {
9191
case IOCTL_MBOX_PROPERTY:
92-
return vcio_user_property_list((void *)ioctl_param);
92+
return vcio_user_property_list(vcio, (void *)ioctl_param);
9393
default:
9494
pr_err("unknown ioctl: %x\n", ioctl_num);
9595
return -EINVAL;
@@ -100,9 +100,12 @@ static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
100100
static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
101101
unsigned long ioctl_param)
102102
{
103+
struct vcio_data *vcio = container_of(file->private_data,
104+
struct vcio_data, misc_dev);
105+
103106
switch (ioctl_num) {
104107
case IOCTL_MBOX_PROPERTY32:
105-
return vcio_user_property_list(compat_ptr(ioctl_param));
108+
return vcio_user_property_list(vcio, compat_ptr(ioctl_param));
106109
default:
107110
pr_err("unknown ioctl: %x\n", ioctl_num);
108111
return -EINVAL;
@@ -119,77 +122,65 @@ const struct file_operations vcio_fops = {
119122
.release = vcio_device_release,
120123
};
121124

122-
static int __init vcio_init(void)
125+
static int vcio_probe(struct platform_device *pdev)
123126
{
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-
}
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;
150132

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;
133+
fw_node = of_get_parent(np);
134+
if (!fw_node) {
135+
dev_err(dev, "Missing firmware node\n");
136+
return -ENOENT;
161137
}
162138

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-
}
139+
fw = rpi_firmware_get(fw_node);
140+
of_node_put(fw_node);
141+
if (!fw)
142+
return -EPROBE_DEFER;
169143

170-
return 0;
144+
vcio = devm_kzalloc(dev, sizeof(struct vcio_data), GFP_KERNEL);
145+
if (!vcio)
146+
return -ENOMEM;
171147

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);
148+
vcio->fw = fw;
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;
178153

179-
return ret;
154+
return misc_register(&vcio->misc_dev);
180155
}
181-
module_init(vcio_init);
182156

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

192182
MODULE_AUTHOR("Gray Girling");
193183
MODULE_AUTHOR("Noralf Trønnes");
194184
MODULE_DESCRIPTION("Mailbox userspace access");
195185
MODULE_LICENSE("GPL");
186+
MODULE_ALIAS("platform:rpi-vcio");

0 commit comments

Comments
 (0)