qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [patch] TOC support for raw cdrom block devices
@ 2006-10-23 19:30 Josh Elsasser
  0 siblings, 0 replies; 4+ messages in thread
From: Josh Elsasser @ 2006-10-23 19:30 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 714 bytes --]

The current raw block drvice code fakes a TOC with one track covering
the entire disc.  With this patch it attempts to read the TOC from a
cdrom device and make that information available to the ide driver
when the guest issues an ATAPI READ TOC/PMA/ATIP type 0 (read TOC)
command.

There is only support for reading the TOC on the BSDs, MacOS X, and
Linux, Win32 and other OSes will still fake one large data track.  All
tracks are reported as data, no attempt was made to support audio
tracks.  The ATAPI READ TOC/PMA/ATIP type 2 (read full TOC) command is
unchanged, I did not have a way of testing it.

The purpose of this patch, in case anyone was wondering, was to get
the BeOS R5 CD booting in qemu.

 -jre

[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [Qemu-devel] [patch] TOC support for raw cdrom block devices
@ 2006-10-24 21:25 Josh Elsasser
  2006-10-25 11:47 ` Pascal Terjan
  0 siblings, 1 reply; 4+ messages in thread
From: Josh Elsasser @ 2006-10-24 21:25 UTC (permalink / raw)
  To: qemu-devel


[-- Attachment #1.1: Type: text/plain, Size: 714 bytes --]

The current raw block drvice code fakes a TOC with one track covering
the entire disc.  With this patch it attempts to read the TOC from a
cdrom device and make that information available to the ide driver
when the guest issues an ATAPI READ TOC/PMA/ATIP type 0 (read TOC)
command.

There is only support for reading the TOC on the BSDs, MacOS X, and
Linux, Win32 and other OSes will still fake one large data track.  All
tracks are reported as data, no attempt was made to support audio
tracks.  The ATAPI READ TOC/PMA/ATIP type 2 (read full TOC) command is
unchanged, I did not have a way of testing it.

The purpose of this patch, in case anyone was wondering, was to get
the BeOS R5 CD booting in qemu.

 -jre

[-- Attachment #1.2: multitrack2.diff --]
[-- Type: text/plain, Size: 10468 bytes --]

Index: block-raw.c
===================================================================
RCS file: /sources/qemu/qemu/block-raw.c,v
retrieving revision 1.10
diff -u -r1.10 block-raw.c
--- block-raw.c	3 Sep 2006 12:08:37 -0000	1.10
+++ block-raw.c	18 Oct 2006 23:17:33 -0000
@@ -39,6 +39,7 @@
 #include <IOKit/storage/IOMediaBSDClient.h>
 #include <IOKit/storage/IOMedia.h>
 #include <IOKit/storage/IOCDMedia.h>
+#include <IOKit/storage/IOCDMediaBSDClient.h>
 //#include <IOKit/storage/IOCDTypes.h>
 #include <CoreFoundation/CoreFoundation.h>
 #endif
@@ -51,6 +52,10 @@
 #include <linux/cdrom.h>
 #include <linux/fd.h>
 #endif
+#if defined(_BSD) && !defined(CONFIG_COCOA)
+#include <sys/cdio.h>
+#include <arpa/inet.h>
+#endif
 
 //#define DEBUG_FLOPPY
 
@@ -675,6 +680,114 @@
 }
 #endif
 
+static void raw_gettracks(BlockDriverState *bs, int *start, int *end)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+#ifdef CDROMREADTOCHDR
+    struct cdrom_tochdr hdr;
+#endif
+#ifdef CDIOREADTOCHEADER
+    struct ioc_toc_header hdr;
+#endif
+#ifdef DKIOCCDREADTOC
+    dk_cd_read_toc_t hdr;
+    uint8_t buf[4];
+#endif
+    int ret;
+
+    *start = -1;
+    *end = -1;
+    ret = fd_open(bs);
+    if (ret < 0)
+        return;
+
+#if defined(CDROMREADTOCHDR)
+    if (!ioctl(fd, CDROMREADTOCHDR, &hdr)) {
+        *start = hdr.cdth_trk0;
+        *end = hdr.cdth_trk1;
+    }
+#endif
+#ifdef CDIOREADTOCHEADER
+    if (!ioctl(fd, CDIOREADTOCHEADER, &hdr)) {
+        *start = hdr.starting_track;
+        *end = hdr.ending_track;
+    }
+#endif
+#if defined(DKIOCCDREADTOC)
+    memset(&hdr, 0, sizeof(hdr));
+    hdr.bufferLength = sizeof(buf);
+    hdr.buffer = &buf;
+    if (!ioctl(fd, DKIOCCDREADTOC, &hdr) && sizeof(buf) == hdr.bufferLength) {
+        /* buf is the same format as an ATAPI READ TOC/PMA/ATIP response */
+        *start = buf[2];
+        *end = buf[3];
+    }
+#endif
+
+    return;
+}
+
+static int64_t raw_gettrackoff(BlockDriverState *bs, int track)
+{
+    BDRVRawState *s = bs->opaque;
+    int fd = s->fd;
+    int64_t off;
+#if defined(CDIOREADTOCENTRY)
+    struct ioc_read_toc_single_entry entry;
+#elif defined(CDIOREADTOCENTRIES)
+    struct ioc_read_toc_entry entry;
+    struct cd_toc_entry buf;
+#elif defined(CDROMREADTOCENTRY)
+    struct cdrom_tocentry entry;
+#elif defined(DKIOCCDREADTOC)
+    dk_cd_read_toc_t hdr;
+    uint8_t buf[804];
+    int skip, max;
+#endif
+    int ret;
+
+    off = -1;
+    ret = fd_open(bs);
+    if (ret < 0)
+        return off;
+
+#if defined(CDIOREADTOCENTRY)
+    entry.address_format = CD_LBA_FORMAT;
+    entry.track = track;
+    if (!ioctl(fd, CDIOREADTOCENTRY, &entry))
+        off = ntohl(entry.entry.addr.lba);
+#elif defined(CDIOREADTOCENTRIES)
+    entry.address_format = CD_LBA_FORMAT;
+    entry.starting_track = track;
+    entry.data_len = sizeof(buf);
+    entry.data = &buf;
+    if (!ioctl(fd, CDIOREADTOCENTRIES, &entry))
+        off = buf.addr.lba;
+#elif defined(CDROMREADTOCENTRY)
+    entry.cdte_track = track;
+    entry.cdte_format = CDROM_LBA;
+    if (!ioctl(fd, CDROMREADTOCENTRY, &entry))
+        off = entry.cdte_addr.lba;
+#elif defined(DKIOCCDREADTOC)
+    memset(&hdr, 0, sizeof(hdr));
+    hdr.address.track = track;
+    hdr.bufferLength = sizeof(buf);
+    hdr.buffer = &buf;
+    if (!ioctl(fd, DKIOCCDREADTOC, &hdr) && 4 <= hdr.bufferLength) {
+        /* buf is the same format as an ATAPI READ TOC/PMA/ATIP response */
+        max = OSReadBigInt16(buf, 0) + 2;
+        if (sizeof(buf) < max)
+            max = sizeof(buf);
+        for (skip = 4; 0 > off && skip + 8 <= max; skip += 8)
+            if(track == buf[skip + 2])
+                off = OSReadBigInt32(buf, skip + 4);
+    }
+#endif
+
+    return off;
+}
+
 #if defined(__linux__)
 
 static int raw_is_inserted(BlockDriverState *bs)
@@ -818,6 +931,8 @@
     .bdrv_pread = raw_pread,
     .bdrv_pwrite = raw_pwrite,
     .bdrv_getlength = raw_getlength,
+    .bdrv_gettracks = raw_gettracks,
+    .bdrv_gettrackoff = raw_gettrackoff,
 
     /* removable device support */
     .bdrv_is_inserted = raw_is_inserted,
Index: block.c
===================================================================
RCS file: /sources/qemu/qemu/block.c,v
retrieving revision 1.37
diff -u -r1.37 block.c
--- block.c	24 Aug 2006 19:53:37 -0000	1.37
+++ block.c	18 Oct 2006 23:17:34 -0000
@@ -705,6 +705,38 @@
     *nb_sectors_ptr = length;
 }
 
+void bdrv_get_track_count(BlockDriverState *bs, int *start, int *end)
+{
+    BlockDriver *drv = bs->drv;
+    if (!drv)
+        *start = *end = 0;
+    else if (!drv->bdrv_gettracks)
+        *start = *end = 1;
+    else
+        drv->bdrv_gettracks(bs, start, end);
+}
+
+int64_t bdrv_get_track_offset(BlockDriverState *bs, int track)
+{
+    BlockDriver *drv = bs->drv;
+    int64_t ret;
+
+    if (!drv)
+        ret = -1;
+    else if (!drv->bdrv_gettrackoff) {
+        if (1 == track)
+            ret = 0;
+        else if(0xaa == track)
+            bdrv_get_geometry(bs, &ret);
+        else
+            ret = -1;
+    }
+    else
+        ret = drv->bdrv_gettrackoff(bs, track);
+
+    return ret;
+}
+
 /* force a given boot sector. */
 void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
 {
Index: block_int.h
===================================================================
RCS file: /sources/qemu/qemu/block_int.h,v
retrieving revision 1.10
diff -u -r1.10 block_int.h
--- block_int.h	19 Aug 2006 11:45:59 -0000	1.10
+++ block_int.h	18 Oct 2006 23:17:34 -0000
@@ -58,6 +58,8 @@
                        const uint8_t *buf, int count);
     int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
     int64_t (*bdrv_getlength)(BlockDriverState *bs);
+    void (*bdrv_gettracks)(BlockDriverState *bs, int *start, int *end);
+    int64_t (*bdrv_gettrackoff)(BlockDriverState *bs, int track);
     int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, 
                                  const uint8_t *buf, int nb_sectors);
 
Index: vl.h
===================================================================
RCS file: /sources/qemu/qemu/vl.h,v
retrieving revision 1.154
diff -u -r1.154 vl.h
--- vl.h	24 Sep 2006 18:49:43 -0000	1.154
+++ vl.h	18 Oct 2006 23:17:35 -0000
@@ -564,6 +564,8 @@
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
 void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
+void bdrv_get_track_count(BlockDriverState *bs, int *start, int *end);
+int64_t bdrv_get_track_offset(BlockDriverState *bs, int track);
 int bdrv_commit(BlockDriverState *bs);
 void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
 /* async block I/O */
@@ -882,7 +884,7 @@
                    SetIRQFunc *set_irq, void *irq_opaque, int irq);
 
 /* cdrom.c */
-int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
+int cdrom_read_toc(BlockDriverState *bs, uint8_t *buf, int msf, int start_track);
 int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
 
 /* es1370.c */
Index: hw/cdrom.c
===================================================================
RCS file: /sources/qemu/qemu/hw/cdrom.c,v
retrieving revision 1.1
diff -u -r1.1 cdrom.c
--- hw/cdrom.c	25 May 2006 23:58:51 -0000	1.1
+++ hw/cdrom.c	18 Oct 2006 23:17:35 -0000
@@ -37,42 +37,55 @@
 
 /* same toc as bochs. Return -1 if error or the toc length */
 /* XXX: check this */
-int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
+int cdrom_read_toc(BlockDriverState *bs, uint8_t *buf, int msf, int start_track)
 {
     uint8_t *q;
-    int len;
-    
-    if (start_track > 1 && start_track != 0xaa)
+    int start, end, len;
+    int64_t off;
+
+    bdrv_get_track_count(bs, &start, &end);
+    if (0 > start || 0 > end)
+        return -1;
+    if (0 == start_track)
+        start_track = start;
+    if (start_track < start || (start_track > end && start_track != 0xaa))
         return -1;
     q = buf + 2;
-    *q++ = 1; /* first session */
-    *q++ = 1; /* last session */
-    if (start_track <= 1) {
+    *q++ = start; /* first session */
+    *q++ = end; /* last session */
+    while (start_track <= end) {
+        off = bdrv_get_track_offset(bs, start_track);
+        if (0 > off)
+            return -1;
         *q++ = 0; /* reserved */
-        *q++ = 0x14; /* ADR, control */
-        *q++ = 1;    /* track number */
+        *q++ = 0x14; /* ADR, control XXX audio tracks are not supported */
+        *q++ = start_track; /* track number */
         *q++ = 0; /* reserved */
         if (msf) {
             *q++ = 0; /* reserved */
-            lba_to_msf(q, 0);
+            lba_to_msf(q, off);
             q += 3;
         } else {
-            /* sector 0 */
-            cpu_to_be32wu((uint32_t *)q, 0);
+            /* start sector */
+            cpu_to_be32wu((uint32_t *)q, off);
             q += 4;
         }
+        start_track++;
     }
     /* lead out track */
+    off = bdrv_get_track_offset(bs, 0xaa);
+    if (0 > off)
+        return -1;
     *q++ = 0; /* reserved */
     *q++ = 0x16; /* ADR, control */
     *q++ = 0xaa; /* track number */
     *q++ = 0; /* reserved */
     if (msf) {
         *q++ = 0; /* reserved */
-        lba_to_msf(q, nb_sectors);
+        lba_to_msf(q, off);
         q += 3;
     } else {
-        cpu_to_be32wu((uint32_t *)q, nb_sectors);
+        cpu_to_be32wu((uint32_t *)q, off);
         q += 4;
     }
     len = q - buf;
Index: hw/ide.c
===================================================================
RCS file: /sources/qemu/qemu/hw/ide.c,v
retrieving revision 1.48
diff -u -r1.48 ide.c
--- hw/ide.c	19 Aug 2006 11:44:21 -0000	1.48
+++ hw/ide.c	18 Oct 2006 23:17:37 -0000
@@ -1415,7 +1415,7 @@
             start_track = packet[6];
             switch(format) {
             case 0:
-                len = cdrom_read_toc(total_sectors, buf, msf, start_track);
+                len = cdrom_read_toc(s->bs, buf, msf, start_track);
                 if (len < 0)
                     goto error_cmd;
                 ide_atapi_cmd_reply(s, len, max_len);

[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [patch] TOC support for raw cdrom block devices
  2006-10-24 21:25 [Qemu-devel] [patch] TOC support for raw cdrom block devices Josh Elsasser
@ 2006-10-25 11:47 ` Pascal Terjan
  2006-10-25 15:59   ` Josh Elsasser
  0 siblings, 1 reply; 4+ messages in thread
From: Pascal Terjan @ 2006-10-25 11:47 UTC (permalink / raw)
  To: qemu-devel

On 10/24/06, Josh Elsasser <josh@elsasser.org> wrote:
> The current raw block drvice code fakes a TOC with one track covering
> the entire disc.  With this patch it attempts to read the TOC from a
> cdrom device and make that information available to the ide driver
> when the guest issues an ATAPI READ TOC/PMA/ATIP type 0 (read TOC)
> command.

I recently sent a patch to add this for linux but then I thought of a
better way to do it.
I the TOC was stored in a struct somewhere, built when starting (or
changing media) using either .toc, .cue, real CD or maybe even a list
of track files this would allow to use such methods. Would be really
useful for me actually to be able to use a list of tracks but
generating toc/cue is quite easy.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Qemu-devel] [patch] TOC support for raw cdrom block devices
  2006-10-25 11:47 ` Pascal Terjan
@ 2006-10-25 15:59   ` Josh Elsasser
  0 siblings, 0 replies; 4+ messages in thread
From: Josh Elsasser @ 2006-10-25 15:59 UTC (permalink / raw)
  To: qemu-devel

[-- Attachment #1: Type: text/plain, Size: 672 bytes --]

On Wed, Oct 25, 2006 at 01:47:00PM +0200, Pascal Terjan wrote:
> I recently sent a patch to add this for linux but then I thought of a
> better way to do it.
> I the TOC was stored in a struct somewhere, built when starting (or
> changing media) using either .toc, .cue, real CD or maybe even a list
> of track files this would allow to use such methods. Would be really
> useful for me actually to be able to use a list of tracks but
> generating toc/cue is quite easy.

That would probably be better than reading the TOC from the CD each
time the guest requests it.  I had thought of using a .toc or .cue
file as well, however it wasn't required for my purposes.

 -jre

[-- Attachment #2: Type: application/pgp-signature, Size: 187 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2006-10-25 15:59 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-24 21:25 [Qemu-devel] [patch] TOC support for raw cdrom block devices Josh Elsasser
2006-10-25 11:47 ` Pascal Terjan
2006-10-25 15:59   ` Josh Elsasser
  -- strict thread matches above, loose matches on Subject: below --
2006-10-23 19:30 Josh Elsasser

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).