Skip to content

Commit dfc0962

Browse files
miloukxxmustafacooTR
authored andcommitted
usb: Add Drivedroid Support
1 parent bbe060d commit dfc0962

File tree

2 files changed

+237
-1
lines changed

2 files changed

+237
-1
lines changed

drivers/usb/gadget/function/f_mass_storage.c

+236-1
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@
227227

228228
/*------------------------------------------------------------------------*/
229229

230+
#define PAGE_CACHE_SIZE PAGE_SIZE
230231
#define FSG_DRIVER_DESC "mass_storage"
231232
#define FSG_DRIVER_VERSION "2009/09/11"
232233

@@ -1215,19 +1216,240 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
12151216
return 8;
12161217
}
12171218

1219+
static void _lba_to_msf(u8 *buf, int lba)
1220+
{
1221+
lba += 150;
1222+
buf[0] = (lba / 75) / 60;
1223+
buf[1] = (lba / 75) % 60;
1224+
buf[2] = lba % 75;
1225+
}
1226+
1227+
static int _read_toc_raw(struct fsg_common *common,
1228+
struct fsg_buffhd *bh)
1229+
{
1230+
struct fsg_lun *curlun = common->curlun;
1231+
u8 *buf = (u8 *) bh->buf;
1232+
u8 *q;
1233+
int len;
1234+
int msf = common->cmnd[1] & 0x02;
1235+
q = buf + 2;
1236+
*q++ = 1; /* first session */
1237+
*q++ = 1; /* last session */
1238+
*q++ = 1; /* session number */
1239+
*q++ = 0x14; /* data track */
1240+
*q++ = 0; /* track number */
1241+
*q++ = 0xa0; /* lead-in */
1242+
*q++ = 0; /* min */
1243+
*q++ = 0; /* sec */
1244+
*q++ = 0; /* frame */
1245+
*q++ = 0;
1246+
*q++ = 1; /* first track */
1247+
*q++ = 0x00; /* disk type */
1248+
*q++ = 0x00;
1249+
*q++ = 1; /* session number */
1250+
*q++ = 0x14; /* data track */
1251+
*q++ = 0; /* track number */
1252+
*q++ = 0xa1;
1253+
*q++ = 0; /* min */
1254+
*q++ = 0; /* sec */
1255+
*q++ = 0; /* frame */
1256+
*q++ = 0;
1257+
*q++ = 1; /* last track */
1258+
*q++ = 0x00;
1259+
*q++ = 0x00;
1260+
*q++ = 1; /* session number */
1261+
*q++ = 0x14; /* data track */
1262+
*q++ = 0; /* track number */
1263+
*q++ = 0xa2; /* lead-out */
1264+
*q++ = 0; /* min */
1265+
*q++ = 0; /* sec */
1266+
*q++ = 0; /* frame */
1267+
if (msf) {
1268+
*q++ = 0; /* reserved */
1269+
_lba_to_msf(q, curlun->num_sectors);
1270+
q += 3;
1271+
} else {
1272+
put_unaligned_be32(curlun->num_sectors, q);
1273+
q += 4;
1274+
}
1275+
*q++ = 1; /* session number */
1276+
*q++ = 0x14; /* ADR, control */
1277+
*q++ = 0; /* track number */
1278+
*q++ = 1; /* point */
1279+
*q++ = 0; /* min */
1280+
*q++ = 0; /* sec */
1281+
*q++ = 0; /* frame */
1282+
if (msf) {
1283+
*q++ = 0;
1284+
_lba_to_msf(q, 0);
1285+
q += 3;
1286+
} else {
1287+
*q++ = 0;
1288+
*q++ = 0;
1289+
*q++ = 0;
1290+
*q++ = 0;
1291+
}
1292+
len = q - buf;
1293+
put_unaligned_be16(len - 2, buf);
1294+
return len;
1295+
}
1296+
1297+
static void cd_data_to_raw(u8 *buf, int lba)
1298+
{
1299+
/* sync bytes */
1300+
buf[0] = 0x00;
1301+
memset(buf + 1, 0xff, 10);
1302+
buf[11] = 0x00;
1303+
buf += 12;
1304+
/* MSF */
1305+
_lba_to_msf(buf, lba);
1306+
buf[3] = 0x01; /* mode 1 data */
1307+
buf += 4;
1308+
/* data */
1309+
buf += 2048;
1310+
/* XXX: ECC not computed */
1311+
memset(buf, 0, 288);
1312+
}
1313+
1314+
static int do_read_cd(struct fsg_common *common)
1315+
{
1316+
struct fsg_lun *curlun = common->curlun;
1317+
struct fsg_buffhd *bh;
1318+
int rc;
1319+
u32 lba;
1320+
u32 amount_left;
1321+
u32 nb_sectors, transfer_request;
1322+
loff_t file_offset, file_offset_tmp;
1323+
unsigned int amount;
1324+
unsigned int partial_page;
1325+
ssize_t nread;
1326+
nb_sectors = (common->cmnd[6] << 16) |
1327+
(common->cmnd[7] << 8) | common->cmnd[8];
1328+
lba = get_unaligned_be32(&common->cmnd[2]);
1329+
if (nb_sectors == 0)
1330+
return 0;
1331+
if (lba >= curlun->num_sectors) {
1332+
curlun->sense_data =
1333+
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1334+
return -EINVAL;
1335+
}
1336+
transfer_request = common->cmnd[9];
1337+
if ((transfer_request & 0xf8) == 0xf8) {
1338+
file_offset = ((loff_t) lba) << 11;
1339+
/* read all data - 2352 byte */
1340+
amount_left = 2352;
1341+
} else {
1342+
file_offset = ((loff_t) lba) << 9;
1343+
/* Carry out the file reads */
1344+
amount_left = common->data_size_from_cmnd;
1345+
}
1346+
if (unlikely(amount_left == 0))
1347+
return -EIO; /* No default reply */
1348+
for (;;) {
1349+
/*
1350+
* Figure out how much we need to read:
1351+
* Try to read the remaining amount.
1352+
* But don't read more than the buffer size.
1353+
* And don't try to read past the end of the file.
1354+
* Finally, if we're not at a page boundary, don't read past
1355+
* the next page.
1356+
* If this means reading 0 then we were asked to read past
1357+
* the end of file.
1358+
*/
1359+
amount = min(amount_left, FSG_BUFLEN);
1360+
amount = min((loff_t) amount,
1361+
curlun->file_length - file_offset);
1362+
partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
1363+
if (partial_page > 0)
1364+
amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
1365+
partial_page);
1366+
/* Wait for the next buffer to become available */
1367+
bh = common->next_buffhd_to_fill;
1368+
while (bh->state != BUF_STATE_EMPTY) {
1369+
rc = sleep_thread(common, true);
1370+
if (rc)
1371+
return rc;
1372+
}
1373+
/*
1374+
* If we were asked to read past the end of file,
1375+
* end with an empty buffer.
1376+
*/
1377+
if (amount == 0) {
1378+
curlun->sense_data =
1379+
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
1380+
curlun->sense_data_info = file_offset >> 9;
1381+
curlun->info_valid = 1;
1382+
bh->inreq->length = 0;
1383+
bh->state = BUF_STATE_FULL;
1384+
break;
1385+
}
1386+
/* Perform the read */
1387+
file_offset_tmp = file_offset;
1388+
if ((transfer_request & 0xf8) == 0xf8) {
1389+
nread = vfs_read(curlun->filp,
1390+
((char __user *)bh->buf)+16,
1391+
amount, &file_offset_tmp);
1392+
} else {
1393+
nread = vfs_read(curlun->filp,
1394+
(char __user *)bh->buf,
1395+
amount, &file_offset_tmp);
1396+
}
1397+
VLDBG(curlun, "file read %u @ %llu -> %d\n", amount,
1398+
(unsigned long long) file_offset,
1399+
(int) nread);
1400+
if (signal_pending(current))
1401+
return -EINTR;
1402+
if (nread < 0) {
1403+
LDBG(curlun, "error in file read: %d\n",
1404+
(int) nread);
1405+
nread = 0;
1406+
} else if (nread < amount) {
1407+
LDBG(curlun, "partial file read: %d/%u\n",
1408+
(int) nread, amount);
1409+
nread -= (nread & 511); /* Round down to a block */
1410+
}
1411+
file_offset += nread;
1412+
amount_left -= nread;
1413+
common->residue -= nread;
1414+
bh->inreq->length = nread;
1415+
bh->state = BUF_STATE_FULL;
1416+
/* If an error occurred, report it and its position */
1417+
if (nread < amount) {
1418+
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
1419+
curlun->sense_data_info = file_offset >> 9;
1420+
curlun->info_valid = 1;
1421+
break;
1422+
}
1423+
if (amount_left == 0)
1424+
break; /* No more left to read */
1425+
/* Send this buffer and go read some more */
1426+
if (!start_in_transfer(common, bh))
1427+
return -EIO;
1428+
common->next_buffhd_to_fill = bh->next;
1429+
}
1430+
if ((transfer_request & 0xf8) == 0xf8)
1431+
cd_data_to_raw(bh->buf, lba);
1432+
return -EIO; /* No default reply */
1433+
}
1434+
12181435
static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
12191436
{
12201437
struct fsg_lun *curlun = common->curlun;
12211438
int msf = common->cmnd[1] & 0x02;
12221439
int start_track = common->cmnd[6];
12231440
u8 *buf = (u8 *)bh->buf;
12241441

1442+
int format = (common->cmnd[9] & 0xC0) >> 6;
1443+
12251444
if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
12261445
start_track > 1) {
12271446
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
12281447
return -EINVAL;
12291448
}
12301449

