diff -r 3ed325fa395b tools/ioemu/block.c
--- a/tools/ioemu/block.c	Fri May 26 13:53:49 2006 +0100
+++ b/tools/ioemu/block.c	Fri May 26 12:27:16 2006 -0600
@@ -147,6 +147,7 @@ int bdrv_open2(BlockDriverState *bs, con
     }
 
     bs->inserted = 1;
+    shdev_set_media_instance(bs);
 
     /* call the change callback */
     if (bs->change_cb)
@@ -170,6 +171,7 @@ void bdrv_close(BlockDriverState *bs)
         bs->opaque = NULL;
         bs->drv = NULL;
         bs->inserted = 0;
+	bs->media_instance = 0;
 
         /* call the change callback */
         if (bs->change_cb)
@@ -387,7 +389,7 @@ void bdrv_iterate_format(void (*it)(void
     }
 }
 
-BlockDriverState *bdrv_find(const char *name)
+BlockDriverState *bdrv_find_by_device(const char *name)
 {
     BlockDriverState *bs;
 
@@ -396,6 +398,15 @@ BlockDriverState *bdrv_find(const char *
             return bs;
     }
     return NULL;
+}
+
+BlockDriverState *bdrv_find_bs(int (*it)(BlockDriverState *, void *), void *opaque)
+{
+    BlockDriverState *bs;
+
+    for (bs = bdrv_first; bs != NULL && !it(bs, opaque); bs = bs->next);
+
+    return( bs );
 }
 
 void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque)
diff -r 3ed325fa395b tools/ioemu/block_int.h
--- a/tools/ioemu/block_int.h	Fri May 26 13:53:49 2006 +0100
+++ b/tools/ioemu/block_int.h	Fri May 26 12:27:16 2006 -0600
@@ -24,36 +24,22 @@
 #ifndef BLOCK_INT_H
 #define BLOCK_INT_H
 
-struct BlockDriver {
-    const char *format_name;
-    int instance_size;
-    int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
-    int (*bdrv_open)(BlockDriverState *bs, const char *filename);
-    int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, 
-                     uint8_t *buf, int nb_sectors);
-    int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, 
-                      const uint8_t *buf, int nb_sectors);
-    void (*bdrv_close)(BlockDriverState *bs);
-    int (*bdrv_create)(const char *filename, int64_t total_sectors, 
-                       const char *backing_file, int flags);
-    int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
-                             int nb_sectors, int *pnum);
-    int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
-    struct BlockDriver *next;
-};
+struct BlockDriver;
 
-struct BlockDriverState {
+typedef struct BlockDriverState {
     int64_t total_sectors;
     int read_only; /* if true, the media is read only */
     int inserted; /* if true, the media is present */
     int removable; /* if true, the media can be removed */
     int locked;    /* if true, the media cannot temporarily be ejected */
     int encrypted; /* if true, the media is encrypted */
+    int media_instance;
+    int shdev_el;
     /* event callback when inserting/removing */
     void (*change_cb)(void *opaque);
     void *change_opaque;
 
-    BlockDriver *drv;
+    struct BlockDriver *drv;
     void *opaque;
 
     int boot_sector_enabled;
@@ -63,15 +49,34 @@ struct BlockDriverState {
     char backing_file[1024]; /* if non zero, the image is a diff of
                                 this file image */
     int is_temporary;
-    
-    BlockDriverState *backing_hd;
-    
+
+    struct BlockDriverState *backing_hd;
+
     /* NOTE: the following infos are only hints for real hardware
        drivers. They are not used by the block driver */
     int cyls, heads, secs;
     int type;
     char device_name[32];
-    BlockDriverState *next;
-};
+    struct BlockDriverState *next;
+} BlockDriverState;
+
+typedef struct BlockDriver {
+    const char *format_name;
+    int instance_size;
+    int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
+    int (*bdrv_open)(BlockDriverState *bs, const char *filename);
+    int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
+                     uint8_t *buf, int nb_sectors);
+    int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
+                      const uint8_t *buf, int nb_sectors);
+    void (*bdrv_close)(BlockDriverState *bs);
+    int (*bdrv_create)(const char *filename, int64_t total_sectors,
+                       const char *backing_file, int flags);
+    int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
+                             int nb_sectors, int *pnum);
+    int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
+    struct BlockDriver *next;
+} BlockDriver;
+
 
 #endif /* BLOCK_INT_H */
