qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v02] add 1394 bus support


From: itamar . tal4
Subject: [Qemu-devel] [PATCH v02] add 1394 bus support
Date: Sun, 19 Apr 2015 13:52:21 +0300

From: Itamar Tal <address@hidden>

---
 default-configs/i386-softmmu.mak   |    1 +
 default-configs/x86_64-softmmu.mak |    1 +
 hw/1394/Makefile.objs              |    1 +
 hw/1394/hcd-ohci.c                 | 1754 ++++++++++++++++++++++++++++++++++++
 hw/1394/hcd-ohci.h                 |  147 +++
 hw/Makefile.objs                   |    1 +
 6 files changed, 1905 insertions(+)
 create mode 100644 hw/1394/Makefile.objs
 create mode 100644 hw/1394/hcd-ohci.c
 create mode 100644 hw/1394/hcd-ohci.h

diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 6a74e00..8742af9 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -45,3 +45,4 @@ CONFIG_MEM_HOTPLUG=y
 CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
+CONFIG_1394_OHCI=y
diff --git a/default-configs/x86_64-softmmu.mak 
b/default-configs/x86_64-softmmu.mak
index 46b87dd..a47863d 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -45,3 +45,4 @@ CONFIG_MEM_HOTPLUG=y
 CONFIG_XIO3130=y
 CONFIG_IOH3420=y
 CONFIG_I82801B11=y
