2011-03-09 12:19:39

by Roger Quadros

[permalink] [raw]
Subject: [PATCH 0/3] usb: gadget: storage: Make CD-ROM emulation work with Mac OS-X

Hi,

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.

The first patch introduces a fsg_get_toc() helper which builds the
Table of Contents (TOC) that can be used for the READ_TOC command.
The remaining two patches simply make file_storage gadget and mass_storage
gadget use the new helper function.

---
Roger Quadros (3):
usb: gadget: storage: Add fsg_get_toc helper
usb: gadget: file_storage: Make CD-ROM emulation work with Mac OS-X
usb: gadget: f_mass_storage: Make CD-ROM emulation work with Mac OS-X

drivers/usb/gadget/f_mass_storage.c | 31 ++++++++------
drivers/usb/gadget/file_storage.c | 32 ++++++++------
drivers/usb/gadget/storage_common.c | 79 +++++++++++++++++++++++++++++++++++
3 files changed, 116 insertions(+), 26 deletions(-)


2011-03-09 12:19:09

by Roger Quadros

[permalink] [raw]
Subject: [PATCH 2/3] usb: gadget: file_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.

Signed-off-by: Roger Quadros <[email protected]>
---
drivers/usb/gadget/file_storage.c | 32 +++++++++++++++++++-------------
1 files changed, 19 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index a6eacb5..753ac94 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1696,6 +1696,8 @@ static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
int msf = fsg->cmnd[1] & 0x02;
int start_track = fsg->cmnd[6];
u8 *buf = (u8 *) bh->buf;
+ u8 format;
+ int ret;

if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
start_track > 1) {
@@ -1703,18 +1705,22 @@ static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
return -EINVAL;
}

- memset(buf, 0, 20);
- buf[1] = (20-2); /* TOC data length */
- buf[2] = 1; /* First track number */
- buf[3] = 1; /* Last track number */
- buf[5] = 0x16; /* Data track, copying allowed */
- buf[6] = 0x01; /* Only track is number 1 */
- store_cdrom_address(&buf[8], msf, 0);
+ /*
+ * 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.
+ */
+ format = (fsg->cmnd[9] >> 6) & 0x3;
+ if (format == 0)
+ format = fsg->cmnd[2] & 0xf; /* new style MMC-2 */
+
+ ret = fsg_get_toc(curlun, msf, format, buf);
+ if (ret < 0) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ return ret;

- 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;
}


@@ -2486,7 +2492,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
goto unknown_cmnd;
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
- (7<<6) | (1<<1), 1,
+ (0xf<<6) | (1<<1), 1,
"READ TOC")) == 0)
reply = do_read_toc(fsg, bh);
break;
--
1.6.0.4

2011-03-09 12:19:08

by Roger Quadros

[permalink] [raw]
Subject: [PATCH 3/3] 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.

Signed-off-by: Roger Quadros <[email protected]>
---
drivers/usb/gadget/f_mass_storage.c | 31 ++++++++++++++++++-------------
1 files changed, 18 insertions(+), 13 deletions(-)

diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 6d8e533..d3fd60d 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -1315,6 +1315,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 ret;

if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
start_track > 1) {
@@ -1322,18 +1324,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 */
- buf[2] = 1; /* First track number */
- buf[3] = 1; /* Last track number */
- buf[5] = 0x16; /* Data track, copying allowed */
- buf[6] = 0x01; /* Only track is number 1 */
- store_cdrom_address(&buf[8], msf, 0);
+ /*
+ * 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.
+ */
+ format = (common->cmnd[9] >> 6) & 0x3;
+ if (format == 0)
+ format = common->cmnd[2] & 0xf; /* new style MMC-2 */

- 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;
+ ret = fsg_get_toc(curlun, msf, format, buf);
+ if (ret < 0) {
+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+ return -EINVAL;
+ }
+ return ret;
}

static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
@@ -2103,7 +2108,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) | (1<<1), 1,
"READ TOC");
if (reply == 0)
reply = do_read_toc(common, bh);
--
1.6.0.4

2011-03-09 12:19:40

by Roger Quadros

[permalink] [raw]
Subject: [PATCH 1/3] usb: gadget: storage: Add fsg_get_toc helper