diff -r 3ed325fa395b tools/ioemu/hw/ide.c
--- a/tools/ioemu/hw/ide.c	Fri May 26 13:53:49 2006 +0100
+++ b/tools/ioemu/hw/ide.c	Fri May 26 12:27:16 2006 -0600
@@ -278,6 +278,7 @@
 #define ASC_ILLEGAL_OPCODE                   0x20
 #define ASC_LOGICAL_BLOCK_OOR                0x21
 #define ASC_INV_FIELD_IN_CMD_PACKET          0x24
+#define ASC_MEDIA_CHANGED		     0x28
 #define ASC_MEDIUM_NOT_PRESENT               0x3a
 #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED  0x39
 
@@ -294,6 +295,7 @@ typedef struct IDEState {
 typedef struct IDEState {
     /* ide config */
     int is_cdrom;
+    int media_changed;
     int cylinders, heads, sectors;
     int64_t nb_sectors;
     int mult_sectors;
@@ -1132,11 +1134,34 @@ static int cdrom_read_toc_raw(IDEState *
     return len;
 }
 
+static int cd_media_inserted(IDEState *s)
+{
+    int h, x = 0;
+
+    if (s->bs->removable) {
+        h = open(s->bs->filename, O_NONBLOCK, O_RDONLY);
+
+        if (h >= 0) {
+	    x = fcntl(h, F_GETFL);
+            x &= ~O_NONBLOCK;
+            fcntl(h, F_SETFL, x);
+
+	    x = read(h, &x, sizeof(x));
+	    close(h);
+        }
+    }
+    else 
+	x = sizeof( x );
+
+    return((x == sizeof(x)));
+}
+	
 static void ide_atapi_cmd(IDEState *s)
 {
     const uint8_t *packet;
     uint8_t *buf;
     int max_len;
+
 
     packet = s->io_buffer;
     buf = s->io_buffer;
@@ -1150,13 +1175,28 @@ static void ide_atapi_cmd(IDEState *s)
         printf("\n");
     }
 #endif
+
     switch(s->io_buffer[0]) {
     case GPCMD_TEST_UNIT_READY:
         if (bdrv_is_inserted(s->bs)) {
-            ide_atapi_cmd_ok(s);
+	    if (s->media_changed) {
+		s->media_changed = 0;
+            	ide_atapi_cmd_error(s, SENSE_UNIT_ATTENTION, ASC_MEDIA_CHANGED);
+	    }
+            else {
+		if (!cd_media_inserted(s) || shdev_media_check(s->bs)) {
+		    bdrv_close(s->bs);
+                    ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                }
+                else 
+                    ide_atapi_cmd_ok(s);
+	    }
         } else {
-            ide_atapi_cmd_error(s, SENSE_NOT_READY, 
-                                ASC_MEDIUM_NOT_PRESENT);
+            ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+
+            if (cd_media_inserted(s)) {
+		    do_insert_request();
+	    }
         }
         break;
     case GPCMD_MODE_SENSE_10:
@@ -1288,6 +1328,13 @@ static void ide_atapi_cmd(IDEState *s)
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
             }
+
+            if (shdev_media_check(s->bs)) {
+		bdrv_close(s->bs);
+                ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                break;
+            }
+
             nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8];
             lba = ube32_to_cpu(packet + 2);
             if (nb_sectors == 0) {
@@ -1345,7 +1392,7 @@ static void ide_atapi_cmd(IDEState *s)
             
             if (eject && !start) {
                 /* eject the disk */
-                bdrv_close(s->bs);
+                do_eject(1, s->bs->device_name);
             }
             ide_atapi_cmd_ok(s);
         }
@@ -1372,6 +1419,13 @@ static void ide_atapi_cmd(IDEState *s)
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
             }
+
+            if (shdev_media_check(s->bs)) {
+		bdrv_close(s->bs);
+                ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);
+                break;
+            }
+
             max_len = ube16_to_cpu(packet + 7);
             format = packet[9] >> 6;
             msf = (packet[1] >> 1) & 1;
