diff mbox series

[RFC] usb: gadget: mass_storage: Add GET_EVENT_STATUS_NOTIFICATION

Message ID 3af4cd764ba00439e1204be66fd45e5a546ffa66.camel@kernel.crashing.org (mailing list archive)
State New, archived
Headers show
Series [RFC] usb: gadget: mass_storage: Add GET_EVENT_STATUS_NOTIFICATION | expand

Commit Message

Benjamin Herrenschmidt July 27, 2018, 12:22 a.m. UTC
This is just RFC at this stage, I was getting annoyed at the once-per-second
debug message about unsupported command when using f_mass_storage as a CDROM,
so I quickly hacked that up.

I'm not clearing the events per-se, I'm just sending events based on the
state of pending unit attentions, which seems to be enough to please Linux
on the other side, but definitely needs more testing or expert opinions.

If I find some spare cycle in the next few weeks I might add a few more
of the basic MMC commands so we at least support everything Linux throws
at us for a normal read-only CDROM.

Comments ?

Not-Yet-Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
 drivers/usb/gadget/function/f_mass_storage.c | 49 +++++++++++++++++++-
 1 file changed, 48 insertions(+), 1 deletion(-)




--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox series

Patch

diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 7b13928077c9..d8c83359f470 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -1390,6 +1390,42 @@  static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
 	return -EINVAL;
 }
 
+static int do_get_event_status_notification(struct fsg_common *common,
+					    struct fsg_buffhd *bh)
+{
+	struct fsg_lun	*curlun = common->curlun;
+	u8		*buf = (u8 *) bh->buf;
+	bool		media_class;
+	u8		event;
+	int		size;
+
+	/* We only support media class */
+	media_class = (common->cmnd[4] & 0x10) != 0;
+
+	/* We just mirror the unit attentions */
+	if (curlun->unit_attention_data == SS_NOT_READY_TO_READY_TRANSITION)
+		event = 2; /* New media */
+	else if (curlun->unit_attention_data == SS_MEDIUM_NOT_PRESENT)
+		event = 3;
+	else
+		event = 0;
+
+	/* Fill common header */
+	size = 4;
+	buf[3] = 0x10; /* Support classes: media */
+	if (media_class) {
+		buf[2] = 4; /* Return media event */
+		if (event == 0)
+			buf[2] |= 0x80; /* No Event Available */
+		size += 8;
+		buf[4] = event;
+		buf[5] = 1; /* Active */
+		buf[6] = buf[7] = 0;
+	} else {
+		buf[2] = 0; /* None of the req. classes supported */
+	}
+	return size;
+}
 
 /*-------------------------------------------------------------------------*/
 
@@ -1753,7 +1789,8 @@  static int check_command(struct fsg_common *common, int cmnd_size,
 	 */
 	if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
 	    common->cmnd[0] != INQUIRY &&
-	    common->cmnd[0] != REQUEST_SENSE) {
+	    common->cmnd[0] != REQUEST_SENSE &&
+	    common->cmnd[0] != GET_EVENT_STATUS_NOTIFICATION) {
 		curlun->sense_data = curlun->unit_attention_data;
 		curlun->unit_attention_data = SS_NO_SENSE;
 		return -EINVAL;
@@ -2025,6 +2062,16 @@  static int do_scsi_command(struct fsg_common *common)
 			reply = do_write(common);
 		break;
 
+	case GET_EVENT_STATUS_NOTIFICATION:
+		common->data_size_from_cmnd =
+			get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				      (1 << 1) | (1 << 4) | (3 << 7) | (1 << 9),
+				      0, "GET_EVENT_STATUS_NOTIFICATION");
+		if (reply == 0)
+			reply = do_get_event_status_notification(common, bh);
+		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