OSDN Git Service

Merge tag 'usb-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[uclinux-h8/linux.git] / drivers / usb / gadget / function / f_mass_storage.c
index 7371c6e..3a77bca 100644 (file)
@@ -1189,6 +1189,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) {
@@ -1196,18 +1198,62 @@ 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);
+       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 */
+               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 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 */
 
-       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;
+               /* 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)
@@ -1945,7 +1991,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);