@@ -1444,9 +1498,9 @@ static void cdrom_change_cb(void *opaque
     IDEState *s = opaque;
     int64_t nb_sectors;
 
-    /* XXX: send interrupt too */
     bdrv_get_geometry(s->bs, &nb_sectors);
     s->nb_sectors = nb_sectors;
+    s->media_changed = 1;
 }
 
 static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -1631,6 +1685,7 @@ static void ide_ioport_write(void *opaqu
             ide_set_signature(s);
             s->status = 0x00; /* NOTE: READY is _not_ set */
             s->error = 0x01;
+	    s->media_changed = 0;
             break;
         case WIN_PACKETCMD:
             if (!s->is_cdrom)
diff -r 3ed325fa395b tools/ioemu/monitor.c
--- a/tools/ioemu/monitor.c	Fri May 26 13:53:49 2006 +0100
+++ b/tools/ioemu/monitor.c	Fri May 26 12:27:16 2006 -0600
@@ -1,8 +1,8 @@
 /*
  * QEMU monitor
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -23,6 +23,7 @@
  */
 #include "vl.h"
 #include <dirent.h>
+#include <sys/shm.h>
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -33,7 +34,7 @@
 
 /*
  * Supported types:
- * 
+ *
  * 'F'          filename
  * 'B'          block device name
  * 's'          string (accept optional quote)
@@ -66,7 +67,7 @@ void term_flush(void)
 {
     if (term_outbuf_index > 0) {
 	if(monitor_hd)
-        qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index);
+        qemu_chr_write(monitor_hd, (const uint8_t *)term_outbuf, term_outbuf_index);
 	else
 	    fwrite(term_outbuf, term_outbuf_index, 1, stderr);
         term_outbuf_index = 0;
@@ -240,7 +241,7 @@ static const KeyDef key_defs[] = {
 static const KeyDef key_defs[] = {
     { 0x2a, "shift" },
     { 0x36, "shift_r" },
-    
+
     { 0x38, "alt" },
     { 0xb8, "alt_r" },
     { 0x1d, "ctrl" },
@@ -293,7 +294,7 @@ static const KeyDef key_defs[] = {
     { 0x30, "b" },
     { 0x31, "n" },
     { 0x32, "m" },
-    
+
     { 0x39, "spc" },
     { 0x3a, "caps_lock" },
     { 0x3b, "f1" },
@@ -348,7 +349,7 @@ static void do_send_key(const char *stri
     uint8_t keycodes[16];
     const char *p;
     int nb_keycodes, keycode, i;
-    
+
     nb_keycodes = 0;
     p = string;
     while (*p != '\0') {
@@ -387,7 +388,7 @@ static void do_send_key(const char *stri
 }
 
 
-static int eject_device(BlockDriverState *bs, int force)
+static int eject_logical_device(BlockDriverState *bs, int force)
 {
     if (bdrv_is_inserted(bs)) {
         if (!force) {
@@ -405,23 +406,57 @@ static int eject_device(BlockDriverState
     return 0;
 }
 
-static void do_eject(int force, const char *filename)
+void do_eject(int force, const char *device)
 {
     char cmd[1024];
     BlockDriverState *bs;
 
-    bs = bdrv_find(filename);
+    bs = bdrv_find_by_device(device);
+
     if (!bs) {
-        term_printf("device not found\n");
+        term_printf("'%s' not found\n", device);
         return;
     }
-    eject_device(bs, force);
-    sprintf(cmd, "eject %s", filename);
-    system(cmd);
-
-}
-
-static void do_change(const char *device, const char *filename)
+
+    if (eject_logical_device(bs, force) == 0) {
+        shdev_eject_notice(bs);
+        sprintf(cmd, "eject %s", bs->filename);
+        system(cmd);
+    }
+}
+
+void do_insert(const char *device)
+{
+    BlockDriverState *bs;
+
+    bs = bdrv_find_by_device(device);
+
+    if (!bs) {
+        term_printf("'%s' not found\n", device);
+        return;
+    }
+
+    if (!bs->removable) {
+        term_printf("'%s' not removable\n", device);
+        return;
+    }
+
+    if (bs->inserted) {
+        term_printf("'%s' is already inserted\n", device);
+        return;
+    }
+
+    bdrv_open(bs, bs->filename, 0);
+}
+
+static int find_bs_by_type(BlockDriverState *bs, void *opaque)
+{
+   int *type = (int *)opaque;
+
+   return( (bs->type == *type) );
+}
+
+static void do_change_source(const char *device, const char *filename)
 {
     BlockDriverState *bs;
 #if 0
@@ -429,14 +464,18 @@ static void do_change(const char *device
     char password[256];
 #endif
 
-    bs = bdrv_find(device);
+    bs = bdrv_find_by_device(device);
+
     if (!bs) {
         term_printf("device not found\n");
         return;
     }
-    if (eject_device(bs, 0) < 0)
+
+    if (eject_logical_device(bs, 0) < 0)
         return;
-    bdrv_open(bs, filename, 0);
+
+    do_insert(bs->device_name);
+
 #if 0
     if (bdrv_is_encrypted(bs)) {
         term_printf("%s is encrypted.\n", device);
@@ -448,6 +487,20 @@ static void do_change(const char *device
         }
     }
 #endif
+}
+
+void do_insert_request()
+{
+    BlockDriverState *bs = NULL;
+    int type = BDRV_TYPE_CDROM;
+
+    bs = bdrv_find_bs(find_bs_by_type, &type);
+
+    if (bs) {
+        do_change_source(bs->device_name, bs->filename);
+    }
+    else
+        term_printf("Did not find cdrom bs.\n");
 }
 
 static void do_screen_dump(const char *filename)
@@ -482,17 +535,19 @@ static term_cmd_t term_cmds[] = {
       "", "quit the emulator" },
     { "eject", "-fB", do_eject,
       "[-f] device", "eject a removable media (use -f to force it)" },
-    { "change", "BF", do_change,
-      "device filename", "change a removable media" },
+    { "insert", "B", do_insert,
+      "device", "notifies qemu of inserted removable media." },
+    { "change", "BF", do_change_source,
+      "device filename", "change source for virtual removable-media device." },
     { "screendump", "F", do_screen_dump,
       "filename", "save screen into PPM image 'filename'" },
     { "log", "s", do_log,
diff -r 3ed325fa395b tools/ioemu/vl.h
--- a/tools/ioemu/vl.h	Fri May 26 13:53:49 2006 +0100
+++ b/tools/ioemu/vl.h	Fri May 26 12:27:16 2006 -0600
@@ -37,6 +37,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <block_int.h>
 #include "audio/audio.h"
 #include "xenctrl.h"
 #include "xs.h"
@@ -84,6 +85,8 @@ static inline char *realpath(const char 
 #endif
 
 /* vl.c */
+#define CDROM_DISK_POSITION 2
+
 uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c);
 
 void hw_error(const char *fmt, ...);
