ppc: suppressed unneeded globals and headers - added explicit type for ppc nvram
[qemu] / hw / ide.c
index 480a7be..f5efa8e 100644 (file)
--- a/hw/ide.c
+++ b/hw/ide.c
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/time.h>
-#include <malloc.h>
-#include <termios.h>
-#include <sys/poll.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <netinet/in.h>
-
-#define NO_THUNK_TYPE_SIZE
-#include "thunk.h"
-
-#include "cpu.h"
-#include "exec-all.h"
-
 #include "vl.h"
 
 /* debug IDE devices */
 #define ATAPI_INT_REASON_TAG            0xf8
 
 /* same constants as bochs */
+#define ASC_ILLEGAL_OPCODE                   0x20
 #define ASC_LOGICAL_BLOCK_OOR                0x21
 #define ASC_INV_FIELD_IN_CMD_PACKET          0x24
 #define ASC_MEDIUM_NOT_PRESENT               0x3a
@@ -313,10 +289,10 @@ struct IDEState;
 
 typedef void EndTransferFunc(struct IDEState *);
 
+/* NOTE: IDEState represents in fact one drive */
 typedef struct IDEState {
     /* ide config */
     int is_cdrom;
-    int cdrom_locked;
     int cylinders, heads, sectors;
     int64_t nb_sectors;
     int mult_sectors;
@@ -350,14 +326,6 @@ typedef struct IDEState {
     uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
 } IDEState;
 
-IDEState ide_state[MAX_DISKS];
-IDEState *ide_table[0x400 >> 3];
-
-static inline IDEState *get_ide_interface(uint32_t addr)
-{
-    return ide_table[addr >> 3];
-}
-
 static void padstr(char *str, const char *src, int len)
 {
     int i, v;
@@ -382,6 +350,15 @@ static void padstr8(uint8_t *buf, int buf_size, const char *src)
     }
 }
 
+static void put_le16(uint16_t *p, unsigned int v)
+{
+#ifdef WORDS_BIGENDIAN
+    *p = bswap16(v);
+#else
+    *p = v;
+#endif
+}
+
 static void ide_identify(IDEState *s)
 {
     uint16_t *p;
@@ -389,42 +366,43 @@ static void ide_identify(IDEState *s)
 
     memset(s->io_buffer, 0, 512);
     p = (uint16_t *)s->io_buffer;
-    stw_raw(p + 0, 0x0040);
-    stw_raw(p + 1, s->cylinders); 
-    stw_raw(p + 3, s->heads);
-    stw_raw(p + 4, 512 * s->sectors); /* sectors */
-    stw_raw(p + 5, 512); /* sector size */
-    stw_raw(p + 6, s->sectors); 
+    put_le16(p + 0, 0x0040);
+    put_le16(p + 1, s->cylinders); 
+    put_le16(p + 3, s->heads);
+    put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
+    put_le16(p + 5, 512); /* XXX: retired, remove ? */
+    put_le16(p + 6, s->sectors); 
     padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */
-    stw_raw(p + 20, 3); /* buffer type */
-    stw_raw(p + 21, 512); /* cache size in sectors */
-    stw_raw(p + 22, 4); /* ecc bytes */
+    put_le16(p + 20, 3); /* XXX: retired, remove ? */
+    put_le16(p + 21, 512); /* cache size in sectors */
+    put_le16(p + 22, 4); /* ecc bytes */
     padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
     padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */
 #if MAX_MULT_SECTORS > 1    
-    stw_raw(p + 47, MAX_MULT_SECTORS);
+    put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
 #endif
-    stw_raw(p + 48, 1); /* dword I/O */
-    stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */
-    stw_raw(p + 51, 0x200); /* PIO transfer cycle */
-    stw_raw(p + 52, 0x200); /* DMA transfer cycle */
-    stw_raw(p + 54, s->cylinders);
-    stw_raw(p + 55, s->heads);
-    stw_raw(p + 56, s->sectors);
+    put_le16(p + 48, 1); /* dword I/O */
+    put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
+    put_le16(p + 51, 0x200); /* PIO transfer cycle */
+    put_le16(p + 52, 0x200); /* DMA transfer cycle */
+    put_le16(p + 53, 1); /* words 54-58 are valid */
+    put_le16(p + 54, s->cylinders);
+    put_le16(p + 55, s->heads);
+    put_le16(p + 56, s->sectors);
     oldsize = s->cylinders * s->heads * s->sectors;
-    stw_raw(p + 57, oldsize);
-    stw_raw(p + 58, oldsize >> 16);
+    put_le16(p + 57, oldsize);
+    put_le16(p + 58, oldsize >> 16);
     if (s->mult_sectors)
-        stw_raw(p + 59, 0x100 | s->mult_sectors);
-    stw_raw(p + 60, s->nb_sectors);
-    stw_raw(p + 61, s->nb_sectors >> 16);
-    stw_raw(p + 80, (1 << 1) | (1 << 2));
-    stw_raw(p + 82, (1 << 14));
-    stw_raw(p + 83, (1 << 14));
-    stw_raw(p + 84, (1 << 14));
-    stw_raw(p + 85, (1 << 14));
-    stw_raw(p + 86, 0);
-    stw_raw(p + 87, (1 << 14));
+        put_le16(p + 59, 0x100 | s->mult_sectors);
+    put_le16(p + 60, s->nb_sectors);
+    put_le16(p + 61, s->nb_sectors >> 16);
+    put_le16(p + 80, (1 << 1) | (1 << 2));
+    put_le16(p + 82, (1 << 14));
+    put_le16(p + 83, (1 << 14));
+    put_le16(p + 84, (1 << 14));
+    put_le16(p + 85, (1 << 14));
+    put_le16(p + 86, 0);
+    put_le16(p + 87, (1 << 14));
 }
 
 static void ide_atapi_identify(IDEState *s)