1450+
if (format == 2)
1451+
return _read_toc_raw(common, bh);
1452+
12311453
memset(buf, 0, 20);
12321454
buf[1] = (20-2); /* TOC data length */
12331455
buf[2] = 1; /* First track number */
@@ -1974,12 +2196,23 @@ static int do_scsi_command(struct fsg_common *common)
19742196
common->data_size_from_cmnd =
19752197
get_unaligned_be16(&common->cmnd[7]);
19762198
reply = check_command(common, 10, DATA_DIR_TO_HOST,
1977-
(7<<6) | (1<<1), 1,
2199+
(0xf<<6) | (1<<1), 1,
19782200
"READ TOC");
19792201
if (reply == 0)
19802202
reply = do_read_toc(common, bh);
19812203
break;
19822204

2205+
case READ_CD:
2206+
common->data_size_from_cmnd = ((common->cmnd[6] << 16)
2207+
| (common->cmnd[7] << 8)
2208+
| (common->cmnd[8])) << 9;
2209+
reply = check_command(common, 12, DATA_DIR_TO_HOST,
2210+
(0xf<<2) | (7<<7), 1,
2211+
"READ CD");
2212+
if (reply == 0)
2213+
reply = do_read_cd(common);
2214+
break;
2215+
19832216
case READ_FORMAT_CAPACITIES:
19842217
common->data_size_from_cmnd =
19852218
get_unaligned_be16(&common->cmnd[7]);
@@ -3278,6 +3511,8 @@ static struct config_group *fsg_lun_make(struct config_group *group,
32783511

32793512
memset(&config, 0, sizeof(config));
32803513
config.removable = true;
3514+
config.cdrom = true;
3515+
config.ro = true;
32813516

32823517
ret = fsg_common_create_lun(fsg_opts->common, &config, num, name,
32833518
(const char **)&group->cg_item.ci_name);

include/scsi/scsi_proto.h

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#define WRITE_SAME 0x41
7272
#define UNMAP 0x42
7373
#define READ_TOC 0x43
74+
#define READ_CD 0xbe
7475
#define READ_HEADER 0x44
7576
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
7677
#define LOG_SELECT 0x4c

0 commit comments

Comments
 (0)