[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