@@ -434,32 +412,32 @@ static void ide_atapi_identify(IDEState *s)
     memset(s->io_buffer, 0, 512);
     p = (uint16_t *)s->io_buffer;
     /* Removable CDROM, 50us response, 12 byte packets */
-    stw_raw(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
-    stw_raw(p + 1, s->cylinders); 
-    stw_raw(p + 3, s->heads);
-    stw_raw(p + 4, 512 * s->sectors); /* sectors */
-    stw_raw(p + 5, 512); /* sector size */
-    stw_raw(p + 6, s->sectors); 
+    put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
+    put_le16(p + 1, s->cylinders); 
+    put_le16(p + 3, s->heads);
+    put_le16(p + 4, 512 * s->sectors); /* sectors */
+    put_le16(p + 5, 512); /* sector size */
+    put_le16(p + 6, s->sectors); 
     padstr((uint8_t *)(p + 10), "QM00001", 20); /* serial number */
-    stw_raw(p + 20, 3); /* buffer type */
-    stw_raw(p + 21, 512); /* cache size in sectors */
-    stw_raw(p + 22, 4); /* ecc bytes */
+    put_le16(p + 20, 3); /* buffer type */
+    put_le16(p + 21, 512); /* cache size in sectors */
+    put_le16(p + 22, 4); /* ecc bytes */
     padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
     padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
-    stw_raw(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
-    stw_raw(p + 49, 1 << 9); /* LBA supported, no DMA */
-    stw_raw(p + 53, 3); /* words 64-70, 54-58 valid */
-    stw_raw(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
-    stw_raw(p + 64, 1); /* PIO modes */
-    stw_raw(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
-    stw_raw(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
-    stw_raw(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
-    stw_raw(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */
+    put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
+    put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
+    put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
+    put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
+    put_le16(p + 64, 1); /* PIO modes */
+    put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
+    put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
+    put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
+    put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */
     
-    stw_raw(p + 71, 30); /* in ns */
-    stw_raw(p + 72, 30); /* in ns */
+    put_le16(p + 71, 30); /* in ns */
+    put_le16(p + 72, 30); /* in ns */
 
-    stw_raw(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
+    put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
 }
 
 static void ide_set_signature(IDEState *s)
@@ -550,6 +528,7 @@ static void ide_sector_read(IDEState *s)
     int ret, n;
 
     s->status = READY_STAT | SEEK_STAT;
+    s->error = 0; /* not needed by IDE spec, but needed by Windows */
     sector_num = ide_get_sector(s);
     n = s->nsector;
     if (n == 0) {
@@ -694,10 +673,9 @@ static void ide_atapi_cmd_reply_end(IDEState *s)
                 if (byte_count_limit & 1)
                     byte_count_limit--;
                 size = byte_count_limit;
-            } else {
-                s->lcyl = size;
-                s->hcyl = size >> 8;
             }
+            s->lcyl = size;
+            s->hcyl = size >> 8;
             s->elementary_transfer_size = size;
             /* we cannot transmit more than one sector at a time */
             if (s->lba != -1) {
@@ -813,7 +791,7 @@ static void ide_atapi_cmd(IDEState *s)
 #endif
     switch(s->io_buffer[0]) {
     case GPCMD_TEST_UNIT_READY:
-        if (s->bs) {
+        if (bdrv_is_inserted(s->bs)) {
             ide_atapi_cmd_ok(s);
         } else {
             ide_atapi_cmd_error(s, SENSE_NOT_READY, 
@@ -865,7 +843,7 @@ static void ide_atapi_cmd(IDEState *s)
                     buf[12] = 0x70;
                     buf[13] = 3 << 5;
                     buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
-                    if (s->cdrom_locked)
+                    if (bdrv_is_locked(s->bs))
                         buf[6] |= 1 << 1;
                     buf[15] = 0x00;
                     cpu_to_ube16(&buf[16], 706);
@@ -905,8 +883,8 @@ static void ide_atapi_cmd(IDEState *s)
         ide_atapi_cmd_reply(s, 18, max_len);
         break;
     case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
-        if (s->bs) {
-            s->cdrom_locked = packet[4] & 1;
+        if (bdrv_is_inserted(s->bs)) {
+            bdrv_set_locked(s->bs, packet[4] & 1);
             ide_atapi_cmd_ok(s);
         } else {
             ide_atapi_cmd_error(s, SENSE_NOT_READY, 
@@ -918,7 +896,7 @@ static void ide_atapi_cmd(IDEState *s)
         {
             int nb_sectors, lba;
 
-            if (!s->bs) {
+            if (!bdrv_is_inserted(s->bs)) {
                 ide_atapi_cmd_error(s, SENSE_NOT_READY, 
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
@@ -943,7 +921,7 @@ static void ide_atapi_cmd(IDEState *s)
     case GPCMD_SEEK:
         {
             int lba;
-            if (!s->bs) {
+            if (!bdrv_is_inserted(s->bs)) {
                 ide_atapi_cmd_error(s, SENSE_NOT_READY, 
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
@@ -963,7 +941,10 @@ static void ide_atapi_cmd(IDEState *s)
             start = packet[4] & 1;
             eject = (packet[4] >> 1) & 1;
             
-            /* XXX: currently none implemented */
+            if (eject && !start) {
+                /* eject the disk */
+                bdrv_close(s->bs);
+            }
             ide_atapi_cmd_ok(s);
         }
         break;
@@ -984,7 +965,7 @@ static void ide_atapi_cmd(IDEState *s)
         {
             int format, msf, start_track, len;
 
-            if (!s->bs) {
+            if (!bdrv_is_inserted(s->bs)) {
                 ide_atapi_cmd_error(s, SENSE_NOT_READY, 
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
@@ -1009,12 +990,15 @@ static void ide_atapi_cmd(IDEState *s)
                 ide_atapi_cmd_reply(s, 12, max_len);
                 break;
             default:
-                goto error_cmd;
+            error_cmd:
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
+                                    ASC_INV_FIELD_IN_CMD_PACKET);
+                break;
             }
         }
         break;
     case GPCMD_READ_CDVD_CAPACITY:
-        if (!s->bs) {
+        if (!bdrv_is_inserted(s->bs)) {
             ide_atapi_cmd_error(s, SENSE_NOT_READY, 
                                 ASC_MEDIUM_NOT_PRESENT);
             break;
@@ -1040,17 +1024,27 @@ static void ide_atapi_cmd(IDEState *s)
         ide_atapi_cmd_reply(s, 36, max_len);
         break;
     default:
-        error_cmd:
         ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
-                            ASC_INV_FIELD_IN_CMD_PACKET);
+                            ASC_ILLEGAL_OPCODE);
         break;
     }
 }
 
-static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
+/* called when the inserted state of the media has changed */
+static void cdrom_change_cb(void *opaque)
 {
-    IDEState *ide_if = get_ide_interface(addr);
-    IDEState *s = ide_if->cur_drive;
+    IDEState *s = opaque;
+    int64_t nb_sectors;
+
+    /* XXX: send interrupt too */
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    s->nb_sectors = nb_sectors;
+}
+
+static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    IDEState *ide_if = opaque;
+    IDEState *s;
     int unit, n;
 
 #ifdef DEBUG_IDE
@@ -1061,28 +1055,35 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
     case 0:
         break;
     case 1:
-        s->feature = val;
+        /* NOTE: data is written to the two drives */
+        ide_if[0].feature = val;
+        ide_if[1].feature = val;
         break;
     case 2:
         if (val == 0)
             val = 256;
-        s->nsector = val;
+        ide_if[0].nsector = val;
+        ide_if[1].nsector = val;
         break;
     case 3:
-        s->sector = val;
+        ide_if[0].sector = val;
+        ide_if[1].sector = val;
         break;
     case 4:
-        s->lcyl = val;
+        ide_if[0].lcyl = val;
+        ide_if[1].lcyl = val;
         break;
     case 5:
-        s->hcyl = val;
+        ide_if[0].hcyl = val;
+        ide_if[1].hcyl = val;
         break;
     case 6:
+        ide_if[0].select = (val & ~0x10) | 0xa0;
+        ide_if[1].select = (val | 0x10) | 0xa0;
         /* select drive */
         unit = (val >> 4) & 1;
         s = ide_if + unit;
         ide_if->cur_drive = s;
-        s->select = val;
         break;
     default:
     case 7:
@@ -1090,6 +1091,7 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
 #if defined(DEBUG_IDE)
         printf("ide: CMD=%02x\n", val);
 #endif
+        s = ide_if->cur_drive;
         switch(val) {
         case WIN_IDENTIFY:
             if (s->bs && !s->is_cdrom) {
@@ -1106,6 +1108,7 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
             break;
         case WIN_SPECIFY:
         case WIN_RECAL:
+            s->error = 0;
             s->status = READY_STAT;
             ide_set_irq(s);
             break;
@@ -1135,6 +1138,7 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
             break;
         case WIN_WRITE:
         case WIN_WRITE_ONCE:
+            s->error = 0;
             s->status = SEEK_STAT;
             s->req_nb_sectors = 1;
             ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
@@ -1148,6 +1152,7 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
         case WIN_MULTWRITE:
             if (!s->mult_sectors)
                 goto abort_cmd;
+            s->error = 0;
             s->status = SEEK_STAT;
             s->req_nb_sectors = s->mult_sectors;
             n = s->nsector;
@@ -1160,6 +1165,11 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
             s->status = READY_STAT;
             ide_set_irq(s);
             break;
+        case WIN_CHECKPOWERMODE1:
+            s->nsector = 0xff; /* device active or idle */
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
 
             /* ATAPI commands */
         case WIN_PIDENTIFY:
@@ -1198,9 +1208,10 @@ static void ide_ioport_write(CPUState *env, uint32_t addr, uint32_t val)
     }
 }
 
-static uint32_t ide_ioport_read(CPUState *env, uint32_t addr1)
+static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
 {
-    IDEState *s = get_ide_interface(addr1)->cur_drive;
+    IDEState *ide_if = opaque;
+    IDEState *s = ide_if->cur_drive;
     uint32_t addr;
     int ret;
 
@@ -1210,26 +1221,47 @@ static uint32_t ide_ioport_read(CPUState *env, uint32_t addr1)
         ret = 0xff;
         break;
     case 1:
-        ret = s->error;
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->error;
         break;
     case 2:
-        ret = s->nsector & 0xff;
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->nsector & 0xff;
         break;
     case 3:
-        ret = s->sector;
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->sector;
         break;
     case 4:
-        ret = s->lcyl;
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->lcyl;
         break;
     case 5:
-        ret = s->hcyl;
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->hcyl;
         break;
     case 6:
-        ret = s->select;
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->select;
         break;
     default:
     case 7:
-        ret = s->status;
+        if (!ide_if[0].bs && !ide_if[1].bs)
+            ret = 0;
+        else
+            ret = s->status;
         pic_set_irq(s->irq, 0);
         break;
     }
@@ -1239,20 +1271,25 @@ static uint32_t ide_ioport_read(CPUState *env, uint32_t addr1)
     return ret;
 }
 
-static uint32_t ide_status_read(CPUState *env, uint32_t addr)
+static uint32_t ide_status_read(void *opaque, uint32_t addr)
 {
-    IDEState *s = get_ide_interface(addr)->cur_drive;
+    IDEState *ide_if = opaque;
+    IDEState *s = ide_if->cur_drive;
     int ret;
-    ret = s->status;
+
+    if (!ide_if[0].bs && !ide_if[1].bs)
+        ret = 0;
+    else
+        ret = s->status;
 #ifdef DEBUG_IDE
     printf("ide: read status addr=0x%x val=%02x\n", addr, ret);
 #endif
     return ret;
 }
 
-static void ide_cmd_write(CPUState *env, uint32_t addr, uint32_t val)
+static void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
 {
-    IDEState *ide_if = get_ide_interface(addr);
+    IDEState *ide_if = opaque;
     IDEState *s;
     int i;
 
@@ -1276,7 +1313,7 @@ static void ide_cmd_write(CPUState *env, uint32_t addr, uint32_t val)
             if (s->is_cdrom)
                 s->status = 0x00; /* NOTE: READY is _not_ set */
             else
-                s->status = READY_STAT;
+                s->status = READY_STAT | SEEK_STAT;
             ide_set_signature(s);
         }
     }
@@ -1285,9 +1322,9 @@ static void ide_cmd_write(CPUState *env, uint32_t addr, uint32_t val)
     ide_if[1].cmd = val;
 }
 
-static void ide_data_writew(CPUState *env, uint32_t addr, uint32_t val)
+static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
 {
-    IDEState *s = get_ide_interface(addr)->cur_drive;
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
 
     p = s->data_ptr;
@@ -1298,9 +1335,9 @@ static void ide_data_writew(CPUState *env, uint32_t addr, uint32_t val)
         s->end_transfer_func(s);
 }
 
-static uint32_t ide_data_readw(CPUState *env, uint32_t addr)
+static uint32_t ide_data_readw(void *opaque, uint32_t addr)
 {
-    IDEState *s = get_ide_interface(addr)->cur_drive;
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
     int ret;
     p = s->data_ptr;
@@ -1312,9 +1349,9 @@ static uint32_t ide_data_readw(CPUState *env, uint32_t addr)
     return ret;
 }
 
-static void ide_data_writel(CPUState *env, uint32_t addr, uint32_t val)
+static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
 {
-    IDEState *s = get_ide_interface(addr)->cur_drive;
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
 
     p = s->data_ptr;
@@ -1325,9 +1362,9 @@ static void ide_data_writel(CPUState *env, uint32_t addr, uint32_t val)
         s->end_transfer_func(s);
 }
 
-static uint32_t ide_data_readl(CPUState *env, uint32_t addr)
+static uint32_t ide_data_readl(void *opaque, uint32_t addr)
 {
-    IDEState *s = get_ide_interface(addr)->cur_drive;
+    IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
     int ret;
     
@@ -1395,64 +1432,64 @@ static void ide_guess_geometry(IDEState *s)
     }
 }
 
-void ide_init(void)
+void ide_init(int iobase, int iobase2, int irq,
+              BlockDriverState *hd0, BlockDriverState *hd1)
 {
-    IDEState *s;
-    int i, cylinders, iobase, iobase2;
+    IDEState *s, *ide_state;
+    int i, cylinders, heads, secs;
     int64_t nb_sectors;
-    static const int ide_iobase[2] = { 0x1f0, 0x170 };
-    static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-    static const int ide_irq[2] = { 14, 15 };
 
-    for(i = 0; i < MAX_DISKS; i++) {
-        s = &ide_state[i];
-        s->bs = bs_table[i];
+    ide_state = qemu_mallocz(sizeof(IDEState) * 2);
+    if (!ide_state)
+        return;
+
+    for(i = 0; i < 2; i++) {
+        s = ide_state + i;
+        if (i == 0)
+            s->bs = hd0;
+        else
+            s->bs = hd1;
         if (s->bs) {
             bdrv_get_geometry(s->bs, &nb_sectors);
             s->nb_sectors = nb_sectors;
-            ide_guess_geometry(s);
-            if (s->cylinders == 0) {
-                /* if no geometry, use a LBA compatible one */
-                cylinders = nb_sectors / (16 * 63);
-                if (cylinders > 16383)
-                    cylinders = 16383;
-                else if (cylinders < 2)
-                    cylinders = 2;
+            /* if a geometry hint is available, use it */
+            bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
+            if (cylinders != 0) {
                 s->cylinders = cylinders;
-                s->heads = 16;
-                s->sectors = 63;
+                s->heads = heads;
+                s->sectors = secs;
+            } else {
+                ide_guess_geometry(s);
+                if (s->cylinders == 0) {
+                    /* if no geometry, use a LBA compatible one */
+                    cylinders = nb_sectors / (16 * 63);
+                    if (cylinders > 16383)
+                        cylinders = 16383;
+                    else if (cylinders < 2)
+                        cylinders = 2;
+                    s->cylinders = cylinders;
+                    s->heads = 16;
+                    s->sectors = 63;
+                }
+            }
+            if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
+                s->is_cdrom = 1;
+                bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
             }
         }
-        s->irq = ide_irq[i >> 1];
+        s->irq = irq;
         ide_reset(s);
     }
-    for(i = 0; i < (MAX_DISKS / 2); i++) {
-        iobase = ide_iobase[i];
-        iobase2 = ide_iobase2[i];
-        ide_table[iobase >> 3] = &ide_state[2 * i];
-        if (ide_iobase2[i]) 
-            ide_table[iobase2 >> 3] = &ide_state[2 * i];
-        register_ioport_write(iobase, 8, ide_ioport_write, 1);
-        register_ioport_read(iobase, 8, ide_ioport_read, 1);
-        register_ioport_read(iobase2, 1, ide_status_read, 1);
-        register_ioport_write(iobase2, 1, ide_cmd_write, 1);
-        
-        /* data ports */
-        register_ioport_write(iobase, 2, ide_data_writew, 2);
-        register_ioport_read(iobase, 2, ide_data_readw, 2);
-        register_ioport_write(iobase, 4, ide_data_writel, 4);
-        register_ioport_read(iobase, 4, ide_data_readl, 4);
+    register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state);
+    register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state);
+    if (iobase2) {
+        register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state);
+        register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state);
     }
-}
-
-void ide_set_geometry(int n, int cyls, int heads, int secs)
-{
-    ide_state[n].cylinders = cyls;
-    ide_state[n].heads = heads;
-    ide_state[n].sectors = secs;
-}
-
-void ide_set_cdrom(int n, int is_cdrom)
-{
-    ide_state[n].is_cdrom = is_cdrom;
+    
+    /* data ports */
+    register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state);
+    register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state);
+    register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state);
+    register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state);
 }