+ ubi_put_device(ubi);
+ return err;
+}
+
+static int ctrl_cdev_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int err = 0;
+ void __user *argp = (void __user *)arg;
+
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EPERM;
+
+ switch (cmd) {
+ /* Attach an MTD device command */
+ case UBI_IOCATT:
+ {
+ struct ubi_attach_req req;
+ struct mtd_info *mtd;
+
+ dbg_msg("attach MTD device");
+ err = copy_from_user(&req, argp, sizeof(struct ubi_attach_req));
+ if (err) {
+ err = -EFAULT;
+ break;
+ }
+
+ if (req.mtd_num < 0 ||
+ (req.ubi_num < 0 && req.ubi_num != UBI_DEV_NUM_AUTO)) {
+ err = -EINVAL;
+ break;
+ }
+
+ mtd = get_mtd_device(NULL, req.mtd_num);
+ if (IS_ERR(mtd)) {
+ err = PTR_ERR(mtd);
+ break;
+ }
+
+ /*
+ * Note, further request verification is done by
+ * 'ubi_attach_mtd_dev()'.
+ */
+ mutex_lock(&ubi_devices_mutex);
+ err = ubi_attach_mtd_dev(mtd, req.ubi_num, req.vid_hdr_offset);
+ mutex_unlock(&ubi_devices_mutex);
+ if (err < 0)
+ put_mtd_device(mtd);
+ else
+ /* @err contains UBI device number */
+ err = put_user(err, (__user int32_t *)argp);
+
+ break;
+ }
+
+ /* Detach an MTD device command */
+ case UBI_IOCDET:
+ {
+ int ubi_num;
+
+ dbg_msg("dettach MTD device");
+ err = get_user(ubi_num, (__user int32_t *)argp);
+ if (err) {
+ err = -EFAULT;
+ break;
+ }
+
+ mutex_lock(&ubi_devices_mutex);
+ err = ubi_detach_mtd_dev(ubi_num, 0);
+ mutex_unlock(&ubi_devices_mutex);
+ break;
+ }
+
+ default:
+ err = -ENOTTY;
+ break;
+ }
+