fsg_get_toc can be used by both storage gadgets to build a CD-ROM
Table of Contents which can be used as data for READ_TOC command.
Currently fsg_get_toc supports two TOC formats, i.e.
format 0: Formatted TOC and format 2: Raw TOC.

Raw TOC is required for CD-ROM emulation to work with Mac OS-X.

Signed-off-by: Roger Quadros <[email protected]>
---
drivers/usb/gadget/storage_common.c | 79 +++++++++++++++++++++++++++++++++++
1 files changed, 79 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index b015561..ffad1d9 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -655,6 +655,85 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
}
}

+/*
+ * put_toc() - Builds a TOC with required format @format.
+ * @curlun: The LUN for which the TOC has to be built
+ * @msf: Min Sec Frame format or LBA format for address
+ * @format: TOC format code
+ * @buf: the buffer into which the TOC is built
+ *
+ * Builds a Table of Content which can be used as data for READ_TOC command.
+ * The TOC simulates a single session, single track CD-ROM mode 1 disc.
+ *
+ * Returns number of bytes written to @buf, -EINVAL if format not supported.
+ */
+static int fsg_get_toc(struct fsg_lun *curlun, int msf, int format, u8 *buf)
+{
+ switch (format) {
+ case 0:
+ /* Formatted TOC */
+ memset(buf, 0, 20);
+ buf[1] = (20-2); /* TOC data length */
+ buf[2] = 1; /* First track number */
+ buf[3] = 1; /* Last track number */
+ buf[5] = 0x16; /* Data track, copying allowed */
+ buf[6] = 0x01; /* Only track is number 1 */
+ store_cdrom_address(&buf[8], msf, 0);
+
+ 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;
+ break;
+
+ case 2:
+ /* Raw TOC */
+ memset(buf, 0, 37); /* Header + A0, A1 & A2 descriptors */
+ buf[1] = 37; /* 4 + 3*11 */
+ buf[2] = 1; /* First complete session */
+ buf[3] = 2; /* Last complete session */
+
+ buf += 4;
+ /* A0 point */
+ buf[0] = 1; /* Session number */
+ buf[1] = 0x16; /* Data track, copying alowed */
+ /* 2 - Track number 0 -> TOC */
+ buf[3] = 0xA0; /* Point A0 */
+ /* 4, 5, 6 - Min, sec, frame is zero */
+ /* 7 - zero */
+ buf[8] = 1; /* Pmin: 1st track number */
+ /* 9 - disc type 0: CD-ROM/DA with 1st track in mode 1 */
+ /* 10 - pframe 0 */
+
+ buf += 11;
+ /* A1 point*/
+ buf[0] = 1; /* Session number */
+ buf[1] = 0x16; /* Data track, copying alowed */
+ /* 2 - Track number 0 -> TOC */
+ buf[3] = 0xA1; /* Point A1 */
+ /* 4, 5, 6 - Min, sec, frame is zero */
+ /* 7, zero */
+ buf[8] = 1; /* Pmin: last track number */
+ /* 9, 10 - pmin and pframe are 0 */
+
+ buf += 11;
+ /* A2 point*/
+ buf[0] = 1; /* Session number */
+ buf[1] = 0x16; /* Data track, copying alowed */
+ /* 2 - Track number 0 -> TOC */
+ buf[3] = 0xA2; /* Point A2 */
+ /* 4, 5, 6 - Min, sec, frame is zero */
+ /* 7, 8, 9, 10 - zero, Pmin, Psec, Pframe of Lead out */
+ store_cdrom_address(&buf[7], msf, curlun->num_sectors);
+ return 37;
+ break;
+ default:
+ /* Multi-session, PMA, ATIP, CD-TEXT not supported/required */
+ return -EINVAL;
+ break;
+ }
+}
+

/*-------------------------------------------------------------------------*/

--
1.6.0.4

2011-03-09 13:42:29

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 1/3] usb: gadget: storage: Add fsg_get_toc helper

Hello.

On 09-03-2011 15:21, Roger Quadros wrote:

> fsg_get_toc can be used by both storage gadgets to build a CD-ROM
> Table of Contents which can be used as data for READ_TOC command.
> Currently fsg_get_toc supports two TOC formats, i.e.
> format 0: Formatted TOC and format 2: Raw TOC.

> Raw TOC is required for CD-ROM emulation to work with Mac OS-X.

