From: Kisang Lee Date: Thu, 27 Dec 2018 11:03:37 +0000 (+0900) Subject: [RAMEN9610-11980][COMMON] usb: gadget: add vendor specific command in mass storage X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=577d1c7613a5457eb83b7112ee99cac5f317d65d;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git [RAMEN9610-11980][COMMON] usb: gadget: add vendor specific command in mass storage Change-Id: If8b4e8a89bbff020beee88618693514b61cffd22 Signed-off-by: Kisang Lee --- diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 41b5baa1f43b..bfc733f06b22 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -209,6 +209,7 @@ #include #include #include +#include #include #include #include @@ -228,9 +229,16 @@ /*------------------------------------------------------------------------*/ -#define FSG_DRIVER_DESC "Mass Storage Function" +#define FSG_DRIVER_DESC "mass_storage" #define FSG_DRIVER_VERSION "2009/09/11" +enum fsg_restart_type { + FSG_RESTART_NONE, + FSG_REBOOT, + FSG_REBOOT_BL, +}; + + static const char fsg_string_interface[] = "Mass Storage"; #include "storage_common.h" @@ -316,6 +324,8 @@ struct fsg_common { char inquiry_string[INQUIRY_STRING_LEN]; struct kref ref; + enum fsg_restart_type restart_type; + struct delayed_work restart_work; }; struct fsg_dev { @@ -2030,6 +2040,35 @@ static int do_scsi_command(struct fsg_common *common) reply = do_write(common); break; + case SC_REBOOT: + common->data_size_from_cmnd = 0; + reply = check_command(common, common->cmnd_size, + DATA_DIR_NONE, 0, 0, "REBOOT BL"); + if (reply == 0) { + common->curlun->sense_data = SS_INVALID_COMMAND; + reply = -EINVAL; + } else { + pr_err("Triggered Reboot from SCSI Command\n"); + common->restart_type = FSG_REBOOT; + schedule_delayed_work(&common->restart_work, + msecs_to_jiffies(1000)); + } + break; + case SC_REBOOT_2: + common->data_size_from_cmnd = 0; + reply = check_command(common, common->cmnd_size, + DATA_DIR_NONE, 0, 0, "REBOOT"); + if (reply == 0) { + common->curlun->sense_data = SS_INVALID_COMMAND; + reply = -EINVAL; + } else { + pr_err("Triggered Reboot BL from SCSI Command\n"); + common->restart_type = FSG_REBOOT_BL; + schedule_delayed_work(&common->restart_work, + msecs_to_jiffies(1000)); + } + break; + /* * Some mandatory commands that we recognize but don't implement. * They don't mean much in this setting. It's left as an exercise @@ -2580,6 +2619,32 @@ void fsg_common_put(struct fsg_common *common) } EXPORT_SYMBOL_GPL(fsg_common_put); +static int disable_restarts; +module_param(disable_restarts, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(disable_restarts, "Disable SCSI Initiated Reboots"); +static void fsg_restart_work(struct work_struct *work) +{ + struct fsg_common *common = container_of(work, + struct fsg_common, + restart_work.work); + + if (disable_restarts) { + pr_err("SCSI Reboots Disabled\n"); + return; + } + + switch (common->restart_type) { + case FSG_REBOOT: + kernel_restart(""); + break; + case FSG_REBOOT_BL: + kernel_restart("bootloader"); + break; + default: + break; + } +} + static struct fsg_common *fsg_common_setup(struct fsg_common *common) { if (!common) { @@ -2596,6 +2661,7 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common) init_completion(&common->thread_notifier); init_waitqueue_head(&common->io_wait); init_waitqueue_head(&common->fsg_wait); + INIT_DELAYED_WORK(&common->restart_work, fsg_restart_work); common->state = FSG_STATE_TERMINATED; memset(common->luns, 0, sizeof(common->luns)); diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index 68e7e3e18004..9474d6096912 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -171,6 +171,8 @@ /* Vendor specific CDBs start here */ #define VENDOR_SPECIFIC_CDB 0xc0 +#define SC_REBOOT 0xd7 +#define SC_REBOOT_2 0xd8 /* * SCSI command lengths