qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH] PING - add 1394 support


From: Itamar Tal
Subject: Re: [Qemu-devel] [PATCH] PING - add 1394 support
Date: Tue, 7 Apr 2015 11:18:41 +0300

Hi,

Haven't got any response to this patch and couldn't find relevant maintainer as well. Can anyone direct me to the right guy?

Thanks,

Itamar Tal,
Guardicore

On Mon, Mar 23, 2015 at 6:07 PM, Itamar Tal <address@hidden> wrote:
From 9c4425d4145ac6b0a2d19a6fdf5803dd13f1fa93 Mon Sep 17 00:00:00 2001
From: Itamar Tal <address@hidden>
Date: Mon, 23 Mar 2015 14:26:47 +0200
Subject: [PATCH] add 1394 support

This patch add 1394 (firewire) support to x86_64 and i386 qemu
softmmu. It allows one virtual machine to be the server side and the
other to be the client side, connected by TCP stream socket (same
thing is possible using serial port). This is very useful in for
allowing legacy devices to communicate over the firewire channel, but
doesn't support USB communication. Especially, it's useful for remote
Windows kernel debugging over qemu for malware analysis and so on...
The patch was tested on major stable version 2.0.0, 2.2.1 and current
master (2.3.0rc?).

Itamar Tal,
Guardicore

---
 hw/1394/Makefile.objs |    7 +
 hw/1394/hcd-ohci.c    | 1645 +++++++++++++++++++++++++++++++++++++++++++++++++
 hw/1394/hcd-ohci.h    |  147 +++++
 hw/Makefile.objs      |    1 +
 4 files changed, 1800 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/hw/1394/Makefile.objs b/hw/1394/Makefile.objs
new file mode 100644
index 0000000..6c039e6
--- /dev/null
+++ b/hw/1394/Makefile.objs
@@ -0,0 +1,7 @@
+ifeq ($(TARGET_X86_64),y)
+common-obj-y += hcd-ohci.o
+else
+ifeq ($(TARGET_I386),y)
+common-obj-y += hcd-ohci.o
+endif
+endif
diff --git a/hw/1394/hcd-ohci.c b/hw/1394/hcd-ohci.c
new file mode 100644
index 0000000..cf373e6
--- /dev/null
+++ b/hw/1394/hcd-ohci.c
@@ -0,0 +1,1645 @@
+/*
+ * 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))
+
+
+// root node  0x80400882;
+// other node 0x814000c0;
+typedef union {
+    uint32_t val;
+    struct {
+        uint32 m:1;         /* = 0 */
+        uint32 initiated:1; /* = 1 for root node */
+        uint32 p2:2;        /* = 0 */
+        uint32 p1:2;        /* = 0 */
+        uint32 p0:2;        /* = 3 but maybe 2 when "child" compared
to root? */
+        uint32 pwr:3;       /* = 0 */
+        uint32 c:1;         /* = 1 when root */
+        uint32 del:2;       /* = 0? */
+        uint32 sp:2;        /* = 0? */
+        uint32 gap_cnt:6;   /* = 0? */
+        uint32 L:1;         /* = 1? maybe just when connected */
+        uint32 :1;          /* = 0 */
+        uint32 node_id:6;
+        uint32 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;
+        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
+ 0, &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;
+    uint32_t status;
+    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: fix this - 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;
+    //int64_t t_now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+
+    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) {
+    } 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;
+            //hcd_async_rx_rsp_packet(s, (uint8_t *)data, 12, ACK_COMPLETE);
+            // reset because PHY packet
+            hcd_bus_reset(s); // TODO: 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); //t_now + get_ticks_per_sec() / 100000);
// TODO: 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) {
+     // ??
+    }
+    return ret;
+}
+
+static void hcd_mmio_write(void *opaque, hwaddr addr, uint64_t data,
unsigned size) {
+    hcd_state_t *s = (hcd_state_t *)opaque;
+    //uint32_t orig = s->mmio.regs[addr >> 2];
+    DECLARE_PHY phy_control;
+    DECLARE_NODE_ID NodeID;
+
+    if ((addr & 0xFFE0) != 0x0100) {
+        // ??
+    }
+    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, // ?
+};
+
+static int
+hcd_chr_can_receive(void *opaque) {
+    //hcd_state_t *s = (hcd_state_t *)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 ((req_nodata_packet->destination_offset_low &
0xFFFFFC00) == 0xF0000400) {
+                        dma_memory_read(&address_space_memory,
s->mmio.ConfigROMMap + (req_nodata_packet->destination_offset_low &
0x3ff), &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) {
+                        dma_memory_read(&address_space_memory,
s->mmio.ConfigROMMap + (req_packet->destination_offset_low & 0x3ff),
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);
+            }
+        }
+#if 0
+        s->phy_pages[0][0] = 0xFE;
+        // TODO: interrupt?
+        s->phy.PEI = 1;
+        s->mmio.IntEvent |= (1 << 19);
+        hcd_bus_reset(s);
+#endif
+        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,
+};
+
+static void hcd_register_types(void) {
+    type_register_static(&hcd_info);
+}
+
+type_init(hcd_register_types)
diff --git a/hw/1394/hcd-ohci.h b/hw/1394/hcd-ohci.h
new file mode 100644
index 0000000..bf6d600
--- /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/
--
1.8.5.2.msysgit.0


reply via email to

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