|
227 | 227 |
|
228 | 228 | /*------------------------------------------------------------------------*/
|
229 | 229 |
|
| 230 | +#define PAGE_CACHE_SIZE PAGE_SIZE |
230 | 231 | #define FSG_DRIVER_DESC "mass_storage"
|
231 | 232 | #define FSG_DRIVER_VERSION "2009/09/11"
|
232 | 233 |
|
@@ -1215,19 +1216,240 @@ static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh)
|
1215 | 1216 | return 8;
|
1216 | 1217 | }
|
1217 | 1218 |
|
| 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 | + |
1218 | 1435 | static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh)
|
1219 | 1436 | {
|
1220 | 1437 | struct fsg_lun *curlun = common->curlun;
|
1221 | 1438 | int msf = common->cmnd[1] & 0x02;
|
1222 | 1439 | int start_track = common->cmnd[6];
|
1223 | 1440 | u8 *buf = (u8 *)bh->buf;
|
1224 | 1441 |
|
| 1442 | + int format = (common->cmnd[9] & 0xC0) >> 6; |
| 1443 | + |
1225 | 1444 | if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */
|
1226 | 1445 | start_track > 1) {
|
1227 | 1446 | curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
1228 | 1447 | return -EINVAL;
|
1229 | 1448 | }
|
1230 | 1449 |
|
| 1450 | + if (format == 2) |
| 1451 | + return _read_toc_raw(common, bh); |
| 1452 | + |
1231 | 1453 | memset(buf, 0, 20);
|
1232 | 1454 | buf[1] = (20-2); /* TOC data length */
|
1233 | 1455 | buf[2] = 1; /* First track number */
|
@@ -1974,12 +2196,23 @@ static int do_scsi_command(struct fsg_common *common)
|
1974 | 2196 | common->data_size_from_cmnd =
|
1975 | 2197 | get_unaligned_be16(&common->cmnd[7]);
|
1976 | 2198 | reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
1977 |
| - (7<<6) | (1<<1), 1, |
| 2199 | + (0xf<<6) | (1<<1), 1, |
1978 | 2200 | "READ TOC");
|
1979 | 2201 | if (reply == 0)
|
1980 | 2202 | reply = do_read_toc(common, bh);
|
1981 | 2203 | break;
|
1982 | 2204 |
|
| 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 | + |
1983 | 2216 | case READ_FORMAT_CAPACITIES:
|
1984 | 2217 | common->data_size_from_cmnd =
|
1985 | 2218 | get_unaligned_be16(&common->cmnd[7]);
|
@@ -3278,6 +3511,8 @@ static struct config_group *fsg_lun_make(struct config_group *group,
|
3278 | 3511 |
|
3279 | 3512 | memset(&config, 0, sizeof(config));
|
3280 | 3513 | config.removable = true;
|
| 3514 | + config.cdrom = true; |
| 3515 | + config.ro = true; |
3281 | 3516 |
|
3282 | 3517 | ret = fsg_common_create_lun(fsg_opts->common, &config, num, name,
|
3283 | 3518 | (const char **)&group->cg_item.ci_name);
|
|
0 commit comments