@@ -374,9 +377,6 @@ void port_e9_init(void);
 void port_e9_init(void);
 
 /* block.c */
-typedef struct BlockDriverState BlockDriverState;
-typedef struct BlockDriver BlockDriver;
-
 extern BlockDriver bdrv_raw;
 extern BlockDriver bdrv_cow;
 extern BlockDriver bdrv_qcow;
@@ -421,7 +421,8 @@ void bdrv_set_change_cb(BlockDriverState
                         void (*change_cb)(void *opaque), void *opaque);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 void bdrv_info(void);
-BlockDriverState *bdrv_find(const char *name);
+BlockDriverState *bdrv_find_bs(int (*it)(BlockDriverState *bs, void *opaque), void *opaque);
+BlockDriverState *bdrv_find_by_device(const char *name);
 void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque);
 int bdrv_is_encrypted(BlockDriverState *bs);
 int bdrv_set_key(BlockDriverState *bs, const char *key);
@@ -797,6 +798,15 @@ int cuda_init(openpic_t *openpic, int ir
 
 #endif /* defined(QEMU_TOOL) */
 
+/* shdev.h */
+
+int shdev_init(void);
+int shdev_report_device(BlockDriverState *bs, const char *name);
+void shdev_set_media_instance(BlockDriverState *bs);
+void shdev_eject_notice(BlockDriverState *bs);
+inline int shdev_media_check(BlockDriverState *bs);
+void do_info_shdev(void);
+
 /* monitor.c */
 void monitor_init(CharDriverState *hd, int show_banner);
 void term_puts(const char *str);
@@ -804,6 +814,9 @@ void term_printf(const char *fmt, ...) _
 void term_printf(const char *fmt, ...) __attribute__ ((__format__ (__printf__, 1, 2)));
 void term_flush(void);
 void term_print_help(void);
+void do_insert_request(void);
+void do_eject(int force, const char *device);
+
 
 /* readline.c */
 typedef void ReadLineFunc(void *opaque, const char *str);
diff -r 3ed325fa395b tools/ioemu/shdev.c
--- /dev/null	Thu Jan  1 00:00:00 1970 +0000
+++ b/tools/ioemu/shdev.c	Fri May 26 12:36:54 2006 -0600
@@ -0,0 +1,137 @@
+/*
+ * Managment for Devices Shared Across Guests 
+ *
+ * Copyright (c) 2006 Novell, Inc.
+ * 
+ * - Author: Ross Maxfield (ross.maxfield@novell.com)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+#include <sys/shm.h>
+
+#define MAX_SHARED_DEVS 4
+#define SHDEV_NAME_LEN 128
+#define SHARED_DEVS_SIGNATURE "ShRdDeVs"
+#define QEMU_KEY_PATH "/etc/xen"
+
+typedef struct SharedDevice {
+    char name[SHDEV_NAME_LEN];
+    int  media_instance;
+} SharedDevice;
+
+typedef struct SharedDevices {
+    char         signature[sizeof(SHARED_DEVS_SIGNATURE)];
+    SharedDevice device[MAX_SHARED_DEVS];
+} SharedDevices;
+
+SharedDevices *shdevs;
+
+int shdev_init()
+{
+    key_t shm_key;
+    int shm_id;
+
+    /* Alloc/Get shared device memory */
+    shm_key = ftok(QEMU_KEY_PATH, 'X');
+
+    if (((shm_id = shmget(shm_key,
+                          sizeof(SharedDevices),
+                          IPC_CREAT|IPC_EXCL|0660)) != -1)
+          && ((shdevs = shmat(shm_id, 0, 0)) != (void *)-1)) {
+        memcpy(&shdevs->signature, SHARED_DEVS_SIGNATURE,
+               sizeof(SHARED_DEVS_SIGNATURE));
+    }
+    else
+    if (errno == EEXIST)
+    {
+        if (((shm_id = shmget(shm_key, sizeof(SharedDevices), 0)) == -1)
+            || ((shdevs = shmat(shm_id, 0, 0)) == (void *)-1)
+            || (memcmp(shdevs->signature, SHARED_DEVS_SIGNATURE,
+                       sizeof(SHARED_DEVS_SIGNATURE)) != 0)) {
+            shdevs = NULL;
+            fprintf(stderr, "Could not setup support for shared devices.\n");
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+void shdev_set_media_instance(BlockDriverState *bs)
+{
+    bs->media_instance = shdevs->device[bs->shdev_el].media_instance;
+}
+
+void shdev_eject_notice(BlockDriverState *bs)
+{
+    shdevs->device[bs->shdev_el].media_instance++;
+}
+
+inline int shdev_media_check(BlockDriverState *bs)
+{
+    return(!(bs->media_instance == shdevs->device[bs->shdev_el].media_instance));
+}
+
+int shdev_report_device(BlockDriverState *bs, const char *name)
+{
+    int i;
+
+    for (i = 0;
+         (i < MAX_SHARED_DEVS) && strcmp(shdevs->device[i].name, name);
+         i++);
+
+    if (i == MAX_SHARED_DEVS) {
+        for (i = 0;
+             (i < MAX_SHARED_DEVS) && (shdevs->device[i].name[0] != '\0');
+             i++);
+
+        if (i < MAX_SHARED_DEVS) {
+            pstrcpy(shdevs->device[i].name, SHDEV_NAME_LEN, name);
+            shdevs->device[i].media_instance = 0;
+        }
+        else {
+            fprintf(stderr, "%s exceeds maximum of %d shared devices.\n",
+                    name, MAX_SHARED_DEVS );
+            return -1;
+        }
+    }
+
+    bs->media_instance = shdevs->device[i].media_instance;
+    bs->shdev_el = i;
+
+    return 0;
+}
+
+void do_info_shdev(void)
+{
+    int i;
+
+    /* Can this device be made availble to this domain? */
+    for (i = 0; i < MAX_SHARED_DEVS; i++) {
+        if (shdevs->device[i].name[0] != '\0') {
+            term_printf("'%s' [%d]\n",
+                        shdevs->device[i].name,
+			shdevs->device[i].media_instance);
+        }
+    }
+}
+
+
