summaryrefslogtreecommitdiffstats
path: root/sys/dev/firewire/fwcrom.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/firewire/fwcrom.c')
-rw-r--r--sys/dev/firewire/fwcrom.c265
1 files changed, 258 insertions, 7 deletions
diff --git a/sys/dev/firewire/fwcrom.c b/sys/dev/firewire/fwcrom.c
index d58be50..282a7fd 100644
--- a/sys/dev/firewire/fwcrom.c
+++ b/sys/dev/firewire/fwcrom.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002
+ * Copyright (c) 2002-2003
* Hidetoshi Shimokawa. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,9 @@
*/
#include <sys/param.h>
-#include <dev/firewire/firewire.h>
-#include <dev/firewire/iec13213.h>
+#if defined(_KERNEL) || defined(TEST)
+#include <sys/queue.h>
+#endif
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -48,6 +49,8 @@
#include <stdlib.h>
#include <string.h>
#endif
+#include <dev/firewire/firewire.h>
+#include <dev/firewire/iec13213.h>
void
crom_init_context(struct crom_context *cc, u_int32_t *p)
@@ -179,20 +182,28 @@ crom_desc(struct crom_context *cc, char *buf, int len)
struct csrreg *reg;
struct csrdirectory *dir;
char *desc;
+ u_int16_t crc;
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_L:
+ /* XXX fall through */
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);
+ crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
+ len -= snprintf(buf, len, "len=%d crc=0x%04x",
+ dir->crc_len, dir->crc);
+ if (crc == dir->crc)
+ strncat(buf, "(OK) ", len);
+ else
+ strncat(buf, "(NG) ", len);
+ len -= 5;
}
switch (reg->key) {
case 0x03:
@@ -239,7 +250,7 @@ crom_desc(struct crom_context *cc, char *buf, int len)
break;
case 0x81:
desc = "text_leaf";
- crom_parse_text(cc, buf, len);
+ crom_parse_text(cc, buf + strlen(buf), len);
break;
case 0xd1:
desc = "unit_directory";
@@ -253,3 +264,243 @@ crom_desc(struct crom_context *cc, char *buf, int len)
return desc;
}
#endif
+
+#if defined(_KERNEL) || defined(TEST)
+
+int
+crom_add_quad(struct crom_chunk *chunk, u_int32_t entry)
+{
+ int index;
+
+ index = chunk->data.crc_len;
+ if (index >= CROM_MAX_CHUNK_LEN - 1) {
+ printf("too large chunk %d\n", index);
+ return(-1);
+ }
+ chunk->data.buf[index] = entry;
+ chunk->data.crc_len++;
+ return(index);
+}
+
+int
+crom_add_entry(struct crom_chunk *chunk, int key, int val)
+{
+ struct csrreg *reg;
+ u_int32_t i;
+
+ reg = (struct csrreg *)&i;
+ reg->key = key;
+ reg->val = val;
+ return(crom_add_quad(chunk, (u_int32_t) i));
+}
+
+int
+crom_add_chunk(struct crom_src *src, struct crom_chunk *parent,
+ struct crom_chunk *child, int key)
+{
+ int index;
+
+ if (parent == NULL) {
+ STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
+ return(0);
+ }
+
+ index = crom_add_entry(parent, key, 0);
+ if (index < 0) {
+ return(-1);
+ }
+ child->ref_chunk = parent;
+ child->ref_index = index;
+ STAILQ_INSERT_TAIL(&src->chunk_list, child, link);
+ return(index);
+}
+
+int
+crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent,
+ struct crom_chunk *chunk, char *buf)
+{
+ struct csrtext *tl;
+ u_int32_t *p;
+ int len, i;
+
+ len = strlen(buf);
+#define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
+ if (len > MAX_TEXT) {
+#if __FreeBSD_version < 500000
+ printf("text(%d) trancated to %d.\n", len, MAX_TEXT);
+#else
+ printf("text(%d) trancated to %td.\n", len, MAX_TEXT);
+#endif
+ len = MAX_TEXT;
+ }
+
+ tl = (struct csrtext *) &chunk->data;
+ tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t));
+ tl->spec_id = 0;
+ tl->spec_type = 0;
+ tl->lang_id = 0;
+ p = (u_int32_t *) buf;
+ for (i = 0; i < howmany(len, sizeof(u_int32_t)) / 4; i ++)
+ tl->text[i] = ntohl(*p++);
+ return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF));
+}
+
+static int
+crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen)
+{
+ if (*offset + len > maxlen) {
+ printf("Config. ROM is too large for the buffer\n");
+ return(-1);
+ }
+ bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t));
+ *offset += len;
+ return(0);
+}
+
+int
+crom_load(struct crom_src *src, u_int32_t *buf, int maxlen)
+{
+ struct crom_chunk *chunk, *parent;
+ struct csrhdr *hdr;
+#if 0
+ u_int32_t *ptr;
+#endif
+ int count, offset;
+ int len;
+
+ offset = 0;
+ /* Determine offset */
+ STAILQ_FOREACH(chunk, &src->chunk_list, link) {
+ chunk->offset = offset;
+ /* Assume the offset of the parent is already known */
+ parent = chunk->ref_chunk;
+ if (parent != NULL) {
+ struct csrreg *reg;
+ reg = (struct csrreg *)
+ &parent->data.buf[chunk->ref_index];
+ reg->val = offset -
+ (parent->offset + 1 + chunk->ref_index);
+ }
+ offset += 1 + chunk->data.crc_len;
+ }
+
+ /* Calculate CRC and dump to the buffer */
+ len = 1 + src->hdr.info_len;
+ count = 0;
+ if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0)
+ return(-1);
+ STAILQ_FOREACH(chunk, &src->chunk_list, link) {
+ chunk->data.crc =
+ crom_crc(&chunk->data.buf[0], chunk->data.crc_len);
+
+ len = 1 + chunk->data.crc_len;
+ if (crom_copy((u_int32_t *)&chunk->data, buf,
+ &count, len, maxlen) < 0)
+ return(-1);
+ }
+ hdr = (struct csrhdr *)buf;
+ hdr->crc_len = count - 1;
+ hdr->crc = crom_crc(buf + 1, hdr->crc_len);
+
+#if 0
+ /* byte swap */
+ ptr = buf;
+ for (i = 0; i < count; i ++) {
+ *ptr = htonl(*ptr);
+ ptr++;
+ }
+#endif
+
+ return(count);
+}
+#endif
+
+#ifdef TEST
+int
+main () {
+ struct crom_src src;
+ struct crom_chunk root,unit1,unit2,unit3;
+ struct crom_chunk text1,text2,text3,text4,text5,text6,text7;
+ u_int32_t buf[256], *p;
+ int i;
+
+ bzero(&src, sizeof(src));
+ bzero(&root, sizeof(root));
+ bzero(&unit1, sizeof(unit1));
+ bzero(&unit2, sizeof(unit2));
+ bzero(&unit3, sizeof(unit3));
+ bzero(&text1, sizeof(text1));
+ bzero(&text2, sizeof(text2));
+ bzero(&text3, sizeof(text3));
+ bzero(&text3, sizeof(text4));
+ bzero(&text3, sizeof(text5));
+ bzero(&text3, sizeof(text6));
+ bzero(&text3, sizeof(text7));
+ bzero(buf, sizeof(buf));
+
+ /* BUS info sample */
+ src.hdr.info_len = 4;
+ src.businfo.bus_name = CSR_BUS_NAME_IEEE1394;
+ src.businfo.eui64.hi = 0x11223344;
+ src.businfo.eui64.lo = 0x55667788;
+ src.businfo.link_spd = FWSPD_S400;
+ src.businfo.generation = 0;
+ src.businfo.max_rom = MAXROM_4;
+ src.businfo.max_rec = 10;
+ src.businfo.cyc_clk_acc = 100;
+ src.businfo.pmc = 0;
+ src.businfo.bmc = 1;
+ src.businfo.isc = 1;
+ src.businfo.cmc = 1;
+ src.businfo.irmc = 1;
+ STAILQ_INIT(&src.chunk_list);
+
+ /* Root directory */
+ crom_add_chunk(&src, NULL, &root, 0);
+ crom_add_entry(&root, CSRKEY_NCAP, 0x123456);
+ /* private company_id */
+ crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48);
+
+ crom_add_simple_text(&src, &root, &text1, "FreeBSD");
+ crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version);
+ crom_add_simple_text(&src, &root, &text2, "FreeBSD-5");
+
+ /* SBP unit directory */
+ crom_add_chunk(&src, &root, &unit1, CROM_UDIR);
+ crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10);
+ crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2);
+ crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10);
+ crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI);
+ /* management_agent */
+ crom_add_entry(&unit1, CROM_MGM, 0x1000);
+ crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8);
+ /* Device type and LUN */
+ crom_add_entry(&unit1, CROM_LUN, 0);
+ crom_add_entry(&unit1, CSRKEY_MODEL, 1);
+ crom_add_simple_text(&src, &unit1, &text3, "scsi_target");
+
+ /* RFC2734 IPv4 over IEEE1394 */
+ crom_add_chunk(&src, &root, &unit2, CROM_UDIR);
+ crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF);
+ crom_add_simple_text(&src, &unit2, &text4, "IANA");
+ crom_add_entry(&unit2, CSRKEY_VER, 1);
+ crom_add_simple_text(&src, &unit2, &text5, "IPv4");
+
+ /* RFC3146 IPv6 over IEEE1394 */
+ crom_add_chunk(&src, &root, &unit3, CROM_UDIR);
+ crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF);
+ crom_add_simple_text(&src, &unit3, &text6, "IANA");
+ crom_add_entry(&unit3, CSRKEY_VER, 2);
+ crom_add_simple_text(&src, &unit3, &text7, "IPv6");
+
+ crom_load(&src, buf, 256);
+ p = buf;
+#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
+ for (i = 0; i < 256/8; i ++) {
+ printf(DUMP_FORMAT,
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
+ p += 8;
+ }
+ return(0);
+}
+#endif
OpenPOWER on IntegriCloud