> Signed-off-by: Roger Quadros<[email protected]>
> ---
> drivers/usb/gadget/storage_common.c | 79 +++++++++++++++++++++++++++++++++++
> 1 files changed, 79 insertions(+), 0 deletions(-)

> diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
> index b015561..ffad1d9 100644
> --- a/drivers/usb/gadget/storage_common.c
> +++ b/drivers/usb/gadget/storage_common.c
> @@ -655,6 +655,85 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
> }
> }
>
> +/*

The kerneldoc comments should start with "/**".

> + * put_toc() - Builds a TOC with required format @format.

The function is called gsg_get_toc, isn't it?

> + * @curlun: The LUN for which the TOC has to be built
> + * @msf: Min Sec Frame format or LBA format for address
> + * @format: TOC format code
> + * @buf: the buffer into which the TOC is built
> + *
> + * Builds a Table of Content which can be used as data for READ_TOC command.
> + * The TOC simulates a single session, single track CD-ROM mode 1 disc.
> + *
> + * Returns number of bytes written to @buf, -EINVAL if format not supported.
> + */
> +static int fsg_get_toc(struct fsg_lun *curlun, int msf, int format, u8 *buf)
> +{
> + switch (format) {
> + case 0:
> + /* Formatted TOC */
> + memset(buf, 0, 20);
> + buf[1] = (20-2); /* TOC data length */

Parens not needed here. And kernel style assumes putting spacves around
operators.

> + buf[2] = 1; /* First track number */
> + buf[3] = 1; /* Last track number */
> + buf[5] = 0x16; /* Data track, copying allowed */
> + buf[6] = 0x01; /* Only track is number 1 */
> + store_cdrom_address(&buf[8], msf, 0);
> +
> + 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;
> + break;
> +
> + case 2:
> + /* Raw TOC */
> + memset(buf, 0, 37); /* Header + A0, A1& A2 descriptors */
> + buf[1] = 37; /* 4 + 3*11 */
> + buf[2] = 1; /* First complete session */
> + buf[3] = 2; /* Last complete session */
> +
> + buf += 4;
> + /* A0 point */
> + buf[0] = 1; /* Session number */
> + buf[1] = 0x16; /* Data track, copying alowed */
> + /* 2 - Track number 0 -> TOC */
> + buf[3] = 0xA0; /* Point A0 */
> + /* 4, 5, 6 - Min, sec, frame is zero */
> + /* 7 - zero */
> + buf[8] = 1; /* Pmin: 1st track number */
> + /* 9 - disc type 0: CD-ROM/DA with 1st track in mode 1 */
> + /* 10 - pframe 0 */
> +
> + buf += 11;
> + /* A1 point*/
> + buf[0] = 1; /* Session number */
> + buf[1] = 0x16; /* Data track, copying alowed */
> + /* 2 - Track number 0 -> TOC */
> + buf[3] = 0xA1; /* Point A1 */
> + /* 4, 5, 6 - Min, sec, frame is zero */
> + /* 7, zero */
> + buf[8] = 1; /* Pmin: last track number */
> + /* 9, 10 - pmin and pframe are 0 */

The above code is repetitive -- might be worth factoring out into a function.

> +
> + buf += 11;
> + /* A2 point*/
> + buf[0] = 1; /* Session number */
> + buf[1] = 0x16; /* Data track, copying alowed */
> + /* 2 - Track number 0 -> TOC */
> + buf[3] = 0xA2; /* Point A2 */
> + /* 4, 5, 6 - Min, sec, frame is zero */
> + /* 7, 8, 9, 10 - zero, Pmin, Psec, Pframe of Lead out */
> + store_cdrom_address(&buf[7], msf, curlun->num_sectors);
> + return 37;
> + break;
> + default:
> + /* Multi-session, PMA, ATIP, CD-TEXT not supported/required */
> + return -EINVAL;
> + break;
> + }
> +}
> +

OK, but where this function is called from?

WBR, Sergei

2011-03-09 14:06:29

by Roger Quadros

[permalink] [raw]
Subject: Re: [PATCH 1/3] usb: gadget: storage: Add fsg_get_toc helper

Hi,

