diff options
Diffstat (limited to 'sys/dev/firewire/fwcrom.c')
-rw-r--r-- | sys/dev/firewire/fwcrom.c | 265 |
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 |