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 | 4 | * Copyright (c) 2003 Fabrice Bellard |
5 | 5 | * Copyright (c) 2006 Openedhand Ltd. |
... | ... | @@ -284,6 +284,58 @@ |
284 | 284 | * of MODE_SENSE_POWER_PAGE */ |
285 | 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 | 339 | #define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ |
288 | 340 | #define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ |
289 | 341 | #define ATAPI_INT_REASON_REL 0x04 |
... | ... | @@ -540,7 +592,7 @@ static void ide_atapi_identify(IDEState *s) |
540 | 592 | put_le16(p + 21, 512); /* cache size in sectors */ |
541 | 593 | put_le16(p + 22, 4); /* ecc bytes */ |
542 | 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 | 596 | put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */ |
545 | 597 | #ifdef USE_DMA_CDROM |
546 | 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 | 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 | 1361 | static void ide_atapi_cmd(IDEState *s) |
1294 | 1362 | { |
1295 | 1363 | const uint8_t *packet; |
... | ... | @@ -1634,13 +1702,13 @@ static void ide_atapi_cmd(IDEState *s) |
1634 | 1702 | buf[6] = 0; /* reserved */ |
1635 | 1703 | buf[7] = 0; /* reserved */ |
1636 | 1704 | padstr8(buf + 8, 8, "QEMU"); |
1637 | - padstr8(buf + 16, 16, "QEMU CD-ROM"); | |
1705 | + padstr8(buf + 16, 16, "QEMU DVD-ROM"); | |
1638 | 1706 | padstr8(buf + 32, 4, QEMU_VERSION); |
1639 | 1707 | ide_atapi_cmd_reply(s, 36, max_len); |
1640 | 1708 | break; |
1641 | 1709 | case GPCMD_GET_CONFIGURATION: |
1642 | 1710 | { |
1643 | - uint64_t total_sectors; | |
1711 | + uint32_t len; | |
1644 | 1712 | |
1645 | 1713 | /* only feature 0 is supported */ |
1646 | 1714 | if (packet[2] != 0 || packet[3] != 0) { |
... | ... | @@ -1648,17 +1716,46 @@ static void ide_atapi_cmd(IDEState *s) |
1648 | 1716 | ASC_INV_FIELD_IN_CMD_PACKET); |
1649 | 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 | 1759 | break; |
1663 | 1760 | } |
1664 | 1761 | default: | ... | ... |