summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoritojun <itojun@openbsd.org>2002-06-25 17:11:49 +0000
committeritojun <itojun@openbsd.org>2002-06-25 17:11:49 +0000
commit4360dd477e56bac8d9ea96dc25ccbdf9e094d0cd (patch)
treefb8726dc6b2158ae387a5b68306b941b9b6858a9
parentadd ARP hardware type for IEEE1394 (diff)
downloadwireguard-openbsd-4360dd477e56bac8d9ea96dc25ccbdf9e094d0cd.tar.xz
wireguard-openbsd-4360dd477e56bac8d9ea96dc25ccbdf9e094d0cd.zip
IEEE1394 infrastructure part.
IP-over-FW and SCSI over FW are being worked on.
-rw-r--r--sys/arch/macppc/conf/GENERIC8
-rw-r--r--sys/arch/macppc/conf/files.macppc7
-rw-r--r--sys/dev/ieee1394/IMPLEMENTATION58
-rw-r--r--sys/dev/ieee1394/TODO41
-rw-r--r--sys/dev/ieee1394/files.ieee139416
-rw-r--r--sys/dev/ieee1394/fwnode.c339
-rw-r--r--sys/dev/ieee1394/fwnodereg.h59
-rw-r--r--sys/dev/ieee1394/fwnodevar.h58
-rw-r--r--sys/dev/ieee1394/fwohci.c3944
-rw-r--r--sys/dev/ieee1394/fwohcireg.h552
-rw-r--r--sys/dev/ieee1394/fwohcivar.h241
-rw-r--r--sys/dev/ieee1394/ieee1394reg.h241
-rw-r--r--sys/dev/ieee1394/ieee1394var.h118
-rw-r--r--sys/dev/pci/files.pci9
-rw-r--r--sys/dev/pci/fwlynx_pci.c138
-rw-r--r--sys/dev/pci/fwohci_pci.c175
-rw-r--r--sys/dev/std/ieee1212.c1427
-rw-r--r--sys/dev/std/ieee1212reg.h257
-rw-r--r--sys/dev/std/ieee1212var.h108
-rw-r--r--sys/sys/malloc.h11
20 files changed, 7800 insertions, 7 deletions
diff --git a/sys/arch/macppc/conf/GENERIC b/sys/arch/macppc/conf/GENERIC
index fa95c13cdc3..4651f252fa5 100644
--- a/sys/arch/macppc/conf/GENERIC
+++ b/sys/arch/macppc/conf/GENERIC
@@ -1,4 +1,4 @@
-# $OpenBSD: GENERIC,v 1.27 2002/06/23 23:19:46 itojun Exp $g
+# $OpenBSD: GENERIC,v 1.28 2002/06/25 17:11:49 itojun Exp $g
#
# PPC GENERIC config file
#
@@ -103,6 +103,11 @@ gpio* at gpio? # GPIO, PMU interrupt router.
aed* at adb? # ADB Event Device
akbd* at adb? # ADB keyboard
+fwohci* at pci? dev ? function ? # FireWire on ohci
+#fw* at fwbus? # IPv4/v6 over FireWire
+fwnode* at fwbus? idhi ? idlo ?
+#fwscsi* at fwnode?
+
wskbd* at akbd? console ? mux 1
ams* at adb? # ADB mouse
wsmouse* at ams? mux 0
@@ -127,6 +132,7 @@ scsibus* at ioprbs?
scsibus* at iopsp?
#scsibus* at pcscp?
scsibus* at siop?
+#scsibus* at fwscsi?
wdc* at macobio? flags 0x1
wd* at wdc? drive ? flags 0x0000
diff --git a/sys/arch/macppc/conf/files.macppc b/sys/arch/macppc/conf/files.macppc
index 0885e488c1c..3f7b71b8655 100644
--- a/sys/arch/macppc/conf/files.macppc
+++ b/sys/arch/macppc/conf/files.macppc
@@ -1,4 +1,4 @@
-# $OpenBSD: files.macppc,v 1.11 2002/06/23 23:20:19 itojun Exp $
+# $OpenBSD: files.macppc,v 1.12 2002/06/25 17:11:49 itojun Exp $
#
# macppc-specific configuration info
@@ -216,6 +216,11 @@ include "dev/pcmcia/files.pcmcia"
#
include "dev/usb/files.usb"
+#
+# Machine-independent IEEE1394 drivers
+#
+include "dev/ieee1394/files.ieee1394"
+
# Sun HME Ethernet controllers
device hme: ether, ifnet, mii, ifmedia
file dev/ic/hme.c
diff --git a/sys/dev/ieee1394/IMPLEMENTATION b/sys/dev/ieee1394/IMPLEMENTATION
new file mode 100644
index 00000000000..f814065c52c
--- /dev/null
+++ b/sys/dev/ieee1394/IMPLEMENTATION
@@ -0,0 +1,58 @@
+$OpenBSD: IMPLEMENTATION,v 1.1 2002/06/25 17:11:49 itojun Exp $
+$NetBSD: IMPLEMENTATION,v 1.6 2002/02/03 07:29:14 jmc Exp $
+
+At time point in time, there are 3 controller drivers planned:
+
+ fwochi IEEE 1394 OHCI Controller (PCI & CardBus)
+ fwlynx TI TSB12LV21 (found B&W G3s)
+ fwsony Sony CXD1947A (found on Sony Vaio laptops)
+
+(Though as of this time, Sony has declined to release documentation
+about the CXD1947A).
+
+The device hierarchy will look like (using fwohci as the example):
+
+#
+# The controller driver. Handles the device-specific 1394 functions.
+#
+fwohci* at pci? dev ? function ?
+# For each remote 1394 device on the 1394 bus, there will be a corresponding
+# fwnode. If a 1394 device offers any supported services, they will be
+# a child of corresponding fwnode. A particular fwnode can be tied to a
+# specific device by specifing its nodeid as its identifier (XXX this
+# is a 64 bit quantity and locators used by config must be 32 bit integers).
+#
+fwnode0 at fwbus? idhi 0x003065ff idlo 0xfedc46c0
+fwnode1 at fwbus? idhi 0x0060e202 idlo 0x0000157e
+fwnode2 at fwbus? idhi 0x00110600 idlo 0x00003169
+fwnode* at fwbus? idhi ? idlo ?
+#
+# An ip capable interface can be added to the local bus as a service to offer
+# on the bus. (the code will only attach to the local bridge so 2 boxes plugged
+# into each other would only each have fw0, but would see the other side as
+# fwnodeX when it probes for remote devices)
+#
+fw* at fwbus?
+#
+# NOTE: All fwbus's, fw's, fwnode's derive their device struct from an
+# ieee1394_softc which allows the various layers to have a standard way to
+# look at values in their children nodes. (updating nodeid's, etc)
+#
+# One of the services that a node might offer is access to SCSI devices via
+# SBP-2. As decsribed above, this mean a scsibus is a child of fwnode at some
+# point. (Making it a direct child is bad since that drags in the whole scsi
+# code base even if all a person wants is an fwnode and camera support)
+#
+fwscsi* at fwnode?
+scsibus* at fwscsi?
+
+Note that with advent of highly mobile storage devices, the need for
+signatures or other mechanisms to identity disks indepentend of their
+localtion in the device hierarchy is sorely needed.
+
+fwohci0 at pci1 dev 12 function 0: NEC uPD72870 IEEE 1394 OHCI Host Controller (rev. 0x01)
+fwohci0: interrupting at isa irq 15
+fwohci0: OHCI 1.0
+fw0 at fwohci0: Id 00:d0:f5:20:00:00:5e:84, 400Mb/s, 1024 byte packets max
+fw0: isochronous channels: 16 transmit, 16 receive
+fwnode0 at fwohci0: Id xx:xx:xx:xx:xx:xx:xx:xx
diff --git a/sys/dev/ieee1394/TODO b/sys/dev/ieee1394/TODO
new file mode 100644
index 00000000000..2d70aff26c7
--- /dev/null
+++ b/sys/dev/ieee1394/TODO
@@ -0,0 +1,41 @@
+Rewrite handler_set to allow sub regions, minimums, etc without having to
+register 100 callbacks for 100 quad reads.
+
+Use handler set (with NULL cb) to create a higher level <bus>_unreg
+
+Move all mbuf code to if_fw.c. Make if_fw use the generic read/write/inreg and
+then it can translate the packets into the appropriate mbuf's.
+
+Need a tlabel alloc routine within fwohci and a way to use 64 tlabel's per
+node (rather than a global set of 64 as it's used now).
+
+Flesh out the documentation of the high level API in fwohci.c (fwlynx will need
+to implement the same thing so this should be more than just comments in
+fwohci.c)
+
+Move SBP2 routines into their own file.
+
+done - Rewrite ROM parsing/validation. Unroll all recursion, add ref counting,
+ path elimination, etc.
+
+done - Move rom routines into their own files to allow easier cross usage.
+
+done - Write sub match setup for fwnode/fwscsi so matching devices listed in
+ the ROM can be done via autoconf.
+
+done - Remove all of the devcap stuff.
+
+SBP2 needs a complete API written up: logins, ORB management/allocation, etc.
+
+done - Add locator detection/usage into fwohci code.
+
+Should do topology maps, speed maps, the various bus managers, etc.
+
+done - change all FW_DEBUG wrapped printf's to DPRINTF macro's
+
+done - ack errors from a TX complete should get passed up to any registered callbacks
+
+Track down issues where multiple hosts plugged into a firewire hub don't
+init/see all devices on resets sometimes.
+
+done - Make fwohci detach correctly (for cardbus/etc type interfaces)
diff --git a/sys/dev/ieee1394/files.ieee1394 b/sys/dev/ieee1394/files.ieee1394
new file mode 100644
index 00000000000..9b2ed596dfb
--- /dev/null
+++ b/sys/dev/ieee1394/files.ieee1394
@@ -0,0 +1,16 @@
+# $NetBSD: files.ieee1394,v 1.6 2002/02/27 05:02:25 jmc Exp $
+
+file dev/ieee1394/fwlynx.c fwlynx
+file dev/ieee1394/fwohci.c fwohci
+
+device fwnode { }
+attach fwnode at fwbus: ieee1212
+file dev/ieee1394/fwnode.c fwnode
+
+#device fwscsi: scsi
+#attach fwscsi at fwnode
+#file dev/ieee1394/fwscsi.c fwscsi
+
+#device fw: ieee1394, ifnet
+#attach fw at fwbus
+#file dev/ieee1394/if_fw.c fw
diff --git a/sys/dev/ieee1394/fwnode.c b/sys/dev/ieee1394/fwnode.c
new file mode 100644
index 00000000000..6d7e2ccc199
--- /dev/null
+++ b/sys/dev/ieee1394/fwnode.c
@@ -0,0 +1,339 @@
+/* $OpenBSD: fwnode.c,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: fwnode.c,v 1.13 2002/04/03 04:15:59 jmc Exp $ */
+
+/*
+ * Copyright (c) 2001,2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by James Chacon.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __KERNEL_RCSID
+__KERNEL_RCSID(0, "$NetBSD: fwnode.c,v 1.13 2002/04/03 04:15:59 jmc Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+#include <dev/std/ieee1212var.h>
+#include <dev/std/ieee1212reg.h>
+
+#include <dev/ieee1394/ieee1394reg.h>
+#include <dev/ieee1394/fwnodereg.h>
+
+#include <dev/ieee1394/ieee1394var.h>
+#include <dev/ieee1394/fwnodevar.h>
+
+static const char * const ieee1394_speeds[] = { IEEE1394_SPD_STRINGS };
+
+#ifdef __NetBSD__
+int fwnode_match(struct device *, struct cfdata *, void *);
+#else
+int fwnode_match(struct device *, void *, void *);
+#endif
+void fwnode_attach(struct device *, struct device *, void *);
+int fwnode_detach(struct device *, int);
+static void fwnode_configrom_input(struct ieee1394_abuf *, int);
+static int fwnode_print(void *, const char *);
+#ifdef FWNODE_DEBUG
+static void fwnode_dump_rom(struct fwnode_softc *,u_int32_t *, u_int32_t);
+#endif
+
+#ifdef FWNODE_DEBUG
+#define DPRINTF(x) if (fwnodedebug) printf x
+#define DPRINTFN(n,x) if (fwnodedebug>(n)) printf x
+int fwnodedebug = 1;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#ifdef __OpenBSD__
+struct cfdriver fwnode_cd = {
+ NULL, "fwnode", DV_DULL
+};
+#endif
+
+struct cfattach fwnode_ca = {
+ sizeof(struct fwnode_softc), fwnode_match, fwnode_attach,
+ fwnode_detach
+};
+
+#ifdef __NetBSD__
+int
+fwnode_match(struct device *parent, struct cfdata *match, void *aux)
+#else
+int
+fwnode_match(struct device *parent, void *match, void *aux)
+#endif
+{
+ struct ieee1394_attach_args *fwa = aux;
+
+ if (strcmp(fwa->name, "fwnode") == 0)
+ return 1;
+ return 0;
+}
+
+void
+fwnode_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct fwnode_softc *sc = (struct fwnode_softc *)self;
+ struct ieee1394_softc *psc = (struct ieee1394_softc *)parent;
+ struct ieee1394_attach_args *fwa = aux;
+ struct ieee1394_abuf *ab;
+
+#ifdef M_ZERO
+ ab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK|M_ZERO);
+#else
+ ab = malloc(sizeof(struct ieee1394_abuf), M_1394DATA, M_WAITOK);
+ bzero(ab, sizeof(struct ieee1394_abuf));
+#endif
+ ab->ab_data = malloc(4, M_1394DATA, M_WAITOK);
+ ab->ab_data[0] = 0;
+
+ sc->sc_sc1394.sc1394_node_id = fwa->nodeid;
+ memcpy(sc->sc_sc1394.sc1394_guid, fwa->uid, 8);
+ sc->sc1394_read = fwa->read;
+ sc->sc1394_write = fwa->write;
+ sc->sc1394_inreg = fwa->inreg;
+ sc->sc1394_unreg = fwa->unreg;
+
+ /* XXX. Fix the fw code to use the generic routines. */
+ sc->sc_sc1394.sc1394_ifinreg = psc->sc1394_ifinreg;
+ sc->sc_sc1394.sc1394_ifoutput = psc->sc1394_ifoutput;
+
+ printf(" Node %d: UID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ sc->sc_sc1394.sc1394_node_id,
+ sc->sc_sc1394.sc1394_guid[0], sc->sc_sc1394.sc1394_guid[1],
+ sc->sc_sc1394.sc1394_guid[2], sc->sc_sc1394.sc1394_guid[3],
+ sc->sc_sc1394.sc1394_guid[4], sc->sc_sc1394.sc1394_guid[5],
+ sc->sc_sc1394.sc1394_guid[6], sc->sc_sc1394.sc1394_guid[7]);
+ ab->ab_req = (struct ieee1394_softc *)sc;
+ ab->ab_addr = CSR_BASE + CSR_CONFIG_ROM;
+ ab->ab_length = 4;
+ ab->ab_retlen = 0;
+ ab->ab_cbarg = NULL;
+ ab->ab_cb = fwnode_configrom_input;
+ sc->sc1394_read(ab);
+}
+
+int
+fwnode_detach(struct device *self, int flags)
+{
+ struct fwnode_softc *sc = (struct fwnode_softc *)self;
+ struct device **children;
+
+ if (sc->sc_children) {
+ children = sc->sc_children;
+ while (*children++)
+ config_detach(*children, 0);
+ free(sc->sc_children, M_DEVBUF);
+ }
+
+ if (sc->sc_sc1394.sc1394_configrom &&
+ sc->sc_sc1394.sc1394_configrom_len)
+ free(sc->sc_sc1394.sc1394_configrom, M_1394DATA);
+
+ if (sc->sc_configrom)
+ p1212_free(sc->sc_configrom);
+ return 0;
+}
+
+/*
+ * This code is trying to build a complete image of the ROM in memory.
+ * This is done all here to keep the bus_read logic/callback for the ROM in one
+ * place since reading the whole ROM may require lots of small reads up front
+ * and building separate callback handlers for each step would be even worse.
+ */
+
+static void
+fwnode_configrom_input(struct ieee1394_abuf *ab, int rcode)
+{
+ struct fwnode_softc *sc = (struct fwnode_softc *)ab->ab_req;
+ u_int32_t val;
+
+ if (rcode != IEEE1394_RCODE_COMPLETE) {
+ DPRINTF(("Aborting configrom input, rcode: %d\n", rcode));
+#ifdef FWNODE_DEBUG
+ fwnode_dump_rom(sc, ab->ab_data, ab->ab_retlen);
+#endif
+ free(ab->ab_data, M_1394DATA);
+ free(ab, M_1394DATA);
+ return;
+ }
+
+ if (ab->ab_cbarg)
+ panic("Got an invalid abuf on callback\n");
+
+ if (ab->ab_length != ab->ab_retlen) {
+ DPRINTF(("%s: config rom short read. Expected :%d, received: "
+ "%d. Not attaching\n", sc->sc_sc1394.sc1394_dev.dv_xname,
+ ab->ab_length, ab->ab_retlen));
+ free(ab->ab_data, M_1394DATA);
+ free(ab, M_1394DATA);
+ return;
+ }
+ if (ab->ab_retlen % 4) {
+ DPRINTF(("%s: configrom read of invalid length: %d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, ab->ab_retlen));
+ free(ab->ab_data, M_1394DATA);
+ free(ab, M_1394DATA);
+ return;
+ }
+
+ ab->ab_retlen = ab->ab_retlen / 4;
+ if (p1212_iscomplete(ab->ab_data, &ab->ab_retlen) == -1) {
+ DPRINTF(("%s: configrom parse error\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname));
+ free(ab->ab_data, M_1394DATA);
+ free(ab, M_1394DATA);
+ return;
+ }
+
+#ifdef DIAGNOSTIC
+ if (ab->ab_retlen < (ab->ab_length / 4))
+ panic("Configrom shrank during iscomplete check?\n");
+#endif
+
+ if (ab->ab_retlen > (ab->ab_length / 4)) {
+
+ free(ab->ab_data, M_1394DATA);
+#ifdef M_ZERO
+ ab->ab_data = malloc(ab->ab_retlen * 4, M_1394DATA,
+ M_WAITOK|M_ZERO);
+#else
+ ab->ab_data = malloc(ab->ab_retlen * 4, M_1394DATA, M_WAITOK);
+ bzero(ab->ab_data, ab->ab_retlen * 4);
+#endif
+
+ ab->ab_addr = CSR_BASE + CSR_CONFIG_ROM;
+ ab->ab_length = ab->ab_retlen * 4;
+ ab->ab_retlen = 0;
+ ab->ab_cbarg = NULL;
+ ab->ab_cb = fwnode_configrom_input;
+ sc->sc1394_read(ab);
+ return;
+ } else {
+ sc->sc_sc1394.sc1394_configrom_len = ab->ab_retlen;
+ sc->sc_sc1394.sc1394_configrom = ab->ab_data;
+ ab->ab_data = NULL;
+
+ free(ab, M_1394DATA);
+
+ /*
+ * Set P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE and
+ * P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE as some protocols
+ * such as SBP2 need it.
+ */
+
+ val = P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE;
+ val |= P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE;
+ val |= P1212_ALLOW_VENDOR_DIRECTORY_TYPE;
+ sc->sc_configrom =
+ p1212_parse(sc->sc_sc1394.sc1394_configrom,
+ sc->sc_sc1394.sc1394_configrom_len, val);
+ if ((sc->sc_configrom == NULL) ||
+ (sc->sc_configrom->len != IEEE1394_BUSINFO_LEN)) {
+#ifdef FWNODE_DEBUG
+ DPRINTF(("Parse error with config rom\n"));
+ fwnode_dump_rom(sc, sc->sc_sc1394.sc1394_configrom,
+ sc->sc_sc1394.sc1394_configrom_len);
+#endif
+ if (sc->sc_configrom)
+ p1212_free(sc->sc_configrom);
+ free(sc->sc_sc1394.sc1394_configrom, M_1394DATA);
+ sc->sc_sc1394.sc1394_configrom = NULL;
+ sc->sc_sc1394.sc1394_configrom_len = 0;
+ return;
+ }
+
+ val = htonl(IEEE1394_SIGNATURE);
+ if (memcmp(sc->sc_configrom->name, &val, 4)) {
+ DPRINTF(("Invalid signature found in bus info block: "
+ "%s\n", sc->sc_configrom->name));
+ p1212_free(sc->sc_configrom);
+ sc->sc_sc1394.sc1394_configrom = NULL;
+ sc->sc_sc1394.sc1394_configrom_len = 0;
+ return;
+ }
+
+ sc->sc_sc1394.sc1394_max_receive =
+ IEEE1394_GET_MAX_REC(ntohl(sc->sc_configrom->data[0]));
+ sc->sc_sc1394.sc1394_link_speed =
+ IEEE1394_GET_LINK_SPD(ntohl(sc->sc_configrom->data[0]));
+ printf("%s: Link Speed: %s, max_rec: %d bytes\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname,
+ ieee1394_speeds[sc->sc_sc1394.sc1394_link_speed],
+ IEEE1394_MAX_REC(sc->sc_sc1394.sc1394_max_receive));
+#ifdef FWNODE_DEBUG
+ fwnode_dump_rom(sc, sc->sc_sc1394.sc1394_configrom,
+ sc->sc_sc1394.sc1394_configrom_len);
+ p1212_print(sc->sc_configrom->root);
+#endif
+ sc->sc_children = p1212_match_units(&sc->sc_sc1394.sc1394_dev,
+ sc->sc_configrom->root, fwnode_print);
+ }
+}
+
+static int
+fwnode_print(void *aux, const char *pnp)
+{
+ if (pnp)
+ printf("Unknown device at %s", pnp);
+
+ return UNCONF;
+}
+
+#ifdef FWNODE_DEBUG
+static void
+fwnode_dump_rom(struct fwnode_softc *sc, u_int32_t *t, u_int32_t len)
+{
+ int i;
+ printf("%s: Config rom dump:\n", sc->sc_sc1394.sc1394_dev.dv_xname);
+ for (i = 0; i < len; i++) {
+ if ((i % 4) == 0) {
+ if (i)
+ printf("\n");
+ printf("%s: 0x%02hx: ",
+ sc->sc_sc1394.sc1394_dev.dv_xname, (short)(4 * i));
+ }
+ printf("0x%08x ", ntohl(t[i]));
+ }
+ printf("\n");
+}
+#endif
diff --git a/sys/dev/ieee1394/fwnodereg.h b/sys/dev/ieee1394/fwnodereg.h
new file mode 100644
index 00000000000..d6788a498da
--- /dev/null
+++ b/sys/dev/ieee1394/fwnodereg.h
@@ -0,0 +1,59 @@
+/* $OpenBSD: fwnodereg.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: fwnodereg.h,v 1.1 2001/05/01 04:46:23 jmc Exp $ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by James Chacon.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_IEEE1394_FWNODEREG_H
+#define _DEV_IEEE1394_FWNODEREG_H
+
+#define DEVTYPE_UNKNOWN 0x0
+#define DEVTYPE_SBP2 0x1
+
+#define DEVSPEC_UNKNOWN 0x0
+#define DEVSPEC_SCSI2 0x1
+
+#define FWNODE_ENABLED 0x0001
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#endif /* _DEV_IEEE1394_FWNODEREG_H */
diff --git a/sys/dev/ieee1394/fwnodevar.h b/sys/dev/ieee1394/fwnodevar.h
new file mode 100644
index 00000000000..9660ab80a8a
--- /dev/null
+++ b/sys/dev/ieee1394/fwnodevar.h
@@ -0,0 +1,58 @@
+/* $OpenBSD: fwnodevar.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: fwnodevar.h,v 1.4 2002/02/27 05:02:25 jmc Exp $ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by James Chacon.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_IEEE1394_FWNODEVAR_H
+#define _DEV_IEEE1394_FWNODEVAR_H
+
+struct fwnode_softc {
+ struct ieee1394_softc sc_sc1394;
+
+ int sc_flags;
+
+ int (*sc1394_read)(struct ieee1394_abuf *);
+ int (*sc1394_write)(struct ieee1394_abuf *);
+ int (*sc1394_inreg)(struct ieee1394_abuf *, int);
+ int (*sc1394_unreg)(struct ieee1394_abuf *, int);
+
+ struct device **sc_children;
+
+ struct p1212_rom *sc_configrom;
+};
+
+#endif /* _DEV_IEEE1394_FWNODEVAR_H */
diff --git a/sys/dev/ieee1394/fwohci.c b/sys/dev/ieee1394/fwohci.c
new file mode 100644
index 00000000000..f772dba003b
--- /dev/null
+++ b/sys/dev/ieee1394/fwohci.c
@@ -0,0 +1,3944 @@
+/* $OpenBSD: fwohci.c,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: fwohci.c,v 1.54 2002/03/29 05:06:42 jmc Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * IEEE1394 Open Host Controller Interface
+ * based on OHCI Specification 1.1 (January 6, 2000)
+ * The first version to support network interface part is wrtten by
+ * Atsushi Onoe <onoe@netbsd.org>.
+ */
+
+/*
+ * The first version to support isochronous acquisition part is wrtten
+ * by HAYAKAWA Koichi <haya@netbsd.org>.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __KERNEL_RCSID
+__KERNEL_RCSID(0, "$NetBSD: fwohci.c,v 1.54 2002/03/29 05:06:42 jmc Exp $");
+#endif
+
+#define DOUBLEBUF 1
+#define NO_THREAD 1
+
+#ifdef __NetBSD__
+#include "opt_inet.h"
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kthread.h>
+#include <sys/socket.h>
+#ifdef __NetBSD__
+#include <sys/callout.h>
+#else
+#include <sys/timeout.h>
+#endif
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#ifdef __OpenBSD__
+#include <sys/endian.h>
+#endif
+
+#if __NetBSD_Version__ >= 105010000 || !defined(__NetBSD__)
+#include <uvm/uvm_extern.h>
+#else
+#include <vm/vm.h>
+#endif
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/ieee1394/ieee1394reg.h>
+#include <dev/ieee1394/fwohcireg.h>
+
+#include <dev/ieee1394/ieee1394var.h>
+#include <dev/ieee1394/fwohcivar.h>
+
+static const char * const ieee1394_speeds[] = { IEEE1394_SPD_STRINGS };
+
+#if 0
+static int fwohci_dnamem_alloc(struct fwohci_softc *sc, int size,
+ int alignment, bus_dmamap_t *mapp, caddr_t *kvap, int flags);
+#endif
+static void fwohci_create_event_thread(void *);
+static void fwohci_thread_init(void *);
+
+static void fwohci_event_thread(struct fwohci_softc *);
+static void fwohci_hw_init(struct fwohci_softc *);
+static void fwohci_power(int, void *);
+static void fwohci_shutdown(void *);
+
+static int fwohci_desc_alloc(struct fwohci_softc *);
+static struct fwohci_desc *fwohci_desc_get(struct fwohci_softc *, int);
+static void fwohci_desc_put(struct fwohci_softc *, struct fwohci_desc *, int);
+
+static int fwohci_ctx_alloc(struct fwohci_softc *, struct fwohci_ctx **,
+ int, int, int);
+static void fwohci_ctx_free(struct fwohci_softc *, struct fwohci_ctx *);
+static void fwohci_ctx_init(struct fwohci_softc *, struct fwohci_ctx *);
+
+static int fwohci_buf_alloc(struct fwohci_softc *, struct fwohci_buf *);
+static void fwohci_buf_free(struct fwohci_softc *, struct fwohci_buf *);
+static void fwohci_buf_init_rx(struct fwohci_softc *);
+static void fwohci_buf_start_rx(struct fwohci_softc *);
+static void fwohci_buf_stop_tx(struct fwohci_softc *);
+static void fwohci_buf_stop_rx(struct fwohci_softc *);
+static void fwohci_buf_next(struct fwohci_softc *, struct fwohci_ctx *);
+static int fwohci_buf_pktget(struct fwohci_softc *, struct fwohci_buf **,
+ caddr_t *, int);
+static int fwohci_buf_input(struct fwohci_softc *, struct fwohci_ctx *,
+ struct fwohci_pkt *);
+static int fwohci_buf_input_ppb(struct fwohci_softc *, struct fwohci_ctx *,
+ struct fwohci_pkt *);
+
+static u_int8_t fwohci_phy_read(struct fwohci_softc *, u_int8_t);
+static void fwohci_phy_write(struct fwohci_softc *, u_int8_t, u_int8_t);
+static void fwohci_phy_busreset(struct fwohci_softc *);
+static void fwohci_phy_input(struct fwohci_softc *, struct fwohci_pkt *);
+
+static int fwohci_handler_set(struct fwohci_softc *, int, u_int32_t, u_int32_t,
+ int (*)(struct fwohci_softc *, void *, struct fwohci_pkt *), void *);
+
+static void fwohci_arrq_input(struct fwohci_softc *, struct fwohci_ctx *);
+static void fwohci_arrs_input(struct fwohci_softc *, struct fwohci_ctx *);
+static void fwohci_ir_input(struct fwohci_softc *, struct fwohci_ctx *);
+
+static int fwohci_at_output(struct fwohci_softc *, struct fwohci_ctx *,
+ struct fwohci_pkt *);
+static void fwohci_at_done(struct fwohci_softc *, struct fwohci_ctx *, int);
+static void fwohci_atrs_output(struct fwohci_softc *, int, struct fwohci_pkt *,
+ struct fwohci_pkt *);
+
+static int fwohci_guidrom_init(struct fwohci_softc *);
+static void fwohci_configrom_init(struct fwohci_softc *);
+static int fwohci_configrom_input(struct fwohci_softc *, void *,
+ struct fwohci_pkt *);
+static void fwohci_selfid_init(struct fwohci_softc *);
+static int fwohci_selfid_input(struct fwohci_softc *);
+
+static void fwohci_csr_init(struct fwohci_softc *);
+static int fwohci_csr_input(struct fwohci_softc *, void *,
+ struct fwohci_pkt *);
+
+static void fwohci_uid_collect(struct fwohci_softc *);
+static void fwohci_uid_req(struct fwohci_softc *, int);
+static int fwohci_uid_input(struct fwohci_softc *, void *,
+ struct fwohci_pkt *);
+static int fwohci_uid_lookup(struct fwohci_softc *, const u_int8_t *);
+static void fwohci_check_nodes(struct fwohci_softc *);
+
+static int fwohci_if_inreg(struct device *, u_int32_t, u_int32_t,
+ void (*)(struct device *, struct mbuf *));
+static int fwohci_if_input(struct fwohci_softc *, void *, struct fwohci_pkt *);
+static int fwohci_if_input_iso(struct fwohci_softc *, void *, struct fwohci_pkt *);
+static int fwohci_if_output(struct device *, struct mbuf *,
+ void (*)(struct device *, struct mbuf *));
+static int fwohci_if_setiso(struct device *, u_int32_t, u_int32_t, u_int32_t,
+ void (*)(struct device *, struct mbuf *));
+static int fwohci_read(struct ieee1394_abuf *);
+static int fwohci_write(struct ieee1394_abuf *);
+static int fwohci_read_resp(struct fwohci_softc *, void *, struct fwohci_pkt *);
+static int fwohci_write_ack(struct fwohci_softc *, void *, struct fwohci_pkt *);
+static int fwohci_read_multi_resp(struct fwohci_softc *, void *,
+ struct fwohci_pkt *);
+static int fwohci_inreg(struct ieee1394_abuf *, int);
+static int fwohci_unreg(struct ieee1394_abuf *, int);
+static int fwohci_parse_input(struct fwohci_softc *, void *,
+ struct fwohci_pkt *);
+#ifdef __NetBSD__
+static int fwohci_submatch(struct device *, struct cfdata *, void *);
+#else
+static int fwohci_submatch(struct device *, void *, void *);
+#endif
+
+#ifdef FW_DEBUG
+static void fwohci_show_intr(struct fwohci_softc *, u_int32_t);
+static void fwohci_show_phypkt(struct fwohci_softc *, u_int32_t);
+
+/* 1 is normal debug, 2 is verbose debug, 3 is complete (packet dumps). */
+
+#define DPRINTF(x) if (fwdebug) printf x
+#define DPRINTFN(n,x) if (fwdebug>(n)) printf x
+int fwdebug = 1;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#ifdef __OpenBSD__
+struct cfdriver fwohci_cd = {
+ NULL, "fwohci", DV_DULL
+};
+#endif
+
+int
+fwohci_init(struct fwohci_softc *sc, const struct evcnt *ev)
+{
+ int i;
+ u_int32_t val;
+#if 0
+ int error;
+#endif
+
+#ifdef __NetBSD__
+ evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ev,
+ sc->sc_sc1394.sc1394_dev.dv_xname, "intr");
+
+ evcnt_attach_dynamic(&sc->sc_isocnt, EVCNT_TYPE_MISC, ev,
+ sc->sc_sc1394.sc1394_dev.dv_xname, "iso");
+ evcnt_attach_dynamic(&sc->sc_isopktcnt, EVCNT_TYPE_MISC, ev,
+ sc->sc_sc1394.sc1394_dev.dv_xname, "isopackets");
+#endif
+
+ /*
+ * Wait for reset completion
+ */
+ for (i = 0; i < OHCI_LOOP; i++) {
+ val = OHCI_CSR_READ(sc, OHCI_REG_HCControlClear);
+ if ((val & OHCI_HCControl_SoftReset) == 0)
+ break;
+ DELAY(10);
+ }
+
+ /* What dialect of OHCI is this device?
+ */
+ val = OHCI_CSR_READ(sc, OHCI_REG_Version);
+ printf("%s: OHCI %u.%u", sc->sc_sc1394.sc1394_dev.dv_xname,
+ OHCI_Version_GET_Version(val), OHCI_Version_GET_Revision(val));
+
+ LIST_INIT(&sc->sc_nodelist);
+
+ if (fwohci_guidrom_init(sc) != 0) {
+ printf("\n%s: fatal: no global UID ROM\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname);
+ return -1;
+ }
+
+ printf(", %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
+ sc->sc_sc1394.sc1394_guid[0], sc->sc_sc1394.sc1394_guid[1],
+ sc->sc_sc1394.sc1394_guid[2], sc->sc_sc1394.sc1394_guid[3],
+ sc->sc_sc1394.sc1394_guid[4], sc->sc_sc1394.sc1394_guid[5],
+ sc->sc_sc1394.sc1394_guid[6], sc->sc_sc1394.sc1394_guid[7]);
+
+ /* Get the maximum link speed and receive size
+ */
+ val = OHCI_CSR_READ(sc, OHCI_REG_BusOptions);
+ sc->sc_sc1394.sc1394_link_speed =
+ OHCI_BITVAL(val, OHCI_BusOptions_LinkSpd);
+ if (sc->sc_sc1394.sc1394_link_speed < IEEE1394_SPD_MAX) {
+ printf(", %s",
+ ieee1394_speeds[sc->sc_sc1394.sc1394_link_speed]);
+ } else {
+ printf(", unknown speed %u", sc->sc_sc1394.sc1394_link_speed);
+ }
+
+ /* MaxRec is encoded as log2(max_rec_octets)-1
+ */
+ sc->sc_sc1394.sc1394_max_receive =
+ 1 << (OHCI_BITVAL(val, OHCI_BusOptions_MaxRec) + 1);
+ printf(", %u max_rec", sc->sc_sc1394.sc1394_max_receive);
+
+ /*
+ * Count how many isochronous ctx we have.
+ */
+ OHCI_CSR_WRITE(sc, OHCI_REG_IsoRecvIntMaskSet, ~0);
+ val = OHCI_CSR_READ(sc, OHCI_REG_IsoRecvIntMaskClear);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IsoRecvIntMaskClear, ~0);
+ for (i = 0; val != 0; val >>= 1) {
+ if (val & 0x1)
+ i++;
+ }
+ sc->sc_isoctx = i;
+ printf(", %d iso_ctx", sc->sc_isoctx);
+
+ printf("\n");
+
+#if 0
+ error = fwohci_dnamem_alloc(sc, OHCI_CONFIG_SIZE,
+ OHCI_CONFIG_ALIGNMENT, &sc->sc_configrom_map,
+ (caddr_t *) &sc->sc_configrom, BUS_DMA_WAITOK|BUS_DMA_COHERENT);
+ return error;
+#endif
+
+ sc->sc_dying = 0;
+ sc->sc_nodeid = 0xffff; /* invalid */
+
+#ifdef __NetBSD__
+ kthread_create(fwohci_create_event_thread, sc);
+#else
+ kthread_create_deferred(fwohci_create_event_thread, sc);
+#endif
+ return 0;
+}
+
+static int
+fwohci_if_setiso(struct device *self, u_int32_t channel, u_int32_t tag,
+ u_int32_t direction, void (*handler)(struct device *, struct mbuf *))
+{
+ struct fwohci_softc *sc = (struct fwohci_softc *)self;
+ int retval;
+ int s;
+
+ if (direction == 1) {
+ return EIO;
+ }
+
+ s = splnet();
+ retval = fwohci_handler_set(sc, IEEE1394_TCODE_STREAM_DATA,
+ channel, tag, fwohci_if_input_iso, handler);
+ splx(s);
+
+ if (!retval) {
+ printf("%s: dummy iso handler set\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname);
+ } else {
+ printf("%s: dummy iso handler cannot set\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname);
+ }
+
+ return retval;
+}
+
+int
+fwohci_intr(void *arg)
+{
+ struct fwohci_softc * const sc = arg;
+ int progress = 0;
+ u_int32_t intmask, iso;
+
+ for (;;) {
+ intmask = OHCI_CSR_READ(sc, OHCI_REG_IntEventClear);
+
+ /*
+ * On a bus reset, everything except bus reset gets
+ * cleared. That can't get cleared until the selfid
+ * phase completes (which happens outside the
+ * interrupt routines). So if just a bus reset is left
+ * in the mask and it's already in the sc_intmask,
+ * just return.
+ */
+
+ if ((intmask == 0) ||
+ (progress && (intmask == OHCI_Int_BusReset) &&
+ (sc->sc_intmask & OHCI_Int_BusReset))) {
+ if (progress)
+ wakeup(fwohci_event_thread);
+ return progress;
+ }
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntEventClear,
+ intmask & ~OHCI_Int_BusReset);
+#ifdef FW_DEBUG
+ if (fwdebug > 1)
+ fwohci_show_intr(sc, intmask);
+#endif
+
+ if (intmask & OHCI_Int_BusReset) {
+ /*
+ * According to OHCI spec 6.1.1 "busReset",
+ * All asynchronous transmit must be stopped before
+ * clearing BusReset. Moreover, the BusReset
+ * interrupt bit should not be cleared during the
+ * SelfID phase. Thus we turned off interrupt mask
+ * bit of BusReset instead until SelfID completion
+ * or SelfID timeout.
+ */
+ intmask &= OHCI_Int_SelfIDComplete;
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskClear,
+ OHCI_Int_BusReset);
+ sc->sc_intmask = OHCI_Int_BusReset;
+ }
+ sc->sc_intmask |= intmask;
+
+ if (intmask & OHCI_Int_IsochTx) {
+ iso = OHCI_CSR_READ(sc, OHCI_REG_IsoXmitIntEventClear);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IsoXmitIntEventClear, iso);
+ }
+ if (intmask & OHCI_Int_IsochRx) {
+#if NO_THREAD
+ int i;
+ int asyncstream = 0;
+#endif
+
+ iso = OHCI_CSR_READ(sc, OHCI_REG_IsoRecvIntEventClear);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IsoRecvIntEventClear, iso);
+#if NO_THREAD
+ for (i = 0; i < sc->sc_isoctx; i++) {
+ if ((iso & (1<<i)) && sc->sc_ctx_ir[i] != NULL) {
+ if (sc->sc_ctx_ir[i]->fc_type == FWOHCI_CTX_ISO_SINGLE) {
+ asyncstream |= (1 << i);
+ continue;
+ }
+ bus_dmamap_sync(sc->sc_dmat,
+ sc->sc_ddmamap,
+ 0, sizeof(struct fwohci_desc) * sc->sc_descsize,
+ BUS_DMASYNC_PREREAD);
+ sc->sc_isocnt.ev_count++;
+
+ fwohci_ir_input(sc, sc->sc_ctx_ir[i]);
+ }
+ }
+ if (asyncstream != 0) {
+ sc->sc_iso |= asyncstream;
+ } else {
+ /* all iso intr is pure isochronous */
+ sc->sc_intmask &= ~OHCI_Int_IsochRx;
+ }
+#else
+ sc->sc_iso |= iso;
+#endif /* NO_THREAD */
+ }
+
+ if (!progress) {
+ sc->sc_intrcnt.ev_count++;
+ progress = 1;
+ }
+ }
+}
+
+static void
+fwohci_create_event_thread(void *arg)
+{
+ struct fwohci_softc *sc = arg;
+
+#ifdef __NetBSD__
+ if (kthread_create1(fwohci_thread_init, sc, &sc->sc_event_thread, "%s",
+ sc->sc_sc1394.sc1394_dev.dv_xname))
+#else
+ if (kthread_create(fwohci_thread_init, sc, &sc->sc_event_thread, "%s",
+ sc->sc_sc1394.sc1394_dev.dv_xname))
+#endif
+ {
+ printf("%s: unable to create event thread\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname);
+ panic("fwohci_create_event_thread");
+ }
+}
+
+static void
+fwohci_thread_init(void *arg)
+{
+ struct fwohci_softc *sc = arg;
+ int i;
+
+ /*
+ * Allocate descriptors
+ */
+ if (fwohci_desc_alloc(sc)) {
+ printf("%s: not enabling interrupts\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname);
+ kthread_exit(1);
+ }
+
+ /*
+ * Enable Link Power
+ */
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LPS);
+
+ /*
+ * Allocate DMA Context
+ */
+ fwohci_ctx_alloc(sc, &sc->sc_ctx_arrq, OHCI_BUF_ARRQ_CNT,
+ OHCI_CTX_ASYNC_RX_REQUEST, FWOHCI_CTX_ASYNC);
+ fwohci_ctx_alloc(sc, &sc->sc_ctx_arrs, OHCI_BUF_ARRS_CNT,
+ OHCI_CTX_ASYNC_RX_RESPONSE, FWOHCI_CTX_ASYNC);
+ fwohci_ctx_alloc(sc, &sc->sc_ctx_atrq, 0, OHCI_CTX_ASYNC_TX_REQUEST,
+ FWOHCI_CTX_ASYNC);
+ fwohci_ctx_alloc(sc, &sc->sc_ctx_atrs, 0, OHCI_CTX_ASYNC_TX_RESPONSE,
+ FWOHCI_CTX_ASYNC);
+ sc->sc_ctx_ir = malloc(sizeof(sc->sc_ctx_ir[0]) * sc->sc_isoctx,
+ M_DEVBUF, M_WAITOK);
+ for (i = 0; i < sc->sc_isoctx; i++)
+ sc->sc_ctx_ir[i] = NULL;
+
+ /*
+ * Allocate buffer for configuration ROM and SelfID buffer
+ */
+ fwohci_buf_alloc(sc, &sc->sc_buf_cnfrom);
+ fwohci_buf_alloc(sc, &sc->sc_buf_selfid);
+
+#ifdef __NetBSD__
+ callout_init(&sc->sc_selfid_callout);
+#else
+ bzero(&sc->sc_selfid_callout, sizeof(sc->sc_selfid_callout));
+#endif
+
+ sc->sc_sc1394.sc1394_ifinreg = fwohci_if_inreg;
+ sc->sc_sc1394.sc1394_ifoutput = fwohci_if_output;
+ sc->sc_sc1394.sc1394_ifsetiso = fwohci_if_setiso;
+
+ /*
+ * establish hooks for shutdown and suspend/resume
+ */
+ sc->sc_shutdownhook = shutdownhook_establish(fwohci_shutdown, sc);
+ sc->sc_powerhook = powerhook_establish(fwohci_power, sc);
+
+ sc->sc_sc1394.sc1394_if = config_found(&sc->sc_sc1394.sc1394_dev, "fw",
+ fwohci_print);
+
+ /* Main loop. It's not coming back normally. */
+
+ fwohci_event_thread(sc);
+
+ kthread_exit(0);
+}
+
+static void
+fwohci_event_thread(struct fwohci_softc *sc)
+{
+ int i, s;
+ u_int32_t intmask, iso;
+
+ s = splbio();
+
+ /*
+ * Initialize hardware registers.
+ */
+
+ fwohci_hw_init(sc);
+
+ /* Initial Bus Reset */
+ fwohci_phy_busreset(sc);
+ splx(s);
+
+ while (!sc->sc_dying) {
+ s = splbio();
+ intmask = sc->sc_intmask;
+ if (intmask == 0) {
+ tsleep(fwohci_event_thread, PZERO, "fwohciev", 0);
+ splx(s);
+ continue;
+ }
+ sc->sc_intmask = 0;
+ splx(s);
+
+ if (intmask & OHCI_Int_BusReset) {
+ fwohci_buf_stop_tx(sc);
+ if (sc->sc_uidtbl != NULL) {
+ free(sc->sc_uidtbl, M_DEVBUF);
+ sc->sc_uidtbl = NULL;
+ }
+
+#ifdef __NetBSD__
+ callout_reset(&sc->sc_selfid_callout,
+ OHCI_SELFID_TIMEOUT,
+ (void (*)(void *))fwohci_phy_busreset, sc);
+#else
+ timeout_set(&sc->sc_selfid_callout,
+ (void (*)(void *))fwohci_phy_busreset, sc);
+ timeout_add(&sc->sc_selfid_callout,
+ OHCI_SELFID_TIMEOUT);
+#endif
+ sc->sc_nodeid = 0xffff; /* indicate invalid */
+ sc->sc_rootid = 0;
+ sc->sc_irmid = IEEE1394_BCAST_PHY_ID;
+ }
+ if (intmask & OHCI_Int_SelfIDComplete) {
+ s = splbio();
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntEventClear,
+ OHCI_Int_BusReset);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskSet,
+ OHCI_Int_BusReset);
+ splx(s);
+#ifdef __NetBSD__
+ callout_stop(&sc->sc_selfid_callout);
+#else
+ timeout_del(&sc->sc_selfid_callout);
+#endif
+ if (fwohci_selfid_input(sc) == 0) {
+ fwohci_buf_start_rx(sc);
+ fwohci_uid_collect(sc);
+ }
+ }
+ if (intmask & OHCI_Int_ReqTxComplete)
+ fwohci_at_done(sc, sc->sc_ctx_atrq, 0);
+ if (intmask & OHCI_Int_RespTxComplete)
+ fwohci_at_done(sc, sc->sc_ctx_atrs, 0);
+ if (intmask & OHCI_Int_RQPkt)
+ fwohci_arrq_input(sc, sc->sc_ctx_arrq);
+ if (intmask & OHCI_Int_RSPkt)
+ fwohci_arrs_input(sc, sc->sc_ctx_arrs);
+ if (intmask & OHCI_Int_IsochRx) {
+ s = splbio();
+ iso = sc->sc_iso;
+ sc->sc_iso = 0;
+ splx(s);
+ for (i = 0; i < sc->sc_isoctx; i++) {
+ if ((iso & (1 << i)) &&
+ sc->sc_ctx_ir[i] != NULL) {
+ fwohci_ir_input(sc, sc->sc_ctx_ir[i]);
+ sc->sc_isocnt.ev_count++;
+ }
+ }
+ }
+ }
+}
+
+#if 0
+static int
+fwohci_dnamem_alloc(struct fwohci_softc *sc, int size, int alignment,
+ bus_dmamap_t *mapp, caddr_t *kvap, int flags)
+{
+ bus_dma_segment_t segs[1];
+ int error, nsegs, steps;
+
+ steps = 0;
+ error = bus_dmamem_alloc(sc->sc_dmat, size, alignment, alignment,
+ segs, 1, &nsegs, flags);
+ if (error)
+ goto cleanup;
+
+ steps = 1;
+ error = bus_dmamem_map(sc->sc_dmat, segs, nsegs, segs[0].ds_len,
+ kvap, flags);
+ if (error)
+ goto cleanup;
+
+ if (error == 0)
+ error = bus_dmamap_create(sc->sc_dmat, size, 1, alignment,
+ size, flags, mapp);
+ if (error)
+ goto cleanup;
+ if (error == 0)
+ error = bus_dmamap_load(sc->sc_dmat, *mapp, *kvap, size, NULL,
+ flags);
+ if (error)
+ goto cleanup;
+
+ cleanup:
+ switch (steps) {
+ case 1:
+ bus_dmamem_free(sc->sc_dmat, segs, nsegs);
+ }
+
+ return error;
+}
+#endif
+
+int
+fwohci_print(void *aux, const char *pnp)
+{
+ char *name = aux;
+
+ if (pnp)
+ printf("%s at %s", name, pnp);
+
+ return UNCONF;
+}
+
+static void
+fwohci_hw_init(struct fwohci_softc *sc)
+{
+ int i;
+ u_int32_t val;
+
+ /*
+ * Software Reset.
+ */
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_SoftReset);
+ for (i = 0; i < OHCI_LOOP; i++) {
+ val = OHCI_CSR_READ(sc, OHCI_REG_HCControlClear);
+ if ((val & OHCI_HCControl_SoftReset) == 0)
+ break;
+ DELAY(10);
+ }
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LPS);
+
+ /*
+ * First, initilize CSRs with undefined value to default settings.
+ */
+ val = OHCI_CSR_READ(sc, OHCI_REG_BusOptions);
+ val |= OHCI_BusOptions_ISC | OHCI_BusOptions_CMC;
+#if 0
+ val |= OHCI_BusOptions_BMC | OHCI_BusOptions_IRMC;
+#else
+ val &= ~(OHCI_BusOptions_BMC | OHCI_BusOptions_IRMC);
+#endif
+ OHCI_CSR_WRITE(sc, OHCI_REG_BusOptions, val);
+ for (i = 0; i < sc->sc_isoctx; i++) {
+ OHCI_SYNC_RX_DMA_WRITE(sc, i, OHCI_SUBREG_ContextControlClear,
+ ~0);
+ }
+ OHCI_CSR_WRITE(sc, OHCI_REG_LinkControlClear, ~0);
+
+ fwohci_configrom_init(sc);
+ fwohci_selfid_init(sc);
+ fwohci_buf_init_rx(sc);
+ fwohci_csr_init(sc);
+
+ /*
+ * Final CSR settings.
+ */
+ OHCI_CSR_WRITE(sc, OHCI_REG_LinkControlSet,
+ OHCI_LinkControl_CycleTimerEnable |
+ OHCI_LinkControl_RcvSelfID | OHCI_LinkControl_RcvPhyPkt);
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_ATRetries, 0x00000888); /*XXX*/
+
+ /* clear receive filter */
+ OHCI_CSR_WRITE(sc, OHCI_REG_IRMultiChanMaskHiClear, ~0);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IRMultiChanMaskLoClear, ~0);
+ OHCI_CSR_WRITE(sc, OHCI_REG_AsynchronousRequestFilterHiSet, 0x80000000);
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlClear,
+ OHCI_HCControl_NoByteSwapData | OHCI_HCControl_APhyEnhanceEnable);
+#if BYTE_ORDER == BIG_ENDIAN
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet,
+ OHCI_HCControl_NoByteSwapData);
+#endif
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskClear, ~0);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskSet, OHCI_Int_BusReset |
+ OHCI_Int_SelfIDComplete | OHCI_Int_IsochRx | OHCI_Int_IsochTx |
+ OHCI_Int_RSPkt | OHCI_Int_RQPkt | OHCI_Int_ARRS | OHCI_Int_ARRQ |
+ OHCI_Int_RespTxComplete | OHCI_Int_ReqTxComplete);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskSet, OHCI_Int_CycleTooLong |
+ OHCI_Int_UnrecoverableError | OHCI_Int_CycleInconsistent |
+ OHCI_Int_LockRespErr | OHCI_Int_PostedWriteErr);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IsoXmitIntMaskSet, ~0);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IsoRecvIntMaskSet, ~0);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskSet, OHCI_Int_MasterEnable);
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_LinkEnable);
+
+ /*
+ * Start the receivers
+ */
+ fwohci_buf_start_rx(sc);
+}
+
+static void
+fwohci_power(int why, void *arg)
+{
+ struct fwohci_softc *sc = arg;
+ int s;
+
+ s = splbio();
+ switch (why) {
+ case PWR_SUSPEND:
+ case PWR_STANDBY:
+ fwohci_shutdown(sc);
+ break;
+ case PWR_RESUME:
+ fwohci_hw_init(sc);
+ fwohci_phy_busreset(sc);
+ break;
+#ifdef __NetBSD__
+ case PWR_SOFTSUSPEND:
+ case PWR_SOFTSTANDBY:
+ case PWR_SOFTRESUME:
+ break;
+#endif
+ }
+ splx(s);
+}
+
+static void
+fwohci_shutdown(void *arg)
+{
+ struct fwohci_softc *sc = arg;
+ u_int32_t val;
+
+#ifdef __NetBSD__
+ callout_stop(&sc->sc_selfid_callout);
+#else
+ timeout_del(&sc->sc_selfid_callout);
+#endif
+ /* disable all interrupt */
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskClear, OHCI_Int_MasterEnable);
+ fwohci_buf_stop_tx(sc);
+ fwohci_buf_stop_rx(sc);
+ val = OHCI_CSR_READ(sc, OHCI_REG_BusOptions);
+ val &= ~(OHCI_BusOptions_BMC | OHCI_BusOptions_ISC |
+ OHCI_BusOptions_CMC | OHCI_BusOptions_IRMC);
+ OHCI_CSR_WRITE(sc, OHCI_REG_BusOptions, val);
+ fwohci_phy_busreset(sc);
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlClear, OHCI_HCControl_LinkEnable);
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlClear, OHCI_HCControl_LPS);
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet, OHCI_HCControl_SoftReset);
+}
+
+/*
+ * COMMON FUNCTIONS
+ */
+
+/*
+ * read the PHY Register.
+ */
+static u_int8_t
+fwohci_phy_read(struct fwohci_softc *sc, u_int8_t reg)
+{
+ int i;
+ u_int32_t val;
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_PhyControl,
+ OHCI_PhyControl_RdReg | (reg << OHCI_PhyControl_RegAddr_BITPOS));
+ for (i = 0; i < OHCI_LOOP; i++) {
+ if (OHCI_CSR_READ(sc, OHCI_REG_PhyControl) &
+ OHCI_PhyControl_RdDone)
+ break;
+ DELAY(10);
+ }
+ val = OHCI_CSR_READ(sc, OHCI_REG_PhyControl);
+ return (val & OHCI_PhyControl_RdData) >> OHCI_PhyControl_RdData_BITPOS;
+}
+
+/*
+ * write the PHY Register.
+ */
+static void
+fwohci_phy_write(struct fwohci_softc *sc, u_int8_t reg, u_int8_t val)
+{
+ int i;
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_PhyControl, OHCI_PhyControl_WrReg |
+ (reg << OHCI_PhyControl_RegAddr_BITPOS) |
+ (val << OHCI_PhyControl_WrData_BITPOS));
+ for (i = 0; i < OHCI_LOOP; i++) {
+ if (!(OHCI_CSR_READ(sc, OHCI_REG_PhyControl) &
+ OHCI_PhyControl_WrReg))
+ break;
+ DELAY(10);
+ }
+}
+
+/*
+ * Initiate Bus Reset
+ */
+static void
+fwohci_phy_busreset(struct fwohci_softc *sc)
+{
+ int s;
+ u_int8_t val;
+
+ s = splbio();
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntEventClear,
+ OHCI_Int_BusReset | OHCI_Int_SelfIDComplete);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IntMaskSet, OHCI_Int_BusReset);
+#ifdef __NetBSD__
+ callout_stop(&sc->sc_selfid_callout);
+#else
+ timeout_del(&sc->sc_selfid_callout);
+#endif
+ val = fwohci_phy_read(sc, 1);
+ val = (val & 0x80) | /* preserve RHB (force root) */
+ 0x40 | /* Initiate Bus Reset */
+ 0x3f; /* default GAP count */
+ fwohci_phy_write(sc, 1, val);
+ splx(s);
+}
+
+/*
+ * PHY Packet
+ */
+static void
+fwohci_phy_input(struct fwohci_softc *sc, struct fwohci_pkt *pkt)
+{
+ u_int32_t val;
+
+ val = pkt->fp_hdr[1];
+ if (val != ~pkt->fp_hdr[2]) {
+ if (val == 0 && ((*pkt->fp_trail & 0x001f0000) >> 16) ==
+ OHCI_CTXCTL_EVENT_BUS_RESET) {
+ DPRINTFN(1, ("fwohci_phy_input: BusReset: 0x%08x\n",
+ pkt->fp_hdr[2]));
+ } else {
+ printf("%s: phy packet corrupted (0x%08x, 0x%08x)\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, val,
+ pkt->fp_hdr[2]);
+ }
+ return;
+ }
+#ifdef FW_DEBUG
+ if (fwdebug > 1)
+ fwohci_show_phypkt(sc, val);
+#endif
+}
+
+/*
+ * Descriptor for context DMA.
+ */
+static int
+fwohci_desc_alloc(struct fwohci_softc *sc)
+{
+ int error, mapsize, dsize;
+
+ /*
+ * allocate descriptor buffer
+ */
+
+ sc->sc_descsize = OHCI_BUF_ARRQ_CNT + OHCI_BUF_ARRS_CNT +
+ OHCI_BUF_ATRQ_CNT + OHCI_BUF_ATRS_CNT +
+ OHCI_BUF_IR_CNT * sc->sc_isoctx + 2;
+ dsize = sizeof(struct fwohci_desc) * sc->sc_descsize;
+ mapsize = howmany(sc->sc_descsize, NBBY);
+#ifdef M_ZERO
+ sc->sc_descmap = malloc(mapsize, M_DEVBUF, M_WAITOK|M_ZERO);
+#else
+ sc->sc_descmap = malloc(mapsize, M_DEVBUF, M_WAITOK);
+ bzero(sc->sc_descmap, mapsize);
+#endif
+
+ if ((error = bus_dmamem_alloc(sc->sc_dmat, dsize, PAGE_SIZE, 0,
+ &sc->sc_dseg, 1, &sc->sc_dnseg, 0)) != 0) {
+ printf("%s: unable to allocate descriptor buffer, error = %d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, error);
+ goto fail_0;
+ }
+
+ if ((error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dseg, sc->sc_dnseg,
+ dsize, (caddr_t *)&sc->sc_desc, BUS_DMA_COHERENT | BUS_DMA_WAITOK))
+ != 0) {
+ printf("%s: unable to map descriptor buffer, error = %d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, error);
+ goto fail_1;
+ }
+
+ if ((error = bus_dmamap_create(sc->sc_dmat, dsize, sc->sc_dnseg,
+ dsize, 0, BUS_DMA_WAITOK, &sc->sc_ddmamap)) != 0) {
+ printf("%s: unable to create descriptor buffer DMA map, "
+ "error = %d\n", sc->sc_sc1394.sc1394_dev.dv_xname, error);
+ goto fail_2;
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_ddmamap, sc->sc_desc,
+ dsize, NULL, BUS_DMA_WAITOK)) != 0) {
+ printf("%s: unable to load descriptor buffer DMA map, "
+ "error = %d\n", sc->sc_sc1394.sc1394_dev.dv_xname, error);
+ goto fail_3;
+ }
+
+ return 0;
+
+ fail_3:
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_ddmamap);
+ fail_2:
+ bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_desc, dsize);
+ fail_1:
+ bus_dmamem_free(sc->sc_dmat, &sc->sc_dseg, sc->sc_dnseg);
+ fail_0:
+ return error;
+}
+
+static struct fwohci_desc *
+fwohci_desc_get(struct fwohci_softc *sc, int ndesc)
+{
+ int i, n;
+
+ for (n = 0; n <= sc->sc_descsize - ndesc; n++) {
+ for (i = 0; ; i++) {
+ if (i == ndesc) {
+ for (i = 0; i < ndesc; i++)
+ setbit(sc->sc_descmap, n + i);
+ return sc->sc_desc + n;
+ }
+ if (isset(sc->sc_descmap, n + i))
+ break;
+ }
+ }
+ return NULL;
+}
+
+static void
+fwohci_desc_put(struct fwohci_softc *sc, struct fwohci_desc *fd, int ndesc)
+{
+ int i, n;
+
+ n = fd - sc->sc_desc;
+ for (i = 0; i < ndesc; i++, n++) {
+#ifdef DIAGNOSTIC
+ if (isclr(sc->sc_descmap, n))
+ panic("fwohci_desc_put: duplicated free");
+#endif
+ clrbit(sc->sc_descmap, n);
+ }
+}
+
+/*
+ * Asyncronous/Isochronous Transmit/Receive Context
+ */
+static int
+fwohci_ctx_alloc(struct fwohci_softc *sc, struct fwohci_ctx **fcp,
+ int bufcnt, int ctx, int ctxtype)
+{
+ int i, error;
+ struct fwohci_ctx *fc;
+ struct fwohci_buf *fb;
+ struct fwohci_desc *fd;
+#if DOUBLEBUF
+ int buf2cnt;
+#endif
+
+#ifdef M_ZERO
+ fc = malloc(sizeof(*fc), M_DEVBUF, M_WAITOK|M_ZERO);
+#else
+ fc = malloc(sizeof(*fc), M_DEVBUF, M_WAITOK);
+ bzero(fc, sizeof(*fc));
+#endif
+ LIST_INIT(&fc->fc_handler);
+ TAILQ_INIT(&fc->fc_buf);
+ fc->fc_ctx = ctx;
+#ifdef M_ZERO
+ fc->fc_buffers = fb = malloc(sizeof(*fb) * bufcnt, M_DEVBUF, M_WAITOK|M_ZERO);
+#else
+ fc->fc_buffers = fb = malloc(sizeof(*fb) * bufcnt, M_DEVBUF, M_WAITOK);
+ bzero(fb, sizeof(*fb));
+#endif
+ fc->fc_bufcnt = bufcnt;
+#if DOUBLEBUF
+ TAILQ_INIT(&fc->fc_buf2); /* for isochronous */
+ if (ctxtype == FWOHCI_CTX_ISO_MULTI) {
+ buf2cnt = bufcnt/2;
+ bufcnt -= buf2cnt;
+ if (buf2cnt == 0) {
+ panic("cannot allocate iso buffer");
+ }
+ }
+#endif
+ for (i = 0; i < bufcnt; i++, fb++) {
+ if ((error = fwohci_buf_alloc(sc, fb)) != 0)
+ goto fail;
+ if ((fd = fwohci_desc_get(sc, 1)) == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ fb->fb_desc = fd;
+ fb->fb_daddr = sc->sc_ddmamap->dm_segs[0].ds_addr +
+ ((caddr_t)fd - (caddr_t)sc->sc_desc);
+ fd->fd_flags = OHCI_DESC_INPUT | OHCI_DESC_STATUS |
+ OHCI_DESC_INTR_ALWAYS | OHCI_DESC_BRANCH;
+ fd->fd_reqcount = fb->fb_dmamap->dm_segs[0].ds_len;
+ fd->fd_data = fb->fb_dmamap->dm_segs[0].ds_addr;
+ TAILQ_INSERT_TAIL(&fc->fc_buf, fb, fb_list);
+ }
+#if DOUBLEBUF
+ if (ctxtype == FWOHCI_CTX_ISO_MULTI) {
+ for (i = bufcnt; i < bufcnt + buf2cnt; i++, fb++) {
+ if ((error = fwohci_buf_alloc(sc, fb)) != 0)
+ goto fail;
+ if ((fd = fwohci_desc_get(sc, 1)) == NULL) {
+ error = ENOBUFS;
+ goto fail;
+ }
+ fb->fb_desc = fd;
+ fb->fb_daddr = sc->sc_ddmamap->dm_segs[0].ds_addr +
+ ((caddr_t)fd - (caddr_t)sc->sc_desc);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_ddmamap,
+ (caddr_t)fd - (caddr_t)sc->sc_desc, sizeof(struct fwohci_desc),
+ BUS_DMASYNC_PREWRITE);
+ fd->fd_flags = OHCI_DESC_INPUT | OHCI_DESC_STATUS |
+ OHCI_DESC_INTR_ALWAYS | OHCI_DESC_BRANCH;
+ fd->fd_reqcount = fb->fb_dmamap->dm_segs[0].ds_len;
+ fd->fd_data = fb->fb_dmamap->dm_segs[0].ds_addr;
+ TAILQ_INSERT_TAIL(&fc->fc_buf2, fb, fb_list);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_ddmamap,
+ (caddr_t)fd - (caddr_t)sc->sc_desc, sizeof(struct fwohci_desc),
+ BUS_DMASYNC_POSTWRITE);
+ }
+ }
+#endif /* DOUBLEBUF */
+ fc->fc_type = ctxtype;
+ *fcp = fc;
+ return 0;
+
+ fail:
+ while (i-- > 0) {
+ fb--;
+ if (fb->fb_desc)
+ fwohci_desc_put(sc, fb->fb_desc, 1);
+ fwohci_buf_free(sc, fb);
+ }
+ free(fc, M_DEVBUF);
+ return error;
+}
+
+static void
+fwohci_ctx_free(struct fwohci_softc *sc, struct fwohci_ctx *fc)
+{
+ struct fwohci_buf *fb;
+ struct fwohci_handler *fh;
+
+#if DOUBLEBUF
+ if ((fc->fc_type == FWOHCI_CTX_ISO_MULTI) &&
+ (TAILQ_FIRST(&fc->fc_buf) > TAILQ_FIRST(&fc->fc_buf2))) {
+ struct fwohci_buf_s fctmp;
+
+ fctmp = fc->fc_buf;
+ fc->fc_buf = fc->fc_buf2;
+ fc->fc_buf2 = fctmp;
+ }
+#endif
+ while ((fh = LIST_FIRST(&fc->fc_handler)) != NULL)
+ fwohci_handler_set(sc, fh->fh_tcode, fh->fh_key1, fh->fh_key2,
+ NULL, NULL);
+ while ((fb = TAILQ_FIRST(&fc->fc_buf)) != NULL) {
+ TAILQ_REMOVE(&fc->fc_buf, fb, fb_list);
+ if (fb->fb_desc)
+ fwohci_desc_put(sc, fb->fb_desc, 1);
+ fwohci_buf_free(sc, fb);
+ }
+#if DOUBLEBUF
+ while ((fb = TAILQ_FIRST(&fc->fc_buf2)) != NULL) {
+ TAILQ_REMOVE(&fc->fc_buf2, fb, fb_list);
+ if (fb->fb_desc)
+ fwohci_desc_put(sc, fb->fb_desc, 1);
+ fwohci_buf_free(sc, fb);
+ }
+#endif /* DOUBLEBUF */
+ free(fc->fc_buffers, M_DEVBUF);
+ free(fc, M_DEVBUF);
+}
+
+static void
+fwohci_ctx_init(struct fwohci_softc *sc, struct fwohci_ctx *fc)
+{
+ struct fwohci_buf *fb, *nfb;
+ struct fwohci_desc *fd;
+ struct fwohci_handler *fh;
+ int n;
+
+ for (fb = TAILQ_FIRST(&fc->fc_buf); fb != NULL; fb = nfb) {
+ nfb = TAILQ_NEXT(fb, fb_list);
+ fb->fb_off = 0;
+ fd = fb->fb_desc;
+ fd->fd_branch = (nfb != NULL) ? (nfb->fb_daddr | 1) : 0;
+ fd->fd_rescount = fd->fd_reqcount;
+ }
+
+#if DOUBLEBUF
+ for (fb = TAILQ_FIRST(&fc->fc_buf2); fb != NULL; fb = nfb) {
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_ddmamap,
+ (caddr_t)fd - (caddr_t)sc->sc_desc, sizeof(struct fwohci_desc),
+ BUS_DMASYNC_PREWRITE);
+ nfb = TAILQ_NEXT(fb, fb_list);
+ fb->fb_off = 0;
+ fd = fb->fb_desc;
+ fd->fd_branch = (nfb != NULL) ? (nfb->fb_daddr | 1) : 0;
+ fd->fd_rescount = fd->fd_reqcount;
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_ddmamap,
+ (caddr_t)fd - (caddr_t)sc->sc_desc, sizeof(struct fwohci_desc),
+ BUS_DMASYNC_POSTWRITE);
+ }
+#endif /* DOUBLEBUF */
+
+ n = fc->fc_ctx;
+ fb = TAILQ_FIRST(&fc->fc_buf);
+ if (fc->fc_type != FWOHCI_CTX_ASYNC) {
+ OHCI_SYNC_RX_DMA_WRITE(sc, n, OHCI_SUBREG_CommandPtr,
+ fb->fb_daddr | 1);
+ OHCI_SYNC_RX_DMA_WRITE(sc, n, OHCI_SUBREG_ContextControlClear,
+ OHCI_CTXCTL_RX_BUFFER_FILL |
+ OHCI_CTXCTL_RX_CYCLE_MATCH_ENABLE |
+ OHCI_CTXCTL_RX_MULTI_CHAN_MODE |
+ OHCI_CTXCTL_RX_DUAL_BUFFER_MODE);
+ OHCI_SYNC_RX_DMA_WRITE(sc, n, OHCI_SUBREG_ContextControlSet,
+ OHCI_CTXCTL_RX_ISOCH_HEADER);
+ if (fc->fc_type == FWOHCI_CTX_ISO_MULTI) {
+ OHCI_SYNC_RX_DMA_WRITE(sc, n,
+ OHCI_SUBREG_ContextControlSet,
+ OHCI_CTXCTL_RX_BUFFER_FILL);
+ }
+ fh = LIST_FIRST(&fc->fc_handler);
+ OHCI_SYNC_RX_DMA_WRITE(sc, n, OHCI_SUBREG_ContextMatch,
+ (OHCI_CTXMATCH_TAG0 << fh->fh_key2) | fh->fh_key1);
+ } else {
+ OHCI_ASYNC_DMA_WRITE(sc, n, OHCI_SUBREG_CommandPtr,
+ fb->fb_daddr | 1);
+ }
+}
+
+/*
+ * DMA data buffer
+ */
+static int
+fwohci_buf_alloc(struct fwohci_softc *sc, struct fwohci_buf *fb)
+{
+ int error;
+
+ if ((error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE,
+ PAGE_SIZE, &fb->fb_seg, 1, &fb->fb_nseg, BUS_DMA_WAITOK)) != 0) {
+ printf("%s: unable to allocate buffer, error = %d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, error);
+ goto fail_0;
+ }
+
+ if ((error = bus_dmamem_map(sc->sc_dmat, &fb->fb_seg,
+ fb->fb_nseg, PAGE_SIZE, &fb->fb_buf, BUS_DMA_WAITOK)) != 0) {
+ printf("%s: unable to map buffer, error = %d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, error);
+ goto fail_1;
+ }
+
+ if ((error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, fb->fb_nseg,
+ PAGE_SIZE, 0, BUS_DMA_WAITOK, &fb->fb_dmamap)) != 0) {
+ printf("%s: unable to create buffer DMA map, "
+ "error = %d\n", sc->sc_sc1394.sc1394_dev.dv_xname,
+ error);
+ goto fail_2;
+ }
+
+ if ((error = bus_dmamap_load(sc->sc_dmat, fb->fb_dmamap,
+ fb->fb_buf, PAGE_SIZE, NULL, BUS_DMA_WAITOK)) != 0) {
+ printf("%s: unable to load buffer DMA map, "
+ "error = %d\n", sc->sc_sc1394.sc1394_dev.dv_xname,
+ error);
+ goto fail_3;
+ }
+
+ return 0;
+
+ bus_dmamap_unload(sc->sc_dmat, fb->fb_dmamap);
+ fail_3:
+ bus_dmamap_destroy(sc->sc_dmat, fb->fb_dmamap);
+ fail_2:
+ bus_dmamem_unmap(sc->sc_dmat, fb->fb_buf, PAGE_SIZE);
+ fail_1:
+ bus_dmamem_free(sc->sc_dmat, &fb->fb_seg, fb->fb_nseg);
+ fail_0:
+ return error;
+}
+
+static void
+fwohci_buf_free(struct fwohci_softc *sc, struct fwohci_buf *fb)
+{
+
+ bus_dmamap_unload(sc->sc_dmat, fb->fb_dmamap);
+ bus_dmamap_destroy(sc->sc_dmat, fb->fb_dmamap);
+ bus_dmamem_unmap(sc->sc_dmat, fb->fb_buf, PAGE_SIZE);
+ bus_dmamem_free(sc->sc_dmat, &fb->fb_seg, fb->fb_nseg);
+}
+
+static void
+fwohci_buf_init_rx(struct fwohci_softc *sc)
+{
+ int i;
+
+ /*
+ * Initialize for Asynchronous Receive Queue.
+ */
+ fwohci_ctx_init(sc, sc->sc_ctx_arrq);
+ fwohci_ctx_init(sc, sc->sc_ctx_arrs);
+
+ /*
+ * Initialize for Isochronous Receive Queue.
+ */
+ for (i = 0; i < sc->sc_isoctx; i++) {
+ if (sc->sc_ctx_ir[i] != NULL)
+ fwohci_ctx_init(sc, sc->sc_ctx_ir[i]);
+ }
+}
+
+static void
+fwohci_buf_start_rx(struct fwohci_softc *sc)
+{
+ int i;
+
+ OHCI_ASYNC_DMA_WRITE(sc, OHCI_CTX_ASYNC_RX_REQUEST,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_RUN);
+ OHCI_ASYNC_DMA_WRITE(sc, OHCI_CTX_ASYNC_RX_RESPONSE,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_RUN);
+ for (i = 0; i < sc->sc_isoctx; i++) {
+ if (sc->sc_ctx_ir[i] != NULL)
+ OHCI_SYNC_RX_DMA_WRITE(sc, i,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_RUN);
+ }
+}
+
+static void
+fwohci_buf_stop_tx(struct fwohci_softc *sc)
+{
+ int i;
+
+ OHCI_ASYNC_DMA_WRITE(sc, OHCI_CTX_ASYNC_TX_REQUEST,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ OHCI_ASYNC_DMA_WRITE(sc, OHCI_CTX_ASYNC_TX_RESPONSE,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+
+ /*
+ * Make sure the transmitter is stopped.
+ */
+ for (i = 0; i < OHCI_LOOP; i++) {
+ DELAY(10);
+ if (OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_TX_REQUEST,
+ OHCI_SUBREG_ContextControlClear) & OHCI_CTXCTL_ACTIVE)
+ continue;
+ if (OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_TX_RESPONSE,
+ OHCI_SUBREG_ContextControlClear) & OHCI_CTXCTL_ACTIVE)
+ continue;
+ break;
+ }
+
+ /*
+ * Initialize for Asynchronous Transmit Queue.
+ */
+ fwohci_at_done(sc, sc->sc_ctx_atrq, 1);
+ fwohci_at_done(sc, sc->sc_ctx_atrs, 1);
+}
+
+static void
+fwohci_buf_stop_rx(struct fwohci_softc *sc)
+{
+ int i;
+
+ OHCI_ASYNC_DMA_WRITE(sc, OHCI_CTX_ASYNC_RX_REQUEST,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ OHCI_ASYNC_DMA_WRITE(sc, OHCI_CTX_ASYNC_RX_RESPONSE,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ for (i = 0; i < sc->sc_isoctx; i++) {
+ OHCI_SYNC_RX_DMA_WRITE(sc, i,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ }
+}
+
+static void
+fwohci_buf_next(struct fwohci_softc *sc, struct fwohci_ctx *fc)
+{
+ struct fwohci_buf *fb, *tfb;
+
+#if DOUBLEBUF
+ if (fc->fc_type != FWOHCI_CTX_ISO_MULTI) {
+#endif
+ while ((fb = TAILQ_FIRST(&fc->fc_buf)) != NULL) {
+ if (fc->fc_type) {
+ if (fb->fb_off == 0)
+ break;
+ } else {
+ if (fb->fb_off != fb->fb_desc->fd_reqcount ||
+ fb->fb_desc->fd_rescount != 0)
+ break;
+ }
+ TAILQ_REMOVE(&fc->fc_buf, fb, fb_list);
+ fb->fb_desc->fd_rescount = fb->fb_desc->fd_reqcount;
+ fb->fb_off = 0;
+ fb->fb_desc->fd_branch = 0;
+ tfb = TAILQ_LAST(&fc->fc_buf, fwohci_buf_s);
+ tfb->fb_desc->fd_branch = fb->fb_daddr | 1;
+ TAILQ_INSERT_TAIL(&fc->fc_buf, fb, fb_list);
+ }
+#if DOUBLEBUF
+ } else {
+ struct fwohci_buf_s fctmp;
+
+ /* cleaning buffer */
+ for (fb = TAILQ_FIRST(&fc->fc_buf); fb != NULL;
+ fb = TAILQ_NEXT(fb, fb_list)) {
+ fb->fb_off = 0;
+ fb->fb_desc->fd_rescount = fb->fb_desc->fd_reqcount;
+ }
+
+ /* rotating buffer */
+ fctmp = fc->fc_buf;
+ fc->fc_buf = fc->fc_buf2;
+ fc->fc_buf2 = fctmp;
+ }
+#endif
+}
+
+static int
+fwohci_buf_pktget(struct fwohci_softc *sc, struct fwohci_buf **fbp, caddr_t *pp,
+ int len)
+{
+ struct fwohci_buf *fb;
+ struct fwohci_desc *fd;
+ int bufend;
+
+ fb = *fbp;
+ again:
+ fd = fb->fb_desc;
+ DPRINTFN(1, ("fwohci_buf_pktget: desc %ld, off %d, req %d, res %d,"
+ " len %d, avail %d\n", (long)(fd - sc->sc_desc), fb->fb_off,
+ fd->fd_reqcount, fd->fd_rescount, len,
+ fd->fd_reqcount - fd->fd_rescount - fb->fb_off));
+ bufend = fd->fd_reqcount - fd->fd_rescount;
+ if (fb->fb_off >= bufend) {
+ DPRINTFN(5, ("buf %x finish req %d res %d off %d ",
+ fb->fb_desc->fd_data, fd->fd_reqcount, fd->fd_rescount,
+ fb->fb_off));
+ if (fd->fd_rescount == 0) {
+ *fbp = fb = TAILQ_NEXT(fb, fb_list);
+ if (fb != NULL)
+ goto again;
+ }
+ return 0;
+ }
+ if (fb->fb_off + len > bufend)
+ len = bufend - fb->fb_off;
+ bus_dmamap_sync(sc->sc_dmat, fb->fb_dmamap, fb->fb_off, len,
+ BUS_DMASYNC_POSTREAD);
+ *pp = fb->fb_buf + fb->fb_off;
+ fb->fb_off += roundup(len, 4);
+ return len;
+}
+
+static int
+fwohci_buf_input(struct fwohci_softc *sc, struct fwohci_ctx *fc,
+ struct fwohci_pkt *pkt)
+{
+ caddr_t p;
+ struct fwohci_buf *fb;
+ int len, count, i;
+
+ memset(pkt, 0, sizeof(*pkt));
+ pkt->fp_uio.uio_iov = pkt->fp_iov;
+ pkt->fp_uio.uio_rw = UIO_WRITE;
+ pkt->fp_uio.uio_segflg = UIO_SYSSPACE;
+
+ /* get first quadlet */
+ fb = TAILQ_FIRST(&fc->fc_buf);
+ count = 4;
+ len = fwohci_buf_pktget(sc, &fb, &p, count);
+ if (len <= 0) {
+ DPRINTFN(1, ("fwohci_buf_input: no input for %d\n",
+ fc->fc_ctx));
+ return 0;
+ }
+ pkt->fp_hdr[0] = *(u_int32_t *)p;
+ pkt->fp_tcode = (pkt->fp_hdr[0] & 0x000000f0) >> 4;
+ switch (pkt->fp_tcode) {
+ case IEEE1394_TCODE_WRITE_REQ_QUAD:
+ case IEEE1394_TCODE_READ_RESP_QUAD:
+ pkt->fp_hlen = 12;
+ pkt->fp_dlen = 4;
+ break;
+ case IEEE1394_TCODE_READ_REQ_BLOCK:
+ pkt->fp_hlen = 16;
+ pkt->fp_dlen = 0;
+ break;
+ case IEEE1394_TCODE_WRITE_REQ_BLOCK:
+ case IEEE1394_TCODE_READ_RESP_BLOCK:
+ case IEEE1394_TCODE_LOCK_REQ:
+ case IEEE1394_TCODE_LOCK_RESP:
+ pkt->fp_hlen = 16;
+ break;
+ case IEEE1394_TCODE_STREAM_DATA:
+#ifdef DIAGNOSTIC
+ if (fc->fc_type == FWOHCI_CTX_ISO_MULTI)
+#endif
+ {
+ pkt->fp_hlen = 4;
+ pkt->fp_dlen = pkt->fp_hdr[0] >> 16;
+ DPRINTFN(5, ("[%d]", pkt->fp_dlen));
+ break;
+ }
+#ifdef DIAGNOSTIC
+ else {
+ printf("fwohci_buf_input: bad tcode: STREAM_DATA\n");
+ return 0;
+ }
+#endif
+ default:
+ pkt->fp_hlen = 12;
+ pkt->fp_dlen = 0;
+ break;
+ }
+
+ /* get header */
+ while (count < pkt->fp_hlen) {
+ len = fwohci_buf_pktget(sc, &fb, &p, pkt->fp_hlen - count);
+ if (len == 0) {
+ printf("fwohci_buf_input: malformed input 1: %d\n",
+ pkt->fp_hlen - count);
+ return 0;
+ }
+ memcpy((caddr_t)pkt->fp_hdr + count, p, len);
+ count += len;
+ }
+ if (pkt->fp_hlen == 16 &&
+ pkt->fp_tcode != IEEE1394_TCODE_READ_REQ_BLOCK)
+ pkt->fp_dlen = pkt->fp_hdr[3] >> 16;
+ DPRINTFN(1, ("fwohci_buf_input: tcode=0x%x, hlen=%d, dlen=%d\n",
+ pkt->fp_tcode, pkt->fp_hlen, pkt->fp_dlen));
+
+ /* get data */
+ count = 0;
+ i = 0;
+ while (count < pkt->fp_dlen) {
+ len = fwohci_buf_pktget(sc, &fb,
+ (caddr_t *)&pkt->fp_iov[i].iov_base,
+ pkt->fp_dlen - count);
+ if (len == 0) {
+ printf("fwohci_buf_input: malformed input 2: %d\n",
+ pkt->fp_dlen - count);
+ return 0;
+ }
+ pkt->fp_iov[i++].iov_len = len;
+ count += len;
+ }
+ pkt->fp_uio.uio_iovcnt = i;
+ pkt->fp_uio.uio_resid = count;
+
+ /* get trailer */
+ len = fwohci_buf_pktget(sc, &fb, (caddr_t *)&pkt->fp_trail,
+ sizeof(*pkt->fp_trail));
+ if (len <= 0) {
+ printf("fwohci_buf_input: malformed input 3: %d\n",
+ pkt->fp_hlen - count);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+fwohci_buf_input_ppb(struct fwohci_softc *sc, struct fwohci_ctx *fc,
+ struct fwohci_pkt *pkt)
+{
+ caddr_t p;
+ int len;
+ struct fwohci_buf *fb;
+ struct fwohci_desc *fd;
+
+ if (fc->fc_type == FWOHCI_CTX_ISO_MULTI) {
+ return fwohci_buf_input(sc, fc, pkt);
+ }
+
+ memset(pkt, 0, sizeof(*pkt));
+ pkt->fp_uio.uio_iov = pkt->fp_iov;
+ pkt->fp_uio.uio_rw = UIO_WRITE;
+ pkt->fp_uio.uio_segflg = UIO_SYSSPACE;
+
+ for (fb = TAILQ_FIRST(&fc->fc_buf); ; fb = TAILQ_NEXT(fb, fb_list)) {
+ if (fb == NULL)
+ return 0;
+ if (fb->fb_off == 0)
+ break;
+ }
+ fd = fb->fb_desc;
+ len = fd->fd_reqcount - fd->fd_rescount;
+ if (len == 0)
+ return 0;
+ bus_dmamap_sync(sc->sc_dmat, fb->fb_dmamap, fb->fb_off, len,
+ BUS_DMASYNC_POSTREAD);
+
+ p = fb->fb_buf;
+ fb->fb_off += roundup(len, 4);
+ if (len < 8) {
+ printf("fwohci_buf_input_ppb: malformed input 1: %d\n", len);
+ return 0;
+ }
+
+ /*
+ * get trailer first, may be bogus data unless status update
+ * in descriptor is set.
+ */
+ pkt->fp_trail = (u_int32_t *)p;
+ *pkt->fp_trail = (*pkt->fp_trail & 0xffff) | (fd->fd_status << 16);
+ pkt->fp_hdr[0] = ((u_int32_t *)p)[1];
+ pkt->fp_tcode = (pkt->fp_hdr[0] & 0x000000f0) >> 4;
+#ifdef DIAGNOSTIC
+ if (pkt->fp_tcode != IEEE1394_TCODE_STREAM_DATA) {
+ printf("fwohci_buf_input_ppb: bad tcode: 0x%x\n",
+ pkt->fp_tcode);
+ return 0;
+ }
+#endif
+ pkt->fp_hlen = 4;
+ pkt->fp_dlen = pkt->fp_hdr[0] >> 16;
+ p += 8;
+ len -= 8;
+ if (pkt->fp_dlen != len) {
+ printf("fwohci_buf_input_ppb: malformed input 2: %d != %d\n",
+ pkt->fp_dlen, len);
+ return 0;
+ }
+ DPRINTFN(1, ("fwohci_buf_input_ppb: tcode=0x%x, hlen=%d, dlen=%d\n",
+ pkt->fp_tcode, pkt->fp_hlen, pkt->fp_dlen));
+ pkt->fp_iov[0].iov_base = p;
+ pkt->fp_iov[0].iov_len = len;
+ pkt->fp_uio.uio_iovcnt = 0;
+ pkt->fp_uio.uio_resid = len;
+ return 1;
+}
+
+static int
+fwohci_handler_set(struct fwohci_softc *sc,
+ int tcode, u_int32_t key1, u_int32_t key2,
+ int (*handler)(struct fwohci_softc *, void *, struct fwohci_pkt *),
+ void *arg)
+{
+ struct fwohci_ctx *fc;
+ struct fwohci_handler *fh;
+ int i, j;
+
+ if (tcode == IEEE1394_TCODE_STREAM_DATA) {
+ int isasync = key1 & OHCI_ASYNC_STREAM;
+
+ key1 &= IEEE1394_ISOCH_MASK;
+ j = sc->sc_isoctx;
+ fh = NULL;
+ for (i = 0; i < sc->sc_isoctx; i++) {
+ if ((fc = sc->sc_ctx_ir[i]) == NULL) {
+ if (j == sc->sc_isoctx)
+ j = i;
+ continue;
+ }
+ fh = LIST_FIRST(&fc->fc_handler);
+ if (fh->fh_tcode == tcode &&
+ fh->fh_key1 == key1 && fh->fh_key2 == key2)
+ break;
+ fh = NULL;
+ }
+ if (fh == NULL) {
+ if (handler == NULL)
+ return 0;
+ if (j == sc->sc_isoctx) {
+ DPRINTF(("fwohci_handler_set: no more free "
+ "context\n"));
+ return ENOMEM;
+ }
+ if ((fc = sc->sc_ctx_ir[j]) == NULL) {
+ fwohci_ctx_alloc(sc, &fc, OHCI_BUF_IR_CNT, j,
+ isasync ? FWOHCI_CTX_ISO_SINGLE :
+ FWOHCI_CTX_ISO_MULTI);
+ sc->sc_ctx_ir[j] = fc;
+ }
+ }
+ } else {
+ switch (tcode) {
+ case IEEE1394_TCODE_WRITE_REQ_QUAD:
+ case IEEE1394_TCODE_WRITE_REQ_BLOCK:
+ case IEEE1394_TCODE_READ_REQ_QUAD:
+ case IEEE1394_TCODE_READ_REQ_BLOCK:
+ case IEEE1394_TCODE_LOCK_REQ:
+ fc = sc->sc_ctx_arrq;
+ break;
+ case IEEE1394_TCODE_WRITE_RESP:
+ case IEEE1394_TCODE_READ_RESP_QUAD:
+ case IEEE1394_TCODE_READ_RESP_BLOCK:
+ case IEEE1394_TCODE_LOCK_RESP:
+ fc = sc->sc_ctx_arrs;
+ break;
+ default:
+ return EIO;
+ }
+ for (fh = LIST_FIRST(&fc->fc_handler); fh != NULL;
+ fh = LIST_NEXT(fh, fh_list)) {
+ if (fh->fh_tcode == tcode &&
+ fh->fh_key1 == key1 && fh->fh_key2 == key2)
+ break;
+ }
+ }
+ if (handler == NULL) {
+ if (fh != NULL) {
+ LIST_REMOVE(fh, fh_list);
+ free(fh, M_DEVBUF);
+ }
+ if (tcode == IEEE1394_TCODE_STREAM_DATA) {
+ OHCI_SYNC_RX_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ sc->sc_ctx_ir[fc->fc_ctx] = NULL;
+ fwohci_ctx_free(sc, fc);
+ }
+ return 0;
+ }
+ if (fh == NULL) {
+ fh = malloc(sizeof(*fh), M_DEVBUF, M_WAITOK);
+ LIST_INSERT_HEAD(&fc->fc_handler, fh, fh_list);
+ }
+ fh->fh_tcode = tcode;
+ fh->fh_key1 = key1;
+ fh->fh_key2 = key2;
+ fh->fh_handler = handler;
+ fh->fh_handarg = arg;
+ DPRINTFN(1, ("fwohci_handler_set: ctx %d, tcode %x, key 0x%x, 0x%x\n",
+ fc->fc_ctx, tcode, key1, key2));
+
+ if (tcode == IEEE1394_TCODE_STREAM_DATA) {
+ fwohci_ctx_init(sc, fc);
+ DPRINTFN(1, ("fwohci_handler_set: SYNC desc %ld\n",
+ (long)(TAILQ_FIRST(&fc->fc_buf)->fb_desc - sc->sc_desc)));
+ OHCI_SYNC_RX_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_RUN);
+ }
+ return 0;
+}
+
+/*
+ * Asyncronous Receive Requests input frontend.
+ */
+static void
+fwohci_arrq_input(struct fwohci_softc *sc, struct fwohci_ctx *fc)
+{
+ int rcode;
+ u_int32_t key1, key2;
+ struct fwohci_handler *fh;
+ struct fwohci_pkt pkt, res;
+
+ /*
+ * Do not return if next packet is in the buffer, or the next
+ * packet cannot be received until the next receive interrupt.
+ */
+ while (fwohci_buf_input(sc, fc, &pkt)) {
+ if (pkt.fp_tcode == OHCI_TCODE_PHY) {
+ fwohci_phy_input(sc, &pkt);
+ continue;
+ }
+ key1 = pkt.fp_hdr[1] & 0xffff;
+ key2 = pkt.fp_hdr[2];
+ memset(&res, 0, sizeof(res));
+ res.fp_uio.uio_rw = UIO_WRITE;
+ res.fp_uio.uio_segflg = UIO_SYSSPACE;
+ for (fh = LIST_FIRST(&fc->fc_handler); fh != NULL;
+ fh = LIST_NEXT(fh, fh_list)) {
+ if (pkt.fp_tcode == fh->fh_tcode &&
+ key1 == fh->fh_key1 &&
+ key2 == fh->fh_key2) {
+ rcode = (*fh->fh_handler)(sc, fh->fh_handarg,
+ &pkt);
+ break;
+ }
+ }
+ if (fh == NULL) {
+ rcode = IEEE1394_RCODE_ADDRESS_ERROR;
+ DPRINTFN(1, ("fwohci_arrq_input: no listener: tcode "
+ "0x%x, addr=0x%04x %08x\n", pkt.fp_tcode, key1,
+ key2));
+ }
+ if (((*pkt.fp_trail & 0x001f0000) >> 16) !=
+ OHCI_CTXCTL_EVENT_ACK_PENDING)
+ continue;
+ if (rcode != -1)
+ fwohci_atrs_output(sc, rcode, &pkt, &res);
+ }
+ fwohci_buf_next(sc, fc);
+ OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_WAKE);
+}
+
+
+/*
+ * Asynchronous Receive Response input frontend.
+ */
+static void
+fwohci_arrs_input(struct fwohci_softc *sc, struct fwohci_ctx *fc)
+{
+ struct fwohci_pkt pkt;
+ struct fwohci_handler *fh;
+ u_int16_t srcid;
+ int rcode, tlabel;
+
+ while (fwohci_buf_input(sc, fc, &pkt)) {
+ srcid = pkt.fp_hdr[1] >> 16;
+ rcode = (pkt.fp_hdr[1] & 0x0000f000) >> 12;
+ tlabel = (pkt.fp_hdr[0] & 0x0000fc00) >> 10;
+ DPRINTFN(1, ("fwohci_arrs_input: tcode 0x%x, from 0x%04x,"
+ " tlabel 0x%x, rcode 0x%x, hlen %d, dlen %d\n",
+ pkt.fp_tcode, srcid, tlabel, rcode, pkt.fp_hlen,
+ pkt.fp_dlen));
+ for (fh = LIST_FIRST(&fc->fc_handler); fh != NULL;
+ fh = LIST_NEXT(fh, fh_list)) {
+ if (pkt.fp_tcode == fh->fh_tcode &&
+ (srcid & OHCI_NodeId_NodeNumber) == fh->fh_key1 &&
+ tlabel == fh->fh_key2) {
+ (*fh->fh_handler)(sc, fh->fh_handarg, &pkt);
+ LIST_REMOVE(fh, fh_list);
+ free(fh, M_DEVBUF);
+ break;
+ }
+ }
+ if (fh == NULL)
+ DPRINTFN(1, ("fwohci_arrs_input: no listner\n"));
+ }
+ fwohci_buf_next(sc, fc);
+ OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_WAKE);
+}
+
+/*
+ * Isochronous Receive input frontend.
+ */
+static void
+fwohci_ir_input(struct fwohci_softc *sc, struct fwohci_ctx *fc)
+{
+ int rcode, chan, tag;
+ struct iovec *iov;
+ struct fwohci_handler *fh;
+ struct fwohci_pkt pkt;
+
+#if DOUBLEBUF
+ if (fc->fc_type == FWOHCI_CTX_ISO_MULTI) {
+ struct fwohci_buf *fb;
+ int i;
+ u_int32_t reg;
+
+ /* stop dma engine before read buffer */
+ reg = OHCI_SYNC_RX_DMA_READ(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlClear);
+ DPRINTFN(5, ("ir_input %08x =>", reg));
+ if (reg & OHCI_CTXCTL_RUN) {
+ OHCI_SYNC_RX_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ }
+ DPRINTFN(5, (" %08x\n", OHCI_SYNC_RX_DMA_READ(sc, fc->fc_ctx, OHCI_SUBREG_ContextControlClear)));
+
+ i = 0;
+ while ((reg = OHCI_SYNC_RX_DMA_READ(sc, fc->fc_ctx, OHCI_SUBREG_ContextControlSet)) & OHCI_CTXCTL_ACTIVE) {
+ delay(10);
+ if (++i > 10000) {
+ printf("cannot stop dma engine 0x%08x\n", reg);
+ return;
+ }
+ }
+
+ /* rotate dma buffer */
+ fb = TAILQ_FIRST(&fc->fc_buf2);
+ OHCI_SYNC_RX_DMA_WRITE(sc, fc->fc_ctx, OHCI_SUBREG_CommandPtr,
+ fb->fb_daddr | 1);
+ /* start dma engine */
+ OHCI_SYNC_RX_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_RUN);
+ OHCI_CSR_WRITE(sc, OHCI_REG_IsoRecvIntEventClear,
+ (1 << fc->fc_ctx));
+ }
+#endif
+
+ while (fwohci_buf_input_ppb(sc, fc, &pkt)) {
+ chan = (pkt.fp_hdr[0] & 0x00003f00) >> 8;
+ tag = (pkt.fp_hdr[0] & 0x0000c000) >> 14;
+ DPRINTFN(1, ("fwohci_ir_input: hdr 0x%08x, tcode 0x%0x, hlen %d"
+ ", dlen %d\n", pkt.fp_hdr[0], pkt.fp_tcode, pkt.fp_hlen,
+ pkt.fp_dlen));
+ if (tag == IEEE1394_TAG_GASP) {
+ /*
+ * The pkt with tag=3 is GASP format.
+ * Move GASP header to header part.
+ */
+ if (pkt.fp_dlen < 8)
+ continue;
+ iov = pkt.fp_iov;
+ /* assuming pkt per buffer mode */
+ pkt.fp_hdr[1] = ntohl(((u_int32_t *)iov->iov_base)[0]);
+ pkt.fp_hdr[2] = ntohl(((u_int32_t *)iov->iov_base)[1]);
+ iov->iov_base = (caddr_t)iov->iov_base + 8;
+ iov->iov_len -= 8;
+ pkt.fp_hlen += 8;
+ pkt.fp_dlen -= 8;
+ }
+ sc->sc_isopktcnt.ev_count++;
+ for (fh = LIST_FIRST(&fc->fc_handler); fh != NULL;
+ fh = LIST_NEXT(fh, fh_list)) {
+ if (pkt.fp_tcode == fh->fh_tcode &&
+ chan == fh->fh_key1 && tag == fh->fh_key2) {
+ rcode = (*fh->fh_handler)(sc, fh->fh_handarg,
+ &pkt);
+ break;
+ }
+ }
+#ifdef FW_DEBUG
+ if (fh == NULL) {
+ DPRINTFN(1, ("fwohci_ir_input: no handler\n"));
+ } else {
+ DPRINTFN(1, ("fwohci_ir_input: rcode %d\n", rcode));
+ }
+#endif
+ }
+ fwohci_buf_next(sc, fc);
+
+ if (fc->fc_type == FWOHCI_CTX_ISO_SINGLE) {
+ OHCI_SYNC_RX_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlSet,
+ OHCI_CTXCTL_WAKE);
+ }
+}
+
+/*
+ * Asynchronous Transmit common routine.
+ */
+static int
+fwohci_at_output(struct fwohci_softc *sc, struct fwohci_ctx *fc,
+ struct fwohci_pkt *pkt)
+{
+ struct fwohci_buf *fb;
+ struct fwohci_desc *fd;
+ struct mbuf *m, *m0;
+ int i, ndesc, error, off, len;
+ u_int32_t val;
+#ifdef FW_DEBUG
+ struct iovec *iov;
+#endif
+
+ if ((sc->sc_nodeid & OHCI_NodeId_NodeNumber) == IEEE1394_BCAST_PHY_ID)
+ /* We can't send anything during selfid duration */
+ return EAGAIN;
+
+#ifdef FW_DEBUG
+ DPRINTFN(1, ("fwohci_at_output: tcode 0x%x, hlen %d, dlen %d",
+ pkt->fp_tcode, pkt->fp_hlen, pkt->fp_dlen));
+ for (i = 0; i < pkt->fp_hlen/4; i++)
+ DPRINTFN(2, ("%s%08x", i?" ":"\n ", pkt->fp_hdr[i]));
+ DPRINTFN(2, ("$"));
+ for (ndesc = 0, iov = pkt->fp_iov;
+ ndesc < pkt->fp_uio.uio_iovcnt; ndesc++, iov++) {
+ for (i = 0; i < iov->iov_len; i++)
+ DPRINTFN(2, ("%s%02x", (i%32)?((i%4)?"":" "):"\n ",
+ ((u_int8_t *)iov->iov_base)[i]));
+ DPRINTFN(2, ("$"));
+ }
+ DPRINTFN(1, ("\n"));
+#endif
+
+ if ((m = pkt->fp_m) != NULL) {
+ for (ndesc = 2; m != NULL; m = m->m_next)
+ ndesc++;
+ if (ndesc > OHCI_DESC_MAX) {
+ m0 = NULL;
+ ndesc = 2;
+ for (off = 0; off < pkt->fp_dlen; off += len) {
+ if (m0 == NULL) {
+ MGETHDR(m0, M_DONTWAIT, MT_DATA);
+ if (m0 != NULL) {
+#ifdef __NetBSD__
+ M_COPY_PKTHDR(m0, pkt->fp_m);
+#else
+ M_DUP_PKTHDR(m0, pkt->fp_m);
+#endif
+ }
+ m = m0;
+ } else {
+ MGET(m->m_next, M_DONTWAIT, MT_DATA);
+ m = m->m_next;
+ }
+ if (m != NULL)
+ MCLGET(m, M_DONTWAIT);
+ if (m == NULL || (m->m_flags & M_EXT) == 0) {
+ m_freem(m0);
+ return ENOMEM;
+ }
+ len = pkt->fp_dlen - off;
+ if (len > m->m_ext.ext_size)
+ len = m->m_ext.ext_size;
+ m_copydata(pkt->fp_m, off, len,
+ mtod(m, caddr_t));
+ m->m_len = len;
+ ndesc++;
+ }
+ m_freem(pkt->fp_m);
+ pkt->fp_m = m0;
+ }
+ } else
+ ndesc = 2 + pkt->fp_uio.uio_iovcnt;
+
+ if (ndesc > OHCI_DESC_MAX)
+ return ENOBUFS;
+
+ if (fc->fc_bufcnt > 50) /*XXX*/
+ return ENOBUFS;
+ fb = malloc(sizeof(*fb), M_DEVBUF, M_WAITOK);
+ fb->fb_nseg = ndesc;
+ fb->fb_desc = fwohci_desc_get(sc, ndesc);
+ if (fb->fb_desc == NULL) {
+ free(fb, M_DEVBUF);
+ return ENOBUFS;
+ }
+ fb->fb_daddr = sc->sc_ddmamap->dm_segs[0].ds_addr +
+ ((caddr_t)fb->fb_desc - (caddr_t)sc->sc_desc);
+ fb->fb_m = pkt->fp_m;
+ fb->fb_callback = pkt->fp_callback;
+ fb->fb_statuscb = pkt->fp_statuscb;
+ fb->fb_statusarg = pkt->fp_statusarg;
+
+ if (ndesc > 2) {
+ if ((error = bus_dmamap_create(sc->sc_dmat, pkt->fp_dlen, ndesc,
+ PAGE_SIZE, 0, BUS_DMA_WAITOK, &fb->fb_dmamap)) != 0) {
+ fwohci_desc_put(sc, fb->fb_desc, ndesc);
+ free(fb, M_DEVBUF);
+ return error;
+ }
+
+ if (pkt->fp_m != NULL)
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, fb->fb_dmamap,
+ pkt->fp_m, BUS_DMA_WAITOK);
+ else
+ error = bus_dmamap_load_uio(sc->sc_dmat, fb->fb_dmamap,
+ &pkt->fp_uio, BUS_DMA_WAITOK);
+ if (error != 0) {
+ bus_dmamap_destroy(sc->sc_dmat, fb->fb_dmamap);
+ fwohci_desc_put(sc, fb->fb_desc, ndesc);
+ free(fb, M_DEVBUF);
+ return error;
+ }
+ bus_dmamap_sync(sc->sc_dmat, fb->fb_dmamap, 0, pkt->fp_dlen,
+ BUS_DMASYNC_PREWRITE);
+ }
+
+ fd = fb->fb_desc;
+ fd->fd_flags = OHCI_DESC_IMMED;
+ fd->fd_reqcount = pkt->fp_hlen;
+ fd->fd_data = 0;
+ fd->fd_branch = 0;
+ fd->fd_status = 0;
+ if (fc->fc_ctx == OHCI_CTX_ASYNC_TX_RESPONSE) {
+ i = 3; /* XXX: 3 sec */
+ val = OHCI_CSR_READ(sc, OHCI_REG_IsochronousCycleTimer);
+ fd->fd_timestamp = ((val >> 12) & 0x1fff) |
+ ((((val >> 25) + i) & 0x7) << 13);
+ } else
+ fd->fd_timestamp = 0;
+ memcpy(fd + 1, pkt->fp_hdr, pkt->fp_hlen);
+ for (i = 0; i < ndesc - 2; i++) {
+ fd = fb->fb_desc + 2 + i;
+ fd->fd_flags = 0;
+ fd->fd_reqcount = fb->fb_dmamap->dm_segs[i].ds_len;
+ fd->fd_data = fb->fb_dmamap->dm_segs[i].ds_addr;
+ fd->fd_branch = 0;
+ fd->fd_status = 0;
+ fd->fd_timestamp = 0;
+ }
+ fd->fd_flags |= OHCI_DESC_LAST | OHCI_DESC_BRANCH;
+ fd->fd_flags |= OHCI_DESC_INTR_ALWAYS;
+
+#ifdef FW_DEBUG
+ DPRINTFN(1, ("fwohci_at_output: desc %ld",
+ (long)(fb->fb_desc - sc->sc_desc)));
+ for (i = 0; i < ndesc * 4; i++)
+ DPRINTFN(2, ("%s%08x", i&7?" ":"\n ",
+ ((u_int32_t *)fb->fb_desc)[i]));
+ DPRINTFN(1, ("\n"));
+#endif
+
+ val = OHCI_ASYNC_DMA_READ(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlClear);
+
+ if (val & OHCI_CTXCTL_RUN) {
+ if (fc->fc_branch == NULL) {
+ OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ goto run;
+ }
+ *fc->fc_branch = fb->fb_daddr | ndesc;
+ OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_WAKE);
+ } else {
+ run:
+ OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_CommandPtr, fb->fb_daddr | ndesc);
+ OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlSet, OHCI_CTXCTL_RUN);
+ }
+ fc->fc_branch = &fd->fd_branch;
+
+ fc->fc_bufcnt++;
+ TAILQ_INSERT_TAIL(&fc->fc_buf, fb, fb_list);
+ pkt->fp_m = NULL;
+ return 0;
+}
+
+static void
+fwohci_at_done(struct fwohci_softc *sc, struct fwohci_ctx *fc, int force)
+{
+ struct fwohci_buf *fb;
+ struct fwohci_desc *fd;
+ struct fwohci_pkt pkt;
+ int i;
+
+ while ((fb = TAILQ_FIRST(&fc->fc_buf)) != NULL) {
+ fd = fb->fb_desc;
+#ifdef FW_DEBUG
+ DPRINTFN(1, ("fwohci_at_done: %sdesc %ld (%d)",
+ force ? "force " : "", (long)(fd - sc->sc_desc),
+ fb->fb_nseg));
+ for (i = 0; i < fb->fb_nseg * 4; i++)
+ DPRINTFN(2, ("%s%08x", i&7?" ":"\n ",
+ ((u_int32_t *)fd)[i]));
+ DPRINTFN(1, ("\n"));
+#endif
+ if (fb->fb_nseg > 2)
+ fd += fb->fb_nseg - 1;
+ if (!force && !(fd->fd_status & OHCI_CTXCTL_ACTIVE))
+ break;
+ TAILQ_REMOVE(&fc->fc_buf, fb, fb_list);
+ if (fc->fc_branch == &fd->fd_branch) {
+ OHCI_ASYNC_DMA_WRITE(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlClear, OHCI_CTXCTL_RUN);
+ fc->fc_branch = NULL;
+ for (i = 0; i < OHCI_LOOP; i++) {
+ if (!(OHCI_ASYNC_DMA_READ(sc, fc->fc_ctx,
+ OHCI_SUBREG_ContextControlClear) &
+ OHCI_CTXCTL_ACTIVE))
+ break;
+ DELAY(10);
+ }
+ }
+
+ if (fb->fb_statuscb) {
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.fp_status = fd->fd_status;
+ memcpy(pkt.fp_hdr, fd + 1, sizeof(pkt.fp_hdr[0]));
+
+ /* Indicate this is just returning the status bits. */
+ pkt.fp_tcode = -1;
+ (*fb->fb_statuscb)(sc, fb->fb_statusarg, &pkt);
+ fb->fb_statuscb = NULL;
+ fb->fb_statusarg = NULL;
+ }
+ fwohci_desc_put(sc, fb->fb_desc, fb->fb_nseg);
+ if (fb->fb_nseg > 2)
+ bus_dmamap_destroy(sc->sc_dmat, fb->fb_dmamap);
+ fc->fc_bufcnt--;
+ if (fb->fb_callback) {
+ (*fb->fb_callback)(sc->sc_sc1394.sc1394_if, fb->fb_m);
+ fb->fb_callback = NULL;
+ } else if (fb->fb_m != NULL)
+ m_freem(fb->fb_m);
+ free(fb, M_DEVBUF);
+ }
+}
+
+/*
+ * Asynchronous Transmit Reponse -- in response of request packet.
+ */
+static void
+fwohci_atrs_output(struct fwohci_softc *sc, int rcode, struct fwohci_pkt *req,
+ struct fwohci_pkt *res)
+{
+
+ if (((*req->fp_trail & 0x001f0000) >> 16) !=
+ OHCI_CTXCTL_EVENT_ACK_PENDING)
+ return;
+
+ res->fp_hdr[0] = (req->fp_hdr[0] & 0x0000fc00) | 0x00000100;
+ res->fp_hdr[1] = (req->fp_hdr[1] & 0xffff0000) | (rcode << 12);
+ switch (req->fp_tcode) {
+ case IEEE1394_TCODE_WRITE_REQ_QUAD:
+ case IEEE1394_TCODE_WRITE_REQ_BLOCK:
+ res->fp_tcode = IEEE1394_TCODE_WRITE_RESP;
+ res->fp_hlen = 12;
+ break;
+ case IEEE1394_TCODE_READ_REQ_QUAD:
+ res->fp_tcode = IEEE1394_TCODE_READ_RESP_QUAD;
+ res->fp_hlen = 16;
+ res->fp_dlen = 0;
+ if (res->fp_uio.uio_iovcnt == 1 && res->fp_iov[0].iov_len == 4)
+ res->fp_hdr[3] =
+ *(u_int32_t *)res->fp_iov[0].iov_base;
+ res->fp_uio.uio_iovcnt = 0;
+ break;
+ case IEEE1394_TCODE_READ_REQ_BLOCK:
+ case IEEE1394_TCODE_LOCK_REQ:
+ if (req->fp_tcode == IEEE1394_TCODE_LOCK_REQ)
+ res->fp_tcode = IEEE1394_TCODE_LOCK_RESP;
+ else
+ res->fp_tcode = IEEE1394_TCODE_READ_RESP_BLOCK;
+ res->fp_hlen = 16;
+ res->fp_dlen = res->fp_uio.uio_resid;
+ res->fp_hdr[3] = res->fp_dlen << 16;
+ break;
+ }
+ res->fp_hdr[0] |= (res->fp_tcode << 4);
+ fwohci_at_output(sc, sc->sc_ctx_atrs, res);
+}
+
+/*
+ * APPLICATION LAYER SERVICES
+ */
+
+/*
+ * Retrieve Global UID from GUID ROM
+ */
+static int
+fwohci_guidrom_init(struct fwohci_softc *sc)
+{
+ int i, n, off;
+ u_int32_t val1, val2;
+
+ /* Extract the Global UID
+ */
+ val1 = OHCI_CSR_READ(sc, OHCI_REG_GUIDHi);
+ val2 = OHCI_CSR_READ(sc, OHCI_REG_GUIDLo);
+
+ if (val1 != 0 || val2 != 0) {
+ sc->sc_sc1394.sc1394_guid[0] = (val1 >> 24) & 0xff;
+ sc->sc_sc1394.sc1394_guid[1] = (val1 >> 16) & 0xff;
+ sc->sc_sc1394.sc1394_guid[2] = (val1 >> 8) & 0xff;
+ sc->sc_sc1394.sc1394_guid[3] = (val1 >> 0) & 0xff;
+ sc->sc_sc1394.sc1394_guid[4] = (val2 >> 24) & 0xff;
+ sc->sc_sc1394.sc1394_guid[5] = (val2 >> 16) & 0xff;
+ sc->sc_sc1394.sc1394_guid[6] = (val2 >> 8) & 0xff;
+ sc->sc_sc1394.sc1394_guid[7] = (val2 >> 0) & 0xff;
+ } else {
+ val1 = OHCI_CSR_READ(sc, OHCI_REG_Version);
+ if ((val1 & OHCI_Version_GUID_ROM) == 0)
+ return -1;
+ OHCI_CSR_WRITE(sc, OHCI_REG_Guid_Rom, OHCI_Guid_AddrReset);
+ for (i = 0; i < OHCI_LOOP; i++) {
+ val1 = OHCI_CSR_READ(sc, OHCI_REG_Guid_Rom);
+ if (!(val1 & OHCI_Guid_AddrReset))
+ break;
+ DELAY(10);
+ }
+ off = OHCI_BITVAL(val1, OHCI_Guid_MiniROM) + 4;
+ val2 = 0;
+ for (n = 0; n < off + sizeof(sc->sc_sc1394.sc1394_guid); n++) {
+ OHCI_CSR_WRITE(sc, OHCI_REG_Guid_Rom,
+ OHCI_Guid_RdStart);
+ for (i = 0; i < OHCI_LOOP; i++) {
+ val1 = OHCI_CSR_READ(sc, OHCI_REG_Guid_Rom);
+ if (!(val1 & OHCI_Guid_RdStart))
+ break;
+ DELAY(10);
+ }
+ if (n < off)
+ continue;
+ val1 = OHCI_BITVAL(val1, OHCI_Guid_RdData);
+ sc->sc_sc1394.sc1394_guid[n - off] = val1;
+ val2 |= val1;
+ }
+ if (val2 == 0)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Initialization for Configuration ROM (no DMA context)
+ */
+
+#define CFR_MAXUNIT 20
+
+struct configromctx {
+ u_int32_t *ptr;
+ int curunit;
+ struct {
+ u_int32_t *start;
+ int length;
+ u_int32_t *refer;
+ int refunit;
+ } unit[CFR_MAXUNIT];
+};
+
+#define CFR_PUT_DATA4(cfr, d1, d2, d3, d4) \
+ (*(cfr)->ptr++ = (((d1)<<24) | ((d2)<<16) | ((d3)<<8) | (d4)))
+
+#define CFR_PUT_DATA1(cfr, d) (*(cfr)->ptr++ = (d))
+
+#define CFR_PUT_VALUE(cfr, key, d) (*(cfr)->ptr++ = ((key)<<24) | (d))
+
+#define CFR_PUT_CRC(cfr, n) \
+ (*(cfr)->unit[n].start = ((cfr)->unit[n].length << 16) | \
+ fwohci_crc16((cfr)->unit[n].start + 1, (cfr)->unit[n].length))
+
+#define CFR_START_UNIT(cfr, n) \
+do { \
+ if ((cfr)->unit[n].refer != NULL) { \
+ *(cfr)->unit[n].refer |= \
+ (cfr)->ptr - (cfr)->unit[n].refer; \
+ CFR_PUT_CRC(cfr, (cfr)->unit[n].refunit); \
+ } \
+ (cfr)->curunit = (n); \
+ (cfr)->unit[n].start = (cfr)->ptr++; \
+} while (0 /* CONSTCOND */)
+
+#define CFR_PUT_REFER(cfr, key, n) \
+do { \
+ (cfr)->unit[n].refer = (cfr)->ptr; \
+ (cfr)->unit[n].refunit = (cfr)->curunit; \
+ *(cfr)->ptr++ = (key) << 24; \
+} while (0 /* CONSTCOND */)
+
+#define CFR_END_UNIT(cfr) \
+do { \
+ (cfr)->unit[(cfr)->curunit].length = (cfr)->ptr - \
+ ((cfr)->unit[(cfr)->curunit].start + 1); \
+ CFR_PUT_CRC(cfr, (cfr)->curunit); \
+} while (0 /* CONSTCOND */)
+
+static u_int16_t
+fwohci_crc16(u_int32_t *ptr, int len)
+{
+ int shift;
+ u_int32_t crc, sum, data;
+
+ crc = 0;
+ while (len-- > 0) {
+ data = *ptr++;
+ for (shift = 28; shift >= 0; shift -= 4) {
+ sum = ((crc >> 12) ^ (data >> shift)) & 0x000f;
+ crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
+ }
+ crc &= 0xffff;
+ }
+ return crc;
+}
+
+static void
+fwohci_configrom_init(struct fwohci_softc *sc)
+{
+ int i, val;
+ struct fwohci_buf *fb;
+ u_int32_t *hdr;
+ struct configromctx cfr;
+
+ fb = &sc->sc_buf_cnfrom;
+ memset(&cfr, 0, sizeof(cfr));
+ cfr.ptr = hdr = (u_int32_t *)fb->fb_buf;
+
+ /* headers */
+ CFR_START_UNIT(&cfr, 0);
+ CFR_PUT_DATA1(&cfr, OHCI_CSR_READ(sc, OHCI_REG_BusId));
+ CFR_PUT_DATA1(&cfr, OHCI_CSR_READ(sc, OHCI_REG_BusOptions));
+ CFR_PUT_DATA1(&cfr, OHCI_CSR_READ(sc, OHCI_REG_GUIDHi));
+ CFR_PUT_DATA1(&cfr, OHCI_CSR_READ(sc, OHCI_REG_GUIDLo));
+ CFR_END_UNIT(&cfr);
+ /* copy info_length from crc_length */
+ *hdr |= (*hdr & 0x00ff0000) << 8;
+ OHCI_CSR_WRITE(sc, OHCI_REG_ConfigROMhdr, *hdr);
+
+ /* root directory */
+ CFR_START_UNIT(&cfr, 1);
+ CFR_PUT_VALUE(&cfr, 0x03, 0x00005e); /* vendor id */
+ CFR_PUT_REFER(&cfr, 0x81, 2); /* textual descriptor offset */
+ CFR_PUT_VALUE(&cfr, 0x0c, 0x0083c0); /* node capability */
+ /* spt,64,fix,lst,drq */
+#ifdef INET
+ CFR_PUT_REFER(&cfr, 0xd1, 3); /* IPv4 unit directory */
+#endif /* INET */
+#ifdef INET6
+ CFR_PUT_REFER(&cfr, 0xd1, 4); /* IPv6 unit directory */
+#endif /* INET6 */
+ CFR_END_UNIT(&cfr);
+
+ CFR_START_UNIT(&cfr, 2);
+ CFR_PUT_VALUE(&cfr, 0, 0); /* textual descriptor */
+ CFR_PUT_DATA1(&cfr, 0); /* minimal ASCII */
+ CFR_PUT_DATA4(&cfr, 'N', 'e', 't', 'B');
+ CFR_PUT_DATA4(&cfr, 'S', 'D', 0x00, 0x00);
+ CFR_END_UNIT(&cfr);
+
+#ifdef INET
+ /* IPv4 unit directory */
+ CFR_START_UNIT(&cfr, 3);
+ CFR_PUT_VALUE(&cfr, 0x12, 0x00005e); /* unit spec id */
+ CFR_PUT_REFER(&cfr, 0x81, 6); /* textual descriptor offset */
+ CFR_PUT_VALUE(&cfr, 0x13, 0x000001); /* unit sw version */
+ CFR_PUT_REFER(&cfr, 0x81, 7); /* textual descriptor offset */
+ CFR_PUT_REFER(&cfr, 0x95, 8); /* Unit location */
+ CFR_END_UNIT(&cfr);
+
+ CFR_START_UNIT(&cfr, 6);
+ CFR_PUT_VALUE(&cfr, 0, 0); /* textual descriptor */
+ CFR_PUT_DATA1(&cfr, 0); /* minimal ASCII */
+ CFR_PUT_DATA4(&cfr, 'I', 'A', 'N', 'A');
+ CFR_END_UNIT(&cfr);
+
+ CFR_START_UNIT(&cfr, 7);
+ CFR_PUT_VALUE(&cfr, 0, 0); /* textual descriptor */
+ CFR_PUT_DATA1(&cfr, 0); /* minimal ASCII */
+ CFR_PUT_DATA4(&cfr, 'I', 'P', 'v', '4');
+ CFR_END_UNIT(&cfr);
+
+ CFR_START_UNIT(&cfr, 8); /* Spec's valid addr range. */
+ CFR_PUT_DATA1(&cfr, FW_FIFO_HI);
+ CFR_PUT_DATA1(&cfr, (FW_FIFO_LO | 0x1));
+ CFR_PUT_DATA1(&cfr, FW_FIFO_HI);
+ CFR_PUT_DATA1(&cfr, FW_FIFO_LO);
+ CFR_END_UNIT(&cfr);
+
+#endif /* INET */
+
+#ifdef INET6
+ /* IPv6 unit directory */
+ CFR_START_UNIT(&cfr, 4);
+ CFR_PUT_VALUE(&cfr, 0x12, 0x00005e); /* unit spec id */
+ CFR_PUT_REFER(&cfr, 0x81, 9); /* textual descriptor offset */
+ CFR_PUT_VALUE(&cfr, 0x13, 0x000002); /* unit sw version */
+ /* XXX: TBA by IANA */
+ CFR_PUT_REFER(&cfr, 0x81, 10); /* textual descriptor offset */
+ CFR_PUT_REFER(&cfr, 0x95, 11); /* Unit location */
+ CFR_END_UNIT(&cfr);
+
+ CFR_START_UNIT(&cfr, 9);
+ CFR_PUT_VALUE(&cfr, 0, 0); /* textual descriptor */
+ CFR_PUT_DATA1(&cfr, 0); /* minimal ASCII */
+ CFR_PUT_DATA4(&cfr, 'I', 'A', 'N', 'A');
+ CFR_END_UNIT(&cfr);
+
+ CFR_START_UNIT(&cfr, 10);
+ CFR_PUT_VALUE(&cfr, 0, 0); /* textual descriptor */
+ CFR_PUT_DATA1(&cfr, 0);
+ CFR_PUT_DATA4(&cfr, 'I', 'P', 'v', '6');
+ CFR_END_UNIT(&cfr);
+
+ CFR_START_UNIT(&cfr, 11); /* Spec's valid addr range. */
+ CFR_PUT_DATA1(&cfr, FW_FIFO_HI);
+ CFR_PUT_DATA1(&cfr, (FW_FIFO_LO | 0x1));
+ CFR_PUT_DATA1(&cfr, FW_FIFO_HI);
+ CFR_PUT_DATA1(&cfr, FW_FIFO_LO);
+ CFR_END_UNIT(&cfr);
+
+#endif /* INET6 */
+
+ fb->fb_off = cfr.ptr - hdr;
+#ifdef FW_DEBUG
+ DPRINTF(("%s: Config ROM:", sc->sc_sc1394.sc1394_dev.dv_xname));
+ for (i = 0; i < fb->fb_off; i++)
+ DPRINTF(("%s%08x", i&7?" ":"\n ", hdr[i]));
+ DPRINTF(("\n"));
+#endif /* FW_DEBUG */
+
+ /*
+ * Make network byte order for DMA
+ */
+ for (i = 0; i < fb->fb_off; i++)
+ HTONL(hdr[i]);
+ bus_dmamap_sync(sc->sc_dmat, fb->fb_dmamap, 0,
+ (caddr_t)cfr.ptr - fb->fb_buf, BUS_DMASYNC_PREWRITE);
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_ConfigROMmap,
+ fb->fb_dmamap->dm_segs[0].ds_addr);
+
+ /* This register is only valid on OHCI 1.1. */
+ val = OHCI_CSR_READ(sc, OHCI_REG_Version);
+ if ((OHCI_Version_GET_Version(val) == 1) &&
+ (OHCI_Version_GET_Revision(val) == 1))
+ OHCI_CSR_WRITE(sc, OHCI_REG_HCControlSet,
+ OHCI_HCControl_BIBImageValid);
+
+ /* Just allow quad reads of the rom. */
+ for (i = 0; i < fb->fb_off; i++)
+ fwohci_handler_set(sc, IEEE1394_TCODE_READ_REQ_QUAD,
+ CSR_BASE_HI, CSR_BASE_LO + CSR_CONFIG_ROM + (i * 4),
+ fwohci_configrom_input, NULL);
+}
+
+static int
+fwohci_configrom_input(struct fwohci_softc *sc, void *arg,
+ struct fwohci_pkt *pkt)
+{
+ struct fwohci_pkt res;
+ u_int32_t loc, *rom;
+
+ /* This will be used as an array index so size accordingly. */
+ loc = pkt->fp_hdr[2] - (CSR_BASE_LO + CSR_CONFIG_ROM);
+ if ((loc & 0x03) != 0) {
+ /* alignment error */
+ return IEEE1394_RCODE_ADDRESS_ERROR;
+ }
+ else
+ loc /= 4;
+ rom = (u_int32_t *)sc->sc_buf_cnfrom.fb_buf;
+
+ DPRINTFN(1, ("fwohci_configrom_input: ConfigRom[0x%04x]: 0x%08x\n", loc,
+ ntohl(rom[loc])));
+
+ memset(&res, 0, sizeof(res));
+ res.fp_hdr[3] = rom[loc];
+ fwohci_atrs_output(sc, IEEE1394_RCODE_COMPLETE, pkt, &res);
+ return -1;
+}
+
+/*
+ * SelfID buffer (no DMA context)
+ */
+static void
+fwohci_selfid_init(struct fwohci_softc *sc)
+{
+ struct fwohci_buf *fb;
+
+ fb = &sc->sc_buf_selfid;
+#ifdef DIAGNOSTIC
+ if ((fb->fb_dmamap->dm_segs[0].ds_addr & 0x7ff) != 0)
+ panic("fwohci_selfid_init: not aligned: %ld (%ld) %p",
+ (unsigned long)fb->fb_dmamap->dm_segs[0].ds_addr,
+ (unsigned long)fb->fb_dmamap->dm_segs[0].ds_len, fb->fb_buf);
+#endif
+ memset(fb->fb_buf, 0, fb->fb_dmamap->dm_segs[0].ds_len);
+ bus_dmamap_sync(sc->sc_dmat, fb->fb_dmamap, 0,
+ fb->fb_dmamap->dm_segs[0].ds_len, BUS_DMASYNC_PREREAD);
+
+ OHCI_CSR_WRITE(sc, OHCI_REG_SelfIDBuffer,
+ fb->fb_dmamap->dm_segs[0].ds_addr);
+}
+
+static int
+fwohci_selfid_input(struct fwohci_softc *sc)
+{
+ int i;
+ u_int32_t count, val, gen;
+ u_int32_t *buf;
+
+ buf = (u_int32_t *)sc->sc_buf_selfid.fb_buf;
+ val = OHCI_CSR_READ(sc, OHCI_REG_SelfIDCount);
+ again:
+ if (val & OHCI_SelfID_Error) {
+ printf("%s: SelfID Error\n", sc->sc_sc1394.sc1394_dev.dv_xname);
+ return -1;
+ }
+ count = OHCI_BITVAL(val, OHCI_SelfID_Size);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_buf_selfid.fb_dmamap,
+ 0, count << 2, BUS_DMASYNC_POSTREAD);
+ gen = OHCI_BITVAL(buf[0], OHCI_SelfID_Gen);
+
+#ifdef FW_DEBUG
+ DPRINTFN(1, ("%s: SelfID: 0x%08x", sc->sc_sc1394.sc1394_dev.dv_xname,
+ val));
+ for (i = 0; i < count; i++)
+ DPRINTFN(2, ("%s%08x", i&7?" ":"\n ", buf[i]));
+ DPRINTFN(1, ("\n"));
+#endif /* FW_DEBUG */
+
+ for (i = 1; i < count; i += 2) {
+ if (buf[i] != ~buf[i + 1])
+ break;
+ if (buf[i] & 0x00000001)
+ continue; /* more pkt */
+ if (buf[i] & 0x00800000)
+ continue; /* external id */
+ sc->sc_rootid = (buf[i] & 0x3f000000) >> 24;
+ if ((buf[i] & 0x00400800) == 0x00400800)
+ sc->sc_irmid = sc->sc_rootid;
+ }
+
+ val = OHCI_CSR_READ(sc, OHCI_REG_SelfIDCount);
+ if (OHCI_BITVAL(val, OHCI_SelfID_Gen) != gen) {
+ if (OHCI_BITVAL(val, OHCI_SelfID_Gen) !=
+ OHCI_BITVAL(buf[0], OHCI_SelfID_Gen))
+ goto again;
+ DPRINTF(("%s: SelfID Gen mismatch (%d, %d)\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, gen,
+ OHCI_BITVAL(val, OHCI_SelfID_Gen)));
+ return -1;
+ }
+ if (i != count) {
+ printf("%s: SelfID corrupted (%d, 0x%08x, 0x%08x)\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, i, buf[i], buf[i + 1]);
+#if 1
+ if (i == 1 && buf[i] == 0 && buf[i + 1] == 0) {
+ /*
+ * XXX: CXD3222 sometimes fails to DMA
+ * selfid packet??
+ */
+ sc->sc_rootid = (count - 1) / 2 - 1;
+ sc->sc_irmid = sc->sc_rootid;
+ } else
+#endif
+ return -1;
+ }
+
+ val = OHCI_CSR_READ(sc, OHCI_REG_NodeId);
+ if ((val & OHCI_NodeId_IDValid) == 0) {
+ sc->sc_nodeid = 0xffff; /* invalid */
+ printf("%s: nodeid is invalid\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname);
+ return -1;
+ }
+ sc->sc_nodeid = val & 0xffff;
+
+ DPRINTF(("%s: nodeid=0x%04x(%d), rootid=%d, irmid=%d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, sc->sc_nodeid,
+ sc->sc_nodeid & OHCI_NodeId_NodeNumber, sc->sc_rootid,
+ sc->sc_irmid));
+
+ if ((sc->sc_nodeid & OHCI_NodeId_NodeNumber) > sc->sc_rootid)
+ return -1;
+
+ if ((sc->sc_nodeid & OHCI_NodeId_NodeNumber) == sc->sc_rootid)
+ OHCI_CSR_WRITE(sc, OHCI_REG_LinkControlSet,
+ OHCI_LinkControl_CycleMaster);
+ else
+ OHCI_CSR_WRITE(sc, OHCI_REG_LinkControlClear,
+ OHCI_LinkControl_CycleMaster);
+ return 0;
+}
+
+/*
+ * some CSRs are handled by driver.
+ */
+static void
+fwohci_csr_init(struct fwohci_softc *sc)
+{
+ int i;
+ static u_int32_t csr[] = {
+ CSR_STATE_CLEAR, CSR_STATE_SET, CSR_SB_CYCLE_TIME,
+ CSR_SB_BUS_TIME, CSR_SB_BUSY_TIMEOUT, CSR_SB_BUS_MANAGER_ID,
+ CSR_SB_CHANNEL_AVAILABLE_HI, CSR_SB_CHANNEL_AVAILABLE_LO,
+ CSR_SB_BROADCAST_CHANNEL
+ };
+
+ for (i = 0; i < sizeof(csr) / sizeof(csr[0]); i++) {
+ fwohci_handler_set(sc, IEEE1394_TCODE_WRITE_REQ_QUAD,
+ CSR_BASE_HI, CSR_BASE_LO + csr[i], fwohci_csr_input, NULL);
+ fwohci_handler_set(sc, IEEE1394_TCODE_READ_REQ_QUAD,
+ CSR_BASE_HI, CSR_BASE_LO + csr[i], fwohci_csr_input, NULL);
+ }
+ sc->sc_csr[CSR_SB_BROADCAST_CHANNEL] = 31; /*XXX*/
+}
+
+static int
+fwohci_csr_input(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
+{
+ struct fwohci_pkt res;
+ u_int32_t reg;
+
+ /*
+ * XXX need to do special functionality other than just r/w...
+ */
+ reg = pkt->fp_hdr[2] - CSR_BASE_LO;
+
+ if ((reg & 0x03) != 0) {
+ /* alignment error */
+ return IEEE1394_RCODE_ADDRESS_ERROR;
+ }
+ DPRINTFN(1, ("fwohci_csr_input: CSR[0x%04x]: 0x%08x", reg,
+ *(u_int32_t *)(&sc->sc_csr[reg])));
+ if (pkt->fp_tcode == IEEE1394_TCODE_WRITE_REQ_QUAD) {
+ DPRINTFN(1, (" -> 0x%08x\n",
+ ntohl(*(u_int32_t *)pkt->fp_iov[0].iov_base)));
+ *(u_int32_t *)&sc->sc_csr[reg] =
+ ntohl(*(u_int32_t *)pkt->fp_iov[0].iov_base);
+ } else {
+ DPRINTFN(1, ("\n"));
+ res.fp_hdr[3] = htonl(*(u_int32_t *)&sc->sc_csr[reg]);
+ res.fp_iov[0].iov_base = &res.fp_hdr[3];
+ res.fp_iov[0].iov_len = 4;
+ res.fp_uio.uio_resid = 4;
+ res.fp_uio.uio_iovcnt = 1;
+ fwohci_atrs_output(sc, IEEE1394_RCODE_COMPLETE, pkt, &res);
+ return -1;
+ }
+ return IEEE1394_RCODE_COMPLETE;
+}
+
+/*
+ * Mapping between nodeid and unique ID (EUI-64).
+ *
+ * Track old mappings and simply update their devices with the new id's when
+ * they match an existing EUI. This allows proper renumeration of the bus.
+ */
+static void
+fwohci_uid_collect(struct fwohci_softc *sc)
+{
+ int i;
+ struct fwohci_uidtbl *fu;
+ struct ieee1394_softc *iea;
+
+ LIST_FOREACH(iea, &sc->sc_nodelist, sc1394_node)
+ iea->sc1394_node_id = 0xffff;
+
+ if (sc->sc_uidtbl != NULL)
+ free(sc->sc_uidtbl, M_DEVBUF);
+#ifdef M_ZERO
+ sc->sc_uidtbl = malloc(sizeof(*fu) * (sc->sc_rootid + 1), M_DEVBUF,
+ M_NOWAIT|M_ZERO); /* XXX M_WAITOK requires locks */
+#else
+ sc->sc_uidtbl = malloc(sizeof(*fu) * (sc->sc_rootid + 1), M_DEVBUF,
+ M_NOWAIT); /* XXX M_WAITOK requires locks */
+ bzero(sc->sc_uidtbl, sizeof(*fu) * (sc->sc_rootid + 1));
+#endif
+ if (sc->sc_uidtbl == NULL)
+ return;
+
+ for (i = 0, fu = sc->sc_uidtbl; i <= sc->sc_rootid; i++, fu++) {
+ if (i == (sc->sc_nodeid & OHCI_NodeId_NodeNumber)) {
+ memcpy(fu->fu_uid, sc->sc_sc1394.sc1394_guid, 8);
+ fu->fu_valid = 3;
+
+ iea = (struct ieee1394_softc *)sc->sc_sc1394.sc1394_if;
+ if (iea) {
+ iea->sc1394_node_id = i;
+ DPRINTF(("%s: Updating nodeid to %d\n",
+ iea->sc1394_dev.dv_xname,
+ iea->sc1394_node_id));
+ }
+ } else {
+ fu->fu_valid = 0;
+ fwohci_uid_req(sc, i);
+ }
+ }
+ if (sc->sc_rootid == 0)
+ fwohci_check_nodes(sc);
+}
+
+static void
+fwohci_uid_req(struct fwohci_softc *sc, int phyid)
+{
+ struct fwohci_pkt pkt;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.fp_tcode = IEEE1394_TCODE_READ_REQ_QUAD;
+ pkt.fp_hlen = 12;
+ pkt.fp_dlen = 0;
+ pkt.fp_hdr[0] = 0x00000100 | (sc->sc_tlabel << 10) |
+ (pkt.fp_tcode << 4);
+ pkt.fp_hdr[1] = ((0xffc0 | phyid) << 16) | CSR_BASE_HI;
+ pkt.fp_hdr[2] = CSR_BASE_LO + CSR_CONFIG_ROM + 12;
+ fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD, phyid,
+ sc->sc_tlabel, fwohci_uid_input, (void *)0);
+ sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
+ fwohci_at_output(sc, sc->sc_ctx_atrq, &pkt);
+
+ pkt.fp_hdr[0] = 0x00000100 | (sc->sc_tlabel << 10) |
+ (pkt.fp_tcode << 4);
+ pkt.fp_hdr[2] = CSR_BASE_LO + CSR_CONFIG_ROM + 16;
+ fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD, phyid,
+ sc->sc_tlabel, fwohci_uid_input, (void *)1);
+ sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
+ fwohci_at_output(sc, sc->sc_ctx_atrq, &pkt);
+}
+
+static int
+fwohci_uid_input(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *res)
+{
+ struct fwohci_uidtbl *fu;
+ struct ieee1394_softc *iea;
+ struct ieee1394_attach_args fwa;
+ int i, n, done, rcode, found;
+
+ found = 0;
+
+ n = (res->fp_hdr[1] >> 16) & OHCI_NodeId_NodeNumber;
+ rcode = (res->fp_hdr[1] & 0x0000f000) >> 12;
+ if (rcode != IEEE1394_RCODE_COMPLETE ||
+ sc->sc_uidtbl == NULL ||
+ n > sc->sc_rootid)
+ return 0;
+ fu = &sc->sc_uidtbl[n];
+ if (arg == 0) {
+ memcpy(fu->fu_uid, res->fp_iov[0].iov_base, 4);
+ fu->fu_valid |= 0x1;
+ } else {
+ memcpy(fu->fu_uid + 4, res->fp_iov[0].iov_base, 4);
+ fu->fu_valid |= 0x2;
+ }
+#ifdef FW_DEBUG
+ if (fu->fu_valid == 0x3)
+ DPRINTFN(1, ("fwohci_uid_input: "
+ "Node %d, UID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", n,
+ fu->fu_uid[0], fu->fu_uid[1], fu->fu_uid[2], fu->fu_uid[3],
+ fu->fu_uid[4], fu->fu_uid[5], fu->fu_uid[6], fu->fu_uid[7]));
+#endif
+ if (fu->fu_valid == 0x3) {
+ LIST_FOREACH(iea, &sc->sc_nodelist, sc1394_node)
+ if (memcmp(iea->sc1394_guid, fu->fu_uid, 8) == 0) {
+ found = 1;
+ iea->sc1394_node_id = n;
+ DPRINTF(("%s: Updating nodeid to %d\n",
+ iea->sc1394_dev.dv_xname,
+ iea->sc1394_node_id));
+ break;
+ }
+ if (!found) {
+ strcpy(fwa.name, "fwnode");
+ memcpy(fwa.uid, fu->fu_uid, 8);
+ fwa.nodeid = n;
+ fwa.read = fwohci_read;
+ fwa.write = fwohci_write;
+ fwa.inreg = fwohci_inreg;
+ fwa.unreg = fwohci_unreg;
+ iea = (struct ieee1394_softc *)
+ config_found_sm(&sc->sc_sc1394.sc1394_dev, &fwa,
+ fwohci_print, fwohci_submatch);
+ if (iea != NULL)
+ LIST_INSERT_HEAD(&sc->sc_nodelist, iea,
+ sc1394_node);
+ }
+ }
+ done = 1;
+
+ for (i = 0; i < sc->sc_rootid + 1; i++) {
+ fu = &sc->sc_uidtbl[i];
+ if (fu->fu_valid != 0x3) {
+ done = 0;
+ break;
+ }
+ }
+ if (done)
+ fwohci_check_nodes(sc);
+
+ return 0;
+}
+
+static void
+fwohci_check_nodes(struct fwohci_softc *sc)
+{
+ struct device *detach = NULL;
+ struct ieee1394_softc *iea;
+
+ LIST_FOREACH(iea, &sc->sc_nodelist, sc1394_node) {
+
+ /*
+ * Have to defer detachment until the next
+ * loop iteration since config_detach
+ * free's the softc and the loop iterator
+ * needs data from the softc to move
+ * forward.
+ */
+
+ if (detach) {
+ config_detach(detach, 0);
+ detach = NULL;
+ }
+ if (iea->sc1394_node_id == 0xffff) {
+ detach = (struct device *)iea;
+ LIST_REMOVE(iea, sc1394_node);
+ }
+ }
+ if (detach)
+ config_detach(detach, 0);
+}
+
+static int
+fwohci_uid_lookup(struct fwohci_softc *sc, const u_int8_t *uid)
+{
+ struct fwohci_uidtbl *fu;
+ int n;
+ static const u_int8_t bcast[] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ fu = sc->sc_uidtbl;
+ if (fu == NULL) {
+ if (memcmp(uid, bcast, sizeof(bcast)) == 0)
+ return IEEE1394_BCAST_PHY_ID;
+ fwohci_uid_collect(sc); /* try to get */
+ return -1;
+ }
+ for (n = 0; n <= sc->sc_rootid; n++, fu++) {
+ if (fu->fu_valid == 0x3 && memcmp(fu->fu_uid, uid, 8) == 0)
+ return n;
+ }
+ if (memcmp(uid, bcast, sizeof(bcast)) == 0)
+ return IEEE1394_BCAST_PHY_ID;
+ for (n = 0, fu = sc->sc_uidtbl; n <= sc->sc_rootid; n++, fu++) {
+ if (fu->fu_valid != 0x3) {
+ /*
+ * XXX: need timer before retransmission
+ */
+ fwohci_uid_req(sc, n);
+ }
+ }
+ return -1;
+}
+
+/*
+ * functions to support network interface
+ */
+static int
+fwohci_if_inreg(struct device *self, u_int32_t offhi, u_int32_t offlo,
+ void (*handler)(struct device *, struct mbuf *))
+{
+ struct fwohci_softc *sc = (struct fwohci_softc *)self;
+
+ fwohci_handler_set(sc, IEEE1394_TCODE_WRITE_REQ_BLOCK, offhi, offlo,
+ handler ? fwohci_if_input : NULL, handler);
+ fwohci_handler_set(sc, IEEE1394_TCODE_STREAM_DATA,
+ (sc->sc_csr[CSR_SB_BROADCAST_CHANNEL] & IEEE1394_ISOCH_MASK) |
+ OHCI_ASYNC_STREAM,
+ IEEE1394_TAG_GASP, handler ? fwohci_if_input : NULL, handler);
+ return 0;
+}
+
+static int
+fwohci_if_input(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
+{
+ int n, len;
+ struct mbuf *m;
+ struct iovec *iov;
+ void (*handler)(struct device *, struct mbuf *) = arg;
+
+#ifdef FW_DEBUG
+ int i;
+ DPRINTFN(1, ("fwohci_if_input: tcode=0x%x, dlen=%d", pkt->fp_tcode,
+ pkt->fp_dlen));
+ for (i = 0; i < pkt->fp_hlen/4; i++)
+ DPRINTFN(2, ("%s%08x", i?" ":"\n ", pkt->fp_hdr[i]));
+ DPRINTFN(2, ("$"));
+ for (n = 0, len = pkt->fp_dlen; len > 0; len -= i, n++){
+ iov = &pkt->fp_iov[n];
+ for (i = 0; i < iov->iov_len; i++)
+ DPRINTFN(2, ("%s%02x", (i%32)?((i%4)?"":" "):"\n ",
+ ((u_int8_t *)iov->iov_base)[i]));
+ DPRINTFN(2, ("$"));
+ }
+ DPRINTFN(1, ("\n"));
+#endif /* FW_DEBUG */
+ len = pkt->fp_dlen;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return IEEE1394_RCODE_COMPLETE;
+ m->m_len = 16;
+ if (len + m->m_len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ return IEEE1394_RCODE_COMPLETE;
+ }
+ }
+ n = (pkt->fp_hdr[1] >> 16) & OHCI_NodeId_NodeNumber;
+ if (sc->sc_uidtbl == NULL || n > sc->sc_rootid ||
+ sc->sc_uidtbl[n].fu_valid != 0x3) {
+ printf("%s: packet from unknown node: phy id %d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, n);
+ m_freem(m);
+ fwohci_uid_req(sc, n);
+ return IEEE1394_RCODE_COMPLETE;
+ }
+ memcpy(mtod(m, caddr_t), sc->sc_uidtbl[n].fu_uid, 8);
+ if (pkt->fp_tcode == IEEE1394_TCODE_STREAM_DATA) {
+ m->m_flags |= M_BCAST;
+ mtod(m, u_int32_t *)[2] = mtod(m, u_int32_t *)[3] = 0;
+ } else {
+ mtod(m, u_int32_t *)[2] = htonl(pkt->fp_hdr[1]);
+ mtod(m, u_int32_t *)[3] = htonl(pkt->fp_hdr[2]);
+ }
+ mtod(m, u_int8_t *)[8] = n; /*XXX: node id for debug */
+ mtod(m, u_int8_t *)[9] =
+ (*pkt->fp_trail >> (16 + OHCI_CTXCTL_SPD_BITPOS)) &
+ ((1 << OHCI_CTXCTL_SPD_BITLEN) - 1);
+
+ m->m_pkthdr.rcvif = NULL; /* set in child */
+ m->m_pkthdr.len = len + m->m_len;
+ /*
+ * We may use receive buffer by external mbuf instead of copy here.
+ * But asynchronous receive buffer must be operate in buffer fill
+ * mode, so that each receive buffer will shared by multiple mbufs.
+ * If upper layer doesn't free mbuf soon, e.g. application program
+ * is suspended, buffer must be reallocated.
+ * Isochronous buffer must be operate in packet buffer mode, and
+ * it is easy to map receive buffer to external mbuf. But it is
+ * used for broadcast/multicast only, and is expected not so
+ * performance sensitive for now.
+ * XXX: The performance may be important for multicast case,
+ * so we should revisit here later.
+ * -- onoe
+ */
+ n = 0;
+ iov = pkt->fp_uio.uio_iov;
+ while (len > 0) {
+ memcpy(mtod(m, caddr_t) + m->m_len, iov->iov_base,
+ iov->iov_len);
+ m->m_len += iov->iov_len;
+ len -= iov->iov_len;
+ iov++;
+ }
+ (*handler)(sc->sc_sc1394.sc1394_if, m);
+ return IEEE1394_RCODE_COMPLETE;
+}
+
+static int
+fwohci_if_input_iso(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
+{
+ int n, len;
+ int chan, tag;
+ struct mbuf *m;
+ struct iovec *iov;
+ void (*handler)(struct device *, struct mbuf *) = arg;
+#ifdef FW_DEBUG
+ int i;
+#endif
+
+ chan = (pkt->fp_hdr[0] & 0x00003f00) >> 8;
+ tag = (pkt->fp_hdr[0] & 0x0000c000) >> 14;
+#ifdef FW_DEBUG
+ DPRINTFN(1, ("fwohci_if_input_iso: "
+ "tcode=0x%x, chan=%d, tag=%x, dlen=%d",
+ pkt->fp_tcode, chan, tag, pkt->fp_dlen));
+ for (i = 0; i < pkt->fp_hlen/4; i++)
+ DPRINTFN(2, ("%s%08x", i?" ":"\n\t", pkt->fp_hdr[i]));
+ DPRINTFN(2, ("$"));
+ for (n = 0, len = pkt->fp_dlen; len > 0; len -= i, n++){
+ iov = &pkt->fp_iov[n];
+ for (i = 0; i < iov->iov_len; i++)
+ DPRINTFN(2, ("%s%02x",
+ (i%32)?((i%4)?"":" "):"\n\t",
+ ((u_int8_t *)iov->iov_base)[i]));
+ DPRINTFN(2, ("$"));
+ }
+ DPRINTFN(2, ("\n"));
+#endif /* FW_DEBUG */
+ len = pkt->fp_dlen;
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return IEEE1394_RCODE_COMPLETE;
+ m->m_len = 16;
+ if (m->m_len + len > MHLEN) {
+ MCLGET(m, M_DONTWAIT);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ return IEEE1394_RCODE_COMPLETE;
+ }
+ }
+
+ m->m_flags |= M_BCAST;
+
+ if (tag == IEEE1394_TAG_GASP) {
+ n = (pkt->fp_hdr[1] >> 16) & OHCI_NodeId_NodeNumber;
+ if (sc->sc_uidtbl == NULL || n > sc->sc_rootid ||
+ sc->sc_uidtbl[n].fu_valid != 0x3) {
+ printf("%s: packet from unknown node: phy id %d\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname, n);
+ m_freem(m);
+ return IEEE1394_RCODE_COMPLETE;
+ }
+ memcpy(mtod(m, caddr_t), sc->sc_uidtbl[n].fu_uid, 8);
+ mtod(m, u_int32_t *)[2] = htonl(pkt->fp_hdr[1]);
+ mtod(m, u_int32_t *)[3] = htonl(pkt->fp_hdr[2]);
+ mtod(m, u_int8_t *)[8] = n; /*XXX: node id for debug */
+ mtod(m, u_int8_t *)[9] =
+ (*pkt->fp_trail >> (16 + OHCI_CTXCTL_SPD_BITPOS)) &
+ ((1 << OHCI_CTXCTL_SPD_BITLEN) - 1);
+ }
+ mtod(m, u_int8_t *)[14] = chan;
+ mtod(m, u_int8_t *)[15] = tag;
+
+
+ m->m_pkthdr.rcvif = NULL; /* set in child */
+ m->m_pkthdr.len = len + m->m_len;
+ /*
+ * We may use receive buffer by external mbuf instead of copy here.
+ * But asynchronous receive buffer must be operate in buffer fill
+ * mode, so that each receive buffer will shared by multiple mbufs.
+ * If upper layer doesn't free mbuf soon, e.g. application program
+ * is suspended, buffer must be reallocated.
+ * Isochronous buffer must be operate in packet buffer mode, and
+ * it is easy to map receive buffer to external mbuf. But it is
+ * used for broadcast/multicast only, and is expected not so
+ * performance sensitive for now.
+ * XXX: The performance may be important for multicast case,
+ * so we should revisit here later.
+ * -- onoe
+ */
+ n = 0;
+ iov = pkt->fp_uio.uio_iov;
+ while (len > 0) {
+ memcpy(mtod(m, caddr_t) + m->m_len, iov->iov_base,
+ iov->iov_len);
+ m->m_len += iov->iov_len;
+ len -= iov->iov_len;
+ iov++;
+ }
+ (*handler)(sc->sc_sc1394.sc1394_if, m);
+ return IEEE1394_RCODE_COMPLETE;
+}
+
+
+
+static int
+fwohci_if_output(struct device *self, struct mbuf *m0,
+ void (*callback)(struct device *, struct mbuf *))
+{
+ struct fwohci_softc *sc = (struct fwohci_softc *)self;
+ struct fwohci_pkt pkt;
+ u_int8_t *p;
+ int n, error, spd, hdrlen, maxrec;
+#ifdef FW_DEBUG
+ struct mbuf *m;
+#endif
+
+ p = mtod(m0, u_int8_t *);
+ if (m0->m_flags & (M_BCAST | M_MCAST)) {
+ spd = IEEE1394_SPD_S100; /*XXX*/
+ maxrec = 512; /*XXX*/
+ hdrlen = 8;
+ } else {
+ n = fwohci_uid_lookup(sc, p);
+ if (n < 0) {
+ printf("%s: nodeid unknown:"
+ " %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname,
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ error = EHOSTUNREACH;
+ goto end;
+ }
+ if (n == IEEE1394_BCAST_PHY_ID) {
+ printf("%s: broadcast with !M_MCAST\n",
+ sc->sc_sc1394.sc1394_dev.dv_xname);
+#ifdef FW_DEBUG
+ DPRINTFN(2, ("packet:"));
+ for (m = m0; m != NULL; m = m->m_next) {
+ for (n = 0; n < m->m_len; n++)
+ DPRINTFN(2, ("%s%02x", (n%32)?
+ ((n%4)?"":" "):"\n ",
+ mtod(m, u_int8_t *)[n]));
+ DPRINTFN(2, ("$"));
+ }
+ DPRINTFN(2, ("\n"));
+#endif
+ error = EHOSTUNREACH;
+ goto end;
+ }
+ maxrec = 2 << p[8];
+ spd = p[9];
+ hdrlen = 0;
+ }
+ if (spd > sc->sc_sc1394.sc1394_link_speed) {
+ DPRINTF(("fwohci_if_output: spd (%d) is faster than %d\n",
+ spd, sc->sc_sc1394.sc1394_link_speed));
+ spd = sc->sc_sc1394.sc1394_link_speed;
+ }
+ if (maxrec > (512 << spd)) {
+ DPRINTF(("fwohci_if_output: maxrec (%d) is larger for spd (%d)"
+ "\n", maxrec, spd));
+ maxrec = 512 << spd;
+ }
+ while (maxrec > sc->sc_sc1394.sc1394_max_receive) {
+ DPRINTF(("fwohci_if_output: maxrec (%d) is larger than"
+ " %d\n", maxrec, sc->sc_sc1394.sc1394_max_receive));
+ maxrec >>= 1;
+ }
+ if (maxrec < 512) {
+ DPRINTF(("fwohci_if_output: maxrec (%d) is smaller than "
+ "minimum\n", maxrec));
+ maxrec = 512;
+ }
+
+ m_adj(m0, 16 - hdrlen);
+ if (m0->m_pkthdr.len > maxrec) {
+ DPRINTF(("fwohci_if_output: packet too big: hdr %d, pktlen "
+ "%d, maxrec %d\n", hdrlen, m0->m_pkthdr.len, maxrec));
+ error = E2BIG; /*XXX*/
+ goto end;
+ }
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.fp_uio.uio_iov = pkt.fp_iov;
+ pkt.fp_uio.uio_segflg = UIO_SYSSPACE;
+ pkt.fp_uio.uio_rw = UIO_WRITE;
+ if (m0->m_flags & (M_BCAST | M_MCAST)) {
+ /* construct GASP header */
+ p = mtod(m0, u_int8_t *);
+ p[0] = sc->sc_nodeid >> 8;
+ p[1] = sc->sc_nodeid & 0xff;
+ p[2] = 0x00; p[3] = 0x00; p[4] = 0x5e;
+ p[5] = 0x00; p[6] = 0x00; p[7] = 0x01;
+ pkt.fp_tcode = IEEE1394_TCODE_STREAM_DATA;
+ pkt.fp_hlen = 8;
+ pkt.fp_hdr[0] = (spd << 16) | (IEEE1394_TAG_GASP << 14) |
+ ((sc->sc_csr[CSR_SB_BROADCAST_CHANNEL] &
+ OHCI_NodeId_NodeNumber) << 8);
+ pkt.fp_hdr[1] = m0->m_pkthdr.len << 16;
+ } else {
+ pkt.fp_tcode = IEEE1394_TCODE_WRITE_REQ_BLOCK;
+ pkt.fp_hlen = 16;
+ pkt.fp_hdr[0] = 0x00800100 | (sc->sc_tlabel << 10) |
+ (spd << 16);
+ pkt.fp_hdr[1] =
+ (((sc->sc_nodeid & OHCI_NodeId_BusNumber) | n) << 16) |
+ (p[10] << 8) | p[11];
+ pkt.fp_hdr[2] = (p[12]<<24) | (p[13]<<16) | (p[14]<<8) | p[15];
+ pkt.fp_hdr[3] = m0->m_pkthdr.len << 16;
+ sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
+ }
+ pkt.fp_hdr[0] |= (pkt.fp_tcode << 4);
+ pkt.fp_dlen = m0->m_pkthdr.len;
+ pkt.fp_m = m0;
+ pkt.fp_callback = callback;
+ error = fwohci_at_output(sc, sc->sc_ctx_atrq, &pkt);
+ m0 = pkt.fp_m;
+ end:
+ if (m0 != NULL) {
+ if (callback)
+ (*callback)(sc->sc_sc1394.sc1394_if, m0);
+ else
+ m_freem(m0);
+ }
+ return error;
+}
+
+/*
+ * High level routines to provide abstraction to attaching layers to
+ * send/receive data.
+ */
+
+/*
+ * These break down into 4 routines as follows:
+ *
+ * int fwohci_read(struct ieee1394_abuf *)
+ *
+ * This routine will attempt to read a region from the requested node.
+ * A callback must be provided which will be called when either the completed
+ * read is done or an unrecoverable error occurs. This is mainly a convenience
+ * routine since it will encapsulate retrying a region as quadlet vs. block
+ * reads and recombining all the returned data. This could also be done with a
+ * series of write/inreg's for each packet sent.
+ *
+ * int fwohci_write(struct ieee1394_abuf *)
+ *
+ * The work horse main entry point for putting packets on the bus. This is the
+ * generalized interface for fwnode/etc code to put packets out onto the bus.
+ * It accepts all standard ieee1394 tcodes (XXX: only a few today) and
+ * optionally will callback via a func pointer to the calling code with the
+ * resulting ACK code from the packet. If the ACK code is to be ignored (i.e.
+ * no cb) then the write routine will take care of free'ing the abuf since the
+ * fwnode/etc code won't have any knowledge of when to do this. This allows for
+ * simple one-off packets to be sent from the upper-level code without worrying
+ * about a callback for cleanup.
+ *
+ * int fwohci_inreg(struct ieee1394_abuf *, int)
+ *
+ * This is very simple. It evals the abuf passed in and registers an internal
+ * handler as the callback for packets received for that operation.
+ * The integer argument specifies whether on a block read/write operation to
+ * allow sub-regions to be read/written (in block form) as well.
+ *
+ * XXX: This whole structure needs to be redone as a list of regions and
+ * operations allowed on those regions.
+ *
+ * int fwohci_unreg(struct ieee1394_abuf *, int)
+ *
+ * This simply unregisters the respective callback done via inreg for items
+ * which only need to register an area for a one-time operation (like a status
+ * buffer a remote node will write to when the current operation is done). The
+ * int argument specifies the same behavior as inreg, except in reverse (i.e.
+ * it unregisters).
+ */
+
+static int
+fwohci_read(struct ieee1394_abuf *ab)
+{
+ struct fwohci_pkt pkt;
+ struct ieee1394_softc *sc = ab->ab_req;
+ struct fwohci_softc *psc =
+ (struct fwohci_softc *)sc->sc1394_dev.dv_parent;
+ struct fwohci_cb *fcb;
+ u_int32_t high, lo;
+ int rv, tcode;
+
+ /* Have to have a callback when reading. */
+ if (ab->ab_cb == NULL)
+ return -1;
+
+ fcb = malloc(sizeof(struct fwohci_cb), M_DEVBUF, M_WAITOK);
+ fcb->ab = ab;
+ fcb->count = 0;
+ fcb->abuf_valid = 1;
+
+ high = ((ab->ab_addr & 0x0000ffff00000000) >> 32);
+ lo = (ab->ab_addr & 0x00000000ffffffff);
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.fp_hdr[1] = ((0xffc0 | ab->ab_req->sc1394_node_id) << 16) | high;
+ pkt.fp_hdr[2] = lo;
+ pkt.fp_dlen = 0;
+
+ if (ab->ab_length == 4) {
+ pkt.fp_tcode = IEEE1394_TCODE_READ_REQ_QUAD;
+ tcode = IEEE1394_TCODE_READ_RESP_QUAD;
+ pkt.fp_hlen = 12;
+ } else {
+ pkt.fp_tcode = IEEE1394_TCODE_READ_REQ_BLOCK;
+ pkt.fp_hlen = 16;
+ tcode = IEEE1394_TCODE_READ_RESP_BLOCK;
+ pkt.fp_hdr[3] = (ab->ab_length << 16);
+ }
+ pkt.fp_hdr[0] = 0x00000100 | (sc->sc1394_link_speed << 16) |
+ (psc->sc_tlabel << 10) | (pkt.fp_tcode << 4);
+
+ pkt.fp_statusarg = fcb;
+ pkt.fp_statuscb = fwohci_read_resp;
+
+ rv = fwohci_handler_set(psc, tcode, ab->ab_req->sc1394_node_id,
+ psc->sc_tlabel, fwohci_read_resp, fcb);
+ if (rv)
+ return rv;
+ rv = fwohci_at_output(psc, psc->sc_ctx_atrq, &pkt);
+ if (rv)
+ fwohci_handler_set(psc, tcode, ab->ab_req->sc1394_node_id,
+ psc->sc_tlabel, NULL, NULL);
+ psc->sc_tlabel = (psc->sc_tlabel + 1) & 0x3f;
+ fcb->count = 1;
+ return rv;
+}
+
+static int
+fwohci_write(struct ieee1394_abuf *ab)
+{
+ struct fwohci_pkt pkt;
+ struct ieee1394_softc *sc = ab->ab_req;
+ struct fwohci_softc *psc =
+ (struct fwohci_softc *)sc->sc1394_dev.dv_parent;
+ u_int32_t high, lo;
+ int rv;
+
+ if (ab->ab_length > IEEE1394_MAX_REC(sc->sc1394_max_receive)) {
+ DPRINTF(("Packet too large: %d\n", ab->ab_length));
+ return E2BIG;
+ }
+
+ if (ab->ab_data && ab->ab_uio)
+ panic("Can't call with uio and data set\n");
+ if ((ab->ab_data == NULL) && (ab->ab_uio == NULL))
+ panic("One of either ab_data or ab_uio must be set\n");
+
+ memset(&pkt, 0, sizeof(pkt));
+
+ pkt.fp_tcode = ab->ab_tcode;
+ if (ab->ab_data) {
+ pkt.fp_uio.uio_iov = pkt.fp_iov;
+ pkt.fp_uio.uio_segflg = UIO_SYSSPACE;
+ pkt.fp_uio.uio_rw = UIO_WRITE;
+ } else
+ memcpy(&pkt.fp_uio, ab->ab_uio, sizeof(struct uio));
+
+ pkt.fp_statusarg = ab;
+ pkt.fp_statuscb = fwohci_write_ack;
+
+ switch (ab->ab_tcode) {
+ case IEEE1394_TCODE_WRITE_RESP:
+ pkt.fp_hlen = 12;
+ case IEEE1394_TCODE_READ_RESP_QUAD:
+ case IEEE1394_TCODE_READ_RESP_BLOCK:
+ if (!pkt.fp_hlen)
+ pkt.fp_hlen = 16;
+ high = ab->ab_retlen;
+ ab->ab_retlen = 0;
+ lo = 0;
+ pkt.fp_hdr[0] = 0x00000100 | (sc->sc1394_link_speed << 16) |
+ (ab->ab_tlabel << 10) | (pkt.fp_tcode << 4);
+ break;
+ default:
+ pkt.fp_hlen = 16;
+ high = ((ab->ab_addr & 0x0000ffff00000000) >> 32);
+ lo = (ab->ab_addr & 0x00000000ffffffff);
+ pkt.fp_hdr[0] = 0x00000100 | (sc->sc1394_link_speed << 16) |
+ (psc->sc_tlabel << 10) | (pkt.fp_tcode << 4);
+ break;
+ }
+
+ pkt.fp_hdr[1] = ((0xffc0 | ab->ab_req->sc1394_node_id) << 16) | high;
+ pkt.fp_hdr[2] = lo;
+ if (pkt.fp_hlen == 16) {
+ if (ab->ab_length == 4) {
+ pkt.fp_hdr[3] = ab->ab_data[0];
+ pkt.fp_dlen = 0;
+ } else {
+ pkt.fp_hdr[3] = (ab->ab_length << 16);
+ pkt.fp_dlen = ab->ab_length;
+ if (ab->ab_data) {
+ pkt.fp_uio.uio_iovcnt = 1;
+ pkt.fp_uio.uio_resid = ab->ab_length;
+ pkt.fp_iov[0].iov_base = ab->ab_data;
+ pkt.fp_iov[0].iov_len = ab->ab_length;
+ }
+ }
+ }
+ switch (ab->ab_tcode) {
+ case IEEE1394_TCODE_WRITE_RESP:
+ case IEEE1394_TCODE_READ_RESP_QUAD:
+ case IEEE1394_TCODE_READ_RESP_BLOCK:
+ rv = fwohci_at_output(psc, psc->sc_ctx_atrs, &pkt);
+ break;
+ default:
+ rv = fwohci_at_output(psc, psc->sc_ctx_atrq, &pkt);
+ break;
+ }
+ return rv;
+}
+
+static int
+fwohci_read_resp(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
+{
+ struct fwohci_cb *fcb = arg;
+ struct ieee1394_abuf *ab = fcb->ab;
+ struct fwohci_pkt newpkt;
+ u_int32_t *cur, high, lo;
+ int i, tcode, rcode, status, rv;
+
+ /*
+ * Both the ACK handling and normal response callbacks are handled here.
+ * The main reason for this is the various error conditions that can
+ * occur trying to block read some areas and the ways that gets reported
+ * back to calling station. This is a variety of ACK codes, responses,
+ * etc which makes it much more difficult to process if both aren't
+ * handled here.
+ */
+
+ /* Check for status packet. */
+
+ if (pkt->fp_tcode == -1) {
+ status = pkt->fp_status & OHCI_DESC_STATUS_ACK_MASK;
+ rcode = -1;
+ tcode = (pkt->fp_hdr[0] >> 4) & 0xf;
+ if ((status != OHCI_CTXCTL_EVENT_ACK_COMPLETE) &&
+ (status != OHCI_CTXCTL_EVENT_ACK_PENDING))
+ DPRINTFN(2, ("Got status packet: 0x%02x\n",
+ (unsigned int)status));
+ fcb->count--;
+
+ /*
+ * Got all the ack's back and the buffer is invalid (i.e. the
+ * callback has been called. Clean up.
+ */
+
+ if (fcb->abuf_valid == 0) {
+ if (fcb->count == 0)
+ free(fcb, M_DEVBUF);
+ return IEEE1394_RCODE_COMPLETE;
+ }
+ } else {
+ status = -1;
+ tcode = pkt->fp_tcode;
+ rcode = (pkt->fp_hdr[1] & 0x0000f000) >> 12;
+ }
+
+ /*
+ * Some area's (like the config rom want to be read as quadlets only.
+ *
+ * The current ideas to try are:
+ *
+ * Got an ACK_TYPE_ERROR on a block read.
+ *
+ * Got either RCODE_TYPE or RCODE_ADDRESS errors in a block read
+ * response.
+ *
+ * In all cases construct a new packet for a quadlet read and let
+ * mutli_resp handle the iteration over the space.
+ */
+
+ if (((status == OHCI_CTXCTL_EVENT_ACK_TYPE_ERROR) &&
+ (tcode == IEEE1394_TCODE_READ_REQ_BLOCK)) ||
+ (((rcode == IEEE1394_RCODE_TYPE_ERROR) ||
+ (rcode == IEEE1394_RCODE_ADDRESS_ERROR)) &&
+ (tcode == IEEE1394_TCODE_READ_RESP_BLOCK))) {
+
+ /* Read the area in quadlet chunks (internally track this). */
+
+ memset(&newpkt, 0, sizeof(newpkt));
+
+ high = ((ab->ab_addr & 0x0000ffff00000000) >> 32);
+ lo = (ab->ab_addr & 0x00000000ffffffff);
+
+ newpkt.fp_tcode = IEEE1394_TCODE_READ_REQ_QUAD;
+ newpkt.fp_hlen = 12;
+ newpkt.fp_dlen = 0;
+ newpkt.fp_hdr[1] =
+ ((0xffc0 | ab->ab_req->sc1394_node_id) << 16) | high;
+ newpkt.fp_hdr[2] = lo;
+ newpkt.fp_hdr[0] = 0x00000100 | (sc->sc_tlabel << 10) |
+ (newpkt.fp_tcode << 4);
+
+ rv = fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
+ ab->ab_req->sc1394_node_id, sc->sc_tlabel,
+ fwohci_read_multi_resp, fcb);
+ if (rv) {
+ (*ab->ab_cb)(ab, -1);
+ goto cleanup;
+ }
+ newpkt.fp_statusarg = fcb;
+ newpkt.fp_statuscb = fwohci_read_resp;
+ rv = fwohci_at_output(sc, sc->sc_ctx_atrq, &newpkt);
+ if (rv) {
+ fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
+ ab->ab_req->sc1394_node_id, sc->sc_tlabel, NULL,
+ NULL);
+ (*ab->ab_cb)(ab, -1);
+ goto cleanup;
+ }
+ fcb->count++;
+ sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
+ return IEEE1394_RCODE_COMPLETE;
+ } else if ((rcode != -1) || ((status != -1) &&
+ (status != OHCI_CTXCTL_EVENT_ACK_COMPLETE) &&
+ (status != OHCI_CTXCTL_EVENT_ACK_PENDING))) {
+
+ /*
+ * Recombine all the iov data into 1 chunk for higher
+ * level code.
+ */
+
+ if (rcode != -1) {
+ cur = ab->ab_data;
+ for (i = 0; i < pkt->fp_uio.uio_iovcnt; i++) {
+ /*
+ * Make sure and don't exceed the buffer
+ * allocated for return.
+ */
+ if ((ab->ab_retlen + pkt->fp_iov[i].iov_len) >
+ ab->ab_length) {
+ memcpy(cur, pkt->fp_iov[i].iov_base,
+ (ab->ab_length - ab->ab_retlen));
+ ab->ab_retlen = ab->ab_length;
+ break;
+ }
+ memcpy(cur, pkt->fp_iov[i].iov_base,
+ pkt->fp_iov[i].iov_len);
+ cur += pkt->fp_iov[i].iov_len;
+ ab->ab_retlen += pkt->fp_iov[i].iov_len;
+ }
+ }
+ if (status != -1)
+ /* XXX: Need a complete tlabel interface. */
+ for (i = 0; i < 64; i++)
+ fwohci_handler_set(sc,
+ IEEE1394_TCODE_READ_RESP_QUAD,
+ ab->ab_req->sc1394_node_id, i, NULL, NULL);
+ (*ab->ab_cb)(ab, rcode);
+ goto cleanup;
+ } else
+ /* Good ack packet. */
+ return IEEE1394_RCODE_COMPLETE;
+
+ /* Can't get here unless ab->ab_cb has been called. */
+
+ cleanup:
+ fcb->abuf_valid = 0;
+ if (fcb->count == 0)
+ free(fcb, M_DEVBUF);
+ return IEEE1394_RCODE_COMPLETE;
+}
+
+static int
+fwohci_read_multi_resp(struct fwohci_softc *sc, void *arg,
+ struct fwohci_pkt *pkt)
+{
+ struct fwohci_cb *fcb = arg;
+ struct ieee1394_abuf *ab = fcb->ab;
+ struct fwohci_pkt newpkt;
+ u_int32_t high, lo;
+ int rcode, rv;
+
+ /*
+ * Bad return codes from the wire, just return what's already in the
+ * buf.
+ */
+
+ /* Make sure a response packet didn't arrive after a bad ACK. */
+ if (fcb->abuf_valid == 0)
+ return IEEE1394_RCODE_COMPLETE;
+
+ rcode = (pkt->fp_hdr[1] & 0x0000f000) >> 12;
+
+ if (rcode) {
+ (*ab->ab_cb)(ab, rcode);
+ goto cleanup;
+ }
+
+ if ((ab->ab_retlen + pkt->fp_iov[0].iov_len) > ab->ab_length) {
+ memcpy(((char *)ab->ab_data + ab->ab_retlen),
+ pkt->fp_iov[0].iov_base, (ab->ab_length - ab->ab_retlen));
+ ab->ab_retlen = ab->ab_length;
+ } else {
+ memcpy(((char *)ab->ab_data + ab->ab_retlen),
+ pkt->fp_iov[0].iov_base, 4);
+ ab->ab_retlen += 4;
+ }
+ /* Still more, loop and read 4 more bytes. */
+ if (ab->ab_retlen < ab->ab_length) {
+ memset(&newpkt, 0, sizeof(newpkt));
+
+ high = ((ab->ab_addr & 0x0000ffff00000000) >> 32);
+ lo = (ab->ab_addr & 0x00000000ffffffff) + ab->ab_retlen;
+
+ newpkt.fp_tcode = IEEE1394_TCODE_READ_REQ_QUAD;
+ newpkt.fp_hlen = 12;
+ newpkt.fp_dlen = 0;
+ newpkt.fp_hdr[1] =
+ ((0xffc0 | ab->ab_req->sc1394_node_id) << 16) | high;
+ newpkt.fp_hdr[2] = lo;
+ newpkt.fp_hdr[0] = 0x00000100 | (sc->sc_tlabel << 10) |
+ (newpkt.fp_tcode << 4);
+
+ newpkt.fp_statusarg = fcb;
+ newpkt.fp_statuscb = fwohci_read_resp;
+
+ /*
+ * Bad return code. Just give up and return what's
+ * come in now.
+ */
+ rv = fwohci_handler_set(sc, IEEE1394_TCODE_READ_RESP_QUAD,
+ ab->ab_req->sc1394_node_id, sc->sc_tlabel,
+ fwohci_read_multi_resp, fcb);
+ if (rv)
+ (*ab->ab_cb)(ab, -1);
+ else {
+ rv = fwohci_at_output(sc, sc->sc_ctx_atrq, &newpkt);
+ if (rv) {
+ fwohci_handler_set(sc,
+ IEEE1394_TCODE_READ_RESP_QUAD,
+ ab->ab_req->sc1394_node_id, sc->sc_tlabel,
+ NULL, NULL);
+ (*ab->ab_cb)(ab, -1);
+ } else {
+ sc->sc_tlabel = (sc->sc_tlabel + 1) & 0x3f;
+ fcb->count++;
+ return IEEE1394_RCODE_COMPLETE;
+ }
+ }
+ } else
+ (*ab->ab_cb)(ab, IEEE1394_RCODE_COMPLETE);
+
+ cleanup:
+ /* Can't get here unless ab_cb has been called. */
+ fcb->abuf_valid = 0;
+ if (fcb->count == 0)
+ free(fcb, M_DEVBUF);
+ return IEEE1394_RCODE_COMPLETE;
+}
+
+static int
+fwohci_write_ack(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
+{
+ struct ieee1394_abuf *ab = arg;
+ u_int16_t status;
+
+
+ status = pkt->fp_status & OHCI_DESC_STATUS_ACK_MASK;
+ if ((status != OHCI_CTXCTL_EVENT_ACK_COMPLETE) &&
+ (status != OHCI_CTXCTL_EVENT_ACK_PENDING))
+ DPRINTF(("Got status packet: 0x%02x\n",
+ (unsigned int)status));
+
+ /* No callback means this level should free the buffers. */
+ if (ab->ab_cb)
+ (*ab->ab_cb)(ab, status);
+ else {
+ if (ab->ab_data)
+ free(ab->ab_data, M_1394DATA);
+ free(ab, M_1394DATA);
+ }
+ return IEEE1394_RCODE_COMPLETE;
+}
+
+static int
+fwohci_inreg(struct ieee1394_abuf *ab, int allow)
+{
+ struct ieee1394_softc *sc = ab->ab_req;
+ struct fwohci_softc *psc =
+ (struct fwohci_softc *)sc->sc1394_dev.dv_parent;
+ u_int32_t high, lo;
+ int i, j, rv;
+
+ high = ((ab->ab_addr & 0x0000ffff00000000) >> 32);
+ lo = (ab->ab_addr & 0x00000000ffffffff);
+
+ rv = 0;
+ switch (ab->ab_tcode) {
+ case IEEE1394_TCODE_READ_REQ_QUAD:
+ case IEEE1394_TCODE_WRITE_REQ_QUAD:
+ if (ab->ab_cb)
+ rv = fwohci_handler_set(psc, ab->ab_tcode, high, lo,
+ fwohci_parse_input, ab);
+ else
+ fwohci_handler_set(psc, ab->ab_tcode, high, lo, NULL,
+ NULL);
+ break;
+ case IEEE1394_TCODE_READ_REQ_BLOCK:
+ case IEEE1394_TCODE_WRITE_REQ_BLOCK:
+ if (allow) {
+ for (i = 0; i < (ab->ab_length / 4); i++) {
+ if (ab->ab_cb) {
+ rv = fwohci_handler_set(psc,
+ ab->ab_tcode, high, lo + (i * 4),
+ fwohci_parse_input, ab);
+ if (rv)
+ break;
+ } else
+ fwohci_handler_set(psc, ab->ab_tcode,
+ high, lo + (i * 4), NULL, NULL);
+ }
+ if (i != (ab->ab_length / 4)) {
+ j = i + 1;
+ for (i = 0; i < j; i++)
+ fwohci_handler_set(psc, ab->ab_tcode,
+ high, lo + (i * 4), NULL, NULL);
+ }
+ /*
+ * XXX: Need something to indicate writing a smaller
+ * amount is ok.
+ */
+ if (ab->ab_cb)
+ ab->ab_data = (void *)1;
+ } else {
+ if (ab->ab_cb)
+ rv = fwohci_handler_set(psc, ab->ab_tcode, high,
+ lo, fwohci_parse_input, ab);
+ else
+ fwohci_handler_set(psc, ab->ab_tcode, high, lo,
+ NULL, NULL);
+ }
+ break;
+ default:
+ DPRINTF(("Invalid registration tcode: %d\n", ab->ab_tcode));
+ return -1;
+ break;
+ }
+ return rv;
+}
+
+static int
+fwohci_unreg(struct ieee1394_abuf *ab, int allow)
+{
+ void *save;
+ int rv;
+
+ save = ab->ab_cb;
+ ab->ab_cb = NULL;
+ rv = fwohci_inreg(ab, allow);
+ ab->ab_cb = save;
+ return rv;
+}
+
+static int
+fwohci_parse_input(struct fwohci_softc *sc, void *arg, struct fwohci_pkt *pkt)
+{
+ struct ieee1394_abuf *ab = (struct ieee1394_abuf *)arg;
+ u_int64_t addr;
+ u_int32_t *cur;
+ int i, count;
+
+ ab->ab_tcode = (pkt->fp_hdr[0] >> 4) & 0xf;
+ ab->ab_tlabel = (pkt->fp_hdr[0] >> 10) & 0x3f;
+ addr = (((u_int64_t)(pkt->fp_hdr[1] & 0xffff) << 32) | pkt->fp_hdr[2]);
+
+ switch (ab->ab_tcode) {
+ case IEEE1394_TCODE_READ_REQ_QUAD:
+ ab->ab_retlen = 4;
+ break;
+ case IEEE1394_TCODE_READ_REQ_BLOCK:
+ ab->ab_retlen = (pkt->fp_hdr[3] >> 16) & 0xffff;
+ if (ab->ab_data) {
+ if ((addr + ab->ab_retlen) >
+ (ab->ab_addr + ab->ab_length))
+ return IEEE1394_RCODE_ADDRESS_ERROR;
+ ab->ab_data = NULL;
+ } else
+ if (ab->ab_retlen != ab->ab_length)
+ return IEEE1394_RCODE_ADDRESS_ERROR;
+ break;
+ case IEEE1394_TCODE_WRITE_REQ_QUAD:
+ ab->ab_retlen = 4;
+ case IEEE1394_TCODE_WRITE_REQ_BLOCK:
+ if (!ab->ab_retlen)
+ ab->ab_retlen = (pkt->fp_hdr[3] >> 16) & 0xffff;
+ if (ab->ab_data) {
+ if ((addr + ab->ab_retlen) >
+ (ab->ab_addr + ab->ab_length))
+ return IEEE1394_RCODE_ADDRESS_ERROR;
+ ab->ab_data = NULL;
+ } else
+ if (ab->ab_retlen != ab->ab_length)
+ return IEEE1394_RCODE_ADDRESS_ERROR;
+
+ ab->ab_data = malloc(ab->ab_retlen, M_1394DATA, M_WAITOK);
+ if (ab->ab_tcode == IEEE1394_TCODE_WRITE_REQ_QUAD)
+ ab->ab_data[0] = pkt->fp_hdr[3];
+ else {
+ count = 0;
+ cur = ab->ab_data;
+ for (i = 0; i < pkt->fp_uio.uio_iovcnt; i++) {
+ memcpy(cur, pkt->fp_iov[i].iov_base,
+ pkt->fp_iov[i].iov_len);
+ cur += pkt->fp_iov[i].iov_len;
+ count += pkt->fp_iov[i].iov_len;
+ }
+ if (ab->ab_retlen != count)
+ panic("Packet claims %d length "
+ "but only %d bytes returned\n",
+ ab->ab_retlen, count);
+ }
+ break;
+ default:
+ panic("Got a callback for a tcode that wasn't requested: %d\n",
+ ab->ab_tcode);
+ break;
+ }
+ ab->ab_addr = addr;
+ ab->ab_cb(ab, IEEE1394_RCODE_COMPLETE);
+ return -1;
+}
+
+#ifdef __NetBSD__
+static int
+fwohci_submatch(struct device *parent, struct cfdata *cf, void *aux)
+#else
+static int
+fwohci_submatch(struct device *parent, void *vcf, void *aux)
+#endif
+{
+ struct ieee1394_attach_args *fwa = aux;
+#ifdef __OpenBSD__
+ struct cfdata *cf = (struct cfdata *)vcf;
+#endif
+
+ /* Both halves must be filled in for a match. */
+ if ((cf->fwbuscf_idhi == FWBUS_UNK_IDHI &&
+ cf->fwbuscf_idlo == FWBUS_UNK_IDLO) ||
+ (cf->fwbuscf_idhi == ntohl(*((u_int32_t *)&fwa->uid[0])) &&
+ cf->fwbuscf_idlo == ntohl(*((u_int32_t *)&fwa->uid[4]))))
+ return ((*cf->cf_attach->ca_match)(parent, cf, aux));
+ return 0;
+}
+
+int
+fwohci_detach(struct fwohci_softc *sc, int flags)
+{
+ int rv = 0;
+
+ if (sc->sc_sc1394.sc1394_if != NULL)
+ rv = config_detach(sc->sc_sc1394.sc1394_if, flags);
+ if (rv != 0)
+ return (rv);
+
+#ifdef __NetBSD__
+ callout_stop(&sc->sc_selfid_callout);
+#else
+ timeout_del(&sc->sc_selfid_callout);
+#endif
+
+ if (sc->sc_powerhook != NULL)
+ powerhook_disestablish(sc->sc_powerhook);
+ if (sc->sc_shutdownhook != NULL)
+ shutdownhook_disestablish(sc->sc_shutdownhook);
+
+ return (rv);
+}
+
+int
+fwohci_activate(struct device *self, enum devact act)
+{
+ struct fwohci_softc *sc = (struct fwohci_softc *)self;
+ int s, rv = 0;
+
+ s = splhigh();
+ switch (act) {
+ case DVACT_ACTIVATE:
+ rv = EOPNOTSUPP;
+ break;
+
+ case DVACT_DEACTIVATE:
+ if (sc->sc_sc1394.sc1394_if != NULL)
+ rv = config_deactivate(sc->sc_sc1394.sc1394_if);
+ break;
+ }
+ splx(s);
+
+ return (rv);
+}
+
+#ifdef FW_DEBUG
+static void
+fwohci_show_intr(struct fwohci_softc *sc, u_int32_t intmask)
+{
+
+ printf("%s: intmask=0x%08x:", sc->sc_sc1394.sc1394_dev.dv_xname,
+ intmask);
+ if (intmask & OHCI_Int_CycleTooLong)
+ printf(" CycleTooLong");
+ if (intmask & OHCI_Int_UnrecoverableError)
+ printf(" UnrecoverableError");
+ if (intmask & OHCI_Int_CycleInconsistent)
+ printf(" CycleInconsistent");
+ if (intmask & OHCI_Int_BusReset)
+ printf(" BusReset");
+ if (intmask & OHCI_Int_SelfIDComplete)
+ printf(" SelfIDComplete");
+ if (intmask & OHCI_Int_LockRespErr)
+ printf(" LockRespErr");
+ if (intmask & OHCI_Int_PostedWriteErr)
+ printf(" PostedWriteErr");
+ if (intmask & OHCI_Int_ReqTxComplete)
+ printf(" ReqTxComplete(0x%04x)",
+ OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_TX_REQUEST,
+ OHCI_SUBREG_ContextControlClear));
+ if (intmask & OHCI_Int_RespTxComplete)
+ printf(" RespTxComplete(0x%04x)",
+ OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_TX_RESPONSE,
+ OHCI_SUBREG_ContextControlClear));
+ if (intmask & OHCI_Int_ARRS)
+ printf(" ARRS(0x%04x)",
+ OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_RX_RESPONSE,
+ OHCI_SUBREG_ContextControlClear));
+ if (intmask & OHCI_Int_ARRQ)
+ printf(" ARRQ(0x%04x)",
+ OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_RX_REQUEST,
+ OHCI_SUBREG_ContextControlClear));
+ if (intmask & OHCI_Int_IsochRx)
+ printf(" IsochRx(0x%08x)",
+ OHCI_CSR_READ(sc, OHCI_REG_IsoRecvIntEventClear));
+ if (intmask & OHCI_Int_IsochTx)
+ printf(" IsochTx(0x%08x)",
+ OHCI_CSR_READ(sc, OHCI_REG_IsoXmitIntEventClear));
+ if (intmask & OHCI_Int_RQPkt)
+ printf(" RQPkt(0x%04x)",
+ OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_RX_REQUEST,
+ OHCI_SUBREG_ContextControlClear));
+ if (intmask & OHCI_Int_RSPkt)
+ printf(" RSPkt(0x%04x)",
+ OHCI_ASYNC_DMA_READ(sc, OHCI_CTX_ASYNC_RX_RESPONSE,
+ OHCI_SUBREG_ContextControlClear));
+ printf("\n");
+}
+
+static void
+fwohci_show_phypkt(struct fwohci_softc *sc, u_int32_t val)
+{
+ u_int8_t key, phyid;
+
+ key = (val & 0xc0000000) >> 30;
+ phyid = (val & 0x3f000000) >> 24;
+ printf("%s: PHY packet from %d: ",
+ sc->sc_sc1394.sc1394_dev.dv_xname, phyid);
+ switch (key) {
+ case 0:
+ printf("PHY Config:");
+ if (val & 0x00800000)
+ printf(" ForceRoot");
+ if (val & 0x00400000)
+ printf(" Gap=%x", (val & 0x003f0000) >> 16);
+ printf("\n");
+ break;
+ case 1:
+ printf("Link-on\n");
+ break;
+ case 2:
+ printf("SelfID:");
+ if (val & 0x00800000) {
+ printf(" #%d", (val & 0x00700000) >> 20);
+ } else {
+ if (val & 0x00400000)
+ printf(" LinkActive");
+ printf(" Gap=%x", (val & 0x003f0000) >> 16);
+ printf(" Spd=S%d", 100 << ((val & 0x0000c000) >> 14));
+ if (val & 0x00000800)
+ printf(" Cont");
+ if (val & 0x00000002)
+ printf(" InitiateBusReset");
+ }
+ if (val & 0x00000001)
+ printf(" +");
+ printf("\n");
+ break;
+ default:
+ printf("unknown: 0x%08x\n", val);
+ break;
+ }
+}
+#endif /* FW_DEBUG */
diff --git a/sys/dev/ieee1394/fwohcireg.h b/sys/dev/ieee1394/fwohcireg.h
new file mode 100644
index 00000000000..9cb85bb0d9b
--- /dev/null
+++ b/sys/dev/ieee1394/fwohcireg.h
@@ -0,0 +1,552 @@
+/* $OpenBSD: fwohcireg.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: fwohcireg.h,v 1.11 2002/01/26 16:34:27 ichiro Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_IEEE1394_FWOHCIREG_H_
+#define _DEV_IEEE1394_FWOHCIREG_H_
+
+/* PCI/CardBus-Specific definitions
+ */
+
+/* In the PCI Class Code Register ...
+ */
+#define PCI_INTERFACE_OHCI 0x10
+
+/* The OHCI Regisers are in PCI BAR0.
+ */
+#define PCI_OHCI_MAP_REGISTER 0x10
+
+/* HCI Control Register (in PCI config space)
+ */
+#define PCI_OHCI_CONTROL_REGISTER 0x40
+
+/* If the following bit, all OHCI register access
+ * and DMA transactions are byte swapped.
+ */
+#define PCI_GLOBAL_SWAP_BE 0x00000001
+
+/* Bus Independent Definitions */
+
+#define OHCI_CONFIG_SIZE 1024
+#define OHCI_CONFIG_ALIGNMENT 1024
+
+/* OHCI Registers
+ * OHCI Registers are divided into four spaces:
+ * 1) 0x000 .. 0x17C = Control register space
+ * 2) 0x180 .. 0x1FC = Asynchronous DMA context register space
+ * (4 contexts)
+ * 3) 0x200 .. 0x3FC = Isochronous Transmit DMA context register space
+ * (32 contexts)
+ * 4) 0x400 .. 0x7FC = Isochronous Receive DMA context register space
+ * (32 contexts)
+ */
+#define OHCI_REG_Version 0x000
+#define OHCI_REG_Guid_Rom 0x004
+#define OHCI_REG_ATRetries 0x008
+#define OHCI_REG_CsrReadData 0x00c
+#define OHCI_REG_CsrCompareData 0x010
+#define OHCI_REG_CsrControl 0x014
+#define OHCI_REG_ConfigROMhdr 0x018
+#define OHCI_REG_BusId 0x01c
+#define OHCI_REG_BusOptions 0x020
+#define OHCI_REG_GUIDHi 0x024
+#define OHCI_REG_GUIDLo 0x028
+#define OHCI_REG_reserved_02c 0x02c
+#define OHCI_REG_reserved_030 0x030
+#define OHCI_REG_ConfigROMmap 0x034
+#define OHCI_REG_PostedWriteAddressLo 0x038
+#define OHCI_REG_PostedWriteAddressHi 0x03c
+#define OHCI_REG_VendorId 0x040
+#define OHCI_REG_reserved_044 0x044
+#define OHCI_REG_reserved_048 0x048
+#define OHCI_REG_reserved_04c 0x04c
+#define OHCI_REG_HCControlSet 0x050
+#define OHCI_REG_HCControlClear 0x054
+#define OHCI_REG_reserved_058 0x058
+#define OHCI_REG_reserved_05c 0x05c
+#define OHCI_REG_reserved_060 0x060
+#define OHCI_REG_SelfIDBuffer 0x064
+#define OHCI_REG_SelfIDCount 0x068
+#define OHCI_REG_reserved_06c 0x06c
+#define OHCI_REG_IRMultiChanMaskHiSet 0x070
+#define OHCI_REG_IRMultiChanMaskHiClear 0x074
+#define OHCI_REG_IRMultiChanMaskLoSet 0x078
+#define OHCI_REG_IRMultiChanMaskLoClear 0x07c
+#define OHCI_REG_IntEventSet 0x080
+#define OHCI_REG_IntEventClear 0x084
+#define OHCI_REG_IntMaskSet 0x088
+#define OHCI_REG_IntMaskClear 0x08c
+#define OHCI_REG_IsoXmitIntEventSet 0x090
+#define OHCI_REG_IsoXmitIntEventClear 0x094
+#define OHCI_REG_IsoXmitIntMaskSet 0x098
+#define OHCI_REG_IsoXmitIntMaskClear 0x09c
+#define OHCI_REG_IsoRecvIntEventSet 0x0a0
+#define OHCI_REG_IsoRecvIntEventClear 0x0a4
+#define OHCI_REG_IsoRecvIntMaskSet 0x0a8
+#define OHCI_REG_IsoRecvIntMaskClear 0x0ac
+#define OHCI_REG_InitialBandwidthAvailable 0x0b0
+#define OHCI_REG_InitialChannelsAvailableHi 0x0b4
+#define OHCI_REG_InitialChannelsAvailableLo 0x0b8
+#define OHCI_REG_reserved_0bc 0x0bc
+#define OHCI_REG_reserved_0c0 0x0c0
+#define OHCI_REG_reserved_0c4 0x0c4
+#define OHCI_REG_reserved_0c8 0x0c8
+#define OHCI_REG_reserved_0cc 0x0cc
+#define OHCI_REG_reserved_0d0 0x0d0
+#define OHCI_REG_reserved_0d4 0x0d4
+#define OHCI_REG_reserved_0d8 0x0d8
+#define OHCI_REG_FairnessConctrol 0x0dc
+#define OHCI_REG_LinkControlSet 0x0e0
+#define OHCI_REG_LinkControlClear 0x0e4
+#define OHCI_REG_NodeId 0x0e8
+#define OHCI_REG_PhyControl 0x0ec
+#define OHCI_REG_IsochronousCycleTimer 0x0f0
+#define OHCI_REG_reserved_0f0 0x0f4
+#define OHCI_REG_reserved_0f8 0x0f8
+#define OHCI_REG_reserved_0fc 0x0fc
+#define OHCI_REG_AsynchronousRequestFilterHiSet 0x100
+#define OHCI_REG_AsynchronousRequestFilterHiClear 0x104
+#define OHCI_REG_AsynchronousRequestFilterLoSet 0x108
+#define OHCI_REG_AsynchronousRequestFilterLoClear 0x10c
+#define OHCI_REG_PhysicalRequestFilterHiSet 0x110
+#define OHCI_REG_PhysicalRequestFilterHiClear 0x114
+#define OHCI_REG_PhysicalRequestFilterLoSet 0x118
+#define OHCI_REG_PhysicalRequestFilterLoClear 0x11c
+#define OHCI_REG_PhysicalUpperBound 0x120
+#define OHCI_REG_reserved_124 0x124
+#define OHCI_REG_reserved_128 0x128
+#define OHCI_REG_reserved_12c 0x12c
+#define OHCI_REG_reserved_130 0x130
+#define OHCI_REG_reserved_134 0x134
+#define OHCI_REG_reserved_138 0x138
+#define OHCI_REG_reserved_13c 0x13c
+#define OHCI_REG_reserved_140 0x140
+#define OHCI_REG_reserved_144 0x144
+#define OHCI_REG_reserved_148 0x148
+#define OHCI_REG_reserved_14c 0x14c
+#define OHCI_REG_reserved_150 0x150
+#define OHCI_REG_reserved_154 0x154
+#define OHCI_REG_reserved_158 0x158
+#define OHCI_REG_reserved_15c 0x15c
+#define OHCI_REG_reserved_160 0x160
+#define OHCI_REG_reserved_164 0x164
+#define OHCI_REG_reserved_168 0x168
+#define OHCI_REG_reserved_16c 0x16c
+#define OHCI_REG_reserved_170 0x170
+#define OHCI_REG_reserved_174 0x174
+#define OHCI_REG_reserved_178 0x178
+#define OHCI_REG_reserved_17c 0x17c
+
+
+#define OHCI_REG_ASYNC_DMA_BASE 0x180
+#define OHCI_CTX_ASYNC_TX_REQUEST 0
+#define OHCI_CTX_ASYNC_TX_RESPONSE 1
+#define OHCI_CTX_ASYNC_RX_REQUEST 2
+#define OHCI_CTX_ASYNC_RX_RESPONSE 3
+#define OHCI_SUBREG_ContextControlSet 0x000
+#define OHCI_SUBREG_ContextControlClear 0x004
+#define OHCI_SUBREG_reserved_008 0x008
+#define OHCI_SUBREG_CommandPtr 0x00c
+#define OHCI_SUBREG_ContextMatch 0x010
+#define OHCI_SUBREG_reserved_014 0x014
+#define OHCI_SUBREG_reserved_018 0x018
+#define OHCI_SUBREG_reserved_01c 0x01c
+#define OHCI_ASYNC_DMA_WRITE(sc, ctx, reg, val) \
+ OHCI_CSR_WRITE(sc, OHCI_REG_ASYNC_DMA_BASE + 32*(ctx) + (reg), val)
+#define OHCI_ASYNC_DMA_READ(sc, ctx, reg) \
+ OHCI_CSR_READ(sc, OHCI_REG_ASYNC_DMA_BASE + 32*(ctx) + (reg))
+
+#define OHCI_REG_SYNC_TX_DMA_BASE 0x200
+#define OHCI_SYNC_TX_DMA_WRITE(sc, ctx, reg, val) \
+ OHCI_CSR_WRITE(sc, OHCI_REG_SYNC_TX_DMA_BASE + 16*(ctx) + (reg), val)
+#define OHCI_SYNC_TX_DMA_READ(sc, ctx, reg) \
+ OHCI_CSR_READ(sc, OHCI_REG_SYNC_TX_DMA_BASE + 16*(ctx) + (reg))
+
+#define OHCI_REG_SYNC_RX_DMA_BASE 0x400
+#define OHCI_SYNC_RX_DMA_WRITE(sc, ctx, reg, val) \
+ OHCI_CSR_WRITE(sc, OHCI_REG_SYNC_RX_DMA_BASE + 32*(ctx) + (reg), val)
+#define OHCI_SYNC_RX_DMA_READ(sc, ctx, reg) \
+ OHCI_CSR_READ(sc, OHCI_REG_SYNC_RX_DMA_BASE + 32*(ctx) + (reg))
+
+#define OHCI_BITVAL(val, name) \
+ ((((val) & name##_MASK) >> name##_BITPOS))
+
+/* OHCI_REG_Version
+ */
+#define OHCI_Version_GUID_ROM 0x01000000
+#define OHCI_Version_GET_Version(x) \
+ ((((x) >> 16) & 0xf) + (((x) >> 20) & 0xf) * 10)
+#define OHCI_Version_GET_Revision(x) \
+ ((((x) >> 4) & 0xf) + ((x) & 0xf) * 10)
+
+/* OHCI_REG_Guid_Rom
+ */
+#define OHCI_Guid_AddrReset 0x80000000
+#define OHCI_Guid_RdStart 0x02000000
+#define OHCI_Guid_RdData_MASK 0x00ff0000
+#define OHCI_Guid_RdData_BITPOS 16
+#define OHCI_Guid_MiniROM_MASK 0x000000ff
+#define OHCI_Guid_MiniROM_BITPOS 0
+
+/* OHCI_REG_GUIDxx
+ */
+
+/* OHCI_REG_CsrControl
+ */
+#define OHCI_CsrControl_Done 0x80000000
+#define OHCI_CsrControl_SelMASK 0x00000003
+#define OHCI_CsrControl_BusManId 0
+#define OHCI_CsrControl_BWAvail 1
+#define OHCI_CsrControl_ChanAvailHi 2
+#define OHCI_CsrControl_ChanAvailLo 3
+
+/* OHCI_REG_BusOptions
+ */
+#define OHCI_BusOptions_LinkSpd_MASK 0x00000007
+#define OHCI_BusOptions_LinkSpd_BITPOS 0
+#define OHCI_BusOptions_G_MASK 0x000000c0
+#define OHCI_BusOptions_G_BITPOS 6
+#define OHCI_BusOptions_MaxRec_MASK 0x0000f000
+#define OHCI_BusOptions_MaxRec_BITPOS 12
+#define OHCI_BusOptions_CycClkAcc_MASK 0x00ff0000
+#define OHCI_BusOptions_CycClkAcc_BITPOS 16
+#define OHCI_BusOptions_PMC 0x08000000
+#define OHCI_BusOptions_BMC 0x10000000
+#define OHCI_BusOptions_ISC 0x20000000
+#define OHCI_BusOptions_CMC 0x40000000
+#define OHCI_BusOptions_IRMC 0x80000000
+#define OHCI_BusOptions_reserved 0x07000f38
+
+/* OHCI_REG_HCControl
+ */
+
+#define OHCI_HCControl_SoftReset 0x00010000
+#define OHCI_HCControl_LinkEnable 0x00020000
+#define OHCI_HCControl_PostedWriteEnable 0x00040000
+#define OHCI_HCControl_LPS 0x00080000
+#define OHCI_HCControl_APhyEnhanceEnable 0x00400000
+#define OHCI_HCControl_ProgramPhyEnable 0x00800000
+#define OHCI_HCControl_NoByteSwapData 0x40000000
+#define OHCI_HCControl_BIBImageValid 0x80000000
+
+/* OHCI_REG_SelfID
+ */
+#define OHCI_SelfID_Error 0x80000000
+#define OHCI_SelfID_Gen_MASK 0x00ff0000
+#define OHCI_SelfID_Gen_BITPOS 16
+#define OHCI_SelfID_Size_MASK 0x000007fc
+#define OHCI_SelfID_Size_BITPOS 2
+
+/* OHCI_REG_Int{Event|Mask}*
+ */
+#define OHCI_Int_MasterEnable 0x80000000
+#define OHCI_Int_VendorSpecific 0x40000000
+#define OHCI_Int_SoftInterrupt 0x20000000
+#define OHCI_Int_Ack_Tardy 0x08000000
+#define OHCI_Int_PhyRegRcvd 0x04000000
+#define OHCI_Int_CycleTooLong 0x02000000
+#define OHCI_Int_UnrecoverableError 0x01000000
+#define OHCI_Int_CycleInconsistent 0x00800000
+#define OHCI_Int_CycleLost 0x00400000
+#define OHCI_Int_Cycle64Seconds 0x00200000
+#define OHCI_Int_CycleSynch 0x00100000
+#define OHCI_Int_Phy 0x00080000
+#define OHCI_Int_RegAccessFail 0x00040000
+#define OHCI_Int_BusReset 0x00020000
+#define OHCI_Int_SelfIDComplete 0x00010000
+#define OHCI_Int_SelfIDCOmplete2 0x00008000
+#define OHCI_Int_LockRespErr 0x00000200
+#define OHCI_Int_PostedWriteErr 0x00000100
+#define OHCI_Int_IsochRx 0x00000080
+#define OHCI_Int_IsochTx 0x00000040
+#define OHCI_Int_RSPkt 0x00000020
+#define OHCI_Int_RQPkt 0x00000010
+#define OHCI_Int_ARRS 0x00000008
+#define OHCI_Int_ARRQ 0x00000004
+#define OHCI_Int_RespTxComplete 0x00000002
+#define OHCI_Int_ReqTxComplete 0x00000001
+
+/* OHCI_REG_LinkControl
+ */
+#define OHCI_LinkControl_CycleSource 0x00400000
+#define OHCI_LinkControl_CycleMaster 0x00200000
+#define OHCI_LinkControl_CycleTimerEnable 0x00100000
+#define OHCI_LinkControl_RcvPhyPkt 0x00000400
+#define OHCI_LinkControl_RcvSelfID 0x00000200
+#define OHCI_LinkControl_Tag1SyncFilterLock 0x00000040
+
+/* OHCI_REG_NodeId
+ */
+#define OHCI_NodeId_IDValid 0x80000000
+#define OHCI_NodeId_ROOT 0x40000000
+#define OHCI_NodeId_CPS 0x08000000
+#define OHCI_NodeId_BusNumber 0x0000ffc0
+#define OHCI_NodeId_NodeNumber 0x0000003f
+
+/* OHCI_REG_PhyControl
+ */
+#define OHCI_PhyControl_RdDone 0x80000000
+#define OHCI_PhyControl_RdAddr 0x0f000000
+#define OHCI_PhyControl_RdAddr_BITPOS 24
+#define OHCI_PhyControl_RdData 0x00ff0000
+#define OHCI_PhyControl_RdData_BITPOS 16
+#define OHCI_PhyControl_RdReg 0x00008000
+#define OHCI_PhyControl_WrReg 0x00004000
+#define OHCI_PhyControl_RegAddr 0x00000f00
+#define OHCI_PhyControl_RegAddr_BITPOS 8
+#define OHCI_PhyControl_WrData 0x000000ff
+#define OHCI_PhyControl_WrData_BITPOS 0
+
+/*
+ * Section 3.1.1: ContextControl register
+ *
+ *
+ */
+#define OHCI_CTXCTL_RUN 0x00008000
+#define OHCI_CTXCTL_WAKE 0x00001000
+#define OHCI_CTXCTL_DEAD 0x00000800
+#define OHCI_CTXCTL_ACTIVE 0x00000400
+
+#define OHCI_CTXCTL_SPD_BITLEN 3
+#define OHCI_CTXCTL_SPD_BITPOS 5
+
+#define OHCI_CTXCTL_SPD_100 0
+#define OHCI_CTXCTL_SPD_200 1
+#define OHCI_CTXCTL_SPD_400 2
+
+#define OHCI_CTXCTL_EVENT_BITLEN 5
+#define OHCI_CTXCTL_EVENT_BITPOS 0
+
+/* Events from 0 to 15 are generated by the OpenHCI controller.
+ * Events from 16 to 31 are four-bit IEEE 1394 ack codes or'ed with bit 4 set.
+ */
+#define OHCI_CTXCTL_EVENT_NO_STATUS 0
+#define OHCI_CTXCTL_EVENT_RESERVED1 1
+
+/* The received data length was greater than the buffer's data_length.
+ */
+#define OHCI_CTXCTL_EVENT_LONG_PACKET 2
+
+/* A subaction gap was detected before an ack arrived or the received
+ * ack had a parity error.
+ */
+#define OHCI_CTXCTL_EVENT_MISSING_ACK 3
+
+/* Underrun on the corresponding FIFO. The packet was truncated.
+ */
+#define OHCI_CTXCTL_EVENT_UNDERRUN 4
+
+/* A receive FIFO overflowed during the reception of an isochronous packet.
+ */
+#define OHCI_CTXCTL_EVENT_OVERRUN 5
+
+/* An unrecoverable error occurred while the Host Controller was reading
+ * a descriptor block.
+ */
+#define OHCI_CTXCTL_EVENT_DESCRIPTOR_READ 6
+
+/* An error occurred while the Host Controller was attempting to read
+ * from host memory in the data stage of descriptor processing.
+ */
+#define OHCI_CTXCTL_EVENT_DATA_READ 7
+
+/* An error occurred while the Host Controller was attempting to write
+ * to host memory either in the data stage of descriptor processing
+ * (AR, IR), or when processing a single 16-bit host * memory write (IT).
+ */
+#define OHCI_CTXCTL_EVENT_DATA_WRITE 8
+
+/* Identifies a PHY packet in the receive buffer as being the synthesized
+ * bus reset packet. (See section 8.4.2.3).
+ */
+#define OHCI_CTXCTL_EVENT_BUS_RESET 9
+
+/* Indicates that the asynchronous transmit response packet expired and
+ * was not transmitted, or that an IT DMA context experienced a skip
+ * processing overflow (See section 9.3.3).
+ */
+#define OHCI_CTXCTL_EVENT_TIMEOUT 10
+
+/* A bad tCode is associated with this packet. The packet was flushed.
+ */
+#define OHCI_CTXCTL_EVENT_TCODE_ERR 11
+#define OHCI_CTXCTL_EVENT_RESERVED12 12
+#define OHCI_CTXCTL_EVENT_RESERVED13 13
+
+/* An error condition has occurred that cannot be represented
+ * by any other event codes defined herein.
+ */
+#define OHCI_CTXCTL_EVENT_UNKNOWN 14
+
+/* Sent by the link side of the output FIFO when asynchronous
+ * packets are being flushed due to a bus reset.
+ */
+#define OHCI_CTXCTL_EVENT_FLUSHED 15
+
+/* IEEE1394 derived ACK codes follow
+ */
+#define OHCI_CTXCTL_EVENT_RESERVED16 16
+
+/* For asynchronous request and response packets, this event
+ * indicates the destination node has successfully accepted
+ * the packet. If the packet was a request subaction, the
+ * destination node has successfully completed the transaction
+ * and no response subaction shall follow. The event code for
+ * transmitted PHY, isochronous, asynchronous stream and broadcast
+ * packets, none of which yields a 1394 ack code, shall be set
+ * by hardware to ack_complete unless an event occurs.
+ */
+#define OHCI_CTXCTL_EVENT_ACK_COMPLETE 17
+
+/* The destination node has successfully accepted the packet.
+ * If the packet was a request subaction, a response subaction
+ * should follow at a later time. This code is not returned for
+ * a response subaction.
+ */
+#define OHCI_CTXCTL_EVENT_ACK_PENDING 18
+#define OHCI_CTXCTL_EVENT_RESERVED19 19
+
+/* The packet could not be accepted after max ATRetries (see
+ * section 5.4) attempts, and the last ack received was ack_busy_X.
+ */
+#define OHCI_CTXCTL_EVENT_ACK_BUSY_X 20
+
+/* The packet could not be accepted after max ATRetries (see
+ * section 5.4) attempts, and the last ack received was ack_busy_A.
+ */
+#define OHCI_CTXCTL_EVENT_ACK_BUSY_A 21
+
+/* The packet could not be accepted after max AT Retries (see
+ * section 5.4) attempts, and the last ack received was ack_busy_B.
+ */
+#define OHCI_CTXCTL_EVENT_ACK_BUSY_B 22
+#define OHCI_CTXCTL_EVENT_RESERVED23 23
+#define OHCI_CTXCTL_EVENT_RESERVED24 24
+#define OHCI_CTXCTL_EVENT_RESERVED25 25
+#define OHCI_CTXCTL_EVENT_RESERVED26 26
+
+/* The destination node could not accept the packet because
+ * the link and higher layers are in a suspended state.
+ */
+#define OHCI_CTXCTL_EVENT_ACK_TARDY 27
+#define OHCI_CTXCTL_EVENT_RESERVED28 28
+
+/* An AT context received an ack_data_error, or an IR context
+ * in packet-per-buffer mode detected a data field CRC or
+ * data_length error.
+ */
+#define OHCI_CTXCTL_EVENT_ACK_DATA_ERROR 29
+
+/* A field in the request packet header was set to an unsupported or
+ * incorrect value, or an invalid transaction was attempted (e.g., a
+ * write to a read-only address).
+ */
+#define OHCI_CTXCTL_EVENT_ACK_TYPE_ERROR 30
+#define OHCI_CTXCTL_EVENT_RESERVED31 31
+
+/* Context Control for isochronous transmit context
+ */
+#define OHCI_CTXCTL_TX_CYCLE_MATCH_ENABLE 0x80000000
+#define OHCI_CTXCTL_TX_CYCLE_MATCH_BITLEN 0x7fff0000
+#define OHCI_CTXCTL_TX_CYCLE_MATCH_BITPOS 16
+
+#define OHCI_CTXCTL_RX_BUFFER_FILL 0x80000000
+#define OHCI_CTXCTL_RX_ISOCH_HEADER 0x40000000
+#define OHCI_CTXCTL_RX_CYCLE_MATCH_ENABLE 0x20000000
+#define OHCI_CTXCTL_RX_MULTI_CHAN_MODE 0x10000000
+#define OHCI_CTXCTL_RX_DUAL_BUFFER_MODE 0x08000000
+
+/* Context Match registers
+ */
+#define OHCI_CTXMATCH_TAG3 0x80000000
+#define OHCI_CTXMATCH_TAG2 0x40000000
+#define OHCI_CTXMATCH_TAG1 0x20000000
+#define OHCI_CTXMATCH_TAG0 0x10000000
+#define OHCI_CTXMATCH_CYCLE_MATCH_MASK 0x07fff000
+#define OHCI_CTXMATCH_CYCLE_MATCH_BITPOS 12
+#define OHCI_CTXMATCH_SYNC_MASK 0x00000f00
+#define OHCI_CTXMATCH_SYNC_BITPOS 8
+#define OHCI_CTXMATCH_TAG1_SYNC_FILTER 0x00000040
+#define OHCI_CTXMATCH_CHANNEL_NUMBER_MASK 0x0000003f
+#define OHCI_CTXMATCH_CHANNEL_NUMBER_BITPOS 0
+
+/*
+ * Miscellaneous definitions.
+ */
+
+#define OHCI_TCODE_PHY 0xe
+
+#if BYTE_ORDER == BIG_ENDIAN
+struct fwohci_desc {
+ u_int16_t fd_flags;
+ u_int16_t fd_reqcount;
+ u_int32_t fd_data;
+ u_int32_t fd_branch;
+ u_int16_t fd_status;
+ u_int16_t fd_rescount;
+};
+#endif
+#if BYTE_ORDER == LITTLE_ENDIAN
+struct fwohci_desc {
+ u_int16_t fd_reqcount;
+ u_int16_t fd_flags;
+ u_int32_t fd_data;
+ u_int32_t fd_branch;
+ u_int16_t fd_rescount;
+ u_int16_t fd_status;
+};
+#endif
+#define fd_timestamp fd_rescount
+
+#define OHCI_DESC_INPUT 0x2000
+#define OHCI_DESC_LAST 0x1000
+#define OHCI_DESC_STATUS 0x0800
+#define OHCI_DESC_IMMED 0x0200
+#define OHCI_DESC_PING 0x0080
+#define OHCI_DESC_INTR_ALWAYS 0x0030
+#define OHCI_DESC_INTR_ERR 0x0010
+#define OHCI_DESC_BRANCH 0x000c
+#define OHCI_DESC_WAIT 0x0003
+
+#define OHCI_DESC_MAX 8
+
+/* Some constants for passing ACK values around with from status reg's */
+
+#define OHCI_DESC_STATUS_ACK_MASK 0x1f
+
+#endif /* _DEV_IEEE1394_FWOHCIREG_ */
diff --git a/sys/dev/ieee1394/fwohcivar.h b/sys/dev/ieee1394/fwohcivar.h
new file mode 100644
index 00000000000..65a9c4470aa
--- /dev/null
+++ b/sys/dev/ieee1394/fwohcivar.h
@@ -0,0 +1,241 @@
+/* $OpenBSD: fwohcivar.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: fwohcivar.h,v 1.17 2002/01/16 01:47:37 eeh Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of the 3am Software Foundry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_IEEE1394_FWOHCIVAR_H_
+#define _DEV_IEEE1394_FWOHCIVAR_H_
+
+#ifdef __NetBSD__
+#include <sys/callout.h>
+#else
+#include <sys/timeout.h>
+#endif
+#include <sys/queue.h>
+
+#include <machine/bus.h>
+
+#define OHCI_PAGE_SIZE 0x0800
+#define OHCI_BUF_ARRQ_CNT 16
+#define OHCI_BUF_ARRS_CNT 8
+#define OHCI_BUF_ATRQ_CNT (8*8)
+#define OHCI_BUF_ATRS_CNT (8*8)
+#define OHCI_BUF_IR_CNT 8
+#define OHCI_BUF_CNT \
+ (OHCI_BUF_ARRQ_CNT + OHCI_BUF_ARRS_CNT + OHCI_BUF_ATRQ_CNT + \
+ OHCI_BUF_ATRS_CNT + OHCI_BUF_IR_CNT + 1 + 1)
+
+#define OHCI_LOOP 1000
+#define OHCI_SELFID_TIMEOUT (hz * 3)
+#define OHCI_ASYNC_STREAM 0x40
+
+struct fwohci_softc;
+struct fwohci_pkt;
+struct mbuf;
+
+struct fwohci_buf {
+ TAILQ_ENTRY(fwohci_buf) fb_list;
+ bus_dma_segment_t fb_seg;
+ int fb_nseg;
+ bus_dmamap_t fb_dmamap; /* DMA map of the buffer */
+ caddr_t fb_buf; /* kernel virtual addr of the buffer */
+ struct fwohci_desc *fb_desc; /* kernel virtual addr of descriptor */
+ bus_addr_t fb_daddr; /* physical addr of the descriptor */
+ int fb_off;
+ struct mbuf *fb_m;
+ void *fb_statusarg;
+ void (*fb_callback)(struct device *, struct mbuf *);
+ int (*fb_statuscb)(struct fwohci_softc *, void *, struct fwohci_pkt *);
+};
+
+struct fwohci_pkt {
+ int fp_tcode;
+ int fp_hlen;
+ int fp_dlen;
+ u_int32_t fp_hdr[4];
+ struct uio fp_uio;
+ struct iovec fp_iov[6];
+ u_int32_t *fp_trail;
+ struct mbuf *fp_m;
+ u_int16_t fp_status;
+ void *fp_statusarg;
+ int (*fp_statuscb)(struct fwohci_softc *, void *, struct fwohci_pkt *);
+ void (*fp_callback)(struct device *, struct mbuf *);
+};
+
+struct fwohci_handler {
+ LIST_ENTRY(fwohci_handler) fh_list;
+ u_int32_t fh_tcode; /* ARRQ / ARRS / IR */
+ u_int32_t fh_key1; /* addrhi / srcid / chan */
+ u_int32_t fh_key2; /* addrlo / tlabel / tag */
+ int (*fh_handler)(struct fwohci_softc *, void *,
+ struct fwohci_pkt *);
+ void *fh_handarg;
+};
+
+struct fwohci_ctx {
+ int fc_ctx;
+ int fc_type; /* FWOHCI_CTX_(ASYNC|ISO_SINGLE|ISO_MULTI) */
+ int fc_bufcnt;
+ u_int32_t *fc_branch;
+ TAILQ_HEAD(fwohci_buf_s, fwohci_buf) fc_buf;
+ struct fwohci_buf_s fc_buf2; /* for iso */
+ LIST_HEAD(, fwohci_handler) fc_handler;
+ struct fwohci_buf *fc_buffers;
+};
+
+struct fwohci_uidtbl {
+ int fu_valid;
+ u_int8_t fu_uid[8];
+};
+
+/*
+ * Needed to keep track of outstanding packets during a read op. Since the
+ * packet stream is asynch it's possible to parse a response packet before the
+ * ack bits are processed. In this case something needs to track whether the
+ * abuf is still valid before possibly attempting to use items from within it.
+ */
+
+struct fwohci_cb {
+ struct ieee1394_abuf *ab;
+ int count;
+ int abuf_valid;
+};
+
+struct fwohci_softc {
+ struct ieee1394_softc sc_sc1394;
+ struct evcnt sc_intrcnt;
+ struct evcnt sc_isocnt;
+ struct evcnt sc_isopktcnt;
+
+ bus_space_tag_t sc_memt;
+ bus_space_handle_t sc_memh;
+ bus_dma_tag_t sc_dmat;
+ bus_size_t sc_memsize;
+#if 0
+
+/* Mandatory structures to get the link enabled
+ */
+ bus_dmamap_t sc_configrom_map;
+ bus_dmamap_t sc_selfid_map;
+ u_int32_t *sc_selfid_buf;
+ u_int32_t *sc_configrom;
+#endif
+
+ bus_dma_segment_t sc_dseg;
+ int sc_dnseg;
+ bus_dmamap_t sc_ddmamap;
+ struct fwohci_desc *sc_desc;
+ u_int8_t *sc_descmap;
+ int sc_descsize;
+ int sc_isoctx;
+
+ void *sc_shutdownhook;
+ void *sc_powerhook;
+#ifdef __NetBSD__
+ struct callout sc_selfid_callout;
+#else
+ struct timeout sc_selfid_callout;
+#endif
+ int sc_selfid_fail;
+
+ struct fwohci_ctx *sc_ctx_arrq;
+ struct fwohci_ctx *sc_ctx_arrs;
+ struct fwohci_ctx *sc_ctx_atrq;
+ struct fwohci_ctx *sc_ctx_atrs;
+ struct fwohci_ctx **sc_ctx_ir;
+ struct fwohci_buf sc_buf_cnfrom;
+ struct fwohci_buf sc_buf_selfid;
+
+ struct proc *sc_event_thread;
+
+ int sc_dying;
+ u_int32_t sc_intmask;
+ u_int32_t sc_iso;
+
+ u_int8_t sc_csr[CSR_SB_END];
+
+ struct fwohci_uidtbl *sc_uidtbl;
+ u_int16_t sc_nodeid; /* Full Node ID of this node */
+ u_int8_t sc_rootid; /* Phy ID of Root */
+ u_int8_t sc_irmid; /* Phy ID of IRM */
+ u_int8_t sc_tlabel; /* Transaction Label */
+
+ LIST_HEAD(, ieee1394_softc) sc_nodelist;
+};
+
+int fwohci_init (struct fwohci_softc *, const struct evcnt *);
+int fwohci_intr (void *);
+int fwohci_print (void *, const char *);
+int fwohci_detach(struct fwohci_softc *, int);
+int fwohci_activate(struct device *, enum devact);
+
+/* Macros to read and write the OHCI registers
+ */
+#define OHCI_CSR_WRITE(sc, reg, val) \
+ bus_space_write_4((sc)->sc_memt, (sc)->sc_memh, reg, htole32(val))
+#ifdef __NetBSD__
+#define OHCI_CSR_READ(sc, reg) \
+ le32toh(bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, reg))
+#else
+#define OHCI_CSR_READ(sc, reg) \
+ letoh32(bus_space_read_4((sc)->sc_memt, (sc)->sc_memh, reg))
+#endif
+
+#define FWOHCI_CTX_ASYNC 0
+#define FWOHCI_CTX_ISO_SINGLE 1 /* for async stream */
+#define FWOHCI_CTX_ISO_MULTI 2 /* for isochronous */
+
+/* Locators. */
+
+#ifdef __NetBSD__
+#include "locators.h"
+#else
+/* dup from sys/conf/files */
+#define FWBUSCF_IDHI_DEFAULT (-1)
+#define FWBUSCF_IDLO_DEFAULT (-1)
+#define FWBUSCF_IDHI 1
+#define FWBUSCF_IDLO 0
+#endif
+
+#define fwbuscf_idhi cf_loc[FWBUSCF_IDHI]
+#define FWBUS_UNK_IDHI FWBUSCF_IDHI_DEFAULT
+
+#define fwbuscf_idlo cf_loc[FWBUSCF_IDLO]
+#define FWBUS_UNK_IDLO FWBUSCF_IDLO_DEFAULT
+
+#endif /* _DEV_IEEE1394_FWOHCIVAR_H_ */
diff --git a/sys/dev/ieee1394/ieee1394reg.h b/sys/dev/ieee1394/ieee1394reg.h
new file mode 100644
index 00000000000..bf9df800d13
--- /dev/null
+++ b/sys/dev/ieee1394/ieee1394reg.h
@@ -0,0 +1,241 @@
+/* $OpenBSD: ieee1394reg.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: ieee1394reg.h,v 1.12 2002/02/27 05:07:25 jmc Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_IEEE1394_IEEE1394REG_H_
+#define _DEV_IEEE1394_IEEE1394REG_H_
+
+#include <dev/std/ieee1212reg.h>
+
+/* Transaction Codes (Table 6-9)
+ */
+#define IEEE1394_TCODE_WRITE_REQUEST_QUADLET 0
+#define IEEE1394_TCODE_WRITE_REQUEST_DATABLOCK 1
+#define IEEE1394_TCODE_WRITE_RESPONSE 2
+#define IEEE1394_TCODE_RESERVED_3 3
+#define IEEE1394_TCODE_READ_REQUEST_QUADLET 4
+#define IEEE1394_TCODE_READ_REQUEST_DATABLOCK 5
+#define IEEE1394_TCODE_READ_RESPONSE_QUADLET 6
+#define IEEE1394_TCODE_READ_RESPONSE_DATABLOCK 7
+#define IEEE1394_TCODE_CYCLE_START 0x8
+#define IEEE1394_TCODE_LOCK_REQUEST 9
+#define IEEE1394_TCODE_ISOCHRONOUS_DATA_BLOCK 10
+#define IEEE1394_TCODE_LOCK_RESPONSE 11
+#define IEEE1394_TCODE_RESERVED_12 12
+#define IEEE1394_TCODE_RESERVED_13 13
+#define IEEE1394_TCODE_RESERVED_14 14
+#define IEEE1394_TCODE_RESERVED_15 15
+
+/* Extended transaction codes (Table 6-10)
+ */
+#define IEEE1394_XTCODE_RESERVED_0 P1212_LOCK_RESERVED_0
+#define IEEE1394_XTCODE_MASK_SWAP P1212_LOCK_MASK_SWAP
+#define IEEE1394_XTCODE_COMPARE_SWAP P1212_LOCK_COMPARE_SWAP
+#define IEEE1394_XTCODE_FETCH_ADD P1212_LOCK_FETCH_ADD
+#define IEEE1394_XTCODE_LITTLE_ADD P1212_LOCK_LITTLE_ADD
+#define IEEE1394_XTCODE_BOUNDED_ADD P1212_LOCK_BOUNDED_ADD
+#define IEEE1394_XTCODE_WRAP_ADD P1212_LOCK_WRAP_ADD
+#define IEEE1394_XTCODE_VENDOR_DEPENDENT P1212_LOCK_VENDOR_DEPENDENT
+/* 0x0008 .. 0xFFFF are reserved.
+ */
+
+/* Response codes (Table 6-11)
+ */
+#define IEEE1394_RCODE_RESP_COMPLETE 0
+#define IEEE1394_RCODE_RESERVED_1 1
+#define IEEE1394_RCODE_RESERVED_2 2
+#define IEEE1394_RCODE_RESERVED_3 3
+#define IEEE1394_RCODE_RESP_CONFLICT_ERROR 4
+#define IEEE1394_RCODE_RESP_DATA_ERROR 5
+#define IEEE1394_RCODE_RESP_TYPE_ERROR 6
+#define IEEE1394_RCODE_RESP_ADDRESS_ERROR 7
+#define IEEE1394_RCODE_RESERVED_8 8
+#define IEEE1394_RCODE_RESERVED_9 9
+#define IEEE1394_RCODE_RESERVED_10 10
+#define IEEE1394_RCODE_RESERVED_11 11
+#define IEEE1394_RCODE_RESERVED_12 12
+#define IEEE1394_RCODE_RESERVED_13 13
+#define IEEE1394_RCODE_RESERVED_14 14
+#define IEEE1394_RCODE_RESERVED_15 15
+
+#define IEEE1394_TAG_UNFORMATTED 0
+#define IEEE1394_TAG_RESERVED_1 1
+#define IEEE1394_TAG_RESERVED_2 2
+#define IEEE1394_TAG_RESERVED_3 3
+
+#define IEEE1394_ACK_RESERVED_0 0
+#define IEEE1394_ACK_COMPLETE 1
+#define IEEE1394_ACK_PENDING 2
+#define IEEE1394_ACK_RESERVED_3 3
+#define IEEE1394_ACK_BUSY_X 4
+#define IEEE1394_ACK_BUSY_A 5
+#define IEEE1394_ACK_BUSY_B 6
+#define IEEE1394_ACK_RESERVED_7 7
+#define IEEE1394_ACK_RESERVED_8 8
+#define IEEE1394_ACK_RESERVED_9 9
+#define IEEE1394_ACK_RESERVED_10 10
+#define IEEE1394_ACK_RESERVED_11 11
+#define IEEE1394_ACK_RESERVED_12 12
+#define IEEE1394_ACK_DATA_ERROR 13
+#define IEEE1394_ACK_TYPE_ERROR 14
+#define IEEE1394_ACK_RESERVED_15 15
+
+/* Defined IEEE 1394 speeds.
+ */
+#define IEEE1394_SPD_S100 0 /* 1394-1995 */
+#define IEEE1394_SPD_S200 1 /* 1394-1995 */
+#define IEEE1394_SPD_S400 2 /* 1394-1995 */
+#define IEEE1394_SPD_S800 3 /* 1394b */
+#define IEEE1394_SPD_S1600 4 /* 1394b */
+#define IEEE1394_SPD_S3200 5 /* 1394b */
+#define IEEE1394_SPD_MAX 6
+
+#define IEEE1394_SPD_STRINGS "100Mb/s", "200Mb/s", "400Mb/s", "800Mb/s", \
+ "1.6Gb/s", "3.2Gb/s"
+
+#if 0
+struct ieee1394_async_nodata {
+ u_int32_t an_header_crc;
+} __attribute((__packed__));
+#endif
+
+#define IEEE1394_BCAST_PHY_ID 0x3f
+#define IEEE1394_ISOCH_MASK 0x3f
+
+/*
+ * Transaction code
+ */
+#define IEEE1394_TCODE_WRITE_REQ_QUAD 0x0
+#define IEEE1394_TCODE_WRITE_REQ_BLOCK 0x1
+#define IEEE1394_TCODE_WRITE_RESP 0x2
+#define IEEE1394_TCODE_READ_REQ_QUAD 0x4
+#define IEEE1394_TCODE_READ_REQ_BLOCK 0x5
+#define IEEE1394_TCODE_READ_RESP_QUAD 0x6
+#define IEEE1394_TCODE_READ_RESP_BLOCK 0x7
+#define IEEE1394_TCODE_CYCLE_START 0x8
+#define IEEE1394_TCODE_LOCK_REQ 0x9
+#define IEEE1394_TCODE_STREAM_DATA 0xa
+#define IEEE1394_TCODE_LOCK_RESP 0xb
+
+/*
+ * Response code
+ */
+#define IEEE1394_RCODE_COMPLETE 0x0
+#define IEEE1394_RCODE_CONFLICT_ERROR 0x4
+#define IEEE1394_RCODE_DATA_ERROR 0x5
+#define IEEE1394_RCODE_TYPE_ERROR 0x6
+#define IEEE1394_RCODE_ADDRESS_ERROR 0x7
+
+/*
+ * Signature
+ */
+#define IEEE1394_SIGNATURE 0x31333934
+
+/*
+ * Tag value
+ */
+#define IEEE1394_TAG_GASP 0x3
+
+/*
+ * Control and Status Registers (IEEE1212 & IEEE1394)
+ */
+#define CSR_BASE_HI 0x0000ffff
+#define CSR_BASE_LO 0xf0000000
+#define CSR_BASE 0x0000fffff0000000
+
+#define CSR_STATE_CLEAR 0x0000
+#define CSR_STATE_SET 0x0004
+#define CSR_NODE_IDS 0x0008
+#define CSR_RESET_START 0x000c
+#define CSR_INDIRECT_ADDRESS 0x0010
+#define CSR_INDIRECT_DATA 0x0014
+#define CSR_SPLIT_TIMEOUT_HI 0x0018
+#define CSR_SPLIT_TIMEOUT_LO 0x001c
+#define CSR_ARGUMENT_HI 0x0020
+#define CSR_ARGUMENT_LO 0x0024
+#define CSR_TEST_START 0x0028
+#define CSR_TEST_STATUS 0x002c
+#define CSR_INTERRUPT_TARGET 0x0050
+#define CSR_INTERRUPT_MASK 0x0054
+#define CSR_CLOCK_VALUE 0x0058
+#define CSR_CLOCK_PERIOD 0x005c
+#define CSR_CLOCK_STROBE_ARRIVED 0x0060
+#define CSR_CLOCK_INFO 0x0064
+#define CSR_MESSAGE_REQUEST 0x0080
+#define CSR_MESSAGE_RESPONSE 0x00c0
+
+#define CSR_SB_CYCLE_TIME 0x0200
+#define CSR_SB_BUS_TIME 0x0204
+#define CSR_SB_POWER_FAIL_IMMINENT 0x0208
+#define CSR_SB_POWER_SOURCE 0x020c
+#define CSR_SB_BUSY_TIMEOUT 0x0210
+#define CSR_SB_PRIORITY_BUDGET_HI 0x0214
+#define CSR_SB_PRIORITY_BUDGET_LO 0x0218
+#define CSR_SB_BUS_MANAGER_ID 0x021c
+#define CSR_SB_BANDWIDTH_AVAILABLE 0x0220
+#define CSR_SB_CHANNEL_AVAILABLE_HI 0x0224
+#define CSR_SB_CHANNEL_AVAILABLE_LO 0x0228
+#define CSR_SB_MAINT_CONTROL 0x022c
+#define CSR_SB_MAINT_UTILITY 0x0230
+#define CSR_SB_BROADCAST_CHANNEL 0x0234
+
+#define CSR_CONFIG_ROM 0x0400
+
+#define CSR_SB_OUTPUT_MASTER_PLUG 0x0900
+#define CSR_SB_OUTPUT_PLUG 0x0904
+#define CSR_SB_INPUT_MASTER_PLUG 0x0980
+#define CSR_SB_INPUT_PLUG 0x0984
+#define CSR_SB_FCP_COMMAND_FRAME 0x0b00
+#define CSR_SB_FCP_RESPONSE_FRAME 0x0d00
+#define CSR_SB_TOPOLOGY_MAP 0x1000
+#define CSR_SB_END 0x1400
+
+#define IEEE1394_MAX_REC(i) ((0x1 << (i + 1)))
+#define IEEE1394_BUSINFO_LEN 3
+
+#define IEEE1394_GET_MAX_REC(i) ((i & 0x0000f000) >> 12)
+#define IEEE1394_GET_LINK_SPD(i) (i & 0x00000007)
+
+/* XXX. Should be at if_fw level but needed here for constructing the config
+ rom. An interface for if_fw to send up a config rom should be done (probably
+ in the p1212 routines. */
+
+#define FW_FIFO_HI 0x2000
+#define FW_FIFO_LO 0x00000000
+
+#endif /* _DEV_IEEE1394_IEEE1394REG_H_ */
diff --git a/sys/dev/ieee1394/ieee1394var.h b/sys/dev/ieee1394/ieee1394var.h
new file mode 100644
index 00000000000..66fbe2d5199
--- /dev/null
+++ b/sys/dev/ieee1394/ieee1394var.h
@@ -0,0 +1,118 @@
+/* $OpenBSD: ieee1394var.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: ieee1394var.h,v 1.15 2002/02/27 05:04:28 jmc Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_IEEE1394_IEEE1394VAR_H_
+#define _DEV_IEEE1394_IEEE1394VAR_H_
+
+struct ieee1394_softc;
+struct ieee1394_node;
+
+/* These buffers have no reference counting. It is assumed that
+ * the upper level buffer (struct buf or struct mbuf) will have the
+ * requisite reference counting.
+ */
+struct ieee1394_abuf {
+ struct ieee1394_softc *ab_req; /* requestor */
+ struct ieee1394_softc *ab_resp; /* response */
+ u_int32_t *ab_data;
+ struct uio *ab_uio;
+ u_int64_t ab_addr;
+ u_int8_t ab_tcode;
+ u_int8_t ab_tlabel;
+ u_int32_t ab_length;
+ u_int32_t ab_retlen; /* length returned from read. */
+ u_int32_t ab_retries;
+ void (*ab_cb)(struct ieee1394_abuf *, int);
+ void *ab_cbarg;
+};
+
+struct ieee1394_callbacks {
+ void (*cb1394_busreset)(struct ieee1394_softc *);
+ void (*cb1394_at_queue)(struct ieee1394_softc *, int type,
+ struct ieee1394_abuf *);
+ void (*cb1394_at_done)(struct ieee1394_softc *,
+ struct ieee1394_abuf *);
+};
+
+struct ieee1394_attach_args {
+ char name[7];
+ u_int8_t uid[8];
+ u_int16_t nodeid;
+ int (*read)(struct ieee1394_abuf *);
+ int (*write)(struct ieee1394_abuf *);
+ int (*inreg)(struct ieee1394_abuf *, int);
+ int (*unreg)(struct ieee1394_abuf *, int);
+};
+
+struct ieee1394_softc {
+ struct device sc1394_dev;
+ struct device *sc1394_if; /* Move to fwohci level. */
+
+ const struct ieee1394_callbacks sc1394_callback; /* Nuke probably. */
+ u_int32_t *sc1394_configrom;
+ u_int32_t sc1394_configrom_len; /* quadlets. */
+ u_int32_t sc1394_max_receive;
+ u_int8_t sc1394_guid[8];
+ u_int8_t sc1394_link_speed; /* IEEE1394_SPD_* */
+ u_int16_t sc1394_node_id; /* my node id in network order */
+
+ int (*sc1394_ifoutput)(struct device *, struct mbuf *,
+ void (*)(struct device *, struct mbuf *)); /* Nuke. */
+ int (*sc1394_ifinreg)(struct device *, u_int32_t, u_int32_t,
+ void (*)(struct device *, struct mbuf *)); /* Nuke */
+ int (*sc1394_ifsetiso)(struct device *, u_int32_t, u_int32_t, u_int32_t,
+ void (*)(struct device *, struct mbuf *)); /* Nuke */
+
+ LIST_ENTRY(ieee1394_softc) sc1394_node;
+};
+
+struct ieee1394_node {
+ struct device node_dev;
+
+ struct ieee1394_softc *node_sc; /* owning bus */
+ u_int32_t *node_configrom;
+ size_t node_configrom_len;
+};
+
+int ieee1394_init __P((struct ieee1394_softc *));
+
+#define IEEE1394_ARGTYPE_PTR 0
+#define IEEE1394_ARGTYPE_MBUF 1
+
+#endif /* _DEV_IEEE1394_IEEE1394VAR_H_ */
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index be283d5efa6..d6c0a620a78 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.137 2002/06/05 22:35:16 mickey Exp $
+# $OpenBSD: files.pci,v 1.138 2002/06/25 17:11:49 itojun Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -447,3 +447,10 @@ device amdpm {}
attach amdpm at pci
file dev/pci/amdpm.c amdpm
+# OHCI IEEE 1394 controller
+attach fwohci at pci with fwohci_pci
+file dev/pci/fwohci_pci.c fwohci_pci
+
+# IEEE 1394 TI "Lynx" controller
+attach fwlynx at pci with fwlynx_pci
+file dev/pci/fwlynx_pci.c fwlynx_pci
diff --git a/sys/dev/pci/fwlynx_pci.c b/sys/dev/pci/fwlynx_pci.c
new file mode 100644
index 00000000000..cba7264154d
--- /dev/null
+++ b/sys/dev/pci/fwlynx_pci.c
@@ -0,0 +1,138 @@
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: fwlynx_pci.c,v 1.3 2001/11/15 09:48:12 lukem Exp $");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/ieee1394/ieee1394reg.h>
+#include <dev/ieee1394/ieee1394var.h>
+#include <dev/ieee1394/fwlynxreg.h>
+#include <dev/ieee1394/fwlynxvar.h>
+
+struct fwlynx_pci_softc {
+ struct fwlynx_softc psc_sc;
+ pci_chipset_tag_t psc_pc;
+ void *psc_ih;
+};
+
+static int fwlynx_pci_match __P((struct device *, struct cfdata *, void *));
+static void fwlynx_pci_attach __P((struct device *, struct device *, void *));
+
+struct cfattach fwlynx_pci_ca = {
+ sizeof(struct fwlynx_pci_softc), fwlynx_pci_match, fwlynx_pci_attach,
+#if 0
+ fwlynx_pci_detach, fwlynx_activate
+#endif
+};
+
+static int
+fwlynx_pci_match(struct device *parent, struct cfdata *match, void *aux)
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+
+ if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_TI &&
+ PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_TI_TSB12LV21)
+ return 1;
+
+ return 0;
+}
+
+static void
+fwlynx_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+ struct fwlynx_pci_softc *psc = (struct fwlynx_pci_softc *) self;
+ char devinfo[256];
+ char const *intrstr;
+ pci_intr_handle_t ih;
+ u_int32_t csr;
+
+ pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
+ printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
+
+ psc->psc_sc.sc_dmat = pa->pa_dmat;
+ psc->psc_pc = pa->pa_pc;
+ psc->psc_tag = pa->pa_tag;
+
+ /* Map I/O registers */
+ if (pci_mapreg_map(pa, PCI_LYNX_MAP_REGISTER, PCI_MAPREG_TYPE_MEM, 0,
+ &psc->psc_sc.sc_memt, &psc->psc_sc.sc_memh,
+ NULL, &psc->psc_sc.sc_memsize)) {
+ printf("%s: can't map register space\n", self->dv_xname);
+ return;
+ }
+
+ /* Disable interrupts, so we don't get any spurious ones. */
+ pci_conf_write(psc->psc_pc, psc->psc_tag, 0);
+
+ /* Enable the device. */
+ csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ csr | PCI_COMMAND_MASTER_ENABLE);
+
+ /* Map and establish the interrupt. */
+ if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
+ pa->pa_intrline, &ih)) {
+ printf("%s: couldn't map interrupt\n", self->dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+ psc->psc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, fwlynx_intr, &psc->psc_sc);
+ if (psc->psc_ih == NULL) {
+ printf("%s: couldn't establish interrupt", self->dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf("%s: interrupting at %s\n", self->dv_xname, intrstr);
+
+ if (fwlynx_init(&psc->psc_sc, pci_intr_evcnt(pa->pa_pc, ih)) != 0) {
+ pci_intr_disestablish(pa->pa_pc, psc->psc_ih);
+ bus_space_unmap(psc->psc_sc.sc_memt, psc->psc_sc.sc_memh,
+ psc->psc_sc.sc_memsize);
+ }
+}
diff --git a/sys/dev/pci/fwohci_pci.c b/sys/dev/pci/fwohci_pci.c
new file mode 100644
index 00000000000..3733b585192
--- /dev/null
+++ b/sys/dev/pci/fwohci_pci.c
@@ -0,0 +1,175 @@
+/* $NetBSD: fwohci_pci.c,v 1.13 2002/01/26 16:30:00 ichiro Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas of 3am Software Foundry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __KERNEL_RCSID
+__KERNEL_RCSID(0, "$NetBSD: fwohci_pci.c,v 1.13 2002/01/26 16:30:00 ichiro Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/ieee1394/ieee1394reg.h>
+#include <dev/ieee1394/ieee1394var.h>
+#include <dev/ieee1394/fwohcireg.h>
+#include <dev/ieee1394/fwohcivar.h>
+
+struct fwohci_pci_softc {
+ struct fwohci_softc psc_sc;
+ pci_chipset_tag_t psc_pc;
+ void *psc_ih;
+};
+
+#ifdef __NetBSD__
+static int fwohci_pci_match __P((struct device *, struct cfdata *, void *));
+#else
+static int fwohci_pci_match __P((struct device *, void *, void *));
+#endif
+static void fwohci_pci_attach __P((struct device *, struct device *, void *));
+
+struct cfattach fwohci_pci_ca = {
+ sizeof(struct fwohci_pci_softc), fwohci_pci_match, fwohci_pci_attach,
+#if 0
+ fwohci_pci_detach, fwohci_activate
+#endif
+};
+
+#ifdef __NetBSD__
+static int
+fwohci_pci_match(struct device *parent, struct cfdata *match, void *aux)
+#else
+static int
+fwohci_pci_match(struct device *parent, void *match, void *aux)
+#endif
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+
+ if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS &&
+ PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_FIREWIRE &&
+ PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_OHCI)
+ return 1;
+
+ return 0;
+}
+
+static void
+fwohci_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct pci_attach_args *pa = (struct pci_attach_args *) aux;
+ struct fwohci_pci_softc *psc = (struct fwohci_pci_softc *) self;
+ char devinfo[256];
+ char const *intrstr;
+ pci_intr_handle_t ih;
+ u_int32_t csr;
+
+ pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo);
+ printf(": %s (rev. 0x%02x)\n", devinfo, PCI_REVISION(pa->pa_class));
+
+ psc->psc_sc.sc_dmat = pa->pa_dmat;
+ psc->psc_pc = pa->pa_pc;
+
+ /* Map I/O registers */
+#ifdef __NetBSD__
+ if (pci_mapreg_map(pa, PCI_OHCI_MAP_REGISTER, PCI_MAPREG_TYPE_MEM, 0,
+ &psc->psc_sc.sc_memt, &psc->psc_sc.sc_memh,
+ NULL, &psc->psc_sc.sc_memsize))
+#else
+ if (pci_mapreg_map(pa, PCI_OHCI_MAP_REGISTER, PCI_MAPREG_TYPE_MEM, 0,
+ &psc->psc_sc.sc_memt, &psc->psc_sc.sc_memh,
+ NULL, &psc->psc_sc.sc_memsize, 0))
+#endif
+ {
+ printf("%s: can't map OHCI register space\n", self->dv_xname);
+ return;
+ }
+
+ /* Disable interrupts, so we don't get any spurious ones. */
+ OHCI_CSR_WRITE(&psc->psc_sc, OHCI_REG_IntMaskClear,
+ OHCI_Int_MasterEnable);
+
+ /* Enable the device. */
+ csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
+ csr | PCI_COMMAND_MASTER_ENABLE);
+
+#if BYTE_ORDER == BIG_ENDIAN
+ csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_OHCI_CONTROL_REGISTER);
+ pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_OHCI_CONTROL_REGISTER,
+ csr | PCI_GLOBAL_SWAP_BE);
+#endif
+
+ /* Map and establish the interrupt. */
+ if (pci_intr_map(pa, &ih)) {
+ printf("%s: couldn't map interrupt\n", self->dv_xname);
+ return;
+ }
+ intrstr = pci_intr_string(pa->pa_pc, ih);
+#ifdef __NetBSD__
+ psc->psc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, fwohci_intr,
+ &psc->psc_sc);
+#else
+ psc->psc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, fwohci_intr,
+ &psc->psc_sc, self->dv_xname);
+#endif
+ if (psc->psc_ih == NULL) {
+ printf("%s: couldn't establish interrupt", self->dv_xname);
+ if (intrstr != NULL)
+ printf(" at %s", intrstr);
+ printf("\n");
+ return;
+ }
+ printf("%s: interrupting at %s\n", self->dv_xname, intrstr);
+
+#ifdef __NetBSD__
+ if (fwohci_init(&psc->psc_sc, pci_intr_evcnt(pa->pa_pc, ih)) != 0)
+#else
+ if (fwohci_init(&psc->psc_sc, NULL) != 0)
+#endif
+ {
+ pci_intr_disestablish(pa->pa_pc, psc->psc_ih);
+ bus_space_unmap(psc->psc_sc.sc_memt, psc->psc_sc.sc_memh,
+ psc->psc_sc.sc_memsize);
+ }
+}
diff --git a/sys/dev/std/ieee1212.c b/sys/dev/std/ieee1212.c
new file mode 100644
index 00000000000..5a053d89278
--- /dev/null
+++ b/sys/dev/std/ieee1212.c
@@ -0,0 +1,1427 @@
+/* $OpenBSD: ieee1212.c,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: ieee1212.c,v 1.3 2002/05/23 00:10:46 jmc Exp $ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by James Chacon.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <dev/std/ieee1212reg.h>
+#include <dev/std/ieee1212var.h>
+
+static const char * const p1212_keytype_strings[] = P1212_KEYTYPE_STRINGS ;
+static const char * const p1212_keyvalue_strings[] = P1212_KEYVALUE_STRINGS ;
+
+static u_int16_t p1212_calc_crc(u_int32_t, u_int32_t *, int, int);
+static int p1212_parse_directory(struct p1212_dir *, u_int32_t *, u_int32_t);
+static struct p1212_leafdata *p1212_parse_leaf(u_int32_t *);
+static int p1212_parse_textdir(struct p1212_com *, u_int32_t *);
+static struct p1212_textdata *p1212_parse_text_desc(u_int32_t *);
+static void p1212_print_node(struct p1212_key *, void *);
+static int p1212_validate_offset(u_int16_t, u_int32_t);
+static int p1212_validate_immed(u_int16_t, u_int32_t);
+static int p1212_validate_leaf(u_int16_t, u_int32_t);
+static int p1212_validate_dir(u_int16_t, u_int32_t);
+
+#ifdef P1212_DEBUG
+#define DPRINTF(x) if (p1212debug) printf x
+#define DPRINTFN(n,x) if (p1212debug>(n)) printf x
+int p1212debug = 1;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+/*
+ * Routines to parse the ROM into a tree that's usable. Also verify integrity
+ * vs. the P1212 standard
+ */
+
+/*
+ * A buffer of u_int32_t's and a size in quads gets passed in. The output will
+ * return -1 on error, or 0 on success and possibly reset *size to a larger
+ * value.
+ *
+ * NOTE: Rom's are guarentee'd per the ISO spec to be contiguous but only the
+ * first 1k is directly mapped. Anything past 1k is supposed to use a loop
+ * around the indirect registers to read in the rom. This code only assumes the
+ * buffer passed in represents a total rom regardless of end size. It is the
+ * callers responsibility to treat a size > 1024 as a special case.
+ */
+
+int
+p1212_iscomplete(u_int32_t *t, u_int32_t *size)
+{
+ u_int16_t infolen, crclen, len;
+ u_int32_t newlen, offset, test;
+ int complete, i, numdirs, type, val, *dirs;
+#ifdef __OpenBSD__
+ int *p;
+#endif
+
+ dirs = NULL;
+
+ if (*size == 0) {
+ DPRINTF(("Invalid size for ROM: %d\n", (unsigned int)*size));
+ return -1;
+ }
+
+ infolen = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0])));
+ if (infolen <= 1) {
+ DPRINTF(("ROM not initialized or minimal ROM: Info "
+ "length: %d\n", infolen));
+ return -1;
+ }
+ crclen = P1212_ROMFMT_GET_CRCLEN((ntohl(t[0])));
+ if (crclen < infolen) {
+ DPRINTF(("CRC len less than info len. CRC len: %d, "
+ "Info len: %d\n", crclen, infolen));
+ return -1;
+ }
+
+ /*
+ * Now loop through it to check if all the offsets referenced are
+ * within the image stored so far. If not, get those as well.
+ */
+
+ offset = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0]))) + 1;
+
+ /*
+ * Make sure at least the bus info block is in memory + the root dir
+ * header quad. Add 1 here since offset is an array offset and size is
+ * the total array size we want. If this is getting the root dir
+ * then add another since infolen doesn't end on the root dir entry but
+ * right before it.
+ */
+
+ if ((*size == 1) || (*size < (offset + 1))) {
+ *size = (crclen > infolen) ? crclen : infolen;
+ if (crclen == infolen)
+ (*size)++;
+ (*size)++;
+ return 0;
+ }
+
+ complete = 0;
+ numdirs = 0;
+ newlen = 0;
+
+ while (!complete) {
+
+ /*
+ * Make sure the whole directory is in memory. If not, bail now
+ * and read it in.
+ */
+
+ newlen = P1212_DIRENT_GET_LEN((ntohl(t[offset])));
+ if ((offset + newlen + 1) > *size) {
+ newlen += offset + 1;
+ break;
+ }
+
+ if (newlen == 0) {
+ DPRINTF(("Impossible directory length of 0!\n"));
+ return -1;
+ }
+
+ /*
+ * Starting with the first byte of the directory, read through
+ * and check the values found. On offsets and directories read
+ * them in if appropriate (always for offsets, if not in memory
+ * for leaf/directories).
+ */
+
+ offset++;
+ len = newlen;
+ newlen = 0;
+ for (i = 0; i < len; i++) {
+ type = P1212_DIRENT_GET_KEYTYPE((ntohl(t[offset+i])));
+ val = P1212_DIRENT_GET_VALUE((ntohl(t[offset+i])));
+ switch (type) {
+ case P1212_KEYTYPE_Immediate:
+ case P1212_KEYTYPE_Offset:
+ break;
+ case P1212_KEYTYPE_Leaf:
+
+ /*
+ * If a leaf is found, and it's beyond the
+ * current rom length and it's beyond the
+ * current newlen setting,
+ * then set newlen accordingly.
+ */
+
+ test = offset + i + val + 1;
+ if ((test > *size) && (test > newlen)) {
+ newlen = test;
+ break;
+ }
+
+ /*
+ * For leaf nodes just make sure the whole leaf
+ * length is in the buffer. There's no data
+ * inside of them that can refer to outside
+ * nodes. (Uless it's vendor specific and then
+ * you're on your own anyways).
+ */
+
+ test--;
+ infolen =
+ P1212_DIRENT_GET_LEN((ntohl(t[test])));
+ test++;
+ test += infolen;
+ if ((test > *size) && (test > newlen)) {
+ newlen = test;
+ }
+ break;
+
+ case P1212_KEYTYPE_Directory:
+
+ /* Make sure the first quad is in memory. */
+
+ test = offset + i + val + 1;
+ if ((test > *size) && (test > newlen)) {
+ newlen = test;
+ break;
+ }
+
+ /*
+ * Can't just walk the ROM looking at type
+ * codes since these are only valid on
+ * directory entries. So save any directories
+ * we find into a queue and the bottom of the
+ * while loop will pop the last one off and
+ * walk that directory.
+ */
+
+ test--;
+#ifdef __NetBSD__
+ dirs = realloc(dirs,
+ sizeof(int) * (numdirs + 1), M_DEVBUF,
+ M_WAITOK);
+#else
+ p = malloc(sizeof(int) * (numdirs + 1),
+ M_DEVBUF, M_WAITOK);
+ bcopy(dirs, p, sizeof(int) * numdirs);
+ dirs = p;
+#endif
+ dirs[numdirs++] = test;
+ break;
+ default:
+ panic("Impossible type code: 0x%04hx",
+ (unsigned short)type);
+ break;
+ }
+ }
+
+ if (newlen) {
+ /* Cleanup. */
+ if (dirs)
+ free(dirs, M_DEVBUF);
+ break;
+ }
+ if (dirs) {
+ offset = dirs[--numdirs];
+#ifdef __NetBSD__
+ dirs = realloc(dirs, sizeof(int) * numdirs, M_DEVBUF,
+ M_WAITOK);
+#else
+ p = malloc(sizeof(int) * numdirs, M_DEVBUF,
+ M_WAITOK);
+ bcopy(dirs, p, sizeof(int) * numdirs);
+ dirs = p;
+#endif
+ } else
+ complete = 1;
+ }
+
+ if (newlen)
+ *size = newlen;
+ return 0;
+
+}
+
+struct p1212_rom *
+p1212_parse(u_int32_t *t, u_int32_t size, u_int32_t mask)
+{
+
+ u_int16_t crc, romcrc, crc1;
+ u_int32_t next, check;
+ struct p1212_rom *rom;
+ int i;
+
+ check = size;
+
+ if (p1212_iscomplete(t, &check) == -1) {
+ DPRINTF(("ROM is not complete\n"));
+ return NULL;
+ }
+ if (check != size) {
+ DPRINTF(("ROM is not complete (check != size)\n"));
+ return NULL;
+ }
+
+ /* Calculate both a good and known bad crc. */
+
+ /* CRC's are calculated from everything except the first quad. */
+
+ crc = p1212_calc_crc(0, &t[1], P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))),
+ 0);
+
+ romcrc = P1212_ROMFMT_GET_CRC((ntohl(t[0])));
+ if (crc != romcrc) {
+ crc1 = p1212_calc_crc(0, &t[1],
+ P1212_ROMFMT_GET_CRCLEN((ntohl(t[0]))), 1);
+ if (crc1 != romcrc) {
+ DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated "
+ "CRC: 0x%04hx, CRC1: 0x%04hx\n",
+ (unsigned short)romcrc, (unsigned short)crc,
+ (unsigned short)crc1));
+ return NULL;
+ }
+ }
+
+ /* Now, walk the ROM. */
+
+ /* Get the initial offset for the root dir. */
+
+ rom = malloc(sizeof(struct p1212_rom), M_DEVBUF, M_WAITOK);
+ rom->len = P1212_ROMFMT_GET_INFOLEN((ntohl(t[0])));
+ next = rom->len + 1;
+
+ if ((rom->len < 1) || (rom->len > size)) {
+ DPRINTF(("Invalid ROM info length: %d\n", rom->len));
+ free(rom, M_DEVBUF);
+ return NULL;
+ }
+
+ /* Exclude the quad which covers the bus name. */
+ rom->len--;
+
+ if (rom->len) {
+ rom->data = malloc(sizeof(u_int32_t) * rom->len, M_DEVBUF,
+ M_WAITOK);
+ /* Add 2 to account for info/crc and bus name skipped. */
+ for (i = 0; i < rom->len; i++)
+ rom->data[i] = t[i + 2];
+ }
+
+ /* The name field is always 4 bytes and always the 2nd field. */
+ strncpy(rom->name, (char *)&t[1], 4);
+ rom->name[4] = 0;
+
+ /*
+ * Fill out the root directory. All these values are hardcoded so the
+ * parse/print/match routines have a standard layout to work against.
+ */
+
+#ifdef M_ZERO
+ rom->root = malloc(sizeof(*rom->root), M_DEVBUF, M_WAITOK|M_ZERO);
+#else
+ rom->root = malloc(sizeof(*rom->root), M_DEVBUF, M_WAITOK);
+ bzero(rom->root, sizeof(*rom->root));
+#endif
+ rom->root->com.key.key_type = P1212_KEYTYPE_Directory;
+ rom->root->com.key.key_value = 0;
+ rom->root->com.key.key = (u_int8_t)P1212_KEYTYPE_Directory;
+ rom->root->com.key.val = 0;
+ TAILQ_INIT(&rom->root->data_root);
+ TAILQ_INIT(&rom->root->subdir_root);
+
+ if (p1212_parse_directory(rom->root, &t[next], mask)) {
+ DPRINTF(("Parse error in ROM. Bailing\n"));
+ p1212_free(rom);
+ return NULL;
+ }
+ return rom;
+}
+
+static int
+p1212_parse_directory(struct p1212_dir *root, u_int32_t *addr, u_int32_t mask)
+{
+ struct p1212_dir *dir, *sdir;
+ struct p1212_data *data;
+ struct p1212_com *com;
+ u_int32_t *t, desc;
+ u_int16_t crclen, crc, crc1, romcrc;
+ u_int8_t type, val;
+ unsigned long size;
+ int i, module_vendor_flag, module_sw_flag, node_sw_flag, unit_sw_flag;
+ int node_capabilities_flag, offset, unit_location_flag, unitdir_cnt;
+ int leafoff;
+
+ t = addr;
+ dir = root;
+
+ module_vendor_flag = 0;
+ module_sw_flag = 0;
+ node_sw_flag = 0;
+ node_capabilities_flag = 0;
+ unitdir_cnt = 0;
+ offset = 0;
+
+ while (dir) {
+ dir->match = 0;
+ crclen = P1212_DIRENT_GET_LEN((ntohl(t[offset])));
+ romcrc = P1212_DIRENT_GET_CRC((ntohl(t[offset])));
+
+ crc = p1212_calc_crc(0, &t[offset + 1], crclen, 0);
+ if (crc != romcrc) {
+ crc1 = p1212_calc_crc(0, &t[offset + 1], crclen, 1);
+ if (crc1 != romcrc) {
+ DPRINTF(("Invalid ROM: CRC: 0x%04hx, "
+ "Calculated CRC: "
+ "0x%04hx, CRC1: 0x%04hx\n",
+ (unsigned short)romcrc,
+ (unsigned short)crc,
+ (unsigned short)crc1));
+ return 1;
+ }
+ }
+ com = NULL;
+ unit_sw_flag = 0;
+ unit_location_flag = 0;
+ offset++;
+
+ if ((dir->parent == NULL) && dir->com.key.val) {
+ DPRINTF(("Invalid root dir. key.val is 0x%0x and not"
+ " 0x0\n", dir->com.key.val));
+ return 1;
+ }
+
+ for (i = offset; i < (offset + crclen); i++) {
+ desc = ntohl(t[i]);
+ type = P1212_DIRENT_GET_KEYTYPE(desc);
+ val = P1212_DIRENT_GET_KEYVALUE(desc);
+
+ /*
+ * Sanity check for valid types/locations/etc.
+ *
+ * See pages 79-100 of
+ * ISO/IEC 13213:1194(ANSI/IEEE Std 1212, 1994 edition)
+ * for specifics.
+ *
+ * XXX: These all really should be broken out into
+ * subroutines as it's grown large and complicated
+ * in certain cases.
+ */
+
+ switch (val) {
+ case P1212_KEYVALUE_Unit_Spec_Id:
+ case P1212_KEYVALUE_Unit_Sw_Version:
+ case P1212_KEYVALUE_Unit_Dependent_Info:
+ case P1212_KEYVALUE_Unit_Location:
+ case P1212_KEYVALUE_Unit_Poll_Mask:
+ if (dir->parent == NULL) {
+ DPRINTF(("Invalid ROM: %s is not "
+ "valid in the root directory.\n",
+ p1212_keyvalue_strings[val]));
+ return 1;
+ }
+ break;
+ default:
+ if (dir->com.key.val ==
+ P1212_KEYVALUE_Unit_Directory) {
+ DPRINTF(("Invalid ROM: %s is "
+ "not valid in a unit directory.\n",
+ p1212_keyvalue_strings[val]));
+ return 1;
+ }
+ break;
+ }
+
+ switch (type) {
+ case P1212_KEYTYPE_Immediate:
+ if (p1212_validate_immed(val, mask)) {
+ DPRINTF(("Invalid ROM: Can't have an "
+ "immediate type with %s value. Key"
+ " used at location 0x%0x in ROM\n",
+ p1212_keyvalue_strings[val],
+ (unsigned int)(&t[i]-&addr[0])));
+ return 1;
+ }
+ break;
+ case P1212_KEYTYPE_Offset:
+ if (p1212_validate_offset(val, mask)) {
+ DPRINTF(("Invalid ROM: Can't have "
+ "an offset type with key %s."
+ " Used at location 0x%0x in ROM\n",
+ p1212_keyvalue_strings[val],
+ (unsigned int)(&t[i]-&addr[0])));
+ return 1;
+ }
+ break;
+ case P1212_KEYTYPE_Leaf:
+ if (p1212_validate_leaf(val, mask)) {
+ DPRINTF(("Invalid ROM: Can't have a "
+ "leaf type with %s value. Key "
+ "used at location 0x%0x in ROM\n",
+ p1212_keyvalue_strings[val],
+ (unsigned int)(&t[i]-&addr[0])));
+ return 1;
+ }
+ break;
+ case P1212_KEYTYPE_Directory:
+ if (p1212_validate_dir(val, mask)) {
+ DPRINTF(("Invalid ROM: Can't have a "
+ "directory type with %s value. Key"
+ " used at location 0x%0x in ROM\n",
+ p1212_keyvalue_strings[val],
+ (unsigned int)(&t[i]-&addr[0])));
+ return 1;
+ }
+ break;
+ default:
+ panic("Impossible type code: 0x%04hx",
+ (unsigned short)type);
+ break;
+ }
+
+ /* Note flags for required fields. */
+
+ if (val == P1212_KEYVALUE_Module_Vendor_Id) {
+ module_vendor_flag = 1;
+ }
+
+ if (val == P1212_KEYVALUE_Node_Capabilities) {
+ node_capabilities_flag = 1;
+ }
+
+ if (val == P1212_KEYVALUE_Unit_Sw_Version)
+ unit_sw_flag = 1;
+
+ if (val == P1212_KEYVALUE_Unit_Location)
+ unit_location_flag = 1;
+
+ /*
+ * This is just easier to spell out. You can't have
+ * a module sw version if you include a node sw version
+ * and vice-versa. Both aren't allowed if you have unit
+ * dirs.
+ */
+
+ if (val == P1212_KEYVALUE_Module_Sw_Version) {
+ if (node_sw_flag) {
+ DPRINTF(("Can't have a module software"
+ " version along with a node "
+ "software version entry\n"));
+ return 1;
+ }
+ if (unitdir_cnt) {
+ DPRINTF(("Can't have unit directories "
+ "with module software version "
+ "defined.\n"));
+ return 1;
+ }
+ module_sw_flag = 1;
+ }
+
+ if (val == P1212_KEYVALUE_Node_Sw_Version) {
+ if (module_sw_flag) {
+ DPRINTF(("Can't have a node software "
+ "version along with a module "
+ "software version entry\n"));
+ return 1;
+ }
+ if (unitdir_cnt) {
+ DPRINTF(("Can't have unit directories "
+ "with node software version "
+ "defined.\n"));
+ return 1;
+ }
+ node_sw_flag = 1;
+ }
+
+ if (val == P1212_KEYVALUE_Unit_Directory) {
+ if (module_sw_flag || node_sw_flag) {
+ DPRINTF(("Can't have unit directories "
+ "with either module or node "
+ "software version defined.\n"));
+ return 1;
+ }
+ unitdir_cnt++;
+ }
+
+ /*
+ * Text descriptors are special. They describe the
+ * last entry they follow. So they need to be included
+ * with it's struct and there's nothing in the spec
+ * preventing one from putting text descriptors after
+ * directory descriptors. Also they can be a single
+ * value or a list of them in a directory format so
+ * account for either. Finally if they're in a
+ * directory those can be the only types in a
+ * directory.
+ */
+
+ if (val == P1212_KEYVALUE_Textual_Descriptor) {
+
+ size = sizeof(struct p1212_textdata *);
+ leafoff = P1212_DIRENT_GET_VALUE(desc);
+ leafoff += i;
+
+ if (com == NULL) {
+ DPRINTF(("Can't have a text descriptor"
+ " as the first entry in a "
+ "directory\n"));
+ return 1;
+ }
+
+ if (com->textcnt != 0) {
+ DPRINTF(("Text descriptors can't "
+ "follow each other in a "
+ "directory\n"));
+ return 1;
+ }
+
+ if (type == P1212_KEYTYPE_Leaf) {
+ com->text =
+ malloc(size, M_DEVBUF, M_WAITOK);
+ com->text[0] =
+ p1212_parse_text_desc(&t[leafoff]);
+ if (com->text[0] == NULL) {
+ DPRINTF(("Got an error parsing"
+ " text descriptor at "
+ "offset 0x%0x\n",
+ &t[leafoff]-&addr[0]));
+ free(com->text, M_DEVBUF);
+ return 1;
+ }
+ com->textcnt = 1;
+ } else {
+ i = p1212_parse_textdir(com,
+ &t[leafoff]);
+ if (i)
+ return 1;
+ }
+ }
+
+ if ((type != P1212_KEYTYPE_Directory) &&
+ (val != P1212_KEYVALUE_Textual_Descriptor)) {
+#ifdef M_ZERO
+ data = malloc(sizeof(struct p1212_data),
+ M_DEVBUF, M_WAITOK|M_ZERO);
+#else
+ data = malloc(sizeof(struct p1212_data),
+ M_DEVBUF, M_WAITOK);
+ bzero(data, sizeof(struct p1212_data));
+#endif
+ data->com.key.key_type = type;
+ data->com.key.key_value = val;
+ data->com.key.key =
+ P1212_DIRENT_GET_KEY((ntohl(t[i])));
+ data->com.key.val =
+ P1212_DIRENT_GET_VALUE((ntohl(t[i])));
+ com = &data->com;
+
+ /*
+ * Don't try and read the offset. It may be
+ * a register or something special. Generally
+ * these are node specific so let the upper
+ * level code figure it out.
+ */
+
+ if ((type == P1212_KEYTYPE_Immediate) ||
+ (type == P1212_KEYTYPE_Offset))
+ data->val = data->com.key.val;
+
+ data->leafdata = NULL;
+ TAILQ_INSERT_TAIL(&dir->data_root, data, data);
+
+ if (type == P1212_KEYTYPE_Leaf) {
+ leafoff = i + data->com.key.val;
+ data->leafdata =
+ p1212_parse_leaf(&t[leafoff]);
+ if (data->leafdata == NULL) {
+ DPRINTF(("Error parsing leaf\n"));
+ return 1;
+ }
+ }
+ }
+ if (type == P1212_KEYTYPE_Directory) {
+
+#ifdef M_ZERO
+ sdir = malloc(sizeof(struct p1212_dir),
+ M_DEVBUF, M_WAITOK|M_ZERO);
+#else
+ sdir = malloc(sizeof(struct p1212_dir),
+ M_DEVBUF, M_WAITOK);
+ bzero(sdir, sizeof(struct p1212_dir));
+#endif
+ sdir->parent = dir;
+ sdir->com.key.key_type = type;
+ sdir->com.key.key_value = val;
+ sdir->com.key.key =
+ P1212_DIRENT_GET_KEY((ntohl(t[i])));
+ sdir->com.key.val =
+ P1212_DIRENT_GET_VALUE((ntohl(t[i])));
+ com = &sdir->com;
+ sdir->match = sdir->com.key.val + i;
+ TAILQ_INIT(&sdir->data_root);
+ TAILQ_INIT(&sdir->subdir_root);
+ TAILQ_INSERT_TAIL(&dir->subdir_root, sdir,dir);
+ }
+ }
+
+ /* More validity checks. */
+
+ if (dir->parent == NULL) {
+ if (module_vendor_flag == 0) {
+ DPRINTF(("Missing module vendor entry in root "
+ "directory.\n"));
+ return 1;
+ }
+ if (node_capabilities_flag == 0) {
+ DPRINTF(("Missing node capabilities entry in "
+ "root directory.\n"));
+ return 1;
+ }
+ } else {
+ if ((unitdir_cnt > 1) && (unit_location_flag == 0)) {
+ DPRINTF(("Must have a unit location in each "
+ "unit directory when more than one unit "
+ "directory exists.\n"));
+ return 1;
+ }
+ }
+
+ /*
+ * Ok, done with this directory and it's sanity checked. Now
+ * loop through and either find an unparsed subdir or one
+ * farther back up the chain.
+ */
+
+ if (!TAILQ_EMPTY(&dir->subdir_root)) {
+ sdir = TAILQ_FIRST(&dir->subdir_root);
+ } else {
+ do {
+ sdir = TAILQ_NEXT(dir, dir);
+ if (sdir == NULL) {
+ dir = dir->parent;
+ }
+ } while ((sdir == NULL) && (dir != NULL));
+ }
+ if (dir) {
+ dir = sdir;
+ if (!dir->match) {
+ DPRINTF(("Invalid subdir..Has no offset\n"));
+ return 1;
+ }
+ offset = dir->match;
+ }
+ }
+ return 0;
+}
+
+static struct p1212_leafdata *
+p1212_parse_leaf(u_int32_t *t)
+{
+ u_int16_t crclen, crc, crc1, romcrc;
+ struct p1212_leafdata *leafdata;
+ int i;
+
+ crclen = P1212_DIRENT_GET_LEN((ntohl(t[0])));
+ romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0])));
+ crc = p1212_calc_crc(0, &t[1], crclen, 0);
+ crc1 = p1212_calc_crc(0,&t[1], crclen, 1);
+ if ((crc != romcrc) && (crc1 != romcrc)) {
+ DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: "
+ "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc,
+ (unsigned short)crc, (unsigned short)crc1));
+ return NULL;
+ }
+ t++;
+
+ /*
+ * Most of these are vendor specific so don't bother trying to map them
+ * out. Anything which needs them later on can extract them.
+ */
+
+ leafdata = malloc(sizeof(struct p1212_leafdata), M_DEVBUF, M_WAITOK);
+ leafdata->data = malloc((sizeof(u_int32_t) * crclen), M_DEVBUF,
+ M_WAITOK);
+ leafdata->len = crclen;
+ for (i = 0; i < crclen; i++)
+ leafdata->data[i] = ntohl(t[i]);
+ return leafdata;
+}
+
+static int
+p1212_parse_textdir(struct p1212_com *com, u_int32_t *addr)
+{
+ u_int32_t *t, entry, new;
+ u_int16_t crclen, crc, crc1, romcrc;
+ u_int8_t type, val;
+#ifdef __OpenBSD__
+ struct p1212_textdata **p;
+#endif
+
+ int i, size;
+
+ /*
+ * A bit more complicated. A directory for a text descriptor can
+ * contain text descriptor leaf nodes only.
+ */
+
+ com->text = NULL;
+ size = sizeof(struct p1212_text *);
+
+ crclen = P1212_DIRENT_GET_LEN((ntohl(t[0])));
+ romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0])));
+ crc = p1212_calc_crc(0, &t[1], crclen, 0);
+ crc1 = p1212_calc_crc(0,&t[1], crclen, 1);
+ if ((crc != romcrc) && (crc1 != romcrc)) {
+ DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: "
+ "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc,
+ (unsigned short)crc, (unsigned short)crc1));
+ return 1;
+ }
+ t++;
+ for (i = 0; i < crclen; i++) {
+ entry = ntohl(t[i]);
+
+ type = P1212_DIRENT_GET_KEYTYPE(entry);
+ val = P1212_DIRENT_GET_KEYVALUE(entry);
+ if ((type != P1212_KEYTYPE_Leaf) ||
+ (val != P1212_KEYVALUE_Textual_Descriptor)) {
+ DPRINTF(("Text descriptor directories can only "
+ "contain text descriptors. Type: %s, value: %s "
+ "isn't valid at offset 0x%0x\n",
+ p1212_keytype_strings[type],
+ p1212_keyvalue_strings[val], &t[i]-&addr[0]));
+ return 1;
+ }
+
+ new = P1212_DIRENT_GET_VALUE(entry);
+#ifdef __NetBSD__
+ com->text = realloc(com->text, size * (com->textcnt + 1),
+ M_DEVBUF, M_WAITOK);
+#else
+ p = malloc(size * (com->textcnt + 1), M_DEVBUF, M_WAITOK);
+ bcopy(com->text, p, sizeof(com->textcnt));
+ com->text = p;
+#endif
+ if ((com->text[i] = p1212_parse_text_desc(&t[i+new])) == NULL) {
+ DPRINTF(("Got an error parsing text descriptor.\n"));
+ if (com->textcnt == 0)
+ free(com->text, M_DEVBUF);
+ return 1;
+ }
+ com->textcnt++;
+ }
+ return 0;
+}
+
+static struct p1212_textdata *
+p1212_parse_text_desc(u_int32_t *addr)
+{
+ u_int32_t *t;
+ u_int16_t crclen, crc, crc1, romcrc;
+ struct p1212_textdata *text;
+ int size;
+
+ t = addr;
+
+ crclen = P1212_DIRENT_GET_LEN((ntohl(t[0])));
+ romcrc = P1212_DIRENT_GET_CRC((ntohl(t[0])));
+
+ if (crclen < P1212_TEXT_Min_Leaf_Length) {
+ DPRINTF(("Invalid ROM: text descriptor too short\n"));
+ return NULL;
+ }
+
+ crc = p1212_calc_crc(0, &t[1], crclen, 0);
+ if (crc != romcrc) {
+ crc1 = p1212_calc_crc(0, &t[1], crclen, 1);
+ if (crc1 != romcrc) {
+ DPRINTF(("Invalid ROM: CRC: 0x%04hx, Calculated CRC: "
+ "0x%04hx, CRC1: 0x%04hx\n", (unsigned short)romcrc,
+ (unsigned short)crc, (unsigned short)crc1));
+ return NULL;
+ }
+ }
+
+ t++;
+ text = malloc(sizeof(struct p1212_textdata), M_DEVBUF, M_WAITOK);
+ text->spec_type = P1212_TEXT_GET_Spec_Type((ntohl(t[0])));
+ text->spec_id = P1212_TEXT_GET_Spec_Id((ntohl(t[0])));
+ text->lang_id = ntohl(t[1]);
+
+ t++;
+ t++;
+ crclen -= 2;
+ size = (crclen * sizeof(u_int32_t));
+
+#ifdef M_ZERO
+ text->text = malloc(size + 1, M_DEVBUF, M_WAITOK|M_ZERO);
+#else
+ text->text = malloc(size + 1, M_DEVBUF, M_WAITOK);
+ bzero(text->text, size + 1);
+#endif
+
+ memcpy(text->text, &t[0], size);
+
+ return text;
+}
+
+struct p1212_key **
+p1212_find(struct p1212_dir *root, int type, int value, int flags)
+{
+ struct p1212_key **retkeys;
+ struct p1212_dir *dir, *sdir, *parent;
+ struct p1212_data *data;
+ int numkeys;
+#ifdef __OpenBSD__
+ struct p1212_key **p;
+#endif
+
+ numkeys = 0;
+ retkeys = NULL;
+
+ if ((type < P1212_KEYTYPE_Immediate) ||
+ (type > P1212_KEYTYPE_Directory)) {
+#ifdef DIAGNOSTIC
+ printf("p1212_find: invalid type - %d\n", type);
+#endif
+ return NULL;
+ }
+
+ if ((value < -1) ||
+ (value > (sizeof(p1212_keyvalue_strings) / sizeof(char *)))) {
+#ifdef DIAGNOSTIC
+ printf("p1212_find: invalid value - %d\n", value);
+#endif
+ return NULL;
+ }
+
+ if (flags & ~(P1212_FIND_SEARCHALL | P1212_FIND_RETURNALL)) {
+#ifdef DIAGNOSTIC
+ printf("p1212_find: invalid flags - %d\n", flags);
+#endif
+ return NULL;
+ }
+
+ /*
+ * Part of this is copied from p1212_walk to do depth first traversal
+ * without using recursion. Using the walk API would have made things
+ * more complicated in trying to build up the return struct otherwise.
+ */
+
+ dir = root;
+ sdir = NULL;
+
+ parent = root->parent;
+ root->parent = NULL;
+
+ while (dir) {
+ if (type == P1212_KEYTYPE_Directory) {
+ TAILQ_FOREACH(sdir, &dir->subdir_root, dir) {
+ if ((sdir->com.key.key_value == value) ||
+ (value == -1)) {
+ numkeys++;
+#ifdef __NetBSD__
+ retkeys = realloc(retkeys,
+ sizeof(struct p1212_key *) *
+ (numkeys + 1), M_WAITOK, M_DEVBUF);
+#else
+ p = malloc(sizeof(struct p1212_key *) *
+ (numkeys + 1), M_WAITOK, M_DEVBUF);
+ bcopy(retkeys, p,
+ sizeof(struct p1212_key *) *
+ numkeys);
+ retkeys = p;
+#endif
+ retkeys[numkeys - 1] = &sdir->com.key;
+ retkeys[numkeys] = NULL;
+ if ((flags & P1212_FIND_RETURNALL)
+ == 0) {
+ root->parent = parent;
+ return retkeys;
+ }
+ }
+ }
+ } else {
+ TAILQ_FOREACH(data, &dir->data_root, data) {
+ if (((data->com.key.key_type == type) &&
+ (data->com.key.key_value == value)) ||
+ ((data->com.key.key_type == type) &&
+ (value == -1))) {
+ numkeys++;
+#ifdef __NetBSD__
+ retkeys = realloc(retkeys,
+ sizeof(struct p1212_key *) *
+ (numkeys + 1), M_WAITOK, M_DEVBUF);
+#else
+ p = malloc(sizeof(struct p1212_key *) *
+ (numkeys + 1), M_WAITOK, M_DEVBUF);
+ bcopy(retkeys, p,
+ sizeof(struct p1212_key *) *
+ numkeys);
+ retkeys = p;
+#endif
+ retkeys[numkeys - 1] = &data->com.key;
+ retkeys[numkeys] = NULL;
+ if ((flags & P1212_FIND_RETURNALL)
+ == 0) {
+ root->parent = parent;
+ return retkeys;
+ }
+ }
+ }
+ }
+ if (flags & P1212_FIND_SEARCHALL) {
+ do {
+ sdir = TAILQ_NEXT(dir, dir);
+ if (sdir == NULL) {
+ dir = dir->parent;
+ }
+ } while ((sdir == NULL) && (dir != NULL));
+ dir = sdir;
+ } else
+ dir = NULL;
+ }
+ root->parent = parent;
+ return retkeys;
+}
+
+void
+p1212_walk(struct p1212_dir *root, void *arg,
+ void (*func)(struct p1212_key *, void *))
+{
+ struct p1212_data *data;
+ struct p1212_dir *sdir, *dir, *parent;
+
+ dir = root;
+ sdir = NULL;
+
+ if (func == NULL) {
+#ifdef DIAGNOSTIC
+ printf("p1212_walk: Passed in NULL function\n");
+#endif
+ return;
+ }
+ if (root == NULL) {
+#ifdef DIAGNOSTIC
+ printf("p1212_walk: Called with NULL root\n");
+#endif
+ return;
+ }
+
+ /* Allow walking from any point. Just mark the starting point. */
+ parent = root->parent;
+ root->parent = NULL;
+
+ /*
+ * Depth first traversal that doesn't use recursion.
+ *
+ * Call the function first for the directory node and then loop through
+ * all the data nodes and call the function for them.
+ *
+ * Finally, figure out the next possible directory node if one is
+ * available or bail out.
+ */
+
+ while (dir) {
+ func((struct p1212_key *) dir, arg);
+ TAILQ_FOREACH(data, &dir->data_root, data)
+ func((struct p1212_key *) data, arg);
+ if (!TAILQ_EMPTY(&dir->subdir_root)) {
+ sdir = TAILQ_FIRST(&dir->subdir_root);
+ } else {
+ do {
+ sdir = TAILQ_NEXT(dir, dir);
+ if (sdir == NULL) {
+ dir = dir->parent;
+ }
+ } while ((sdir == NULL) && dir);
+ }
+ dir = sdir;
+ }
+
+ root->parent = parent;
+}
+
+void
+p1212_print(struct p1212_dir *dir)
+{
+ int indent;
+
+ indent = 0;
+
+ p1212_walk(dir, &indent, p1212_print_node);
+ printf("\n");
+}
+
+static void
+p1212_print_node(struct p1212_key *key, void *arg)
+{
+
+ struct p1212_data *data;
+ struct p1212_dir *sdir, *dir;
+ int i, j, *indent;
+
+ indent = arg;
+
+ if (key->key_type == P1212_KEYTYPE_Directory) {
+ dir = (struct p1212_dir *) key;
+ data = NULL;
+ } else {
+ data = (struct p1212_data *) key;
+ dir = NULL;
+ }
+
+ /* Recompute the indent level on each directory. */
+ if (dir) {
+ *indent = 0;
+ sdir = dir->parent;
+ while (sdir != NULL) {
+ (*indent)++;
+ sdir = sdir->parent;
+ }
+ }
+
+ if (dir && dir->parent)
+ printf("\n");
+
+ /* Set the indent string up. 4 spaces per level. */
+ for (i = 0; i < (*indent * 4); i++)
+ printf(" ");
+
+ if (dir) {
+ printf("Directory: ");
+ if (dir->print)
+ dir->print(dir);
+ else {
+ if (key->key_value >=
+ (sizeof(p1212_keyvalue_strings) / sizeof(char *)))
+ printf("Unknown type 0x%04hx\n",
+ (unsigned short)key->key_value);
+ else
+ printf("%s\n",
+ p1212_keyvalue_strings[key->key_value]);
+ }
+ if (dir->com.textcnt) {
+ for (i = 0; i < dir->com.textcnt; i++) {
+ for (j = 0; j < (*indent * 4); j++)
+ printf(" ");
+ printf("Text descriptor: %s\n",
+ dir->com.text[i]->text);
+ }
+ }
+ printf("\n");
+ } else {
+ if (data->print)
+ data->print(data);
+ else {
+ if (key->key_value >=
+ (sizeof(p1212_keyvalue_strings) / sizeof(char *)))
+ printf("Unknown type 0x%04hx: ",
+ (unsigned short)key->key_value);
+ else
+ printf("%s: ",
+ p1212_keyvalue_strings[key->key_value]);
+
+ printf("0x%08x\n", key->val);
+#ifdef DIAGNOSTIC
+ if ((data->com.key.key_type == P1212_KEYTYPE_Leaf) &&
+ (data->leafdata == NULL))
+ panic("Invalid data node in configrom tree");
+#endif
+
+ if (data->leafdata) {
+ for (i = 0; i < data->leafdata->len; i++) {
+ for (j = 0; j < (*indent * 4); j++)
+ printf(" ");
+ printf ("Leaf data: 0x%08x\n",
+ data->leafdata->data[i]);
+ }
+ }
+ if (data->com.textcnt)
+ for (i = 0; i < data->com.textcnt; i++) {
+ for (j = 0; j < (*indent * 4); j++)
+ printf(" ");
+ printf("Text descriptor: %s\n",
+ data->com.text[i]->text);
+ }
+
+ }
+ }
+}
+
+
+void
+p1212_free(struct p1212_rom *rom)
+{
+ struct p1212_dir *sdir, *dir;
+ struct p1212_data *data;
+ int i;
+
+ dir = rom->root;
+
+ /* Avoid recursing. Find the bottom most node and work back. */
+ while (dir) {
+ if (!TAILQ_EMPTY(&dir->subdir_root)) {
+ sdir = TAILQ_FIRST(&dir->subdir_root);
+ if (TAILQ_EMPTY(&sdir->subdir_root)) {
+ TAILQ_REMOVE(&dir->subdir_root, sdir, dir);
+ dir = sdir;
+ }
+ else {
+ dir = sdir;
+ continue;
+ }
+ } else {
+ if (dir->parent)
+ TAILQ_REMOVE(&dir->parent->subdir_root, dir,
+ dir);
+ }
+
+ while ((data = TAILQ_FIRST(&dir->data_root))) {
+ if (data->leafdata) {
+ if (data->leafdata->data)
+ free(data->leafdata->data, M_DEVBUF);
+ free(data->leafdata, M_DEVBUF);
+ }
+ TAILQ_REMOVE(&dir->data_root, data, data);
+ if (data->com.textcnt) {
+ for (i = 0; i < data->com.textcnt; i++)
+ free(data->com.text[i], M_DEVBUF);
+ free(data->com.text, M_DEVBUF);
+ }
+ free(data, M_DEVBUF);
+ }
+ sdir = dir;
+ if (dir->parent)
+ dir = dir->parent;
+ else
+ dir = NULL;
+ if (sdir->com.textcnt) {
+ for (i = 0; i < sdir->com.textcnt; i++)
+ free(sdir->com.text[i], M_DEVBUF);
+ free(sdir->com.text, M_DEVBUF);
+ }
+ free(sdir, M_DEVBUF);
+ }
+ if (rom->len)
+ free(rom->data, M_DEVBUF);
+ free(rom, M_DEVBUF);
+}
+
+/*
+ * A fairly well published reference implementation of the CRC routine had
+ * a typo in it and some devices may be using it rather than the correct one
+ * in calculating their ROM CRC's. To compensate an interface for generating
+ * either is provided.
+ *
+ * len is the number of u_int32_t entries, not bytes.
+ */
+
+static u_int16_t
+p1212_calc_crc(u_int32_t crc, u_int32_t *data, int len, int broke)
+{
+ int shift;
+ u_int32_t sum;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ for (shift = 28; shift > 0; shift -= 4) {
+ sum = ((crc >> 12) ^ (ntohl(data[i]) >> shift)) &
+ 0x0000000f;
+ crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
+ }
+
+
+ /* The broken implementation doesn't do the last shift. */
+ if (!broke) {
+ sum = ((crc >> 12) ^ ntohl(data[i])) & 0x0000000f;
+ crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
+ }
+ }
+ return (u_int16_t)crc;
+}
+
+/*
+ * This is almost identical to the standard autoconf *match idea except it
+ * can match and attach multiple children in one pass.
+ */
+
+struct device **
+p1212_match_units(struct device *sc, struct p1212_dir *dir,
+ int (*print)(void *, const char *))
+{
+ struct p1212_dir **udirs;
+ struct device **devret, *dev;
+ int numdev;
+#ifdef __OpenBSD__
+ struct device **p;
+#endif
+
+ /*
+ * Setup typical return val. Always allocate one extra pointer for a
+ * NULL guard end pointer.
+ */
+
+ numdev = 0;
+ devret = malloc(sizeof(struct device *) * 2, M_DEVBUF, M_WAITOK);
+ devret[1] = NULL;
+
+ udirs = (struct p1212_dir **)p1212_find(dir, P1212_KEYTYPE_Directory,
+ P1212_KEYVALUE_Unit_Directory,
+ P1212_FIND_SEARCHALL|P1212_FIND_RETURNALL);
+
+ if (udirs) {
+ do {
+ dev = config_found_sm(sc, udirs, print, NULL);
+ if (dev && numdev) {
+#ifdef __NetBSD__
+ devret = realloc(devret,
+ sizeof(struct device *) *
+ (numdev + 2), M_DEVBUF, M_WAITOK);
+#else
+ p = malloc(sizeof(struct device *) *
+ (numdev + 2), M_DEVBUF, M_WAITOK);
+ bcopy(devret, p,
+ sizeof(struct device *) * (numdev + 1));
+ devret = p;
+#endif
+ devret[numdev++] = dev;
+ devret[numdev] = NULL;
+ } else if (dev) {
+ devret[0] = dev;
+ numdev++;
+ }
+ udirs++;
+ } while (*udirs);
+ }
+ if (numdev == 0) {
+ free(devret, M_DEVBUF);
+ return NULL;
+ }
+ return devret;
+}
+
+/*
+ * Make these their own functions as they have slightly complicated rules.
+ *
+ * For example:
+ *
+ * Under normal circumstances only the 2 extent types can be offset
+ * types. However some spec's which use p1212 like SBP2 for
+ * firewire/1394 will define a dependent info type as an offset value.
+ * Allow the upper level code to flag this and pass it down during
+ * parsing. The same thing applies to immediate types.
+ */
+
+static int
+p1212_validate_offset(u_int16_t val, u_int32_t mask)
+{
+ if ((val == P1212_KEYVALUE_Node_Units_Extent) ||
+ (val == P1212_KEYVALUE_Node_Memory_Extent) ||
+ ((mask & P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE) &&
+ ((val == P1212_KEYVALUE_Unit_Dependent_Info) ||
+ (val == P1212_KEYVALUE_Node_Dependent_Info) ||
+ (val == P1212_KEYVALUE_Module_Dependent_Info))))
+ return 0;
+ return 1;
+}
+
+static int
+p1212_validate_immed(u_int16_t val, u_int32_t mask)
+{
+ switch (val) {
+ case P1212_KEYVALUE_Textual_Descriptor:
+ case P1212_KEYVALUE_Bus_Dependent_Info:
+ case P1212_KEYVALUE_Module_Dependent_Info:
+ case P1212_KEYVALUE_Node_Unique_Id:
+ case P1212_KEYVALUE_Node_Dependent_Info:
+ case P1212_KEYVALUE_Unit_Directory:
+ case P1212_KEYVALUE_Unit_Dependent_Info:
+ case P1212_KEYVALUE_Unit_Location:
+ if ((mask & P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE) &&
+ ((val == P1212_KEYVALUE_Module_Dependent_Info) ||
+ (val == P1212_KEYVALUE_Node_Dependent_Info) ||
+ (val == P1212_KEYVALUE_Unit_Dependent_Info)))
+ break;
+ return 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int
+p1212_validate_leaf(u_int16_t val, u_int32_t mask)
+{
+ switch(val) {
+ case P1212_KEYVALUE_Textual_Descriptor:
+ case P1212_KEYVALUE_Bus_Dependent_Info:
+ case P1212_KEYVALUE_Module_Dependent_Info:
+ case P1212_KEYVALUE_Node_Unique_Id:
+ case P1212_KEYVALUE_Node_Dependent_Info:
+ case P1212_KEYVALUE_Unit_Dependent_Info:
+ case P1212_KEYVALUE_Unit_Location:
+ break;
+ default:
+ return 1;
+ break;
+ }
+ return 0;
+}
+
+static int
+p1212_validate_dir(u_int16_t val, u_int32_t mask)
+{
+ switch(val) {
+ case P1212_KEYVALUE_Textual_Descriptor:
+ case P1212_KEYVALUE_Bus_Dependent_Info:
+ case P1212_KEYVALUE_Module_Dependent_Info:
+ case P1212_KEYVALUE_Node_Dependent_Info:
+ case P1212_KEYVALUE_Unit_Directory:
+ case P1212_KEYVALUE_Unit_Dependent_Info:
+ break;
+ default:
+ if ((mask & P1212_ALLOW_VENDOR_DIRECTORY_TYPE) &&
+ (val == P1212_KEYVALUE_Module_Vendor_Id))
+ break;
+ return 1;
+ break;
+ }
+ return 0;
+}
diff --git a/sys/dev/std/ieee1212reg.h b/sys/dev/std/ieee1212reg.h
new file mode 100644
index 00000000000..c60f22134c3
--- /dev/null
+++ b/sys/dev/std/ieee1212reg.h
@@ -0,0 +1,257 @@
+/* $OpenBSD: ieee1212reg.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: ieee1212reg.h,v 1.7 2002/04/02 10:10:54 jmc Exp $ */
+
+/*-
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_STD_IEEE1212REG_H_
+#define _DEV_STD_IEEE1212REG_H_
+
+/* This file contains definitions from ISO/IEC 1312 or ANSI/IEEE Std 1212
+ * Informaton techonology
+ * Microprocessor systes
+ * Control and Status Registers (CSR)
+ * Architecture for microcomputer buses
+ * First edition 1994-10-05
+ */
+
+/* Lock transaction codes (Table 5)
+ */
+#define P1212_XTCODE_RESERVED_0 0
+#define P1212_XTCODE_MASK_SWAP 1
+#define P1212_XTCODE_COMPARE_SWAP 2
+#define P1212_XTCODE_FETCH_ADD 3
+#define P1212_XTCODE_LITTLE_ADD 4
+#define P1212_XTCODE_BOUNDED_ADD 5
+#define P1212_XTCODE_WRAP_ADD 6
+#define P1212_XTCODE_VENDOR_DEPENDENT 7
+
+/* Header: Rom Format (1 Quadlet)
+ * Bus Info Block: <info-length> Quadlets
+ * Root Directory
+ * Unit Directory
+ * Root & Unit Leaves
+ * Vendor Dependent Information
+ */
+/* ROM Formats
+ * 0x00-0x000000 Initializing
+ * 0x01-0xzzyyxx Minimal (zz-yy-xx is an OUI)
+ * 0xii-0xcc-0xllll General (ii is info-length,
+ * cc is crc-length, llll is length)
+ */
+
+#define P1212_ROMFMT_INIT 0x00
+#define P1212_ROMFMT_MINIMAL 0x01
+
+/* uint32_t P1212_ROMFMT_MK_INIT(void)
+ */
+#define P1212_ROMFMT_MK_INIT() 0x00000000
+
+/* uint32_t P1212_ROMFMT_MK_MINIMAL(const uint8_t *oui);
+ */
+#define P1212_ROMFMT_MK_MINIMAL(oui) \
+ ((P1212_ROMFMT_MINIMAL << 24) \
+ | ((oui[0]) << 16) \
+ | ((oui[1]) << 8) \
+ | ((oui[2]) << 0))
+
+/* uint32_t P1212_ROMFMT_MK_GENERAL(size_t info_len, size_t crc_len,
+ * uint16_t crc);
+ */
+#define P1212_ROMFMT_MK_GENERAL(info_len, crc_len, crc_value) \
+ (((info_len) << 24) \
+ | ((crc_len) << 16) \
+ | ((crc_value) << 0))
+
+/* unsigned P1212_ROMFMT_GET_FMT(uint32_t);
+ */
+#define P1212_ROMFMT_GET_FMT(quadlet) (((quadlet) >> 24) & 0xff)
+
+/* void P1212_ROMFMT_GET_OUI(uint32_t quadlet, uint8_t *oui);
+ */
+#define P1212_ROMTFMT_GET_OUI(quadlet, oui) do { \
+ (oui)[0] = ((quadlet) >> 16) & 0xff; \
+ (oui)[1] = ((quadlet) >> 8) & 0xff; \
+ (oui)[2] = ((quadlet) >> 0) & 0xff; \
+ } while (0)
+
+/* size_t P1212_ROMGET_GET_INFOLEN(uint32_t quadlet);
+ */
+#define P1212_ROMFMT_GET_INFOLEN(quadlet) (((quadlet) >> 24) & 0xff)
+
+/* size_t P1212_ROMGET_GET_CRCLEN(uint32_t quadlet);
+ */
+#define P1212_ROMFMT_GET_CRCLEN(quadlet) (((quadlet) >> 16) & 0xff)
+
+/* size_t P1212_ROMGET_GET_CRC(uint32_t quadlet);
+ */
+#define P1212_ROMFMT_GET_CRC(quadlet) ((uint16_t)(quadlet))
+
+/* uint8_t P1212_DIRENT_GET_KEY(uint32_t quadlet);
+ */
+#define P1212_DIRENT_GET_KEY(quadlet) (((quadlet) >> 24) & 0xff)
+
+/* unsigned int P1212_DIRENT_GET_KEYTYPE(uint32_t quadlet);
+ */
+#define P1212_DIRENT_GET_KEYTYPE(quadlet) (((quadlet) >> 30) & 0x03)
+
+/* unsigned int P1212_DIRENT_GET_KEYVALUE(uint32_t quadlet);
+ */
+#define P1212_DIRENT_GET_KEYVALUE(quadlet) (((quadlet) >> 24) & 0x3f)
+
+/* unsigned int P1212_DIRENT_GET_OFFSET(uint32_t quadlet);
+ */
+#define P1212_DIRENT_GET_OFFSET(quadlet) ((quadlet) & 0xffffff)
+
+/* unsigned int P1212_DIRENT_GET_VALUE(uint32_t quadlet);
+ */
+#define P1212_DIRENT_GET_VALUE(quadlet) ((quadlet) & 0xffffff)
+
+/* u_int16_t P1212_DIRENT_GET_LEN(quadlet);
+ */
+#define P1212_DIRENT_GET_LEN(quadlet) (((quadlet) >> 16) & 0xffff)
+
+/* u_int16_t P1212_DIRENT_GET_CRC(quadlet);
+ */
+#define P1212_DIRENT_GET_CRC(quadlet) ((uint16_t)(quadlet))
+
+/* Key Types are stored in bits 31-30 of a directory entry.
+ */
+
+#define P1212_KEYTYPE_Immediate 0x00
+#define P1212_KEYTYPE_Offset 0x01
+#define P1212_KEYTYPE_Leaf 0x02
+#define P1212_KEYTYPE_Directory 0x03
+
+/* Key Values are stored in bits 29-24 of a directory entry.
+ */
+#define P1212_KEYVALUE_Textual_Descriptor 0x01 /* leaf | directory */
+#define P1212_KEYVALUE_Bus_Dependent_Info 0x02 /* leaf | directory */
+#define P1212_KEYVALUE_Module_Vendor_Id 0x03 /* immediate */
+#define P1212_KEYVALUE_Module_Hw_Version 0x04 /* immediate */
+#define P1212_KEYVALUE_Module_Spec_Id 0x05 /* immediate */
+#define P1212_KEYVALUE_Module_Sw_Version 0x06 /* immediate */
+#define P1212_KEYVALUE_Module_Dependent_Info 0x07 /* leaf | directory */
+#define P1212_KEYVALUE_Node_Vendor_Id 0x08 /* immediate */
+#define P1212_KEYVALUE_Node_Hw_Version 0x09 /* immediate */
+#define P1212_KEYVALUE_Node_Spec_Id 0x0a /* immediate */
+#define P1212_KEYVALUE_Node_Sw_Version 0x0b /* immediate */
+#define P1212_KEYVALUE_Node_Capabilities 0x0c /* immediate */
+#define P1212_KEYVALUE_Node_Unique_Id 0x0d /* leaf */
+#define P1212_KEYVALUE_Node_Units_Extent 0x0e /* immediate | offset */
+#define P1212_KEYVALUE_Node_Memory_Extent 0x0f /* immediate | offset */
+#define P1212_KEYVALUE_Node_Dependent_Info 0x10 /* leaf | directory */
+#define P1212_KEYVALUE_Unit_Directory 0x11 /* directory */
+#define P1212_KEYVALUE_Unit_Spec_Id 0x12 /* immediate */
+#define P1212_KEYVALUE_Unit_Sw_Version 0x13 /* immediate */
+#define P1212_KEYVALUE_Unit_Dependent_Info 0x14 /* leaf | directory */
+#define P1212_KEYVALUE_Unit_Location 0x15 /* leaf */
+#define P1212_KEYVALUE_Unit_Poll_Mask 0x16 /* immediate */
+
+/*
+ * Items not in original p1212 standard but are in proposed drafts and in use
+ * already in some roms.
+ */
+
+#define P1212_KEYVALUE_Model 0x17 /* immediate */
+#define P1212_KEYVALUR_Instance_Directory 0x18 /* directory */
+#define P1212_KEYVALUE_Keyword 0x19 /* leaf */
+#define P1212_KEYVALUE_Feature_Directory 0x1A /* directory */
+#define P1212_KEYVALUE_Extended_ROM 0x1B /* leaf */
+#define P1212_KEYVALUE_Extended_Key_Spec_Id 0x1C /* immediate */
+#define P1212_KEYVALUE_Extended_Key 0x1D /* immediate */
+#define P1212_KEYVALUE_Extended_Data 0x1E /* imm|leaf|dir|offset */
+#define P1212_KEYVALUE_Modifiable_Descriptor 0x1F /* leaf */
+#define P1212_KEYVALUE_Directory_Id 0x20 /* immediate */
+
+#define P1212_KEYTYPE_STRINGS { "Immediate", "Offset", "Leaf", "Directory" }
+
+#define P1212_KEYVALUE_STRINGS { "Root-Directory", \
+ "Textual-Descriptor", "Bus-Dependent-Info", "Module-Vendor-Id", \
+ "Module-Hw-Version", "Module-Spec-Id", "Module-Sw-Version", \
+ "Module-Dependent-Info", "Node-Vendor-Id", "Node-Hw_Version", \
+ "Node-Spec-Id", "Node-Sw-Verson", "Node-Capabilities", \
+ "Node-Unique-Id", "Node-Units-Extent", "Node-Memory-Extent", \
+ "Node-Dependent-Info", "Unit-Directory", "Unit-Spec-Id", \
+ "Unit-Sw-Version", "Unit-Dependent-Info", "Unit-Location", \
+ "Unit-Poll-Mask", "Model", "Instance-Directory", "Keyword", \
+ "Feature-Directory", "Extended-ROM", "Extended-Key-Spec-Id", \
+ "Extended-Key", "Extended-Data", "Modifiable-Descriptor", \
+ "Directory-Id" }
+
+/* Leaf nodes look like:
+ *
+ * [0] 0xnnnn-0xcccc length, crc16
+ * [n]
+ *
+ * Text leaves look like:
+ * [0] 0xnnnn-0xcccc length, crc16
+ * [1] 0xtt-0xiiiiii specifier type, specifier id
+ * [2] 0xllllllll language id
+ */
+
+#define P1212_TEXT_Min_Leaf_Length 0x3
+#define P1212_TEXT_GET_Spec_Type(quadlet) (((quadlet) & 0xff000000) >> 24)
+#define P1212_TEXT_GET_Spec_Id(quadlet) ((quadlet) & 0xffffff)
+
+/*
+ * Directory nodes look like:
+ * [0] 0xnnnn-0xcccc length, crc16
+ * [1] direntry
+ * [n] direntry
+ */
+
+/* Some definitions for the p1212_find routines. */
+
+#define P1212_FIND_SEARCHALL 0x1
+#define P1212_FIND_RETURNALL 0x2
+
+/* Mask definitions for overriding the p1212 standard checks. */
+
+/*
+ * XXX: Note that some of these go away if full p1212r support is done as
+ * a lot of the restrictions were lifted there in what can go where.
+ */
+
+
+/* Normally dependent info can only be leaf or directory. Allow offsets also */
+#define P1212_ALLOW_DEPENDENT_INFO_OFFSET_TYPE 0x1
+
+/* Same thing applies for immediate types. */
+#define P1212_ALLOW_DEPENDENT_INFO_IMMED_TYPE 0x2
+#define P1212_ALLOW_VENDOR_DIRECTORY_TYPE 0x4
+
+#endif /* _DEV_STD_IEEE1212REG_H_ */
diff --git a/sys/dev/std/ieee1212var.h b/sys/dev/std/ieee1212var.h
new file mode 100644
index 00000000000..7bb34364ebb
--- /dev/null
+++ b/sys/dev/std/ieee1212var.h
@@ -0,0 +1,108 @@
+/* $OpenBSD: ieee1212var.h,v 1.1 2002/06/25 17:11:49 itojun Exp $ */
+/* $NetBSD: ieee1212var.h,v 1.1 2002/02/27 04:58:51 jmc Exp $ */
+
+/*
+ * Copyright (c) 2000 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by James Chacon.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_STD_IEEE1212VAR_H
+#define _DEV_STD_IEEE1212VAR_H
+
+struct p1212_dir;
+
+struct p1212_key {
+ u_int8_t key_type;
+ u_int8_t key_value;
+ u_int8_t key;
+ u_int32_t val;
+};
+
+struct p1212_leafdata {
+ u_int32_t len;
+ u_int32_t *data;
+};
+
+struct p1212_textdata {
+ u_int8_t spec_type;
+ u_int32_t spec_id;
+ u_int32_t lang_id;
+ char *text;
+};
+
+struct p1212_com {
+ struct p1212_key key;
+ u_int32_t textcnt;
+ struct p1212_textdata **text;
+};
+
+struct p1212_data {
+ struct p1212_com com;
+
+ u_int32_t val;
+ struct p1212_leafdata *leafdata;
+ void (*print)(struct p1212_data *);
+ TAILQ_ENTRY(p1212_data) data;
+};
+
+
+struct p1212_dir {
+ struct p1212_com com;
+
+ int match;
+ void (*print)(struct p1212_dir *);
+ struct p1212_dir *parent;
+ TAILQ_HEAD(, p1212_data) data_root;
+ TAILQ_HEAD(, p1212_dir) subdir_root;
+ TAILQ_ENTRY(p1212_dir) dir;
+};
+
+struct p1212_rom {
+ char name[5];
+ u_int32_t len;
+ u_int32_t *data;
+ struct p1212_dir *root;
+};
+
+int p1212_iscomplete(u_int32_t *, u_int32_t *);
+struct p1212_rom *p1212_parse (u_int32_t *, u_int32_t, u_int32_t);
+void p1212_walk(struct p1212_dir *, void *,
+ void (*)(struct p1212_key *, void *));
+struct p1212_key **p1212_find(struct p1212_dir *, int, int, int);
+void p1212_print(struct p1212_dir *);
+void p1212_free(struct p1212_rom *);
+struct device **p1212_match_units(struct device *, struct p1212_dir *,
+ int (*)(void *, const char *));
+
+#endif /* _DEV_STD_IEEE1212VAR_H */
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index 0985b26bd7a..cc957594ec7 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: malloc.h,v 1.58 2002/06/21 12:14:21 itojun Exp $ */
+/* $OpenBSD: malloc.h,v 1.59 2002/06/25 17:11:49 itojun Exp $ */
/* $NetBSD: malloc.h,v 1.39 1998/07/12 19:52:01 augustss Exp $ */
/*
@@ -155,7 +155,9 @@
/* 109 - free */
#define M_CREDENTIALS 110 /* IPsec-related credentials and ID info */
#define M_PACKET_TAGS 111 /* Packet-attached information */
-/* 112-122 - free */
+#define M_1394CTL 112 /* IEEE 1394 control structures */
+#define M_1394DATA 113 /* IEEE 1394 data buffers */
+/* 114-122 - free */
/* KAME IPv6 */
#define M_IP6OPT 123 /* IPv6 options */
@@ -270,9 +272,10 @@
NULL, \
"IPsec creds", /* 110 M_CREDENTIALS */ \
"packet tags", /* 111 M_PACKET_TAGS */ \
+ "1394ctl", /* 112 M_1394CTL */ \
+ "1394data", /* 113 M_1394DATA */ \
NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, NULL, NULL, NULL, \
- NULL, \
+ NULL, NULL, NULL, NULL, \
"ip6_options", /* 123 M_IP6OPT */ \
"NDP", /* 124 M_IP6NDP */ \
"ip6rr", /* 125 M_IP6RR */ \