On 03/09/2011 03:41 PM, ext Sergei Shtylyov wrote:
> Hello.
>
>> --- a/drivers/usb/gadget/storage_common.c
>> +++ b/drivers/usb/gadget/storage_common.c
>> @@ -655,6 +655,85 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
>> }
>> }
>>
>> +/*
>
> The kerneldoc comments should start with "/**".

OK.

>
>> + * put_toc() - Builds a TOC with required format @format.
>
> The function is called gsg_get_toc, isn't it?

Yes :). My initial version was named put_toc(). will correct it.

>
>> + * @curlun: The LUN for which the TOC has to be built
>> + * @msf: Min Sec Frame format or LBA format for address
>> + * @format: TOC format code
>> + * @buf: the buffer into which the TOC is built
>> + *
>> + * Builds a Table of Content which can be used as data for READ_TOC command.
>> + * The TOC simulates a single session, single track CD-ROM mode 1 disc.
>> + *
>> + * Returns number of bytes written to @buf, -EINVAL if format not supported.
>> + */
>> +static int fsg_get_toc(struct fsg_lun *curlun, int msf, int format, u8 *buf)
>> +{
>> + switch (format) {
>> + case 0:
>> + /* Formatted TOC */
>> + memset(buf, 0, 20);
>> + buf[1] = (20-2); /* TOC data length */
>
> Parens not needed here. And kernel style assumes putting spacves around operators.

I copied case 0: code from file_storage.c. But will correct it.
>
>> + buf[2] = 1; /* First track number */
>> + buf[3] = 1; /* Last track number */
>> + buf[5] = 0x16; /* Data track, copying allowed */
>> + buf[6] = 0x01; /* Only track is number 1 */
>> + store_cdrom_address(&buf[8], msf, 0);
>> +
>> + 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;
>> + break;
>> +
>> + case 2:
>> + /* Raw TOC */
>> + memset(buf, 0, 37); /* Header + A0, A1& A2 descriptors */
>> + buf[1] = 37; /* 4 + 3*11 */
>> + buf[2] = 1; /* First complete session */
>> + buf[3] = 2; /* Last complete session */
>> +
>> + buf += 4;
>> + /* A0 point */
>> + buf[0] = 1; /* Session number */
>> + buf[1] = 0x16; /* Data track, copying alowed */
>> + /* 2 - Track number 0 -> TOC */
>> + buf[3] = 0xA0; /* Point A0 */
>> + /* 4, 5, 6 - Min, sec, frame is zero */
>> + /* 7 - zero */
>> + buf[8] = 1; /* Pmin: 1st track number */
>> + /* 9 - disc type 0: CD-ROM/DA with 1st track in mode 1 */
>> + /* 10 - pframe 0 */
>> +
>> + buf += 11;
>> + /* A1 point*/
>> + buf[0] = 1; /* Session number */
>> + buf[1] = 0x16; /* Data track, copying alowed */
>> + /* 2 - Track number 0 -> TOC */
>> + buf[3] = 0xA1; /* Point A1 */
>> + /* 4, 5, 6 - Min, sec, frame is zero */
>> + /* 7, zero */
>> + buf[8] = 1; /* Pmin: last track number */
>> + /* 9, 10 - pmin and pframe are 0 */
>
> The above code is repetitive -- might be worth factoring out into a function.
>
I would leave it as it is as nobody else would use the function.

> OK, but where this function is called from?
>
from file_storage.c and f_mass_storage.c in the next two patches of this series.

--
regards,
-roger

2011-03-09 15:10:40

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH 1/3] usb: gadget: storage: Add fsg_get_toc helper

On Wed, 9 Mar 2011, Roger Quadros wrote:

> fsg_get_toc can be used by both storage gadgets to build a CD-ROM
> Table of Contents which can be used as data for READ_TOC command.
> Currently fsg_get_toc supports two TOC formats, i.e.
> format 0: Formatted TOC and format 2: Raw TOC.
>
> Raw TOC is required for CD-ROM emulation to work with Mac OS-X.

In addition to the things Sergei mentioned...

> +/*
> + * put_toc() - Builds a TOC with required format @format.
> + * @curlun: The LUN for which the TOC has to be built
> + * @msf: Min Sec Frame format or LBA format for address
> + * @format: TOC format code
> + * @buf: the buffer into which the TOC is built
> + *
> + * Builds a Table of Content which can be used as data for READ_TOC command.
> + * The TOC simulates a single session, single track CD-ROM mode 1 disc.
> + *
> + * Returns number of bytes written to @buf, -EINVAL if format not supported.
> + */
> +static int fsg_get_toc(struct fsg_lun *curlun, int msf, int format, u8 *buf)
> +{
> + switch (format) {
> + case 0:
> + /* Formatted TOC */
> + memset(buf, 0, 20);
> + buf[1] = (20-2); /* TOC data length */
> + buf[2] = 1; /* First track number */
> + buf[3] = 1; /* Last track number */
> + buf[5] = 0x16; /* Data track, copying allowed */
> + buf[6] = 0x01; /* Only track is number 1 */
> + store_cdrom_address(&buf[8], msf, 0);
> +
> + 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;
> + break;
> +
> + case 2:
> + /* Raw TOC */
> + memset(buf, 0, 37); /* Header + A0, A1 & A2 descriptors */
> + buf[1] = 37; /* 4 + 3*11 */

There's no reason to do it this way. The compiler is a lot better than
you are at addition. Just put 4 + 3*11 in the assignment statement,
and in the comment explain what the numbers mean.

> + buf[2] = 1; /* First complete session */
> + buf[3] = 2; /* Last complete session */
> +
> + buf += 4;
> + /* A0 point */
> + buf[0] = 1; /* Session number */
> + buf[1] = 0x16; /* Data track, copying alowed */
> + /* 2 - Track number 0 -> TOC */
> + buf[3] = 0xA0; /* Point A0 */
> + /* 4, 5, 6 - Min, sec, frame is zero */
> + /* 7 - zero */
> + buf[8] = 1; /* Pmin: 1st track number */
> + /* 9 - disc type 0: CD-ROM/DA with 1st track in mode 1 */
> + /* 10 - pframe 0 */
> +
> + buf += 11;
> + /* A1 point*/
> + buf[0] = 1; /* Session number */
> + buf[1] = 0x16; /* Data track, copying alowed */
> + /* 2 - Track number 0 -> TOC */
> + buf[3] = 0xA1; /* Point A1 */
> + /* 4, 5, 6 - Min, sec, frame is zero */
> + /* 7, zero */
> + buf[8] = 1; /* Pmin: last track number */
> + /* 9, 10 - pmin and pframe are 0 */
> +
> + buf += 11;
> + /* A2 point*/
> + buf[0] = 1; /* Session number */
> + buf[1] = 0x16; /* Data track, copying alowed */
> + /* 2 - Track number 0 -> TOC */
> + buf[3] = 0xA2; /* Point A2 */
> + /* 4, 5, 6 - Min, sec, frame is zero */
> + /* 7, 8, 9, 10 - zero, Pmin, Psec, Pframe of Lead out */
> + store_cdrom_address(&buf[7], msf, curlun->num_sectors);

These things could be put into a loop, instead of a separate function.

> + return 37;

It might be a good idea to use a variable instead of having all these
"37"s floating around. It would make future updates more reliable.

> + break;
> + default:
> + /* Multi-session, PMA, ATIP, CD-TEXT not supported/required */
> + return -EINVAL;
> + break;
> + }
> +}

Alan Stern

2011-03-09 15:35:24

by Roger Quadros

[permalink] [raw]
Subject: Re: [PATCH 1/3] usb: gadget: storage: Add fsg_get_toc helper

On 03/09/2011 05:10 PM, ext Alan Stern wrote:

>> + case 2:
>> + /* Raw TOC */
>> + memset(buf, 0, 37); /* Header + A0, A1& A2 descriptors */
>> + buf[1] = 37; /* 4 + 3*11 */
>
> There's no reason to do it this way. The compiler is a lot better than
> you are at addition. Just put 4 + 3*11 in the assignment statement,
> and in the comment explain what the numbers mean.

OK.

>
>> + buf[2] = 1; /* First complete session */
>> + buf[3] = 2; /* Last complete session */
>> +
>> + buf += 4;
>> + /* A0 point */
>> + buf[0] = 1; /* Session number */
>> + buf[1] = 0x16; /* Data track, copying alowed */
>> + /* 2 - Track number 0 -> TOC */
>> + buf[3] = 0xA0; /* Point A0 */
>> + /* 4, 5, 6 - Min, sec, frame is zero */
>> + /* 7 - zero */
>> + buf[8] = 1; /* Pmin: 1st track number */
>> + /* 9 - disc type 0: CD-ROM/DA with 1st track in mode 1 */
>> + /* 10 - pframe 0 */
>> +
>> + buf += 11;
>> + /* A1 point*/
>> + buf[0] = 1; /* Session number */
>> + buf[1] = 0x16; /* Data track, copying alowed */
>> + /* 2 - Track number 0 -> TOC */
>> + buf[3] = 0xA1; /* Point A1 */
>> + /* 4, 5, 6 - Min, sec, frame is zero */
>> + /* 7, zero */
>> + buf[8] = 1; /* Pmin: last track number */
>> + /* 9, 10 - pmin and pframe are 0 */
>> +
>> + buf += 11;
>> + /* A2 point*/
>> + buf[0] = 1; /* Session number */
>> + buf[1] = 0x16; /* Data track, copying alowed */
>> + /* 2 - Track number 0 -> TOC */
>> + buf[3] = 0xA2; /* Point A2 */
>> + /* 4, 5, 6 - Min, sec, frame is zero */
>> + /* 7, 8, 9, 10 - zero, Pmin, Psec, Pframe of Lead out */
>> + store_cdrom_address(&buf[7], msf, curlun->num_sectors);
>
> These things could be put into a loop, instead of a separate function.

Yes loop is better than function for this case.

>
>> + return 37;
>
> It might be a good idea to use a variable instead of having all these
> "37"s floating around. It would make future updates more reliable.

OK.

--
regards,
-roger

2011-03-09 16:07:18

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH 1/3] usb: gadget: storage: Add fsg_get_toc helper

