summaryrefslogtreecommitdiffstats
path: root/usr.sbin/fwcontrol
diff options
context:
space:
mode:
authorsimokawa <simokawa@FreeBSD.org>2002-12-30 10:13:16 +0000
committersimokawa <simokawa@FreeBSD.org>2002-12-30 10:13:16 +0000
commit41352fb7b20f1a4088848598da8af0e45cd4fd40 (patch)
treefbddb50decc696b20d3af0ca6fa51726a9c3e842 /usr.sbin/fwcontrol
parent88d4214ecfac5aafdd4868ef4e043a637346e459 (diff)
downloadFreeBSD-src-41352fb7b20f1a4088848598da8af0e45cd4fd40.zip
FreeBSD-src-41352fb7b20f1a4088848598da8af0e45cd4fd40.tar.gz
Import FireWire userland utility.
Diffstat (limited to 'usr.sbin/fwcontrol')
-rw-r--r--usr.sbin/fwcontrol/Makefile7
-rw-r--r--usr.sbin/fwcontrol/fwcontrol.887
-rw-r--r--usr.sbin/fwcontrol/fwcontrol.c410
-rw-r--r--usr.sbin/fwcontrol/fwcrom.c254
4 files changed, 758 insertions, 0 deletions
diff --git a/usr.sbin/fwcontrol/Makefile b/usr.sbin/fwcontrol/Makefile
new file mode 100644
index 0000000..725ee18
--- /dev/null
+++ b/usr.sbin/fwcontrol/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+PROG= fwcontrol
+SRCS= fwcontrol.c fwcrom.c
+MAN= fwcontrol.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/fwcontrol/fwcontrol.8 b/usr.sbin/fwcontrol/fwcontrol.8
new file mode 100644
index 0000000..809389c
--- /dev/null
+++ b/usr.sbin/fwcontrol/fwcontrol.8
@@ -0,0 +1,87 @@
+.\" Copyright (c) 2002 Hidetoshi Shimokawa
+.\" All rights reserved.
+.\"
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+.\"
+.\" $FreeBSD$
+.\"
+.\"
+.Dd December 30, 2002
+.Dt FWCONTROL 8
+.Os
+.Sh NAME
+.Nm fwcontrol
+.Nd FireWire control utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl rts
+.Op Fl c Ar node
+.Op Fl d Ar node
+.Op Fl l Ar file
+.Op Fl g Ar gap_count
+.Op Fl b Ar pri_req
+.Sh DESCRIPTION
+The
+.Nm
+utility is designed to provide a way for users to access and control the
+.Fx
+FireWire subsystem.
+.Pp
+.Bl -tag -width indent
+.It Fl r
+Initiate bus reset.
+.It Fl t
+Show the topology map.
+.It Fl s
+Show the speed map.
+.It Fl c Ar node
+Show the configuration ROM on the node.
+.It Fl d Ar node
+Hex dump of the configuration ROM.
+.It Fl l Ar file
+Load hex dump file of the configuration ROM and parse it.
+.It Fl g Ar gap_count
+Broadcast gap_count by phy_config packet.
+.It Fl i Ar pri_req
+Set PRIORITY_BUDGET register on all supported nodes.
+.El
+
+.Sh FILES
+.Bl -tag -width indent
+.It Pa /dev/fw0
+.El
+.Sh SEE ALSO
+.Xr firewire 4 ,
+.Xr fwohci 4 ,
+.Xr sbp 4 ,
+.Xr fwe 4
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 5.0 .
+.Pp
+.Sh AUTHORS
+.An Hidetoshi Shimokawa Aq simokawa@FreeBSD.org
+.Sh BUGS
+This utility is still under development and provided for debug purpose.
+.Pp
diff --git a/usr.sbin/fwcontrol/fwcontrol.c b/usr.sbin/fwcontrol/fwcontrol.c
new file mode 100644
index 0000000..248188b
--- /dev/null
+++ b/usr.sbin/fwcontrol/fwcontrol.c
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2002
+ * Hidetoshi Shimokawa. All rights reserved.
+ *
+ * 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 Hidetoshi Shimokawa.
+ *
+ * 4. Neither the name of the author 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 REGENTS 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 REGENTS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/iec13213.h>
+
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void
+usage(void)
+{
+ printf("fwcontrol [-g gap_count] [-b pri_req] [-c node]"
+ " [-r] [-t] [-s] [-d node] [-l file]\n");
+ printf("\t-g: broadcast gap_count by phy_config packet\n");
+ printf("\t-b: set PRIORITY_BUDGET register on all supported nodes\n");
+ printf("\t-c: read configuration ROM\n");
+ printf("\t-r: bus reset\n");
+ printf("\t-t: read topology map\n");
+ printf("\t-s: read speed map\n");
+ printf("\t-d: hex dump of configuration ROM\n");
+ printf("\t-l: load and parse hex dump file of configuration ROM\n");
+ exit(0);
+}
+
+void
+get_num_of_dev(int fd, struct fw_devlstreq *data)
+{
+ data->n = 64;
+ if( ioctl(fd, FW_GDEVLST, data) < 0) {
+ err(1, "ioctl");
+ }
+}
+
+void
+list_dev(int fd)
+{
+ struct fw_devlstreq data;
+ int i;
+
+ get_num_of_dev(fd, &data);
+ printf("%d devices\n", data.n);
+ for (i = 0; i < data.n; i++) {
+ printf("%d node %d eui:%08x%08x status:%d\n",
+ i,
+ data.dst[i],
+ data.eui[i].hi,
+ data.eui[i].lo,
+ data.status[i]
+ );
+ }
+}
+
+u_int32_t
+read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int32_t data)
+{
+ struct fw_asyreq *asyreq;
+ u_int32_t *qld, res;
+
+ asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
+ asyreq->req.len = 16;
+ asyreq->req.type = FWASREQEUI;
+ asyreq->req.dst.eui = eui;
+#if 0
+ asyreq->pkt.mode.rreqq.dst = htons(FWLOCALBUS | node);
+#endif
+ asyreq->pkt.mode.rreqq.tlrt = 0;
+ if (read)
+ asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ;
+ else
+ asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
+
+ asyreq->pkt.mode.rreqq.dest_hi = htons(0xffff);
+ asyreq->pkt.mode.rreqq.dest_lo = htonl(addr_lo);
+
+ qld = (u_int32_t *)&asyreq->pkt;
+ if (!read)
+ asyreq->pkt.mode.wreqq.data = data;
+
+ if (ioctl(fd, FW_ASYREQ, asyreq) < 0) {
+ err(1, "ioctl");
+ }
+ res = qld[3];
+ free(asyreq);
+ if (read)
+ return ntohl(res);
+ else
+ return 0;
+}
+void
+send_phy_config(int fd, int root_node, int gap_count)
+{
+ struct fw_asyreq *asyreq;
+
+ asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12);
+ asyreq->req.len = 12;
+ asyreq->req.type = FWASREQNODE;
+ asyreq->pkt.mode.ld[0] = 0;
+ asyreq->pkt.mode.ld[1] = 0;
+ asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
+ if (root_node >= 0)
+ asyreq->pkt.mode.ld[1] |= htonl((root_node & 0x3f) << 24 | 1 << 23);
+ if (gap_count >= 0)
+ asyreq->pkt.mode.ld[1] |= htonl(1 << 22 | (gap_count & 0x3f) << 16);
+ asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
+
+ printf("send phy_config root_node=%d gap_count=%d\n",
+ root_node, gap_count);
+
+ if (ioctl(fd, FW_ASYREQ, asyreq) < 0) {
+ err(1, "ioctl");
+ }
+}
+
+void
+set_pri_req(int fd, int pri_req)
+{
+ struct fw_devlstreq data;
+ u_int32_t max, reg, old;
+ int i;
+
+ get_num_of_dev(fd, &data);
+#define BUGET_REG 0xf0000218
+ for (i = 0; i < data.n; i++) {
+ if (!data.status[i])
+ continue;
+ reg = read_write_quad(fd, data.eui[i], BUGET_REG, 1, 0);
+ printf("%d %08x:%08x, %08x",
+ data.dst[i], data.eui[i].hi, data.eui[i].lo, reg);
+ if (reg > 0 && pri_req >= 0) {
+ old = (reg & 0x3f);
+ max = (reg & 0x3f00) >> 8;
+ if (pri_req > max)
+ pri_req = max;
+ printf(" 0x%x -> 0x%x\n", old, pri_req);
+ read_write_quad(fd, data.eui[i], BUGET_REG, 0, pri_req);
+ } else {
+ printf("\n");
+ }
+ }
+}
+
+void parse_bus_info_block(u_int32_t *p, int info_len)
+{
+ int i;
+
+ for (i = 0; i < info_len; i++) {
+ printf("bus_info%d: 0x%08x\n", i, *p++);
+ }
+}
+
+int
+get_crom(int fd, int node, void *crom_buf, int len)
+{
+ struct fw_crom_buf buf;
+ int i, error;
+ struct fw_devlstreq data;
+
+ get_num_of_dev(fd, &data);
+
+ for (i = 0; i < data.n; i++) {
+ if (data.dst[i] == node && data.eui[i].lo != 0)
+ break;
+ }
+ if (i != data.n) {
+ buf.eui = data.eui[i];
+ } else {
+ err(1, "no such node: %d\n", node);
+ }
+
+ buf.len = len;
+ buf.ptr = crom_buf;
+ if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) {
+ err(1, "ioctl");
+ }
+ return error;
+}
+
+show_crom(u_int32_t *crom_buf)
+{
+ int i;
+ struct crom_context cc;
+ char *desc, info[256];
+ static char *key_types = "ICLD";
+ struct csrreg *reg;
+ struct csrdirectory *dir;
+ struct csrhdr *hdr;
+
+ printf("first quad: 0x%08x\n", *crom_buf);
+ hdr = (struct csrhdr *)crom_buf;
+ if (hdr->info_len == 1) {
+ /* minimum ROM */
+ struct csrreg *reg;
+ reg = (struct csrreg *)hdr;
+ printf("verndor ID: 0x%06x\n", reg->val);
+ return;
+ }
+ printf("len: %d\n", hdr->crc_len);
+ parse_bus_info_block(crom_buf+1, hdr->info_len);
+
+ crom_init_context(&cc, crom_buf);
+ dir = cc.stack[0].dir;
+ printf("root_directory: len=0x%04x(%d) crc=0x%04x\n",
+ dir->crc_len, dir->crc_len, dir->crc);
+ while (cc.depth >= 0) {
+ desc = crom_desc(&cc, info, sizeof(info));
+ reg = crom_get(&cc);
+ for (i = 0; i < cc.depth; i++)
+ printf("\t");
+ printf("%02x(%c:%02x) %06x %s: %s\n",
+ reg->key,
+ key_types[(reg->key & CSRTYPE_MASK)>>6],
+ reg->key & CSRKEY_MASK, reg->val,
+ desc, info);
+ crom_next(&cc);
+ }
+}
+
+#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
+
+dump_crom(u_int32_t *p)
+{
+ int len=1024, i;
+
+ for (i = 0; i < len/(4*8); i ++) {
+ printf(DUMP_FORMAT,
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ }
+}
+
+load_crom(char *filename, u_int32_t *p)
+{
+ FILE *file;
+ int len=1024, i;
+
+ if ((file = fopen(filename, "r")) == NULL)
+ err(1, "load_crom");
+ for (i = 0; i < len/(4*8); i ++) {
+ fscanf(file, DUMP_FORMAT,
+ p, p+1, p+2, p+3, p+4, p+5, p+6, p+7);
+ p += 8;
+ }
+}
+
+static void
+show_topology_map(int fd)
+{
+ struct fw_topology_map *tmap;
+ union fw_self_id sid;
+ int i;
+ static char *port_status[] = {" ", "-", "P", "C"};
+ static char *pwr_class[] = {" 0W", "15W", "30W", "45W",
+ "-1W", "-2W", "-5W", "-9W"};
+ static char *speed[] = {"S100", "S200", "S400", "S800"};
+ tmap = malloc(sizeof(struct fw_topology_map));
+ if (tmap == NULL)
+ return;
+ if (ioctl(fd, FW_GTPMAP, tmap) < 0) {
+ err(1, "ioctl");
+ }
+ printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n",
+ tmap->crc_len, tmap->generation,
+ tmap->node_count, tmap->self_id_count);
+ printf("id link gap_cnt speed delay cIRM power port0 port1 port2"
+ " ini more\n");
+ for (i = 0; i < tmap->crc_len - 2; i++) {
+ sid = tmap->self_id[i];
+ if (sid.p0.sequel) {
+ printf("%02d sequel packet\n", sid.p0.phy_id);
+ continue;
+ }
+ printf("%02d %2d %d %4s %d %d %3s"
+ " %s %s %s %d %d\n",
+ sid.p0.phy_id,
+ sid.p0.link_active,
+ sid.p0.gap_count,
+ speed[sid.p0.phy_speed],
+ sid.p0.phy_delay,
+ sid.p0.contender,
+ pwr_class[sid.p0.power_class],
+ port_status[sid.p0.port0],
+ port_status[sid.p0.port1],
+ port_status[sid.p0.port2],
+ sid.p0.initiated_reset,
+ sid.p0.more_packets
+ );
+ }
+ free(tmap);
+}
+
+static void
+show_speed_map(int fd)
+{
+ struct fw_speed_map *smap;
+ int i,j;
+
+ smap = malloc(sizeof(struct fw_speed_map));
+ if (smap == NULL)
+ return;
+ if (ioctl(fd, FW_GSPMAP, &smap) < 0) {
+ err(1, "ioctl");
+ }
+ printf("crc_len: %d generation:%d\n", smap->crc_len, smap->generation);
+ for (i = 0; i < 64; i ++) {
+ for (j = 0; j < 64; j ++)
+ printf("%d", smap->speed[i][j]);
+ printf("\n");
+ }
+ free(smap);
+}
+
+int
+main(int argc, char **argv)
+{
+ char devname[] = "/dev/fw1";
+ u_int32_t crom_buf[1024/4];
+ int fd, tmp, ch, len=1024;
+
+ if ((fd = open(devname, O_RDWR)) < 0)
+ err(1, "open");
+
+ if (argc < 2) {
+ list_dev(fd);
+ usage();
+ }
+
+ while ((ch = getopt(argc, argv, "g:b:rtsc:d:l:")) != -1)
+ switch(ch) {
+ case 'g':
+ /* gap count */
+ tmp = strtol(optarg, NULL, 0);
+ send_phy_config(fd, -1, tmp);
+ break;
+ case 'b':
+ tmp = strtol(optarg, NULL, 0);
+ set_pri_req(fd, tmp);
+ break;
+ case 'r':
+ if(ioctl(fd, FW_IBUSRST, &tmp) < 0)
+ err(1, "ioctl");
+ break;
+ case 't':
+ show_topology_map(fd);
+ break;
+ case 's':
+ show_speed_map(fd);
+ break;
+ case 'c':
+ tmp = strtol(optarg, NULL, 0);
+ get_crom(fd, tmp, crom_buf, len);
+ show_crom(crom_buf);
+ break;
+ case 'd':
+ tmp = strtol(optarg, NULL, 0);
+ get_crom(fd, tmp, crom_buf, len);
+ dump_crom(crom_buf);
+ break;
+ case 'l':
+ load_crom(optarg, crom_buf);
+ show_crom(crom_buf);
+ break;
+ default:
+ usage();
+ }
+ return 0;
+}
diff --git a/usr.sbin/fwcontrol/fwcrom.c b/usr.sbin/fwcontrol/fwcrom.c
new file mode 100644
index 0000000..34e1674
--- /dev/null
+++ b/usr.sbin/fwcontrol/fwcrom.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2002
+ * Hidetoshi Shimokawa. All rights reserved.
+ *
+ * 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 Hidetoshi Shimokawa.
+ *
+ * 4. Neither the name of the author 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 REGENTS 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 REGENTS 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/iec13213.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#else
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+void
+crom_init_context(struct crom_context *cc, u_int32_t *p)
+{
+ struct csrhdr *hdr;
+
+ hdr = (struct csrhdr *)p;
+ if (hdr->info_len == 1) {
+ /* minimum ROM */
+ cc->depth = -1;
+ }
+ p += 1 + hdr->info_len;
+ cc->depth = 0;
+ cc->stack[0].dir = (struct csrdirectory *)p;
+ cc->stack[0].index = 0;
+}
+
+struct csrreg *
+crom_get(struct crom_context *cc)
+{
+ struct crom_ptr *ptr;
+
+ ptr = &cc->stack[cc->depth];
+ return (&ptr->dir->entry[ptr->index]);
+}
+
+void
+crom_next(struct crom_context *cc)
+{
+ struct crom_ptr *ptr;
+ struct csrreg *reg;
+
+ if (cc->depth < 0)
+ return;
+ reg = crom_get(cc);
+ if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) {
+ cc->depth ++;
+ if (cc->depth > CROM_MAX_DEPTH) {
+ printf("crom_next: too deep\n");
+ cc->depth --;
+ goto again;
+ }
+ cc->stack[cc->depth].dir = (struct csrdirectory *)
+ (reg + reg->val);
+ cc->stack[cc->depth].index = 0;
+ return;
+ }
+again:
+ ptr = &cc->stack[cc->depth];
+ ptr->index ++;
+ if (ptr->index < ptr->dir->crc_len)
+ return;
+ if (cc->depth > 0) {
+ cc->depth--;
+ goto again;
+ }
+ /* no more data */
+ cc->depth = -1;
+}
+
+
+struct csrreg *
+crom_search_key(struct crom_context *cc, u_int8_t key)
+{
+ struct csrreg *reg;
+
+ while(cc->depth >= 0) {
+ reg = crom_get(cc);
+ if (reg->key == key)
+ return reg;
+ crom_next(cc);
+ }
+ return NULL;
+}
+
+void
+crom_parse_text(struct crom_context *cc, char *buf, int len)
+{
+ struct csrreg *reg;
+ struct csrtext *textleaf;
+ u_int32_t *bp;
+ int i, qlen;
+ static char *nullstr = "(null)";
+
+ reg = crom_get(cc);
+ if (reg->key != CROM_TEXTLEAF) {
+ strncpy(buf, nullstr, len);
+ return;
+ }
+ textleaf = (struct csrtext *)(reg + reg->val);
+
+ /* XXX should check spec and type */
+
+ bp = (u_int32_t *)&buf[0];
+ qlen = textleaf->crc_len - 2;
+ if (len < qlen * 4)
+ qlen = len/4;
+ for (i = 0; i < qlen; i ++)
+ *bp++ = ntohl(textleaf->text[i]);
+ /* make sure to terminate the string */
+ if (len <= qlen * 4)
+ buf[len - 1] = 0;
+ else
+ buf[qlen * 4] = 0;
+}
+
+u_int16_t
+crom_crc(u_int32_t *ptr, int len)
+{
+ int i, shift;
+ u_int32_t data, sum, crc = 0;
+
+ for (i = 0; i < len; i++) {
+ data = ptr[i];
+ for (shift = 28; shift >= 0; shift -= 4) {
+ sum = ((crc >> 12) ^ (data >> shift)) & 0xf;
+ crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;
+ }
+ crc &= 0xffff;
+ }
+ return((u_int16_t) crc);
+}
+
+#ifndef _KERNEL
+char *
+crom_desc(struct crom_context *cc, char *buf, int len)
+{
+ struct csrreg *reg;
+ struct csrdirectory *dir;
+ char *desc;
+
+ reg = crom_get(cc);
+ switch (reg->key & CSRTYPE_MASK) {
+ case CSRTYPE_I:
+ snprintf(buf, len, "%d", reg->val);
+ break;
+ case CSRTYPE_L:
+ case CSRTYPE_C:
+ snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val);
+ break;
+ case CSRTYPE_D:
+ dir = (struct csrdirectory *) (reg + reg->val);
+ snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x",
+ dir->crc_len, dir->crc_len, dir->crc);
+ }
+ switch (reg->key) {
+ case 0x03:
+ desc = "module_vendor_ID";
+ break;
+ case 0x04:
+ desc = "hardware_version";
+ break;
+ case 0x0c:
+ desc = "node_capabilities";
+ break;
+ case 0x12:
+ desc = "unit_spec_ID";
+ break;
+ case 0x13:
+ desc = "unit_sw_version";
+ break;
+ case 0x14:
+ desc = "logical_unit_number";
+ break;
+ case 0x17:
+ desc = "model_ID";
+ break;
+ case 0x38:
+ desc = "command_set_spec_ID";
+ break;
+ case 0x39:
+ desc = "command_set";
+ break;
+ case 0x3a:
+ desc = "unit_characteristics";
+ break;
+ case 0x3b:
+ desc = "command_set_revision";
+ break;
+ case 0x3c:
+ desc = "firmware_revision";
+ break;
+ case 0x3d:
+ desc = "reconnect_timeout";
+ break;
+ case 0x54:
+ desc = "management_agent";
+ break;
+ case 0x81:
+ desc = "text_leaf";
+ crom_parse_text(cc, buf, len);
+ break;
+ case 0xd1:
+ desc = "unit_directory";
+ break;
+ case 0xd4:
+ desc = "logical_unit_directory";
+ break;
+ default:
+ desc = "unknown";
+ }
+ return desc;
+}
+#endif
OpenPOWER on IntegriCloud