+CONFIG_1394_OHCI=y
diff --git a/hw/1394/Makefile.objs b/hw/1394/Makefile.objs
new file mode 100644
index 0000000..bddc0e1
--- /dev/null
+++ b/hw/1394/Makefile.objs
@@ -0,0 +1 @@
+common-obj-$(CONFIG_1394_OHCI) += hcd-ohci.o
diff --git a/hw/1394/hcd-ohci.c b/hw/1394/hcd-ohci.c
new file mode 100644
index 0000000..3f7ad75
--- /dev/null
+++ b/hw/1394/hcd-ohci.c
@@ -0,0 +1,1754 @@
+/*
+ * FireWire (1394) support
+ *
+ * Copyright (c) 2015 Guardicore
+ * - address@hidden
+ * Originally Written by James Harper
+ *
+ * This is a `bare-bones' implementation of the Firewire 1394 OHCI
+ * for virtual->virtual firewire connections emulation
+ *
+ * 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 "hcd-ohci.h"
+#include <sys/time.h>
+
+#define OHCI_1394_MMIO_SIZE 0x800
+
+#define HCCONTROL_RESET 16
+#define HCCONTROL_LINK_ENABLE 17
+#define HCCONTROL_LPS 19
+
+#define HCCONTROL_RESET_MASK (1 << (HCCONTROL_RESET))
+#define HCCONTROL_LINK_ENABLE_MASK (1 << (HCCONTROL_LINK_ENABLE))
+#define HCCONTROL_LPS_MASK (1 << (HCCONTROL_LPS))
+
+#define HCD_STATE_UNPLUGGED    0 /* no connection */
+#define HCD_STATE_MAGIC        1 /* waiting for magic */
+#define HCD_STATE_DISCONNECTED 2 /* waiting for link packet */
+#define HCD_STATE_ARBITRATION1 3 /* send bid */
+#define HCD_STATE_ARBITRATION2 4 /* receive bid and compare */
+#define HCD_STATE_CONNECTED    5 /* connected and ready to go */
+
+#define IS_Ax_ACTIVE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] & (1 << 10))
+#define SET_Ax_ACTIVE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] |= (1 << 10))
+#define CLR_Ax_ACTIVE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] &= ~(1 << 10))
+
+#define IS_Ax_DEAD(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] & (1 << 11))
+#define SET_Ax_DEAD(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] |= (1 << 11))
+
+#define IS_Ax_WAKE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] & (1 << 12))
+#define CLR_Ax_WAKE(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] &= ~(1 << 12))
+
+#define IS_Ax_RUN(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] & (1 << 15))
+
+#define SET_Ax_EVENT_CODE(n, e) s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x000) >> 2] = ((s->mmio.regs[((0x180 + \
+                                      ((n) * 0x20)) + 0x00) >> 2] & \
+                                      0xFFFFFFE0) | (e))
+
+#define Ax_COMMAND_PTR(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x00C) >> 2])
+#define SET_Ax_COMMAND_PTR(n, c) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x00C) >> 2] = (c))
+
+#define Ax_CONTEXT_CONTROL(n) (s->mmio.regs[((0x180 + ((n) * 0x20)) + \
+                                      0x00) >> 2])
+
+#define DECLARE_PHY \
+union { \
+    uint32_t PhyControl; \
+    struct { \
+        uint32_t PhyControl_wrData:8; \
+        uint32_t PhyControl_regAddr:4; \
+        uint32_t:2; \
+        uint32_t PhyControl_wrReg:1; \
+        uint32_t PhyControl_rdReg:1; \
+        uint32_t PhyControl_rdData:8; \
+        uint32_t PhyControl_rdAddr:4; \
+        uint32_t:3; \
+        uint32_t PhyControl_rdDone:1; \
+    }; \
+}
+
+#define DECLARE_INT(prefix) \
+union { \
+    uint32_t prefix; \
+    struct { \
+        uint32_t prefix##_reqTxComplete:1; \
+        uint32_t prefix##_respTxComplete:1; \
+        uint32_t prefix##_ARRQ:1; \
+        uint32_t prefix##_ARRS:1; \
+        uint32_t prefix##_RQPkt:1; \
+        uint32_t prefix##_RSPkt:1; \
+        uint32_t prefix##_isochTx:1; \
+        uint32_t prefix##_isockRx:1; \
+        uint32_t prefix##_postedWriteErr:1; \
+        uint32_t prefix##_lockRespErr:1; \
+        uint32_t:5; \
+        uint32_t prefix##_selfIDComplete2:1; \
+        uint32_t prefix##_selfIDComplete:1; \
+        uint32_t prefix##_busReset:1; \
+        uint32_t prefix##_regAccessFail:1; \
+        uint32_t prefix##_phy:1; \
+        uint32_t prefix##_cycleSynch:1; \
+        uint32_t prefix##_cycle64Seconds:1; \
+        uint32_t prefix##_cycleLost:1; \
+        uint32_t prefix##_cycleInconsistent:1; \
+        uint32_t prefix##_unrecoverableError:1; \
+        uint32_t prefix##_cycleTooLong:1; \
+        uint32_t prefix##_phyRegRcvd:1; \
+        uint32_t prefix##_ack_tardy:1; \
+        uint32_t:1; \
+        uint32_t prefix##_softInterrupt:1; \
+        uint32_t prefix##_vendorSpecific:1; \
+        uint32_t prefix##_masterIntEnable:1; \
+    }; \
+}
+
+#define DECLARE_CONFIG_ROM_HDR \
+union { \
+    uint32_t ConfigROMhdr; \
+    struct { \
+        uint32_t ConfigRomhdr_rom_crc_value:16; \
+        uint32_t ConfigRomhdr_crc_length:8; \
+        uint32_t ConfigRomhdr_info_length:8; \
+    }; \
+}
+
+#define DECLARE_NODE_ID \
+union { \
+    uint32_t NodeID; \
+    struct { \
+        uint32_t NodeID_nodeNumber:6; \
+        uint32_t NodeID_busNumber:10; \
+        uint32_t:11; \
+        uint32_t NodeID_CPS:1; \
+        uint32_t:2; \
+        uint32_t NodeID_root:1; \
+        uint32_t NodeID_iDValid:1; \
+    }; \
+}
+
+#define DECLARE_SELF_ID_COUNT \
+union { \
+    uint32_t SelfIDCount; \
+    struct { \
+        uint32_t:2; \
+        uint32_t SelfIDCount_Size:9; \
+        uint32_t:5; \
+        uint32_t SelfIDCount_Generation:8; \
+        uint32_t:7; \
+        uint32_t SelfIDCount_Error:1; \
+    }; \
+}
+
+#define DECLARE_ASYNC(prefix) \
+struct { \
+    union { \
+       struct { \
+           uint32_t prefix##ContextControl; \
+           uint32_t prefix##ContextControl_Alt; \
+       }; \
+       struct { \
+           uint32_t prefix##ContextControlSet; \
+           uint32_t prefix##ContextControlClear; \
+       }; \
+    }; \
+    uint32_t prefix##Reserved_08; \
+    uint32_t prefix##CommandPtr; \
+    uint32_t prefix##Reserved_10; \
+    uint32_t prefix##Reserved_14; \
+    uint32_t prefix##Reserved_18; \
+    uint32_t prefix##Reserved_1c; \
+}
+
+typedef union {
+    struct {
+        uint32_t Version;
+        uint32_t GUID_ROM;
+        uint32_t ATRetries;
+        union {
+            uint32_t CSRReadData; /* 00c */
+            uint32_t CSRWriteData; /* 00c */
+        };
+        uint32_t CSRCompareData;
+        uint32_t CSRControl;
+        DECLARE_CONFIG_ROM_HDR;
+        uint32_t BusID;
+        uint32_t BusOptions;
+        uint32_t GUIDHi;
+        uint32_t GUIDLo;
+        uint32_t Reserved_002c;
+        uint32_t Reserved_0030;
+        uint32_t ConfigROMMap;
+        uint32_t PostedWriteAddressLo;
+        uint32_t PostedWriteAddressHi;;
+        uint32_t VendorID;
+        uint32_t Reserved_0044;
+        uint32_t Reserved_0048;
+        uint32_t Reserved_004c;
+        union {
+            struct {
+                /* read */
+                uint32_t HCControl;
+                uint32_t HCControl_Alt;
+            };
+            struct {
+                /* write */
+                uint32_t HCControlSet;
+                uint32_t HCControlClear;
+            };
+        };
+        uint32_t Reserved_0058;
+        uint32_t Reserved_005c;
+        uint32_t Reserved_0060;
+        uint32_t SelfIDBuffer;
+        DECLARE_SELF_ID_COUNT;
+        uint32_t Reserved_006c;
+        union {
+            struct {
+                /* read */
+                uint32_t IRMultiChanMaskHi;
+                uint32_t IRMultiChanMaskHi_Alt;
+            };
+            struct {
+                /* write */
+                uint32_t IRMultiChanMaskHiSet;
+                uint32_t IRMultiChanMaskHiClear;
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t IRMultiChanMaskLo;
+                uint32_t IRMultiChanMaskLo_Alt;
+            };
+            struct {
+                /* write */
+                uint32_t IRMultiChanMaskLoSet;
+                uint32_t IRMultiChanMaskLoClear;
+            };
+        };
+        union {
+            struct {
+                /* read */
+                DECLARE_INT(IntEvent);            /* 0080 */
+                DECLARE_INT(IntEventMasked);      /* 0084 */
+            };
+            struct {
+                /* write */
+                DECLARE_INT(IntEventSet);         /* 0080 */
+                DECLARE_INT(IntEventClear);       /* 0084 */
+            };
+        };
+        union {
+            struct {
+                /* read */
+                DECLARE_INT(IntMask);
+                DECLARE_INT(IntMask_Alt);
+            };
+            struct {
+                /* write */
+                DECLARE_INT(IntMaskSet);
+                DECLARE_INT(IntMaskClear);
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t IsoXmitIntEvent;
+                uint32_t IsoXmitIntEventMasked;
+            };
+            struct {
+                /* write */
+                uint32_t IsoXmitIntEventSet;
+                uint32_t IsoXmitIntEventClear;
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t IsoXmitIntMask;
+                uint32_t IsoXmitIntMask_Alt;
+            };
+            struct {
+                /* write */
+                uint32_t IsoXmitIntMaskSet;
+                uint32_t IsoXmitIntMaskClear;
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t IsoRecvIntEvent;
+                uint32_t IsoRecvIntEventMasked;
+            };
+            struct {
+                /* write */
+                uint32_t IsoRecvIntEventSet;
+                uint32_t IsoRecvIntEventClear;
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t IsoRecvIntMask;
+                uint32_t IsoRecvIntMask_Alt;
+            };
+            struct {
+                /* write */
+                uint32_t IsoRecvIntMaskSet;
+                uint32_t IsoRecvIntMaskClear;
+            };
+        };
+        uint32_t InitialBandwidthAvailable;  /* 00B0 */
+        uint32_t InitialChannelsAvailableHi; /* 00B4 */
+        uint32_t InitialChannelsAvailableLo; /* 00B8 */
+        uint32_t Reserved_00bc;
+        uint32_t Reserved_00c0;
+        uint32_t Reserved_00c4;
+        uint32_t Reserved_00c8;
+        uint32_t Reserved_00dc;
+        uint32_t Reserved_00d0;
+        uint32_t Reserved_00d4;
+        uint32_t Reserved_00d8;
+        uint32_t FairnessControl; /* 00dc */
+        union {
+            struct {
+                /* read */
+                uint32_t LinkControl;     /* 0xe0 */
+                uint32_t LinkControl_Alt; /* 0xe4 */
+            };
+            struct {
+                /* write */
+                uint32_t LinkControlSet;   /* 0xe0 */
+                uint32_t LinkControlClear; /* 0xe4 */
+            };
+        };
+        DECLARE_NODE_ID;                                   /* 00e8 */
+        DECLARE_PHY;                                       /* 00ec */
+        uint32_t IsochronousCycleTimer;                    /* 00f0 */
+        uint32_t Reserved_00f4;
+        uint32_t Reserved_00f8;
+        uint32_t Reserved_00fc;
+        union {
+            struct {
+                /* read */
+                uint32_t AsynchronousRequestFilterHi;      /* 0100 */
+                uint32_t AsynchronousRequestFilterHi_Alt;  /* 0104 */
+            };
+            struct {
+                /* write */
+                uint32_t AsynchronousRequestFilterHiSet;   /* 0100 */
+                uint32_t AsynchronousRequestFilterHiClear; /* 0104 */
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t AsynchronousRequestFilterLo;      /* 0108 */
+                uint32_t AsynchronousRequestFilterLo_Alt;  /* 010c */
+            };
+            struct {
+                /* write */
+                uint32_t AsynchronousRequestFilterLoSet;   /* 0108 */
+                uint32_t AsynchronousRequestFilterLoClear; /* 010c */
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t PhysicalRequestFilterHi;          /* 0110 */
+                uint32_t PhysicalRequestFilterHi_Alt;      /* 0114 */
+            };
+            struct {
+                /* write */
+                uint32_t PhysicalRequestFilterHiSet;       /* 0110 */
+                uint32_t PhysicalRequestFilterHiClear;     /* 0114 */
+            };
+        };
+        union {
+            struct {
+                /* read */
+                uint32_t PhysicalRequestFilterLo;          /* 0118 */
+                uint32_t PhysicalRequestFilterLo_Alt;      /* 011c */
+            };
+            struct {
+                /* write */
+                uint32_t PhysicalRequestFilterLoSet;       /* 0118 */
+                uint32_t PhysicalRequestFilterLoClear;     /* 011c */
+            };
+        };
+        uint32_t PhyiscalUpperBound; /* 0120 */
+        uint32_t Reserved_0124;
+        uint32_t Reserved_0128;
+        uint32_t Reserved_012c;
+        uint32_t Reserved_0130;
+        uint32_t Reserved_0134;
+        uint32_t Reserved_0138;
+        uint32_t Reserved_013c;
+        uint32_t Reserved_0140;
+        uint32_t Reserved_0144;
+        uint32_t Reserved_0148;
+        uint32_t Reserved_014c;
+        uint32_t Reserved_0150;
+        uint32_t Reserved_0154;
+        uint32_t Reserved_0158;
+        uint32_t Reserved_015c;
+        uint32_t Reserved_0160;
+        uint32_t Reserved_0164;
+        uint32_t Reserved_0168;
+        uint32_t Reserved_016c;
+        uint32_t Reserved_0170;
+        uint32_t Reserved_0174;
+        uint32_t Reserved_0178;
+        uint32_t Reserved_017c;
+        DECLARE_ASYNC(AsyncRequestTransmit);
+        DECLARE_ASYNC(AsyncResponseTransmit);
+        DECLARE_ASYNC(AsyncRequestReceive);
+        DECLARE_ASYNC(AsyncResponseReceive);
+        /* Isoch stuff */
+    };
+    uint32_t regs[OHCI_1394_MMIO_SIZE >> 2];
+} mmio_regs_t;
+
+typedef union {
+    uint8_t bytes[1024];
+    uint32_t quads[1024 / 4];
+    struct {
+        DECLARE_CONFIG_ROM_HDR;
+        uint32_t BusID;
+        uint32_t BusOptions;
+        uint32_t GUIDHi;
+        uint32_t GUIDLo;
+    };
+} config_rom_t;
+
+typedef union {
+    uint8_t bytes[16];
+    struct {
+        /* 00 */
+        uint8_t CPS:1;
+        uint8_t Root:1;
+        uint8_t PhysicalID:6;
+        /* 01 */
+        uint8_t GapCount:6;
+        uint8_t IBR:1;
+        uint8_t RHB:1;
+        /* 02 */
+        uint8_t NumPorts:4;
+        uint8_t:1;
+        uint8_t Extended:3;
+        /* 03 */
+        uint8_t Delay:4;
+        uint8_t:1;
+        uint8_t PHYSpeed:3;
+        /* 04 */
+        uint8_t PwrClass:3;
+        uint8_t Jitter:3;
+        uint8_t C:1;
+        uint8_t L:1;
+        /* 05 */
+        uint8_t EMC:1;
+        uint8_t EAA:1;
+        uint8_t PEI:1;
+        uint8_t STOI:1;
+        uint8_t CPSI:1;
+        uint8_t CTOI:1;
+        uint8_t ISBR:1;
+        uint8_t RPIE:1;
+        /* 06 */
+        uint8_t reg6;
+        /* 07 */
+        uint8_t PortSelect:4;
+        uint8_t:1;
+        uint8_t PageSelect:3;
+    };
+} phy_t;
+
+#define REG_OFFSET(field) ((uint32_t)(uintptr_t)&(((mmio_regs_t *)0)->field))
+
+typedef union {
+    uint32_t val;
+    struct {
+        uint32_t m:1;         /* = 0 */
+        uint32_t initiated:1; /* = 1 for root node */
+        uint32_t p2:2;        /* = 0 */
+        uint32_t p1:2;        /* = 0 */
+        uint32_t p0:2;        /* = 3, maybe 2 when "child" compared to root */
+        uint32_t pwr:3;       /* = 0 */
+        uint32_t c:1;         /* = 1 when root */
+        uint32_t del:2;       /* = 0? */
+        uint32_t sp:2;        /* = 0? */
+        uint32_t gap_cnt:6;   /* = 0? */
+        uint32_t L:1;         /* = 1? maybe just when connected */
+        uint32_t:1;           /* = 0 */
+        uint32_t node_id:6;
+        uint32_t type:2;      /* = 2 */
+    };
+} self_id_t;
+
+struct _hcd_state_t;
+
+typedef struct _hcd_state_t hcd_state_t;
+
+typedef struct {
+    uint16_t req_count;
+    uint16_t:2;
+    uint16_t branch:2;
+    uint16_t interrupt:2;
+    uint16_t:1;
+    uint16_t ping:1;
+    uint16_t key:3;
+    uint16_t:1;
+    uint16_t cmd:4;
+    uint32_t data_address;
+    uint32_t branch_address;
+    uint16_t timestamp;
+    uint16_t transfer_status;
+} hcd_at_db_t;
+
+typedef struct {
+    hcd_state_t *s;
+    QEMUTimer *timer;
+    uint32_t num; /* base register is 0x180 + num * 0x20 */
+    uint32_t address; /* current address */
+    uint32_t response;
+} hcd_timer_state_t;
+
+struct _hcd_state_t {
+    PCIDevice pci_dev;
+    MemoryRegion mmio_bar;
+    mmio_regs_t mmio;
+    hcd_timer_state_t at_req_timer;
+    hcd_timer_state_t at_rsp_timer;
+    phy_t phy;
+    uint8_t phy_pages[8][8];
+    qemu_irq irq;
+    uint32_t irq_asserted;
+    /* properties from init */
+    CharDriverState *chr;
+    int state;
+    int other_link;
+    uint16_t bid;
+    int root;
+    int bufpos;
+    uint8_t buf[16 + 65536]; /* maximum request size + maximum data size */
+};
+
+static void hcd_bus_reset(hcd_state_t *s);
+static void hcd_chr_event(void *opaque, int event);
+
+static const VMStateDescription vmstate_pci_hcd = {
+    .name = "ohci-1394",
+    .version_id = 3,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(pci_dev, hcd_state_t),
+        VMSTATE_UINT32_ARRAY(mmio.regs, hcd_state_t, OHCI_1394_MMIO_SIZE >> 2),
+        VMSTATE_UINT8_ARRAY(phy.bytes, hcd_state_t, 16),
+        VMSTATE_UINT8_2DARRAY(phy_pages, hcd_state_t, 8, 8),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static void
+hcd_check_irq(hcd_state_t *s) {
+    if ((s->mmio.IntMask & 0x80000000) &&
+        (s->mmio.IntEvent & s->mmio.IntMask)) {
+        if (!s->irq_asserted) {
+            qemu_set_irq(s->irq, 1);
+            s->irq_asserted = 1;
+        }
+    } else {
+        if (s->irq_asserted) {
+            qemu_set_irq(s->irq, 0);
+            s->irq_asserted = 0;
+        }
+    }
+}
+
+static void
+hcd_soft_reset(hcd_state_t *s) {
+    s->mmio.BusOptions = 0x00008002; /* 5.11 */
+    s->mmio.HCControl &= 0x00C00000; /* 5.7.2 */
+}
+
+static void
+hcd_hard_reset(hcd_state_t *s) {
+    memset(&s->mmio, 0, sizeof(s->mmio));
+    s->mmio.Version = 0x00010010; /* Release 1.1 of OHCI spec */
+    s->mmio.BusID = 0x31333934; /* 1394 */
+    s->mmio.BusOptions = 0x00008002; /* 5.11 */
+    s->mmio.GUIDHi = 0x89abcdef;
+    s->mmio.GUIDLo = 0x01234567;
+    memset(&s->phy, 0, sizeof(s->phy));
+    s->phy.NumPorts = 1;
+    s->phy.L = 1;
+    s->phy.C = 1;
+    s->phy_pages[0][0] = 0x08; /* 0xFE; */
+    hcd_soft_reset(s);
+}
+
+static void
+hcd_complete_self_id(hcd_state_t *s) {
+    s->mmio.NodeID_nodeNumber = (s->root) ? 0 : 1; /* 5.11 */
+    s->mmio.NodeID_busNumber = 0x3ff;
+    s->mmio.NodeID_CPS = (s->state != HCD_STATE_CONNECTED) ? 0 : 1;
+    s->mmio.NodeID_root = s->root;
+    s->mmio.NodeID_iDValid = 1;
+    s->mmio.SelfIDCount_Size = 0;
+    s->mmio.SelfIDCount_Error = 0;
+    if (s->mmio.LinkControl & 0x00000200) { /* if RcvSelfID */
+        uint32_t tmp = 0;
+        self_id_t sid;
+
+        sid.val = 0;
+        sid.initiated = 1;
+        sid.p0 = 2;
+        sid.c = 1;
+        sid.L = 1;
+        sid.node_id = 0;
+        sid.type = 2;
+        dma_memory_write(&address_space_memory,
+                         s->mmio.SelfIDBuffer + 4,
+                         &sid.val, 4);
+        sid.val = ~sid.val;
+        dma_memory_write(&address_space_memory,
+                         s->mmio.SelfIDBuffer + 8,
+                         &sid.val, 4);
+        s->mmio.SelfIDCount_Size += 2;
+
+        if (s->state == HCD_STATE_CONNECTED) {
+            sid.val = 0;
+            sid.initiated = 0;
+            sid.p0 = 3;
+            sid.c = 0;
+            sid.L = 1;
+            sid.node_id = 1;
+            sid.type = 2;
+            dma_memory_write(&address_space_memory,
+                             s->mmio.SelfIDBuffer + 12,
+                             &sid.val, 4);
+            sid.val = ~sid.val;
+            dma_memory_write(&address_space_memory,
+                             s->mmio.SelfIDBuffer + 16,
+                             &sid.val, 4);
+            s->mmio.SelfIDCount_Size += 2;
+        }
+
+        tmp = (s->mmio.SelfIDCount_Generation << 16) | 1;
+        dma_memory_write(&address_space_memory,
+                         s->mmio.SelfIDBuffer,
+                         &tmp, 4);
+        s->mmio.SelfIDCount_Size++;
+    }
+    s->mmio.IntEvent |= 0x00018000; /* selfIDcomplete | selfIDcomplete2 */
+    hcd_check_irq(s);
+}
+
+typedef struct {
+    uint32_t req_count:16;
+    uint32_t:2;
+    uint32_t branch:2;
+    uint32_t interrupt:2;
+    uint32_t:2;
+    uint32_t key:3;
+    uint32_t status:1;
+    uint32_t cmd:4;
+    uint32_t data_address;
+    uint32_t branch_address;
+    uint32_t res_count:16;
+    uint32_t transfer_status:16;
+} hcd_ar_db_t;
+
+static void
+hcd_async_rx_rsp_packet(hcd_state_t *s, uint8_t *buf, uint32_t size,
+                        uint8_t response) {
+    int num = 3;
+    hcd_ar_db_t db;
+    uint32_t data_address = 0;
+    uint32_t status = 0;
+    int state = 0;
+
+    if (size == 0) {
+        return;
+    }
+    SET_Ax_EVENT_CODE(num, response);
+    dma_memory_read(&address_space_memory,
+                    Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+                    &db, sizeof(db));
+    data_address = db.data_address + db.req_count - db.res_count;
+    while (state != 3) {
+        int write_size;
+
+        db.transfer_status =
+                          s->mmio.AsyncResponseReceiveContextControl & 0xFFFF;
+        if (db.res_count == 0) {
+            dma_memory_write(&address_space_memory,
+                             Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+                             &db, sizeof(db));
+            if (db.branch_address == 0) {
+                CLR_Ax_ACTIVE(num);
+                /* TODO: need to roll back if this happens */
+            }
+            SET_Ax_COMMAND_PTR(num, db.branch_address);
+            dma_memory_read(&address_space_memory,
+                            Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+                            &db, sizeof(db));
+            data_address = db.data_address + db.req_count - db.res_count;
+        }
+        switch (state) {
+        case 0:
+            if (db.res_count > size) {
+                write_size = size;
+            } else {
+                write_size = db.res_count;
+            }
+            dma_memory_write(&address_space_memory,
+                             data_address,
+                             buf, write_size);
+            db.res_count -= write_size;
+            data_address += write_size;
+            size -= write_size;
+            buf += write_size;
+            if (size == 0) {
+                state = 1;
+            }
+            break;
+        case 1:
+            status = s->mmio.AsyncResponseReceiveContextControl << 16;
+            db.transfer_status =
+                           s->mmio.AsyncResponseReceiveContextControl & 0xFFFF;
+            dma_memory_write(&address_space_memory, data_address, &status, 4);
+            db.res_count -= 4;
+            data_address += 4;
+            dma_memory_write(&address_space_memory,
+                             Ax_COMMAND_PTR(num) & 0xFFFFFFF0,
+                             &db, sizeof(db));
+            state = 2;
+            break;
+        case 2:
+            /* this state exists to go around the loop again and update the db
+            if required */
+            state = 3;
+            break;
+        }
+    }
+    s->mmio.IntEvent |= (1 << 5);
+    hcd_check_irq(s);
+}
+
+static void
+hcd_async_rx_run(hcd_state_t *s, uint32_t addr) {
+    int num;
+
+    num = (addr & 0x0180) >> 7;
+    SET_Ax_ACTIVE(num);
+}
+
+static void
+hcd_async_rx_stop(hcd_state_t *s, uint32_t addr) {
+    int num;
+
+    num = (addr & 0x0180) >> 7;
+    CLR_Ax_ACTIVE(num);
+}
+
+static void
+hcd_async_rx_wake(hcd_state_t *s, uint32_t addr) {
+    uint32_t address;
+    hcd_ar_db_t db;
+    int num;
+
+    num = (addr & 0x0180) >> 7;
+    if (IS_Ax_ACTIVE(num)) {
+        return;
+    }
+    address = s->mmio.regs[(addr >> 2) + 0x00c];
+    dma_memory_read(&address_space_memory,
+                    address & 0xFFFFFFF0,
+                    &db, sizeof(db));
+    if ((db.branch_address & 0x0000000f) != 0) {
+        SET_Ax_ACTIVE(num);
+        SET_Ax_COMMAND_PTR(num, db.branch_address);
+    }
+}
+
+static void
+hcd_at_run(hcd_timer_state_t *t) {
+    hcd_state_t *s = t->s;
+    t->address = Ax_COMMAND_PTR(t->num) & 0xfffffff0;
+    t->response = EVT_TCODE_ERR;
+    SET_Ax_ACTIVE(t->num);
+}
+
+static void
+hcd_at_timer(void *o) {
+    hcd_timer_state_t *t = (hcd_timer_state_t *)o;
+    hcd_state_t *s = t->s;
+    ohci_packet_header_t packet_header;
+    hcd_at_db_t db;
+
+    if (IS_Ax_DEAD(t->num) || !IS_Ax_RUN(t->num)) {
+        CLR_Ax_WAKE(t->num);
+        CLR_Ax_ACTIVE(t->num);
+        return;
+    }
+    if (!IS_Ax_ACTIVE(t->num)) {
+        if (!IS_Ax_WAKE(t->num)) {
+            return;
+        }
+        CLR_Ax_WAKE(t->num);
+        dma_memory_read(&address_space_memory,
+                        t->address, &db,
+                        sizeof(hcd_at_db_t));
+        if (!(db.branch_address & 0x0000000f)) {
+            return;
+        }
+        SET_Ax_COMMAND_PTR(t->num, db.branch_address);
+        hcd_at_run(t); /* also sets active */
+    }
+    CLR_Ax_WAKE(t->num);
+    dma_memory_read(&address_space_memory,
+                    t->address, &db,
+                    sizeof(hcd_at_db_t));
+    if (db.cmd == 0 && db.key == 0) {
+        /* Do nothing */
+    } else if (db.cmd == 0 && db.key == 2) {
+        /* OUTPUT_MORE_Immediate */
+    } else if (db.cmd == 1 && db.key == 0) {
+        /* OUTPUT_LAST */
+    } else if (db.cmd == 1 && db.key == 2) {
+        /* OUTPUT_LAST_Immediate */
+    } else {
+        /* UNKNOWN COMMAND */
+        return ;
+    }
+
+    switch (db.key) {
+    case 0: { /* non-Immediate */
+        uint8_t buf[65536];
+        dma_memory_read(&address_space_memory,
+                        db.data_address, buf,
+                        db.req_count);
+        qemu_chr_fe_write(s->chr, buf, db.req_count);
+        break;
+    }
+    case 2: { /* Immediate */
+        uint32_t data[4];
+        dma_memory_read(&address_space_memory,
+                        t->address + sizeof(hcd_at_db_t),
+                        data, db.req_count);
+
+        packet_header = *(ohci_packet_header_t *)data;
+        switch (packet_header.t_code) {
+        case 0x00: { /* quadlet write - quadlet format */
+            ohci_req_quadlet_packet_t at_packet =
+                                            *(ohci_req_quadlet_packet_t *)data;
+            qemu_chr_fe_write(s->chr, (uint8_t *)data, sizeof(at_packet));
+            t->response = ACK_PENDING;
+            break;
+        }
+        case 0x01: { /* block write - block write format */
+            qemu_chr_fe_write(s->chr, (uint8_t *)data, db.req_count);
+            t->response = ACK_PENDING;
+            break;
+        }
+        case 0x04: { /* quadlet read - nodata format */
+            qemu_chr_fe_write(s->chr, (uint8_t *)data, db.req_count);
+            t->response = ACK_PENDING;
+            break;
+        }
+        case 0x05: { /* read bytes from target */
+            qemu_chr_fe_write(s->chr, (uint8_t *)data, db.req_count);
+            t->response = ACK_PENDING;
+            break;
+        }
+        case 0x0e: { /* PHY packet */
+            /* probably just configuring the gap count... */
+            t->response = ACK_COMPLETE;
+            /* reset because PHY packet */
+            hcd_bus_reset(s); /* not all PHY packets require reset... */
+            break;
+        }
+        default:
+            break;
+        }
+        break;
+    }
+    default:
+        break;
+    }
+    if (db.cmd == 0) { /* more */
+        if (db.key == 2) {
+            t->address += sizeof(hcd_at_db_t) + sizeof(int32_t) * 4;
+        } else {
+            t->address += sizeof(hcd_at_db_t);
+        }
+    } else { /* last */
+        if (db.interrupt == 3) {
+            s->mmio.IntEvent |= (1 << t->num);
+        }
+        SET_Ax_EVENT_CODE(t->num, t->response);
+        db.transfer_status = (uint16_t)Ax_CONTEXT_CONTROL(t->num);
+        dma_memory_write(&address_space_memory, t->address, &db, sizeof(db));
+        if ((db.branch_address & 0x0000000f) == 0) {
+            CLR_Ax_ACTIVE(t->num);
+            return;
+        }
+        SET_Ax_COMMAND_PTR(t->num, db.branch_address);
+        hcd_at_run(t);
+    }
+    timer_mod(t->timer, 0);
+    /* maybe
+    t_now + get_ticks_per_sec() / 100000);
+    100/sec isn't going to be right */
+}
+
+static void
+hcd_bus_reset(hcd_state_t *s) {
+    uint32_t bus_reset_packet[3] = {0x000000e0, 0x00000000, 0x00000000};
+    s->mmio.NodeID_busNumber = 0x3ff;
+    s->mmio.NodeID_CPS = 0;
+    s->mmio.NodeID_root = 0;
+    s->mmio.NodeID_iDValid = 0;
+    s->mmio.SelfIDCount_Generation++;
+    s->mmio.IntEvent |= 0x00020000; /* bus reset complete */
+    if (s->state != HCD_STATE_CONNECTED) {
+        s->root = 1;
+    }
+    s->mmio.AsyncRequestTransmitContextControl &= 0xFFFFFBFF;
+    s->mmio.AsyncResponseTransmitContextControl &= 0xFFFFFBFF;
+    if (s->mmio.AsyncResponseReceiveContextControl & 0x00008000) {
+        bus_reset_packet[2] |= s->mmio.SelfIDCount_Generation << 16;
+        hcd_async_rx_rsp_packet(s, (uint8_t *)bus_reset_packet,
+                                sizeof(bus_reset_packet), EVT_BUS_RESET);
+    }
+    hcd_complete_self_id(s);
+}
+
+static uint8_t
+hcd_phy_read(hcd_state_t *s, uint8_t reg) {
+    if (reg < 8) {
+        return s->phy.bytes[reg];
+    } else {
+        return s->phy_pages[s->phy.PageSelect][reg & 7];
+    }
+}
+
+static void
+hcd_phy_write(hcd_state_t *s, uint8_t reg, uint8_t data) {
+    if (reg < 8) {
+        switch (reg) {
+        case 0: /* not allowed? */
+            break;
+        case 1:
+            s->phy.bytes[reg] = data & 0xBF;
+            if (data & 0x40) {
+                hcd_bus_reset(s);
+            }
+            break;
+        case 5:
+            s->phy.bytes[reg] = data & 0xBF;
+            if (data & 0x40) {
+                hcd_bus_reset(s);
+            }
+            break;
+        default:
+            s->phy.bytes[reg] = data;
+            break;
+        }
+    } else {
+        s->phy_pages[s->phy.PageSelect][reg & 7] = data;
+    }
+}
+
+static uint64_t hcd_mmio_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t ret;
+    hcd_state_t *s = (hcd_state_t *)opaque;
+    switch (addr) {
+    case REG_OFFSET(IntEventMasked): /* 0084 */
+        ret = s->mmio.IntEvent & s->mmio.IntMask;
+         break;
+    default:
+        ret = s->mmio.regs[addr >> 2];
+        break;
+    }
+    if (addr != 0x0080) {
+        /* what to do? */
+    }
+    return ret;
+}
+
+static void hcd_mmio_write(void *opaque, hwaddr addr, uint64_t data,
+                           unsigned size)
+{
+    hcd_state_t *s = (hcd_state_t *)opaque;
+    DECLARE_PHY phy_control;
+    DECLARE_NODE_ID NodeID;
+
+    if ((addr & 0xFFE0) != 0x0100) {
+        /* what to do? */
+    }
+    switch (addr) {
+    case REG_OFFSET(ATRetries): /* 0008 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(CSRWriteData):    /* 00c */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(CSRCompareData): /* 010 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(CSRControl):     /* 014 */
+        switch (data & 0x00000003) {
+        case 0: /* BUS_MANAGER_ID */
+            /* TODO: set bus manager somewhere... */
+            s->mmio.CSRReadData = s->mmio.CSRCompareData;
+            s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+            break;
+        case 1: /* BANDWIDTH_AVAILABLE */
+            /* not actioned */
+            s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+            break;
+        case 2: /* CHANNELS_AVAILABLE_HI */
+            /* not actioned */
+            s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+            break;
+        case 3: /* CHANNELS_AVAILABLE_LO */
+            /* not actioned */
+            s->mmio.CSRControl = 0x80000000 | (data & 0x00000003);
+            break;
+        }
+        break;
+    case REG_OFFSET(ConfigROMhdr): /* 0018 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(BusID): /* 001c */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(BusOptions): /* 0020 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(GUIDHi): /* 0024 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(GUIDLo): /* 0028 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(ConfigROMMap): /* 0034 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(HCControlSet): /* 0050 */
+        data &= 0xE0CF0000;
+        s->mmio.HCControl |= data;
+        if (data & HCCONTROL_RESET_MASK) {
+            /* do a reset */
+            hcd_soft_reset(s);
+        }
+        if (data & HCCONTROL_LINK_ENABLE_MASK) {
+            if ((s->state == HCD_STATE_DISCONNECTED) ||
+                (s->state == HCD_STATE_ARBITRATION1)) {
+                uint32_t buf = 0xFFFFFFFF;
+                qemu_chr_fe_write(s->chr, (uint8_t *)&buf, 4);
+            }
+        }
+        break;
+    case REG_OFFSET(HCControlClear): /* 0054 */
+        data &= 0xE0CE0000;
+        s->mmio.HCControl &= ~data;
+        break;
+    case REG_OFFSET(SelfIDBuffer): /* 0064 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(SelfIDCount): /* 0068 */
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    case REG_OFFSET(IRMultiChanMaskHiSet): /* 0070 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(IRMultiChanMaskHiClear): /* 0074 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(IRMultiChanMaskLoSet): /* 0078 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(IRMultiChanMaskLoClear): /* 007c */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(IntEventSet): /* 0080 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        break;
+    case REG_OFFSET(IntEventClear): /* 0084 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        break;
+    case REG_OFFSET(IntMaskSet): /* 0088 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        break;
+    case REG_OFFSET(IntMaskClear): /* 008c */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        break;
+    case REG_OFFSET(IsoXmitIntMaskSet):
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        break;
+    case REG_OFFSET(IsoXmitIntMaskClear):
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        break;
+    case REG_OFFSET(IsoRecvIntMaskSet):
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        break;
+    case REG_OFFSET(IsoRecvIntMaskClear):
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        break;
+    case REG_OFFSET(LinkControlSet):
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        break;
+    case REG_OFFSET(LinkControlClear):
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        break;
+    case REG_OFFSET(NodeID): /* 00E8 */
+        NodeID.NodeID = data;
+        s->mmio.NodeID_busNumber = NodeID.NodeID_busNumber;
+        break;
+    case REG_OFFSET(PhyControl): /* 00ec */
+        *(uint32_t *)&phy_control = data;
+        s->mmio.PhyControl_regAddr = phy_control.PhyControl_regAddr;
+        if (phy_control.PhyControl_rdReg) {
+            s->mmio.PhyControl_rdAddr = phy_control.PhyControl_regAddr;
+            s->mmio.PhyControl_rdData =
+                               hcd_phy_read(s, phy_control.PhyControl_regAddr);
+            s->mmio.PhyControl_rdDone = 1;
+            s->mmio.IntEvent_phyRegRcvd = 1;
+        }
+        if (phy_control.PhyControl_wrReg) {
+            hcd_phy_write(s, phy_control.PhyControl_regAddr,
+                          phy_control.PhyControl_wrData);
+            s->mmio.PhyControl_wrData = phy_control.PhyControl_wrData;
+            s->mmio.PhyControl_rdDone = 0;
+        }
+        break;
+    case REG_OFFSET(AsynchronousRequestFilterHiSet): /* 0x100 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(AsynchronousRequestFilterHiClear): /* 0x104 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(AsynchronousRequestFilterLoSet): /* 0x108 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(AsynchronousRequestFilterLoClear): /* 0x10c */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(PhysicalRequestFilterHiSet): /* 0x110 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(PhysicalRequestFilterHiClear): /* 0x114 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(PhysicalRequestFilterLoSet): /* 0x118 */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(PhysicalRequestFilterLoClear): /* 0x11c */
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(AsyncRequestTransmitContextControlSet):
+    case REG_OFFSET(AsyncResponseTransmitContextControlSet):
+        data &= 0x00009000;
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        if (data & 0x00009000) {
+            hcd_timer_state_t *t = NULL;
+            if (addr == REG_OFFSET(AsyncRequestTransmitContextControlSet)) {
+                t = &s->at_req_timer;
+            } else {
+                t = &s->at_rsp_timer;
+            }
+            if (data & 0x00008000) {
+                hcd_at_run(t);
+            }
+            timer_mod(t->timer, 0);
+        }
+        break;
+    case REG_OFFSET(AsyncRequestReceiveContextControlSet):
+    case REG_OFFSET(AsyncResponseReceiveContextControlSet):
+        data &= 0x00009000;
+        s->mmio.regs[(addr >> 2) & 0xFFFE] |= data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        if (data & 0x00008000) {
+            hcd_async_rx_run(s, addr & 0xFFE0);
+        }
+        if (data & 0x00001000) {
+            hcd_async_rx_wake(s, addr & 0xFFE0);
+        }
+        break;
+    case REG_OFFSET(AsyncRequestTransmitContextControlClear):
+    case REG_OFFSET(AsyncResponseTransmitContextControlClear):
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        break;
+    case REG_OFFSET(AsyncRequestReceiveContextControlClear):
+    case REG_OFFSET(AsyncResponseReceiveContextControlClear):
+        data &= 0x00008000;
+        s->mmio.regs[(addr >> 2) & 0xFFFE] &= ~data;
+        s->mmio.regs[((addr >> 2) & 0xFFFE) + 1] =
+                                          s->mmio.regs[((addr >> 2) & 0xFFFE)];
+        if (data & 0x00008000) {
+            hcd_async_rx_stop(s, addr & 0xFFE0);
+        }
+        break;
+    default:
+        s->mmio.regs[addr >> 2] = data;
+        break;
+    }
+    hcd_check_irq(s);
+}
+
+static const MemoryRegionOps hcd_mmio_ops = {
+    .read = hcd_mmio_read,
+    .write = hcd_mmio_write,
+    .endianness = DEVICE_LITTLE_ENDIAN, /* TODO: might change with arch */
+};
+
+static int hcd_chr_can_receive(void *opaque)
+{
+    if (runstate_check(RUN_STATE_INMIGRATE)) {
+        /* this seems to race with the restore
+        RUN_STATE_INMIGRATE */
+        return 0;
+    } else {
+        return 8192;
+    }
+}
+
+static void hcd_fill_buffer(hcd_state_t *s, const uint8_t **buf, int *len,
+                            int required)
+{
+    int to_copy;
+
+    if (s->bufpos >= required) {
+        return;
+    }
+    if (required - s->bufpos > *len) {
+        to_copy = *len;
+    } else {
+        to_copy = required - s->bufpos;
+    }
+
+    memcpy(s->buf + s->bufpos, *buf, to_copy);
+    *buf += to_copy;
+    *len -= to_copy;
+    s->bufpos += to_copy;
+}
+
+static void hcd_chr_receive(void *opaque, const uint8_t *buf, int len)
+{
+    hcd_state_t *s = (hcd_state_t *)opaque;
+    uint16_t received_bid;
+    struct timeval tv;
+    ohci_packet_header_t *packet_header;
+
+    while (len) {
+        switch (s->state) {
+        case HCD_STATE_UNPLUGGED:
+            /* restore races with chr event, just fake it here */
+            hcd_chr_event(s, CHR_EVENT_OPENED);
+            break;
+        case HCD_STATE_MAGIC: /* waiting for magic */
+            hcd_fill_buffer(s, &buf, &len, 4);
+            if (s->bufpos < 4) {
+                /* not enough data yet HCD_MAGIC */
+                break;
+            }
+            if (s->bufpos > 4) {
+                /* overflow HCD_MAGIC */
+                break;
+            }
+            if (memcmp(s->buf, "1394", 4) != 0) {
+                /* TODO: what do we do here? drop the connection I suppose */
+                break;
+            } else {
+                s->state = HCD_STATE_DISCONNECTED;
+            }
+            s->bufpos = 0;
+            break;
+        case HCD_STATE_DISCONNECTED:
+            hcd_fill_buffer(s, &buf, &len, 4);
+            if (s->bufpos < 4) {
+                /* not enough data yet HCD_STATE_DISCONNECTED */
+                return;
+            }
+            s->bufpos = 0;
+            if (*(uint32_t *)s->buf != 0xFFFFFFFF) {
+                /* unknown data */
+                break;
+            }
+            s->other_link = 1;
+            /* link change - connected */
+            s->state = HCD_STATE_ARBITRATION1;
+            if (!(s->mmio.HCControl & HCCONTROL_LINK_ENABLE_MASK)) {
+                /* we will progress when our link comes up and the other end
+                sends a bid */
+                break;
+            }
+            /* fall through as we won't go around again because len == 0 */
+        case HCD_STATE_ARBITRATION1:
+            gettimeofday(&tv, NULL);
+            s->bid = 0;
+            s->bid ^= (tv.tv_sec >> 0) & 0xFFFF;
+            s->bid ^= (tv.tv_sec >> 16) & 0xFFFF;
+            s->bid ^= (tv.tv_sec >> 32) & 0xFFFF;
+            s->bid ^= (tv.tv_sec >> 48) & 0xFFFF;
+            s->bid ^= (tv.tv_usec >> 0) & 0xFFFF;
+            s->bid ^= (tv.tv_usec >> 16) & 0xFFFF;
+            s->bid ^= (tv.tv_usec >> 32) & 0xFFFF;
+            s->bid ^= (tv.tv_usec >> 48) & 0xFFFF;
+            s->bid &= 0x7FFF;
+            /* TODO: set high bit based on preference to become root */
+            qemu_chr_fe_write(s->chr, (uint8_t *)&s->bid, 2);
+            s->state = HCD_STATE_ARBITRATION2;
+            break;
+        case HCD_STATE_ARBITRATION2:
+            hcd_fill_buffer(s, &buf, &len, 2);
+            if (s->bufpos < 2) {
+                /* not enough data yet HCD_STATE_ARBITRATION2 */
+                break;
+            }
+            received_bid = *(uint16_t *)s->buf;
+            s->bufpos = 0;
+            if (received_bid == s->bid) {
+                s->state = HCD_STATE_ARBITRATION1;
+                break;
+            } else if (received_bid < s->bid) {
+                s->root = 1;
+                s->state = HCD_STATE_CONNECTED;
+            } else {
+                s->root = 0;
+                s->state = HCD_STATE_CONNECTED;
+            }
+            hcd_bus_reset(s);
+            break;
+        case HCD_STATE_CONNECTED:
+            if (!(s->mmio.HCControl & HCCONTROL_LINK_ENABLE_MASK)) {
+                return;
+            }
+            hcd_fill_buffer(s, &buf, &len, 4);
+            if (s->bufpos < 4) {
+                /* not enough data yet HCD_STATE_CONNECTED */
+                return;
+            }
+            if (*(uint32_t *)s->buf == 0xFFFFFFFE) {
+                /* Reset because link change */
+                s->bufpos = 0;
+                s->state = HCD_STATE_DISCONNECTED;
+                hcd_bus_reset(s);
+                break;
+            }
+            packet_header = (ohci_packet_header_t *)s->buf;
+
+            switch (packet_header->t_code) {
+            case 0x00: { /* request - quadlet write */
+                ohci_req_quadlet_packet_t *req_packet;
+                ohci_rsp_nodata_packet_t rsp_packet;
+                hcd_fill_buffer(s, &buf, &len, sizeof(*req_packet));
+                if (s->bufpos < sizeof(*req_packet)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 00 */
+                    return;
+                }
+                if (s->bufpos > sizeof(*req_packet)) {
+                    /* overflow HCD_STATE_CONNECTED 00 */
+                    return;
+                }
+                req_packet = (ohci_req_quadlet_packet_t *)s->buf;
+                dma_memory_write(&address_space_memory,
+                                 req_packet->destination_offset_low,
+                                 &req_packet->data, sizeof(uint32_t));
+                /* forward to ar or handle here?? */
+                rsp_packet.t_code = 0x02;
+                rsp_packet.rt = req_packet->rt;
+                rsp_packet.t_label = req_packet->t_label;
+                rsp_packet.r_code = RESP_COMPLETE;
+                rsp_packet.destination_id = req_packet->destination_id ^ 1;
+                rsp_packet.source_id = req_packet->destination_id;
+                qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_packet,
+                                  sizeof(rsp_packet));
+                s->bufpos = 0;
+                break;
+            }
+            case 0x01: { /* request - block write */
+                ohci_req_block_packet_t *req_packet;
+                ohci_rsp_nodata_packet_t rsp_packet;
+                hcd_fill_buffer(s, &buf, &len, sizeof(*req_packet));
+                if (s->bufpos < sizeof(*req_packet)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 01 */
+                    return;
+                }
+                req_packet = (ohci_req_block_packet_t *)s->buf;
+                hcd_fill_buffer(s, &buf, &len,
+                                sizeof(*req_packet) + req_packet->data_length);
+                if (s->bufpos < (sizeof(*req_packet) +
+                                  req_packet->data_length)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 01 */
+                    return;
+                }
+                if (s->bufpos > (sizeof(*req_packet) +
+                                  req_packet->data_length)) {
+                    /* overflow HCD_STATE_CONNECTED 01 */
+                    return;
+                }
+                dma_memory_write(&address_space_memory,
+                                 req_packet->destination_offset_low,
+                                 s->buf + sizeof(*req_packet),
+                                 req_packet->data_length);
+                /* forward to ar or handle here?? */
+                rsp_packet.t_code = 0x02;
+                rsp_packet.rt = req_packet->rt;
+                rsp_packet.t_label = req_packet->t_label;
+                rsp_packet.r_code = RESP_COMPLETE;
+                rsp_packet.destination_id = req_packet->destination_id ^ 1;
+                rsp_packet.source_id = req_packet->destination_id;
+                qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_packet,
+                                  sizeof(rsp_packet));
+                s->bufpos = 0;
+                break;
+            }
+            case 0x02: { /* response - quadlet write */
+                ohci_rsp_nodata_packet_t *rsp_packet;
+                hcd_fill_buffer(s, &buf, &len, sizeof(*rsp_packet));
+                if (s->bufpos < sizeof(*rsp_packet)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 02 */
+                    return;
+                }
+                if (s->bufpos > sizeof(*rsp_packet)) {
+                    /* overflow HCD_STATE_CONNECTED 02 */
+                    return;
+                }
+                rsp_packet = (ohci_rsp_nodata_packet_t *)s->buf;
+                hcd_async_rx_rsp_packet(s, (uint8_t *)rsp_packet,
+                                        sizeof(*rsp_packet), ACK_COMPLETE);
+                s->bufpos = 0;
+                break;
+            }
+            case 0x04: { /* request - quadlet read */
+                ohci_req_nodata_packet_t *req_nodata_packet;
+                ohci_rsp_quadlet_packet_t rsp_quadlet_packet;
+                hcd_fill_buffer(s, &buf, &len, 12);
+                if (s->bufpos < 12) {
+                    /* not enough data yet HCD_STATE_CONNECTED 04 */
+                    return;
+                }
+                if (s->bufpos > 12) {
+                    /* overflow HCD_STATE_CONNECTED 04 */
+                    return;
+                }
+                req_nodata_packet = (ohci_req_nodata_packet_t *)s->buf;
+                /* forward to ar or handle here?? */
+                rsp_quadlet_packet.t_code = 0x06;
+                rsp_quadlet_packet.rt = req_nodata_packet->rt;
+                rsp_quadlet_packet.t_label = req_nodata_packet->t_label;
+                rsp_quadlet_packet.destination_id =
+                                         req_nodata_packet->destination_id ^ 1;
+                rsp_quadlet_packet.source_id =
+                                             req_nodata_packet->destination_id;
+                if (req_nodata_packet->destination_offset_high == 0xFFFF) {
+                    if (0xF0000400 ==
+                        (req_nodata_packet->destination_offset_low &
+                                 0xFFFFFC00)) {
+                        uint32_t tmp_addr = s->mmio.ConfigROMMap +
+                           (req_nodata_packet->destination_offset_low & 0x3ff);
+
+                        dma_memory_read(&address_space_memory,
+                                        tmp_addr,
+                                        &rsp_quadlet_packet.data,
+                                        sizeof(uint32_t));
+                        rsp_quadlet_packet.r_code = RESP_COMPLETE;
+                    } else {
+                        /* Unknown address */
+                        rsp_quadlet_packet.r_code = RESP_ADDRESS_ERROR;
+                    }
+                } else if ((req_nodata_packet->destination_offset_high) ==
+                                               0x0000) {
+                    if (dma_memory_read(
+                                 &address_space_memory,
+                                 req_nodata_packet->destination_offset_low,
+                                 &rsp_quadlet_packet.data, sizeof(uint32_t))) {
+                        rsp_quadlet_packet.r_code = RESP_ADDRESS_ERROR;
+                    } else {
+                        rsp_quadlet_packet.r_code = RESP_COMPLETE;
+                    }
+                } else {
+                    /* Unknown address */
+                    rsp_quadlet_packet.r_code = RESP_ADDRESS_ERROR;
+                }
+
+                qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_quadlet_packet,
+                                  sizeof(rsp_quadlet_packet));
+                s->bufpos = 0;
+                break;
+            }
+            case 0x05: { /* request - block read */
+                ohci_req_block_packet_t *req_packet;
+                ohci_rsp_block_packet_t rsp_packet;
+                uint8_t bounce_buffer[65536];
+                hcd_fill_buffer(s, &buf, &len, sizeof(*req_packet));
+                if (s->bufpos < sizeof(*req_packet)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 05 */
+                    return;
+                }
+                if (s->bufpos > sizeof(*req_packet)) {
+                    /* overflow HCD_STATE_CONNECTED 05 */
+                    return;
+                }
+                req_packet = (ohci_req_block_packet_t *)s->buf;
+                /* forward to ar or handle here?? */
+                rsp_packet.t_code = 0x07;
+                rsp_packet.rt = req_packet->rt;
+                rsp_packet.t_label = req_packet->t_label;
+                rsp_packet.destination_id = req_packet->destination_id ^ 1;
+                rsp_packet.source_id = req_packet->destination_id;
+                rsp_packet.data_length = req_packet->data_length;
+                if (req_packet->destination_offset_high == 0xFFFF) {
+                    if ((req_packet->destination_offset_low & 0xFFFFFC00) ==
+                                                                  0xF0000400) {
+                        uint32_t tmp_addr = s->mmio.ConfigROMMap +
+                                  (req_packet->destination_offset_low & 0x3ff);
+                        dma_memory_read(&address_space_memory,
+                                        tmp_addr,
+                                        bounce_buffer, rsp_packet.data_length);
+                        rsp_packet.r_code = RESP_COMPLETE;
+                    } else {
+                        /* Unknown address */
+                        rsp_packet.r_code = RESP_ADDRESS_ERROR;
+                    }
+                } else if ((req_packet->destination_offset_high) == 0x0000) {
+                    if (dma_memory_read(&address_space_memory,
+                                        req_packet->destination_offset_low,
+                                        bounce_buffer,
+                                        rsp_packet.data_length)) {
+                        /* address error */
+                        rsp_packet.r_code = RESP_ADDRESS_ERROR;
+                    } else {
+                        rsp_packet.r_code = RESP_COMPLETE;
+                    }
+                } else {
+                    /* Unknown address */
+                    rsp_packet.r_code = RESP_ADDRESS_ERROR;
+                }
+                qemu_chr_fe_write(s->chr, (uint8_t *)&rsp_packet,
+                                  sizeof(rsp_packet));
+                if (rsp_packet.r_code == RESP_COMPLETE) {
+                    qemu_chr_fe_write(s->chr, bounce_buffer,
+                                      rsp_packet.data_length);
+                }
+                s->bufpos = 0;
+                break;
+            }
+            case 0x06: { /* response - quadlet read */
+                ohci_rsp_quadlet_packet_t *rsp_packet;
+                hcd_fill_buffer(s, &buf, &len, sizeof(*rsp_packet));
+                if (s->bufpos < sizeof(*rsp_packet)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 4 */
+                    return;
+                }
+                if (s->bufpos > sizeof(*rsp_packet)) {
+                    /* overflow HCD_STATE_CONNECTED 4 */
+                    return;
+                }
+                rsp_packet = (ohci_rsp_quadlet_packet_t *)s->buf;
+
+                hcd_async_rx_rsp_packet(s, (uint8_t *)rsp_packet,
+                                        sizeof(*rsp_packet), ACK_COMPLETE);
+                s->bufpos = 0;
+                break;
+            }
+            case 0x07: { /* response - block read */
+                ohci_rsp_block_packet_t *rsp_packet;
+                hcd_fill_buffer(s, &buf, &len, sizeof(*rsp_packet));
+                if (s->bufpos < sizeof(*rsp_packet)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 07 */
+                    return;
+                }
+                rsp_packet = (ohci_rsp_block_packet_t *)s->buf;
+                hcd_fill_buffer(s, &buf, &len,
+                                sizeof(*rsp_packet) + rsp_packet->data_length);
+                if (s->bufpos <
+                             (sizeof(*rsp_packet) + rsp_packet->data_length)) {
+                    /* not enough data yet HCD_STATE_CONNECTED 07 */
+                    return;
+                }
+                if (s->bufpos >
+                             (sizeof(*rsp_packet) + rsp_packet->data_length)) {
+                    /* overflow HCD_STATE_CONNECTED 07 */
+                    return;
+                }
+                hcd_async_rx_rsp_packet(s, (uint8_t *)rsp_packet,
+                                        sizeof(*rsp_packet) +
+                                                       rsp_packet->data_length,
+                                        ACK_COMPLETE);
+                s->bufpos = 0;
+                break;
+            }
+            default:
+                /* unknown t_code */
+                break;
+            }
+            return;
+        }
+    }
+}
+
+static void hcd_chr_event(void *opaque, int event)
+{
+    hcd_state_t *s = (hcd_state_t *)opaque;
+
+    if (runstate_check(RUN_STATE_INMIGRATE)) {
+        /* RUN_STATE_INMIGRATE */
+        return;
+    }
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        s->state = HCD_STATE_MAGIC;
+        qemu_chr_fe_write(s->chr, (uint8_t *)"1394", 4);
+        if (s->mmio.HCControl & HCCONTROL_LINK_ENABLE_MASK) {
+            uint32_t buf = 0xFFFFFFFF;
+            qemu_chr_fe_write(s->chr, (uint8_t *)&buf, 4);
+            if (s->other_link) {
+                hcd_bus_reset(s);
+            }
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        s->state = HCD_STATE_UNPLUGGED;
+        s->phy_pages[0][0] = 0x08; /* 0xFE ? */
+        /* TODO: interrupt? */
+        s->phy.PEI = 1;
+        s->mmio.IntEvent |= (1 << 19);
+        hcd_bus_reset(s);
+        break;
+    default:
+        break;
+    }
+}
+
+static int
+hcd_pci_init(PCIDevice *pci_dev) {
+    hcd_state_t *s = DO_UPCAST(hcd_state_t, pci_dev, pci_dev);
+    uint8_t *pci_conf = pci_dev->config;
+
+    pci_set_byte(pci_conf + PCI_CLASS_PROG, 0x10);
+    pci_set_word(pci_conf + PCI_STATUS,
+                 PCI_STATUS_DEVSEL_MEDIUM | PCI_STATUS_FAST_BACK);
+    pci_set_byte(pci_conf + PCI_INTERRUPT_PIN, 1);
+    pci_set_byte(pci_conf + PCI_MIN_GNT, 0x08);
+
+    memory_region_init_io(&s->mmio_bar, OBJECT(s), &hcd_mmio_ops, s,
+                          "ohci-1394-mmio", OHCI_1394_MMIO_SIZE);
+    pci_register_bar(&s->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
+                     &s->mmio_bar);
+    s->irq = pci_allocate_irq(&s->pci_dev);
+    s->at_req_timer.s = s;
+    s->at_req_timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hcd_at_timer,
+                                         &s->at_req_timer);
+    s->at_req_timer.num = 0;
+    s->at_rsp_timer.s = s;
+    s->at_rsp_timer.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hcd_at_timer,
+                                         &s->at_rsp_timer);
+    s->at_rsp_timer.num = 1;
+    qemu_chr_add_handlers(s->chr, hcd_chr_can_receive, hcd_chr_receive,
+                          hcd_chr_event, s);
+    hcd_hard_reset(s);
+    return 0;
+}
+
+static void
+hcd_pci_exit(PCIDevice *pci_dev)
+{
+    /*
+    hcd_state_t *s = DO_UPCAST(hcd_state_t, pci_dev, pci_dev);
+    memory_region_destroy(&s->mmio_bar); */
+}
+
+static Property hcd_properties[] = {
+    DEFINE_PROP_CHR("chardev", hcd_state_t, chr),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void
+hcd_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->init = hcd_pci_init;
+    k->exit = hcd_pci_exit;
+    k->vendor_id = PCI_VENDOR_ID_QEMU;
+    k->device_id = 0x1394;
+    k->class_id = 0x0C00;
+    dc->vmsd = &vmstate_pci_hcd;
+    dc->props = hcd_properties;
+}
+
+static const TypeInfo hcd_info = {
+    .name          = "ohci-1394",
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(hcd_state_t),
+    .class_init    = hcd_class_init,
+};
+
diff --git a/hw/1394/hcd-ohci.h b/hw/1394/hcd-ohci.h
new file mode 100644
index 0000000..b150175
--- /dev/null
+++ b/hw/1394/hcd-ohci.h
@@ -0,0 +1,147 @@
+#ifndef HCD_OHCI_H
+#define HCD_OHCI_H
+
+#include "hw/hw.h"
+#include "hw/pci/pci.h"
+#include "hcd-ohci.h"
+#include "hw/loader.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/char.h"
+#include "qemu/timer.h"
+
+#define EVT_NO_STATUS  0x00
+#define EVT_UNDERRUN   0x04
+#define EVT_OVERRUN    0x05
+#define EVT_DATA_READ  0x07
+#define EVT_DATA_WRITE 0x08
+#define EVT_BUS_RESET  0x09
+#define EVT_TCODE_ERR  0x0B
+#define EVT_UNKNOWN    0x0E
+#define EVT_FLUSHED    0x0F
+#define ACK_COMPLETE   0x11
+#define ACK_PENDING    0x12
+
+#define RESP_COMPLETE       0x00
+#define RESP_CONFLICT_ERROR 0x04
+#define RESP_DATA_ERROR     0x05
+#define RESP_TYPE_ERROR     0x06
+#define RESP_ADDRESS_ERROR  0x07
+
+typedef union {
+    uint32_t qdata[3];
+    struct {
+        uint32_t:4;
+        uint32_t t_code:4;
+        uint32_t rt:2;
+        uint32_t t_label:6;
+        uint32_t spd:3;
+        uint32_t:4;
+        uint32_t src_bus_id:1;
+        uint32_t:8;
+    };
+} ohci_packet_header_t;
+
+typedef union {
+    uint32_t qdata[3];
+    struct {
+        uint32_t:4;
+        uint32_t t_code:4;
+        uint32_t rt:2;
+        uint32_t t_label:6;
+        uint32_t spd:3;
+        uint32_t:4;
+        uint32_t src_bus_id:1;
+        uint32_t:8;
+        uint32_t destination_offset_high:16;
+        uint32_t destination_id:16;
+        uint32_t destination_offset_low:32;
+    };
+} ohci_req_nodata_packet_t;
+
+typedef union {
+    uint32_t qdata[3];
+    struct {
+        uint32_t:4;
+        uint32_t t_code:4;
+        uint32_t rt:2;
+        uint32_t t_label:6;
+        uint32_t spd:3;
+        uint32_t:4;
+        uint32_t src_bus_id:1;
+        uint32_t:8;
+        uint32_t destination_offset_high:16;
+        uint32_t destination_id:16;
+        uint32_t destination_offset_low:32;
+        uint32_t data;
+    };
+} ohci_req_quadlet_packet_t;
+
+typedef union {
+    uint32_t qdata[4];
+    struct {
+        uint32_t:4;
+        uint32_t t_code:4;
+        uint32_t rt:2;
+        uint32_t t_label:6;
+        uint32_t spd:3;
+        uint32_t:4;
+        uint32_t src_bus_id:1;
+        uint32_t:8;
+        uint32_t destination_offset_high:16;
+        uint32_t destination_id:16;
+        uint32_t destination_offset_low:32;
+        uint32_t:16;
+        uint32_t data_length:16;
+    };
+} ohci_req_block_packet_t;
+
+typedef union {
+    uint32_t qdata[3];
+    struct {
+        uint32_t:4;
+        uint32_t t_code:4;
+        uint32_t rt:2;
+        uint32_t t_label:6;
+        uint32_t destination_id:16;
+        uint32_t:12;
+        uint32_t r_code:4;
+        uint32_t source_id:16;
+        uint32_t:32;
+    };
+} ohci_rsp_nodata_packet_t;
+
+typedef union {
+    uint32_t qdata[4];
+    struct {
+        uint32_t:4;
+        uint32_t t_code:4;
+        uint32_t rt:2;
+        uint32_t t_label:6;
+        uint32_t destination_id:16;
+        uint32_t:12;
+        uint32_t r_code:4;
+        uint32_t source_id:16;
+        uint32_t:32;
+        uint32_t data;
+    };
+} ohci_rsp_quadlet_packet_t;
+
+typedef union {
+    uint32_t qdata[4];
+    struct {
+        uint32_t:4;
+        uint32_t t_code:4;
+        uint32_t rt:2;
+        uint32_t t_label:6;
+        uint32_t destination_id:16;
+        uint32_t:12;
+        uint32_t r_code:4;
+        uint32_t source_id:16;
+        uint32_t:32;
+        uint32_t:16;
+        uint32_t data_length:16;
+    };
+} ohci_rsp_block_packet_t;
+
+#endif
+
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 73afa41..c3baffa 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -1,4 +1,5 @@
 devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call 
land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/
+devices-dirs-$(CONFIG_SOFTMMU) += 1394/
 devices-dirs-$(CONFIG_ACPI) += acpi/
 devices-dirs-$(CONFIG_SOFTMMU) += audio/
 devices-dirs-$(CONFIG_SOFTMMU) += block/
-- 
2.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]