diff options
author | 2002-06-25 17:11:49 +0000 | |
---|---|---|
committer | 2002-06-25 17:11:49 +0000 | |
commit | 4360dd477e56bac8d9ea96dc25ccbdf9e094d0cd (patch) | |
tree | fb8726dc6b2158ae387a5b68306b941b9b6858a9 | |
parent | add ARP hardware type for IEEE1394 (diff) | |
download | wireguard-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/GENERIC | 8 | ||||
-rw-r--r-- | sys/arch/macppc/conf/files.macppc | 7 | ||||
-rw-r--r-- | sys/dev/ieee1394/IMPLEMENTATION | 58 | ||||
-rw-r--r-- | sys/dev/ieee1394/TODO | 41 | ||||
-rw-r--r-- | sys/dev/ieee1394/files.ieee1394 | 16 | ||||
-rw-r--r-- | sys/dev/ieee1394/fwnode.c | 339 | ||||
-rw-r--r-- | sys/dev/ieee1394/fwnodereg.h | 59 | ||||
-rw-r--r-- | sys/dev/ieee1394/fwnodevar.h | 58 | ||||
-rw-r--r-- | sys/dev/ieee1394/fwohci.c | 3944 | ||||
-rw-r--r-- | sys/dev/ieee1394/fwohcireg.h | 552 | ||||
-rw-r--r-- | sys/dev/ieee1394/fwohcivar.h | 241 | ||||
-rw-r--r-- | sys/dev/ieee1394/ieee1394reg.h | 241 | ||||
-rw-r--r-- | sys/dev/ieee1394/ieee1394var.h | 118 | ||||
-rw-r--r-- | sys/dev/pci/files.pci | 9 | ||||
-rw-r--r-- | sys/dev/pci/fwlynx_pci.c | 138 | ||||
-rw-r--r-- | sys/dev/pci/fwohci_pci.c | 175 | ||||
-rw-r--r-- | sys/dev/std/ieee1212.c | 1427 | ||||
-rw-r--r-- | sys/dev/std/ieee1212reg.h | 257 | ||||
-rw-r--r-- | sys/dev/std/ieee1212var.h | 108 | ||||
-rw-r--r-- | sys/sys/malloc.h | 11 |
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 */ \ |