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 if (rproc
->state
== RPROC_RUNNING
)
38 ret
= rproc_boot(rproc
);
39 } else if (!strncmp(cmd
, "stop", len
)) {
40 if (rproc
->state
!= RPROC_RUNNING
)
43 rproc_shutdown(rproc
);
45 dev_err(&rproc
->dev
, "Unrecognized option\n");
49 return ret
? ret
: len
;
52 static long rproc_device_ioctl(struct file
*filp
, unsigned int ioctl
, unsigned long arg
)
54 struct rproc
*rproc
= container_of(filp
->f_inode
->i_cdev
, struct rproc
, cdev
);
55 void __user
*argp
= (void __user
*)arg
;
59 case RPROC_SET_SHUTDOWN_ON_RELEASE
:
60 if (copy_from_user(¶m
, argp
, sizeof(s32
)))
63 rproc
->cdev_put_on_release
= !!param
;
65 case RPROC_GET_SHUTDOWN_ON_RELEASE
:
66 param
= (s32
)rproc
->cdev_put_on_release
;
67 if (copy_to_user(argp
, ¶m
, sizeof(s32
)))
72 dev_err(&rproc
->dev
, "Unsupported ioctl\n");
79 static int rproc_cdev_release(struct inode
*inode
, struct file
*filp
)
81 struct rproc
*rproc
= container_of(inode
->i_cdev
, struct rproc
, cdev
);
83 if (rproc
->cdev_put_on_release
&& rproc
->state
== RPROC_RUNNING
)
84 rproc_shutdown(rproc
);
89 static const struct file_operations rproc_fops
= {
90 .write
= rproc_cdev_write
,
91 .unlocked_ioctl
= rproc_device_ioctl
,
92 .compat_ioctl
= compat_ptr_ioctl
,
93 .release
= rproc_cdev_release
,
96 int rproc_char_device_add(struct rproc
*rproc
)
100 cdev_init(&rproc
->cdev
, &rproc_fops
);
101 rproc
->cdev
.owner
= THIS_MODULE
;
103 rproc
->dev
.devt
= MKDEV(MAJOR(rproc_major
), rproc
->index
);
104 cdev_set_parent(&rproc
->cdev
, &rproc
->dev
.kobj
);
105 ret
= cdev_add(&rproc
->cdev
, rproc
->dev
.devt
, 1);
107 dev_err(&rproc
->dev
, "Failed to add char dev for %s\n", rproc
->name
);
112 void rproc_char_device_remove(struct rproc
*rproc
)
114 __unregister_chrdev(MAJOR(rproc
->dev
.devt
), rproc
->index
, 1, "remoteproc");
117 void __init
rproc_init_cdev(void)
121 ret
= alloc_chrdev_region(&rproc_major
, 0, NUM_RPROC_DEVICES
, "remoteproc");
123 pr_err("Failed to alloc rproc_cdev region, err %d\n", ret
);