On Wed, 9 Mar 2011, Roger Quadros wrote:

> fsg_get_toc can be used by both storage gadgets to build a CD-ROM
> Table of Contents which can be used as data for READ_TOC command.
> Currently fsg_get_toc supports two TOC formats, i.e.
> format 0: Formatted TOC and format 2: Raw TOC.
>
> Raw TOC is required for CD-ROM emulation to work with Mac OS-X.
>
> Signed-off-by: Roger Quadros <[email protected]>
> ---
> drivers/usb/gadget/storage_common.c | 79 +++++++++++++++++++++++++++++++++++
> 1 files changed, 79 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
> index b015561..ffad1d9 100644
> --- a/drivers/usb/gadget/storage_common.c
> +++ b/drivers/usb/gadget/storage_common.c
> @@ -655,6 +655,85 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
> }
> }
>
> +/*
> + * put_toc() - Builds a TOC with required format @format.
> + * @curlun: The LUN for which the TOC has to be built
> + * @msf: Min Sec Frame format or LBA format for address
> + * @format: TOC format code
> + * @buf: the buffer into which the TOC is built
> + *
> + * Builds a Table of Content which can be used as data for READ_TOC command.
> + * The TOC simulates a single session, single track CD-ROM mode 1 disc.
> + *
> + * Returns number of bytes written to @buf, -EINVAL if format not supported.
> + */
> +static int fsg_get_toc(struct fsg_lun *curlun, int msf, int format, u8 *buf)
> +{
> + switch (format) {
> + case 0:
> + /* Formatted TOC */
> + memset(buf, 0, 20);
> + buf[1] = (20-2); /* TOC data length */
> + buf[2] = 1; /* First track number */
> + buf[3] = 1; /* Last track number */
> + buf[5] = 0x16; /* Data track, copying allowed */
> + buf[6] = 0x01; /* Only track is number 1 */
> + store_cdrom_address(&buf[8], msf, 0);
> +
> + 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;
> + break;
> +
> + case 2:
> + /* Raw TOC */
> + memset(buf, 0, 37); /* Header + A0, A1 & A2 descriptors */
> + buf[1] = 37; /* 4 + 3*11 */

According to the SFF8020i spec Table 128, TOC Data Length is 2 + 11 *
(number of descriptors returned). But that's probably a misprint.

> + buf[2] = 1; /* First complete session */
> + buf[3] = 2; /* Last complete session */

According to the spec, for drives that do not support multi-session,
the First session number should be equal to the Last session number.


On Wed, 9 Mar 2011, Roger Quadros wrote:

> 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.
>
> Signed-off-by: Roger Quadros <[email protected]>
> ---
> drivers/usb/gadget/file_storage.c | 32 +++++++++++++++++++-------------
> 1 files changed, 19 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
> index a6eacb5..753ac94 100644
> --- a/drivers/usb/gadget/file_storage.c
> +++ b/drivers/usb/gadget/file_storage.c
> @@ -1696,6 +1696,8 @@ static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
> int msf = fsg->cmnd[1] & 0x02;
> int start_track = fsg->cmnd[6];
> u8 *buf = (u8 *) bh->buf;
> + u8 format;
> + int ret;
>
> if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
> start_track > 1) {
> @@ -1703,18 +1705,22 @@ static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
> return -EINVAL;
> }
>
> - memset(buf, 0, 20);
> - buf[1] = (20-2); /* TOC data length */
> - buf[2] = 1; /* First track number */
> - buf[3] = 1; /* Last track number */
> - buf[5] = 0x16; /* Data track, copying allowed */
> - buf[6] = 0x01; /* Only track is number 1 */
> - store_cdrom_address(&buf[8], msf, 0);
> + /*
> + * 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.
> + */
> + format = (fsg->cmnd[9] >> 6) & 0x3;
> + if (format == 0)
> + format = fsg->cmnd[2] & 0xf; /* new style MMC-2 */

The spec says: "Format field definition: When Format in Byte 2 is zero,
then Byte 9 is used." This logic does not follow that description.

Alan Stern

2011-03-10 14:55:33

by Roger Quadros

[permalink] [raw]
Subject: Re: [PATCH 1/3] usb: gadget: storage: Add fsg_get_toc helper

Hi,

On 03/09/2011 06:07 PM, ext Alan Stern wrote:
>> + case 2:
>> + /* Raw TOC */
>> + memset(buf, 0, 37); /* Header + A0, A1& A2 descriptors */
>> + buf[1] = 37; /* 4 + 3*11 */
>
> According to the SFF8020i spec Table 128, TOC Data Length is 2 + 11 *
> (number of descriptors returned). But that's probably a misprint.

It's probably right. I will fix it and verify if it works.
>
>> + buf[2] = 1; /* First complete session */
>> + buf[3] = 2; /* Last complete session */
>
> According to the spec, for drives that do not support multi-session,
> the First session number should be equal to the Last session number.
>
Right. good catch.

>
> On Wed, 9 Mar 2011, Roger Quadros wrote:
>
>> 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.
>>
>> Signed-off-by: Roger Quadros<[email protected]>
>> ---
>> drivers/usb/gadget/file_storage.c | 32 +++++++++++++++++++-------------
>> 1 files changed, 19 insertions(+), 13 deletions(-)
>>
>> diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
>> index a6eacb5..753ac94 100644
>> --- a/drivers/usb/gadget/file_storage.c
>> +++ b/drivers/usb/gadget/file_storage.c
>> @@ -1696,6 +1696,8 @@ static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
>> int msf = fsg->cmnd[1]& 0x02;
>> int start_track = fsg->cmnd[6];
>> u8 *buf = (u8 *) bh->buf;
>> + u8 format;
>> + int ret;
>>
>> if ((fsg->cmnd[1]& ~0x02) != 0 || /* Mask away MSF */
>> start_track> 1) {
>> @@ -1703,18 +1705,22 @@ static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
>> return -EINVAL;
>> }
>>
>> - memset(buf, 0, 20);
>> - buf[1] = (20-2); /* TOC data length */
>> - buf[2] = 1; /* First track number */
>> - buf[3] = 1; /* Last track number */
>> - buf[5] = 0x16; /* Data track, copying allowed */
>> - buf[6] = 0x01; /* Only track is number 1 */
>> - store_cdrom_address(&buf[8], msf, 0);
>> + /*
>> + * 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.
>> + */
>> + format = (fsg->cmnd[9]>> 6)& 0x3;
>> + if (format == 0)
>> + format = fsg->cmnd[2]& 0xf; /* new style MMC-2 */
>
> The spec says: "Format field definition: When Format in Byte 2 is zero,
> then Byte 9 is used." This logic does not follow that description.
>

Yes indeed. I'll fix all this in v2. Thanks for review.

--
regards,
-roger