Commit 89ada0fe authored by Roger Quadros's avatar Roger Quadros Committed by Greg Kroah-Hartman
Browse files

usb: gadget: f_mass_storage: Make CD-ROM emulation work with Mac OS-X



Mac OS-X expects CD-ROM TOC in raw format (i.e. format:2). It also
sends the READ_TOC CDB in old style SFF8020i format. i.e. 2 format bits
are encoded in MSBs of CDB byte 9.

This patch will enable CD-ROM emulation to work with Mac OS-X. Tested on
Mac OS X v10.6.3.

Acked-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarRoger Quadros <roger.quadros@nokia.com>
Signed-off-by: default avatarJack Pham <quic_jackp@quicinc.com>
Link: https://lore.kernel.org/r/20220124160150.19499-1-quic_jackp@quicinc.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e62667f8
Loading
Loading
Loading
Loading
+58 −12
Original line number Diff line number Diff line
@@ -1188,6 +1188,8 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
	int		msf = common->cmnd[1] & 0x02;
	int		start_track = common->cmnd[6];
	u8		*buf = (u8 *)bh->buf;
	u8		format;
	int		i, len;

	if ((common->cmnd[1] & ~0x02) != 0 ||	/* Mask away MSF */
			start_track > 1) {
@@ -1195,8 +1197,21 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
		return -EINVAL;
	}

	memset(buf, 0, 20);
	buf[1] = (20-2);		/* TOC data length */
	format = common->cmnd[2] & 0xf;
	/*
	 * Check if CDB is old style SFF-8020i
	 * i.e. format is in 2 MSBs of byte 9
	 * Mac OS-X host sends us this.
	 */
	if (format == 0)
		format = (common->cmnd[9] >> 6) & 0x3;

	switch (format) {
	case 0:
		/* Formatted TOC */
		len = 4 + 2*8;		/* 4 byte header + 2 descriptors */
		memset(buf, 0, len);
		buf[1] = len - 2;	/* TOC Length excludes length field */
		buf[2] = 1;		/* First track number */
		buf[3] = 1;		/* Last track number */
		buf[5] = 0x16;		/* Data track, copying allowed */
@@ -1206,7 +1221,38 @@ static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
		buf[13] = 0x16;		/* Lead-out track is data */
		buf[14] = 0xAA;		/* Lead-out track number */
		store_cdrom_address(&buf[16], msf, curlun->num_sectors);
	return 20;
		return len;

	case 2:
		/* Raw TOC */
		len = 4 + 3*11;		/* 4 byte header + 3 descriptors */
		memset(buf, 0, len);	/* Header + A0, A1 & A2 descriptors */
		buf[1] = len - 2;	/* TOC Length excludes length field */
		buf[2] = 1;		/* First complete session */
		buf[3] = 1;		/* Last complete session */

		buf += 4;
		/* fill in A0, A1 and A2 points */
		for (i = 0; i < 3; i++) {
			buf[0] = 1;	/* Session number */
			buf[1] = 0x16;	/* Data track, copying allowed */
			/* 2 - Track number 0 ->  TOC */
			buf[3] = 0xA0 + i; /* A0, A1, A2 point */
			/* 4, 5, 6 - Min, sec, frame is zero */
			buf[8] = 1;	/* Pmin: last track number */
			buf += 11;	/* go to next track descriptor */
		}
		buf -= 11;		/* go back to A2 descriptor */

		/* For A2, 7, 8, 9, 10 - zero, Pmin, Psec, Pframe of Lead out */
		store_cdrom_address(&buf[7], msf, curlun->num_sectors);
		return len;

	default:
		/* Multi-session, PMA, ATIP, CD-TEXT not supported/required */
		curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
		return -EINVAL;
	}
}

static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
@@ -1944,7 +1990,7 @@ static int do_scsi_command(struct fsg_common *common)
		common->data_size_from_cmnd =
			get_unaligned_be16(&common->cmnd[7]);
		reply = check_command(common, 10, DATA_DIR_TO_HOST,
				      (7<<6) | (1<<1), 1,
				      (0xf<<6) | (3<<1), 1,
				      "READ TOC");
		if (reply == 0)
			reply = do_read_toc(common, bh);