mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-20 14:13:16 +00:00
238 lines
6.6 KiB
Diff
238 lines
6.6 KiB
Diff
|
From 512d9fadc272271e1e8e9bc81d445883940f81ca Mon Sep 17 00:00:00 2001
|
||
|
From: Phil Elwell <phil@raspberrypi.com>
|
||
|
Date: Mon, 11 Oct 2021 17:33:05 +0100
|
||
|
Subject: [PATCH] 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: https://github.com/raspberrypi/linux/issues/4620
|
||
|
|
||
|
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
|
||
|
---
|
||
|
drivers/char/broadcom/vcio.c | 133 ++++++++++++++++-------------------
|
||
|
1 file changed, 62 insertions(+), 71 deletions(-)
|
||
|
|
||
|
--- a/drivers/char/broadcom/vcio.c
|
||
|
+++ b/drivers/char/broadcom/vcio.c
|
||
|
@@ -1,6 +1,7 @@
|
||
|
/*
|
||
|
* Copyright (C) 2010 Broadcom
|
||
|
* Copyright (C) 2015 Noralf Trønnes
|
||
|
+ * Copyright (C) 2021 Raspberry Pi (Trading) Ltd.
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License version 2 as
|
||
|
@@ -8,8 +9,6 @@
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||
|
-
|
||
|
#include <linux/cdev.h>
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/fs.h>
|
||
|
@@ -19,24 +18,22 @@
|
||
|
#include <linux/slab.h>
|
||
|
#include <linux/uaccess.h>
|
||
|
#include <linux/compat.h>
|
||
|
+#include <linux/miscdevice.h>
|
||
|
#include <soc/bcm2835/raspberrypi-firmware.h>
|
||
|
|
||
|
-#define MBOX_CHAN_PROPERTY 8
|
||
|
-
|
||
|
+#define MODULE_NAME "vcio"
|
||
|
#define VCIO_IOC_MAGIC 100
|
||
|
#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
|
||
|
#ifdef CONFIG_COMPAT
|
||
|
#define IOCTL_MBOX_PROPERTY32 _IOWR(VCIO_IOC_MAGIC, 0, compat_uptr_t)
|
||
|
#endif
|
||
|
|
||
|
-static struct {
|
||
|
- dev_t devt;
|
||
|
- struct cdev cdev;
|
||
|
- struct class *class;
|
||
|
+struct vcio_data {
|
||
|
struct rpi_firmware *fw;
|
||
|
-} vcio;
|
||
|
+ struct miscdevice misc_dev;
|
||
|
+};
|
||
|
|
||
|
-static int vcio_user_property_list(void *user)
|
||
|
+static int vcio_user_property_list(struct vcio_data *vcio, void *user)
|
||
|
{
|
||
|
u32 *buf, size;
|
||
|
int ret;
|
||
|
@@ -55,7 +52,7 @@ static int vcio_user_property_list(void
|
||
|
}
|
||
|
|
||
|
/* Strip off protocol encapsulation */
|
||
|
- ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
|
||
|
+ ret = rpi_firmware_property_list(vcio->fw, &buf[2], size - 12);
|
||
|
if (ret) {
|
||
|
kfree(buf);
|
||
|
return ret;
|
||
|
@@ -87,9 +84,12 @@ static int vcio_device_release(struct in
|
||
|
static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
|
||
|
unsigned long ioctl_param)
|
||
|
{
|
||
|
+ struct vcio_data *vcio = container_of(file->private_data,
|
||
|
+ struct vcio_data, misc_dev);
|
||
|
+
|
||
|
switch (ioctl_num) {
|
||
|
case IOCTL_MBOX_PROPERTY:
|
||
|
- return vcio_user_property_list((void *)ioctl_param);
|
||
|
+ return vcio_user_property_list(vcio, (void *)ioctl_param);
|
||
|
default:
|
||
|
pr_err("unknown ioctl: %x\n", ioctl_num);
|
||
|
return -EINVAL;
|
||
|
@@ -100,9 +100,12 @@ static long vcio_device_ioctl(struct fil
|
||
|
static long vcio_device_compat_ioctl(struct file *file, unsigned int ioctl_num,
|
||
|
unsigned long ioctl_param)
|
||
|
{
|
||
|
+ struct vcio_data *vcio = container_of(file->private_data,
|
||
|
+ struct vcio_data, misc_dev);
|
||
|
+
|
||
|
switch (ioctl_num) {
|
||
|
case IOCTL_MBOX_PROPERTY32:
|
||
|
- return vcio_user_property_list(compat_ptr(ioctl_param));
|
||
|
+ return vcio_user_property_list(vcio, compat_ptr(ioctl_param));
|
||
|
default:
|
||
|
pr_err("unknown ioctl: %x\n", ioctl_num);
|
||
|
return -EINVAL;
|
||
|
@@ -119,77 +122,65 @@ const struct file_operations vcio_fops =
|
||
|
.release = vcio_device_release,
|
||
|
};
|
||
|
|
||
|
-static int __init vcio_init(void)
|
||
|
+static int vcio_probe(struct platform_device *pdev)
|
||
|
{
|
||
|
- struct device_node *np;
|
||
|
- static struct device *dev;
|
||
|
- int ret;
|
||
|
-
|
||
|
- np = of_find_compatible_node(NULL, NULL,
|
||
|
- "raspberrypi,bcm2835-firmware");
|
||
|
- if (!of_device_is_available(np))
|
||
|
- return -ENODEV;
|
||
|
-
|
||
|
- vcio.fw = rpi_firmware_get(np);
|
||
|
- if (!vcio.fw)
|
||
|
- return -ENODEV;
|
||
|
-
|
||
|
- ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
|
||
|
- if (ret) {
|
||
|
- pr_err("failed to allocate device number\n");
|
||
|
- return ret;
|
||
|
- }
|
||
|
-
|
||
|
- cdev_init(&vcio.cdev, &vcio_fops);
|
||
|
- vcio.cdev.owner = THIS_MODULE;
|
||
|
- ret = cdev_add(&vcio.cdev, vcio.devt, 1);
|
||
|
- if (ret) {
|
||
|
- pr_err("failed to register device\n");
|
||
|
- goto err_unregister_chardev;
|
||
|
- }
|
||
|
+ struct device *dev = &pdev->dev;
|
||
|
+ struct device_node *np = dev->of_node;
|
||
|
+ struct device_node *fw_node;
|
||
|
+ struct rpi_firmware *fw;
|
||
|
+ struct vcio_data *vcio;
|
||
|
|
||
|
- /*
|
||
|
- * Create sysfs entries
|
||
|
- * 'bcm2708_vcio' is used for backwards compatibility so we don't break
|
||
|
- * userspace. Raspian has a udev rule that changes the permissions.
|
||
|
- */
|
||
|
- vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
|
||
|
- if (IS_ERR(vcio.class)) {
|
||
|
- ret = PTR_ERR(vcio.class);
|
||
|
- pr_err("failed to create class\n");
|
||
|
- goto err_cdev_del;
|
||
|
+ fw_node = of_get_parent(np);
|
||
|
+ if (!fw_node) {
|
||
|
+ dev_err(dev, "Missing firmware node\n");
|
||
|
+ return -ENOENT;
|
||
|
}
|
||
|
|
||
|
- dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
|
||
|
- if (IS_ERR(dev)) {
|
||
|
- ret = PTR_ERR(dev);
|
||
|
- pr_err("failed to create device\n");
|
||
|
- goto err_class_destroy;
|
||
|
- }
|
||
|
+ fw = rpi_firmware_get(fw_node);
|
||
|
+ of_node_put(fw_node);
|
||
|
+ if (!fw)
|
||
|
+ return -EPROBE_DEFER;
|
||
|
|
||
|
- return 0;
|
||
|
+ vcio = devm_kzalloc(dev, sizeof(struct vcio_data), GFP_KERNEL);
|
||
|
+ if (!vcio)
|
||
|
+ return -ENOMEM;
|
||
|
|
||
|
-err_class_destroy:
|
||
|
- class_destroy(vcio.class);
|
||
|
-err_cdev_del:
|
||
|
- cdev_del(&vcio.cdev);
|
||
|
-err_unregister_chardev:
|
||
|
- unregister_chrdev_region(vcio.devt, 1);
|
||
|
+ vcio->fw = fw;
|
||
|
+ vcio->misc_dev.fops = &vcio_fops;
|
||
|
+ vcio->misc_dev.minor = MISC_DYNAMIC_MINOR;
|
||
|
+ vcio->misc_dev.name = "vcio";
|
||
|
+ vcio->misc_dev.parent = dev;
|
||
|
|
||
|
- return ret;
|
||
|
+ return misc_register(&vcio->misc_dev);
|
||
|
}
|
||
|
-module_init(vcio_init);
|
||
|
|
||
|
-static void __exit vcio_exit(void)
|
||
|
+static int vcio_remove(struct platform_device *pdev)
|
||
|
{
|
||
|
- device_destroy(vcio.class, vcio.devt);
|
||
|
- class_destroy(vcio.class);
|
||
|
- cdev_del(&vcio.cdev);
|
||
|
- unregister_chrdev_region(vcio.devt, 1);
|
||
|
+ struct device *dev = &pdev->dev;
|
||
|
+
|
||
|
+ misc_deregister(dev_get_drvdata(dev));
|
||
|
+ return 0;
|
||
|
}
|
||
|
-module_exit(vcio_exit);
|
||
|
+
|
||
|
+static const struct of_device_id vcio_ids[] = {
|
||
|
+ { .compatible = "raspberrypi,vcio" },
|
||
|
+ { }
|
||
|
+};
|
||
|
+MODULE_DEVICE_TABLE(of, vcio_ids);
|
||
|
+
|
||
|
+static struct platform_driver vcio_driver = {
|
||
|
+ .driver = {
|
||
|
+ .name = MODULE_NAME,
|
||
|
+ .of_match_table = of_match_ptr(vcio_ids),
|
||
|
+ },
|
||
|
+ .probe = vcio_probe,
|
||
|
+ .remove = vcio_remove,
|
||
|
+};
|
||
|
+
|
||
|
+module_platform_driver(vcio_driver);
|
||
|
|
||
|
MODULE_AUTHOR("Gray Girling");
|
||
|
MODULE_AUTHOR("Noralf Trønnes");
|
||
|
MODULE_DESCRIPTION("Mailbox userspace access");
|
||
|
MODULE_LICENSE("GPL");
|
||
|
+MODULE_ALIAS("platform:rpi-vcio");
|