mirror of
https://github.com/sipeed/LicheeRV-Nano-Build.git
synced 2026-09-11 05:09:56 -05:00
add: support windows iso on usb mass storage function
This commit is contained in:
@@ -1167,6 +1167,16 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
|
||||
u32 lba = get_unaligned_be32(&common->cmnd[2]);
|
||||
u8 *buf = (u8 *)bh->buf;
|
||||
|
||||
if (curlun->cd_as_dvd) {
|
||||
/*
|
||||
* The READ_HEADER command is obsolete since MMC-3.
|
||||
* We're keeping it for backward compatibility,
|
||||
* but disabling it for big images since they will be
|
||||
* handled as DVD.
|
||||
*/
|
||||
curlun->sense_data = SS_INVALID_COMMAND;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (common->cmnd[1] & ~0x02) { /* Mask away MSF */
|
||||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
@@ -1205,7 +1215,19 @@ 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);
|
||||
if (curlun->cd_as_dvd) {
|
||||
/*
|
||||
* According to specifications, for DVD images
|
||||
* the lead-out address should be fabricated.
|
||||
* It seems it's not using by drivers at all,
|
||||
* so it can contain any big valid MSF address.
|
||||
* This address MSF:0,0x23,0,0 is taken
|
||||
* from the example in the doc.
|
||||
*/
|
||||
store_cdrom_address(&buf[16], msf, 157350);
|
||||
} else {
|
||||
store_cdrom_address(&buf[16], msf, curlun->num_sectors);
|
||||
}
|
||||
return 20;
|
||||
}
|
||||
|
||||
@@ -1220,6 +1242,23 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
|
||||
int valid_page = 0;
|
||||
int len, limit;
|
||||
|
||||
/*
|
||||
* This magic blob contains a bunch of flags according to
|
||||
* "Table 580 - C/DVD Capabilities and Mechanical Status"
|
||||
* and too long to decode it here.
|
||||
* See the big PDF "INF-TA-1010 Rev 1.0.0".
|
||||
*/
|
||||
const u8 capabilities[] =
|
||||
"\x3f\x00\xf1\x77\x29\x23\x2b\x48" \
|
||||
"\x01\x00\x06\x00\x2b\x48\x00\x10" \
|
||||
"\x2b\x48\x2b\x48\x00\x01\x00\x00" \
|
||||
"\x00\x00\x2b\x48\x00\x09\x00\x00" \
|
||||
"\x2b\x48\x00\x00\x20\x76\x00\x00" \
|
||||
"\x15\xa4\x00\x00\x10\x3b\x00\x00" \
|
||||
"\x10\x3b\x00\x00\x10\x3b\x00\x00" \
|
||||
"\x10\x3b\x00\x00\x10\x3b\x00\x00" \
|
||||
"\x10\x3b";
|
||||
|
||||
if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */
|
||||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
@@ -1252,10 +1291,9 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
|
||||
|
||||
/* No block descriptors */
|
||||
|
||||
/*
|
||||
* The mode pages, in numerical order. The only page we support
|
||||
* is the Caching page.
|
||||
*/
|
||||
/* The mode pages, in numerical order */
|
||||
|
||||
/* Caching page */
|
||||
if (page_code == 0x08 || all_pages) {
|
||||
valid_page = 1;
|
||||
buf[0] = 0x08; /* Page code */
|
||||
@@ -1277,6 +1315,24 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
|
||||
buf += 12;
|
||||
}
|
||||
|
||||
/* Power Condition Page */
|
||||
if (page_code == 0x1A || all_pages) {
|
||||
valid_page = 1;
|
||||
buf[0] = 0x1A; /* Page code */
|
||||
buf[1] = 10; /* Page length */
|
||||
memset(buf+2, 0, 10); /* Disable the Standby/Idle timers */
|
||||
buf += 12;
|
||||
}
|
||||
|
||||
/* C/DVD Capabilities and Mechanical Status Page */
|
||||
if (curlun->cdrom && (page_code == 0x2A || all_pages)) {
|
||||
valid_page = 1;
|
||||
buf[0] = 0x2A; /* Page code */
|
||||
buf[1] = sizeof(capabilities) - 1; /* Page length */
|
||||
memcpy(buf+2, capabilities, buf[1]);
|
||||
buf += buf[1] + 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that a valid page was requested and the mode data length
|
||||
* isn't too long.
|
||||
@@ -1396,6 +1452,249 @@ static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int do_get_configuration(struct fsg_common *common,
|
||||
struct fsg_buffhd *bh)
|
||||
{
|
||||
struct fsg_lun *curlun = common->curlun;
|
||||
u8 *buf = (u8 *) bh->buf;
|
||||
u8 *buf0 = buf;
|
||||
int len;
|
||||
int profile;
|
||||
int rt; /* Request type */
|
||||
int starting; /* Feature code */
|
||||
|
||||
/*
|
||||
* The standard prescribes to return disabled profiles
|
||||
* MMC_PROFILE_NONE when we have no medium, but it seems
|
||||
* it is enough to make unknown_cmnd in do_scsi_command().
|
||||
*/
|
||||
if (curlun->cd_as_dvd) {
|
||||
/* Big images will be handled as DVD */
|
||||
profile = MMC_PROFILE_DVD_ROM;
|
||||
} else {
|
||||
profile = MMC_PROFILE_CD_ROM;
|
||||
}
|
||||
|
||||
/*
|
||||
* RT == 0x00 - Return all features since starting;
|
||||
* RT == 0x01 - Same but filtered by Current bit (all in our case);
|
||||
* RT == 0x02 - Return only header and zero or one supported feature;
|
||||
* RT == 0x03 - Reserved, but we'll handle it as 0x00 for paranoia;
|
||||
* ... So we have only one special case for 0x02.
|
||||
*/
|
||||
rt = common->cmnd[1] & 0x03;
|
||||
starting = get_unaligned_be16(&common->cmnd[2]);
|
||||
|
||||
memset(buf, 0, 256); /* This should be enough for our all features */
|
||||
/* Allocation Length in buf[0,1,2,3] will be calculated later */
|
||||
put_unaligned_be16(profile, &buf[6]);
|
||||
buf += 8;
|
||||
|
||||
#define NEED_REPORT(feature) \
|
||||
(rt == 0x02 ? (starting == feature) : (starting <= feature))
|
||||
|
||||
/* Profile List feature */
|
||||
if (NEED_REPORT(0)) {
|
||||
/* buf[8,9] = 0 for the feature */
|
||||
buf[2] = 0 | 0x03; /* Version = 0, Persistent|Current */
|
||||
buf[3] = 8; /* Additional length for two profiles */
|
||||
put_unaligned_be16(MMC_PROFILE_DVD_ROM, &buf[4]);
|
||||
buf[6] = (profile == MMC_PROFILE_DVD_ROM);
|
||||
put_unaligned_be16(MMC_PROFILE_CD_ROM, &buf[8]);
|
||||
buf[10] = (profile == MMC_PROFILE_CD_ROM);
|
||||
buf += 12;
|
||||
}
|
||||
|
||||
/* Core feature */
|
||||
if (NEED_REPORT(0x0001)) {
|
||||
put_unaligned_be16(0x0001, &buf[0]);
|
||||
buf[2] = 0x08 | 0x03; /* Version = 2, Persistent|Current */
|
||||
buf[3] = 8; /* Additional length */
|
||||
put_unaligned_be32(1, &buf[4]); /* Phy = SCSI Family */
|
||||
buf[8] = 0x01; /* Device Busy Class Events = 1 */
|
||||
buf += 12;
|
||||
}
|
||||
|
||||
/* Morphing feature */
|
||||
if (NEED_REPORT(0x0002)) {
|
||||
put_unaligned_be16(0x0002, &buf[0]);
|
||||
buf[2] = 0x04 | 0x03; /* Version = 1, Persistent|Current */
|
||||
buf[3] = 4; /* Additional length */
|
||||
buf += 8;
|
||||
}
|
||||
|
||||
/* Removable Medium feature */
|
||||
if (NEED_REPORT(0x0003)) {
|
||||
put_unaligned_be16(0x0003, &buf[0]);
|
||||
buf[2] = 0x08 | 0x03; /* Version = 2, Persistent|Current */
|
||||
buf[3] = 4; /* Additional length */
|
||||
buf[4] = 0x20 | 0x19; /* Tray mechanism, Load|Eject|Lock */
|
||||
buf += 8;
|
||||
}
|
||||
|
||||
/* Random Readable feature */
|
||||
if (NEED_REPORT(0x0010)) {
|
||||
put_unaligned_be16(0x0010, &buf[0]);
|
||||
buf[2] = 0 | 0x03; /* Version = 0, Persistent|Current */
|
||||
buf[3] = 8; /* Additional length */
|
||||
put_unaligned_be32(2048, &buf[4]); /* Logical Block Size */
|
||||
/* buf[8,9] = 0, no Blocking size presented */
|
||||
buf[10] = 0x01; /* RW Error Recovery Mode Page */
|
||||
buf += 12;
|
||||
}
|
||||
|
||||
/* MultiRead feature */
|
||||
if (NEED_REPORT(0x001D)) {
|
||||
put_unaligned_be16(0x001D, &buf[0]);
|
||||
buf[2] = 0 | 0x03; /* Version = 0, Persistent|Current */
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
/* CD Read feature */
|
||||
if (NEED_REPORT(0x001E)) {
|
||||
put_unaligned_be16(0x001E, &buf[0]);
|
||||
buf[2] = 0x04 | 0x03; /* Version = 1, Persistent|Current */
|
||||
buf[3] = 4; /* Additional length */
|
||||
buf[4] = 0x03; /* C2|CD-Text */
|
||||
buf += 8;
|
||||
}
|
||||
|
||||
/* DVD Read feature */
|
||||
if (NEED_REPORT(0x001F)) {
|
||||
put_unaligned_be16(0x001F, &buf[0]);
|
||||
buf[2] = 0x04 | 0x03; /* Version = 1, Persistent|Current */
|
||||
buf[3] = 4; /* Additional length */
|
||||
buf[4] = 0x01; /* MULTI110 */
|
||||
buf[6] = 0x01; /* Dual-R */
|
||||
buf += 8;
|
||||
}
|
||||
|
||||
/* Power Management feature */
|
||||
if (NEED_REPORT(0x0100)) {
|
||||
put_unaligned_be16(0x0100, &buf[0]);
|
||||
buf[2] = 0 | 0x03; /* Version = 0, Persistent|Current */
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
/* Timeout feature */
|
||||
if (NEED_REPORT(0x0105)) {
|
||||
put_unaligned_be16(0x0105,&buf[0]);
|
||||
buf[2] = 0x04 | 0x03; /* Version = 1, Persistent|Current */
|
||||
buf[3] = 4; /* Additional length */
|
||||
buf += 8;
|
||||
}
|
||||
|
||||
/* Real Time Streaming feature */
|
||||
if (NEED_REPORT(0x0107)) {
|
||||
put_unaligned_be16(0x0107, &buf[0]);
|
||||
buf[2] = 0x10 | 0x03; /* Version = 4, Persistent|Current */
|
||||
buf[3] = 4; /* Additional length */
|
||||
buf[4] = 0x0F; /* SCS|MP2A|WSPD|SW */
|
||||
buf += 8;
|
||||
}
|
||||
|
||||
#undef NEED_REPORT
|
||||
|
||||
len = buf - buf0;
|
||||
/* Put len minus the size of data length field (be32) */
|
||||
put_unaligned_be32(len - 4, &buf0[0]);
|
||||
return len;
|
||||
}
|
||||
|
||||
static int do_read_disc_information(struct fsg_common *common,
|
||||
struct fsg_buffhd *bh)
|
||||
{
|
||||
struct fsg_lun *curlun = common->curlun;
|
||||
u8 *buf = (u8 *) bh->buf;
|
||||
|
||||
/*
|
||||
* (common->cmnd[1] & 0x07) contains Data Type, but it is safe
|
||||
* to ignore it and always return Data Type = 0 in buf[2]
|
||||
* for the Standard Disc Information.
|
||||
*/
|
||||
|
||||
memset(buf, 0, 34);
|
||||
put_unaligned_be16(32, &buf[0]);
|
||||
buf[2] = 0x0E; /* Last session complete, disc finalized */
|
||||
buf[3] = 1; /* First track on disc */
|
||||
buf[4] = 1; /* Number of sessions */
|
||||
buf[5] = 1; /* First track of last session */
|
||||
buf[6] = 1; /* Last track of last session */
|
||||
buf[7] = 0x20; /* Unrestricted use */
|
||||
buf[8] = 0; /* For CD should be 0, for DVD is inapplicable */
|
||||
|
||||
if (!curlun->cd_as_dvd) {
|
||||
/*
|
||||
* For CD if the disc is complete, both should be 0xFF.
|
||||
* For DVD it's inapplicable and shall be set to 0.
|
||||
* buf[16,17,18,19] - Last Session Lead-in Start Time.
|
||||
* buf[20,21,22,23] - Last Possible Start Time
|
||||
* for Start of Lead-out.
|
||||
*/
|
||||
memset(&buf[16], 0, 8);
|
||||
}
|
||||
return 34;
|
||||
}
|
||||
|
||||
static int do_read_track_information(struct fsg_common* common,
|
||||
struct fsg_buffhd * bh)
|
||||
{
|
||||
struct fsg_lun *curlun = common->curlun;
|
||||
u8 *buf = (u8 *) bh->buf;
|
||||
u32 track;
|
||||
|
||||
track = get_unaligned_be32(&common->cmnd[2]);
|
||||
|
||||
/* We only support T_CDB */
|
||||
if ((common->cmnd[1] & 0x03) != 1 || track != 1) {
|
||||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(buf, 0, 36);
|
||||
put_unaligned_be16(34, &buf[0]);
|
||||
buf[2] = 1; /* Track 1 */
|
||||
buf[3] = 1; /* Session 1 */
|
||||
buf[5] = 0x06; /* Data track | Digital copy permitted */
|
||||
buf[6] = 0x01; /* Data mode 1 */
|
||||
put_unaligned_be32(curlun->num_sectors, &buf[24]);
|
||||
return 36;
|
||||
}
|
||||
|
||||
static int do_read_disc_structure(struct fsg_common* common,
|
||||
struct fsg_buffhd * bh)
|
||||
{
|
||||
struct fsg_lun *curlun = common->curlun;
|
||||
u8 *buf = (u8 *) bh->buf;
|
||||
|
||||
/* We only support physical format info */
|
||||
if (common->cmnd[7] != 0x00) {
|
||||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(buf, 0, 2052);
|
||||
put_unaligned_be16(2050, &buf[0]);
|
||||
buf += 4; /* Skip size and 2 reserved bytes */
|
||||
buf[0] = 0 | 0x01; /* DVD-ROM, DVD-R Part Version 1 */
|
||||
buf[1] = 0 | 0x0F; /* 120mm disc, No transfer rate limit */
|
||||
buf[2] = 0 | 0 | 0x01; /* 1 Layer, Single Layer, Read-Only */
|
||||
/* buf[3] = 0 - Linear Density = 0.267, Track Density = 0.74 */
|
||||
|
||||
/* Starting sector of main data is always 0x30000 for DVD-ROM */
|
||||
put_unaligned_be24(0x030000, &buf[5]);
|
||||
|
||||
/*
|
||||
* We can't address more than (2 ^^ 24) - 0x30000 sectors
|
||||
* i.e. 32384MB per layer, and it seems we will never reach
|
||||
* this limit. But maybe we should make a check to be sure.
|
||||
*/
|
||||
put_unaligned_be24(0x030000 + curlun->num_sectors, &buf[9]);
|
||||
|
||||
/* It is okay to keep 0 in End physical sector number of Layer 0 */
|
||||
return 2052;
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@@ -1817,6 +2116,63 @@ static int do_scsi_command(struct fsg_common *common)
|
||||
down_read(&common->filesem); /* We're using the backing file */
|
||||
switch (common->cmnd[0]) {
|
||||
|
||||
case 0x46: /* GET_CONFIGURATION */
|
||||
if (!common->curlun || !common->curlun->cdrom)
|
||||
goto unknown_cmnd;
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
0xffffffff, 1,
|
||||
"GET CONFIGURATION");
|
||||
if (reply == 0)
|
||||
reply = do_get_configuration(common, bh);
|
||||
break;
|
||||
|
||||
case 0x51: /* READ_DISC_INFORMATION */
|
||||
if (!common->curlun || !common->curlun->cdrom)
|
||||
goto unknown_cmnd;
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
0xffffffff, 1,
|
||||
"READ DISK INFORMATION");
|
||||
if (reply == 0)
|
||||
reply = do_read_disc_information(common, bh);
|
||||
break;
|
||||
|
||||
case 0x52: /* READ_TRACK_INFORMATION */
|
||||
if (!common->curlun || !common->curlun->cdrom)
|
||||
goto unknown_cmnd;
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
0xffffffff, 1,
|
||||
"READ TRACK INFORMATION");
|
||||
if (reply == 0)
|
||||
reply = do_read_track_information(common, bh);
|
||||
break;
|
||||
|
||||
case 0xAD: /* READ_DISK_STRUCTURE */
|
||||
if (!common->curlun || !common->curlun->cdrom)
|
||||
goto unknown_cmnd;
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[8]);
|
||||
reply = check_command(common, 12, DATA_DIR_TO_HOST,
|
||||
0xffffffff, 1,
|
||||
"READ DISK STRUCTURE");
|
||||
if (reply == 0)
|
||||
reply = do_read_disc_structure(common, bh);
|
||||
break;
|
||||
|
||||
case 0xBB: /* SET_CD_SPEED */
|
||||
if (!common->curlun || !common->curlun->cdrom)
|
||||
goto unknown_cmnd;
|
||||
common->data_size_from_cmnd = 0;
|
||||
reply = check_command(common, 12, DATA_DIR_NONE,
|
||||
0xffffffff, 1,
|
||||
"SET CD SPEED");
|
||||
break;
|
||||
|
||||
case INQUIRY:
|
||||
common->data_size_from_cmnd = common->cmnd[4];
|
||||
reply = check_command(common, 6, DATA_DIR_TO_HOST,
|
||||
@@ -1933,7 +2289,8 @@ 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,
|
||||
/* TODO: Why? */
|
||||
0xffffffff, 1, /* (7<<6) | (1<<1), 1, */
|
||||
"READ TOC");
|
||||
if (reply == 0)
|
||||
reply = do_read_toc(common, bh);
|
||||
|
||||
@@ -240,16 +240,7 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
}
|
||||
|
||||
num_sectors = size >> blkbits; /* File size in logic-block-size blocks */
|
||||
min_sectors = 1;
|
||||
if (curlun->cdrom) {
|
||||
min_sectors = 300; /* Smallest track is 300 frames */
|
||||
if (num_sectors >= 256*60*75) {
|
||||
num_sectors = 256*60*75 - 1;
|
||||
LINFO(curlun, "file too big: %s\n", filename);
|
||||
LINFO(curlun, "using only first %d blocks\n",
|
||||
(int) num_sectors);
|
||||
}
|
||||
}
|
||||
min_sectors = curlun->cdrom ? 300 : 1; /* Smallest track is 300 frames */
|
||||
if (num_sectors < min_sectors) {
|
||||
LINFO(curlun, "file too small: %s\n", filename);
|
||||
rc = -ETOOSMALL;
|
||||
@@ -259,6 +250,10 @@ int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
|
||||
if (fsg_lun_is_open(curlun))
|
||||
fsg_lun_close(curlun);
|
||||
|
||||
/* Too big CD-ROM images will be handled as DVD-ROM */
|
||||
curlun->cd_as_dvd = curlun->cdrom &&
|
||||
(num_sectors >= CD_MAX_MSF_SECTORS);
|
||||
|
||||
curlun->blksize = blksize;
|
||||
curlun->blkbits = blkbits;
|
||||
curlun->ro = ro;
|
||||
|
||||
@@ -85,6 +85,19 @@ do { \
|
||||
#define SS_WRITE_ERROR 0x030c02
|
||||
#define SS_WRITE_PROTECTED 0x072700
|
||||
|
||||
/* Some used profiles from MMC-3 */
|
||||
#define MMC_PROFILE_NONE 0x0000
|
||||
#define MMC_PROFILE_CD_ROM 0x0008
|
||||
#define MMC_PROFILE_DVD_ROM 0x0010
|
||||
|
||||
/*
|
||||
* Maximum number of sectors of CD with MSF addressing.
|
||||
* A bit paranoid value is calculated based on standard
|
||||
* and store_cdrom_address() implementation.
|
||||
* It is assumed that bigger images will be handled as DVD.
|
||||
*/
|
||||
#define CD_MAX_MSF_SECTORS ((255 * 59 * 74) - (2 * 75))
|
||||
|
||||
#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */
|
||||
#define ASC(x) ((u8) ((x) >> 8))
|
||||
#define ASCQ(x) ((u8) (x))
|
||||
@@ -104,6 +117,7 @@ struct fsg_lun {
|
||||
unsigned int ro:1;
|
||||
unsigned int removable:1;
|
||||
unsigned int cdrom:1;
|
||||
unsigned int cd_as_dvd:1; /* Handle big CD as DVD if cdrom == 1 */
|
||||
unsigned int prevent_medium_removal:1;
|
||||
unsigned int registered:1;
|
||||
unsigned int info_valid:1;
|
||||
|
||||
Reference in New Issue
Block a user