diff options
author | simokawa <simokawa@FreeBSD.org> | 2002-12-30 10:13:16 +0000 |
---|---|---|
committer | simokawa <simokawa@FreeBSD.org> | 2002-12-30 10:13:16 +0000 |
commit | 41352fb7b20f1a4088848598da8af0e45cd4fd40 (patch) | |
tree | fbddb50decc696b20d3af0ca6fa51726a9c3e842 /usr.sbin | |
parent | 88d4214ecfac5aafdd4868ef4e043a637346e459 (diff) | |
download | FreeBSD-src-41352fb7b20f1a4088848598da8af0e45cd4fd40.zip FreeBSD-src-41352fb7b20f1a4088848598da8af0e45cd4fd40.tar.gz |
Import FireWire userland utility.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/Makefile | 1 | ||||
-rw-r--r-- | usr.sbin/fwcontrol/Makefile | 7 | ||||
-rw-r--r-- | usr.sbin/fwcontrol/fwcontrol.8 | 87 | ||||
-rw-r--r-- | usr.sbin/fwcontrol/fwcontrol.c | 410 | ||||
-rw-r--r-- | usr.sbin/fwcontrol/fwcrom.c | 254 |
5 files changed, 759 insertions, 0 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 2e1f72d..1f0214b 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -33,6 +33,7 @@ SUBDIR= IPXrouted \ fdformat \ fdread \ fdwrite \ + fwcontrol \ getfmac \ getpmac \ ifmcstat \ 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 |