1 // SPDX-License-Identifier: GPL-2.0-only
3 * Character device interface driver for Remoteproc framework.
5 * Copyright (c) 2020, The Linux Foundation. All rights reserved.
8 #include <linux/cdev.h>
9 #include <linux/compat.h>
11 #include <linux/module.h>
12 #include <linux/remoteproc.h>
13 #include <linux/uaccess.h>
14 #include <uapi/linux/remoteproc_cdev.h>
16 #include "remoteproc_internal.h"
18 #define NUM_RPROC_DEVICES 64
19 static dev_t rproc_major
;
21 static ssize_t
rproc_cdev_write(struct file
*filp
, const char __user
*buf
, size_t len
, loff_t
*pos
)
23 struct rproc
*rproc
= container_of(filp
->f_inode
->i_cdev
, struct rproc
, cdev
);
27 if (!len
|| len
> sizeof(cmd
))
30 ret
= copy_from_user(cmd
, buf
, len
);
34 if (!strncmp(cmd
, "start", len
)) {
35 ret
= rproc_boot(rproc
);
36 } else if (!strncmp(cmd
, "stop", len
)) {
37 ret
= rproc_shutdown(rproc
);
38 } else if (!strncmp(cmd
, "detach", len
)) {
39 ret
= rproc_detach(rproc
);
41 dev_err(&rproc
->dev
, "Unrecognized option\n");
45 return ret
? ret
: len
;
48 static long rproc_device_ioctl(struct file
*filp
, unsigned int ioctl
, unsigned long arg
)
50 struct rproc
*rproc
= container_of(filp
->f_inode
->i_cdev
, struct rproc
, cdev
);
51 void __user
*argp
= (void __user
*)arg
;
55 case RPROC_SET_SHUTDOWN_ON_RELEASE
:
56 if (copy_from_user(¶m
, argp
, sizeof(s32
)))
59 rproc
->cdev_put_on_release
= !!param
;
61 case RPROC_GET_SHUTDOWN_ON_RELEASE
:
62 param
= (s32
)rproc
->cdev_put_on_release
;
63 if (copy_to_user(argp
, ¶m
, sizeof(s32
)))
68 dev_err(&rproc
->dev
, "Unsupported ioctl\n");
75 static int rproc_cdev_release(struct inode
*inode
, struct file
*filp
)
77 struct rproc
*rproc
= container_of(inode
->i_cdev
, struct rproc
, cdev
);
80 if (!rproc
->cdev_put_on_release
)
83 if (rproc
->state
== RPROC_RUNNING
)
84 rproc_shutdown(rproc
);
85 else if (rproc
->state
== RPROC_ATTACHED
)
86 ret
= rproc_detach(rproc
);
91 static const struct file_operations rproc_fops
= {
92 .write
= rproc_cdev_write
,
93 .unlocked_ioctl
= rproc_device_ioctl
,
94 .compat_ioctl
= compat_ptr_ioctl
,
95 .release
= rproc_cdev_release
,
98 int rproc_char_device_add(struct rproc
*rproc
)
102 cdev_init(&rproc
->cdev
, &rproc_fops
);
103 rproc
->cdev
.owner
= THIS_MODULE
;
105 rproc
->dev
.devt
= MKDEV(MAJOR(rproc_major
), rproc
->index
);
106 cdev_set_parent(&rproc
->cdev
, &rproc
->dev
.kobj
);
107 ret
= cdev_add(&rproc
->cdev
, rproc
->dev
.devt
, 1);
109 dev_err(&rproc
->dev
, "Failed to add char dev for %s\n", rproc
->name
);
114 void rproc_char_device_remove(struct rproc
*rproc
)
116 cdev_del(&rproc
->cdev
);
119 void __init
rproc_init_cdev(void)
123 ret
= alloc_chrdev_region(&rproc_major
, 0, NUM_RPROC_DEVICES
, "remoteproc");
125 pr_err("Failed to alloc rproc_cdev region, err %d\n", ret
);