Commit 38cdea7ccf34ad81a9129b46db914ca3291ad193
1 parent
609497ab
Multi-profile DVD-ROM support (Carlo Marcelo Arenas Belon).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3910 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
112 additions
and
15 deletions
hw/ide.c
| 1 | /* | 1 | /* |
| 2 | - * QEMU IDE disk and CD-ROM Emulator | 2 | + * QEMU IDE disk and CD/DVD-ROM Emulator |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2003 Fabrice Bellard | 4 | * Copyright (c) 2003 Fabrice Bellard |
| 5 | * Copyright (c) 2006 Openedhand Ltd. | 5 | * Copyright (c) 2006 Openedhand Ltd. |
| @@ -284,6 +284,58 @@ | @@ -284,6 +284,58 @@ | ||
| 284 | * of MODE_SENSE_POWER_PAGE */ | 284 | * of MODE_SENSE_POWER_PAGE */ |
| 285 | #define GPMODE_CDROM_PAGE 0x0d | 285 | #define GPMODE_CDROM_PAGE 0x0d |
| 286 | 286 | ||
| 287 | +/* | ||
| 288 | + * Based on values from <linux/cdrom.h> but extending CD_MINS | ||
| 289 | + * to the maximum common size allowed by the Orange's Book ATIP | ||
| 290 | + * | ||
| 291 | + * 90 and 99 min CDs are also available but using them as the | ||
| 292 | + * upper limit reduces the effectiveness of the heuristic to | ||
| 293 | + * detect DVDs burned to less than 25% of their maximum capacity | ||
| 294 | + */ | ||
| 295 | + | ||
| 296 | +/* Some generally useful CD-ROM information */ | ||
| 297 | +#define CD_MINS 80 /* max. minutes per CD */ | ||
| 298 | +#define CD_SECS 60 /* seconds per minute */ | ||
| 299 | +#define CD_FRAMES 75 /* frames per second */ | ||
| 300 | +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ | ||
| 301 | +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) | ||
| 302 | +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) | ||
| 303 | + | ||
| 304 | +/* | ||
| 305 | + * The MMC values are not IDE specific and might need to be moved | ||
| 306 | + * to a common header if they are also needed for the SCSI emulation | ||
| 307 | + */ | ||
| 308 | + | ||
| 309 | +/* Profile list from MMC-6 revision 1 table 91 */ | ||
| 310 | +#define MMC_PROFILE_NONE 0x0000 | ||
| 311 | +#define MMC_PROFILE_CD_ROM 0x0008 | ||
| 312 | +#define MMC_PROFILE_CD_R 0x0009 | ||
| 313 | +#define MMC_PROFILE_CD_RW 0x000A | ||
| 314 | +#define MMC_PROFILE_DVD_ROM 0x0010 | ||
| 315 | +#define MMC_PROFILE_DVD_R_SR 0x0011 | ||
| 316 | +#define MMC_PROFILE_DVD_RAM 0x0012 | ||
| 317 | +#define MMC_PROFILE_DVD_RW_RO 0x0013 | ||
| 318 | +#define MMC_PROFILE_DVD_RW_SR 0x0014 | ||
| 319 | +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 | ||
| 320 | +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 | ||
| 321 | +#define MMC_PROFILE_DVD_RW_DL 0x0017 | ||
| 322 | +#define MMC_PROFILE_DVD_DDR 0x0018 | ||
| 323 | +#define MMC_PROFILE_DVD_PLUS_RW 0x001A | ||
| 324 | +#define MMC_PROFILE_DVD_PLUS_R 0x001B | ||
| 325 | +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A | ||
| 326 | +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B | ||
| 327 | +#define MMC_PROFILE_BD_ROM 0x0040 | ||
| 328 | +#define MMC_PROFILE_BD_R_SRM 0x0041 | ||
| 329 | +#define MMC_PROFILE_BD_R_RRM 0x0042 | ||
| 330 | +#define MMC_PROFILE_BD_RE 0x0043 | ||
| 331 | +#define MMC_PROFILE_HDDVD_ROM 0x0050 | ||
| 332 | +#define MMC_PROFILE_HDDVD_R 0x0051 | ||
| 333 | +#define MMC_PROFILE_HDDVD_RAM 0x0052 | ||
| 334 | +#define MMC_PROFILE_HDDVD_RW 0x0053 | ||
| 335 | +#define MMC_PROFILE_HDDVD_R_DL 0x0058 | ||
| 336 | +#define MMC_PROFILE_HDDVD_RW_DL 0x005A | ||
| 337 | +#define MMC_PROFILE_INVALID 0xFFFF | ||
| 338 | + | ||
| 287 | #define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ | 339 | #define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ |
| 288 | #define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ | 340 | #define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ |
| 289 | #define ATAPI_INT_REASON_REL 0x04 | 341 | #define ATAPI_INT_REASON_REL 0x04 |
| @@ -540,7 +592,7 @@ static void ide_atapi_identify(IDEState *s) | @@ -540,7 +592,7 @@ static void ide_atapi_identify(IDEState *s) | ||
| 540 | put_le16(p + 21, 512); /* cache size in sectors */ | 592 | put_le16(p + 21, 512); /* cache size in sectors */ |
| 541 | put_le16(p + 22, 4); /* ecc bytes */ | 593 | put_le16(p + 22, 4); /* ecc bytes */ |
| 542 | padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ | 594 | padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */ |
| 543 | - padstr((char *)(p + 27), "QEMU CD-ROM", 40); /* model */ | 595 | + padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */ |
| 544 | put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ | 596 | put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ |
| 545 | #ifdef USE_DMA_CDROM | 597 | #ifdef USE_DMA_CDROM |
| 546 | put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ | 598 | put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */ |
| @@ -1290,6 +1342,22 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, | @@ -1290,6 +1342,22 @@ static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, | ||
| 1290 | } | 1342 | } |
| 1291 | } | 1343 | } |
| 1292 | 1344 | ||
| 1345 | +static inline uint8_t ide_atapi_set_profile(uint8_t *buf, uint8_t *index, | ||
| 1346 | + uint16_t profile) | ||
| 1347 | +{ | ||
| 1348 | + uint8_t *buf_profile = buf + 12; /* start of profiles */ | ||
| 1349 | + | ||
| 1350 | + buf_profile += ((*index) * 4); /* start of indexed profile */ | ||
| 1351 | + cpu_to_ube16 (buf_profile, profile); | ||
| 1352 | + buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); | ||
| 1353 | + | ||
| 1354 | + /* each profile adds 4 bytes to the response */ | ||
| 1355 | + (*index)++; | ||
| 1356 | + buf[11] += 4; /* Additional Length */ | ||
| 1357 | + | ||
| 1358 | + return 4; | ||
| 1359 | +} | ||
| 1360 | + | ||
| 1293 | static void ide_atapi_cmd(IDEState *s) | 1361 | static void ide_atapi_cmd(IDEState *s) |
| 1294 | { | 1362 | { |
| 1295 | const uint8_t *packet; | 1363 | const uint8_t *packet; |
| @@ -1634,13 +1702,13 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1634,13 +1702,13 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1634 | buf[6] = 0; /* reserved */ | 1702 | buf[6] = 0; /* reserved */ |
| 1635 | buf[7] = 0; /* reserved */ | 1703 | buf[7] = 0; /* reserved */ |
| 1636 | padstr8(buf + 8, 8, "QEMU"); | 1704 | padstr8(buf + 8, 8, "QEMU"); |
| 1637 | - padstr8(buf + 16, 16, "QEMU CD-ROM"); | 1705 | + padstr8(buf + 16, 16, "QEMU DVD-ROM"); |
| 1638 | padstr8(buf + 32, 4, QEMU_VERSION); | 1706 | padstr8(buf + 32, 4, QEMU_VERSION); |
| 1639 | ide_atapi_cmd_reply(s, 36, max_len); | 1707 | ide_atapi_cmd_reply(s, 36, max_len); |
| 1640 | break; | 1708 | break; |
| 1641 | case GPCMD_GET_CONFIGURATION: | 1709 | case GPCMD_GET_CONFIGURATION: |
| 1642 | { | 1710 | { |
| 1643 | - uint64_t total_sectors; | 1711 | + uint32_t len; |
| 1644 | 1712 | ||
| 1645 | /* only feature 0 is supported */ | 1713 | /* only feature 0 is supported */ |
| 1646 | if (packet[2] != 0 || packet[3] != 0) { | 1714 | if (packet[2] != 0 || packet[3] != 0) { |
| @@ -1648,17 +1716,46 @@ static void ide_atapi_cmd(IDEState *s) | @@ -1648,17 +1716,46 @@ static void ide_atapi_cmd(IDEState *s) | ||
| 1648 | ASC_INV_FIELD_IN_CMD_PACKET); | 1716 | ASC_INV_FIELD_IN_CMD_PACKET); |
| 1649 | break; | 1717 | break; |
| 1650 | } | 1718 | } |
| 1651 | - memset(buf, 0, 32); | ||
| 1652 | - bdrv_get_geometry(s->bs, &total_sectors); | ||
| 1653 | - buf[3] = 16; | ||
| 1654 | - buf[7] = total_sectors <= 1433600 ? 0x08 : 0x10; /* current profile */ | ||
| 1655 | - buf[10] = 0x10 | 0x1; | ||
| 1656 | - buf[11] = 0x08; /* size of profile list */ | ||
| 1657 | - buf[13] = 0x10; /* DVD-ROM profile */ | ||
| 1658 | - buf[14] = buf[7] == 0x10; /* (in)active */ | ||
| 1659 | - buf[17] = 0x08; /* CD-ROM profile */ | ||
| 1660 | - buf[18] = buf[7] == 0x08; /* (in)active */ | ||
| 1661 | - ide_atapi_cmd_reply(s, 32, 32); | 1719 | + |
| 1720 | + /* XXX: could result in alignment problems in some architectures */ | ||
| 1721 | + max_len = ube16_to_cpu(packet + 7); | ||
| 1722 | + /* | ||
| 1723 | + * XXX: avoid overflow for io_buffer if max_len is bigger than the | ||
| 1724 | + * size of that buffer (dimensioned to max number of sectors | ||
| 1725 | + * to transfer at once) | ||
| 1726 | + * | ||
| 1727 | + * Only a problem if the feature/profiles grow exponentially. | ||
| 1728 | + */ | ||
| 1729 | + if (max_len > 512) /* XXX: assume 1 sector */ | ||
| 1730 | + max_len = 512; | ||
| 1731 | + | ||
| 1732 | + memset(buf, 0, max_len); | ||
| 1733 | + /* | ||
| 1734 | + * the number of sectors from the media tells us which profile | ||
| 1735 | + * to use as current. 0 means there is no media | ||
| 1736 | + * | ||
| 1737 | + * XXX: fails to detect correctly DVDs with less data burned | ||
| 1738 | + * than what a CD can hold | ||
| 1739 | + */ | ||
| 1740 | + if ((s -> nb_sectors)) { | ||
| 1741 | + if ((s -> nb_sectors > CD_MAX_SECTORS)) | ||
| 1742 | + cpu_to_ube16(buf + 6, MMC_PROFILE_DVD_ROM); | ||
| 1743 | + else | ||
| 1744 | + cpu_to_ube16(buf + 6, MMC_PROFILE_CD_ROM); | ||
| 1745 | + } | ||
| 1746 | + | ||
| 1747 | + len = 8; /* header completed */ | ||
| 1748 | + if (max_len > len) { | ||
| 1749 | + uint8_t index = 0; | ||
| 1750 | + | ||
| 1751 | + buf[10] = 0x02 | 0x01; /* persistent and current */ | ||
| 1752 | + len += 4; /* header */ | ||
| 1753 | + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_DVD_ROM); | ||
| 1754 | + len += ide_atapi_set_profile(buf, &index, MMC_PROFILE_CD_ROM); | ||
| 1755 | + } | ||
| 1756 | + cpu_to_ube32(buf, len - 4); /* data length */ | ||
| 1757 | + | ||
| 1758 | + ide_atapi_cmd_reply(s, len, max_len); | ||
| 1662 | break; | 1759 | break; |
| 1663 | } | 1760 | } |
| 1664 | default: | 1761 | default: |